From daniel at zuster.org Mon Feb 22 01:13:55 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Sun, 21 Feb 2010 23:13:55 -0800 Subject: [cfe-commits] r96772 - /cfe/trunk/lib/Analysis/CFG.cpp In-Reply-To: <20100222025927.B76472A6C124@llvm.org> References: <20100222025927.B76472A6C124@llvm.org> Message-ID: <6a8523d61002212313k1929a84fk20d92018395fe4bb@mail.gmail.com> Hi Zhongxing, On Sun, Feb 21, 2010 at 6:59 PM, Zhongxing Xu wrote: > Author: zhongxingxu > Date: Sun Feb 21 20:59:27 2010 > New Revision: 96772 > > URL: http://llvm.org/viewvc/llvm-project?rev=96772&view=rev > Log: > Simplify code: Succ is guaranteed to be not NULL. This turns out not to be true, here is a test case: -- ddunbar at giles:tmp$ cat t.m @interface I0 @end @implementation I0 - (id) im0 { @synchronized(self) { @try {} @catch (...) {} } } @end ddunbar at giles:tmp$ clang -c t.m Assertion failed: (B), function buildCFG, file /Volumes/Data/Users/ddunbar/llvm/tools/clang/lib/Analysis/CFG.cpp, line 267. 0 clang 0x0000000101338cd2 PrintStackTrace(void*) + 34 1 clang 0x000000010133955c SignalHandler(int) + 652 2 libSystem.B.dylib 0x00007fff881f4eaa _sigtramp + 26 3 libSystem.B.dylib 0x00007fff88199bea tiny_malloc_from_free_list + 1196 4 libSystem.B.dylib 0x00007fff88270e74 __pthread_markcancel + 0 5 clang 0x0000000100518b8d (anonymous namespace)::CFGBuilder::buildCFG(clang::Decl const*, clang::Stmt*, clang::ASTContext*, bool, bool) + 1245 6 clang 0x0000000100518e0b clang::CFG::buildCFG(clang::Decl const*, clang::Stmt*, clang::ASTContext*, bool, bool) + 523 7 clang 0x000000010050c94d clang::AnalysisContext::getCFG() + 93 8 clang 0x000000010028490f clang::Sema::CheckFallThrough(clang::AnalysisContext&) + 31 9 clang 0x000000010028babe clang::Sema::CheckFallThroughForFunctionDef(clang::Decl*, clang::Stmt*, clang::AnalysisContext&) + 382 10 clang 0x00000001002b29a9 clang::Sema::ActOnFinishFunctionBody(clang::OpaquePtr<0>, clang::ASTOwningResult<&(clang::ActionBase::DeleteStmt(void*))>, bool) + 377 11 clang 0x00000001002b3483 clang::Sema::ActOnFinishFunctionBody(clang::OpaquePtr<0>, clang::ASTOwningResult<&(clang::ActionBase::DeleteStmt(void*))>) + 67 12 clang 0x0000000100638b73 clang::Parser::ParseObjCMethodDefinition() + 899 13 clang 0x0000000100656543 clang::Parser::ParseExternalDeclaration(clang::CXX0XAttributeList) + 2211 14 clang 0x0000000100656758 clang::Parser::ParseTopLevelDecl(clang::OpaquePtr<1>&) + 104 15 clang 0x0000000100270d4b clang::ParseAST(clang::Preprocessor&, clang::ASTConsumer*, clang::ASTContext&, bool, bool, clang::CodeCompleteConsumer*) + 251 16 clang 0x0000000100052659 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) + 393 17 clang 0x000000010003793e cc1_main(char const**, char const**, char const*, void*) + 2062 18 clang 0x000000010003a89d main + 2077 19 clang 0x00000001000354c8 start + 52 20 clang 0x000000000000001d start + 4294749065 Stack dump: 0. Program arguments: /Volumes/Data/Users/ddunbar/llvm.obj.64/Release/bin/clang -cc1 -triple x86_64-apple-darwin10.0.0 -S -disable-free -main-file-name t.m -pic-level 1 -mdisable-fp-elim -munwind-tables -target-cpu core2 -resource-dir /Volumes/Data/Users/ddunbar/llvm.obj.64/Release/lib/clang/1.1 -fmessage-length 88 -stack-protector 1 -fblocks -fexceptions -fobjc-nonfragile-abi -fdiagnostics-show-option -o /var/folders/DQ/DQ8GT3++HESEzT1obWBynE+++TI/-Tmp-/cc-JnPFgL.s -x objective-c t.m 1. t.m:9:1: current parser token '@' 2. t.m:3:12: parsing Objective-C method 'I0::im0' clang: error: compiler command failed due to signal 6 (use -v to see invocation) -- - Daniel > Modified: > ? ?cfe/trunk/lib/Analysis/CFG.cpp > > Modified: cfe/trunk/lib/Analysis/CFG.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=96772&r1=96771&r2=96772&view=diff > ============================================================================== > --- cfe/trunk/lib/Analysis/CFG.cpp (original) > +++ cfe/trunk/lib/Analysis/CFG.cpp Sun Feb 21 20:59:27 2010 > @@ -264,44 +264,44 @@ > ? 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(), > + ?assert(B); > + > + ?// Finalize the last constructed block. ?This usually involves reversing the > + ?// order of the statements in the 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()); > + ? ?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; > + ? ?// 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; > > - ? ? ?AddSuccessor(B, LI->second); > - ? ?} > + ? ?AddSuccessor(B, 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(), > + ?// 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); > + ? ? ?// 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; > + ? ? ?// 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; > > - ? ? ? ?AddSuccessor(B, LI->second); > - ? ? ?} > + ? ? ?AddSuccessor(B, LI->second); > + ? ?} > > - ? ?Succ = B; > - ?} > + ?Succ = B; > > ? // Create an empty entry block that has no predecessors. > ? cfg->setEntry(createBlock()); > > > _______________________________________________ > cfe-commits mailing list > cfe-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits > From dgregor at apple.com Mon Feb 22 10:44:27 2010 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 22 Feb 2010 16:44:27 -0000 Subject: [cfe-commits] r96784 - /cfe/trunk/lib/CodeGen/CGVtable.cpp Message-ID: <20100222164427.B3D9D2A6C124@llvm.org> Author: dgregor Date: Mon Feb 22 10:44:27 2010 New Revision: 96784 URL: http://llvm.org/viewvc/llvm-project?rev=96784&view=rev Log: Don't use NamedDecl::getNameAsCString() when dealing with C++ methods, since they may not have normal identifiers for names. Fixes PR6369. Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=96784&r1=96783&r2=96784&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVtable.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVtable.cpp Mon Feb 22 10:44:27 2010 @@ -1877,10 +1877,10 @@ // If already set, note the two sets as the same if (0) printf("%s::%s same as %s::%s\n", - PrevU->getParent()->getNameAsCString(), - PrevU->getNameAsCString(), - U->getParent()->getNameAsCString(), - U->getNameAsCString()); + PrevU->getParent()->getNameAsString().c_str(), + PrevU->getNameAsString().c_str(), + U->getParent()->getNameAsString().c_str(), + U->getNameAsString().c_str()); ForwardUnique[PrevU] = U; return; } @@ -1888,11 +1888,11 @@ // Not set, set it now if (0) printf("marking %s::%s %p override as %s::%s\n", - MD->getParent()->getNameAsCString(), - MD->getNameAsCString(), + MD->getParent()->getNameAsString().c_str(), + MD->getNameAsString().c_str(), (void*)MD, - U->getParent()->getNameAsCString(), - U->getNameAsCString()); + U->getParent()->getNameAsString().c_str(), + U->getNameAsString().c_str()); UniqueOverrider[MD] = U; for (CXXMethodDecl::method_iterator mi = MD->begin_overridden_methods(), @@ -1914,8 +1914,8 @@ BuildUniqueOverrider(MD, MD); if (0) printf("top set is %s::%s %p\n", - MD->getParent()->getNameAsCString(), - MD->getNameAsCString(), + MD->getParent()->getNameAsString().c_str(), + MD->getNameAsString().c_str(), (void*)MD); ForwardUnique[MD] = MD; } @@ -1950,7 +1950,7 @@ A_t::iterator J = I; while (++J != E && DclCmp(I, J) == 0) if (DclIsSame(*I, *J)) { - if (0) printf("connecting %s\n", (*I)->getNameAsCString()); + if (0) printf("connecting %s\n", (*I)->getNameAsString().c_str()); ForwardUnique[*J] = *I; } } @@ -2178,7 +2178,7 @@ return; D1(printf(" vfn for %s at %d\n", - dyn_cast(GD.getDecl())->getNameAsCString(), + dyn_cast(GD.getDecl())->getNameAsString().c_str(), (int)Methods.size())); // We didn't find an entry in the vtable that we could use, add a new @@ -2201,7 +2201,7 @@ idx = VCalls.size()+1; VCalls.push_back(Offset/8 - CurrentVBaseOffset/8); D1(printf(" vcall for %s at %d with delta %d\n", - dyn_cast(GD.getDecl())->getNameAsCString(), + dyn_cast(GD.getDecl())->getNameAsString().c_str(), (int)-VCalls.size()-3, (int)VCalls[idx-1])); } } From dgregor at apple.com Mon Feb 22 10:48:26 2010 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 22 Feb 2010 16:48:26 -0000 Subject: [cfe-commits] r96785 - /cfe/trunk/lib/CodeGen/CGVtable.cpp Message-ID: <20100222164826.7BDAF2A6C124@llvm.org> Author: dgregor Date: Mon Feb 22 10:48:26 2010 New Revision: 96785 URL: http://llvm.org/viewvc/llvm-project?rev=96785&view=rev Log: Change the name of the vtable-debugging environment variable to CLANG_VTABLE_DEBUG. Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=96785&r1=96784&r2=96785&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVtable.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVtable.cpp Mon Feb 22 10:48:26 2010 @@ -2034,7 +2034,7 @@ } //#define D1(x) -#define D1(X) do { if (getenv("DEBUG")) { X; } } while (0) +#define D1(X) do { if (getenv("CLANG_VTABLE_DEBUG")) { X; } } while (0) void GenerateVBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset, bool updateVBIndex, Index_t current_vbindex) { From dgregor at apple.com Mon Feb 22 11:06:41 2010 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 22 Feb 2010 17:06:41 -0000 Subject: [cfe-commits] r96787 - in /cfe/trunk: lib/Sema/SemaOverload.cpp test/CXX/temp/temp.spec/temp.explicit/p6.cpp Message-ID: <20100222170641.EF1022A6C124@llvm.org> Author: dgregor Date: Mon Feb 22 11:06:41 2010 New Revision: 96787 URL: http://llvm.org/viewvc/llvm-project?rev=96787&view=rev Log: Do not require a complete type when checking for a pointer conversion between cv1 T* and cv2 T*. Modified: cfe/trunk/lib/Sema/SemaOverload.cpp cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p6.cpp Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=96787&r1=96786&r2=96787&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Feb 22 11:06:41 2010 @@ -1094,6 +1094,7 @@ // here. That is handled by CheckPointerConversion. if (getLangOptions().CPlusPlus && FromPointeeType->isRecordType() && ToPointeeType->isRecordType() && + !Context.hasSameUnqualifiedType(FromPointeeType, ToPointeeType) && !RequireCompleteType(From->getLocStart(), FromPointeeType, PDiag()) && IsDerivedFrom(FromPointeeType, ToPointeeType)) { ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, Modified: cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p6.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p6.cpp?rev=96787&r1=96786&r2=96787&view=diff ============================================================================== --- cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p6.cpp (original) +++ cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p6.cpp Mon Feb 22 11:06:41 2010 @@ -12,3 +12,24 @@ template void f0(int, float*); template void f0<>(double, float*); + +template struct hash { }; +struct S { + bool operator==(const S&) const { return false; } +}; + +template struct Hash_map { + void Method(const T& x) { h(x); } + hash h; +}; + +Hash_map *x; +const Hash_map *foo() { + return x; +} + +template<> struct hash { + int operator()(const S& k) const { + return 0; + } +}; From dgregor at apple.com Mon Feb 22 11:42:47 2010 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 22 Feb 2010 17:42:47 -0000 Subject: [cfe-commits] r96788 - /cfe/trunk/lib/AST/ASTImporter.cpp Message-ID: <20100222174248.02EA22A6C124@llvm.org> Author: dgregor Date: Mon Feb 22 11:42:47 2010 New Revision: 96788 URL: http://llvm.org/viewvc/llvm-project?rev=96788&view=rev Log: Set access specifiers on imported declarations. Modified: cfe/trunk/lib/AST/ASTImporter.cpp Modified: cfe/trunk/lib/AST/ASTImporter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=96788&r1=96787&r2=96788&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTImporter.cpp (original) +++ cfe/trunk/lib/AST/ASTImporter.cpp Mon Feb 22 11:42:47 2010 @@ -1522,6 +1522,7 @@ TypedefDecl *ToTypedef = TypedefDecl::Create(Importer.getToContext(), DC, Loc, Name.getAsIdentifierInfo(), TInfo); + ToTypedef->setAccess(D->getAccess()); ToTypedef->setLexicalDeclContext(LexicalDC); Importer.Imported(D, ToTypedef); LexicalDC->addDecl(ToTypedef); @@ -1581,6 +1582,7 @@ Name.getAsIdentifierInfo(), Importer.Import(D->getTagKeywordLoc()), 0); + D2->setAccess(D->getAccess()); D2->setLexicalDeclContext(LexicalDC); Importer.Imported(D, D2); LexicalDC->addDecl(D2); @@ -1691,6 +1693,7 @@ Name.getAsIdentifierInfo(), Importer.Import(D->getTagKeywordLoc())); D2 = D2CXX; + D2->setAccess(D->getAccess()); if (D->isDefinition()) { // Add base classes. @@ -1779,6 +1782,7 @@ = EnumConstantDecl::Create(Importer.getToContext(), cast(DC), Loc, Name.getAsIdentifierInfo(), T, Init, D->getInitVal()); + ToEnumerator->setAccess(D->getAccess()); ToEnumerator->setLexicalDeclContext(LexicalDC); Importer.Imported(D, ToEnumerator); LexicalDC->addDecl(ToEnumerator); @@ -1886,6 +1890,7 @@ D->isInlineSpecified(), D->hasWrittenPrototype()); } + ToFunction->setAccess(D->getAccess()); ToFunction->setLexicalDeclContext(LexicalDC); Importer.Imported(D, ToFunction); LexicalDC->addDecl(ToFunction); @@ -1939,6 +1944,7 @@ FieldDecl *ToField = FieldDecl::Create(Importer.getToContext(), DC, Loc, Name.getAsIdentifierInfo(), T, TInfo, BitWidth, D->isMutable()); + ToField->setAccess(D->getAccess()); ToField->setLexicalDeclContext(LexicalDC); Importer.Imported(D, ToField); LexicalDC->addDecl(ToField); @@ -2094,6 +2100,7 @@ VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, Loc, Name.getAsIdentifierInfo(), T, TInfo, D->getStorageClass()); + ToVar->setAccess(D->getAccess()); ToVar->setLexicalDeclContext(LexicalDC); Importer.Imported(D, ToVar); LexicalDC->addDecl(ToVar); From dgregor at apple.com Mon Feb 22 11:53:38 2010 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 22 Feb 2010 17:53:38 -0000 Subject: [cfe-commits] r96792 - /cfe/trunk/lib/AST/DeclBase.cpp Message-ID: <20100222175338.C13392A6C124@llvm.org> Author: dgregor Date: Mon Feb 22 11:53:38 2010 New Revision: 96792 URL: http://llvm.org/viewvc/llvm-project?rev=96792&view=rev Log: Don't assert that we have a valid access specifier on an invalid declaration. This is the trivial part of PR6365. Modified: cfe/trunk/lib/AST/DeclBase.cpp Modified: cfe/trunk/lib/AST/DeclBase.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=96792&r1=96791&r2=96792&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclBase.cpp (original) +++ cfe/trunk/lib/AST/DeclBase.cpp Mon Feb 22 11:53:38 2010 @@ -436,7 +436,8 @@ // FunctionDecl) // 4. the context is not a record if (isa(this) || - !isa(getDeclContext())) + !isa(getDeclContext()) || + isInvalidDecl()) return; assert(Access != AS_none && From dgregor at apple.com Mon Feb 22 12:26:18 2010 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 22 Feb 2010 10:26:18 -0800 Subject: [cfe-commits] PATCH: Fix the complex overloading behavior in Clang In-Reply-To: <74c447501002201253p4503c792v2df16885412599b5@mail.gmail.com> References: <74c447501002201253p4503c792v2df16885412599b5@mail.gmail.com> Message-ID: <862C0EDC-5336-40C3-AF5C-BF3A65EA74A4@apple.com> On Feb 20, 2010, at 12:53 PM, Chandler Carruth wrote: > This fixes the Clang behavior for overloads involving complex floating > point numbers. It now agrees with GCC about how these overloads should > be resolved. All the tests were here, they simply had specified that > we expected to do the opposite of what GCC does. Looks good, thanks! > Notably, this fixes the handling of std::complex extensions present in > libstdc++ when converting from integers (among other cases). Excellent. - Doug From dgregor at apple.com Mon Feb 22 12:35:17 2010 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 22 Feb 2010 10:35:17 -0800 Subject: [cfe-commits] PATCH: Initial stab at improving recovery for invalid destructors In-Reply-To: <74c447501002202300s4856c707j943d1de0a6fb4314@mail.gmail.com> References: <74c447501002202300s4856c707j943d1de0a6fb4314@mail.gmail.com> Message-ID: <122872CA-F5DC-4161-BE98-5AC77B5C482F@apple.com> On Feb 20, 2010, at 11:00 PM, Chandler Carruth wrote: > I've been noticing several problems with Clang's recovery for invalid > destructors now that typedef names are being correctly flagged. Most > of them end up asserting due to the strict constraints on the > representation of destructors in the AST. > > The most disruptive thing here is allowing a lot more checking of > invalid function declarations. This allows redeclaration and other > logic to fire which cleans up the destructor representation. I can't > predict exactly how much it will hurt of course. I'm open to other > suggestions. The attached test case now passes, and I'm fixing the new > failures next. They just consist of adding expected errors and notes. Yeah, this looks good. Moving the updates to the user-declared-destructor, POD, and has-trivial-destructor flags into the destructor decl's constructor is definitely goodness. FYI, I already committed the change to lib/AST/DeclBase.cpp separately, so don't be surprised if you get a conflict there. - Doug From dgregor at apple.com Mon Feb 22 12:47:29 2010 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 22 Feb 2010 10:47:29 -0800 Subject: [cfe-commits] [patch] Add support for weakref In-Reply-To: <38a0d8451002202101u7836817cv7742937c7a923294@mail.gmail.com> References: <38a0d8451002161420l737e839bl997ac248d2f62295@mail.gmail.com> <6a8523d61002200819k1c4b1eb3g1976ec52d8611778@mail.gmail.com> <38a0d8451002202101u7836817cv7742937c7a923294@mail.gmail.com> Message-ID: On Feb 20, 2010, at 9:01 PM, Rafael Espindola wrote: >> I don't understand enough about weakref to evaluate the semantics of >> this, but from the docs it seems to not be just equivalent to weak + >> alias? > > At the C/C++ level? It is not, they have different warnings and are > supported in different cases. I update the patch with comments and > tests to try to show where exactly it is supported. > > At the llvm level it gets represented as "alias weak", that is why I > implemented it with WeakAttr + AliasAttr. I can add a WeakRefAttr and > codegen it as "weak" if you want. I would rather have WeakRefAttr in the AST, so we model the source more closely. Codegen can just handle it the same way as "weak" or "alias weak", depending on whether the "alias" attribute is also present. Otherwise, this looks fine to me, but I admit that I don't have a solid understanding of weakref. - Doug From eli.friedman at gmail.com Mon Feb 22 14:40:47 2010 From: eli.friedman at gmail.com (Eli Friedman) Date: Mon, 22 Feb 2010 12:40:47 -0800 Subject: [cfe-commits] [patch] Add support for weakref In-Reply-To: <38a0d8451002202101u7836817cv7742937c7a923294@mail.gmail.com> References: <38a0d8451002161420l737e839bl997ac248d2f62295@mail.gmail.com> <6a8523d61002200819k1c4b1eb3g1976ec52d8611778@mail.gmail.com> <38a0d8451002202101u7836817cv7742937c7a923294@mail.gmail.com> Message-ID: On Sat, Feb 20, 2010 at 9:01 PM, Rafael Espindola wrote: >> I don't understand enough about weakref to evaluate the semantics of >> this, but from the docs it seems to not be just equivalent to weak + >> alias? > > At the C/C++ level? It is not, they have different warnings and are > supported in different cases. I update the patch with comments and > tests to try to show where exactly it is supported. > > At the llvm level it gets represented as "alias weak", that is why I > implemented it with WeakAttr + AliasAttr. I can add a WeakRefAttr and > codegen it as "weak" if you want. That's a bug in llvm-gcc; there's a PR in Bugzilla on it, although it's down at the moment. The correct semantics for weakref if we implement it purely in clang are as follows: 1. Emit weakref variables as external declarations, and put them on a list to go through after everything is emitted. 2. For each weakref variable, see if there is an existing declaration of the target: if there isn't, build a weak declaration of the target. 3. Replace all uses of the weakref with the target. The only issue with this is that it doesn't interact with inline asm correctly. -Eli From fjahanian at apple.com Mon Feb 22 14:48:10 2010 From: fjahanian at apple.com (Fariborz Jahanian) Date: Mon, 22 Feb 2010 20:48:10 -0000 Subject: [cfe-commits] r96798 - in /cfe/trunk: lib/Frontend/RewriteObjC.cpp test/Rewriter/rewrite-rewritten-initializer.mm Message-ID: <20100222204810.E0C1E2A6C12C@llvm.org> Author: fjahanian Date: Mon Feb 22 14:48:10 2010 New Revision: 96798 URL: http://llvm.org/viewvc/llvm-project?rev=96798&view=rev Log: Fixes a rewriting of byref variable when its initializer is itself rewritten. Radar 7669784. Added: cfe/trunk/test/Rewriter/rewrite-rewritten-initializer.mm Modified: cfe/trunk/lib/Frontend/RewriteObjC.cpp Modified: cfe/trunk/lib/Frontend/RewriteObjC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/RewriteObjC.cpp?rev=96798&r1=96797&r2=96798&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/RewriteObjC.cpp (original) +++ cfe/trunk/lib/Frontend/RewriteObjC.cpp Mon Feb 22 14:48:10 2010 @@ -301,8 +301,12 @@ Stmt *RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, SourceLocation OrigEnd); CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD, - Expr **args, unsigned nargs); - Stmt *SynthMessageExpr(ObjCMessageExpr *Exp); + Expr **args, unsigned nargs, + SourceLocation StartLoc=SourceLocation(), + SourceLocation EndLoc=SourceLocation()); + Stmt *SynthMessageExpr(ObjCMessageExpr *Exp, + SourceLocation StartLoc=SourceLocation(), + SourceLocation EndLoc=SourceLocation()); Stmt *RewriteBreakStmt(BreakStmt *S); Stmt *RewriteContinueStmt(ContinueStmt *S); void SynthCountByEnumWithState(std::string &buf); @@ -1952,7 +1956,8 @@ } CallExpr *RewriteObjC::SynthesizeCallToFunctionDecl( - FunctionDecl *FD, Expr **args, unsigned nargs) { + FunctionDecl *FD, Expr **args, unsigned nargs, SourceLocation StartLoc, + SourceLocation EndLoc) { // Get the type, we will need to reference it in a couple spots. QualType msgSendType = FD->getType(); @@ -1968,8 +1973,10 @@ const FunctionType *FT = msgSendType->getAs(); - return new (Context) CallExpr(*Context, ICE, args, nargs, FT->getResultType(), - SourceLocation()); + CallExpr *Exp = + new (Context) CallExpr(*Context, ICE, args, nargs, FT->getResultType(), + EndLoc); + return Exp; } static bool scanForProtocolRefs(const char *startBuf, const char *endBuf, @@ -2533,7 +2540,9 @@ return Context->getTagDeclType(ConstantStringDecl); } -Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { +Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, + SourceLocation StartLoc, + SourceLocation EndLoc) { if (!SelGetUidFunctionDecl) SynthSelGetUidFunctionDecl(); if (!MsgSendFunctionDecl) @@ -2599,7 +2608,9 @@ false, argType, SourceLocation())); CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl, &ClsExprs[0], - ClsExprs.size()); + ClsExprs.size(), + StartLoc, + EndLoc); // To turn off a warning, type-cast to 'id' InitExprs.push_back( // set 'super class', using objc_getClass(). NoTypeInfoCStyleCastExpr(Context, @@ -2654,7 +2665,8 @@ SourceLocation())); CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, &ClsExprs[0], - ClsExprs.size()); + ClsExprs.size(), + StartLoc, EndLoc); MsgExprs.push_back(Cls); } } else { // instance message. @@ -2684,7 +2696,8 @@ false, argType, SourceLocation())); CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, &ClsExprs[0], - ClsExprs.size()); + ClsExprs.size(), + StartLoc, EndLoc); // To turn off a warning, type-cast to 'id' InitExprs.push_back( // set 'super class', using objc_getClass(). @@ -2743,7 +2756,9 @@ Exp->getSelector().getAsString().size(), false, argType, SourceLocation())); CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, - &SelExprs[0], SelExprs.size()); + &SelExprs[0], SelExprs.size(), + StartLoc, + EndLoc); MsgExprs.push_back(SelExp); // Now push any user supplied arguments. @@ -2830,12 +2845,12 @@ cast); // Don't forget the parens to enforce the proper binding. - ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast); + ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); const FunctionType *FT = msgSendType->getAs(); CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0], MsgExprs.size(), - FT->getResultType(), SourceLocation()); + FT->getResultType(), EndLoc); Stmt *ReplacingStmt = CE; if (MsgSendStretFlavor) { // We have the method which returns a struct/union. Must also generate @@ -2898,7 +2913,8 @@ } Stmt *RewriteObjC::RewriteMessageExpr(ObjCMessageExpr *Exp) { - Stmt *ReplacingStmt = SynthMessageExpr(Exp); + Stmt *ReplacingStmt = SynthMessageExpr(Exp, Exp->getLocStart(), + Exp->getLocEnd()); // Now do the actual rewrite. ReplaceStmt(Exp, ReplacingStmt); Added: cfe/trunk/test/Rewriter/rewrite-rewritten-initializer.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Rewriter/rewrite-rewritten-initializer.mm?rev=96798&view=auto ============================================================================== --- cfe/trunk/test/Rewriter/rewrite-rewritten-initializer.mm (added) +++ cfe/trunk/test/Rewriter/rewrite-rewritten-initializer.mm Mon Feb 22 14:48:10 2010 @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// radar 7669784 + +typedef void * id; +void *sel_registerName(const char *); + + at interface NSMutableString +- (NSMutableString *)string; + at end + + at interface Z + at end + + at implementation Z + +- (void)x { + id numbers; + int i, numbersCount = 42; + __attribute__((__blocks__(byref))) int blockSum = 0; + void (^add)(id n, int idx, char *stop) = ^(id n, int idx, char *stop) { }; + [numbers enumerateObjectsUsingBlock:add]; + NSMutableString *forwardAppend = [NSMutableString string]; + __attribute__((__blocks__(byref))) NSMutableString *blockAppend = [NSMutableString string]; +} + + at end + From espindola at google.com Mon Feb 22 15:42:03 2010 From: espindola at google.com (Rafael Espindola) Date: Mon, 22 Feb 2010 16:42:03 -0500 Subject: [cfe-commits] [patch] Add support for weakref In-Reply-To: References: <38a0d8451002161420l737e839bl997ac248d2f62295@mail.gmail.com> <6a8523d61002200819k1c4b1eb3g1976ec52d8611778@mail.gmail.com> <38a0d8451002202101u7836817cv7742937c7a923294@mail.gmail.com> Message-ID: <38a0d8451002221342x613b75efi6d469f1fad8dc705@mail.gmail.com> > I would rather have WeakRefAttr in the AST, so we model the source more closely. Codegen can just handle it the same way as "weak" or "alias weak", depending on whether the "alias" attribute is also present. > > Otherwise, this looks fine to me, but I admit that I don't have a solid understanding of weakref. It is fuzzy for me too. I am mostly trying to do what llvm-gcc does. I have update the patch to add a WeakRefAttr. I have also updated it to be more strict about what it accepts. It will now reject a weakref with a missing target. We can add that back if it is actually used. > ? ? ? ?- Doug Cheers, -- Rafael ?vila de Esp?ndola -------------- next part -------------- A non-text attachment was scrubbed... Name: weakref.patch Type: text/x-patch Size: 9122 bytes Desc: not available Url : http://lists.cs.uiuc.edu/pipermail/cfe-commits/attachments/20100222/f069733f/attachment-0001.bin From espindola at google.com Mon Feb 22 16:09:34 2010 From: espindola at google.com (Rafael Espindola) Date: Mon, 22 Feb 2010 17:09:34 -0500 Subject: [cfe-commits] [patch] Add support for weakref In-Reply-To: References: <38a0d8451002161420l737e839bl997ac248d2f62295@mail.gmail.com> <6a8523d61002200819k1c4b1eb3g1976ec52d8611778@mail.gmail.com> <38a0d8451002202101u7836817cv7742937c7a923294@mail.gmail.com> Message-ID: <38a0d8451002221409y3ac4103bie6e514a5c2d6d85d@mail.gmail.com> > That's a bug in llvm-gcc; there's a PR in Bugzilla on it, although > it's down at the moment. ?The correct semantics for weakref if we > implement it purely in clang are as follows: > > 1. Emit weakref variables as external declarations, and put them on a > list to go through after everything is emitted. > 2. For each weakref variable, see if there is an existing declaration > of the target: if there isn't, build a weak declaration of the target. > 3. Replace all uses of the weakref with the target. > > The only issue with this is that it doesn't interact with inline asm correctly. Interesting. I did some experimentation with gcc Compiling ------------------------------------ extern int a(void); static int c(void) __attribute__((weakref("a"))); void* f(void) { return (void*)c; } ------------------------------- the generated .o by has WEAK DEFAULT UND a but if I add --------------------------------- void* g(void) { return (void*)a; } -------------------------------- the generated file has GLOBAL DEFAULT UND a in no case a "c" symbol is produced. In the case of gcc all it does is pass the work to the assembler via ".weakref c,a". I see two ways we could implement this: 1) Add support in LLVM. The advantage is that we can also just emit a .weakref. The problem is that this would have very strange semantics for LTO. 2) Do it in clang. The first example above would be compiled to ------------------------------------------------- .... declare extern_weak i32 @a() ---------------------------------------------- but the second example would be compiled to ------------------------------------------ .... declare i32 @a() ---------------------------------------- I think the algorithm is a bit different than what you described: 1) Emit uses of a weakref as uses the target if (If the target exists in this file) { nothing to do. There will be no undefined references } else { If (the target declaration is marked with __attribute__((weak))) { declare it using extern_weak. } else if (there is at least one direct undefined reference to it) { declare it without extern_weak. } else { declare it using extern_weak. } } for now my patch gets clang on the same level as llvm-gcc at least. > -Eli > Cheers, -- Rafael ?vila de Esp?ndola From fjahanian at apple.com Mon Feb 22 17:04:20 2010 From: fjahanian at apple.com (Fariborz Jahanian) Date: Mon, 22 Feb 2010 23:04:20 -0000 Subject: [cfe-commits] r96819 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Parse/Parser.h lib/Parse/ParseObjc.cpp lib/Sema/SemaDecl.cpp Message-ID: <20100222230420.F0E0A2A6C130@llvm.org> Author: fjahanian Date: Mon Feb 22 17:04:20 2010 New Revision: 96819 URL: http://llvm.org/viewvc/llvm-project?rev=96819&view=rev Log: Early support for declaring ivars in class extensions. wip. Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Parse/Parser.h cfe/trunk/lib/Parse/ParseObjc.cpp cfe/trunk/lib/Sema/SemaDecl.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=96819&r1=96818&r2=96819&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Feb 22 17:04:20 2010 @@ -1490,6 +1490,8 @@ "ISO C++ forbids forward references to 'enum' types">; def err_redefinition_of_enumerator : Error<"redefinition of enumerator %0">; def err_duplicate_member : Error<"duplicate member %0">; +def err_misplaced_ivar : Error<"ivar may be placed in a class extension " + "in non-fragile-abi2 mode only">; def ext_enum_value_not_int : Extension< "ISO C restricts enumerator values to range of 'int' (%0 is too " "%select{small|large}1)">; Modified: cfe/trunk/include/clang/Parse/Parser.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=96819&r1=96818&r2=96819&view=diff ============================================================================== --- cfe/trunk/include/clang/Parse/Parser.h (original) +++ cfe/trunk/include/clang/Parse/Parser.h Mon Feb 22 17:04:20 2010 @@ -849,6 +849,7 @@ DeclPtrTy ParseObjCAtInterfaceDeclaration(SourceLocation atLoc, AttributeList *prefixAttrs = 0); void ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, + tok::ObjCKeywordKind visibility, SourceLocation atLoc); bool ParseObjCProtocolReferences(llvm::SmallVectorImpl &P, llvm::SmallVectorImpl &PLocs, Modified: cfe/trunk/lib/Parse/ParseObjc.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=96819&r1=96818&r2=96819&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseObjc.cpp (original) +++ cfe/trunk/lib/Parse/ParseObjc.cpp Mon Feb 22 17:04:20 2010 @@ -188,7 +188,10 @@ ProtocolRefs.size(), ProtocolLocs.data(), EndProtoLoc); - + if (Tok.is(tok::l_brace)) + ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, + atLoc); + ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword); return CategoryType; } @@ -229,7 +232,7 @@ EndProtoLoc, attrList); if (Tok.is(tok::l_brace)) - ParseObjCClassInstanceVariables(ClsType, atLoc); + ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, atLoc); ParseObjCInterfaceDeclList(ClsType, tok::objc_interface); return ClsType; @@ -965,6 +968,7 @@ /// struct-declaration /// void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, + tok::ObjCKeywordKind visibility, SourceLocation atLoc) { assert(Tok.is(tok::l_brace) && "expected {"); llvm::SmallVector AllIvarDecls; @@ -973,7 +977,6 @@ SourceLocation LBraceLoc = ConsumeBrace(); // the "{" - tok::ObjCKeywordKind visibility = tok::objc_protected; // While we still have something to read, read the instance variables. while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { // Each iteration of this loop reads one objc-instance-variable-decl. @@ -1228,7 +1231,8 @@ superClassId, superClassLoc); if (Tok.is(tok::l_brace)) // we have ivars - ParseObjCClassInstanceVariables(ImplClsType/*FIXME*/, atLoc); + ParseObjCClassInstanceVariables(ImplClsType/*FIXME*/, + tok::objc_protected, atLoc); ObjCImpDecl = ImplClsType; PendingObjCImpDecl.push_back(ObjCImpDecl); Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=96819&r1=96818&r2=96819&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Feb 22 17:04:20 2010 @@ -5682,6 +5682,19 @@ // Only it is in implementation's lexical context. ClsFields[I]->setLexicalDeclContext(IMPDecl); CheckImplementationIvars(IMPDecl, ClsFields, RecFields.size(), RBrac); + } else if (ObjCCategoryDecl *CDecl = + dyn_cast(EnclosingDecl)) { + if (!LangOpts.ObjCNonFragileABI2 || !CDecl->IsClassExtension()) + Diag(LBrac, diag::err_misplaced_ivar); + else { + // FIXME. Class extension does not have a LocEnd field. + // CDecl->setLocEnd(RBrac); + // Add ivar's to class extension's DeclContext. + for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { + ClsFields[i]->setLexicalDeclContext(CDecl); + CDecl->addDecl(ClsFields[i]); + } + } } } From dgregor at apple.com Mon Feb 22 17:17:23 2010 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 22 Feb 2010 23:17:23 -0000 Subject: [cfe-commits] r96823 - in /cfe/trunk: include/clang-c/Index.h tools/CIndex/CIndex.cpp tools/CIndex/CIndex.exports tools/CIndex/CIndexDiagnostic.cpp tools/c-index-test/c-index-test.c Message-ID: <20100222231723.447AC2A6C12E@llvm.org> Author: dgregor Date: Mon Feb 22 17:17:23 2010 New Revision: 96823 URL: http://llvm.org/viewvc/llvm-project?rev=96823&view=rev Log: Rework the CIndex API for displaying diagnostics. Instead of printing the diagnostics to a FILE*, return a CXString containing the formatted diagnostic. Modified: cfe/trunk/include/clang-c/Index.h cfe/trunk/tools/CIndex/CIndex.cpp cfe/trunk/tools/CIndex/CIndex.exports cfe/trunk/tools/CIndex/CIndexDiagnostic.cpp cfe/trunk/tools/c-index-test/c-index-test.c Modified: cfe/trunk/include/clang-c/Index.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang-c/Index.h?rev=96823&r1=96822&r2=96823&view=diff ============================================================================== --- cfe/trunk/include/clang-c/Index.h (original) +++ cfe/trunk/include/clang-c/Index.h Mon Feb 22 17:17:23 2010 @@ -460,23 +460,22 @@ }; /** - * \brief Display the given diagnostic by printing it to the given file. + * \brief Format the given diagnostic in a manner that is suitable for display. * - * This routine will display the given diagnostic to a file, rendering + * This routine will format the given diagnostic to a string, rendering * the diagnostic according to the various options given. The * \c clang_defaultDiagnosticDisplayOptions() function returns the set of * options that most closely mimics the behavior of the clang compiler. * * \param Diagnostic The diagnostic to print. * - * \param File The file to print to (e.g., \c stderr). - * * \param Options A set of options that control the diagnostic display, * created by combining \c CXDiagnosticDisplayOptions values. + * + * \returns A new string containing for formatted diagnostic. */ -CINDEX_LINKAGE void clang_displayDiagnostic(CXDiagnostic Diagnostic, - FILE *File, - unsigned Options); +CINDEX_LINKAGE CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, + unsigned Options); /** * \brief Retrieve the set of display options most similar to the Modified: cfe/trunk/tools/CIndex/CIndex.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CIndex/CIndex.cpp?rev=96823&r1=96822&r2=96823&view=diff ============================================================================== --- cfe/trunk/tools/CIndex/CIndex.cpp (original) +++ cfe/trunk/tools/CIndex/CIndex.cpp Mon Feb 22 17:17:23 2010 @@ -1007,9 +1007,17 @@ DEnd = Unit->diag_end(); D != DEnd; ++D) { CXStoredDiagnostic Diag(*D, Unit->getASTContext().getLangOptions()); - clang_displayDiagnostic(&Diag, stderr, - clang_defaultDiagnosticDisplayOptions()); + CXString Msg = clang_formatDiagnostic(&Diag, + clang_defaultDiagnosticDisplayOptions()); + fprintf(stderr, "%s\n", clang_getCString(Msg)); + clang_disposeString(Msg); } +#ifdef LLVM_ON_WIN32 + // On Windows, force a flush, since there may be multiple copies of + // stderr and stdout in the file system, all with different buffers + // but writing to the same device. + fflush(stderr); +#endif } return 0; } @@ -1124,9 +1132,18 @@ DEnd = Diags.end(); D != DEnd; ++D) { CXStoredDiagnostic Diag(*D, LangOpts); - clang_displayDiagnostic(&Diag, stderr, - clang_defaultDiagnosticDisplayOptions()); + CXString Msg = clang_formatDiagnostic(&Diag, + clang_defaultDiagnosticDisplayOptions()); + fprintf(stderr, "%s\n", clang_getCString(Msg)); + clang_disposeString(Msg); } + +#ifdef LLVM_ON_WIN32 + // On Windows, force a flush, since there may be multiple copies of + // stderr and stdout in the file system, all with different buffers + // but writing to the same device. + fflush(stderr); +#endif } if (ATU) { Modified: cfe/trunk/tools/CIndex/CIndex.exports URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CIndex/CIndex.exports?rev=96823&r1=96822&r2=96823&view=diff ============================================================================== --- cfe/trunk/tools/CIndex/CIndex.exports (original) +++ cfe/trunk/tools/CIndex/CIndex.exports Mon Feb 22 17:17:23 2010 @@ -6,7 +6,6 @@ _clang_createTranslationUnit _clang_createTranslationUnitFromSourceFile _clang_defaultDiagnosticDisplayOptions -_clang_displayDiagnostic _clang_disposeCodeCompleteResults _clang_disposeDiagnostic _clang_disposeIndex @@ -16,6 +15,7 @@ _clang_enableStackTraces _clang_equalCursors _clang_equalLocations +_clang_formatDiagnostic _clang_getClangVersion _clang_getCString _clang_getCompletionChunkCompletionString Modified: cfe/trunk/tools/CIndex/CIndexDiagnostic.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CIndex/CIndexDiagnostic.cpp?rev=96823&r1=96822&r2=96823&view=diff ============================================================================== --- cfe/trunk/tools/CIndex/CIndexDiagnostic.cpp (original) +++ cfe/trunk/tools/CIndex/CIndexDiagnostic.cpp Mon Feb 22 17:17:23 2010 @@ -15,8 +15,10 @@ #include "CXSourceLocation.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; using namespace clang::cxloc; @@ -47,17 +49,19 @@ delete Stored; } -void clang_displayDiagnostic(CXDiagnostic Diagnostic, FILE *Out, - unsigned Options) { - if (!Diagnostic || !Out) - return; +CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) { + if (!Diagnostic) + return createCXString(""); CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic); // Ignore diagnostics that should be ignored. if (Severity == CXDiagnostic_Ignored) - return; + return createCXString(""); + llvm::SmallString<256> Str; + llvm::raw_svector_ostream Out(Str); + if (Options & CXDiagnostic_DisplaySourceLocation) { // Print source location (file:line), along with optional column // and source ranges. @@ -67,10 +71,10 @@ &File, &Line, &Column, 0); if (File) { CXString FName = clang_getFileName(File); - fprintf(Out, "%s:%d:", clang_getCString(FName), Line); + Out << clang_getCString(FName) << ":" << Line << ":"; clang_disposeString(FName); if (Options & CXDiagnostic_DisplayColumn) - fprintf(Out, "%d:", Column); + Out << Column << ":"; if (Options & CXDiagnostic_DisplaySourceRanges) { unsigned N = clang_getDiagnosticNumRanges(Diagnostic); @@ -89,40 +93,34 @@ if (StartFile != EndFile || StartFile != File) continue; - fprintf(Out, "{%d:%d-%d:%d}", StartLine, StartColumn, - EndLine, EndColumn); + Out << "{" << StartLine << ":" << StartColumn << "-" + << EndLine << ":" << EndColumn << "}"; PrintedRange = true; } if (PrintedRange) - fprintf(Out, ":"); + Out << ":"; } } - fprintf(Out, " "); + Out << " "; } /* Print warning/error/etc. */ switch (Severity) { case CXDiagnostic_Ignored: assert(0 && "impossible"); break; - case CXDiagnostic_Note: fprintf(Out, "note: "); break; - case CXDiagnostic_Warning: fprintf(Out, "warning: "); break; - case CXDiagnostic_Error: fprintf(Out, "error: "); break; - case CXDiagnostic_Fatal: fprintf(Out, "fatal error: "); break; + case CXDiagnostic_Note: Out << "note: "; break; + case CXDiagnostic_Warning: Out << "warning: "; break; + case CXDiagnostic_Error: Out << "error: "; break; + case CXDiagnostic_Fatal: Out << "fatal error: "; break; } CXString Text = clang_getDiagnosticSpelling(Diagnostic); if (clang_getCString(Text)) - fprintf(Out, "%s\n", clang_getCString(Text)); + Out << clang_getCString(Text); else - fprintf(Out, "\n"); + Out << ""; clang_disposeString(Text); - -#ifdef LLVM_ON_WIN32 - // On Windows, force a flush, since there may be multiple copies of - // stderr and stdout in the file system, all with different buffers - // but writing to the same device. - fflush(Out); -#endif + return createCXString(Out.str(), true); } unsigned clang_defaultDiagnosticDisplayOptions() { Modified: cfe/trunk/tools/c-index-test/c-index-test.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/c-index-test/c-index-test.c?rev=96823&r1=96822&r2=96823&view=diff ============================================================================== --- cfe/trunk/tools/c-index-test/c-index-test.c (original) +++ cfe/trunk/tools/c-index-test/c-index-test.c Mon Feb 22 17:17:23 2010 @@ -198,14 +198,18 @@ void PrintDiagnostic(CXDiagnostic Diagnostic) { FILE *out = stderr; CXFile file; + CXString Msg; unsigned display_opts = CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn | CXDiagnostic_DisplaySourceRanges; unsigned i, num_fixits; - - clang_displayDiagnostic(Diagnostic, out, display_opts); + if (clang_getDiagnosticSeverity(Diagnostic) == CXDiagnostic_Ignored) return; + Msg = clang_formatDiagnostic(Diagnostic, display_opts); + fprintf(stderr, "%s\n", clang_getCString(Msg)); + clang_disposeString(Msg); + clang_getInstantiationLocation(clang_getDiagnosticLocation(Diagnostic), &file, 0, 0, 0); if (!file) From dgregor at apple.com Mon Feb 22 18:15:22 2010 From: dgregor at apple.com (Douglas Gregor) Date: Tue, 23 Feb 2010 00:15:22 -0000 Subject: [cfe-commits] r96836 - in /cfe/trunk: lib/Sema/SemaExprCXX.cpp test/CXX/basic/basic.lookup/basic.lookup.classref/p3.cpp test/CXX/basic/basic.lookup/basic.lookup.qual/p6-0x.cpp test/CXX/basic/basic.lookup/basic.lookup.qual/p6.cpp test/SemaCXX/pseudo-destructors.cpp Message-ID: <20100223001522.3DB0A2A6C12E@llvm.org> Author: dgregor Date: Mon Feb 22 18:15:22 2010 New Revision: 96836 URL: http://llvm.org/viewvc/llvm-project?rev=96836&view=rev Log: Implement crazy destructor name lookup semantics differently in C++98/03 and C++0x, since the '0x semantics break valid C++98/03 code. This new mess is tracked by core issue 399, which is still unresolved. Fixes PR6358 and PR6359. Added: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.classref/p3.cpp cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/p6-0x.cpp cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/p6.cpp Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/test/SemaCXX/pseudo-destructors.cpp Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=96836&r1=96835&r2=96836&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Mon Feb 22 18:15:22 2010 @@ -49,7 +49,7 @@ // s->N::S::~S(); // } // - // + // See also PR6358 and PR6359. QualType SearchType; DeclContext *LookupCtx = 0; bool isDependent = false; @@ -62,7 +62,39 @@ SearchType = GetTypeFromParser(ObjectTypePtr); if (SS.isSet()) { - // C++ [basic.lookup.qual]p6: + NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep(); + + bool AlreadySearched = false; + bool LookAtPrefix = true; + if (!getLangOptions().CPlusPlus0x) { + // C++ [basic.lookup.qual]p6: + // If a pseudo-destructor-name (5.2.4) contains a nested-name-specifier, + // the type-names are looked up as types in the scope designated by the + // nested-name-specifier. In a qualified-id of the form: + // + // ::[opt] nested-name-specifier ?? class-name + // + // where the nested-name-specifier designates a namespace scope, and in + // a qualified-id of the form: + // + // ::opt nested-name-specifier class-name :: ?? class-name + // + // the class-names are looked up as types in the scope designated by + // the nested-name-specifier. + // + // Here, we check the first case (completely) and determine whether the + // code below is permitted to look at the prefix of the + // nested-name-specifier (as we do in C++0x). + DeclContext *DC = computeDeclContext(SS, EnteringContext); + if (DC && DC->isFileContext()) { + AlreadySearched = true; + LookupCtx = DC; + isDependent = false; + } else if (DC && isa(DC)) + LookAtPrefix = false; + } + + // C++0x [basic.lookup.qual]p6: // If a pseudo-destructor-name (5.2.4) contains a // nested-name-specifier, the type-names are looked up as types // in the scope designated by the nested-name-specifier. Similarly, in @@ -72,23 +104,33 @@ // // the second class-name is looked up in the same scope as the first. // - // FIXME: We don't implement this, because it breaks lots of - // perfectly reasonable code that no other compilers diagnose. The - // issue is that the first class-name is looked up as a - // nested-name-specifier, so we ignore value declarations, but the - // second lookup is presumably an ordinary name lookup. Hence, we - // end up finding values (say, a function) and complain. See PRs - // 6358 and 6359 for examples of such code. DPG to investigate - // further. - if (ObjectTypePtr) { + // To implement this, we look at the prefix of the + // nested-name-specifier we were given, and determine the lookup + // context from that. + // + // We also fold in the second case from the C++03 rules quoted further + // above. + NestedNameSpecifier *Prefix = 0; + if (AlreadySearched) { + // Nothing left to do. + } else if (LookAtPrefix && (Prefix = NNS->getPrefix())) { + CXXScopeSpec PrefixSS; + PrefixSS.setScopeRep(Prefix); + LookupCtx = computeDeclContext(PrefixSS, EnteringContext); + isDependent = isDependentScopeSpecifier(PrefixSS); + } else if (getLangOptions().CPlusPlus0x && + (LookupCtx = computeDeclContext(SS, EnteringContext))) { + if (!LookupCtx->isTranslationUnit()) + LookupCtx = LookupCtx->getParent(); + isDependent = LookupCtx && LookupCtx->isDependentContext(); + } else if (ObjectTypePtr) { LookupCtx = computeDeclContext(SearchType); isDependent = SearchType->isDependentType(); } else { LookupCtx = computeDeclContext(SS, EnteringContext); - if (LookupCtx) - isDependent = LookupCtx->isDependentContext(); + isDependent = LookupCtx && LookupCtx->isDependentContext(); } - + LookInScope = (LookupCtx == 0) && !isDependent; } else if (ObjectTypePtr) { // C++ [basic.lookup.classref]p3: Added: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.classref/p3.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.classref/p3.cpp?rev=96836&view=auto ============================================================================== --- cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.classref/p3.cpp (added) +++ cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.classref/p3.cpp Mon Feb 22 18:15:22 2010 @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// C++0x [basic.lookup.classref]p3: +// If the unqualified-id is ???type-name, the type-name is looked up in the +// context of the entire postfix-expression. If the type T of the object +// expression is of a class type C, the type-name is also looked up in the +// scope of class C. At least one of the lookups shall find a name that +// refers to (possibly cv-qualified) T. + +// From core issue 305 +struct A { +}; + +struct C { + struct A {}; + void f (); +}; + +void C::f () { + ::A *a; + a->~A (); +} + +// From core issue 414 +struct X {}; +void f() { + X x; + struct X {}; + x.~X(); +} Added: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/p6-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/p6-0x.cpp?rev=96836&view=auto ============================================================================== --- cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/p6-0x.cpp (added) +++ cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/p6-0x.cpp Mon Feb 22 18:15:22 2010 @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s +struct C { + typedef int I; +}; + +typedef int I1, I2; +extern int* p; +extern int* q; + +void f() { + p->C::I::~I(); + q->I1::~I2(); +} + +struct A { + ~A(); +}; + +typedef A AB; +int main() { + AB *p; + p->AB::~AB(); +} Added: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/p6.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/p6.cpp?rev=96836&view=auto ============================================================================== --- cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/p6.cpp (added) +++ cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/p6.cpp Mon Feb 22 18:15:22 2010 @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +struct C { + typedef int I; +}; + +typedef int I1, I2; +extern int* p; +extern int* q; + +void f() { + p->C::I::~I(); + q->I1::~I2(); +} + +struct A { + ~A(); +}; + +typedef A AB; +int main() { + AB *p; + p->AB::~AB(); // expected-error{{identifier 'AB' in pseudo-destructor expression does not name a type}} +} Modified: cfe/trunk/test/SemaCXX/pseudo-destructors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/pseudo-destructors.cpp?rev=96836&r1=96835&r2=96836&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/pseudo-destructors.cpp (original) +++ cfe/trunk/test/SemaCXX/pseudo-destructors.cpp Mon Feb 22 18:15:22 2010 @@ -29,7 +29,7 @@ g().~Bar(); // expected-error{{non-scalar}} f->::~Bar(); - f->N::~Wibble(); // FIXME: Cannot use typedef name in destructor id. + f->N::~Wibble(); // FIXME: technically, Wibble isn't a class-name f->::~Bar(17, 42); // expected-error{{cannot have any arguments}} From rjmccall at apple.com Mon Feb 22 18:48:20 2010 From: rjmccall at apple.com (John McCall) Date: Tue, 23 Feb 2010 00:48:20 -0000 Subject: [cfe-commits] r96842 - in /cfe/trunk: include/clang/AST/DeclCXX.h lib/AST/DeclCXX.cpp lib/CodeGen/CGCXX.cpp lib/CodeGen/CGCall.cpp lib/CodeGen/CGClass.cpp lib/CodeGen/CodeGenFunction.h lib/CodeGen/CodeGenModule.cpp lib/CodeGen/CodeGenModule.h lib/CodeGen/CodeGenTypes.h test/CodeGenCXX/constructors.cpp test/CodeGenCXX/default-arguments.cpp test/CodeGenCXX/destructors.cpp test/CodeGenCXX/virtual-destructor-calls.cpp test/CodeGenCXX/vtable-pointer-initialization.cpp Message-ID: <20100223004821.144DD2A6C12C@llvm.org> Author: rjmccall Date: Mon Feb 22 18:48:20 2010 New Revision: 96842 URL: http://llvm.org/viewvc/llvm-project?rev=96842&view=rev Log: Perform two more constructor/destructor code-size optimizations: 1) emit base destructors as aliases to their unique base class destructors under some careful conditions. This is enabled for the same targets that can support complete-to-base aliases, i.e. not darwin. 2) Emit non-variadic complete constructors for classes with no virtual bases as calls to the base constructor. This is enabled on all targets and in theory can trigger in situations that the alias optimization can't (mostly involving virtual bases, mostly not yet supported). These are bundled together because I didn't think it worthwhile to split them, not because they really need to be. Added: cfe/trunk/test/CodeGenCXX/constructors.cpp Modified: cfe/trunk/include/clang/AST/DeclCXX.h cfe/trunk/lib/AST/DeclCXX.cpp cfe/trunk/lib/CodeGen/CGCXX.cpp cfe/trunk/lib/CodeGen/CGCall.cpp cfe/trunk/lib/CodeGen/CGClass.cpp cfe/trunk/lib/CodeGen/CodeGenFunction.h cfe/trunk/lib/CodeGen/CodeGenModule.cpp cfe/trunk/lib/CodeGen/CodeGenModule.h cfe/trunk/lib/CodeGen/CodeGenTypes.h cfe/trunk/test/CodeGenCXX/default-arguments.cpp cfe/trunk/test/CodeGenCXX/destructors.cpp cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp cfe/trunk/test/CodeGenCXX/vtable-pointer-initialization.cpp Modified: cfe/trunk/include/clang/AST/DeclCXX.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=96842&r1=96841&r2=96842&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclCXX.h (original) +++ cfe/trunk/include/clang/AST/DeclCXX.h Mon Feb 22 18:48:20 2010 @@ -710,7 +710,7 @@ CXXConstructorDecl *getDefaultConstructor(ASTContext &Context); /// getDestructor - Returns the destructor decl for this class. - CXXDestructorDecl *getDestructor(ASTContext &Context); + CXXDestructorDecl *getDestructor(ASTContext &Context) const; /// isLocalClass - If the class is a local class [class.local], returns /// the enclosing function declaration. Modified: cfe/trunk/lib/AST/DeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=96842&r1=96841&r2=96842&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclCXX.cpp (original) +++ cfe/trunk/lib/AST/DeclCXX.cpp Mon Feb 22 18:48:20 2010 @@ -543,14 +543,14 @@ return 0; } -CXXDestructorDecl *CXXRecordDecl::getDestructor(ASTContext &Context) { +CXXDestructorDecl *CXXRecordDecl::getDestructor(ASTContext &Context) const { QualType ClassType = Context.getTypeDeclType(this); DeclarationName Name = Context.DeclarationNames.getCXXDestructorName( Context.getCanonicalType(ClassType)); - DeclContext::lookup_iterator I, E; + DeclContext::lookup_const_iterator I, E; llvm::tie(I, E) = lookup(Name); assert(I != E && "Did not find a destructor!"); Modified: cfe/trunk/lib/CodeGen/CGCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXX.cpp?rev=96842&r1=96841&r2=96842&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGCXX.cpp (original) +++ cfe/trunk/lib/CodeGen/CGCXX.cpp Mon Feb 22 18:48:20 2010 @@ -27,24 +27,88 @@ using namespace clang; using namespace CodeGen; -/// Try to emit a definition as a global alias for another definition. -bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl, - GlobalDecl TargetDecl) { +/// Determines whether the given function has a trivial body that does +/// not require any specific codegen. +static bool HasTrivialBody(const FunctionDecl *FD) { + Stmt *S = FD->getBody(); + if (!S) + return true; + if (isa(S) && cast(S)->body_empty()) + return true; + return false; +} + +/// Try to emit a base destructor as an alias to its primary +/// base-class destructor. +bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) { if (!getCodeGenOpts().CXXCtorDtorAliases) return true; - // Find the referrent. - llvm::GlobalValue *Ref = cast(GetAddrOfGlobal(TargetDecl)); + // If the destructor doesn't have a trivial body, we have to emit it + // separately. + if (!HasTrivialBody(D)) + return true; - // Look for an existing entry. - const char *MangledName = getMangledName(AliasDecl); - llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName]; - if (Entry) { - assert(Entry->isDeclaration() && "definition already exists for alias"); - assert(Entry->getType() == Ref->getType() && - "declaration exists with different type"); + const CXXRecordDecl *Class = D->getParent(); + + // If we need to manipulate a VTT parameter, give up. + if (Class->getNumVBases()) { + // Extra Credit: passing extra parameters is perfectly safe + // in many calling conventions, so only bail out if the ctor's + // calling convention is nonstandard. + return true; } + // If any fields have a non-trivial destructor, we have to emit it + // separately. + for (CXXRecordDecl::field_iterator I = Class->field_begin(), + E = Class->field_end(); I != E; ++I) + if (const RecordType *RT = (*I)->getType()->getAs()) + if (!cast(RT->getDecl())->hasTrivialDestructor()) + return true; + + // Try to find a unique base class with a non-trivial destructor. + const CXXRecordDecl *UniqueBase = 0; + for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(), + E = Class->bases_end(); I != E; ++I) { + + // We're in the base destructor, so skip virtual bases. + if (I->isVirtual()) continue; + + // Skip base classes with trivial destructors. + const CXXRecordDecl *Base + = cast(I->getType()->getAs()->getDecl()); + if (Base->hasTrivialDestructor()) continue; + + // If we've already found a base class with a non-trivial + // destructor, give up. + if (UniqueBase) return true; + UniqueBase = Base; + } + + // If we didn't find any bases with a non-trivial destructor, then + // the base destructor is actually effectively trivial, which can + // happen if it was needlessly user-defined or if there are virtual + // bases with non-trivial destructors. + if (!UniqueBase) + return true; + + // If the base is at a non-zero offset, give up. + const ASTRecordLayout &ClassLayout = Context.getASTRecordLayout(Class); + if (ClassLayout.getBaseClassOffset(UniqueBase) != 0) + return true; + + const CXXDestructorDecl *BaseD = UniqueBase->getDestructor(getContext()); + return TryEmitDefinitionAsAlias(GlobalDecl(D, Dtor_Base), + GlobalDecl(BaseD, Dtor_Base)); +} + +/// Try to emit a definition as a global alias for another definition. +bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl, + GlobalDecl TargetDecl) { + if (!getCodeGenOpts().CXXCtorDtorAliases) + return true; + // The alias will use the linkage of the referrent. If we can't // support aliases with that linkage, fail. llvm::GlobalValue::LinkageTypes Linkage @@ -72,11 +136,32 @@ return true; } + // Derive the type for the alias. + const llvm::PointerType *AliasType + = getTypes().GetFunctionType(AliasDecl)->getPointerTo(); + + // Look for an existing entry. + const char *MangledName = getMangledName(AliasDecl); + llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName]; + if (Entry) { + assert(Entry->isDeclaration() && "definition already exists for alias"); + assert(Entry->getType() == AliasType && + "declaration exists with different type"); + } + + // Find the referrent. Some aliases might require a bitcast, in + // which case the caller is responsible for ensuring the soundness + // of these semantics. + llvm::GlobalValue *Ref = cast(GetAddrOfGlobal(TargetDecl)); + llvm::Constant *Aliasee = Ref; + if (Ref->getType() != AliasType) + Aliasee = llvm::ConstantExpr::getBitCast(Ref, AliasType); + // Create the alias with no name. llvm::GlobalAlias *Alias = - new llvm::GlobalAlias(Ref->getType(), Linkage, "", Ref, &getModule()); + new llvm::GlobalAlias(AliasType, Linkage, "", Aliasee, &getModule()); - // Switch any previous uses to the alias and continue. + // Switch any previous uses to the alias and kill the previous decl. if (Entry) { Entry->replaceAllUsesWith(Alias); Entry->eraseFromParent(); @@ -90,7 +175,6 @@ return false; } - void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) { // The constructor used for constructing this as a complete class; // constucts the virtual bases, then calls the base constructor. @@ -169,6 +253,13 @@ GlobalDecl(D, Dtor_Base))) return; + // The base destructor is equivalent to the base destructor of its + // base class if there is exactly one non-virtual base class with a + // non-trivial destructor, there are no fields with a non-trivial + // destructor, and the body of the destructor is trivial. + if (Type == Dtor_Base && !TryEmitBaseDestructorAsAlias(D)) + return; + llvm::Function *Fn = cast(GetAddrOfCXXDestructor(D, Type)); CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn); Modified: cfe/trunk/lib/CodeGen/CGCall.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=96842&r1=96841&r2=96842&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGCall.cpp (original) +++ cfe/trunk/lib/CodeGen/CGCall.cpp Mon Feb 22 18:48:20 2010 @@ -416,6 +416,18 @@ return FI.getReturnInfo().isIndirect(); } +const llvm::FunctionType *CodeGenTypes::GetFunctionType(GlobalDecl GD) { + const CGFunctionInfo &FI = getFunctionInfo(GD); + + // For definition purposes, don't consider a K&R function variadic. + bool Variadic = false; + if (const FunctionProtoType *FPT = + cast(GD.getDecl())->getType()->getAs()) + Variadic = FPT->isVariadic(); + + return GetFunctionType(FI, Variadic); +} + const llvm::FunctionType * CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic) { std::vector ArgTys; Modified: cfe/trunk/lib/CodeGen/CGClass.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=96842&r1=96841&r2=96842&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGClass.cpp (original) +++ cfe/trunk/lib/CodeGen/CGClass.cpp Mon Feb 22 18:48:20 2010 @@ -891,31 +891,80 @@ } } +/// Checks whether the given constructor is a valid subject for the +/// complete-to-base constructor delegation optimization, i.e. +/// emitting the complete constructor as a simple call to the base +/// constructor. +static bool IsConstructorDelegationValid(const CXXConstructorDecl *Ctor) { + + // Currently we disable the optimization for classes with virtual + // bases because (1) the addresses of parameter variables need to be + // consistent across all initializers but (2) the delegate function + // call necessarily creates a second copy of the parameter variable. + // + // The limiting example (purely theoretical AFAIK): + // struct A { A(int &c) { c++; } }; + // struct B : virtual A { + // B(int count) : A(count) { printf("%d\n", count); } + // }; + // ...although even this example could in principle be emitted as a + // delegation since the address of the parameter doesn't escape. + if (Ctor->getParent()->getNumVBases()) { + // TODO: white-list trivial vbase initializers. This case wouldn't + // be subject to the restrictions below. + + // TODO: white-list cases where: + // - there are no non-reference parameters to the constructor + // - the initializers don't access any non-reference parameters + // - the initializers don't take the address of non-reference + // parameters + // - etc. + // If we ever add any of the above cases, remember that: + // - function-try-blocks will always blacklist this optimization + // - we need to perform the constructor prologue and cleanup in + // EmitConstructorBody. + + return false; + } + + // We also disable the optimization for variadic functions because + // it's impossible to "re-pass" varargs. + if (Ctor->getType()->getAs()->isVariadic()) + return false; + + return true; +} + /// EmitConstructorBody - Emits the body of the current constructor. void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) { const CXXConstructorDecl *Ctor = cast(CurGD.getDecl()); CXXCtorType CtorType = CurGD.getCtorType(); + // Before we go any further, try the complete->base constructor + // delegation optimization. + if (CtorType == Ctor_Complete && IsConstructorDelegationValid(Ctor)) { + EmitDelegateCXXConstructorCall(Ctor, Ctor_Base, Args); + return; + } + Stmt *Body = Ctor->getBody(); - // Some of the optimizations we want to do can't be done with - // function try blocks. + // Enter the function-try-block before the constructor prologue if + // applicable. CXXTryStmtInfo TryInfo; - bool isTryBody = (Body && isa(Body)); - if (isTryBody) + bool IsTryBody = (Body && isa(Body)); + + if (IsTryBody) TryInfo = EnterCXXTryStmt(*cast(Body)); unsigned CleanupStackSize = CleanupEntries.size(); - // Emit the constructor prologue, i.e. the base and member initializers. - - // TODO: for non-variadic complete-object constructors without a - // function try block for a body, we can get away with just emitting - // the vbase initializers, then calling the base constructor. + // Emit the constructor prologue, i.e. the base and member + // initializers. EmitCtorPrologue(Ctor, CtorType); // Emit the body of the statement. - if (isTryBody) + if (IsTryBody) EmitStmt(cast(Body)->getTryBlock()); else if (Body) EmitStmt(Body); @@ -933,7 +982,7 @@ // constructed. EmitCleanupBlocks(CleanupStackSize); - if (isTryBody) + if (IsTryBody) ExitCXXTryStmt(*cast(Body), TryInfo); } @@ -1406,6 +1455,71 @@ EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, VTT, ArgBeg, ArgEnd); } +void +CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, + CXXCtorType CtorType, + const FunctionArgList &Args) { + CallArgList DelegateArgs; + + FunctionArgList::const_iterator I = Args.begin(), E = Args.end(); + assert(I != E && "no parameters to constructor"); + + // this + DelegateArgs.push_back(std::make_pair(RValue::get(LoadCXXThis()), + I->second)); + ++I; + + // vtt + if (llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(Ctor, CtorType))) { + QualType VoidPP = getContext().getPointerType(getContext().VoidPtrTy); + DelegateArgs.push_back(std::make_pair(RValue::get(VTT), VoidPP)); + + if (CGVtableInfo::needsVTTParameter(CurGD)) { + assert(I != E && "cannot skip vtt parameter, already done with args"); + assert(I->second == VoidPP && "skipping parameter not of vtt type"); + ++I; + } + } + + // Explicit arguments. + for (; I != E; ++I) { + + const VarDecl *Param = I->first; + QualType ArgType = Param->getType(); // because we're passing it to itself + + // StartFunction converted the ABI-lowered parameter(s) into a + // local alloca. We need to turn that into an r-value suitable + // for EmitCall. + llvm::Value *Local = GetAddrOfLocalVar(Param); + RValue Arg; + + // For the most part, we just need to load the alloca, except: + // 1) aggregate r-values are actually pointers to temporaries, and + // 2) references to aggregates are pointers directly to the aggregate. + // I don't know why references to non-aggregates are different here. + if (ArgType->isReferenceType()) { + const ReferenceType *RefType = ArgType->getAs(); + if (hasAggregateLLVMType(RefType->getPointeeType())) + Arg = RValue::getAggregate(Local); + else + // Locals which are references to scalars are represented + // with allocas holding the pointer. + Arg = RValue::get(Builder.CreateLoad(Local)); + } else { + if (hasAggregateLLVMType(ArgType)) + Arg = RValue::getAggregate(Local); + else + Arg = RValue::get(EmitLoadOfScalar(Local, false, ArgType)); + } + + DelegateArgs.push_back(std::make_pair(Arg, ArgType)); + } + + EmitCall(CGM.getTypes().getFunctionInfo(Ctor, CtorType), + CGM.GetAddrOfCXXConstructor(Ctor, CtorType), + ReturnValueSlot(), DelegateArgs, Ctor); +} + void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, CXXDtorType Type, llvm::Value *This) { Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=96842&r1=96841&r2=96842&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original) +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Mon Feb 22 18:48:20 2010 @@ -789,6 +789,9 @@ const CXXRecordDecl *BaseClassDecl, QualType Ty); + void EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, + CXXCtorType CtorType, + const FunctionArgList &Args); void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=96842&r1=96841&r2=96842&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Mon Feb 22 18:48:20 2010 @@ -1195,28 +1195,8 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) { - const llvm::FunctionType *Ty; const FunctionDecl *D = cast(GD.getDecl()); - - if (const CXXMethodDecl *MD = dyn_cast(D)) { - bool isVariadic = D->getType()->getAs()->isVariadic(); - - Ty = getTypes().GetFunctionType(getTypes().getFunctionInfo(MD), isVariadic); - } else { - Ty = cast(getTypes().ConvertType(D->getType())); - - // As a special case, make sure that definitions of K&R function - // "type foo()" aren't declared as varargs (which forces the backend - // to do unnecessary work). - if (D->getType()->isFunctionNoProtoType()) { - assert(Ty->isVarArg() && "Didn't lower type as expected"); - // Due to stret, the lowered function could have arguments. - // Just create the same type as was lowered by ConvertType - // but strip off the varargs bit. - std::vector Args(Ty->param_begin(), Ty->param_end()); - Ty = llvm::FunctionType::get(Ty->getReturnType(), Args, false); - } - } + const llvm::FunctionType *Ty = getTypes().GetFunctionType(GD); // Get or create the prototype for the function. llvm::Constant *Entry = GetAddrOfFunction(GD, Ty); Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=96842&r1=96841&r2=96842&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.h (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.h Mon Feb 22 18:48:20 2010 @@ -485,6 +485,7 @@ // C++ related functions. bool TryEmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target); + bool TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D); void EmitNamespace(const NamespaceDecl *D); void EmitLinkageSpec(const LinkageSpecDecl *D); Modified: cfe/trunk/lib/CodeGen/CodeGenTypes.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenTypes.h?rev=96842&r1=96841&r2=96842&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenTypes.h (original) +++ cfe/trunk/lib/CodeGen/CodeGenTypes.h Mon Feb 22 18:48:20 2010 @@ -168,6 +168,8 @@ const llvm::FunctionType *GetFunctionType(const CGFunctionInfo &Info, bool IsVariadic); + const llvm::FunctionType *GetFunctionType(GlobalDecl GD); + /// GetFunctionTypeForVtable - Get the LLVM function type for use in a vtable, /// given a CXXMethodDecl. If the method to has an incomplete return type, Added: cfe/trunk/test/CodeGenCXX/constructors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/constructors.cpp?rev=96842&view=auto ============================================================================== --- cfe/trunk/test/CodeGenCXX/constructors.cpp (added) +++ cfe/trunk/test/CodeGenCXX/constructors.cpp Mon Feb 22 18:48:20 2010 @@ -0,0 +1,94 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -emit-llvm -o - | FileCheck %s + +struct Member { int x; Member(); Member(int); Member(const Member &); }; +struct VBase { int x; VBase(); VBase(int); VBase(const VBase &); }; + +struct ValueClass { + ValueClass(int x, int y) : x(x), y(y) {} + int x; + int y; +}; // subject to ABI trickery + + + +/* Test basic functionality. */ +class A { + A(struct Undeclared &); + A(ValueClass); + Member mem; +}; + +A::A(struct Undeclared &ref) : mem(0) {} + +// Check that delegation works. +// CHECK: define void @_ZN1AC1ER10Undeclared( +// CHECK: call void @_ZN1AC2ER10Undeclared( + +// CHECK: define void @_ZN1AC2ER10Undeclared( +// CHECK: call void @_ZN6MemberC1Ei( + +A::A(ValueClass v) : mem(v.y - v.x) {} + +// CHECK: define void @_ZN1AC1E10ValueClass( +// CHECK: call void @_ZN1AC2E10ValueClass( + +// CHECK: define void @_ZN1AC2E10ValueClass( +// CHECK: call void @_ZN6MemberC1Ei( + + +/* Test that things work for inheritance. */ +struct B : A { + B(struct Undeclared &); + Member mem; +}; + +B::B(struct Undeclared &ref) : A(ref), mem(1) {} + +// CHECK: define void @_ZN1BC1ER10Undeclared( +// CHECK: call void @_ZN1BC2ER10Undeclared( + +// CHECK: define void @_ZN1BC2ER10Undeclared( +// CHECK: call void @_ZN1AC2ER10Undeclared( +// CHECK: call void @_ZN6MemberC1Ei( + + + +/* Test that the delegation optimization is disabled for classes with + virtual bases (for now). This is necessary because a vbase + initializer could access one of the parameter variables by + reference. That's a solvable problem, but let's not solve it right + now. */ +struct C : virtual A { + C(int); + Member mem; +}; +C::C(int x) : A(ValueClass(x, x+1)), mem(x * x) {} + +// CHECK: define void @_ZN1CC1Ei( +// CHECK: call void @_ZN10ValueClassC1Eii( +// CHECK: call void @_ZN1AC2E10ValueClass( +// CHECK: call void @_ZN6MemberC1Ei( + +// CHECK: define void @_ZN1CC2Ei( +// CHECK: call void @_ZN6MemberC1Ei( + + + +/* Test that the delegation optimization is disabled for varargs + constructors. */ +struct D : A { + D(int, ...); + Member mem; +}; + +D::D(int x, ...) : A(ValueClass(x, x+1)), mem(x*x) {} + +// CHECK: define void @_ZN1DC1Eiz( +// CHECK: call void @_ZN10ValueClassC1Eii( +// CHECK: call void @_ZN1AC2E10ValueClass( +// CHECK: call void @_ZN6MemberC1Ei( + +// CHECK: define void @_ZN1DC2Eiz( +// CHECK: call void @_ZN10ValueClassC1Eii( +// CHECK: call void @_ZN1AC2E10ValueClass( +// CHECK: call void @_ZN6MemberC1Ei( Modified: cfe/trunk/test/CodeGenCXX/default-arguments.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/default-arguments.cpp?rev=96842&r1=96841&r2=96842&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/default-arguments.cpp (original) +++ cfe/trunk/test/CodeGenCXX/default-arguments.cpp Mon Feb 22 18:48:20 2010 @@ -43,11 +43,7 @@ }; // CHECK: define void @_ZN1CC1Ev( -// CHECK: call void @_ZN2A1C1Ev( -// CHECK: call void @_ZN2A2C1Ev( -// CHECK: call void @_ZN1BC1ERK2A1RK2A2( -// CHECK: call void @_ZN2A2D1Ev -// CHECK: call void @_ZN2A1D1Ev +// CHECK: call void @_ZN1CC2Ev( // CHECK: define void @_ZN1CC2Ev( // CHECK: call void @_ZN2A1C1Ev( Modified: cfe/trunk/test/CodeGenCXX/destructors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/destructors.cpp?rev=96842&r1=96841&r2=96842&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/destructors.cpp (original) +++ cfe/trunk/test/CodeGenCXX/destructors.cpp Mon Feb 22 18:48:20 2010 @@ -1,4 +1,11 @@ // RUN: %clang_cc1 %s -emit-llvm -o - -mconstructor-aliases | FileCheck %s + +// CHECK: @_ZN5test01AD1Ev = alias {{.*}} @_ZN5test01AD2Ev +// CHECK: @_ZN5test11MD2Ev = alias {{.*}} @_ZN5test11AD2Ev +// CHECK: @_ZN5test11ND2Ev = alias {{.*}} @_ZN5test11AD2Ev +// CHECK: @_ZN5test11OD2Ev = alias {{.*}} @_ZN5test11AD2Ev +// CHECK: @_ZN5test11SD2Ev = alias bitcast {{.*}} @_ZN5test11AD2Ev + struct A { int a; @@ -60,7 +67,7 @@ // The function-try-block won't suppress -mconstructor-aliases here. A::~A() try { } catch (int i) {} -// CHECK: @_ZN5test01AD1Ev = alias {{.*}} @_ZN5test01AD2Ev +// complete destructor alias tested above // CHECK: define void @_ZN5test01AD2Ev // CHECK: invoke void @_ZN5test06MemberD1Ev @@ -89,3 +96,40 @@ // CHECK: invoke void @_ZN5test04BaseD2Ev // CHECK: unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]] } + +// Test base-class aliasing. +namespace test1 { + struct A { ~A(); char ***m; }; // non-trivial destructor + struct B { ~B(); }; // non-trivial destructor + struct Empty { }; // trivial destructor, empty + struct NonEmpty { int x; }; // trivial destructor, non-empty + + struct M : A { ~M(); }; + M::~M() {} // alias tested above + + struct N : A, Empty { ~N(); }; + N::~N() {} // alias tested above + + struct O : Empty, A { ~O(); }; + O::~O() {} // alias tested above + + struct P : NonEmpty, A { ~P(); }; + P::~P() {} // CHECK: define void @_ZN5test11PD2Ev + + struct Q : A, B { ~Q(); }; + Q::~Q() {} // CHECK: define void @_ZN5test11QD2Ev + + struct R : A { ~R(); }; + R::~R() { A a; } // CHECK: define void @_ZN5test11RD2Ev + + struct S : A { ~S(); int x; }; + S::~S() {} // alias tested above + + struct T : A { ~T(); B x; }; + T::~T() {} // CHECK: define void @_ZN5test11TD2Ev + + // The VTT parameter prevents this. We could still make this work + // for calling conventions that are safe against extra parameters. + struct U : A, virtual B { ~U(); }; + U::~U() {} // CHECK: define void @_ZN5test11UD2Ev +} Modified: cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp?rev=96842&r1=96841&r2=96842&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp (original) +++ cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp Mon Feb 22 18:48:20 2010 @@ -1,16 +1,25 @@ // RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 -mconstructor-aliases | FileCheck %s +struct Member { + ~Member(); +}; + struct A { virtual ~A(); }; struct B : A { + Member m; virtual ~B(); }; // Complete dtor: just an alias because there are no virtual bases. // CHECK: @_ZN1BD1Ev = alias {{.*}} @_ZN1BD2Ev +// (aliases from C) +// CHECK: @_ZN1CD1Ev = alias {{.*}} @_ZN1CD2Ev +// CHECK: @_ZN1CD2Ev = alias bitcast {{.*}} @_ZN1BD2Ev + // Deleting dtor: defers to the complete dtor. // CHECK: define void @_ZN1BD0Ev // CHECK: call void @_ZN1BD1Ev @@ -18,6 +27,22 @@ // Base dtor: actually calls A's base dtor. // CHECK: define void @_ZN1BD2Ev +// CHECK: call void @_ZN6MemberD1Ev // CHECK: call void @_ZN1AD2Ev B::~B() { } + +struct C : B { + ~C(); +}; + +C::~C() { } + +// Complete dtor: just an alias (checked above). + +// Deleting dtor: defers to the complete dtor. +// CHECK: define void @_ZN1CD0Ev +// CHECK: call void @_ZN1CD1Ev +// CHECK: call void @_ZdlPv + +// Base dtor: just an alias to B's base dtor. Modified: cfe/trunk/test/CodeGenCXX/vtable-pointer-initialization.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/vtable-pointer-initialization.cpp?rev=96842&r1=96841&r2=96842&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/vtable-pointer-initialization.cpp (original) +++ cfe/trunk/test/CodeGenCXX/vtable-pointer-initialization.cpp Mon Feb 22 18:48:20 2010 @@ -42,13 +42,16 @@ void f() { B b; } // CHECK: define linkonce_odr void @_ZN1BC1Ev( -// CHECK: call void @_ZN4BaseC2Ev( -// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2) -// CHECK: call void @_ZN5FieldC1Ev -// CHECK: ret void +// CHECK: call void @_ZN1BC2Ev( // CHECK: define linkonce_odr void @_ZN1BD1Ev( // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2) // CHECK: call void @_ZN5FieldD1Ev( // CHECK: call void @_ZN4BaseD2Ev( // CHECK: ret void + +// CHECK: define linkonce_odr void @_ZN1BC2Ev( +// CHECK: call void @_ZN4BaseC2Ev( +// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2) +// CHECK: call void @_ZN5FieldC1Ev +// CHECK: ret void From xuzhongxing at gmail.com Mon Feb 22 19:17:41 2010 From: xuzhongxing at gmail.com (Zhongxing Xu) Date: Tue, 23 Feb 2010 01:17:41 -0000 Subject: [cfe-commits] r96846 - /cfe/trunk/include/clang/Checker/PathSensitive/MemRegion.h Message-ID: <20100223011741.643C72A6C12C@llvm.org> Author: zhongxingxu Date: Mon Feb 22 19:17:41 2010 New Revision: 96846 URL: http://llvm.org/viewvc/llvm-project?rev=96846&view=rev Log: Correct comment. Modified: cfe/trunk/include/clang/Checker/PathSensitive/MemRegion.h Modified: cfe/trunk/include/clang/Checker/PathSensitive/MemRegion.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/MemRegion.h?rev=96846&r1=96845&r2=96846&view=diff ============================================================================== --- cfe/trunk/include/clang/Checker/PathSensitive/MemRegion.h (original) +++ cfe/trunk/include/clang/Checker/PathSensitive/MemRegion.h Mon Feb 22 19:17:41 2010 @@ -428,7 +428,6 @@ /// which correspond to "code+data". The distinction is important, because /// like a closure a block captures the values of externally referenced /// variables. -/// BlockDataRegion - A region that represents code texts of blocks (closures). class BlockDataRegion : public SubRegion { friend class MemRegionManager; const BlockTextRegion *BC; From kremenek at apple.com Mon Feb 22 19:19:11 2010 From: kremenek at apple.com (Ted Kremenek) Date: Tue, 23 Feb 2010 01:19:11 -0000 Subject: [cfe-commits] r96847 - /cfe/trunk/lib/Sema/SemaChecking.cpp Message-ID: <20100223011911.CECEC2A6C12C@llvm.org> Author: kremenek Date: Mon Feb 22 19:19:11 2010 New Revision: 96847 URL: http://llvm.org/viewvc/llvm-project?rev=96847&view=rev Log: Simplify logic for determining values of 'ReturnsVoid' and 'HasNoReturn' flags. No functionality change. Modified: cfe/trunk/lib/Sema/SemaChecking.cpp Modified: cfe/trunk/lib/Sema/SemaChecking.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=96847&r1=96846&r2=96847&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) +++ cfe/trunk/lib/Sema/SemaChecking.cpp Mon Feb 22 19:19:11 2010 @@ -2490,22 +2490,20 @@ bool ReturnsVoid = false; bool HasNoReturn = false; + if (FunctionDecl *FD = dyn_cast(D)) { // For function templates, class templates and member function templates // we'll do the analysis at instantiation time. if (FD->isDependentContext()) return; - if (FD->getResultType()->isVoidType()) - ReturnsVoid = true; - if (FD->hasAttr() || - FD->getType()->getAs()->getNoReturnAttr()) - HasNoReturn = true; + ReturnsVoid = FD->getResultType()->isVoidType(); + HasNoReturn = FD->hasAttr() || + FD->getType()->getAs()->getNoReturnAttr(); + } else if (ObjCMethodDecl *MD = dyn_cast(D)) { - if (MD->getResultType()->isVoidType()) - ReturnsVoid = true; - if (MD->hasAttr()) - HasNoReturn = true; + ReturnsVoid = MD->getResultType()->isVoidType(); + HasNoReturn = MD->hasAttr(); } // Short circuit for compilation speed. From kremenek at apple.com Mon Feb 22 19:19:17 2010 From: kremenek at apple.com (Ted Kremenek) Date: Tue, 23 Feb 2010 01:19:17 -0000 Subject: [cfe-commits] r96848 - /cfe/trunk/lib/Sema/SemaChecking.cpp Message-ID: <20100223011917.379242A6C12D@llvm.org> Author: kremenek Date: Mon Feb 22 19:19:17 2010 New Revision: 96848 URL: http://llvm.org/viewvc/llvm-project?rev=96848&view=rev Log: Use SmallVectorImpl::iterator. Modified: cfe/trunk/lib/Sema/SemaChecking.cpp Modified: cfe/trunk/lib/Sema/SemaChecking.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=96848&r1=96847&r2=96848&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) +++ cfe/trunk/lib/Sema/SemaChecking.cpp Mon Feb 22 19:19:17 2010 @@ -2342,10 +2342,8 @@ } llvm::array_pod_sort(lines.begin(), lines.end(), LineCmp); - for (llvm::SmallVector::iterator I = lines.begin(), - E = lines.end(); - I != E; - ++I) + for (llvm::SmallVectorImpl::iterator I = lines.begin(), E = lines.end(); + I != E; ++I) if (I->Loc.isValid()) Diag(I->Loc, diag::warn_unreachable) << I->R1 << I->R2; } From fjahanian at apple.com Mon Feb 22 19:26:30 2010 From: fjahanian at apple.com (Fariborz Jahanian) Date: Tue, 23 Feb 2010 01:26:30 -0000 Subject: [cfe-commits] r96850 - in /cfe/trunk: include/clang/AST/DeclObjC.h lib/AST/ASTContext.cpp lib/AST/DeclObjC.cpp lib/Sema/SemaDeclObjC.cpp test/SemaObjC/ivar-in-class-extension.m Message-ID: <20100223012630.E77542A6C12C@llvm.org> Author: fjahanian Date: Mon Feb 22 19:26:30 2010 New Revision: 96850 URL: http://llvm.org/viewvc/llvm-project?rev=96850&view=rev Log: More support for ivars in class extension. Added: cfe/trunk/test/SemaObjC/ivar-in-class-extension.m Modified: cfe/trunk/include/clang/AST/DeclObjC.h cfe/trunk/lib/AST/ASTContext.cpp cfe/trunk/lib/AST/DeclObjC.cpp cfe/trunk/lib/Sema/SemaDeclObjC.cpp Modified: cfe/trunk/include/clang/AST/DeclObjC.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclObjC.h?rev=96850&r1=96849&r2=96850&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclObjC.h (original) +++ cfe/trunk/include/clang/AST/DeclObjC.h Mon Feb 22 19:26:30 2010 @@ -527,6 +527,8 @@ CategoryList = category; } + ObjCCategoryDecl* getClassExtension() const; + /// isSuperClassOf - Return true if this class is the specified class or is a /// super class of the specified interface class. bool isSuperClassOf(const ObjCInterfaceDecl *I) const { @@ -949,6 +951,20 @@ bool IsClassExtension() const { return getIdentifier() == 0; } + typedef specific_decl_iterator ivar_iterator; + ivar_iterator ivar_begin() const { + return ivar_iterator(decls_begin()); + } + ivar_iterator ivar_end() const { + return ivar_iterator(decls_end()); + } + unsigned ivar_size() const { + return std::distance(ivar_begin(), ivar_end()); + } + bool ivar_empty() const { + return ivar_begin() == ivar_end(); + } + SourceLocation getAtLoc() const { return AtLoc; } void setAtLoc(SourceLocation At) { AtLoc = At; } Modified: cfe/trunk/lib/AST/ASTContext.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=96850&r1=96849&r2=96850&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTContext.cpp (original) +++ cfe/trunk/lib/AST/ASTContext.cpp Mon Feb 22 19:26:30 2010 @@ -900,6 +900,14 @@ /// void ASTContext::CollectNonClassIvars(const ObjCInterfaceDecl *OI, llvm::SmallVectorImpl &Ivars) { + // Find ivars declared in class extension. + if (const ObjCCategoryDecl *CDecl = OI->getClassExtension()) { + for (ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(), + E = CDecl->ivar_end(); I != E; ++I) { + Ivars.push_back(*I); + } + } + for (ObjCInterfaceDecl::prop_iterator I = OI->prop_begin(), E = OI->prop_end(); I != E; ++I) { if (ObjCIvarDecl *Ivar = (*I)->getPropertyIvarDecl()) Modified: cfe/trunk/lib/AST/DeclObjC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclObjC.cpp?rev=96850&r1=96849&r2=96850&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclObjC.cpp (original) +++ cfe/trunk/lib/AST/DeclObjC.cpp Mon Feb 22 19:26:30 2010 @@ -202,6 +202,17 @@ setProtocolList(ProtocolRefs.data(), NumProtoRefs, ProtocolLocs.data(), C); } +/// getClassExtension - Find class extension of the given class. +// FIXME. can speed it up, if need be. +ObjCCategoryDecl* ObjCInterfaceDecl::getClassExtension() const { + const ObjCInterfaceDecl* ClassDecl = this; + for (ObjCCategoryDecl *CDecl = ClassDecl->getCategoryList(); CDecl; + CDecl = CDecl->getNextClassCategory()) + if (CDecl->IsClassExtension()) + return CDecl; + return 0; +} + ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID, ObjCInterfaceDecl *&clsDeclared) { ObjCInterfaceDecl* ClassDecl = this; @@ -210,6 +221,12 @@ clsDeclared = ClassDecl; return I; } + if (const ObjCCategoryDecl *CDecl = ClassDecl->getClassExtension()) + if (ObjCIvarDecl *I = CDecl->getIvarDecl(ID)) { + clsDeclared = ClassDecl; + return I; + } + ClassDecl = ClassDecl->getSuperClass(); } return NULL; Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=96850&r1=96849&r2=96850&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Mon Feb 22 19:26:30 2010 @@ -599,13 +599,9 @@ SourceLocation EndProtoLoc) { ObjCCategoryDecl *CDecl = 0; ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc); - if (!CategoryName) { + if (!CategoryName) // Class extensions require a special treatment. Use an existing one. - for (CDecl = IDecl->getCategoryList(); CDecl; - CDecl = CDecl->getNextClassCategory()) - if (CDecl->IsClassExtension()) - break; - } + CDecl = IDecl->getClassExtension(); if (!CDecl) { CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, ClassLoc, CategoryLoc, CategoryName); Added: cfe/trunk/test/SemaObjC/ivar-in-class-extension.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/ivar-in-class-extension.m?rev=96850&view=auto ============================================================================== --- cfe/trunk/test/SemaObjC/ivar-in-class-extension.m (added) +++ cfe/trunk/test/SemaObjC/ivar-in-class-extension.m Mon Feb 22 19:26:30 2010 @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi2 -verify %s + + at interface SomeClass @end + +int fn1(SomeClass *obj) { + obj->privateIvar = 1; // expected-error {{'SomeClass' does not have a member named 'privateIvar}} + return obj->publicIvar; // expected-error {{'SomeClass' does not have a member named 'publicIvar'}} +} + + at interface SomeClass () { +// @private by default + int privateIvar; + at public + int publicIvar; +} + at end + +int fn2(SomeClass *obj) { + obj->publicIvar = 1; + return obj->publicIvar // ok + + obj->privateIvar; // expected-error {{instance variable 'privateIvar' is private}} +} + + at implementation SomeClass + +int fn3(SomeClass *obj) { + obj->privateIvar = 2; + return obj->publicIvar // ok + + obj->privateIvar; // ok + } + at end + + at interface SomeClass (Category) + { // expected-error {{ivar may be placed in a class extension}} + int categoryIvar; + } + at end + + at interface SomeClass (Category1) + { // expected-error {{ivar may be placed in a class extension}} + } + at end From andersca at mac.com Mon Feb 22 19:34:29 2010 From: andersca at mac.com (Anders Carlsson) Date: Tue, 23 Feb 2010 01:34:29 -0000 Subject: [cfe-commits] r96853 - /cfe/trunk/lib/CodeGen/CGVtable.cpp Message-ID: <20100223013429.15F5E2A6C12C@llvm.org> Author: andersca Date: Mon Feb 22 19:34:28 2010 New Revision: 96853 URL: http://llvm.org/viewvc/llvm-project?rev=96853&view=rev Log: Move BaseOffset out of the FinalOverriders class. Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=96853&r1=96852&r2=96853&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVtable.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVtable.cpp Mon Feb 22 19:34:28 2010 @@ -25,35 +25,35 @@ namespace { +/// BaseOffset - Represents an offset from a derived class to a direct or +/// indirect base class. +struct BaseOffset { + /// DerivedClass - The derived class. + const CXXRecordDecl *DerivedClass; + + /// VirtualBase - If the path from the derived class to the base class + /// involves a virtual base class, this holds its declaration. + const CXXRecordDecl *VirtualBase; + + /// NonVirtualOffset - The offset from the derived class to the base class. + /// (Or the offset from the virtual base class to the base class, if the + /// path from the derived class to the base class involves a virtual base + /// class. + int64_t NonVirtualOffset; + + BaseOffset() : DerivedClass(0), VirtualBase(0), NonVirtualOffset(0) { } + BaseOffset(const CXXRecordDecl *DerivedClass, + const CXXRecordDecl *VirtualBase, int64_t NonVirtualOffset) + : DerivedClass(DerivedClass), VirtualBase(VirtualBase), + NonVirtualOffset(NonVirtualOffset) { } + + bool isEmpty() const { return !NonVirtualOffset && !VirtualBase; } +}; + /// FinalOverriders - Contains the final overrider member functions for all /// member functions in the base subobjects of a class. class FinalOverriders { public: - /// BaseOffset - Represents an offset from a derived class to a direct or - /// indirect base class. - struct BaseOffset { - /// DerivedClass - The derived class. - const CXXRecordDecl *DerivedClass; - - /// VirtualBase - If the path from the derived class to the base class - /// involves a virtual base class, this holds its declaration. - const CXXRecordDecl *VirtualBase; - - /// NonVirtualOffset - The offset from the derived class to the base class. - /// (Or the offset from the virtual base class to the base class, if the - /// path from the derived class to the base class involves a virtual base - /// class. - int64_t NonVirtualOffset; - - BaseOffset() : DerivedClass(0), VirtualBase(0), NonVirtualOffset(0) { } - BaseOffset(const CXXRecordDecl *DerivedClass, - const CXXRecordDecl *VirtualBase, int64_t NonVirtualOffset) - : DerivedClass(DerivedClass), VirtualBase(VirtualBase), - NonVirtualOffset(NonVirtualOffset) { } - - bool isEmpty() const { return !NonVirtualOffset && !VirtualBase; } - }; - /// OverriderInfo - Information about a final overrider. struct OverriderInfo { /// Method - The method decl of the overrider. @@ -244,9 +244,9 @@ } } -static FinalOverriders::BaseOffset -ComputeBaseOffset(ASTContext &Context, const CXXRecordDecl *DerivedRD, - const CXXBasePath &Path) { +static BaseOffset ComputeBaseOffset(ASTContext &Context, + const CXXRecordDecl *DerivedRD, + const CXXBasePath &Path) { int64_t NonVirtualOffset = 0; unsigned NonVirtualStart = 0; @@ -282,27 +282,26 @@ // FIXME: This should probably use CharUnits or something. Maybe we should // even change the base offsets in ASTRecordLayout to be specified in // CharUnits. - return FinalOverriders::BaseOffset(DerivedRD, VirtualBase, - NonVirtualOffset / 8); + return BaseOffset(DerivedRD, VirtualBase, NonVirtualOffset / 8); } -static FinalOverriders::BaseOffset -ComputeBaseOffset(ASTContext &Context, const CXXRecordDecl *BaseRD, - const CXXRecordDecl *DerivedRD) { +static BaseOffset ComputeBaseOffset(ASTContext &Context, + const CXXRecordDecl *BaseRD, + const CXXRecordDecl *DerivedRD) { CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true, /*DetectVirtual=*/false); if (!const_cast(DerivedRD)-> isDerivedFrom(const_cast(BaseRD), Paths)) { assert(false && "Class must be derived from the passed in base class!"); - return FinalOverriders::BaseOffset(); + return BaseOffset(); } return ComputeBaseOffset(Context, DerivedRD, Paths.front()); } -static FinalOverriders::BaseOffset +static BaseOffset ComputeReturnAdjustmentBaseOffset(ASTContext &Context, const CXXMethodDecl *DerivedMD, const CXXMethodDecl *BaseMD) { @@ -321,7 +320,7 @@ if (CanDerivedReturnType == CanBaseReturnType) { // No adjustment needed. - return FinalOverriders::BaseOffset(); + return BaseOffset(); } if (isa(CanDerivedReturnType)) { @@ -344,7 +343,7 @@ if (CanDerivedReturnType.getUnqualifiedType() == CanBaseReturnType.getUnqualifiedType()) { // No adjustment needed. - return FinalOverriders::BaseOffset(); + return BaseOffset(); } const CXXRecordDecl *DerivedRD = @@ -356,7 +355,7 @@ return ComputeBaseOffset(Context, BaseRD, DerivedRD); } -FinalOverriders::BaseOffset +BaseOffset FinalOverriders::ComputeThisAdjustmentBaseOffset(BaseSubobject Base, BaseSubobject Derived) { const CXXRecordDecl *BaseRD = Base.getBase(); @@ -976,13 +975,13 @@ /// ComputeReturnAdjustment - Compute the return adjustment given a return /// adjustment base offset. - ReturnAdjustment ComputeReturnAdjustment(FinalOverriders::BaseOffset Offset); + ReturnAdjustment ComputeReturnAdjustment(BaseOffset Offset); /// ComputeThisAdjustment - Compute the 'this' pointer adjustment for the /// given virtual member function and the 'this' pointer adjustment base /// offset. ThisAdjustment ComputeThisAdjustment(const CXXMethodDecl *MD, - FinalOverriders::BaseOffset Offset); + BaseOffset Offset); /// AddMethod - Add a single virtual member function to the vtable /// components vector. @@ -1044,7 +1043,7 @@ } VtableBuilder::ReturnAdjustment -VtableBuilder::ComputeReturnAdjustment(FinalOverriders::BaseOffset Offset) { +VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { ReturnAdjustment Adjustment; if (!Offset.isEmpty()) { @@ -1067,7 +1066,7 @@ VtableBuilder::ThisAdjustment VtableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD, - FinalOverriders::BaseOffset Offset) { + BaseOffset Offset) { ThisAdjustment Adjustment; if (!Offset.isEmpty()) { @@ -1150,7 +1149,7 @@ continue; // Get the 'this' pointer adjustment offset. - FinalOverriders::BaseOffset ThisAdjustmentOffset = + BaseOffset ThisAdjustmentOffset = Overriders.getThisAdjustmentOffset(Base, MD); int64_t Offset = 0; @@ -1298,14 +1297,14 @@ } // Check if this overrider needs a return adjustment. - FinalOverriders::BaseOffset ReturnAdjustmentOffset = + BaseOffset ReturnAdjustmentOffset = Overriders.getReturnAdjustmentOffset(Base, MD); ReturnAdjustment ReturnAdjustment = ComputeReturnAdjustment(ReturnAdjustmentOffset); // Check if this overrider needs a 'this' pointer adjustment. - FinalOverriders::BaseOffset ThisAdjustmentOffset = + BaseOffset ThisAdjustmentOffset = Overriders.getThisAdjustmentOffset(Base, MD); ThisAdjustment ThisAdjustment = ComputeThisAdjustment(Overrider.Method, From kremenek at apple.com Mon Feb 22 19:39:04 2010 From: kremenek at apple.com (Ted Kremenek) Date: Tue, 23 Feb 2010 01:39:04 -0000 Subject: [cfe-commits] r96855 - /cfe/trunk/lib/Sema/SemaChecking.cpp Message-ID: <20100223013904.96DEC2A6C12C@llvm.org> Author: kremenek Date: Mon Feb 22 19:39:04 2010 New Revision: 96855 URL: http://llvm.org/viewvc/llvm-project?rev=96855&view=rev Log: Convert use of std::queue to llvm::SmallVector and fix buildbot. Modified: cfe/trunk/lib/Sema/SemaChecking.cpp Modified: cfe/trunk/lib/Sema/SemaChecking.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=96855&r1=96854&r2=96855&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) +++ cfe/trunk/lib/Sema/SemaChecking.cpp Mon Feb 22 19:39:04 2010 @@ -2104,29 +2104,33 @@ return; } -// MarkLive - Mark all the blocks reachable from e as live. Returns the total -// number of blocks just marked live. -static unsigned MarkLive(CFGBlock *e, llvm::BitVector &live) { +// MarkReachable - Mark all the blocks reachable from Start as live. +// Returns the total number of blocks that were marked reachable. +static unsigned MarkReachable(CFGBlock &Start, llvm::BitVector &live) { unsigned count = 0; - std::queue workq; + llvm::SmallVector WL; + // Prep work queue - live.set(e->getBlockID()); + live.set(Start.getBlockID()); ++count; - workq.push(e); - // Solve - while (!workq.empty()) { - CFGBlock *item = workq.front(); - workq.pop(); - for (CFGBlock::succ_iterator I=item->succ_begin(), - E=item->succ_end(); - I != E; - ++I) { - if ((*I) && !live[(*I)->getBlockID()]) { - live.set((*I)->getBlockID()); - ++count; - workq.push(*I); + WL.push_back(&Start); + + // Find the reachable blocks from 'Start'. + while (!WL.empty()) { + CFGBlock *item = WL.back(); + WL.pop_back(); + + // Look at the successors and mark then reachable. + for (CFGBlock::succ_iterator I=item->succ_begin(), E=item->succ_end(); + I != E; ++I) + if (CFGBlock *B = *I) { + unsigned blockID = B->getBlockID(); + if (!live[blockID]) { + live.set(blockID); + ++count; + WL.push_back(B); + } } - } } return count; } @@ -2280,21 +2284,20 @@ unsigned count; // We avoid checking when there are errors, as the CFG won't faithfully match // the user's code. - if (getDiagnostics().hasErrorOccurred()) - return; - if (Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored) + if (getDiagnostics().hasErrorOccurred() || + Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored) return; CFG *cfg = AC.getCFG(); if (cfg == 0) return; - llvm::BitVector live(cfg->getNumBlockIDs()); // Mark all live things first. - count = MarkLive(&cfg->getEntry(), live); + llvm::BitVector live(cfg->getNumBlockIDs()); + count = MarkReachable(cfg->getEntry(), live); + // If there are no dead blocks, we're done. if (count == cfg->getNumBlockIDs()) - // If there are no dead blocks, we're done. return; SourceRange R1, R2; @@ -2311,7 +2314,7 @@ && isa(b.getTerminator())) { // When not adding EH edges from calls, catch clauses // can otherwise seem dead. Avoid noting them as dead. - count += MarkLive(&b, live); + count += MarkReachable(b, live); continue; } SourceLocation c = GetUnreachableLoc(b, R1, R2); @@ -2324,7 +2327,7 @@ } lines.push_back(ErrLoc(c, R1, R2)); // Avoid excessive errors by marking everything reachable from here - count += MarkLive(&b, live); + count += MarkReachable(b, live); } } } @@ -2342,7 +2345,7 @@ } llvm::array_pod_sort(lines.begin(), lines.end(), LineCmp); - for (llvm::SmallVectorImpl::iterator I = lines.begin(), E = lines.end(); + for (llvm::SmallVectorImpl::iterator I=lines.begin(), E=lines.end(); I != E; ++I) if (I->Loc.isValid()) Diag(I->Loc, diag::warn_unreachable) << I->R1 << I->R2; @@ -2367,7 +2370,7 @@ // confuse us, so we mark all live things first. std::queue workq; llvm::BitVector live(cfg->getNumBlockIDs()); - unsigned count = MarkLive(&cfg->getEntry(), live); + unsigned count = MarkReachable(cfg->getEntry(), live); bool AddEHEdges = AC.getAddEHEdges(); if (!AddEHEdges && count != cfg->getNumBlockIDs()) @@ -2381,7 +2384,7 @@ if (b.getTerminator() && isa(b.getTerminator())) // When not adding EH edges from calls, catch clauses // can otherwise seem dead. Avoid noting them as dead. - count += MarkLive(&b, live); + count += MarkReachable(b, live); continue; } } From kremenek at apple.com Mon Feb 22 20:39:17 2010 From: kremenek at apple.com (Ted Kremenek) Date: Tue, 23 Feb 2010 02:39:17 -0000 Subject: [cfe-commits] r96872 - in /cfe/trunk/lib: Analysis/CMakeLists.txt Analysis/ReachableCode.cpp Sema/SemaChecking.cpp Message-ID: <20100223023917.11EC82A6C12C@llvm.org> Author: kremenek Date: Mon Feb 22 20:39:16 2010 New Revision: 96872 URL: http://llvm.org/viewvc/llvm-project?rev=96872&view=rev Log: Start moving some of the logic for the unreachable code analysis out of libSema and into libAnalysis. Added: cfe/trunk/lib/Analysis/ReachableCode.cpp Modified: cfe/trunk/lib/Analysis/CMakeLists.txt cfe/trunk/lib/Sema/SemaChecking.cpp Modified: cfe/trunk/lib/Analysis/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CMakeLists.txt?rev=96872&r1=96871&r2=96872&view=diff ============================================================================== --- cfe/trunk/lib/Analysis/CMakeLists.txt (original) +++ cfe/trunk/lib/Analysis/CMakeLists.txt Mon Feb 22 20:39:16 2010 @@ -5,6 +5,7 @@ CFG.cpp LiveVariables.cpp PrintfFormatString.cpp + ReachableCode.cpp UninitializedValues.cpp ) Added: cfe/trunk/lib/Analysis/ReachableCode.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ReachableCode.cpp?rev=96872&view=auto ============================================================================== --- cfe/trunk/lib/Analysis/ReachableCode.cpp (added) +++ cfe/trunk/lib/Analysis/ReachableCode.cpp Mon Feb 22 20:39:16 2010 @@ -0,0 +1,52 @@ +//=- ReachableCodePathInsensitive.cpp ---------------------------*- C++ --*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a flow-sensitive, path-insensitive analysis of +// determining reachable blocks within a CFG. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/SmallVector.h" +#include "clang/Analysis/Analyses/ReachableCode.h" +#include "clang/Analysis/CFG.h" + +using namespace clang; + +/// ScanReachableFromBlock - Mark all blocks reachable from Start. +/// Returns the total number of blocks that were marked reachable. +unsigned clang::ScanReachableFromBlock(const CFGBlock &Start, + llvm::BitVector &Reachable) { + unsigned count = 0; + llvm::SmallVector WL; + + // Prep work queue + Reachable.set(Start.getBlockID()); + ++count; + WL.push_back(&Start); + + // Find the reachable blocks from 'Start'. + while (!WL.empty()) { + const CFGBlock *item = WL.back(); + WL.pop_back(); + + // Look at the successors and mark then reachable. + for (CFGBlock::const_succ_iterator I=item->succ_begin(), E=item->succ_end(); + I != E; ++I) + if (const CFGBlock *B = *I) { + unsigned blockID = B->getBlockID(); + if (!Reachable[blockID]) { + Reachable.set(blockID); + ++count; + WL.push_back(B); + } + } + } + return count; +} Modified: cfe/trunk/lib/Sema/SemaChecking.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=96872&r1=96871&r2=96872&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) +++ cfe/trunk/lib/Sema/SemaChecking.cpp Mon Feb 22 20:39:16 2010 @@ -13,8 +13,9 @@ //===----------------------------------------------------------------------===// #include "Sema.h" -#include "clang/Analysis/CFG.h" #include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/Analyses/ReachableCode.h" #include "clang/Analysis/Analyses/PrintfFormatString.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" @@ -2104,37 +2105,6 @@ return; } -// MarkReachable - Mark all the blocks reachable from Start as live. -// Returns the total number of blocks that were marked reachable. -static unsigned MarkReachable(CFGBlock &Start, llvm::BitVector &live) { - unsigned count = 0; - llvm::SmallVector WL; - - // Prep work queue - live.set(Start.getBlockID()); - ++count; - WL.push_back(&Start); - - // Find the reachable blocks from 'Start'. - while (!WL.empty()) { - CFGBlock *item = WL.back(); - WL.pop_back(); - - // Look at the successors and mark then reachable. - for (CFGBlock::succ_iterator I=item->succ_begin(), E=item->succ_end(); - I != E; ++I) - if (CFGBlock *B = *I) { - unsigned blockID = B->getBlockID(); - if (!live[blockID]) { - live.set(blockID); - ++count; - WL.push_back(B); - } - } - } - return count; -} - static SourceLocation GetUnreachableLoc(CFGBlock &b, SourceRange &R1, SourceRange &R2) { Stmt *S; @@ -2281,7 +2251,6 @@ /// CheckUnreachable - Check for unreachable code. void Sema::CheckUnreachable(AnalysisContext &AC) { - unsigned count; // We avoid checking when there are errors, as the CFG won't faithfully match // the user's code. if (getDiagnostics().hasErrorOccurred() || @@ -2293,11 +2262,11 @@ return; // Mark all live things first. - llvm::BitVector live(cfg->getNumBlockIDs()); - count = MarkReachable(cfg->getEntry(), live); + llvm::BitVector reachable(cfg->getNumBlockIDs()); + unsigned numReachable = ScanReachableFromBlock(cfg->getEntry(), reachable); // If there are no dead blocks, we're done. - if (count == cfg->getNumBlockIDs()) + if (numReachable == cfg->getNumBlockIDs()) return; SourceRange R1, R2; @@ -2308,37 +2277,37 @@ // can't be part of a loop. for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { CFGBlock &b = **I; - if (!live[b.getBlockID()]) { + if (!reachable[b.getBlockID()]) { if (b.pred_begin() == b.pred_end()) { if (!AddEHEdges && b.getTerminator() && isa(b.getTerminator())) { // When not adding EH edges from calls, catch clauses // can otherwise seem dead. Avoid noting them as dead. - count += MarkReachable(b, live); + numReachable += ScanReachableFromBlock(b, reachable); continue; } SourceLocation c = GetUnreachableLoc(b, R1, R2); if (!c.isValid()) { // Blocks without a location can't produce a warning, so don't mark // reachable blocks from here as live. - live.set(b.getBlockID()); - ++count; + reachable.set(b.getBlockID()); + ++numReachable; continue; } lines.push_back(ErrLoc(c, R1, R2)); // Avoid excessive errors by marking everything reachable from here - count += MarkReachable(b, live); + numReachable += ScanReachableFromBlock(b, reachable); } } } - if (count < cfg->getNumBlockIDs()) { + if (numReachable < cfg->getNumBlockIDs()) { // And then give warnings for the tops of loops. for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { CFGBlock &b = **I; - if (!live[b.getBlockID()]) + if (!reachable[b.getBlockID()]) // Avoid excessive errors by marking everything reachable from here - lines.push_back(ErrLoc(MarkLiveTop(&b, live, + lines.push_back(ErrLoc(MarkLiveTop(&b, reachable, Context.getSourceManager()), SourceRange(), SourceRange())); } @@ -2370,7 +2339,7 @@ // confuse us, so we mark all live things first. std::queue workq; llvm::BitVector live(cfg->getNumBlockIDs()); - unsigned count = MarkReachable(cfg->getEntry(), live); + unsigned count = ScanReachableFromBlock(cfg->getEntry(), live); bool AddEHEdges = AC.getAddEHEdges(); if (!AddEHEdges && count != cfg->getNumBlockIDs()) @@ -2384,7 +2353,7 @@ if (b.getTerminator() && isa(b.getTerminator())) // When not adding EH edges from calls, catch clauses // can otherwise seem dead. Avoid noting them as dead. - count += MarkReachable(b, live); + count += ScanReachableFromBlock(b, live); continue; } } From andersca at mac.com Mon Feb 22 20:47:31 2010 From: andersca at mac.com (Anders Carlsson) Date: Tue, 23 Feb 2010 02:47:31 -0000 Subject: [cfe-commits] r96874 - /cfe/trunk/lib/CodeGen/CGVtable.cpp Message-ID: <20100223024731.B05C42A6C12C@llvm.org> Author: andersca Date: Mon Feb 22 20:47:31 2010 New Revision: 96874 URL: http://llvm.org/viewvc/llvm-project?rev=96874&view=rev Log: More work on vcall offsets. We now emit the right number of vcall offsets in my local test case, but not the right values. Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=96874&r1=96873&r2=96874&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVtable.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVtable.cpp Mon Feb 22 20:47:31 2010 @@ -1106,7 +1106,7 @@ int64_t OffsetToTop = -(int64_t)Base.getBaseOffset() / 8; AddVBaseOffsets(Base.getBase(), OffsetToTop, VBases); - // We only want to add vcall offsets for virtual bases in secondary vtables. + // We only want to add vcall offsets for virtual bases. if (BaseIsVirtual && OffsetToTop != 0) AddVCallOffsets(Base); } @@ -1183,10 +1183,6 @@ const CXXRecordDecl *BaseDecl = cast(I->getType()->getAs()->getDecl()); - // Ignore the primary base. - if (BaseDecl == PrimaryBase) - continue; - // Get the base offset of this base. uint64_t BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl); From kremenek at apple.com Mon Feb 22 21:08:27 2010 From: kremenek at apple.com (Ted Kremenek) Date: Tue, 23 Feb 2010 03:08:27 -0000 Subject: [cfe-commits] r96875 - /cfe/trunk/include/clang/Analysis/Analyses/ReachableCode.h Message-ID: <20100223030827.13BE52A6C12C@llvm.org> Author: kremenek Date: Mon Feb 22 21:08:26 2010 New Revision: 96875 URL: http://llvm.org/viewvc/llvm-project?rev=96875&view=rev Log: Add missing header file. Added: cfe/trunk/include/clang/Analysis/Analyses/ReachableCode.h Added: cfe/trunk/include/clang/Analysis/Analyses/ReachableCode.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ReachableCode.h?rev=96875&view=auto ============================================================================== --- cfe/trunk/include/clang/Analysis/Analyses/ReachableCode.h (added) +++ cfe/trunk/include/clang/Analysis/Analyses/ReachableCode.h Mon Feb 22 21:08:26 2010 @@ -0,0 +1,41 @@ +//===- ReachableCode.h -----------------------------------------*- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// A flow-sensitive, path-insensitive analysis of unreachable code. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_REACHABLECODE_H +#define LLVM_CLANG_REACHABLECODE_H + +//===----------------------------------------------------------------------===// +// Forward declarations. +//===----------------------------------------------------------------------===// + +namespace llvm { +class BitVector; +} // end llvm namespace + +namespace clang { +class CFGBlock; +} // end clang namespace + +//===----------------------------------------------------------------------===// +// API. +//===----------------------------------------------------------------------===// + +namespace clang { + +/// ScanReachableFromBlock - Mark all blocks reachable from Start. +/// Returns the total number of blocks that were marked reachable. +unsigned ScanReachableFromBlock(const CFGBlock &B, llvm::BitVector &Reachable); + +} // end clang namespace + +#endif From stoklund at 2pi.dk Mon Feb 22 21:10:39 2010 From: stoklund at 2pi.dk (Jakob Stoklund Olesen) Date: Mon, 22 Feb 2010 19:10:39 -0800 Subject: [cfe-commits] r96875 - /cfe/trunk/include/clang/Analysis/Analyses/ReachableCode.h In-Reply-To: <20100223030827.13BE52A6C12C@llvm.org> References: <20100223030827.13BE52A6C12C@llvm.org> Message-ID: <62B0B3D9-3A46-4B55-B6BF-AD7FD1A33166@2pi.dk> On Feb 22, 2010, at 7:08 PM, Ted Kremenek wrote: > Author: kremenek > Date: Mon Feb 22 21:08:26 2010 > New Revision: 96875 > > URL: http://llvm.org/viewvc/llvm-project?rev=96875&view=rev > Log: > Add missing header file. Thanks! -------------- next part -------------- A non-text attachment was scrubbed... Name: smime.p7s Type: application/pkcs7-signature Size: 1929 bytes Desc: not available Url : http://lists.cs.uiuc.edu/pipermail/cfe-commits/attachments/20100222/9d8566c6/attachment.bin From andersca at mac.com Mon Feb 22 21:14:49 2010 From: andersca at mac.com (Anders Carlsson) Date: Tue, 23 Feb 2010 03:14:49 -0000 Subject: [cfe-commits] r96877 - /cfe/trunk/lib/CodeGen/CGVtable.cpp Message-ID: <20100223031449.C14EC2A6C12C@llvm.org> Author: andersca Date: Mon Feb 22 21:14:49 2010 New Revision: 96877 URL: http://llvm.org/viewvc/llvm-project?rev=96877&view=rev Log: Simplify the vcall offset calculation and make it give the correct answers :) My test case now has the right values but in the wrong order. Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=96877&r1=96876&r2=96877&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVtable.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVtable.cpp Mon Feb 22 21:14:49 2010 @@ -967,7 +967,7 @@ VisitedVirtualBasesSetTy &VBases); /// AddVCallOffsets - Add vcall offsets for the given base subobject. - void AddVCallOffsets(BaseSubobject Base); + void AddVCallOffsets(BaseSubobject Base, uint64_t VBaseOffset); /// AddVBaseOffsets - Add vbase offsets for the given class. void AddVBaseOffsets(const CXXRecordDecl *Base, int64_t OffsetToTop, @@ -1108,10 +1108,13 @@ // We only want to add vcall offsets for virtual bases. if (BaseIsVirtual && OffsetToTop != 0) - AddVCallOffsets(Base); + AddVCallOffsets(Base, Base.getBaseOffset()); } -void VtableBuilder::AddVCallOffsets(BaseSubobject Base) { +void VtableBuilder::AddVCallOffsets(BaseSubobject Base, uint64_t VBaseOffset) { + printf("adding call offsets for (%s, %llu) vbase offset %llu\n", + Base.getBase()->getQualifiedNameAsString().c_str(), + Base.getBaseOffset(), VBaseOffset); const CXXRecordDecl *RD = Base.getBase(); const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); @@ -1122,7 +1125,8 @@ uint64_t PrimaryBaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(PrimaryBase); - AddVCallOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset)); + AddVCallOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset), + VBaseOffset); } // Add the vcall offsets. @@ -1147,28 +1151,15 @@ // signature. if (!VCallOffsets.AddVCallOffset(MD, OffsetOffset)) continue; - - // Get the 'this' pointer adjustment offset. - BaseOffset ThisAdjustmentOffset = - Overriders.getThisAdjustmentOffset(Base, MD); - - int64_t Offset = 0; - if (const CXXRecordDecl *VBaseDecl = ThisAdjustmentOffset.VirtualBase) { - const ASTRecordLayout &MostDerivedClassLayout = - Context.getASTRecordLayout(MostDerivedClass); - - FinalOverriders::OverriderInfo Overrider = - Overriders.getOverrider(Base, MD); - Offset = - -(int64_t)MostDerivedClassLayout.getVBaseClassOffset(VBaseDecl); - - // The base offset should be relative to the final overrider. - Offset += Overrider.BaseOffset; - - // FIXME: We should not use / 8 here. - Offset = Offset / 8; - } + // Get the final overrider. + FinalOverriders::OverriderInfo Overrider = + Overriders.getOverrider(Base, MD); + + /// The vcall offset is the offset from the virtual base to the object where + /// the function was overridden. + // FIXME: We should not use / 8 here. + int64_t Offset = (int64_t)(Overrider.BaseOffset - VBaseOffset) / 8; VCallAndVBaseOffsets.push_back(VtableComponent::MakeVCallOffset(Offset)); } @@ -1187,7 +1178,7 @@ uint64_t BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl); - AddVCallOffsets(BaseSubobject(BaseDecl, BaseOffset)); + AddVCallOffsets(BaseSubobject(BaseDecl, BaseOffset), VBaseOffset); } } From andersca at mac.com Mon Feb 22 21:26:17 2010 From: andersca at mac.com (Anders Carlsson) Date: Tue, 23 Feb 2010 03:26:17 -0000 Subject: [cfe-commits] r96880 - in /cfe/trunk: lib/CodeGen/CGVtable.cpp test/CodeGenCXX/vtable-layout.cpp Message-ID: <20100223032617.3FB0E2A6C12C@llvm.org> Author: andersca Date: Mon Feb 22 21:26:17 2010 New Revision: 96880 URL: http://llvm.org/viewvc/llvm-project?rev=96880&view=rev Log: Always emit vcall offset for the primary base, not only if it's virtual. Remove a debug printf, and add the test case that now passes. Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp cfe/trunk/test/CodeGenCXX/vtable-layout.cpp Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=96880&r1=96879&r2=96880&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVtable.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVtable.cpp Mon Feb 22 21:26:17 2010 @@ -1112,15 +1112,11 @@ } void VtableBuilder::AddVCallOffsets(BaseSubobject Base, uint64_t VBaseOffset) { - printf("adding call offsets for (%s, %llu) vbase offset %llu\n", - Base.getBase()->getQualifiedNameAsString().c_str(), - Base.getBaseOffset(), VBaseOffset); const CXXRecordDecl *RD = Base.getBase(); const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); // Handle the primary base first. - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - if (PrimaryBase && Layout.getPrimaryBaseWasVirtual()) { + if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { // Get the base offset of the primary base. uint64_t PrimaryBaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(PrimaryBase); Modified: cfe/trunk/test/CodeGenCXX/vtable-layout.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/vtable-layout.cpp?rev=96880&r1=96879&r2=96880&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/vtable-layout.cpp (original) +++ cfe/trunk/test/CodeGenCXX/vtable-layout.cpp Mon Feb 22 21:26:17 2010 @@ -422,3 +422,62 @@ void C::f() { } } + +namespace Test12 { + +// Test that the right vcall offsets are generated in the right order. + +// CHECK: Vtable for 'Test12::B' (19 entries). +// CHECK-NEXT: 0 | vbase_offset (8) +// CHECK-NEXT: 1 | offset_to_top (0) +// CHECK-NEXT: 2 | Test12::B RTTI +// CHECK-NEXT: -- (Test12::B, 0) vtable address -- +// CHECK-NEXT: 3 | void Test12::B::f() +// CHECK-NEXT: 4 | void Test12::B::a() +// CHECK-NEXT: 5 | vcall_offset (32) +// CHECK-NEXT: 6 | vcall_offset (16) +// CHECK-NEXT: 7 | vcall_offset (-8) +// CHECK-NEXT: 8 | vcall_offset (0) +// CHECK-NEXT: 9 | offset_to_top (-8) +// CHECK-NEXT: 10 | Test12::B RTTI +// CHECK-NEXT: -- (Test12::A, 8) vtable address -- +// CHECK-NEXT: -- (Test12::A1, 8) vtable address -- +// CHECK-NEXT: 11 | void Test12::A1::a1() +// CHECK-NEXT: 12 | void Test12::B::a() +// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] +// CHECK-NEXT: 13 | offset_to_top (-24) +// CHECK-NEXT: 14 | Test12::B RTTI +// CHECK-NEXT: -- (Test12::A2, 24) vtable address -- +// CHECK-NEXT: 15 | void Test12::A2::a2() +// CHECK-NEXT: 16 | offset_to_top (-40) +// CHECK-NEXT: 17 | Test12::B RTTI +// CHECK-NEXT: -- (Test12::A3, 40) vtable address -- +// CHECK-NEXT: 18 | void Test12::A3::a3() +struct A1 { + virtual void a1(); + int a; +}; + +struct A2 { + virtual void a2(); + int a; +}; + +struct A3 { + virtual void a3(); + int a; +}; + +struct A : A1, A2, A3 { + virtual void a(); + int i; +}; + +struct B : virtual A { + virtual void f(); + + virtual void a(); +}; +void B::f() { } + +} From andersca at mac.com Mon Feb 22 21:48:14 2010 From: andersca at mac.com (Anders Carlsson) Date: Tue, 23 Feb 2010 03:48:14 -0000 Subject: [cfe-commits] r96881 - in /cfe/trunk: lib/CodeGen/CGVtable.cpp test/CodeGenCXX/vtable-layout.cpp Message-ID: <20100223034814.A4FF22A6C12C@llvm.org> Author: andersca Date: Mon Feb 22 21:48:14 2010 New Revision: 96881 URL: http://llvm.org/viewvc/llvm-project?rev=96881&view=rev Log: More fixes. Don't try to emit a virtual base vtable if the virtual base in question is a primary virtual base of some other base. Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp cfe/trunk/test/CodeGenCXX/vtable-layout.cpp Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=96881&r1=96880&r2=96881&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVtable.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVtable.cpp Mon Feb 22 21:48:14 2010 @@ -961,6 +961,10 @@ typedef llvm::SmallPtrSet VisitedVirtualBasesSetTy; + /// PrimaryVirtualBases - All known virtual bases who is a primary base of + /// some other base. + VisitedVirtualBasesSetTy PrimaryVirtualBases; + /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the /// given base subobject. void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual, @@ -1107,7 +1111,7 @@ AddVBaseOffsets(Base.getBase(), OffsetToTop, VBases); // We only want to add vcall offsets for virtual bases. - if (BaseIsVirtual && OffsetToTop != 0) + if (BaseIsVirtual) AddVCallOffsets(Base, Base.getBaseOffset()); } @@ -1117,9 +1121,24 @@ // Handle the primary base first. if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { + uint64_t PrimaryBaseOffset; + // Get the base offset of the primary base. - uint64_t PrimaryBaseOffset = Base.getBaseOffset() + - Layout.getBaseClassOffset(PrimaryBase); + if (Layout.getPrimaryBaseWasVirtual()) { + assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && + "Primary vbase should have a zero offset!"); + + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + + PrimaryBaseOffset = + MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); + } else { + assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && + "Primary base should have a zero offset!"); + + PrimaryBaseOffset = Base.getBaseOffset(); + } AddVCallOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset), VBaseOffset); @@ -1245,13 +1264,26 @@ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { - if (Layout.getPrimaryBaseWasVirtual()) - assert(false && "FIXME: Handle vbases here."); - else + uint64_t BaseOffset; + if (Layout.getPrimaryBaseWasVirtual()) { + assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && + "Primary vbase should have a zero offset!"); + + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + + BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); + + // Keep track of this primary virtual base. + PrimaryVirtualBases.insert(PrimaryBase); + } else { assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && "Primary base should have a zero offset!"); + + BaseOffset = Base.getBaseOffset(); + } - AddMethods(BaseSubobject(PrimaryBase, Base.getBaseOffset()), PrimaryBases); + AddMethods(BaseSubobject(PrimaryBase, BaseOffset), PrimaryBases); if (!PrimaryBases.insert(PrimaryBase)) assert(false && "Found a duplicate primary base!"); @@ -1409,10 +1441,11 @@ const CXXRecordDecl *BaseDecl = cast(I->getType()->getAs()->getDecl()); - // Check if this base needs a vtable. (If it's virtual, and we haven't - // visited it before). + // Check if this base needs a vtable. (If it's virtual, not a primary base + // of some other class, and we haven't visited it before). if (I->isVirtual() && BaseDecl->isDynamicClass() && - BaseDecl != PrimaryBase && VBases.insert(BaseDecl)) { + BaseDecl != PrimaryBase && !PrimaryVirtualBases.count(BaseDecl) && + VBases.insert(BaseDecl)) { const ASTRecordLayout &MostDerivedClassLayout = Context.getASTRecordLayout(MostDerivedClass); uint64_t BaseOffset = Modified: cfe/trunk/test/CodeGenCXX/vtable-layout.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/vtable-layout.cpp?rev=96881&r1=96880&r2=96881&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/vtable-layout.cpp (original) +++ cfe/trunk/test/CodeGenCXX/vtable-layout.cpp Mon Feb 22 21:48:14 2010 @@ -481,3 +481,32 @@ void B::f() { } } + +namespace Test13 { + +// Test that we don't try to emit a vtable for 'A' twice. +struct A { + virtual void f(); +}; + +struct B : virtual A { + virtual void f(); +}; + +// CHECK: Vtable for 'Test13::C' (6 entries). +// CHECK-NEXT: 0 | vbase_offset (0) +// CHECK-NEXT: 1 | vbase_offset (0) +// CHECK-NEXT: 2 | vcall_offset (0) +// CHECK-NEXT: 3 | offset_to_top (0) +// CHECK-NEXT: 4 | Test13::C RTTI +// CHECK-NEXT: -- (Test13::A, 0) vtable address -- +// CHECK-NEXT: -- (Test13::B, 0) vtable address -- +// CHECK-NEXT: -- (Test13::C, 0) vtable address -- +// CHECK-NEXT: 5 | void Test13::C::f() +struct C : virtual B, virtual A { + virtual void f(); +}; +void C::f() { } + +} + From andersca at mac.com Mon Feb 22 22:26:39 2010 From: andersca at mac.com (Anders Carlsson) Date: Tue, 23 Feb 2010 04:26:39 -0000 Subject: [cfe-commits] r96883 - /cfe/trunk/lib/CodeGen/CGVtable.cpp Message-ID: <20100223042639.4966B2A6C12C@llvm.org> Author: andersca Date: Mon Feb 22 22:26:39 2010 New Revision: 96883 URL: http://llvm.org/viewvc/llvm-project?rev=96883&view=rev Log: Stub out IsOverriderUsed. Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=96883&r1=96882&r2=96883&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVtable.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVtable.cpp Mon Feb 22 22:26:39 2010 @@ -992,9 +992,33 @@ void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment, ThisAdjustment ThisAdjustment); + /// IsOverriderUsed - Returns whether the overrider will ever be used in this + /// part of the vtable. + /// + /// Itanium C++ ABI 2.5.2: + /// + /// struct A { virtual void f(); }; + /// struct B : virtual public A { int i; }; + /// struct C : virtual public A { int j; }; + /// struct D : public B, public C {}; + /// + /// When B and C are declared, A is a primary base in each case, so although + /// vcall offsets are allocated in the A-in-B and A-in-C vtables, no this + /// adjustment is required and no thunk is generated. However, inside D + /// objects, A is no longer a primary base of C, so if we allowed calls to + /// C::f() to use the copy of A's vtable in the C subobject, we would need + /// to adjust this from C* to B::A*, which would require a third-party + /// thunk. Since we require that a call to C::f() first convert to A*, + /// C-in-D's copy of A's vtable is never referenced, so this is not + /// necessary. + bool IsOverriderUsed(BaseSubobject Base, + BaseSubobject FirstBaseInPrimaryBaseChain, + FinalOverriders::OverriderInfo Overrider) const; + /// AddMethods - Add the methods of this base subobject and all its /// primary bases to the vtable components vector. - void AddMethods(BaseSubobject Base, PrimaryBasesSetTy &PrimaryBases); + void AddMethods(BaseSubobject Base, BaseSubobject FirstBaseInPrimaryBaseChain, + PrimaryBasesSetTy &PrimaryBases); // LayoutVtable - Layout the vtable for the most derived class, including its // secondary vtables and any vtables for virtual bases. @@ -1257,8 +1281,22 @@ } } +bool +VtableBuilder::IsOverriderUsed(BaseSubobject Base, + BaseSubobject FirstBaseInPrimaryBaseChain, + FinalOverriders::OverriderInfo Overrider) const { + // If the base and the first base in the primary base chain have the same + // offsets, then this overrider will be used. + if (Base.getBaseOffset() == FirstBaseInPrimaryBaseChain.getBaseOffset()) + return true; + + return true; +} + void -VtableBuilder::AddMethods(BaseSubobject Base, PrimaryBasesSetTy &PrimaryBases) { +VtableBuilder::AddMethods(BaseSubobject Base, + BaseSubobject FirstBaseInPrimaryBaseChain, + PrimaryBasesSetTy &PrimaryBases) { const CXXRecordDecl *RD = Base.getBase(); const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); @@ -1283,7 +1321,8 @@ BaseOffset = Base.getBaseOffset(); } - AddMethods(BaseSubobject(PrimaryBase, BaseOffset), PrimaryBases); + AddMethods(BaseSubobject(PrimaryBase, BaseOffset), + FirstBaseInPrimaryBaseChain, PrimaryBases); if (!PrimaryBases.insert(PrimaryBase)) assert(false && "Found a duplicate primary base!"); @@ -1311,6 +1350,13 @@ continue; } + // Check if this overrider is going to be used. + if (!IsOverriderUsed(Base, FirstBaseInPrimaryBaseChain, Overrider)) { + const CXXMethodDecl *OverriderMD = Overrider.Method; + Components.push_back(VtableComponent::MakeUnusedFunction(OverriderMD)); + continue; + } + // Check if this overrider needs a return adjustment. BaseOffset ReturnAdjustmentOffset = Overriders.getReturnAdjustmentOffset(Base, MD); @@ -1363,7 +1409,7 @@ // Now go through all virtual member functions and add them. PrimaryBasesSetTy PrimaryBases; - AddMethods(Base, PrimaryBases); + AddMethods(Base, Base, PrimaryBases); // Record the address point. AddressPoints.insert(std::make_pair(Base, AddressPoint)); From cdavis at mymail.mines.edu Mon Feb 22 22:37:32 2010 From: cdavis at mymail.mines.edu (Charles Davis) Date: Mon, 22 Feb 2010 21:37:32 -0700 Subject: [cfe-commits] [PATCH] Fix __alignof__ behavior with a field as the operand Message-ID: <4B835B8C.5050202@mymail.mines.edu> This patch fixes __alignof__ to behave the same as GCC when a reference to a field of a struct is the operand. This fixes PR6362. GCC returns the lesser of the alignment of the type of the field or the packed alignment of the struct in this situation. Right now, clang just returns the alignment of the type, no matter what. This means that the behavior of clang deviates from GCC when a field of a packed struct (i.e. one with the 'packed' attribute or one declared after a pack pragma) is the operand. Software in the wild (e.g., Wine) already depends on this behavior. This is a simple patch, but I wanted to run it past you guys before committing. Chip -------------- next part -------------- An embedded and charset-unspecified text was scrubbed... Name: pr6362-fix.patch Url: http://lists.cs.uiuc.edu/pipermail/cfe-commits/attachments/20100222/620e340f/attachment.pl From andersca at mac.com Mon Feb 22 22:40:04 2010 From: andersca at mac.com (Anders Carlsson) Date: Mon, 22 Feb 2010 20:40:04 -0800 Subject: [cfe-commits] [PATCH] Fix __alignof__ behavior with a field as the operand In-Reply-To: <4B835B8C.5050202@mymail.mines.edu> References: <4B835B8C.5050202@mymail.mines.edu> Message-ID: <1E479935-E73D-4B60-ADAE-285201209E7E@mac.com> 22 feb 2010 kl. 20.37 skrev Charles Davis: > This patch fixes __alignof__ to behave the same as GCC when a reference > to a field of a struct is the operand. This fixes PR6362. > > GCC returns the lesser of the alignment of the type of the field or the > packed alignment of the struct in this situation. Right now, clang just > returns the alignment of the type, no matter what. This means that the > behavior of clang deviates from GCC when a field of a packed struct > (i.e. one with the 'packed' attribute or one declared after a pack > pragma) is the operand. > > Software in the wild (e.g., Wine) already depends on this behavior. > > This is a simple patch, but I wanted to run it past you guys before > committing. > Hi Charles, patch looks good. I assume all tests pass? :) > + // In the case of a field in a packed struct, we want the MINIMUM No need to shout here :), plz change to "minimum". Anders -------------- next part -------------- An HTML attachment was scrubbed... URL: http://lists.cs.uiuc.edu/pipermail/cfe-commits/attachments/20100222/db4f1c83/attachment.html From cdavis at mines.edu Mon Feb 22 22:52:00 2010 From: cdavis at mines.edu (Charles Davis) Date: Tue, 23 Feb 2010 04:52:00 -0000 Subject: [cfe-commits] r96884 - in /cfe/trunk: lib/AST/ASTContext.cpp test/Sema/align-x86.c Message-ID: <20100223045200.AB6D62A6C12C@llvm.org> Author: cdavis Date: Mon Feb 22 22:52:00 2010 New Revision: 96884 URL: http://llvm.org/viewvc/llvm-project?rev=96884&view=rev Log: When a reference to a field of a struct/union/class is passed to the __alignof__ operator, make sure to take into account the packed alignment of the struct/union/class itself. Matches GCC's behavior and fixes PR6362. Modified: cfe/trunk/lib/AST/ASTContext.cpp cfe/trunk/test/Sema/align-x86.c Modified: cfe/trunk/lib/AST/ASTContext.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=96884&r1=96883&r2=96884&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTContext.cpp (original) +++ cfe/trunk/lib/AST/ASTContext.cpp Mon Feb 22 22:52:00 2010 @@ -563,6 +563,12 @@ Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr())); } + if (const FieldDecl *FD = dyn_cast(VD)) { + // In the case of a field in a packed struct, we want the minimum + // of the alignment of the field and the alignment of the struct. + Align = std::min(Align, + getPreferredTypeAlign(FD->getParent()->getTypeForDecl())); + } } return CharUnits::fromQuantity(Align / Target.getCharWidth()); Modified: cfe/trunk/test/Sema/align-x86.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/align-x86.c?rev=96884&r1=96883&r2=96884&view=diff ============================================================================== --- cfe/trunk/test/Sema/align-x86.c (original) +++ cfe/trunk/test/Sema/align-x86.c Mon Feb 22 22:52:00 2010 @@ -12,3 +12,9 @@ _Complex double g3; short chk1[__alignof__(g3) == 8 ? 1 : -1]; short chk2[__alignof__(_Complex double) == 8 ? 1 : -1]; + +// PR6362 +struct __attribute__((packed)) {unsigned int a} g4; +short chk1[__alignof__(g4) == 1 ? 1 : -1]; +short chk2[__alignof__(g4.a) == 1 ? 1 : -1]; + From cdavis at mymail.mines.edu Mon Feb 22 22:53:23 2010 From: cdavis at mymail.mines.edu (Charles Davis) Date: Mon, 22 Feb 2010 21:53:23 -0700 Subject: [cfe-commits] [PATCH] Fix __alignof__ behavior with a field as the operand In-Reply-To: <1E479935-E73D-4B60-ADAE-285201209E7E@mac.com> References: <4B835B8C.5050202@mymail.mines.edu> <1E479935-E73D-4B60-ADAE-285201209E7E@mac.com> Message-ID: <4B835F43.8020604@mymail.mines.edu> Anders Carlsson wrote: > > 22 feb 2010 kl. 20.37 skrev Charles Davis: > >> This patch fixes __alignof__ to behave the same as GCC when a reference >> to a field of a struct is the operand. This fixes PR6362. >> >> GCC returns the lesser of the alignment of the type of the field or the >> packed alignment of the struct in this situation. Right now, clang just >> returns the alignment of the type, no matter what. This means that the >> behavior of clang deviates from GCC when a field of a packed struct >> (i.e. one with the 'packed' attribute or one declared after a pack >> pragma) is the operand. >> >> Software in the wild (e.g., Wine) already depends on this behavior. >> >> This is a simple patch, but I wanted to run it past you guys before >> committing. >> > > Hi Charles, > > patch looks good. I assume all tests pass? :) Of course. Otherwise, I wouldn't even consider posting to this list. :) > >> + // In the case of a field in a packed struct, we want the MINIMUM > > No need to shout here :), plz change to "minimum". Done. I wanted to emphasize that it's the minimum we want as opposed to the maximum. I guess that's not really necessary. Committed as r96884. Chip From kremenek at apple.com Mon Feb 22 23:59:16 2010 From: kremenek at apple.com (Ted Kremenek) Date: Tue, 23 Feb 2010 05:59:16 -0000 Subject: [cfe-commits] r96892 - /cfe/trunk/lib/Sema/SemaChecking.cpp Message-ID: <20100223055916.7E30E2A6C12D@llvm.org> Author: kremenek Date: Mon Feb 22 23:59:16 2010 New Revision: 96892 URL: http://llvm.org/viewvc/llvm-project?rev=96892&view=rev Log: Simplify check for basic block with a CXXTryStmt terminator. Modified: cfe/trunk/lib/Sema/SemaChecking.cpp Modified: cfe/trunk/lib/Sema/SemaChecking.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=96892&r1=96891&r2=96892&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) +++ cfe/trunk/lib/Sema/SemaChecking.cpp Mon Feb 22 23:59:16 2010 @@ -2278,9 +2278,8 @@ for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { CFGBlock &b = **I; if (!reachable[b.getBlockID()]) { - if (b.pred_begin() == b.pred_end()) { - if (!AddEHEdges && b.getTerminator() - && isa(b.getTerminator())) { + if (b.pred_empty()) { + if (!AddEHEdges && dyn_cast_or_null(b.getTerminator())) { // When not adding EH edges from calls, catch clauses // can otherwise seem dead. Avoid noting them as dead. numReachable += ScanReachableFromBlock(b, reachable); From kremenek at apple.com Mon Feb 22 23:59:21 2010 From: kremenek at apple.com (Ted Kremenek) Date: Tue, 23 Feb 2010 05:59:21 -0000 Subject: [cfe-commits] r96893 - in /cfe/trunk: include/clang/Analysis/Analyses/ReachableCode.h lib/Analysis/ReachableCode.cpp lib/Sema/SemaChecking.cpp Message-ID: <20100223055921.108892A6C12C@llvm.org> Author: kremenek Date: Mon Feb 22 23:59:20 2010 New Revision: 96893 URL: http://llvm.org/viewvc/llvm-project?rev=96893&view=rev Log: Move the rest of the unreachable code analysis from libSema to libAnalysis (with only the error reporting in libSema). Modified: cfe/trunk/include/clang/Analysis/Analyses/ReachableCode.h cfe/trunk/lib/Analysis/ReachableCode.cpp cfe/trunk/lib/Sema/SemaChecking.cpp Modified: cfe/trunk/include/clang/Analysis/Analyses/ReachableCode.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ReachableCode.h?rev=96893&r1=96892&r2=96893&view=diff ============================================================================== --- cfe/trunk/include/clang/Analysis/Analyses/ReachableCode.h (original) +++ cfe/trunk/include/clang/Analysis/Analyses/ReachableCode.h Mon Feb 22 23:59:20 2010 @@ -14,28 +14,42 @@ #ifndef LLVM_CLANG_REACHABLECODE_H #define LLVM_CLANG_REACHABLECODE_H +#include "clang/Basic/SourceLocation.h" + //===----------------------------------------------------------------------===// // Forward declarations. //===----------------------------------------------------------------------===// namespace llvm { -class BitVector; -} // end llvm namespace + class BitVector; +} namespace clang { -class CFGBlock; -} // end clang namespace + class AnalysisContext; + class CFGBlock; +} //===----------------------------------------------------------------------===// // API. //===----------------------------------------------------------------------===// namespace clang { +namespace reachable_code { + +class Callback { +public: + virtual ~Callback() {} + virtual void HandleUnreachable(SourceLocation L, SourceRange R1, + SourceRange R2) = 0; +}; /// ScanReachableFromBlock - Mark all blocks reachable from Start. -/// Returns the total number of blocks that were marked reachable. -unsigned ScanReachableFromBlock(const CFGBlock &B, llvm::BitVector &Reachable); +/// Returns the total number of blocks that were marked reachable. +unsigned ScanReachableFromBlock(const CFGBlock &Start, + llvm::BitVector &Reachable); + +void FindUnreachableCode(AnalysisContext &AC, Callback &CB); -} // end clang namespace +}} // end namespace clang::reachable_code #endif Modified: cfe/trunk/lib/Analysis/ReachableCode.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ReachableCode.cpp?rev=96893&r1=96892&r2=96893&view=diff ============================================================================== --- cfe/trunk/lib/Analysis/ReachableCode.cpp (original) +++ cfe/trunk/lib/Analysis/ReachableCode.cpp Mon Feb 22 23:59:20 2010 @@ -14,29 +14,188 @@ #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallVector.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtCXX.h" #include "clang/Analysis/Analyses/ReachableCode.h" #include "clang/Analysis/CFG.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Basic/SourceManager.h" using namespace clang; +static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1, + SourceRange &R2) { + const Stmt *S = 0; + unsigned sn = 0; + R1 = R2 = SourceRange(); + +top: + if (sn < b.size()) + S = b[sn].getStmt(); + else if (b.getTerminator()) + S = b.getTerminator(); + else + return SourceLocation(); + + switch (S->getStmtClass()) { + case Expr::BinaryOperatorClass: { + const BinaryOperator *BO = cast(S); + if (BO->getOpcode() == BinaryOperator::Comma) { + if (sn+1 < b.size()) + return b[sn+1].getStmt()->getLocStart(); + const CFGBlock *n = &b; + while (1) { + if (n->getTerminator()) + return n->getTerminator()->getLocStart(); + if (n->succ_size() != 1) + return SourceLocation(); + n = n[0].succ_begin()[0]; + if (n->pred_size() != 1) + return SourceLocation(); + if (!n->empty()) + return n[0][0].getStmt()->getLocStart(); + } + } + R1 = BO->getLHS()->getSourceRange(); + R2 = BO->getRHS()->getSourceRange(); + return BO->getOperatorLoc(); + } + case Expr::UnaryOperatorClass: { + const UnaryOperator *UO = cast(S); + R1 = UO->getSubExpr()->getSourceRange(); + return UO->getOperatorLoc(); + } + case Expr::CompoundAssignOperatorClass: { + const CompoundAssignOperator *CAO = cast(S); + R1 = CAO->getLHS()->getSourceRange(); + R2 = CAO->getRHS()->getSourceRange(); + return CAO->getOperatorLoc(); + } + case Expr::ConditionalOperatorClass: { + const ConditionalOperator *CO = cast(S); + return CO->getQuestionLoc(); + } + case Expr::MemberExprClass: { + const MemberExpr *ME = cast(S); + R1 = ME->getSourceRange(); + return ME->getMemberLoc(); + } + case Expr::ArraySubscriptExprClass: { + const ArraySubscriptExpr *ASE = cast(S); + R1 = ASE->getLHS()->getSourceRange(); + R2 = ASE->getRHS()->getSourceRange(); + return ASE->getRBracketLoc(); + } + case Expr::CStyleCastExprClass: { + const CStyleCastExpr *CSC = cast(S); + R1 = CSC->getSubExpr()->getSourceRange(); + return CSC->getLParenLoc(); + } + case Expr::CXXFunctionalCastExprClass: { + const CXXFunctionalCastExpr *CE = cast (S); + R1 = CE->getSubExpr()->getSourceRange(); + return CE->getTypeBeginLoc(); + } + case Expr::ImplicitCastExprClass: + ++sn; + goto top; + case Stmt::CXXTryStmtClass: { + return cast(S)->getHandler(0)->getCatchLoc(); + } + default: ; + } + R1 = S->getSourceRange(); + return S->getLocStart(); +} + +static SourceLocation MarkLiveTop(const CFGBlock *Start, + llvm::BitVector &reachable, + SourceManager &SM) { + + // Prep work worklist. + llvm::SmallVector WL; + WL.push_back(Start); + + SourceRange R1, R2; + SourceLocation top = GetUnreachableLoc(*Start, R1, R2); + + bool FromMainFile = false; + bool FromSystemHeader = false; + bool TopValid = false; + + if (top.isValid()) { + FromMainFile = SM.isFromMainFile(top); + FromSystemHeader = SM.isInSystemHeader(top); + TopValid = true; + } + + // Solve + while (!WL.empty()) { + const CFGBlock *item = WL.back(); + WL.pop_back(); + + SourceLocation c = GetUnreachableLoc(*item, R1, R2); + if (c.isValid() + && (!TopValid + || (SM.isFromMainFile(c) && !FromMainFile) + || (FromSystemHeader && !SM.isInSystemHeader(c)) + || SM.isBeforeInTranslationUnit(c, top))) { + top = c; + FromMainFile = SM.isFromMainFile(top); + FromSystemHeader = SM.isInSystemHeader(top); + } + + reachable.set(item->getBlockID()); + for (CFGBlock::const_succ_iterator I=item->succ_begin(), E=item->succ_end(); + I != E; ++I) + if (const CFGBlock *B = *I) { + unsigned blockID = B->getBlockID(); + if (!reachable[blockID]) { + reachable.set(blockID); + WL.push_back(B); + } + } + } + + return top; +} + +static int LineCmp(const void *p1, const void *p2) { + SourceLocation *Line1 = (SourceLocation *)p1; + SourceLocation *Line2 = (SourceLocation *)p2; + return !(*Line1 < *Line2); +} + +namespace { +struct ErrLoc { + SourceLocation Loc; + SourceRange R1; + SourceRange R2; + ErrLoc(SourceLocation l, SourceRange r1, SourceRange r2) + : Loc(l), R1(r1), R2(r2) { } +}; +} +namespace clang { namespace reachable_code { + /// ScanReachableFromBlock - Mark all blocks reachable from Start. /// Returns the total number of blocks that were marked reachable. -unsigned clang::ScanReachableFromBlock(const CFGBlock &Start, - llvm::BitVector &Reachable) { +unsigned ScanReachableFromBlock(const CFGBlock &Start, + llvm::BitVector &Reachable) { unsigned count = 0; - llvm::SmallVector WL; - - // Prep work queue + llvm::SmallVector WL; + + // Prep work queue Reachable.set(Start.getBlockID()); ++count; WL.push_back(&Start); - - // Find the reachable blocks from 'Start'. + + // Find the reachable blocks from 'Start'. while (!WL.empty()) { const CFGBlock *item = WL.back(); WL.pop_back(); - - // Look at the successors and mark then reachable. + + // Look at the successors and mark then reachable. for (CFGBlock::const_succ_iterator I=item->succ_begin(), E=item->succ_end(); I != E; ++I) if (const CFGBlock *B = *I) { @@ -50,3 +209,70 @@ } return count; } + +void FindUnreachableCode(AnalysisContext &AC, Callback &CB) { + CFG *cfg = AC.getCFG(); + if (!cfg) + return; + + // Scan for reachable blocks. + llvm::BitVector reachable(cfg->getNumBlockIDs()); + unsigned numReachable = ScanReachableFromBlock(cfg->getEntry(), reachable); + + // If there are no unreachable blocks, we're done. + if (numReachable == cfg->getNumBlockIDs()) + return; + + SourceRange R1, R2; + + llvm::SmallVector lines; + bool AddEHEdges = AC.getAddEHEdges(); + + // First, give warnings for blocks with no predecessors, as they + // can't be part of a loop. + for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { + CFGBlock &b = **I; + if (!reachable[b.getBlockID()]) { + if (b.pred_empty()) { + if (!AddEHEdges && dyn_cast_or_null(b.getTerminator())) { + // When not adding EH edges from calls, catch clauses + // can otherwise seem dead. Avoid noting them as dead. + numReachable += ScanReachableFromBlock(b, reachable); + continue; + } + SourceLocation c = GetUnreachableLoc(b, R1, R2); + if (!c.isValid()) { + // Blocks without a location can't produce a warning, so don't mark + // reachable blocks from here as live. + reachable.set(b.getBlockID()); + ++numReachable; + continue; + } + lines.push_back(ErrLoc(c, R1, R2)); + // Avoid excessive errors by marking everything reachable from here + numReachable += ScanReachableFromBlock(b, reachable); + } + } + } + + if (numReachable < cfg->getNumBlockIDs()) { + // And then give warnings for the tops of loops. + for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { + CFGBlock &b = **I; + if (!reachable[b.getBlockID()]) + // Avoid excessive errors by marking everything reachable from here + lines.push_back(ErrLoc(MarkLiveTop(&b, reachable, + AC.getASTContext().getSourceManager()), + SourceRange(), SourceRange())); + } + } + + llvm::array_pod_sort(lines.begin(), lines.end(), LineCmp); + + for (llvm::SmallVectorImpl::iterator I=lines.begin(), E=lines.end(); + I != E; ++I) + if (I->Loc.isValid()) + CB.HandleUnreachable(I->Loc, I->R1, I->R2); +} + +}} // end namespace clang::reachable_code Modified: cfe/trunk/lib/Sema/SemaChecking.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=96893&r1=96892&r2=96893&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) +++ cfe/trunk/lib/Sema/SemaChecking.cpp Mon Feb 22 23:59:20 2010 @@ -2105,148 +2105,18 @@ return; } -static SourceLocation GetUnreachableLoc(CFGBlock &b, SourceRange &R1, - SourceRange &R2) { - Stmt *S; - unsigned sn = 0; - R1 = R2 = SourceRange(); - - top: - if (sn < b.size()) - S = b[sn].getStmt(); - else if (b.getTerminator()) - S = b.getTerminator(); - else - return SourceLocation(); - - switch (S->getStmtClass()) { - case Expr::BinaryOperatorClass: { - BinaryOperator *BO = cast(S); - if (BO->getOpcode() == BinaryOperator::Comma) { - if (sn+1 < b.size()) - return b[sn+1].getStmt()->getLocStart(); - CFGBlock *n = &b; - while (1) { - if (n->getTerminator()) - return n->getTerminator()->getLocStart(); - if (n->succ_size() != 1) - return SourceLocation(); - n = n[0].succ_begin()[0]; - if (n->pred_size() != 1) - return SourceLocation(); - if (!n->empty()) - return n[0][0].getStmt()->getLocStart(); - } - } - R1 = BO->getLHS()->getSourceRange(); - R2 = BO->getRHS()->getSourceRange(); - return BO->getOperatorLoc(); - } - case Expr::UnaryOperatorClass: { - const UnaryOperator *UO = cast(S); - R1 = UO->getSubExpr()->getSourceRange(); - return UO->getOperatorLoc(); - } - case Expr::CompoundAssignOperatorClass: { - const CompoundAssignOperator *CAO = cast(S); - R1 = CAO->getLHS()->getSourceRange(); - R2 = CAO->getRHS()->getSourceRange(); - return CAO->getOperatorLoc(); - } - case Expr::ConditionalOperatorClass: { - const ConditionalOperator *CO = cast(S); - return CO->getQuestionLoc(); - } - case Expr::MemberExprClass: { - const MemberExpr *ME = cast(S); - R1 = ME->getSourceRange(); - return ME->getMemberLoc(); - } - case Expr::ArraySubscriptExprClass: { - const ArraySubscriptExpr *ASE = cast(S); - R1 = ASE->getLHS()->getSourceRange(); - R2 = ASE->getRHS()->getSourceRange(); - return ASE->getRBracketLoc(); - } - case Expr::CStyleCastExprClass: { - const CStyleCastExpr *CSC = cast(S); - R1 = CSC->getSubExpr()->getSourceRange(); - return CSC->getLParenLoc(); - } - case Expr::CXXFunctionalCastExprClass: { - const CXXFunctionalCastExpr *CE = cast (S); - R1 = CE->getSubExpr()->getSourceRange(); - return CE->getTypeBeginLoc(); - } - case Expr::ImplicitCastExprClass: - ++sn; - goto top; - case Stmt::CXXTryStmtClass: { - return cast(S)->getHandler(0)->getCatchLoc(); - } - default: ; - } - R1 = S->getSourceRange(); - return S->getLocStart(); -} -static SourceLocation MarkLiveTop(CFGBlock *e, llvm::BitVector &live, - SourceManager &SM) { - std::queue workq; - // Prep work queue - workq.push(e); - SourceRange R1, R2; - SourceLocation top = GetUnreachableLoc(*e, R1, R2); - bool FromMainFile = false; - bool FromSystemHeader = false; - bool TopValid = false; - if (top.isValid()) { - FromMainFile = SM.isFromMainFile(top); - FromSystemHeader = SM.isInSystemHeader(top); - TopValid = true; - } - // Solve - while (!workq.empty()) { - CFGBlock *item = workq.front(); - workq.pop(); - SourceLocation c = GetUnreachableLoc(*item, R1, R2); - if (c.isValid() - && (!TopValid - || (SM.isFromMainFile(c) && !FromMainFile) - || (FromSystemHeader && !SM.isInSystemHeader(c)) - || SM.isBeforeInTranslationUnit(c, top))) { - top = c; - FromMainFile = SM.isFromMainFile(top); - FromSystemHeader = SM.isInSystemHeader(top); - } - live.set(item->getBlockID()); - for (CFGBlock::succ_iterator I=item->succ_begin(), - E=item->succ_end(); - I != E; - ++I) { - if ((*I) && !live[(*I)->getBlockID()]) { - live.set((*I)->getBlockID()); - workq.push(*I); - } - } - } - return top; -} - -static int LineCmp(const void *p1, const void *p2) { - SourceLocation *Line1 = (SourceLocation *)p1; - SourceLocation *Line2 = (SourceLocation *)p2; - return !(*Line1 < *Line2); -} namespace { - struct ErrLoc { - SourceLocation Loc; - SourceRange R1; - SourceRange R2; - ErrLoc(SourceLocation l, SourceRange r1, SourceRange r2) - : Loc(l), R1(r1), R2(r2) { } - }; +class UnreachableCodeHandler : public reachable_code::Callback { + Sema &S; +public: + UnreachableCodeHandler(Sema *s) : S(*s) {} + + void HandleUnreachable(SourceLocation L, SourceRange R1, SourceRange R2) { + S.Diag(L, diag::warn_unreachable) << R1 << R2; + } +}; } /// CheckUnreachable - Check for unreachable code. @@ -2257,66 +2127,8 @@ Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored) return; - CFG *cfg = AC.getCFG(); - if (cfg == 0) - return; - - // Mark all live things first. - llvm::BitVector reachable(cfg->getNumBlockIDs()); - unsigned numReachable = ScanReachableFromBlock(cfg->getEntry(), reachable); - - // If there are no dead blocks, we're done. - if (numReachable == cfg->getNumBlockIDs()) - return; - - SourceRange R1, R2; - - llvm::SmallVector lines; - bool AddEHEdges = AC.getAddEHEdges(); - // First, give warnings for blocks with no predecessors, as they - // can't be part of a loop. - for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { - CFGBlock &b = **I; - if (!reachable[b.getBlockID()]) { - if (b.pred_empty()) { - if (!AddEHEdges && dyn_cast_or_null(b.getTerminator())) { - // When not adding EH edges from calls, catch clauses - // can otherwise seem dead. Avoid noting them as dead. - numReachable += ScanReachableFromBlock(b, reachable); - continue; - } - SourceLocation c = GetUnreachableLoc(b, R1, R2); - if (!c.isValid()) { - // Blocks without a location can't produce a warning, so don't mark - // reachable blocks from here as live. - reachable.set(b.getBlockID()); - ++numReachable; - continue; - } - lines.push_back(ErrLoc(c, R1, R2)); - // Avoid excessive errors by marking everything reachable from here - numReachable += ScanReachableFromBlock(b, reachable); - } - } - } - - if (numReachable < cfg->getNumBlockIDs()) { - // And then give warnings for the tops of loops. - for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { - CFGBlock &b = **I; - if (!reachable[b.getBlockID()]) - // Avoid excessive errors by marking everything reachable from here - lines.push_back(ErrLoc(MarkLiveTop(&b, reachable, - Context.getSourceManager()), - SourceRange(), SourceRange())); - } - } - - llvm::array_pod_sort(lines.begin(), lines.end(), LineCmp); - for (llvm::SmallVectorImpl::iterator I=lines.begin(), E=lines.end(); - I != E; ++I) - if (I->Loc.isValid()) - Diag(I->Loc, diag::warn_unreachable) << I->R1 << I->R2; + UnreachableCodeHandler UC(this); + reachable_code::FindUnreachableCode(AC, UC); } /// CheckFallThrough - Check that we don't fall off the end of a @@ -2338,7 +2150,8 @@ // confuse us, so we mark all live things first. std::queue workq; llvm::BitVector live(cfg->getNumBlockIDs()); - unsigned count = ScanReachableFromBlock(cfg->getEntry(), live); + unsigned count = reachable_code::ScanReachableFromBlock(cfg->getEntry(), + live); bool AddEHEdges = AC.getAddEHEdges(); if (!AddEHEdges && count != cfg->getNumBlockIDs()) @@ -2352,7 +2165,7 @@ if (b.getTerminator() && isa(b.getTerminator())) // When not adding EH edges from calls, catch clauses // can otherwise seem dead. Avoid noting them as dead. - count += ScanReachableFromBlock(b, live); + count += reachable_code::ScanReachableFromBlock(b, live); continue; } } From cdavis at mines.edu Tue Feb 23 00:13:56 2010 From: cdavis at mines.edu (Charles Davis) Date: Tue, 23 Feb 2010 06:13:56 -0000 Subject: [cfe-commits] r96895 - in /cfe/trunk: lib/Sema/SemaType.cpp test/Sema/callingconv.c Message-ID: <20100223061356.1A6092A6C12C@llvm.org> Author: cdavis Date: Tue Feb 23 00:13:55 2010 New Revision: 96895 URL: http://llvm.org/viewvc/llvm-project?rev=96895&view=rev Log: When comparing two calling conventions after redeclaring a function, compare the canonical calling conventions instead of comparing the raw calling conventions directly. Fixes PR6361. Modified: cfe/trunk/lib/Sema/SemaType.cpp cfe/trunk/test/Sema/callingconv.c Modified: cfe/trunk/lib/Sema/SemaType.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=96895&r1=96894&r2=96895&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaType.cpp (original) +++ cfe/trunk/lib/Sema/SemaType.cpp Tue Feb 23 00:13:55 2010 @@ -1755,7 +1755,8 @@ } CallingConv CCOld = Fn->getCallConv(); - if (CC == CCOld) return false; + if (S.Context.getCanonicalCallConv(CC) == + S.Context.getCanonicalCallConv(CCOld)) return false; if (CCOld != CC_Default) { // Should we diagnose reapplications of the same convention? Modified: cfe/trunk/test/Sema/callingconv.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/callingconv.c?rev=96895&r1=96894&r2=96895&view=diff ============================================================================== --- cfe/trunk/test/Sema/callingconv.c (original) +++ cfe/trunk/test/Sema/callingconv.c Tue Feb 23 00:13:55 2010 @@ -36,3 +36,7 @@ typedef void (__attribute__((fastcall)) *Handler) (float *); Handler H = foo; +// PR6361 +void ctest3(); +void __attribute__((cdecl)) ctest3() {} + From andersca at mac.com Tue Feb 23 00:34:44 2010 From: andersca at mac.com (Anders Carlsson) Date: Tue, 23 Feb 2010 06:34:44 -0000 Subject: [cfe-commits] r96897 - /cfe/trunk/lib/CodeGen/CGVtable.cpp Message-ID: <20100223063444.A8F912A6C12C@llvm.org> Author: andersca Date: Tue Feb 23 00:34:44 2010 New Revision: 96897 URL: http://llvm.org/viewvc/llvm-project?rev=96897&view=rev Log: Implement IsOverriderUsed. This can't be tested yet due to some other bugs :) Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=96897&r1=96896&r2=96897&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVtable.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVtable.cpp Tue Feb 23 00:34:44 2010 @@ -1288,9 +1288,54 @@ // If the base and the first base in the primary base chain have the same // offsets, then this overrider will be used. if (Base.getBaseOffset() == FirstBaseInPrimaryBaseChain.getBaseOffset()) + return true; + + // We know now that Base (or a direct or indirect base of it) is a primary + // base in part of the class hierarchy, but not a primary base in the most + // derived class. + + // If the overrider is the first base in the primary base chain, we know + // that the overrider will be used. + if (Overrider.Method->getParent() == FirstBaseInPrimaryBaseChain.getBase()) return true; - return true; + VtableBuilder::PrimaryBasesSetTy PrimaryBases; + + const CXXRecordDecl *RD = FirstBaseInPrimaryBaseChain.getBase(); + PrimaryBases.insert(RD); + + // Now traverse the base chain, starting with the first base, until we find + // the base that is no longer a primary base. + while (true) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + if (!PrimaryBase) + break; + + if (Layout.getPrimaryBaseWasVirtual()) { + assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && + "Primary base should always be at offset 0!"); + + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + + // Now check if this is the primary base that is not a primary base in the + // most derived class. + if (MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase) != + FirstBaseInPrimaryBaseChain.getBaseOffset()) { + // We found it, stop walking the chain. + break; + } + } else { + assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && + "Primary base should always be at offset 0!"); + } + } + + // If the final overrider is an override of one of the primary bases, + // then we know that it will be used. + return OverridesMethodInPrimaryBase(Overrider.Method, PrimaryBases); } void From kremenek at apple.com Tue Feb 23 01:17:57 2010 From: kremenek at apple.com (Ted Kremenek) Date: Tue, 23 Feb 2010 07:17:57 -0000 Subject: [cfe-commits] r96902 - /cfe/trunk/test/Analysis/misc-ps-region-store.m Message-ID: <20100223071757.9EE082A6C12C@llvm.org> Author: kremenek Date: Tue Feb 23 01:17:57 2010 New Revision: 96902 URL: http://llvm.org/viewvc/llvm-project?rev=96902&view=rev Log: Add test case for , which appears to have been fixed in the recent changes to RegionStore::InvalidateRegions(). Note that we are still not yet modeling 'memcpy()' explicitly. Modified: cfe/trunk/test/Analysis/misc-ps-region-store.m Modified: cfe/trunk/test/Analysis/misc-ps-region-store.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/misc-ps-region-store.m?rev=96902&r1=96901&r2=96902&view=diff ============================================================================== --- cfe/trunk/test/Analysis/misc-ps-region-store.m (original) +++ cfe/trunk/test/Analysis/misc-ps-region-store.m Tue Feb 23 01:17:57 2010 @@ -1,6 +1,10 @@ // RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s // RUN: %clang_cc1 -triple x86_64-apple-darwin9 -DTEST_64 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s +typedef long unsigned int size_t; +void *memcpy(void *, const void *, size_t); +void *alloca(size_t); + typedef struct objc_selector *SEL; typedef signed char BOOL; typedef int NSInteger; @@ -867,3 +871,20 @@ test_a_rev96062_aux2(&z); return a + b; // no-warning } + +//===----------------------------------------------------------------------===// +// - The access to y[0] at the bottom previously +// was reported as an uninitialized value. +//===----------------------------------------------------------------------===// + +char *rdar_7242010(int count, char **y) { + char **x = alloca((count + 4) * sizeof(*x)); + x[0] = "hi"; + x[1] = "there"; + x[2] = "every"; + x[3] = "body"; + memcpy(x + 4, y, count * sizeof(*x)); + y = x; + return y[0]; // no-warning +} + From rich at pennware.com Tue Feb 23 06:22:13 2010 From: rich at pennware.com (Richard Pennington) Date: Tue, 23 Feb 2010 12:22:13 -0000 Subject: [cfe-commits] r96941 - in /cfe/trunk: lib/Parse/Parser.cpp test/Parser/knr_parameter_attributes.c Message-ID: <20100223122213.CCF6F2A6C12C@llvm.org> Author: rich Date: Tue Feb 23 06:22:13 2010 New Revision: 96941 URL: http://llvm.org/viewvc/llvm-project?rev=96941&view=rev Log: Retain attributes for K&R style parameter declarations. Added: cfe/trunk/test/Parser/knr_parameter_attributes.c Modified: cfe/trunk/lib/Parse/Parser.cpp Modified: cfe/trunk/lib/Parse/Parser.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=96941&r1=96940&r2=96941&view=diff ============================================================================== --- cfe/trunk/lib/Parse/Parser.cpp (original) +++ cfe/trunk/lib/Parse/Parser.cpp Tue Feb 23 06:22:13 2010 @@ -743,10 +743,11 @@ // Handle the full declarator list. while (1) { // If attributes are present, parse them. - llvm::OwningPtr AttrList; - if (Tok.is(tok::kw___attribute)) - // FIXME: attach attributes too. - AttrList.reset(ParseGNUAttributes()); + if (Tok.is(tok::kw___attribute)) { + SourceLocation Loc; + AttributeList *AttrList = ParseGNUAttributes(&Loc); + ParmDeclarator.AddAttributes(AttrList, Loc); + } // Ask the actions module to compute the type for this declarator. Action::DeclPtrTy Param = Added: cfe/trunk/test/Parser/knr_parameter_attributes.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/knr_parameter_attributes.c?rev=96941&view=auto ============================================================================== --- cfe/trunk/test/Parser/knr_parameter_attributes.c (added) +++ cfe/trunk/test/Parser/knr_parameter_attributes.c Tue Feb 23 06:22:13 2010 @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -fsyntax-only -W -Wall -Werror -verify %s + +int f(int i __attribute__((__unused__))) +{ + return 0; +} +int g(i) + int i __attribute__((__unused__)); +{ + return 0; +} From eli.friedman at gmail.com Tue Feb 23 11:58:36 2010 From: eli.friedman at gmail.com (Eli Friedman) Date: Tue, 23 Feb 2010 17:58:36 -0000 Subject: [cfe-commits] r96958 - in /cfe/trunk: lib/CodeGen/CGExprAgg.cpp test/CodeGen/cast-emit.c Message-ID: <20100223175836.2180A2A6C12C@llvm.org> Author: efriedma Date: Tue Feb 23 11:58:35 2010 New Revision: 96958 URL: http://llvm.org/viewvc/llvm-project?rev=96958&view=rev Log: PR6386: Fix a recent regression in IRGen of cast-to-union constructs. Added: cfe/trunk/test/CodeGen/cast-emit.c Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprAgg.cpp?rev=96958&r1=96957&r2=96958&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExprAgg.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp Tue Feb 23 11:58:35 2010 @@ -189,7 +189,7 @@ CGF.ConvertType(PtrTy)); EmitInitializationToLValue(E->getSubExpr(), LValue::MakeAddr(CastPtr, Qualifiers()), - E->getType()); + E->getSubExpr()->getType()); break; } Added: cfe/trunk/test/CodeGen/cast-emit.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/cast-emit.c?rev=96958&view=auto ============================================================================== --- cfe/trunk/test/CodeGen/cast-emit.c (added) +++ cfe/trunk/test/CodeGen/cast-emit.c Tue Feb 23 11:58:35 2010 @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s + +typedef union { + int i; + float f; +} MyUnion; +void unionf(MyUnion a); +void uniontest(float a) { + f((MyUnion)1.0f); +// CHECK: store float 1.000000e+00 +} + From eli.friedman at gmail.com Tue Feb 23 12:20:18 2010 From: eli.friedman at gmail.com (Eli Friedman) Date: Tue, 23 Feb 2010 18:20:18 -0000 Subject: [cfe-commits] r96961 - in /cfe/trunk: lib/CodeGen/Mangle.cpp test/CodeGenCXX/mangle-subst-std.cpp Message-ID: <20100223182018.7E60C2A6C12C@llvm.org> Author: efriedma Date: Tue Feb 23 12:20:18 2010 New Revision: 96961 URL: http://llvm.org/viewvc/llvm-project?rev=96961&view=rev Log: PR6400: Handle an extreme edge case in mangling correctly. Modified: cfe/trunk/lib/CodeGen/Mangle.cpp cfe/trunk/test/CodeGenCXX/mangle-subst-std.cpp Modified: cfe/trunk/lib/CodeGen/Mangle.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/Mangle.cpp?rev=96961&r1=96960&r2=96961&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/Mangle.cpp (original) +++ cfe/trunk/lib/CodeGen/Mangle.cpp Tue Feb 23 12:20:18 2010 @@ -1652,6 +1652,9 @@ // ::std::char_traits, // ::std::allocator > if (SD->getIdentifier()->isStr("basic_string")) { + if (!isStdNamespace(SD->getDeclContext())) + return false; + const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); if (TemplateArgs.size() != 3) Modified: cfe/trunk/test/CodeGenCXX/mangle-subst-std.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle-subst-std.cpp?rev=96961&r1=96960&r2=96961&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/mangle-subst-std.cpp (original) +++ cfe/trunk/test/CodeGenCXX/mangle-subst-std.cpp Tue Feb 23 12:20:18 2010 @@ -55,3 +55,9 @@ terminate_handler set_terminate(terminate_handler) { return 0; } } } + +// Make sure we don't treat the following like std::string +// CHECK: define void @_Z1f12basic_stringIcSt11char_traitsIcESaIcEE +template struct basic_string { }; +typedef basic_string, std::allocator > not_string; +void f(not_string) { } From eli.friedman at gmail.com Tue Feb 23 12:25:09 2010 From: eli.friedman at gmail.com (Eli Friedman) Date: Tue, 23 Feb 2010 18:25:09 -0000 Subject: [cfe-commits] r96962 - /cfe/trunk/lib/CodeGen/Mangle.cpp Message-ID: <20100223182509.C43292A6C12C@llvm.org> Author: efriedma Date: Tue Feb 23 12:25:09 2010 New Revision: 96962 URL: http://llvm.org/viewvc/llvm-project?rev=96962&view=rev Log: Make previous fix handle a few more edge cases. Modified: cfe/trunk/lib/CodeGen/Mangle.cpp Modified: cfe/trunk/lib/CodeGen/Mangle.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/Mangle.cpp?rev=96962&r1=96961&r2=96962&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/Mangle.cpp (original) +++ cfe/trunk/lib/CodeGen/Mangle.cpp Tue Feb 23 12:25:09 2010 @@ -1648,13 +1648,13 @@ if (const ClassTemplateSpecializationDecl *SD = dyn_cast(ND)) { + if (!isStdNamespace(SD->getDeclContext())) + return false; + // ::= Ss # ::std::basic_string, // ::std::allocator > if (SD->getIdentifier()->isStr("basic_string")) { - if (!isStdNamespace(SD->getDeclContext())) - return false; - const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); if (TemplateArgs.size() != 3) From fjahanian at apple.com Tue Feb 23 12:50:01 2010 From: fjahanian at apple.com (Fariborz Jahanian) Date: Tue, 23 Feb 2010 18:50:01 -0000 Subject: [cfe-commits] r96968 - /cfe/trunk/test/SemaObjC/property-and-class-extension.m Message-ID: <20100223185001.E9B852A6C12C@llvm.org> Author: fjahanian Date: Tue Feb 23 12:50:01 2010 New Revision: 96968 URL: http://llvm.org/viewvc/llvm-project?rev=96968&view=rev Log: A test case for property synthesis using ivar in class extensions. Added: cfe/trunk/test/SemaObjC/property-and-class-extension.m Added: cfe/trunk/test/SemaObjC/property-and-class-extension.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/property-and-class-extension.m?rev=96968&view=auto ============================================================================== --- cfe/trunk/test/SemaObjC/property-and-class-extension.m (added) +++ cfe/trunk/test/SemaObjC/property-and-class-extension.m Tue Feb 23 12:50:01 2010 @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi2 -verify %s + +/** +When processing @synthesize, treat ivars in a class extension the same as ivars in the class @interface, +and treat ivars in a superclass extension the same as ivars in the superclass @interface. +In particular, when searching for an ivar to back an @synthesize, do look at ivars in the class's own class +extension but ignore any ivars in superclass class extensions. +*/ + + at interface Super { + int ISA; +} + at end + + at interface Super() { + int Property; // expected-note {{previously declared 'Property' here}} +} + at end + + at interface SomeClass : Super { + int interfaceIvar1; + int interfaceIvar2; +} + at property int Property; + at property int Property1; + at end + + at interface SomeClass () { + int Property1; +} + at end + + at implementation SomeClass + at synthesize Property; // expected-error {{property 'Property' attempting to use ivar 'Property' declared in super class 'Super'}} + at synthesize Property1; // OK + at end From rjmccall at apple.com Tue Feb 23 13:22:29 2010 From: rjmccall at apple.com (John McCall) Date: Tue, 23 Feb 2010 19:22:29 -0000 Subject: [cfe-commits] r96970 - in /cfe/trunk: lib/Sema/SemaChecking.cpp test/Sema/conversion.c Message-ID: <20100223192229.C11382A6C12C@llvm.org> Author: rjmccall Date: Tue Feb 23 13:22:29 2010 New Revision: 96970 URL: http://llvm.org/viewvc/llvm-project?rev=96970&view=rev Log: Don't assert on compound assignment operators that operate in FP types when the result is integral. Fixes . Modified: cfe/trunk/lib/Sema/SemaChecking.cpp cfe/trunk/test/Sema/conversion.c Modified: cfe/trunk/lib/Sema/SemaChecking.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=96970&r1=96969&r2=96970&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) +++ cfe/trunk/lib/Sema/SemaChecking.cpp Tue Feb 23 13:22:29 2010 @@ -1682,13 +1682,13 @@ } // Returns the supremum of two ranges: i.e. their conservative merge. - static IntRange join(const IntRange &L, const IntRange &R) { + static IntRange join(IntRange L, IntRange R) { return IntRange(std::max(L.Width, R.Width), L.NonNegative && R.NonNegative); } // Returns the infinum of two ranges: i.e. their aggressive merge. - static IntRange meet(const IntRange &L, const IntRange &R) { + static IntRange meet(IntRange L, IntRange R) { return IntRange(std::min(L.Width, R.Width), L.NonNegative || R.NonNegative); } @@ -1806,6 +1806,15 @@ case BinaryOperator::NE: return IntRange::forBoolType(); + // The type of these compound assignments is the type of the LHS, + // so the RHS is not necessarily an integer. + case BinaryOperator::MulAssign: + case BinaryOperator::DivAssign: + case BinaryOperator::RemAssign: + case BinaryOperator::AddAssign: + case BinaryOperator::SubAssign: + return IntRange::forType(C, E->getType()); + // Operations with opaque sources are black-listed. case BinaryOperator::PtrMemD: case BinaryOperator::PtrMemI: @@ -1813,15 +1822,18 @@ // Bitwise-and uses the *infinum* of the two source ranges. case BinaryOperator::And: + case BinaryOperator::AndAssign: return IntRange::meet(GetExprRange(C, BO->getLHS(), MaxWidth), GetExprRange(C, BO->getRHS(), MaxWidth)); // Left shift gets black-listed based on a judgement call. case BinaryOperator::Shl: + case BinaryOperator::ShlAssign: return IntRange::forType(C, E->getType()); // Right shift by a constant can narrow its left argument. - case BinaryOperator::Shr: { + case BinaryOperator::Shr: + case BinaryOperator::ShrAssign: { IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth); // If the shift amount is a positive constant, drop the width by Modified: cfe/trunk/test/Sema/conversion.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/conversion.c?rev=96970&r1=96969&r2=96970&view=diff ============================================================================== --- cfe/trunk/test/Sema/conversion.c (original) +++ cfe/trunk/test/Sema/conversion.c Tue Feb 23 13:22:29 2010 @@ -279,3 +279,11 @@ // This should show up despite the caret being inside a macro substitution char s = LONG_MAX; // expected-warning {{implicit cast loses integer precision: 'long' to 'char'}} } + +// : assertion for compound operators with non-integral RHS +void f7676608(int); +void test_7676608(void) { + float q = 0.7f; + char c = 5; + f7676608(c *= q); +} From kremenek at apple.com Tue Feb 23 13:39:46 2010 From: kremenek at apple.com (Ted Kremenek) Date: Tue, 23 Feb 2010 19:39:46 -0000 Subject: [cfe-commits] r96976 - in /cfe/trunk: lib/Sema/SemaDeclObjC.cpp test/SemaObjC/category-1.m Message-ID: <20100223193946.843082A6C12C@llvm.org> Author: kremenek Date: Tue Feb 23 13:39:46 2010 New Revision: 96976 URL: http://llvm.org/viewvc/llvm-project?rev=96976&view=rev Log: Fix another crash on invalid code. In this case, handle ObjC categories (with no names) that refer to an undefined class. Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp cfe/trunk/test/SemaObjC/category-1.m Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=96976&r1=96975&r2=96976&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Tue Feb 23 13:39:46 2010 @@ -599,22 +599,31 @@ SourceLocation EndProtoLoc) { ObjCCategoryDecl *CDecl = 0; ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc); - if (!CategoryName) + + /// Check that class of this category is already completely declared. + if (!IDecl || IDecl->isForwardDecl()) { + // Create an invalid ObjCCategoryDecl to serve as context for + // the enclosing method declarations. We mark the decl invalid + // to make it clear that this isn't a valid AST. + CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, + ClassLoc, CategoryLoc, CategoryName); + CDecl->setInvalidDecl(); + Diag(ClassLoc, diag::err_undef_interface) << ClassName; + return DeclPtrTy::make(CDecl); + } + + if (!CategoryName) { // Class extensions require a special treatment. Use an existing one. + // Note that 'getClassExtension()' can return NULL. CDecl = IDecl->getClassExtension(); + } + if (!CDecl) { - CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, ClassLoc, - CategoryLoc, CategoryName); + CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, + ClassLoc, CategoryLoc, CategoryName); // FIXME: PushOnScopeChains? CurContext->addDecl(CDecl); - /// Check that class of this category is already completely declared. - if (!IDecl || IDecl->isForwardDecl()) { - CDecl->setInvalidDecl(); - Diag(ClassLoc, diag::err_undef_interface) << ClassName; - return DeclPtrTy::make(CDecl); - } - CDecl->setClassInterface(IDecl); // Insert first use of class extension to the list of class's categories. if (!CategoryName) Modified: cfe/trunk/test/SemaObjC/category-1.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/category-1.m?rev=96976&r1=96975&r2=96976&view=diff ============================================================================== --- cfe/trunk/test/SemaObjC/category-1.m (original) +++ cfe/trunk/test/SemaObjC/category-1.m Tue Feb 23 13:39:46 2010 @@ -73,3 +73,7 @@ @implementation MultipleCat_I // expected-warning {{incomplete implementation}}, expected-warning {{method definition for 'im0' not found}} @end + +// - Handle nameless categories with no name that refer +// to an undefined class + at interface RDar7680391 () @end // expected-error{{cannot find interface declaration}} From cdavis at mymail.mines.edu Tue Feb 23 13:51:55 2010 From: cdavis at mymail.mines.edu (Charles Davis) Date: Tue, 23 Feb 2010 12:51:55 -0700 Subject: [cfe-commits] [PATCH] Don't apply function attributes to the return type Message-ID: <4B8431DB.5040605@mymail.mines.edu> This patch fixes part of PR6408. It teaches clang not to try to apply function attributes to the return type of a function. GCC never does this, so neither should we. Chip -------------- next part -------------- An embedded and charset-unspecified text was scrubbed... Name: pr6408-fix-1.patch Url: http://lists.cs.uiuc.edu/pipermail/cfe-commits/attachments/20100223/4da6a64e/attachment.pl From daniel at zuster.org Tue Feb 23 14:23:45 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Tue, 23 Feb 2010 20:23:45 -0000 Subject: [cfe-commits] r96978 - in /cfe/trunk: include/clang/Basic/DiagnosticFrontendKinds.td tools/CIndex/CIndex.cpp tools/CIndex/CIndexCodeCompletion.cpp Message-ID: <20100223202345.CB78F2A6C12C@llvm.org> Author: ddunbar Date: Tue Feb 23 14:23:45 2010 New Revision: 96978 URL: http://llvm.org/viewvc/llvm-project?rev=96978&view=rev Log: Fix bogus diagnostic format string. Modified: cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td cfe/trunk/tools/CIndex/CIndex.cpp cfe/trunk/tools/CIndex/CIndexCodeCompletion.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td?rev=96978&r1=96977&r2=96978&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td Tue Feb 23 14:23:45 2010 @@ -82,7 +82,7 @@ def warn_fixit_no_changes : Note< "FIX-IT detected errors it could not fix; no output will be generated">; -def err_fe_clang : Error<"error invoking%s: %s">, DefaultFatal; +def err_fe_invoking : Error<"error invoking%0: %1">, DefaultFatal; // PCH reader def err_relocatable_without_without_isysroot : Error< Modified: cfe/trunk/tools/CIndex/CIndex.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CIndex/CIndex.cpp?rev=96978&r1=96977&r2=96978&view=diff ============================================================================== --- cfe/trunk/tools/CIndex/CIndex.cpp (original) +++ cfe/trunk/tools/CIndex/CIndex.cpp Tue Feb 23 14:23:45 2010 @@ -1103,7 +1103,7 @@ AllArgs += *I; } - Diags->Report(diag::err_fe_clang) << AllArgs << ErrMsg; + Diags->Report(diag::err_fe_invoking) << AllArgs << ErrMsg; } ASTUnit *ATU = ASTUnit::LoadFromPCHFile(astTmpFile, *Diags, Modified: cfe/trunk/tools/CIndex/CIndexCodeCompletion.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CIndex/CIndexCodeCompletion.cpp?rev=96978&r1=96977&r2=96978&view=diff ============================================================================== --- cfe/trunk/tools/CIndex/CIndexCodeCompletion.cpp (original) +++ cfe/trunk/tools/CIndex/CIndexCodeCompletion.cpp Tue Feb 23 14:23:45 2010 @@ -330,7 +330,7 @@ AllArgs += *I; } - Diags->Report(diag::err_fe_clang) << AllArgs << ErrMsg; + Diags->Report(diag::err_fe_invoking) << AllArgs << ErrMsg; } // Parse the resulting source file to find code-completion results. From dgregor at apple.com Tue Feb 23 14:39:59 2010 From: dgregor at apple.com (Douglas Gregor) Date: Tue, 23 Feb 2010 12:39:59 -0800 Subject: [cfe-commits] [patch] Add support for weakref In-Reply-To: <38a0d8451002221342x613b75efi6d469f1fad8dc705@mail.gmail.com> References: <38a0d8451002161420l737e839bl997ac248d2f62295@mail.gmail.com> <6a8523d61002200819k1c4b1eb3g1976ec52d8611778@mail.gmail.com> <38a0d8451002202101u7836817cv7742937c7a923294@mail.gmail.com> <38a0d8451002221342x613b75efi6d469f1fad8dc705@mail.gmail.com> Message-ID: Sent from my iPhone On Feb 22, 2010, at 1:42 PM, Rafael Espindola wrote: >> I would rather have WeakRefAttr in the AST, so we model the source >> more closely. Codegen can just handle it the same way as "weak" or >> "alias weak", depending on whether the "alias" attribute is also >> present. >> >> Otherwise, this looks fine to me, but I admit that I don't have a >> solid understanding of weakref. > > It is fuzzy for me too. I am mostly trying to do what llvm-gcc does. > > I have update the patch to add a WeakRefAttr. I have also updated it > to be more strict about what it accepts. It will now reject a weakref > with a missing target. We can add that back if it is actually used. Looks good. I'm AFK at the moment, but could you check that this attribute will be (de-)serialized correctly for PCH before committing? >> - Doug > > Cheers, > -- > Rafael ?vila de Esp?ndola > From kremenek at apple.com Tue Feb 23 15:19:33 2010 From: kremenek at apple.com (Ted Kremenek) Date: Tue, 23 Feb 2010 21:19:33 -0000 Subject: [cfe-commits] r96985 - in /cfe/trunk: lib/Checker/CheckDeadStores.cpp test/Analysis/dead-stores.m Message-ID: <20100223211933.BC6B62A6C12C@llvm.org> Author: kremenek Date: Tue Feb 23 15:19:33 2010 New Revision: 96985 URL: http://llvm.org/viewvc/llvm-project?rev=96985&view=rev Log: Dead emit dead store warnings when assigning nil to an ObjC object pointer (for defensive programming). This matches the behavior with assigning NULL to a regular pointer. Fixes . Modified: cfe/trunk/lib/Checker/CheckDeadStores.cpp cfe/trunk/test/Analysis/dead-stores.m Modified: cfe/trunk/lib/Checker/CheckDeadStores.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/CheckDeadStores.cpp?rev=96985&r1=96984&r2=96985&view=diff ============================================================================== --- cfe/trunk/lib/Checker/CheckDeadStores.cpp (original) +++ cfe/trunk/lib/Checker/CheckDeadStores.cpp Tue Feb 23 15:19:33 2010 @@ -142,7 +142,8 @@ if (VarDecl *VD = dyn_cast(DR->getDecl())) { // Special case: check for assigning null to a pointer. // This is a common form of defensive programming. - if (VD->getType()->isPointerType()) { + QualType T = VD->getType(); + if (T->isPointerType() || T->isObjCObjectPointerType()) { if (B->getRHS()->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNull)) return; Modified: cfe/trunk/test/Analysis/dead-stores.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/dead-stores.m?rev=96985&r1=96984&r2=96985&view=diff ============================================================================== --- cfe/trunk/test/Analysis/dead-stores.m (original) +++ cfe/trunk/test/Analysis/dead-stores.m Tue Feb 23 15:19:33 2010 @@ -34,3 +34,10 @@ ([keys containsObject:@"name"] && [keys containsObject:@"icon"])) {} } +// This test case was a false positive due to how clang models +// pointer types and ObjC object pointer types differently. Here +// we don't warn about a dead store because 'nil' is assigned to +// an object pointer for the sake of defensive programming. +void rdar_7631278(NSObject *x) { + x = ((void*)0); +} From fjahanian at apple.com Tue Feb 23 15:34:38 2010 From: fjahanian at apple.com (Fariborz Jahanian) Date: Tue, 23 Feb 2010 21:34:38 -0000 Subject: [cfe-commits] r96987 - in /cfe/trunk: lib/Frontend/RewriteObjC.cpp test/Rewriter/rewrite-qualified-id.mm Message-ID: <20100223213438.BA01D2A6C12C@llvm.org> Author: fjahanian Date: Tue Feb 23 15:34:38 2010 New Revision: 96987 URL: http://llvm.org/viewvc/llvm-project?rev=96987&view=rev Log: Fixes a rewriting of qualified-id type which exposed a bigger rewriting problem. Fixes radar 7680953. Added: cfe/trunk/test/Rewriter/rewrite-qualified-id.mm Modified: cfe/trunk/lib/Frontend/RewriteObjC.cpp Modified: cfe/trunk/lib/Frontend/RewriteObjC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/RewriteObjC.cpp?rev=96987&r1=96986&r2=96987&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/RewriteObjC.cpp (original) +++ cfe/trunk/lib/Frontend/RewriteObjC.cpp Tue Feb 23 15:34:38 2010 @@ -5358,11 +5358,6 @@ RewriteBlockPointerDecl(TD); else if (TD->getUnderlyingType()->isFunctionPointerType()) CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); - else if (TD->getUnderlyingType()->isRecordType()) { - RecordDecl *RD = TD->getUnderlyingType()->getAs()->getDecl(); - if (RD->isDefinition()) - RewriteRecordBody(RD); - } return; } if (RecordDecl *RD = dyn_cast(D)) { Added: cfe/trunk/test/Rewriter/rewrite-qualified-id.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Rewriter/rewrite-qualified-id.mm?rev=96987&view=auto ============================================================================== --- cfe/trunk/test/Rewriter/rewrite-qualified-id.mm (added) +++ cfe/trunk/test/Rewriter/rewrite-qualified-id.mm Tue Feb 23 15:34:38 2010 @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// radar 7680953 + +typedef void * id; + + at protocol foo + at end + + at interface CL +{ + id changeSource; + CL * changeSource1; +} + at end + +typedef struct x +{ + id changeSource; +} x; + From blaine at apple.com Tue Feb 23 15:51:17 2010 From: blaine at apple.com (Blaine Garst) Date: Tue, 23 Feb 2010 21:51:17 -0000 Subject: [cfe-commits] r96989 - in /cfe/trunk: include/clang/Basic/LangOptions.h include/clang/Driver/Options.td lib/CodeGen/CGBlocks.cpp lib/CodeGen/CGBlocks.h lib/CodeGen/CodeGenFunction.h lib/Driver/Tools.cpp test/CodeGen/blocksignature.c Message-ID: <20100223215117.ADBB12A6C12C@llvm.org> Author: blaine Date: Tue Feb 23 15:51:17 2010 New Revision: 96989 URL: http://llvm.org/viewvc/llvm-project?rev=96989&view=rev Log: Unconditionally support block introspection data in a new field at the end of the block descriptor field. This field is the ObjC style @encode signature of the implementation function, and was to this point conditionally provided in the block literal data structure. That provisional support is removed. Additionally, eliminate unused enumerations for the block literal flags field. The first shipping ABI unconditionally set (1<<29) but this bit is unused by the runtime, so the second ABI will unconditionally have (1<<30) set so that the runtime can in fact distinguish whether the additional data is present or not. Added: cfe/trunk/test/CodeGen/blocksignature.c Modified: cfe/trunk/include/clang/Basic/LangOptions.h cfe/trunk/include/clang/Driver/Options.td cfe/trunk/lib/CodeGen/CGBlocks.cpp cfe/trunk/lib/CodeGen/CGBlocks.h cfe/trunk/lib/CodeGen/CodeGenFunction.h cfe/trunk/lib/Driver/Tools.cpp Modified: cfe/trunk/include/clang/Basic/LangOptions.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.h?rev=96989&r1=96988&r2=96989&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/LangOptions.h (original) +++ cfe/trunk/include/clang/Basic/LangOptions.h Tue Feb 23 15:51:17 2010 @@ -59,7 +59,6 @@ unsigned POSIXThreads : 1; // Compiling with POSIX thread support // (-pthread) unsigned Blocks : 1; // block extension to C - unsigned BlockIntrospection: 1; // block have ObjC type encodings. unsigned EmitAllDecls : 1; // Emit all declarations, even if // they are unused. unsigned MathErrno : 1; // Math functions must respect errno @@ -143,7 +142,6 @@ ThreadsafeStatics = 1; POSIXThreads = 0; Blocks = 0; - BlockIntrospection = 0; EmitAllDecls = 0; MathErrno = 1; Modified: cfe/trunk/include/clang/Driver/Options.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Options.td?rev=96989&r1=96988&r2=96989&view=diff ============================================================================== --- cfe/trunk/include/clang/Driver/Options.td (original) +++ cfe/trunk/include/clang/Driver/Options.td Tue Feb 23 15:51:17 2010 @@ -235,7 +235,6 @@ def fastf : Flag<"-fastf">, Group; def fast : Flag<"-fast">, Group; def fasynchronous_unwind_tables : Flag<"-fasynchronous-unwind-tables">, Group; -def fblock_introspection : Flag<"-fblock-introspection">, Group; def fblocks : Flag<"-fblocks">, Group; def fbootclasspath_EQ : Joined<"-fbootclasspath=">, Group; def fbuiltin_strcat : Flag<"-fbuiltin-strcat">, Group; Modified: cfe/trunk/lib/CodeGen/CGBlocks.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBlocks.cpp?rev=96989&r1=96988&r2=96989&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGBlocks.cpp (original) +++ cfe/trunk/lib/CodeGen/CGBlocks.cpp Tue Feb 23 15:51:17 2010 @@ -24,7 +24,7 @@ using namespace CodeGen; llvm::Constant *CodeGenFunction:: -BuildDescriptorBlockDecl(bool BlockHasCopyDispose, CharUnits Size, +BuildDescriptorBlockDecl(const BlockExpr *BE, bool BlockHasCopyDispose, CharUnits Size, const llvm::StructType* Ty, std::vector *NoteForHelper) { const llvm::Type *UnsignedLongTy @@ -43,6 +43,7 @@ C = llvm::ConstantInt::get(UnsignedLongTy, Size.getQuantity()); Elts.push_back(C); + // optional copy/dispose helpers if (BlockHasCopyDispose) { // copy_func_helper_decl Elts.push_back(BuildCopyHelper(Ty, NoteForHelper)); @@ -51,6 +52,17 @@ Elts.push_back(BuildDestroyHelper(Ty, NoteForHelper)); } + // Signature. non-optional ObjC-style method descriptor @encode sequence + std::string BlockTypeEncoding; + CGM.getContext().getObjCEncodingForBlock(BE, BlockTypeEncoding); + + Elts.push_back(llvm::ConstantExpr::getBitCast( + CGM.GetAddrOfConstantCString(BlockTypeEncoding), PtrToInt8Ty)); + + // Layout. + C = llvm::ConstantInt::get(UnsignedLongTy, 0); + Elts.push_back(C); + C = llvm::ConstantStruct::get(VMContext, Elts, false); C = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, @@ -135,30 +147,14 @@ size_t BlockFields = 5; - bool hasIntrospection = CGM.getContext().getLangOptions().BlockIntrospection; - - if (hasIntrospection) { - BlockFields++; - } std::vector Elts(BlockFields); - if (hasIntrospection) { - std::string BlockTypeEncoding; - CGM.getContext().getObjCEncodingForBlock(BE, BlockTypeEncoding); - - Elts[5] = llvm::ConstantExpr::getBitCast( - CGM.GetAddrOfConstantCString(BlockTypeEncoding), PtrToInt8Ty); - } - llvm::Constant *C; llvm::Value *V; { // C = BuildBlockStructInitlist(); - unsigned int flags = BLOCK_HAS_DESCRIPTOR; - - if (hasIntrospection) - flags |= BLOCK_HAS_OBJC_TYPE; + unsigned int flags = BLOCK_HAS_OBJC_TYPE; // We run this first so that we set BlockHasCopyDispose from the entire // block literal. @@ -199,7 +195,7 @@ if (subBlockDeclRefDecls.size() == 0) { // __descriptor - Elts[4] = BuildDescriptorBlockDecl(subBlockHasCopyDispose, subBlockSize, + Elts[4] = BuildDescriptorBlockDecl(BE, subBlockHasCopyDispose, subBlockSize, 0, 0); // Optimize to being a global block. @@ -221,8 +217,6 @@ for (int i=0; i<4; ++i) Types[i] = Elts[i]->getType(); Types[4] = PtrToInt8Ty; - if (hasIntrospection) - Types[5] = PtrToInt8Ty; for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i) { const Expr *E = subBlockDeclRefDecls[i]; @@ -245,8 +239,6 @@ for (unsigned i=0; i<4; ++i) Builder.CreateStore(Elts[i], Builder.CreateStructGEP(V, i, "block.tmp")); - if (hasIntrospection) - Builder.CreateStore(Elts[5], Builder.CreateStructGEP(V, 5, "block.tmp")); for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i) { @@ -335,7 +327,8 @@ NoteForHelper.resize(helpersize); // __descriptor - llvm::Value *Descriptor = BuildDescriptorBlockDecl(subBlockHasCopyDispose, + llvm::Value *Descriptor = BuildDescriptorBlockDecl(BE, + subBlockHasCopyDispose, subBlockSize, Ty, &NoteForHelper); Descriptor = Builder.CreateBitCast(Descriptor, PtrToInt8Ty); @@ -371,6 +364,16 @@ // struct __block_descriptor { // unsigned long reserved; // unsigned long block_size; + // + // // later, the following will be added + // + // struct { + // void (*copyHelper)(); + // void (*copyHelper)(); + // } helpers; // !!! optional + // + // const char *signature; // the block signature + // const char *layout; // reserved // }; BlockDescriptorType = llvm::StructType::get(UnsignedLongTy->getContext(), UnsignedLongTy, @@ -399,20 +402,8 @@ // int __reserved; // void (*__invoke)(void *); // struct __block_descriptor *__descriptor; - // // GNU runtime only: - // const char *types; // }; - if (CGM.getContext().getLangOptions().BlockIntrospection) - GenericBlockLiteralType = llvm::StructType::get(IntTy->getContext(), - PtrToInt8Ty, - IntTy, - IntTy, - PtrToInt8Ty, - BlockDescPtrTy, - PtrToInt8Ty, - NULL); - else - GenericBlockLiteralType = llvm::StructType::get(IntTy->getContext(), + GenericBlockLiteralType = llvm::StructType::get(IntTy->getContext(), PtrToInt8Ty, IntTy, IntTy, @@ -556,7 +547,7 @@ const llvm::IntegerType *IntTy = cast( getTypes().ConvertType(getContext().IntTy)); - llvm::Constant *DescriptorFields[2]; + llvm::Constant *DescriptorFields[4]; // Reserved DescriptorFields[0] = llvm::Constant::getNullValue(UnsignedLongTy); @@ -567,9 +558,21 @@ CGM.GetTargetTypeStoreSize(getGenericBlockLiteralType()); DescriptorFields[1] = llvm::ConstantInt::get(UnsignedLongTy,BlockLiteralSize.getQuantity()); + + // signature. non-optional ObjC-style method descriptor @encode sequence + std::string BlockTypeEncoding; + CGM.getContext().getObjCEncodingForBlock(BE, BlockTypeEncoding); + + DescriptorFields[2] = llvm::ConstantExpr::getBitCast( + CGM.GetAddrOfConstantCString(BlockTypeEncoding), PtrToInt8Ty); + + // layout + DescriptorFields[3] = + llvm::ConstantInt::get(UnsignedLongTy,0); + // build the structure from the 4 elements llvm::Constant *DescriptorStruct = - llvm::ConstantStruct::get(VMContext, &DescriptorFields[0], 2, false); + llvm::ConstantStruct::get(VMContext, &DescriptorFields[0], 4, false); llvm::GlobalVariable *Descriptor = new llvm::GlobalVariable(getModule(), DescriptorStruct->getType(), true, @@ -578,8 +581,6 @@ int FieldCount = 5; // Generate the constants for the block literal. - if (CGM.getContext().getLangOptions().BlockIntrospection) - FieldCount = 6; std::vector LiteralFields(FieldCount); @@ -602,10 +603,8 @@ LiteralFields[0] = getNSConcreteGlobalBlock(); // Flags - LiteralFields[1] = CGM.getContext().getLangOptions().BlockIntrospection ? - llvm::ConstantInt::get(IntTy, BLOCK_IS_GLOBAL | BLOCK_HAS_DESCRIPTOR | - BLOCK_HAS_OBJC_TYPE) : - llvm::ConstantInt::get(IntTy, BLOCK_IS_GLOBAL | BLOCK_HAS_DESCRIPTOR); + LiteralFields[1] = + llvm::ConstantInt::get(IntTy, BLOCK_IS_GLOBAL | BLOCK_HAS_OBJC_TYPE); // Reserved LiteralFields[2] = llvm::Constant::getNullValue(IntTy); @@ -616,14 +615,6 @@ // Descriptor LiteralFields[4] = Descriptor; - // Type encoding - if (CGM.getContext().getLangOptions().BlockIntrospection) { - std::string BlockTypeEncoding; - CGM.getContext().getObjCEncodingForBlock(BE, BlockTypeEncoding); - - LiteralFields[5] = CGM.GetAddrOfConstantCString(BlockTypeEncoding); - } - llvm::Constant *BlockLiteralStruct = llvm::ConstantStruct::get(VMContext, LiteralFields, false); Modified: cfe/trunk/lib/CodeGen/CGBlocks.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBlocks.h?rev=96989&r1=96988&r2=96989&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGBlocks.h (original) +++ cfe/trunk/lib/CodeGen/CGBlocks.h Tue Feb 23 15:51:17 2010 @@ -54,7 +54,6 @@ BLOCK_HAS_COPY_DISPOSE = (1 << 25), BLOCK_HAS_CXX_OBJ = (1 << 26), BLOCK_IS_GLOBAL = (1 << 28), - BLOCK_HAS_DESCRIPTOR = (1 << 29), BLOCK_HAS_OBJC_TYPE = (1 << 30) }; }; Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=96989&r1=96988&r2=96989&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original) +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Tue Feb 23 15:51:17 2010 @@ -465,7 +465,8 @@ //===--------------------------------------------------------------------===// llvm::Value *BuildBlockLiteralTmp(const BlockExpr *); - llvm::Constant *BuildDescriptorBlockDecl(bool BlockHasCopyDispose, + llvm::Constant *BuildDescriptorBlockDecl(const BlockExpr *, + bool BlockHasCopyDispose, CharUnits Size, const llvm::StructType *, std::vector *); Modified: cfe/trunk/lib/Driver/Tools.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=96989&r1=96988&r2=96989&view=diff ============================================================================== --- cfe/trunk/lib/Driver/Tools.cpp (original) +++ cfe/trunk/lib/Driver/Tools.cpp Tue Feb 23 15:51:17 2010 @@ -1011,7 +1011,6 @@ // -fblocks=0 is default. if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks, getToolChain().IsBlocksDefault())) { - Args.AddLastArg(CmdArgs, options::OPT_fblock_introspection); CmdArgs.push_back("-fblocks"); } Added: cfe/trunk/test/CodeGen/blocksignature.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/blocksignature.c?rev=96989&view=auto ============================================================================== --- cfe/trunk/test/CodeGen/blocksignature.c (added) +++ cfe/trunk/test/CodeGen/blocksignature.c Tue Feb 23 15:51:17 2010 @@ -0,0 +1,94 @@ +// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin9 %s -emit-llvm -o - | FileCheck %s -check-prefix=X64 +// RUN: %clang_cc1 -fblocks -triple i686-apple-darwin9 %s -emit-llvm -o - | FileCheck %s -check-prefix=X32 + +// X64: @.str = private constant [6 x i8] c"v8@?0\00" +// X64: @__block_literal_global = internal constant %1 { i8** @_NSConcreteGlobalBlock, i32 1342177280, +// X64: @.str1 = private constant [12 x i8] c"i16@?0c8f12\00" +// X64: store i32 1073741824, i32* %block.tmp2 + +// X32: @.str = private constant [6 x i8] c"v4@?0\00" +// X32: @__block_literal_global = internal constant %1 { i8** @_NSConcreteGlobalBlock, i32 1342177280, +// X32: @.str1 = private constant [11 x i8] c"i12@?0c4f8\00" +// X32: store i32 1073741824, i32* %block.tmp2 + +// rdar://7635294 + + +int globalInt; +void (^global)(void) = ^{ ++globalInt; }; + + +void foo(int param) { + extern int rand(void); + extern void rand_r(int (^b)(char x, float y)); // name a function present at runtime + while (param--) + rand_r(^(char x, float y){ return x + (int)y + param + rand(); }); // generate a local block binding param +} + +#if 0 +#include +enum { + BLOCK_HAS_COPY_DISPOSE = (1 << 25), + BLOCK_HAS_CXX_OBJ = (1 << 26), + BLOCK_IS_GLOBAL = (1 << 28), + BLOCK_HAS_DESCRIPTOR = (1 << 29), + BLOCK_HAS_OBJC_TYPE = (1 << 30) +}; + +struct block_descriptor_big { + unsigned long int reserved; + unsigned long int size; + void (*copy)(void *dst, void *src); // conditional on BLOCK_HAS_COPY_DISPOSE + void (*dispose)(void *); // conditional on BLOCK_HAS_COPY_DISPOSE + const char *signature; // conditional on BLOCK_HAS_OBJC + const char *layout; // conditional on BLOCK_HAS_OBJC +}; +struct block_descriptor_small { + unsigned long int reserved; + unsigned long int size; + const char *signature; // conditional on BLOCK_HAS_OBJC + const char *layout; // conditional on BLOCK_HAS_OBJC +}; + +struct block_layout_abi { // can't change + void *isa; + int flags; + int reserved; + void (*invoke)(void *, ...); + struct block_descriptor_big *descriptor; +}; + +const char *getBlockSignature(void *block) { + struct block_layout_abi *layout = (struct block_layout_abi *)block; + if ((layout->flags & BLOCK_HAS_OBJC_TYPE) != BLOCK_HAS_OBJC_TYPE) return NULL; + if (layout->flags & BLOCK_HAS_COPY_DISPOSE) + return layout->descriptor->signature; + else + return ((struct block_descriptor_small *)layout->descriptor)->signature; +} + + + +int main(int argc, char *argv[]) { + printf("desired global flags: %d\n", BLOCK_IS_GLOBAL | BLOCK_HAS_OBJC_TYPE); + printf("desired stack flags: %d\n", BLOCK_HAS_OBJC_TYPE); + + printf("types for global: %s\n", getBlockSignature(global)); + printf("types for local: %s\n", getBlockSignature(^int(char x, float y) { return (int)(y + x); })); + return 0; +} + +/* +x86_64 +desired global flags: 1342177280 +desired stack flags: 1073741824 +types for global: v8@?0 +types for local: i16@?0c8f12 + +i386 +desired global flags: 1342177280 +desired stack flags: 1073741824 +types for global: v4@?0 +types for local: i12@?0c4f8 +*/ +#endif From rafael.espindola at gmail.com Tue Feb 23 16:00:30 2010 From: rafael.espindola at gmail.com (Rafael Espindola) Date: Tue, 23 Feb 2010 22:00:30 -0000 Subject: [cfe-commits] r96992 - in /cfe/trunk: include/clang/AST/Attr.h include/clang/Basic/DiagnosticSemaKinds.td include/clang/Parse/AttributeList.h lib/AST/AttrImpl.cpp lib/CodeGen/CodeGenModule.cpp lib/Frontend/PCHReaderDecl.cpp lib/Frontend/PCHWriter.cpp lib/Parse/AttributeList.cpp lib/Sema/SemaDeclAttr.cpp test/CodeGen/attributes.c test/SemaCXX/attr-weakref.cpp Message-ID: <20100223220030.695612A6C12C@llvm.org> Author: rafael Date: Tue Feb 23 16:00:30 2010 New Revision: 96992 URL: http://llvm.org/viewvc/llvm-project?rev=96992&view=rev Log: Add support for the weakref attribute. We still produce "alias weak" as llvm-gcc does, but are more strict on what uses of weakref we accept. Added: cfe/trunk/test/SemaCXX/attr-weakref.cpp Modified: cfe/trunk/include/clang/AST/Attr.h cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Parse/AttributeList.h cfe/trunk/lib/AST/AttrImpl.cpp cfe/trunk/lib/CodeGen/CodeGenModule.cpp cfe/trunk/lib/Frontend/PCHReaderDecl.cpp cfe/trunk/lib/Frontend/PCHWriter.cpp cfe/trunk/lib/Parse/AttributeList.cpp cfe/trunk/lib/Sema/SemaDeclAttr.cpp cfe/trunk/test/CodeGen/attributes.c Modified: cfe/trunk/include/clang/AST/Attr.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Attr.h?rev=96992&r1=96991&r2=96992&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Attr.h (original) +++ cfe/trunk/include/clang/AST/Attr.h Tue Feb 23 16:00:30 2010 @@ -94,6 +94,7 @@ WarnUnusedResult, Weak, WeakImport, + WeakRef, FIRST_TARGET_ATTRIBUTE, DLLExport, @@ -357,6 +358,7 @@ DEF_SIMPLE_ATTR(Used); DEF_SIMPLE_ATTR(Weak); DEF_SIMPLE_ATTR(WeakImport); +DEF_SIMPLE_ATTR(WeakRef); DEF_SIMPLE_ATTR(NoThrow); DEF_SIMPLE_ATTR(Const); DEF_SIMPLE_ATTR(Pure); Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=96992&r1=96991&r2=96992&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Feb 23 16:00:30 2010 @@ -747,6 +747,12 @@ "weak declaration of '%0' must be public">; def warn_attribute_weak_import_invalid_on_definition : Warning< "'weak_import' attribute cannot be specified on a definition">; +def err_attribute_weakref_not_static : Error< + "weakref declaration of '%0' must be static">; +def err_attribute_weakref_not_global_context : Error< + "weakref declaration of '%0' must be in a global context">; +def err_attribute_weakref_without_alias : Error< + "weakref declaration of '%0' must also have an alias attribute">; def warn_attribute_wrong_decl_type : Warning< "%0 attribute only applies to %select{function|union|" "variable and function|function or method|parameter|" Modified: cfe/trunk/include/clang/Parse/AttributeList.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/AttributeList.h?rev=96992&r1=96991&r2=96992&view=diff ============================================================================== --- cfe/trunk/include/clang/Parse/AttributeList.h (original) +++ cfe/trunk/include/clang/Parse/AttributeList.h Tue Feb 23 16:00:30 2010 @@ -109,6 +109,7 @@ AT_visibility, AT_warn_unused_result, AT_weak, + AT_weakref, AT_weak_import, AT_reqd_wg_size, IgnoredAttribute, Modified: cfe/trunk/lib/AST/AttrImpl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/AttrImpl.cpp?rev=96992&r1=96991&r2=96992&view=diff ============================================================================== --- cfe/trunk/lib/AST/AttrImpl.cpp (original) +++ cfe/trunk/lib/AST/AttrImpl.cpp Tue Feb 23 16:00:30 2010 @@ -107,6 +107,7 @@ DEF_SIMPLE_ATTR_CLONE(WarnUnusedResult) DEF_SIMPLE_ATTR_CLONE(Weak) DEF_SIMPLE_ATTR_CLONE(WeakImport) +DEF_SIMPLE_ATTR_CLONE(WeakRef) DEF_SIMPLE_ATTR_CLONE(X86ForceAlignArgPointer) Attr* PragmaPackAttr::clone(ASTContext &C) const { @@ -196,5 +197,3 @@ Attr *MSP430InterruptAttr::clone(ASTContext &C) const { return ::new (C) MSP430InterruptAttr(Number); } - - Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=96992&r1=96991&r2=96992&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Tue Feb 23 16:00:30 2010 @@ -1327,6 +1327,7 @@ GA->setLinkage(llvm::Function::DLLExportLinkage); } } else if (D->hasAttr() || + D->hasAttr() || D->hasAttr()) { GA->setLinkage(llvm::Function::WeakAnyLinkage); } Modified: cfe/trunk/lib/Frontend/PCHReaderDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReaderDecl.cpp?rev=96992&r1=96991&r2=96992&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/PCHReaderDecl.cpp (original) +++ cfe/trunk/lib/Frontend/PCHReaderDecl.cpp Tue Feb 23 16:00:30 2010 @@ -586,6 +586,7 @@ SIMPLE_ATTR(WarnUnusedResult); SIMPLE_ATTR(Weak); + SIMPLE_ATTR(WeakRef); SIMPLE_ATTR(WeakImport); } Modified: cfe/trunk/lib/Frontend/PCHWriter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriter.cpp?rev=96992&r1=96991&r2=96992&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/PCHWriter.cpp (original) +++ cfe/trunk/lib/Frontend/PCHWriter.cpp Tue Feb 23 16:00:30 2010 @@ -1916,6 +1916,7 @@ case Attr::WarnUnusedResult: case Attr::Weak: + case Attr::WeakRef: case Attr::WeakImport: break; } @@ -2335,4 +2336,3 @@ break; } } - Modified: cfe/trunk/lib/Parse/AttributeList.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/AttributeList.cpp?rev=96992&r1=96991&r2=96992&view=diff ============================================================================== --- cfe/trunk/lib/Parse/AttributeList.cpp (original) +++ cfe/trunk/lib/Parse/AttributeList.cpp Tue Feb 23 16:00:30 2010 @@ -57,6 +57,7 @@ // FIXME: Hand generating this is neither smart nor efficient. return llvm::StringSwitch(AttrName) .Case("weak", AT_weak) + .Case("weakref", AT_weakref) .Case("pure", AT_pure) .Case("mode", AT_mode) .Case("used", AT_used) Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=96992&r1=96991&r2=96992&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Tue Feb 23 16:00:30 2010 @@ -329,6 +329,86 @@ d->addAttr(::new (S.Context) NonNullAttr(S.Context, start, size)); } +static bool isStaticVarOrStaticFunciton(Decl *D) { + if (VarDecl *VD = dyn_cast(D)) + return VD->getStorageClass() == VarDecl::Static; + if (FunctionDecl *FD = dyn_cast(D)) + return FD->getStorageClass() == FunctionDecl::Static; + return false; +} + +static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) { + // Check the attribute arguments. + if (Attr.getNumArgs() > 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + + // gcc rejects + // class c { + // static int a __attribute__((weakref ("v2"))); + // static int b() __attribute__((weakref ("f3"))); + // }; + // and ignores the attributes of + // void f(void) { + // static int a __attribute__((weakref ("v2"))); + // } + // we reject them + if (const DeclContext *Ctx = d->getDeclContext()) { + Ctx = Ctx->getLookupContext(); + if (!isa(Ctx) && !isa(Ctx) ) { + S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_global_context) << + dyn_cast(d)->getNameAsString(); + return; + } + } + + // The GCC manual says + // + // At present, a declaration to which `weakref' is attached can only + // be `static'. + // + // It also says + // + // Without a TARGET, + // given as an argument to `weakref' or to `alias', `weakref' is + // equivalent to `weak'. + // + // gcc 4.4.1 will accept + // int a7 __attribute__((weakref)); + // as + // int a7 __attribute__((weak)); + // This looks like a bug in gcc. We reject that for now. We should revisit + // it if this behaviour is actually used. + + if (!isStaticVarOrStaticFunciton(d)) { + S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_static) << + dyn_cast(d)->getNameAsString(); + return; + } + + // GCC rejects + // static ((alias ("y"), weakref)). + // Should we? How to check that weakref is before or after alias? + + if (Attr.getNumArgs() == 1) { + Expr *Arg = static_cast(Attr.getArg(0)); + Arg = Arg->IgnoreParenCasts(); + StringLiteral *Str = dyn_cast(Arg); + + if (Str == 0 || Str->isWide()) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) + << "weakref" << 1; + return; + } + // GCC will accept anything as the argument of weakref. Should we + // check for an existing decl? + d->addAttr(::new (S.Context) AliasAttr(S.Context, Str->getString())); + } + + d->addAttr(::new (S.Context) WeakRefAttr()); +} + static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() != 1) { @@ -777,13 +857,7 @@ } /* weak only applies to non-static declarations */ - bool isStatic = false; - if (VarDecl *VD = dyn_cast(D)) { - isStatic = VD->getStorageClass() == VarDecl::Static; - } else if (FunctionDecl *FD = dyn_cast(D)) { - isStatic = FD->getStorageClass() == FunctionDecl::Static; - } - if (isStatic) { + if (isStaticVarOrStaticFunciton(D)) { S.Diag(Attr.getLoc(), diag::err_attribute_weak_static) << dyn_cast(D)->getNameAsString(); return; @@ -1809,6 +1883,7 @@ case AttributeList::AT_warn_unused_result: HandleWarnUnusedResult(D,Attr,S); break; case AttributeList::AT_weak: HandleWeakAttr (D, Attr, S); break; + case AttributeList::AT_weakref: HandleWeakRefAttr (D, Attr, S); break; case AttributeList::AT_weak_import: HandleWeakImportAttr (D, Attr, S); break; case AttributeList::AT_transparent_union: HandleTransparentUnionAttr(D, Attr, S); @@ -1847,9 +1922,17 @@ /// ProcessDeclAttributeList - Apply all the decl attributes in the specified /// attribute list to the specified decl, ignoring any type attributes. void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AttrList) { - while (AttrList) { - ProcessDeclAttribute(S, D, *AttrList, *this); - AttrList = AttrList->getNext(); + for (const AttributeList* l = AttrList; l; l = l->getNext()) { + ProcessDeclAttribute(S, D, *l, *this); + } + + // GCC accepts + // static int a9 __attribute__((weakref)); + // but that looks really pointless. We reject it. + if (D->hasAttr() && !D->hasAttr()) { + Diag(AttrList->getLoc(), diag::err_attribute_weakref_without_alias) << + dyn_cast(D)->getNameAsString(); + return; } } Modified: cfe/trunk/test/CodeGen/attributes.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/attributes.c?rev=96992&r1=96991&r2=96992&view=diff ============================================================================== --- cfe/trunk/test/CodeGen/attributes.c (original) +++ cfe/trunk/test/CodeGen/attributes.c Tue Feb 23 16:00:30 2010 @@ -30,6 +30,12 @@ void __t8() {} void t9() __attribute__((weak, alias("__t8"))); +static void t22(void) __attribute__((weakref("t8"))); +// CHECK: @t22 = alias weak void ()* @t8 + +static void t23(void) __attribute__((weakref, alias("t8"))); +// CHECK: @t23 = alias weak void ()* @t8 + // CHECK: declare extern_weak i32 @t15() int __attribute__((weak_import)) t15(void); int t17() { Added: cfe/trunk/test/SemaCXX/attr-weakref.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-weakref.cpp?rev=96992&view=auto ============================================================================== --- cfe/trunk/test/SemaCXX/attr-weakref.cpp (added) +++ cfe/trunk/test/SemaCXX/attr-weakref.cpp Tue Feb 23 16:00:30 2010 @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// GCC will accept anything as the argument of weakref. Should we +// check for an existing decl? +static int a1() __attribute__((weakref ("foo"))); +static int a2() __attribute__((weakref, alias ("foo"))); + +static int a3 __attribute__((weakref ("foo"))); +static int a4 __attribute__((weakref, alias ("foo"))); + +// gcc rejects, clang accepts +static int a5 __attribute__((alias ("foo"), weakref)); + +// this is pointless, but accepted by gcc. We reject it. +static int a6 __attribute__((weakref)); //expected-error {{weakref declaration of 'a6' must also have an alias attribute}} + +// gcc warns, clang rejects +void f(void) { + static int a __attribute__((weakref ("v2"))); // expected-error {{declaration of 'a' must be in a global context}} +} + +// both gcc and clang reject +class c { + static int a __attribute__((weakref ("v2"))); // expected-error {{declaration of 'a' must be in a global context}} + static int b() __attribute__((weakref ("f3"))); // expected-error {{declaration of 'b' must be in a global context}} +}; +int a7() __attribute__((weakref ("f1"))); // expected-error {{declaration of 'a7' must be static}} +int a8 __attribute__((weakref ("v1"))); // expected-error {{declaration of 'a8' must be static}} + +// gcc accepts this +int a9 __attribute__((weakref)); // expected-error {{declaration of 'a9' must be static}} From blaine at apple.com Tue Feb 23 16:59:01 2010 From: blaine at apple.com (Blaine Garst) Date: Tue, 23 Feb 2010 22:59:01 -0000 Subject: [cfe-commits] r96998 - /cfe/trunk/test/CodeGen/blocksignature.c Message-ID: <20100223225901.3F2BA2A6C12E@llvm.org> Author: blaine Date: Tue Feb 23 16:59:01 2010 New Revision: 96998 URL: http://llvm.org/viewvc/llvm-project?rev=96998&view=rev Log: fix buildbot failure on windows by slightly trimming test output to ignore temporary name Modified: cfe/trunk/test/CodeGen/blocksignature.c Modified: cfe/trunk/test/CodeGen/blocksignature.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/blocksignature.c?rev=96998&r1=96997&r2=96998&view=diff ============================================================================== --- cfe/trunk/test/CodeGen/blocksignature.c (original) +++ cfe/trunk/test/CodeGen/blocksignature.c Tue Feb 23 16:59:01 2010 @@ -4,12 +4,12 @@ // X64: @.str = private constant [6 x i8] c"v8@?0\00" // X64: @__block_literal_global = internal constant %1 { i8** @_NSConcreteGlobalBlock, i32 1342177280, // X64: @.str1 = private constant [12 x i8] c"i16@?0c8f12\00" -// X64: store i32 1073741824, i32* %block.tmp2 +// X64: store i32 1073741824, i32* // X32: @.str = private constant [6 x i8] c"v4@?0\00" // X32: @__block_literal_global = internal constant %1 { i8** @_NSConcreteGlobalBlock, i32 1342177280, // X32: @.str1 = private constant [11 x i8] c"i12@?0c4f8\00" -// X32: store i32 1073741824, i32* %block.tmp2 +// X32: store i32 1073741824, i32* // rdar://7635294 From dpatel at apple.com Tue Feb 23 16:59:39 2010 From: dpatel at apple.com (Devang Patel) Date: Tue, 23 Feb 2010 22:59:39 -0000 Subject: [cfe-commits] r96999 - in /cfe/trunk: lib/CodeGen/CGDebugInfo.cpp lib/CodeGen/CGDebugInfo.h test/CodeGen/2010-02-18-Dbg-VectorType.c Message-ID: <20100223225939.5C1242A6C12E@llvm.org> Author: dpatel Date: Tue Feb 23 16:59:39 2010 New Revision: 96999 URL: http://llvm.org/viewvc/llvm-project?rev=96999&view=rev Log: Emit debug info for VectorType. Added: cfe/trunk/test/CodeGen/2010-02-18-Dbg-VectorType.c Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp cfe/trunk/lib/CodeGen/CGDebugInfo.h Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.cpp?rev=96999&r1=96998&r2=96999&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGDebugInfo.cpp (original) +++ cfe/trunk/lib/CodeGen/CGDebugInfo.cpp Tue Feb 23 16:59:39 2010 @@ -1034,6 +1034,28 @@ return llvm::DIType(); } +llvm::DIType CGDebugInfo::CreateType(const VectorType *Ty, + llvm::DICompileUnit Unit) { + llvm::DIType ElementTy = getOrCreateType(Ty->getElementType(), Unit); + uint64_t NumElems = Ty->getNumElements(); + if (NumElems > 0) + --NumElems; + llvm::SmallVector Subscripts; + Subscripts.push_back(DebugFactory.GetOrCreateSubrange(0, NumElems)); + + llvm::DIArray SubscriptArray = + DebugFactory.GetOrCreateArray(Subscripts.data(), Subscripts.size()); + + uint64_t Size = CGM.getContext().getTypeSize(Ty); + uint64_t Align = CGM.getContext().getTypeAlign(Ty); + + return + DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_vector_type, + Unit, "", llvm::DICompileUnit(), + 0, Size, Align, 0, 0, + ElementTy, SubscriptArray); +} + llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty, llvm::DICompileUnit Unit) { uint64_t Size; @@ -1214,9 +1236,10 @@ // FIXME: Handle these. case Type::ExtVector: - case Type::Vector: return llvm::DIType(); - + + case Type::Vector: + return CreateType(cast(Ty), Unit); case Type::ObjCObjectPointer: return CreateType(cast(Ty), Unit); case Type::ObjCInterface: Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.h?rev=96999&r1=96998&r2=96999&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGDebugInfo.h (original) +++ cfe/trunk/lib/CodeGen/CGDebugInfo.h Tue Feb 23 16:59:39 2010 @@ -84,6 +84,7 @@ llvm::DIType CreateType(const RecordType *Ty, llvm::DICompileUnit U); llvm::DIType CreateType(const ObjCInterfaceType *Ty, llvm::DICompileUnit U); llvm::DIType CreateType(const EnumType *Ty, llvm::DICompileUnit U); + llvm::DIType CreateType(const VectorType *Ty, llvm::DICompileUnit Unit); llvm::DIType CreateType(const ArrayType *Ty, llvm::DICompileUnit U); llvm::DIType CreateType(const LValueReferenceType *Ty, llvm::DICompileUnit U); llvm::DIType CreateType(const MemberPointerType *Ty, llvm::DICompileUnit U); Added: cfe/trunk/test/CodeGen/2010-02-18-Dbg-VectorType.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/2010-02-18-Dbg-VectorType.c?rev=96999&view=auto ============================================================================== --- cfe/trunk/test/CodeGen/2010-02-18-Dbg-VectorType.c (added) +++ cfe/trunk/test/CodeGen/2010-02-18-Dbg-VectorType.c Tue Feb 23 16:59:39 2010 @@ -0,0 +1,9 @@ +// RUN: %clang -emit-llvm -S -O0 -g %s -o - | grep DW_TAG_typedef | grep float4 +typedef float float4 __attribute__((vector_size(16))); + +int main(){ + volatile float4 x = (float4) { 0.0f, 1.0f, 2.0f, 3.0f }; + x += x; + return 0; +} + From rjmccall at apple.com Tue Feb 23 17:05:06 2010 From: rjmccall at apple.com (John McCall) Date: Tue, 23 Feb 2010 15:05:06 -0800 Subject: [cfe-commits] [PATCH] Don't apply function attributes to the return type In-Reply-To: <4B8431DB.5040605@mymail.mines.edu> References: <4B8431DB.5040605@mymail.mines.edu> Message-ID: On Feb 23, 2010, at 11:51 AM, Charles Davis wrote: > This patch fixes part of PR6408. It teaches clang not to try to apply > function attributes to the return type of a function. GCC never does > this, so neither should we. Is this actually what gcc does? The documentation I've seen suggested that gcc tries to apply a function type attribute in the decl spec to the return type if it's a function pointer, and otherwise tries to apply it to the function itself. But maybe I'm misinterpreting it, or maybe that documentation is incorrect: http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Attribute-Syntax.html#Attribute-Syntax At any rate, please do more investigation. If this is the right thing to do, we'll do it, but until we have a clear idea what on earth gcc is doing here, I'd rather hold off. John. From cdavis at mymail.mines.edu Tue Feb 23 17:40:00 2010 From: cdavis at mymail.mines.edu (Charles Davis) Date: Tue, 23 Feb 2010 16:40:00 -0700 Subject: [cfe-commits] [PATCH] Don't apply function attributes to the return type In-Reply-To: References: <4B8431DB.5040605@mymail.mines.edu> Message-ID: <4B846750.5060507@mymail.mines.edu> John McCall wrote: > Is this actually what gcc does? The documentation I've seen suggested that gcc tries to apply a function type attribute in the decl spec to the return type if it's a function pointer, and otherwise tries to apply it to the function itself. But maybe I'm misinterpreting it, or maybe that documentation is incorrect: > http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Attribute-Syntax.html#Attribute-Syntax > > At any rate, please do more investigation. If this is the right thing to do, we'll do it, but until we have a clear idea what on earth gcc is doing here, I'd rather hold off. I did some experimentation with GCC 4.2. The results are on the page for PR6408. For your convenience, I reiterate them here: - If the return type is a function pointer typedef, GCC does not even attempt to apply the attribute to the return type. So, for example, this: typedef void (*p)(); p __attribute__((stdcall)) f(void); declares a function with the stdcall convention that returns a function pointer instead of a function that returns a pointer to a function with the stdcall convention. These two are equivalent: __attribute__((stdcall)) p f(void); p __attribute__((stdcall)) f(void); In both cases, the stdcall attribute belongs to 'f' instead of 'p'. To understand why this is important, consider this example: typedef void (__attribute__((stdcall)) *p)(); p __attribute__((cdecl)) f(const char *x); GCC correctly interprets this to mean "The function 'f' is a 'cdecl' function... that returns a pointer to a 'stdcall' function." Clang without this patch, on the other hand, thinks that both the 'stdcall' and the 'cdecl' belong to the return type. Since the return type already has 'stdcall', Clang complains. The patch fixes this. - If the return type is a raw function pointer, the attribute belongs to the function itself if it's outside the parentheses and to the return type if it's inside the parentheses. So in this: void __attribute__((cdecl)) (__attribute__((stdcall)) *f(const char *x)); the function itself has the cdecl convention and the return type is a pointer to a function with the stdcall convention. Clang currently has this case backwards, even with this patch, in that the function has the stdcall convention and the return type has the cdecl convention. Chip From fjahanian at apple.com Tue Feb 23 17:41:11 2010 From: fjahanian at apple.com (Fariborz Jahanian) Date: Tue, 23 Feb 2010 23:41:11 -0000 Subject: [cfe-commits] r97002 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclObjC.cpp test/SemaObjC/duplicate-ivar-in-class-extension.m Message-ID: <20100223234111.E380B2A6C12C@llvm.org> Author: fjahanian Date: Tue Feb 23 17:41:11 2010 New Revision: 97002 URL: http://llvm.org/viewvc/llvm-project?rev=97002&view=rev Log: More Sema check for ivars in class continuation. Added: cfe/trunk/test/SemaObjC/duplicate-ivar-in-class-extension.m Modified: cfe/trunk/lib/Sema/Sema.h cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaDeclObjC.cpp Modified: cfe/trunk/lib/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=97002&r1=97001&r2=97002&view=diff ============================================================================== --- cfe/trunk/lib/Sema/Sema.h (original) +++ cfe/trunk/lib/Sema/Sema.h Tue Feb 23 17:41:11 2010 @@ -1440,6 +1440,8 @@ void AtomicPropertySetterGetterRules(ObjCImplDecl* IMPDecl, ObjCContainerDecl* IDecl); + void DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, ObjCInterfaceDecl *SID); + /// MatchTwoMethodDeclarations - Checks if two methods' type match and returns /// true, or false, accordingly. bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=97002&r1=97001&r2=97002&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Feb 23 17:41:11 2010 @@ -5659,21 +5659,8 @@ } // Must enforce the rule that ivars in the base classes may not be // duplicates. - if (ID->getSuperClass()) { - for (ObjCInterfaceDecl::ivar_iterator IVI = ID->ivar_begin(), - IVE = ID->ivar_end(); IVI != IVE; ++IVI) { - ObjCIvarDecl* Ivar = (*IVI); - - if (IdentifierInfo *II = Ivar->getIdentifier()) { - ObjCIvarDecl* prevIvar = - ID->getSuperClass()->lookupInstanceVariable(II); - if (prevIvar) { - Diag(Ivar->getLocation(), diag::err_duplicate_member) << II; - Diag(prevIvar->getLocation(), diag::note_previous_declaration); - } - } - } - } + if (ID->getSuperClass()) + DiagnoseDuplicateIvars(ID, ID->getSuperClass()); } else if (ObjCImplementationDecl *IMPDecl = dyn_cast(EnclosingDecl)) { assert(IMPDecl && "ActOnFields - missing ObjCImplementationDecl"); Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=97002&r1=97001&r2=97002&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Tue Feb 23 17:41:11 2010 @@ -1781,6 +1781,29 @@ } } +/// DiagnoseDuplicateIvars - +/// Check for duplicate ivars in the entire class at the start of +/// @implementation. This becomes necesssary because class extension can +/// add ivars to a class in random order which will not be known until +/// class's @implementation is seen. +void Sema::DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, + ObjCInterfaceDecl *SID) { + for (ObjCInterfaceDecl::ivar_iterator IVI = ID->ivar_begin(), + IVE = ID->ivar_end(); IVI != IVE; ++IVI) { + ObjCIvarDecl* Ivar = (*IVI); + if (Ivar->isInvalidDecl()) + continue; + if (IdentifierInfo *II = Ivar->getIdentifier()) { + ObjCIvarDecl* prevIvar = SID->lookupInstanceVariable(II); + if (prevIvar) { + Diag(Ivar->getLocation(), diag::err_duplicate_member) << II; + Diag(prevIvar->getLocation(), diag::note_previous_declaration); + Ivar->setInvalidDecl(); + } + } + } +} + // Note: For class/category implemenations, allMethods/allProperties is // always null. void Sema::ActOnAtEnd(SourceRange AtEnd, @@ -1892,6 +1915,11 @@ if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) { ImplMethodsVsClassMethods(IC, IDecl); AtomicPropertySetterGetterRules(IC, IDecl); + if (LangOpts.ObjCNonFragileABI2) + while (IDecl->getSuperClass()) { + DiagnoseDuplicateIvars(IDecl, IDecl->getSuperClass()); + IDecl = IDecl->getSuperClass(); + } } } else if (ObjCCategoryImplDecl* CatImplClass = dyn_cast(ClassDecl)) { Added: cfe/trunk/test/SemaObjC/duplicate-ivar-in-class-extension.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/duplicate-ivar-in-class-extension.m?rev=97002&view=auto ============================================================================== --- cfe/trunk/test/SemaObjC/duplicate-ivar-in-class-extension.m (added) +++ cfe/trunk/test/SemaObjC/duplicate-ivar-in-class-extension.m Tue Feb 23 17:41:11 2010 @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi2 -verify %s + + at interface Root @end + + at interface SuperClass : Root +{ + int iSuper; // expected-note {{previous declaration is here}} +} + at end + + at interface SubClass : SuperClass { + int ivar; // expected-error {{duplicate member 'ivar'}} + int another_ivar; // expected-error {{duplicate member 'another_ivar'}} + int iSuper; // expected-error {{duplicate member 'iSuper'}} +} + at end + + at interface SuperClass () { + int ivar; // expected-note {{previous declaration is here}} +} + at end + + at interface Root () { + int another_ivar; // expected-note {{previous declaration is here}} +} + at end + + at implementation SubClass +-(int) method { + return self->ivar; // would be ambiguous if the duplicate ivar were allowed +} + at end From kremenek at apple.com Tue Feb 23 18:05:54 2010 From: kremenek at apple.com (Ted Kremenek) Date: Wed, 24 Feb 2010 00:05:54 -0000 Subject: [cfe-commits] r97005 - in /cfe/trunk: include/clang/Analysis/Analyses/PrintfFormatString.h lib/Analysis/PrintfFormatString.cpp test/Sema/format-strings.c Message-ID: <20100224000554.E344A2A6C12C@llvm.org> Author: kremenek Date: Tue Feb 23 18:05:54 2010 New Revision: 97005 URL: http://llvm.org/viewvc/llvm-project?rev=97005&view=rev Log: Add support for '%C' and '%S' printf conversion specifiers. Modified: cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h cfe/trunk/lib/Analysis/PrintfFormatString.cpp cfe/trunk/test/Sema/format-strings.c Modified: cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h?rev=97005&r1=97004&r2=97005&view=diff ============================================================================== --- cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h (original) +++ cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h Tue Feb 23 18:05:54 2010 @@ -75,11 +75,14 @@ VoidPtrArg, // 'p' OutIntPtrArg, // 'n' PercentArg, // '%' - // Objective-C specific specifiers. + // MacOS X unicode extensions. + CArg, // 'C' + UnicodeStrArg, // 'S' + // Objective-C specific specifiers. ObjCObjArg, // '@' - // GlibC specific specifiers. + // GlibC specific specifiers. PrintErrno, // 'm' - // Specifier ranges. + // Specifier ranges. IntArgBeg = dArg, IntArgEnd = iArg, UIntArgBeg = oArg, Modified: cfe/trunk/lib/Analysis/PrintfFormatString.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/PrintfFormatString.cpp?rev=97005&r1=97004&r2=97005&view=diff ============================================================================== --- cfe/trunk/lib/Analysis/PrintfFormatString.cpp (original) +++ cfe/trunk/lib/Analysis/PrintfFormatString.cpp Tue Feb 23 18:05:54 2010 @@ -214,25 +214,28 @@ default: break; // C99: 7.19.6.1 (section 8). - case 'd': k = ConversionSpecifier::dArg; break; - case 'i': k = ConversionSpecifier::iArg; break; - case 'o': k = ConversionSpecifier::oArg; break; - case 'u': k = ConversionSpecifier::uArg; break; - case 'x': k = ConversionSpecifier::xArg; break; - case 'X': k = ConversionSpecifier::XArg; break; - case 'f': k = ConversionSpecifier::fArg; break; - case 'F': k = ConversionSpecifier::FArg; break; - case 'e': k = ConversionSpecifier::eArg; break; + case '%': k = ConversionSpecifier::PercentArg; break; + case 'A': k = ConversionSpecifier::AArg; break; case 'E': k = ConversionSpecifier::EArg; break; - case 'g': k = ConversionSpecifier::gArg; break; + case 'F': k = ConversionSpecifier::FArg; break; case 'G': k = ConversionSpecifier::GArg; break; + case 'X': k = ConversionSpecifier::XArg; break; case 'a': k = ConversionSpecifier::aArg; break; - case 'A': k = ConversionSpecifier::AArg; break; case 'c': k = ConversionSpecifier::IntAsCharArg; break; - case 's': k = ConversionSpecifier::CStrArg; break; - case 'p': k = ConversionSpecifier::VoidPtrArg; break; + case 'd': k = ConversionSpecifier::dArg; break; + case 'e': k = ConversionSpecifier::eArg; break; + case 'f': k = ConversionSpecifier::fArg; break; + case 'g': k = ConversionSpecifier::gArg; break; + case 'i': k = ConversionSpecifier::iArg; break; case 'n': k = ConversionSpecifier::OutIntPtrArg; break; - case '%': k = ConversionSpecifier::PercentArg; break; + case 'o': k = ConversionSpecifier::oArg; break; + case 'p': k = ConversionSpecifier::VoidPtrArg; break; + case 's': k = ConversionSpecifier::CStrArg; break; + case 'u': k = ConversionSpecifier::uArg; break; + case 'x': k = ConversionSpecifier::xArg; break; + // Mac OS X (unicode) specific + case 'C': k = ConversionSpecifier::CArg; break; + case 'S': k = ConversionSpecifier::UnicodeStrArg; break; // Objective-C. case '@': k = ConversionSpecifier::ObjCObjArg; break; // Glibc specific. @@ -345,8 +348,10 @@ if (!PT) return false; - QualType pointeeTy = PT->getPointeeType(); - return pointeeTy == C.WCharTy; + QualType pointeeTy = + C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType(); + + return pointeeTy == C.getWCharType(); } return false; @@ -359,7 +364,7 @@ if (K == CStrTy) return C.getPointerType(C.CharTy); if (K == WCStrTy) - return C.getPointerType(C.WCharTy); + return C.getPointerType(C.getWCharType()); if (K == ObjCPointerTy) return C.ObjCBuiltinIdTy; @@ -425,11 +430,19 @@ return Ctx.LongDoubleTy; return Ctx.DoubleTy; } - - if (CS.getKind() == ConversionSpecifier::CStrArg) - return ArgTypeResult(LM == AsWideChar ? ArgTypeResult::WCStrTy - : ArgTypeResult::CStrTy); - + + switch (CS.getKind()) { + case ConversionSpecifier::CStrArg: + return ArgTypeResult(LM == AsWideChar ? ArgTypeResult::WCStrTy : ArgTypeResult::CStrTy); + case ConversionSpecifier::UnicodeStrArg: + // FIXME: This appears to be Mac OS X specific. + return ArgTypeResult::WCStrTy; + case ConversionSpecifier::CArg: + return Ctx.WCharTy; + default: + break; + } + // FIXME: Handle other cases. return ArgTypeResult(); } Modified: cfe/trunk/test/Sema/format-strings.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/format-strings.c?rev=97005&r1=97004&r2=97005&view=diff ============================================================================== --- cfe/trunk/test/Sema/format-strings.c (original) +++ cfe/trunk/test/Sema/format-strings.c Tue Feb 23 18:05:54 2010 @@ -204,3 +204,18 @@ // typedef enum { A } int_t; void f0(int_t x) { printf("%d\n", x); } + +// Unicode test cases. These are possibly specific to Mac OS X. If so, they should +// eventually be moved into a separate test. +typedef __WCHAR_TYPE__ wchar_t; + +void test_unicode_conversions(wchar_t *s) { + printf("%S", s); // no-warning + printf("%s", s); // expected-warning{{conversion specifies type 'char *' but the argument has type 'wchar_t *'}} + printf("%C", s[0]); // no-warning + printf("%c", s[0]); + printf("%C", 10); + // FIXME: we report the expected type as 'int*' instead of 'wchar_t*' + printf("%S", "hello"); // expected-warning{{but the argument has type 'char *'}} +} + From rjmccall at apple.com Tue Feb 23 18:18:02 2010 From: rjmccall at apple.com (John McCall) Date: Tue, 23 Feb 2010 16:18:02 -0800 Subject: [cfe-commits] [PATCH] Don't apply function attributes to the return type In-Reply-To: <4B846750.5060507@mymail.mines.edu> References: <4B8431DB.5040605@mymail.mines.edu> <4B846750.5060507@mymail.mines.edu> Message-ID: <8EA879FB-F228-4A8E-9920-F901F4BE56FE@apple.com> On Feb 23, 2010, at 3:40 PM, Charles Davis wrote: > John McCall wrote: >> Is this actually what gcc does? The documentation I've seen suggested that gcc tries to apply a function type attribute in the decl spec to the return type if it's a function pointer, and otherwise tries to apply it to the function itself. But maybe I'm misinterpreting it, or maybe that documentation is incorrect: >> http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Attribute-Syntax.html#Attribute-Syntax >> >> At any rate, please do more investigation. If this is the right thing to do, we'll do it, but until we have a clear idea what on earth gcc is doing here, I'd rather hold off. > I did some experimentation with GCC 4.2. The results are on the page for > PR6408. For your convenience, I reiterate them here: I did read the bug commentary before I posted. My question is whether this behavior is intentional or extensional :). That is, is this an *aspect* of the rule that gcc uses, or merely a *consequence*? In particular, it is quite possible that gcc checks if the innermost declarator is a function (or pointer to function?) and, if so, applying CCs in the declaration-specifiers to that function rather than the type in the type-specifiers. That's distinguishable from "don't apply CCs to the return type" in several ways: typedef void ftype(int); ftype __attribute__((fastcall)) **fpp; // is this accepted? ftype __attribute__((fastcall)) *fpa[10]; // or this? ftype __attribute__((fastcall)) (**fpfpp)(int); // and which function does the attribute affect here? Also, what happens in a declaration group? Does it make the decision separately for each declaration, or is the decision made for the first declaration carried over to subsequent declarations? I accept that the rule I implemented earlier is incorrect; I just want to know what the correct rule is before we start hacking in more things that make individual projects work. John. From fjahanian at apple.com Tue Feb 23 19:25:40 2010 From: fjahanian at apple.com (Fariborz Jahanian) Date: Wed, 24 Feb 2010 01:25:40 -0000 Subject: [cfe-commits] r97008 - in /cfe/trunk: lib/Frontend/RewriteObjC.cpp test/Rewriter/rewrite-block-pointer.mm Message-ID: <20100224012540.565E72A6C12C@llvm.org> Author: fjahanian Date: Tue Feb 23 19:25:40 2010 New Revision: 97008 URL: http://llvm.org/viewvc/llvm-project?rev=97008&view=rev Log: Fix rewriting of a method when return type is a block pointer type. Fixes radar 7682149. Modified: cfe/trunk/lib/Frontend/RewriteObjC.cpp cfe/trunk/test/Rewriter/rewrite-block-pointer.mm Modified: cfe/trunk/lib/Frontend/RewriteObjC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/RewriteObjC.cpp?rev=97008&r1=97007&r2=97008&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/RewriteObjC.cpp (original) +++ cfe/trunk/lib/Frontend/RewriteObjC.cpp Tue Feb 23 19:25:40 2010 @@ -2815,6 +2815,10 @@ } returnType = OMD->getResultType()->isObjCQualifiedIdType() ? Context->getObjCIdType() : OMD->getResultType(); + if (isTopLevelBlockPointerType(returnType)) { + const BlockPointerType *BPT = returnType->getAs(); + returnType = Context->getPointerType(BPT->getPointeeType()); + } } else { returnType = Context->getObjCIdType(); } Modified: cfe/trunk/test/Rewriter/rewrite-block-pointer.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Rewriter/rewrite-block-pointer.mm?rev=97008&r1=97007&r2=97008&view=diff ============================================================================== --- cfe/trunk/test/Rewriter/rewrite-block-pointer.mm (original) +++ cfe/trunk/test/Rewriter/rewrite-block-pointer.mm Tue Feb 23 19:25:40 2010 @@ -3,6 +3,7 @@ // radar 7638400 typedef void * id; +void *sel_registerName(const char *); @interface X @end @@ -33,3 +34,27 @@ void x(void (^block)(void)) { block = ((__typeof(block))_Block_copy((const void *)(block))); } + +// radar 7682149 + at interface Y { + at private + id _private; +} +- (void (^)(void))f; + at end + +typedef void (^void_block_t)(void); + + at interface YY { + void_block_t __completion; +} + at property (copy) void_block_t f; + at end + + at implementation Y +- (void (^)(void))f { + return [_private f]; +} + + at end + From cdavis at mymail.mines.edu Tue Feb 23 19:34:09 2010 From: cdavis at mymail.mines.edu (Charles Davis) Date: Tue, 23 Feb 2010 18:34:09 -0700 Subject: [cfe-commits] [PATCH] Don't apply function attributes to the return type In-Reply-To: <8EA879FB-F228-4A8E-9920-F901F4BE56FE@apple.com> References: <4B8431DB.5040605@mymail.mines.edu> <4B846750.5060507@mymail.mines.edu> <8EA879FB-F228-4A8E-9920-F901F4BE56FE@apple.com> Message-ID: <4B848211.3070304@mymail.mines.edu> John McCall wrote: > On Feb 23, 2010, at 3:40 PM, Charles Davis wrote: >> John McCall wrote: >>> Is this actually what gcc does? The documentation I've seen suggested that gcc tries to apply a function type attribute in the decl spec to the return type if it's a function pointer, and otherwise tries to apply it to the function itself. But maybe I'm misinterpreting it, or maybe that documentation is incorrect: >>> http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Attribute-Syntax.html#Attribute-Syntax >>> >>> At any rate, please do more investigation. If this is the right thing to do, we'll do it, but until we have a clear idea what on earth gcc is doing here, I'd rather hold off. >> I did some experimentation with GCC 4.2. The results are on the page for >> PR6408. For your convenience, I reiterate them here: > > I did read the bug commentary before I posted. My question is whether this behavior is intentional or extensional :). That is, is this an *aspect* of the rule that gcc uses, or merely a *consequence*? > > In particular, it is quite possible that gcc checks if the innermost declarator is a function (or pointer to function?) and, if so, applying CCs in the declaration-specifiers to that function rather than the type in the type-specifiers. That's distinguishable from "don't apply CCs to the return type" in several ways: > > typedef void ftype(int); > ftype __attribute__((fastcall)) **fpp; // is this accepted? > ftype __attribute__((fastcall)) *fpa[10]; // or this? For both tof these, GCC tried to apply it to the pointer (or the array, in the second case). > ftype __attribute__((fastcall)) (**fpfpp)(int); // and which function does the attribute affect here? Neither. For one thing, GCC didn't like that this function returns a function. This probably confused GCC, and so it ended up applying it to the pointer itself (which, of course, fails). Adding an asterisk causes GCC to accept it, but placement of the asterisk was important. If it came before the calling convention attribute, GCC attached it to the return type (which I determined by looking at the generated code for a function of the type to which fpfpp points). If the asterisk came after, GCC once again fails to apply the attribute, but that's because it's trying to apply the attribute to the pointer to a function pointer. It understands functions and function pointers, but not pointers to function pointers. It's interesting how GCC gets this backwards--at least, in my opinion. I would think that it would be the other way around, that if the calling convention comes before the asterisk, it belongs to the return type, and if it comes after, it belongs to the function. My verdict: this is definitely extensional behavior. How do you come up with this stuff? > > Also, what happens in a declaration group? Does it make the decision separately for each declaration, or is the decision made for the first declaration carried over to subsequent declarations? For a function typedef (not a function *pointer* typedef), it depends on where the asterisk is. If the calling convention comes before the asterisk, the attribute applies to the whole group. If it comes after, it only applies to the first one. For function pointer typedefs, it always applies the attribute to the whole group. > > I accept that the rule I implemented earlier is incorrect; I just want to know what the correct rule is before we start hacking in more things that make individual projects work. Good point. Hope this helps. Chip From fjahanian at apple.com Tue Feb 23 19:37:04 2010 From: fjahanian at apple.com (Fariborz Jahanian) Date: Wed, 24 Feb 2010 01:37:04 -0000 Subject: [cfe-commits] r97009 - /cfe/trunk/test/Rewriter/rewrite-block-pointer.mm Message-ID: <20100224013704.582042A6C12C@llvm.org> Author: fjahanian Date: Tue Feb 23 19:37:04 2010 New Revision: 97009 URL: http://llvm.org/viewvc/llvm-project?rev=97009&view=rev Log: Correct radar no. Modified: cfe/trunk/test/Rewriter/rewrite-block-pointer.mm Modified: cfe/trunk/test/Rewriter/rewrite-block-pointer.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Rewriter/rewrite-block-pointer.mm?rev=97009&r1=97008&r2=97009&view=diff ============================================================================== --- cfe/trunk/test/Rewriter/rewrite-block-pointer.mm (original) +++ cfe/trunk/test/Rewriter/rewrite-block-pointer.mm Tue Feb 23 19:37:04 2010 @@ -35,7 +35,7 @@ block = ((__typeof(block))_Block_copy((const void *)(block))); } -// radar 7682149 +// radar 7682763 @interface Y { @private id _private; From rjmccall at apple.com Tue Feb 23 20:00:04 2010 From: rjmccall at apple.com (John McCall) Date: Tue, 23 Feb 2010 18:00:04 -0800 Subject: [cfe-commits] [PATCH] Don't apply function attributes to the return type In-Reply-To: <4B848211.3070304@mymail.mines.edu> References: <4B8431DB.5040605@mymail.mines.edu> <4B846750.5060507@mymail.mines.edu> <8EA879FB-F228-4A8E-9920-F901F4BE56FE@apple.com> <4B848211.3070304@mymail.mines.edu> Message-ID: On Feb 23, 2010, at 5:34 PM, Charles Davis wrote: > John McCall wrote: >> On Feb 23, 2010, at 3:40 PM, Charles Davis wrote: >>> John McCall wrote: >>>> Is this actually what gcc does? The documentation I've seen suggested that gcc tries to apply a function type attribute in the decl spec to the return type if it's a function pointer, and otherwise tries to apply it to the function itself. But maybe I'm misinterpreting it, or maybe that documentation is incorrect: >>>> http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Attribute-Syntax.html#Attribute-Syntax >>>> >>>> At any rate, please do more investigation. If this is the right thing to do, we'll do it, but until we have a clear idea what on earth gcc is doing here, I'd rather hold off. >>> I did some experimentation with GCC 4.2. The results are on the page for >>> PR6408. For your convenience, I reiterate them here: >> >> I did read the bug commentary before I posted. My question is whether this behavior is intentional or extensional :). That is, is this an *aspect* of the rule that gcc uses, or merely a *consequence*? >> >> In particular, it is quite possible that gcc checks if the innermost declarator is a function (or pointer to function?) and, if so, applying CCs in the declaration-specifiers to that function rather than the type in the type-specifiers. That's distinguishable from "don't apply CCs to the return type" in several ways: >> >> typedef void ftype(int); >> ftype __attribute__((fastcall)) **fpp; // is this accepted? >> ftype __attribute__((fastcall)) *fpa[10]; // or this? > For both tof these, GCC tried to apply it to the pointer (or the array, > in the second case). >> ftype __attribute__((fastcall)) (**fpfpp)(int); // and which function does the attribute affect here? > Neither. For one thing, GCC didn't like that this function returns a > function. This probably confused GCC, and so it ended up applying it to > the pointer itself (which, of course, fails). > > Adding an asterisk causes GCC to accept it, but placement of the > asterisk was important. If it came before the calling convention > attribute, GCC attached it to the return type (which I determined by > looking at the generated code for a function of the type to which fpfpp > points). > > If the asterisk came after, GCC once again fails to apply the attribute, > but that's because it's trying to apply the attribute to the pointer to > a function pointer. It understands functions and function pointers, but > not pointers to function pointers. > > It's interesting how GCC gets this backwards--at least, in my opinion. I > would think that it would be the other way around, that if the calling > convention comes before the asterisk, it belongs to the return type, and > if it comes after, it belongs to the function. My verdict: this is > definitely extensional behavior. > > How do you come up with this stuff? >> >> Also, what happens in a declaration group? Does it make the decision separately for each declaration, or is the decision made for the first declaration carried over to subsequent declarations? > For a function typedef (not a function *pointer* typedef), it depends on > where the asterisk is. If the calling convention comes before the > asterisk, the attribute applies to the whole group. If it comes after, > it only applies to the first one. > > For function pointer typedefs, it always applies the attribute to the > whole group. >> >> I accept that the rule I implemented earlier is incorrect; I just want to know what the correct rule is before we start hacking in more things that make individual projects work. > Good point. Hope this helps. Okay. All of this is indeed consistent with the idea that function type attributes in the declaration-specifiers always apply to the entire declaration and never to the return type, so your patch seems fine to me. The remaining problems are quite possibly just errors in where the parser is grouping attributes in declarators; I'd suggest starting by looking at that and making sure it's sane. John. From xuzhongxing at gmail.com Tue Feb 23 20:19:28 2010 From: xuzhongxing at gmail.com (Zhongxing Xu) Date: Wed, 24 Feb 2010 02:19:28 -0000 Subject: [cfe-commits] r97014 - in /cfe/trunk: lib/Analysis/CFG.cpp test/Sema/warn-unreachable.c test/SemaCXX/warn-unreachable.cpp Message-ID: <20100224021928.498662A6C12C@llvm.org> Author: zhongxingxu Date: Tue Feb 23 20:19:28 2010 New Revision: 97014 URL: http://llvm.org/viewvc/llvm-project?rev=97014&view=rev Log: Always add CallExpr as block-level expression. Inline-based interprocedural analysis needs this. Modified: cfe/trunk/lib/Analysis/CFG.cpp cfe/trunk/test/Sema/warn-unreachable.c cfe/trunk/test/SemaCXX/warn-unreachable.cpp Modified: cfe/trunk/lib/Analysis/CFG.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=97014&r1=97013&r2=97014&view=diff ============================================================================== --- cfe/trunk/lib/Analysis/CFG.cpp (original) +++ cfe/trunk/lib/Analysis/CFG.cpp Tue Feb 23 20:19:28 2010 @@ -589,7 +589,7 @@ AddEHEdge = false; if (!NoReturn && !AddEHEdge) - return VisitStmt(C, asc); + return VisitStmt(C, AddStmtChoice::AlwaysAdd); if (Block) { Succ = Block; Modified: cfe/trunk/test/Sema/warn-unreachable.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/warn-unreachable.c?rev=97014&r1=97013&r2=97014&view=diff ============================================================================== --- cfe/trunk/test/Sema/warn-unreachable.c (original) +++ cfe/trunk/test/Sema/warn-unreachable.c Tue Feb 23 20:19:28 2010 @@ -35,8 +35,8 @@ dead(); // expected-warning {{will never be executed}} case 3: - live() - + // expected-warning {{will never be executed}} + live() // expected-warning {{will never be executed}} + + halt(); dead(); Modified: cfe/trunk/test/SemaCXX/warn-unreachable.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-unreachable.cpp?rev=97014&r1=97013&r2=97014&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/warn-unreachable.cpp (original) +++ cfe/trunk/test/SemaCXX/warn-unreachable.cpp Tue Feb 23 20:19:28 2010 @@ -52,8 +52,8 @@ int mem; } s; S &foor(); - halt(), foor() - .mem; // expected-warning {{will never be executed}} + halt(), foor()// expected-warning {{will never be executed}} + .mem; } void test5() { From cdavis at mines.edu Tue Feb 23 20:27:18 2010 From: cdavis at mines.edu (Charles Davis) Date: Wed, 24 Feb 2010 02:27:18 -0000 Subject: [cfe-commits] r97015 - in /cfe/trunk: lib/Sema/SemaType.cpp test/Sema/callingconv.c Message-ID: <20100224022718.730152A6C12C@llvm.org> Author: cdavis Date: Tue Feb 23 20:27:18 2010 New Revision: 97015 URL: http://llvm.org/viewvc/llvm-project?rev=97015&view=rev Log: When we encounter a function-specific attribute in a declaration specifier, apply it only to the function itself, and never to the return type. Fixes part of PR6408. Modified: cfe/trunk/lib/Sema/SemaType.cpp cfe/trunk/test/Sema/callingconv.c Modified: cfe/trunk/lib/Sema/SemaType.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=97015&r1=97014&r2=97015&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaType.cpp (original) +++ cfe/trunk/lib/Sema/SemaType.cpp Tue Feb 23 20:27:18 2010 @@ -72,6 +72,7 @@ typedef llvm::SmallVectorImpl DelayedAttributeSet; static void ProcessTypeAttributeList(Sema &S, QualType &Type, + bool IsDeclSpec, const AttributeList *Attrs, DelayedAttributeSet &DelayedFnAttrs); static bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr); @@ -385,7 +386,7 @@ // See if there are any attributes on the declspec that apply to the type (as // opposed to the decl). if (const AttributeList *AL = DS.getAttributes()) - ProcessTypeAttributeList(TheSema, Result, AL, Delayed); + ProcessTypeAttributeList(TheSema, Result, true, AL, Delayed); // Apply const/volatile/restrict qualifiers to T. if (unsigned TypeQuals = DS.getTypeQualifiers()) { @@ -1297,7 +1298,7 @@ // See if there are any attributes on this declarator chunk. if (const AttributeList *AL = DeclType.getAttrs()) - ProcessTypeAttributeList(*this, T, AL, FnAttrsFromPreviousChunk); + ProcessTypeAttributeList(*this, T, false, AL, FnAttrsFromPreviousChunk); } if (getLangOptions().CPlusPlus && T->isFunctionType()) { @@ -1337,7 +1338,8 @@ // block-literal expressions, which are parsed wierdly. if (D.getContext() != Declarator::BlockLiteralContext) if (const AttributeList *Attrs = D.getAttributes()) - ProcessTypeAttributeList(*this, T, Attrs, FnAttrsFromPreviousChunk); + ProcessTypeAttributeList(*this, T, false, Attrs, + FnAttrsFromPreviousChunk); DiagnoseDelayedFnAttrs(*this, FnAttrsFromPreviousChunk); @@ -1834,7 +1836,7 @@ } void ProcessTypeAttributeList(Sema &S, QualType &Result, - const AttributeList *AL, + bool IsDeclSpec, const AttributeList *AL, DelayedAttributeSet &FnAttrs) { // Scan through and apply attributes to this type where it makes sense. Some // attributes (such as __address_space__, __vector_size__, etc) apply to the @@ -1860,7 +1862,9 @@ case AttributeList::AT_cdecl: case AttributeList::AT_fastcall: case AttributeList::AT_stdcall: - if (ProcessFnAttr(S, Result, *AL)) + // Don't process these on the DeclSpec. + if (IsDeclSpec || + ProcessFnAttr(S, Result, *AL)) FnAttrs.push_back(DelayedAttribute(AL, Result)); break; } Modified: cfe/trunk/test/Sema/callingconv.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/callingconv.c?rev=97015&r1=97014&r2=97015&view=diff ============================================================================== --- cfe/trunk/test/Sema/callingconv.c (original) +++ cfe/trunk/test/Sema/callingconv.c Tue Feb 23 20:27:18 2010 @@ -40,3 +40,7 @@ void ctest3(); void __attribute__((cdecl)) ctest3() {} +// PR6408 +typedef __attribute__((stdcall)) void (*PROC)(); +PROC __attribute__((cdecl)) ctest4(const char *x) {} + From kremenek at apple.com Tue Feb 23 20:28:29 2010 From: kremenek at apple.com (Ted Kremenek) Date: Wed, 24 Feb 2010 02:28:29 -0000 Subject: [cfe-commits] r97016 - /cfe/trunk/test/Sema/format-strings.c Message-ID: <20100224022829.7E3A32A6C12C@llvm.org> Author: kremenek Date: Tue Feb 23 20:28:29 2010 New Revision: 97016 URL: http://llvm.org/viewvc/llvm-project?rev=97016&view=rev Log: Disable one test case because of the inconsistent results it is giving on Windows and Mac OS X. Will investigate later. Modified: cfe/trunk/test/Sema/format-strings.c Modified: cfe/trunk/test/Sema/format-strings.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/format-strings.c?rev=97016&r1=97015&r2=97016&view=diff ============================================================================== --- cfe/trunk/test/Sema/format-strings.c (original) +++ cfe/trunk/test/Sema/format-strings.c Tue Feb 23 20:28:29 2010 @@ -214,7 +214,9 @@ printf("%s", s); // expected-warning{{conversion specifies type 'char *' but the argument has type 'wchar_t *'}} printf("%C", s[0]); // no-warning printf("%c", s[0]); - printf("%C", 10); + // FIXME: This test reports inconsistent results. On Windows, '%C' expects + // 'unsigned short'. + // printf("%C", 10); // FIXME: we report the expected type as 'int*' instead of 'wchar_t*' printf("%S", "hello"); // expected-warning{{but the argument has type 'char *'}} } From xuzhongxing at gmail.com Tue Feb 23 22:54:56 2010 From: xuzhongxing at gmail.com (Zhongxing Xu) Date: Wed, 24 Feb 2010 04:54:56 -0000 Subject: [cfe-commits] r97020 - /cfe/trunk/include/clang/Checker/PathSensitive/Checker.h Message-ID: <20100224045456.DFC952A6C12C@llvm.org> Author: zhongxingxu Date: Tue Feb 23 22:54:56 2010 New Revision: 97020 URL: http://llvm.org/viewvc/llvm-project?rev=97020&view=rev Log: Add comments. Modified: cfe/trunk/include/clang/Checker/PathSensitive/Checker.h Modified: cfe/trunk/include/clang/Checker/PathSensitive/Checker.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/Checker.h?rev=97020&r1=97019&r2=97020&view=diff ============================================================================== --- cfe/trunk/include/clang/Checker/PathSensitive/Checker.h (original) +++ cfe/trunk/include/clang/Checker/PathSensitive/Checker.h Tue Feb 23 22:54:56 2010 @@ -147,6 +147,8 @@ void addTransition(const GRState *state) { assert(state); + // If the 'state' is not new, we need to check if the cached state 'ST' + // is new. if (state != getState() || (ST && ST != B.GetState(Pred))) GenerateNode(state, true); else From rjmccall at apple.com Wed Feb 24 01:14:12 2010 From: rjmccall at apple.com (John McCall) Date: Wed, 24 Feb 2010 07:14:12 -0000 Subject: [cfe-commits] r97030 - in /cfe/trunk: lib/CodeGen/CGCall.cpp lib/CodeGen/CGCall.h lib/CodeGen/CodeGenTypes.h lib/CodeGen/TargetInfo.cpp test/CodeGen/functions.c test/CodeGenObjC/messages-2.m Message-ID: <20100224071412.4ECE02A6C12C@llvm.org> Author: rjmccall Date: Wed Feb 24 01:14:12 2010 New Revision: 97030 URL: http://llvm.org/viewvc/llvm-project?rev=97030&view=rev Log: Canonicalize parameter and return types before computing ABI info. Eliminates a common source of oddities and, in theory, removes some redundant ABI computations. Also fixes a miscompile I introduced yesterday by refactoring some code and causing a slightly different code path to be taken that didn't perform *parameter* type canonicalization, just normal type canonicalization; this in turn caused a bit of ABI code to misfire because it was looking for 'double' or 'float' but received 'const float'. Modified: cfe/trunk/lib/CodeGen/CGCall.cpp cfe/trunk/lib/CodeGen/CGCall.h cfe/trunk/lib/CodeGen/CodeGenTypes.h cfe/trunk/lib/CodeGen/TargetInfo.cpp cfe/trunk/test/CodeGen/functions.c cfe/trunk/test/CodeGenObjC/messages-2.m Modified: cfe/trunk/lib/CodeGen/CGCall.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=97030&r1=97029&r2=97030&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGCall.cpp (original) +++ cfe/trunk/lib/CodeGen/CGCall.cpp Wed Feb 24 01:14:12 2010 @@ -41,21 +41,54 @@ } } -const -CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionNoProtoType *FTNP) { - return getFunctionInfo(FTNP->getResultType(), +/// Derives the 'this' type for codegen purposes, i.e. ignoring method +/// qualification. +/// FIXME: address space qualification? +static QualType GetThisType(ASTContext &Context, const CXXRecordDecl *RD) { + return Context.getPointerType(Context.getTagDeclType(RD)); +} + +/// Returns the canonical formal type of the given C++ method. +static const FunctionProtoType *GetFormalType(const CXXMethodDecl *MD) { + return cast(MD->getType()->getCanonicalTypeInternal()); +} + +/// Returns the "extra-canonicalized" return type, which discards +/// qualifiers on the return type. Codegen doesn't care about them, +/// and it makes ABI code a little easier to be able to assume that +/// all parameter and return types are top-level unqualified. +static QualType GetReturnType(QualType RetTy) { + return RetTy->getCanonicalTypeInternal().getUnqualifiedType(); +} + +const CGFunctionInfo & +CodeGenTypes::getFunctionInfo(const FunctionNoProtoType *FTNP) { + assert(FTNP->isCanonicalUnqualified() && "type must be canonical"); + return getFunctionInfo(GetReturnType(FTNP->getResultType()), llvm::SmallVector(), - FTNP->getCallConv(), FTNP->getNoReturnAttr()); + FTNP->getCallConv(), + FTNP->getNoReturnAttr()); } -const -CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionProtoType *FTP) { - llvm::SmallVector ArgTys; +/// \param Args - contains any initial parameters besides those +/// in the formal type +static const CGFunctionInfo &getFunctionInfo(CodeGenTypes &CGT, + llvm::SmallVectorImpl &ArgTys, + const FunctionProtoType *FTP) { + assert(FTP->isCanonicalUnqualified() && "type must be canonical"); // FIXME: Kill copy. for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) ArgTys.push_back(FTP->getArgType(i)); - return getFunctionInfo(FTP->getResultType(), ArgTys, - FTP->getCallConv(), FTP->getNoReturnAttr()); + return CGT.getFunctionInfo(GetReturnType(FTP->getResultType()), + ArgTys, + FTP->getCallConv(), + FTP->getNoReturnAttr()); +} + +const CGFunctionInfo & +CodeGenTypes::getFunctionInfo(const FunctionProtoType *FTP) { + llvm::SmallVector ArgTys; + return ::getFunctionInfo(*this, ArgTys, FTP); } static CallingConv getCallingConventionForDecl(const Decl *D) { @@ -72,30 +105,22 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD, const FunctionProtoType *FTP) { llvm::SmallVector ArgTys; - + // Add the 'this' pointer. - ArgTys.push_back(Context.getPointerType(Context.getTagDeclType(RD))); - - for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) - ArgTys.push_back(FTP->getArgType(i)); - - // FIXME: Set calling convention correctly, it needs to be associated with the - // type somehow. - return getFunctionInfo(FTP->getResultType(), ArgTys, - FTP->getCallConv(), FTP->getNoReturnAttr()); + ArgTys.push_back(GetThisType(Context, RD)); + + return ::getFunctionInfo(*this, ArgTys, + cast(FTP->getCanonicalTypeInternal())); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) { llvm::SmallVector ArgTys; + // Add the 'this' pointer unless this is a static method. if (MD->isInstance()) - ArgTys.push_back(MD->getThisType(Context)); + ArgTys.push_back(GetThisType(Context, MD->getParent())); - const FunctionProtoType *FTP = MD->getType()->getAs(); - for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) - ArgTys.push_back(FTP->getArgType(i)); - return getFunctionInfo(FTP->getResultType(), ArgTys, FTP->getCallConv(), - FTP->getNoReturnAttr()); + return ::getFunctionInfo(*this, ArgTys, GetFormalType(MD)); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D, @@ -103,17 +128,13 @@ llvm::SmallVector ArgTys; // Add the 'this' pointer. - ArgTys.push_back(D->getThisType(Context)); + ArgTys.push_back(GetThisType(Context, D->getParent())); // Check if we need to add a VTT parameter (which has type void **). if (Type == Ctor_Base && D->getParent()->getNumVBases() != 0) ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy)); - - const FunctionProtoType *FTP = D->getType()->getAs(); - for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) - ArgTys.push_back(FTP->getArgType(i)); - return getFunctionInfo(FTP->getResultType(), ArgTys, FTP->getCallConv(), - FTP->getNoReturnAttr()); + + return ::getFunctionInfo(*this, ArgTys, GetFormalType(D)); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D, @@ -126,12 +147,8 @@ // Check if we need to add a VTT parameter (which has type void **). if (Type == Dtor_Base && D->getParent()->getNumVBases() != 0) ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy)); - - const FunctionProtoType *FTP = D->getType()->getAs(); - for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) - ArgTys.push_back(FTP->getArgType(i)); - return getFunctionInfo(FTP->getResultType(), ArgTys, FTP->getCallConv(), - FTP->getNoReturnAttr()); + + return ::getFunctionInfo(*this, ArgTys, GetFormalType(D)); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) { @@ -139,19 +156,11 @@ if (MD->isInstance()) return getFunctionInfo(MD); - const FunctionType *FTy = FD->getType()->getAs(); - if (const FunctionNoProtoType *FNTP = dyn_cast(FTy)) - return getFunctionInfo(FNTP->getResultType(), - llvm::SmallVector(), - FNTP->getCallConv(), FNTP->getNoReturnAttr()); - - const FunctionProtoType *FPT = cast(FTy); - llvm::SmallVector ArgTys; - // FIXME: Kill copy. - for (unsigned i = 0, e = FPT->getNumArgs(); i != e; ++i) - ArgTys.push_back(FPT->getArgType(i)); - return getFunctionInfo(FPT->getResultType(), ArgTys, - FPT->getCallConv(), FPT->getNoReturnAttr()); + const FunctionType *FTy + = cast(FD->getType()->getCanonicalTypeInternal()); + if (isa(FTy)) + return getFunctionInfo(cast(FTy)); + return getFunctionInfo(cast(FTy)); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) { @@ -160,9 +169,11 @@ ArgTys.push_back(Context.getObjCSelType()); // FIXME: Kill copy? for (ObjCMethodDecl::param_iterator i = MD->param_begin(), - e = MD->param_end(); i != e; ++i) - ArgTys.push_back((*i)->getType()); - return getFunctionInfo(MD->getResultType(), ArgTys, + e = MD->param_end(); i != e; ++i) { + ArgTys.push_back(Context.getCanonicalParamType((*i)->getType())); + } + return getFunctionInfo(GetReturnType(MD->getResultType()), + ArgTys, getCallingConventionForDecl(MD), /*NoReturn*/ false); } @@ -188,8 +199,8 @@ llvm::SmallVector ArgTys; for (CallArgList::const_iterator i = Args.begin(), e = Args.end(); i != e; ++i) - ArgTys.push_back(i->second); - return getFunctionInfo(ResTy, ArgTys, CC, NoReturn); + ArgTys.push_back(Context.getCanonicalParamType(i->second)); + return getFunctionInfo(GetReturnType(ResTy), ArgTys, CC, NoReturn); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, @@ -200,12 +211,12 @@ llvm::SmallVector ArgTys; for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end(); i != e; ++i) - ArgTys.push_back(i->second); - return getFunctionInfo(ResTy, ArgTys, CC, NoReturn); + ArgTys.push_back(Context.getCanonicalParamType(i->second)); + return getFunctionInfo(GetReturnType(ResTy), ArgTys, CC, NoReturn); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, - const llvm::SmallVector &ArgTys, + const llvm::SmallVectorImpl &ArgTys, CallingConv CallConv, bool NoReturn) { unsigned CC = ClangCallConvToLLVMCallConv(CallConv); @@ -233,7 +244,7 @@ CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention, bool _NoReturn, QualType ResTy, - const llvm::SmallVector &ArgTys) + const llvm::SmallVectorImpl &ArgTys) : CallingConvention(_CallingConvention), EffectiveCallingConvention(_CallingConvention), NoReturn(_NoReturn) Modified: cfe/trunk/lib/CodeGen/CGCall.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.h?rev=97030&r1=97029&r2=97030&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGCall.h (original) +++ cfe/trunk/lib/CodeGen/CGCall.h Wed Feb 24 01:14:12 2010 @@ -82,7 +82,7 @@ CGFunctionInfo(unsigned CallingConvention, bool NoReturn, QualType ResTy, - const llvm::SmallVector &ArgTys); + const llvm::SmallVectorImpl &ArgTys); ~CGFunctionInfo() { delete[] Args; } const_arg_iterator arg_begin() const { return Args + 1; } Modified: cfe/trunk/lib/CodeGen/CodeGenTypes.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenTypes.h?rev=97030&r1=97029&r2=97030&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenTypes.h (original) +++ cfe/trunk/lib/CodeGen/CodeGenTypes.h Wed Feb 24 01:14:12 2010 @@ -186,11 +186,6 @@ /// replace the 'opaque' type we previously made for it if applicable. void UpdateCompletedType(const TagDecl *TD); -private: - const CGFunctionInfo &getFunctionInfo(const FunctionNoProtoType *FTNP); - const CGFunctionInfo &getFunctionInfo(const FunctionProtoType *FTP); - -public: /// getFunctionInfo - Get the function info for the specified function decl. const CGFunctionInfo &getFunctionInfo(GlobalDecl GD); @@ -207,6 +202,8 @@ return getFunctionInfo(Ty->getResultType(), Args, Ty->getCallConv(), Ty->getNoReturnAttr()); } + const CGFunctionInfo &getFunctionInfo(const FunctionProtoType *Ty); + const CGFunctionInfo &getFunctionInfo(const FunctionNoProtoType *Ty); // getFunctionInfo - Get the function info for a member function. const CGFunctionInfo &getFunctionInfo(const CXXRecordDecl *RD, @@ -224,7 +221,7 @@ CallingConv CC, bool NoReturn); const CGFunctionInfo &getFunctionInfo(QualType RetTy, - const llvm::SmallVector &ArgTys, + const llvm::SmallVectorImpl &ArgTys, CallingConv CC, bool NoReturn); Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=97030&r1=97029&r2=97030&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original) +++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Wed Feb 24 01:14:12 2010 @@ -972,12 +972,11 @@ return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } else if (CoerceTo == llvm::Type::getDoubleTy(CoerceTo->getContext())) { - // FIXME: It would probably be better to make CGFunctionInfo only map using - // canonical types than to canonize here. - QualType CTy = Context.getCanonicalType(Ty); + assert(Ty.isCanonical() && "should always have a canonical type here"); + assert(!Ty.hasQualifiers() && "should never have a qualified type here"); // Float and double end up in a single SSE reg. - if (CTy == Context.FloatTy || CTy == Context.DoubleTy) + if (Ty == Context.FloatTy || Ty == Context.DoubleTy) return ABIArgInfo::getDirect(); } Modified: cfe/trunk/test/CodeGen/functions.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/functions.c?rev=97030&r1=97029&r2=97030&view=diff ============================================================================== --- cfe/trunk/test/CodeGen/functions.c (original) +++ cfe/trunk/test/CodeGen/functions.c Wed Feb 24 01:14:12 2010 @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -emit-llvm -o %t +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s int g(); @@ -38,3 +38,12 @@ // PR4423 - This shouldn't crash in codegen void f4() {} void f5() { f4(42); } + +// Qualifiers on parameter types shouldn't make a difference. +static void f6(const float f, const float g) { +} +void f7(float f, float g) { + f6(f, g); +// CHECK: define void @f7(float{{.*}}, float{{.*}}) +// CHECK: call void @f6(float{{.*}}, float{{.*}}) +} Modified: cfe/trunk/test/CodeGenObjC/messages-2.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/messages-2.m?rev=97030&r1=97029&r2=97030&view=diff ============================================================================== --- cfe/trunk/test/CodeGenObjC/messages-2.m (original) +++ cfe/trunk/test/CodeGenObjC/messages-2.m Wed Feb 24 01:14:12 2010 @@ -136,4 +136,7 @@ x.height *= 2; return x; } +-(const float) returnAConstFloat { + return 5; +} @end From rjmccall at apple.com Wed Feb 24 01:33:39 2010 From: rjmccall at apple.com (John McCall) Date: Wed, 24 Feb 2010 07:33:39 -0000 Subject: [cfe-commits] r97032 - /cfe/trunk/test/CodeGen/functions.c Message-ID: <20100224073339.A61AF2A6C12C@llvm.org> Author: rjmccall Date: Wed Feb 24 01:33:39 2010 New Revision: 97032 URL: http://llvm.org/viewvc/llvm-project?rev=97032&view=rev Log: Fix test case and convert fully to FileCheck. Modified: cfe/trunk/test/CodeGen/functions.c Modified: cfe/trunk/test/CodeGen/functions.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/functions.c?rev=97032&r1=97031&r2=97032&view=diff ============================================================================== --- cfe/trunk/test/CodeGen/functions.c (original) +++ cfe/trunk/test/CodeGen/functions.c Wed Feb 24 01:33:39 2010 @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -emit-llvm -o - -verify | FileCheck %s int g(); @@ -19,25 +19,25 @@ int a(int); int a() {return 1;} -// RUN: grep 'define void @f0()' %t void f0() {} +// CHECK: define void @f0() void f1(); -// RUN: grep 'call void @f1()' %t void f2(void) { +// CHECK: call void @f1() f1(1, 2, 3); } -// RUN: grep 'define void @f1()' %t +// CHECK: define void @f1() void f1() {} -// RUN: grep 'define .* @f3' %t | not grep -F '...' +// CHECK: define {{.*}} @f3() struct foo { int X, Y, Z; } f3() { while (1) {} } // PR4423 - This shouldn't crash in codegen void f4() {} -void f5() { f4(42); } +void f5() { f4(42); } //expected-warning {{too many arguments}} // Qualifiers on parameter types shouldn't make a difference. static void f6(const float f, const float g) { From rjmccall at apple.com Wed Feb 24 02:14:27 2010 From: rjmccall at apple.com (John McCall) Date: Wed, 24 Feb 2010 08:14:27 -0000 Subject: [cfe-commits] r97035 - /cfe/trunk/test/CodeGen/functions.c Message-ID: <20100224081427.E846F2A6C12C@llvm.org> Author: rjmccall Date: Wed Feb 24 02:14:27 2010 New Revision: 97035 URL: http://llvm.org/viewvc/llvm-project?rev=97035&view=rev Log: Make this test portable to ABIs that use sret. Modified: cfe/trunk/test/CodeGen/functions.c Modified: cfe/trunk/test/CodeGen/functions.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/functions.c?rev=97035&r1=97034&r2=97035&view=diff ============================================================================== --- cfe/trunk/test/CodeGen/functions.c (original) +++ cfe/trunk/test/CodeGen/functions.c Wed Feb 24 02:14:27 2010 @@ -30,7 +30,7 @@ // CHECK: define void @f1() void f1() {} -// CHECK: define {{.*}} @f3() +// CHECK: define {{.*}} @f3{{\(\)|\(.*sret.*\)}} struct foo { int X, Y, Z; } f3() { while (1) {} } From rjmccall at apple.com Wed Feb 24 03:03:18 2010 From: rjmccall at apple.com (John McCall) Date: Wed, 24 Feb 2010 09:03:18 -0000 Subject: [cfe-commits] r97037 - in /cfe/trunk: lib/AST/Expr.cpp test/SemaCXX/i-c-e-cxx.cpp Message-ID: <20100224090318.5BCC62A6C12C@llvm.org> Author: rjmccall Date: Wed Feb 24 03:03:18 2010 New Revision: 97037 URL: http://llvm.org/viewvc/llvm-project?rev=97037&view=rev Log: References to const int parameters with ICE default arguments are not ICEs. Fixes PR6373. Modified: cfe/trunk/lib/AST/Expr.cpp cfe/trunk/test/SemaCXX/i-c-e-cxx.cpp Modified: cfe/trunk/lib/AST/Expr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=97037&r1=97036&r2=97037&view=diff ============================================================================== --- cfe/trunk/lib/AST/Expr.cpp (original) +++ cfe/trunk/lib/AST/Expr.cpp Wed Feb 24 03:03:18 2010 @@ -1682,11 +1682,18 @@ return NoDiag(); if (Ctx.getLangOptions().CPlusPlus && E->getType().getCVRQualifiers() == Qualifiers::Const) { + const NamedDecl *D = cast(E)->getDecl(); + + // Parameter variables are never constants. Without this check, + // getAnyInitializer() can find a default argument, which leads + // to chaos. + if (isa(D)) + return ICEDiag(2, cast(E)->getLocation()); + // C++ 7.1.5.1p2 // A variable of non-volatile const-qualified integral or enumeration // type initialized by an ICE can be used in ICEs. - if (const VarDecl *Dcl = - dyn_cast(cast(E)->getDecl())) { + if (const VarDecl *Dcl = dyn_cast(D)) { Qualifiers Quals = Ctx.getCanonicalType(Dcl->getType()).getQualifiers(); if (Quals.hasVolatile() || !Quals.hasConst()) return ICEDiag(2, cast(E)->getLocation()); Modified: cfe/trunk/test/SemaCXX/i-c-e-cxx.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/i-c-e-cxx.cpp?rev=97037&r1=97036&r2=97037&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/i-c-e-cxx.cpp (original) +++ cfe/trunk/test/SemaCXX/i-c-e-cxx.cpp Wed Feb 24 03:03:18 2010 @@ -37,3 +37,8 @@ return str[0]; } } + +// PR6373: default arguments don't count. +void pr6373(const unsigned x = 0) { + unsigned max = 80 / x; +} From andersca at mac.com Wed Feb 24 10:43:12 2010 From: andersca at mac.com (Anders Carlsson) Date: Wed, 24 Feb 2010 16:43:12 -0000 Subject: [cfe-commits] r97039 - in /cfe/trunk: lib/CodeGen/CGVtable.cpp test/CodeGenCXX/vtable-layout-abi-examples.cpp Message-ID: <20100224164312.8496C2A6C12C@llvm.org> Author: andersca Date: Wed Feb 24 10:43:12 2010 New Revision: 97039 URL: http://llvm.org/viewvc/llvm-project?rev=97039&view=rev Log: Generate correct vcall offsets when we have a primary virtual base that is not a primary base in the complete class hierarchy. Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp cfe/trunk/test/CodeGenCXX/vtable-layout-abi-examples.cpp Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=97039&r1=97038&r2=97039&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVtable.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVtable.cpp Wed Feb 24 10:43:12 2010 @@ -968,6 +968,7 @@ /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the /// given base subobject. void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual, + uint64_t RealBaseOffset, VisitedVirtualBasesSetTy &VBases); /// AddVCallOffsets - Add vcall offsets for the given base subobject. @@ -1112,6 +1113,7 @@ void VtableBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual, + uint64_t RealBaseOffset, VisitedVirtualBasesSetTy &VBases) { const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base.getBase()); @@ -1126,8 +1128,28 @@ // emit them for the primary base first). if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { bool PrimaryBaseIsVirtual = Layout.getPrimaryBaseWasVirtual(); - AddVCallAndVBaseOffsets(BaseSubobject(PrimaryBase, Base.getBaseOffset()), - PrimaryBaseIsVirtual, VBases); + + uint64_t PrimaryBaseOffset; + + // Get the base offset of the primary base. + if (PrimaryBaseIsVirtual) { + assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && + "Primary vbase should have a zero offset!"); + + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + + PrimaryBaseOffset = + MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); + } else { + assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && + "Primary base should have a zero offset!"); + + PrimaryBaseOffset = Base.getBaseOffset(); + } + + AddVCallAndVBaseOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset), + PrimaryBaseIsVirtual, RealBaseOffset, VBases); } // FIXME: Don't use /8 here. @@ -1136,7 +1158,7 @@ // We only want to add vcall offsets for virtual bases. if (BaseIsVirtual) - AddVCallOffsets(Base, Base.getBaseOffset()); + AddVCallOffsets(Base, RealBaseOffset); } void VtableBuilder::AddVCallOffsets(BaseSubobject Base, uint64_t VBaseOffset) { @@ -1434,7 +1456,7 @@ // Add vcall and vbase offsets for this vtable. VisitedVirtualBasesSetTy VBases; - AddVCallAndVBaseOffsets(Base, BaseIsVirtual, VBases); + AddVCallAndVBaseOffsets(Base, BaseIsVirtual, Base.getBaseOffset(), VBases); // Reverse them and add them to the vtable components. std::reverse(VCallAndVBaseOffsets.begin(), VCallAndVBaseOffsets.end()); @@ -1470,11 +1492,11 @@ AddressPoints.insert(std::make_pair(PrimaryBase, AddressPoint)); } - // Layout secondary vtables. - LayoutSecondaryVtables(Base); - // Clear the vcall offsets. VCallOffsets.clear(); + + // Layout secondary vtables. + LayoutSecondaryVtables(Base); } void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base) { Modified: cfe/trunk/test/CodeGenCXX/vtable-layout-abi-examples.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/vtable-layout-abi-examples.cpp?rev=97039&r1=97038&r2=97039&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/vtable-layout-abi-examples.cpp (original) +++ cfe/trunk/test/CodeGenCXX/vtable-layout-abi-examples.cpp Wed Feb 24 10:43:12 2010 @@ -155,3 +155,35 @@ void E::f() { } } + +namespace Test2 { + +// From http://www.codesourcery.com/public/cxx-abi/abi.html#class-types. + +struct A { virtual void f(); }; +struct B : virtual public A { int i; }; +struct C : virtual public A { int j; }; + +// CHECK: Vtable for 'Test2::D' (11 entries). +// CHECK-NEXT: 0 | vbase_offset (0) +// CHECK-NEXT: 1 | vcall_offset (0) +// CHECK-NEXT: 2 | offset_to_top (0) +// CHECK-NEXT: 3 | Test2::D RTTI +// CHECK-NEXT: -- (Test2::A, 0) vtable address -- +// CHECK-NEXT: -- (Test2::B, 0) vtable address -- +// CHECK-NEXT: -- (Test2::D, 0) vtable address -- +// CHECK-NEXT: 4 | void Test2::A::f() +// CHECK-NEXT: 5 | void Test2::D::d() +// CHECK-NEXT: 6 | vbase_offset (-16) +// CHECK-NEXT: 7 | vcall_offset (-16) +// CHECK-NEXT: 8 | offset_to_top (-16) +// CHECK-NEXT: 9 | Test2::D RTTI +// CHECK-NEXT: -- (Test2::A, 16) vtable address -- +// CHECK-NEXT: -- (Test2::C, 16) vtable address -- +// CHECK-NEXT: 10 | [unused] void Test2::A::f() +struct D : public B, public C { + virtual void d(); +}; +void D::d() { } + +} From dgregor at apple.com Wed Feb 24 12:44:31 2010 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 24 Feb 2010 18:44:31 -0000 Subject: [cfe-commits] r97045 - in /cfe/trunk: include/clang/Parse/Action.h include/clang/Parse/Parser.h lib/Parse/ParseExpr.cpp lib/Parse/ParseExprCXX.cpp lib/Sema/Sema.h lib/Sema/SemaExprCXX.cpp lib/Sema/TreeTransform.h Message-ID: <20100224184432.0F1572A6C12E@llvm.org> Author: dgregor Date: Wed Feb 24 12:44:31 2010 New Revision: 97045 URL: http://llvm.org/viewvc/llvm-project?rev=97045&view=rev Log: Rework parsing of pseudo-destructor expressions and explicit destructor calls, e.g., p->T::~T We now detect when the member access that we've parsed, e.g., p-> or x. may be a pseudo-destructor expression, either because the type of p or x is a scalar or because it is dependent (and, therefore, may become a scalar at template instantiation time). We then parse the pseudo-destructor grammar specifically: ::[opt] nested-name-specifier[opt] type-name :: ? type-name and hand those results to a new action, ActOnPseudoDestructorExpr, which will cope with both dependent member accesses of destructors and with pseudo-destructor expressions. This commit affects the parsing of pseudo-destructors, only; the semantic actions still go through the semantic actions for member access expressions. That will change soon. Modified: cfe/trunk/include/clang/Parse/Action.h cfe/trunk/include/clang/Parse/Parser.h cfe/trunk/lib/Parse/ParseExpr.cpp cfe/trunk/lib/Parse/ParseExprCXX.cpp cfe/trunk/lib/Sema/Sema.h cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/lib/Sema/TreeTransform.h Modified: cfe/trunk/include/clang/Parse/Action.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=97045&r1=97044&r2=97045&view=diff ============================================================================== --- cfe/trunk/include/clang/Parse/Action.h (original) +++ cfe/trunk/include/clang/Parse/Action.h Wed Feb 24 12:44:31 2010 @@ -1614,12 +1614,66 @@ /// with the type into which name lookup should look to find the member in /// the member access expression. /// + /// \param MayBePseudoDestructor Originally false. The action should + /// set this true if the expression may end up being a + /// pseudo-destructor expression, indicating to the parser that it + /// shoudl be parsed as a pseudo-destructor rather than as a member + /// access expression. Note that this should apply both when the + /// object type is a scalar and when the object type is dependent. + /// /// \returns the (possibly modified) \p Base expression virtual OwningExprResult ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, - TypeTy *&ObjectType) { + TypeTy *&ObjectType, + bool &MayBePseudoDestructor) { + return ExprEmpty(); + } + + /// \brief Parsed a C++ pseudo-destructor expression or a dependent + /// member access expression that has the same syntactic form as a + /// pseudo-destructor expression. + /// + /// \param S The scope in which the member access expression occurs. + /// + /// \param Base The expression in which a member is being accessed, e.g., the + /// "x" in "x.f". + /// + /// \param OpLoc The location of the member access operator ("." or "->") + /// + /// \param OpKind The kind of member access operator ("." or "->") + /// + /// \param SS The nested-name-specifier that precedes the type names + /// in the grammar. Note that this nested-name-specifier will not + /// cover the last "type-name ::" in the grammar, because it isn't + /// necessarily a nested-name-specifier. + /// + /// \param FirstTypeName The type name that follows the optional + /// nested-name-specifier but precedes the '::', e.g., the first + /// type-name in "type-name :: type-name". This type name may be + /// empty. This will be either an identifier or a template-id. + /// + /// \param CCLoc The location of the '::' in "type-name :: + /// typename". May be invalid, if there is no \p FirstTypeName. + /// + /// \param TildeLoc The location of the '~'. + /// + /// \param SecondTypeName The type-name following the '~', which is + /// the name of the type being destroyed. This will be either an + /// identifier or a template-id. + /// + /// \param HasTrailingLParen Whether the next token in the stream is + /// a left parentheses. + virtual OwningExprResult ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + UnqualifiedId &FirstTypeName, + SourceLocation CCLoc, + SourceLocation TildeLoc, + UnqualifiedId &SecondTypeName, + bool HasTrailingLParen) { return ExprEmpty(); } Modified: cfe/trunk/include/clang/Parse/Parser.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=97045&r1=97044&r2=97045&view=diff ============================================================================== --- cfe/trunk/include/clang/Parse/Parser.h (original) +++ cfe/trunk/include/clang/Parse/Parser.h Wed Feb 24 12:44:31 2010 @@ -964,7 +964,7 @@ bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, TypeTy *ObjectType, bool EnteringContext, - bool InMemberAccessExpr = false); + bool *MayBePseudoDestructor = 0); //===--------------------------------------------------------------------===// // C++ 5.2p1: C++ Casts @@ -975,6 +975,13 @@ OwningExprResult ParseCXXTypeid(); //===--------------------------------------------------------------------===// + // C++ 5.2.4: C++ Pseudo-Destructor Expressions + OwningExprResult ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc, + tok::TokenKind OpKind, + CXXScopeSpec &SS, + Action::TypeTy *ObjectType); + + //===--------------------------------------------------------------------===// // C++ 9.3.2: C++ 'this' pointer OwningExprResult ParseCXXThis(); @@ -1415,7 +1422,8 @@ SourceLocation NameLoc, bool EnteringContext, TypeTy *ObjectType, - UnqualifiedId &Id); + UnqualifiedId &Id, + bool AssumeTemplateId = false); bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, TypeTy *ObjectType, UnqualifiedId &Result); Modified: cfe/trunk/lib/Parse/ParseExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=97045&r1=97044&r2=97045&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseExpr.cpp (original) +++ cfe/trunk/lib/Parse/ParseExpr.cpp Wed Feb 24 12:44:31 2010 @@ -996,12 +996,16 @@ CXXScopeSpec SS; Action::TypeTy *ObjectType = 0; + bool MayBePseudoDestructor = false; if (getLang().CPlusPlus && !LHS.isInvalid()) { LHS = Actions.ActOnStartCXXMemberReference(CurScope, move(LHS), - OpLoc, OpKind, ObjectType); + OpLoc, OpKind, ObjectType, + MayBePseudoDestructor); if (LHS.isInvalid()) break; - ParseOptionalCXXScopeSpecifier(SS, ObjectType, false, true); + + ParseOptionalCXXScopeSpecifier(SS, ObjectType, false, + &MayBePseudoDestructor); } if (Tok.is(tok::code_completion)) { @@ -1012,6 +1016,17 @@ ConsumeToken(); } + if (MayBePseudoDestructor) { + LHS = ParseCXXPseudoDestructor(move(LHS), OpLoc, OpKind, SS, + ObjectType); + break; + } + + // Either the action has told is that this cannot be a + // pseudo-destructor expression (based on the type of base + // expression), or we didn't see a '~' in the right place. We + // can still parse a destructor name here, but in that case it + // names a real destructor. UnqualifiedId Name; if (ParseUnqualifiedId(SS, /*EnteringContext=*/false, @@ -1022,10 +1037,9 @@ return ExprError(); if (!LHS.isInvalid()) - LHS = Actions.ActOnMemberAccessExpr(CurScope, move(LHS), OpLoc, OpKind, - SS, Name, ObjCImpDecl, + LHS = Actions.ActOnMemberAccessExpr(CurScope, move(LHS), OpLoc, + OpKind, SS, Name, ObjCImpDecl, Tok.is(tok::l_paren)); - break; } case tok::plusplus: // postfix-expression: postfix-expression '++' Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=97045&r1=97044&r2=97045&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original) +++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Wed Feb 24 12:44:31 2010 @@ -45,14 +45,21 @@ /// \param EnteringContext whether we will be entering into the context of /// the nested-name-specifier after parsing it. /// -/// \param InMemberAccessExpr Whether this scope specifier is within a +/// \param MayBePseudoDestructor When non-NULL, points to a flag that +/// indicates whether this nested-name-specifier may be part of a +/// pseudo-destructor name. In this case, the flag will be set false +/// if we don't actually end up parsing a destructor name. Moreorover, +/// if we do end up determining that we are parsing a destructor name, +/// the last component of the nested-name-specifier is not parsed as +/// part of the scope specifier. + /// member access expression, e.g., the \p T:: in \p p->T::m. /// /// \returns true if a scope specifier was parsed. bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, Action::TypeTy *ObjectType, bool EnteringContext, - bool InMemberAccessExpr) { + bool *MayBePseudoDestructor) { assert(getLang().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); @@ -79,6 +86,12 @@ HasScopeSpecifier = true; } + bool CheckForDestructor = false; + if (MayBePseudoDestructor && *MayBePseudoDestructor) { + CheckForDestructor = true; + *MayBePseudoDestructor = false; + } + while (true) { if (HasScopeSpecifier) { // C++ [basic.lookup.classref]p5: @@ -173,8 +186,11 @@ // convert it into a type within the nested-name-specifier. TemplateIdAnnotation *TemplateId = static_cast(Tok.getAnnotationValue()); - bool MayBePseudoDestructor - = InMemberAccessExpr && GetLookAheadToken(2).is(tok::tilde); + if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) { + *MayBePseudoDestructor = true; + return HasScopeSpecifier; + } + if (TemplateId->Kind == TNK_Type_template || TemplateId->Kind == TNK_Dependent_template_name) { AnnotateTemplateIdTokenAsType(&SS); @@ -197,7 +213,7 @@ TypeToken.getAnnotationValue(), TypeToken.getAnnotationRange(), CCLoc, - MayBePseudoDestructor)); + false)); else SS.setScopeRep(0); SS.setEndLoc(CCLoc); @@ -224,11 +240,13 @@ // If we get foo:bar, this is almost certainly a typo for foo::bar. Recover // and emit a fixit hint for it. if (Next.is(tok::colon) && !ColonIsSacred) { - bool MayBePseudoDestructor - = InMemberAccessExpr && GetLookAheadToken(2).is(tok::tilde); - + if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) { + *MayBePseudoDestructor = true; + return HasScopeSpecifier; + } + if (Actions.IsInvalidUnlessNestedName(CurScope, SS, II, - MayBePseudoDestructor, ObjectType, + false, ObjectType, EnteringContext) && // If the token after the colon isn't an identifier, it's still an // error, but they probably meant something else strange so don't @@ -243,6 +261,11 @@ } if (Next.is(tok::coloncolon)) { + if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) { + *MayBePseudoDestructor = true; + return HasScopeSpecifier; + } + // We have an identifier followed by a '::'. Lookup this name // as the name in a nested-name-specifier. SourceLocation IdLoc = ConsumeToken(); @@ -258,11 +281,9 @@ if (SS.isInvalid()) continue; - bool MayBePseudoDestructor = InMemberAccessExpr && Tok.is(tok::tilde); - SS.setScopeRep( Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, II, - MayBePseudoDestructor, ObjectType, + false, ObjectType, EnteringContext)); SS.setEndLoc(CCLoc); continue; @@ -298,6 +319,12 @@ break; } + // Even if we didn't see any pieces of a nested-name-specifier, we + // still check whether there is a tilde in this position, which + // indicates a potential pseudo-destructor. + if (CheckForDestructor && Tok.is(tok::tilde)) + *MayBePseudoDestructor = true; + return HasScopeSpecifier; } @@ -493,6 +520,77 @@ return move(Result); } +/// \brief Parse a C++ pseudo-destructor expression after the base, +/// . or -> operator, and nested-name-specifier have already been +/// parsed. +/// +/// postfix-expression: [C++ 5.2] +/// postfix-expression . pseudo-destructor-name +/// postfix-expression -> pseudo-destructor-name +/// +/// pseudo-destructor-name: +/// ::[opt] nested-name-specifier[opt] type-name :: ~type-name +/// ::[opt] nested-name-specifier template simple-template-id :: +/// ~type-name +/// ::[opt] nested-name-specifier[opt] ~type-name +/// +Parser::OwningExprResult +Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc, + tok::TokenKind OpKind, + CXXScopeSpec &SS, + Action::TypeTy *ObjectType) { + // We're parsing either a pseudo-destructor-name or a dependent + // member access that has the same form as a + // pseudo-destructor-name. We parse both in the same way and let + // the action model sort them out. + // + // Note that the ::[opt] nested-name-specifier[opt] has already + // been parsed, and if there was a simple-template-id, it has + // been coalesced into a template-id annotation token. + UnqualifiedId FirstTypeName; + SourceLocation CCLoc; + if (Tok.is(tok::identifier)) { + FirstTypeName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + ConsumeToken(); + assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail"); + CCLoc = ConsumeToken(); + } else if (Tok.is(tok::annot_template_id)) { + FirstTypeName.setTemplateId( + (TemplateIdAnnotation *)Tok.getAnnotationValue()); + ConsumeToken(); + assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail"); + CCLoc = ConsumeToken(); + } else { + FirstTypeName.setIdentifier(0, SourceLocation()); + } + + // Parse the tilde. + assert(Tok.is(tok::tilde) && "ParseOptionalCXXScopeSpecifier fail"); + SourceLocation TildeLoc = ConsumeToken(); + if (!Tok.is(tok::identifier)) { + Diag(Tok, diag::err_destructor_tilde_identifier); + return ExprError(); + } + + // Parse the second type. + UnqualifiedId SecondTypeName; + IdentifierInfo *Name = Tok.getIdentifierInfo(); + SourceLocation NameLoc = ConsumeToken(); + SecondTypeName.setIdentifier(Name, NameLoc); + + // If there is a '<', the second type name is a template-id. Parse + // it as such. + if (Tok.is(tok::less) && + ParseUnqualifiedIdTemplateId(SS, Name, NameLoc, false, ObjectType, + SecondTypeName, /*AssumeTemplateName=*/true)) + return ExprError(); + + return Actions.ActOnPseudoDestructorExpr(CurScope, move(Base), OpLoc, OpKind, + SS, FirstTypeName, CCLoc, + TildeLoc, SecondTypeName, + Tok.is(tok::l_paren)); +} + /// ParseCXXBoolLiteral - This handles the C++ Boolean literals. /// /// boolean-literal: [C++ 2.13.5] @@ -818,13 +916,17 @@ /// that precedes the '<'. If template arguments were parsed successfully, /// will be updated with the template-id. /// +/// \param AssumeTemplateId When true, this routine will assume that the name +/// refers to a template without performing name lookup to verify. +/// /// \returns true if a parse error occurred, false otherwise. bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, bool EnteringContext, TypeTy *ObjectType, - UnqualifiedId &Id) { + UnqualifiedId &Id, + bool AssumeTemplateId) { assert(Tok.is(tok::less) && "Expected '<' to finish parsing a template-id"); TemplateTy Template; @@ -833,8 +935,16 @@ case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_OperatorFunctionId: case UnqualifiedId::IK_LiteralOperatorId: - TNK = Actions.isTemplateName(CurScope, SS, Id, ObjectType, EnteringContext, - Template); + if (AssumeTemplateId) { + Template = Actions.ActOnDependentTemplateName(SourceLocation(), SS, + Id, ObjectType, + EnteringContext); + TNK = TNK_Dependent_template_name; + if (!Template.get()) + return true; + } else + TNK = Actions.isTemplateName(CurScope, SS, Id, ObjectType, + EnteringContext, Template); break; case UnqualifiedId::IK_ConstructorName: { Modified: cfe/trunk/lib/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=97045&r1=97044&r2=97045&view=diff ============================================================================== --- cfe/trunk/lib/Sema/Sema.h (original) +++ cfe/trunk/lib/Sema/Sema.h Wed Feb 24 12:44:31 2010 @@ -2175,7 +2175,18 @@ ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, - TypeTy *&ObjectType); + TypeTy *&ObjectType, + bool &MayBePseudoDestructor); + + virtual OwningExprResult ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + UnqualifiedId &FirstTypeName, + SourceLocation CCLoc, + SourceLocation TildeLoc, + UnqualifiedId &SecondTypeName, + bool HasTrailingLParen); /// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is /// non-empty, will create a new CXXExprWithTemporaries expression. Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=97045&r1=97044&r2=97045&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Feb 24 12:44:31 2010 @@ -21,6 +21,7 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Parse/DeclSpec.h" +#include "clang/Parse/Template.h" #include "llvm/ADT/STLExtras.h" using namespace clang; @@ -2325,7 +2326,8 @@ Sema::OwningExprResult Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, - tok::TokenKind OpKind, TypeTy *&ObjectType) { + tok::TokenKind OpKind, TypeTy *&ObjectType, + bool &MayBePseudoDestructor) { // Since this might be a postfix expression, get rid of ParenListExprs. Base = MaybeConvertParenListExprToParenExpr(S, move(Base)); @@ -2333,6 +2335,7 @@ assert(BaseExpr && "no record expansion"); QualType BaseType = BaseExpr->getType(); + MayBePseudoDestructor = false; if (BaseType->isDependentType()) { // If we have a pointer to a dependent type and are using the -> operator, // the object type is the type that the pointer points to. We might still @@ -2342,6 +2345,7 @@ BaseType = Ptr->getPointeeType(); ObjectType = BaseType.getAsOpaquePtr(); + MayBePseudoDestructor = true; return move(Base); } @@ -2383,7 +2387,11 @@ // [...] If the type of the object expression is of pointer to scalar // type, the unqualified-id is looked up in the context of the complete // postfix-expression. + // + // This also indicates that we should be parsing a + // pseudo-destructor-name. ObjectType = 0; + MayBePseudoDestructor = true; return move(Base); } @@ -2399,10 +2407,149 @@ // type C (or of pointer to a class type C), the unqualified-id is looked // up in the scope of class C. [...] ObjectType = BaseType.getAsOpaquePtr(); - return move(Base); } +Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + UnqualifiedId &FirstTypeName, + SourceLocation CCLoc, + SourceLocation TildeLoc, + UnqualifiedId &SecondTypeName, + bool HasTrailingLParen) { + assert((FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId || + FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) && + "Invalid first type name in pseudo-destructor"); + assert((SecondTypeName.getKind() == UnqualifiedId::IK_TemplateId || + SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) && + "Invalid second type name in pseudo-destructor"); + + Expr *BaseE = (Expr *)Base.get(); + QualType ObjectType; + if (BaseE->isTypeDependent()) + ObjectType = Context.DependentTy; + + // The nested-name-specifier provided by the parser, then extended + // by the "type-name ::" in the pseudo-destructor-name, if present. + CXXScopeSpec ExtendedSS = SS; + + if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId || + FirstTypeName.Identifier) { + // We have a pseudo-destructor with a "type-name ::". + // FIXME: As a temporary hack, we go ahead and resolve this to part of + // a nested-name-specifier. + if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) { + // Resolve the identifier to a nested-name-specifier. + CXXScopeTy *FinalScope + = ActOnCXXNestedNameSpecifier(S, SS, + FirstTypeName.StartLocation, + CCLoc, + *FirstTypeName.Identifier, + true, + ObjectType.getAsOpaquePtr(), + false); + if (SS.getBeginLoc().isInvalid()) + ExtendedSS.setBeginLoc(FirstTypeName.StartLocation); + ExtendedSS.setEndLoc(CCLoc); + ExtendedSS.setScopeRep(FinalScope); + } else { + // Resolve the template-id to a type, and that to a + // nested-name-specifier. + TemplateIdAnnotation *TemplateId = FirstTypeName.TemplateId; + ASTTemplateArgsPtr TemplateArgsPtr(*this, + TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc); + if (!T.isInvalid()) { + CXXScopeTy *FinalScope + = ActOnCXXNestedNameSpecifier(S, SS, T.get(), + SourceRange(TemplateId->TemplateNameLoc, + TemplateId->RAngleLoc), + CCLoc, + true); + if (SS.getBeginLoc().isInvalid()) + ExtendedSS.setBeginLoc(TemplateId->TemplateNameLoc); + ExtendedSS.setEndLoc(CCLoc); + ExtendedSS.setScopeRep(FinalScope); + } + } + } + + // Produce a destructor name based on the second type-name (which + // follows the tilde). + TypeTy *DestructedType; + SourceLocation EndLoc; + if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) { + const CXXScopeSpec *LookupSS = &SS; + bool isDependent = isDependentScopeSpecifier(ExtendedSS); + if (isDependent || computeDeclContext(ExtendedSS)) + LookupSS = &ExtendedSS; + + DestructedType = getTypeName(*SecondTypeName.Identifier, + SecondTypeName.StartLocation, + S, LookupSS, true, ObjectType.getTypePtr()); + if (!DestructedType && isDependent) { + // We didn't find our type, but that's okay: it's dependent + // anyway. + // FIXME: We should not be building a typename type here! + NestedNameSpecifier *NNS = 0; + SourceRange Range; + if (SS.isSet()) { + NNS = (NestedNameSpecifier *)ExtendedSS.getScopeRep(); + Range = SourceRange(ExtendedSS.getRange().getBegin(), + SecondTypeName.StartLocation); + } else { + NNS = NestedNameSpecifier::Create(Context, SecondTypeName.Identifier); + Range = SourceRange(SecondTypeName.StartLocation); + } + + DestructedType = CheckTypenameType(NNS, *SecondTypeName.Identifier, + Range).getAsOpaquePtr(); + if (!DestructedType) + return ExprError(); + } + + if (!DestructedType) { + // FIXME: Crummy diagnostic. + Diag(SecondTypeName.StartLocation, diag::err_destructor_class_name); + return ExprError(); + } + + EndLoc = SecondTypeName.EndLocation; + } else { + // Resolve the template-id to a type, and that to a + // nested-name-specifier. + TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId; + ASTTemplateArgsPtr TemplateArgsPtr(*this, + TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + EndLoc = TemplateId->RAngleLoc; + TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc); + if (T.isInvalid() || !T.get()) + return ExprError(); + + DestructedType = T.get(); + } + + // Form a (possibly fake) destructor name and let the member access + // expression code deal with this. + // FIXME: Don't do this! It's totally broken! + UnqualifiedId Destructor; + Destructor.setDestructorName(TildeLoc, DestructedType, EndLoc); + return ActOnMemberAccessExpr(S, move(Base), OpLoc, OpKind, ExtendedSS, + Destructor, DeclPtrTy(), HasTrailingLParen); +} + CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, CXXMethodDecl *Method) { if (PerformObjectArgumentInitialization(Exp, Method)) Modified: cfe/trunk/lib/Sema/TreeTransform.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=97045&r1=97044&r2=97045&view=diff ============================================================================== --- cfe/trunk/lib/Sema/TreeTransform.h (original) +++ cfe/trunk/lib/Sema/TreeTransform.h Wed Feb 24 12:44:31 2010 @@ -5041,10 +5041,12 @@ // Start the member reference and compute the object's type. Sema::TypeTy *ObjectTy = 0; + bool MayBePseudoDestructor = false; Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), E->getOperatorLoc(), E->isArrow()? tok::arrow : tok::period, - ObjectTy); + ObjectTy, + MayBePseudoDestructor); if (Base.isInvalid()) return SemaRef.ExprError(); From rjmccall at apple.com Wed Feb 24 14:32:01 2010 From: rjmccall at apple.com (John McCall) Date: Wed, 24 Feb 2010 20:32:01 -0000 Subject: [cfe-commits] r97055 - /cfe/trunk/lib/CodeGen/CGCXX.cpp Message-ID: <20100224203201.497302A6C130@llvm.org> Author: rjmccall Date: Wed Feb 24 14:32:01 2010 New Revision: 97055 URL: http://llvm.org/viewvc/llvm-project?rev=97055&view=rev Log: Fix an iterator-invalidation bug that was causing selfhost errors on non-darwin platforms. Fixes PR6411. Test case doesn't reduce, unfortunately. Modified: cfe/trunk/lib/CodeGen/CGCXX.cpp Modified: cfe/trunk/lib/CodeGen/CGCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXX.cpp?rev=97055&r1=97054&r2=97055&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGCXX.cpp (original) +++ cfe/trunk/lib/CodeGen/CGCXX.cpp Wed Feb 24 14:32:01 2010 @@ -140,15 +140,6 @@ const llvm::PointerType *AliasType = getTypes().GetFunctionType(AliasDecl)->getPointerTo(); - // Look for an existing entry. - const char *MangledName = getMangledName(AliasDecl); - llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName]; - if (Entry) { - assert(Entry->isDeclaration() && "definition already exists for alias"); - assert(Entry->getType() == AliasType && - "declaration exists with different type"); - } - // Find the referrent. Some aliases might require a bitcast, in // which case the caller is responsible for ensuring the soundness // of these semantics. @@ -161,8 +152,13 @@ llvm::GlobalAlias *Alias = new llvm::GlobalAlias(AliasType, Linkage, "", Aliasee, &getModule()); - // Switch any previous uses to the alias and kill the previous decl. + // Switch any previous uses to the alias. + const char *MangledName = getMangledName(AliasDecl); + llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName]; if (Entry) { + assert(Entry->isDeclaration() && "definition already exists for alias"); + assert(Entry->getType() == AliasType && + "declaration exists with different type"); Entry->replaceAllUsesWith(Alias); Entry->eraseFromParent(); } From dgregor at apple.com Wed Feb 24 15:29:12 2010 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 24 Feb 2010 21:29:12 -0000 Subject: [cfe-commits] r97058 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Parse/Action.h lib/Parse/ParseExprCXX.cpp lib/Sema/Sema.h lib/Sema/SemaCXXScopeSpec.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp test/SemaCXX/pseudo-destructors.cpp Message-ID: <20100224212913.1B4A72A6C136@llvm.org> Author: dgregor Date: Wed Feb 24 15:29:12 2010 New Revision: 97058 URL: http://llvm.org/viewvc/llvm-project?rev=97058&view=rev Log: ActOnPseudoDestructorExpr now performs all semantic analysis for pseudo-destructor expressions, and builds the CXXPseudoDestructorExpr node directly. Currently, this only affects pseudo-destructor expressions when they are parsed, but not after template instantiation. That's coming next... Improve parsing of pseudo-destructor-names. When parsing the nested-name-specifier and we hit the sequence of tokens X :: ~, query the actual module to determine whether X is a type-name (in which case the X :: is part of the pseudo-destructor-name but not the nested-name-specifier) or not (in which case the X :: is part of the nested-name-specifier). Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Parse/Action.h cfe/trunk/lib/Parse/ParseExprCXX.cpp cfe/trunk/lib/Sema/Sema.h cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/test/SemaCXX/pseudo-destructors.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=97058&r1=97057&r2=97058&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Feb 24 15:29:12 2010 @@ -2078,7 +2078,12 @@ def err_dtor_expr_without_call : Error< "%select{destructor reference|pseudo-destructor expression}0 must be " "called immediately with '()'">; - +def err_pseudo_dtor_destructor_non_type : Error< + "%0 does not refer to a type name in pseudo-destructor expression; expected " + "the name of type %1">; +def err_pseudo_dtor_template : Error< + "specialization of template %0 does not refer to a scalar type in pseudo-" + "destructor expression">; def err_invalid_use_of_function_type : Error< "a function type is not allowed here">; def err_invalid_use_of_array_type : Error<"an array type is not allowed here">; Modified: cfe/trunk/include/clang/Parse/Action.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=97058&r1=97057&r2=97058&view=diff ============================================================================== --- cfe/trunk/include/clang/Parse/Action.h (original) +++ cfe/trunk/include/clang/Parse/Action.h Wed Feb 24 15:29:12 2010 @@ -327,13 +327,26 @@ return false; } + /// \brief Determine whether the given name refers to a non-type nested name + /// specifier, e.g., the name of a namespace or namespace alias. + /// + /// This actual is used in the parsing of pseudo-destructor names to + /// distinguish a nested-name-specifier and a "type-name ::" when we + /// see the token sequence "X :: ~". + virtual bool isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, + SourceLocation IdLoc, + IdentifierInfo &II, + TypeTy *ObjectType) { + return false; + } + /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the /// global scope ('::'). virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S, SourceLocation CCLoc) { return 0; } - + /// \brief Parsed an identifier followed by '::' in a C++ /// nested-name-specifier. /// Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=97058&r1=97057&r2=97058&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original) +++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Wed Feb 24 15:29:12 2010 @@ -240,7 +240,9 @@ // If we get foo:bar, this is almost certainly a typo for foo::bar. Recover // and emit a fixit hint for it. if (Next.is(tok::colon) && !ColonIsSacred) { - if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) { + if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde) && + !Actions.isNonTypeNestedNameSpecifier(CurScope, SS, Tok.getLocation(), + II, ObjectType)) { *MayBePseudoDestructor = true; return HasScopeSpecifier; } @@ -261,7 +263,9 @@ } if (Next.is(tok::coloncolon)) { - if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) { + if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde) && + !Actions.isNonTypeNestedNameSpecifier(CurScope, SS, Tok.getLocation(), + II, ObjectType)) { *MayBePseudoDestructor = true; return HasScopeSpecifier; } Modified: cfe/trunk/lib/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=97058&r1=97057&r2=97058&view=diff ============================================================================== --- cfe/trunk/lib/Sema/Sema.h (original) +++ cfe/trunk/lib/Sema/Sema.h Wed Feb 24 15:29:12 2010 @@ -2178,6 +2178,20 @@ TypeTy *&ObjectType, bool &MayBePseudoDestructor); + OwningExprResult DiagnoseDtorReference(SourceLocation NameLoc, + ExprArg MemExpr); + + OwningExprResult ActOnDependentPseudoDestructorExpr(Scope *S, + ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + UnqualifiedId &FirstTypeName, + SourceLocation CCLoc, + SourceLocation TildeLoc, + UnqualifiedId &SecondTypeName, + bool HasTrailingLParen); + virtual OwningExprResult ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, @@ -2187,7 +2201,7 @@ SourceLocation TildeLoc, UnqualifiedId &SecondTypeName, bool HasTrailingLParen); - + /// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is /// non-empty, will create a new CXXExprWithTemporaries expression. /// Otherwise, just returs the passed in expression. @@ -2215,7 +2229,11 @@ bool MayBePseudoDestructor = false); NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS); - + virtual bool isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, + SourceLocation IdLoc, + IdentifierInfo &II, + TypeTy *ObjectType); + CXXScopeTy *BuildCXXNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, SourceLocation IdLoc, Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=97058&r1=97057&r2=97058&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original) +++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Wed Feb 24 15:29:12 2010 @@ -332,6 +332,54 @@ return 0; } +bool Sema::isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, + SourceLocation IdLoc, + IdentifierInfo &II, + TypeTy *ObjectTypePtr) { + QualType ObjectType = GetTypeFromParser(ObjectTypePtr); + LookupResult Found(*this, &II, IdLoc, LookupNestedNameSpecifierName); + + // Determine where to perform name lookup + DeclContext *LookupCtx = 0; + bool isDependent = false; + if (!ObjectType.isNull()) { + // This nested-name-specifier occurs in a member access expression, e.g., + // x->B::f, and we are looking into the type of the object. + assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); + LookupCtx = computeDeclContext(ObjectType); + isDependent = ObjectType->isDependentType(); + } else if (SS.isSet()) { + // This nested-name-specifier occurs after another nested-name-specifier, + // so long into the context associated with the prior nested-name-specifier. + LookupCtx = computeDeclContext(SS, false); + isDependent = isDependentScopeSpecifier(SS); + Found.setContextRange(SS.getRange()); + } + + if (LookupCtx) { + // Perform "qualified" name lookup into the declaration context we + // computed, which is either the type of the base of a member access + // expression or the declaration context associated with a prior + // nested-name-specifier. + + // The declaration context must be complete. + if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS)) + return false; + + LookupQualifiedName(Found, LookupCtx); + } else if (isDependent) { + return false; + } else { + LookupName(Found, S); + } + Found.suppressDiagnostics(); + + if (NamedDecl *ND = Found.getAsSingle()) + return isa(ND) || isa(ND); + + return false; +} + /// \brief Build a new nested-name-specifier for "identifier::", as described /// by ActOnCXXNestedNameSpecifier. /// Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=97058&r1=97057&r2=97058&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Feb 24 15:29:12 2010 @@ -3178,23 +3178,6 @@ return ExprError(); } -static Sema::OwningExprResult DiagnoseDtorReference(Sema &SemaRef, - SourceLocation NameLoc, - Sema::ExprArg MemExpr) { - Expr *E = (Expr *) MemExpr.get(); - SourceLocation ExpectedLParenLoc = SemaRef.PP.getLocForEndOfToken(NameLoc); - SemaRef.Diag(E->getLocStart(), diag::err_dtor_expr_without_call) - << isa(E) - << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()"); - - return SemaRef.ActOnCallExpr(/*Scope*/ 0, - move(MemExpr), - /*LPLoc*/ ExpectedLParenLoc, - Sema::MultiExprArg(SemaRef, 0, 0), - /*CommaLocs*/ 0, - /*RPLoc*/ ExpectedLParenLoc); -} - /// The main callback when the parser finds something like /// expression . [nested-name-specifier] identifier /// expression -> [nested-name-specifier] identifier @@ -3265,7 +3248,7 @@ // call now. if (!HasTrailingLParen && Id.getKind() == UnqualifiedId::IK_DestructorName) - return DiagnoseDtorReference(*this, NameLoc, move(Result)); + return DiagnoseDtorReference(NameLoc, move(Result)); return move(Result); } Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=97058&r1=97057&r2=97058&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Feb 24 15:29:12 2010 @@ -2410,31 +2410,41 @@ return move(Base); } -Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - const CXXScopeSpec &SS, - UnqualifiedId &FirstTypeName, - SourceLocation CCLoc, - SourceLocation TildeLoc, - UnqualifiedId &SecondTypeName, - bool HasTrailingLParen) { - assert((FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId || - FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) && - "Invalid first type name in pseudo-destructor"); - assert((SecondTypeName.getKind() == UnqualifiedId::IK_TemplateId || - SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) && - "Invalid second type name in pseudo-destructor"); +Sema::OwningExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc, + ExprArg MemExpr) { + Expr *E = (Expr *) MemExpr.get(); + SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(NameLoc); + Diag(E->getLocStart(), diag::err_dtor_expr_without_call) + << isa(E) + << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()"); + + return ActOnCallExpr(/*Scope*/ 0, + move(MemExpr), + /*LPLoc*/ ExpectedLParenLoc, + Sema::MultiExprArg(*this, 0, 0), + /*CommaLocs*/ 0, + /*RPLoc*/ ExpectedLParenLoc); +} +Sema::OwningExprResult +Sema::ActOnDependentPseudoDestructorExpr(Scope *S, + ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + UnqualifiedId &FirstTypeName, + SourceLocation CCLoc, + SourceLocation TildeLoc, + UnqualifiedId &SecondTypeName, + bool HasTrailingLParen) { Expr *BaseE = (Expr *)Base.get(); - QualType ObjectType; - if (BaseE->isTypeDependent()) - ObjectType = Context.DependentTy; - + QualType ObjectType = BaseE->getType(); + assert(ObjectType->isDependentType()); + // The nested-name-specifier provided by the parser, then extended // by the "type-name ::" in the pseudo-destructor-name, if present. CXXScopeSpec ExtendedSS = SS; - + if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId || FirstTypeName.Identifier) { // We have a pseudo-destructor with a "type-name ::". @@ -2443,13 +2453,13 @@ if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) { // Resolve the identifier to a nested-name-specifier. CXXScopeTy *FinalScope - = ActOnCXXNestedNameSpecifier(S, SS, - FirstTypeName.StartLocation, - CCLoc, - *FirstTypeName.Identifier, - true, - ObjectType.getAsOpaquePtr(), - false); + = ActOnCXXNestedNameSpecifier(S, SS, + FirstTypeName.StartLocation, + CCLoc, + *FirstTypeName.Identifier, + true, + ObjectType.getAsOpaquePtr(), + false); if (SS.getBeginLoc().isInvalid()) ExtendedSS.setBeginLoc(FirstTypeName.StartLocation); ExtendedSS.setEndLoc(CCLoc); @@ -2468,11 +2478,11 @@ TemplateId->RAngleLoc); if (!T.isInvalid()) { CXXScopeTy *FinalScope - = ActOnCXXNestedNameSpecifier(S, SS, T.get(), - SourceRange(TemplateId->TemplateNameLoc, - TemplateId->RAngleLoc), - CCLoc, - true); + = ActOnCXXNestedNameSpecifier(S, SS, T.get(), + SourceRange(TemplateId->TemplateNameLoc, + TemplateId->RAngleLoc), + CCLoc, + true); if (SS.getBeginLoc().isInvalid()) ExtendedSS.setBeginLoc(TemplateId->TemplateNameLoc); ExtendedSS.setEndLoc(CCLoc); @@ -2480,7 +2490,7 @@ } } } - + // Produce a destructor name based on the second type-name (which // follows the tilde). TypeTy *DestructedType; @@ -2490,7 +2500,7 @@ bool isDependent = isDependentScopeSpecifier(ExtendedSS); if (isDependent || computeDeclContext(ExtendedSS)) LookupSS = &ExtendedSS; - + DestructedType = getTypeName(*SecondTypeName.Identifier, SecondTypeName.StartLocation, S, LookupSS, true, ObjectType.getTypePtr()); @@ -2514,13 +2524,13 @@ if (!DestructedType) return ExprError(); } - + if (!DestructedType) { // FIXME: Crummy diagnostic. Diag(SecondTypeName.StartLocation, diag::err_destructor_class_name); return ExprError(); } - + EndLoc = SecondTypeName.EndLocation; } else { // Resolve the template-id to a type, and that to a @@ -2528,7 +2538,7 @@ TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId; ASTTemplateArgsPtr TemplateArgsPtr(*this, TemplateId->getTemplateArgs(), - TemplateId->NumArgs); + TemplateId->NumArgs); EndLoc = TemplateId->RAngleLoc; TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), TemplateId->TemplateNameLoc, @@ -2540,7 +2550,7 @@ DestructedType = T.get(); } - + // Form a (possibly fake) destructor name and let the member access // expression code deal with this. // FIXME: Don't do this! It's totally broken! @@ -2548,6 +2558,169 @@ Destructor.setDestructorName(TildeLoc, DestructedType, EndLoc); return ActOnMemberAccessExpr(S, move(Base), OpLoc, OpKind, ExtendedSS, Destructor, DeclPtrTy(), HasTrailingLParen); + +} + +Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + UnqualifiedId &FirstTypeName, + SourceLocation CCLoc, + SourceLocation TildeLoc, + UnqualifiedId &SecondTypeName, + bool HasTrailingLParen) { + assert((FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId || + FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) && + "Invalid first type name in pseudo-destructor"); + assert((SecondTypeName.getKind() == UnqualifiedId::IK_TemplateId || + SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) && + "Invalid second type name in pseudo-destructor"); + + Expr *BaseE = (Expr *)Base.get(); + if (BaseE->isTypeDependent()) + return ActOnDependentPseudoDestructorExpr(S, move(Base), OpLoc, OpKind, + SS, FirstTypeName, CCLoc, + TildeLoc, SecondTypeName, + HasTrailingLParen); + + // C++ [expr.pseudo]p2: + // The left-hand side of the dot operator shall be of scalar type. The + // left-hand side of the arrow operator shall be of pointer to scalar type. + // This scalar type is the object type. + QualType ObjectType = BaseE->getType(); + if (OpKind == tok::arrow) { + if (const PointerType *Ptr = ObjectType->getAs()) { + ObjectType = Ptr->getPointeeType(); + } else { + // The user wrote "p->" when she probably meant "p."; fix it. + Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) + << ObjectType << true + << CodeModificationHint::CreateReplacement(OpLoc, "."); + if (isSFINAEContext()) + return ExprError(); + + OpKind = tok::period; + } + } + + if (!ObjectType->isScalarType()) { + Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar) + << ObjectType << BaseE->getSourceRange(); + return ExprError(); + } + + // + + // C++ [expr.pseudo]p2: + // [...] The cv-unqualified versions of the object type and of the type + // designated by the pseudo-destructor-name shall be the same type. + QualType DestructedType; + TypeSourceInfo *DestructedTypeInfo = 0; + if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) { + TypeTy *T = getTypeName(*SecondTypeName.Identifier, + SecondTypeName.StartLocation, + S, &SS); + if (!T) { + Diag(SecondTypeName.StartLocation, + diag::err_pseudo_dtor_destructor_non_type) + << SecondTypeName.Identifier << ObjectType; + if (isSFINAEContext()) + return ExprError(); + + // Recover by assuming we had the right type all along. + DestructedType = ObjectType; + } else { + DestructedType = GetTypeFromParser(T, &DestructedTypeInfo); + + if (!DestructedType->isDependentType() && + !Context.hasSameUnqualifiedType(DestructedType, ObjectType)) { + // The types mismatch. Recover by assuming we had the right type + // all along. + Diag(SecondTypeName.StartLocation, diag::err_pseudo_dtor_type_mismatch) + << ObjectType << DestructedType << BaseE->getSourceRange(); + + DestructedType = ObjectType; + DestructedTypeInfo = 0; + } + } + } else { + // FIXME: C++0x template aliases would allow a template-id here. For now, + // just diagnose this as an error. + TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId; + Diag(TemplateId->TemplateNameLoc, diag::err_pseudo_dtor_template) + << TemplateId->Name << ObjectType + << SourceRange(TemplateId->TemplateNameLoc, TemplateId->RAngleLoc); + if (isSFINAEContext()) + return ExprError(); + + // Recover by assuming we had the right type all along. + DestructedType = ObjectType; + } + + // C++ [expr.pseudo]p2: + // [...] Furthermore, the two type-names in a pseudo-destructor-name of the + // form + // + // ::[opt] nested-name-specifier[opt] type-name :: ~ type-name + // + // shall designate the same scalar type. + QualType ScopeType; + if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId || + FirstTypeName.Identifier) { + if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) { + TypeTy *T = getTypeName(*FirstTypeName.Identifier, + FirstTypeName.StartLocation, + S, &SS); + if (!T) { + Diag(FirstTypeName.StartLocation, + diag::err_pseudo_dtor_destructor_non_type) + << FirstTypeName.Identifier << ObjectType; + if (isSFINAEContext()) + return ExprError(); + } else { + // FIXME: Drops source-location information. + ScopeType = GetTypeFromParser(T); + + if (!ScopeType->isDependentType() && + !Context.hasSameUnqualifiedType(DestructedType, ScopeType)) { + // The types mismatch. Recover by assuming we don't have a scoping + // type. + Diag(FirstTypeName.StartLocation, diag::err_pseudo_dtor_type_mismatch) + << ObjectType << ScopeType << BaseE->getSourceRange(); + + ScopeType = QualType(); + } + } + } else { + // FIXME: C++0x template aliases would allow a template-id here. For now, + // just diagnose this as an error. + TemplateIdAnnotation *TemplateId = FirstTypeName.TemplateId; + Diag(TemplateId->TemplateNameLoc, diag::err_pseudo_dtor_template) + << TemplateId->Name << ObjectType + << SourceRange(TemplateId->TemplateNameLoc, TemplateId->RAngleLoc); + if (isSFINAEContext()) + return ExprError(); + + // Recover by assuming we have no scoping type. + DestructedType = ObjectType; + } + } + + // FIXME: Drops the scope type. + OwningExprResult Result + = Owned(new (Context) CXXPseudoDestructorExpr(Context, + Base.takeAs(), + OpKind == tok::arrow, + OpLoc, + (NestedNameSpecifier *) SS.getScopeRep(), + SS.getRange(), + DestructedType, + SecondTypeName.StartLocation)); + if (HasTrailingLParen) + return move(Result); + + return DiagnoseDtorReference(SecondTypeName.StartLocation, move(Result)); } CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, Modified: cfe/trunk/test/SemaCXX/pseudo-destructors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/pseudo-destructors.cpp?rev=97058&r1=97057&r2=97058&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/pseudo-destructors.cpp (original) +++ cfe/trunk/test/SemaCXX/pseudo-destructors.cpp Wed Feb 24 15:29:12 2010 @@ -11,6 +11,7 @@ namespace N { typedef Foo Wibble; + typedef int OtherInteger; } void f(A* a, Foo *f, int *i, double *d) { @@ -35,8 +36,11 @@ i->~Integer(); i->Integer::~Integer(); - - i->Integer::~Double(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('double') in pseudo-destructor expression}} + i->N::~OtherInteger(); + i->N::OtherInteger::~OtherInteger(); + i->N::OtherInteger::~Integer(); // expected-error{{'Integer' does not refer to a type name in pseudo-destructor expression; expected the name of type 'int'}} + i->N::~Integer(); // expected-error{{'Integer' does not refer to a type name in pseudo-destructor expression; expected the name of type 'int'}} + i->Integer::~Double(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('Double' (aka 'double')) in pseudo-destructor expression}} } typedef int Integer; From dgregor at apple.com Wed Feb 24 15:52:20 2010 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 24 Feb 2010 21:52:20 -0000 Subject: [cfe-commits] r97060 - in /cfe/trunk: include/clang/AST/ExprCXX.h lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp Message-ID: <20100224215220.DBFDE2A6C136@llvm.org> Author: dgregor Date: Wed Feb 24 15:52:20 2010 New Revision: 97060 URL: http://llvm.org/viewvc/llvm-project?rev=97060&view=rev Log: Retain source information for the "type-name ::" in a pseudo-destructor expression such as p->T::~T() Modified: cfe/trunk/include/clang/AST/ExprCXX.h cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/lib/Sema/SemaExprCXX.cpp Modified: cfe/trunk/include/clang/AST/ExprCXX.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=97060&r1=97059&r2=97060&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ExprCXX.h (original) +++ cfe/trunk/include/clang/AST/ExprCXX.h Wed Feb 24 15:52:20 2010 @@ -999,19 +999,28 @@ /// \brief Represents a C++ pseudo-destructor (C++ [expr.pseudo]). /// -/// Example: +/// A pseudo-destructor is an expression that looks like a member access to a +/// destructor of a scalar type, except that scalar types don't have +/// destructors. For example: +/// +/// \code +/// typedef int T; +/// void f(int *p) { +/// p->T::~T(); +/// } +/// \endcode /// +/// Pseudo-destructors typically occur when instantiating templates such as: +/// /// \code /// template /// void destroy(T* ptr) { -/// ptr->~T(); +/// ptr->T::~T(); /// } /// \endcode /// -/// When the template is parsed, the expression \c ptr->~T will be stored as -/// a member reference expression. If it then instantiated with a scalar type -/// as a template argument for T, the resulting expression will be a -/// pseudo-destructor expression. +/// for scalar types. A pseudo-destructor expression has no run-time semantics +/// beyond evaluating the base expression. class CXXPseudoDestructorExpr : public Expr { /// \brief The base expression (that is being destroyed). Stmt *Base; @@ -1030,6 +1039,14 @@ /// present. SourceRange QualifierRange; + /// \brief The type that precedes the '::' in a qualified pseudo-destructor + /// expression. + TypeSourceInfo *ScopeType; + + /// \brief The location of the '::' in a qualified pseudo-destructor + /// expression. + SourceLocation ColonColonLoc; + /// \brief The type being destroyed. QualType DestroyedType; @@ -1041,6 +1058,8 @@ Expr *Base, bool isArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, + TypeSourceInfo *ScopeType, + SourceLocation ColonColonLoc, QualType DestroyedType, SourceLocation DestroyedTypeLoc) : Expr(CXXPseudoDestructorExprClass, @@ -1052,8 +1071,9 @@ /*isValueDependent=*/Base->isValueDependent()), Base(static_cast(Base)), IsArrow(isArrow), OperatorLoc(OperatorLoc), Qualifier(Qualifier), - QualifierRange(QualifierRange), DestroyedType(DestroyedType), - DestroyedTypeLoc(DestroyedTypeLoc) { } + QualifierRange(QualifierRange), + ScopeType(ScopeType), ColonColonLoc(ColonColonLoc), + DestroyedType(DestroyedType), DestroyedTypeLoc(DestroyedTypeLoc) { } void setBase(Expr *E) { Base = E; } Expr *getBase() const { return cast(Base); } @@ -1081,6 +1101,21 @@ /// \brief Retrieve the location of the '.' or '->' operator. SourceLocation getOperatorLoc() const { return OperatorLoc; } + /// \brief Retrieve the scope type in a qualified pseudo-destructor + /// expression. + /// + /// Pseudo-destructor expressions can have extra qualification within them + /// that is not part of the nested-name-specifier, e.g., \c p->T::~T(). + /// Here, if the object type of the expression is (or may be) a scalar type, + /// \p T may also be a scalar type and, therefore, cannot be part of a + /// nested-name-specifier. It is stored as the "scope type" of the pseudo- + /// destructor expression. + TypeSourceInfo *getScopeTypeLoc() const { return ScopeType; } + + /// \brief Retrieve the location of the '::' in a qualified pseudo-destructor + /// expression. + SourceLocation getColonColonLoc() const { return ColonColonLoc; } + /// \brief Retrieve the type that is being destroyed. QualType getDestroyedType() const { return DestroyedType; } Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=97060&r1=97059&r2=97060&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Feb 24 15:52:20 2010 @@ -2936,6 +2936,7 @@ IsArrow, OpLoc, (NestedNameSpecifier *) SS.getScopeRep(), SS.getRange(), + 0, SourceLocation(), MemberName.getCXXNameType(), MemberLoc)); } Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=97060&r1=97059&r2=97060&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Feb 24 15:52:20 2010 @@ -2664,7 +2664,8 @@ // // ::[opt] nested-name-specifier[opt] type-name :: ~ type-name // - // shall designate the same scalar type. + // shall designate the same scalar type. + TypeSourceInfo *ScopeTypeLoc; QualType ScopeType; if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId || FirstTypeName.Identifier) { @@ -2680,7 +2681,7 @@ return ExprError(); } else { // FIXME: Drops source-location information. - ScopeType = GetTypeFromParser(T); + ScopeType = GetTypeFromParser(T, &ScopeTypeLoc); if (!ScopeType->isDependentType() && !Context.hasSameUnqualifiedType(DestructedType, ScopeType)) { @@ -2690,6 +2691,7 @@ << ObjectType << ScopeType << BaseE->getSourceRange(); ScopeType = QualType(); + ScopeTypeLoc = 0; } } } else { @@ -2707,7 +2709,6 @@ } } - // FIXME: Drops the scope type. OwningExprResult Result = Owned(new (Context) CXXPseudoDestructorExpr(Context, Base.takeAs(), @@ -2715,6 +2716,8 @@ OpLoc, (NestedNameSpecifier *) SS.getScopeRep(), SS.getRange(), + ScopeTypeLoc, + CCLoc, DestructedType, SecondTypeName.StartLocation)); if (HasTrailingLParen) From dgregor at apple.com Wed Feb 24 15:52:55 2010 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 24 Feb 2010 21:52:55 -0000 Subject: [cfe-commits] r97061 - in /cfe/trunk/test/PCH: Inputs/ Inputs/namespaces.h namespaces.cpp Message-ID: <20100224215255.504192A6C136@llvm.org> Author: dgregor Date: Wed Feb 24 15:52:55 2010 New Revision: 97061 URL: http://llvm.org/viewvc/llvm-project?rev=97061&view=rev Log: Add PCH test for C++ namespaces, missing from a previous commit Added: cfe/trunk/test/PCH/Inputs/ cfe/trunk/test/PCH/Inputs/namespaces.h cfe/trunk/test/PCH/namespaces.cpp Added: cfe/trunk/test/PCH/Inputs/namespaces.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/Inputs/namespaces.h?rev=97061&view=auto ============================================================================== --- cfe/trunk/test/PCH/Inputs/namespaces.h (added) +++ cfe/trunk/test/PCH/Inputs/namespaces.h Wed Feb 24 15:52:55 2010 @@ -0,0 +1,13 @@ +// Header for PCH test namespaces.cpp + +namespace N1 { + typedef int t1; +} + +namespace N1 { + typedef int t2; +} + +namespace N2 { + typedef float t1; +} Added: cfe/trunk/test/PCH/namespaces.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/namespaces.cpp?rev=97061&view=auto ============================================================================== --- cfe/trunk/test/PCH/namespaces.cpp (added) +++ cfe/trunk/test/PCH/namespaces.cpp Wed Feb 24 15:52:55 2010 @@ -0,0 +1,14 @@ +// Test this without pch. +// RUN: %clang_cc1 -x c++ -include %S/Inputs/namespaces.h -fsyntax-only %s + +// Test with pch. +// RUN: %clang_cc1 -x c++ -emit-pch -o %t %S/Inputs/namespaces.h +// RUN: %clang_cc1 -x c++ -include-pch %t -fsyntax-only %s + +int int_val; +N1::t1 *ip1 = &int_val; +N1::t2 *ip2 = &int_val; + +float float_val; +namespace N2 { } +N2::t1 *fp1 = &float_val; From dgregor at apple.com Wed Feb 24 15:53:36 2010 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 24 Feb 2010 21:53:36 -0000 Subject: [cfe-commits] r97062 - in /cfe/trunk/test/ASTMerge: Inputs/namespace1.cpp Inputs/namespace2.cpp namespace.cpp Message-ID: <20100224215336.701A52A6C136@llvm.org> Author: dgregor Date: Wed Feb 24 15:53:36 2010 New Revision: 97062 URL: http://llvm.org/viewvc/llvm-project?rev=97062&view=rev Log: Add test for AST importing of C++ namespaces, missing from a prior commit Added: cfe/trunk/test/ASTMerge/Inputs/namespace1.cpp cfe/trunk/test/ASTMerge/Inputs/namespace2.cpp cfe/trunk/test/ASTMerge/namespace.cpp Added: cfe/trunk/test/ASTMerge/Inputs/namespace1.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/Inputs/namespace1.cpp?rev=97062&view=auto ============================================================================== --- cfe/trunk/test/ASTMerge/Inputs/namespace1.cpp (added) +++ cfe/trunk/test/ASTMerge/Inputs/namespace1.cpp Wed Feb 24 15:53:36 2010 @@ -0,0 +1,17 @@ +// Merge success +namespace N1 { + int x; +} + +// Merge multiple namespaces +namespace N2 { + extern int x; +} +namespace N2 { + extern float y; +} + +// Merge namespace with conflict +namespace N3 { + extern float z; +} Added: cfe/trunk/test/ASTMerge/Inputs/namespace2.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/Inputs/namespace2.cpp?rev=97062&view=auto ============================================================================== --- cfe/trunk/test/ASTMerge/Inputs/namespace2.cpp (added) +++ cfe/trunk/test/ASTMerge/Inputs/namespace2.cpp Wed Feb 24 15:53:36 2010 @@ -0,0 +1,17 @@ +// Merge success +namespace N1 { + extern int x0; +} + +// Merge multiple namespaces +namespace N2 { + extern int x; +} +namespace N2 { + extern float y; +} + +// Merge namespace with conflict +namespace N3 { + extern double z; +} Added: cfe/trunk/test/ASTMerge/namespace.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/namespace.cpp?rev=97062&view=auto ============================================================================== --- cfe/trunk/test/ASTMerge/namespace.cpp (added) +++ cfe/trunk/test/ASTMerge/namespace.cpp Wed Feb 24 15:53:36 2010 @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/namespace1.cpp +// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/namespace2.cpp +// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s + +// CHECK: namespace2.cpp:16:17: error: external variable 'z' declared with incompatible types in different translation units ('double' vs. 'float') +// CHECK: namespace1.cpp:16:16: note: declared here with type 'float' From dgregor at apple.com Wed Feb 24 15:54:27 2010 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 24 Feb 2010 21:54:27 -0000 Subject: [cfe-commits] r97063 - /cfe/trunk/test/CXX/special/class.copy/p3.cpp Message-ID: <20100224215427.4650C2A6C136@llvm.org> Author: dgregor Date: Wed Feb 24 15:54:27 2010 New Revision: 97063 URL: http://llvm.org/viewvc/llvm-project?rev=97063&view=rev Log: Add test case for PR6141, which was fixed a few days ago Added: cfe/trunk/test/CXX/special/class.copy/p3.cpp Added: cfe/trunk/test/CXX/special/class.copy/p3.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.copy/p3.cpp?rev=97063&view=auto ============================================================================== --- cfe/trunk/test/CXX/special/class.copy/p3.cpp (added) +++ cfe/trunk/test/CXX/special/class.copy/p3.cpp Wed Feb 24 15:54:27 2010 @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s + +// PR6141 +template +struct X { + X(); + template X(X); + X(const X&); +}; + +void f(X) { } + +struct Y : X { }; +struct Z : X { }; + +// CHECK: define i32 @main() +int main() { + // CHECK: call void @_ZN1YC1Ev + // CHECK: call void @_ZN1XIiEC1ERKS0_ + // CHECK: call void @_Z1f1XIiE + f(Y()); + // CHECK: call void @_ZN1ZC1Ev + // CHECK: call void @_ZN1XIfEC1ERKS0_ + // CHECK: call void @_ZN1XIiEC1IfEES_IT_E + // CHECK: call void @_Z1f1XIiE + f(Z()); +} From andersca at mac.com Wed Feb 24 16:18:02 2010 From: andersca at mac.com (Anders Carlsson) Date: Wed, 24 Feb 2010 22:18:02 -0000 Subject: [cfe-commits] r97066 - /cfe/trunk/lib/CodeGen/CGVtable.cpp Message-ID: <20100224221802.27F892A6C136@llvm.org> Author: andersca Date: Wed Feb 24 16:18:01 2010 New Revision: 97066 URL: http://llvm.org/viewvc/llvm-project?rev=97066&view=rev Log: Make ComputeThisAdjustmentBaseOffset public for now. Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=97066&r1=97065&r2=97066&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVtable.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVtable.cpp Wed Feb 24 16:18:01 2010 @@ -144,17 +144,18 @@ const CXXMethodDecl *NewMD, SubobjectOffsetsMapTy &Offsets); - /// ComputeThisAdjustmentBaseOffset - Compute the base offset for adjusting - /// the 'this' pointer from the base subobject to the derived subobject. - BaseOffset ComputeThisAdjustmentBaseOffset(BaseSubobject Base, - BaseSubobject Derived); - static void MergeSubobjectOffsets(const SubobjectOffsetsMapTy &NewOffsets, SubobjectOffsetsMapTy &Offsets); public: explicit FinalOverriders(const CXXRecordDecl *MostDerivedClass); - + + /// ComputeThisAdjustmentBaseOffset - Compute the base offset for adjusting + /// the 'this' pointer from the base subobject to the derived subobject. + /// FIXME: This should move to VtableBuilder. + BaseOffset ComputeThisAdjustmentBaseOffset(BaseSubobject Base, + BaseSubobject Derived) const; + /// getOverrider - Get the final overrider for the given method declaration in /// the given base subobject. OverriderInfo getOverrider(BaseSubobject Base, @@ -357,7 +358,7 @@ BaseOffset FinalOverriders::ComputeThisAdjustmentBaseOffset(BaseSubobject Base, - BaseSubobject Derived) { + BaseSubobject Derived) const { const CXXRecordDecl *BaseRD = Base.getBase(); const CXXRecordDecl *DerivedRD = Derived.getBase(); From andersca at mac.com Wed Feb 24 16:27:12 2010 From: andersca at mac.com (Anders Carlsson) Date: Wed, 24 Feb 2010 22:27:12 -0000 Subject: [cfe-commits] r97067 - /cfe/trunk/lib/CodeGen/CGVtable.cpp Message-ID: <20100224222712.339FC2A6C136@llvm.org> Author: andersca Date: Wed Feb 24 16:27:12 2010 New Revision: 97067 URL: http://llvm.org/viewvc/llvm-project?rev=97067&view=rev Log: Improve this adjustment pointer calculation. Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=97067&r1=97066&r2=97067&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVtable.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVtable.cpp Wed Feb 24 16:27:12 2010 @@ -1432,12 +1432,23 @@ ReturnAdjustment ReturnAdjustment = ComputeReturnAdjustment(ReturnAdjustmentOffset); - // Check if this overrider needs a 'this' pointer adjustment. - BaseOffset ThisAdjustmentOffset = - Overriders.getThisAdjustmentOffset(Base, MD); + ThisAdjustment ThisAdjustment; - ThisAdjustment ThisAdjustment = ComputeThisAdjustment(Overrider.Method, - ThisAdjustmentOffset); + // Check if this overrider needs a 'this' pointer adjustment. + // (We use the base offset of the first base in the primary base chain here, + // because Base will not have the right offset if it is a primary virtual + // base that is not a primary base in the complete class. + if (FirstBaseInPrimaryBaseChain.getBaseOffset() != Overrider.BaseOffset) { + BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(), + Overrider.BaseOffset); + + BaseOffset ThisAdjustmentOffset = + Overriders.ComputeThisAdjustmentBaseOffset(FirstBaseInPrimaryBaseChain, + OverriderBaseSubobject); + + ThisAdjustment = ComputeThisAdjustment(Overrider.Method, + ThisAdjustmentOffset); + } AddMethod(Overrider.Method, ReturnAdjustment, ThisAdjustment); } From andersca at mac.com Wed Feb 24 16:32:18 2010 From: andersca at mac.com (Anders Carlsson) Date: Wed, 24 Feb 2010 22:32:18 -0000 Subject: [cfe-commits] r97068 - /cfe/trunk/lib/CodeGen/CGVtable.cpp Message-ID: <20100224223218.6AC642A6C136@llvm.org> Author: andersca Date: Wed Feb 24 16:32:18 2010 New Revision: 97068 URL: http://llvm.org/viewvc/llvm-project?rev=97068&view=rev Log: Get rid of 'this' adjustments from the FinalOverriders class since they can be different for the same overrider in different parts of the vtable. Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=97068&r1=97067&r2=97068&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVtable.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVtable.cpp Wed Feb 24 16:32:18 2010 @@ -97,10 +97,6 @@ /// ReturnAdjustments - Holds return adjustments for all the overriders that /// need to perform return value adjustments. AdjustmentOffsetsMapTy ReturnAdjustments; - - /// ThisAdjustments - Holds 'this' adjustments for all the overriders that - /// need them. - AdjustmentOffsetsMapTy ThisAdjustments; typedef llvm::SmallVector OffsetVectorTy; @@ -174,14 +170,6 @@ return ReturnAdjustments.lookup(std::make_pair(Base, MD)); } - /// getThisAdjustmentOffset - Get the 'this' pointer adjustment offset for the - /// method decl in the given base subobject. Returns an empty base offset if - /// no adjustment is needed. - BaseOffset getThisAdjustmentOffset(BaseSubobject Base, - const CXXMethodDecl *MD) const { - return ThisAdjustments.lookup(std::make_pair(Base, MD)); - } - /// dump - dump the final overriders. void dump() { assert(VisitedVirtualBases.empty() && @@ -450,17 +438,6 @@ // Store the return adjustment base offset. ReturnAdjustments[SubobjectAndMethod] = ReturnBaseOffset; } - - // Check if we need a 'this' adjustment base offset as well. - if (Offset != NewBase.getBaseOffset()) { - BaseOffset ThisBaseOffset = - ComputeThisAdjustmentBaseOffset(OverriddenSubobject, - NewBase); - assert(!ThisBaseOffset.isEmpty() && - "Should not get an empty 'this' adjustment!"); - - ThisAdjustments[SubobjectAndMethod] = ThisBaseOffset; - } } // Set the new overrider. @@ -639,17 +616,6 @@ Out << Offset.NonVirtualOffset << " nv]"; } - AI = ThisAdjustments.find(std::make_pair(Base, MD)); - if (AI != ThisAdjustments.end()) { - const BaseOffset &Offset = AI->second; - - Out << " [this-adj: "; - if (Offset.VirtualBase) - Out << Offset.VirtualBase->getQualifiedNameAsString() << " vbase, "; - - Out << Offset.NonVirtualOffset << " nv]"; - } - Out << "\n"; } } From dgregor at apple.com Wed Feb 24 16:38:50 2010 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 24 Feb 2010 22:38:50 -0000 Subject: [cfe-commits] r97070 - in /cfe/trunk/lib/Sema: Sema.h SemaExprCXX.cpp Message-ID: <20100224223851.065C82A6C136@llvm.org> Author: dgregor Date: Wed Feb 24 16:38:50 2010 New Revision: 97070 URL: http://llvm.org/viewvc/llvm-project?rev=97070&view=rev Log: Split ActOnPseudoDestructorExpr into the part that interprets the parser's data structures and the part that performs semantic analysis and AST building, in preparation for improved template instantiation of pseudo-destructor expressions. Modified: cfe/trunk/lib/Sema/Sema.h cfe/trunk/lib/Sema/SemaExprCXX.cpp Modified: cfe/trunk/lib/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=97070&r1=97069&r2=97070&view=diff ============================================================================== --- cfe/trunk/lib/Sema/Sema.h (original) +++ cfe/trunk/lib/Sema/Sema.h Wed Feb 24 16:38:50 2010 @@ -2181,6 +2181,15 @@ OwningExprResult DiagnoseDtorReference(SourceLocation NameLoc, ExprArg MemExpr); + OwningExprResult BuildPseudoDestructorExpr(ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + TypeSourceInfo *ScopeType, + SourceLocation CCLoc, + TypeSourceInfo *DestroyedType, + bool HasTrailingLParen); + OwningExprResult ActOnDependentPseudoDestructorExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=97070&r1=97069&r2=97070&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Feb 24 16:38:50 2010 @@ -17,6 +17,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/TypeLoc.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" @@ -2426,6 +2427,102 @@ /*RPLoc*/ ExpectedLParenLoc); } +Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + TypeSourceInfo *ScopeTypeInfo, + SourceLocation CCLoc, + TypeSourceInfo *DestructedTypeLoc, + bool HasTrailingLParen) { + assert(DestructedTypeLoc && "No destructed type in pseudo-destructor expr?"); + + // C++ [expr.pseudo]p2: + // The left-hand side of the dot operator shall be of scalar type. The + // left-hand side of the arrow operator shall be of pointer to scalar type. + // This scalar type is the object type. + Expr *BaseE = (Expr *)Base.get(); + QualType ObjectType = BaseE->getType(); + if (OpKind == tok::arrow) { + if (const PointerType *Ptr = ObjectType->getAs()) { + ObjectType = Ptr->getPointeeType(); + } else if (!BaseE->isTypeDependent()) { + // The user wrote "p->" when she probably meant "p."; fix it. + Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) + << ObjectType << true + << CodeModificationHint::CreateReplacement(OpLoc, "."); + if (isSFINAEContext()) + return ExprError(); + + OpKind = tok::period; + } + } + + if (!ObjectType->isDependentType() && !ObjectType->isScalarType()) { + Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar) + << ObjectType << BaseE->getSourceRange(); + return ExprError(); + } + + // C++ [expr.pseudo]p2: + // [...] The cv-unqualified versions of the object type and of the type + // designated by the pseudo-destructor-name shall be the same type. + QualType DestructedType = DestructedTypeLoc->getType(); + SourceLocation DestructedTypeStart + = DestructedTypeLoc->getTypeLoc().getSourceRange().getBegin(); + if (!DestructedType->isDependentType() && !ObjectType->isDependentType() && + !Context.hasSameUnqualifiedType(DestructedType, ObjectType)) { + Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch) + << ObjectType << DestructedType << BaseE->getSourceRange() + << DestructedTypeLoc->getTypeLoc().getSourceRange(); + + // Recover by + DestructedType = ObjectType; + DestructedTypeLoc = Context.getTrivialTypeSourceInfo(ObjectType, + DestructedTypeStart); + } + + // C++ [expr.pseudo]p2: + // [...] Furthermore, the two type-names in a pseudo-destructor-name of the + // form + // + // ::[opt] nested-name-specifier[opt] type-name :: ~ type-name + // + // shall designate the same scalar type. + if (ScopeTypeInfo) { + QualType ScopeType = ScopeTypeInfo->getType(); + if (!ScopeType->isDependentType() && !ObjectType->isDependentType() && + !Context.hasSameType(ScopeType, ObjectType)) { + + Diag(ScopeTypeInfo->getTypeLoc().getSourceRange().getBegin(), + diag::err_pseudo_dtor_type_mismatch) + << ObjectType << ScopeType << BaseE->getSourceRange() + << ScopeTypeInfo->getTypeLoc().getSourceRange(); + + ScopeType = QualType(); + ScopeTypeInfo = 0; + } + } + + OwningExprResult Result + = Owned(new (Context) CXXPseudoDestructorExpr(Context, + Base.takeAs(), + OpKind == tok::arrow, + OpLoc, + (NestedNameSpecifier *) SS.getScopeRep(), + SS.getRange(), + ScopeTypeInfo, + CCLoc, + DestructedType, + DestructedTypeStart)); + if (HasTrailingLParen) + return move(Result); + + return DiagnoseDtorReference( + DestructedTypeLoc->getTypeLoc().getSourceRange().getBegin(), + move(Result)); +} + Sema::OwningExprResult Sema::ActOnDependentPseudoDestructorExpr(Scope *S, ExprArg Base, @@ -2592,29 +2689,20 @@ if (OpKind == tok::arrow) { if (const PointerType *Ptr = ObjectType->getAs()) { ObjectType = Ptr->getPointeeType(); - } else { + } else if (!BaseE->isTypeDependent()) { // The user wrote "p->" when she probably meant "p."; fix it. Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) - << ObjectType << true - << CodeModificationHint::CreateReplacement(OpLoc, "."); + << ObjectType << true + << CodeModificationHint::CreateReplacement(OpLoc, "."); if (isSFINAEContext()) return ExprError(); OpKind = tok::period; } } - - if (!ObjectType->isScalarType()) { - Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar) - << ObjectType << BaseE->getSourceRange(); - return ExprError(); - } - - // - // C++ [expr.pseudo]p2: - // [...] The cv-unqualified versions of the object type and of the type - // designated by the pseudo-destructor-name shall be the same type. + // Convert the name of the type being destructed (following the ~) into a + // type (with source-location information). QualType DestructedType; TypeSourceInfo *DestructedTypeInfo = 0; if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) { @@ -2630,42 +2718,34 @@ // Recover by assuming we had the right type all along. DestructedType = ObjectType; - } else { + } else DestructedType = GetTypeFromParser(T, &DestructedTypeInfo); - - if (!DestructedType->isDependentType() && - !Context.hasSameUnqualifiedType(DestructedType, ObjectType)) { - // The types mismatch. Recover by assuming we had the right type - // all along. - Diag(SecondTypeName.StartLocation, diag::err_pseudo_dtor_type_mismatch) - << ObjectType << DestructedType << BaseE->getSourceRange(); - - DestructedType = ObjectType; - DestructedTypeInfo = 0; - } - } } else { - // FIXME: C++0x template aliases would allow a template-id here. For now, - // just diagnose this as an error. + // Resolve the template-id to a type. TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId; - Diag(TemplateId->TemplateNameLoc, diag::err_pseudo_dtor_template) - << TemplateId->Name << ObjectType - << SourceRange(TemplateId->TemplateNameLoc, TemplateId->RAngleLoc); - if (isSFINAEContext()) - return ExprError(); - - // Recover by assuming we had the right type all along. - DestructedType = ObjectType; + ASTTemplateArgsPtr TemplateArgsPtr(*this, + TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc); + if (T.isInvalid() || !T.get()) { + // Recover by assuming we had the right type all along. + DestructedType = ObjectType; + } else + DestructedType = GetTypeFromParser(T.get(), &DestructedTypeInfo); } - // C++ [expr.pseudo]p2: - // [...] Furthermore, the two type-names in a pseudo-destructor-name of the - // form - // - // ::[opt] nested-name-specifier[opt] type-name :: ~ type-name - // - // shall designate the same scalar type. - TypeSourceInfo *ScopeTypeLoc; + // If we've performed some kind of recovery, (re-)build the type source + // information. + if (!DestructedTypeInfo) + DestructedTypeInfo = Context.getTrivialTypeSourceInfo(DestructedType, + SecondTypeName.StartLocation); + + // Convert the name of the scope type (the type prior to '::') into a type. + TypeSourceInfo *ScopeTypeInfo = 0; QualType ScopeType; if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId || FirstTypeName.Identifier) { @@ -2677,53 +2757,36 @@ Diag(FirstTypeName.StartLocation, diag::err_pseudo_dtor_destructor_non_type) << FirstTypeName.Identifier << ObjectType; + if (isSFINAEContext()) - return ExprError(); - } else { - // FIXME: Drops source-location information. - ScopeType = GetTypeFromParser(T, &ScopeTypeLoc); + return ExprError(); - if (!ScopeType->isDependentType() && - !Context.hasSameUnqualifiedType(DestructedType, ScopeType)) { - // The types mismatch. Recover by assuming we don't have a scoping - // type. - Diag(FirstTypeName.StartLocation, diag::err_pseudo_dtor_type_mismatch) - << ObjectType << ScopeType << BaseE->getSourceRange(); - - ScopeType = QualType(); - ScopeTypeLoc = 0; - } - } + // Just drop this type. It's unnecessary anyway. + ScopeType = QualType(); + } else + ScopeType = GetTypeFromParser(T, &ScopeTypeInfo); } else { - // FIXME: C++0x template aliases would allow a template-id here. For now, - // just diagnose this as an error. + // Resolve the template-id to a type. TemplateIdAnnotation *TemplateId = FirstTypeName.TemplateId; - Diag(TemplateId->TemplateNameLoc, diag::err_pseudo_dtor_template) - << TemplateId->Name << ObjectType - << SourceRange(TemplateId->TemplateNameLoc, TemplateId->RAngleLoc); - if (isSFINAEContext()) - return ExprError(); - - // Recover by assuming we have no scoping type. - DestructedType = ObjectType; + ASTTemplateArgsPtr TemplateArgsPtr(*this, + TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc); + if (T.isInvalid() || !T.get()) { + // Recover by dropping this type. + ScopeType = QualType(); + } else + ScopeType = GetTypeFromParser(T.get(), &ScopeTypeInfo); } } - - OwningExprResult Result - = Owned(new (Context) CXXPseudoDestructorExpr(Context, - Base.takeAs(), - OpKind == tok::arrow, - OpLoc, - (NestedNameSpecifier *) SS.getScopeRep(), - SS.getRange(), - ScopeTypeLoc, - CCLoc, - DestructedType, - SecondTypeName.StartLocation)); - if (HasTrailingLParen) - return move(Result); - - return DiagnoseDtorReference(SecondTypeName.StartLocation, move(Result)); + + return BuildPseudoDestructorExpr(move(Base), OpLoc, OpKind, SS, + ScopeTypeInfo, CCLoc, DestructedTypeInfo, + HasTrailingLParen); } CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, From fjahanian at apple.com Wed Feb 24 16:48:18 2010 From: fjahanian at apple.com (Fariborz Jahanian) Date: Wed, 24 Feb 2010 22:48:18 -0000 Subject: [cfe-commits] r97073 - in /cfe/trunk: lib/Frontend/RewriteObjC.cpp test/Rewriter/rewrite-nested-blocks.mm Message-ID: <20100224224818.583542A6C136@llvm.org> Author: fjahanian Date: Wed Feb 24 16:48:18 2010 New Revision: 97073 URL: http://llvm.org/viewvc/llvm-project?rev=97073&view=rev Log: Implement nasty rewriting of nested blocks when inner blocks use variables not used in any of the outer blocks. (Fixes radar 7682149). Added: cfe/trunk/test/Rewriter/rewrite-nested-blocks.mm Modified: cfe/trunk/lib/Frontend/RewriteObjC.cpp Modified: cfe/trunk/lib/Frontend/RewriteObjC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/RewriteObjC.cpp?rev=97073&r1=97072&r2=97073&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/RewriteObjC.cpp (original) +++ cfe/trunk/lib/Frontend/RewriteObjC.cpp Wed Feb 24 16:48:18 2010 @@ -120,6 +120,9 @@ // Block expressions. llvm::SmallVector Blocks; + llvm::SmallVector InnerDeclRefsCount; + llvm::SmallVector InnerDeclRefs; + llvm::SmallVector BlockDeclRefs; llvm::DenseMap BlockCallExprs; @@ -385,6 +388,9 @@ void CollectBlockDeclRefInfo(BlockExpr *Exp); void GetBlockCallExprs(Stmt *S); void GetBlockDeclRefExprs(Stmt *S); + void GetInnerBlockDeclRefExprs(Stmt *S, + llvm::SmallVector &InnerBlockDeclRefs, + llvm::SmallPtrSet &InnerBlockValueDecls); // We avoid calling Type::isBlockPointerType(), since it operates on the // canonical type. We only care if the top-level type is a closure pointer. @@ -416,7 +422,8 @@ void RewriteCastExpr(CStyleCastExpr *CE); FunctionDecl *SynthBlockInitFunctionDecl(const char *name); - Stmt *SynthBlockInitExpr(BlockExpr *Exp); + Stmt *SynthBlockInitExpr(BlockExpr *Exp, + const llvm::SmallVector &InnerBlockDeclRefs); void QuoteDoublequotes(std::string &From, std::string &To) { for (unsigned i = 0; i < From.length(); i++) { @@ -4187,8 +4194,15 @@ RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock); // Insert closures that were part of the function. for (unsigned i = 0; i < Blocks.size(); i++) { - + // Need to copy-in the inner copied-in variables not actually used in this + // block. + for (int j = 0; j < InnerDeclRefsCount[i]; j++) + BlockDeclRefs.push_back(InnerDeclRefs[j]); CollectBlockDeclRefInfo(Blocks[i]); + llvm::SmallPtrSet InnerBlockValueDecls; + llvm::SmallVector InnerBlockDeclRefs; + GetInnerBlockDeclRefExprs(Blocks[i]->getBody(), + InnerBlockDeclRefs, InnerBlockValueDecls); std::string ImplTag = "__" + std::string(FunName) + "_block_impl_" + utostr(i); std::string DescTag = "__" + std::string(FunName) + "_block_desc_" + utostr(i); @@ -4218,6 +4232,8 @@ ImportedBlockDecls.clear(); } Blocks.clear(); + InnerDeclRefsCount.clear(); + InnerDeclRefs.clear(); RewrittenBlockExprs.clear(); } @@ -4265,6 +4281,33 @@ return; } +void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S, + llvm::SmallVector &InnerBlockDeclRefs, + llvm::SmallPtrSet &InnerBlockValueDecls) { + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); + CI != E; ++CI) + if (*CI) { + if (BlockExpr *CBE = dyn_cast(*CI)) + GetInnerBlockDeclRefExprs(CBE->getBody(), + InnerBlockDeclRefs, + InnerBlockValueDecls); + else + GetInnerBlockDeclRefExprs(*CI, + InnerBlockDeclRefs, + InnerBlockValueDecls); + + } + // Handle specific things. + if (BlockDeclRefExpr *CDRE = dyn_cast(S)) + if (!isa(CDRE->getDecl()) && + !CDRE->isByRef() && + !InnerBlockValueDecls.count(CDRE->getDecl())) { + InnerBlockValueDecls.insert(CDRE->getDecl()); + InnerBlockDeclRefs.push_back(CDRE); + } + return; +} + void RewriteObjC::GetBlockCallExprs(Stmt *S) { for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E; ++CI) @@ -4854,10 +4897,34 @@ false); } -Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) { +Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, + const llvm::SmallVector &InnerBlockDeclRefs) { Blocks.push_back(Exp); CollectBlockDeclRefInfo(Exp); + + // Add inner imported variables now used in current block. + int countOfInnerDecls = 0; + for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) { + BlockDeclRefExpr *Exp = InnerBlockDeclRefs[i]; + ValueDecl *VD = Exp->getDecl(); + if (!BlockByCopyDeclsPtrSet.count(VD)) { + // We need to save the copied-in variables in nested + // blocks because it is needed at the end for some of the API generations. + // See SynthesizeBlockLiterals routine. + InnerDeclRefs.push_back(Exp); countOfInnerDecls++; + BlockDeclRefs.push_back(Exp); + BlockByCopyDeclsPtrSet.insert(VD); + BlockByCopyDecls.push_back(VD); + if (Exp->getType()->isObjCObjectPointerType() || + Exp->getType()->isBlockPointerType()) { + GetBlockCallExprs(Exp); + ImportedBlockDecls.insert(VD); + } + } + } + InnerDeclRefsCount.push_back(countOfInnerDecls); + std::string FuncName; if (CurFunctionDef) @@ -5036,6 +5103,10 @@ } if (BlockExpr *BE = dyn_cast(S)) { + llvm::SmallPtrSet InnerBlockValueDecls; + llvm::SmallVector InnerBlockDeclRefs; + GetInnerBlockDeclRefExprs(BE->getBody(), + InnerBlockDeclRefs, InnerBlockValueDecls); // Rewrite the block body in place. RewriteFunctionBodyOrGlobalInitializer(BE->getBody()); @@ -5043,7 +5114,8 @@ std::string Str = Rewrite.getRewrittenText(BE->getSourceRange()); RewrittenBlockExprs[BE] = Str; - Stmt *blockTranscribed = SynthBlockInitExpr(BE); + Stmt *blockTranscribed = SynthBlockInitExpr(BE, InnerBlockDeclRefs); + //blockTranscribed->dump(); ReplaceStmt(S, blockTranscribed); return blockTranscribed; Added: cfe/trunk/test/Rewriter/rewrite-nested-blocks.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Rewriter/rewrite-nested-blocks.mm?rev=97073&view=auto ============================================================================== --- cfe/trunk/test/Rewriter/rewrite-nested-blocks.mm (added) +++ cfe/trunk/test/Rewriter/rewrite-nested-blocks.mm Wed Feb 24 16:48:18 2010 @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// radar 7682149 + + +void f(void (^block)(void)); + + at interface X { + int y; +} +- (void)foo; + at end + + at implementation X +- (void)foo { + f(^{ + f(^{ + f(^{ + y=42; + }); + }); +}); + +} + at end + From fjahanian at apple.com Wed Feb 24 16:53:58 2010 From: fjahanian at apple.com (Fariborz Jahanian) Date: Wed, 24 Feb 2010 22:53:58 -0000 Subject: [cfe-commits] r97075 - /cfe/trunk/test/Rewriter/rewrite-nested-blocks.mm Message-ID: <20100224225358.4C6182A6C136@llvm.org> Author: fjahanian Date: Wed Feb 24 16:53:58 2010 New Revision: 97075 URL: http://llvm.org/viewvc/llvm-project?rev=97075&view=rev Log: Added test case for non-objective-c situation in my last patch. Modified: cfe/trunk/test/Rewriter/rewrite-nested-blocks.mm Modified: cfe/trunk/test/Rewriter/rewrite-nested-blocks.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Rewriter/rewrite-nested-blocks.mm?rev=97075&r1=97074&r2=97075&view=diff ============================================================================== --- cfe/trunk/test/Rewriter/rewrite-nested-blocks.mm (original) +++ cfe/trunk/test/Rewriter/rewrite-nested-blocks.mm Wed Feb 24 16:53:58 2010 @@ -24,3 +24,15 @@ } @end +struct S { + int y; +}; + +void foo () { + struct S *SELF; + f(^{ + f(^{ + SELF->y = 42; + }); + }); +} From dgregor at apple.com Wed Feb 24 17:02:30 2010 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 24 Feb 2010 23:02:30 -0000 Subject: [cfe-commits] r97076 - /cfe/trunk/lib/Sema/SemaExprCXX.cpp Message-ID: <20100224230230.55B602A6C136@llvm.org> Author: dgregor Date: Wed Feb 24 17:02:30 2010 New Revision: 97076 URL: http://llvm.org/viewvc/llvm-project?rev=97076&view=rev Log: Make sure that we have type source information for the scope type of a pseudo-destructor expression. Attempt #1 at fixing the MSVC buildbot. Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=97076&r1=97075&r2=97076&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Feb 24 17:02:30 2010 @@ -2783,7 +2783,12 @@ ScopeType = GetTypeFromParser(T.get(), &ScopeTypeInfo); } } - + + if (!ScopeType.isNull() && !ScopeTypeInfo) + ScopeTypeInfo = Context.getTrivialTypeSourceInfo(ScopeType, + FirstTypeName.StartLocation); + + return BuildPseudoDestructorExpr(move(Base), OpLoc, OpKind, SS, ScopeTypeInfo, CCLoc, DestructedTypeInfo, HasTrailingLParen); From dgregor at apple.com Wed Feb 24 17:13:13 2010 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 24 Feb 2010 23:13:13 -0000 Subject: [cfe-commits] r97077 - /cfe/trunk/lib/Parse/ParseExprCXX.cpp Message-ID: <20100224231313.339FA2A6C136@llvm.org> Author: dgregor Date: Wed Feb 24 17:13:13 2010 New Revision: 97077 URL: http://llvm.org/viewvc/llvm-project?rev=97077&view=rev Log: Make sure that we finish the DeclSpec when parsing a C++ type-specifier-seq. Fixes some conditional-jump-on-unitialized-value errors in valgrind. Also counts as attempt #2 at making the MSVC buildbot happy. Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=97077&r1=97076&r2=97077&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original) +++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Wed Feb 24 17:13:13 2010 @@ -889,6 +889,7 @@ ParsedTemplateInfo(), /*SuppressDeclarations*/true)) {} + DS.Finish(Diags, PP); return false; } From dgregor at apple.com Wed Feb 24 17:40:28 2010 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 24 Feb 2010 23:40:28 -0000 Subject: [cfe-commits] r97079 - in /cfe/trunk: include/clang/AST/ExprCXX.h lib/AST/ExprCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/TreeTransform.h Message-ID: <20100224234028.AB2112A6C136@llvm.org> Author: dgregor Date: Wed Feb 24 17:40:28 2010 New Revision: 97079 URL: http://llvm.org/viewvc/llvm-project?rev=97079&view=rev Log: Retain complete source information for the type after the '~' in a CXXPseudoDestructorExpr. Update template instantiation for pseudo-destructor expressions to use this source information and to make use of Sema::BuildPseudoDestructorExpr when the base expression is dependent or refers to a scalar type. Modified: cfe/trunk/include/clang/AST/ExprCXX.h cfe/trunk/lib/AST/ExprCXX.cpp cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/lib/Sema/TreeTransform.h Modified: cfe/trunk/include/clang/AST/ExprCXX.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=97079&r1=97078&r2=97079&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ExprCXX.h (original) +++ cfe/trunk/include/clang/AST/ExprCXX.h Wed Feb 24 17:40:28 2010 @@ -1048,10 +1048,7 @@ SourceLocation ColonColonLoc; /// \brief The type being destroyed. - QualType DestroyedType; - - /// \brief The location of the type after the '~'. - SourceLocation DestroyedTypeLoc; + TypeSourceInfo *DestroyedType; public: CXXPseudoDestructorExpr(ASTContext &Context, @@ -1060,20 +1057,20 @@ SourceRange QualifierRange, TypeSourceInfo *ScopeType, SourceLocation ColonColonLoc, - QualType DestroyedType, - SourceLocation DestroyedTypeLoc) + TypeSourceInfo *DestroyedType) : Expr(CXXPseudoDestructorExprClass, Context.getPointerType(Context.getFunctionType(Context.VoidTy, 0, 0, false, 0, false, false, 0, 0, false, CC_Default)), - /*isTypeDependent=*/false, + /*isTypeDependent=*/(Base->isTypeDependent() || + DestroyedType->getType()->isDependentType()), /*isValueDependent=*/Base->isValueDependent()), Base(static_cast(Base)), IsArrow(isArrow), OperatorLoc(OperatorLoc), Qualifier(Qualifier), QualifierRange(QualifierRange), ScopeType(ScopeType), ColonColonLoc(ColonColonLoc), - DestroyedType(DestroyedType), DestroyedTypeLoc(DestroyedTypeLoc) { } + DestroyedType(DestroyedType) { } void setBase(Expr *E) { Base = E; } Expr *getBase() const { return cast(Base); } @@ -1110,21 +1107,20 @@ /// \p T may also be a scalar type and, therefore, cannot be part of a /// nested-name-specifier. It is stored as the "scope type" of the pseudo- /// destructor expression. - TypeSourceInfo *getScopeTypeLoc() const { return ScopeType; } + TypeSourceInfo *getScopeTypeInfo() const { return ScopeType; } /// \brief Retrieve the location of the '::' in a qualified pseudo-destructor /// expression. SourceLocation getColonColonLoc() const { return ColonColonLoc; } /// \brief Retrieve the type that is being destroyed. - QualType getDestroyedType() const { return DestroyedType; } + QualType getDestroyedType() const { return DestroyedType->getType(); } - /// \brief Retrieve the location of the type being destroyed. - SourceLocation getDestroyedTypeLoc() const { return DestroyedTypeLoc; } + /// \brief Retrieve the source location information for the type + /// being destroyed. + TypeSourceInfo *getDestroyedTypeInfo() const { return DestroyedType; } - virtual SourceRange getSourceRange() const { - return SourceRange(Base->getLocStart(), DestroyedTypeLoc); - } + virtual SourceRange getSourceRange() const; static bool classof(const Stmt *T) { return T->getStmtClass() == CXXPseudoDestructorExprClass; Modified: cfe/trunk/lib/AST/ExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=97079&r1=97078&r2=97079&view=diff ============================================================================== --- cfe/trunk/lib/AST/ExprCXX.cpp (original) +++ cfe/trunk/lib/AST/ExprCXX.cpp Wed Feb 24 17:40:28 2010 @@ -15,6 +15,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/TypeLoc.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -121,6 +122,12 @@ return &Base + 1; } +SourceRange CXXPseudoDestructorExpr::getSourceRange() const { + return SourceRange(Base->getLocStart(), + DestroyedType->getTypeLoc().getSourceRange().getEnd()); +} + + // UnresolvedLookupExpr UnresolvedLookupExpr * UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent, Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=97079&r1=97078&r2=97079&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Feb 24 17:40:28 2010 @@ -2932,13 +2932,15 @@ // FIXME: We've lost the precise spelling of the type by going through // DeclarationName. Can we do better? + TypeSourceInfo *DestroyedTypeInfo + = Context.getTrivialTypeSourceInfo(MemberName.getCXXNameType(), + MemberLoc); return Owned(new (Context) CXXPseudoDestructorExpr(Context, BaseExpr, IsArrow, OpLoc, (NestedNameSpecifier *) SS.getScopeRep(), SS.getRange(), 0, SourceLocation(), - MemberName.getCXXNameType(), - MemberLoc)); + DestroyedTypeInfo)); } // Handle access to Objective-C instance variables, such as "Obj->ivar" and Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=97079&r1=97078&r2=97079&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Feb 24 17:40:28 2010 @@ -2431,11 +2431,11 @@ SourceLocation OpLoc, tok::TokenKind OpKind, const CXXScopeSpec &SS, - TypeSourceInfo *ScopeTypeInfo, + TypeSourceInfo *ScopeTypeInfo, SourceLocation CCLoc, - TypeSourceInfo *DestructedTypeLoc, + TypeSourceInfo *DestructedTypeInfo, bool HasTrailingLParen) { - assert(DestructedTypeLoc && "No destructed type in pseudo-destructor expr?"); + assert(DestructedTypeInfo && "No destructed type in pseudo-destructor expr?"); // C++ [expr.pseudo]p2: // The left-hand side of the dot operator shall be of scalar type. The @@ -2467,18 +2467,18 @@ // C++ [expr.pseudo]p2: // [...] The cv-unqualified versions of the object type and of the type // designated by the pseudo-destructor-name shall be the same type. - QualType DestructedType = DestructedTypeLoc->getType(); + QualType DestructedType = DestructedTypeInfo->getType(); SourceLocation DestructedTypeStart - = DestructedTypeLoc->getTypeLoc().getSourceRange().getBegin(); + = DestructedTypeInfo->getTypeLoc().getSourceRange().getBegin(); if (!DestructedType->isDependentType() && !ObjectType->isDependentType() && !Context.hasSameUnqualifiedType(DestructedType, ObjectType)) { Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch) << ObjectType << DestructedType << BaseE->getSourceRange() - << DestructedTypeLoc->getTypeLoc().getSourceRange(); + << DestructedTypeInfo->getTypeLoc().getSourceRange(); // Recover by DestructedType = ObjectType; - DestructedTypeLoc = Context.getTrivialTypeSourceInfo(ObjectType, + DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType, DestructedTypeStart); } @@ -2513,13 +2513,12 @@ SS.getRange(), ScopeTypeInfo, CCLoc, - DestructedType, - DestructedTypeStart)); + DestructedTypeInfo)); if (HasTrailingLParen) return move(Result); return DiagnoseDtorReference( - DestructedTypeLoc->getTypeLoc().getSourceRange().getBegin(), + DestructedTypeInfo->getTypeLoc().getSourceRange().getBegin(), move(Result)); } Modified: cfe/trunk/lib/Sema/TreeTransform.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=97079&r1=97078&r2=97079&view=diff ============================================================================== --- cfe/trunk/lib/Sema/TreeTransform.h (original) +++ cfe/trunk/lib/Sema/TreeTransform.h Wed Feb 24 17:40:28 2010 @@ -884,28 +884,11 @@ OwningExprResult RebuildCXXPseudoDestructorExpr(ExprArg Base, SourceLocation OperatorLoc, bool isArrow, - SourceLocation DestroyedTypeLoc, - QualType DestroyedType, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange) { - CXXScopeSpec SS; - if (Qualifier) { - SS.setRange(QualifierRange); - SS.setScopeRep(Qualifier); - } - - QualType BaseType = ((Expr*) Base.get())->getType(); - - DeclarationName Name - = SemaRef.Context.DeclarationNames.getCXXDestructorName( - SemaRef.Context.getCanonicalType(DestroyedType)); - - return getSema().BuildMemberReferenceExpr(move(Base), BaseType, - OperatorLoc, isArrow, - SS, /*FIXME: FirstQualifier*/ 0, - Name, DestroyedTypeLoc, - /*TemplateArgs*/ 0); - } + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + TypeSourceInfo *ScopeType, + SourceLocation CCLoc, + TypeSourceInfo *DestroyedType); /// \brief Build a new unary operator expression. /// @@ -4694,27 +4677,35 @@ if (E->getQualifier() && !Qualifier) return SemaRef.ExprError(); - QualType DestroyedType; - { - TemporaryBase Rebase(*this, E->getDestroyedTypeLoc(), DeclarationName()); - DestroyedType = getDerived().TransformType(E->getDestroyedType()); - if (DestroyedType.isNull()) + // FIXME: Object type! + TypeSourceInfo *DestroyedTypeInfo + = getDerived().TransformType(E->getDestroyedTypeInfo()); + if (!DestroyedTypeInfo) + return SemaRef.ExprError(); + + // FIXME: Object type! + TypeSourceInfo *ScopeTypeInfo = 0; + if (E->getScopeTypeInfo()) { + ScopeTypeInfo = getDerived().TransformType(E->getScopeTypeInfo()); + if (!ScopeTypeInfo) return SemaRef.ExprError(); } - + if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase() && Qualifier == E->getQualifier() && - DestroyedType == E->getDestroyedType()) + ScopeTypeInfo == E->getScopeTypeInfo() && + DestroyedTypeInfo == E->getDestroyedTypeInfo()) return SemaRef.Owned(E->Retain()); return getDerived().RebuildCXXPseudoDestructorExpr(move(Base), E->getOperatorLoc(), E->isArrow(), - E->getDestroyedTypeLoc(), - DestroyedType, Qualifier, - E->getQualifierRange()); + E->getQualifierRange(), + ScopeTypeInfo, + E->getColonColonLoc(), + DestroyedTypeInfo); } template @@ -5755,6 +5746,50 @@ return move(Result); } +template +Sema::OwningExprResult +TreeTransform::RebuildCXXPseudoDestructorExpr(ExprArg Base, + SourceLocation OperatorLoc, + bool isArrow, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + TypeSourceInfo *ScopeType, + SourceLocation CCLoc, + TypeSourceInfo *DestroyedType) { + CXXScopeSpec SS; + if (Qualifier) { + SS.setRange(QualifierRange); + SS.setScopeRep(Qualifier); + } + + Expr *BaseE = (Expr *)Base.get(); + QualType BaseType = BaseE->getType(); + if (BaseE->isTypeDependent() || + (!isArrow && !BaseType->getAs()) || + (isArrow && BaseType->getAs() && + !BaseType->getAs()->getAs())) { + // This pseudo-destructor expression is still a pseudo-destructor. + return SemaRef.BuildPseudoDestructorExpr(move(Base), OperatorLoc, + isArrow? tok::arrow : tok::period, + SS, ScopeType, CCLoc, + DestroyedType, + /*FIXME?*/true); + } + + DeclarationName Name + = SemaRef.Context.DeclarationNames.getCXXDestructorName( + SemaRef.Context.getCanonicalType(DestroyedType->getType())); + + // FIXME: the ScopeType should be tacked onto SS. + + return getSema().BuildMemberReferenceExpr(move(Base), BaseType, + OperatorLoc, isArrow, + SS, /*FIXME: FirstQualifier*/ 0, + Name, + DestroyedType->getTypeLoc().getSourceRange().getBegin(), + /*TemplateArgs*/ 0); +} + } // end namespace clang #endif // LLVM_CLANG_SEMA_TREETRANSFORM_H From dgregor at apple.com Wed Feb 24 17:50:38 2010 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 24 Feb 2010 23:50:38 -0000 Subject: [cfe-commits] r97080 - in /cfe/trunk: include/clang/AST/ExprCXX.h lib/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/TreeTransform.h Message-ID: <20100224235038.55E2E2A6C136@llvm.org> Author: dgregor Date: Wed Feb 24 17:50:37 2010 New Revision: 97080 URL: http://llvm.org/viewvc/llvm-project?rev=97080&view=rev Log: Keep track of the location of the '~' in a pseudo-destructor expression. Modified: cfe/trunk/include/clang/AST/ExprCXX.h cfe/trunk/lib/Sema/Sema.h cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/lib/Sema/TreeTransform.h Modified: cfe/trunk/include/clang/AST/ExprCXX.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=97080&r1=97079&r2=97080&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ExprCXX.h (original) +++ cfe/trunk/include/clang/AST/ExprCXX.h Wed Feb 24 17:50:37 2010 @@ -1047,6 +1047,9 @@ /// expression. SourceLocation ColonColonLoc; + /// \brief The location of the '~'. + SourceLocation TildeLoc; + /// \brief The type being destroyed. TypeSourceInfo *DestroyedType; @@ -1057,6 +1060,7 @@ SourceRange QualifierRange, TypeSourceInfo *ScopeType, SourceLocation ColonColonLoc, + SourceLocation TildeLoc, TypeSourceInfo *DestroyedType) : Expr(CXXPseudoDestructorExprClass, Context.getPointerType(Context.getFunctionType(Context.VoidTy, 0, 0, @@ -1069,7 +1073,7 @@ Base(static_cast(Base)), IsArrow(isArrow), OperatorLoc(OperatorLoc), Qualifier(Qualifier), QualifierRange(QualifierRange), - ScopeType(ScopeType), ColonColonLoc(ColonColonLoc), + ScopeType(ScopeType), ColonColonLoc(ColonColonLoc), TildeLoc(TildeLoc), DestroyedType(DestroyedType) { } void setBase(Expr *E) { Base = E; } @@ -1113,6 +1117,9 @@ /// expression. SourceLocation getColonColonLoc() const { return ColonColonLoc; } + /// \brief Retrieve the location of the '~'. + SourceLocation getTildeLoc() const { return TildeLoc; } + /// \brief Retrieve the type that is being destroyed. QualType getDestroyedType() const { return DestroyedType->getType(); } Modified: cfe/trunk/lib/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=97080&r1=97079&r2=97080&view=diff ============================================================================== --- cfe/trunk/lib/Sema/Sema.h (original) +++ cfe/trunk/lib/Sema/Sema.h Wed Feb 24 17:50:37 2010 @@ -2187,6 +2187,7 @@ const CXXScopeSpec &SS, TypeSourceInfo *ScopeType, SourceLocation CCLoc, + SourceLocation TildeLoc, TypeSourceInfo *DestroyedType, bool HasTrailingLParen); Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=97080&r1=97079&r2=97080&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Feb 24 17:50:37 2010 @@ -2940,6 +2940,7 @@ (NestedNameSpecifier *) SS.getScopeRep(), SS.getRange(), 0, SourceLocation(), + MemberLoc, DestroyedTypeInfo)); } Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=97080&r1=97079&r2=97080&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Feb 24 17:50:37 2010 @@ -2433,6 +2433,7 @@ const CXXScopeSpec &SS, TypeSourceInfo *ScopeTypeInfo, SourceLocation CCLoc, + SourceLocation TildeLoc, TypeSourceInfo *DestructedTypeInfo, bool HasTrailingLParen) { assert(DestructedTypeInfo && "No destructed type in pseudo-destructor expr?"); @@ -2513,6 +2514,7 @@ SS.getRange(), ScopeTypeInfo, CCLoc, + TildeLoc, DestructedTypeInfo)); if (HasTrailingLParen) return move(Result); @@ -2789,8 +2791,8 @@ return BuildPseudoDestructorExpr(move(Base), OpLoc, OpKind, SS, - ScopeTypeInfo, CCLoc, DestructedTypeInfo, - HasTrailingLParen); + ScopeTypeInfo, CCLoc, TildeLoc, + DestructedTypeInfo, HasTrailingLParen); } CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, Modified: cfe/trunk/lib/Sema/TreeTransform.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=97080&r1=97079&r2=97080&view=diff ============================================================================== --- cfe/trunk/lib/Sema/TreeTransform.h (original) +++ cfe/trunk/lib/Sema/TreeTransform.h Wed Feb 24 17:50:37 2010 @@ -888,6 +888,7 @@ SourceRange QualifierRange, TypeSourceInfo *ScopeType, SourceLocation CCLoc, + SourceLocation TildeLoc, TypeSourceInfo *DestroyedType); /// \brief Build a new unary operator expression. @@ -4705,6 +4706,7 @@ E->getQualifierRange(), ScopeTypeInfo, E->getColonColonLoc(), + E->getTildeLoc(), DestroyedTypeInfo); } @@ -5755,6 +5757,7 @@ SourceRange QualifierRange, TypeSourceInfo *ScopeType, SourceLocation CCLoc, + SourceLocation TildeLoc, TypeSourceInfo *DestroyedType) { CXXScopeSpec SS; if (Qualifier) { @@ -5771,7 +5774,7 @@ // This pseudo-destructor expression is still a pseudo-destructor. return SemaRef.BuildPseudoDestructorExpr(move(Base), OperatorLoc, isArrow? tok::arrow : tok::period, - SS, ScopeType, CCLoc, + SS, ScopeType, CCLoc, TildeLoc, DestroyedType, /*FIXME?*/true); } From kremenek at apple.com Wed Feb 24 18:20:22 2010 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 25 Feb 2010 00:20:22 -0000 Subject: [cfe-commits] r97082 - /cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h Message-ID: <20100225002023.067942A6C136@llvm.org> Author: kremenek Date: Wed Feb 24 18:20:22 2010 New Revision: 97082 URL: http://llvm.org/viewvc/llvm-project?rev=97082&view=rev Log: Sort list of checker registration functions. Modified: cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h Modified: cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h?rev=97082&r1=97081&r2=97082&view=diff ============================================================================== --- cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h (original) +++ cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h Wed Feb 24 18:20:22 2010 @@ -20,26 +20,26 @@ class GRExprEngine; void RegisterAdjustedReturnValueChecker(GRExprEngine &Eng); +void RegisterArrayBoundChecker(GRExprEngine &Eng); void RegisterAttrNonNullChecker(GRExprEngine &Eng); +void RegisterBuiltinFunctionChecker(GRExprEngine &Eng); +void RegisterCallAndMessageChecker(GRExprEngine &Eng); +void RegisterCastToStructChecker(GRExprEngine &Eng); void RegisterDereferenceChecker(GRExprEngine &Eng); void RegisterDivZeroChecker(GRExprEngine &Eng); +void RegisterFixedAddressChecker(GRExprEngine &Eng); +void RegisterNoReturnFunctionChecker(GRExprEngine &Eng); +void RegisterOSAtomicChecker(GRExprEngine &Eng); +void RegisterPointerArithChecker(GRExprEngine &Eng); +void RegisterPointerSubChecker(GRExprEngine &Eng); void RegisterReturnPointerRangeChecker(GRExprEngine &Eng); void RegisterReturnStackAddressChecker(GRExprEngine &Eng); void RegisterReturnUndefChecker(GRExprEngine &Eng); -void RegisterVLASizeChecker(GRExprEngine &Eng); -void RegisterPointerSubChecker(GRExprEngine &Eng); -void RegisterPointerArithChecker(GRExprEngine &Eng); -void RegisterFixedAddressChecker(GRExprEngine &Eng); -void RegisterCastToStructChecker(GRExprEngine &Eng); -void RegisterCallAndMessageChecker(GRExprEngine &Eng); -void RegisterArrayBoundChecker(GRExprEngine &Eng); -void RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng); -void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng); void RegisterUndefBranchChecker(GRExprEngine &Eng); void RegisterUndefCapturedBlockVarChecker(GRExprEngine &Eng); void RegisterUndefResultChecker(GRExprEngine &Eng); -void RegisterNoReturnFunctionChecker(GRExprEngine &Eng); -void RegisterBuiltinFunctionChecker(GRExprEngine &Eng); -void RegisterOSAtomicChecker(GRExprEngine &Eng); +void RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng); +void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng); +void RegisterVLASizeChecker(GRExprEngine &Eng); } // end clang namespace #endif From kremenek at apple.com Wed Feb 24 18:20:25 2010 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 25 Feb 2010 00:20:25 -0000 Subject: [cfe-commits] r97083 - /cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h Message-ID: <20100225002025.CC96A2A6C137@llvm.org> Author: kremenek Date: Wed Feb 24 18:20:25 2010 New Revision: 97083 URL: http://llvm.org/viewvc/llvm-project?rev=97083&view=rev Log: Divide list of registration functions in API and foundational checks. Also trim whitespace. Modified: cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h Modified: cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h?rev=97083&r1=97082&r2=97083&view=diff ============================================================================== --- cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h (original) +++ cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h Wed Feb 24 18:20:25 2010 @@ -19,6 +19,7 @@ class GRExprEngine; +// Foundational checks that handle basic semantics. void RegisterAdjustedReturnValueChecker(GRExprEngine &Eng); void RegisterArrayBoundChecker(GRExprEngine &Eng); void RegisterAttrNonNullChecker(GRExprEngine &Eng); @@ -29,11 +30,10 @@ void RegisterDivZeroChecker(GRExprEngine &Eng); void RegisterFixedAddressChecker(GRExprEngine &Eng); void RegisterNoReturnFunctionChecker(GRExprEngine &Eng); -void RegisterOSAtomicChecker(GRExprEngine &Eng); void RegisterPointerArithChecker(GRExprEngine &Eng); void RegisterPointerSubChecker(GRExprEngine &Eng); void RegisterReturnPointerRangeChecker(GRExprEngine &Eng); -void RegisterReturnStackAddressChecker(GRExprEngine &Eng); +void RegisterReturnStackAddressChecker(GRExprEngine &Eng); void RegisterReturnUndefChecker(GRExprEngine &Eng); void RegisterUndefBranchChecker(GRExprEngine &Eng); void RegisterUndefCapturedBlockVarChecker(GRExprEngine &Eng); @@ -41,5 +41,9 @@ void RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng); void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng); void RegisterVLASizeChecker(GRExprEngine &Eng); + +// API checks. +void RegisterOSAtomicChecker(GRExprEngine &Eng); + } // end clang namespace #endif From kremenek at apple.com Wed Feb 24 18:20:28 2010 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 25 Feb 2010 00:20:28 -0000 Subject: [cfe-commits] r97084 - /cfe/trunk/lib/Checker/BuiltinFunctionChecker.cpp Message-ID: <20100225002028.991AD2A6C138@llvm.org> Author: kremenek Date: Wed Feb 24 18:20:28 2010 New Revision: 97084 URL: http://llvm.org/viewvc/llvm-project?rev=97084&view=rev Log: Remove #include. Modified: cfe/trunk/lib/Checker/BuiltinFunctionChecker.cpp Modified: cfe/trunk/lib/Checker/BuiltinFunctionChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/BuiltinFunctionChecker.cpp?rev=97084&r1=97083&r2=97084&view=diff ============================================================================== --- cfe/trunk/lib/Checker/BuiltinFunctionChecker.cpp (original) +++ cfe/trunk/lib/Checker/BuiltinFunctionChecker.cpp Wed Feb 24 18:20:28 2010 @@ -14,7 +14,6 @@ #include "GRExprEngineInternalChecks.h" #include "clang/Checker/PathSensitive/Checker.h" #include "clang/Basic/Builtins.h" -#include "llvm/ADT/StringSwitch.h" using namespace clang; From kremenek at apple.com Wed Feb 24 18:20:31 2010 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 25 Feb 2010 00:20:31 -0000 Subject: [cfe-commits] r97085 - /cfe/trunk/lib/Checker/OSAtomicChecker.cpp Message-ID: <20100225002031.6748A2A6C136@llvm.org> Author: kremenek Date: Wed Feb 24 18:20:31 2010 New Revision: 97085 URL: http://llvm.org/viewvc/llvm-project?rev=97085&view=rev Log: Remove stray #include. Modified: cfe/trunk/lib/Checker/OSAtomicChecker.cpp Modified: cfe/trunk/lib/Checker/OSAtomicChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/OSAtomicChecker.cpp?rev=97085&r1=97084&r2=97085&view=diff ============================================================================== --- cfe/trunk/lib/Checker/OSAtomicChecker.cpp (original) +++ cfe/trunk/lib/Checker/OSAtomicChecker.cpp Wed Feb 24 18:20:31 2010 @@ -14,7 +14,6 @@ #include "GRExprEngineInternalChecks.h" #include "clang/Checker/PathSensitive/Checker.h" #include "clang/Basic/Builtins.h" -#include "llvm/ADT/StringSwitch.h" using namespace clang; From kremenek at apple.com Wed Feb 24 18:20:35 2010 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 25 Feb 2010 00:20:35 -0000 Subject: [cfe-commits] r97086 - in /cfe/trunk: lib/Checker/CMakeLists.txt lib/Checker/GRExprEngine.cpp lib/Checker/GRExprEngineInternalChecks.h lib/Checker/UnixAPIChecker.cpp test/Analysis/unix-fns.c Message-ID: <20100225002036.104732A6C137@llvm.org> Author: kremenek Date: Wed Feb 24 18:20:35 2010 New Revision: 97086 URL: http://llvm.org/viewvc/llvm-project?rev=97086&view=rev Log: Add UnixAPIChecker, a meta checker to include various precondition checks for calls to various unix/posix functions, e.g. 'open()'. As a first check, check that when 'open()' is passed 'O_CREAT' that it has a third argument. Added: cfe/trunk/lib/Checker/UnixAPIChecker.cpp cfe/trunk/test/Analysis/unix-fns.c Modified: cfe/trunk/lib/Checker/CMakeLists.txt cfe/trunk/lib/Checker/GRExprEngine.cpp cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h Modified: cfe/trunk/lib/Checker/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/CMakeLists.txt?rev=97086&r1=97085&r2=97086&view=diff ============================================================================== --- cfe/trunk/lib/Checker/CMakeLists.txt (original) +++ cfe/trunk/lib/Checker/CMakeLists.txt Wed Feb 24 18:20:35 2010 @@ -62,6 +62,7 @@ UndefResultChecker.cpp UndefinedArraySubscriptChecker.cpp UndefinedAssignmentChecker.cpp + UnixAPIChecker.cpp VLASizeChecker.cpp ValueManager.cpp ) Modified: cfe/trunk/lib/Checker/GRExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRExprEngine.cpp?rev=97086&r1=97085&r2=97086&view=diff ============================================================================== --- cfe/trunk/lib/Checker/GRExprEngine.cpp (original) +++ cfe/trunk/lib/Checker/GRExprEngine.cpp Wed Feb 24 18:20:35 2010 @@ -318,6 +318,7 @@ RegisterNoReturnFunctionChecker(Eng); RegisterBuiltinFunctionChecker(Eng); RegisterOSAtomicChecker(Eng); + RegisterUnixAPIChecker(Eng); } GRExprEngine::GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf) Modified: cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h?rev=97086&r1=97085&r2=97086&view=diff ============================================================================== --- cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h (original) +++ cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h Wed Feb 24 18:20:35 2010 @@ -44,6 +44,7 @@ // API checks. void RegisterOSAtomicChecker(GRExprEngine &Eng); +void RegisterUnixAPIChecker(GRExprEngine &Eng); } // end clang namespace #endif Added: cfe/trunk/lib/Checker/UnixAPIChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/UnixAPIChecker.cpp?rev=97086&view=auto ============================================================================== --- cfe/trunk/lib/Checker/UnixAPIChecker.cpp (added) +++ cfe/trunk/lib/Checker/UnixAPIChecker.cpp Wed Feb 24 18:20:35 2010 @@ -0,0 +1,151 @@ +//= UnixAPIChecker.h - Checks preconditions for various Unix APIs --*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines UnixAPIChecker, which is an assortment of checks on calls +// to various, widely used UNIX/Posix functions. +// +//===----------------------------------------------------------------------===// + +#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/PathSensitive/GRStateTrait.h" +#include "llvm/ADT/StringSwitch.h" +#include "GRExprEngineInternalChecks.h" +#include + +using namespace clang; + +namespace { +class UnixAPIChecker : public CheckerVisitor { + enum SubChecks { + OpenFn = 0, + NumChecks + }; + + BugType *BTypes[NumChecks]; + +public: + UnixAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); } + static void *getTag() { static unsigned tag = 0; return &tag; } + + void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); +}; +} //end anonymous namespace + +void clang::RegisterUnixAPIChecker(GRExprEngine &Eng) { + Eng.registerCheck(new UnixAPIChecker()); +} + +//===----------------------------------------------------------------------===// +// Utility functions. +//===----------------------------------------------------------------------===// + +static inline void LazyInitialize(BugType *&BT, const char *name) { + if (BT) + return; + BT = new BugType(name, "Unix API"); +} + +//===----------------------------------------------------------------------===// +// "open" (man 2 open) +//===----------------------------------------------------------------------===// + +static void CheckOpen(CheckerContext &C, const CallExpr *CE, BugType *&BT) { + LazyInitialize(BT, "Improper use of 'open'"); + + // Look at the 'oflags' argument for the O_CREAT flag. + const GRState *state = C.getState(); + + if (CE->getNumArgs() < 2) { + // The frontend should issue a warning for this case, so this is a sanity + // check. + return; + } + + // Now check if oflags has O_CREAT set. + const Expr *oflagsEx = CE->getArg(1); + const SVal V = state->getSVal(oflagsEx); + if (!isa(V)) { + // The case where 'V' can be a location can only be due to a bad header, + // so in this case bail out. + return; + } + NonLoc oflags = cast(V); + NonLoc ocreateFlag = + cast(C.getValueManager().makeIntVal((uint64_t) O_CREAT, + oflagsEx->getType())); + SVal maskedFlagsUC = C.getSValuator().EvalBinOpNN(state, BinaryOperator::And, + oflags, ocreateFlag, + oflagsEx->getType()); + if (maskedFlagsUC.isUnknownOrUndef()) + return; + DefinedSVal maskedFlags = cast(maskedFlagsUC); + + // Check if maskedFlags is non-zero. + const GRState *trueState, *falseState; + llvm::tie(trueState, falseState) = state->Assume(maskedFlags); + + // Only emit an error if the value of 'maskedFlags' is properly + // constrained; + if (!(trueState && !falseState)) + return; + + if (CE->getNumArgs() < 3) { + ExplodedNode *N = C.GenerateSink(trueState); + EnhancedBugReport *report = + new EnhancedBugReport(*BT, + "Call to 'open' requires a third argument when " + "the 'O_CREAT' flag is set", N); + report->addRange(oflagsEx->getSourceRange()); + C.EmitReport(report); + } +} + +//===----------------------------------------------------------------------===// +// Central dispatch function. +//===----------------------------------------------------------------------===// + +typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT); +namespace { + class SubCheck { + SubChecker SC; + BugType **BT; + public: + SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {} + SubCheck() : SC(NULL), BT(NULL) {} + + void run(CheckerContext &C, const CallExpr *CE) const { + if (SC) + SC(C, CE, *BT); + } + }; +} // end anonymous namespace + +void UnixAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { + // Get the callee. All the functions we care about are C functions + // with simple identifiers. + const GRState *state = C.getState(); + const Expr *Callee = CE->getCallee(); + const FunctionTextRegion *Fn = + dyn_cast_or_null(state->getSVal(Callee).getAsRegion()); + + if (!Fn) + return; + + const IdentifierInfo *FI = Fn->getDecl()->getIdentifier(); + if (!FI) + return; + + const SubCheck &SC = + llvm::StringSwitch(FI->getName()) + .Case("open", SubCheck(CheckOpen, BTypes[OpenFn])) + .Default(SubCheck()); + + SC.run(C, CE); +} Added: cfe/trunk/test/Analysis/unix-fns.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/unix-fns.c?rev=97086&view=auto ============================================================================== --- cfe/trunk/test/Analysis/unix-fns.c (added) +++ cfe/trunk/test/Analysis/unix-fns.c Wed Feb 24 18:20:35 2010 @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem %s -analyzer-store=region +// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem %s -analyzer-store=basic + +#include + +void test_open(const char *path) { + int fd; + fd = open(path, O_RDONLY); // no-warning + if (!fd) + close(fd); + + fd = open(path, O_CREAT); // expected-warning{{Call to 'open' requires a third argument when the 'O_CREAT' flag is set}} + if (!fd) + close(fd); +} From kremenek at apple.com Wed Feb 24 19:16:07 2010 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 25 Feb 2010 01:16:07 -0000 Subject: [cfe-commits] r97088 - /cfe/trunk/test/Analysis/unix-fns.c Message-ID: <20100225011607.5C37F2A6C136@llvm.org> Author: kremenek Date: Wed Feb 24 19:16:07 2010 New Revision: 97088 URL: http://llvm.org/viewvc/llvm-project?rev=97088&view=rev Log: Remove test case dependancy on platform headers. Modified: cfe/trunk/test/Analysis/unix-fns.c Modified: cfe/trunk/test/Analysis/unix-fns.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/unix-fns.c?rev=97088&r1=97087&r2=97088&view=diff ============================================================================== --- cfe/trunk/test/Analysis/unix-fns.c (original) +++ cfe/trunk/test/Analysis/unix-fns.c Wed Feb 24 19:16:07 2010 @@ -1,7 +1,11 @@ // RUN: %clang_cc1 -analyze -analyzer-check-objc-mem %s -analyzer-store=region // RUN: %clang_cc1 -analyze -analyzer-check-objc-mem %s -analyzer-store=basic -#include +#ifndef O_CREAT +#define O_CREAT 0x0200 +#define O_RDONLY 0x0000 +#endif +int open(const char *, int, ...); void test_open(const char *path) { int fd; From rjmccall at apple.com Wed Feb 24 19:37:25 2010 From: rjmccall at apple.com (John McCall) Date: Thu, 25 Feb 2010 01:37:25 -0000 Subject: [cfe-commits] r97090 - in /cfe/trunk: lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaOverload.h test/SemaCXX/overload-call.cpp Message-ID: <20100225013725.50D7A2A6C136@llvm.org> Author: rjmccall Date: Wed Feb 24 19:37:24 2010 New Revision: 97090 URL: http://llvm.org/viewvc/llvm-project?rev=97090&view=rev Log: Catch more uses of uninitialized implicit conversion sequences. When diagnosing bad conversions, skip the conversion for ignored object arguments. Fixes PR 6398. Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/lib/Sema/SemaOverload.cpp cfe/trunk/lib/Sema/SemaOverload.h cfe/trunk/test/SemaCXX/overload-call.cpp Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=97090&r1=97089&r2=97090&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Feb 24 19:37:24 2010 @@ -4395,8 +4395,7 @@ // Most paths end in a failed conversion. if (ICS) { - ICS->setBad(); - ICS->Bad.init(BadConversionSequence::no_conversion, Init, DeclType); + ICS->setBad(BadConversionSequence::no_conversion, Init, DeclType); } // C++ [dcl.init.ref]p5: Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=97090&r1=97089&r2=97090&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Feb 24 19:37:24 2010 @@ -1344,8 +1344,7 @@ AssignmentAction Action, bool AllowExplicit, bool Elidable, ImplicitConversionSequence& ICS) { - ICS.setBad(); - ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType); + ICS.setBad(BadConversionSequence::no_conversion, From, ToType); if (Elidable && getLangOptions().CPlusPlus0x) { ICS = TryImplicitConversion(From, ToType, /*SuppressUserConversions=*/false, @@ -1759,6 +1758,7 @@ return ICS.UserDefined.After.getToType(2); case ImplicitConversionSequence::AmbiguousConversion: return ICS.Ambiguous.getToType(); + case ImplicitConversionSequence::EllipsisConversion: case ImplicitConversionSequence::BadConversion: llvm_unreachable("function not valid for ellipsis or bad conversions"); @@ -1802,7 +1802,7 @@ return false; } } - ICS.setBad(); + // -- If E2 is an rvalue, or if the conversion above cannot be done: // -- if E1 and E2 have class type, and the underlying class types are // the same or one is a base class of the other: @@ -1816,14 +1816,22 @@ // E1 can be converted to match E2 if the class of T2 is the // same type as, or a base class of, the class of T1, and // [cv2 > cv1]. - if ((FRec == TRec || FDerivedFromT) && TTy.isAtLeastAsQualifiedAs(FTy)) { - // Could still fail if there's no copy constructor. - // FIXME: Is this a hard error then, or just a conversion failure? The - // standard doesn't say. - ICS = Self.TryCopyInitialization(From, TTy, - /*SuppressUserConversions=*/false, - /*ForceRValue=*/false, - /*InOverloadResolution=*/false); + if (FRec == TRec || FDerivedFromT) { + if (TTy.isAtLeastAsQualifiedAs(FTy)) { + // Could still fail if there's no copy constructor. + // FIXME: Is this a hard error then, or just a conversion failure? The + // standard doesn't say. + ICS = Self.TryCopyInitialization(From, TTy, + /*SuppressUserConversions=*/false, + /*ForceRValue=*/false, + /*InOverloadResolution=*/false); + } else { + ICS.setBad(BadConversionSequence::bad_qualifiers, From, TTy); + } + } else { + // Can't implicitly convert FTy to a derived class TTy. + // TODO: more specific error for this. + ICS.setBad(BadConversionSequence::no_conversion, From, TTy); } } else { // -- Otherwise: E1 can be converted to match E2 if E1 can be @@ -2212,9 +2220,8 @@ /*ForceRValue=*/false, /*InOverloadResolution=*/false); + bool ToC2Viable = false; ImplicitConversionSequence E1ToC2, E2ToC2; - E1ToC2.setBad(); - E2ToC2.setBad(); if (Context.getCanonicalType(Composite1) != Context.getCanonicalType(Composite2)) { E1ToC2 = TryImplicitConversion(E1, Composite2, @@ -2227,10 +2234,10 @@ /*AllowExplicit=*/false, /*ForceRValue=*/false, /*InOverloadResolution=*/false); + ToC2Viable = !E1ToC2.isBad() && !E2ToC2.isBad(); } bool ToC1Viable = !E1ToC1.isBad() && !E2ToC1.isBad(); - bool ToC2Viable = !E1ToC2.isBad() && !E2ToC2.isBad(); if (ToC1Viable && !ToC2Viable) { if (!PerformImplicitConversion(E1, Composite1, E1ToC1, Sema::AA_Converting) && !PerformImplicitConversion(E2, Composite1, E2ToC1, Sema::AA_Converting)) Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=97090&r1=97089&r2=97090&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Feb 24 19:37:24 2010 @@ -453,8 +453,7 @@ } if (!getLangOptions().CPlusPlus) { - ICS.setBad(); - ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType); + ICS.setBad(BadConversionSequence::no_conversion, From, ToType); return ICS; } @@ -500,8 +499,7 @@ // 13.3.1.6 in all cases, only standard conversion sequences and // ellipsis conversion sequences are allowed. if (SuppressUserConversions && ICS.isUserDefined()) { - ICS.setBad(); - ICS.Bad.init(BadConversionSequence::suppressed_user, From, ToType); + ICS.setBad(BadConversionSequence::suppressed_user, From, ToType); } } else if (UserDefResult == OR_Ambiguous && !SuppressUserConversions) { ICS.setAmbiguous(); @@ -512,8 +510,7 @@ if (Cand->Viable) ICS.Ambiguous.addConversion(Cand->Function); } else { - ICS.setBad(); - ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType); + ICS.setBad(BadConversionSequence::no_conversion, From, ToType); } return ICS; @@ -2196,7 +2193,7 @@ bool InOverloadResolution) { if (ToType->isReferenceType()) { ImplicitConversionSequence ICS; - ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType); + ICS.setBad(BadConversionSequence::no_conversion, From, ToType); CheckReferenceInit(From, ToType, /*FIXME:*/From->getLocStart(), SuppressUserConversions, @@ -2268,8 +2265,6 @@ // Set up the conversion sequence as a "bad" conversion, to allow us // to exit early. ImplicitConversionSequence ICS; - ICS.Standard.setAsIdentityConversion(); - ICS.setBad(); // We need to have an object of class type. QualType FromType = OrigFromType; @@ -2293,25 +2288,29 @@ if (ImplicitParamType.getCVRQualifiers() != FromTypeCanon.getLocalCVRQualifiers() && !ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) { - ICS.Bad.init(BadConversionSequence::bad_qualifiers, - OrigFromType, ImplicitParamType); + ICS.setBad(BadConversionSequence::bad_qualifiers, + OrigFromType, ImplicitParamType); return ICS; } // Check that we have either the same type or a derived type. It // affects the conversion rank. QualType ClassTypeCanon = Context.getCanonicalType(ClassType); - if (ClassTypeCanon == FromTypeCanon.getLocalUnqualifiedType()) - ICS.Standard.Second = ICK_Identity; - else if (IsDerivedFrom(FromType, ClassType)) - ICS.Standard.Second = ICK_Derived_To_Base; + ImplicitConversionKind SecondKind; + if (ClassTypeCanon == FromTypeCanon.getLocalUnqualifiedType()) { + SecondKind = ICK_Identity; + } else if (IsDerivedFrom(FromType, ClassType)) + SecondKind = ICK_Derived_To_Base; else { - ICS.Bad.init(BadConversionSequence::unrelated_class, FromType, ImplicitParamType); + ICS.setBad(BadConversionSequence::unrelated_class, + FromType, ImplicitParamType); return ICS; } // Success. Mark this as a reference binding. ICS.setStandard(); + ICS.Standard.setAsIdentityConversion(); + ICS.Standard.Second = SecondKind; ICS.Standard.setFromType(FromType); ICS.Standard.setAllToTypes(ImplicitParamType); ICS.Standard.ReferenceBinding = true; @@ -4464,7 +4463,7 @@ QualType ToTy = Conv.Bad.getToType(); if (FromTy == S.Context.OverloadTy) { - assert(FromExpr); + assert(FromExpr && "overload set argument came from implicit argument?"); Expr *E = FromExpr->IgnoreParens(); if (isa(E)) E = cast(E)->getSubExpr()->IgnoreParens(); @@ -4667,8 +4666,9 @@ case ovl_fail_bad_final_conversion: return S.NoteOverloadCandidate(Fn); - case ovl_fail_bad_conversion: - for (unsigned I = 0, N = Cand->Conversions.size(); I != N; ++I) + case ovl_fail_bad_conversion: { + unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0); + for (unsigned N = Cand->Conversions.size(); I != N; ++I) if (Cand->Conversions[I].isBad()) return DiagnoseBadConversion(S, Cand, I); @@ -4677,6 +4677,7 @@ // those conditions and diagnose them well. return S.NoteOverloadCandidate(Fn); } + } } void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) { @@ -4842,7 +4843,7 @@ if (Cand->FailureKind != ovl_fail_bad_conversion) return; // Skip forward to the first bad conversion. - unsigned ConvIdx = 0; + unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0); unsigned ConvCount = Cand->Conversions.size(); while (true) { assert(ConvIdx != ConvCount && "no bad conversion in candidate"); @@ -4854,6 +4855,9 @@ if (ConvIdx == ConvCount) return; + assert(!Cand->Conversions[ConvIdx].isInitialized() && + "remaining conversion is initialized?"); + // FIXME: these should probably be preserved from the overload // operation somehow. bool SuppressUserConversions = false; Modified: cfe/trunk/lib/Sema/SemaOverload.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.h?rev=97090&r1=97089&r2=97090&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.h (original) +++ cfe/trunk/lib/Sema/SemaOverload.h Wed Feb 24 19:37:24 2010 @@ -316,14 +316,22 @@ }; private: + enum { + Uninitialized = BadConversion + 1 + }; + /// ConversionKind - The kind of implicit conversion sequence. - Kind ConversionKind; + unsigned ConversionKind; void setKind(Kind K) { - if (isAmbiguous()) Ambiguous.destruct(); + destruct(); ConversionKind = K; } + void destruct() { + if (ConversionKind == AmbiguousConversion) Ambiguous.destruct(); + } + public: union { /// When ConversionKind == StandardConversion, provides the @@ -343,14 +351,15 @@ BadConversionSequence Bad; }; - ImplicitConversionSequence() : ConversionKind(BadConversion) {} + ImplicitConversionSequence() : ConversionKind(Uninitialized) {} ~ImplicitConversionSequence() { - if (isAmbiguous()) Ambiguous.destruct(); + destruct(); } ImplicitConversionSequence(const ImplicitConversionSequence &Other) : ConversionKind(Other.ConversionKind) { switch (ConversionKind) { + case Uninitialized: break; case StandardConversion: Standard = Other.Standard; break; case UserDefinedConversion: UserDefined = Other.UserDefined; break; case AmbiguousConversion: Ambiguous.copyFrom(Other.Ambiguous); break; @@ -361,26 +370,45 @@ ImplicitConversionSequence & operator=(const ImplicitConversionSequence &Other) { - if (isAmbiguous()) Ambiguous.destruct(); + destruct(); new (this) ImplicitConversionSequence(Other); return *this; } - Kind getKind() const { return ConversionKind; } - bool isBad() const { return ConversionKind == BadConversion; } - bool isStandard() const { return ConversionKind == StandardConversion; } - bool isEllipsis() const { return ConversionKind == EllipsisConversion; } - bool isAmbiguous() const { return ConversionKind == AmbiguousConversion; } - bool isUserDefined() const { - return ConversionKind == UserDefinedConversion; + Kind getKind() const { + assert(isInitialized() && "querying uninitialized conversion"); + return Kind(ConversionKind); + } + bool isBad() const { return getKind() == BadConversion; } + bool isStandard() const { return getKind() == StandardConversion; } + bool isEllipsis() const { return getKind() == EllipsisConversion; } + bool isAmbiguous() const { return getKind() == AmbiguousConversion; } + bool isUserDefined() const { return getKind() == UserDefinedConversion; } + + /// Determines whether this conversion sequence has been + /// initialized. Most operations should never need to query + /// uninitialized conversions and should assert as above. + bool isInitialized() const { return ConversionKind != Uninitialized; } + + /// Sets this sequence as a bad conversion for an explicit argument. + void setBad(BadConversionSequence::FailureKind Failure, + Expr *FromExpr, QualType ToType) { + setKind(BadConversion); + Bad.init(Failure, FromExpr, ToType); + } + + /// Sets this sequence as a bad conversion for an implicit argument. + void setBad(BadConversionSequence::FailureKind Failure, + QualType FromType, QualType ToType) { + setKind(BadConversion); + Bad.init(Failure, FromType, ToType); } - void setBad() { setKind(BadConversion); } void setStandard() { setKind(StandardConversion); } void setEllipsis() { setKind(EllipsisConversion); } void setUserDefined() { setKind(UserDefinedConversion); } void setAmbiguous() { - if (isAmbiguous()) return; + if (ConversionKind == AmbiguousConversion) return; ConversionKind = AmbiguousConversion; Ambiguous.construct(); } @@ -490,6 +518,7 @@ bool hasAmbiguousConversion() const { for (llvm::SmallVectorImpl::const_iterator I = Conversions.begin(), E = Conversions.end(); I != E; ++I) { + if (!I->isInitialized()) return false; if (I->isAmbiguous()) return true; } return false; Modified: cfe/trunk/test/SemaCXX/overload-call.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overload-call.cpp?rev=97090&r1=97089&r2=97090&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/overload-call.cpp (original) +++ cfe/trunk/test/SemaCXX/overload-call.cpp Wed Feb 24 19:37:24 2010 @@ -359,3 +359,16 @@ int &ir = f(b); } } + +// PR 6398 +namespace test4 { + class A; + class B { + static void foo(); // expected-note {{not viable}} + static void foo(int*); // expected-note {{not viable}} + + void bar(A *a) { + foo(a); // expected-error {{no matching function for call}} + } + }; +} From dgregor at apple.com Wed Feb 24 19:56:36 2010 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 25 Feb 2010 01:56:36 -0000 Subject: [cfe-commits] r97092 - in /cfe/trunk: include/clang/AST/ExprCXX.h lib/AST/ExprCXX.cpp lib/AST/StmtPrinter.cpp lib/Sema/Sema.h lib/Sema/SemaExprCXX.cpp lib/Sema/TreeTransform.h test/SemaTemplate/destructor-template.cpp test/SemaTemplate/member-access-expr.cpp Message-ID: <20100225015636.B302B2A6C136@llvm.org> Author: dgregor Date: Wed Feb 24 19:56:36 2010 New Revision: 97092 URL: http://llvm.org/viewvc/llvm-project?rev=97092&view=rev Log: Use CXXPseudoDestructorExpr as the stored representation for dependent expressions that look like pseudo-destructors, e.g., p->T::~T() where p has dependent type. At template instantiate time, we determine whether we actually have a pseudo-destructor or a member access, and funnel down to the appropriate routine in Sema. Fixes PR6380. Modified: cfe/trunk/include/clang/AST/ExprCXX.h cfe/trunk/lib/AST/ExprCXX.cpp cfe/trunk/lib/AST/StmtPrinter.cpp cfe/trunk/lib/Sema/Sema.h cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/lib/Sema/TreeTransform.h cfe/trunk/test/SemaTemplate/destructor-template.cpp cfe/trunk/test/SemaTemplate/member-access-expr.cpp Modified: cfe/trunk/include/clang/AST/ExprCXX.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=97092&r1=97091&r2=97092&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ExprCXX.h (original) +++ cfe/trunk/include/clang/AST/ExprCXX.h Wed Feb 24 19:56:36 2010 @@ -997,6 +997,35 @@ virtual child_iterator child_end(); }; +/// \brief Structure used to store the type being destroyed by a +/// pseudo-destructor expression. +class PseudoDestructorTypeStorage { + /// \brief Either the type source information or the name of the type, if + /// it couldn't be resolved due to type-dependence. + llvm::PointerUnion Type; + + /// \brief The starting source location of the pseudo-destructor type. + SourceLocation Location; + +public: + PseudoDestructorTypeStorage() { } + + PseudoDestructorTypeStorage(IdentifierInfo *II, SourceLocation Loc) + : Type(II), Location(Loc) { } + + PseudoDestructorTypeStorage(TypeSourceInfo *Info); + + TypeSourceInfo *getTypeSourceInfo() const { + return Type.dyn_cast(); + } + + IdentifierInfo *getIdentifier() const { + return Type.dyn_cast(); + } + + SourceLocation getLocation() const { return Location; } +}; + /// \brief Represents a C++ pseudo-destructor (C++ [expr.pseudo]). /// /// A pseudo-destructor is an expression that looks like a member access to a @@ -1050,8 +1079,9 @@ /// \brief The location of the '~'. SourceLocation TildeLoc; - /// \brief The type being destroyed. - TypeSourceInfo *DestroyedType; + /// \brief The type being destroyed, or its name if we were unable to + /// resolve the name. + PseudoDestructorTypeStorage DestroyedType; public: CXXPseudoDestructorExpr(ASTContext &Context, @@ -1061,14 +1091,15 @@ TypeSourceInfo *ScopeType, SourceLocation ColonColonLoc, SourceLocation TildeLoc, - TypeSourceInfo *DestroyedType) + PseudoDestructorTypeStorage DestroyedType) : Expr(CXXPseudoDestructorExprClass, Context.getPointerType(Context.getFunctionType(Context.VoidTy, 0, 0, false, 0, false, false, 0, 0, false, CC_Default)), /*isTypeDependent=*/(Base->isTypeDependent() || - DestroyedType->getType()->isDependentType()), + (DestroyedType.getTypeSourceInfo() && + DestroyedType.getTypeSourceInfo()->getType()->isDependentType())), /*isValueDependent=*/Base->isValueDependent()), Base(static_cast(Base)), IsArrow(isArrow), OperatorLoc(OperatorLoc), Qualifier(Qualifier), @@ -1120,12 +1151,31 @@ /// \brief Retrieve the location of the '~'. SourceLocation getTildeLoc() const { return TildeLoc; } - /// \brief Retrieve the type that is being destroyed. - QualType getDestroyedType() const { return DestroyedType->getType(); } - /// \brief Retrieve the source location information for the type /// being destroyed. - TypeSourceInfo *getDestroyedTypeInfo() const { return DestroyedType; } + /// + /// This type-source information is available for non-dependent + /// pseudo-destructor expressions and some dependent pseudo-destructor + /// expressions. Returns NULL if we only have the identifier for a + /// dependent pseudo-destructor expression. + TypeSourceInfo *getDestroyedTypeInfo() const { + return DestroyedType.getTypeSourceInfo(); + } + + /// \brief In a dependent pseudo-destructor expression for which we do not + /// have full type information on the destroyed type, provides the name + /// of the destroyed type. + IdentifierInfo *getDestroyedTypeIdentifier() const { + return DestroyedType.getIdentifier(); + } + + /// \brief Retrieve the type being destroyed. + QualType getDestroyedType() const; + + /// \brief Retrieve the starting location of the type being destroyed. + SourceLocation getDestroyedTypeLoc() const { + return DestroyedType.getLocation(); + } virtual SourceRange getSourceRange() const; Modified: cfe/trunk/lib/AST/ExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=97092&r1=97091&r2=97092&view=diff ============================================================================== --- cfe/trunk/lib/AST/ExprCXX.cpp (original) +++ cfe/trunk/lib/AST/ExprCXX.cpp Wed Feb 24 19:56:36 2010 @@ -122,9 +122,24 @@ return &Base + 1; } +PseudoDestructorTypeStorage::PseudoDestructorTypeStorage(TypeSourceInfo *Info) + : Type(Info) +{ + Location = Info->getTypeLoc().getSourceRange().getBegin(); +} + +QualType CXXPseudoDestructorExpr::getDestroyedType() const { + if (TypeSourceInfo *TInfo = DestroyedType.getTypeSourceInfo()) + return TInfo->getType(); + + return QualType(); +} + SourceRange CXXPseudoDestructorExpr::getSourceRange() const { - return SourceRange(Base->getLocStart(), - DestroyedType->getTypeLoc().getSourceRange().getEnd()); + SourceLocation End = DestroyedType.getLocation(); + if (TypeSourceInfo *TInfo = DestroyedType.getTypeSourceInfo()) + End = TInfo->getTypeLoc().getSourceRange().getEnd(); + return SourceRange(Base->getLocStart(), End); } Modified: cfe/trunk/lib/AST/StmtPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=97092&r1=97091&r2=97092&view=diff ============================================================================== --- cfe/trunk/lib/AST/StmtPrinter.cpp (original) +++ cfe/trunk/lib/AST/StmtPrinter.cpp Wed Feb 24 19:56:36 2010 @@ -1120,7 +1120,10 @@ E->getQualifier()->print(OS, Policy); std::string TypeS; - E->getDestroyedType().getAsStringInternal(TypeS, Policy); + if (IdentifierInfo *II = E->getDestroyedTypeIdentifier()) + OS << II->getName(); + else + E->getDestroyedType().getAsStringInternal(TypeS, Policy); OS << TypeS; } Modified: cfe/trunk/lib/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=97092&r1=97091&r2=97092&view=diff ============================================================================== --- cfe/trunk/lib/Sema/Sema.h (original) +++ cfe/trunk/lib/Sema/Sema.h Wed Feb 24 19:56:36 2010 @@ -95,6 +95,7 @@ class ObjCMethodDecl; class ObjCPropertyDecl; class ObjCContainerDecl; + class PseudoDestructorTypeStorage; class FunctionProtoType; class CXXBasePath; class CXXBasePaths; @@ -2188,20 +2189,9 @@ TypeSourceInfo *ScopeType, SourceLocation CCLoc, SourceLocation TildeLoc, - TypeSourceInfo *DestroyedType, + PseudoDestructorTypeStorage DestroyedType, bool HasTrailingLParen); - - OwningExprResult ActOnDependentPseudoDestructorExpr(Scope *S, - ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - const CXXScopeSpec &SS, - UnqualifiedId &FirstTypeName, - SourceLocation CCLoc, - SourceLocation TildeLoc, - UnqualifiedId &SecondTypeName, - bool HasTrailingLParen); - + virtual OwningExprResult ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=97092&r1=97091&r2=97092&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Feb 24 19:56:36 2010 @@ -161,7 +161,7 @@ Found.clear(); if (Step == 0 && LookupCtx) LookupQualifiedName(Found, LookupCtx); - else if (Step == 1 && LookInScope) + else if (Step == 1 && LookInScope && S) LookupName(Found, S); else continue; @@ -2441,9 +2441,9 @@ TypeSourceInfo *ScopeTypeInfo, SourceLocation CCLoc, SourceLocation TildeLoc, - TypeSourceInfo *DestructedTypeInfo, + PseudoDestructorTypeStorage Destructed, bool HasTrailingLParen) { - assert(DestructedTypeInfo && "No destructed type in pseudo-destructor expr?"); + TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo(); // C++ [expr.pseudo]p2: // The left-hand side of the dot operator shall be of scalar type. The @@ -2475,21 +2475,24 @@ // C++ [expr.pseudo]p2: // [...] The cv-unqualified versions of the object type and of the type // designated by the pseudo-destructor-name shall be the same type. - QualType DestructedType = DestructedTypeInfo->getType(); - SourceLocation DestructedTypeStart - = DestructedTypeInfo->getTypeLoc().getSourceRange().getBegin(); - if (!DestructedType->isDependentType() && !ObjectType->isDependentType() && - !Context.hasSameUnqualifiedType(DestructedType, ObjectType)) { - Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch) - << ObjectType << DestructedType << BaseE->getSourceRange() - << DestructedTypeInfo->getTypeLoc().getSourceRange(); - - // Recover by - DestructedType = ObjectType; - DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType, - DestructedTypeStart); + if (DestructedTypeInfo) { + QualType DestructedType = DestructedTypeInfo->getType(); + SourceLocation DestructedTypeStart + = DestructedTypeInfo->getTypeLoc().getSourceRange().getBegin(); + if (!DestructedType->isDependentType() && !ObjectType->isDependentType() && + !Context.hasSameUnqualifiedType(DestructedType, ObjectType)) { + Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch) + << ObjectType << DestructedType << BaseE->getSourceRange() + << DestructedTypeInfo->getTypeLoc().getSourceRange(); + + // Recover by setting the destructed type to the object type. + DestructedType = ObjectType; + DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType, + DestructedTypeStart); + Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); + } } - + // C++ [expr.pseudo]p2: // [...] Furthermore, the two type-names in a pseudo-destructor-name of the // form @@ -2522,148 +2525,12 @@ ScopeTypeInfo, CCLoc, TildeLoc, - DestructedTypeInfo)); + Destructed)); + if (HasTrailingLParen) return move(Result); - return DiagnoseDtorReference( - DestructedTypeInfo->getTypeLoc().getSourceRange().getBegin(), - move(Result)); -} - -Sema::OwningExprResult -Sema::ActOnDependentPseudoDestructorExpr(Scope *S, - ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - const CXXScopeSpec &SS, - UnqualifiedId &FirstTypeName, - SourceLocation CCLoc, - SourceLocation TildeLoc, - UnqualifiedId &SecondTypeName, - bool HasTrailingLParen) { - Expr *BaseE = (Expr *)Base.get(); - QualType ObjectType = BaseE->getType(); - assert(ObjectType->isDependentType()); - - // The nested-name-specifier provided by the parser, then extended - // by the "type-name ::" in the pseudo-destructor-name, if present. - CXXScopeSpec ExtendedSS = SS; - - if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId || - FirstTypeName.Identifier) { - // We have a pseudo-destructor with a "type-name ::". - // FIXME: As a temporary hack, we go ahead and resolve this to part of - // a nested-name-specifier. - if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) { - // Resolve the identifier to a nested-name-specifier. - CXXScopeTy *FinalScope - = ActOnCXXNestedNameSpecifier(S, SS, - FirstTypeName.StartLocation, - CCLoc, - *FirstTypeName.Identifier, - true, - ObjectType.getAsOpaquePtr(), - false); - if (SS.getBeginLoc().isInvalid()) - ExtendedSS.setBeginLoc(FirstTypeName.StartLocation); - ExtendedSS.setEndLoc(CCLoc); - ExtendedSS.setScopeRep(FinalScope); - } else { - // Resolve the template-id to a type, and that to a - // nested-name-specifier. - TemplateIdAnnotation *TemplateId = FirstTypeName.TemplateId; - ASTTemplateArgsPtr TemplateArgsPtr(*this, - TemplateId->getTemplateArgs(), - TemplateId->NumArgs); - TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), - TemplateId->TemplateNameLoc, - TemplateId->LAngleLoc, - TemplateArgsPtr, - TemplateId->RAngleLoc); - if (!T.isInvalid()) { - CXXScopeTy *FinalScope - = ActOnCXXNestedNameSpecifier(S, SS, T.get(), - SourceRange(TemplateId->TemplateNameLoc, - TemplateId->RAngleLoc), - CCLoc, - true); - if (SS.getBeginLoc().isInvalid()) - ExtendedSS.setBeginLoc(TemplateId->TemplateNameLoc); - ExtendedSS.setEndLoc(CCLoc); - ExtendedSS.setScopeRep(FinalScope); - } - } - } - - // Produce a destructor name based on the second type-name (which - // follows the tilde). - TypeTy *DestructedType; - SourceLocation EndLoc; - if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) { - const CXXScopeSpec *LookupSS = &SS; - bool isDependent = isDependentScopeSpecifier(ExtendedSS); - if (isDependent || computeDeclContext(ExtendedSS)) - LookupSS = &ExtendedSS; - - DestructedType = getTypeName(*SecondTypeName.Identifier, - SecondTypeName.StartLocation, - S, LookupSS, true, ObjectType.getTypePtr()); - if (!DestructedType && isDependent) { - // We didn't find our type, but that's okay: it's dependent - // anyway. - // FIXME: We should not be building a typename type here! - NestedNameSpecifier *NNS = 0; - SourceRange Range; - if (SS.isSet()) { - NNS = (NestedNameSpecifier *)ExtendedSS.getScopeRep(); - Range = SourceRange(ExtendedSS.getRange().getBegin(), - SecondTypeName.StartLocation); - } else { - NNS = NestedNameSpecifier::Create(Context, SecondTypeName.Identifier); - Range = SourceRange(SecondTypeName.StartLocation); - } - - DestructedType = CheckTypenameType(NNS, *SecondTypeName.Identifier, - Range).getAsOpaquePtr(); - if (!DestructedType) - return ExprError(); - } - - if (!DestructedType) { - // FIXME: Crummy diagnostic. - Diag(SecondTypeName.StartLocation, diag::err_destructor_class_name); - return ExprError(); - } - - EndLoc = SecondTypeName.EndLocation; - } else { - // Resolve the template-id to a type, and that to a - // nested-name-specifier. - TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId; - ASTTemplateArgsPtr TemplateArgsPtr(*this, - TemplateId->getTemplateArgs(), - TemplateId->NumArgs); - EndLoc = TemplateId->RAngleLoc; - TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), - TemplateId->TemplateNameLoc, - TemplateId->LAngleLoc, - TemplateArgsPtr, - TemplateId->RAngleLoc); - if (T.isInvalid() || !T.get()) - return ExprError(); - - DestructedType = T.get(); - } - - // Form a (possibly fake) destructor name and let the member access - // expression code deal with this. - // FIXME: Don't do this! It's totally broken! - UnqualifiedId Destructor; - Destructor.setDestructorName(TildeLoc, DestructedType, EndLoc); - return ActOnMemberAccessExpr(S, move(Base), OpLoc, OpKind, ExtendedSS, - Destructor, DeclPtrTy(), HasTrailingLParen); - + return DiagnoseDtorReference(Destructed.getLocation(), move(Result)); } Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, @@ -2683,11 +2550,6 @@ "Invalid second type name in pseudo-destructor"); Expr *BaseE = (Expr *)Base.get(); - if (BaseE->isTypeDependent()) - return ActOnDependentPseudoDestructorExpr(S, move(Base), OpLoc, OpKind, - SS, FirstTypeName, CCLoc, - TildeLoc, SecondTypeName, - HasTrailingLParen); // C++ [expr.pseudo]p2: // The left-hand side of the dot operator shall be of scalar type. The @@ -2697,27 +2559,46 @@ if (OpKind == tok::arrow) { if (const PointerType *Ptr = ObjectType->getAs()) { ObjectType = Ptr->getPointeeType(); - } else if (!BaseE->isTypeDependent()) { + } else if (!ObjectType->isDependentType()) { // The user wrote "p->" when she probably meant "p."; fix it. Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) - << ObjectType << true - << CodeModificationHint::CreateReplacement(OpLoc, "."); + << ObjectType << true + << CodeModificationHint::CreateReplacement(OpLoc, "."); if (isSFINAEContext()) return ExprError(); OpKind = tok::period; } } + + // Compute the object type that we should use for name lookup purposes. Only + // record types and dependent types matter. + void *ObjectTypePtrForLookup = 0; + if (!SS.isSet()) { + ObjectTypePtrForLookup = (void *)ObjectType->getAs(); + if (!ObjectTypePtrForLookup && ObjectType->isDependentType()) + ObjectTypePtrForLookup = Context.DependentTy.getAsOpaquePtr(); + } // Convert the name of the type being destructed (following the ~) into a // type (with source-location information). QualType DestructedType; TypeSourceInfo *DestructedTypeInfo = 0; + PseudoDestructorTypeStorage Destructed; if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) { TypeTy *T = getTypeName(*SecondTypeName.Identifier, SecondTypeName.StartLocation, - S, &SS); - if (!T) { + S, &SS, true, ObjectTypePtrForLookup); + if (!T && + ((SS.isSet() && !computeDeclContext(SS, false)) || + (!SS.isSet() && ObjectType->isDependentType()))) { + // The name of the type being destroyed is a dependent name, and we + // couldn't find anything useful in scope. Just store the identifier and + // it's location, and we'll perform (qualified) name lookup again at + // template instantiation time. + Destructed = PseudoDestructorTypeStorage(SecondTypeName.Identifier, + SecondTypeName.StartLocation); + } else if (!T) { Diag(SecondTypeName.StartLocation, diag::err_pseudo_dtor_destructor_non_type) << SecondTypeName.Identifier << ObjectType; @@ -2748,9 +2629,12 @@ // If we've performed some kind of recovery, (re-)build the type source // information. - if (!DestructedTypeInfo) - DestructedTypeInfo = Context.getTrivialTypeSourceInfo(DestructedType, + if (!DestructedType.isNull()) { + if (!DestructedTypeInfo) + DestructedTypeInfo = Context.getTrivialTypeSourceInfo(DestructedType, SecondTypeName.StartLocation); + Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); + } // Convert the name of the scope type (the type prior to '::') into a type. TypeSourceInfo *ScopeTypeInfo = 0; @@ -2760,7 +2644,7 @@ if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) { TypeTy *T = getTypeName(*FirstTypeName.Identifier, FirstTypeName.StartLocation, - S, &SS); + S, &SS, false, ObjectTypePtrForLookup); if (!T) { Diag(FirstTypeName.StartLocation, diag::err_pseudo_dtor_destructor_non_type) @@ -2799,7 +2683,7 @@ return BuildPseudoDestructorExpr(move(Base), OpLoc, OpKind, SS, ScopeTypeInfo, CCLoc, TildeLoc, - DestructedTypeInfo, HasTrailingLParen); + Destructed, HasTrailingLParen); } CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, Modified: cfe/trunk/lib/Sema/TreeTransform.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=97092&r1=97091&r2=97092&view=diff ============================================================================== --- cfe/trunk/lib/Sema/TreeTransform.h (original) +++ cfe/trunk/lib/Sema/TreeTransform.h Wed Feb 24 19:56:36 2010 @@ -884,12 +884,12 @@ OwningExprResult RebuildCXXPseudoDestructorExpr(ExprArg Base, SourceLocation OperatorLoc, bool isArrow, - NestedNameSpecifier *Qualifier, + NestedNameSpecifier *Qualifier, SourceRange QualifierRange, TypeSourceInfo *ScopeType, SourceLocation CCLoc, SourceLocation TildeLoc, - TypeSourceInfo *DestroyedType); + PseudoDestructorTypeStorage Destroyed); /// \brief Build a new unary operator expression. /// @@ -4671,34 +4671,67 @@ if (Base.isInvalid()) return SemaRef.ExprError(); + Sema::TypeTy *ObjectTypePtr = 0; + bool MayBePseudoDestructor = false; + Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), + E->getOperatorLoc(), + E->isArrow()? tok::arrow : tok::period, + ObjectTypePtr, + MayBePseudoDestructor); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr); NestedNameSpecifier *Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), E->getQualifierRange(), - true); + true, + ObjectType); if (E->getQualifier() && !Qualifier) return SemaRef.ExprError(); - // FIXME: Object type! - TypeSourceInfo *DestroyedTypeInfo - = getDerived().TransformType(E->getDestroyedTypeInfo()); - if (!DestroyedTypeInfo) - return SemaRef.ExprError(); + PseudoDestructorTypeStorage Destroyed; + if (E->getDestroyedTypeInfo()) { + TypeSourceInfo *DestroyedTypeInfo + = getDerived().TransformType(E->getDestroyedTypeInfo(), ObjectType); + if (!DestroyedTypeInfo) + return SemaRef.ExprError(); + Destroyed = DestroyedTypeInfo; + } else if (ObjectType->isDependentType()) { + // We aren't likely to be able to resolve the identifier down to a type + // now anyway, so just retain the identifier. + Destroyed = PseudoDestructorTypeStorage(E->getDestroyedTypeIdentifier(), + E->getDestroyedTypeLoc()); + } else { + // Look for a destructor known with the given name. + CXXScopeSpec SS; + if (Qualifier) { + SS.setScopeRep(Qualifier); + SS.setRange(E->getQualifierRange()); + } + + Sema::TypeTy *T = SemaRef.getDestructorName(E->getTildeLoc(), + *E->getDestroyedTypeIdentifier(), + E->getDestroyedTypeLoc(), + /*Scope=*/0, + SS, ObjectTypePtr, + false); + if (!T) + return SemaRef.ExprError(); + + Destroyed + = SemaRef.Context.getTrivialTypeSourceInfo(SemaRef.GetTypeFromParser(T), + E->getDestroyedTypeLoc()); + } - // FIXME: Object type! TypeSourceInfo *ScopeTypeInfo = 0; if (E->getScopeTypeInfo()) { - ScopeTypeInfo = getDerived().TransformType(E->getScopeTypeInfo()); + ScopeTypeInfo = getDerived().TransformType(E->getScopeTypeInfo(), + ObjectType); if (!ScopeTypeInfo) return SemaRef.ExprError(); } - if (!getDerived().AlwaysRebuild() && - Base.get() == E->getBase() && - Qualifier == E->getQualifier() && - ScopeTypeInfo == E->getScopeTypeInfo() && - DestroyedTypeInfo == E->getDestroyedTypeInfo()) - return SemaRef.Owned(E->Retain()); - return getDerived().RebuildCXXPseudoDestructorExpr(move(Base), E->getOperatorLoc(), E->isArrow(), @@ -4707,7 +4740,7 @@ ScopeTypeInfo, E->getColonColonLoc(), E->getTildeLoc(), - DestroyedTypeInfo); + Destroyed); } template @@ -5758,7 +5791,7 @@ TypeSourceInfo *ScopeType, SourceLocation CCLoc, SourceLocation TildeLoc, - TypeSourceInfo *DestroyedType) { + PseudoDestructorTypeStorage Destroyed) { CXXScopeSpec SS; if (Qualifier) { SS.setRange(QualifierRange); @@ -5767,18 +5800,19 @@ Expr *BaseE = (Expr *)Base.get(); QualType BaseType = BaseE->getType(); - if (BaseE->isTypeDependent() || + if (BaseE->isTypeDependent() || Destroyed.getIdentifier() || (!isArrow && !BaseType->getAs()) || (isArrow && BaseType->getAs() && - !BaseType->getAs()->getAs())) { + !BaseType->getAs()->getPointeeType()->getAs())){ // This pseudo-destructor expression is still a pseudo-destructor. return SemaRef.BuildPseudoDestructorExpr(move(Base), OperatorLoc, isArrow? tok::arrow : tok::period, SS, ScopeType, CCLoc, TildeLoc, - DestroyedType, + Destroyed, /*FIXME?*/true); } + TypeSourceInfo *DestroyedType = Destroyed.getTypeSourceInfo(); DeclarationName Name = SemaRef.Context.DeclarationNames.getCXXDestructorName( SemaRef.Context.getCanonicalType(DestroyedType->getType())); @@ -5788,8 +5822,7 @@ return getSema().BuildMemberReferenceExpr(move(Base), BaseType, OperatorLoc, isArrow, SS, /*FIXME: FirstQualifier*/ 0, - Name, - DestroyedType->getTypeLoc().getSourceRange().getBegin(), + Name, Destroyed.getLocation(), /*TemplateArgs*/ 0); } Modified: cfe/trunk/test/SemaTemplate/destructor-template.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/destructor-template.cpp?rev=97092&r1=97091&r2=97092&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/destructor-template.cpp (original) +++ cfe/trunk/test/SemaTemplate/destructor-template.cpp Wed Feb 24 19:56:36 2010 @@ -25,6 +25,8 @@ void X::f() { Y *y; y->template Y::~Y(); + y->template Y::~Y(); + y->~Y(); } template struct X; Modified: cfe/trunk/test/SemaTemplate/member-access-expr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/member-access-expr.cpp?rev=97092&r1=97091&r2=97092&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/member-access-expr.cpp (original) +++ cfe/trunk/test/SemaTemplate/member-access-expr.cpp Wed Feb 24 19:56:36 2010 @@ -63,11 +63,13 @@ template void destruct(T* ptr) { ptr->~T(); + ptr->T::~T(); } template void destruct_intptr(int *ip) { ip->~T(); + ip->T::~T(); } void test_destruct(X2 *x2p, int *ip) { From dgregor at apple.com Wed Feb 24 20:00:27 2010 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 25 Feb 2010 02:00:27 -0000 Subject: [cfe-commits] r97095 - /cfe/trunk/lib/Sema/SemaExpr.cpp Message-ID: <20100225020028.004432A6C136@llvm.org> Author: dgregor Date: Wed Feb 24 20:00:27 2010 New Revision: 97095 URL: http://llvm.org/viewvc/llvm-project?rev=97095&view=rev Log: Remove some oogly code made dead by the pseudo-destructor instantiation changes. Modified: cfe/trunk/lib/Sema/SemaExpr.cpp Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=97095&r1=97094&r2=97095&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Feb 24 20:00:27 2010 @@ -2900,50 +2900,6 @@ return Owned((Expr*) 0); } - // Handle pseudo-destructors (C++ [expr.pseudo]). Since anything referring - // into a record type was handled above, any destructor we see here is a - // pseudo-destructor. - if (MemberName.getNameKind() == DeclarationName::CXXDestructorName) { - // C++ [expr.pseudo]p2: - // The left hand side of the dot operator shall be of scalar type. The - // left hand side of the arrow operator shall be of pointer to scalar - // type. - if (!BaseType->isScalarType()) - return Owned(Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar) - << BaseType << BaseExpr->getSourceRange()); - - // [...] The type designated by the pseudo-destructor-name shall be the - // same as the object type. - if (!MemberName.getCXXNameType()->isDependentType() && - !Context.hasSameUnqualifiedType(BaseType, MemberName.getCXXNameType())) - return Owned(Diag(OpLoc, diag::err_pseudo_dtor_type_mismatch) - << BaseType << MemberName.getCXXNameType() - << BaseExpr->getSourceRange() << SourceRange(MemberLoc)); - - // [...] Furthermore, the two type-names in a pseudo-destructor-name of - // the form - // - // ::[opt] nested-name-specifier[opt] type-name :: ?? type-name - // - // shall designate the same scalar type. - // - // FIXME: DPG can't see any way to trigger this particular clause, so it - // isn't checked here. - - // FIXME: We've lost the precise spelling of the type by going through - // DeclarationName. Can we do better? - TypeSourceInfo *DestroyedTypeInfo - = Context.getTrivialTypeSourceInfo(MemberName.getCXXNameType(), - MemberLoc); - return Owned(new (Context) CXXPseudoDestructorExpr(Context, BaseExpr, - IsArrow, OpLoc, - (NestedNameSpecifier *) SS.getScopeRep(), - SS.getRange(), - 0, SourceLocation(), - MemberLoc, - DestroyedTypeInfo)); - } - // Handle access to Objective-C instance variables, such as "Obj->ivar" and // (*Obj).ivar. if ((IsArrow && BaseType->isObjCObjectPointerType()) || From daniel at zuster.org Wed Feb 24 21:23:40 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Thu, 25 Feb 2010 03:23:40 -0000 Subject: [cfe-commits] r97101 - in /cfe/trunk: include/clang/Frontend/TextDiagnosticPrinter.h lib/Frontend/TextDiagnosticPrinter.cpp Message-ID: <20100225032340.4D0DD2A6C136@llvm.org> Author: ddunbar Date: Wed Feb 24 21:23:40 2010 New Revision: 97101 URL: http://llvm.org/viewvc/llvm-project?rev=97101&view=rev Log: Add TextDiagnosticPrinter::setPrefix, for adding a string to prefix diagnostic messages with. Modified: cfe/trunk/include/clang/Frontend/TextDiagnosticPrinter.h cfe/trunk/lib/Frontend/TextDiagnosticPrinter.cpp Modified: cfe/trunk/include/clang/Frontend/TextDiagnosticPrinter.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/TextDiagnosticPrinter.h?rev=97101&r1=97100&r2=97101&view=diff ============================================================================== --- cfe/trunk/include/clang/Frontend/TextDiagnosticPrinter.h (original) +++ cfe/trunk/include/clang/Frontend/TextDiagnosticPrinter.h Wed Feb 24 21:23:40 2010 @@ -37,11 +37,19 @@ unsigned LastCaretDiagnosticWasNote : 1; unsigned OwnsOutputStream : 1; + /// A string to prefix to error messages. + std::string Prefix; + public: TextDiagnosticPrinter(llvm::raw_ostream &os, const DiagnosticOptions &diags, bool OwnsOutputStream = false); virtual ~TextDiagnosticPrinter(); + /// setPrefix - Set the diagnostic printer prefix string, which will be + /// printed at the start of any diagnostics. If empty, no prefix string is + /// used. + void setPrefix(std::string Value) { Prefix = Value; } + void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) { LangOpts = &LO; } Modified: cfe/trunk/lib/Frontend/TextDiagnosticPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/TextDiagnosticPrinter.cpp?rev=97101&r1=97100&r2=97101&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/TextDiagnosticPrinter.cpp (original) +++ cfe/trunk/lib/Frontend/TextDiagnosticPrinter.cpp Wed Feb 24 21:23:40 2010 @@ -31,7 +31,7 @@ llvm::raw_ostream::MAGENTA; static const enum llvm::raw_ostream::Colors errorColor = llvm::raw_ostream::RED; static const enum llvm::raw_ostream::Colors fatalColor = llvm::raw_ostream::RED; -// used for changing only the bold attribute +// Used for changing only the bold attribute. static const enum llvm::raw_ostream::Colors savedColor = llvm::raw_ostream::SAVEDCOLOR; @@ -682,6 +682,9 @@ // file+line+column number prefix is. uint64_t StartOfLocationInfo = OS.tell(); + if (!Prefix.empty()) + OS << Prefix << ": "; + // If the location is specified, print out a file/line/col and include trace // if enabled. if (Info.getLocation().isValid()) { From daniel at zuster.org Wed Feb 24 21:23:43 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Thu, 25 Feb 2010 03:23:43 -0000 Subject: [cfe-commits] r97102 - /cfe/trunk/tools/driver/driver.cpp Message-ID: <20100225032343.3C6412A6C137@llvm.org> Author: ddunbar Date: Wed Feb 24 21:23:43 2010 New Revision: 97102 URL: http://llvm.org/viewvc/llvm-project?rev=97102&view=rev Log: Driver: Use TextDiagnosticPrinter instead of a custom one. Modified: cfe/trunk/tools/driver/driver.cpp Modified: cfe/trunk/tools/driver/driver.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/driver/driver.cpp?rev=97102&r1=97101&r2=97102&view=diff ============================================================================== --- cfe/trunk/tools/driver/driver.cpp (original) +++ cfe/trunk/tools/driver/driver.cpp Wed Feb 24 21:23:43 2010 @@ -15,6 +15,8 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/Option.h" +#include "clang/Frontend/DiagnosticOptions.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/OwningPtr.h" @@ -29,38 +31,6 @@ using namespace clang; using namespace clang::driver; -class DriverDiagnosticPrinter : public DiagnosticClient { - std::string ProgName; - llvm::raw_ostream &OS; - -public: - DriverDiagnosticPrinter(const std::string _ProgName, - llvm::raw_ostream &_OS) - : ProgName(_ProgName), - OS(_OS) {} - - virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, - const DiagnosticInfo &Info); -}; - -void DriverDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, - const DiagnosticInfo &Info) { - OS << ProgName << ": "; - - switch (Level) { - case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type"); - case Diagnostic::Note: OS << "note: "; break; - case Diagnostic::Warning: OS << "warning: "; break; - case Diagnostic::Error: OS << "error: "; break; - case Diagnostic::Fatal: OS << "fatal error: "; break; - } - - llvm::SmallString<100> OutStr; - Info.FormatDiagnostic(OutStr); - OS.write(OutStr.begin(), OutStr.size()); - OS << '\n'; -} - llvm::sys::Path GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) { if (!CanonicalPrefixes) return llvm::sys::Path(Argv0); @@ -218,7 +188,8 @@ llvm::sys::Path Path = GetExecutablePath(argv[0], CanonicalPrefixes); - DriverDiagnosticPrinter DiagClient(Path.getBasename(), llvm::errs()); + TextDiagnosticPrinter DiagClient(llvm::errs(), DiagnosticOptions()); + DiagClient.setPrefix(Path.getBasename()); Diagnostic Diags(&DiagClient); From kremenek at apple.com Wed Feb 24 21:26:51 2010 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 25 Feb 2010 03:26:51 -0000 Subject: [cfe-commits] r97103 - in /cfe/trunk: lib/Sema/SemaDeclAttr.cpp test/SemaObjC/unused.m Message-ID: <20100225032651.844202A6C136@llvm.org> Author: kremenek Date: Wed Feb 24 21:26:51 2010 New Revision: 97103 URL: http://llvm.org/viewvc/llvm-project?rev=97103&view=rev Log: Allow __attribute__((unused)) to be applied to ObjC ivars. Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp cfe/trunk/test/SemaObjC/unused.m Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=97103&r1=97102&r2=97103&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Wed Feb 24 21:26:51 2010 @@ -521,7 +521,7 @@ return; } - if (!isa(d) && !isFunctionOrMethod(d)) { + if (!isa(d) && !isa(d) && !isFunctionOrMethod(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 2 /*variable and function*/; return; Modified: cfe/trunk/test/SemaObjC/unused.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/unused.m?rev=97103&r1=97102&r2=97103&view=diff ============================================================================== --- cfe/trunk/test/SemaObjC/unused.m (original) +++ cfe/trunk/test/SemaObjC/unused.m Wed Feb 24 21:26:51 2010 @@ -7,19 +7,14 @@ @end @implementation Greeter -+ (void) hello { - printf("Hello, World!\n"); -} ++ (void) hello { printf("Hello, World!\n"); } @end - int test1(void) { [Greeter hello]; return 0; } - - @interface NSObject @end @interface NSString : NSObject - (int)length; @@ -29,10 +24,6 @@ @"pointless example call for test purposes".length; // expected-warning {{property access result unused - getters should not have side effects}} } - - - - @interface foo - (int)meth: (int)x: (int)y: (int)z ; @end @@ -42,3 +33,13 @@ (int)y: // expected-warning{{unused}} (int) __attribute__((unused))z { return x; } @end + +//===------------------------------------------------------------------------=== +// The next test shows how clang accepted attribute((unused)) on ObjC +// instance variables, which GCC does not. +//===------------------------------------------------------------------------=== + + at interface TestUnusedIvar { + id x __attribute__((unused)); // no-warning +} + at end From kremenek at apple.com Wed Feb 24 21:26:56 2010 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 25 Feb 2010 03:26:56 -0000 Subject: [cfe-commits] r97104 - in /cfe/trunk: lib/Checker/CMakeLists.txt lib/Checker/CheckObjCUnusedIVars.cpp lib/Checker/ObjCUnusedIVarsChecker.cpp test/Analysis/unused-ivars.m Message-ID: <20100225032656.26DAE2A6C137@llvm.org> Author: kremenek Date: Wed Feb 24 21:26:55 2010 New Revision: 97104 URL: http://llvm.org/viewvc/llvm-project?rev=97104&view=rev Log: Enhance the unused ivar checker to not consider an ivar to be accidentally unused when it is explicitly marked as unused via __attribute__((unused)). Added: cfe/trunk/lib/Checker/ObjCUnusedIVarsChecker.cpp - copied, changed from r97103, cfe/trunk/lib/Checker/CheckObjCUnusedIVars.cpp Removed: cfe/trunk/lib/Checker/CheckObjCUnusedIVars.cpp Modified: cfe/trunk/lib/Checker/CMakeLists.txt cfe/trunk/test/Analysis/unused-ivars.m Modified: cfe/trunk/lib/Checker/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/CMakeLists.txt?rev=97104&r1=97103&r2=97104&view=diff ============================================================================== --- cfe/trunk/lib/Checker/CMakeLists.txt (original) +++ cfe/trunk/lib/Checker/CMakeLists.txt Wed Feb 24 21:26:55 2010 @@ -18,7 +18,6 @@ CheckDeadStores.cpp CheckObjCDealloc.cpp CheckObjCInstMethSignature.cpp - CheckObjCUnusedIVars.cpp CheckSecuritySyntaxOnly.cpp CheckSizeofPointer.cpp Checker.cpp @@ -42,6 +41,7 @@ NSErrorChecker.cpp NoReturnFunctionChecker.cpp OSAtomicChecker.cpp + ObjCUnusedIVarsChecker.cpp PathDiagnostic.cpp PointerArithChecker.cpp PointerSubChecker.cpp Removed: cfe/trunk/lib/Checker/CheckObjCUnusedIVars.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/CheckObjCUnusedIVars.cpp?rev=97103&view=auto ============================================================================== --- cfe/trunk/lib/Checker/CheckObjCUnusedIVars.cpp (original) +++ cfe/trunk/lib/Checker/CheckObjCUnusedIVars.cpp (removed) @@ -1,162 +0,0 @@ -//==- CheckObjCUnusedIVars.cpp - Check for unused ivars ----------*- 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 a CheckObjCUnusedIvars, a checker that -// analyzes an Objective-C class's interface/implementation to determine if it -// has any ivars that are never accessed. -// -//===----------------------------------------------------------------------===// - -#include "clang/Checker/Checkers/LocalCheckers.h" -#include "clang/Checker/BugReporter/PathDiagnostic.h" -#include "clang/Checker/BugReporter/BugReporter.h" -#include "clang/AST/ExprObjC.h" -#include "clang/AST/Expr.h" -#include "clang/AST/DeclObjC.h" -#include "clang/Basic/LangOptions.h" -#include "clang/Basic/SourceManager.h" - -using namespace clang; - -enum IVarState { Unused, Used }; -typedef llvm::DenseMap IvarUsageMap; - -static void Scan(IvarUsageMap& M, const Stmt* S) { - if (!S) - return; - - if (const ObjCIvarRefExpr *Ex = dyn_cast(S)) { - const ObjCIvarDecl *D = Ex->getDecl(); - IvarUsageMap::iterator I = M.find(D); - if (I != M.end()) - I->second = Used; - return; - } - - // Blocks can reference an instance variable of a class. - if (const BlockExpr *BE = dyn_cast(S)) { - Scan(M, BE->getBody()); - return; - } - - for (Stmt::const_child_iterator I=S->child_begin(),E=S->child_end(); I!=E;++I) - Scan(M, *I); -} - -static void Scan(IvarUsageMap& M, const ObjCPropertyImplDecl* D) { - if (!D) - return; - - const ObjCIvarDecl* ID = D->getPropertyIvarDecl(); - - if (!ID) - return; - - IvarUsageMap::iterator I = M.find(ID); - if (I != M.end()) - I->second = Used; -} - -static void Scan(IvarUsageMap& M, const ObjCContainerDecl* D) { - // Scan the methods for accesses. - for (ObjCContainerDecl::instmeth_iterator I = D->instmeth_begin(), - E = D->instmeth_end(); I!=E; ++I) - Scan(M, (*I)->getBody()); - - if (const ObjCImplementationDecl *ID = dyn_cast(D)) { - // Scan for @synthesized property methods that act as setters/getters - // to an ivar. - for (ObjCImplementationDecl::propimpl_iterator I = ID->propimpl_begin(), - E = ID->propimpl_end(); I!=E; ++I) - Scan(M, *I); - - // Scan the associated categories as well. - for (const ObjCCategoryDecl *CD = - ID->getClassInterface()->getCategoryList(); CD ; - CD = CD->getNextClassCategory()) { - if (const ObjCCategoryImplDecl *CID = CD->getImplementation()) - Scan(M, CID); - } - } -} - -static void Scan(IvarUsageMap &M, const DeclContext *C, const FileID FID, - SourceManager &SM) { - for (DeclContext::decl_iterator I=C->decls_begin(), E=C->decls_end(); - I!=E; ++I) - if (const FunctionDecl *FD = dyn_cast(*I)) { - SourceLocation L = FD->getLocStart(); - if (SM.getFileID(L) == FID) - Scan(M, FD->getBody()); - } -} - -void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D, - BugReporter &BR) { - - const ObjCInterfaceDecl* ID = D->getClassInterface(); - IvarUsageMap M; - - // Iterate over the ivars. - for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(), - E=ID->ivar_end(); I!=E; ++I) { - - const ObjCIvarDecl* ID = *I; - - // Ignore ivars that aren't private. - if (ID->getAccessControl() != ObjCIvarDecl::Private) - continue; - - // Skip IB Outlets. - if (ID->getAttr()) - continue; - - M[ID] = Unused; - } - - if (M.empty()) - return; - - // Now scan the implementation declaration. - Scan(M, D); - - - // Any potentially unused ivars? - bool hasUnused = false; - for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I) - if (I->second == Unused) { - hasUnused = true; - break; - } - - if (!hasUnused) - return; - - // We found some potentially unused ivars. Scan the entire translation unit - // for functions inside the @implementation that reference these ivars. - // FIXME: In the future hopefully we can just use the lexical DeclContext - // to go from the ObjCImplementationDecl to the lexically "nested" - // C functions. - SourceManager &SM = BR.getSourceManager(); - Scan(M, D->getDeclContext(), SM.getFileID(D->getLocation()), SM); - - // Find ivars that are unused. - for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I) - if (I->second == Unused) { - std::string sbuf; - llvm::raw_string_ostream os(sbuf); - os << "Instance variable '" << I->first->getNameAsString() - << "' in class '" << ID->getNameAsString() - << "' is never used by the methods in its @implementation " - "(although it may be used by category methods)."; - - BR.EmitBasicReport("Unused instance variable", "Optimization", - os.str(), I->first->getLocation()); - } -} Copied: cfe/trunk/lib/Checker/ObjCUnusedIVarsChecker.cpp (from r97103, cfe/trunk/lib/Checker/CheckObjCUnusedIVars.cpp) URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/ObjCUnusedIVarsChecker.cpp?p2=cfe/trunk/lib/Checker/ObjCUnusedIVarsChecker.cpp&p1=cfe/trunk/lib/Checker/CheckObjCUnusedIVars.cpp&r1=97103&r2=97104&rev=97104&view=diff ============================================================================== --- cfe/trunk/lib/Checker/CheckObjCUnusedIVars.cpp (original) +++ cfe/trunk/lib/Checker/ObjCUnusedIVarsChecker.cpp Wed Feb 24 21:26:55 2010 @@ -1,4 +1,4 @@ -//==- CheckObjCUnusedIVars.cpp - Check for unused ivars ----------*- C++ -*-==// +//==- ObjCUnusedIVarsChecker.cpp - Check for unused ivars --------*- C++ -*-==// // // The LLVM Compiler Infrastructure // @@ -68,14 +68,14 @@ for (ObjCContainerDecl::instmeth_iterator I = D->instmeth_begin(), E = D->instmeth_end(); I!=E; ++I) Scan(M, (*I)->getBody()); - - if (const ObjCImplementationDecl *ID = dyn_cast(D)) { + + if (const ObjCImplementationDecl *ID = dyn_cast(D)) { // Scan for @synthesized property methods that act as setters/getters // to an ivar. for (ObjCImplementationDecl::propimpl_iterator I = ID->propimpl_begin(), E = ID->propimpl_end(); I!=E; ++I) Scan(M, *I); - + // Scan the associated categories as well. for (const ObjCCategoryDecl *CD = ID->getClassInterface()->getCategoryList(); CD ; @@ -92,7 +92,7 @@ I!=E; ++I) if (const FunctionDecl *FD = dyn_cast(*I)) { SourceLocation L = FD->getLocStart(); - if (SM.getFileID(L) == FID) + if (SM.getFileID(L) == FID) Scan(M, FD->getBody()); } } @@ -109,12 +109,12 @@ const ObjCIvarDecl* ID = *I; - // Ignore ivars that aren't private. - if (ID->getAccessControl() != ObjCIvarDecl::Private) - continue; - - // Skip IB Outlets. - if (ID->getAttr()) + // Ignore ivars that... + // (a) aren't private + // (b) explicitly marked unused + // (c) are iboutlets + if (ID->getAccessControl() != ObjCIvarDecl::Private || + ID->getAttr() || ID->getAttr()) continue; M[ID] = Unused; @@ -122,11 +122,10 @@ if (M.empty()) return; - + // Now scan the implementation declaration. Scan(M, D); - // Any potentially unused ivars? bool hasUnused = false; for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I) @@ -134,10 +133,10 @@ hasUnused = true; break; } - + if (!hasUnused) return; - + // We found some potentially unused ivars. Scan the entire translation unit // for functions inside the @implementation that reference these ivars. // FIXME: In the future hopefully we can just use the lexical DeclContext Modified: cfe/trunk/test/Analysis/unused-ivars.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/unused-ivars.m?rev=97104&r1=97103&r2=97104&view=diff ============================================================================== --- cfe/trunk/test/Analysis/unused-ivars.m (original) +++ cfe/trunk/test/Analysis/unused-ivars.m Wed Feb 24 21:26:55 2010 @@ -81,3 +81,18 @@ return a->x; } @end + +//===----------------------------------------------------------------------===// +// - consult attribute((unused)) to silence warnings +// about unused instance variables +//===----------------------------------------------------------------------===// + + at interface RDar7353683 { + at private + id x __attribute__((unused)); +} + at end + + at implementation RDar7353683 + at end + From daniel at zuster.org Wed Feb 24 21:31:53 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Thu, 25 Feb 2010 03:31:53 -0000 Subject: [cfe-commits] r97106 - in /cfe/trunk: include/clang/Driver/Driver.h lib/Driver/Driver.cpp Message-ID: <20100225033153.EC3D92A6C136@llvm.org> Author: ddunbar Date: Wed Feb 24 21:31:53 2010 New Revision: 97106 URL: http://llvm.org/viewvc/llvm-project?rev=97106&view=rev Log: Driver: Allow driver title (for --help) to be overridden by clients. Modified: cfe/trunk/include/clang/Driver/Driver.h cfe/trunk/lib/Driver/Driver.cpp Modified: cfe/trunk/include/clang/Driver/Driver.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Driver.h?rev=97106&r1=97105&r2=97106&view=diff ============================================================================== --- cfe/trunk/include/clang/Driver/Driver.h (original) +++ cfe/trunk/include/clang/Driver/Driver.h Wed Feb 24 21:31:53 2010 @@ -70,6 +70,9 @@ /// Default name for linked images (e.g., "a.out"). std::string DefaultImageName; + /// Driver title to use with help. + std::string DriverTitle; + /// Host information for the platform the driver is running as. This /// will generally be the actual host platform, but not always. const HostInfo *Host; @@ -137,6 +140,9 @@ void setCheckInputsExist(bool Value) { CheckInputsExist = Value; } + const std::string &getTitle() { return DriverTitle; } + void setTitle(std::string Value) { DriverTitle = Value; } + /// @} /// @name Primary Functionality /// @{ Modified: cfe/trunk/lib/Driver/Driver.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Driver.cpp?rev=97106&r1=97105&r2=97106&view=diff ============================================================================== --- cfe/trunk/lib/Driver/Driver.cpp (original) +++ cfe/trunk/lib/Driver/Driver.cpp Wed Feb 24 21:31:53 2010 @@ -49,6 +49,7 @@ : Opts(createDriverOptTable()), Diags(_Diags), Name(_Name), Dir(_Dir), DefaultHostTriple(_DefaultHostTriple), DefaultImageName(_DefaultImageName), + DriverTitle("clang \"gcc-compatible\" driver"), Host(0), CCCGenericGCCName("gcc"), CCCIsCXX(false), CCCEcho(false), CCCPrintBindings(false), CheckInputsExist(true), CCCUseClang(true), @@ -273,8 +274,8 @@ // FIXME: Move -ccc options to real options in the .td file (or eliminate), and // then move to using OptTable::PrintHelp. void Driver::PrintHelp(bool ShowHidden) const { - getOpts().PrintHelp(llvm::outs(), Name.c_str(), - "clang \"gcc-compatible\" driver", ShowHidden); + getOpts().PrintHelp(llvm::outs(), Name.c_str(), DriverTitle.c_str(), + ShowHidden); } void Driver::PrintVersion(const Compilation &C, llvm::raw_ostream &OS) const { From andersca at mac.com Wed Feb 24 21:45:56 2010 From: andersca at mac.com (Anders Carlsson) Date: Thu, 25 Feb 2010 03:45:56 -0000 Subject: [cfe-commits] r97107 - /cfe/trunk/lib/CodeGen/CGVtable.cpp Message-ID: <20100225034556.95E8C2A6C136@llvm.org> Author: andersca Date: Wed Feb 24 21:45:56 2010 New Revision: 97107 URL: http://llvm.org/viewvc/llvm-project?rev=97107&view=rev Log: Move the vcall and vbase offset layout code out into its own class. Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=97107&r1=97106&r2=97107&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVtable.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVtable.cpp Wed Feb 24 21:45:56 2010 @@ -855,6 +855,223 @@ return 0; } +/// VCallAndVBaseOffsetBuilder - Class for building vcall and vbase offsets. +class VCallAndVBaseOffsetBuilder { + /// MostDerivedClass - The most derived class for which we're building this + /// vtable. + const CXXRecordDecl *MostDerivedClass; + + /// Context - The ASTContext which we will use for layout information. + ASTContext &Context; + + /// Components - vcall and vbase offset components + typedef llvm::SmallVector VtableComponentVectorTy; + VtableComponentVectorTy Components; + + /// VisitedVirtualBases - Visited virtual bases. + llvm::SmallPtrSet VisitedVirtualBases; + + /// VCallOffsets - Keeps track of vcall offsets. + VCallOffsetMap VCallOffsets; + + /// FinalOverriders - The final overriders of the most derived class. + /// (Can be null when we're not building a vtable of the most derived class). + const FinalOverriders *Overriders; + + /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the + /// given base subobject. + void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual, + uint64_t RealBaseOffset); + + /// AddVCallOffsets - Add vcall offsets for the given base subobject. + void AddVCallOffsets(BaseSubobject Base, uint64_t VBaseOffset); + + /// AddVBaseOffsets - Add vbase offsets for the given class. + void AddVBaseOffsets(const CXXRecordDecl *Base, int64_t OffsetToTop); + +public: + VCallAndVBaseOffsetBuilder(const CXXRecordDecl *MostDerivedClass, + const FinalOverriders *Overriders, + BaseSubobject Base, bool BaseIsVirtual) + : MostDerivedClass(MostDerivedClass), + Context(MostDerivedClass->getASTContext()), Overriders(Overriders) { + + // Add vcall and vbase offsets. + AddVCallAndVBaseOffsets(Base, BaseIsVirtual, Base.getBaseOffset()); + } + + /// Methods for iterating over the components. + typedef VtableComponentVectorTy::const_reverse_iterator const_iterator; + const_iterator components_begin() const { return Components.rbegin(); } + const_iterator components_end() const { return Components.rend(); } + + /// FIXME: Get rid of this getter. + const VCallOffsetMap& getVCallOffsets() const { return VCallOffsets; } +}; + +void +VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base, + bool BaseIsVirtual, + uint64_t RealBaseOffset) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base.getBase()); + + // Itanium C++ ABI 2.5.2: + // ..in classes sharing a virtual table with a primary base class, the vcall + // and vbase offsets added by the derived class all come before the vcall + // and vbase offsets required by the base class, so that the latter may be + // laid out as required by the base class without regard to additions from + // the derived class(es). + + // (Since we're emitting the vcall and vbase offsets in reverse order, we'll + // emit them for the primary base first). + if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { + bool PrimaryBaseIsVirtual = Layout.getPrimaryBaseWasVirtual(); + + uint64_t PrimaryBaseOffset; + + // Get the base offset of the primary base. + if (PrimaryBaseIsVirtual) { + assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && + "Primary vbase should have a zero offset!"); + + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + + PrimaryBaseOffset = + MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); + } else { + assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && + "Primary base should have a zero offset!"); + + PrimaryBaseOffset = Base.getBaseOffset(); + } + + AddVCallAndVBaseOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset), + PrimaryBaseIsVirtual, RealBaseOffset); + } + + // FIXME: Don't use /8 here. + int64_t OffsetToTop = -(int64_t)Base.getBaseOffset() / 8; + AddVBaseOffsets(Base.getBase(), OffsetToTop); + + // We only want to add vcall offsets for virtual bases. + if (BaseIsVirtual) + AddVCallOffsets(Base, RealBaseOffset); +} + +void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base, + uint64_t VBaseOffset) { + const CXXRecordDecl *RD = Base.getBase(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + // Handle the primary base first. + if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { + uint64_t PrimaryBaseOffset; + + // Get the base offset of the primary base. + if (Layout.getPrimaryBaseWasVirtual()) { + assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && + "Primary vbase should have a zero offset!"); + + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + + PrimaryBaseOffset = + MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); + } else { + assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && + "Primary base should have a zero offset!"); + + PrimaryBaseOffset = Base.getBaseOffset(); + } + + AddVCallOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset), + VBaseOffset); + } + + // Add the vcall offsets. + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + if (!MD->isVirtual()) + continue; + + // OffsetIndex is the index of this vcall offset, relative to the vtable + // address point. (We subtract 3 to account for the information just + // above the address point, the RTTI info, the offset to top, and the + // vcall offset itself). + int64_t OffsetIndex = -(int64_t)(3 + Components.size()); + + // FIXME: We shouldn't use / 8 here. + int64_t OffsetOffset = OffsetIndex * + (int64_t)Context.Target.getPointerWidth(0) / 8; + + // Don't add a vcall offset if we already have one for this member function + // signature. + if (!VCallOffsets.AddVCallOffset(MD, OffsetOffset)) + continue; + + int64_t Offset = 0; + + if (Overriders) { + // Get the final overrider. + FinalOverriders::OverriderInfo Overrider = + Overriders->getOverrider(Base, MD); + + /// The vcall offset is the offset from the virtual base to the object where + /// the function was overridden. + // FIXME: We should not use / 8 here. + Offset = (int64_t)(Overrider.BaseOffset - VBaseOffset) / 8; + } + + Components.push_back(VtableComponent::MakeVCallOffset(Offset)); + } + + // And iterate over all non-virtual bases (ignoring the primary base). + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + + if (I->isVirtual()) + continue; + + const CXXRecordDecl *BaseDecl = + cast(I->getType()->getAs()->getDecl()); + + // Get the base offset of this base. + uint64_t BaseOffset = Base.getBaseOffset() + + Layout.getBaseClassOffset(BaseDecl); + + AddVCallOffsets(BaseSubobject(BaseDecl, BaseOffset), VBaseOffset); + } +} + + +void VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD, + int64_t OffsetToTop) { + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + + // Add vbase offsets. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast(I->getType()->getAs()->getDecl()); + + // Check if this is a virtual base that we haven't visited before. + if (I->isVirtual() && VisitedVirtualBases.insert(BaseDecl)) { + // FIXME: We shouldn't use / 8 here. + uint64_t Offset = + OffsetToTop + MostDerivedClassLayout.getVBaseClassOffset(BaseDecl) / 8; + + Components.push_back(VtableComponent::MakeVBaseOffset(Offset)); + } + + // Check the base class looking for more vbase offsets. + AddVBaseOffsets(BaseDecl, OffsetToTop); + } +} + /// VtableBuilder - Class for building vtable layout information. class VtableBuilder { public: @@ -873,7 +1090,7 @@ ASTContext &Context; /// FinalOverriders - The final overriders of the most derived class. - FinalOverriders Overriders; + const FinalOverriders Overriders; /// VCallAndVBaseOffsets - The vcall and vbase offset, of the vtable we're // building (in reverse order). @@ -1433,13 +1650,12 @@ assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!"); // Add vcall and vbase offsets for this vtable. - VisitedVirtualBasesSetTy VBases; - AddVCallAndVBaseOffsets(Base, BaseIsVirtual, Base.getBaseOffset(), VBases); - - // Reverse them and add them to the vtable components. - std::reverse(VCallAndVBaseOffsets.begin(), VCallAndVBaseOffsets.end()); - Components.append(VCallAndVBaseOffsets.begin(), VCallAndVBaseOffsets.end()); - VCallAndVBaseOffsets.clear(); + VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, &Overriders, + Base, BaseIsVirtual); + Components.append(Builder.components_begin(), Builder.components_end()); + + // FIXME: This is not how we should do vcall offsets. + VCallOffsets = Builder.getVCallOffsets(); // Add the offset to top. // FIXME: This is not going to be right for construction vtables. From andersca at mac.com Wed Feb 24 21:57:50 2010 From: andersca at mac.com (Anders Carlsson) Date: Thu, 25 Feb 2010 03:57:50 -0000 Subject: [cfe-commits] r97109 - /cfe/trunk/lib/CodeGen/CGVtable.cpp Message-ID: <20100225035750.848502A6C136@llvm.org> Author: andersca Date: Wed Feb 24 21:57:50 2010 New Revision: 97109 URL: http://llvm.org/viewvc/llvm-project?rev=97109&view=rev Log: Remove dead code. Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=97109&r1=97108&r2=97109&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVtable.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVtable.cpp Wed Feb 24 21:57:50 2010 @@ -1092,10 +1092,6 @@ /// FinalOverriders - The final overriders of the most derived class. const FinalOverriders Overriders; - /// VCallAndVBaseOffsets - The vcall and vbase offset, of the vtable we're - // building (in reverse order). - llvm::SmallVector VCallAndVBaseOffsets; - /// VCallOffsets - Keeps track of vcall offsets for the current vtable. VCallOffsetMap VCallOffsets; @@ -1149,19 +1145,6 @@ /// some other base. VisitedVirtualBasesSetTy PrimaryVirtualBases; - /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the - /// given base subobject. - void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual, - uint64_t RealBaseOffset, - VisitedVirtualBasesSetTy &VBases); - - /// AddVCallOffsets - Add vcall offsets for the given base subobject. - void AddVCallOffsets(BaseSubobject Base, uint64_t VBaseOffset); - - /// AddVBaseOffsets - Add vbase offsets for the given class. - void AddVBaseOffsets(const CXXRecordDecl *Base, int64_t OffsetToTop, - VisitedVirtualBasesSetTy &VBases); - /// ComputeReturnAdjustment - Compute the return adjustment given a return /// adjustment base offset. ReturnAdjustment ComputeReturnAdjustment(BaseOffset Offset); @@ -1295,165 +1278,6 @@ } void -VtableBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base, - bool BaseIsVirtual, - uint64_t RealBaseOffset, - VisitedVirtualBasesSetTy &VBases) { - const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base.getBase()); - - // Itanium C++ ABI 2.5.2: - // ..in classes sharing a virtual table with a primary base class, the vcall - // and vbase offsets added by the derived class all come before the vcall - // and vbase offsets required by the base class, so that the latter may be - // laid out as required by the base class without regard to additions from - // the derived class(es). - - // (Since we're emitting the vcall and vbase offsets in reverse order, we'll - // emit them for the primary base first). - if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { - bool PrimaryBaseIsVirtual = Layout.getPrimaryBaseWasVirtual(); - - uint64_t PrimaryBaseOffset; - - // Get the base offset of the primary base. - if (PrimaryBaseIsVirtual) { - assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && - "Primary vbase should have a zero offset!"); - - const ASTRecordLayout &MostDerivedClassLayout = - Context.getASTRecordLayout(MostDerivedClass); - - PrimaryBaseOffset = - MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); - } else { - assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && - "Primary base should have a zero offset!"); - - PrimaryBaseOffset = Base.getBaseOffset(); - } - - AddVCallAndVBaseOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset), - PrimaryBaseIsVirtual, RealBaseOffset, VBases); - } - - // FIXME: Don't use /8 here. - int64_t OffsetToTop = -(int64_t)Base.getBaseOffset() / 8; - AddVBaseOffsets(Base.getBase(), OffsetToTop, VBases); - - // We only want to add vcall offsets for virtual bases. - if (BaseIsVirtual) - AddVCallOffsets(Base, RealBaseOffset); -} - -void VtableBuilder::AddVCallOffsets(BaseSubobject Base, uint64_t VBaseOffset) { - const CXXRecordDecl *RD = Base.getBase(); - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - - // Handle the primary base first. - if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { - uint64_t PrimaryBaseOffset; - - // Get the base offset of the primary base. - if (Layout.getPrimaryBaseWasVirtual()) { - assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && - "Primary vbase should have a zero offset!"); - - const ASTRecordLayout &MostDerivedClassLayout = - Context.getASTRecordLayout(MostDerivedClass); - - PrimaryBaseOffset = - MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); - } else { - assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && - "Primary base should have a zero offset!"); - - PrimaryBaseOffset = Base.getBaseOffset(); - } - - AddVCallOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset), - VBaseOffset); - } - - // Add the vcall offsets. - for (CXXRecordDecl::method_iterator I = RD->method_begin(), - E = RD->method_end(); I != E; ++I) { - const CXXMethodDecl *MD = *I; - - if (!MD->isVirtual()) - continue; - - // OffsetIndex is the index of this vcall offset, relative to the vtable - // address point. (We subtract 3 to account for the information just - // above the address point, the RTTI info, the offset to top, and the - // vcall offset itself). - int64_t OffsetIndex = -(int64_t)(3 + VCallAndVBaseOffsets.size()); - - // FIXME: We shouldn't use / 8 here. - int64_t OffsetOffset = OffsetIndex * - (int64_t)Context.Target.getPointerWidth(0) / 8; - - // Don't add a vcall offset if we already have one for this member function - // signature. - if (!VCallOffsets.AddVCallOffset(MD, OffsetOffset)) - continue; - - // Get the final overrider. - FinalOverriders::OverriderInfo Overrider = - Overriders.getOverrider(Base, MD); - - /// The vcall offset is the offset from the virtual base to the object where - /// the function was overridden. - // FIXME: We should not use / 8 here. - int64_t Offset = (int64_t)(Overrider.BaseOffset - VBaseOffset) / 8; - - VCallAndVBaseOffsets.push_back(VtableComponent::MakeVCallOffset(Offset)); - } - - // And iterate over all non-virtual bases (ignoring the primary base). - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - - if (I->isVirtual()) - continue; - - const CXXRecordDecl *BaseDecl = - cast(I->getType()->getAs()->getDecl()); - - // Get the base offset of this base. - uint64_t BaseOffset = Base.getBaseOffset() + - Layout.getBaseClassOffset(BaseDecl); - - AddVCallOffsets(BaseSubobject(BaseDecl, BaseOffset), VBaseOffset); - } -} - -void VtableBuilder::AddVBaseOffsets(const CXXRecordDecl *RD, - int64_t OffsetToTop, - VisitedVirtualBasesSetTy &VBases) { - const ASTRecordLayout &MostDerivedClassLayout = - Context.getASTRecordLayout(MostDerivedClass); - - // Add vbase offsets. - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { - const CXXRecordDecl *BaseDecl = - cast(I->getType()->getAs()->getDecl()); - - // Check if this is a virtual base that we haven't visited before. - if (I->isVirtual() && VBases.insert(BaseDecl)) { - // FIXME: We shouldn't use / 8 here. - uint64_t Offset = - OffsetToTop + MostDerivedClassLayout.getVBaseClassOffset(BaseDecl) / 8; - - VCallAndVBaseOffsets.push_back(VtableComponent::MakeVBaseOffset(Offset)); - } - - // Check the base class looking for more vbase offsets. - AddVBaseOffsets(BaseDecl, OffsetToTop, VBases); - } -} - -void VtableBuilder::AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment, ThisAdjustment ThisAdjustment) { From daniel at zuster.org Wed Feb 24 22:37:50 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Thu, 25 Feb 2010 04:37:50 -0000 Subject: [cfe-commits] r97111 - in /cfe/trunk: include/clang/Frontend/CodeGenAction.h lib/Frontend/CodeGenAction.cpp Message-ID: <20100225043750.3097E2A6C137@llvm.org> Author: ddunbar Date: Wed Feb 24 22:37:50 2010 New Revision: 97111 URL: http://llvm.org/viewvc/llvm-project?rev=97111&view=rev Log: Frontend: Add CodeGenAction::takeModule(). Modified: cfe/trunk/include/clang/Frontend/CodeGenAction.h cfe/trunk/lib/Frontend/CodeGenAction.cpp Modified: cfe/trunk/include/clang/Frontend/CodeGenAction.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CodeGenAction.h?rev=97111&r1=97110&r2=97111&view=diff ============================================================================== --- cfe/trunk/include/clang/Frontend/CodeGenAction.h (original) +++ cfe/trunk/include/clang/Frontend/CodeGenAction.h Wed Feb 24 22:37:50 2010 @@ -8,18 +8,31 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/FrontendAction.h" +#include "llvm/ADT/OwningPtr.h" + +namespace llvm { + class Module; +} namespace clang { class CodeGenAction : public ASTFrontendAction { private: unsigned Act; + llvm::OwningPtr TheModule; protected: CodeGenAction(unsigned _Act); virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile); + + virtual void EndSourceFileAction(); + +public: + /// takeModule - Take the generated LLVM module, for use after the action has + /// been run. The result may be null on failure. + llvm::Module *takeModule(); }; class EmitAssemblyAction : public CodeGenAction { Modified: cfe/trunk/lib/Frontend/CodeGenAction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CodeGenAction.cpp?rev=97111&r1=97110&r2=97111&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/CodeGenAction.cpp (original) +++ cfe/trunk/lib/Frontend/CodeGenAction.cpp Wed Feb 24 22:37:50 2010 @@ -62,7 +62,7 @@ llvm::OwningPtr Gen; - llvm::Module *TheModule; + llvm::OwningPtr TheModule; llvm::TargetData *TheTargetData; mutable FunctionPassManager *CodeGenPasses; @@ -97,7 +97,7 @@ LLVMIRGeneration("LLVM IR Generation Time"), CodeGenerationTime("Code Generation Time"), Gen(CreateLLVMCodeGen(Diags, infile, compopts, C)), - TheModule(0), TheTargetData(0), + TheTargetData(0), CodeGenPasses(0), PerModulePasses(0), PerFunctionPasses(0) { if (AsmOutStream) @@ -109,12 +109,13 @@ ~BackendConsumer() { delete TheTargetData; - delete TheModule; delete CodeGenPasses; delete PerModulePasses; delete PerFunctionPasses; } + llvm::Module *takeModule() { return TheModule.take(); } + virtual void Initialize(ASTContext &Ctx) { Context = &Ctx; @@ -123,7 +124,7 @@ Gen->Initialize(Ctx); - TheModule = Gen->GetModule(); + TheModule.reset(Gen->GetModule()); TheTargetData = new llvm::TargetData(Ctx.Target.getTargetDescription()); if (llvm::TimePassesIsEnabled) @@ -179,7 +180,7 @@ FunctionPassManager *BackendConsumer::getCodeGenPasses() const { if (!CodeGenPasses) { - CodeGenPasses = new FunctionPassManager(TheModule); + CodeGenPasses = new FunctionPassManager(&*TheModule); CodeGenPasses->add(new TargetData(*TheTargetData)); } @@ -197,7 +198,7 @@ FunctionPassManager *BackendConsumer::getPerFunctionPasses() const { if (!PerFunctionPasses) { - PerFunctionPasses = new FunctionPassManager(TheModule); + PerFunctionPasses = new FunctionPassManager(&*TheModule); PerFunctionPasses->add(new TargetData(*TheTargetData)); } @@ -391,11 +392,12 @@ if (!M) { // The module has been released by IR gen on failures, do not // double free. - TheModule = 0; + TheModule.take(); return; } - assert(TheModule == M && "Unexpected module change during IR generation"); + assert(TheModule.get() == M && + "Unexpected module change during IR generation"); CreatePasses(); if (!AddEmitPasses()) @@ -433,6 +435,22 @@ CodeGenAction::CodeGenAction(unsigned _Act) : Act(_Act) {} +void CodeGenAction::EndSourceFileAction() { + // If the consumer creation failed, do nothing. + if (!getCompilerInstance().hasASTConsumer()) + return; + + // Steal the module from the consumer. + BackendConsumer *Consumer = static_cast( + &getCompilerInstance().getASTConsumer()); + + TheModule.reset(Consumer->takeModule()); +} + +llvm::Module *CodeGenAction::takeModule() { + return TheModule.take(); +} + ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { BackendAction BA = static_cast(Act); From daniel at zuster.org Wed Feb 24 22:37:45 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Thu, 25 Feb 2010 04:37:45 -0000 Subject: [cfe-commits] r97110 - in /cfe/trunk: include/clang/Frontend/ASTConsumers.h include/clang/Frontend/CodeGenAction.h include/clang/Frontend/FrontendActions.h lib/Frontend/Backend.cpp lib/Frontend/CodeGenAction.cpp lib/Frontend/FrontendActions.cpp tools/driver/cc1_main.cpp Message-ID: <20100225043745.DC07A2A6C136@llvm.org> Author: ddunbar Date: Wed Feb 24 22:37:45 2010 New Revision: 97110 URL: http://llvm.org/viewvc/llvm-project?rev=97110&view=rev Log: Frontend: Pull CodeGenAction out more, and eliminate CreateBackendConsumer. This is the way I would like to move the frontend function towards -- distinct pieces of functionality should be exposed only via FrontendAction implementations which have clean and relatively-stable APIs. This also isolates the surface area in clang which depends on LLVM CodeGen. Added: cfe/trunk/include/clang/Frontend/CodeGenAction.h cfe/trunk/lib/Frontend/CodeGenAction.cpp - copied, changed from r97109, cfe/trunk/lib/Frontend/Backend.cpp Removed: cfe/trunk/lib/Frontend/Backend.cpp Modified: cfe/trunk/include/clang/Frontend/ASTConsumers.h cfe/trunk/include/clang/Frontend/FrontendActions.h cfe/trunk/lib/Frontend/FrontendActions.cpp cfe/trunk/tools/driver/cc1_main.cpp Modified: cfe/trunk/include/clang/Frontend/ASTConsumers.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/ASTConsumers.h?rev=97110&r1=97109&r2=97110&view=diff ============================================================================== --- cfe/trunk/include/clang/Frontend/ASTConsumers.h (original) +++ cfe/trunk/include/clang/Frontend/ASTConsumers.h Wed Feb 24 22:37:45 2010 @@ -69,26 +69,6 @@ const LangOptions &LOpts, bool SilenceRewriteMacroWarning); -// LLVM code generator: uses the code generation backend to generate LLVM -// assembly. This runs optimizations depending on the CodeGenOptions -// parameter. The output depends on the Action parameter. -enum BackendAction { - Backend_EmitAssembly, // Emit native assembly files - Backend_EmitBC, // Emit LLVM bitcode files - Backend_EmitLL, // Emit human-readable LLVM assembly - Backend_EmitNothing, // Don't emit anything (benchmarking mode) - Backend_EmitObj // Emit native object files -}; -ASTConsumer *CreateBackendConsumer(BackendAction Action, - Diagnostic &Diags, - const LangOptions &Features, - const CodeGenOptions &CodeGenOpts, - const TargetOptions &TargetOpts, - bool TimePasses, - const std::string &ModuleID, - llvm::raw_ostream *OS, - llvm::LLVMContext& C); - /// CreateHTMLPrinter - Create an AST consumer which rewrites source code to /// HTML with syntax highlighting suitable for viewing in a web-browser. ASTConsumer *CreateHTMLPrinter(llvm::raw_ostream *OS, Preprocessor &PP, Added: cfe/trunk/include/clang/Frontend/CodeGenAction.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CodeGenAction.h?rev=97110&view=auto ============================================================================== --- cfe/trunk/include/clang/Frontend/CodeGenAction.h (added) +++ cfe/trunk/include/clang/Frontend/CodeGenAction.h Wed Feb 24 22:37:45 2010 @@ -0,0 +1,50 @@ +//===--- CodeGenAction.h - LLVM Code Generation Frontend Action -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/FrontendAction.h" + +namespace clang { + +class CodeGenAction : public ASTFrontendAction { +private: + unsigned Act; + +protected: + CodeGenAction(unsigned _Act); + + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile); +}; + +class EmitAssemblyAction : public CodeGenAction { +public: + EmitAssemblyAction(); +}; + +class EmitBCAction : public CodeGenAction { +public: + EmitBCAction(); +}; + +class EmitLLVMAction : public CodeGenAction { +public: + EmitLLVMAction(); +}; + +class EmitLLVMOnlyAction : public CodeGenAction { +public: + EmitLLVMOnlyAction(); +}; + +class EmitObjAction : public CodeGenAction { +public: + EmitObjAction(); +}; + +} Modified: cfe/trunk/include/clang/Frontend/FrontendActions.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendActions.h?rev=97110&r1=97109&r2=97110&view=diff ============================================================================== --- cfe/trunk/include/clang/Frontend/FrontendActions.h (original) +++ cfe/trunk/include/clang/Frontend/FrontendActions.h Wed Feb 24 22:37:45 2010 @@ -159,46 +159,6 @@ }; //===----------------------------------------------------------------------===// -// Code Gen AST Actions -//===----------------------------------------------------------------------===// - -class CodeGenAction : public ASTFrontendAction { -private: - unsigned Act; - -protected: - CodeGenAction(unsigned _Act); - - virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile); -}; - -class EmitAssemblyAction : public CodeGenAction { -public: - EmitAssemblyAction(); -}; - -class EmitBCAction : public CodeGenAction { -public: - EmitBCAction(); -}; - -class EmitLLVMAction : public CodeGenAction { -public: - EmitLLVMAction(); -}; - -class EmitLLVMOnlyAction : public CodeGenAction { -public: - EmitLLVMOnlyAction(); -}; - -class EmitObjAction : public CodeGenAction { -public: - EmitObjAction(); -}; - -//===----------------------------------------------------------------------===// // Preprocessor Actions //===----------------------------------------------------------------------===// Removed: cfe/trunk/lib/Frontend/Backend.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/Backend.cpp?rev=97109&view=auto ============================================================================== --- cfe/trunk/lib/Frontend/Backend.cpp (original) +++ cfe/trunk/lib/Frontend/Backend.cpp (removed) @@ -1,433 +0,0 @@ -//===--- Backend.cpp - Interface to LLVM backend technologies -------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "clang/Frontend/ASTConsumers.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/DeclGroup.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/Basic/TargetOptions.h" -#include "clang/CodeGen/CodeGenOptions.h" -#include "clang/CodeGen/ModuleBuilder.h" -#include "clang/Frontend/FrontendDiagnostic.h" -#include "llvm/Module.h" -#include "llvm/PassManager.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/Assembly/PrintModulePass.h" -#include "llvm/Analysis/CallGraph.h" -#include "llvm/Analysis/Verifier.h" -#include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/CodeGen/RegAllocRegistry.h" -#include "llvm/CodeGen/SchedulerRegistry.h" -#include "llvm/Support/FormattedStream.h" -#include "llvm/Support/StandardPasses.h" -#include "llvm/Support/Timer.h" -#include "llvm/Target/SubtargetFeature.h" -#include "llvm/Target/TargetData.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetOptions.h" -#include "llvm/Target/TargetRegistry.h" -using namespace clang; -using namespace llvm; - -namespace { - class BackendConsumer : public ASTConsumer { - Diagnostic &Diags; - BackendAction Action; - const CodeGenOptions &CodeGenOpts; - const LangOptions &LangOpts; - const TargetOptions &TargetOpts; - llvm::raw_ostream *AsmOutStream; - llvm::formatted_raw_ostream FormattedOutStream; - ASTContext *Context; - - Timer LLVMIRGeneration; - Timer CodeGenerationTime; - - llvm::OwningPtr Gen; - - llvm::Module *TheModule; - llvm::TargetData *TheTargetData; - - mutable FunctionPassManager *CodeGenPasses; - mutable PassManager *PerModulePasses; - mutable FunctionPassManager *PerFunctionPasses; - - FunctionPassManager *getCodeGenPasses() const; - PassManager *getPerModulePasses() const; - FunctionPassManager *getPerFunctionPasses() const; - - void CreatePasses(); - - /// AddEmitPasses - Add passes necessary to emit assembly or LLVM IR. - /// - /// \return True on success. - bool AddEmitPasses(); - - void EmitAssembly(); - - public: - BackendConsumer(BackendAction action, Diagnostic &_Diags, - const LangOptions &langopts, const CodeGenOptions &compopts, - const TargetOptions &targetopts, bool TimePasses, - const std::string &infile, llvm::raw_ostream *OS, - LLVMContext& C) : - Diags(_Diags), - Action(action), - CodeGenOpts(compopts), - LangOpts(langopts), - TargetOpts(targetopts), - AsmOutStream(OS), - LLVMIRGeneration("LLVM IR Generation Time"), - CodeGenerationTime("Code Generation Time"), - Gen(CreateLLVMCodeGen(Diags, infile, compopts, C)), - TheModule(0), TheTargetData(0), - CodeGenPasses(0), PerModulePasses(0), PerFunctionPasses(0) { - - if (AsmOutStream) - FormattedOutStream.setStream(*AsmOutStream, - formatted_raw_ostream::PRESERVE_STREAM); - - llvm::TimePassesIsEnabled = TimePasses; - } - - ~BackendConsumer() { - delete TheTargetData; - delete TheModule; - delete CodeGenPasses; - delete PerModulePasses; - delete PerFunctionPasses; - } - - virtual void Initialize(ASTContext &Ctx) { - Context = &Ctx; - - if (llvm::TimePassesIsEnabled) - LLVMIRGeneration.startTimer(); - - Gen->Initialize(Ctx); - - TheModule = Gen->GetModule(); - TheTargetData = new llvm::TargetData(Ctx.Target.getTargetDescription()); - - if (llvm::TimePassesIsEnabled) - LLVMIRGeneration.stopTimer(); - } - - virtual void HandleTopLevelDecl(DeclGroupRef D) { - PrettyStackTraceDecl CrashInfo(*D.begin(), SourceLocation(), - Context->getSourceManager(), - "LLVM IR generation of declaration"); - - if (llvm::TimePassesIsEnabled) - LLVMIRGeneration.startTimer(); - - Gen->HandleTopLevelDecl(D); - - if (llvm::TimePassesIsEnabled) - LLVMIRGeneration.stopTimer(); - } - - virtual void HandleTranslationUnit(ASTContext &C) { - { - PrettyStackTraceString CrashInfo("Per-file LLVM IR generation"); - if (llvm::TimePassesIsEnabled) - LLVMIRGeneration.startTimer(); - - Gen->HandleTranslationUnit(C); - - if (llvm::TimePassesIsEnabled) - LLVMIRGeneration.stopTimer(); - } - - // EmitAssembly times and registers crash info itself. - EmitAssembly(); - - // Force a flush here in case we never get released. - if (AsmOutStream) - FormattedOutStream.flush(); - } - - virtual void HandleTagDeclDefinition(TagDecl *D) { - PrettyStackTraceDecl CrashInfo(D, SourceLocation(), - Context->getSourceManager(), - "LLVM IR generation of declaration"); - Gen->HandleTagDeclDefinition(D); - } - - virtual void CompleteTentativeDefinition(VarDecl *D) { - Gen->CompleteTentativeDefinition(D); - } - }; -} - -FunctionPassManager *BackendConsumer::getCodeGenPasses() const { - if (!CodeGenPasses) { - CodeGenPasses = new FunctionPassManager(TheModule); - CodeGenPasses->add(new TargetData(*TheTargetData)); - } - - return CodeGenPasses; -} - -PassManager *BackendConsumer::getPerModulePasses() const { - if (!PerModulePasses) { - PerModulePasses = new PassManager(); - PerModulePasses->add(new TargetData(*TheTargetData)); - } - - return PerModulePasses; -} - -FunctionPassManager *BackendConsumer::getPerFunctionPasses() const { - if (!PerFunctionPasses) { - PerFunctionPasses = new FunctionPassManager(TheModule); - PerFunctionPasses->add(new TargetData(*TheTargetData)); - } - - return PerFunctionPasses; -} - -bool BackendConsumer::AddEmitPasses() { - if (Action == Backend_EmitNothing) - return true; - - if (Action == Backend_EmitBC) { - getPerModulePasses()->add(createBitcodeWriterPass(FormattedOutStream)); - } else if (Action == Backend_EmitLL) { - getPerModulePasses()->add(createPrintModulePass(&FormattedOutStream)); - } else { - bool Fast = CodeGenOpts.OptimizationLevel == 0; - - // Create the TargetMachine for generating code. - std::string Error; - std::string Triple = TheModule->getTargetTriple(); - const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error); - if (!TheTarget) { - Diags.Report(diag::err_fe_unable_to_create_target) << Error; - return false; - } - - // FIXME: Expose these capabilities via actual APIs!!!! Aside from just - // being gross, this is also totally broken if we ever care about - // concurrency. - llvm::NoFramePointerElim = CodeGenOpts.DisableFPElim; - if (CodeGenOpts.FloatABI == "soft") - llvm::FloatABIType = llvm::FloatABI::Soft; - else if (CodeGenOpts.FloatABI == "hard") - llvm::FloatABIType = llvm::FloatABI::Hard; - else { - assert(CodeGenOpts.FloatABI.empty() && "Invalid float abi!"); - llvm::FloatABIType = llvm::FloatABI::Default; - } - NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS; - llvm::UseSoftFloat = CodeGenOpts.SoftFloat; - UnwindTablesMandatory = CodeGenOpts.UnwindTables; - - TargetMachine::setAsmVerbosityDefault(CodeGenOpts.AsmVerbose); - - // FIXME: Parse this earlier. - if (CodeGenOpts.RelocationModel == "static") { - TargetMachine::setRelocationModel(llvm::Reloc::Static); - } else if (CodeGenOpts.RelocationModel == "pic") { - TargetMachine::setRelocationModel(llvm::Reloc::PIC_); - } else { - assert(CodeGenOpts.RelocationModel == "dynamic-no-pic" && - "Invalid PIC model!"); - TargetMachine::setRelocationModel(llvm::Reloc::DynamicNoPIC); - } - // FIXME: Parse this earlier. - if (CodeGenOpts.CodeModel == "small") { - TargetMachine::setCodeModel(llvm::CodeModel::Small); - } else if (CodeGenOpts.CodeModel == "kernel") { - TargetMachine::setCodeModel(llvm::CodeModel::Kernel); - } else if (CodeGenOpts.CodeModel == "medium") { - TargetMachine::setCodeModel(llvm::CodeModel::Medium); - } else if (CodeGenOpts.CodeModel == "large") { - TargetMachine::setCodeModel(llvm::CodeModel::Large); - } else { - assert(CodeGenOpts.CodeModel.empty() && "Invalid code model!"); - TargetMachine::setCodeModel(llvm::CodeModel::Default); - } - - std::vector BackendArgs; - BackendArgs.push_back("clang"); // Fake program name. - if (!CodeGenOpts.DebugPass.empty()) { - BackendArgs.push_back("-debug-pass"); - BackendArgs.push_back(CodeGenOpts.DebugPass.c_str()); - } - if (!CodeGenOpts.LimitFloatPrecision.empty()) { - BackendArgs.push_back("-limit-float-precision"); - BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str()); - } - if (llvm::TimePassesIsEnabled) - BackendArgs.push_back("-time-passes"); - BackendArgs.push_back(0); - llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1, - (char**) &BackendArgs[0]); - - std::string FeaturesStr; - if (TargetOpts.CPU.size() || TargetOpts.Features.size()) { - SubtargetFeatures Features; - Features.setCPU(TargetOpts.CPU); - for (std::vector::const_iterator - it = TargetOpts.Features.begin(), - ie = TargetOpts.Features.end(); it != ie; ++it) - Features.AddFeature(*it); - FeaturesStr = Features.getString(); - } - TargetMachine *TM = TheTarget->createTargetMachine(Triple, FeaturesStr); - - // Set register scheduler & allocation policy. - RegisterScheduler::setDefault(createDefaultScheduler); - RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator : - createLinearScanRegisterAllocator); - - // From llvm-gcc: - // If there are passes we have to run on the entire module, we do codegen - // as a separate "pass" after that happens. - // FIXME: This is disabled right now until bugs can be worked out. Reenable - // this for fast -O0 compiles! - FunctionPassManager *PM = getCodeGenPasses(); - CodeGenOpt::Level OptLevel = CodeGenOpt::Default; - - switch (CodeGenOpts.OptimizationLevel) { - default: break; - case 0: OptLevel = CodeGenOpt::None; break; - case 3: OptLevel = CodeGenOpt::Aggressive; break; - } - - // Normal mode, emit a .s or .o file by running the code generator. Note, - // this also adds codegenerator level optimization passes. - TargetMachine::CodeGenFileType CGFT = TargetMachine::CGFT_AssemblyFile; - if (Action == Backend_EmitObj) - CGFT = TargetMachine::CGFT_ObjectFile; - if (TM->addPassesToEmitFile(*PM, FormattedOutStream, CGFT, OptLevel)) { - Diags.Report(diag::err_fe_unable_to_interface_with_target); - return false; - } - } - - return true; -} - -void BackendConsumer::CreatePasses() { - unsigned OptLevel = CodeGenOpts.OptimizationLevel; - CodeGenOptions::InliningMethod Inlining = CodeGenOpts.Inlining; - - // Handle disabling of LLVM optimization, where we want to preserve the - // internal module before any optimization. - if (CodeGenOpts.DisableLLVMOpts) { - OptLevel = 0; - Inlining = CodeGenOpts.NoInlining; - } - - // In -O0 if checking is disabled, we don't even have per-function passes. - if (CodeGenOpts.VerifyModule) - getPerFunctionPasses()->add(createVerifierPass()); - - // Assume that standard function passes aren't run for -O0. - if (OptLevel > 0) - llvm::createStandardFunctionPasses(getPerFunctionPasses(), OptLevel); - - llvm::Pass *InliningPass = 0; - switch (Inlining) { - case CodeGenOptions::NoInlining: break; - case CodeGenOptions::NormalInlining: { - // Set the inline threshold following llvm-gcc. - // - // FIXME: Derive these constants in a principled fashion. - unsigned Threshold = 225; - if (CodeGenOpts.OptimizeSize) - Threshold = 75; - else if (OptLevel > 2) - Threshold = 275; - InliningPass = createFunctionInliningPass(Threshold); - break; - } - case CodeGenOptions::OnlyAlwaysInlining: - InliningPass = createAlwaysInlinerPass(); // Respect always_inline - break; - } - - // For now we always create per module passes. - PassManager *PM = getPerModulePasses(); - llvm::createStandardModulePasses(PM, OptLevel, CodeGenOpts.OptimizeSize, - CodeGenOpts.UnitAtATime, - CodeGenOpts.UnrollLoops, - /*SimplifyLibCalls=*/!LangOpts.NoBuiltin, - /*HaveExceptions=*/true, - InliningPass); -} - -/// EmitAssembly - Handle interaction with LLVM backend to generate -/// actual machine code. -void BackendConsumer::EmitAssembly() { - // Silently ignore if we weren't initialized for some reason. - if (!TheModule || !TheTargetData) - return; - - TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : 0); - - // Make sure IR generation is happy with the module. This is - // released by the module provider. - Module *M = Gen->ReleaseModule(); - if (!M) { - // The module has been released by IR gen on failures, do not - // double free. - TheModule = 0; - return; - } - - assert(TheModule == M && "Unexpected module change during IR generation"); - - CreatePasses(); - if (!AddEmitPasses()) - return; - - // Run passes. For now we do all passes at once, but eventually we - // would like to have the option of streaming code generation. - - if (PerFunctionPasses) { - PrettyStackTraceString CrashInfo("Per-function optimization"); - - PerFunctionPasses->doInitialization(); - for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) - if (!I->isDeclaration()) - PerFunctionPasses->run(*I); - PerFunctionPasses->doFinalization(); - } - - if (PerModulePasses) { - PrettyStackTraceString CrashInfo("Per-module optimization passes"); - PerModulePasses->run(*M); - } - - if (CodeGenPasses) { - PrettyStackTraceString CrashInfo("Code generation"); - CodeGenPasses->doInitialization(); - for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) - if (!I->isDeclaration()) - CodeGenPasses->run(*I); - CodeGenPasses->doFinalization(); - } -} - -ASTConsumer *clang::CreateBackendConsumer(BackendAction Action, - Diagnostic &Diags, - const LangOptions &LangOpts, - const CodeGenOptions &CodeGenOpts, - const TargetOptions &TargetOpts, - bool TimePasses, - const std::string& InFile, - llvm::raw_ostream* OS, - LLVMContext& C) { - return new BackendConsumer(Action, Diags, LangOpts, CodeGenOpts, - TargetOpts, TimePasses, InFile, OS, C); -} Copied: cfe/trunk/lib/Frontend/CodeGenAction.cpp (from r97109, cfe/trunk/lib/Frontend/Backend.cpp) URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CodeGenAction.cpp?p2=cfe/trunk/lib/Frontend/CodeGenAction.cpp&p1=cfe/trunk/lib/Frontend/Backend.cpp&r1=97109&r2=97110&rev=97110&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/Backend.cpp (original) +++ cfe/trunk/lib/Frontend/CodeGenAction.cpp Wed Feb 24 22:37:45 2010 @@ -1,4 +1,4 @@ -//===--- Backend.cpp - Interface to LLVM backend technologies -------------===// +//===--- CodeGenAction.cpp - LLVM Code Generation Frontend Action ---------===// // // The LLVM Compiler Infrastructure // @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Frontend/ASTConsumers.h" +#include "clang/Frontend/CodeGenAction.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclGroup.h" @@ -15,6 +15,8 @@ #include "clang/Basic/TargetOptions.h" #include "clang/CodeGen/CodeGenOptions.h" #include "clang/CodeGen/ModuleBuilder.h" +#include "clang/Frontend/ASTConsumers.h" +#include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "llvm/Module.h" #include "llvm/PassManager.h" @@ -37,6 +39,14 @@ using namespace llvm; namespace { + enum BackendAction { + Backend_EmitAssembly, ///< Emit native assembly files + Backend_EmitBC, ///< Emit LLVM bitcode files + Backend_EmitLL, ///< Emit human-readable LLVM assembly + Backend_EmitNothing, ///< Don't emit anything (benchmarking mode) + Backend_EmitObj ///< Emit native object files + }; + class BackendConsumer : public ASTConsumer { Diagnostic &Diags; BackendAction Action; @@ -419,15 +429,46 @@ } } -ASTConsumer *clang::CreateBackendConsumer(BackendAction Action, - Diagnostic &Diags, - const LangOptions &LangOpts, - const CodeGenOptions &CodeGenOpts, - const TargetOptions &TargetOpts, - bool TimePasses, - const std::string& InFile, - llvm::raw_ostream* OS, - LLVMContext& C) { - return new BackendConsumer(Action, Diags, LangOpts, CodeGenOpts, - TargetOpts, TimePasses, InFile, OS, C); +// + +CodeGenAction::CodeGenAction(unsigned _Act) : Act(_Act) {} + +ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + BackendAction BA = static_cast(Act); + llvm::OwningPtr OS; + switch (BA) { + case Backend_EmitAssembly: + OS.reset(CI.createDefaultOutputFile(false, InFile, "s")); + break; + case Backend_EmitLL: + OS.reset(CI.createDefaultOutputFile(false, InFile, "ll")); + break; + case Backend_EmitBC: + OS.reset(CI.createDefaultOutputFile(true, InFile, "bc")); + break; + case Backend_EmitNothing: + break; + case Backend_EmitObj: + OS.reset(CI.createDefaultOutputFile(true, InFile, "o")); + break; + } + if (BA != Backend_EmitNothing && !OS) + return 0; + + return new BackendConsumer(BA, CI.getDiagnostics(), CI.getLangOpts(), + CI.getCodeGenOpts(), CI.getTargetOpts(), + CI.getFrontendOpts().ShowTimers, InFile, OS.take(), + CI.getLLVMContext()); } + +EmitAssemblyAction::EmitAssemblyAction() + : CodeGenAction(Backend_EmitAssembly) {} + +EmitBCAction::EmitBCAction() : CodeGenAction(Backend_EmitBC) {} + +EmitLLVMAction::EmitLLVMAction() : CodeGenAction(Backend_EmitLL) {} + +EmitLLVMOnlyAction::EmitLLVMOnlyAction() : CodeGenAction(Backend_EmitNothing) {} + +EmitObjAction::EmitObjAction() : CodeGenAction(Backend_EmitObj) {} Modified: cfe/trunk/lib/Frontend/FrontendActions.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendActions.cpp?rev=97110&r1=97109&r2=97110&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/FrontendActions.cpp (original) +++ cfe/trunk/lib/Frontend/FrontendActions.cpp Wed Feb 24 22:37:45 2010 @@ -159,48 +159,6 @@ return new ASTConsumer(); } -CodeGenAction::CodeGenAction(unsigned _Act) : Act(_Act) {} - -ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { - BackendAction BA = static_cast(Act); - llvm::OwningPtr OS; - switch (BA) { - case Backend_EmitAssembly: - OS.reset(CI.createDefaultOutputFile(false, InFile, "s")); - break; - case Backend_EmitLL: - OS.reset(CI.createDefaultOutputFile(false, InFile, "ll")); - break; - case Backend_EmitBC: - OS.reset(CI.createDefaultOutputFile(true, InFile, "bc")); - break; - case Backend_EmitNothing: - break; - case Backend_EmitObj: - OS.reset(CI.createDefaultOutputFile(true, InFile, "o")); - break; - } - if (BA != Backend_EmitNothing && !OS) - return 0; - - return CreateBackendConsumer(BA, CI.getDiagnostics(), CI.getLangOpts(), - CI.getCodeGenOpts(), CI.getTargetOpts(), - CI.getFrontendOpts().ShowTimers, InFile, - OS.take(), CI.getLLVMContext()); -} - -EmitAssemblyAction::EmitAssemblyAction() - : CodeGenAction(Backend_EmitAssembly) {} - -EmitBCAction::EmitBCAction() : CodeGenAction(Backend_EmitBC) {} - -EmitLLVMAction::EmitLLVMAction() : CodeGenAction(Backend_EmitLL) {} - -EmitLLVMOnlyAction::EmitLLVMOnlyAction() : CodeGenAction(Backend_EmitNothing) {} - -EmitObjAction::EmitObjAction() : CodeGenAction(Backend_EmitObj) {} - //===----------------------------------------------------------------------===// // Preprocessor Actions //===----------------------------------------------------------------------===// Modified: cfe/trunk/tools/driver/cc1_main.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/driver/cc1_main.cpp?rev=97110&r1=97109&r2=97110&view=diff ============================================================================== --- cfe/trunk/tools/driver/cc1_main.cpp (original) +++ cfe/trunk/tools/driver/cc1_main.cpp Wed Feb 24 22:37:45 2010 @@ -19,6 +19,7 @@ #include "clang/Driver/CC1Options.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/OptTable.h" +#include "clang/Frontend/CodeGenAction.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" From dgregor at apple.com Wed Feb 24 22:46:05 2010 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 25 Feb 2010 04:46:05 -0000 Subject: [cfe-commits] r97112 - in /cfe/trunk: include/clang/Parse/Action.h lib/Parse/ParseExpr.cpp lib/Parse/ParseExprCXX.cpp lib/Sema/Sema.h lib/Sema/SemaCXXScopeSpec.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateInstantiate.cpp lib/Sema/TreeTransform.h Message-ID: <20100225044605.596E12A6C136@llvm.org> Author: dgregor Date: Wed Feb 24 22:46:04 2010 New Revision: 97112 URL: http://llvm.org/viewvc/llvm-project?rev=97112&view=rev Log: Restore the invariant that a nested-name-specifier can only contain class types, dependent types, and namespaces. I had previously weakened this invariant while working on parsing pseudo-destructor expressions, but recent work in that area has made these changes unnecessary. Modified: cfe/trunk/include/clang/Parse/Action.h cfe/trunk/lib/Parse/ParseExpr.cpp cfe/trunk/lib/Parse/ParseExprCXX.cpp cfe/trunk/lib/Sema/Sema.h cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp cfe/trunk/lib/Sema/TreeTransform.h Modified: cfe/trunk/include/clang/Parse/Action.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=97112&r1=97111&r2=97112&view=diff ============================================================================== --- cfe/trunk/include/clang/Parse/Action.h (original) +++ cfe/trunk/include/clang/Parse/Action.h Wed Feb 24 22:46:04 2010 @@ -365,11 +365,6 @@ /// \param II the identifier that represents the scope that this /// nested-name-specifier refers to, e.g., the "bar" in "foo::bar::". /// - /// \param MayBePseudoDestructor Whether this nested-name-specifier - /// may be part of a pseudo-destructor, meaning that we are in a - /// member access expression (such as p->T::~T()) and a '~' follows - /// the '::'. - /// /// \param ObjectType if this nested-name-specifier occurs as part of a /// C++ member access expression such as "x->Base::f", the type of the base /// object (e.g., *x in the example, if "x" were a pointer). @@ -384,7 +379,6 @@ SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, - bool MayBePseudoDestructor, TypeTy *ObjectType, bool EnteringContext) { return 0; @@ -399,7 +393,6 @@ virtual bool IsInvalidUnlessNestedName(Scope *S, const CXXScopeSpec &SS, IdentifierInfo &II, - bool MayBePseudoDestructor, TypeTy *ObjectType, bool EnteringContext) { return false; @@ -417,8 +410,7 @@ const CXXScopeSpec &SS, TypeTy *Type, SourceRange TypeRange, - SourceLocation CCLoc, - bool MayBePseudoDestructor) { + SourceLocation CCLoc) { return 0; } Modified: cfe/trunk/lib/Parse/ParseExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=97112&r1=97111&r2=97112&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseExpr.cpp (original) +++ cfe/trunk/lib/Parse/ParseExpr.cpp Wed Feb 24 22:46:04 2010 @@ -1004,7 +1004,7 @@ if (LHS.isInvalid()) break; - ParseOptionalCXXScopeSpecifier(SS, ObjectType, false, + ParseOptionalCXXScopeSpecifier(SS, ObjectType, false, &MayBePseudoDestructor); } Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=97112&r1=97111&r2=97112&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original) +++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Wed Feb 24 22:46:04 2010 @@ -212,8 +212,7 @@ Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, TypeToken.getAnnotationValue(), TypeToken.getAnnotationRange(), - CCLoc, - false)); + CCLoc)); else SS.setScopeRep(0); SS.setEndLoc(CCLoc); @@ -240,15 +239,7 @@ // If we get foo:bar, this is almost certainly a typo for foo::bar. Recover // and emit a fixit hint for it. if (Next.is(tok::colon) && !ColonIsSacred) { - if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde) && - !Actions.isNonTypeNestedNameSpecifier(CurScope, SS, Tok.getLocation(), - II, ObjectType)) { - *MayBePseudoDestructor = true; - return HasScopeSpecifier; - } - - if (Actions.IsInvalidUnlessNestedName(CurScope, SS, II, - false, ObjectType, + if (Actions.IsInvalidUnlessNestedName(CurScope, SS, II, ObjectType, EnteringContext) && // If the token after the colon isn't an identifier, it's still an // error, but they probably meant something else strange so don't @@ -287,8 +278,7 @@ SS.setScopeRep( Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, II, - false, ObjectType, - EnteringContext)); + ObjectType, EnteringContext)); SS.setEndLoc(CCLoc); continue; } Modified: cfe/trunk/lib/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=97112&r1=97111&r2=97112&view=diff ============================================================================== --- cfe/trunk/lib/Sema/Sema.h (original) +++ cfe/trunk/lib/Sema/Sema.h Wed Feb 24 22:46:04 2010 @@ -2225,8 +2225,7 @@ virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S, SourceLocation CCLoc); - bool isAcceptableNestedNameSpecifier(NamedDecl *SD, - bool MayBePseudoDestructor = false); + bool isAcceptableNestedNameSpecifier(NamedDecl *SD); NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS); virtual bool isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, @@ -2239,7 +2238,6 @@ SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, - bool MayBePseudoDestructor, QualType ObjectType, NamedDecl *ScopeLookupResult, bool EnteringContext, @@ -2250,14 +2248,12 @@ SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, - bool MayBePseudoDestructor, TypeTy *ObjectType, bool EnteringContext); virtual bool IsInvalidUnlessNestedName(Scope *S, const CXXScopeSpec &SS, IdentifierInfo &II, - bool MayBePseudoDestructor, TypeTy *ObjectType, bool EnteringContext); @@ -2273,8 +2269,7 @@ const CXXScopeSpec &SS, TypeTy *Type, SourceRange TypeRange, - SourceLocation CCLoc, - bool MayBePseudoDestructor); + SourceLocation CCLoc); virtual bool ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS); Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=97112&r1=97111&r2=97112&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original) +++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Wed Feb 24 22:46:04 2010 @@ -176,15 +176,16 @@ case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { - if (const TagType *Tag = NNS->getAsType()->getAs()) - return Tag->getDecl(); - break; - } + const TagType *Tag = NNS->getAsType()->getAs(); + assert(Tag && "Non-tag type in nested-name-specifier"); + return Tag->getDecl(); + } break; case NestedNameSpecifier::Global: return Context.getTranslationUnitDecl(); } + // Required to silence a GCC warning. return 0; } @@ -269,8 +270,7 @@ /// \brief Determines whether the given declaration is an valid acceptable /// result for name lookup of a nested-name-specifier. -bool Sema::isAcceptableNestedNameSpecifier(NamedDecl *SD, - bool MayBePseudoDestructor) { +bool Sema::isAcceptableNestedNameSpecifier(NamedDecl *SD) { if (!SD) return false; @@ -281,11 +281,6 @@ if (!isa(SD)) return false; - // If this may be part of a pseudo-destructor expression, we'll - // accept any type. - if (MayBePseudoDestructor) - return true; - // Determine whether we have a class (or, in C++0x, an enum) or // a typedef thereof. If so, build the nested-name-specifier. QualType T = Context.getTypeDeclType(cast(SD)); @@ -326,7 +321,7 @@ return 0; NamedDecl *Result = Found.getFoundDecl(); - if (isAcceptableNestedNameSpecifier(Result, true)) + if (isAcceptableNestedNameSpecifier(Result)) return Result; return 0; @@ -398,7 +393,6 @@ SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, - bool MayBePseudoDestructor, QualType ObjectType, NamedDecl *ScopeLookupResult, bool EnteringContext, @@ -493,8 +487,7 @@ DeclarationName Name = Found.getLookupName(); if (CorrectTypo(Found, S, &SS, LookupCtx, EnteringContext) && Found.isSingleResult() && - isAcceptableNestedNameSpecifier(Found.getAsSingle(), - MayBePseudoDestructor)) { + isAcceptableNestedNameSpecifier(Found.getAsSingle())) { if (LookupCtx) Diag(Found.getNameLoc(), diag::err_no_member_suggest) << Name << LookupCtx << Found.getLookupName() << SS.getRange() @@ -514,7 +507,7 @@ } NamedDecl *SD = Found.getAsSingle(); - if (isAcceptableNestedNameSpecifier(SD, MayBePseudoDestructor)) { + if (isAcceptableNestedNameSpecifier(SD)) { if (!ObjectType.isNull() && !ObjectTypeSearchedInScope) { // C++ [basic.lookup.classref]p4: // [...] If the name is found in both contexts, the @@ -526,14 +519,13 @@ // scope, reconstruct the result from the template instantiation itself. NamedDecl *OuterDecl; if (S) { - LookupResult FoundOuter(*this, &II, IdLoc, - LookupNestedNameSpecifierName); + LookupResult FoundOuter(*this, &II, IdLoc, LookupNestedNameSpecifierName); LookupName(FoundOuter, S); OuterDecl = FoundOuter.getAsSingle(); } else OuterDecl = ScopeLookupResult; - if (isAcceptableNestedNameSpecifier(OuterDecl, MayBePseudoDestructor) && + if (isAcceptableNestedNameSpecifier(OuterDecl) && OuterDecl->getCanonicalDecl() != SD->getCanonicalDecl() && (!isa(OuterDecl) || !isa(SD) || !Context.hasSameType( @@ -610,11 +602,9 @@ SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, - bool MayBePseudoDestructor, TypeTy *ObjectTypePtr, bool EnteringContext) { return BuildCXXNestedNameSpecifier(S, SS, IdLoc, CCLoc, II, - MayBePseudoDestructor, QualType::getFromOpaquePtr(ObjectTypePtr), /*ScopeLookupResult=*/0, EnteringContext, false); @@ -627,13 +617,10 @@ /// /// The arguments are the same as those passed to ActOnCXXNestedNameSpecifier. bool Sema::IsInvalidUnlessNestedName(Scope *S, const CXXScopeSpec &SS, - IdentifierInfo &II, - bool MayBePseudoDestructor, - TypeTy *ObjectType, + IdentifierInfo &II, TypeTy *ObjectType, bool EnteringContext) { return BuildCXXNestedNameSpecifier(S, SS, SourceLocation(), SourceLocation(), - II, MayBePseudoDestructor, - QualType::getFromOpaquePtr(ObjectType), + II, QualType::getFromOpaquePtr(ObjectType), /*ScopeLookupResult=*/0, EnteringContext, true); } @@ -642,8 +629,7 @@ const CXXScopeSpec &SS, TypeTy *Ty, SourceRange TypeRange, - SourceLocation CCLoc, - bool MayBePseudoDestructor) { + SourceLocation CCLoc) { NestedNameSpecifier *Prefix = static_cast(SS.getScopeRep()); QualType T = GetTypeFromParser(Ty); Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=97112&r1=97111&r2=97112&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Feb 24 22:46:04 2010 @@ -133,7 +133,7 @@ isDependent = LookupCtx && LookupCtx->isDependentContext(); } - LookInScope = (LookupCtx == 0) && !isDependent; + LookInScope = false; } else if (ObjectTypePtr) { // C++ [basic.lookup.classref]p3: // If the unqualified-id is ~type-name, the type-name is looked up Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=97112&r1=97111&r2=97112&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Feb 24 22:46:04 2010 @@ -4925,7 +4925,6 @@ NestedNameSpecifier *NNS = TransformNestedNameSpecifier(T->getQualifier(), /*FIXME:*/SourceRange(getBaseLocation()), - false, ObjectType); if (!NNS) return QualType(); Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=97112&r1=97111&r2=97112&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Wed Feb 24 22:46:04 2010 @@ -1486,7 +1486,7 @@ const MultiLevelTemplateArgumentList &TemplateArgs) { TemplateInstantiator Instantiator(*this, TemplateArgs, Range.getBegin(), DeclarationName()); - return Instantiator.TransformNestedNameSpecifier(NNS, Range, false); + return Instantiator.TransformNestedNameSpecifier(NNS, Range); } TemplateName Modified: cfe/trunk/lib/Sema/TreeTransform.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=97112&r1=97111&r2=97112&view=diff ============================================================================== --- cfe/trunk/lib/Sema/TreeTransform.h (original) +++ cfe/trunk/lib/Sema/TreeTransform.h Wed Feb 24 22:46:04 2010 @@ -265,7 +265,6 @@ /// alternate behavior. NestedNameSpecifier *TransformNestedNameSpecifier(NestedNameSpecifier *NNS, SourceRange Range, - bool MayBePseudoDestructor, QualType ObjectType = QualType(), NamedDecl *FirstQualifierInScope = 0); @@ -556,7 +555,6 @@ NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, SourceRange Range, IdentifierInfo &II, - bool MayBePseudoDestructor, QualType ObjectType, NamedDecl *FirstQualifierInScope); @@ -579,8 +577,7 @@ NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, SourceRange Range, bool TemplateKW, - QualType T, - bool MayBePseudoDestructor); + QualType T); /// \brief Build a new template name given a nested name specifier, a flag /// indicating whether the "template" keyword was provided, and the template @@ -1712,7 +1709,6 @@ NestedNameSpecifier * TreeTransform::TransformNestedNameSpecifier(NestedNameSpecifier *NNS, SourceRange Range, - bool MayBePseudoDestructor, QualType ObjectType, NamedDecl *FirstQualifierInScope) { if (!NNS) @@ -1722,7 +1718,6 @@ NestedNameSpecifier *Prefix = NNS->getPrefix(); if (Prefix) { Prefix = getDerived().TransformNestedNameSpecifier(Prefix, Range, - false, ObjectType, FirstQualifierInScope); if (!Prefix) @@ -1744,7 +1739,6 @@ return getDerived().RebuildNestedNameSpecifier(Prefix, Range, *NNS->getAsIdentifier(), - MayBePseudoDestructor, ObjectType, FirstQualifierInScope); @@ -1780,8 +1774,7 @@ return getDerived().RebuildNestedNameSpecifier(Prefix, Range, NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate, - T, - MayBePseudoDestructor); + T); } } @@ -1833,7 +1826,6 @@ NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(QTN->getQualifier(), /*FIXME:*/SourceRange(getDerived().getBaseLocation()), - false, ObjectType); if (!NNS) return TemplateName(); @@ -1861,7 +1853,6 @@ NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(DTN->getQualifier(), /*FIXME:*/SourceRange(getDerived().getBaseLocation()), - false, ObjectType); if (!NNS && DTN->getQualifier()) return TemplateName(); @@ -2921,7 +2912,6 @@ NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(T->getQualifier(), SourceRange(), - false, ObjectType); if (!NNS) return QualType(); @@ -2956,7 +2946,7 @@ NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(T->getQualifier(), SR, - false, ObjectType); + ObjectType); if (!NNS) return QualType(); @@ -3592,8 +3582,7 @@ NestedNameSpecifier *Qualifier = 0; if (E->getQualifier()) { Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), - E->getQualifierRange(), - false); + E->getQualifierRange()); if (!Qualifier) return SemaRef.ExprError(); } @@ -3802,8 +3791,7 @@ if (E->hasQualifier()) { Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), - E->getQualifierRange(), - false); + E->getQualifierRange()); if (Qualifier == 0) return SemaRef.ExprError(); } @@ -4685,7 +4673,6 @@ NestedNameSpecifier *Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), E->getQualifierRange(), - true, ObjectType); if (E->getQualifier() && !Qualifier) return SemaRef.ExprError(); @@ -4786,8 +4773,7 @@ NestedNameSpecifier *Qualifier = 0; if (Old->getQualifier()) { Qualifier = getDerived().TransformNestedNameSpecifier(Old->getQualifier(), - Old->getQualifierRange(), - false); + Old->getQualifierRange()); if (!Qualifier) return SemaRef.ExprError(); @@ -4843,8 +4829,7 @@ DependentScopeDeclRefExpr *E) { NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(E->getQualifier(), - E->getQualifierRange(), - false); + E->getQualifierRange()); if (!NNS) return SemaRef.ExprError(); @@ -5093,11 +5078,8 @@ NestedNameSpecifier *Qualifier = 0; if (E->getQualifier()) { - bool MayBePseudoDestructor - = E->getMember().getNameKind() == DeclarationName::CXXDestructorName; Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), E->getQualifierRange(), - MayBePseudoDestructor, ObjectType, FirstQualifierInScope); if (!Qualifier) @@ -5172,8 +5154,7 @@ if (Old->getQualifier()) { Qualifier = getDerived().TransformNestedNameSpecifier(Old->getQualifier(), - Old->getQualifierRange(), - false); + Old->getQualifierRange()); if (Qualifier == 0) return SemaRef.ExprError(); } @@ -5598,7 +5579,6 @@ TreeTransform::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, SourceRange Range, IdentifierInfo &II, - bool MayBePseudoDestructor, QualType ObjectType, NamedDecl *FirstQualifierInScope) { CXXScopeSpec SS; @@ -5608,7 +5588,6 @@ return static_cast( SemaRef.BuildCXXNestedNameSpecifier(0, SS, Range.getEnd(), Range.getEnd(), II, - MayBePseudoDestructor, ObjectType, FirstQualifierInScope, false, false)); @@ -5627,9 +5606,8 @@ TreeTransform::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, SourceRange Range, bool TemplateKW, - QualType T, - bool MayBePseudoDestructor) { - if (MayBePseudoDestructor || T->isDependentType() || T->isRecordType() || + QualType T) { + if (T->isDependentType() || T->isRecordType() || (SemaRef.getLangOptions().CPlusPlus0x && T->isEnumeralType())) { assert(!T.hasLocalQualifiers() && "Can't get cv-qualifiers here"); return NestedNameSpecifier::Create(SemaRef.Context, Prefix, TemplateKW, From dgregor at apple.com Wed Feb 24 22:52:01 2010 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 25 Feb 2010 04:52:01 -0000 Subject: [cfe-commits] r97113 - /cfe/trunk/lib/Frontend/CMakeLists.txt Message-ID: <20100225045201.A90B32A6C136@llvm.org> Author: dgregor Date: Wed Feb 24 22:52:01 2010 New Revision: 97113 URL: http://llvm.org/viewvc/llvm-project?rev=97113&view=rev Log: Update CMake makefiles Modified: cfe/trunk/lib/Frontend/CMakeLists.txt Modified: cfe/trunk/lib/Frontend/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CMakeLists.txt?rev=97113&r1=97112&r2=97113&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/CMakeLists.txt (original) +++ cfe/trunk/lib/Frontend/CMakeLists.txt Wed Feb 24 22:52:01 2010 @@ -5,8 +5,8 @@ ASTMerge.cpp ASTUnit.cpp AnalysisConsumer.cpp - Backend.cpp CacheTokens.cpp + CodeGenAction.cpp CompilerInstance.cpp CompilerInvocation.cpp DeclXML.cpp From dgregor at apple.com Wed Feb 24 22:53:11 2010 From: dgregor at apple.com (Douglas Gregor) Date: Wed, 24 Feb 2010 20:53:11 -0800 Subject: [cfe-commits] r97110 - in /cfe/trunk: include/clang/Frontend/ASTConsumers.h include/clang/Frontend/CodeGenAction.h include/clang/Frontend/FrontendActions.h lib/Frontend/Backend.cpp lib/Frontend/CodeGenAction.cpp lib/Frontend/FrontendActions.cpp tools/driver/cc1_main.cpp In-Reply-To: <20100225043745.DC07A2A6C136@llvm.org> References: <20100225043745.DC07A2A6C136@llvm.org> Message-ID: <7A1F5CDC-CDA2-4DC6-9359-3C5041E35F9C@apple.com> On Feb 24, 2010, at 8:37 PM, Daniel Dunbar wrote: > Author: ddunbar > Date: Wed Feb 24 22:37:45 2010 > New Revision: 97110 > > URL: http://llvm.org/viewvc/llvm-project?rev=97110&view=rev > Log: > Frontend: Pull CodeGenAction out more, and eliminate CreateBackendConsumer. > > This is the way I would like to move the frontend function towards -- distinct > pieces of functionality should be exposed only via FrontendAction > implementations which have clean and relatively-stable APIs. > > This also isolates the surface area in clang which depends on LLVM CodeGen. FYI, I'm seeing: /Users/dgregor/Projects/llvm/include/llvm/ADT/OwningPtr.h:35:5: warning: deleting pointer to incomplete type 'class llvm::Module' may cause undefined behaviour delete Ptr; ^ ~~~ In file included from /Users/dgregor/Projects/llvm/tools/clang/tools/driver/cc1_main.cpp:22: /Users/dgregor/Projects/llvm/tools/clang/include/clang/Frontend/CodeGenAction.h:61:1: note: in instantiation of member function 'llvm::OwningPtr::~OwningPtr' requested here }; ^ /Users/dgregor/Projects/llvm/tools/clang/include/clang/Frontend/CodeGenAction.h:14:9: note: forward declaration of 'class llvm::Module' class Module; ^ That looks like it's coming from the synthesized destructor for EmitObjAction, and I think it's legitimate. - Doug > > Added: > cfe/trunk/include/clang/Frontend/CodeGenAction.h > cfe/trunk/lib/Frontend/CodeGenAction.cpp > - copied, changed from r97109, cfe/trunk/lib/Frontend/Backend.cpp > Removed: > cfe/trunk/lib/Frontend/Backend.cpp > Modified: > cfe/trunk/include/clang/Frontend/ASTConsumers.h > cfe/trunk/include/clang/Frontend/FrontendActions.h > cfe/trunk/lib/Frontend/FrontendActions.cpp > cfe/trunk/tools/driver/cc1_main.cpp > > Modified: cfe/trunk/include/clang/Frontend/ASTConsumers.h > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/ASTConsumers.h?rev=97110&r1=97109&r2=97110&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Frontend/ASTConsumers.h (original) > +++ cfe/trunk/include/clang/Frontend/ASTConsumers.h Wed Feb 24 22:37:45 2010 > @@ -69,26 +69,6 @@ > const LangOptions &LOpts, > bool SilenceRewriteMacroWarning); > > -// LLVM code generator: uses the code generation backend to generate LLVM > -// assembly. This runs optimizations depending on the CodeGenOptions > -// parameter. The output depends on the Action parameter. > -enum BackendAction { > - Backend_EmitAssembly, // Emit native assembly files > - Backend_EmitBC, // Emit LLVM bitcode files > - Backend_EmitLL, // Emit human-readable LLVM assembly > - Backend_EmitNothing, // Don't emit anything (benchmarking mode) > - Backend_EmitObj // Emit native object files > -}; > -ASTConsumer *CreateBackendConsumer(BackendAction Action, > - Diagnostic &Diags, > - const LangOptions &Features, > - const CodeGenOptions &CodeGenOpts, > - const TargetOptions &TargetOpts, > - bool TimePasses, > - const std::string &ModuleID, > - llvm::raw_ostream *OS, > - llvm::LLVMContext& C); > - > /// CreateHTMLPrinter - Create an AST consumer which rewrites source code to > /// HTML with syntax highlighting suitable for viewing in a web-browser. > ASTConsumer *CreateHTMLPrinter(llvm::raw_ostream *OS, Preprocessor &PP, > > Added: cfe/trunk/include/clang/Frontend/CodeGenAction.h > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CodeGenAction.h?rev=97110&view=auto > ============================================================================== > --- cfe/trunk/include/clang/Frontend/CodeGenAction.h (added) > +++ cfe/trunk/include/clang/Frontend/CodeGenAction.h Wed Feb 24 22:37:45 2010 > @@ -0,0 +1,50 @@ > +//===--- CodeGenAction.h - LLVM Code Generation Frontend Action -*- C++ -*-===// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > +//===----------------------------------------------------------------------===// > + > +#include "clang/Frontend/FrontendAction.h" > + > +namespace clang { > + > +class CodeGenAction : public ASTFrontendAction { > +private: > + unsigned Act; > + > +protected: > + CodeGenAction(unsigned _Act); > + > + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, > + llvm::StringRef InFile); > +}; > + > +class EmitAssemblyAction : public CodeGenAction { > +public: > + EmitAssemblyAction(); > +}; > + > +class EmitBCAction : public CodeGenAction { > +public: > + EmitBCAction(); > +}; > + > +class EmitLLVMAction : public CodeGenAction { > +public: > + EmitLLVMAction(); > +}; > + > +class EmitLLVMOnlyAction : public CodeGenAction { > +public: > + EmitLLVMOnlyAction(); > +}; > + > +class EmitObjAction : public CodeGenAction { > +public: > + EmitObjAction(); > +}; > + > +} > > Modified: cfe/trunk/include/clang/Frontend/FrontendActions.h > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendActions.h?rev=97110&r1=97109&r2=97110&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Frontend/FrontendActions.h (original) > +++ cfe/trunk/include/clang/Frontend/FrontendActions.h Wed Feb 24 22:37:45 2010 > @@ -159,46 +159,6 @@ > }; > > //===----------------------------------------------------------------------===// > -// Code Gen AST Actions > -//===----------------------------------------------------------------------===// > - > -class CodeGenAction : public ASTFrontendAction { > -private: > - unsigned Act; > - > -protected: > - CodeGenAction(unsigned _Act); > - > - virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, > - llvm::StringRef InFile); > -}; > - > -class EmitAssemblyAction : public CodeGenAction { > -public: > - EmitAssemblyAction(); > -}; > - > -class EmitBCAction : public CodeGenAction { > -public: > - EmitBCAction(); > -}; > - > -class EmitLLVMAction : public CodeGenAction { > -public: > - EmitLLVMAction(); > -}; > - > -class EmitLLVMOnlyAction : public CodeGenAction { > -public: > - EmitLLVMOnlyAction(); > -}; > - > -class EmitObjAction : public CodeGenAction { > -public: > - EmitObjAction(); > -}; > - > -//===----------------------------------------------------------------------===// > // Preprocessor Actions > //===----------------------------------------------------------------------===// > > > Removed: cfe/trunk/lib/Frontend/Backend.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/Backend.cpp?rev=97109&view=auto > ============================================================================== > --- cfe/trunk/lib/Frontend/Backend.cpp (original) > +++ cfe/trunk/lib/Frontend/Backend.cpp (removed) > @@ -1,433 +0,0 @@ > -//===--- Backend.cpp - Interface to LLVM backend technologies -------------===// > -// > -// The LLVM Compiler Infrastructure > -// > -// This file is distributed under the University of Illinois Open Source > -// License. See LICENSE.TXT for details. > -// > -//===----------------------------------------------------------------------===// > - > -#include "clang/Frontend/ASTConsumers.h" > -#include "clang/AST/ASTConsumer.h" > -#include "clang/AST/ASTContext.h" > -#include "clang/AST/DeclGroup.h" > -#include "clang/Basic/TargetInfo.h" > -#include "clang/Basic/TargetOptions.h" > -#include "clang/CodeGen/CodeGenOptions.h" > -#include "clang/CodeGen/ModuleBuilder.h" > -#include "clang/Frontend/FrontendDiagnostic.h" > -#include "llvm/Module.h" > -#include "llvm/PassManager.h" > -#include "llvm/ADT/OwningPtr.h" > -#include "llvm/Assembly/PrintModulePass.h" > -#include "llvm/Analysis/CallGraph.h" > -#include "llvm/Analysis/Verifier.h" > -#include "llvm/Bitcode/ReaderWriter.h" > -#include "llvm/CodeGen/RegAllocRegistry.h" > -#include "llvm/CodeGen/SchedulerRegistry.h" > -#include "llvm/Support/FormattedStream.h" > -#include "llvm/Support/StandardPasses.h" > -#include "llvm/Support/Timer.h" > -#include "llvm/Target/SubtargetFeature.h" > -#include "llvm/Target/TargetData.h" > -#include "llvm/Target/TargetMachine.h" > -#include "llvm/Target/TargetOptions.h" > -#include "llvm/Target/TargetRegistry.h" > -using namespace clang; > -using namespace llvm; > - > -namespace { > - class BackendConsumer : public ASTConsumer { > - Diagnostic &Diags; > - BackendAction Action; > - const CodeGenOptions &CodeGenOpts; > - const LangOptions &LangOpts; > - const TargetOptions &TargetOpts; > - llvm::raw_ostream *AsmOutStream; > - llvm::formatted_raw_ostream FormattedOutStream; > - ASTContext *Context; > - > - Timer LLVMIRGeneration; > - Timer CodeGenerationTime; > - > - llvm::OwningPtr Gen; > - > - llvm::Module *TheModule; > - llvm::TargetData *TheTargetData; > - > - mutable FunctionPassManager *CodeGenPasses; > - mutable PassManager *PerModulePasses; > - mutable FunctionPassManager *PerFunctionPasses; > - > - FunctionPassManager *getCodeGenPasses() const; > - PassManager *getPerModulePasses() const; > - FunctionPassManager *getPerFunctionPasses() const; > - > - void CreatePasses(); > - > - /// AddEmitPasses - Add passes necessary to emit assembly or LLVM IR. > - /// > - /// \return True on success. > - bool AddEmitPasses(); > - > - void EmitAssembly(); > - > - public: > - BackendConsumer(BackendAction action, Diagnostic &_Diags, > - const LangOptions &langopts, const CodeGenOptions &compopts, > - const TargetOptions &targetopts, bool TimePasses, > - const std::string &infile, llvm::raw_ostream *OS, > - LLVMContext& C) : > - Diags(_Diags), > - Action(action), > - CodeGenOpts(compopts), > - LangOpts(langopts), > - TargetOpts(targetopts), > - AsmOutStream(OS), > - LLVMIRGeneration("LLVM IR Generation Time"), > - CodeGenerationTime("Code Generation Time"), > - Gen(CreateLLVMCodeGen(Diags, infile, compopts, C)), > - TheModule(0), TheTargetData(0), > - CodeGenPasses(0), PerModulePasses(0), PerFunctionPasses(0) { > - > - if (AsmOutStream) > - FormattedOutStream.setStream(*AsmOutStream, > - formatted_raw_ostream::PRESERVE_STREAM); > - > - llvm::TimePassesIsEnabled = TimePasses; > - } > - > - ~BackendConsumer() { > - delete TheTargetData; > - delete TheModule; > - delete CodeGenPasses; > - delete PerModulePasses; > - delete PerFunctionPasses; > - } > - > - virtual void Initialize(ASTContext &Ctx) { > - Context = &Ctx; > - > - if (llvm::TimePassesIsEnabled) > - LLVMIRGeneration.startTimer(); > - > - Gen->Initialize(Ctx); > - > - TheModule = Gen->GetModule(); > - TheTargetData = new llvm::TargetData(Ctx.Target.getTargetDescription()); > - > - if (llvm::TimePassesIsEnabled) > - LLVMIRGeneration.stopTimer(); > - } > - > - virtual void HandleTopLevelDecl(DeclGroupRef D) { > - PrettyStackTraceDecl CrashInfo(*D.begin(), SourceLocation(), > - Context->getSourceManager(), > - "LLVM IR generation of declaration"); > - > - if (llvm::TimePassesIsEnabled) > - LLVMIRGeneration.startTimer(); > - > - Gen->HandleTopLevelDecl(D); > - > - if (llvm::TimePassesIsEnabled) > - LLVMIRGeneration.stopTimer(); > - } > - > - virtual void HandleTranslationUnit(ASTContext &C) { > - { > - PrettyStackTraceString CrashInfo("Per-file LLVM IR generation"); > - if (llvm::TimePassesIsEnabled) > - LLVMIRGeneration.startTimer(); > - > - Gen->HandleTranslationUnit(C); > - > - if (llvm::TimePassesIsEnabled) > - LLVMIRGeneration.stopTimer(); > - } > - > - // EmitAssembly times and registers crash info itself. > - EmitAssembly(); > - > - // Force a flush here in case we never get released. > - if (AsmOutStream) > - FormattedOutStream.flush(); > - } > - > - virtual void HandleTagDeclDefinition(TagDecl *D) { > - PrettyStackTraceDecl CrashInfo(D, SourceLocation(), > - Context->getSourceManager(), > - "LLVM IR generation of declaration"); > - Gen->HandleTagDeclDefinition(D); > - } > - > - virtual void CompleteTentativeDefinition(VarDecl *D) { > - Gen->CompleteTentativeDefinition(D); > - } > - }; > -} > - > -FunctionPassManager *BackendConsumer::getCodeGenPasses() const { > - if (!CodeGenPasses) { > - CodeGenPasses = new FunctionPassManager(TheModule); > - CodeGenPasses->add(new TargetData(*TheTargetData)); > - } > - > - return CodeGenPasses; > -} > - > -PassManager *BackendConsumer::getPerModulePasses() const { > - if (!PerModulePasses) { > - PerModulePasses = new PassManager(); > - PerModulePasses->add(new TargetData(*TheTargetData)); > - } > - > - return PerModulePasses; > -} > - > -FunctionPassManager *BackendConsumer::getPerFunctionPasses() const { > - if (!PerFunctionPasses) { > - PerFunctionPasses = new FunctionPassManager(TheModule); > - PerFunctionPasses->add(new TargetData(*TheTargetData)); > - } > - > - return PerFunctionPasses; > -} > - > -bool BackendConsumer::AddEmitPasses() { > - if (Action == Backend_EmitNothing) > - return true; > - > - if (Action == Backend_EmitBC) { > - getPerModulePasses()->add(createBitcodeWriterPass(FormattedOutStream)); > - } else if (Action == Backend_EmitLL) { > - getPerModulePasses()->add(createPrintModulePass(&FormattedOutStream)); > - } else { > - bool Fast = CodeGenOpts.OptimizationLevel == 0; > - > - // Create the TargetMachine for generating code. > - std::string Error; > - std::string Triple = TheModule->getTargetTriple(); > - const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error); > - if (!TheTarget) { > - Diags.Report(diag::err_fe_unable_to_create_target) << Error; > - return false; > - } > - > - // FIXME: Expose these capabilities via actual APIs!!!! Aside from just > - // being gross, this is also totally broken if we ever care about > - // concurrency. > - llvm::NoFramePointerElim = CodeGenOpts.DisableFPElim; > - if (CodeGenOpts.FloatABI == "soft") > - llvm::FloatABIType = llvm::FloatABI::Soft; > - else if (CodeGenOpts.FloatABI == "hard") > - llvm::FloatABIType = llvm::FloatABI::Hard; > - else { > - assert(CodeGenOpts.FloatABI.empty() && "Invalid float abi!"); > - llvm::FloatABIType = llvm::FloatABI::Default; > - } > - NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS; > - llvm::UseSoftFloat = CodeGenOpts.SoftFloat; > - UnwindTablesMandatory = CodeGenOpts.UnwindTables; > - > - TargetMachine::setAsmVerbosityDefault(CodeGenOpts.AsmVerbose); > - > - // FIXME: Parse this earlier. > - if (CodeGenOpts.RelocationModel == "static") { > - TargetMachine::setRelocationModel(llvm::Reloc::Static); > - } else if (CodeGenOpts.RelocationModel == "pic") { > - TargetMachine::setRelocationModel(llvm::Reloc::PIC_); > - } else { > - assert(CodeGenOpts.RelocationModel == "dynamic-no-pic" && > - "Invalid PIC model!"); > - TargetMachine::setRelocationModel(llvm::Reloc::DynamicNoPIC); > - } > - // FIXME: Parse this earlier. > - if (CodeGenOpts.CodeModel == "small") { > - TargetMachine::setCodeModel(llvm::CodeModel::Small); > - } else if (CodeGenOpts.CodeModel == "kernel") { > - TargetMachine::setCodeModel(llvm::CodeModel::Kernel); > - } else if (CodeGenOpts.CodeModel == "medium") { > - TargetMachine::setCodeModel(llvm::CodeModel::Medium); > - } else if (CodeGenOpts.CodeModel == "large") { > - TargetMachine::setCodeModel(llvm::CodeModel::Large); > - } else { > - assert(CodeGenOpts.CodeModel.empty() && "Invalid code model!"); > - TargetMachine::setCodeModel(llvm::CodeModel::Default); > - } > - > - std::vector BackendArgs; > - BackendArgs.push_back("clang"); // Fake program name. > - if (!CodeGenOpts.DebugPass.empty()) { > - BackendArgs.push_back("-debug-pass"); > - BackendArgs.push_back(CodeGenOpts.DebugPass.c_str()); > - } > - if (!CodeGenOpts.LimitFloatPrecision.empty()) { > - BackendArgs.push_back("-limit-float-precision"); > - BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str()); > - } > - if (llvm::TimePassesIsEnabled) > - BackendArgs.push_back("-time-passes"); > - BackendArgs.push_back(0); > - llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1, > - (char**) &BackendArgs[0]); > - > - std::string FeaturesStr; > - if (TargetOpts.CPU.size() || TargetOpts.Features.size()) { > - SubtargetFeatures Features; > - Features.setCPU(TargetOpts.CPU); > - for (std::vector::const_iterator > - it = TargetOpts.Features.begin(), > - ie = TargetOpts.Features.end(); it != ie; ++it) > - Features.AddFeature(*it); > - FeaturesStr = Features.getString(); > - } > - TargetMachine *TM = TheTarget->createTargetMachine(Triple, FeaturesStr); > - > - // Set register scheduler & allocation policy. > - RegisterScheduler::setDefault(createDefaultScheduler); > - RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator : > - createLinearScanRegisterAllocator); > - > - // From llvm-gcc: > - // If there are passes we have to run on the entire module, we do codegen > - // as a separate "pass" after that happens. > - // FIXME: This is disabled right now until bugs can be worked out. Reenable > - // this for fast -O0 compiles! > - FunctionPassManager *PM = getCodeGenPasses(); > - CodeGenOpt::Level OptLevel = CodeGenOpt::Default; > - > - switch (CodeGenOpts.OptimizationLevel) { > - default: break; > - case 0: OptLevel = CodeGenOpt::None; break; > - case 3: OptLevel = CodeGenOpt::Aggressive; break; > - } > - > - // Normal mode, emit a .s or .o file by running the code generator. Note, > - // this also adds codegenerator level optimization passes. > - TargetMachine::CodeGenFileType CGFT = TargetMachine::CGFT_AssemblyFile; > - if (Action == Backend_EmitObj) > - CGFT = TargetMachine::CGFT_ObjectFile; > - if (TM->addPassesToEmitFile(*PM, FormattedOutStream, CGFT, OptLevel)) { > - Diags.Report(diag::err_fe_unable_to_interface_with_target); > - return false; > - } > - } > - > - return true; > -} > - > -void BackendConsumer::CreatePasses() { > - unsigned OptLevel = CodeGenOpts.OptimizationLevel; > - CodeGenOptions::InliningMethod Inlining = CodeGenOpts.Inlining; > - > - // Handle disabling of LLVM optimization, where we want to preserve the > - // internal module before any optimization. > - if (CodeGenOpts.DisableLLVMOpts) { > - OptLevel = 0; > - Inlining = CodeGenOpts.NoInlining; > - } > - > - // In -O0 if checking is disabled, we don't even have per-function passes. > - if (CodeGenOpts.VerifyModule) > - getPerFunctionPasses()->add(createVerifierPass()); > - > - // Assume that standard function passes aren't run for -O0. > - if (OptLevel > 0) > - llvm::createStandardFunctionPasses(getPerFunctionPasses(), OptLevel); > - > - llvm::Pass *InliningPass = 0; > - switch (Inlining) { > - case CodeGenOptions::NoInlining: break; > - case CodeGenOptions::NormalInlining: { > - // Set the inline threshold following llvm-gcc. > - // > - // FIXME: Derive these constants in a principled fashion. > - unsigned Threshold = 225; > - if (CodeGenOpts.OptimizeSize) > - Threshold = 75; > - else if (OptLevel > 2) > - Threshold = 275; > - InliningPass = createFunctionInliningPass(Threshold); > - break; > - } > - case CodeGenOptions::OnlyAlwaysInlining: > - InliningPass = createAlwaysInlinerPass(); // Respect always_inline > - break; > - } > - > - // For now we always create per module passes. > - PassManager *PM = getPerModulePasses(); > - llvm::createStandardModulePasses(PM, OptLevel, CodeGenOpts.OptimizeSize, > - CodeGenOpts.UnitAtATime, > - CodeGenOpts.UnrollLoops, > - /*SimplifyLibCalls=*/!LangOpts.NoBuiltin, > - /*HaveExceptions=*/true, > - InliningPass); > -} > - > -/// EmitAssembly - Handle interaction with LLVM backend to generate > -/// actual machine code. > -void BackendConsumer::EmitAssembly() { > - // Silently ignore if we weren't initialized for some reason. > - if (!TheModule || !TheTargetData) > - return; > - > - TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : 0); > - > - // Make sure IR generation is happy with the module. This is > - // released by the module provider. > - Module *M = Gen->ReleaseModule(); > - if (!M) { > - // The module has been released by IR gen on failures, do not > - // double free. > - TheModule = 0; > - return; > - } > - > - assert(TheModule == M && "Unexpected module change during IR generation"); > - > - CreatePasses(); > - if (!AddEmitPasses()) > - return; > - > - // Run passes. For now we do all passes at once, but eventually we > - // would like to have the option of streaming code generation. > - > - if (PerFunctionPasses) { > - PrettyStackTraceString CrashInfo("Per-function optimization"); > - > - PerFunctionPasses->doInitialization(); > - for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) > - if (!I->isDeclaration()) > - PerFunctionPasses->run(*I); > - PerFunctionPasses->doFinalization(); > - } > - > - if (PerModulePasses) { > - PrettyStackTraceString CrashInfo("Per-module optimization passes"); > - PerModulePasses->run(*M); > - } > - > - if (CodeGenPasses) { > - PrettyStackTraceString CrashInfo("Code generation"); > - CodeGenPasses->doInitialization(); > - for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) > - if (!I->isDeclaration()) > - CodeGenPasses->run(*I); > - CodeGenPasses->doFinalization(); > - } > -} > - > -ASTConsumer *clang::CreateBackendConsumer(BackendAction Action, > - Diagnostic &Diags, > - const LangOptions &LangOpts, > - const CodeGenOptions &CodeGenOpts, > - const TargetOptions &TargetOpts, > - bool TimePasses, > - const std::string& InFile, > - llvm::raw_ostream* OS, > - LLVMContext& C) { > - return new BackendConsumer(Action, Diags, LangOpts, CodeGenOpts, > - TargetOpts, TimePasses, InFile, OS, C); > -} > > Copied: cfe/trunk/lib/Frontend/CodeGenAction.cpp (from r97109, cfe/trunk/lib/Frontend/Backend.cpp) > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CodeGenAction.cpp?p2=cfe/trunk/lib/Frontend/CodeGenAction.cpp&p1=cfe/trunk/lib/Frontend/Backend.cpp&r1=97109&r2=97110&rev=97110&view=diff > ============================================================================== > --- cfe/trunk/lib/Frontend/Backend.cpp (original) > +++ cfe/trunk/lib/Frontend/CodeGenAction.cpp Wed Feb 24 22:37:45 2010 > @@ -1,4 +1,4 @@ > -//===--- Backend.cpp - Interface to LLVM backend technologies -------------===// > +//===--- CodeGenAction.cpp - LLVM Code Generation Frontend Action ---------===// > // > // The LLVM Compiler Infrastructure > // > @@ -7,7 +7,7 @@ > // > //===----------------------------------------------------------------------===// > > -#include "clang/Frontend/ASTConsumers.h" > +#include "clang/Frontend/CodeGenAction.h" > #include "clang/AST/ASTConsumer.h" > #include "clang/AST/ASTContext.h" > #include "clang/AST/DeclGroup.h" > @@ -15,6 +15,8 @@ > #include "clang/Basic/TargetOptions.h" > #include "clang/CodeGen/CodeGenOptions.h" > #include "clang/CodeGen/ModuleBuilder.h" > +#include "clang/Frontend/ASTConsumers.h" > +#include "clang/Frontend/CompilerInstance.h" > #include "clang/Frontend/FrontendDiagnostic.h" > #include "llvm/Module.h" > #include "llvm/PassManager.h" > @@ -37,6 +39,14 @@ > using namespace llvm; > > namespace { > + enum BackendAction { > + Backend_EmitAssembly, ///< Emit native assembly files > + Backend_EmitBC, ///< Emit LLVM bitcode files > + Backend_EmitLL, ///< Emit human-readable LLVM assembly > + Backend_EmitNothing, ///< Don't emit anything (benchmarking mode) > + Backend_EmitObj ///< Emit native object files > + }; > + > class BackendConsumer : public ASTConsumer { > Diagnostic &Diags; > BackendAction Action; > @@ -419,15 +429,46 @@ > } > } > > -ASTConsumer *clang::CreateBackendConsumer(BackendAction Action, > - Diagnostic &Diags, > - const LangOptions &LangOpts, > - const CodeGenOptions &CodeGenOpts, > - const TargetOptions &TargetOpts, > - bool TimePasses, > - const std::string& InFile, > - llvm::raw_ostream* OS, > - LLVMContext& C) { > - return new BackendConsumer(Action, Diags, LangOpts, CodeGenOpts, > - TargetOpts, TimePasses, InFile, OS, C); > +// > + > +CodeGenAction::CodeGenAction(unsigned _Act) : Act(_Act) {} > + > +ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI, > + llvm::StringRef InFile) { > + BackendAction BA = static_cast(Act); > + llvm::OwningPtr OS; > + switch (BA) { > + case Backend_EmitAssembly: > + OS.reset(CI.createDefaultOutputFile(false, InFile, "s")); > + break; > + case Backend_EmitLL: > + OS.reset(CI.createDefaultOutputFile(false, InFile, "ll")); > + break; > + case Backend_EmitBC: > + OS.reset(CI.createDefaultOutputFile(true, InFile, "bc")); > + break; > + case Backend_EmitNothing: > + break; > + case Backend_EmitObj: > + OS.reset(CI.createDefaultOutputFile(true, InFile, "o")); > + break; > + } > + if (BA != Backend_EmitNothing && !OS) > + return 0; > + > + return new BackendConsumer(BA, CI.getDiagnostics(), CI.getLangOpts(), > + CI.getCodeGenOpts(), CI.getTargetOpts(), > + CI.getFrontendOpts().ShowTimers, InFile, OS.take(), > + CI.getLLVMContext()); > } > + > +EmitAssemblyAction::EmitAssemblyAction() > + : CodeGenAction(Backend_EmitAssembly) {} > + > +EmitBCAction::EmitBCAction() : CodeGenAction(Backend_EmitBC) {} > + > +EmitLLVMAction::EmitLLVMAction() : CodeGenAction(Backend_EmitLL) {} > + > +EmitLLVMOnlyAction::EmitLLVMOnlyAction() : CodeGenAction(Backend_EmitNothing) {} > + > +EmitObjAction::EmitObjAction() : CodeGenAction(Backend_EmitObj) {} > > Modified: cfe/trunk/lib/Frontend/FrontendActions.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendActions.cpp?rev=97110&r1=97109&r2=97110&view=diff > ============================================================================== > --- cfe/trunk/lib/Frontend/FrontendActions.cpp (original) > +++ cfe/trunk/lib/Frontend/FrontendActions.cpp Wed Feb 24 22:37:45 2010 > @@ -159,48 +159,6 @@ > return new ASTConsumer(); > } > > -CodeGenAction::CodeGenAction(unsigned _Act) : Act(_Act) {} > - > -ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI, > - llvm::StringRef InFile) { > - BackendAction BA = static_cast(Act); > - llvm::OwningPtr OS; > - switch (BA) { > - case Backend_EmitAssembly: > - OS.reset(CI.createDefaultOutputFile(false, InFile, "s")); > - break; > - case Backend_EmitLL: > - OS.reset(CI.createDefaultOutputFile(false, InFile, "ll")); > - break; > - case Backend_EmitBC: > - OS.reset(CI.createDefaultOutputFile(true, InFile, "bc")); > - break; > - case Backend_EmitNothing: > - break; > - case Backend_EmitObj: > - OS.reset(CI.createDefaultOutputFile(true, InFile, "o")); > - break; > - } > - if (BA != Backend_EmitNothing && !OS) > - return 0; > - > - return CreateBackendConsumer(BA, CI.getDiagnostics(), CI.getLangOpts(), > - CI.getCodeGenOpts(), CI.getTargetOpts(), > - CI.getFrontendOpts().ShowTimers, InFile, > - OS.take(), CI.getLLVMContext()); > -} > - > -EmitAssemblyAction::EmitAssemblyAction() > - : CodeGenAction(Backend_EmitAssembly) {} > - > -EmitBCAction::EmitBCAction() : CodeGenAction(Backend_EmitBC) {} > - > -EmitLLVMAction::EmitLLVMAction() : CodeGenAction(Backend_EmitLL) {} > - > -EmitLLVMOnlyAction::EmitLLVMOnlyAction() : CodeGenAction(Backend_EmitNothing) {} > - > -EmitObjAction::EmitObjAction() : CodeGenAction(Backend_EmitObj) {} > - > //===----------------------------------------------------------------------===// > // Preprocessor Actions > //===----------------------------------------------------------------------===// > > Modified: cfe/trunk/tools/driver/cc1_main.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/driver/cc1_main.cpp?rev=97110&r1=97109&r2=97110&view=diff > ============================================================================== > --- cfe/trunk/tools/driver/cc1_main.cpp (original) > +++ cfe/trunk/tools/driver/cc1_main.cpp Wed Feb 24 22:37:45 2010 > @@ -19,6 +19,7 @@ > #include "clang/Driver/CC1Options.h" > #include "clang/Driver/DriverDiagnostic.h" > #include "clang/Driver/OptTable.h" > +#include "clang/Frontend/CodeGenAction.h" > #include "clang/Frontend/CompilerInstance.h" > #include "clang/Frontend/CompilerInvocation.h" > #include "clang/Frontend/FrontendActions.h" > > > _______________________________________________ > cfe-commits mailing list > cfe-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits From sanjiv.gupta at microchip.com Wed Feb 24 23:20:44 2010 From: sanjiv.gupta at microchip.com (Sanjiv Gupta) Date: Thu, 25 Feb 2010 05:20:44 -0000 Subject: [cfe-commits] r97114 - /cfe/trunk/lib/CodeGen/CGDebugInfo.cpp Message-ID: <20100225052044.B78D62A6C136@llvm.org> Author: sgupta Date: Wed Feb 24 23:20:44 2010 New Revision: 97114 URL: http://llvm.org/viewvc/llvm-project?rev=97114&view=rev Log: Targets (like pic16) may have mangled the name of global variables, so get the name from Var rather than the original decl. Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.cpp?rev=97114&r1=97113&r2=97114&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGDebugInfo.cpp (original) +++ cfe/trunk/lib/CodeGen/CGDebugInfo.cpp Wed Feb 24 23:20:44 2010 @@ -1692,7 +1692,7 @@ T = CGM.getContext().getConstantArrayType(ET, ConstVal, ArrayType::Normal, 0); } - llvm::StringRef DeclName = D->getName(); + llvm::StringRef DeclName = Var->getName(); llvm::DIDescriptor DContext = getContextDescriptor(dyn_cast(D->getDeclContext()), Unit); DebugFactory.CreateGlobalVariable(DContext, DeclName, From kremenek at apple.com Wed Feb 24 23:44:05 2010 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 25 Feb 2010 05:44:05 -0000 Subject: [cfe-commits] r97115 - /cfe/trunk/lib/Checker/UnixAPIChecker.cpp Message-ID: <20100225054405.2C7552A6C136@llvm.org> Author: kremenek Date: Wed Feb 24 23:44:05 2010 New Revision: 97115 URL: http://llvm.org/viewvc/llvm-project?rev=97115&view=rev Log: When generating error node, check to see if we already cached out. Modified: cfe/trunk/lib/Checker/UnixAPIChecker.cpp Modified: cfe/trunk/lib/Checker/UnixAPIChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/UnixAPIChecker.cpp?rev=97115&r1=97114&r2=97115&view=diff ============================================================================== --- cfe/trunk/lib/Checker/UnixAPIChecker.cpp (original) +++ cfe/trunk/lib/Checker/UnixAPIChecker.cpp Wed Feb 24 23:44:05 2010 @@ -98,6 +98,9 @@ if (CE->getNumArgs() < 3) { ExplodedNode *N = C.GenerateSink(trueState); + if (!N) + return; + EnhancedBugReport *report = new EnhancedBugReport(*BT, "Call to 'open' requires a third argument when " From kremenek at apple.com Wed Feb 24 23:44:09 2010 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 25 Feb 2010 05:44:09 -0000 Subject: [cfe-commits] r97116 - in /cfe/trunk/lib/Checker: CMakeLists.txt GRExprEngine.cpp GRExprEngineInternalChecks.h MacOSXAPIChecker.cpp Message-ID: <20100225054409.910802A6C137@llvm.org> Author: kremenek Date: Wed Feb 24 23:44:09 2010 New Revision: 97116 URL: http://llvm.org/viewvc/llvm-project?rev=97116&view=rev Log: Add MacOSXAPIChecker, a meta checker to include various precondition checks for calls to various MacOS X functions. The checks in BasicObjCFoundationChecks.cpp will gradually be migrated here. As a first check, check that when 'dispatch_once()' is passed a predicate value that has non-local storage. Added: cfe/trunk/lib/Checker/MacOSXAPIChecker.cpp Modified: cfe/trunk/lib/Checker/CMakeLists.txt cfe/trunk/lib/Checker/GRExprEngine.cpp cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h Modified: cfe/trunk/lib/Checker/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/CMakeLists.txt?rev=97116&r1=97115&r2=97116&view=diff ============================================================================== --- cfe/trunk/lib/Checker/CMakeLists.txt (original) +++ cfe/trunk/lib/Checker/CMakeLists.txt Wed Feb 24 23:44:09 2010 @@ -34,6 +34,7 @@ GRExprEngineExperimentalChecks.cpp GRState.cpp LLVMConventionsChecker.cpp + MacOSXAPIChecker.cpp MallocChecker.cpp ManagerRegistry.cpp MemRegion.cpp Modified: cfe/trunk/lib/Checker/GRExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRExprEngine.cpp?rev=97116&r1=97115&r2=97116&view=diff ============================================================================== --- cfe/trunk/lib/Checker/GRExprEngine.cpp (original) +++ cfe/trunk/lib/Checker/GRExprEngine.cpp Wed Feb 24 23:44:09 2010 @@ -319,6 +319,7 @@ RegisterBuiltinFunctionChecker(Eng); RegisterOSAtomicChecker(Eng); RegisterUnixAPIChecker(Eng); + RegisterMacOSXAPIChecker(Eng); } GRExprEngine::GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf) Modified: cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h?rev=97116&r1=97115&r2=97116&view=diff ============================================================================== --- cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h (original) +++ cfe/trunk/lib/Checker/GRExprEngineInternalChecks.h Wed Feb 24 23:44:09 2010 @@ -43,6 +43,7 @@ void RegisterVLASizeChecker(GRExprEngine &Eng); // API checks. +void RegisterMacOSXAPIChecker(GRExprEngine &Eng); void RegisterOSAtomicChecker(GRExprEngine &Eng); void RegisterUnixAPIChecker(GRExprEngine &Eng); Added: cfe/trunk/lib/Checker/MacOSXAPIChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/MacOSXAPIChecker.cpp?rev=97116&view=auto ============================================================================== --- cfe/trunk/lib/Checker/MacOSXAPIChecker.cpp (added) +++ cfe/trunk/lib/Checker/MacOSXAPIChecker.cpp Wed Feb 24 23:44:09 2010 @@ -0,0 +1,141 @@ +// MacOSXAPIChecker.h - Checks proper use of various MacOS X APIs --*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines MacOSXAPIChecker, which is an assortment of checks on calls +// to various, widely used Mac OS X functions. +// +// FIXME: What's currently in BasicObjCFoundationChecks.cpp should be migrated +// to here, using the new Checker interface. +// +//===----------------------------------------------------------------------===// + +#include "GRExprEngineInternalChecks.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/GRStateTrait.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +namespace { +class MacOSXAPIChecker : public CheckerVisitor { + enum SubChecks { + DispatchOnce = 0, + DispatchOnceF, + NumChecks + }; + + BugType *BTypes[NumChecks]; + +public: + MacOSXAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); } + static void *getTag() { static unsigned tag = 0; return &tag; } + + void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); +}; +} //end anonymous namespace + +void clang::RegisterMacOSXAPIChecker(GRExprEngine &Eng) { + if (Eng.getContext().Target.getTriple().getVendor() == llvm::Triple::Apple) + Eng.registerCheck(new MacOSXAPIChecker()); +} + +//===----------------------------------------------------------------------===// +// dispatch_once and dispatch_once_f +//===----------------------------------------------------------------------===// + +static void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE, + BugType *&BT, const IdentifierInfo *FI) { + + if (!BT) { + llvm::SmallString<128> S; + llvm::raw_svector_ostream os(S); + os << "Improper use of '" << FI->getName() << '\''; + BT = new BugType(os.str(), "Mac OS X API"); + } + + if (CE->getNumArgs() < 1) + return; + + // Check if the first argument is stack allocated. If so, issue a warning + // because that's likely to be bad news. + const GRState *state = C.getState(); + const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion(); + if (!R || !isa(R->getMemorySpace())) + return; + + ExplodedNode *N = C.GenerateSink(state); + if (!N) + return; + + llvm::SmallString<256> S; + llvm::raw_svector_ostream os(S); + os << "Call to '" << FI->getName() << "' uses"; + if (const VarRegion *VR = dyn_cast(R)) + os << " the local variable '" << VR->getDecl()->getName() << '\''; + else + os << " stack allocated memory"; + os << " for the predicate value. Using such transient memory for " + "the predicate is potentially dangerous."; + if (isa(R) && isa(R->getMemorySpace())) + os << " Perhaps you intended to declare the variable as 'static'?"; + + EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N); + report->addRange(CE->getArg(0)->getSourceRange()); + C.EmitReport(report); +} + +//===----------------------------------------------------------------------===// +// Central dispatch function. +//===----------------------------------------------------------------------===// + +typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT, + const IdentifierInfo *FI); +namespace { + class SubCheck { + SubChecker SC; + BugType **BT; + public: + SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {} + SubCheck() : SC(NULL), BT(NULL) {} + + void run(CheckerContext &C, const CallExpr *CE, + const IdentifierInfo *FI) const { + if (SC) + SC(C, CE, *BT, FI); + } + }; +} // end anonymous namespace + +void MacOSXAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { + // FIXME: Mostly copy and paste from UnixAPIChecker. Should refactor. + const GRState *state = C.getState(); + const Expr *Callee = CE->getCallee(); + const FunctionTextRegion *Fn = + dyn_cast_or_null(state->getSVal(Callee).getAsRegion()); + + if (!Fn) + return; + + const IdentifierInfo *FI = Fn->getDecl()->getIdentifier(); + if (!FI) + return; + + const SubCheck &SC = + llvm::StringSwitch(FI->getName()) + .Case("dispatch_once", SubCheck(CheckDispatchOnce, BTypes[DispatchOnce])) + .Case("dispatch_once_f", SubCheck(CheckDispatchOnce, + BTypes[DispatchOnceF])) + .Default(SubCheck()); + + SC.run(C, CE, FI); +} From xuzhongxing at gmail.com Thu Feb 25 00:46:30 2010 From: xuzhongxing at gmail.com (Zhongxing Xu) Date: Thu, 25 Feb 2010 06:46:30 -0000 Subject: [cfe-commits] r97122 - in /cfe/trunk: include/clang/Analysis/ProgramPoint.h include/clang/Checker/PathSensitive/Checker.h include/clang/Checker/PathSensitive/GRCoreEngine.h include/clang/Checker/PathSensitive/GRExprEngine.h include/clang/Checker/PathSensitive/GRSubEngine.h lib/Checker/CallInliner.cpp lib/Checker/GRCoreEngine.cpp lib/Checker/GRExprEngine.cpp Message-ID: <20100225064630.447742A6C136@llvm.org> Author: zhongxingxu Date: Thu Feb 25 00:46:30 2010 New Revision: 97122 URL: http://llvm.org/viewvc/llvm-project?rev=97122&view=rev Log: Call inliner improvements: This patch implements the CallEnter/CallExit idea of Ted. Add two interfaces to GRSubEngine: ProcessCallEnter, ProcessCallExit. The CallEnter program point uses caller's location context. The CallExit program point uses callee's location context. CallEnter is built by GRStmtNodeBuilder. CallExit is built by GREndPathNodeBuilder. Modified: cfe/trunk/include/clang/Analysis/ProgramPoint.h cfe/trunk/include/clang/Checker/PathSensitive/Checker.h cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h cfe/trunk/lib/Checker/CallInliner.cpp cfe/trunk/lib/Checker/GRCoreEngine.cpp cfe/trunk/lib/Checker/GRExprEngine.cpp Modified: cfe/trunk/include/clang/Analysis/ProgramPoint.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/ProgramPoint.h?rev=97122&r1=97121&r2=97122&view=diff ============================================================================== --- cfe/trunk/include/clang/Analysis/ProgramPoint.h (original) +++ cfe/trunk/include/clang/Analysis/ProgramPoint.h Thu Feb 25 00:46:30 2010 @@ -26,6 +26,7 @@ namespace clang { class LocationContext; +class FunctionDecl; class ProgramPoint { public: @@ -41,6 +42,8 @@ PostPurgeDeadSymbolsKind, PostStmtCustomKind, PostLValueKind, + CallEnterKind, + CallExitKind, MinPostStmtKind = PostStmtKind, MaxPostStmtKind = PostLValueKind }; @@ -308,6 +311,36 @@ } }; +class CallEnter : public StmtPoint { +public: + // CallEnter uses the caller's location context. + CallEnter(const Stmt *S, const FunctionDecl *fd, const LocationContext *L) + : StmtPoint(S, fd, CallEnterKind, L, 0) {} + + const Stmt *getCallExpr() const { + return static_cast(getData1()); + } + + const FunctionDecl *getCallee() const { + return static_cast(getData2()); + } + + static bool classof(const ProgramPoint *Location) { + return Location->getKind() == CallEnterKind; + } +}; + +class CallExit : public StmtPoint { +public: + // CallExit uses the callee's location context. + CallExit(const Stmt *S, const LocationContext *L) + : StmtPoint(S, 0, CallExitKind, L, 0) {} + + static bool classof(const ProgramPoint *Location) { + return Location->getKind() == CallExitKind; + } +}; + } // end namespace clang Modified: cfe/trunk/include/clang/Checker/PathSensitive/Checker.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/Checker.h?rev=97122&r1=97121&r2=97122&view=diff ============================================================================== --- cfe/trunk/include/clang/Checker/PathSensitive/Checker.h (original) +++ cfe/trunk/include/clang/Checker/PathSensitive/Checker.h Thu Feb 25 00:46:30 2010 @@ -155,6 +155,14 @@ Dst.Add(Pred); } + // Generate a node with a new program point different from the one that will + // be created by the GRStmtNodeBuilder. + void addTransition(const GRState *state, ProgramPoint Loc) { + ExplodedNode *N = B.generateNode(Loc, state, Pred); + if (N) + addTransition(N); + } + void EmitReport(BugReport *R) { Eng.getBugReporter().EmitReport(R); } Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h?rev=97122&r1=97121&r2=97122&view=diff ============================================================================== --- cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h (original) +++ cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h Thu Feb 25 00:46:30 2010 @@ -40,6 +40,8 @@ friend class GRIndirectGotoNodeBuilder; friend class GRSwitchNodeBuilder; friend class GREndPathNodeBuilder; + friend class GRCallEnterNodeBuilder; + friend class GRCallExitNodeBuilder; GRSubEngine& SubEngine; @@ -67,6 +69,9 @@ void HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock* B, ExplodedNode* Pred); + void HandleCallEnter(const CallEnter &L, const CFGBlock *Block, + unsigned Index, ExplodedNode *Pred); + void HandleCallExit(const CallExit &L, ExplodedNode *Pred); /// Get the initial state from the subengine. const GRState* getInitialState(const LocationContext *InitLoc) { @@ -90,6 +95,9 @@ void ProcessSwitch(GRSwitchNodeBuilder& Builder); + void ProcessCallEnter(GRCallEnterNodeBuilder &Builder); + void ProcessCallExit(GRCallExitNodeBuilder &Builder); + private: GRCoreEngine(const GRCoreEngine&); // Do not implement. GRCoreEngine& operator=(const GRCoreEngine&); @@ -194,6 +202,12 @@ return generateNode(S, St, Pred, PointKind); } + ExplodedNode *generateNode(const ProgramPoint &PP, const GRState* State, + ExplodedNode* Pred) { + HasGeneratedNode = true; + return generateNodeInternal(PP, State, Pred); + } + ExplodedNode* generateNodeInternal(const ProgramPoint &PP, const GRState* State, ExplodedNode* Pred); @@ -431,6 +445,8 @@ ExplodedNode* generateNode(const GRState* State, const void *tag = 0, ExplodedNode *P = 0); + void GenerateCallExitNode(const GRState *state); + CFGBlock* getBlock() const { return &B; } const GRState* getState() const { @@ -438,6 +454,56 @@ } }; +class GRCallEnterNodeBuilder { + GRCoreEngine &Eng; + + const ExplodedNode *Pred; + + // The call site. + const Stmt *CE; + + // The definition of callee. + const FunctionDecl *FD; + + // The parent block of the CallExpr. + const CFGBlock *Block; + + // The CFGBlock index of the CallExpr. + unsigned Index; + +public: + GRCallEnterNodeBuilder(GRCoreEngine &eng, const ExplodedNode *pred, + const Stmt *s, const FunctionDecl *fd, + const CFGBlock *blk, unsigned idx) + : Eng(eng), Pred(pred), CE(s), FD(fd), Block(blk), Index(idx) {} + + const GRState *getState() const { return Pred->getState(); } + + const LocationContext *getLocationContext() const { + return Pred->getLocationContext(); + } + + const Stmt *getCallExpr() const { return CE; } + + const FunctionDecl *getCallee() const { return FD; } + + const CFGBlock *getBlock() const { return Block; } + + unsigned getIndex() const { return Index; } + + void GenerateNode(const GRState *state, const LocationContext *LocCtx); +}; + +class GRCallExitNodeBuilder { + GRCoreEngine &Eng; + const ExplodedNode *Pred; + +public: + GRCallExitNodeBuilder(GRCoreEngine &eng, const ExplodedNode *pred) + : Eng(eng), Pred(pred) {} + + void GenerateNode(); +}; } // end clang namespace #endif Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h?rev=97122&r1=97121&r2=97122&view=diff ============================================================================== --- cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h (original) +++ cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h Thu Feb 25 00:46:30 2010 @@ -171,7 +171,13 @@ /// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path /// nodes when the control reaches the end of a function. void ProcessEndPath(GREndPathNodeBuilder& builder); - + + // Generate the entry node of the callee. + void ProcessCallEnter(GRCallEnterNodeBuilder &builder); + + // Generate the first post callsite node. + void ProcessCallExit(GRCallExitNodeBuilder &builder); + /// EvalAssume - Callback function invoked by the ConstraintManager when /// making assumptions about state values. const GRState *ProcessAssume(const GRState *state, SVal cond, bool assumption); Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h?rev=97122&r1=97121&r2=97122&view=diff ============================================================================== --- cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h (original) +++ cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h Thu Feb 25 00:46:30 2010 @@ -28,6 +28,8 @@ class GRIndirectGotoNodeBuilder; class GRSwitchNodeBuilder; class GREndPathNodeBuilder; +class GRCallEnterNodeBuilder; +class GRCallExitNodeBuilder; class LocationContext; class GRSubEngine { @@ -64,6 +66,12 @@ /// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path /// nodes when the control reaches the end of a function. virtual void ProcessEndPath(GREndPathNodeBuilder& builder) = 0; + + // Generate the entry node of the callee. + virtual void ProcessCallEnter(GRCallEnterNodeBuilder &builder) = 0; + + // Generate the first post callsite node. + virtual void ProcessCallExit(GRCallExitNodeBuilder &builder) = 0; /// EvalAssume - Called by ConstraintManager. Used to call checker-specific /// logic for handling assumptions on symbolic values. Modified: cfe/trunk/lib/Checker/CallInliner.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/CallInliner.cpp?rev=97122&r1=97121&r2=97122&view=diff ============================================================================== --- cfe/trunk/lib/Checker/CallInliner.cpp (original) +++ cfe/trunk/lib/Checker/CallInliner.cpp Thu Feb 25 00:46:30 2010 @@ -46,40 +46,9 @@ if (!FD->isThisDeclarationADefinition()) return false; - GRStmtNodeBuilder &Builder = C.getNodeBuilder(); - // Make a new LocationContext. - const StackFrameContext *LocCtx = C.getAnalysisManager().getStackFrame(FD, - C.getPredecessor()->getLocationContext(), CE, - Builder.getBlock(), Builder.getIndex()); - - CFGBlock const *Entry = &(LocCtx->getCFG()->getEntry()); - - assert (Entry->empty() && "Entry block must be empty."); - - assert (Entry->succ_size() == 1 && "Entry block must have 1 successor."); - - // Get the solitary successor. - CFGBlock const *SuccB = *(Entry->succ_begin()); - - // Construct an edge representing the starting location in the function. - BlockEdge Loc(Entry, SuccB, LocCtx); - - state = C.getStoreManager().EnterStackFrame(state, LocCtx); - - // This is a hack. We really should not use the GRStmtNodeBuilder. - bool isNew; - GRExprEngine &Eng = C.getEngine(); - ExplodedNode *Pred = C.getPredecessor(); - - - ExplodedNode *SuccN = Eng.getGraph().getNode(Loc, state, &isNew); - SuccN->addPredecessor(Pred, Eng.getGraph()); - C.getNodeBuilder().Deferred.erase(Pred); - - if (isNew) - Builder.getWorkList()->Enqueue(SuccN); - - Builder.HasGeneratedNode = true; + // Now we have the definition of the callee, create a CallEnter node. + CallEnter Loc(CE, FD, C.getPredecessor()->getLocationContext()); + C.addTransition(state, Loc); return true; } @@ -102,23 +71,9 @@ SymbolReaper SymReaper(*ParentSF->getLiveVariables(), Eng.getSymbolManager(), ParentSF); const Stmt *CE = LocCtx->getCallSite(); - + // FIXME: move this logic to GRExprEngine::ProcessCallExit(). state = Eng.getStateManager().RemoveDeadBindings(state, const_cast(CE), SymReaper); - - PostStmt NodeLoc(CE, LocCtx->getParent()); - - bool isNew; - ExplodedNode *Succ = Eng.getGraph().getNode(NodeLoc, state, &isNew); - Succ->addPredecessor(Pred, Eng.getGraph()); - - // When creating the new work list unit, increment the statement index to - // point to the statement after the CallExpr. - if (isNew) - B.getWorkList().Enqueue(Succ, - *const_cast(LocCtx->getCallSiteBlock()), - LocCtx->getIndex() + 1); - - B.HasGeneratedNode = true; + B.GenerateCallExitNode(state); } Modified: cfe/trunk/lib/Checker/GRCoreEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRCoreEngine.cpp?rev=97122&r1=97121&r2=97122&view=diff ============================================================================== --- cfe/trunk/lib/Checker/GRCoreEngine.cpp (original) +++ cfe/trunk/lib/Checker/GRCoreEngine.cpp Thu Feb 25 00:46:30 2010 @@ -144,6 +144,14 @@ SubEngine.ProcessSwitch(Builder); } +void GRCoreEngine::ProcessCallEnter(GRCallEnterNodeBuilder &Builder) { + SubEngine.ProcessCallEnter(Builder); +} + +void GRCoreEngine::ProcessCallExit(GRCallExitNodeBuilder &Builder) { + SubEngine.ProcessCallExit(Builder); +} + /// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps. bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) { @@ -196,6 +204,15 @@ assert (false && "BlockExit location never occur in forward analysis."); break; + case ProgramPoint::CallEnterKind: + HandleCallEnter(cast(Node->getLocation()), WU.getBlock(), + WU.getIndex(), Node); + break; + + case ProgramPoint::CallExitKind: + HandleCallExit(cast(Node->getLocation()), Node); + break; + default: assert(isa(Node->getLocation())); HandlePostStmt(cast(Node->getLocation()), WU.getBlock(), @@ -207,6 +224,17 @@ return WList->hasWork(); } +void GRCoreEngine::HandleCallEnter(const CallEnter &L, const CFGBlock *Block, + unsigned Index, ExplodedNode *Pred) { + GRCallEnterNodeBuilder Builder(*this, Pred, L.getCallExpr(), L.getCallee(), + Block, Index); + ProcessCallEnter(Builder); +} + +void GRCoreEngine::HandleCallExit(const CallExit &L, ExplodedNode *Pred) { + GRCallExitNodeBuilder Builder(*this, Pred); + ProcessCallExit(Builder); +} void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) { @@ -400,6 +428,12 @@ void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) { assert (!N->isSink()); + // Check if this node entered a callee. + if (isa(N->getLocation())) { + Eng.WList->Enqueue(N, B, Idx); // Still use the index of the CallExpr. + return; + } + PostStmt Loc(getStmt(), N->getLocationContext()); if (Loc == N->getLocation()) { @@ -597,3 +631,57 @@ return NULL; } + +void GREndPathNodeBuilder::GenerateCallExitNode(const GRState *state) { + HasGeneratedNode = true; + // Create a CallExit node and enqueue it. + const StackFrameContext *LocCtx + = cast(Pred->getLocationContext()); + const Stmt *CE = LocCtx->getCallSite(); + + // Use the the callee location context. + CallExit Loc(CE, LocCtx); + + bool isNew; + ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); + Node->addPredecessor(Pred, *Eng.G); + + if (isNew) + Eng.WList->Enqueue(Node); +} + + +void GRCallEnterNodeBuilder::GenerateNode(const GRState *state, + const LocationContext *LocCtx) { + // Get the callee entry block. + const CFGBlock *Entry = &(LocCtx->getCFG()->getEntry()); + assert(Entry->empty()); + assert(Entry->succ_size() == 1); + + // Get the solitary successor. + const CFGBlock *SuccB = *(Entry->succ_begin()); + + // Construct an edge representing the starting location in the callee. + BlockEdge Loc(Entry, SuccB, LocCtx); + + bool isNew; + ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); + Node->addPredecessor(const_cast(Pred), *Eng.G); + + if (isNew) + Eng.WList->Enqueue(Node); +} + +void GRCallExitNodeBuilder::GenerateNode() { + // Get the callee's location context. + const StackFrameContext *LocCtx + = cast(Pred->getLocationContext()); + + PostStmt Loc(LocCtx->getCallSite(), LocCtx->getParent()); + bool isNew; + ExplodedNode *Node = Eng.G->getNode(Loc, Pred->getState(), &isNew); + Node->addPredecessor(const_cast(Pred), *Eng.G); + if (isNew) + Eng.WList->Enqueue(Node, *const_cast(LocCtx->getCallSiteBlock()), + LocCtx->getIndex() + 1); +} Modified: cfe/trunk/lib/Checker/GRExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRExprEngine.cpp?rev=97122&r1=97121&r2=97122&view=diff ============================================================================== --- cfe/trunk/lib/Checker/GRExprEngine.cpp (original) +++ cfe/trunk/lib/Checker/GRExprEngine.cpp Thu Feb 25 00:46:30 2010 @@ -1290,6 +1290,24 @@ if (defaultIsFeasible) builder.generateDefaultCaseNode(DefaultSt); } +void GRExprEngine::ProcessCallEnter(GRCallEnterNodeBuilder &B) { + const FunctionDecl *FD = B.getCallee(); + const StackFrameContext *LocCtx = AMgr.getStackFrame(FD, + B.getLocationContext(), + B.getCallExpr(), + B.getBlock(), + B.getIndex()); + + const GRState *state = B.getState(); + state = getStoreManager().EnterStackFrame(state, LocCtx); + + B.GenerateNode(state, LocCtx); +} + +void GRExprEngine::ProcessCallExit(GRCallExitNodeBuilder &B) { + B.GenerateNode(); +} + //===----------------------------------------------------------------------===// // Transfer functions: logical operations ('&&', '||'). //===----------------------------------------------------------------------===// @@ -3141,6 +3159,14 @@ assert (false); break; + case ProgramPoint::CallEnterKind: + Out << "CallEnter"; + break; + + case ProgramPoint::CallExitKind: + Out << "CallExit"; + break; + default: { if (StmtPoint *L = dyn_cast(&Loc)) { const Stmt* S = L->getStmt(); From xuzhongxing at gmail.com Thu Feb 25 01:03:08 2010 From: xuzhongxing at gmail.com (Zhongxing Xu) Date: Thu, 25 Feb 2010 07:03:08 -0000 Subject: [cfe-commits] r97127 - /cfe/trunk/lib/Checker/GRCoreEngine.cpp Message-ID: <20100225070308.89FC42A6C131@llvm.org> Author: zhongxingxu Date: Thu Feb 25 01:03:08 2010 New Revision: 97127 URL: http://llvm.org/viewvc/llvm-project?rev=97127&view=rev Log: Add comments. Modified: cfe/trunk/lib/Checker/GRCoreEngine.cpp Modified: cfe/trunk/lib/Checker/GRCoreEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRCoreEngine.cpp?rev=97127&r1=97126&r2=97127&view=diff ============================================================================== --- cfe/trunk/lib/Checker/GRCoreEngine.cpp (original) +++ cfe/trunk/lib/Checker/GRCoreEngine.cpp Thu Feb 25 01:03:08 2010 @@ -430,7 +430,9 @@ // Check if this node entered a callee. if (isa(N->getLocation())) { - Eng.WList->Enqueue(N, B, Idx); // Still use the index of the CallExpr. + // Still use the index of the CallExpr. It's needed to create the callee + // StackFrameContext. + Eng.WList->Enqueue(N, B, Idx); return; } From chandlerc at gmail.com Thu Feb 25 01:20:54 2010 From: chandlerc at gmail.com (Chandler Carruth) Date: Thu, 25 Feb 2010 07:20:54 -0000 Subject: [cfe-commits] r97128 - in /cfe/trunk: lib/Sema/SemaOverload.cpp lib/Sema/SemaOverload.h test/Sema/overloadable-complex.c test/SemaCXX/complex-overload.cpp Message-ID: <20100225072055.0295F2A6C131@llvm.org> Author: chandlerc Date: Thu Feb 25 01:20:54 2010 New Revision: 97128 URL: http://llvm.org/viewvc/llvm-project?rev=97128&view=rev Log: Add a new conversion rank to classify conversions between complex and scalar types. Rank these conversions below other conversions. This allows overload resolution when the only distinction is between a complex and scalar type. It also brings the complex overload resolutin in line with GCC's. Modified: cfe/trunk/lib/Sema/SemaOverload.cpp cfe/trunk/lib/Sema/SemaOverload.h cfe/trunk/test/Sema/overloadable-complex.c cfe/trunk/test/SemaCXX/complex-overload.cpp Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=97128&r1=97127&r2=97128&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Thu Feb 25 01:20:54 2010 @@ -80,7 +80,7 @@ ICR_Conversion, ICR_Conversion, ICR_Conversion, - ICR_Conversion + ICR_Complex_Real_Conversion }; return Rank[(int)Kind]; } @@ -669,14 +669,19 @@ // Integral conversions (C++ 4.7). SCS.Second = ICK_Integral_Conversion; FromType = ToType.getUnqualifiedType(); - } else if (FromType->isFloatingType() && ToType->isFloatingType()) { - // Floating point conversions (C++ 4.8). - SCS.Second = ICK_Floating_Conversion; - FromType = ToType.getUnqualifiedType(); } else if (FromType->isComplexType() && ToType->isComplexType()) { // Complex conversions (C99 6.3.1.6) SCS.Second = ICK_Complex_Conversion; FromType = ToType.getUnqualifiedType(); + } else if ((FromType->isComplexType() && ToType->isArithmeticType()) || + (ToType->isComplexType() && FromType->isArithmeticType())) { + // Complex-real conversions (C99 6.3.1.7) + SCS.Second = ICK_Complex_Real; + FromType = ToType.getUnqualifiedType(); + } else if (FromType->isFloatingType() && ToType->isFloatingType()) { + // Floating point conversions (C++ 4.8). + SCS.Second = ICK_Floating_Conversion; + FromType = ToType.getUnqualifiedType(); } else if ((FromType->isFloatingType() && ToType->isIntegralType() && (!ToType->isBooleanType() && !ToType->isEnumeralType())) || @@ -685,11 +690,6 @@ // Floating-integral conversions (C++ 4.9). SCS.Second = ICK_Floating_Integral; FromType = ToType.getUnqualifiedType(); - } else if ((FromType->isComplexType() && ToType->isArithmeticType()) || - (ToType->isComplexType() && FromType->isArithmeticType())) { - // Complex-real conversions (C99 6.3.1.7) - SCS.Second = ICK_Complex_Real; - FromType = ToType.getUnqualifiedType(); } else if (IsPointerConversion(From, FromType, ToType, InOverloadResolution, FromType, IncompatibleObjC)) { // Pointer conversions (C++ 4.10). Modified: cfe/trunk/lib/Sema/SemaOverload.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.h?rev=97128&r1=97127&r2=97128&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.h (original) +++ cfe/trunk/lib/Sema/SemaOverload.h Thu Feb 25 01:20:54 2010 @@ -54,12 +54,12 @@ ICK_Floating_Conversion, ///< Floating point conversions (C++ 4.8) ICK_Complex_Conversion, ///< Complex conversions (C99 6.3.1.6) ICK_Floating_Integral, ///< Floating-integral conversions (C++ 4.9) - ICK_Complex_Real, ///< Complex-real conversions (C99 6.3.1.7) ICK_Pointer_Conversion, ///< Pointer conversions (C++ 4.10) ICK_Pointer_Member, ///< Pointer-to-member conversions (C++ 4.11) ICK_Boolean_Conversion, ///< Boolean conversions (C++ 4.12) ICK_Compatible_Conversion, ///< Conversions between compatible types in C99 ICK_Derived_To_Base, ///< Derived-to-base (C++ [over.best.ics]) + ICK_Complex_Real, ///< Complex-real conversions (C99 6.3.1.7) ICK_Num_Conversion_Kinds ///< The number of conversion kinds }; @@ -83,9 +83,10 @@ /// 13.3.3.1.1) and are listed such that better conversion ranks /// have smaller values. enum ImplicitConversionRank { - ICR_Exact_Match = 0, ///< Exact Match - ICR_Promotion, ///< Promotion - ICR_Conversion ///< Conversion + ICR_Exact_Match = 0, ///< Exact Match + ICR_Promotion, ///< Promotion + ICR_Conversion, ///< Conversion + ICR_Complex_Real_Conversion ///< Complex <-> Real conversion }; ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind); Modified: cfe/trunk/test/Sema/overloadable-complex.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/overloadable-complex.c?rev=97128&r1=97127&r2=97128&view=diff ============================================================================== --- cfe/trunk/test/Sema/overloadable-complex.c (original) +++ cfe/trunk/test/Sema/overloadable-complex.c Thu Feb 25 01:20:54 2010 @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -char *foo(float) __attribute__((__overloadable__)); // expected-note 3 {{candidate function}} +char *foo(float) __attribute__((__overloadable__)); void test_foo_1(float fv, double dv, float _Complex fc, double _Complex dc) { char *cp1 = foo(fv); @@ -9,20 +9,20 @@ char *cp4 = foo(dc); } -int *foo(float _Complex) __attribute__((__overloadable__)); // expected-note 3 {{candidate function}} +int *foo(float _Complex) __attribute__((__overloadable__)); void test_foo_2(float fv, double dv, float _Complex fc, double _Complex dc) { char *cp1 = foo(fv); - char *cp2 = foo(dv); // expected-error{{call to 'foo' is ambiguous; candidates are:}} + char *cp2 = foo(dv); int *ip = foo(fc); - int *lp = foo(dc); // expected-error{{call to 'foo' is ambiguous; candidates are:}} + int *lp = foo(dc); } -long *foo(double _Complex) __attribute__((__overloadable__)); // expected-note {{candidate function}} +long *foo(double _Complex) __attribute__((__overloadable__)); void test_foo_3(float fv, double dv, float _Complex fc, double _Complex dc) { char *cp1 = foo(fv); - char *cp2 = foo(dv); // expected-error{{call to 'foo' is ambiguous; candidates are:}} + char *cp2 = foo(dv); int *ip = foo(fc); long *lp = foo(dc); } Modified: cfe/trunk/test/SemaCXX/complex-overload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/complex-overload.cpp?rev=97128&r1=97127&r2=97128&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/complex-overload.cpp (original) +++ cfe/trunk/test/SemaCXX/complex-overload.cpp Thu Feb 25 01:20:54 2010 @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -char *foo(float); // expected-note 3 {{candidate function}} +char *foo(float); void test_foo_1(float fv, double dv, float _Complex fc, double _Complex dc) { char *cp1 = foo(fv); @@ -9,20 +9,20 @@ char *cp4 = foo(dc); } -int *foo(float _Complex); // expected-note 3 {{candidate function}} +int *foo(float _Complex); void test_foo_2(float fv, double dv, float _Complex fc, double _Complex dc) { char *cp1 = foo(fv); - char *cp2 = foo(dv); // expected-error{{call to 'foo' is ambiguous; candidates are:}} + char *cp2 = foo(dv); int *ip = foo(fc); - int *lp = foo(dc); // expected-error{{call to 'foo' is ambiguous; candidates are:}} + int *lp = foo(dc); } -long *foo(double _Complex); // expected-note {{candidate function}} +long *foo(double _Complex); void test_foo_3(float fv, double dv, float _Complex fc, double _Complex dc) { char *cp1 = foo(fv); - char *cp2 = foo(dv); // expected-error{{call to 'foo' is ambiguous; candidates are:}} + char *cp2 = foo(dv); int *ip = foo(fc); long *lp = foo(dc); } From jyasskin at google.com Thu Feb 25 01:22:01 2010 From: jyasskin at google.com (Jeffrey Yasskin) Date: Wed, 24 Feb 2010 23:22:01 -0800 Subject: [cfe-commits] [PATCH] Fix the build on Apple gcc-4.0 Message-ID: Apple's gcc-4.0 on 10.5 was complaining that: /Users/jyasskin/src/llvm/clang/src/tools/clang/lib/Sema/TreeTransform.h:5784: error: expected primary-expression before ?>? token /Users/jyasskin/src/llvm/clang/src/tools/clang/lib/Sema/TreeTransform.h:5784: error: expected primary-expression before ?)? token This patch fixes the build there without breaking the build for other compilers or breaking the tests, so I think it's the right thing to do. Please double-check. Jeffrey -------------- next part -------------- A non-text attachment was scrubbed... Name: fix_gcc40_build.patch Type: application/octet-stream Size: 879 bytes Desc: not available Url : http://lists.cs.uiuc.edu/pipermail/cfe-commits/attachments/20100224/27f09b9e/attachment.obj From xuzhongxing at gmail.com Thu Feb 25 01:36:34 2010 From: xuzhongxing at gmail.com (Zhongxing Xu) Date: Thu, 25 Feb 2010 07:36:34 -0000 Subject: [cfe-commits] r97129 - in /cfe/trunk: include/clang/Checker/PathSensitive/GRCoreEngine.h lib/Checker/CallInliner.cpp lib/Checker/GRCoreEngine.cpp lib/Checker/GRExprEngine.cpp Message-ID: <20100225073634.E85862A6C131@llvm.org> Author: zhongxingxu Date: Thu Feb 25 01:36:34 2010 New Revision: 97129 URL: http://llvm.org/viewvc/llvm-project?rev=97129&view=rev Log: Move the dead bindings removal logic from CallInliner to GRExprEngine::ProcessCallExit(). Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h cfe/trunk/lib/Checker/CallInliner.cpp cfe/trunk/lib/Checker/GRCoreEngine.cpp cfe/trunk/lib/Checker/GRExprEngine.cpp Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h?rev=97129&r1=97128&r2=97129&view=diff ============================================================================== --- cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h (original) +++ cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h Thu Feb 25 01:36:34 2010 @@ -502,7 +502,11 @@ GRCallExitNodeBuilder(GRCoreEngine &eng, const ExplodedNode *pred) : Eng(eng), Pred(pred) {} - void GenerateNode(); + const ExplodedNode *getPredecessor() const { return Pred; } + + const GRState *getState() const { return Pred->getState(); } + + void GenerateNode(const GRState *state); }; } // end clang namespace Modified: cfe/trunk/lib/Checker/CallInliner.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/CallInliner.cpp?rev=97129&r1=97128&r2=97129&view=diff ============================================================================== --- cfe/trunk/lib/Checker/CallInliner.cpp (original) +++ cfe/trunk/lib/Checker/CallInliner.cpp Thu Feb 25 01:36:34 2010 @@ -60,20 +60,10 @@ ExplodedNode *Pred = B.getPredecessor(); const StackFrameContext *LocCtx = - cast(Pred->getLocationContext()); + cast(Pred->getLocationContext()); // Check if this is the top level stack frame. if (!LocCtx->getParent()) - return; - - const StackFrameContext *ParentSF = - cast(LocCtx->getParent()); - - SymbolReaper SymReaper(*ParentSF->getLiveVariables(), Eng.getSymbolManager(), - ParentSF); - const Stmt *CE = LocCtx->getCallSite(); - // FIXME: move this logic to GRExprEngine::ProcessCallExit(). - state = Eng.getStateManager().RemoveDeadBindings(state, const_cast(CE), - SymReaper); + return; B.GenerateCallExitNode(state); } Modified: cfe/trunk/lib/Checker/GRCoreEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRCoreEngine.cpp?rev=97129&r1=97128&r2=97129&view=diff ============================================================================== --- cfe/trunk/lib/Checker/GRCoreEngine.cpp (original) +++ cfe/trunk/lib/Checker/GRCoreEngine.cpp Thu Feb 25 01:36:34 2010 @@ -674,14 +674,14 @@ Eng.WList->Enqueue(Node); } -void GRCallExitNodeBuilder::GenerateNode() { +void GRCallExitNodeBuilder::GenerateNode(const GRState *state) { // Get the callee's location context. const StackFrameContext *LocCtx = cast(Pred->getLocationContext()); PostStmt Loc(LocCtx->getCallSite(), LocCtx->getParent()); bool isNew; - ExplodedNode *Node = Eng.G->getNode(Loc, Pred->getState(), &isNew); + ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); Node->addPredecessor(const_cast(Pred), *Eng.G); if (isNew) Eng.WList->Enqueue(Node, *const_cast(LocCtx->getCallSiteBlock()), Modified: cfe/trunk/lib/Checker/GRExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRExprEngine.cpp?rev=97129&r1=97128&r2=97129&view=diff ============================================================================== --- cfe/trunk/lib/Checker/GRExprEngine.cpp (original) +++ cfe/trunk/lib/Checker/GRExprEngine.cpp Thu Feb 25 01:36:34 2010 @@ -1305,7 +1305,21 @@ } void GRExprEngine::ProcessCallExit(GRCallExitNodeBuilder &B) { - B.GenerateNode(); + const GRState *state = B.getState(); + const ExplodedNode *Pred = B.getPredecessor(); + const StackFrameContext *LocCtx = + cast(Pred->getLocationContext()); + const StackFrameContext *ParentSF = + cast(LocCtx->getParent()); + + SymbolReaper SymReaper(*ParentSF->getLiveVariables(), getSymbolManager(), + ParentSF); + const Stmt *CE = LocCtx->getCallSite(); + + state = getStateManager().RemoveDeadBindings(state, const_cast(CE), + SymReaper); + + B.GenerateNode(state); } //===----------------------------------------------------------------------===// From xuzhongxing at gmail.com Thu Feb 25 01:57:35 2010 From: xuzhongxing at gmail.com (Zhongxing Xu) Date: Thu, 25 Feb 2010 07:57:35 -0000 Subject: [cfe-commits] r97131 - in /cfe/trunk/lib/Checker: CallInliner.cpp GRCoreEngine.cpp Message-ID: <20100225075735.DC8FD2A6C131@llvm.org> Author: zhongxingxu Date: Thu Feb 25 01:57:35 2010 New Revision: 97131 URL: http://llvm.org/viewvc/llvm-project?rev=97131&view=rev Log: Move the GenerateCallExitNode logic completely into GREndPathNodeBuilder. Modified: cfe/trunk/lib/Checker/CallInliner.cpp cfe/trunk/lib/Checker/GRCoreEngine.cpp Modified: cfe/trunk/lib/Checker/CallInliner.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/CallInliner.cpp?rev=97131&r1=97130&r2=97131&view=diff ============================================================================== --- cfe/trunk/lib/Checker/CallInliner.cpp (original) +++ cfe/trunk/lib/Checker/CallInliner.cpp Thu Feb 25 01:57:35 2010 @@ -26,7 +26,6 @@ } virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE); - virtual void EvalEndPath(GREndPathNodeBuilder &B,void *tag,GRExprEngine &Eng); }; } @@ -53,17 +52,3 @@ return true; } -void CallInliner::EvalEndPath(GREndPathNodeBuilder &B, void *tag, - GRExprEngine &Eng) { - const GRState *state = B.getState(); - - ExplodedNode *Pred = B.getPredecessor(); - - const StackFrameContext *LocCtx = - cast(Pred->getLocationContext()); - // Check if this is the top level stack frame. - if (!LocCtx->getParent()) - return; - - B.GenerateCallExitNode(state); -} Modified: cfe/trunk/lib/Checker/GRCoreEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRCoreEngine.cpp?rev=97131&r1=97130&r2=97131&view=diff ============================================================================== --- cfe/trunk/lib/Checker/GRCoreEngine.cpp (original) +++ cfe/trunk/lib/Checker/GRCoreEngine.cpp Thu Feb 25 01:57:35 2010 @@ -612,7 +612,13 @@ GREndPathNodeBuilder::~GREndPathNodeBuilder() { // Auto-generate an EOP node if one has not been generated. - if (!HasGeneratedNode) generateNode(Pred->State); + if (!HasGeneratedNode) { + // If we are in an inlined call, generate CallExit node. + if (Pred->getLocationContext()->getParent()) + GenerateCallExitNode(Pred->State); + else + generateNode(Pred->State); + } } ExplodedNode* From daniel at zuster.org Thu Feb 25 02:49:06 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Thu, 25 Feb 2010 08:49:06 -0000 Subject: [cfe-commits] r97133 - in /cfe/trunk/examples: Makefile clang-interpreter/ clang-interpreter/Makefile clang-interpreter/README.txt clang-interpreter/main.cpp Message-ID: <20100225084906.2F1E52A6C130@llvm.org> Author: ddunbar Date: Thu Feb 25 02:49:05 2010 New Revision: 97133 URL: http://llvm.org/viewvc/llvm-project?rev=97133&view=rev Log: Add a minimal C interpreter example. - Demonstrates how to build a standalone tool which loads source code using the Driver and Frontend libraries, and then uses CodeGen and the JIT to actually execute the code. - Still more complicated than it should be, but hey its only 153 lines. :) -- ddunbar at ozzy:tmp$ cat hello.c #include int main() { printf("hello world\n"); return 0; } ddunbar at ozzy:tmp$ clang-interpreter hello.c hello world -- Added: cfe/trunk/examples/clang-interpreter/ cfe/trunk/examples/clang-interpreter/Makefile cfe/trunk/examples/clang-interpreter/README.txt cfe/trunk/examples/clang-interpreter/main.cpp Modified: cfe/trunk/examples/Makefile Modified: cfe/trunk/examples/Makefile URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/Makefile?rev=97133&r1=97132&r2=97133&view=diff ============================================================================== --- cfe/trunk/examples/Makefile (original) +++ cfe/trunk/examples/Makefile Thu Feb 25 02:49:05 2010 @@ -9,6 +9,6 @@ LEVEL = ../../.. -PARALLEL_DIRS := PrintFunctionNames wpa +PARALLEL_DIRS := clang-interpreter PrintFunctionNames wpa include $(LEVEL)/Makefile.common Added: cfe/trunk/examples/clang-interpreter/Makefile URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/clang-interpreter/Makefile?rev=97133&view=auto ============================================================================== --- cfe/trunk/examples/clang-interpreter/Makefile (added) +++ cfe/trunk/examples/clang-interpreter/Makefile Thu Feb 25 02:49:05 2010 @@ -0,0 +1,28 @@ +##===- examples/clang-interpreter/Makefile -----------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. + +TOOLNAME = clang-interpreter +CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include +NO_INSTALL = 1 +TOOL_NO_EXPORTS = 1 + +# Include this here so we can get the configuration of the targets that have +# been configured for construction. We have to do this early so we can set up +# LINK_COMPONENTS before including Makefile.rules +include $(LEVEL)/Makefile.config + +LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \ + selectiondag +USEDLIBS = clangFrontend.a clangDriver.a clangCodeGen.a clangSema.a \ + clangChecker.a clangAnalysis.a clangRewrite.a clangAST.a \ + clangParse.a clangLex.a clangBasic.a + +include $(LLVM_SRC_ROOT)/Makefile.rules Added: cfe/trunk/examples/clang-interpreter/README.txt URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/clang-interpreter/README.txt?rev=97133&view=auto ============================================================================== --- cfe/trunk/examples/clang-interpreter/README.txt (added) +++ cfe/trunk/examples/clang-interpreter/README.txt Thu Feb 25 02:49:05 2010 @@ -0,0 +1,17 @@ +This is an example of Clang based interpreter, for executing standalone C +programs. + +It demonstrates the following features: + 1. Parsing standard compiler command line arguments using the Driver library. + + 2. Constructing a Clang compiler instance, using the appropriate arguments + derived in step #1. + + 3. Invoking the Clang compiler to lex, parse, syntax check, and then generate + LLVM code. + + 4. Use the LLVM JIT functionality to execute the final module. + +The implementation has many limitations and is not designed to be a full fledged +C interpreter. It is designed to demonstrate a simple but functional use of the +Clang compiler libraries. Added: cfe/trunk/examples/clang-interpreter/main.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/clang-interpreter/main.cpp?rev=97133&view=auto ============================================================================== --- cfe/trunk/examples/clang-interpreter/main.cpp (added) +++ cfe/trunk/examples/clang-interpreter/main.cpp Thu Feb 25 02:49:05 2010 @@ -0,0 +1,152 @@ +//===-- examples/clang-interpreter/main.cpp - Clang C Interpreter Example -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Tool.h" +#include "clang/Frontend/CodeGenAction.h" +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/DiagnosticOptions.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" + +#include "llvm/LLVMContext.h" +#include "llvm/Module.h" +#include "llvm/Config/config.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Config/config.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Host.h" +#include "llvm/System/Path.h" +#include "llvm/Target/TargetSelect.h" +using namespace clang; +using namespace clang::driver; + +llvm::sys::Path GetExecutablePath(const char *Argv0) { + // This just needs to be some symbol in the binary; C++ doesn't + // allow taking the address of ::main however. + void *MainAddr = (void*) (intptr_t) GetExecutablePath; + return llvm::sys::Path::GetMainExecutable(Argv0, MainAddr); +} + +int Execute(llvm::Module *Mod, char * const *envp) { + llvm::InitializeNativeTarget(); + + std::string Error; + llvm::OwningPtr EE( + llvm::ExecutionEngine::createJIT(Mod, &Error)); + if (!EE) { + llvm::errs() << "unable to make execution engine: " << Error << "\n"; + return 255; + } + + llvm::Function *EntryFn = Mod->getFunction("main"); + if (!EntryFn) { + llvm::errs() << "'main' function not found in module.\n"; + return 255; + } + + // FIXME: Support passing arguments. + std::vector Args; + Args.push_back(Mod->getModuleIdentifier()); + + return EE->runFunctionAsMain(EntryFn, Args, envp); +} + +int main(int argc, const char **argv, char * const *envp) { + void *MainAddr = (void*) (intptr_t) GetExecutablePath; + llvm::sys::Path Path = GetExecutablePath(argv[0]); + TextDiagnosticPrinter DiagClient(llvm::errs(), DiagnosticOptions()); + + Diagnostic Diags(&DiagClient); + Driver TheDriver(Path.getBasename(), Path.getDirname(), + llvm::sys::getHostTriple(), + "a.out", /*IsProduction=*/false, Diags); + TheDriver.setTitle("clang interpreter"); + + // FIXME: This is a hack to try to force the driver to do something we can + // recognize. We need to extend the driver library to support this use model + // (basically, exactly one input, and the operation mode is hard wired). + llvm::SmallVector Args(argv, argv + argc); + Args.push_back("-fsyntax-only"); + llvm::OwningPtr C(TheDriver.BuildCompilation(Args.size(), + Args.data())); + if (!C) + return 0; + + // FIXME: This is copied from ASTUnit.cpp; simplify and eliminate. + + // We expect to get back exactly one command job, if we didn't something + // failed. Extract that job from the compilation. + const driver::JobList &Jobs = C->getJobs(); + if (Jobs.size() != 1 || !isa(Jobs.begin())) { + llvm::SmallString<256> Msg; + llvm::raw_svector_ostream OS(Msg); + C->PrintJob(OS, C->getJobs(), "; ", true); + Diags.Report(diag::err_fe_expected_compiler_job) << OS.str(); + return 1; + } + + const driver::Command *Cmd = cast(*Jobs.begin()); + if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") { + Diags.Report(diag::err_fe_expected_clang_command); + return 1; + } + + // Initialize a compiler invocation object from the clang (-cc1) arguments. + const driver::ArgStringList &CCArgs = Cmd->getArguments(); + llvm::OwningPtr CI(new CompilerInvocation); + CompilerInvocation::CreateFromArgs(*CI, (const char**) CCArgs.data(), + (const char**) CCArgs.data()+CCArgs.size(), + Diags); + + // Show the invocation, with -v. + if (CI->getHeaderSearchOpts().Verbose) { + llvm::errs() << "clang invocation:\n"; + C->PrintJob(llvm::errs(), C->getJobs(), "\n", true); + llvm::errs() << "\n"; + } + + // FIXME: This is copied from cc1_main.cpp; simplify and eliminate. + + // Create a compiler instance to handle the actual work. + CompilerInstance Clang; + Clang.setLLVMContext(new llvm::LLVMContext); + Clang.setInvocation(CI.take()); + + // Create the compilers actual diagnostics engine. + Clang.createDiagnostics(int(CCArgs.size()), (char**) CCArgs.data()); + if (!Clang.hasDiagnostics()) + return 1; + + // Infer the builtin include path if unspecified. + if (Clang.getHeaderSearchOpts().UseBuiltinIncludes && + Clang.getHeaderSearchOpts().ResourceDir.empty()) + Clang.getHeaderSearchOpts().ResourceDir = + CompilerInvocation::GetResourcesPath(argv[0], MainAddr); + + // Create and execute the frontend to generate an LLVM bitcode module. + llvm::OwningPtr Act(new EmitLLVMOnlyAction()); + if (!Clang.ExecuteAction(*Act)) + return 1; + + int Res = 255; + if (llvm::Module *Module = Act->takeModule()) + Res = Execute(Module, envp); + + // Shutdown. + + llvm::llvm_shutdown(); + + return Res; +} From chandlerc at gmail.com Thu Feb 25 03:32:59 2010 From: chandlerc at gmail.com (Chandler Carruth) Date: Thu, 25 Feb 2010 09:32:59 -0000 Subject: [cfe-commits] r97134 - in /cfe/trunk: lib/Sema/SemaDecl.cpp test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp Message-ID: <20100225093259.8B5A62A6C12D@llvm.org> Author: chandlerc Date: Thu Feb 25 03:32:59 2010 New Revision: 97134 URL: http://llvm.org/viewvc/llvm-project?rev=97134&view=rev Log: Fix a really trivial crasher and begin fleshing out one of the namespace test cases. Modified: cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=97134&r1=97133&r2=97134&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Feb 25 03:32:59 2010 @@ -4778,12 +4778,15 @@ // If a friend declaration in a non-local class first declares a // class or function, the friend class or function is a member of // the innermost enclosing namespace. - while (!SearchDC->isFileContext()) - SearchDC = SearchDC->getParent(); + SearchDC = SearchDC->getEnclosingNamespaceContext(); - // The entity of a decl scope is a DeclContext; see PushDeclContext. - while (S->getEntity() != SearchDC) + // Look up through our scopes until we find one with an entity which + // matches our declaration context. + while (S->getEntity() && + ((DeclContext *)S->getEntity())->getPrimaryContext() != SearchDC) { S = S->getParent(); + assert(S && "No enclosing scope matching the enclosing namespace."); + } } CreateNewDecl: Modified: cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp?rev=97134&r1=97133&r2=97134&view=diff ============================================================================== --- cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp (original) +++ cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp Thu Feb 25 03:32:59 2010 @@ -1,5 +1,47 @@ // RUN: %clang_cc1 -fsyntax-only %s +// C++'0x [namespace.memdef] p3: +// Every name first declared in a namespace is a member of that namespace. If +// a friend declaration in a non-local class first declares a class or +// function the friend class or function is a member of the innermost +// enclosing namespace. + +namespace N { + struct S0 { + friend struct F0; + friend void f0(int); + struct F0 member_func(); + }; + struct F0 { }; + F0 f0() { return S0().member_func(); } +} +N::F0 f0_var = N::f0(); + +// Ensure we can handle attaching friend declarations to an enclosing namespace +// with multiple contexts. +namespace N { struct S1 { struct IS1; }; } +namespace N { + struct S1::IS1 { + friend struct F1; + friend void f1(int); + struct F1 member_func(); + }; + struct F1 { }; + F1 f1() { return S1::IS1().member_func(); } +} +N::F1 f1_var = N::f1(); + +// The name of the friend is not found by unqualified lookup (3.4.1) or by +// qualified lookup (3.4.3) until a matching declaration is provided in that +// namespace scope (either before or after the class definition granting +// friendship). If a friend function is called, its name may be found by the +// name lookup that considers functions from namespaces and classes +// associated with the types of the function arguments (3.4.2). If the name +// in a friend declaration is neither qualified nor a template-id and the +// declaration is a function or an elaborated-type-specifier, the lookup to +// determine whether the entity has been previously declared shall not +// consider any scopes outside the innermost enclosing namespace. + template struct X0 { }; struct X1 { }; @@ -11,5 +53,4 @@ friend union X1; }; - // FIXME: Woefully inadequate for testing From rjmccall at apple.com Thu Feb 25 04:46:06 2010 From: rjmccall at apple.com (John McCall) Date: Thu, 25 Feb 2010 10:46:06 -0000 Subject: [cfe-commits] r97135 - in /cfe/trunk: lib/Sema/SemaOverload.cpp test/SemaCXX/overload-call.cpp Message-ID: <20100225104606.2049D2A6C12C@llvm.org> Author: rjmccall Date: Thu Feb 25 04:46:05 2010 New Revision: 97135 URL: http://llvm.org/viewvc/llvm-project?rev=97135&view=rev Log: When comparing two method overload candidates during overload diagnostics, skip the object argument conversion if either of the candidates didn't initialize it. Fixes PR6421, which is such a very straightforward extension of PR6398 that I should have worked it into the last test case (and therefore caught it then). Ah well. Modified: cfe/trunk/lib/Sema/SemaOverload.cpp cfe/trunk/test/SemaCXX/overload-call.cpp Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=97135&r1=97134&r2=97135&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Thu Feb 25 04:46:05 2010 @@ -4797,7 +4797,8 @@ assert(L->Conversions.size() == R->Conversions.size()); int leftBetter = 0; - for (unsigned I = 0, E = L->Conversions.size(); I != E; ++I) { + unsigned I = (L->IgnoreObjectArgument || R->IgnoreObjectArgument); + for (unsigned E = L->Conversions.size(); I != E; ++I) { switch (S.CompareImplicitConversionSequences(L->Conversions[I], R->Conversions[I])) { case ImplicitConversionSequence::Better: Modified: cfe/trunk/test/SemaCXX/overload-call.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overload-call.cpp?rev=97135&r1=97134&r2=97135&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/overload-call.cpp (original) +++ cfe/trunk/test/SemaCXX/overload-call.cpp Thu Feb 25 04:46:05 2010 @@ -360,12 +360,13 @@ } } -// PR 6398 +// PR 6398 + PR 6421 namespace test4 { class A; class B { static void foo(); // expected-note {{not viable}} static void foo(int*); // expected-note {{not viable}} + static void foo(long*); // expected-note {{not viable}} void bar(A *a) { foo(a); // expected-error {{no matching function for call}} From ggreif at gmail.com Thu Feb 25 07:04:33 2010 From: ggreif at gmail.com (Gabor Greif) Date: Thu, 25 Feb 2010 13:04:33 -0000 Subject: [cfe-commits] r97136 - /cfe/trunk/lib/Sema/TreeTransform.h Message-ID: <20100225130433.5A8202A6C12C@llvm.org> Author: ggreif Date: Thu Feb 25 07:04:33 2010 New Revision: 97136 URL: http://llvm.org/viewvc/llvm-project?rev=97136&view=rev Log: Add "template" keyword at strategic position to fix compilation using g++ v3.4. I'll watch the buildbots and back out if necessary. Feel free to do the same if something breaks. Without this patch I get (on g++ 3.4.6) following error: In file included from clang/lib/Sema/SemaTemplate.cpp:14: clang/lib/Sema/TreeTransform.h: In member function `clang::ASTOwningResult<&clang::ActionBase::DeleteExpr> clang::TreeTransform::RebuildCXXPseudoDestructorExpr(clang::ASTOwningResult<&clang::ActionBase::DeleteExpr>, clang::SourceLocation, bool, clang::NestedNameSpecifier*, clang::SourceRange, clang::TypeSourceInfo*, clang::SourceLocation, clang::SourceLocation, clang::PseudoDestructorTypeStorage)': clang/lib/Sema/TreeTransform.h:5784: error: expected primary-expression before '>' token clang/lib/Sema/TreeTransform.h:5784: error: expected primary-expression before ')' token make[4]: *** [clang/lib/Sema/Release/SemaTemplate.o] Error 1 Modified: cfe/trunk/lib/Sema/TreeTransform.h Modified: cfe/trunk/lib/Sema/TreeTransform.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=97136&r1=97135&r2=97136&view=diff ============================================================================== --- cfe/trunk/lib/Sema/TreeTransform.h (original) +++ cfe/trunk/lib/Sema/TreeTransform.h Thu Feb 25 07:04:33 2010 @@ -5781,7 +5781,8 @@ if (BaseE->isTypeDependent() || Destroyed.getIdentifier() || (!isArrow && !BaseType->getAs()) || (isArrow && BaseType->getAs() && - !BaseType->getAs()->getPointeeType()->getAs())){ + !BaseType->getAs()->getPointeeType() + ->template getAs())){ // This pseudo-destructor expression is still a pseudo-destructor. return SemaRef.BuildPseudoDestructorExpr(move(Base), OperatorLoc, isArrow? tok::arrow : tok::period, From stoklund at 2pi.dk Thu Feb 25 09:47:53 2010 From: stoklund at 2pi.dk (Jakob Stoklund Olesen) Date: Thu, 25 Feb 2010 15:47:53 -0000 Subject: [cfe-commits] r97138 - in /cfe/trunk: include/clang/Analysis/ProgramPoint.h include/clang/Checker/PathSensitive/Checker.h include/clang/Checker/PathSensitive/GRCoreEngine.h include/clang/Checker/PathSensitive/GRExprEngine.h include/clang/Checker/PathSensitive/GRSubEngine.h lib/Checker/CallInliner.cpp lib/Checker/GRCoreEngine.cpp lib/Checker/GRExprEngine.cpp Message-ID: <20100225154753.E5F8B2A6C12C@llvm.org> Author: stoklund Date: Thu Feb 25 09:47:53 2010 New Revision: 97138 URL: http://llvm.org/viewvc/llvm-project?rev=97138&view=rev Log: Revert patches r97122 r97127 r97129 r97131. They were breaking clang-x86_64-darwin10-selfhost Modified: cfe/trunk/include/clang/Analysis/ProgramPoint.h cfe/trunk/include/clang/Checker/PathSensitive/Checker.h cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h cfe/trunk/lib/Checker/CallInliner.cpp cfe/trunk/lib/Checker/GRCoreEngine.cpp cfe/trunk/lib/Checker/GRExprEngine.cpp Modified: cfe/trunk/include/clang/Analysis/ProgramPoint.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/ProgramPoint.h?rev=97138&r1=97137&r2=97138&view=diff ============================================================================== --- cfe/trunk/include/clang/Analysis/ProgramPoint.h (original) +++ cfe/trunk/include/clang/Analysis/ProgramPoint.h Thu Feb 25 09:47:53 2010 @@ -26,7 +26,6 @@ namespace clang { class LocationContext; -class FunctionDecl; class ProgramPoint { public: @@ -42,8 +41,6 @@ PostPurgeDeadSymbolsKind, PostStmtCustomKind, PostLValueKind, - CallEnterKind, - CallExitKind, MinPostStmtKind = PostStmtKind, MaxPostStmtKind = PostLValueKind }; @@ -311,36 +308,6 @@ } }; -class CallEnter : public StmtPoint { -public: - // CallEnter uses the caller's location context. - CallEnter(const Stmt *S, const FunctionDecl *fd, const LocationContext *L) - : StmtPoint(S, fd, CallEnterKind, L, 0) {} - - const Stmt *getCallExpr() const { - return static_cast(getData1()); - } - - const FunctionDecl *getCallee() const { - return static_cast(getData2()); - } - - static bool classof(const ProgramPoint *Location) { - return Location->getKind() == CallEnterKind; - } -}; - -class CallExit : public StmtPoint { -public: - // CallExit uses the callee's location context. - CallExit(const Stmt *S, const LocationContext *L) - : StmtPoint(S, 0, CallExitKind, L, 0) {} - - static bool classof(const ProgramPoint *Location) { - return Location->getKind() == CallExitKind; - } -}; - } // end namespace clang Modified: cfe/trunk/include/clang/Checker/PathSensitive/Checker.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/Checker.h?rev=97138&r1=97137&r2=97138&view=diff ============================================================================== --- cfe/trunk/include/clang/Checker/PathSensitive/Checker.h (original) +++ cfe/trunk/include/clang/Checker/PathSensitive/Checker.h Thu Feb 25 09:47:53 2010 @@ -155,14 +155,6 @@ Dst.Add(Pred); } - // Generate a node with a new program point different from the one that will - // be created by the GRStmtNodeBuilder. - void addTransition(const GRState *state, ProgramPoint Loc) { - ExplodedNode *N = B.generateNode(Loc, state, Pred); - if (N) - addTransition(N); - } - void EmitReport(BugReport *R) { Eng.getBugReporter().EmitReport(R); } Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h?rev=97138&r1=97137&r2=97138&view=diff ============================================================================== --- cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h (original) +++ cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h Thu Feb 25 09:47:53 2010 @@ -40,8 +40,6 @@ friend class GRIndirectGotoNodeBuilder; friend class GRSwitchNodeBuilder; friend class GREndPathNodeBuilder; - friend class GRCallEnterNodeBuilder; - friend class GRCallExitNodeBuilder; GRSubEngine& SubEngine; @@ -69,9 +67,6 @@ void HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock* B, ExplodedNode* Pred); - void HandleCallEnter(const CallEnter &L, const CFGBlock *Block, - unsigned Index, ExplodedNode *Pred); - void HandleCallExit(const CallExit &L, ExplodedNode *Pred); /// Get the initial state from the subengine. const GRState* getInitialState(const LocationContext *InitLoc) { @@ -95,9 +90,6 @@ void ProcessSwitch(GRSwitchNodeBuilder& Builder); - void ProcessCallEnter(GRCallEnterNodeBuilder &Builder); - void ProcessCallExit(GRCallExitNodeBuilder &Builder); - private: GRCoreEngine(const GRCoreEngine&); // Do not implement. GRCoreEngine& operator=(const GRCoreEngine&); @@ -202,12 +194,6 @@ return generateNode(S, St, Pred, PointKind); } - ExplodedNode *generateNode(const ProgramPoint &PP, const GRState* State, - ExplodedNode* Pred) { - HasGeneratedNode = true; - return generateNodeInternal(PP, State, Pred); - } - ExplodedNode* generateNodeInternal(const ProgramPoint &PP, const GRState* State, ExplodedNode* Pred); @@ -445,8 +431,6 @@ ExplodedNode* generateNode(const GRState* State, const void *tag = 0, ExplodedNode *P = 0); - void GenerateCallExitNode(const GRState *state); - CFGBlock* getBlock() const { return &B; } const GRState* getState() const { @@ -454,60 +438,6 @@ } }; -class GRCallEnterNodeBuilder { - GRCoreEngine &Eng; - - const ExplodedNode *Pred; - - // The call site. - const Stmt *CE; - - // The definition of callee. - const FunctionDecl *FD; - - // The parent block of the CallExpr. - const CFGBlock *Block; - - // The CFGBlock index of the CallExpr. - unsigned Index; - -public: - GRCallEnterNodeBuilder(GRCoreEngine &eng, const ExplodedNode *pred, - const Stmt *s, const FunctionDecl *fd, - const CFGBlock *blk, unsigned idx) - : Eng(eng), Pred(pred), CE(s), FD(fd), Block(blk), Index(idx) {} - - const GRState *getState() const { return Pred->getState(); } - - const LocationContext *getLocationContext() const { - return Pred->getLocationContext(); - } - - const Stmt *getCallExpr() const { return CE; } - - const FunctionDecl *getCallee() const { return FD; } - - const CFGBlock *getBlock() const { return Block; } - - unsigned getIndex() const { return Index; } - - void GenerateNode(const GRState *state, const LocationContext *LocCtx); -}; - -class GRCallExitNodeBuilder { - GRCoreEngine &Eng; - const ExplodedNode *Pred; - -public: - GRCallExitNodeBuilder(GRCoreEngine &eng, const ExplodedNode *pred) - : Eng(eng), Pred(pred) {} - - const ExplodedNode *getPredecessor() const { return Pred; } - - const GRState *getState() const { return Pred->getState(); } - - void GenerateNode(const GRState *state); -}; } // end clang namespace #endif Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h?rev=97138&r1=97137&r2=97138&view=diff ============================================================================== --- cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h (original) +++ cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h Thu Feb 25 09:47:53 2010 @@ -171,13 +171,7 @@ /// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path /// nodes when the control reaches the end of a function. void ProcessEndPath(GREndPathNodeBuilder& builder); - - // Generate the entry node of the callee. - void ProcessCallEnter(GRCallEnterNodeBuilder &builder); - - // Generate the first post callsite node. - void ProcessCallExit(GRCallExitNodeBuilder &builder); - + /// EvalAssume - Callback function invoked by the ConstraintManager when /// making assumptions about state values. const GRState *ProcessAssume(const GRState *state, SVal cond, bool assumption); Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h?rev=97138&r1=97137&r2=97138&view=diff ============================================================================== --- cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h (original) +++ cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h Thu Feb 25 09:47:53 2010 @@ -28,8 +28,6 @@ class GRIndirectGotoNodeBuilder; class GRSwitchNodeBuilder; class GREndPathNodeBuilder; -class GRCallEnterNodeBuilder; -class GRCallExitNodeBuilder; class LocationContext; class GRSubEngine { @@ -66,12 +64,6 @@ /// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path /// nodes when the control reaches the end of a function. virtual void ProcessEndPath(GREndPathNodeBuilder& builder) = 0; - - // Generate the entry node of the callee. - virtual void ProcessCallEnter(GRCallEnterNodeBuilder &builder) = 0; - - // Generate the first post callsite node. - virtual void ProcessCallExit(GRCallExitNodeBuilder &builder) = 0; /// EvalAssume - Called by ConstraintManager. Used to call checker-specific /// logic for handling assumptions on symbolic values. Modified: cfe/trunk/lib/Checker/CallInliner.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/CallInliner.cpp?rev=97138&r1=97137&r2=97138&view=diff ============================================================================== --- cfe/trunk/lib/Checker/CallInliner.cpp (original) +++ cfe/trunk/lib/Checker/CallInliner.cpp Thu Feb 25 09:47:53 2010 @@ -26,6 +26,7 @@ } virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE); + virtual void EvalEndPath(GREndPathNodeBuilder &B,void *tag,GRExprEngine &Eng); }; } @@ -45,10 +46,79 @@ if (!FD->isThisDeclarationADefinition()) return false; - // Now we have the definition of the callee, create a CallEnter node. - CallEnter Loc(CE, FD, C.getPredecessor()->getLocationContext()); - C.addTransition(state, Loc); + GRStmtNodeBuilder &Builder = C.getNodeBuilder(); + // Make a new LocationContext. + const StackFrameContext *LocCtx = C.getAnalysisManager().getStackFrame(FD, + C.getPredecessor()->getLocationContext(), CE, + Builder.getBlock(), Builder.getIndex()); + + CFGBlock const *Entry = &(LocCtx->getCFG()->getEntry()); + + assert (Entry->empty() && "Entry block must be empty."); + + assert (Entry->succ_size() == 1 && "Entry block must have 1 successor."); + + // Get the solitary successor. + CFGBlock const *SuccB = *(Entry->succ_begin()); + + // Construct an edge representing the starting location in the function. + BlockEdge Loc(Entry, SuccB, LocCtx); + + state = C.getStoreManager().EnterStackFrame(state, LocCtx); + + // This is a hack. We really should not use the GRStmtNodeBuilder. + bool isNew; + GRExprEngine &Eng = C.getEngine(); + ExplodedNode *Pred = C.getPredecessor(); + + + ExplodedNode *SuccN = Eng.getGraph().getNode(Loc, state, &isNew); + SuccN->addPredecessor(Pred, Eng.getGraph()); + C.getNodeBuilder().Deferred.erase(Pred); + + if (isNew) + Builder.getWorkList()->Enqueue(SuccN); + + Builder.HasGeneratedNode = true; return true; } +void CallInliner::EvalEndPath(GREndPathNodeBuilder &B, void *tag, + GRExprEngine &Eng) { + const GRState *state = B.getState(); + + ExplodedNode *Pred = B.getPredecessor(); + + const StackFrameContext *LocCtx = + cast(Pred->getLocationContext()); + // Check if this is the top level stack frame. + if (!LocCtx->getParent()) + return; + + const StackFrameContext *ParentSF = + cast(LocCtx->getParent()); + + SymbolReaper SymReaper(*ParentSF->getLiveVariables(), Eng.getSymbolManager(), + ParentSF); + const Stmt *CE = LocCtx->getCallSite(); + + state = Eng.getStateManager().RemoveDeadBindings(state, const_cast(CE), + SymReaper); + + + PostStmt NodeLoc(CE, LocCtx->getParent()); + + bool isNew; + ExplodedNode *Succ = Eng.getGraph().getNode(NodeLoc, state, &isNew); + Succ->addPredecessor(Pred, Eng.getGraph()); + + // When creating the new work list unit, increment the statement index to + // point to the statement after the CallExpr. + if (isNew) + B.getWorkList().Enqueue(Succ, + *const_cast(LocCtx->getCallSiteBlock()), + LocCtx->getIndex() + 1); + + B.HasGeneratedNode = true; +} Modified: cfe/trunk/lib/Checker/GRCoreEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRCoreEngine.cpp?rev=97138&r1=97137&r2=97138&view=diff ============================================================================== --- cfe/trunk/lib/Checker/GRCoreEngine.cpp (original) +++ cfe/trunk/lib/Checker/GRCoreEngine.cpp Thu Feb 25 09:47:53 2010 @@ -144,14 +144,6 @@ SubEngine.ProcessSwitch(Builder); } -void GRCoreEngine::ProcessCallEnter(GRCallEnterNodeBuilder &Builder) { - SubEngine.ProcessCallEnter(Builder); -} - -void GRCoreEngine::ProcessCallExit(GRCallExitNodeBuilder &Builder) { - SubEngine.ProcessCallExit(Builder); -} - /// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps. bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) { @@ -204,15 +196,6 @@ assert (false && "BlockExit location never occur in forward analysis."); break; - case ProgramPoint::CallEnterKind: - HandleCallEnter(cast(Node->getLocation()), WU.getBlock(), - WU.getIndex(), Node); - break; - - case ProgramPoint::CallExitKind: - HandleCallExit(cast(Node->getLocation()), Node); - break; - default: assert(isa(Node->getLocation())); HandlePostStmt(cast(Node->getLocation()), WU.getBlock(), @@ -224,17 +207,6 @@ return WList->hasWork(); } -void GRCoreEngine::HandleCallEnter(const CallEnter &L, const CFGBlock *Block, - unsigned Index, ExplodedNode *Pred) { - GRCallEnterNodeBuilder Builder(*this, Pred, L.getCallExpr(), L.getCallee(), - Block, Index); - ProcessCallEnter(Builder); -} - -void GRCoreEngine::HandleCallExit(const CallExit &L, ExplodedNode *Pred) { - GRCallExitNodeBuilder Builder(*this, Pred); - ProcessCallExit(Builder); -} void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) { @@ -428,14 +400,6 @@ void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) { assert (!N->isSink()); - // Check if this node entered a callee. - if (isa(N->getLocation())) { - // Still use the index of the CallExpr. It's needed to create the callee - // StackFrameContext. - Eng.WList->Enqueue(N, B, Idx); - return; - } - PostStmt Loc(getStmt(), N->getLocationContext()); if (Loc == N->getLocation()) { @@ -612,13 +576,7 @@ GREndPathNodeBuilder::~GREndPathNodeBuilder() { // Auto-generate an EOP node if one has not been generated. - if (!HasGeneratedNode) { - // If we are in an inlined call, generate CallExit node. - if (Pred->getLocationContext()->getParent()) - GenerateCallExitNode(Pred->State); - else - generateNode(Pred->State); - } + if (!HasGeneratedNode) generateNode(Pred->State); } ExplodedNode* @@ -639,57 +597,3 @@ return NULL; } - -void GREndPathNodeBuilder::GenerateCallExitNode(const GRState *state) { - HasGeneratedNode = true; - // Create a CallExit node and enqueue it. - const StackFrameContext *LocCtx - = cast(Pred->getLocationContext()); - const Stmt *CE = LocCtx->getCallSite(); - - // Use the the callee location context. - CallExit Loc(CE, LocCtx); - - bool isNew; - ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); - Node->addPredecessor(Pred, *Eng.G); - - if (isNew) - Eng.WList->Enqueue(Node); -} - - -void GRCallEnterNodeBuilder::GenerateNode(const GRState *state, - const LocationContext *LocCtx) { - // Get the callee entry block. - const CFGBlock *Entry = &(LocCtx->getCFG()->getEntry()); - assert(Entry->empty()); - assert(Entry->succ_size() == 1); - - // Get the solitary successor. - const CFGBlock *SuccB = *(Entry->succ_begin()); - - // Construct an edge representing the starting location in the callee. - BlockEdge Loc(Entry, SuccB, LocCtx); - - bool isNew; - ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); - Node->addPredecessor(const_cast(Pred), *Eng.G); - - if (isNew) - Eng.WList->Enqueue(Node); -} - -void GRCallExitNodeBuilder::GenerateNode(const GRState *state) { - // Get the callee's location context. - const StackFrameContext *LocCtx - = cast(Pred->getLocationContext()); - - PostStmt Loc(LocCtx->getCallSite(), LocCtx->getParent()); - bool isNew; - ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); - Node->addPredecessor(const_cast(Pred), *Eng.G); - if (isNew) - Eng.WList->Enqueue(Node, *const_cast(LocCtx->getCallSiteBlock()), - LocCtx->getIndex() + 1); -} Modified: cfe/trunk/lib/Checker/GRExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRExprEngine.cpp?rev=97138&r1=97137&r2=97138&view=diff ============================================================================== --- cfe/trunk/lib/Checker/GRExprEngine.cpp (original) +++ cfe/trunk/lib/Checker/GRExprEngine.cpp Thu Feb 25 09:47:53 2010 @@ -1290,38 +1290,6 @@ if (defaultIsFeasible) builder.generateDefaultCaseNode(DefaultSt); } -void GRExprEngine::ProcessCallEnter(GRCallEnterNodeBuilder &B) { - const FunctionDecl *FD = B.getCallee(); - const StackFrameContext *LocCtx = AMgr.getStackFrame(FD, - B.getLocationContext(), - B.getCallExpr(), - B.getBlock(), - B.getIndex()); - - const GRState *state = B.getState(); - state = getStoreManager().EnterStackFrame(state, LocCtx); - - B.GenerateNode(state, LocCtx); -} - -void GRExprEngine::ProcessCallExit(GRCallExitNodeBuilder &B) { - const GRState *state = B.getState(); - const ExplodedNode *Pred = B.getPredecessor(); - const StackFrameContext *LocCtx = - cast(Pred->getLocationContext()); - const StackFrameContext *ParentSF = - cast(LocCtx->getParent()); - - SymbolReaper SymReaper(*ParentSF->getLiveVariables(), getSymbolManager(), - ParentSF); - const Stmt *CE = LocCtx->getCallSite(); - - state = getStateManager().RemoveDeadBindings(state, const_cast(CE), - SymReaper); - - B.GenerateNode(state); -} - //===----------------------------------------------------------------------===// // Transfer functions: logical operations ('&&', '||'). //===----------------------------------------------------------------------===// @@ -3173,14 +3141,6 @@ assert (false); break; - case ProgramPoint::CallEnterKind: - Out << "CallEnter"; - break; - - case ProgramPoint::CallExitKind: - Out << "CallExit"; - break; - default: { if (StmtPoint *L = dyn_cast(&Loc)) { const Stmt* S = L->getStmt(); From lattner at apple.com Thu Feb 25 10:48:49 2010 From: lattner at apple.com (Tanya Lattner) Date: Thu, 25 Feb 2010 08:48:49 -0800 Subject: [cfe-commits] [PATCH] missing braces warning In-Reply-To: <0CB0D0BD-1B50-4A62-9721-8814764DFEB8@apple.com> References: <0CB0D0BD-1B50-4A62-9721-8814764DFEB8@apple.com> Message-ID: <7BA70841-0A76-43C5-A643-C5E5FD43AA9E@apple.com> Any comments? :) -Tanya On Feb 18, 2010, at 10:55 AM, Tanya Lattner wrote: > Attached is a patch that implements missing braces warning and updates some test cases. Let me know what you think. > > Thanks! > -Tanya > _______________________________________________ > cfe-commits mailing list > cfe-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits From fjahanian at apple.com Thu Feb 25 11:15:14 2010 From: fjahanian at apple.com (Fariborz Jahanian) Date: Thu, 25 Feb 2010 09:15:14 -0800 Subject: [cfe-commits] r97103 - in /cfe/trunk: lib/Sema/SemaDeclAttr.cpp test/SemaObjC/unused.m In-Reply-To: <20100225032651.844202A6C136@llvm.org> References: <20100225032651.844202A6C136@llvm.org> Message-ID: <227F5910-91D3-44C9-920A-0A448F875C97@apple.com> Hi Ted, Is the 'unused' attribute for the benefit of static analyzer only or you are planning on using it in the compiler as well? - Fariborz On Feb 24, 2010, at 7:26 PM, Ted Kremenek wrote: > Author: kremenek > Date: Wed Feb 24 21:26:51 2010 > New Revision: 97103 > > URL: http://llvm.org/viewvc/llvm-project?rev=97103&view=rev > Log: > Allow __attribute__((unused)) to be applied to ObjC ivars. > From dgregor at apple.com Thu Feb 25 11:58:50 2010 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 25 Feb 2010 09:58:50 -0800 Subject: [cfe-commits] r97136 - /cfe/trunk/lib/Sema/TreeTransform.h In-Reply-To: <20100225130433.5A8202A6C12C@llvm.org> References: <20100225130433.5A8202A6C12C@llvm.org> Message-ID: <6C03BB86-2B36-4C91-8BD6-B5C8AC03296A@apple.com> On Feb 25, 2010, at 5:04 AM, Gabor Greif wrote: > Author: ggreif > Date: Thu Feb 25 07:04:33 2010 > New Revision: 97136 > > URL: http://llvm.org/viewvc/llvm-project?rev=97136&view=rev > Log: > Add "template" keyword at strategic position to fix > compilation using g++ v3.4. > > I'll watch the buildbots and back out if necessary. > Feel free to do the same if something breaks. > > Without this patch I get (on g++ 3.4.6) following error: > > In file included from clang/lib/Sema/SemaTemplate.cpp:14: > clang/lib/Sema/TreeTransform.h: In member function `clang::ASTOwningResult<&clang::ActionBase::DeleteExpr> clang::TreeTransform::RebuildCXXPseudoDestructorExpr(clang::ASTOwningResult<&clang::ActionBase::DeleteExpr>, clang::SourceLocation, bool, clang::NestedNameSpecifier*, clang::SourceRange, clang::TypeSourceInfo*, clang::SourceLocation, clang::SourceLocation, clang::PseudoDestructorTypeStorage)': > clang/lib/Sema/TreeTransform.h:5784: error: expected primary-expression before '>' token > clang/lib/Sema/TreeTransform.h:5784: error: expected primary-expression before ')' token > make[4]: *** [clang/lib/Sema/Release/SemaTemplate.o] Error 1 Hah, go figure. Both the code I committed and the change you committed are well-formed. I was building/testing with Clang, which has no problems with the code I committed, but obviously GCC couldn't grok it. Thanks for fixing! - Doug > Modified: > cfe/trunk/lib/Sema/TreeTransform.h > > Modified: cfe/trunk/lib/Sema/TreeTransform.h > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=97136&r1=97135&r2=97136&view=diff > ============================================================================== > --- cfe/trunk/lib/Sema/TreeTransform.h (original) > +++ cfe/trunk/lib/Sema/TreeTransform.h Thu Feb 25 07:04:33 2010 > @@ -5781,7 +5781,8 @@ > if (BaseE->isTypeDependent() || Destroyed.getIdentifier() || > (!isArrow && !BaseType->getAs()) || > (isArrow && BaseType->getAs() && > - !BaseType->getAs()->getPointeeType()->getAs())){ > + !BaseType->getAs()->getPointeeType() > + ->template getAs())){ > // This pseudo-destructor expression is still a pseudo-destructor. > return SemaRef.BuildPseudoDestructorExpr(move(Base), OperatorLoc, > isArrow? tok::arrow : tok::period, > > > _______________________________________________ > cfe-commits mailing list > cfe-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits From kremenek at apple.com Thu Feb 25 12:01:54 2010 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 25 Feb 2010 10:01:54 -0800 Subject: [cfe-commits] r97103 - in /cfe/trunk: lib/Sema/SemaDeclAttr.cpp test/SemaObjC/unused.m In-Reply-To: <227F5910-91D3-44C9-920A-0A448F875C97@apple.com> References: <20100225032651.844202A6C136@llvm.org> <227F5910-91D3-44C9-920A-0A448F875C97@apple.com> Message-ID: Right now it is only used by the static analyzer, but I think the question is a bit ill-phrased. By the compiler, are you taking about code generation or warnings? Right now this attribute is only consulted for the purpose of omitting warnings. In this regards the static analyzer is just a more advanced tool for issuing warnings than the compiler, so there is no reason the compiler couldn't use it for this purpose as well if the need came up. I'm not being hypothetical here; I'm just saying this was added for the sake of better warnings. For code generation, I don't think there is any optimization that can be done right now for an ivar declared unused. On Feb 25, 2010, at 9:15 AM, Fariborz Jahanian wrote: > Hi Ted, > > Is the 'unused' attribute for the benefit of static analyzer only or you are planning on using it > in the compiler as well? > > - Fariborz > > On Feb 24, 2010, at 7:26 PM, Ted Kremenek wrote: > >> Author: kremenek >> Date: Wed Feb 24 21:26:51 2010 >> New Revision: 97103 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=97103&view=rev >> Log: >> Allow __attribute__((unused)) to be applied to ObjC ivars. >> From fjahanian at apple.com Thu Feb 25 12:11:59 2010 From: fjahanian at apple.com (Fariborz Jahanian) Date: Thu, 25 Feb 2010 10:11:59 -0800 Subject: [cfe-commits] r97103 - in /cfe/trunk: lib/Sema/SemaDeclAttr.cpp test/SemaObjC/unused.m In-Reply-To: References: <20100225032651.844202A6C136@llvm.org> <227F5910-91D3-44C9-920A-0A448F875C97@apple.com> Message-ID: <80480705-6739-46FF-B2F5-370F0C53E0A6@apple.com> On Feb 25, 2010, at 10:01 AM, Ted Kremenek wrote: > Right now it is only used by the static analyzer, but I think the > question is a bit ill-phrased. > > By the compiler, are you taking about code generation or warnings? > Right now this attribute is only consulted for the purpose of > omitting warnings. In this I meant warnings. I can't see how code generation can be involved here. > regards the static analyzer is just a more advanced tool for issuing > warnings than the compiler, so there is no reason the compiler > couldn't use it for this purpose as well if the need came up. I'm > not being hypothetical here; I'm just saying this was added for the > sake of better warnings. I am not sure how static analyzer can issue warning and not having many false positives. You need whole program analysis to see all implementations (of class and its categories). Also, ivars maybe be accessed through properties. Does static analyzer consider this? - Fariborz > > > For code generation, I don't think there is any optimization that > can be done right now for an ivar declared unused. > > On Feb 25, 2010, at 9:15 AM, Fariborz Jahanian wrote: > >> Hi Ted, >> >> Is the 'unused' attribute for the benefit of static analyzer only >> or you are planning on using it >> in the compiler as well? >> >> - Fariborz >> >> On Feb 24, 2010, at 7:26 PM, Ted Kremenek wrote: >> >>> Author: kremenek >>> Date: Wed Feb 24 21:26:51 2010 >>> New Revision: 97103 >>> >>> URL: http://llvm.org/viewvc/llvm-project?rev=97103&view=rev >>> Log: >>> Allow __attribute__((unused)) to be applied to ObjC ivars. >>> > From dgregor at apple.com Thu Feb 25 12:11:54 2010 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 25 Feb 2010 18:11:54 -0000 Subject: [cfe-commits] r97152 - in /cfe/trunk: lib/Sema/SemaDeclCXX.cpp test/SemaCXX/destructor.cpp Message-ID: <20100225181154.4F49B2A6C12E@llvm.org> Author: dgregor Date: Thu Feb 25 12:11:54 2010 New Revision: 97152 URL: http://llvm.org/viewvc/llvm-project?rev=97152&view=rev Log: Don't try to finalize an ill-formed variable or one whose class type is ill-formed. Fixes PR6421 Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp cfe/trunk/test/SemaCXX/destructor.cpp Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=97152&r1=97151&r2=97152&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Feb 25 12:11:54 2010 @@ -4023,7 +4023,8 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { CXXRecordDecl *ClassDecl = cast(Record->getDecl()); - if (!ClassDecl->hasTrivialDestructor()) { + if (!ClassDecl->isInvalidDecl() && !VD->isInvalidDecl() && + !ClassDecl->hasTrivialDestructor()) { CXXDestructorDecl *Destructor = ClassDecl->getDestructor(Context); MarkDeclarationReferenced(VD->getLocation(), Destructor); CheckDestructorAccess(VD->getLocation(), Record); Modified: cfe/trunk/test/SemaCXX/destructor.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/destructor.cpp?rev=97152&r1=97151&r2=97152&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/destructor.cpp (original) +++ cfe/trunk/test/SemaCXX/destructor.cpp Thu Feb 25 12:11:54 2010 @@ -61,3 +61,20 @@ struct Y { ~X(); // expected-error {{expected the class name after '~' to name the enclosing class}} }; + +namespace PR6421 { + class T; // expected-note{{forward declaration}} + + class QGenericArgument + { + template + void foo(T t) // expected-error{{variable has incomplete type}} + { } + + void disconnect() + { + T* t; + bob(t); // expected-error{{undeclared identifier 'bob'}} + } + }; +} From kremenek at apple.com Thu Feb 25 12:21:51 2010 From: kremenek at apple.com (Ted Kremenek) Date: Thu, 25 Feb 2010 10:21:51 -0800 Subject: [cfe-commits] r97103 - in /cfe/trunk: lib/Sema/SemaDeclAttr.cpp test/SemaObjC/unused.m In-Reply-To: <80480705-6739-46FF-B2F5-370F0C53E0A6@apple.com> References: <20100225032651.844202A6C136@llvm.org> <227F5910-91D3-44C9-920A-0A448F875C97@apple.com> <80480705-6739-46FF-B2F5-370F0C53E0A6@apple.com> Message-ID: On Feb 25, 2010, at 10:11 AM, Fariborz Jahanian wrote: > > On Feb 25, 2010, at 10:01 AM, Ted Kremenek wrote: > >> Right now it is only used by the static analyzer, but I think the question is a bit ill-phrased. >> >> By the compiler, are you taking about code generation or warnings? Right now this attribute is only consulted for the purpose of omitting warnings. In this > I meant warnings. I can't see how code generation can be involved here. > >> regards the static analyzer is just a more advanced tool for issuing warnings than the compiler, so there is no reason the compiler couldn't use it for this purpose as well if the need came up. I'm not being hypothetical here; I'm just saying this was added for the sake of better warnings. > > I am not sure how static analyzer can issue warning and not having many false positives. You need whole program analysis > to see all implementations (of class and its categories). For ivars, most of the time categories are declared within the same .m file as the @implementation. It's a heuristic, but it works fairly well. Yes there are false positives, but those are acceptable in the static analyzer as long as the false positive rate is reasonable. As for whole-program analysis, we will eventually get there. > Also, ivars maybe be accessed through properties. Does > static analyzer consider this? Yes it does. This check has been around for a long time. People would have severely complained if that wasn't the case. -------------- next part -------------- An HTML attachment was scrubbed... URL: http://lists.cs.uiuc.edu/pipermail/cfe-commits/attachments/20100225/85d32453/attachment.html From fjahanian at apple.com Thu Feb 25 12:24:33 2010 From: fjahanian at apple.com (Fariborz Jahanian) Date: Thu, 25 Feb 2010 18:24:33 -0000 Subject: [cfe-commits] r97157 - in /cfe/trunk: lib/AST/ASTContext.cpp test/SemaObjC/conditional-expr-7.m Message-ID: <20100225182433.5EB4F2A6C12E@llvm.org> Author: fjahanian Date: Thu Feb 25 12:24:33 2010 New Revision: 97157 URL: http://llvm.org/viewvc/llvm-project?rev=97157&view=rev Log: Forgot to include nested protocols in collection, resulting in bogus warning. Fixes radar 7682116. Added: cfe/trunk/test/SemaObjC/conditional-expr-7.m Modified: cfe/trunk/lib/AST/ASTContext.cpp Modified: cfe/trunk/lib/AST/ASTContext.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=97157&r1=97156&r2=97157&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTContext.cpp (original) +++ cfe/trunk/lib/AST/ASTContext.cpp Thu Feb 25 12:24:33 2010 @@ -945,9 +945,11 @@ ObjCProtocolDecl *Proto = (*P); Protocols.insert(Proto); for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(), - PE = Proto->protocol_end(); P != PE; ++P) + PE = Proto->protocol_end(); P != PE; ++P) { + Protocols.insert(*P); CollectInheritedProtocols(*P, Protocols); } + } // Categories of this Interface. for (const ObjCCategoryDecl *CDeclChain = OI->getCategoryList(); Added: cfe/trunk/test/SemaObjC/conditional-expr-7.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/conditional-expr-7.m?rev=97157&view=auto ============================================================================== --- cfe/trunk/test/SemaObjC/conditional-expr-7.m (added) +++ cfe/trunk/test/SemaObjC/conditional-expr-7.m Thu Feb 25 12:24:33 2010 @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// radar 7682116 + + at interface Super @end + + at interface NSArray : Super @end + at interface NSSet : Super @end + + at protocol MyProtocol +- (void)myMethod; + at end + + at protocol MyProtocol2 +- (void)myMethod2; + at end + + at interface NSArray() + at end + + at interface NSSet() + at end + +int main (int argc, const char * argv[]) { + NSArray *array = (void*)0; + NSSet *set = (void*)0; + id instance = (argc) ? array : set; + instance = (void*)0; + return 0; +} + From dgregor at apple.com Thu Feb 25 12:25:47 2010 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 25 Feb 2010 10:25:47 -0800 Subject: [cfe-commits] [PATCH] Fix the build on Apple gcc-4.0 In-Reply-To: References: Message-ID: <448FA278-F89E-49DE-9391-5C605460BC5C@apple.com> On Feb 24, 2010, at 11:22 PM, Jeffrey Yasskin wrote: > Apple's gcc-4.0 on 10.5 was complaining that: > > /Users/jyasskin/src/llvm/clang/src/tools/clang/lib/Sema/TreeTransform.h:5784: > error: expected primary-expression before ?>? token > /Users/jyasskin/src/llvm/clang/src/tools/clang/lib/Sema/TreeTransform.h:5784: > error: expected primary-expression before ?)? token > > This patch fixes the build there without breaking the build for other > compilers or breaking the tests, so I think it's the right thing to > do. Please double-check. Gabor got to fixing this before I got around to reviewing, so we're all set again. Thanks, though. - Doug From dgregor at apple.com Thu Feb 25 12:26:59 2010 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 25 Feb 2010 10:26:59 -0800 Subject: [cfe-commits] r97138 - in /cfe/trunk: include/clang/Analysis/ProgramPoint.h include/clang/Checker/PathSensitive/Checker.h include/clang/Checker/PathSensitive/GRCoreEngine.h include/clang/Checker/PathSensitive/GRExprEngine.h include/clang/Checker/PathSensitive/GRSubEngine.h lib/Checker/CallInliner.cpp lib/Checker/GRCoreEngine.cpp lib/Checker/GRExprEngine.cpp In-Reply-To: <20100225154753.E5F8B2A6C12C@llvm.org> References: <20100225154753.E5F8B2A6C12C@llvm.org> Message-ID: On Feb 25, 2010, at 7:47 AM, Jakob Stoklund Olesen wrote: > Author: stoklund > Date: Thu Feb 25 09:47:53 2010 > New Revision: 97138 > > URL: http://llvm.org/viewvc/llvm-project?rev=97138&view=rev > Log: > Revert patches r97122 r97127 r97129 r97131. > They were breaking clang-x86_64-darwin10-selfhost I'm looking into this right now. It looks like a Clang bug. - Doug From dgregor at apple.com Thu Feb 25 13:01:05 2010 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 25 Feb 2010 19:01:05 -0000 Subject: [cfe-commits] r97161 - in /cfe/trunk: lib/Sema/SemaOverload.cpp test/SemaCXX/overload-call.cpp Message-ID: <20100225190105.438A12A6C12C@llvm.org> Author: dgregor Date: Thu Feb 25 13:01:05 2010 New Revision: 97161 URL: http://llvm.org/viewvc/llvm-project?rev=97161&view=rev Log: Allow us to compare derived-to-base conversions between a reference binding and a copy-construction. Fixes an overloading problem in the Clang-on-Clang build. Modified: cfe/trunk/lib/Sema/SemaOverload.cpp cfe/trunk/test/SemaCXX/overload-call.cpp Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=97161&r1=97160&r2=97161&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Thu Feb 25 13:01:05 2010 @@ -2094,32 +2094,6 @@ } } - // Compare based on reference bindings. - if (SCS1.ReferenceBinding && SCS2.ReferenceBinding && - SCS1.Second == ICK_Derived_To_Base) { - // -- binding of an expression of type C to a reference of type - // B& is better than binding an expression of type C to a - // reference of type A&, - if (Context.hasSameUnqualifiedType(FromType1, FromType2) && - !Context.hasSameUnqualifiedType(ToType1, ToType2)) { - if (IsDerivedFrom(ToType1, ToType2)) - return ImplicitConversionSequence::Better; - else if (IsDerivedFrom(ToType2, ToType1)) - return ImplicitConversionSequence::Worse; - } - - // -- binding of an expression of type B to a reference of type - // A& is better than binding an expression of type C to a - // reference of type A&, - if (!Context.hasSameUnqualifiedType(FromType1, FromType2) && - Context.hasSameUnqualifiedType(ToType1, ToType2)) { - if (IsDerivedFrom(FromType2, FromType1)) - return ImplicitConversionSequence::Better; - else if (IsDerivedFrom(FromType1, FromType2)) - return ImplicitConversionSequence::Worse; - } - } - // Ranking of member-pointer types. if (SCS1.Second == ICK_Pointer_Member && SCS2.Second == ICK_Pointer_Member && FromType1->isMemberPointerType() && FromType2->isMemberPointerType() && @@ -2156,9 +2130,13 @@ } } - if (SCS1.CopyConstructor && SCS2.CopyConstructor && + if ((SCS1.ReferenceBinding || SCS1.CopyConstructor) && + (SCS2.ReferenceBinding || SCS2.CopyConstructor) && SCS1.Second == ICK_Derived_To_Base) { // -- conversion of C to B is better than conversion of C to A, + // -- binding of an expression of type C to a reference of type + // B& is better than binding an expression of type C to a + // reference of type A&, if (Context.hasSameUnqualifiedType(FromType1, FromType2) && !Context.hasSameUnqualifiedType(ToType1, ToType2)) { if (IsDerivedFrom(ToType1, ToType2)) @@ -2168,6 +2146,9 @@ } // -- conversion of B to A is better than conversion of C to A. + // -- binding of an expression of type B to a reference of type + // A& is better than binding an expression of type C to a + // reference of type A&, if (!Context.hasSameUnqualifiedType(FromType1, FromType2) && Context.hasSameUnqualifiedType(ToType1, ToType2)) { if (IsDerivedFrom(FromType2, FromType1)) Modified: cfe/trunk/test/SemaCXX/overload-call.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overload-call.cpp?rev=97161&r1=97160&r2=97161&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/overload-call.cpp (original) +++ cfe/trunk/test/SemaCXX/overload-call.cpp Thu Feb 25 13:01:05 2010 @@ -373,3 +373,16 @@ } }; } + +namespace DerivedToBase { + struct A { }; + struct B : A { }; + struct C : B { }; + + int &f0(const A&); + float &f0(B); + + void g() { + float &fr = f0(C()); + } +} From dgregor at apple.com Thu Feb 25 13:01:53 2010 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 25 Feb 2010 19:01:53 -0000 Subject: [cfe-commits] r97162 - in /cfe/trunk: include/clang/Analysis/ include/clang/Analysis/Support/ include/clang/Checker/PathSensitive/ include/clang/Frontend/ lib/Checker/ lib/Frontend/ lib/Sema/ test/Sema/ test/SemaCXX/ test/SemaObjCXX/ test/SemaTemplate/ tools/scan-build/ utils/analyzer/ Message-ID: <20100225190154.0E5FC2A6C12C@llvm.org> Author: dgregor Date: Thu Feb 25 13:01:53 2010 New Revision: 97162 URL: http://llvm.org/viewvc/llvm-project?rev=97162&view=rev Log: Restore Zhongxing's commits r97122 r97127 r97129 r97131 which were reverted due to a Clang-on-Clang failure Modified: cfe/trunk/include/clang/Analysis/ProgramPoint.h cfe/trunk/include/clang/Analysis/Support/BlkExprDeclBitVector.h (props changed) cfe/trunk/include/clang/Checker/PathSensitive/Checker.h cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h cfe/trunk/include/clang/Checker/PathSensitive/GRState.h (props changed) cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h cfe/trunk/include/clang/Frontend/ASTConsumers.h (props changed) cfe/trunk/include/clang/Frontend/Analyses.def (props changed) cfe/trunk/include/clang/Frontend/AnalysisConsumer.h (props changed) cfe/trunk/include/clang/Frontend/PathDiagnosticClients.h (props changed) cfe/trunk/include/clang/Frontend/Utils.h (props changed) cfe/trunk/lib/Checker/CallInliner.cpp cfe/trunk/lib/Checker/GRCoreEngine.cpp cfe/trunk/lib/Checker/GRExprEngine.cpp cfe/trunk/lib/Checker/GRState.cpp (props changed) cfe/trunk/lib/Frontend/ASTConsumers.cpp (props changed) cfe/trunk/lib/Frontend/AnalysisConsumer.cpp (props changed) cfe/trunk/lib/Frontend/CacheTokens.cpp (props changed) cfe/trunk/lib/Frontend/CodeGenAction.cpp (props changed) cfe/trunk/lib/Frontend/DependencyFile.cpp (props changed) cfe/trunk/lib/Frontend/DiagChecker.cpp (props changed) cfe/trunk/lib/Frontend/GeneratePCH.cpp (props changed) cfe/trunk/lib/Frontend/HTMLPrint.cpp (props changed) cfe/trunk/lib/Frontend/PrintParserCallbacks.cpp (props changed) cfe/trunk/lib/Frontend/PrintPreprocessedOutput.cpp (props changed) cfe/trunk/lib/Frontend/RewriteMacros.cpp (props changed) cfe/trunk/lib/Frontend/RewriteObjC.cpp (props changed) cfe/trunk/lib/Frontend/RewriteTest.cpp (props changed) cfe/trunk/lib/Frontend/Warnings.cpp (props changed) cfe/trunk/lib/Sema/SemaCXXCast.cpp (props changed) cfe/trunk/test/Sema/dllimport-dllexport.c (props changed) cfe/trunk/test/SemaCXX/ambig-user-defined-conversions.cpp (props changed) cfe/trunk/test/SemaObjCXX/protocol-lookup.mm (props changed) cfe/trunk/test/SemaTemplate/typename-specifier-3.cpp (props changed) cfe/trunk/tools/scan-build/ccc-analyzer (props changed) cfe/trunk/tools/scan-build/scan-build (props changed) cfe/trunk/tools/scan-build/scanview.css (props changed) cfe/trunk/tools/scan-build/sorttable.js (props changed) cfe/trunk/utils/analyzer/ubiviz (props changed) Modified: cfe/trunk/include/clang/Analysis/ProgramPoint.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/ProgramPoint.h?rev=97162&r1=97161&r2=97162&view=diff ============================================================================== --- cfe/trunk/include/clang/Analysis/ProgramPoint.h (original) +++ cfe/trunk/include/clang/Analysis/ProgramPoint.h Thu Feb 25 13:01:53 2010 @@ -26,6 +26,7 @@ namespace clang { class LocationContext; +class FunctionDecl; class ProgramPoint { public: @@ -41,6 +42,8 @@ PostPurgeDeadSymbolsKind, PostStmtCustomKind, PostLValueKind, + CallEnterKind, + CallExitKind, MinPostStmtKind = PostStmtKind, MaxPostStmtKind = PostLValueKind }; @@ -308,6 +311,36 @@ } }; +class CallEnter : public StmtPoint { +public: + // CallEnter uses the caller's location context. + CallEnter(const Stmt *S, const FunctionDecl *fd, const LocationContext *L) + : StmtPoint(S, fd, CallEnterKind, L, 0) {} + + const Stmt *getCallExpr() const { + return static_cast(getData1()); + } + + const FunctionDecl *getCallee() const { + return static_cast(getData2()); + } + + static bool classof(const ProgramPoint *Location) { + return Location->getKind() == CallEnterKind; + } +}; + +class CallExit : public StmtPoint { +public: + // CallExit uses the callee's location context. + CallExit(const Stmt *S, const LocationContext *L) + : StmtPoint(S, 0, CallExitKind, L, 0) {} + + static bool classof(const ProgramPoint *Location) { + return Location->getKind() == CallExitKind; + } +}; + } // end namespace clang Propchange: cfe/trunk/include/clang/Analysis/Support/BlkExprDeclBitVector.h ------------------------------------------------------------------------------ (empty) Modified: cfe/trunk/include/clang/Checker/PathSensitive/Checker.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/Checker.h?rev=97162&r1=97161&r2=97162&view=diff ============================================================================== --- cfe/trunk/include/clang/Checker/PathSensitive/Checker.h (original) +++ cfe/trunk/include/clang/Checker/PathSensitive/Checker.h Thu Feb 25 13:01:53 2010 @@ -155,6 +155,14 @@ Dst.Add(Pred); } + // Generate a node with a new program point different from the one that will + // be created by the GRStmtNodeBuilder. + void addTransition(const GRState *state, ProgramPoint Loc) { + ExplodedNode *N = B.generateNode(Loc, state, Pred); + if (N) + addTransition(N); + } + void EmitReport(BugReport *R) { Eng.getBugReporter().EmitReport(R); } Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h?rev=97162&r1=97161&r2=97162&view=diff ============================================================================== --- cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h (original) +++ cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h Thu Feb 25 13:01:53 2010 @@ -40,6 +40,8 @@ friend class GRIndirectGotoNodeBuilder; friend class GRSwitchNodeBuilder; friend class GREndPathNodeBuilder; + friend class GRCallEnterNodeBuilder; + friend class GRCallExitNodeBuilder; GRSubEngine& SubEngine; @@ -67,6 +69,9 @@ void HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock* B, ExplodedNode* Pred); + void HandleCallEnter(const CallEnter &L, const CFGBlock *Block, + unsigned Index, ExplodedNode *Pred); + void HandleCallExit(const CallExit &L, ExplodedNode *Pred); /// Get the initial state from the subengine. const GRState* getInitialState(const LocationContext *InitLoc) { @@ -90,6 +95,9 @@ void ProcessSwitch(GRSwitchNodeBuilder& Builder); + void ProcessCallEnter(GRCallEnterNodeBuilder &Builder); + void ProcessCallExit(GRCallExitNodeBuilder &Builder); + private: GRCoreEngine(const GRCoreEngine&); // Do not implement. GRCoreEngine& operator=(const GRCoreEngine&); @@ -194,6 +202,12 @@ return generateNode(S, St, Pred, PointKind); } + ExplodedNode *generateNode(const ProgramPoint &PP, const GRState* State, + ExplodedNode* Pred) { + HasGeneratedNode = true; + return generateNodeInternal(PP, State, Pred); + } + ExplodedNode* generateNodeInternal(const ProgramPoint &PP, const GRState* State, ExplodedNode* Pred); @@ -431,6 +445,8 @@ ExplodedNode* generateNode(const GRState* State, const void *tag = 0, ExplodedNode *P = 0); + void GenerateCallExitNode(const GRState *state); + CFGBlock* getBlock() const { return &B; } const GRState* getState() const { @@ -438,6 +454,60 @@ } }; +class GRCallEnterNodeBuilder { + GRCoreEngine &Eng; + + const ExplodedNode *Pred; + + // The call site. + const Stmt *CE; + + // The definition of callee. + const FunctionDecl *FD; + + // The parent block of the CallExpr. + const CFGBlock *Block; + + // The CFGBlock index of the CallExpr. + unsigned Index; + +public: + GRCallEnterNodeBuilder(GRCoreEngine &eng, const ExplodedNode *pred, + const Stmt *s, const FunctionDecl *fd, + const CFGBlock *blk, unsigned idx) + : Eng(eng), Pred(pred), CE(s), FD(fd), Block(blk), Index(idx) {} + + const GRState *getState() const { return Pred->getState(); } + + const LocationContext *getLocationContext() const { + return Pred->getLocationContext(); + } + + const Stmt *getCallExpr() const { return CE; } + + const FunctionDecl *getCallee() const { return FD; } + + const CFGBlock *getBlock() const { return Block; } + + unsigned getIndex() const { return Index; } + + void GenerateNode(const GRState *state, const LocationContext *LocCtx); +}; + +class GRCallExitNodeBuilder { + GRCoreEngine &Eng; + const ExplodedNode *Pred; + +public: + GRCallExitNodeBuilder(GRCoreEngine &eng, const ExplodedNode *pred) + : Eng(eng), Pred(pred) {} + + const ExplodedNode *getPredecessor() const { return Pred; } + + const GRState *getState() const { return Pred->getState(); } + + void GenerateNode(const GRState *state); +}; } // end clang namespace #endif Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h?rev=97162&r1=97161&r2=97162&view=diff ============================================================================== --- cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h (original) +++ cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h Thu Feb 25 13:01:53 2010 @@ -171,7 +171,13 @@ /// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path /// nodes when the control reaches the end of a function. void ProcessEndPath(GREndPathNodeBuilder& builder); - + + // Generate the entry node of the callee. + void ProcessCallEnter(GRCallEnterNodeBuilder &builder); + + // Generate the first post callsite node. + void ProcessCallExit(GRCallExitNodeBuilder &builder); + /// EvalAssume - Callback function invoked by the ConstraintManager when /// making assumptions about state values. const GRState *ProcessAssume(const GRState *state, SVal cond, bool assumption); Propchange: cfe/trunk/include/clang/Checker/PathSensitive/GRState.h ------------------------------------------------------------------------------ (empty) Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h?rev=97162&r1=97161&r2=97162&view=diff ============================================================================== --- cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h (original) +++ cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h Thu Feb 25 13:01:53 2010 @@ -28,6 +28,8 @@ class GRIndirectGotoNodeBuilder; class GRSwitchNodeBuilder; class GREndPathNodeBuilder; +class GRCallEnterNodeBuilder; +class GRCallExitNodeBuilder; class LocationContext; class GRSubEngine { @@ -64,6 +66,12 @@ /// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path /// nodes when the control reaches the end of a function. virtual void ProcessEndPath(GREndPathNodeBuilder& builder) = 0; + + // Generate the entry node of the callee. + virtual void ProcessCallEnter(GRCallEnterNodeBuilder &builder) = 0; + + // Generate the first post callsite node. + virtual void ProcessCallExit(GRCallExitNodeBuilder &builder) = 0; /// EvalAssume - Called by ConstraintManager. Used to call checker-specific /// logic for handling assumptions on symbolic values. Propchange: cfe/trunk/include/clang/Frontend/ASTConsumers.h ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/include/clang/Frontend/Analyses.def ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/include/clang/Frontend/AnalysisConsumer.h ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/include/clang/Frontend/PathDiagnosticClients.h ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/include/clang/Frontend/Utils.h ------------------------------------------------------------------------------ (empty) Modified: cfe/trunk/lib/Checker/CallInliner.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/CallInliner.cpp?rev=97162&r1=97161&r2=97162&view=diff ============================================================================== --- cfe/trunk/lib/Checker/CallInliner.cpp (original) +++ cfe/trunk/lib/Checker/CallInliner.cpp Thu Feb 25 13:01:53 2010 @@ -26,7 +26,6 @@ } virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE); - virtual void EvalEndPath(GREndPathNodeBuilder &B,void *tag,GRExprEngine &Eng); }; } @@ -46,79 +45,10 @@ if (!FD->isThisDeclarationADefinition()) return false; - GRStmtNodeBuilder &Builder = C.getNodeBuilder(); - // Make a new LocationContext. - const StackFrameContext *LocCtx = C.getAnalysisManager().getStackFrame(FD, - C.getPredecessor()->getLocationContext(), CE, - Builder.getBlock(), Builder.getIndex()); - - CFGBlock const *Entry = &(LocCtx->getCFG()->getEntry()); - - assert (Entry->empty() && "Entry block must be empty."); - - assert (Entry->succ_size() == 1 && "Entry block must have 1 successor."); - - // Get the solitary successor. - CFGBlock const *SuccB = *(Entry->succ_begin()); - - // Construct an edge representing the starting location in the function. - BlockEdge Loc(Entry, SuccB, LocCtx); - - state = C.getStoreManager().EnterStackFrame(state, LocCtx); - - // This is a hack. We really should not use the GRStmtNodeBuilder. - bool isNew; - GRExprEngine &Eng = C.getEngine(); - ExplodedNode *Pred = C.getPredecessor(); - - - ExplodedNode *SuccN = Eng.getGraph().getNode(Loc, state, &isNew); - SuccN->addPredecessor(Pred, Eng.getGraph()); - C.getNodeBuilder().Deferred.erase(Pred); - - if (isNew) - Builder.getWorkList()->Enqueue(SuccN); - - Builder.HasGeneratedNode = true; + // Now we have the definition of the callee, create a CallEnter node. + CallEnter Loc(CE, FD, C.getPredecessor()->getLocationContext()); + C.addTransition(state, Loc); return true; } -void CallInliner::EvalEndPath(GREndPathNodeBuilder &B, void *tag, - GRExprEngine &Eng) { - const GRState *state = B.getState(); - - ExplodedNode *Pred = B.getPredecessor(); - - const StackFrameContext *LocCtx = - cast(Pred->getLocationContext()); - // Check if this is the top level stack frame. - if (!LocCtx->getParent()) - return; - - const StackFrameContext *ParentSF = - cast(LocCtx->getParent()); - - SymbolReaper SymReaper(*ParentSF->getLiveVariables(), Eng.getSymbolManager(), - ParentSF); - const Stmt *CE = LocCtx->getCallSite(); - - state = Eng.getStateManager().RemoveDeadBindings(state, const_cast(CE), - SymReaper); - - - PostStmt NodeLoc(CE, LocCtx->getParent()); - - bool isNew; - ExplodedNode *Succ = Eng.getGraph().getNode(NodeLoc, state, &isNew); - Succ->addPredecessor(Pred, Eng.getGraph()); - - // When creating the new work list unit, increment the statement index to - // point to the statement after the CallExpr. - if (isNew) - B.getWorkList().Enqueue(Succ, - *const_cast(LocCtx->getCallSiteBlock()), - LocCtx->getIndex() + 1); - - B.HasGeneratedNode = true; -} Modified: cfe/trunk/lib/Checker/GRCoreEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRCoreEngine.cpp?rev=97162&r1=97161&r2=97162&view=diff ============================================================================== --- cfe/trunk/lib/Checker/GRCoreEngine.cpp (original) +++ cfe/trunk/lib/Checker/GRCoreEngine.cpp Thu Feb 25 13:01:53 2010 @@ -144,6 +144,14 @@ SubEngine.ProcessSwitch(Builder); } +void GRCoreEngine::ProcessCallEnter(GRCallEnterNodeBuilder &Builder) { + SubEngine.ProcessCallEnter(Builder); +} + +void GRCoreEngine::ProcessCallExit(GRCallExitNodeBuilder &Builder) { + SubEngine.ProcessCallExit(Builder); +} + /// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps. bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) { @@ -196,6 +204,15 @@ assert (false && "BlockExit location never occur in forward analysis."); break; + case ProgramPoint::CallEnterKind: + HandleCallEnter(cast(Node->getLocation()), WU.getBlock(), + WU.getIndex(), Node); + break; + + case ProgramPoint::CallExitKind: + HandleCallExit(cast(Node->getLocation()), Node); + break; + default: assert(isa(Node->getLocation())); HandlePostStmt(cast(Node->getLocation()), WU.getBlock(), @@ -207,6 +224,17 @@ return WList->hasWork(); } +void GRCoreEngine::HandleCallEnter(const CallEnter &L, const CFGBlock *Block, + unsigned Index, ExplodedNode *Pred) { + GRCallEnterNodeBuilder Builder(*this, Pred, L.getCallExpr(), L.getCallee(), + Block, Index); + ProcessCallEnter(Builder); +} + +void GRCoreEngine::HandleCallExit(const CallExit &L, ExplodedNode *Pred) { + GRCallExitNodeBuilder Builder(*this, Pred); + ProcessCallExit(Builder); +} void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) { @@ -400,6 +428,14 @@ void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) { assert (!N->isSink()); + // Check if this node entered a callee. + if (isa(N->getLocation())) { + // Still use the index of the CallExpr. It's needed to create the callee + // StackFrameContext. + Eng.WList->Enqueue(N, B, Idx); + return; + } + PostStmt Loc(getStmt(), N->getLocationContext()); if (Loc == N->getLocation()) { @@ -576,7 +612,13 @@ GREndPathNodeBuilder::~GREndPathNodeBuilder() { // Auto-generate an EOP node if one has not been generated. - if (!HasGeneratedNode) generateNode(Pred->State); + if (!HasGeneratedNode) { + // If we are in an inlined call, generate CallExit node. + if (Pred->getLocationContext()->getParent()) + GenerateCallExitNode(Pred->State); + else + generateNode(Pred->State); + } } ExplodedNode* @@ -597,3 +639,57 @@ return NULL; } + +void GREndPathNodeBuilder::GenerateCallExitNode(const GRState *state) { + HasGeneratedNode = true; + // Create a CallExit node and enqueue it. + const StackFrameContext *LocCtx + = cast(Pred->getLocationContext()); + const Stmt *CE = LocCtx->getCallSite(); + + // Use the the callee location context. + CallExit Loc(CE, LocCtx); + + bool isNew; + ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); + Node->addPredecessor(Pred, *Eng.G); + + if (isNew) + Eng.WList->Enqueue(Node); +} + + +void GRCallEnterNodeBuilder::GenerateNode(const GRState *state, + const LocationContext *LocCtx) { + // Get the callee entry block. + const CFGBlock *Entry = &(LocCtx->getCFG()->getEntry()); + assert(Entry->empty()); + assert(Entry->succ_size() == 1); + + // Get the solitary successor. + const CFGBlock *SuccB = *(Entry->succ_begin()); + + // Construct an edge representing the starting location in the callee. + BlockEdge Loc(Entry, SuccB, LocCtx); + + bool isNew; + ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); + Node->addPredecessor(const_cast(Pred), *Eng.G); + + if (isNew) + Eng.WList->Enqueue(Node); +} + +void GRCallExitNodeBuilder::GenerateNode(const GRState *state) { + // Get the callee's location context. + const StackFrameContext *LocCtx + = cast(Pred->getLocationContext()); + + PostStmt Loc(LocCtx->getCallSite(), LocCtx->getParent()); + bool isNew; + ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); + Node->addPredecessor(const_cast(Pred), *Eng.G); + if (isNew) + Eng.WList->Enqueue(Node, *const_cast(LocCtx->getCallSiteBlock()), + LocCtx->getIndex() + 1); +} Modified: cfe/trunk/lib/Checker/GRExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRExprEngine.cpp?rev=97162&r1=97161&r2=97162&view=diff ============================================================================== --- cfe/trunk/lib/Checker/GRExprEngine.cpp (original) +++ cfe/trunk/lib/Checker/GRExprEngine.cpp Thu Feb 25 13:01:53 2010 @@ -1290,6 +1290,38 @@ if (defaultIsFeasible) builder.generateDefaultCaseNode(DefaultSt); } +void GRExprEngine::ProcessCallEnter(GRCallEnterNodeBuilder &B) { + const FunctionDecl *FD = B.getCallee(); + const StackFrameContext *LocCtx = AMgr.getStackFrame(FD, + B.getLocationContext(), + B.getCallExpr(), + B.getBlock(), + B.getIndex()); + + const GRState *state = B.getState(); + state = getStoreManager().EnterStackFrame(state, LocCtx); + + B.GenerateNode(state, LocCtx); +} + +void GRExprEngine::ProcessCallExit(GRCallExitNodeBuilder &B) { + const GRState *state = B.getState(); + const ExplodedNode *Pred = B.getPredecessor(); + const StackFrameContext *LocCtx = + cast(Pred->getLocationContext()); + const StackFrameContext *ParentSF = + cast(LocCtx->getParent()); + + SymbolReaper SymReaper(*ParentSF->getLiveVariables(), getSymbolManager(), + ParentSF); + const Stmt *CE = LocCtx->getCallSite(); + + state = getStateManager().RemoveDeadBindings(state, const_cast(CE), + SymReaper); + + B.GenerateNode(state); +} + //===----------------------------------------------------------------------===// // Transfer functions: logical operations ('&&', '||'). //===----------------------------------------------------------------------===// @@ -3141,6 +3173,14 @@ assert (false); break; + case ProgramPoint::CallEnterKind: + Out << "CallEnter"; + break; + + case ProgramPoint::CallExitKind: + Out << "CallExit"; + break; + default: { if (StmtPoint *L = dyn_cast(&Loc)) { const Stmt* S = L->getStmt(); Propchange: cfe/trunk/lib/Checker/GRState.cpp ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/lib/Frontend/ASTConsumers.cpp ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/lib/Frontend/AnalysisConsumer.cpp ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/lib/Frontend/CacheTokens.cpp ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/lib/Frontend/CodeGenAction.cpp ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/lib/Frontend/DependencyFile.cpp ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/lib/Frontend/DiagChecker.cpp ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/lib/Frontend/GeneratePCH.cpp ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/lib/Frontend/HTMLPrint.cpp ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/lib/Frontend/PrintParserCallbacks.cpp ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/lib/Frontend/PrintPreprocessedOutput.cpp ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/lib/Frontend/RewriteMacros.cpp ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/lib/Frontend/RewriteObjC.cpp ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/lib/Frontend/RewriteTest.cpp ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/lib/Frontend/Warnings.cpp ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/lib/Sema/SemaCXXCast.cpp ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/test/Sema/dllimport-dllexport.c ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/test/SemaCXX/ambig-user-defined-conversions.cpp ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/test/SemaObjCXX/protocol-lookup.mm ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/test/SemaTemplate/typename-specifier-3.cpp ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/tools/scan-build/ccc-analyzer ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/tools/scan-build/scan-build ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/tools/scan-build/scanview.css ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/tools/scan-build/sorttable.js ------------------------------------------------------------------------------ (empty) Propchange: cfe/trunk/utils/analyzer/ubiviz ------------------------------------------------------------------------------ (empty) From daniel at zuster.org Thu Feb 25 14:37:44 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Thu, 25 Feb 2010 20:37:44 -0000 Subject: [cfe-commits] r97166 - in /cfe/trunk: include/clang/Frontend/CodeGenAction.h lib/Frontend/CodeGenAction.cpp Message-ID: <20100225203744.E16BD2A6C12C@llvm.org> Author: ddunbar Date: Thu Feb 25 14:37:44 2010 New Revision: 97166 URL: http://llvm.org/viewvc/llvm-project?rev=97166&view=rev Log: Move ~CodeGenAction out-of-line. Modified: cfe/trunk/include/clang/Frontend/CodeGenAction.h cfe/trunk/lib/Frontend/CodeGenAction.cpp Modified: cfe/trunk/include/clang/Frontend/CodeGenAction.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CodeGenAction.h?rev=97166&r1=97165&r2=97166&view=diff ============================================================================== --- cfe/trunk/include/clang/Frontend/CodeGenAction.h (original) +++ cfe/trunk/include/clang/Frontend/CodeGenAction.h Thu Feb 25 14:37:44 2010 @@ -23,6 +23,7 @@ protected: CodeGenAction(unsigned _Act); + ~CodeGenAction(); virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile); Modified: cfe/trunk/lib/Frontend/CodeGenAction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CodeGenAction.cpp?rev=97166&r1=97165&r2=97166&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/CodeGenAction.cpp (original) +++ cfe/trunk/lib/Frontend/CodeGenAction.cpp Thu Feb 25 14:37:44 2010 @@ -435,6 +435,8 @@ CodeGenAction::CodeGenAction(unsigned _Act) : Act(_Act) {} +CodeGenAction::~CodeGenAction() {} + void CodeGenAction::EndSourceFileAction() { // If the consumer creation failed, do nothing. if (!getCompilerInstance().hasASTConsumer()) From daniel at zuster.org Thu Feb 25 14:39:12 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Thu, 25 Feb 2010 12:39:12 -0800 Subject: [cfe-commits] r97110 - in /cfe/trunk: include/clang/Frontend/ASTConsumers.h include/clang/Frontend/CodeGenAction.h include/clang/Frontend/FrontendActions.h lib/Frontend/Backend.cpp lib/Frontend/CodeGenAction.cpp lib/Frontend/FrontendActions.cpp t Message-ID: <6a8523d61002251239l2769ff28h300b569dfddef290@mail.gmail.com> Should be fixed in r97166, thanks. - Daniel On Wed, Feb 24, 2010 at 8:53 PM, Douglas Gregor wrote: > > On Feb 24, 2010, at 8:37 PM, Daniel Dunbar wrote: > >> Author: ddunbar >> Date: Wed Feb 24 22:37:45 2010 >> New Revision: 97110 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=97110&view=rev >> Log: >> Frontend: Pull CodeGenAction out more, and eliminate CreateBackendConsumer. >> >> This is the way I would like to move the frontend function towards -- distinct >> pieces of functionality should be exposed only via FrontendAction >> implementations which have clean and relatively-stable APIs. >> >> This also isolates the surface area in clang which depends on LLVM CodeGen. > > FYI, I'm seeing: > > /Users/dgregor/Projects/llvm/include/llvm/ADT/OwningPtr.h:35:5: warning: > ? ? ?deleting pointer to incomplete type 'class llvm::Module' may cause > ? ? ?undefined behaviour > ? ?delete Ptr; > ? ?^ ? ? ?~~~ > In file included from /Users/dgregor/Projects/llvm/tools/clang/tools/driver/cc1_main.cpp:22: > /Users/dgregor/Projects/llvm/tools/clang/include/clang/Frontend/CodeGenAction.h:61:1: note: > ? ? ?in instantiation of member function 'llvm::OwningPtr ? ? ?llvm::Module>::~OwningPtr' requested here > }; > ^ > /Users/dgregor/Projects/llvm/tools/clang/include/clang/Frontend/CodeGenAction.h:14:9: note: > ? ? ?forward declaration of 'class llvm::Module' > ?class Module; > ? ? ? ?^ > > That looks like it's coming from the synthesized destructor for EmitObjAction, and I think it's legitimate. > > ? ? ? ?- Doug > >> >> Added: >> ? ?cfe/trunk/include/clang/Frontend/CodeGenAction.h >> ? ?cfe/trunk/lib/Frontend/CodeGenAction.cpp >> ? ? ?- copied, changed from r97109, cfe/trunk/lib/Frontend/Backend.cpp >> Removed: >> ? ?cfe/trunk/lib/Frontend/Backend.cpp >> Modified: >> ? ?cfe/trunk/include/clang/Frontend/ASTConsumers.h >> ? ?cfe/trunk/include/clang/Frontend/FrontendActions.h >> ? ?cfe/trunk/lib/Frontend/FrontendActions.cpp >> ? ?cfe/trunk/tools/driver/cc1_main.cpp >> >> Modified: cfe/trunk/include/clang/Frontend/ASTConsumers.h >> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/ASTConsumers.h?rev=97110&r1=97109&r2=97110&view=diff >> ============================================================================== >> --- cfe/trunk/include/clang/Frontend/ASTConsumers.h (original) >> +++ cfe/trunk/include/clang/Frontend/ASTConsumers.h Wed Feb 24 22:37:45 2010 >> @@ -69,26 +69,6 @@ >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const LangOptions &LOpts, >> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? bool SilenceRewriteMacroWarning); >> >> -// LLVM code generator: uses the code generation backend to generate LLVM >> -// assembly. This runs optimizations depending on the CodeGenOptions >> -// parameter. The output depends on the Action parameter. >> -enum BackendAction { >> - ?Backend_EmitAssembly, ?// Emit native assembly files >> - ?Backend_EmitBC, ? ? ? ?// Emit LLVM bitcode files >> - ?Backend_EmitLL, ? ? ? ?// Emit human-readable LLVM assembly >> - ?Backend_EmitNothing, ? // Don't emit anything (benchmarking mode) >> - ?Backend_EmitObj ? ? ? ?// Emit native object files >> -}; >> -ASTConsumer *CreateBackendConsumer(BackendAction Action, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Diagnostic &Diags, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const LangOptions &Features, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const CodeGenOptions &CodeGenOpts, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const TargetOptions &TargetOpts, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? bool TimePasses, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const std::string &ModuleID, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? llvm::raw_ostream *OS, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? llvm::LLVMContext& C); >> - >> /// CreateHTMLPrinter - Create an AST consumer which rewrites source code to >> /// HTML with syntax highlighting suitable for viewing in a web-browser. >> ASTConsumer *CreateHTMLPrinter(llvm::raw_ostream *OS, Preprocessor &PP, >> >> Added: cfe/trunk/include/clang/Frontend/CodeGenAction.h >> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CodeGenAction.h?rev=97110&view=auto >> ============================================================================== >> --- cfe/trunk/include/clang/Frontend/CodeGenAction.h (added) >> +++ cfe/trunk/include/clang/Frontend/CodeGenAction.h Wed Feb 24 22:37:45 2010 >> @@ -0,0 +1,50 @@ >> +//===--- CodeGenAction.h - LLVM Code Generation Frontend Action -*- C++ -*-===// >> +// >> +// ? ? ? ? ? ? ? ? ? ? The LLVM Compiler Infrastructure >> +// >> +// This file is distributed under the University of Illinois Open Source >> +// License. See LICENSE.TXT for details. >> +// >> +//===----------------------------------------------------------------------===// >> + >> +#include "clang/Frontend/FrontendAction.h" >> + >> +namespace clang { >> + >> +class CodeGenAction : public ASTFrontendAction { >> +private: >> + ?unsigned Act; >> + >> +protected: >> + ?CodeGenAction(unsigned _Act); >> + >> + ?virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? llvm::StringRef InFile); >> +}; >> + >> +class EmitAssemblyAction : public CodeGenAction { >> +public: >> + ?EmitAssemblyAction(); >> +}; >> + >> +class EmitBCAction : public CodeGenAction { >> +public: >> + ?EmitBCAction(); >> +}; >> + >> +class EmitLLVMAction : public CodeGenAction { >> +public: >> + ?EmitLLVMAction(); >> +}; >> + >> +class EmitLLVMOnlyAction : public CodeGenAction { >> +public: >> + ?EmitLLVMOnlyAction(); >> +}; >> + >> +class EmitObjAction : public CodeGenAction { >> +public: >> + ?EmitObjAction(); >> +}; >> + >> +} >> >> Modified: cfe/trunk/include/clang/Frontend/FrontendActions.h >> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendActions.h?rev=97110&r1=97109&r2=97110&view=diff >> ============================================================================== >> --- cfe/trunk/include/clang/Frontend/FrontendActions.h (original) >> +++ cfe/trunk/include/clang/Frontend/FrontendActions.h Wed Feb 24 22:37:45 2010 >> @@ -159,46 +159,6 @@ >> }; >> >> //===----------------------------------------------------------------------===// >> -// Code Gen AST Actions >> -//===----------------------------------------------------------------------===// >> - >> -class CodeGenAction : public ASTFrontendAction { >> -private: >> - ?unsigned Act; >> - >> -protected: >> - ?CodeGenAction(unsigned _Act); >> - >> - ?virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? llvm::StringRef InFile); >> -}; >> - >> -class EmitAssemblyAction : public CodeGenAction { >> -public: >> - ?EmitAssemblyAction(); >> -}; >> - >> -class EmitBCAction : public CodeGenAction { >> -public: >> - ?EmitBCAction(); >> -}; >> - >> -class EmitLLVMAction : public CodeGenAction { >> -public: >> - ?EmitLLVMAction(); >> -}; >> - >> -class EmitLLVMOnlyAction : public CodeGenAction { >> -public: >> - ?EmitLLVMOnlyAction(); >> -}; >> - >> -class EmitObjAction : public CodeGenAction { >> -public: >> - ?EmitObjAction(); >> -}; >> - >> -//===----------------------------------------------------------------------===// >> // Preprocessor Actions >> //===----------------------------------------------------------------------===// >> >> >> Removed: cfe/trunk/lib/Frontend/Backend.cpp >> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/Backend.cpp?rev=97109&view=auto >> ============================================================================== >> --- cfe/trunk/lib/Frontend/Backend.cpp (original) >> +++ cfe/trunk/lib/Frontend/Backend.cpp (removed) >> @@ -1,433 +0,0 @@ >> -//===--- Backend.cpp - Interface to LLVM backend technologies -------------===// >> -// >> -// ? ? ? ? ? ? ? ? ? ? The LLVM Compiler Infrastructure >> -// >> -// This file is distributed under the University of Illinois Open Source >> -// License. See LICENSE.TXT for details. >> -// >> -//===----------------------------------------------------------------------===// >> - >> -#include "clang/Frontend/ASTConsumers.h" >> -#include "clang/AST/ASTConsumer.h" >> -#include "clang/AST/ASTContext.h" >> -#include "clang/AST/DeclGroup.h" >> -#include "clang/Basic/TargetInfo.h" >> -#include "clang/Basic/TargetOptions.h" >> -#include "clang/CodeGen/CodeGenOptions.h" >> -#include "clang/CodeGen/ModuleBuilder.h" >> -#include "clang/Frontend/FrontendDiagnostic.h" >> -#include "llvm/Module.h" >> -#include "llvm/PassManager.h" >> -#include "llvm/ADT/OwningPtr.h" >> -#include "llvm/Assembly/PrintModulePass.h" >> -#include "llvm/Analysis/CallGraph.h" >> -#include "llvm/Analysis/Verifier.h" >> -#include "llvm/Bitcode/ReaderWriter.h" >> -#include "llvm/CodeGen/RegAllocRegistry.h" >> -#include "llvm/CodeGen/SchedulerRegistry.h" >> -#include "llvm/Support/FormattedStream.h" >> -#include "llvm/Support/StandardPasses.h" >> -#include "llvm/Support/Timer.h" >> -#include "llvm/Target/SubtargetFeature.h" >> -#include "llvm/Target/TargetData.h" >> -#include "llvm/Target/TargetMachine.h" >> -#include "llvm/Target/TargetOptions.h" >> -#include "llvm/Target/TargetRegistry.h" >> -using namespace clang; >> -using namespace llvm; >> - >> -namespace { >> - ?class BackendConsumer : public ASTConsumer { >> - ? ?Diagnostic &Diags; >> - ? ?BackendAction Action; >> - ? ?const CodeGenOptions &CodeGenOpts; >> - ? ?const LangOptions &LangOpts; >> - ? ?const TargetOptions &TargetOpts; >> - ? ?llvm::raw_ostream *AsmOutStream; >> - ? ?llvm::formatted_raw_ostream FormattedOutStream; >> - ? ?ASTContext *Context; >> - >> - ? ?Timer LLVMIRGeneration; >> - ? ?Timer CodeGenerationTime; >> - >> - ? ?llvm::OwningPtr Gen; >> - >> - ? ?llvm::Module *TheModule; >> - ? ?llvm::TargetData *TheTargetData; >> - >> - ? ?mutable FunctionPassManager *CodeGenPasses; >> - ? ?mutable PassManager *PerModulePasses; >> - ? ?mutable FunctionPassManager *PerFunctionPasses; >> - >> - ? ?FunctionPassManager *getCodeGenPasses() const; >> - ? ?PassManager *getPerModulePasses() const; >> - ? ?FunctionPassManager *getPerFunctionPasses() const; >> - >> - ? ?void CreatePasses(); >> - >> - ? ?/// AddEmitPasses - Add passes necessary to emit assembly or LLVM IR. >> - ? ?/// >> - ? ?/// \return True on success. >> - ? ?bool AddEmitPasses(); >> - >> - ? ?void EmitAssembly(); >> - >> - ?public: >> - ? ?BackendConsumer(BackendAction action, Diagnostic &_Diags, >> - ? ? ? ? ? ? ? ? ? ?const LangOptions &langopts, const CodeGenOptions &compopts, >> - ? ? ? ? ? ? ? ? ? ?const TargetOptions &targetopts, bool TimePasses, >> - ? ? ? ? ? ? ? ? ? ?const std::string &infile, llvm::raw_ostream *OS, >> - ? ? ? ? ? ? ? ? ? ?LLVMContext& C) : >> - ? ? ?Diags(_Diags), >> - ? ? ?Action(action), >> - ? ? ?CodeGenOpts(compopts), >> - ? ? ?LangOpts(langopts), >> - ? ? ?TargetOpts(targetopts), >> - ? ? ?AsmOutStream(OS), >> - ? ? ?LLVMIRGeneration("LLVM IR Generation Time"), >> - ? ? ?CodeGenerationTime("Code Generation Time"), >> - ? ? ?Gen(CreateLLVMCodeGen(Diags, infile, compopts, C)), >> - ? ? ?TheModule(0), TheTargetData(0), >> - ? ? ?CodeGenPasses(0), PerModulePasses(0), PerFunctionPasses(0) { >> - >> - ? ? ?if (AsmOutStream) >> - ? ? ? ?FormattedOutStream.setStream(*AsmOutStream, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? formatted_raw_ostream::PRESERVE_STREAM); >> - >> - ? ? ?llvm::TimePassesIsEnabled = TimePasses; >> - ? ?} >> - >> - ? ?~BackendConsumer() { >> - ? ? ?delete TheTargetData; >> - ? ? ?delete TheModule; >> - ? ? ?delete CodeGenPasses; >> - ? ? ?delete PerModulePasses; >> - ? ? ?delete PerFunctionPasses; >> - ? ?} >> - >> - ? ?virtual void Initialize(ASTContext &Ctx) { >> - ? ? ?Context = &Ctx; >> - >> - ? ? ?if (llvm::TimePassesIsEnabled) >> - ? ? ? ?LLVMIRGeneration.startTimer(); >> - >> - ? ? ?Gen->Initialize(Ctx); >> - >> - ? ? ?TheModule = Gen->GetModule(); >> - ? ? ?TheTargetData = new llvm::TargetData(Ctx.Target.getTargetDescription()); >> - >> - ? ? ?if (llvm::TimePassesIsEnabled) >> - ? ? ? ?LLVMIRGeneration.stopTimer(); >> - ? ?} >> - >> - ? ?virtual void HandleTopLevelDecl(DeclGroupRef D) { >> - ? ? ?PrettyStackTraceDecl CrashInfo(*D.begin(), SourceLocation(), >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Context->getSourceManager(), >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "LLVM IR generation of declaration"); >> - >> - ? ? ?if (llvm::TimePassesIsEnabled) >> - ? ? ? ?LLVMIRGeneration.startTimer(); >> - >> - ? ? ?Gen->HandleTopLevelDecl(D); >> - >> - ? ? ?if (llvm::TimePassesIsEnabled) >> - ? ? ? ?LLVMIRGeneration.stopTimer(); >> - ? ?} >> - >> - ? ?virtual void HandleTranslationUnit(ASTContext &C) { >> - ? ? ?{ >> - ? ? ? ?PrettyStackTraceString CrashInfo("Per-file LLVM IR generation"); >> - ? ? ? ?if (llvm::TimePassesIsEnabled) >> - ? ? ? ? ?LLVMIRGeneration.startTimer(); >> - >> - ? ? ? ?Gen->HandleTranslationUnit(C); >> - >> - ? ? ? ?if (llvm::TimePassesIsEnabled) >> - ? ? ? ? ?LLVMIRGeneration.stopTimer(); >> - ? ? ?} >> - >> - ? ? ?// EmitAssembly times and registers crash info itself. >> - ? ? ?EmitAssembly(); >> - >> - ? ? ?// Force a flush here in case we never get released. >> - ? ? ?if (AsmOutStream) >> - ? ? ? ?FormattedOutStream.flush(); >> - ? ?} >> - >> - ? ?virtual void HandleTagDeclDefinition(TagDecl *D) { >> - ? ? ?PrettyStackTraceDecl CrashInfo(D, SourceLocation(), >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Context->getSourceManager(), >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "LLVM IR generation of declaration"); >> - ? ? ?Gen->HandleTagDeclDefinition(D); >> - ? ?} >> - >> - ? ?virtual void CompleteTentativeDefinition(VarDecl *D) { >> - ? ? ?Gen->CompleteTentativeDefinition(D); >> - ? ?} >> - ?}; >> -} >> - >> -FunctionPassManager *BackendConsumer::getCodeGenPasses() const { >> - ?if (!CodeGenPasses) { >> - ? ?CodeGenPasses = new FunctionPassManager(TheModule); >> - ? ?CodeGenPasses->add(new TargetData(*TheTargetData)); >> - ?} >> - >> - ?return CodeGenPasses; >> -} >> - >> -PassManager *BackendConsumer::getPerModulePasses() const { >> - ?if (!PerModulePasses) { >> - ? ?PerModulePasses = new PassManager(); >> - ? ?PerModulePasses->add(new TargetData(*TheTargetData)); >> - ?} >> - >> - ?return PerModulePasses; >> -} >> - >> -FunctionPassManager *BackendConsumer::getPerFunctionPasses() const { >> - ?if (!PerFunctionPasses) { >> - ? ?PerFunctionPasses = new FunctionPassManager(TheModule); >> - ? ?PerFunctionPasses->add(new TargetData(*TheTargetData)); >> - ?} >> - >> - ?return PerFunctionPasses; >> -} >> - >> -bool BackendConsumer::AddEmitPasses() { >> - ?if (Action == Backend_EmitNothing) >> - ? ?return true; >> - >> - ?if (Action == Backend_EmitBC) { >> - ? ?getPerModulePasses()->add(createBitcodeWriterPass(FormattedOutStream)); >> - ?} else if (Action == Backend_EmitLL) { >> - ? ?getPerModulePasses()->add(createPrintModulePass(&FormattedOutStream)); >> - ?} else { >> - ? ?bool Fast = CodeGenOpts.OptimizationLevel == 0; >> - >> - ? ?// Create the TargetMachine for generating code. >> - ? ?std::string Error; >> - ? ?std::string Triple = TheModule->getTargetTriple(); >> - ? ?const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error); >> - ? ?if (!TheTarget) { >> - ? ? ?Diags.Report(diag::err_fe_unable_to_create_target) << Error; >> - ? ? ?return false; >> - ? ?} >> - >> - ? ?// FIXME: Expose these capabilities via actual APIs!!!! Aside from just >> - ? ?// being gross, this is also totally broken if we ever care about >> - ? ?// concurrency. >> - ? ?llvm::NoFramePointerElim = CodeGenOpts.DisableFPElim; >> - ? ?if (CodeGenOpts.FloatABI == "soft") >> - ? ? ?llvm::FloatABIType = llvm::FloatABI::Soft; >> - ? ?else if (CodeGenOpts.FloatABI == "hard") >> - ? ? ?llvm::FloatABIType = llvm::FloatABI::Hard; >> - ? ?else { >> - ? ? ?assert(CodeGenOpts.FloatABI.empty() && "Invalid float abi!"); >> - ? ? ?llvm::FloatABIType = llvm::FloatABI::Default; >> - ? ?} >> - ? ?NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS; >> - ? ?llvm::UseSoftFloat = CodeGenOpts.SoftFloat; >> - ? ?UnwindTablesMandatory = CodeGenOpts.UnwindTables; >> - >> - ? ?TargetMachine::setAsmVerbosityDefault(CodeGenOpts.AsmVerbose); >> - >> - ? ?// FIXME: Parse this earlier. >> - ? ?if (CodeGenOpts.RelocationModel == "static") { >> - ? ? ?TargetMachine::setRelocationModel(llvm::Reloc::Static); >> - ? ?} else if (CodeGenOpts.RelocationModel == "pic") { >> - ? ? ?TargetMachine::setRelocationModel(llvm::Reloc::PIC_); >> - ? ?} else { >> - ? ? ?assert(CodeGenOpts.RelocationModel == "dynamic-no-pic" && >> - ? ? ? ? ? ? "Invalid PIC model!"); >> - ? ? ?TargetMachine::setRelocationModel(llvm::Reloc::DynamicNoPIC); >> - ? ?} >> - ? ?// FIXME: Parse this earlier. >> - ? ?if (CodeGenOpts.CodeModel == "small") { >> - ? ? ?TargetMachine::setCodeModel(llvm::CodeModel::Small); >> - ? ?} else if (CodeGenOpts.CodeModel == "kernel") { >> - ? ? ?TargetMachine::setCodeModel(llvm::CodeModel::Kernel); >> - ? ?} else if (CodeGenOpts.CodeModel == "medium") { >> - ? ? ?TargetMachine::setCodeModel(llvm::CodeModel::Medium); >> - ? ?} else if (CodeGenOpts.CodeModel == "large") { >> - ? ? ?TargetMachine::setCodeModel(llvm::CodeModel::Large); >> - ? ?} else { >> - ? ? ?assert(CodeGenOpts.CodeModel.empty() && "Invalid code model!"); >> - ? ? ?TargetMachine::setCodeModel(llvm::CodeModel::Default); >> - ? ?} >> - >> - ? ?std::vector BackendArgs; >> - ? ?BackendArgs.push_back("clang"); // Fake program name. >> - ? ?if (!CodeGenOpts.DebugPass.empty()) { >> - ? ? ?BackendArgs.push_back("-debug-pass"); >> - ? ? ?BackendArgs.push_back(CodeGenOpts.DebugPass.c_str()); >> - ? ?} >> - ? ?if (!CodeGenOpts.LimitFloatPrecision.empty()) { >> - ? ? ?BackendArgs.push_back("-limit-float-precision"); >> - ? ? ?BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str()); >> - ? ?} >> - ? ?if (llvm::TimePassesIsEnabled) >> - ? ? ?BackendArgs.push_back("-time-passes"); >> - ? ?BackendArgs.push_back(0); >> - ? ?llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(char**) &BackendArgs[0]); >> - >> - ? ?std::string FeaturesStr; >> - ? ?if (TargetOpts.CPU.size() || TargetOpts.Features.size()) { >> - ? ? ?SubtargetFeatures Features; >> - ? ? ?Features.setCPU(TargetOpts.CPU); >> - ? ? ?for (std::vector::const_iterator >> - ? ? ? ? ? ? it = TargetOpts.Features.begin(), >> - ? ? ? ? ? ? ie = TargetOpts.Features.end(); it != ie; ++it) >> - ? ? ? ?Features.AddFeature(*it); >> - ? ? ?FeaturesStr = Features.getString(); >> - ? ?} >> - ? ?TargetMachine *TM = TheTarget->createTargetMachine(Triple, FeaturesStr); >> - >> - ? ?// Set register scheduler & allocation policy. >> - ? ?RegisterScheduler::setDefault(createDefaultScheduler); >> - ? ?RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator : >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? createLinearScanRegisterAllocator); >> - >> - ? ?// From llvm-gcc: >> - ? ?// If there are passes we have to run on the entire module, we do codegen >> - ? ?// as a separate "pass" after that happens. >> - ? ?// FIXME: This is disabled right now until bugs can be worked out. ?Reenable >> - ? ?// this for fast -O0 compiles! >> - ? ?FunctionPassManager *PM = getCodeGenPasses(); >> - ? ?CodeGenOpt::Level OptLevel = CodeGenOpt::Default; >> - >> - ? ?switch (CodeGenOpts.OptimizationLevel) { >> - ? ?default: break; >> - ? ?case 0: OptLevel = CodeGenOpt::None; break; >> - ? ?case 3: OptLevel = CodeGenOpt::Aggressive; break; >> - ? ?} >> - >> - ? ?// Normal mode, emit a .s or .o file by running the code generator. Note, >> - ? ?// this also adds codegenerator level optimization passes. >> - ? ?TargetMachine::CodeGenFileType CGFT = TargetMachine::CGFT_AssemblyFile; >> - ? ?if (Action == Backend_EmitObj) >> - ? ? ?CGFT = TargetMachine::CGFT_ObjectFile; >> - ? ?if (TM->addPassesToEmitFile(*PM, FormattedOutStream, CGFT, OptLevel)) { >> - ? ? ?Diags.Report(diag::err_fe_unable_to_interface_with_target); >> - ? ? ?return false; >> - ? ?} >> - ?} >> - >> - ?return true; >> -} >> - >> -void BackendConsumer::CreatePasses() { >> - ?unsigned OptLevel = CodeGenOpts.OptimizationLevel; >> - ?CodeGenOptions::InliningMethod Inlining = CodeGenOpts.Inlining; >> - >> - ?// Handle disabling of LLVM optimization, where we want to preserve the >> - ?// internal module before any optimization. >> - ?if (CodeGenOpts.DisableLLVMOpts) { >> - ? ?OptLevel = 0; >> - ? ?Inlining = CodeGenOpts.NoInlining; >> - ?} >> - >> - ?// In -O0 if checking is disabled, we don't even have per-function passes. >> - ?if (CodeGenOpts.VerifyModule) >> - ? ?getPerFunctionPasses()->add(createVerifierPass()); >> - >> - ?// Assume that standard function passes aren't run for -O0. >> - ?if (OptLevel > 0) >> - ? ?llvm::createStandardFunctionPasses(getPerFunctionPasses(), OptLevel); >> - >> - ?llvm::Pass *InliningPass = 0; >> - ?switch (Inlining) { >> - ?case CodeGenOptions::NoInlining: break; >> - ?case CodeGenOptions::NormalInlining: { >> - ? ?// Set the inline threshold following llvm-gcc. >> - ? ?// >> - ? ?// FIXME: Derive these constants in a principled fashion. >> - ? ?unsigned Threshold = 225; >> - ? ?if (CodeGenOpts.OptimizeSize) >> - ? ? ?Threshold = 75; >> - ? ?else if (OptLevel > 2) >> - ? ? ?Threshold = 275; >> - ? ?InliningPass = createFunctionInliningPass(Threshold); >> - ? ?break; >> - ?} >> - ?case CodeGenOptions::OnlyAlwaysInlining: >> - ? ?InliningPass = createAlwaysInlinerPass(); ? ? ? ? // Respect always_inline >> - ? ?break; >> - ?} >> - >> - ?// For now we always create per module passes. >> - ?PassManager *PM = getPerModulePasses(); >> - ?llvm::createStandardModulePasses(PM, OptLevel, CodeGenOpts.OptimizeSize, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? CodeGenOpts.UnitAtATime, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? CodeGenOpts.UnrollLoops, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*SimplifyLibCalls=*/!LangOpts.NoBuiltin, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*HaveExceptions=*/true, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? InliningPass); >> -} >> - >> -/// EmitAssembly - Handle interaction with LLVM backend to generate >> -/// actual machine code. >> -void BackendConsumer::EmitAssembly() { >> - ?// Silently ignore if we weren't initialized for some reason. >> - ?if (!TheModule || !TheTargetData) >> - ? ?return; >> - >> - ?TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : 0); >> - >> - ?// Make sure IR generation is happy with the module. This is >> - ?// released by the module provider. >> - ?Module *M = Gen->ReleaseModule(); >> - ?if (!M) { >> - ? ?// The module has been released by IR gen on failures, do not >> - ? ?// double free. >> - ? ?TheModule = 0; >> - ? ?return; >> - ?} >> - >> - ?assert(TheModule == M && "Unexpected module change during IR generation"); >> - >> - ?CreatePasses(); >> - ?if (!AddEmitPasses()) >> - ? ?return; >> - >> - ?// Run passes. For now we do all passes at once, but eventually we >> - ?// would like to have the option of streaming code generation. >> - >> - ?if (PerFunctionPasses) { >> - ? ?PrettyStackTraceString CrashInfo("Per-function optimization"); >> - >> - ? ?PerFunctionPasses->doInitialization(); >> - ? ?for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) >> - ? ? ?if (!I->isDeclaration()) >> - ? ? ? ?PerFunctionPasses->run(*I); >> - ? ?PerFunctionPasses->doFinalization(); >> - ?} >> - >> - ?if (PerModulePasses) { >> - ? ?PrettyStackTraceString CrashInfo("Per-module optimization passes"); >> - ? ?PerModulePasses->run(*M); >> - ?} >> - >> - ?if (CodeGenPasses) { >> - ? ?PrettyStackTraceString CrashInfo("Code generation"); >> - ? ?CodeGenPasses->doInitialization(); >> - ? ?for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) >> - ? ? ?if (!I->isDeclaration()) >> - ? ? ? ?CodeGenPasses->run(*I); >> - ? ?CodeGenPasses->doFinalization(); >> - ?} >> -} >> - >> -ASTConsumer *clang::CreateBackendConsumer(BackendAction Action, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?Diagnostic &Diags, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?const LangOptions &LangOpts, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?const CodeGenOptions &CodeGenOpts, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?const TargetOptions &TargetOpts, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?bool TimePasses, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?const std::string& InFile, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?llvm::raw_ostream* OS, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?LLVMContext& C) { >> - ?return new BackendConsumer(Action, Diags, LangOpts, CodeGenOpts, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? TargetOpts, TimePasses, InFile, OS, C); >> -} >> >> Copied: cfe/trunk/lib/Frontend/CodeGenAction.cpp (from r97109, cfe/trunk/lib/Frontend/Backend.cpp) >> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CodeGenAction.cpp?p2=cfe/trunk/lib/Frontend/CodeGenAction.cpp&p1=cfe/trunk/lib/Frontend/Backend.cpp&r1=97109&r2=97110&rev=97110&view=diff >> ============================================================================== >> --- cfe/trunk/lib/Frontend/Backend.cpp (original) >> +++ cfe/trunk/lib/Frontend/CodeGenAction.cpp Wed Feb 24 22:37:45 2010 >> @@ -1,4 +1,4 @@ >> -//===--- Backend.cpp - Interface to LLVM backend technologies -------------===// >> +//===--- CodeGenAction.cpp - LLVM Code Generation Frontend Action ---------===// >> // >> // ? ? ? ? ? ? ? ? ? ? The LLVM Compiler Infrastructure >> // >> @@ -7,7 +7,7 @@ >> // >> //===----------------------------------------------------------------------===// >> >> -#include "clang/Frontend/ASTConsumers.h" >> +#include "clang/Frontend/CodeGenAction.h" >> #include "clang/AST/ASTConsumer.h" >> #include "clang/AST/ASTContext.h" >> #include "clang/AST/DeclGroup.h" >> @@ -15,6 +15,8 @@ >> #include "clang/Basic/TargetOptions.h" >> #include "clang/CodeGen/CodeGenOptions.h" >> #include "clang/CodeGen/ModuleBuilder.h" >> +#include "clang/Frontend/ASTConsumers.h" >> +#include "clang/Frontend/CompilerInstance.h" >> #include "clang/Frontend/FrontendDiagnostic.h" >> #include "llvm/Module.h" >> #include "llvm/PassManager.h" >> @@ -37,6 +39,14 @@ >> using namespace llvm; >> >> namespace { >> + ?enum BackendAction { >> + ? ?Backend_EmitAssembly, ?///< Emit native assembly files >> + ? ?Backend_EmitBC, ? ? ? ?///< Emit LLVM bitcode files >> + ? ?Backend_EmitLL, ? ? ? ?///< Emit human-readable LLVM assembly >> + ? ?Backend_EmitNothing, ? ///< Don't emit anything (benchmarking mode) >> + ? ?Backend_EmitObj ? ? ? ?///< Emit native object files >> + ?}; >> + >> ? class BackendConsumer : public ASTConsumer { >> ? ? Diagnostic &Diags; >> ? ? BackendAction Action; >> @@ -419,15 +429,46 @@ >> ? } >> } >> >> -ASTConsumer *clang::CreateBackendConsumer(BackendAction Action, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?Diagnostic &Diags, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?const LangOptions &LangOpts, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?const CodeGenOptions &CodeGenOpts, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?const TargetOptions &TargetOpts, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?bool TimePasses, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?const std::string& InFile, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?llvm::raw_ostream* OS, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?LLVMContext& C) { >> - ?return new BackendConsumer(Action, Diags, LangOpts, CodeGenOpts, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? TargetOpts, TimePasses, InFile, OS, C); >> +// >> + >> +CodeGenAction::CodeGenAction(unsigned _Act) : Act(_Act) {} >> + >> +ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI, >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?llvm::StringRef InFile) { >> + ?BackendAction BA = static_cast(Act); >> + ?llvm::OwningPtr OS; >> + ?switch (BA) { >> + ?case Backend_EmitAssembly: >> + ? ?OS.reset(CI.createDefaultOutputFile(false, InFile, "s")); >> + ? ?break; >> + ?case Backend_EmitLL: >> + ? ?OS.reset(CI.createDefaultOutputFile(false, InFile, "ll")); >> + ? ?break; >> + ?case Backend_EmitBC: >> + ? ?OS.reset(CI.createDefaultOutputFile(true, InFile, "bc")); >> + ? ?break; >> + ?case Backend_EmitNothing: >> + ? ?break; >> + ?case Backend_EmitObj: >> + ? ?OS.reset(CI.createDefaultOutputFile(true, InFile, "o")); >> + ? ?break; >> + ?} >> + ?if (BA != Backend_EmitNothing && !OS) >> + ? ?return 0; >> + >> + ?return new BackendConsumer(BA, CI.getDiagnostics(), CI.getLangOpts(), >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? CI.getCodeGenOpts(), CI.getTargetOpts(), >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? CI.getFrontendOpts().ShowTimers, InFile, OS.take(), >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? CI.getLLVMContext()); >> } >> + >> +EmitAssemblyAction::EmitAssemblyAction() >> + ?: CodeGenAction(Backend_EmitAssembly) {} >> + >> +EmitBCAction::EmitBCAction() : CodeGenAction(Backend_EmitBC) {} >> + >> +EmitLLVMAction::EmitLLVMAction() : CodeGenAction(Backend_EmitLL) {} >> + >> +EmitLLVMOnlyAction::EmitLLVMOnlyAction() : CodeGenAction(Backend_EmitNothing) {} >> + >> +EmitObjAction::EmitObjAction() : CodeGenAction(Backend_EmitObj) {} >> >> Modified: cfe/trunk/lib/Frontend/FrontendActions.cpp >> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendActions.cpp?rev=97110&r1=97109&r2=97110&view=diff >> ============================================================================== >> --- cfe/trunk/lib/Frontend/FrontendActions.cpp (original) >> +++ cfe/trunk/lib/Frontend/FrontendActions.cpp Wed Feb 24 22:37:45 2010 >> @@ -159,48 +159,6 @@ >> ? return new ASTConsumer(); >> } >> >> -CodeGenAction::CodeGenAction(unsigned _Act) : Act(_Act) {} >> - >> -ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?llvm::StringRef InFile) { >> - ?BackendAction BA = static_cast(Act); >> - ?llvm::OwningPtr OS; >> - ?switch (BA) { >> - ?case Backend_EmitAssembly: >> - ? ?OS.reset(CI.createDefaultOutputFile(false, InFile, "s")); >> - ? ?break; >> - ?case Backend_EmitLL: >> - ? ?OS.reset(CI.createDefaultOutputFile(false, InFile, "ll")); >> - ? ?break; >> - ?case Backend_EmitBC: >> - ? ?OS.reset(CI.createDefaultOutputFile(true, InFile, "bc")); >> - ? ?break; >> - ?case Backend_EmitNothing: >> - ? ?break; >> - ?case Backend_EmitObj: >> - ? ?OS.reset(CI.createDefaultOutputFile(true, InFile, "o")); >> - ? ?break; >> - ?} >> - ?if (BA != Backend_EmitNothing && !OS) >> - ? ?return 0; >> - >> - ?return CreateBackendConsumer(BA, CI.getDiagnostics(), CI.getLangOpts(), >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? CI.getCodeGenOpts(), CI.getTargetOpts(), >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? CI.getFrontendOpts().ShowTimers, InFile, >> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OS.take(), CI.getLLVMContext()); >> -} >> - >> -EmitAssemblyAction::EmitAssemblyAction() >> - ?: CodeGenAction(Backend_EmitAssembly) {} >> - >> -EmitBCAction::EmitBCAction() : CodeGenAction(Backend_EmitBC) {} >> - >> -EmitLLVMAction::EmitLLVMAction() : CodeGenAction(Backend_EmitLL) {} >> - >> -EmitLLVMOnlyAction::EmitLLVMOnlyAction() : CodeGenAction(Backend_EmitNothing) {} >> - >> -EmitObjAction::EmitObjAction() : CodeGenAction(Backend_EmitObj) {} >> - >> //===----------------------------------------------------------------------===// >> // Preprocessor Actions >> //===----------------------------------------------------------------------===// >> >> Modified: cfe/trunk/tools/driver/cc1_main.cpp >> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/driver/cc1_main.cpp?rev=97110&r1=97109&r2=97110&view=diff >> ============================================================================== >> --- cfe/trunk/tools/driver/cc1_main.cpp (original) >> +++ cfe/trunk/tools/driver/cc1_main.cpp Wed Feb 24 22:37:45 2010 >> @@ -19,6 +19,7 @@ >> #include "clang/Driver/CC1Options.h" >> #include "clang/Driver/DriverDiagnostic.h" >> #include "clang/Driver/OptTable.h" >> +#include "clang/Frontend/CodeGenAction.h" >> #include "clang/Frontend/CompilerInstance.h" >> #include "clang/Frontend/CompilerInvocation.h" >> #include "clang/Frontend/FrontendActions.h" >> >> >> _______________________________________________ >> cfe-commits mailing list >> cfe-commits at cs.uiuc.edu >> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits > > From dgregor at apple.com Thu Feb 25 14:58:06 2010 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 25 Feb 2010 12:58:06 -0800 Subject: [cfe-commits] r97166 - in /cfe/trunk: include/clang/Frontend/CodeGenAction.h lib/Frontend/CodeGenAction.cpp In-Reply-To: <20100225203744.E16BD2A6C12C@llvm.org> References: <20100225203744.E16BD2A6C12C@llvm.org> Message-ID: <3BBCD72C-6208-4F60-8610-7760EC64EFC5@apple.com> On Feb 25, 2010, at 12:37 PM, Daniel Dunbar wrote: > Author: ddunbar > Date: Thu Feb 25 14:37:44 2010 > New Revision: 97166 > > URL: http://llvm.org/viewvc/llvm-project?rev=97166&view=rev > Log: > Move ~CodeGenAction out-of-line. > > Modified: > cfe/trunk/include/clang/Frontend/CodeGenAction.h > cfe/trunk/lib/Frontend/CodeGenAction.cpp > > Modified: cfe/trunk/include/clang/Frontend/CodeGenAction.h > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CodeGenAction.h?rev=97166&r1=97165&r2=97166&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Frontend/CodeGenAction.h (original) > +++ cfe/trunk/include/clang/Frontend/CodeGenAction.h Thu Feb 25 14:37:44 2010 > @@ -23,6 +23,7 @@ > > protected: > CodeGenAction(unsigned _Act); > + ~CodeGenAction(); This should be public (?). Clang won't diagnose it, but it's breaking with the GCC build. - Doug From andersca at mac.com Thu Feb 25 16:18:35 2010 From: andersca at mac.com (Anders Carlsson) Date: Thu, 25 Feb 2010 22:18:35 -0000 Subject: [cfe-commits] r97173 - in /cfe/trunk: lib/CodeGen/CGVtable.cpp test/CodeGenCXX/vtable-layout.cpp Message-ID: <20100225221835.E5C392A6C12C@llvm.org> Author: andersca Date: Thu Feb 25 16:18:35 2010 New Revision: 97173 URL: http://llvm.org/viewvc/llvm-project?rev=97173&view=rev Log: Fux a bug where we were trying to add overriders for non-virtual bases of virtual bases more than once. Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp cfe/trunk/test/CodeGenCXX/vtable-layout.cpp Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=97173&r1=97172&r2=97173&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVtable.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVtable.cpp Thu Feb 25 16:18:35 2010 @@ -261,10 +261,10 @@ // Check the base class offset. const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class); - + const RecordType *BaseType = Element.Base->getType()->getAs(); const CXXRecordDecl *Base = cast(BaseType->getDecl()); - + NonVirtualOffset += Layout.getBaseClassOffset(Base); } @@ -512,7 +512,7 @@ if (!BaseDecl->isPolymorphic()) continue; - bool IsVisitedVirtualBase = false; + bool IsVisitedVirtualBase = BaseSubobjectIsVisitedVBase; uint64_t BaseOffset; if (I->isVirtual()) { if (!VisitedVirtualBases.insert(BaseDecl)) Modified: cfe/trunk/test/CodeGenCXX/vtable-layout.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/vtable-layout.cpp?rev=97173&r1=97172&r2=97173&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/vtable-layout.cpp (original) +++ cfe/trunk/test/CodeGenCXX/vtable-layout.cpp Thu Feb 25 16:18:35 2010 @@ -510,3 +510,32 @@ } +namespace Test14 { + +// Verify that we handle A being a non-virtual base of B, which is a virtual base. + +struct A { + virtual void f(); +}; + +struct B : A { }; + +struct C : virtual B { }; + +// CHECK: Vtable for 'Test14::D' (5 entries). +// CHECK-NEXT: 0 | vbase_offset (0) +// CHECK-NEXT: 1 | vcall_offset (0) +// CHECK-NEXT: 2 | offset_to_top (0) +// CHECK-NEXT: 3 | Test14::D RTTI +// CHECK-NEXT: -- (Test14::A, 0) vtable address -- +// CHECK-NEXT: -- (Test14::B, 0) vtable address -- +// CHECK-NEXT: -- (Test14::C, 0) vtable address -- +// CHECK-NEXT: -- (Test14::D, 0) vtable address -- +// CHECK-NEXT: 4 | void Test14::D::f() +struct D : C, virtual B { + virtual void f(); +}; +void D::f() { } + +} + From andersca at mac.com Thu Feb 25 16:23:14 2010 From: andersca at mac.com (Anders Carlsson) Date: Thu, 25 Feb 2010 22:23:14 -0000 Subject: [cfe-commits] r97174 - /cfe/trunk/lib/CodeGen/CGVtable.cpp Message-ID: <20100225222314.29DAD2A6C12C@llvm.org> Author: andersca Date: Thu Feb 25 16:23:13 2010 New Revision: 97174 URL: http://llvm.org/viewvc/llvm-project?rev=97174&view=rev Log: Improve vcall offset handling. Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=97174&r1=97173&r2=97174&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVtable.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVtable.cpp Thu Feb 25 16:23:13 2010 @@ -804,8 +804,8 @@ /// vtable address point) for the given virtual member function. int64_t getVCallOffsetOffset(const CXXMethodDecl *MD); - /// clear - Clear the offset map. - void clear() { Offsets.clear(); } + // empty - Return whether the offset map is empty or not. + bool empty() const { return Offsets.empty(); } }; bool VCallOffsetMap::MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, @@ -905,7 +905,6 @@ const_iterator components_begin() const { return Components.rbegin(); } const_iterator components_end() const { return Components.rend(); } - /// FIXME: Get rid of this getter. const VCallOffsetMap& getVCallOffsets() const { return VCallOffsets; } }; @@ -1092,8 +1091,9 @@ /// FinalOverriders - The final overriders of the most derived class. const FinalOverriders Overriders; - /// VCallOffsets - Keeps track of vcall offsets for the current vtable. - VCallOffsetMap VCallOffsets; + /// VCallOffsetsForVBases - Keeps track of vcall offsets for the virtual + /// bases in this vtable. + llvm::DenseMap VCallOffsetsForVBases; /// Components - The components of the vtable being built. llvm::SmallVector Components; @@ -1267,7 +1267,19 @@ if (!Offset.isEmpty()) { if (Offset.VirtualBase) { - // Get the vcall offset offset. + // Get the vcall offset map for this virtual base. + VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Offset.VirtualBase]; + + if (VCallOffsets.empty()) { + // We don't have vcall offsets for this virtual base, go ahead and + // build them. + VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, 0, + BaseSubobject(Offset.VirtualBase, 0), + /*BaseIsVirtual=*/true); + + VCallOffsets = Builder.getVCallOffsets(); + } + Adjustment.VCallOffsetOffset = VCallOffsets.getVCallOffsetOffset(MD); } @@ -1478,9 +1490,14 @@ Base, BaseIsVirtual); Components.append(Builder.components_begin(), Builder.components_end()); - // FIXME: This is not how we should do vcall offsets. - VCallOffsets = Builder.getVCallOffsets(); - + // Check if we need to add these vcall offsets. + if (BaseIsVirtual && !Builder.getVCallOffsets().empty()) { + VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Base.getBase()]; + + if (VCallOffsets.empty()) + VCallOffsets = Builder.getVCallOffsets(); + } + // Add the offset to top. // FIXME: This is not going to be right for construction vtables. // FIXME: We should not use / 8 here. @@ -1510,9 +1527,6 @@ AddressPoints.insert(std::make_pair(PrimaryBase, AddressPoint)); } - // Clear the vcall offsets. - VCallOffsets.clear(); - // Layout secondary vtables. LayoutSecondaryVtables(Base); } From dgregor at apple.com Thu Feb 25 16:29:57 2010 From: dgregor at apple.com (Douglas Gregor) Date: Thu, 25 Feb 2010 22:29:57 -0000 Subject: [cfe-commits] r97177 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp test/SemaCXX/composite-pointer-type.cpp Message-ID: <20100225222958.07D5E2A6C12C@llvm.org> Author: dgregor Date: Thu Feb 25 16:29:57 2010 New Revision: 97177 URL: http://llvm.org/viewvc/llvm-project?rev=97177&view=rev Log: When computing the composite pointer type for relational comparisons, equality comparisons, and conditional operators, produce a composite pointer type with the appropriate additional "const" qualifiers if the pointer types would otherwise be incompatible. This is a small extension (also present in GCC and EDG in a slightly different form) that permits code like: void** i; void const** j; i == j; with the following extwarn: t.cpp:5:5: warning: comparison of distinct pointer types ('void **' and 'void const **') uses non-standard composite pointer type 'void const *const *' [-pedantic] i == j; ~ ^ ~ Fixes PR6346, and I'll be filing a core issue about this with the C++ committee. Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/Sema/Sema.h cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/test/SemaCXX/composite-pointer-type.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=97177&r1=97176&r2=97177&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Feb 25 16:29:57 2010 @@ -1828,6 +1828,9 @@ "incompatible operand types (%0 and %1)">; def err_typecheck_comparison_of_distinct_pointers : Error< "comparison of distinct pointer types (%0 and %1)">; +def ext_typecheck_comparison_of_distinct_pointers_nonstandard : ExtWarn< + "comparison of distinct pointer types (%0 and %1) uses non-standard " + "composite pointer type %2">; def err_typecheck_vector_comparison : Error< "comparison of vector types (%0 and %1) not supported yet">; def err_typecheck_assign_const : Error<"read-only variable is not assignable">; @@ -2252,6 +2255,9 @@ "operand of type %0 where arithmetic or pointer type is required">; def err_typecheck_cond_incompatible_operands : Error< "incompatible operand types (%0 and %1)">; +def ext_typecheck_cond_incompatible_operands_nonstandard : ExtWarn< + "incompatible operand types (%0 and %1) use non-standard composite pointer " + "type %2">; def err_cast_selector_expr : Error< "cannot type cast @selector expression">; def warn_typecheck_cond_incompatible_pointers : ExtWarn< Modified: cfe/trunk/lib/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=97177&r1=97176&r2=97177&view=diff ============================================================================== --- cfe/trunk/lib/Sema/Sema.h (original) +++ cfe/trunk/lib/Sema/Sema.h Thu Feb 25 16:29:57 2010 @@ -3947,7 +3947,8 @@ Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc); QualType CXXCheckConditionalOperands( // C++ 5.16 Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc); - QualType FindCompositePointerType(Expr *&E1, Expr *&E2); // C++ 5.9 + QualType FindCompositePointerType(Expr *&E1, Expr *&E2, + bool *NonStandardCompositeType = 0); QualType FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, SourceLocation questionLoc); Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=97177&r1=97176&r2=97177&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Feb 25 16:29:57 2010 @@ -5324,11 +5324,18 @@ // // C++ [expr.eq]p1 uses the same notion for (in)equality // comparisons of pointers. - QualType T = FindCompositePointerType(lex, rex); + bool NonStandardCompositeType = false; + QualType T = FindCompositePointerType(lex, rex, + isSFINAEContext()? 0 : &NonStandardCompositeType); if (T.isNull()) { Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); return QualType(); + } else if (NonStandardCompositeType) { + Diag(Loc, + diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard) + << lType << rType << T + << lex->getSourceRange() << rex->getSourceRange(); } ImpCastExprToType(lex, T, CastExpr::CK_BitCast); @@ -5390,11 +5397,18 @@ // of one of the operands, with a cv-qualification signature (4.4) // that is the union of the cv-qualification signatures of the operand // types. - QualType T = FindCompositePointerType(lex, rex); + bool NonStandardCompositeType = false; + QualType T = FindCompositePointerType(lex, rex, + isSFINAEContext()? 0 : &NonStandardCompositeType); if (T.isNull()) { Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers) - << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + << lType << rType << lex->getSourceRange() << rex->getSourceRange(); return QualType(); + } else if (NonStandardCompositeType) { + Diag(Loc, + diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard) + << lType << rType << T + << lex->getSourceRange() << rex->getSourceRange(); } ImpCastExprToType(lex, T, CastExpr::CK_BitCast); Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=97177&r1=97176&r2=97177&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Feb 25 16:29:57 2010 @@ -2080,9 +2080,18 @@ // performed to bring them to a common type, whose cv-qualification // shall match the cv-qualification of either the second or the third // operand. The result is of the common type. - QualType Composite = FindCompositePointerType(LHS, RHS); - if (!Composite.isNull()) + bool NonStandardCompositeType = false; + QualType Composite = FindCompositePointerType(LHS, RHS, + isSFINAEContext()? 0 : &NonStandardCompositeType); + if (!Composite.isNull()) { + if (NonStandardCompositeType) + Diag(QuestionLoc, + diag::ext_typecheck_cond_incompatible_operands_nonstandard) + << LTy << RTy << Composite + << LHS->getSourceRange() << RHS->getSourceRange(); + return Composite; + } // Similarly, attempt to find composite type of twp objective-c pointers. Composite = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc); @@ -2101,7 +2110,16 @@ /// and @p E2 according to C++0x 5.9p2. It converts both expressions to this /// type and returns it. /// It does not emit diagnostics. -QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { +/// +/// If \p NonStandardCompositeType is non-NULL, then we are permitted to find +/// a non-standard (but still sane) composite type to which both expressions +/// can be converted. When such a type is chosen, \c *NonStandardCompositeType +/// will be set true. +QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2, + bool *NonStandardCompositeType) { + if (NonStandardCompositeType) + *NonStandardCompositeType = false; + assert(getLangOptions().CPlusPlus && "This function assumes C++"); QualType T1 = E1->getType(), T2 = E2->getType(); @@ -2152,12 +2170,20 @@ ContainingClassVector MemberOfClass; QualType Composite1 = Context.getCanonicalType(T1), Composite2 = Context.getCanonicalType(T2); + unsigned NeedConstBefore = 0; do { const PointerType *Ptr1, *Ptr2; if ((Ptr1 = Composite1->getAs()) && (Ptr2 = Composite2->getAs())) { Composite1 = Ptr1->getPointeeType(); Composite2 = Ptr2->getPointeeType(); + + // If we're allowed to create a non-standard composite type, keep track + // of where we need to fill in additional 'const' qualifiers. + if (NonStandardCompositeType && + Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) + NeedConstBefore = QualifierUnion.size(); + QualifierUnion.push_back( Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); MemberOfClass.push_back(std::make_pair((const Type *)0, (const Type *)0)); @@ -2169,6 +2195,13 @@ (MemPtr2 = Composite2->getAs())) { Composite1 = MemPtr1->getPointeeType(); Composite2 = MemPtr2->getPointeeType(); + + // If we're allowed to create a non-standard composite type, keep track + // of where we need to fill in additional 'const' qualifiers. + if (NonStandardCompositeType && + Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) + NeedConstBefore = QualifierUnion.size(); + QualifierUnion.push_back( Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(), @@ -2182,6 +2215,18 @@ break; } while (true); + if (NeedConstBefore && NonStandardCompositeType) { + // Extension: Add 'const' to qualifiers that come before the first qualifier + // mismatch, so that our (non-standard!) composite type meets the + // requirements of C++ [conv.qual]p4 bullet 3. + for (unsigned I = 0; I != NeedConstBefore; ++I) { + if ((QualifierUnion[I] & Qualifiers::Const) == 0) { + QualifierUnion[I] = QualifierUnion[I] | Qualifiers::Const; + *NonStandardCompositeType = true; + } + } + } + // Rewrap the composites as pointers or member pointers with the union CVRs. ContainingClassVector::reverse_iterator MOC = MemberOfClass.rbegin(); Modified: cfe/trunk/test/SemaCXX/composite-pointer-type.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/composite-pointer-type.cpp?rev=97177&r1=97176&r2=97177&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/composite-pointer-type.cpp (original) +++ cfe/trunk/test/SemaCXX/composite-pointer-type.cpp Thu Feb 25 16:29:57 2010 @@ -50,3 +50,11 @@ bool f(Matrix4 m1, const Matrix4 m2) { return m1 != m2; } + +// PR6346 +bool f1(bool b, void **p, const void **q) { + if (p == q) // expected-warning{{comparison of distinct pointer types ('void **' and 'void const **') uses non-standard composite pointer type 'void const *const *'}} + return false; + + return b? p : q; // expected-warning{{incompatible operand types ('void **' and 'void const **') use non-standard composite pointer type 'void const *const *'}} +} From dgregor at apple.com Thu Feb 25 18:01:57 2010 From: dgregor at apple.com (Douglas Gregor) Date: Fri, 26 Feb 2010 00:01:57 -0000 Subject: [cfe-commits] r97185 - in /cfe/trunk: lib/Sema/TreeTransform.h test/SemaTemplate/instantiate-expr-1.cpp Message-ID: <20100226000157.92E092A6C12C@llvm.org> Author: dgregor Date: Thu Feb 25 18:01:57 2010 New Revision: 97185 URL: http://llvm.org/viewvc/llvm-project?rev=97185&view=rev Log: When we decide to re-use an existing CXXConstructExpr node, make sure to mark the constructor as referenced. Fixes the narrow issue reported in PR6424, but there are a few other places that I'll fix before closing out that PR. Modified: cfe/trunk/lib/Sema/TreeTransform.h cfe/trunk/test/SemaTemplate/instantiate-expr-1.cpp Modified: cfe/trunk/lib/Sema/TreeTransform.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=97185&r1=97184&r2=97185&view=diff ============================================================================== --- cfe/trunk/lib/Sema/TreeTransform.h (original) +++ cfe/trunk/lib/Sema/TreeTransform.h Thu Feb 25 18:01:57 2010 @@ -4906,8 +4906,10 @@ if (!getDerived().AlwaysRebuild() && T == E->getType() && Constructor == E->getConstructor() && - !ArgumentChanged) + !ArgumentChanged) { + SemaRef.MarkDeclarationReferenced(E->getLocStart(), Constructor); return SemaRef.Owned(E->Retain()); + } return getDerived().RebuildCXXConstructExpr(T, /*FIXME:*/E->getLocStart(), Constructor, E->isElidable(), Modified: cfe/trunk/test/SemaTemplate/instantiate-expr-1.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-expr-1.cpp?rev=97185&r1=97184&r2=97185&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/instantiate-expr-1.cpp (original) +++ cfe/trunk/test/SemaTemplate/instantiate-expr-1.cpp Thu Feb 25 18:01:57 2010 @@ -137,3 +137,19 @@ int b; test_asm(b); // expected-note {{in instantiation of function template specialization 'test_asm' requested here}} } + +namespace PR6424 { + template struct X { + X() { + int *ip = I; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}} + } + }; + + template struct Y { + typedef X<7> X7; + + void f() { X7(); } // expected-note{{instantiation}} + }; + + template void Y<3>::f(); +} From kremenek at apple.com Thu Feb 25 18:07:31 2010 From: kremenek at apple.com (Ted Kremenek) Date: Fri, 26 Feb 2010 00:07:31 -0000 Subject: [cfe-commits] r97186 - /cfe/trunk/www/analyzer/latest_checker.html.incl Message-ID: <20100226000731.923BD2A6C12C@llvm.org> Author: kremenek Date: Thu Feb 25 18:07:31 2010 New Revision: 97186 URL: http://llvm.org/viewvc/llvm-project?rev=97186&view=rev Log: Update checker build. Modified: cfe/trunk/www/analyzer/latest_checker.html.incl Modified: cfe/trunk/www/analyzer/latest_checker.html.incl URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/analyzer/latest_checker.html.incl?rev=97186&r1=97185&r2=97186&view=diff ============================================================================== --- cfe/trunk/www/analyzer/latest_checker.html.incl (original) +++ cfe/trunk/www/analyzer/latest_checker.html.incl Thu Feb 25 18:07:31 2010 @@ -1 +1 @@ -checker-235.tar.bz2 (built February 16, 2010) +checker-236.tar.bz2 (built February 25, 2010) From dgregor at apple.com Thu Feb 25 18:38:10 2010 From: dgregor at apple.com (Douglas Gregor) Date: Fri, 26 Feb 2010 00:38:10 -0000 Subject: [cfe-commits] r97195 - in /cfe/trunk: lib/Sema/TreeTransform.h test/SemaTemplate/instantiate-expr-1.cpp Message-ID: <20100226003811.1648A2A6C12C@llvm.org> Author: dgregor Date: Thu Feb 25 18:38:10 2010 New Revision: 97195 URL: http://llvm.org/viewvc/llvm-project?rev=97195&view=rev Log: Make sure to mark constructors, operator new, and operator delete as used when we instantiate C++ new expressions, delete expressions, and object-construction expressions. Fixes PR6424, although we can't test all of it until we finish implementing lookup of "operator delete" for new expressions (!). Modified: cfe/trunk/lib/Sema/TreeTransform.h cfe/trunk/test/SemaTemplate/instantiate-expr-1.cpp Modified: cfe/trunk/lib/Sema/TreeTransform.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=97195&r1=97194&r2=97195&view=diff ============================================================================== --- cfe/trunk/lib/Sema/TreeTransform.h (original) +++ cfe/trunk/lib/Sema/TreeTransform.h Thu Feb 25 18:38:10 2010 @@ -4588,11 +4588,48 @@ ConstructorArgs.push_back(Arg.take()); } + // Transform constructor, new operator, and delete operator. + CXXConstructorDecl *Constructor = 0; + if (E->getConstructor()) { + Constructor = cast_or_null( + getDerived().TransformDecl(E->getConstructor())); + if (!Constructor) + return SemaRef.ExprError(); + } + + FunctionDecl *OperatorNew = 0; + if (E->getOperatorNew()) { + OperatorNew = cast_or_null( + getDerived().TransformDecl(E->getOperatorNew())); + if (!OperatorNew) + return SemaRef.ExprError(); + } + + FunctionDecl *OperatorDelete = 0; + if (E->getOperatorDelete()) { + OperatorDelete = cast_or_null( + getDerived().TransformDecl(E->getOperatorDelete())); + if (!OperatorDelete) + return SemaRef.ExprError(); + } + if (!getDerived().AlwaysRebuild() && AllocType == E->getAllocatedType() && ArraySize.get() == E->getArraySize() && - !ArgumentChanged) + Constructor == E->getConstructor() && + OperatorNew == E->getOperatorNew() && + OperatorDelete == E->getOperatorDelete() && + !ArgumentChanged) { + // Mark any declarations we need as referenced. + // FIXME: instantiation-specific. + if (Constructor) + SemaRef.MarkDeclarationReferenced(E->getLocStart(), Constructor); + if (OperatorNew) + SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorNew); + if (OperatorDelete) + SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorDelete); return SemaRef.Owned(E->Retain()); + } if (!ArraySize.get()) { // If no array size was specified, but the new expression was @@ -4641,9 +4678,24 @@ if (Operand.isInvalid()) return SemaRef.ExprError(); + // Transform the delete operator, if known. + FunctionDecl *OperatorDelete = 0; + if (E->getOperatorDelete()) { + OperatorDelete = cast_or_null( + getDerived().TransformDecl(E->getOperatorDelete())); + if (!OperatorDelete) + return SemaRef.ExprError(); + } + if (!getDerived().AlwaysRebuild() && - Operand.get() == E->getArgument()) + Operand.get() == E->getArgument() && + OperatorDelete == E->getOperatorDelete()) { + // Mark any declarations we need as referenced. + // FIXME: instantiation-specific. + if (OperatorDelete) + SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorDelete); return SemaRef.Owned(E->Retain()); + } return getDerived().RebuildCXXDeleteExpr(E->getLocStart(), E->isGlobalDelete(), @@ -4907,6 +4959,8 @@ T == E->getType() && Constructor == E->getConstructor() && !ArgumentChanged) { + // Mark the constructor as referenced. + // FIXME: Instantiation-specific SemaRef.MarkDeclarationReferenced(E->getLocStart(), Constructor); return SemaRef.Owned(E->Retain()); } Modified: cfe/trunk/test/SemaTemplate/instantiate-expr-1.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-expr-1.cpp?rev=97195&r1=97194&r2=97195&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/instantiate-expr-1.cpp (original) +++ cfe/trunk/test/SemaTemplate/instantiate-expr-1.cpp Thu Feb 25 18:38:10 2010 @@ -152,4 +152,21 @@ }; template void Y<3>::f(); + + template + struct X2 { + void *operator new(__SIZE_TYPE__) { + int *ip = I; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}} + return ip; + } + }; + + template struct Y2 { + typedef X2<7> X; + void f() { + new X(); // expected-note{{instantiation of}} + } + }; + + template void Y2<3>::f(); } From daniel at zuster.org Thu Feb 25 18:40:38 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Thu, 25 Feb 2010 16:40:38 -0800 Subject: [cfe-commits] r97166 - in /cfe/trunk: include/clang/Frontend/CodeGenAction.h lib/Frontend/CodeGenAction.cpp In-Reply-To: <3BBCD72C-6208-4F60-8610-7760EC64EFC5@apple.com> References: <20100225203744.E16BD2A6C12C@llvm.org> <3BBCD72C-6208-4F60-8610-7760EC64EFC5@apple.com> Message-ID: <6a8523d61002251640p2b7acf72pcaf24a108e18ef8c@mail.gmail.com> On Thu, Feb 25, 2010 at 12:58 PM, Douglas Gregor wrote: > > On Feb 25, 2010, at 12:37 PM, Daniel Dunbar wrote: > >> Author: ddunbar >> Date: Thu Feb 25 14:37:44 2010 >> New Revision: 97166 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=97166&view=rev >> Log: >> Move ~CodeGenAction out-of-line. >> >> Modified: >> ? ?cfe/trunk/include/clang/Frontend/CodeGenAction.h >> ? ?cfe/trunk/lib/Frontend/CodeGenAction.cpp >> >> Modified: cfe/trunk/include/clang/Frontend/CodeGenAction.h >> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CodeGenAction.h?rev=97166&r1=97165&r2=97166&view=diff >> ============================================================================== >> --- cfe/trunk/include/clang/Frontend/CodeGenAction.h (original) >> +++ cfe/trunk/include/clang/Frontend/CodeGenAction.h Thu Feb 25 14:37:44 2010 >> @@ -23,6 +23,7 @@ >> >> protected: >> ? CodeGenAction(unsigned _Act); >> + ?~CodeGenAction(); > > This should be public (?). Clang won't diagnose it, but it's breaking with the GCC build. I blame Clang! - Daniel > ? ? ? ?- Doug From rjmccall at apple.com Thu Feb 25 18:48:12 2010 From: rjmccall at apple.com (John McCall) Date: Fri, 26 Feb 2010 00:48:12 -0000 Subject: [cfe-commits] r97197 - in /cfe/trunk: include/clang/AST/CanonicalType.h include/clang/AST/Type.h lib/CodeGen/CGCall.cpp lib/CodeGen/CGCall.h lib/CodeGen/CGObjCGNU.cpp lib/CodeGen/CGObjCMac.cpp lib/CodeGen/CodeGenTypes.cpp lib/CodeGen/CodeGenTypes.h Message-ID: <20100226004812.6BD182A6C12C@llvm.org> Author: rjmccall Date: Thu Feb 25 18:48:12 2010 New Revision: 97197 URL: http://llvm.org/viewvc/llvm-project?rev=97197&view=rev Log: Use the power of types to track down another canonicalization bug in the ABI-computation interface. Fixes . Modified: cfe/trunk/include/clang/AST/CanonicalType.h cfe/trunk/include/clang/AST/Type.h cfe/trunk/lib/CodeGen/CGCall.cpp cfe/trunk/lib/CodeGen/CGCall.h cfe/trunk/lib/CodeGen/CGObjCGNU.cpp cfe/trunk/lib/CodeGen/CGObjCMac.cpp cfe/trunk/lib/CodeGen/CodeGenTypes.cpp cfe/trunk/lib/CodeGen/CodeGenTypes.h Modified: cfe/trunk/include/clang/AST/CanonicalType.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/CanonicalType.h?rev=97197&r1=97196&r2=97197&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/CanonicalType.h (original) +++ cfe/trunk/include/clang/AST/CanonicalType.h Thu Feb 25 18:48:12 2010 @@ -120,6 +120,13 @@ return Stored.isLocalRestrictQualified(); } + /// \brief Determines if this canonical type is furthermore + /// canonical as a parameter. The parameter-canonicalization + /// process decays arrays to pointers and drops top-level qualifiers. + bool isCanonicalAsParam() const { + return Stored.isCanonicalAsParam(); + } + /// \brief Retrieve the unqualified form of this type. CanQual getUnqualifiedType() const; @@ -157,6 +164,10 @@ /// ensure that the given type is a canonical type with the correct // (dynamic) type. static CanQual CreateUnsafe(QualType Other); + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddPointer(getAsOpaquePtr()); + } }; template @@ -172,6 +183,10 @@ /// \brief Represents a canonical, potentially-qualified type. typedef CanQual CanQualType; +inline CanQualType Type::getCanonicalTypeUnqualified() const { + return CanQualType::CreateUnsafe(getCanonicalTypeInternal()); +} + inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, CanQualType T) { DB << static_cast(T); @@ -547,18 +562,24 @@ template<> struct CanProxyAdaptor : public CanProxyBase { LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, getNoReturnAttr) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CallingConv, getCallConv) }; template<> struct CanProxyAdaptor : public CanProxyBase { LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, getNoReturnAttr) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CallingConv, getCallConv) }; template<> struct CanProxyAdaptor : public CanProxyBase { LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, getNoReturnAttr) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CallingConv, getCallConv) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumArgs) CanQualType getArgType(unsigned i) const { return CanQualType::CreateUnsafe(this->getTypePtr()->getArgType(i)); Modified: cfe/trunk/include/clang/AST/Type.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=97197&r1=97196&r2=97197&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Type.h (original) +++ cfe/trunk/include/clang/AST/Type.h Thu Feb 25 18:48:12 2010 @@ -90,9 +90,13 @@ class TemplateArgument; class TemplateArgumentLoc; class TemplateArgumentListInfo; + class Type; class QualifiedNameType; struct PrintingPolicy; + template class CanQual; + typedef CanQual CanQualType; + // Provide forward declarations for all of the *Type classes #define TYPE(Class, Base) class Class##Type; #include "clang/AST/TypeNodes.def" @@ -976,7 +980,10 @@ /// \brief Determine the linkage of this type. virtual Linkage getLinkage() const; - QualType getCanonicalTypeInternal() const { return CanonicalType; } + QualType getCanonicalTypeInternal() const { + return CanonicalType; + } + CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h void dump() const; static bool classof(const Type *) { return true; } }; Modified: cfe/trunk/lib/CodeGen/CGCall.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=97197&r1=97196&r2=97197&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGCall.cpp (original) +++ cfe/trunk/lib/CodeGen/CGCall.cpp Thu Feb 25 18:48:12 2010 @@ -44,28 +44,29 @@ /// Derives the 'this' type for codegen purposes, i.e. ignoring method /// qualification. /// FIXME: address space qualification? -static QualType GetThisType(ASTContext &Context, const CXXRecordDecl *RD) { - return Context.getPointerType(Context.getTagDeclType(RD)); +static CanQualType GetThisType(ASTContext &Context, const CXXRecordDecl *RD) { + QualType RecTy = Context.getTagDeclType(RD)->getCanonicalTypeInternal(); + return Context.getPointerType(CanQualType::CreateUnsafe(RecTy)); } /// Returns the canonical formal type of the given C++ method. -static const FunctionProtoType *GetFormalType(const CXXMethodDecl *MD) { - return cast(MD->getType()->getCanonicalTypeInternal()); +static CanQual GetFormalType(const CXXMethodDecl *MD) { + return MD->getType()->getCanonicalTypeUnqualified() + .getAs(); } /// Returns the "extra-canonicalized" return type, which discards /// qualifiers on the return type. Codegen doesn't care about them, /// and it makes ABI code a little easier to be able to assume that /// all parameter and return types are top-level unqualified. -static QualType GetReturnType(QualType RetTy) { - return RetTy->getCanonicalTypeInternal().getUnqualifiedType(); +static CanQualType GetReturnType(QualType RetTy) { + return RetTy->getCanonicalTypeUnqualified().getUnqualifiedType(); } const CGFunctionInfo & -CodeGenTypes::getFunctionInfo(const FunctionNoProtoType *FTNP) { - assert(FTNP->isCanonicalUnqualified() && "type must be canonical"); - return getFunctionInfo(GetReturnType(FTNP->getResultType()), - llvm::SmallVector(), +CodeGenTypes::getFunctionInfo(CanQual FTNP) { + return getFunctionInfo(FTNP->getResultType().getUnqualifiedType(), + llvm::SmallVector(), FTNP->getCallConv(), FTNP->getNoReturnAttr()); } @@ -73,21 +74,20 @@ /// \param Args - contains any initial parameters besides those /// in the formal type static const CGFunctionInfo &getFunctionInfo(CodeGenTypes &CGT, - llvm::SmallVectorImpl &ArgTys, - const FunctionProtoType *FTP) { - assert(FTP->isCanonicalUnqualified() && "type must be canonical"); + llvm::SmallVectorImpl &ArgTys, + CanQual FTP) { // FIXME: Kill copy. for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) ArgTys.push_back(FTP->getArgType(i)); - return CGT.getFunctionInfo(GetReturnType(FTP->getResultType()), - ArgTys, + CanQualType ResTy = FTP->getResultType().getUnqualifiedType(); + return CGT.getFunctionInfo(ResTy, ArgTys, FTP->getCallConv(), FTP->getNoReturnAttr()); } const CGFunctionInfo & -CodeGenTypes::getFunctionInfo(const FunctionProtoType *FTP) { - llvm::SmallVector ArgTys; +CodeGenTypes::getFunctionInfo(CanQual FTP) { + llvm::SmallVector ArgTys; return ::getFunctionInfo(*this, ArgTys, FTP); } @@ -104,17 +104,17 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD, const FunctionProtoType *FTP) { - llvm::SmallVector ArgTys; + llvm::SmallVector ArgTys; // Add the 'this' pointer. ArgTys.push_back(GetThisType(Context, RD)); return ::getFunctionInfo(*this, ArgTys, - cast(FTP->getCanonicalTypeInternal())); + FTP->getCanonicalTypeUnqualified().getAs()); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) { - llvm::SmallVector ArgTys; + llvm::SmallVector ArgTys; // Add the 'this' pointer unless this is a static method. if (MD->isInstance()) @@ -125,7 +125,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D, CXXCtorType Type) { - llvm::SmallVector ArgTys; + llvm::SmallVector ArgTys; // Add the 'this' pointer. ArgTys.push_back(GetThisType(Context, D->getParent())); @@ -139,10 +139,10 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D, CXXDtorType Type) { - llvm::SmallVector ArgTys; + llvm::SmallVector ArgTys; // Add the 'this' pointer. - ArgTys.push_back(D->getThisType(Context)); + ArgTys.push_back(GetThisType(Context, D->getParent())); // Check if we need to add a VTT parameter (which has type void **). if (Type == Dtor_Base && D->getParent()->getNumVBases() != 0) @@ -156,17 +156,18 @@ if (MD->isInstance()) return getFunctionInfo(MD); - const FunctionType *FTy - = cast(FD->getType()->getCanonicalTypeInternal()); + CanQualType FTy = FD->getType()->getCanonicalTypeUnqualified(); + assert(isa(FTy)); if (isa(FTy)) - return getFunctionInfo(cast(FTy)); - return getFunctionInfo(cast(FTy)); + return getFunctionInfo(FTy.getAs()); + assert(isa(FTy)); + return getFunctionInfo(FTy.getAs()); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) { - llvm::SmallVector ArgTys; - ArgTys.push_back(MD->getSelfDecl()->getType()); - ArgTys.push_back(Context.getObjCSelType()); + llvm::SmallVector ArgTys; + ArgTys.push_back(Context.getCanonicalParamType(MD->getSelfDecl()->getType())); + ArgTys.push_back(Context.getCanonicalParamType(Context.getObjCSelType())); // FIXME: Kill copy? for (ObjCMethodDecl::param_iterator i = MD->param_begin(), e = MD->param_end(); i != e; ++i) { @@ -196,7 +197,7 @@ CallingConv CC, bool NoReturn) { // FIXME: Kill copy. - llvm::SmallVector ArgTys; + llvm::SmallVector ArgTys; for (CallArgList::const_iterator i = Args.begin(), e = Args.end(); i != e; ++i) ArgTys.push_back(Context.getCanonicalParamType(i->second)); @@ -208,17 +209,23 @@ CallingConv CC, bool NoReturn) { // FIXME: Kill copy. - llvm::SmallVector ArgTys; + llvm::SmallVector ArgTys; for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end(); i != e; ++i) ArgTys.push_back(Context.getCanonicalParamType(i->second)); return getFunctionInfo(GetReturnType(ResTy), ArgTys, CC, NoReturn); } -const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, - const llvm::SmallVectorImpl &ArgTys, +const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy, + const llvm::SmallVectorImpl &ArgTys, CallingConv CallConv, bool NoReturn) { +#ifndef NDEBUG + for (llvm::SmallVectorImpl::const_iterator + I = ArgTys.begin(), E = ArgTys.end(); I != E; ++I) + assert(I->isCanonicalAsParam()); +#endif + unsigned CC = ClangCallConvToLLVMCallConv(CallConv); // Lookup or create unique function info. @@ -243,8 +250,8 @@ CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention, bool _NoReturn, - QualType ResTy, - const llvm::SmallVectorImpl &ArgTys) + CanQualType ResTy, + const llvm::SmallVectorImpl &ArgTys) : CallingConvention(_CallingConvention), EffectiveCallingConvention(_CallingConvention), NoReturn(_NoReturn) Modified: cfe/trunk/lib/CodeGen/CGCall.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.h?rev=97197&r1=97196&r2=97197&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGCall.h (original) +++ cfe/trunk/lib/CodeGen/CGCall.h Thu Feb 25 18:48:12 2010 @@ -18,6 +18,7 @@ #include "llvm/ADT/FoldingSet.h" #include "llvm/Value.h" #include "clang/AST/Type.h" +#include "clang/AST/CanonicalType.h" #include "CGValue.h" @@ -57,7 +58,7 @@ /// function definition. class CGFunctionInfo : public llvm::FoldingSetNode { struct ArgInfo { - QualType type; + CanQualType type; ABIArgInfo info; }; @@ -81,8 +82,8 @@ CGFunctionInfo(unsigned CallingConvention, bool NoReturn, - QualType ResTy, - const llvm::SmallVectorImpl &ArgTys); + CanQualType ResTy, + const llvm::SmallVectorImpl &ArgTys); ~CGFunctionInfo() { delete[] Args; } const_arg_iterator arg_begin() const { return Args + 1; } @@ -107,7 +108,7 @@ EffectiveCallingConvention = Value; } - QualType getReturnType() const { return Args[0].type; } + CanQualType getReturnType() const { return Args[0].type; } ABIArgInfo &getReturnInfo() { return Args[0].info; } const ABIArgInfo &getReturnInfo() const { return Args[0].info; } @@ -123,14 +124,16 @@ static void Profile(llvm::FoldingSetNodeID &ID, unsigned CallingConvention, bool NoReturn, - QualType ResTy, + CanQualType ResTy, Iterator begin, Iterator end) { ID.AddInteger(CallingConvention); ID.AddBoolean(NoReturn); ResTy.Profile(ID); - for (; begin != end; ++begin) - begin->Profile(ID); + for (; begin != end; ++begin) { + CanQualType T = *begin; // force iterator to be over canonical types + T.Profile(ID); + } } }; Modified: cfe/trunk/lib/CodeGen/CGObjCGNU.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCGNU.cpp?rev=97197&r1=97196&r2=97197&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGObjCGNU.cpp (original) +++ cfe/trunk/lib/CodeGen/CGObjCGNU.cpp Thu Feb 25 18:48:12 2010 @@ -56,7 +56,7 @@ const llvm::FunctionType *IMPTy; const llvm::PointerType *IdTy; const llvm::PointerType *PtrToIdTy; - QualType ASTIdTy; + CanQualType ASTIdTy; const llvm::IntegerType *IntTy; const llvm::PointerType *PtrTy; const llvm::IntegerType *LongTy; @@ -262,7 +262,7 @@ PtrTy = PtrToInt8Ty; // Object type - ASTIdTy = CGM.getContext().getObjCIdType(); + ASTIdTy = CGM.getContext().getCanonicalType(CGM.getContext().getObjCIdType()); if (QualType() == ASTIdTy) { IdTy = PtrToInt8Ty; } else { @@ -1685,7 +1685,7 @@ CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); // void objc_enumerationMutation (id) - llvm::SmallVector Params; + llvm::SmallVector Params; Params.push_back(ASTIdTy); const llvm::FunctionType *FTy = Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params, Modified: cfe/trunk/lib/CodeGen/CGObjCMac.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCMac.cpp?rev=97197&r1=97196&r2=97197&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGObjCMac.cpp (original) +++ cfe/trunk/lib/CodeGen/CGObjCMac.cpp Thu Feb 25 18:48:12 2010 @@ -297,9 +297,9 @@ CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); // id objc_getProperty (id, SEL, ptrdiff_t, bool) - llvm::SmallVector Params; - QualType IdType = Ctx.getObjCIdType(); - QualType SelType = Ctx.getObjCSelType(); + llvm::SmallVector Params; + CanQualType IdType = Ctx.getCanonicalParamType(Ctx.getObjCIdType()); + CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType()); Params.push_back(IdType); Params.push_back(SelType); Params.push_back(Ctx.LongTy); @@ -314,9 +314,9 @@ CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); // void objc_setProperty (id, SEL, ptrdiff_t, id, bool, bool) - llvm::SmallVector Params; - QualType IdType = Ctx.getObjCIdType(); - QualType SelType = Ctx.getObjCSelType(); + llvm::SmallVector Params; + CanQualType IdType = Ctx.getCanonicalParamType(Ctx.getObjCIdType()); + CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType()); Params.push_back(IdType); Params.push_back(SelType); Params.push_back(Ctx.LongTy); @@ -333,8 +333,8 @@ CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); // void objc_enumerationMutation (id) - llvm::SmallVector Params; - Params.push_back(Ctx.getObjCIdType()); + llvm::SmallVector Params; + Params.push_back(Ctx.getCanonicalParamType(Ctx.getObjCIdType())); const llvm::FunctionType *FTy = Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params, CC_Default, false), false); @@ -5093,9 +5093,8 @@ // Find the message function name. // FIXME. This is too much work to get the ABI-specific result type needed to // find the message name. - const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, - llvm::SmallVector(), - CC_Default, false); + const CGFunctionInfo &FnInfo + = Types.getFunctionInfo(ResultType, CallArgList(), CC_Default, false); llvm::Constant *Fn = 0; std::string Name("\01l_"); if (CGM.ReturnTypeUsesSret(FnInfo)) { Modified: cfe/trunk/lib/CodeGen/CodeGenTypes.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenTypes.cpp?rev=97197&r1=97196&r2=97197&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenTypes.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenTypes.cpp Thu Feb 25 18:48:12 2010 @@ -313,10 +313,14 @@ // The function type can be built; call the appropriate routines to // build it. if (const FunctionProtoType *FPT = dyn_cast(&Ty)) - return GetFunctionType(getFunctionInfo(FPT), FPT->isVariadic()); + return GetFunctionType(getFunctionInfo( + CanQual::CreateUnsafe(QualType(FPT,0))), + FPT->isVariadic()); const FunctionNoProtoType *FNPT = cast(&Ty); - return GetFunctionType(getFunctionInfo(FNPT), true); + return GetFunctionType(getFunctionInfo( + CanQual::CreateUnsafe(QualType(FNPT,0))), + true); } case Type::ObjCInterface: { Modified: cfe/trunk/lib/CodeGen/CodeGenTypes.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenTypes.h?rev=97197&r1=97196&r2=97197&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenTypes.h (original) +++ cfe/trunk/lib/CodeGen/CodeGenTypes.h Thu Feb 25 18:48:12 2010 @@ -35,6 +35,7 @@ namespace clang { class ABIInfo; class ASTContext; + template class CanQual; class CXXConstructorDecl; class CXXDestructorDecl; class CXXMethodDecl; @@ -48,6 +49,7 @@ class TagDecl; class TargetInfo; class Type; + typedef CanQual CanQualType; namespace CodeGen { class CodeGenTypes; @@ -202,8 +204,8 @@ return getFunctionInfo(Ty->getResultType(), Args, Ty->getCallConv(), Ty->getNoReturnAttr()); } - const CGFunctionInfo &getFunctionInfo(const FunctionProtoType *Ty); - const CGFunctionInfo &getFunctionInfo(const FunctionNoProtoType *Ty); + const CGFunctionInfo &getFunctionInfo(CanQual Ty); + const CGFunctionInfo &getFunctionInfo(CanQual Ty); // getFunctionInfo - Get the function info for a member function. const CGFunctionInfo &getFunctionInfo(const CXXRecordDecl *RD, @@ -220,8 +222,12 @@ const FunctionArgList &Args, CallingConv CC, bool NoReturn); - const CGFunctionInfo &getFunctionInfo(QualType RetTy, - const llvm::SmallVectorImpl &ArgTys, + + /// Retrieves the ABI information for the given function signature. + /// + /// \param ArgTys - must all actually be canonical as params + const CGFunctionInfo &getFunctionInfo(CanQualType RetTy, + const llvm::SmallVectorImpl &ArgTys, CallingConv CC, bool NoReturn); From csdavec at swan.ac.uk Thu Feb 25 19:11:38 2010 From: csdavec at swan.ac.uk (David Chisnall) Date: Fri, 26 Feb 2010 01:11:38 -0000 Subject: [cfe-commits] r97199 - /cfe/trunk/lib/CodeGen/CGObjCGNU.cpp Message-ID: <20100226011138.4B4812A6C12C@llvm.org> Author: theraven Date: Thu Feb 25 19:11:38 2010 New Revision: 97199 URL: http://llvm.org/viewvc/llvm-project?rev=97199&view=rev Log: Don't generate method metadata for @dynamic properties. Fixes PR6354. Modified: cfe/trunk/lib/CodeGen/CGObjCGNU.cpp Modified: cfe/trunk/lib/CodeGen/CGObjCGNU.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCGNU.cpp?rev=97199&r1=97198&r2=97199&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGObjCGNU.cpp (original) +++ cfe/trunk/lib/CodeGen/CGObjCGNU.cpp Thu Feb 25 19:11:38 2010 @@ -1192,19 +1192,22 @@ iter != endIter ; iter++) { std::vector Fields; ObjCPropertyDecl *property = (*iter)->getPropertyDecl(); + ObjCPropertyImplDecl *propertyImpl = *iter; + bool isSynthesized = (propertyImpl->getPropertyImplementation() == + ObjCPropertyImplDecl::Synthesize); Fields.push_back(MakeConstantString(property->getNameAsString())); Fields.push_back(llvm::ConstantInt::get(Int8Ty, property->getPropertyAttributes())); - Fields.push_back(llvm::ConstantInt::get(Int8Ty, - (*iter)->getPropertyImplementation() == - ObjCPropertyImplDecl::Synthesize)); + Fields.push_back(llvm::ConstantInt::get(Int8Ty, isSynthesized)); if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) { - InstanceMethodSels.push_back(getter->getSelector()); std::string TypeStr; Context.getObjCEncodingForMethodDecl(getter,TypeStr); llvm::Constant *TypeEncoding = MakeConstantString(TypeStr); - InstanceMethodTypes.push_back(TypeEncoding); + if (isSynthesized) { + InstanceMethodTypes.push_back(TypeEncoding); + InstanceMethodSels.push_back(getter->getSelector()); + } Fields.push_back(MakeConstantString(getter->getSelector().getAsString())); Fields.push_back(TypeEncoding); } else { @@ -1212,11 +1215,13 @@ Fields.push_back(NULLPtr); } if (ObjCMethodDecl *setter = property->getSetterMethodDecl()) { - InstanceMethodSels.push_back(setter->getSelector()); std::string TypeStr; Context.getObjCEncodingForMethodDecl(setter,TypeStr); llvm::Constant *TypeEncoding = MakeConstantString(TypeStr); - InstanceMethodTypes.push_back(TypeEncoding); + if (isSynthesized) { + InstanceMethodTypes.push_back(TypeEncoding); + InstanceMethodSels.push_back(setter->getSelector()); + } Fields.push_back(MakeConstantString(setter->getSelector().getAsString())); Fields.push_back(TypeEncoding); } else { From dgregor at apple.com Thu Feb 25 19:17:27 2010 From: dgregor at apple.com (Douglas Gregor) Date: Fri, 26 Feb 2010 01:17:27 -0000 Subject: [cfe-commits] r97202 - in /cfe/trunk: lib/Sema/SemaInit.cpp test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp Message-ID: <20100226011727.D2E032A6C12C@llvm.org> Author: dgregor Date: Thu Feb 25 19:17:27 2010 New Revision: 97202 URL: http://llvm.org/viewvc/llvm-project?rev=97202&view=rev Log: Commit Eli's fix for implicit conversions to array type. Fixes PR6264. Modified: cfe/trunk/lib/Sema/SemaInit.cpp cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp Modified: cfe/trunk/lib/Sema/SemaInit.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=97202&r1=97201&r2=97202&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaInit.cpp (original) +++ cfe/trunk/lib/Sema/SemaInit.cpp Thu Feb 25 19:17:27 2010 @@ -2227,7 +2227,7 @@ ToType, CandidateSet); else S.AddConversionCandidate(Conv, I.getAccess(), ActingDC, - Initializer, cv1T1, CandidateSet); + Initializer, ToType, CandidateSet); } } } Modified: cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp?rev=97202&r1=97201&r2=97202&view=diff ============================================================================== --- cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp (original) +++ cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5.cpp Thu Feb 25 19:17:27 2010 @@ -10,3 +10,15 @@ const Foo f = { 0 }; // It compiles without the 'const'. bool z = Test(f.x); } + +namespace PR6264 { + typedef int (&T)[3]; + struct S + { + operator T (); + }; + void f() + { + T bar = S(); + } +} From fjahanian at apple.com Thu Feb 25 19:42:20 2010 From: fjahanian at apple.com (Fariborz Jahanian) Date: Fri, 26 Feb 2010 01:42:20 -0000 Subject: [cfe-commits] r97203 - in /cfe/trunk: lib/Frontend/RewriteObjC.cpp test/Rewriter/rewrite-property-attributes.mm Message-ID: <20100226014220.893EB2A6C12C@llvm.org> Author: fjahanian Date: Thu Feb 25 19:42:20 2010 New Revision: 97203 URL: http://llvm.org/viewvc/llvm-project?rev=97203&view=rev Log: Support rewriting of property synthesis with retain/copy attributes. Fixes radar 7214439. Added: cfe/trunk/test/Rewriter/rewrite-property-attributes.mm Modified: cfe/trunk/lib/Frontend/RewriteObjC.cpp Modified: cfe/trunk/lib/Frontend/RewriteObjC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/RewriteObjC.cpp?rev=97203&r1=97202&r2=97203&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/RewriteObjC.cpp (original) +++ cfe/trunk/lib/Frontend/RewriteObjC.cpp Thu Feb 25 19:42:20 2010 @@ -256,6 +256,8 @@ void RewriteInterfaceDecl(ObjCInterfaceDecl *Dcl); void RewriteImplementationDecl(Decl *Dcl); void RewriteObjCMethodDecl(ObjCMethodDecl *MDecl, std::string &ResultStr); + void RewriteTypeIntoString(QualType T, std::string &ResultStr, + const FunctionType *&FPRetType); void RewriteByRefString(std::string &ResultStr, const std::string &Name, ValueDecl *VD); void RewriteCategoryDecl(ObjCCategoryDecl *Dcl); @@ -349,7 +351,7 @@ std::string &Result); void SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, std::string &Result); - void SynthesizeIvarOffsetComputation(ObjCImplementationDecl *IDecl, + void SynthesizeIvarOffsetComputation(ObjCContainerDecl *IDecl, ObjCIvarDecl *ivar, std::string &Result); void RewriteImplementations(); @@ -558,7 +560,7 @@ Preamble += "#define __OBJC_RW_DLLIMPORT extern \"C\" __declspec(dllimport)\n"; Preamble += "#define __OBJC_RW_STATICIMPORT extern \"C\"\n"; } else - Preamble += "#define __OBJC_RW_DLLIMPORT extern\n"; + Preamble += "#define __OBJC_RW_DLLIMPORT extern\n"; Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSend"; Preamble += "(struct objc_object *, struct objc_selector *, ...);\n"; Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper"; @@ -617,7 +619,8 @@ Preamble += "};\n"; Preamble += "// Runtime copy/destroy helper functions (from Block_private.h)\n"; Preamble += "#ifdef __OBJC_EXPORT_BLOCKS\n"; - Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_assign(void *, const void *, const int);\n"; + Preamble += "extern \"C\" __declspec(dllexport) " + "void _Block_object_assign(void *, const void *, const int);\n"; Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_dispose(const void *, const int);\n"; Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];\n"; Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteStackBlock[32];\n"; @@ -638,6 +641,7 @@ Preamble += "#define __block\n"; Preamble += "#define __weak\n"; } + Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long) &((TYPE *)0)->MEMBER)\n"; } @@ -761,6 +765,8 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, ObjCImplementationDecl *IMD, ObjCCategoryImplDecl *CID) { + static bool objcGetPropertyDefined = false; + static bool objcSetPropertyDefined = false; SourceLocation startLoc = PID->getLocStart(); InsertText(startLoc, "// "); const char *startBuf = SM->getCharacterData(startLoc); @@ -780,15 +786,55 @@ if (!OID) return; - + unsigned Attributes = PD->getPropertyAttributes(); + bool GenGetProperty = !(Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) && + (Attributes & (ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_copy)); std::string Getr; + if (GenGetProperty && !objcGetPropertyDefined) { + objcGetPropertyDefined = true; + // FIXME. Is this attribute correct in all cases? + Getr = "\nextern \"C\" __declspec(dllimport) " + "id objc_getProperty(id, SEL, long, bool);\n"; + } RewriteObjCMethodDecl(PD->getGetterMethodDecl(), Getr); Getr += "{ "; // Synthesize an explicit cast to gain access to the ivar. - // FIXME: deal with code generation implications for various property - // attributes (copy, retain, nonatomic). // See objc-act.c:objc_synthesize_new_getter() for details. - Getr += "return " + getIvarAccessString(ClassDecl, OID); + if (GenGetProperty) { + // return objc_getProperty(self, _cmd, offsetof(ClassDecl, OID), 1) + Getr += "typedef "; + const FunctionType *FPRetType = 0; + RewriteTypeIntoString(PD->getGetterMethodDecl()->getResultType(), Getr, + FPRetType); + Getr += " _TYPE"; + if (FPRetType) { + Getr += ")"; // close the precedence "scope" for "*". + + // Now, emit the argument types (if any). + if (const FunctionProtoType *FT = dyn_cast(FPRetType)) { + Getr += "("; + for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) { + if (i) Getr += ", "; + std::string ParamStr = FT->getArgType(i).getAsString(); + Getr += ParamStr; + } + if (FT->isVariadic()) { + if (FT->getNumArgs()) Getr += ", "; + Getr += "..."; + } + Getr += ")"; + } else + Getr += "()"; + } + Getr += ";\n"; + Getr += "return (_TYPE)"; + Getr += "objc_getProperty(self, _cmd, "; + SynthesizeIvarOffsetComputation(ClassDecl, OID, Getr); + Getr += ", 1)"; + } + else + Getr += "return " + getIvarAccessString(ClassDecl, OID); Getr += "; }"; InsertText(onePastSemiLoc, Getr); if (PD->isReadOnly()) @@ -796,14 +842,38 @@ // Generate the 'setter' function. std::string Setr; + bool GenSetProperty = Attributes & (ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_copy); + if (GenSetProperty && !objcSetPropertyDefined) { + objcSetPropertyDefined = true; + // FIXME. Is this attribute correct in all cases? + Setr = "\nextern \"C\" __declspec(dllimport) " + "void objc_setProperty (id, SEL, long, id, bool, bool);\n"; + } + RewriteObjCMethodDecl(PD->getSetterMethodDecl(), Setr); Setr += "{ "; // Synthesize an explicit cast to initialize the ivar. - // FIXME: deal with code generation implications for various property - // attributes (copy, retain, nonatomic). // See objc-act.c:objc_synthesize_new_setter() for details. - Setr += getIvarAccessString(ClassDecl, OID) + " = "; - Setr += PD->getNameAsCString(); + if (GenSetProperty) { + Setr += "objc_setProperty (self, _cmd, "; + SynthesizeIvarOffsetComputation(ClassDecl, OID, Setr); + Setr += ", (id)"; + Setr += PD->getNameAsCString(); + Setr += ", "; + if (Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) + Setr += "0, "; + else + Setr += "1, "; + if (Attributes & ObjCPropertyDecl::OBJC_PR_copy) + Setr += "1)"; + else + Setr += "0)"; + } + else { + Setr += getIvarAccessString(ClassDecl, OID) + " = "; + Setr += PD->getNameAsCString(); + } Setr += "; }"; InsertText(onePastSemiLoc, Setr); } @@ -940,18 +1010,15 @@ ReplaceText(LocStart, 0, "// "); } -void RewriteObjC::RewriteObjCMethodDecl(ObjCMethodDecl *OMD, - std::string &ResultStr) { - //fprintf(stderr,"In RewriteObjCMethodDecl\n"); - const FunctionType *FPRetType = 0; - ResultStr += "\nstatic "; - if (OMD->getResultType()->isObjCQualifiedIdType()) +void RewriteObjC::RewriteTypeIntoString(QualType T, std::string &ResultStr, + const FunctionType *&FPRetType) { + if (T->isObjCQualifiedIdType()) ResultStr += "id"; - else if (OMD->getResultType()->isFunctionPointerType() || - OMD->getResultType()->isBlockPointerType()) { + else if (T->isFunctionPointerType() || + T->isBlockPointerType()) { // needs special handling, since pointer-to-functions have special // syntax (where a decaration models use). - QualType retType = OMD->getResultType(); + QualType retType = T; QualType PointeeTy; if (const PointerType* PT = retType->getAs()) PointeeTy = PT->getPointeeType(); @@ -962,7 +1029,15 @@ ResultStr += "(*"; } } else - ResultStr += OMD->getResultType().getAsString(); + ResultStr += T.getAsString(); +} + +void RewriteObjC::RewriteObjCMethodDecl(ObjCMethodDecl *OMD, + std::string &ResultStr) { + //fprintf(stderr,"In RewriteObjCMethodDecl\n"); + const FunctionType *FPRetType = 0; + ResultStr += "\nstatic "; + RewriteTypeIntoString(OMD->getResultType(), ResultStr, FPRetType); ResultStr += " "; // Unique method name @@ -3509,7 +3584,7 @@ /// SynthesizeIvarOffsetComputation - This rutine synthesizes computation of /// ivar offset. -void RewriteObjC::SynthesizeIvarOffsetComputation(ObjCImplementationDecl *IDecl, +void RewriteObjC::SynthesizeIvarOffsetComputation(ObjCContainerDecl *IDecl, ObjCIvarDecl *ivar, std::string &Result) { if (ivar->isBitField()) { @@ -3807,9 +3882,7 @@ void RewriteObjC::SynthesizeMetaDataIntoBuffer(std::string &Result) { int ClsDefCount = ClassImplementation.size(); int CatDefCount = CategoryImplementation.size(); - - // This is needed for determining instance variable offsets. - Result += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long) &((TYPE *)0)->MEMBER)\n"; + // For each implemented class, write out all its meta data. for (int i = 0; i < ClsDefCount; i++) RewriteObjCClassMetaData(ClassImplementation[i], Result); Added: cfe/trunk/test/Rewriter/rewrite-property-attributes.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Rewriter/rewrite-property-attributes.mm?rev=97203&view=auto ============================================================================== --- cfe/trunk/test/Rewriter/rewrite-property-attributes.mm (added) +++ cfe/trunk/test/Rewriter/rewrite-property-attributes.mm Thu Feb 25 19:42:20 2010 @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// radar 7214439 + +typedef void (^void_block_t)(void); + + at interface Y { + void_block_t __completion; + Y* YVAR; + id ID; +} + at property (copy) void_block_t completionBlock; + at property (retain) Y* Yblock; + at property (copy) id ID; + at end + + at implementation Y + at synthesize completionBlock=__completion; + at synthesize Yblock = YVAR; + at synthesize ID; + at end + From xuzhongxing at gmail.com Thu Feb 25 20:13:28 2010 From: xuzhongxing at gmail.com (Zhongxing Xu) Date: Fri, 26 Feb 2010 10:13:28 +0800 Subject: [cfe-commits] r97162 - in /cfe/trunk: include/clang/Analysis/ include/clang/Analysis/Support/ include/clang/Checker/PathSensitive/ include/clang/Frontend/ lib/Checker/ lib/Frontend/ lib/Sema/ test/Sema/ test/SemaCXX/ test/SemaObjCXX/ test/SemaTem Message-ID: <5400aeb81002251813x21816782p78547f75a3c39300@mail.gmail.com> Thanks Doug! 2010/2/26 Douglas Gregor : > Author: dgregor > Date: Thu Feb 25 13:01:53 2010 > New Revision: 97162 > > URL: http://llvm.org/viewvc/llvm-project?rev=97162&view=rev > Log: > Restore Zhongxing's commits r97122 r97127 r97129 r97131 which were reverted due to a Clang-on-Clang failure > > Modified: > ? ?cfe/trunk/include/clang/Analysis/ProgramPoint.h > ? ?cfe/trunk/include/clang/Analysis/Support/BlkExprDeclBitVector.h ? (props changed) > ? ?cfe/trunk/include/clang/Checker/PathSensitive/Checker.h > ? ?cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h > ? ?cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h > ? ?cfe/trunk/include/clang/Checker/PathSensitive/GRState.h ? (props changed) > ? ?cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h > ? ?cfe/trunk/include/clang/Frontend/ASTConsumers.h ? (props changed) > ? ?cfe/trunk/include/clang/Frontend/Analyses.def ? (props changed) > ? ?cfe/trunk/include/clang/Frontend/AnalysisConsumer.h ? (props changed) > ? ?cfe/trunk/include/clang/Frontend/PathDiagnosticClients.h ? (props changed) > ? ?cfe/trunk/include/clang/Frontend/Utils.h ? (props changed) > ? ?cfe/trunk/lib/Checker/CallInliner.cpp > ? ?cfe/trunk/lib/Checker/GRCoreEngine.cpp > ? ?cfe/trunk/lib/Checker/GRExprEngine.cpp > ? ?cfe/trunk/lib/Checker/GRState.cpp ? (props changed) > ? ?cfe/trunk/lib/Frontend/ASTConsumers.cpp ? (props changed) > ? ?cfe/trunk/lib/Frontend/AnalysisConsumer.cpp ? (props changed) > ? ?cfe/trunk/lib/Frontend/CacheTokens.cpp ? (props changed) > ? ?cfe/trunk/lib/Frontend/CodeGenAction.cpp ? (props changed) > ? ?cfe/trunk/lib/Frontend/DependencyFile.cpp ? (props changed) > ? ?cfe/trunk/lib/Frontend/DiagChecker.cpp ? (props changed) > ? ?cfe/trunk/lib/Frontend/GeneratePCH.cpp ? (props changed) > ? ?cfe/trunk/lib/Frontend/HTMLPrint.cpp ? (props changed) > ? ?cfe/trunk/lib/Frontend/PrintParserCallbacks.cpp ? (props changed) > ? ?cfe/trunk/lib/Frontend/PrintPreprocessedOutput.cpp ? (props changed) > ? ?cfe/trunk/lib/Frontend/RewriteMacros.cpp ? (props changed) > ? ?cfe/trunk/lib/Frontend/RewriteObjC.cpp ? (props changed) > ? ?cfe/trunk/lib/Frontend/RewriteTest.cpp ? (props changed) > ? ?cfe/trunk/lib/Frontend/Warnings.cpp ? (props changed) > ? ?cfe/trunk/lib/Sema/SemaCXXCast.cpp ? (props changed) > ? ?cfe/trunk/test/Sema/dllimport-dllexport.c ? (props changed) > ? ?cfe/trunk/test/SemaCXX/ambig-user-defined-conversions.cpp ? (props changed) > ? ?cfe/trunk/test/SemaObjCXX/protocol-lookup.mm ? (props changed) > ? ?cfe/trunk/test/SemaTemplate/typename-specifier-3.cpp ? (props changed) > ? ?cfe/trunk/tools/scan-build/ccc-analyzer ? (props changed) > ? ?cfe/trunk/tools/scan-build/scan-build ? (props changed) > ? ?cfe/trunk/tools/scan-build/scanview.css ? (props changed) > ? ?cfe/trunk/tools/scan-build/sorttable.js ? (props changed) > ? ?cfe/trunk/utils/analyzer/ubiviz ? (props changed) > > Modified: cfe/trunk/include/clang/Analysis/ProgramPoint.h > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/ProgramPoint.h?rev=97162&r1=97161&r2=97162&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Analysis/ProgramPoint.h (original) > +++ cfe/trunk/include/clang/Analysis/ProgramPoint.h Thu Feb 25 13:01:53 2010 > @@ -26,6 +26,7 @@ > ?namespace clang { > > ?class LocationContext; > +class FunctionDecl; > > ?class ProgramPoint { > ?public: > @@ -41,6 +42,8 @@ > ? ? ? ? ? ? ? PostPurgeDeadSymbolsKind, > ? ? ? ? ? ? ? PostStmtCustomKind, > ? ? ? ? ? ? ? PostLValueKind, > + ? ? ? ? ? ? ?CallEnterKind, > + ? ? ? ? ? ? ?CallExitKind, > ? ? ? ? ? ? ? MinPostStmtKind = PostStmtKind, > ? ? ? ? ? ? ? MaxPostStmtKind = PostLValueKind }; > > @@ -308,6 +311,36 @@ > ? } > ?}; > > +class CallEnter : public StmtPoint { > +public: > + ?// CallEnter uses the caller's location context. > + ?CallEnter(const Stmt *S, const FunctionDecl *fd, const LocationContext *L) > + ? ?: StmtPoint(S, fd, CallEnterKind, L, 0) {} > + > + ?const Stmt *getCallExpr() const { > + ? ?return static_cast(getData1()); > + ?} > + > + ?const FunctionDecl *getCallee() const { > + ? ?return static_cast(getData2()); > + ?} > + > + ?static bool classof(const ProgramPoint *Location) { > + ? ?return Location->getKind() == CallEnterKind; > + ?} > +}; > + > +class CallExit : public StmtPoint { > +public: > + ?// CallExit uses the callee's location context. > + ?CallExit(const Stmt *S, const LocationContext *L) > + ? ?: StmtPoint(S, 0, CallExitKind, L, 0) {} > + > + ?static bool classof(const ProgramPoint *Location) { > + ? ?return Location->getKind() == CallExitKind; > + ?} > +}; > + > > ?} // end namespace clang > > > Propchange: cfe/trunk/include/clang/Analysis/Support/BlkExprDeclBitVector.h > ------------------------------------------------------------------------------ > ? ?(empty) > > Modified: cfe/trunk/include/clang/Checker/PathSensitive/Checker.h > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/Checker.h?rev=97162&r1=97161&r2=97162&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Checker/PathSensitive/Checker.h (original) > +++ cfe/trunk/include/clang/Checker/PathSensitive/Checker.h Thu Feb 25 13:01:53 2010 > @@ -155,6 +155,14 @@ > ? ? ? Dst.Add(Pred); > ? } > > + ?// Generate a node with a new program point different from the one that will > + ?// be created by the GRStmtNodeBuilder. > + ?void addTransition(const GRState *state, ProgramPoint Loc) { > + ? ?ExplodedNode *N = B.generateNode(Loc, state, Pred); > + ? ?if (N) > + ? ? ?addTransition(N); > + ?} > + > ? void EmitReport(BugReport *R) { > ? ? Eng.getBugReporter().EmitReport(R); > ? } > > Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h?rev=97162&r1=97161&r2=97162&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h (original) > +++ cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h Thu Feb 25 13:01:53 2010 > @@ -40,6 +40,8 @@ > ? friend class GRIndirectGotoNodeBuilder; > ? friend class GRSwitchNodeBuilder; > ? friend class GREndPathNodeBuilder; > + ?friend class GRCallEnterNodeBuilder; > + ?friend class GRCallExitNodeBuilder; > > ? GRSubEngine& SubEngine; > > @@ -67,6 +69,9 @@ > > ? void HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock* B, > ? ? ? ? ? ? ? ? ? ? ExplodedNode* Pred); > + ?void HandleCallEnter(const CallEnter &L, const CFGBlock *Block, > + ? ? ? ? ? ? ? ? ? ? ? unsigned Index, ExplodedNode *Pred); > + ?void HandleCallExit(const CallExit &L, ExplodedNode *Pred); > > ? /// Get the initial state from the subengine. > ? const GRState* getInitialState(const LocationContext *InitLoc) { > @@ -90,6 +95,9 @@ > > ? void ProcessSwitch(GRSwitchNodeBuilder& Builder); > > + ?void ProcessCallEnter(GRCallEnterNodeBuilder &Builder); > + ?void ProcessCallExit(GRCallExitNodeBuilder &Builder); > + > ?private: > ? GRCoreEngine(const GRCoreEngine&); // Do not implement. > ? GRCoreEngine& operator=(const GRCoreEngine&); > @@ -194,6 +202,12 @@ > ? ? return generateNode(S, St, Pred, PointKind); > ? } > > + ?ExplodedNode *generateNode(const ProgramPoint &PP, const GRState* State, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ExplodedNode* Pred) { > + ? ?HasGeneratedNode = true; > + ? ?return generateNodeInternal(PP, State, Pred); > + ?} > + > ? ExplodedNode* > ? generateNodeInternal(const ProgramPoint &PP, const GRState* State, > ? ? ? ? ? ? ? ? ? ? ? ?ExplodedNode* Pred); > @@ -431,6 +445,8 @@ > ? ExplodedNode* generateNode(const GRState* State, const void *tag = 0, > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?ExplodedNode *P = 0); > > + ?void GenerateCallExitNode(const GRState *state); > + > ? CFGBlock* getBlock() const { return &B; } > > ? const GRState* getState() const { > @@ -438,6 +454,60 @@ > ? } > ?}; > > +class GRCallEnterNodeBuilder { > + ?GRCoreEngine &Eng; > + > + ?const ExplodedNode *Pred; > + > + ?// The call site. > + ?const Stmt *CE; > + > + ?// The definition of callee. > + ?const FunctionDecl *FD; > + > + ?// The parent block of the CallExpr. > + ?const CFGBlock *Block; > + > + ?// The CFGBlock index of the CallExpr. > + ?unsigned Index; > + > +public: > + ?GRCallEnterNodeBuilder(GRCoreEngine &eng, const ExplodedNode *pred, > + ? ? ? ? ? ? ? ? ? ? ? ? const Stmt *s, const FunctionDecl *fd, > + ? ? ? ? ? ? ? ? ? ? ? ? const CFGBlock *blk, unsigned idx) > + ? ?: Eng(eng), Pred(pred), CE(s), FD(fd), Block(blk), Index(idx) {} > + > + ?const GRState *getState() const { return Pred->getState(); } > + > + ?const LocationContext *getLocationContext() const { > + ? ?return Pred->getLocationContext(); > + ?} > + > + ?const Stmt *getCallExpr() const { return CE; } > + > + ?const FunctionDecl *getCallee() const { return FD; } > + > + ?const CFGBlock *getBlock() const { return Block; } > + > + ?unsigned getIndex() const { return Index; } > + > + ?void GenerateNode(const GRState *state, const LocationContext *LocCtx); > +}; > + > +class GRCallExitNodeBuilder { > + ?GRCoreEngine &Eng; > + ?const ExplodedNode *Pred; > + > +public: > + ?GRCallExitNodeBuilder(GRCoreEngine &eng, const ExplodedNode *pred) > + ? ?: Eng(eng), Pred(pred) {} > + > + ?const ExplodedNode *getPredecessor() const { return Pred; } > + > + ?const GRState *getState() const { return Pred->getState(); } > + > + ?void GenerateNode(const GRState *state); > +}; > ?} // end clang namespace > > ?#endif > > Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h?rev=97162&r1=97161&r2=97162&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h (original) > +++ cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h Thu Feb 25 13:01:53 2010 > @@ -171,7 +171,13 @@ > ? /// ProcessEndPath - Called by GRCoreEngine. ?Used to generate end-of-path > ? /// ?nodes when the control reaches the end of a function. > ? void ProcessEndPath(GREndPathNodeBuilder& builder); > - > + > + ?// Generate the entry node of the callee. > + ?void ProcessCallEnter(GRCallEnterNodeBuilder &builder); > + > + ?// Generate the first post callsite node. > + ?void ProcessCallExit(GRCallExitNodeBuilder &builder); > + > ? /// EvalAssume - Callback function invoked by the ConstraintManager when > ? /// ?making assumptions about state values. > ? const GRState *ProcessAssume(const GRState *state, SVal cond, bool assumption); > > Propchange: cfe/trunk/include/clang/Checker/PathSensitive/GRState.h > ------------------------------------------------------------------------------ > ? ?(empty) > > Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h?rev=97162&r1=97161&r2=97162&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h (original) > +++ cfe/trunk/include/clang/Checker/PathSensitive/GRSubEngine.h Thu Feb 25 13:01:53 2010 > @@ -28,6 +28,8 @@ > ?class GRIndirectGotoNodeBuilder; > ?class GRSwitchNodeBuilder; > ?class GREndPathNodeBuilder; > +class GRCallEnterNodeBuilder; > +class GRCallExitNodeBuilder; > ?class LocationContext; > > ?class GRSubEngine { > @@ -64,6 +66,12 @@ > ? /// ProcessEndPath - Called by GRCoreEngine. ?Used to generate end-of-path > ? /// ?nodes when the control reaches the end of a function. > ? virtual void ProcessEndPath(GREndPathNodeBuilder& builder) = 0; > + > + ?// Generate the entry node of the callee. > + ?virtual void ProcessCallEnter(GRCallEnterNodeBuilder &builder) = 0; > + > + ?// Generate the first post callsite node. > + ?virtual void ProcessCallExit(GRCallExitNodeBuilder &builder) = 0; > > ? /// EvalAssume - Called by ConstraintManager. Used to call checker-specific > ? /// ?logic for handling assumptions on symbolic values. > > Propchange: cfe/trunk/include/clang/Frontend/ASTConsumers.h > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/include/clang/Frontend/Analyses.def > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/include/clang/Frontend/AnalysisConsumer.h > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/include/clang/Frontend/PathDiagnosticClients.h > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/include/clang/Frontend/Utils.h > ------------------------------------------------------------------------------ > ? ?(empty) > > Modified: cfe/trunk/lib/Checker/CallInliner.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/CallInliner.cpp?rev=97162&r1=97161&r2=97162&view=diff > ============================================================================== > --- cfe/trunk/lib/Checker/CallInliner.cpp (original) > +++ cfe/trunk/lib/Checker/CallInliner.cpp Thu Feb 25 13:01:53 2010 > @@ -26,7 +26,6 @@ > ? } > > ? virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE); > - ?virtual void EvalEndPath(GREndPathNodeBuilder &B,void *tag,GRExprEngine &Eng); > ?}; > ?} > > @@ -46,79 +45,10 @@ > ? if (!FD->isThisDeclarationADefinition()) > ? ? return false; > > - ?GRStmtNodeBuilder &Builder = C.getNodeBuilder(); > - ?// Make a new LocationContext. > - ?const StackFrameContext *LocCtx = C.getAnalysisManager().getStackFrame(FD, > - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? C.getPredecessor()->getLocationContext(), CE, > - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Builder.getBlock(), Builder.getIndex()); > - > - ?CFGBlock const *Entry = &(LocCtx->getCFG()->getEntry()); > - > - ?assert (Entry->empty() && "Entry block must be empty."); > - > - ?assert (Entry->succ_size() == 1 && "Entry block must have 1 successor."); > - > - ?// Get the solitary successor. > - ?CFGBlock const *SuccB = *(Entry->succ_begin()); > - > - ?// Construct an edge representing the starting location in the function. > - ?BlockEdge Loc(Entry, SuccB, LocCtx); > - > - ?state = C.getStoreManager().EnterStackFrame(state, LocCtx); > - > - ?// This is a hack. We really should not use the GRStmtNodeBuilder. > - ?bool isNew; > - ?GRExprEngine &Eng = C.getEngine(); > - ?ExplodedNode *Pred = C.getPredecessor(); > - > - > - ?ExplodedNode *SuccN = Eng.getGraph().getNode(Loc, state, &isNew); > - ?SuccN->addPredecessor(Pred, Eng.getGraph()); > - ?C.getNodeBuilder().Deferred.erase(Pred); > - > - ?if (isNew) > - ? ?Builder.getWorkList()->Enqueue(SuccN); > - > - ?Builder.HasGeneratedNode = true; > + ?// Now we have the definition of the callee, create a CallEnter node. > + ?CallEnter Loc(CE, FD, C.getPredecessor()->getLocationContext()); > + ?C.addTransition(state, Loc); > > ? return true; > ?} > > -void CallInliner::EvalEndPath(GREndPathNodeBuilder &B, void *tag, > - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?GRExprEngine &Eng) { > - ?const GRState *state = B.getState(); > - > - ?ExplodedNode *Pred = B.getPredecessor(); > - > - ?const StackFrameContext *LocCtx = > - ? ? ? ? ? ? ? ? ? ? ? ? cast(Pred->getLocationContext()); > - ?// Check if this is the top level stack frame. > - ?if (!LocCtx->getParent()) > - ? ?return; > - > - ?const StackFrameContext *ParentSF = > - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cast(LocCtx->getParent()); > - > - ?SymbolReaper SymReaper(*ParentSF->getLiveVariables(), Eng.getSymbolManager(), > - ? ? ? ? ? ? ? ? ? ? ? ? ParentSF); > - ?const Stmt *CE = LocCtx->getCallSite(); > - > - ?state = Eng.getStateManager().RemoveDeadBindings(state, const_cast(CE), > - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? SymReaper); > - > - > - ?PostStmt NodeLoc(CE, LocCtx->getParent()); > - > - ?bool isNew; > - ?ExplodedNode *Succ = Eng.getGraph().getNode(NodeLoc, state, &isNew); > - ?Succ->addPredecessor(Pred, Eng.getGraph()); > - > - ?// When creating the new work list unit, increment the statement index to > - ?// point to the statement after the CallExpr. > - ?if (isNew) > - ? ?B.getWorkList().Enqueue(Succ, > - ? ? ? ? ? ? ? ? ? ? ? ? ? ?*const_cast(LocCtx->getCallSiteBlock()), > - ? ? ? ? ? ? ? ? ? ? ? ? ? ?LocCtx->getIndex() + 1); > - > - ?B.HasGeneratedNode = true; > -} > > Modified: cfe/trunk/lib/Checker/GRCoreEngine.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRCoreEngine.cpp?rev=97162&r1=97161&r2=97162&view=diff > ============================================================================== > --- cfe/trunk/lib/Checker/GRCoreEngine.cpp (original) > +++ cfe/trunk/lib/Checker/GRCoreEngine.cpp Thu Feb 25 13:01:53 2010 > @@ -144,6 +144,14 @@ > ? SubEngine.ProcessSwitch(Builder); > ?} > > +void GRCoreEngine::ProcessCallEnter(GRCallEnterNodeBuilder &Builder) { > + ?SubEngine.ProcessCallEnter(Builder); > +} > + > +void GRCoreEngine::ProcessCallExit(GRCallExitNodeBuilder &Builder) { > + ?SubEngine.ProcessCallExit(Builder); > +} > + > ?/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps. > ?bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) { > > @@ -196,6 +204,15 @@ > ? ? ? ? assert (false && "BlockExit location never occur in forward analysis."); > ? ? ? ? break; > > + ? ? ?case ProgramPoint::CallEnterKind: > + ? ? ? ?HandleCallEnter(cast(Node->getLocation()), WU.getBlock(), > + ? ? ? ? ? ? ? ? ? ? ? ?WU.getIndex(), Node); > + ? ? ? ?break; > + > + ? ? ?case ProgramPoint::CallExitKind: > + ? ? ? ?HandleCallExit(cast(Node->getLocation()), Node); > + ? ? ? ?break; > + > ? ? ? default: > ? ? ? ? assert(isa(Node->getLocation())); > ? ? ? ? HandlePostStmt(cast(Node->getLocation()), WU.getBlock(), > @@ -207,6 +224,17 @@ > ? return WList->hasWork(); > ?} > > +void GRCoreEngine::HandleCallEnter(const CallEnter &L, const CFGBlock *Block, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned Index, ExplodedNode *Pred) { > + ?GRCallEnterNodeBuilder Builder(*this, Pred, L.getCallExpr(), L.getCallee(), > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Block, Index); > + ?ProcessCallEnter(Builder); > +} > + > +void GRCoreEngine::HandleCallExit(const CallExit &L, ExplodedNode *Pred) { > + ?GRCallExitNodeBuilder Builder(*this, Pred); > + ?ProcessCallExit(Builder); > +} > > ?void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) { > > @@ -400,6 +428,14 @@ > ?void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) { > ? assert (!N->isSink()); > > + ?// Check if this node entered a callee. > + ?if (isa(N->getLocation())) { > + ? ?// Still use the index of the CallExpr. It's needed to create the callee > + ? ?// StackFrameContext. > + ? ?Eng.WList->Enqueue(N, B, Idx); > + ? ?return; > + ?} > + > ? PostStmt Loc(getStmt(), N->getLocationContext()); > > ? if (Loc == N->getLocation()) { > @@ -576,7 +612,13 @@ > > ?GREndPathNodeBuilder::~GREndPathNodeBuilder() { > ? // Auto-generate an EOP node if one has not been generated. > - ?if (!HasGeneratedNode) generateNode(Pred->State); > + ?if (!HasGeneratedNode) { > + ? ?// If we are in an inlined call, generate CallExit node. > + ? ?if (Pred->getLocationContext()->getParent()) > + ? ? ?GenerateCallExitNode(Pred->State); > + ? ?else > + ? ? ?generateNode(Pred->State); > + ?} > ?} > > ?ExplodedNode* > @@ -597,3 +639,57 @@ > > ? return NULL; > ?} > + > +void GREndPathNodeBuilder::GenerateCallExitNode(const GRState *state) { > + ?HasGeneratedNode = true; > + ?// Create a CallExit node and enqueue it. > + ?const StackFrameContext *LocCtx > + ? ? ? ? ? ? ? ? ? ? ? ? = cast(Pred->getLocationContext()); > + ?const Stmt *CE = LocCtx->getCallSite(); > + > + ?// Use the the callee location context. > + ?CallExit Loc(CE, LocCtx); > + > + ?bool isNew; > + ?ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); > + ?Node->addPredecessor(Pred, *Eng.G); > + > + ?if (isNew) > + ? ?Eng.WList->Enqueue(Node); > +} > + > + > +void GRCallEnterNodeBuilder::GenerateNode(const GRState *state, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?const LocationContext *LocCtx) { > + ?// Get the callee entry block. > + ?const CFGBlock *Entry = &(LocCtx->getCFG()->getEntry()); > + ?assert(Entry->empty()); > + ?assert(Entry->succ_size() == 1); > + > + ?// Get the solitary successor. > + ?const CFGBlock *SuccB = *(Entry->succ_begin()); > + > + ?// Construct an edge representing the starting location in the callee. > + ?BlockEdge Loc(Entry, SuccB, LocCtx); > + > + ?bool isNew; > + ?ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); > + ?Node->addPredecessor(const_cast(Pred), *Eng.G); > + > + ?if (isNew) > + ? ?Eng.WList->Enqueue(Node); > +} > + > +void GRCallExitNodeBuilder::GenerateNode(const GRState *state) { > + ?// Get the callee's location context. > + ?const StackFrameContext *LocCtx > + ? ? ? ? ? ? ? ? ? ? ? ? = cast(Pred->getLocationContext()); > + > + ?PostStmt Loc(LocCtx->getCallSite(), LocCtx->getParent()); > + ?bool isNew; > + ?ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); > + ?Node->addPredecessor(const_cast(Pred), *Eng.G); > + ?if (isNew) > + ? ?Eng.WList->Enqueue(Node, *const_cast(LocCtx->getCallSiteBlock()), > + ? ? ? ? ? ? ? ? ? ? ? LocCtx->getIndex() + 1); > +} > > Modified: cfe/trunk/lib/Checker/GRExprEngine.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRExprEngine.cpp?rev=97162&r1=97161&r2=97162&view=diff > ============================================================================== > --- cfe/trunk/lib/Checker/GRExprEngine.cpp (original) > +++ cfe/trunk/lib/Checker/GRExprEngine.cpp Thu Feb 25 13:01:53 2010 > @@ -1290,6 +1290,38 @@ > ? if (defaultIsFeasible) builder.generateDefaultCaseNode(DefaultSt); > ?} > > +void GRExprEngine::ProcessCallEnter(GRCallEnterNodeBuilder &B) { > + ?const FunctionDecl *FD = B.getCallee(); > + ?const StackFrameContext *LocCtx = AMgr.getStackFrame(FD, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? B.getLocationContext(), > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? B.getCallExpr(), > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? B.getBlock(), > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? B.getIndex()); > + > + ?const GRState *state = B.getState(); > + ?state = getStoreManager().EnterStackFrame(state, LocCtx); > + > + ?B.GenerateNode(state, LocCtx); > +} > + > +void GRExprEngine::ProcessCallExit(GRCallExitNodeBuilder &B) { > + ?const GRState *state = B.getState(); > + ?const ExplodedNode *Pred = B.getPredecessor(); > + ?const StackFrameContext *LocCtx = > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?cast(Pred->getLocationContext()); > + ?const StackFrameContext *ParentSF = > + ? ? ? ? ? ? ? ? ? ? ? ? ? ?cast(LocCtx->getParent()); > + > + ?SymbolReaper SymReaper(*ParentSF->getLiveVariables(), getSymbolManager(), > + ? ? ? ? ? ? ? ? ? ? ? ? ParentSF); > + ?const Stmt *CE = LocCtx->getCallSite(); > + > + ?state = getStateManager().RemoveDeadBindings(state, const_cast(CE), > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? SymReaper); > + > + ?B.GenerateNode(state); > +} > + > ?//===----------------------------------------------------------------------===// > ?// Transfer functions: logical operations ('&&', '||'). > ?//===----------------------------------------------------------------------===// > @@ -3141,6 +3173,14 @@ > ? ? ? ? assert (false); > ? ? ? ? break; > > + ? ? ?case ProgramPoint::CallEnterKind: > + ? ? ? ?Out << "CallEnter"; > + ? ? ? ?break; > + > + ? ? ?case ProgramPoint::CallExitKind: > + ? ? ? ?Out << "CallExit"; > + ? ? ? ?break; > + > ? ? ? default: { > ? ? ? ? if (StmtPoint *L = dyn_cast(&Loc)) { > ? ? ? ? ? const Stmt* S = L->getStmt(); > > Propchange: cfe/trunk/lib/Checker/GRState.cpp > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/lib/Frontend/ASTConsumers.cpp > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/lib/Frontend/AnalysisConsumer.cpp > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/lib/Frontend/CacheTokens.cpp > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/lib/Frontend/CodeGenAction.cpp > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/lib/Frontend/DependencyFile.cpp > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/lib/Frontend/DiagChecker.cpp > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/lib/Frontend/GeneratePCH.cpp > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/lib/Frontend/HTMLPrint.cpp > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/lib/Frontend/PrintParserCallbacks.cpp > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/lib/Frontend/PrintPreprocessedOutput.cpp > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/lib/Frontend/RewriteMacros.cpp > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/lib/Frontend/RewriteObjC.cpp > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/lib/Frontend/RewriteTest.cpp > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/lib/Frontend/Warnings.cpp > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/lib/Sema/SemaCXXCast.cpp > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/test/Sema/dllimport-dllexport.c > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/test/SemaCXX/ambig-user-defined-conversions.cpp > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/test/SemaObjCXX/protocol-lookup.mm > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/test/SemaTemplate/typename-specifier-3.cpp > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/tools/scan-build/ccc-analyzer > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/tools/scan-build/scan-build > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/tools/scan-build/scanview.css > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/tools/scan-build/sorttable.js > ------------------------------------------------------------------------------ > ? ?(empty) > > Propchange: cfe/trunk/utils/analyzer/ubiviz > ------------------------------------------------------------------------------ > ? ?(empty) > > > _______________________________________________ > cfe-commits mailing list > cfe-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits > From xuzhongxing at gmail.com Thu Feb 25 20:38:09 2010 From: xuzhongxing at gmail.com (Zhongxing Xu) Date: Fri, 26 Feb 2010 02:38:09 -0000 Subject: [cfe-commits] r97207 - in /cfe/trunk: include/clang/Checker/PathSensitive/GRCoreEngine.h lib/Checker/GRCoreEngine.cpp lib/Checker/GRExprEngine.cpp Message-ID: <20100226023809.8E6162A6C12C@llvm.org> Author: zhongxingxu Date: Thu Feb 25 20:38:09 2010 New Revision: 97207 URL: http://llvm.org/viewvc/llvm-project?rev=97207&view=rev Log: Remove derelict GRStmtNodeBuilder::LastNode. Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h cfe/trunk/lib/Checker/GRCoreEngine.cpp cfe/trunk/lib/Checker/GRExprEngine.cpp Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h?rev=97207&r1=97206&r2=97207&view=diff ============================================================================== --- cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h (original) +++ cfe/trunk/include/clang/Checker/PathSensitive/GRCoreEngine.h Thu Feb 25 20:38:09 2010 @@ -138,7 +138,6 @@ CFGBlock& B; const unsigned Idx; ExplodedNode* Pred; - ExplodedNode* LastNode; GRStateManager& Mgr; GRAuditor* Auditor; @@ -165,10 +164,6 @@ ExplodedNode* getBasePredecessor() const { return Pred; } - ExplodedNode* getLastNode() const { - return LastNode ? (LastNode->isSink() ? NULL : LastNode) : NULL; - } - // FIXME: This should not be exposed. GRWorkList *getWorkList() { return Eng.WList; } Modified: cfe/trunk/lib/Checker/GRCoreEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRCoreEngine.cpp?rev=97207&r1=97206&r2=97207&view=diff ============================================================================== --- cfe/trunk/lib/Checker/GRCoreEngine.cpp (original) +++ cfe/trunk/lib/Checker/GRCoreEngine.cpp Thu Feb 25 20:38:09 2010 @@ -412,11 +412,11 @@ GRStmtNodeBuilder::GRStmtNodeBuilder(CFGBlock* b, unsigned idx, ExplodedNode* N, GRCoreEngine* e, GRStateManager &mgr) - : Eng(*e), B(*b), Idx(idx), Pred(N), LastNode(N), Mgr(mgr), Auditor(0), + : Eng(*e), B(*b), Idx(idx), Pred(N), Mgr(mgr), Auditor(0), PurgingDeadSymbols(false), BuildSinks(false), HasGeneratedNode(false), PointKind(ProgramPoint::PostStmtKind), Tag(0) { Deferred.insert(N); - CleanedState = getLastNode()->getState(); + CleanedState = Pred->getState(); } GRStmtNodeBuilder::~GRStmtNodeBuilder() { @@ -498,11 +498,9 @@ if (IsNew) { Deferred.insert(N); - LastNode = N; return N; } - LastNode = NULL; return NULL; } Modified: cfe/trunk/lib/Checker/GRExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRExprEngine.cpp?rev=97207&r1=97206&r2=97207&view=diff ============================================================================== --- cfe/trunk/lib/Checker/GRExprEngine.cpp (original) +++ cfe/trunk/lib/Checker/GRExprEngine.cpp Thu Feb 25 20:38:09 2010 @@ -460,7 +460,7 @@ "Error evaluating statement"); Builder = &builder; - EntryNode = builder.getLastNode(); + EntryNode = builder.getBasePredecessor(); // Set up our simple checks. if (BatchAuditor) From dgregor at apple.com Thu Feb 25 23:06:18 2010 From: dgregor at apple.com (Douglas Gregor) Date: Fri, 26 Feb 2010 05:06:18 -0000 Subject: [cfe-commits] r97209 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/AST/DeclCXX.cpp lib/Sema/SemaExprCXX.cpp test/CXX/expr/expr.unary/expr.new/p19.cpp test/CXX/expr/expr.unary/expr.new/p20-0x.cpp test/CXX/expr/expr.unary/expr.new/p20.cpp Message-ID: <20100226050618.70BEF2A6C12C@llvm.org> Author: dgregor Date: Thu Feb 25 23:06:18 2010 New Revision: 97209 URL: http://llvm.org/viewvc/llvm-project?rev=97209&view=rev Log: Implement semantic analysis for C++ [expr.new]p18-20, which describe how we find the operator delete that matches withe operator new we found in a C++ new-expression. This will also need CodeGen support. On a happy note, we're now a "nans" away from building tramp3d-v4. Added: cfe/trunk/test/CXX/expr/expr.unary/expr.new/p19.cpp (with props) cfe/trunk/test/CXX/expr/expr.unary/expr.new/p20-0x.cpp (with props) cfe/trunk/test/CXX/expr/expr.unary/expr.new/p20.cpp (with props) Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/AST/DeclCXX.cpp cfe/trunk/lib/Sema/SemaExprCXX.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=97209&r1=97208&r2=97209&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Feb 25 23:06:18 2010 @@ -2016,6 +2016,9 @@ "only the first dimension of an allocated array may have dynamic size">; def err_new_paren_array_nonconst : Error< "when type is in parentheses, array cannot have dynamic size">; +def err_placement_new_non_placement_delete : Error< + "'new' expression with placement arguments refers to non-placement " + "'operator delete'">; def err_array_size_not_integral : Error< "array size expression must have integral or enumerated type, not %0">; def err_default_init_const : Error< Modified: cfe/trunk/lib/AST/DeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=97209&r1=97208&r2=97209&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclCXX.cpp (original) +++ cfe/trunk/lib/AST/DeclCXX.cpp Thu Feb 25 23:06:18 2010 @@ -573,7 +573,13 @@ if (getOverloadedOperator() != OO_Delete && getOverloadedOperator() != OO_Array_Delete) return false; - + + // C++ [basic.stc.dynamic.deallocation]p2: + // A template instance is never a usual deallocation function, + // regardless of its signature. + if (getPrimaryTemplate()) + return false; + // C++ [basic.stc.dynamic.deallocation]p2: // If a class T has a member deallocation function named operator delete // with exactly one parameter, then that function is a usual (non-placement) Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=97209&r1=97208&r2=97209&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Feb 25 23:06:18 2010 @@ -780,6 +780,12 @@ ConsArgs = (Expr **)ConvertedConstructorArgs.take(); } + // Mark the new and delete operators as referenced. + if (OperatorNew) + MarkDeclarationReferenced(StartLoc, OperatorNew); + if (OperatorDelete) + MarkDeclarationReferenced(StartLoc, OperatorDelete); + // FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16) PlacementArgs.release(); @@ -819,6 +825,20 @@ return false; } +/// \brief Determine whether the given function is a non-placement +/// deallocation function. +static bool isNonPlacementDeallocationFunction(FunctionDecl *FD) { + if (FD->isInvalidDecl()) + return false; + + if (CXXMethodDecl *Method = dyn_cast(FD)) + return Method->isUsualDeallocationFunction(); + + return ((FD->getOverloadedOperator() == OO_Delete || + FD->getOverloadedOperator() == OO_Array_Delete) && + FD->getNumParams() == 1); +} + /// FindAllocationFunctions - Finds the overloads of operator new and delete /// that are appropriate for the allocation. bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, @@ -835,7 +855,6 @@ // operator new. // 3) The first argument is always size_t. Append the arguments from the // placement form. - // FIXME: Also find the appropriate delete operator. llvm::SmallVector AllocArgs(1 + NumPlaceArgs); // We don't care about the actual value of this argument. @@ -848,12 +867,20 @@ AllocArgs[0] = &Size; std::copy(PlaceArgs, PlaceArgs + NumPlaceArgs, AllocArgs.begin() + 1); + // C++ [expr.new]p8: + // If the allocated type is a non-array type, the allocation + // function???s name is operator new and the deallocation function???s + // name is operator delete. If the allocated type is an array + // type, the allocation function???s name is operator new[] and the + // deallocation function???s name is operator delete[]. DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName( IsArray ? OO_Array_New : OO_New); + DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( + IsArray ? OO_Array_Delete : OO_Delete); + if (AllocType->isRecordType() && !UseGlobal) { CXXRecordDecl *Record = cast(AllocType->getAs()->getDecl()); - // FIXME: We fail to find inherited overloads. if (FindAllocationOverload(StartLoc, Range, NewName, &AllocArgs[0], AllocArgs.size(), Record, /*AllowMissing=*/true, OperatorNew)) @@ -874,6 +901,110 @@ if (NumPlaceArgs > 0) std::copy(&AllocArgs[1], AllocArgs.end(), PlaceArgs); + // C++ [expr.new]p19: + // + // If the new-expression begins with a unary :: operator, the + // deallocation function???s name is looked up in the global + // scope. Otherwise, if the allocated type is a class type T or an + // array thereof, the deallocation function???s name is looked up in + // the scope of T. If this lookup fails to find the name, or if + // the allocated type is not a class type or array thereof, the + // deallocation function???s name is looked up in the global scope. + LookupResult FoundDelete(*this, DeleteName, StartLoc, LookupOrdinaryName); + if (AllocType->isRecordType() && !UseGlobal) { + CXXRecordDecl *RD + = cast(AllocType->getAs()->getDecl()); + LookupQualifiedName(FoundDelete, RD); + } + + if (FoundDelete.empty()) { + DeclareGlobalNewDelete(); + LookupQualifiedName(FoundDelete, Context.getTranslationUnitDecl()); + } + + FoundDelete.suppressDiagnostics(); + llvm::SmallVector Matches; + if (NumPlaceArgs > 1) { + // C++ [expr.new]p20: + // A declaration of a placement deallocation function matches the + // declaration of a placement allocation function if it has the + // same number of parameters and, after parameter transformations + // (8.3.5), all parameter types except the first are + // identical. [...] + // + // To perform this comparison, we compute the function type that + // the deallocation function should have, and use that type both + // for template argument deduction and for comparison purposes. + QualType ExpectedFunctionType; + { + const FunctionProtoType *Proto + = OperatorNew->getType()->getAs(); + llvm::SmallVector ArgTypes; + ArgTypes.push_back(Context.VoidPtrTy); + for (unsigned I = 1, N = Proto->getNumArgs(); I < N; ++I) + ArgTypes.push_back(Proto->getArgType(I)); + + ExpectedFunctionType + = Context.getFunctionType(Context.VoidTy, ArgTypes.data(), + ArgTypes.size(), + Proto->isVariadic(), + 0, false, false, 0, 0, false, CC_Default); + } + + for (LookupResult::iterator D = FoundDelete.begin(), + DEnd = FoundDelete.end(); + D != DEnd; ++D) { + FunctionDecl *Fn = 0; + if (FunctionTemplateDecl *FnTmpl + = dyn_cast((*D)->getUnderlyingDecl())) { + // Perform template argument deduction to try to match the + // expected function type. + TemplateDeductionInfo Info(Context, StartLoc); + if (DeduceTemplateArguments(FnTmpl, 0, ExpectedFunctionType, Fn, Info)) + continue; + } else + Fn = cast((*D)->getUnderlyingDecl()); + + if (Context.hasSameType(Fn->getType(), ExpectedFunctionType)) + Matches.push_back(Fn); + } + } else { + // C++ [expr.new]p20: + // [...] Any non-placement deallocation function matches a + // non-placement allocation function. [...] + for (LookupResult::iterator D = FoundDelete.begin(), + DEnd = FoundDelete.end(); + D != DEnd; ++D) { + if (FunctionDecl *Fn = dyn_cast((*D)->getUnderlyingDecl())) + if (isNonPlacementDeallocationFunction(Fn)) + Matches.push_back(*D); + } + } + + // C++ [expr.new]p20: + // [...] If the lookup finds a single matching deallocation + // function, that function will be called; otherwise, no + // deallocation function will be called. + if (Matches.size() == 1) { + // FIXME: Drops access, using-declaration info! + OperatorDelete = cast(Matches[0]->getUnderlyingDecl()); + + // C++0x [expr.new]p20: + // If the lookup finds the two-parameter form of a usual + // deallocation function (3.7.4.2) and that function, considered + // as a placement deallocation function, would have been + // selected as a match for the allocation function, the program + // is ill-formed. + if (NumPlaceArgs && getLangOptions().CPlusPlus0x && + isNonPlacementDeallocationFunction(OperatorDelete)) { + Diag(StartLoc, diag::err_placement_new_non_placement_delete) + << SourceRange(PlaceArgs[0]->getLocStart(), + PlaceArgs[NumPlaceArgs - 1]->getLocEnd()); + Diag(OperatorDelete->getLocation(), diag::note_previous_decl) + << DeleteName; + } + } + return false; } Added: cfe/trunk/test/CXX/expr/expr.unary/expr.new/p19.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.unary/expr.new/p19.cpp?rev=97209&view=auto ============================================================================== --- cfe/trunk/test/CXX/expr/expr.unary/expr.new/p19.cpp (added) +++ cfe/trunk/test/CXX/expr/expr.unary/expr.new/p19.cpp Thu Feb 25 23:06:18 2010 @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +typedef __SIZE_TYPE__ size_t; + +// Operator delete template for placement new with global lookup +template +struct X0 { + X0(); + + static void* operator new(size_t) { + return I; // expected-error{{cannot initialize}} + } + + static void operator delete(void*) { + int *ip = I; // expected-error{{cannot initialize}} + } +}; + +void test_X0() { + // Using the global operator new suppresses the search for a + // operator delete in the class. + ::new X0<2>; + + new X0<3>; // expected-note 2{{instantiation}} +} + +// Operator delete template for placement new[] with global lookup +template +struct X1 { + X1(); + + static void* operator new[](size_t) { + return I; // expected-error{{cannot initialize}} + } + + static void operator delete[](void*) { + int *ip = I; // expected-error{{cannot initialize}} + } +}; + +void test_X1() { + // Using the global operator new suppresses the search for a + // operator delete in the class. + ::new X1<2> [17]; + + new X1<3> [17]; // expected-note 2{{instantiation}} +} Propchange: cfe/trunk/test/CXX/expr/expr.unary/expr.new/p19.cpp ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cfe/trunk/test/CXX/expr/expr.unary/expr.new/p19.cpp ------------------------------------------------------------------------------ svn:keywords = Id Propchange: cfe/trunk/test/CXX/expr/expr.unary/expr.new/p19.cpp ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: cfe/trunk/test/CXX/expr/expr.unary/expr.new/p20-0x.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.unary/expr.new/p20-0x.cpp?rev=97209&view=auto ============================================================================== --- cfe/trunk/test/CXX/expr/expr.unary/expr.new/p20-0x.cpp (added) +++ cfe/trunk/test/CXX/expr/expr.unary/expr.new/p20-0x.cpp Thu Feb 25 23:06:18 2010 @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s +typedef __SIZE_TYPE__ size_t; + +struct S { + // Placement allocation function: + static void* operator new(size_t, size_t); + // Usual (non-placement) deallocation function: + static void operator delete(void*, size_t); // expected-note{{declared here}} +}; + +void testS() { + S* p = new (0) S; // expected-error{{'new' expression with placement arguments refers to non-placement 'operator delete'}} +} Propchange: cfe/trunk/test/CXX/expr/expr.unary/expr.new/p20-0x.cpp ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cfe/trunk/test/CXX/expr/expr.unary/expr.new/p20-0x.cpp ------------------------------------------------------------------------------ svn:keywords = Id Propchange: cfe/trunk/test/CXX/expr/expr.unary/expr.new/p20-0x.cpp ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: cfe/trunk/test/CXX/expr/expr.unary/expr.new/p20.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.unary/expr.new/p20.cpp?rev=97209&view=auto ============================================================================== --- cfe/trunk/test/CXX/expr/expr.unary/expr.new/p20.cpp (added) +++ cfe/trunk/test/CXX/expr/expr.unary/expr.new/p20.cpp Thu Feb 25 23:06:18 2010 @@ -0,0 +1,141 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +typedef __SIZE_TYPE__ size_t; + +// Overloaded operator delete with two arguments +template +struct X0 { + X0(); + static void* operator new(size_t); + static void operator delete(void*, size_t) { + int *ip = I; // expected-error{{cannot initialize}} + } +}; + +void test_X0() { + new X0<1>; // expected-note{{instantiation}} +} + +// Overloaded operator delete with one argument +template +struct X1 { + X1(); + + static void* operator new(size_t); + static void operator delete(void*) { + int *ip = I; // expected-error{{cannot initialize}} + } +}; + +void test_X1() { + new X1<1>; // expected-note{{instantiation}} +} + +// Overloaded operator delete for placement new +template +struct X2 { + X2(); + + static void* operator new(size_t, double, double); + static void* operator new(size_t, int, int); + + static void operator delete(void*, const int, int) { + int *ip = I; // expected-error{{cannot initialize}} + } + + static void operator delete(void*, double, double); +}; + +void test_X2() { + new (0, 0) X2<1>; // expected-note{{instantiation}} +} + +// Operator delete template for placement new +struct X3 { + X3(); + + static void* operator new(size_t, double, double); + + template + static void operator delete(void*, T x, T) { + double *dp = &x; + int *ip = &x; // expected-error{{cannot initialize}} + } +}; + +void test_X3() { + new (0, 0) X3; // expected-note{{instantiation}} +} + +// Operator delete template for placement new in global scope. +struct X4 { + X4(); + static void* operator new(size_t, double, double); +}; + +template +void operator delete(void*, T x, T) { + double *dp = &x; + int *ip = &x; // expected-error{{cannot initialize}} +} + +void test_X4() { + new (0, 0) X4; // expected-note{{instantiation}} +} + +// Useless operator delete hides global operator delete template. +struct X5 { + X5(); + static void* operator new(size_t, double, double); + void operator delete(void*, double*, double*); +}; + +void test_X5() { + new (0, 0) X5; // okay, we found X5::operator delete but didn't pick it +} + +// Operator delete template for placement new +template +struct X6 { + X6(); + + static void* operator new(size_t) { + return I; // expected-error{{cannot initialize}} + } + + static void operator delete(void*) { + int *ip = I; // expected-error{{cannot initialize}} + } +}; + +void test_X6() { + new X6<3>; // expected-note 2{{instantiation}} +} + +void *operator new(size_t, double, double, double); + +template +void operator delete(void*, T x, T, T) { + double *dp = &x; + int *ip = &x; // expected-error{{cannot initialize}} +} +void test_int_new() { + new (1.0, 1.0, 1.0) int; // expected-note{{instantiation}} +} + +// We don't need an operator delete if the type has a trivial +// constructor, since we know that constructor cannot throw. +// FIXME: Is this within the standard? Seems fishy, but both EDG+GCC do it. +#if 0 +template +struct X7 { + static void* operator new(size_t); + static void operator delete(void*, size_t) { + int *ip = I; // okay, since it isn't instantiated. + } +}; + +void test_X7() { + new X7<1>; +} +#endif + Propchange: cfe/trunk/test/CXX/expr/expr.unary/expr.new/p20.cpp ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cfe/trunk/test/CXX/expr/expr.unary/expr.new/p20.cpp ------------------------------------------------------------------------------ svn:keywords = Id Propchange: cfe/trunk/test/CXX/expr/expr.unary/expr.new/p20.cpp ------------------------------------------------------------------------------ svn:mime-type = text/plain From dgregor at apple.com Fri Feb 26 00:03:23 2010 From: dgregor at apple.com (Douglas Gregor) Date: Fri, 26 Feb 2010 06:03:23 -0000 Subject: [cfe-commits] r97210 - in /cfe/trunk: lib/Sema/SemaTemplate.cpp test/CXX/temp/temp.spec/temp.expl.spec/p6.cpp Message-ID: <20100226060323.E51792A6C12C@llvm.org> Author: dgregor Date: Fri Feb 26 00:03:23 2010 New Revision: 97210 URL: http://llvm.org/viewvc/llvm-project?rev=97210&view=rev Log: An explicit specialization is allowed following an explicit instantiation so long as that explicit specialization was declared previously. Fixes PR6160. Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p6.cpp Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=97210&r1=97209&r2=97210&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Fri Feb 26 00:03:23 2010 @@ -3242,6 +3242,23 @@ return false; } +/// \brief Retrieve the previous declaration of the given declaration. +static NamedDecl *getPreviousDecl(NamedDecl *ND) { + if (VarDecl *VD = dyn_cast(ND)) + return VD->getPreviousDeclaration(); + if (FunctionDecl *FD = dyn_cast(ND)) + return FD->getPreviousDeclaration(); + if (TagDecl *TD = dyn_cast(ND)) + return TD->getPreviousDeclaration(); + if (TypedefDecl *TD = dyn_cast(ND)) + return TD->getPreviousDeclaration(); + if (FunctionTemplateDecl *FTD = dyn_cast(ND)) + return FTD->getPreviousDeclaration(); + if (ClassTemplateDecl *CTD = dyn_cast(ND)) + return CTD->getPreviousDeclaration(); + return 0; +} + Sema::DeclResult Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, @@ -3547,15 +3564,26 @@ // instantiation to take place, in every translation unit in which such a // use occurs; no diagnostic is required. if (PrevDecl && PrevDecl->getPointOfInstantiation().isValid()) { - SourceRange Range(TemplateNameLoc, RAngleLoc); - Diag(TemplateNameLoc, diag::err_specialization_after_instantiation) - << Context.getTypeDeclType(Specialization) << Range; - - Diag(PrevDecl->getPointOfInstantiation(), - diag::note_instantiation_required_here) - << (PrevDecl->getTemplateSpecializationKind() + bool Okay = false; + for (NamedDecl *Prev = PrevDecl; Prev; Prev = getPreviousDecl(Prev)) { + // Is there any previous explicit specialization declaration? + if (getTemplateSpecializationKind(Prev) == TSK_ExplicitSpecialization) { + Okay = true; + break; + } + } + + if (!Okay) { + SourceRange Range(TemplateNameLoc, RAngleLoc); + Diag(TemplateNameLoc, diag::err_specialization_after_instantiation) + << Context.getTypeDeclType(Specialization) << Range; + + Diag(PrevDecl->getPointOfInstantiation(), + diag::note_instantiation_required_here) + << (PrevDecl->getTemplateSpecializationKind() != TSK_ImplicitInstantiation); - return true; + return true; + } } // If this is not a friend, note that this is an explicit specialization. @@ -3728,6 +3756,12 @@ // before the first use of that specialization that would cause an // implicit instantiation to take place, in every translation unit in // which such a use occurs; no diagnostic is required. + for (NamedDecl *Prev = PrevDecl; Prev; Prev = getPreviousDecl(Prev)) { + // Is there any previous explicit specialization declaration? + if (getTemplateSpecializationKind(Prev) == TSK_ExplicitSpecialization) + return false; + } + Diag(NewLoc, diag::err_specialization_after_instantiation) << PrevDecl; Diag(PrevPointOfInstantiation, diag::note_instantiation_required_here) Modified: cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p6.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p6.cpp?rev=97210&r1=97209&r2=97210&view=diff ============================================================================== --- cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p6.cpp (original) +++ cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p6.cpp Fri Feb 26 00:03:23 2010 @@ -54,3 +54,10 @@ template<> void sort(Array& v); // // expected-error{{after instantiation}} template<> void sort<>(Array& v); // OK: sort not yet used + +namespace PR6160 { + template void f(T); + template<> void f(int); + extern template void f(int); + template<> void f(int) { } +} From rjmccall at apple.com Fri Feb 26 02:45:28 2010 From: rjmccall at apple.com (John McCall) Date: Fri, 26 Feb 2010 08:45:28 -0000 Subject: [cfe-commits] r97221 - in /cfe/trunk: include/clang/Parse/ lib/Parse/ test/CXX/temp/temp.fct.spec/temp.arg.explicit/ test/Parser/ test/SemaCXX/ test/SemaTemplate/ Message-ID: <20100226084528.C863E2A6C12D@llvm.org> Author: rjmccall Date: Fri Feb 26 02:45:28 2010 New Revision: 97221 URL: http://llvm.org/viewvc/llvm-project?rev=97221&view=rev Log: Fix an assertion-on-error during tentative constructor parsing by propagating error conditions out of the various annotate-me-a-snowflake routines. Generally (but not universally) removes redundant diagnostics as well as, you know, not crashing on bad code. On the other hand, I have just signed myself up to fix fiddly parser errors for the next week. Again. Modified: cfe/trunk/include/clang/Parse/Parser.h cfe/trunk/lib/Parse/ParseDecl.cpp cfe/trunk/lib/Parse/ParseDeclCXX.cpp cfe/trunk/lib/Parse/ParseExpr.cpp cfe/trunk/lib/Parse/ParseExprCXX.cpp cfe/trunk/lib/Parse/ParseTentative.cpp cfe/trunk/lib/Parse/Parser.cpp cfe/trunk/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp cfe/trunk/test/Parser/cxx-template-argument.cpp cfe/trunk/test/SemaCXX/member-pointer.cpp cfe/trunk/test/SemaCXX/nested-name-spec.cpp cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp cfe/trunk/test/SemaTemplate/explicit-specialization-member.cpp cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp cfe/trunk/test/SemaTemplate/temp_arg.cpp Modified: cfe/trunk/include/clang/Parse/Parser.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=97221&r1=97220&r2=97221&view=diff ============================================================================== --- cfe/trunk/include/clang/Parse/Parser.h (original) +++ cfe/trunk/include/clang/Parse/Parser.h Fri Feb 26 02:45:28 2010 @@ -320,9 +320,9 @@ /// This returns true if the token was annotated. bool TryAnnotateTypeOrScopeToken(bool EnteringContext = false); - /// TryAnnotateCXXScopeToken - Like TryAnnotateTypeOrScopeToken but only - /// annotates C++ scope specifiers. This returns true if the token was - /// annotated. + /// TryAnnotateCXXScopeToken - Like TryAnnotateTypeOrScopeToken but + /// only annotates C++ scope specifiers. This returns true if there + /// was an unrecoverable error. bool TryAnnotateCXXScopeToken(bool EnteringContext = false); /// TryAltiVecToken - Check for context-sensitive AltiVec identifier tokens, Modified: cfe/trunk/lib/Parse/ParseDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=97221&r1=97220&r2=97221&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseDecl.cpp (original) +++ cfe/trunk/lib/Parse/ParseDecl.cpp Fri Feb 26 02:45:28 2010 @@ -859,10 +859,13 @@ return; case tok::coloncolon: // ::foo::bar - // Annotate C++ scope specifiers. If we get one, loop. - if (TryAnnotateCXXScopeToken(true)) - continue; - goto DoneWithDeclSpec; + // C++ scope specifier. Annotate and loop, or bail out on error. + if (TryAnnotateCXXScopeToken(true)) { + if (!DS.hasTypeSpecifier()) + DS.SetTypeSpecError(); + goto DoneWithDeclSpec; + } + continue; case tok::annot_cxxscope: { if (DS.hasTypeSpecifier()) @@ -1020,8 +1023,15 @@ case tok::identifier: { // In C++, check to see if this is a scope specifier like foo::bar::, if // so handle it as such. This is important for ctor parsing. - if (getLang().CPlusPlus && TryAnnotateCXXScopeToken(true)) - continue; + if (getLang().CPlusPlus) { + if (TryAnnotateCXXScopeToken(true)) { + if (!DS.hasTypeSpecifier()) + DS.SetTypeSpecError(); + goto DoneWithDeclSpec; + } + if (!Tok.is(tok::identifier)) + continue; + } // This identifier can only be a typedef name if we haven't already seen // a type-specifier. Without this check we misparse: @@ -1313,7 +1323,11 @@ // C++ typename-specifier: case tok::kw_typename: - if (TryAnnotateTypeOrScopeToken()) + if (TryAnnotateTypeOrScopeToken()) { + DS.SetTypeSpecError(); + goto DoneWithDeclSpec; + } + if (!Tok.is(tok::kw_typename)) continue; break; @@ -1423,10 +1437,11 @@ // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) - return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, - TemplateInfo, SuppressDeclarations); - // Otherwise, not a type specifier. - return false; + return true; + if (Tok.is(tok::identifier)) + return false; + return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, + TemplateInfo, SuppressDeclarations); case tok::coloncolon: // ::foo::bar if (NextToken().is(tok::kw_new) || // ::new NextToken().is(tok::kw_delete)) // ::delete @@ -1435,10 +1450,9 @@ // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) - return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, - TemplateInfo, SuppressDeclarations); - // Otherwise, not a type specifier. - return false; + return true; + return ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec, DiagID, + TemplateInfo, SuppressDeclarations); // simple-type-specifier: case tok::annot_typename: { @@ -1848,8 +1862,11 @@ Attr.reset(ParseGNUAttributes()); CXXScopeSpec SS; - if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS, 0, false)) { - if (Tok.isNot(tok::identifier)) { + if (getLang().CPlusPlus) { + if (ParseOptionalCXXScopeSpecifier(SS, 0, false)) + return; + + if (SS.isSet() && Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); if (Tok.isNot(tok::l_brace)) { // Has no name and is not a definition. @@ -2016,21 +2033,19 @@ // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) - return isTypeSpecifierQualifier(); - // Otherwise, not a type specifier. - return false; + return true; + if (Tok.is(tok::identifier)) + return false; + return isTypeSpecifierQualifier(); case tok::coloncolon: // ::foo::bar if (NextToken().is(tok::kw_new) || // ::new NextToken().is(tok::kw_delete)) // ::delete return false; - // Annotate typenames and C++ scope specifiers. If we get one, just - // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) - return isTypeSpecifierQualifier(); - // Otherwise, not a type specifier. - return false; + return true; + return isTypeSpecifierQualifier(); // GNU attributes support. case tok::kw___attribute: @@ -2101,14 +2116,15 @@ if (TryAltiVecVectorToken()) return true; // Fall through. - case tok::kw_typename: // typename T::type // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) - return isDeclarationSpecifier(); - // Otherwise, not a declaration specifier. - return false; + return true; + if (Tok.is(tok::identifier)) + return false; + return isDeclarationSpecifier(); + case tok::coloncolon: // ::foo::bar if (NextToken().is(tok::kw_new) || // ::new NextToken().is(tok::kw_delete)) // ::delete @@ -2117,9 +2133,8 @@ // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) - return isDeclarationSpecifier(); - // Otherwise, not a declaration specifier. - return false; + return true; + return isDeclarationSpecifier(); // storage-class-specifier case tok::kw_typedef: @@ -2200,7 +2215,10 @@ // Parse the C++ scope specifier. CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, 0, true); + if (ParseOptionalCXXScopeSpecifier(SS, 0, true)) { + TPA.Revert(); + return false; + } // Parse the constructor name. if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) { @@ -2351,7 +2369,9 @@ (Tok.is(tok::coloncolon) || Tok.is(tok::identifier) || Tok.is(tok::annot_cxxscope))) { CXXScopeSpec SS; - if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true)) { + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true); // ignore fail + + if (SS.isSet()) { if (Tok.isNot(tok::star)) { // The scope spec really belongs to the direct-declarator. D.getCXXScopeSpec() = SS; @@ -2507,9 +2527,13 @@ if (getLang().CPlusPlus && D.mayHaveIdentifier()) { // ParseDeclaratorInternal might already have parsed the scope. - bool afterCXXScope = D.getCXXScopeSpec().isSet() || + bool afterCXXScope = D.getCXXScopeSpec().isSet(); + if (!afterCXXScope) { ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0, true); + afterCXXScope = D.getCXXScopeSpec().isSet(); + } + if (afterCXXScope) { if (Actions.ShouldEnterDeclaratorScope(CurScope, D.getCXXScopeSpec())) // Change the declaration context for name lookup, until this function @@ -2799,7 +2823,7 @@ // K&R-style function: void foo(a,b,c) if (!getLang().CPlusPlus && Tok.is(tok::identifier) && !TryAltiVecVectorToken()) { - if (!TryAnnotateTypeOrScopeToken()) { + if (TryAnnotateTypeOrScopeToken() || !Tok.is(tok::annot_typename)) { // K&R identifier lists can't have typedefs as identifiers, per // C99 6.7.5.3p11. if (RequiresArg) { Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=97221&r1=97220&r2=97221&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original) +++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Fri Feb 26 02:45:28 2010 @@ -645,7 +645,8 @@ // "FOO : BAR" is not a potential typo for "FOO::BAR". ColonProtectionRAIIObject X(*this); - if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true)) + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true); + if (SS.isSet()) if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) Diag(Tok, diag::err_expected_ident); } @@ -1163,7 +1164,7 @@ // Access declarations. if (!TemplateInfo.Kind && (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) && - TryAnnotateCXXScopeToken() && + !TryAnnotateCXXScopeToken() && Tok.is(tok::annot_cxxscope)) { bool isAccessDecl = false; if (NextToken().is(tok::identifier)) Modified: cfe/trunk/lib/Parse/ParseExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=97221&r1=97220&r2=97221&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseExpr.cpp (original) +++ cfe/trunk/lib/Parse/ParseExpr.cpp Fri Feb 26 02:45:28 2010 @@ -626,6 +626,8 @@ Next.is(tok::l_paren)) { // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse. if (TryAnnotateTypeOrScopeToken()) + return ExprError(); + if (!Tok.is(tok::identifier)) return ParseCastExpression(isUnaryExpression, isAddressOfOperand); } } @@ -790,7 +792,7 @@ if (SavedKind == tok::kw_typename) { // postfix-expression: typename-specifier '(' expression-list[opt] ')' - if (!TryAnnotateTypeOrScopeToken()) + if (TryAnnotateTypeOrScopeToken()) return ExprError(); } @@ -852,6 +854,8 @@ // ::foo::bar -> global qualified name etc. If TryAnnotateTypeOrScopeToken // annotates the token, tail recurse. if (TryAnnotateTypeOrScopeToken()) + return ExprError(); + if (!Tok.is(tok::coloncolon)) return ParseCastExpression(isUnaryExpression, isAddressOfOperand); // ::new -> [C++] new-expression Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=97221&r1=97220&r2=97221&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original) +++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Fri Feb 26 02:45:28 2010 @@ -55,7 +55,7 @@ /// member access expression, e.g., the \p T:: in \p p->T::m. /// -/// \returns true if a scope specifier was parsed. +/// \returns true if there was an error parsing a scope specifier bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, Action::TypeTy *ObjectType, bool EnteringContext, @@ -67,7 +67,7 @@ SS.setScopeRep(Tok.getAnnotationValue()); SS.setRange(Tok.getAnnotationRange()); ConsumeToken(); - return true; + return false; } bool HasScopeSpecifier = false; @@ -168,10 +168,10 @@ = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, TemplateName, ObjectType, EnteringContext); if (!Template) - break; + return true; if (AnnotateTemplateIdToken(Template, TNK_Dependent_template_name, &SS, TemplateName, TemplateKWLoc, false)) - break; + return true; continue; } @@ -188,7 +188,7 @@ = static_cast(Tok.getAnnotationValue()); if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) { *MayBePseudoDestructor = true; - return HasScopeSpecifier; + return false; } if (TemplateId->Kind == TNK_Type_template || @@ -258,7 +258,7 @@ !Actions.isNonTypeNestedNameSpecifier(CurScope, SS, Tok.getLocation(), II, ObjectType)) { *MayBePseudoDestructor = true; - return HasScopeSpecifier; + return false; } // We have an identifier followed by a '::'. Lookup this name @@ -303,7 +303,7 @@ ConsumeToken(); if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName, SourceLocation(), false)) - break; + return true; continue; } } @@ -319,7 +319,7 @@ if (CheckForDestructor && Tok.is(tok::tilde)) *MayBePseudoDestructor = true; - return HasScopeSpecifier; + return false; } /// ParseCXXIdExpression - Handle id-expression. Modified: cfe/trunk/lib/Parse/ParseTentative.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=97221&r1=97220&r2=97221&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseTentative.cpp (original) +++ cfe/trunk/lib/Parse/ParseTentative.cpp Fri Feb 26 02:45:28 2010 @@ -491,7 +491,8 @@ while (1) { if (Tok.is(tok::coloncolon) || Tok.is(tok::identifier)) - TryAnnotateCXXScopeToken(true); + if (TryAnnotateCXXScopeToken(true)) + return TPResult::Error(); if (Tok.is(tok::star) || Tok.is(tok::amp) || Tok.is(tok::caret) || (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) { @@ -681,9 +682,10 @@ // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) - return isCXXDeclarationSpecifier(); - // Otherwise, not a typename. - return TPResult::False(); + return TPResult::Error(); + if (Tok.is(tok::identifier)) + return TPResult::False(); + return isCXXDeclarationSpecifier(); case tok::coloncolon: { // ::foo::bar const Token &Next = NextToken(); @@ -694,9 +696,8 @@ // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) - return isCXXDeclarationSpecifier(); - // Otherwise, not a typename. - return TPResult::False(); + return TPResult::Error(); + return isCXXDeclarationSpecifier(); } // decl-specifier: @@ -762,7 +763,9 @@ case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed // We've already annotated a scope; try to annotate a type. - if (!(TryAnnotateTypeOrScopeToken() && Tok.is(tok::annot_typename))) + if (TryAnnotateTypeOrScopeToken()) + return TPResult::Error(); + if (!Tok.is(tok::annot_typename)) return TPResult::False(); // If that succeeded, fallthrough into the generic simple-type-id case. Modified: cfe/trunk/lib/Parse/Parser.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=97221&r1=97220&r2=97221&view=diff ============================================================================== --- cfe/trunk/lib/Parse/Parser.cpp (original) +++ cfe/trunk/lib/Parse/Parser.cpp Fri Feb 26 02:45:28 2010 @@ -891,8 +891,7 @@ /// specifier, and another one to get the actual type inside /// ParseDeclarationSpecifiers). /// -/// This returns true if the token was annotated or an unrecoverable error -/// occurs. +/// This returns true if an error occurred. /// /// Note that this routine emits an error if you call it with ::new or ::delete /// as the current tokens, so only call it in contexts where these are invalid. @@ -910,11 +909,11 @@ // simple-template-id SourceLocation TypenameLoc = ConsumeToken(); CXXScopeSpec SS; - bool HadNestedNameSpecifier - = ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); - if (!HadNestedNameSpecifier) { + if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false)) + return true; + if (!SS.isSet()) { Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename); - return false; + return true; } TypeResult Ty; @@ -928,7 +927,7 @@ if (TemplateId->Kind == TNK_Function_template) { Diag(Tok, diag::err_typename_refers_to_non_type_template) << Tok.getAnnotationRange(); - return false; + return true; } AnnotateTemplateIdTokenAsType(0); @@ -942,7 +941,7 @@ } else { Diag(Tok, diag::err_expected_type_name_after_typename) << SS.getRange(); - return false; + return true; } SourceLocation EndLoc = Tok.getLastLoc(); @@ -951,7 +950,7 @@ Tok.setAnnotationEndLoc(EndLoc); Tok.setLocation(TypenameLoc); PP.AnnotateCachedTokens(Tok); - return true; + return false; } // Remembers whether the token was originally a scope annotation. @@ -959,7 +958,8 @@ CXXScopeSpec SS; if (getLang().CPlusPlus) - ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext); + if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext)) + return true; if (Tok.is(tok::identifier)) { // Determine whether the identifier is a type name. @@ -976,7 +976,7 @@ // In case the tokens were cached, have Preprocessor replace // them with the annotation token. PP.AnnotateCachedTokens(Tok); - return true; + return false; } if (!getLang().CPlusPlus) { @@ -1001,7 +1001,7 @@ // If an unrecoverable error occurred, we need to return true here, // because the token stream is in a damaged state. We may not return // a valid identifier. - return Tok.isNot(tok::identifier); + return true; } } } @@ -1021,12 +1021,12 @@ // to produce a type annotation token. Update the template-id // annotation token to a type annotation token now. AnnotateTemplateIdTokenAsType(&SS); - return true; + return false; } } if (SS.isEmpty()) - return Tok.isNot(tok::identifier) && Tok.isNot(tok::coloncolon); + return false; // A C++ scope specifier that isn't followed by a typename. // Push the current token back into the token stream (or revert it if it is @@ -1044,7 +1044,7 @@ // just reverted back to the state we were in before being called. if (!wasScopeAnnotation) PP.AnnotateCachedTokens(Tok); - return true; + return false; } /// TryAnnotateScopeToken - Like TryAnnotateTypeOrScopeToken but only @@ -1061,10 +1061,10 @@ "Cannot be a type or scope token!"); CXXScopeSpec SS; - if (!ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext)) - // If the token left behind is not an identifier, we either had an error or - // successfully turned it into an annotation token. - return Tok.isNot(tok::identifier); + if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext)) + return true; + if (!SS.isSet()) + return false; // Push the current token back into the token stream (or revert it if it is // cached) and use an annotation scope token for current token. @@ -1079,7 +1079,7 @@ // In case the tokens were cached, have Preprocessor replace them with the // annotation token. PP.AnnotateCachedTokens(Tok); - return true; + return false; } // Anchor the Parser::FieldCallback vtable to this translation unit. Modified: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp?rev=97221&r1=97220&r2=97221&view=diff ============================================================================== --- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp (original) +++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-nodeduct.cpp Fri Feb 26 02:45:28 2010 @@ -33,5 +33,4 @@ template void g(T, T); int typeof2[is_same<__typeof__(g), void (int)>::value? 1 : -1]; // \ - // expected-error{{cannot determine the type of an overloaded function}} \ - // FIXME: expected-error{{use of undeclared identifier}} + // expected-error{{cannot determine the type of an overloaded function}} Modified: cfe/trunk/test/Parser/cxx-template-argument.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-template-argument.cpp?rev=97221&r1=97220&r2=97221&view=diff ============================================================================== --- cfe/trunk/test/Parser/cxx-template-argument.cpp (original) +++ cfe/trunk/test/Parser/cxx-template-argument.cpp Fri Feb 26 02:45:28 2010 @@ -5,5 +5,5 @@ // Check for template argument lists followed by junk // FIXME: The diagnostics here aren't great... A int x; // expected-error {{expected '>'}} expected-error {{expected unqualified-id}} -A'}} expected-error {{C++ requires a type specifier for all declarations}} +A'}} Modified: cfe/trunk/test/SemaCXX/member-pointer.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/member-pointer.cpp?rev=97221&r1=97220&r2=97221&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/member-pointer.cpp (original) +++ cfe/trunk/test/SemaCXX/member-pointer.cpp Fri Feb 26 02:45:28 2010 @@ -12,8 +12,7 @@ int (::A::*pdi2); int (A::*pfi)(int); -int B::*pbi; // expected-error {{expected a class or namespace}} \ - // expected-error{{does not point into a class}} +int B::*pbi; // expected-error {{expected a class or namespace}} int C::*pci; // expected-error {{'pci' does not point into a class}} void A::*pdv; // expected-error {{'pdv' declared as a member pointer to void}} int& A::*pdr; // expected-error {{'pdr' declared as a member pointer to a reference}} Modified: cfe/trunk/test/SemaCXX/nested-name-spec.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/nested-name-spec.cpp?rev=97221&r1=97220&r2=97221&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/nested-name-spec.cpp (original) +++ cfe/trunk/test/SemaCXX/nested-name-spec.cpp Fri Feb 26 02:45:28 2010 @@ -13,8 +13,9 @@ } A:: ; // expected-error {{expected unqualified-id}} -::A::ax::undef ex3; // expected-error {{no member named}} -A::undef1::undef2 ex4; // expected-error {{no member named 'undef1'}} +// FIXME: redundant errors +::A::ax::undef ex3; // expected-error {{no member named}} expected-error {{unknown type name}} +A::undef1::undef2 ex4; // expected-error {{no member named 'undef1'}} expected-error {{unknown type name}} int A::C::Ag1() { return 0; } Modified: cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp?rev=97221&r1=97220&r2=97221&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp (original) +++ cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp Fri Feb 26 02:45:28 2010 @@ -57,7 +57,6 @@ int foo() { class NoDepBase::Nested nested; // expected-error{{'Nested' does not name a tag member in the specified scope}} typedef typename NoDepBase::template MemberTemplate::type type; // expected-error{{'MemberTemplate' following the 'template' keyword does not refer to a template}} \ - // FIXME: expected-error{{expected an identifier or template-id after '::'}} \ // FIXME: expected-error{{unqualified-id}} return NoDepBase::a; // expected-error{{no member named 'a' in 'struct PR6031::NoDepBase'}} } Modified: cfe/trunk/test/SemaTemplate/explicit-specialization-member.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/explicit-specialization-member.cpp?rev=97221&r1=97220&r2=97221&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/explicit-specialization-member.cpp (original) +++ cfe/trunk/test/SemaTemplate/explicit-specialization-member.cpp Fri Feb 26 02:45:28 2010 @@ -16,7 +16,7 @@ // expected-error{{expected class name}} \ // expected-note{{attempt to specialize declaration here}} { - static locale::id id; // expected-error{{use of undeclared identifier}} + static locale::id id; // expected-error{{use of undeclared identifier}} FIXME: expected-error {{unknown type name}} }; numpunct::~numpunct(); // expected-error{{template specialization requires 'template<>'}} \ // expected-error{{specialization of member 'PR6161::numpunct::~numpunct' does not specialize an instantiated member}} Modified: cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp?rev=97221&r1=97220&r2=97221&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp (original) +++ cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp Fri Feb 26 02:45:28 2010 @@ -49,6 +49,5 @@ template struct TestA { typedef typename N::template B::type type; // expected-error{{'B' following the 'template' keyword does not refer to a template}} \ - // expected-error{{identifier or template-id}} \ // expected-error{{expected member name}} }; Modified: cfe/trunk/test/SemaTemplate/temp_arg.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg.cpp?rev=97221&r1=97220&r2=97221&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/temp_arg.cpp (original) +++ cfe/trunk/test/SemaTemplate/temp_arg.cpp Fri Feb 26 02:45:28 2010 @@ -10,3 +10,10 @@ A *a2; // expected-error{{too many template arguments for class template 'A'}} A *a3; // expected-error{{too few template arguments for class template 'A'}} + +namespace test0 { + template class foo {}; + template class bar { + bar(::test0::foo *ptr) {} // FIXME(redundant): expected-error 2 {{use of undeclared identifier 'tee'}} + }; +} From xuzhongxing at gmail.com Fri Feb 26 02:46:13 2010 From: xuzhongxing at gmail.com (Zhongxing Xu) Date: Fri, 26 Feb 2010 08:46:13 -0000 Subject: [cfe-commits] r97222 - /cfe/trunk/include/clang/Checker/PathSensitive/GRState.h Message-ID: <20100226084613.7D3F92A6C12D@llvm.org> Author: zhongxingxu Date: Fri Feb 26 02:46:13 2010 New Revision: 97222 URL: http://llvm.org/viewvc/llvm-project?rev=97222&view=rev Log: Make GDM private. Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRState.h Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRState.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/GRState.h?rev=97222&r1=97221&r2=97222&view=diff ============================================================================== --- cfe/trunk/include/clang/Checker/PathSensitive/GRState.h (original) +++ cfe/trunk/include/clang/Checker/PathSensitive/GRState.h Fri Feb 26 02:46:13 2010 @@ -76,16 +76,13 @@ typedef llvm::ImmutableMap GenericDataMap; private: - void operator=(const GRState& R) const; + void operator=(const GRState& R) const; // Do not implement. friend class GRStateManager; GRStateManager *StateMgr; Environment Env; Store St; - - // FIXME: Make these private. -public: GenericDataMap GDM; public: From chandlerc at gmail.com Fri Feb 26 02:51:12 2010 From: chandlerc at gmail.com (Chandler Carruth) Date: Fri, 26 Feb 2010 08:51:12 -0000 Subject: [cfe-commits] r97223 - /cfe/trunk/include/clang/Frontend/CodeGenAction.h Message-ID: <20100226085112.544652A6C12C@llvm.org> Author: chandlerc Date: Fri Feb 26 02:51:12 2010 New Revision: 97223 URL: http://llvm.org/viewvc/llvm-project?rev=97223&view=rev Log: Make the destructor public. ddunbar, lemme know if you'd prefer a different fix, just trying to get the build bots happy again. Modified: cfe/trunk/include/clang/Frontend/CodeGenAction.h Modified: cfe/trunk/include/clang/Frontend/CodeGenAction.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CodeGenAction.h?rev=97223&r1=97222&r2=97223&view=diff ============================================================================== --- cfe/trunk/include/clang/Frontend/CodeGenAction.h (original) +++ cfe/trunk/include/clang/Frontend/CodeGenAction.h Fri Feb 26 02:51:12 2010 @@ -23,7 +23,6 @@ protected: CodeGenAction(unsigned _Act); - ~CodeGenAction(); virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile); @@ -31,6 +30,8 @@ virtual void EndSourceFileAction(); public: + ~CodeGenAction(); + /// takeModule - Take the generated LLVM module, for use after the action has /// been run. The result may be null on failure. llvm::Module *takeModule(); From xuzhongxing at gmail.com Fri Feb 26 09:43:34 2010 From: xuzhongxing at gmail.com (Zhongxing Xu) Date: Fri, 26 Feb 2010 15:43:34 -0000 Subject: [cfe-commits] r97225 - /cfe/trunk/lib/Checker/GRExprEngine.cpp Message-ID: <20100226154334.4A0532A6C12C@llvm.org> Author: zhongxingxu Date: Fri Feb 26 09:43:34 2010 New Revision: 97225 URL: http://llvm.org/viewvc/llvm-project?rev=97225&view=rev Log: Use a GDM to record the returned expression in the state when VisitReturnStmt. Use this information to find the returned value and bind it to CallExpr in ProcessCallExit. And there is no need to remove dead bindings in ProcessCallExit, because a. it would clean up the return value bound to CallExpr b. we still would do it in the next ProcessStmt(), where we would not misclean up the return value. Modified: cfe/trunk/lib/Checker/GRExprEngine.cpp Modified: cfe/trunk/lib/Checker/GRExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRExprEngine.cpp?rev=97225&r1=97224&r2=97225&view=diff ============================================================================== --- cfe/trunk/lib/Checker/GRExprEngine.cpp (original) +++ cfe/trunk/lib/Checker/GRExprEngine.cpp Fri Feb 26 09:43:34 2010 @@ -37,6 +37,15 @@ using llvm::cast; using llvm::APSInt; +namespace { + // Trait class for recording returned expression in the state. + struct ReturnExpr { + static int TagInt; + typedef const Stmt *data_type; + }; + int ReturnExpr::TagInt; +} + //===----------------------------------------------------------------------===// // Utility functions. //===----------------------------------------------------------------------===// @@ -1309,16 +1318,15 @@ const ExplodedNode *Pred = B.getPredecessor(); const StackFrameContext *LocCtx = cast(Pred->getLocationContext()); - const StackFrameContext *ParentSF = - cast(LocCtx->getParent()); - - SymbolReaper SymReaper(*ParentSF->getLiveVariables(), getSymbolManager(), - ParentSF); const Stmt *CE = LocCtx->getCallSite(); - state = getStateManager().RemoveDeadBindings(state, const_cast(CE), - SymReaper); - + // If the callee returns an expression, bind its value to CallExpr. + const Stmt *ReturnedExpr = state->get(); + if (ReturnedExpr) { + SVal RetVal = state->getSVal(ReturnedExpr); + state = state->BindExpr(CE, RetVal); + } + B.GenerateNode(state); } @@ -2889,10 +2897,20 @@ void GRExprEngine::VisitReturnStmt(ReturnStmt *RS, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - ExplodedNodeSet Src; if (Expr *RetE = RS->getRetValue()) { - Visit(RetE, Pred, Src); + // Record the returned expression in the state. + { + static int Tag; + SaveAndRestore OldTag(Builder->Tag); + Builder->Tag = &Tag; + const GRState *state = GetState(Pred); + state = state->set(RetE); + Pred = Builder->generateNode(RetE, state, Pred); + } + // We may get a NULL Pred because we generated a cached node. + if (Pred) + Visit(RetE, Pred, Src); } else { Src.Add(Pred); From fjahanian at apple.com Fri Feb 26 13:05:20 2010 From: fjahanian at apple.com (Fariborz Jahanian) Date: Fri, 26 Feb 2010 19:05:20 -0000 Subject: [cfe-commits] r97244 - in /cfe/trunk: lib/Frontend/RewriteObjC.cpp test/Rewriter/rewrite-nested-blocks.mm Message-ID: <20100226190520.70BA62A6C130@llvm.org> Author: fjahanian Date: Fri Feb 26 13:05:20 2010 New Revision: 97244 URL: http://llvm.org/viewvc/llvm-project?rev=97244&view=rev Log: Rewriting of imported variable from outer blocks's argument in the inner block requires special treatment. Fixes radar 7692419. Modified: cfe/trunk/lib/Frontend/RewriteObjC.cpp cfe/trunk/test/Rewriter/rewrite-nested-blocks.mm Modified: cfe/trunk/lib/Frontend/RewriteObjC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/RewriteObjC.cpp?rev=97244&r1=97243&r2=97244&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/RewriteObjC.cpp (original) +++ cfe/trunk/lib/Frontend/RewriteObjC.cpp Fri Feb 26 13:05:20 2010 @@ -4374,6 +4374,7 @@ if (BlockDeclRefExpr *CDRE = dyn_cast(S)) if (!isa(CDRE->getDecl()) && !CDRE->isByRef() && + !isa(CDRE->getDecl()) && !InnerBlockValueDecls.count(CDRE->getDecl())) { InnerBlockValueDecls.insert(CDRE->getDecl()); InnerBlockDeclRefs.push_back(CDRE); Modified: cfe/trunk/test/Rewriter/rewrite-nested-blocks.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Rewriter/rewrite-nested-blocks.mm?rev=97244&r1=97243&r2=97244&view=diff ============================================================================== --- cfe/trunk/test/Rewriter/rewrite-nested-blocks.mm (original) +++ cfe/trunk/test/Rewriter/rewrite-nested-blocks.mm Fri Feb 26 13:05:20 2010 @@ -36,3 +36,21 @@ }); }); } + +// radar 7692419 + at interface Bar + at end + +void f(Bar *); +void q(void (^block)(void)); + +void x() { + void (^myblock)(Bar *b) = ^(Bar *b) { + q(^{ + f(b); + }); + }; + + Bar *b = (Bar *)42; + myblock(b); +} From kremenek at apple.com Fri Feb 26 13:18:41 2010 From: kremenek at apple.com (Ted Kremenek) Date: Fri, 26 Feb 2010 19:18:41 -0000 Subject: [cfe-commits] r97248 - in /cfe/trunk: include/clang/Analysis/Analyses/PrintfFormatString.h include/clang/Basic/DiagnosticSemaKinds.td lib/Analysis/PrintfFormatString.cpp lib/Sema/SemaChecking.cpp test/Sema/format-strings.c Message-ID: <20100226191841.686D22A6C12C@llvm.org> Author: kremenek Date: Fri Feb 26 13:18:41 2010 New Revision: 97248 URL: http://llvm.org/viewvc/llvm-project?rev=97248&view=rev Log: For printf format string checking, move the tracking of the data argument index out of Sema and into analyze_printf::ParseFormatString(). Also use a bitvector to determine what arguments have been covered (instead of just checking to see if the last argument consumed is the max argument). This is prep. for support positional arguments (an IEEE extension). Modified: cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/Analysis/PrintfFormatString.cpp cfe/trunk/lib/Sema/SemaChecking.cpp cfe/trunk/test/Sema/format-strings.c Modified: cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h?rev=97248&r1=97247&r2=97248&view=diff ============================================================================== --- cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h (original) +++ cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h Fri Feb 26 13:18:41 2010 @@ -152,18 +152,21 @@ public: enum HowSpecified { NotSpecified, Constant, Arg }; - OptionalAmount(HowSpecified h, const char *st) - : start(st), hs(h), amt(0) {} + OptionalAmount(HowSpecified h, unsigned i, const char *st) + : start(st), hs(h), amt(i) {} OptionalAmount() : start(0), hs(NotSpecified), amt(0) {} - OptionalAmount(unsigned i, const char *st) - : start(st), hs(Constant), amt(i) {} - HowSpecified getHowSpecified() const { return hs; } + bool hasDataArgument() const { return hs == Arg; } + unsigned getArgIndex() const { + assert(hasDataArgument()); + return amt; + } + unsigned getConstantAmount() const { assert(hs == Constant); return amt; @@ -188,14 +191,14 @@ unsigned HasSpacePrefix : 1; unsigned HasAlternativeForm : 1; unsigned HasLeadingZeroes : 1; - unsigned flags : 5; + unsigned argIndex; ConversionSpecifier CS; OptionalAmount FieldWidth; OptionalAmount Precision; public: FormatSpecifier() : LM(None), IsLeftJustified(0), HasPlusPrefix(0), HasSpacePrefix(0), - HasAlternativeForm(0), HasLeadingZeroes(0) {} + HasAlternativeForm(0), HasLeadingZeroes(0), argIndex(0) {} static FormatSpecifier Parse(const char *beg, const char *end); @@ -212,6 +215,16 @@ void setHasAlternativeForm() { HasAlternativeForm = 1; } void setHasLeadingZeros() { HasLeadingZeroes = 1; } + void setArgIndex(unsigned i) { + assert(CS.consumesDataArgument()); + argIndex = i; + } + + unsigned getArgIndex() const { + assert(CS.consumesDataArgument()); + return argIndex; + } + // Methods for querying the format specifier. const ConversionSpecifier &getConversionSpecifier() const { @@ -262,10 +275,10 @@ virtual void HandleNullChar(const char *nullCharacter) {} - virtual void + virtual bool HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS, const char *startSpecifier, - unsigned specifierLen) {} + unsigned specifierLen) { return true; } virtual bool HandleFormatSpecifier(const analyze_printf::FormatSpecifier &FS, const char *startSpecifier, Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=97248&r1=97247&r2=97248&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Feb 26 13:18:41 2010 @@ -2521,8 +2521,8 @@ InGroup; def warn_printf_insufficient_data_args : Warning< "more '%%' conversions than data arguments">, InGroup; -def warn_printf_too_many_data_args : Warning< - "more data arguments than format specifiers">, InGroup; +def warn_printf_data_arg_not_used : Warning< + "data argument not used by format string">, InGroup; def warn_printf_invalid_conversion : Warning< "invalid conversion specifier '%0'">, InGroup; def warn_printf_incomplete_specifier : Warning< Modified: cfe/trunk/lib/Analysis/PrintfFormatString.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/PrintfFormatString.cpp?rev=97248&r1=97247&r2=97248&view=diff ============================================================================== --- cfe/trunk/lib/Analysis/PrintfFormatString.cpp (original) +++ cfe/trunk/lib/Analysis/PrintfFormatString.cpp Fri Feb 26 13:18:41 2010 @@ -62,7 +62,8 @@ // Methods for parsing format strings. //===----------------------------------------------------------------------===// -static OptionalAmount ParseAmount(const char *&Beg, const char *E) { +static OptionalAmount ParseAmount(const char *&Beg, const char *E, + unsigned &argIndex) { const char *I = Beg; UpdateOnReturn UpdateBeg(Beg, I); @@ -78,11 +79,11 @@ } if (foundDigits) - return OptionalAmount(accumulator, Beg); + return OptionalAmount(OptionalAmount::Constant, accumulator, Beg); if (c == '*') { ++I; - return OptionalAmount(OptionalAmount::Arg, Beg); + return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg); } break; @@ -93,7 +94,8 @@ static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H, const char *&Beg, - const char *E) { + const char *E, + unsigned &argIndex) { using namespace clang::analyze_printf; @@ -149,7 +151,7 @@ } // Look for the field width (if any). - FS.setFieldWidth(ParseAmount(I, E)); + FS.setFieldWidth(ParseAmount(I, E, argIndex)); if (I == E) { // No more characters left? @@ -165,7 +167,7 @@ return true; } - FS.setPrecision(ParseAmount(I, E)); + FS.setPrecision(ParseAmount(I, E, argIndex)); if (I == E) { // No more characters left? @@ -241,20 +243,26 @@ // Glibc specific. case 'm': k = ConversionSpecifier::PrintErrno; break; } - FS.setConversionSpecifier(ConversionSpecifier(conversionPosition, k)); + ConversionSpecifier CS(conversionPosition, k); + FS.setConversionSpecifier(CS); + if (CS.consumesDataArgument()) + FS.setArgIndex(argIndex++); if (k == ConversionSpecifier::InvalidSpecifier) { - H.HandleInvalidConversionSpecifier(FS, Beg, I - Beg); - return false; // Keep processing format specifiers. + // Assume the conversion takes one argument. + return !H.HandleInvalidConversionSpecifier(FS, Beg, I - Beg); } return FormatSpecifierResult(Start, FS); } bool clang::analyze_printf::ParseFormatString(FormatStringHandler &H, const char *I, const char *E) { + + unsigned argIndex = 0; + // Keep looking for a format specifier until we have exhausted the string. while (I != E) { - const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E); + const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E, argIndex); // Did a fail-stop error of any kind occur when parsing the specifier? // If so, don't do any more processing. if (FSR.shouldStop()) @@ -430,7 +438,7 @@ return Ctx.LongDoubleTy; return Ctx.DoubleTy; } - + switch (CS.getKind()) { case ConversionSpecifier::CStrArg: return ArgTypeResult(LM == AsWideChar ? ArgTypeResult::WCStrTy : ArgTypeResult::CStrTy); @@ -438,11 +446,11 @@ // FIXME: This appears to be Mac OS X specific. return ArgTypeResult::WCStrTy; case ConversionSpecifier::CArg: - return Ctx.WCharTy; + return Ctx.WCharTy; default: break; } - + // FIXME: Handle other cases. return ArgTypeResult(); } Modified: cfe/trunk/lib/Sema/SemaChecking.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=97248&r1=97247&r2=97248&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) +++ cfe/trunk/lib/Sema/SemaChecking.cpp Fri Feb 26 13:18:41 2010 @@ -955,6 +955,7 @@ /// FormatGuard: Automatic Protection From printf Format String /// Vulnerabilities, Proceedings of the 10th USENIX Security Symposium, 2001. /// +/// TODO: /// Functionality implemented: /// /// We can statically check the following properties for string @@ -965,7 +966,7 @@ /// data arguments? /// /// (2) Does each format conversion correctly match the type of the -/// corresponding data argument? (TODO) +/// corresponding data argument? /// /// Moreover, for all printf functions we can: /// @@ -984,7 +985,6 @@ /// /// All of these checks can be done by parsing the format string. /// -/// For now, we ONLY do (1), (3), (5), (6), (7), and (8). void Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg) { @@ -1044,13 +1044,13 @@ Sema &S; const StringLiteral *FExpr; const Expr *OrigFormatExpr; - unsigned NumConversions; const unsigned NumDataArgs; const bool IsObjCLiteral; const char *Beg; // Start of format string. const bool HasVAListArg; const CallExpr *TheCall; unsigned FormatIdx; + llvm::BitVector CoveredArgs; public: CheckPrintfHandler(Sema &s, const StringLiteral *fexpr, const Expr *origFormatExpr, @@ -1058,17 +1058,20 @@ const char *beg, bool hasVAListArg, const CallExpr *theCall, unsigned formatIdx) : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), - NumConversions(0), NumDataArgs(numDataArgs), + NumDataArgs(numDataArgs), IsObjCLiteral(isObjCLiteral), Beg(beg), HasVAListArg(hasVAListArg), - TheCall(theCall), FormatIdx(formatIdx) {} + TheCall(theCall), FormatIdx(formatIdx) { + CoveredArgs.resize(numDataArgs); + CoveredArgs.reset(); + } void DoneProcessing(); void HandleIncompleteFormatSpecifier(const char *startSpecifier, unsigned specifierLen); - void + bool HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS, const char *startSpecifier, unsigned specifierLen); @@ -1117,18 +1120,35 @@ << getFormatSpecifierRange(startSpecifier, specifierLen); } -void CheckPrintfHandler:: +bool CheckPrintfHandler:: HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS, const char *startSpecifier, unsigned specifierLen) { - ++NumConversions; + unsigned argIndex = FS.getArgIndex(); + bool keepGoing = true; + if (argIndex < NumDataArgs) { + // Consider the argument coverered, even though the specifier doesn't + // make sense. + CoveredArgs.set(argIndex); + } + else { + // If argIndex exceeds the number of data arguments we + // don't issue a warning because that is just a cascade of warnings (and + // they may have intended '%%' anyway). We don't want to continue processing + // the format string after this point, however, as we will like just get + // gibberish when trying to match arguments. + keepGoing = false; + } + const analyze_printf::ConversionSpecifier &CS = FS.getConversionSpecifier(); SourceLocation Loc = getLocationOfByte(CS.getStart()); S.Diag(Loc, diag::warn_printf_invalid_conversion) << llvm::StringRef(CS.getStart(), CS.getLength()) << getFormatSpecifierRange(startSpecifier, specifierLen); + + return keepGoing; } void CheckPrintfHandler::HandleNullChar(const char *nullCharacter) { @@ -1139,7 +1159,7 @@ } const Expr *CheckPrintfHandler::getDataArg(unsigned i) const { - return TheCall->getArg(FormatIdx + i); + return TheCall->getArg(FormatIdx + i + 1); } @@ -1162,9 +1182,9 @@ unsigned specifierLen) { if (Amt.hasDataArgument()) { - ++NumConversions; if (!HasVAListArg) { - if (NumConversions > NumDataArgs) { + unsigned argIndex = Amt.getArgIndex(); + if (argIndex >= NumDataArgs) { S.Diag(getLocationOfByte(Amt.getStart()), MissingArgDiag) << getFormatSpecifierRange(startSpecifier, specifierLen); // Don't do any more checking. We will just emit @@ -1176,7 +1196,8 @@ // Although not in conformance with C99, we also allow the argument to be // an 'unsigned int' as that is a reasonably safe case. GCC also // doesn't emit a warning for that case. - const Expr *Arg = getDataArg(NumConversions); + CoveredArgs.set(argIndex); + const Expr *Arg = getDataArg(argIndex); QualType T = Arg->getType(); const analyze_printf::ArgTypeResult &ATR = Amt.getArgType(S.Context); @@ -1221,22 +1242,21 @@ return false; } - // Check for using an Objective-C specific conversion specifier - // in a non-ObjC literal. - if (!IsObjCLiteral && CS.isObjCArg()) { - HandleInvalidConversionSpecifier(FS, startSpecifier, specifierLen); - - // Continue checking the other format specifiers. - return true; - } - if (!CS.consumesDataArgument()) { // FIXME: Technically specifying a precision or field width here // makes no sense. Worth issuing a warning at some point. return true; } - ++NumConversions; + // Consume the argument. + unsigned argIndex = FS.getArgIndex(); + CoveredArgs.set(argIndex); + + // Check for using an Objective-C specific conversion specifier + // in a non-ObjC literal. + if (!IsObjCLiteral && CS.isObjCArg()) { + return HandleInvalidConversionSpecifier(FS, startSpecifier, specifierLen); + } // Are we using '%n'? Issue a warning about this being // a possible security issue. @@ -1270,7 +1290,7 @@ if (HasVAListArg) return true; - if (NumConversions > NumDataArgs) { + if (argIndex >= NumDataArgs) { S.Diag(getLocationOfByte(CS.getStart()), diag::warn_printf_insufficient_data_args) << getFormatSpecifierRange(startSpecifier, specifierLen); @@ -1280,7 +1300,7 @@ // Now type check the data expression that matches the // format specifier. - const Expr *Ex = getDataArg(NumConversions); + const Expr *Ex = getDataArg(argIndex); const analyze_printf::ArgTypeResult &ATR = FS.getArgType(S.Context); if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType())) { // Check if we didn't match because of an implicit cast from a 'char' @@ -1304,10 +1324,17 @@ void CheckPrintfHandler::DoneProcessing() { // Does the number of data arguments exceed the number of // format conversions in the format string? - if (!HasVAListArg && NumConversions < NumDataArgs) - S.Diag(getDataArg(NumConversions+1)->getLocStart(), - diag::warn_printf_too_many_data_args) - << getFormatStringRange(); + if (!HasVAListArg) { + // Find any arguments that weren't covered. + CoveredArgs.flip(); + signed notCoveredArg = CoveredArgs.find_first(); + if (notCoveredArg >= 0) { + assert((unsigned)notCoveredArg < NumDataArgs); + S.Diag(getDataArg((unsigned) notCoveredArg)->getLocStart(), + diag::warn_printf_data_arg_not_used) + << getFormatStringRange(); + } + } } void Sema::CheckPrintfString(const StringLiteral *FExpr, Modified: cfe/trunk/test/Sema/format-strings.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/format-strings.c?rev=97248&r1=97247&r2=97248&view=diff ============================================================================== --- cfe/trunk/test/Sema/format-strings.c (original) +++ cfe/trunk/test/Sema/format-strings.c Fri Feb 26 13:18:41 2010 @@ -55,7 +55,7 @@ printf(i == 1 ? "yes" : "no"); // no-warning printf(i == 0 ? (i == 1 ? "yes" : "no") : "dont know"); // no-warning printf(i == 0 ? (i == 1 ? s : "no") : "dont know"); // expected-warning{{format string is not a string literal}} - printf("yes" ?: "no %d", 1); // expected-warning{{more data arguments than format specifiers}} + printf("yes" ?: "no %d", 1); // expected-warning{{data argument not used by format string}} } void check_writeback_specifier() @@ -155,7 +155,7 @@ printf("%**\n"); // expected-warning{{invalid conversion specifier '*'}} printf("%n", &i); // expected-warning{{use of '%n' in format string discouraged (potentially insecure)}} printf("%d%d\n", x); // expected-warning{{more '%' conversions than data arguments}} - printf("%d\n", x, x); // expected-warning{{more data arguments than format specifiers}} + printf("%d\n", x, x); // expected-warning{{data argument not used by format string}} printf("%W%d%Z\n", x, x, x); // expected-warning{{invalid conversion specifier 'W'}} expected-warning{{invalid conversion specifier 'Z'}} printf("%"); // expected-warning{{incomplete format specifier}} printf("%.d", x); // no-warning From sabre at nondot.org Fri Feb 26 13:42:53 2010 From: sabre at nondot.org (Chris Lattner) Date: Fri, 26 Feb 2010 19:42:53 -0000 Subject: [cfe-commits] r97253 - in /cfe/trunk: lib/Lex/PPExpressions.cpp test/Preprocessor/directive-invalid.c Message-ID: <20100226194253.3025B2A6C12E@llvm.org> Author: lattner Date: Fri Feb 26 13:42:53 2010 New Revision: 97253 URL: http://llvm.org/viewvc/llvm-project?rev=97253&view=rev Log: fix rdar://7683173, rejecting an invalid conditional Added: cfe/trunk/test/Preprocessor/directive-invalid.c Modified: cfe/trunk/lib/Lex/PPExpressions.cpp Modified: cfe/trunk/lib/Lex/PPExpressions.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPExpressions.cpp?rev=97253&r1=97252&r2=97253&view=diff ============================================================================== --- cfe/trunk/lib/Lex/PPExpressions.cpp (original) +++ cfe/trunk/lib/Lex/PPExpressions.cpp Fri Feb 26 13:42:53 2010 @@ -106,7 +106,7 @@ // Consume identifier. Result.setEnd(PeekTok.getLocation()); - PP.LexNonComment(PeekTok); + PP.LexUnexpandedToken(PeekTok); // If we are in parens, ensure we have a trailing ). if (LParenLoc.isValid()) { Added: cfe/trunk/test/Preprocessor/directive-invalid.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/directive-invalid.c?rev=97253&view=auto ============================================================================== --- cfe/trunk/test/Preprocessor/directive-invalid.c (added) +++ cfe/trunk/test/Preprocessor/directive-invalid.c Fri Feb 26 13:42:53 2010 @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -E -verify %s +// rdar://7683173 + +#define r_paren ) +#if defined( x r_paren // expected-error {{missing ')' after 'defined'}} \ + // expected-note {{to match this '('}} +#endif From fjahanian at apple.com Fri Feb 26 13:55:31 2010 From: fjahanian at apple.com (Fariborz Jahanian) Date: Fri, 26 Feb 2010 19:55:31 -0000 Subject: [cfe-commits] r97254 - in /cfe/trunk: lib/Frontend/RewriteObjC.cpp test/Rewriter/rewrite-byref-in-nested-blocks.mm Message-ID: <20100226195531.97C3C2A6C12C@llvm.org> Author: fjahanian Date: Fri Feb 26 13:55:31 2010 New Revision: 97254 URL: http://llvm.org/viewvc/llvm-project?rev=97254&view=rev Log: Fix rewriting of byref variables in nested blocks. Fixes radar 7692350. Added: cfe/trunk/test/Rewriter/rewrite-byref-in-nested-blocks.mm Modified: cfe/trunk/lib/Frontend/RewriteObjC.cpp Modified: cfe/trunk/lib/Frontend/RewriteObjC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/RewriteObjC.cpp?rev=97254&r1=97253&r2=97254&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/RewriteObjC.cpp (original) +++ cfe/trunk/lib/Frontend/RewriteObjC.cpp Fri Feb 26 13:55:31 2010 @@ -4373,7 +4373,6 @@ // Handle specific things. if (BlockDeclRefExpr *CDRE = dyn_cast(S)) if (!isa(CDRE->getDecl()) && - !CDRE->isByRef() && !isa(CDRE->getDecl()) && !InnerBlockValueDecls.count(CDRE->getDecl())) { InnerBlockValueDecls.insert(CDRE->getDecl()); @@ -4982,7 +4981,7 @@ for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) { BlockDeclRefExpr *Exp = InnerBlockDeclRefs[i]; ValueDecl *VD = Exp->getDecl(); - if (!BlockByCopyDeclsPtrSet.count(VD)) { + if (!Exp->isByRef() && !BlockByCopyDeclsPtrSet.count(VD)) { // We need to save the copied-in variables in nested // blocks because it is needed at the end for some of the API generations. // See SynthesizeBlockLiterals routine. @@ -4996,6 +4995,14 @@ ImportedBlockDecls.insert(VD); } } + if (Exp->isByRef() && !BlockByRefDeclsPtrSet.count(VD)) { + InnerDeclRefs.push_back(Exp); countOfInnerDecls++; + BlockDeclRefs.push_back(Exp); + BlockByRefDeclsPtrSet.insert(VD); + BlockByRefDecls.push_back(VD); + GetBlockCallExprs(Exp); + ImportedBlockDecls.insert(VD); + } } InnerDeclRefsCount.push_back(countOfInnerDecls); Added: cfe/trunk/test/Rewriter/rewrite-byref-in-nested-blocks.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Rewriter/rewrite-byref-in-nested-blocks.mm?rev=97254&view=auto ============================================================================== --- cfe/trunk/test/Rewriter/rewrite-byref-in-nested-blocks.mm (added) +++ cfe/trunk/test/Rewriter/rewrite-byref-in-nested-blocks.mm Fri Feb 26 13:55:31 2010 @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// radar 7692350 + +void f(void (^block)(void)); + + at interface X { + int y; +} +- (void)foo; + at end + + at implementation X +- (void)foo { + __block int kerfluffle; + f(^{ + f(^{ + y = 42; + kerfluffle = 1; + }); + }); +} + at end From rjmccall at apple.com Fri Feb 26 14:22:44 2010 From: rjmccall at apple.com (John McCall) Date: Fri, 26 Feb 2010 20:22:44 -0000 Subject: [cfe-commits] r97258 - /cfe/trunk/lib/CodeGen/CGVtable.cpp Message-ID: <20100226202244.EDDE92A6C12C@llvm.org> Author: rjmccall Date: Fri Feb 26 14:22:44 2010 New Revision: 97258 URL: http://llvm.org/viewvc/llvm-project?rev=97258&view=rev Log: Sundry fixes to the new vtable builder. Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=97258&r1=97257&r2=97258&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGVtable.cpp (original) +++ cfe/trunk/lib/CodeGen/CGVtable.cpp Fri Feb 26 14:22:44 2010 @@ -808,6 +808,28 @@ bool empty() const { return Offsets.empty(); } }; +static bool HasSameVirtualSignature(const CXXMethodDecl *LHS, + const CXXMethodDecl *RHS) { + ASTContext &C = LHS->getASTContext(); // TODO: thread this down + CanQual + LT = C.getCanonicalType(LHS->getType()).getAs(), + RT = C.getCanonicalType(RHS->getType()).getAs(); + + // Fast-path matches in the canonical types. + if (LT == RT) return true; + + // Force the signatures to match. We can't rely on the overrides + // list here because there isn't necessarily an inheritance + // relationship between the two methods. + if (LT.getQualifiers() != RT.getQualifiers() || + LT->getNumArgs() != RT->getNumArgs()) + return false; + for (unsigned I = 0, E = LT->getNumArgs(); I != E; ++I) + if (LT->getArgType(I) != RT->getArgType(I)) + return false; + return true; +} + bool VCallOffsetMap::MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, const CXXMethodDecl *RHS) { assert(LHS->isVirtual() && "LHS must be virtual!"); @@ -815,20 +837,14 @@ // FIXME: We need to check more things here. + // Must have the same name. + // FIXME: are destructors an exception to this? DeclarationName LHSName = LHS->getDeclName(); DeclarationName RHSName = RHS->getDeclName(); - if (LHSName.getNameKind() != LHSName.getNameKind()) + if (LHSName != RHSName) return false; - - switch (LHSName.getNameKind()) { - default: - assert(false && "Unhandled name kind!"); - case DeclarationName::Identifier: - if (LHSName.getAsIdentifierInfo() != RHSName.getAsIdentifierInfo()) - return false; - } - - return true; + + return (HasSameVirtualSignature(LHS, RHS)); } bool VCallOffsetMap::AddVCallOffset(const CXXMethodDecl *MD, @@ -963,8 +979,10 @@ const CXXRecordDecl *RD = Base.getBase(); const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + // Handle the primary base first. - if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { + if (PrimaryBase) { uint64_t PrimaryBaseOffset; // Get the base offset of the primary base. @@ -1036,6 +1054,8 @@ const CXXRecordDecl *BaseDecl = cast(I->getType()->getAs()->getDecl()); + if (BaseDecl == PrimaryBase) + continue; // Get the base offset of this base. uint64_t BaseOffset = Base.getBaseOffset() + @@ -1126,7 +1146,7 @@ /// nearest virtual base. int64_t NonVirtual; - /// VCallOffsetOffset - The offset (in bytes), relative to the address point + /// VCallOffsetOffset - The offset (in bytes), relative to the address point, /// of the virtual call offset. int64_t VCallOffsetOffset; From fjahanian at apple.com Fri Feb 26 15:46:28 2010 From: fjahanian at apple.com (Fariborz Jahanian) Date: Fri, 26 Feb 2010 21:46:28 -0000 Subject: [cfe-commits] r97274 - /cfe/trunk/lib/Frontend/RewriteObjC.cpp Message-ID: <20100226214628.132262A6C12C@llvm.org> Author: fjahanian Date: Fri Feb 26 15:46:27 2010 New Revision: 97274 URL: http://llvm.org/viewvc/llvm-project?rev=97274&view=rev Log: Removed some unused code in rewriter. Modified: cfe/trunk/lib/Frontend/RewriteObjC.cpp Modified: cfe/trunk/lib/Frontend/RewriteObjC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/RewriteObjC.cpp?rev=97274&r1=97273&r2=97274&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/RewriteObjC.cpp (original) +++ cfe/trunk/lib/Frontend/RewriteObjC.cpp Fri Feb 26 15:46:27 2010 @@ -124,7 +124,6 @@ llvm::SmallVector InnerDeclRefs; llvm::SmallVector BlockDeclRefs; - llvm::DenseMap BlockCallExprs; // Block related declarations. llvm::SmallVector BlockByCopyDecls; @@ -388,7 +387,6 @@ void RewriteRecordBody(RecordDecl *RD); void CollectBlockDeclRefInfo(BlockExpr *Exp); - void GetBlockCallExprs(Stmt *S); void GetBlockDeclRefExprs(Stmt *S); void GetInnerBlockDeclRefExprs(Stmt *S, llvm::SmallVector &InnerBlockDeclRefs, @@ -4301,7 +4299,6 @@ BlockByRefDeclsPtrSet.clear(); BlockByCopyDecls.clear(); BlockByCopyDeclsPtrSet.clear(); - BlockCallExprs.clear(); ImportedBlockDecls.clear(); } Blocks.clear(); @@ -4381,24 +4378,6 @@ return; } -void RewriteObjC::GetBlockCallExprs(Stmt *S) { - for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); - CI != E; ++CI) - if (*CI) { - if (BlockExpr *CBE = dyn_cast(*CI)) - GetBlockCallExprs(CBE->getBody()); - else - GetBlockCallExprs(*CI); - } - - if (CallExpr *CE = dyn_cast(S)) { - if (CE->getCallee()->getType()->isBlockPointerType()) { - BlockCallExprs[dyn_cast(CE->getCallee())] = CE; - } - } - return; -} - Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { // Navigate to relevant type information. const BlockPointerType *CPT = 0; @@ -4955,10 +4934,8 @@ for (unsigned i = 0; i < BlockDeclRefs.size(); i++) if (BlockDeclRefs[i]->isByRef() || BlockDeclRefs[i]->getType()->isObjCObjectPointerType() || - BlockDeclRefs[i]->getType()->isBlockPointerType()) { - GetBlockCallExprs(BlockDeclRefs[i]); + BlockDeclRefs[i]->getType()->isBlockPointerType()) ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl()); - } } } @@ -4990,17 +4967,14 @@ BlockByCopyDeclsPtrSet.insert(VD); BlockByCopyDecls.push_back(VD); if (Exp->getType()->isObjCObjectPointerType() || - Exp->getType()->isBlockPointerType()) { - GetBlockCallExprs(Exp); + Exp->getType()->isBlockPointerType()) ImportedBlockDecls.insert(VD); - } } if (Exp->isByRef() && !BlockByRefDeclsPtrSet.count(VD)) { InnerDeclRefs.push_back(Exp); countOfInnerDecls++; BlockDeclRefs.push_back(Exp); BlockByRefDeclsPtrSet.insert(VD); BlockByRefDecls.push_back(VD); - GetBlockCallExprs(Exp); ImportedBlockDecls.insert(VD); } } From fjahanian at apple.com Fri Feb 26 16:36:30 2010 From: fjahanian at apple.com (Fariborz Jahanian) Date: Fri, 26 Feb 2010 22:36:30 -0000 Subject: [cfe-commits] r97280 - /cfe/trunk/lib/Frontend/RewriteObjC.cpp Message-ID: <20100226223630.C15752A6C12C@llvm.org> Author: fjahanian Date: Fri Feb 26 16:36:30 2010 New Revision: 97280 URL: http://llvm.org/viewvc/llvm-project?rev=97280&view=rev Log: Minor cleanup of the rewriter. Modified: cfe/trunk/lib/Frontend/RewriteObjC.cpp Modified: cfe/trunk/lib/Frontend/RewriteObjC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/RewriteObjC.cpp?rev=97280&r1=97279&r2=97280&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/RewriteObjC.cpp (original) +++ cfe/trunk/lib/Frontend/RewriteObjC.cpp Fri Feb 26 16:36:30 2010 @@ -4955,28 +4955,32 @@ // Add inner imported variables now used in current block. int countOfInnerDecls = 0; - for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) { - BlockDeclRefExpr *Exp = InnerBlockDeclRefs[i]; - ValueDecl *VD = Exp->getDecl(); - if (!Exp->isByRef() && !BlockByCopyDeclsPtrSet.count(VD)) { + if (!InnerBlockDeclRefs.empty()) { + for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) { + BlockDeclRefExpr *Exp = InnerBlockDeclRefs[i]; + ValueDecl *VD = Exp->getDecl(); + if (!Exp->isByRef() && !BlockByCopyDeclsPtrSet.count(VD)) { // We need to save the copied-in variables in nested // blocks because it is needed at the end for some of the API generations. // See SynthesizeBlockLiterals routine. - InnerDeclRefs.push_back(Exp); countOfInnerDecls++; - BlockDeclRefs.push_back(Exp); - BlockByCopyDeclsPtrSet.insert(VD); - BlockByCopyDecls.push_back(VD); - if (Exp->getType()->isObjCObjectPointerType() || - Exp->getType()->isBlockPointerType()) - ImportedBlockDecls.insert(VD); - } - if (Exp->isByRef() && !BlockByRefDeclsPtrSet.count(VD)) { - InnerDeclRefs.push_back(Exp); countOfInnerDecls++; - BlockDeclRefs.push_back(Exp); - BlockByRefDeclsPtrSet.insert(VD); - BlockByRefDecls.push_back(VD); - ImportedBlockDecls.insert(VD); + InnerDeclRefs.push_back(Exp); countOfInnerDecls++; + BlockDeclRefs.push_back(Exp); + BlockByCopyDeclsPtrSet.insert(VD); + BlockByCopyDecls.push_back(VD); + } + if (Exp->isByRef() && !BlockByRefDeclsPtrSet.count(VD)) { + InnerDeclRefs.push_back(Exp); countOfInnerDecls++; + BlockDeclRefs.push_back(Exp); + BlockByRefDeclsPtrSet.insert(VD); + BlockByRefDecls.push_back(VD); + } } + // Find any imported blocks...they will need special attention. + for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) + if (InnerBlockDeclRefs[i]->isByRef() || + InnerBlockDeclRefs[i]->getType()->isObjCObjectPointerType() || + InnerBlockDeclRefs[i]->getType()->isBlockPointerType()) + ImportedBlockDecls.insert(InnerBlockDeclRefs[i]->getDecl()); } InnerDeclRefsCount.push_back(countOfInnerDecls); From fjahanian at apple.com Fri Feb 26 16:49:11 2010 From: fjahanian at apple.com (Fariborz Jahanian) Date: Fri, 26 Feb 2010 22:49:11 -0000 Subject: [cfe-commits] r97281 - in /cfe/trunk: lib/Frontend/RewriteObjC.cpp test/Rewriter/rewrite-byref-in-nested-blocks.mm Message-ID: <20100226224911.D29FA2A6C12C@llvm.org> Author: fjahanian Date: Fri Feb 26 16:49:11 2010 New Revision: 97281 URL: http://llvm.org/viewvc/llvm-project?rev=97281&view=rev Log: Prevent rewriter crash when variable type is missing. Fixes radar 7692183. Modified: cfe/trunk/lib/Frontend/RewriteObjC.cpp cfe/trunk/test/Rewriter/rewrite-byref-in-nested-blocks.mm Modified: cfe/trunk/lib/Frontend/RewriteObjC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/RewriteObjC.cpp?rev=97281&r1=97280&r2=97281&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/RewriteObjC.cpp (original) +++ cfe/trunk/lib/Frontend/RewriteObjC.cpp Fri Feb 26 16:49:11 2010 @@ -4781,6 +4781,10 @@ int flag = 0; int isa = 0; SourceLocation DeclLoc = ND->getTypeSpecStartLoc(); + if (DeclLoc.isInvalid()) + // If type location is missing, it is because of missing type (a warning). + // Use variable's location which is good for this case. + DeclLoc = ND->getLocation(); const char *startBuf = SM->getCharacterData(DeclLoc); SourceLocation X = ND->getLocEnd(); X = SM->getInstantiationLoc(X); Modified: cfe/trunk/test/Rewriter/rewrite-byref-in-nested-blocks.mm URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Rewriter/rewrite-byref-in-nested-blocks.mm?rev=97281&r1=97280&r2=97281&view=diff ============================================================================== --- cfe/trunk/test/Rewriter/rewrite-byref-in-nested-blocks.mm (original) +++ cfe/trunk/test/Rewriter/rewrite-byref-in-nested-blocks.mm Fri Feb 26 16:49:11 2010 @@ -13,10 +13,13 @@ @implementation X - (void)foo { __block int kerfluffle; + // radar 7692183 + __block x; f(^{ f(^{ y = 42; kerfluffle = 1; + x = 2; }); }); } From rjmccall at apple.com Fri Feb 26 17:35:57 2010 From: rjmccall at apple.com (John McCall) Date: Fri, 26 Feb 2010 23:35:57 -0000 Subject: [cfe-commits] r97284 - in /cfe/trunk: include/clang/Basic/DiagnosticGroups.td include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaExpr.cpp test/Lexer/constants.c Message-ID: <20100226233557.99F7B2A6C12C@llvm.org> Author: rjmccall Date: Fri Feb 26 17:35:57 2010 New Revision: 97284 URL: http://llvm.org/viewvc/llvm-project?rev=97284&view=rev Log: At sabre's request, drop the FP bounds diagnostics down to warnings and file them under -Wbad-literal. They're still on by default. Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/test/Lexer/constants.c Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=97284&r1=97283&r2=97284&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Fri Feb 26 17:35:57 2010 @@ -24,6 +24,7 @@ def : DiagGroup<"aggregate-return">; def : DiagGroup<"attributes">; def : DiagGroup<"bad-function-cast">; +def BadLiteral : DiagGroup<"bad-literal">; // not in gcc def : DiagGroup<"c++-compat">; def : DiagGroup<"cast-align">; def : DiagGroup<"cast-qual">; Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=97284&r1=97283&r2=97284&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Feb 26 17:35:57 2010 @@ -29,10 +29,12 @@ // Semantic analysis of constant literals. def ext_predef_outside_function : Warning< "predefined identifier is only valid inside function">; -def err_float_overflow : Error< - "magnitude of floating-point constant too large for type %0; maximum is %1">; -def err_float_underflow : Error< - "magnitude of floating-point constant too small for type %0; minimum is %1">; +def warn_float_overflow : Warning< + "magnitude of floating-point constant too large for type %0; maximum is %1">, + InGroup; +def warn_float_underflow : Warning< + "magnitude of floating-point constant too small for type %0; minimum is %1">, + InGroup; // C99 Designated Initializers def err_array_designator_negative : Error< Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=97284&r1=97283&r2=97284&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Feb 26 17:35:57 2010 @@ -1736,10 +1736,10 @@ unsigned diagnostic; llvm::SmallVector buffer; if (result & APFloat::opOverflow) { - diagnostic = diag::err_float_overflow; + diagnostic = diag::warn_float_overflow; APFloat::getLargest(Format).toString(buffer); } else { - diagnostic = diag::err_float_underflow; + diagnostic = diag::warn_float_underflow; APFloat::getSmallest(Format).toString(buffer); } Modified: cfe/trunk/test/Lexer/constants.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Lexer/constants.c?rev=97284&r1=97283&r2=97284&view=diff ============================================================================== --- cfe/trunk/test/Lexer/constants.c (original) +++ cfe/trunk/test/Lexer/constants.c Fri Feb 26 17:35:57 2010 @@ -38,20 +38,20 @@ float t0[] = { 1.9e20f, 1.9e-20f, - 1.9e50f, // expected-error {{too large}} - 1.9e-50f, // expected-error {{too small}} + 1.9e50f, // expected-warning {{too large}} + 1.9e-50f, // expected-warning {{too small}} -1.9e20f, -1.9e-20f, - -1.9e50f, // expected-error {{too large}} - -1.9e-50f // expected-error {{too small}} + -1.9e50f, // expected-warning {{too large}} + -1.9e-50f // expected-warning {{too small}} }; double t1[] = { 1.9e50, 1.9e-50, - 1.9e500, // expected-error {{too large}} - 1.9e-500, // expected-error {{too small}} + 1.9e500, // expected-warning {{too large}} + 1.9e-500, // expected-warning {{too small}} -1.9e50, -1.9e-50, - -1.9e500, // expected-error {{too large}} - -1.9e-500 // expected-error {{too small}} + -1.9e500, // expected-warning {{too large}} + -1.9e-500 // expected-warning {{too small}} }; From clattner at apple.com Fri Feb 26 17:45:03 2010 From: clattner at apple.com (Chris Lattner) Date: Fri, 26 Feb 2010 15:45:03 -0800 Subject: [cfe-commits] r97284 - in /cfe/trunk: include/clang/Basic/DiagnosticGroups.td include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaExpr.cpp test/Lexer/constants.c In-Reply-To: <20100226233557.99F7B2A6C12C@llvm.org> References: <20100226233557.99F7B2A6C12C@llvm.org> Message-ID: <94D4B79D-BB5D-4D8F-B583-5A8C42E03B06@apple.com> On Feb 26, 2010, at 3:35 PM, John McCall wrote: > Author: rjmccall > Date: Fri Feb 26 17:35:57 2010 > New Revision: 97284 > > URL: http://llvm.org/viewvc/llvm-project?rev=97284&view=rev > Log: > At sabre's request, drop the FP bounds diagnostics down to warnings and file > them under -Wbad-literal. They're still on by default. If you'd like, you can still default them to error, that allows people to shut it up with -Wno-error=bad-literal Also, please add the BadLiteral group to the "NotGCC" group. -Chris > > > Modified: > cfe/trunk/include/clang/Basic/DiagnosticGroups.td > cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td > cfe/trunk/lib/Sema/SemaExpr.cpp > cfe/trunk/test/Lexer/constants.c > > Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=97284&r1=97283&r2=97284&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original) > +++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Fri Feb 26 17:35:57 2010 > @@ -24,6 +24,7 @@ > def : DiagGroup<"aggregate-return">; > def : DiagGroup<"attributes">; > def : DiagGroup<"bad-function-cast">; > +def BadLiteral : DiagGroup<"bad-literal">; // not in gcc > def : DiagGroup<"c++-compat">; > def : DiagGroup<"cast-align">; > def : DiagGroup<"cast-qual">; > > Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=97284&r1=97283&r2=97284&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) > +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Feb 26 17:35:57 2010 > @@ -29,10 +29,12 @@ > // Semantic analysis of constant literals. > def ext_predef_outside_function : Warning< > "predefined identifier is only valid inside function">; > -def err_float_overflow : Error< > - "magnitude of floating-point constant too large for type %0; maximum is %1">; > -def err_float_underflow : Error< > - "magnitude of floating-point constant too small for type %0; minimum is %1">; > +def warn_float_overflow : Warning< > + "magnitude of floating-point constant too large for type %0; maximum is %1">, > + InGroup; > +def warn_float_underflow : Warning< > + "magnitude of floating-point constant too small for type %0; minimum is %1">, > + InGroup; > > // C99 Designated Initializers > def err_array_designator_negative : Error< > > Modified: cfe/trunk/lib/Sema/SemaExpr.cpp > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=97284&r1=97283&r2=97284&view=diff > ============================================================================== > --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) > +++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Feb 26 17:35:57 2010 > @@ -1736,10 +1736,10 @@ > unsigned diagnostic; > llvm::SmallVector buffer; > if (result & APFloat::opOverflow) { > - diagnostic = diag::err_float_overflow; > + diagnostic = diag::warn_float_overflow; > APFloat::getLargest(Format).toString(buffer); > } else { > - diagnostic = diag::err_float_underflow; > + diagnostic = diag::warn_float_underflow; > APFloat::getSmallest(Format).toString(buffer); > } > > > Modified: cfe/trunk/test/Lexer/constants.c > URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Lexer/constants.c?rev=97284&r1=97283&r2=97284&view=diff > ============================================================================== > --- cfe/trunk/test/Lexer/constants.c (original) > +++ cfe/trunk/test/Lexer/constants.c Fri Feb 26 17:35:57 2010 > @@ -38,20 +38,20 @@ > float t0[] = { > 1.9e20f, > 1.9e-20f, > - 1.9e50f, // expected-error {{too large}} > - 1.9e-50f, // expected-error {{too small}} > + 1.9e50f, // expected-warning {{too large}} > + 1.9e-50f, // expected-warning {{too small}} > -1.9e20f, > -1.9e-20f, > - -1.9e50f, // expected-error {{too large}} > - -1.9e-50f // expected-error {{too small}} > + -1.9e50f, // expected-warning {{too large}} > + -1.9e-50f // expected-warning {{too small}} > }; > double t1[] = { > 1.9e50, > 1.9e-50, > - 1.9e500, // expected-error {{too large}} > - 1.9e-500, // expected-error {{too small}} > + 1.9e500, // expected-warning {{too large}} > + 1.9e-500, // expected-warning {{too small}} > -1.9e50, > -1.9e-50, > - -1.9e500, // expected-error {{too large}} > - -1.9e-500 // expected-error {{too small}} > + -1.9e500, // expected-warning {{too large}} > + -1.9e-500 // expected-warning {{too small}} > }; > > > _______________________________________________ > cfe-commits mailing list > cfe-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits From rjmccall at apple.com Fri Feb 26 17:48:57 2010 From: rjmccall at apple.com (John McCall) Date: Fri, 26 Feb 2010 23:48:57 -0000 Subject: [cfe-commits] r97286 - /cfe/trunk/include/clang/Basic/DiagnosticGroups.td Message-ID: <20100226234857.7F4D32A6C12C@llvm.org> Author: rjmccall Date: Fri Feb 26 17:48:57 2010 New Revision: 97286 URL: http://llvm.org/viewvc/llvm-project?rev=97286&view=rev Log: Put BadLiteral in the NonGCC group. I'd completely forgotten about this. Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=97286&r1=97285&r2=97286&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Fri Feb 26 17:48:57 2010 @@ -24,7 +24,7 @@ def : DiagGroup<"aggregate-return">; def : DiagGroup<"attributes">; def : DiagGroup<"bad-function-cast">; -def BadLiteral : DiagGroup<"bad-literal">; // not in gcc +def BadLiteral : DiagGroup<"bad-literal">; def : DiagGroup<"c++-compat">; def : DiagGroup<"cast-align">; def : DiagGroup<"cast-qual">; @@ -181,4 +181,4 @@ // A warning group for warnings that we want to have on by default in clang, // but which aren't on by default in GCC. def NonGCC : DiagGroup<"non-gcc", - [SignCompare, Conversion]>; + [SignCompare, Conversion, BadLiteral]>; From dgregor at apple.com Fri Feb 26 18:25:29 2010 From: dgregor at apple.com (Douglas Gregor) Date: Sat, 27 Feb 2010 00:25:29 -0000 Subject: [cfe-commits] r97291 - in /cfe/trunk: lib/AST/DeclCXX.cpp lib/Sema/SemaDeclCXX.cpp test/SemaTemplate/dependent-base-classes.cpp Message-ID: <20100227002529.43E022A6C12C@llvm.org> Author: dgregor Date: Fri Feb 26 18:25:28 2010 New Revision: 97291 URL: http://llvm.org/viewvc/llvm-project?rev=97291&view=rev Log: Skip dependent virtual base classes; fixes PR6413. Modified: cfe/trunk/lib/AST/DeclCXX.cpp cfe/trunk/lib/Sema/SemaDeclCXX.cpp cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp Modified: cfe/trunk/lib/AST/DeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=97291&r1=97290&r2=97291&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclCXX.cpp (original) +++ cfe/trunk/lib/AST/DeclCXX.cpp Fri Feb 26 18:25:28 2010 @@ -94,9 +94,7 @@ // Keep track of inherited vbases for this base class. const CXXBaseSpecifier *Base = Bases[i]; QualType BaseType = Base->getType(); - // Skip template types. - // FIXME. This means that this list must be rebuilt during template - // instantiation. + // Skip dependent types; we can't do any checking on them now. if (BaseType->isDependentType()) continue; CXXRecordDecl *BaseClassDecl @@ -143,6 +141,9 @@ data().NumVBases = vbaseCount; for (int i = 0; i < vbaseCount; i++) { QualType QT = UniqueVbases[i]->getType(); + // Skip dependent types; we can't do any checking on them now. + if (QT->isDependentType()) + continue; CXXRecordDecl *VBaseClassDecl = cast(QT->getAs()->getDecl()); data().VBases[i] = Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=97291&r1=97290&r2=97291&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Feb 26 18:25:28 2010 @@ -586,7 +586,10 @@ return true; AdjustDeclIfTemplate(classdecl); - CXXRecordDecl *Class = cast(classdecl.getAs()); + CXXRecordDecl *Class = dyn_cast(classdecl.getAs()); + if (!Class) + return true; + QualType BaseType = GetTypeFromParser(basetype); if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange, Virtual, Access, Modified: cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp?rev=97291&r1=97290&r2=97291&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp (original) +++ cfe/trunk/test/SemaTemplate/dependent-base-classes.cpp Fri Feb 26 18:25:28 2010 @@ -109,3 +109,15 @@ } }; } + +namespace PR6413 { + template class Base_A { }; + + class Base_B { }; + + template + class Derived + : public virtual Base_A + , public virtual Base_B + { }; +} From dgregor at apple.com Fri Feb 26 19:32:48 2010 From: dgregor at apple.com (Douglas Gregor) Date: Sat, 27 Feb 2010 01:32:48 -0000 Subject: [cfe-commits] r97296 - in /cfe/trunk: include/clang-c/Index.h lib/Frontend/ASTUnit.cpp lib/Frontend/InitPreprocessor.cpp tools/CIndex/CIndex.cpp Message-ID: <20100227013248.D230E2A6C12C@llvm.org> Author: dgregor Date: Fri Feb 26 19:32:48 2010 New Revision: 97296 URL: http://llvm.org/viewvc/llvm-project?rev=97296&view=rev Log: When given unsaved files in clang_createTranslationUnitFromSourceFile, copy the source buffers provided rather than referencing them directly, so that the caller can free those buffers immediately after calling clang_createTranslationUnitFromSourceFile(). Otherwise, we risk hitting those buffers later (when building source ranges, forming diagnostics, etc.). Modified: cfe/trunk/include/clang-c/Index.h cfe/trunk/lib/Frontend/ASTUnit.cpp cfe/trunk/lib/Frontend/InitPreprocessor.cpp cfe/trunk/tools/CIndex/CIndex.cpp Modified: cfe/trunk/include/clang-c/Index.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang-c/Index.h?rev=97296&r1=97295&r2=97296&view=diff ============================================================================== --- cfe/trunk/include/clang-c/Index.h (original) +++ cfe/trunk/include/clang-c/Index.h Fri Feb 26 19:32:48 2010 @@ -87,14 +87,12 @@ const char *Filename; /** - * \brief A null-terminated buffer containing the unsaved contents - * of this file. + * \brief A buffer containing the unsaved contents of this file. */ const char *Contents; /** - * \brief The length of the unsaved contents of this buffer, not - * counting the NULL at the end of the buffer. + * \brief The length of the unsaved contents of this buffer. */ unsigned long Length; }; Modified: cfe/trunk/lib/Frontend/ASTUnit.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/ASTUnit.cpp?rev=97296&r1=97295&r2=97296&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/ASTUnit.cpp (original) +++ cfe/trunk/lib/Frontend/ASTUnit.cpp Fri Feb 26 19:32:48 2010 @@ -162,6 +162,7 @@ if (!FromFile) { Diags.Report(diag::err_fe_remap_missing_from_file) << RemappedFiles[I].first; + delete RemappedFiles[I].second; continue; } Modified: cfe/trunk/lib/Frontend/InitPreprocessor.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/InitPreprocessor.cpp?rev=97296&r1=97295&r2=97296&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/InitPreprocessor.cpp (original) +++ cfe/trunk/lib/Frontend/InitPreprocessor.cpp Fri Feb 26 19:32:48 2010 @@ -439,6 +439,7 @@ if (!FromFile) { Diags.Report(diag::err_fe_remap_missing_from_file) << Remap->first; + delete Remap->second; continue; } @@ -477,7 +478,7 @@ = llvm::MemoryBuffer::getFile(ToFile->getName(), &ErrorStr); if (!Buffer) { Diags.Report(diag::err_fe_error_opening) - << Remap->second << ErrorStr; + << Remap->second << ErrorStr; continue; } Modified: cfe/trunk/tools/CIndex/CIndex.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CIndex/CIndex.cpp?rev=97296&r1=97295&r2=97296&view=diff ============================================================================== --- cfe/trunk/tools/CIndex/CIndex.cpp (original) +++ cfe/trunk/tools/CIndex/CIndex.cpp Fri Feb 26 19:32:48 2010 @@ -966,7 +966,7 @@ llvm::SmallVector RemappedFiles; for (unsigned I = 0; I != num_unsaved_files; ++I) { const llvm::MemoryBuffer *Buffer - = llvm::MemoryBuffer::getMemBuffer(unsaved_files[I].Contents, + = llvm::MemoryBuffer::getMemBufferCopy(unsaved_files[I].Contents, unsaved_files[I].Contents + unsaved_files[I].Length, unsaved_files[I].Filename); RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename, From kremenek at apple.com Fri Feb 26 19:41:03 2010 From: kremenek at apple.com (Ted Kremenek) Date: Sat, 27 Feb 2010 01:41:03 -0000 Subject: [cfe-commits] r97297 - in /cfe/trunk: include/clang/Analysis/Analyses/PrintfFormatString.h include/clang/Basic/DiagnosticSemaKinds.td lib/Analysis/PrintfFormatString.cpp lib/Sema/SemaChecking.cpp test/Sema/format-strings.c Message-ID: <20100227014103.400F92A6C12C@llvm.org> Author: kremenek Date: Fri Feb 26 19:41:03 2010 New Revision: 97297 URL: http://llvm.org/viewvc/llvm-project?rev=97297&view=rev Log: For printf format string checking, add support for positional format strings. Along the way, coelesce some of the diagnostics. Modified: cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/Analysis/PrintfFormatString.cpp cfe/trunk/lib/Sema/SemaChecking.cpp cfe/trunk/test/Sema/format-strings.c Modified: cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h?rev=97297&r1=97296&r2=97297&view=diff ============================================================================== --- cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h (original) +++ cfe/trunk/include/clang/Analysis/Analyses/PrintfFormatString.h Fri Feb 26 19:41:03 2010 @@ -150,13 +150,17 @@ class OptionalAmount { public: - enum HowSpecified { NotSpecified, Constant, Arg }; + enum HowSpecified { NotSpecified, Constant, Arg, Invalid }; OptionalAmount(HowSpecified h, unsigned i, const char *st) : start(st), hs(h), amt(i) {} - OptionalAmount() - : start(0), hs(NotSpecified), amt(0) {} + OptionalAmount(bool b = true) + : start(0), hs(b ? NotSpecified : Invalid), amt(0) {} + + bool isInvalid() const { + return hs == Invalid; + } HowSpecified getHowSpecified() const { return hs; } @@ -191,6 +195,7 @@ unsigned HasSpacePrefix : 1; unsigned HasAlternativeForm : 1; unsigned HasLeadingZeroes : 1; + unsigned UsesPositionalArg : 1; unsigned argIndex; ConversionSpecifier CS; OptionalAmount FieldWidth; @@ -198,7 +203,8 @@ public: FormatSpecifier() : LM(None), IsLeftJustified(0), HasPlusPrefix(0), HasSpacePrefix(0), - HasAlternativeForm(0), HasLeadingZeroes(0), argIndex(0) {} + HasAlternativeForm(0), HasLeadingZeroes(0), UsesPositionalArg(0), + argIndex(0) {} static FormatSpecifier Parse(const char *beg, const char *end); @@ -214,6 +220,7 @@ void setHasSpacePrefix() { HasSpacePrefix = 1; } void setHasAlternativeForm() { HasAlternativeForm = 1; } void setHasLeadingZeros() { HasLeadingZeroes = 1; } + void setUsesPositionalArg() { UsesPositionalArg = 1; } void setArgIndex(unsigned i) { assert(CS.consumesDataArgument()); @@ -263,8 +270,11 @@ bool hasAlternativeForm() const { return (bool) HasAlternativeForm; } bool hasLeadingZeros() const { return (bool) HasLeadingZeroes; } bool hasSpacePrefix() const { return (bool) HasSpacePrefix; } + bool usesPositionalArg() const { return (bool) UsesPositionalArg; } }; +enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 }; + class FormatStringHandler { public: FormatStringHandler() {} @@ -275,6 +285,11 @@ virtual void HandleNullChar(const char *nullCharacter) {} + virtual void HandleInvalidPosition(const char *startPos, unsigned posLen, + PositionContext p) {} + + virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {} + virtual bool HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS, const char *startSpecifier, Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=97297&r1=97296&r2=97297&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Feb 26 19:41:03 2010 @@ -2534,6 +2534,15 @@ def warn_printf_conversion_argument_type_mismatch : Warning< "conversion specifies type %0 but the argument has type %1">, InGroup; +def warn_printf_zero_positional_specifier : Warning< + "position arguments in format strings start counting at 1 (not 0)">, + InGroup; +def warn_printf_invalid_positional_specifier : Warning< + "invalid position specified for %select{field width|field precision}0">, + InGroup; +def warn_printf_mix_positional_nonpositional_args : Warning< + "cannot mix positional and non-positional arguments in format string">, + InGroup; def warn_null_arg : Warning< "null passed to a callee which requires a non-null argu