From 6df2408694f81a03eb8b0e3b013272042233c061 Mon Sep 17 00:00:00 2001 From: rdivacky Date: Thu, 19 Nov 2009 09:00:00 +0000 Subject: Update clang to r89337. --- lib/CodeGen/CGCXX.cpp | 4 +- lib/CodeGen/CGDecl.cpp | 1 - lib/CodeGen/CGRecordLayoutBuilder.cpp | 5 + lib/CodeGen/CGRtti.cpp | 107 +++++-- lib/CodeGen/CGVtable.cpp | 111 +++++-- lib/CodeGen/CGVtable.h | 4 + lib/CodeGen/CodeGenModule.cpp | 10 + lib/Driver/ArgList.cpp | 59 ++-- lib/Driver/CC1Options.cpp | 43 +++ lib/Driver/CMakeLists.txt | 4 +- lib/Driver/Compilation.cpp | 1 + lib/Driver/Driver.cpp | 54 ++-- lib/Driver/DriverOptions.cpp | 42 +++ lib/Driver/HostInfo.cpp | 10 +- lib/Driver/OptTable.cpp | 220 ++++++------- lib/Driver/Option.cpp | 53 ++-- lib/Driver/ToolChains.cpp | 11 +- lib/Driver/Tools.cpp | 30 +- lib/Driver/Types.cpp | 6 +- lib/Frontend/CompilerInvocation.cpp | 15 +- lib/Frontend/InitPreprocessor.cpp | 11 +- lib/Frontend/PCHReader.cpp | 5 +- lib/Headers/stdint.h | 34 +- lib/Parse/ParseExpr.cpp | 11 - lib/Parse/ParseObjc.cpp | 113 ++++++- lib/Sema/CodeCompleteConsumer.cpp | 61 ++++ lib/Sema/Lookup.h | 86 ++++- lib/Sema/Sema.cpp | 2 +- lib/Sema/Sema.h | 66 +++- lib/Sema/SemaCXXCast.cpp | 26 +- lib/Sema/SemaCodeComplete.cpp | 523 ++++++++++++++++++++++++++++--- lib/Sema/SemaDecl.cpp | 457 ++++++++++++++++----------- lib/Sema/SemaDeclCXX.cpp | 22 +- lib/Sema/SemaDeclObjC.cpp | 7 +- lib/Sema/SemaExprCXX.cpp | 6 + lib/Sema/SemaLookup.cpp | 6 +- lib/Sema/SemaOverload.cpp | 222 +++++++------ lib/Sema/SemaTemplate.cpp | 41 ++- lib/Sema/SemaTemplateInstantiateDecl.cpp | 42 +-- lib/Sema/TreeTransform.h | 23 +- 40 files changed, 1777 insertions(+), 777 deletions(-) create mode 100644 lib/Driver/CC1Options.cpp create mode 100644 lib/Driver/DriverOptions.cpp (limited to 'lib') diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 8f5cff4..b1d30a6 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -603,8 +603,8 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, EmitBlock(AfterFor, true); } -/// GenerateCXXAggrDestructorHelper - Generates a helper function which when invoked, -/// calls the default destructor on array elements in reverse order of +/// GenerateCXXAggrDestructorHelper - Generates a helper function which when +/// invoked, calls the default destructor on array elements in reverse order of /// construction. llvm::Constant * CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 1d2040b..349ede5 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -611,4 +611,3 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) { DI->EmitDeclareOfArgVariable(&D, DeclPtr, Builder); } } - diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index 8e0864b..a63c832 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -345,6 +345,11 @@ static const CXXMethodDecl *GetKeyFunction(const RecordDecl *D) { if (MD->isPure()) continue; + // FIXME: This doesn't work. If we have an out of line body, that body will + // set the MD to have a body, what we want to know is, was the body present + // inside the declaration of the class. For now, we just avoid the problem + // by pretending there is no key function. + return 0; if (MD->getBody()) continue; diff --git a/lib/CodeGen/CGRtti.cpp b/lib/CodeGen/CGRtti.cpp index e18843d..79d8664 100644 --- a/lib/CodeGen/CGRtti.cpp +++ b/lib/CodeGen/CGRtti.cpp @@ -47,21 +47,35 @@ public: return llvm::ConstantExpr::getBitCast(C, Int8PtrTy); } - llvm::Constant *BuildName(QualType Ty, bool Hidden) { + llvm::Constant *BuildName(QualType Ty, bool Hidden, bool Extern) { llvm::SmallString<256> OutName; llvm::raw_svector_ostream Out(OutName); mangleCXXRttiName(CGM.getMangleContext(), Ty, Out); + llvm::StringRef Name = Out.str(); llvm::GlobalVariable::LinkageTypes linktype; linktype = llvm::GlobalValue::LinkOnceODRLinkage; + if (!Extern) + linktype = llvm::GlobalValue::InternalLinkage; + + llvm::GlobalVariable *GV; + GV = CGM.getModule().getGlobalVariable(Name); + if (GV && !GV->isDeclaration()) + return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); llvm::Constant *C; - C = llvm::ConstantArray::get(VMContext, Out.str().substr(4)); + C = llvm::ConstantArray::get(VMContext, Name.substr(4)); - llvm::GlobalVariable * GV = new llvm::GlobalVariable(CGM.getModule(), - C->getType(), - true, linktype, C, - Out.str()); + llvm::GlobalVariable *OGV = GV; + GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, linktype, + C, Name); + if (OGV) { + GV->takeName(OGV); + llvm::Constant *NewPtr = llvm::ConstantExpr::getBitCast(GV, + OGV->getType()); + OGV->replaceAllUsesWith(NewPtr); + OGV->eraseFromParent(); + } if (Hidden) GV->setVisibility(llvm::GlobalVariable::HiddenVisibility); return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); @@ -87,8 +101,9 @@ public: llvm::SmallString<256> OutName; llvm::raw_svector_ostream Out(OutName); mangleCXXRtti(CGM.getMangleContext(), Ty, Out); + llvm::StringRef Name = Out.str(); - C = CGM.getModule().getGlobalVariable(Out.str()); + C = CGM.getModule().getGlobalVariable(Name); if (C) return llvm::ConstantExpr::getBitCast(C, Int8PtrTy); @@ -96,7 +111,7 @@ public: linktype = llvm::GlobalValue::ExternalLinkage;; C = new llvm::GlobalVariable(CGM.getModule(), Int8PtrTy, true, linktype, - 0, Out.str()); + 0, Name); return llvm::ConstantExpr::getBitCast(C, Int8PtrTy); } @@ -147,20 +162,19 @@ public: llvm::Constant *finish(std::vector &info, llvm::GlobalVariable *GV, - llvm::StringRef Name, bool Hidden) { + llvm::StringRef Name, bool Hidden, bool Extern) { llvm::GlobalVariable::LinkageTypes linktype; linktype = llvm::GlobalValue::LinkOnceODRLinkage; + if (!Extern) + linktype = llvm::GlobalValue::InternalLinkage; llvm::Constant *C; C = llvm::ConstantStruct::get(VMContext, &info[0], info.size(), false); - if (GV == 0) - GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, - linktype, C, Name); - else { - llvm::GlobalVariable *OGV = GV; - GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, - linktype, C, Name); + llvm::GlobalVariable *OGV = GV; + GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, linktype, + C, Name); + if (OGV) { GV->takeName(OGV); llvm::Constant *NewPtr = llvm::ConstantExpr::getBitCast(GV, OGV->getType()); @@ -183,15 +197,17 @@ public: llvm::raw_svector_ostream Out(OutName); mangleCXXRtti(CGM.getMangleContext(), CGM.getContext().getTagDeclType(RD), Out); + llvm::StringRef Name = Out.str(); llvm::GlobalVariable *GV; - GV = CGM.getModule().getGlobalVariable(Out.str()); + GV = CGM.getModule().getGlobalVariable(Name); if (GV && !GV->isDeclaration()) return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); std::vector info; bool Hidden = CGM.getDeclVisibilityMode(RD) == LangOptions::Hidden; + bool Extern = !RD->isInAnonymousNamespace(); bool simple = false; if (RD->getNumBases() == 0) @@ -202,7 +218,8 @@ public: } else C = BuildVtableRef("_ZTVN10__cxxabiv121__vmi_class_type_infoE"); info.push_back(C); - info.push_back(BuildName(CGM.getContext().getTagDeclType(RD), Hidden)); + info.push_back(BuildName(CGM.getContext().getTagDeclType(RD), Hidden, + Extern)); // If we have no bases, there are no more fields. if (RD->getNumBases()) { @@ -235,7 +252,7 @@ public: } } - return finish(info, GV, Out.str(), Hidden); + return finish(info, GV, Name, Hidden, Extern); } /// - BuildFlags - Build a __flags value for __pbase_type_info. @@ -250,23 +267,49 @@ public: return BuildType(Ty); } + bool DecideExtern(QualType Ty) { + // For this type, see if all components are never in an anonymous namespace. + if (const MemberPointerType *MPT = Ty->getAs()) + return (DecideExtern(MPT->getPointeeType()) + && DecideExtern(QualType(MPT->getClass(), 0))); + if (const PointerType *PT = Ty->getAs()) + return DecideExtern(PT->getPointeeType()); + if (const RecordType *RT = Ty->getAs()) + if (const CXXRecordDecl *RD = dyn_cast(RT->getDecl())) + return !RD->isInAnonymousNamespace(); + return true; + } + + bool DecideHidden(QualType Ty) { + // For this type, see if all components are never hidden. + if (const MemberPointerType *MPT = Ty->getAs()) + return (DecideHidden(MPT->getPointeeType()) + && DecideHidden(QualType(MPT->getClass(), 0))); + if (const PointerType *PT = Ty->getAs()) + return DecideHidden(PT->getPointeeType()); + if (const RecordType *RT = Ty->getAs()) + if (const CXXRecordDecl *RD = dyn_cast(RT->getDecl())) + return CGM.getDeclVisibilityMode(RD) == LangOptions::Hidden; + return false; + } + llvm::Constant *BuildPointerType(QualType Ty) { llvm::Constant *C; llvm::SmallString<256> OutName; llvm::raw_svector_ostream Out(OutName); mangleCXXRtti(CGM.getMangleContext(), Ty, Out); + llvm::StringRef Name = Out.str(); llvm::GlobalVariable *GV; - GV = CGM.getModule().getGlobalVariable(Out.str()); + GV = CGM.getModule().getGlobalVariable(Name); if (GV && !GV->isDeclaration()) return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); std::vector info; - // FIXME: pointer to hidden should be hidden, we should be able to - // grab a bit off the type for this. - bool Hidden = false; + bool Extern = DecideExtern(Ty); + bool Hidden = DecideHidden(Ty); QualType PTy = Ty->getPointeeType(); QualType BTy; @@ -282,7 +325,7 @@ public: else C = BuildVtableRef("_ZTVN10__cxxabiv119__pointer_type_infoE"); info.push_back(C); - info.push_back(BuildName(Ty, Hidden)); + info.push_back(BuildName(Ty, Hidden, Extern)); Qualifiers Q = PTy.getQualifiers(); PTy = CGM.getContext().getCanonicalType(PTy).getUnqualifiedType(); int flags = 0; @@ -300,7 +343,8 @@ public: if (PtrMem) info.push_back(BuildType2(BTy)); - return finish(info, GV, Out.str(), true); + // We always generate these as hidden, only the name isn't hidden. + return finish(info, GV, Name, true, Extern); } llvm::Constant *BuildSimpleType(QualType Ty, const char *vtbl) { @@ -309,23 +353,24 @@ public: llvm::SmallString<256> OutName; llvm::raw_svector_ostream Out(OutName); mangleCXXRtti(CGM.getMangleContext(), Ty, Out); + llvm::StringRef Name = Out.str(); llvm::GlobalVariable *GV; - GV = CGM.getModule().getGlobalVariable(Out.str()); + GV = CGM.getModule().getGlobalVariable(Name); if (GV && !GV->isDeclaration()) return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); std::vector info; - // FIXME: pointer to hidden should be hidden, we should be able to - // grab a bit off the type for this. - bool Hidden = false; + bool Extern = DecideExtern(Ty); + bool Hidden = DecideHidden(Ty); C = BuildVtableRef(vtbl); info.push_back(C); - info.push_back(BuildName(Ty, Hidden)); + info.push_back(BuildName(Ty, Hidden, Extern)); - return finish(info, GV, Out.str(), true); + // We always generate these as hidden, only the name isn't hidden. + return finish(info, GV, Name, true, Extern); } llvm::Constant *BuildType(QualType Ty) { diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index 4c97a9b..9be1a3b 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -69,7 +69,6 @@ private: llvm::DenseMap &AddressPoints; typedef CXXRecordDecl::method_iterator method_iter; - // FIXME: Linkage should follow vtable const bool Extern; const uint32_t LLVMPointerWidth; Index_t extra; @@ -82,7 +81,7 @@ public: BLayout(cgm.getContext().getASTRecordLayout(l)), rtti(cgm.GenerateRttiRef(c)), VMContext(cgm.getModule().getContext()), CGM(cgm), AddressPoints(*new llvm::DenseMap), - Extern(true), + Extern(!l->isInAnonymousNamespace()), LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) { Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); @@ -788,37 +787,73 @@ llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass, mangleCXXCtorVtable(getMangleContext(), LayoutClass, Offset/8, RD, Out); else mangleCXXVtable(getMangleContext(), RD, Out); + llvm::StringRef Name = Out.str(); - llvm::GlobalVariable::LinkageTypes linktype; - linktype = llvm::GlobalValue::LinkOnceODRLinkage; std::vector methods; llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0); int64_t AddressPoint; - VtableBuilder b(methods, RD, LayoutClass, Offset, *this); + llvm::GlobalVariable *GV = getModule().getGlobalVariable(Name); + if (GV && AddressPoints[LayoutClass] && !GV->isDeclaration()) + AddressPoint=(*(*(AddressPoints[LayoutClass]))[RD])[std::make_pair(RD, + Offset)]; + else { + VtableBuilder b(methods, RD, LayoutClass, Offset, *this); - D1(printf("vtable %s\n", RD->getNameAsCString())); - // First comes the vtables for all the non-virtual bases... - AddressPoint = b.GenerateVtableForBase(RD, Offset); + D1(printf("vtable %s\n", RD->getNameAsCString())); + // First comes the vtables for all the non-virtual bases... + AddressPoint = b.GenerateVtableForBase(RD, Offset); - // then the vtables for all the virtual bases. - b.GenerateVtableForVBases(RD, Offset); + // then the vtables for all the virtual bases. + b.GenerateVtableForVBases(RD, Offset); - CodeGenModule::AddrMap_t *&ref = AddressPoints[LayoutClass]; - if (ref == 0) - ref = new CodeGenModule::AddrMap_t; + CodeGenModule::AddrMap_t *&ref = AddressPoints[LayoutClass]; + if (ref == 0) + ref = new CodeGenModule::AddrMap_t; - (*ref)[RD] = b.getAddressPoints(); + (*ref)[RD] = b.getAddressPoints(); + + bool CreateDefinition = true; + if (LayoutClass != RD) + CreateDefinition = true; + else { + // We have to convert it to have a record layout. + Types.ConvertTagDeclType(LayoutClass); + const CGRecordLayout &CGLayout = Types.getCGRecordLayout(LayoutClass); + if (const CXXMethodDecl *KeyFunction = CGLayout.getKeyFunction()) { + if (!KeyFunction->getBody()) { + // If there is a KeyFunction, and it isn't defined, just build a + // reference to the vtable. + CreateDefinition = false; + } + } + } - llvm::Constant *C; - llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, methods.size()); - C = llvm::ConstantArray::get(type, methods); - llvm::GlobalVariable *GV = new llvm::GlobalVariable(getModule(), type, - true, linktype, C, - Out.str()); - bool Hidden = getDeclVisibilityMode(RD) == LangOptions::Hidden; - if (Hidden) - GV->setVisibility(llvm::GlobalVariable::HiddenVisibility); + llvm::Constant *C = 0; + llvm::Type *type = Ptr8Ty; + llvm::GlobalVariable::LinkageTypes linktype + = llvm::GlobalValue::ExternalLinkage; + if (CreateDefinition) { + llvm::ArrayType *ntype = llvm::ArrayType::get(Ptr8Ty, methods.size()); + C = llvm::ConstantArray::get(ntype, methods); + linktype = llvm::GlobalValue::LinkOnceODRLinkage; + if (LayoutClass->isInAnonymousNamespace()) + linktype = llvm::GlobalValue::InternalLinkage; + type = ntype; + } + llvm::GlobalVariable *OGV = GV; + GV = new llvm::GlobalVariable(getModule(), type, true, linktype, C, Name); + if (OGV) { + GV->takeName(OGV); + llvm::Constant *NewPtr = llvm::ConstantExpr::getBitCast(GV, + OGV->getType()); + OGV->replaceAllUsesWith(NewPtr); + OGV->eraseFromParent(); + } + bool Hidden = getDeclVisibilityMode(RD) == LangOptions::Hidden; + if (Hidden) + GV->setVisibility(llvm::GlobalVariable::HiddenVisibility); + } llvm::Constant *vtable = llvm::ConstantExpr::getBitCast(GV, Ptr8Ty); llvm::Constant *AddressPointC; uint32_t LLVMPointerWidth = getContext().Target.getPointerWidth(0); @@ -1001,9 +1036,12 @@ llvm::Constant *CodeGenModule::GenerateVTT(const CXXRecordDecl *RD) { llvm::SmallString<256> OutName; llvm::raw_svector_ostream Out(OutName); mangleCXXVTT(getMangleContext(), RD, Out); + llvm::StringRef Name = Out.str(); llvm::GlobalVariable::LinkageTypes linktype; linktype = llvm::GlobalValue::LinkOnceODRLinkage; + if (RD->isInAnonymousNamespace()) + linktype = llvm::GlobalValue::InternalLinkage; std::vector inits; llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0); @@ -1015,20 +1053,41 @@ llvm::Constant *CodeGenModule::GenerateVTT(const CXXRecordDecl *RD) { llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, inits.size()); C = llvm::ConstantArray::get(type, inits); llvm::GlobalVariable *vtt = new llvm::GlobalVariable(getModule(), type, true, - linktype, C, Out.str()); + linktype, C, Name); bool Hidden = getDeclVisibilityMode(RD) == LangOptions::Hidden; if (Hidden) vtt->setVisibility(llvm::GlobalVariable::HiddenVisibility); return llvm::ConstantExpr::getBitCast(vtt, Ptr8Ty); } +void CGVtableInfo::GenerateClassData(const CXXRecordDecl *RD) { + Vtables[RD] = CGM.GenerateVtable(RD, RD); + CGM.GenerateRtti(RD); + CGM.GenerateVTT(RD); +} + llvm::Constant *CGVtableInfo::getVtable(const CXXRecordDecl *RD) { llvm::Constant *&vtbl = Vtables[RD]; if (vtbl) return vtbl; vtbl = CGM.GenerateVtable(RD, RD); - CGM.GenerateRtti(RD); - CGM.GenerateVTT(RD); + + bool CreateDefinition = true; + // We have to convert it to have a record layout. + CGM.getTypes().ConvertTagDeclType(RD); + const CGRecordLayout &CGLayout = CGM.getTypes().getCGRecordLayout(RD); + if (const CXXMethodDecl *KeyFunction = CGLayout.getKeyFunction()) { + if (!KeyFunction->getBody()) { + // If there is a KeyFunction, and it isn't defined, just build a + // reference to the vtable. + CreateDefinition = false; + } + } + + if (CreateDefinition) { + CGM.GenerateRtti(RD); + CGM.GenerateVTT(RD); + } return vtbl; } diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h index f9ddf44..78ae670 100644 --- a/lib/CodeGen/CGVtable.h +++ b/lib/CodeGen/CGVtable.h @@ -61,6 +61,10 @@ public: llvm::Constant *getVtable(const CXXRecordDecl *RD); llvm::Constant *getCtorVtable(const CXXRecordDecl *RD, const CXXRecordDecl *Class, uint64_t Offset); + /// GenerateClassData - Generate all the class data requires to be generated + /// upon definition of a KeyFunction. This includes the vtable, the + /// rtti data structure and the VTT. + void GenerateClassData(const CXXRecordDecl *RD); }; } diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 0e6f4a6..195acc5 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -616,6 +616,16 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { Context.getSourceManager(), "Generating code for declaration"); + if (const CXXMethodDecl *MD = dyn_cast(D)) { + const CXXRecordDecl *RD = MD->getParent(); + // We have to convert it to have a record layout. + Types.ConvertTagDeclType(RD); + const CGRecordLayout &CGLayout = Types.getCGRecordLayout(RD); + // A definition of a KeyFunction, generates all the class data, such + // as vtable, rtti and the VTT. + if (CGLayout.getKeyFunction() == MD) + getVtableInfo().GenerateClassData(RD); + } if (const CXXConstructorDecl *CD = dyn_cast(D)) EmitCXXConstructor(CD, GD.getCtorType()); else if (const CXXDestructorDecl *DD = dyn_cast(D)) diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp index 8d2138d..ea75c34 100644 --- a/lib/Driver/ArgList.cpp +++ b/lib/Driver/ArgList.cpp @@ -27,38 +27,41 @@ void ArgList::append(Arg *A) { Args.push_back(A); } -Arg *ArgList::getLastArg(options::ID Id, bool Claim) const { +Arg *ArgList::getLastArgNoClaim(OptSpecifier Id) const { // FIXME: Make search efficient? - for (const_reverse_iterator it = rbegin(), ie = rend(); it != ie; ++it) { - if ((*it)->getOption().matches(Id)) { - if (Claim) (*it)->claim(); + for (const_reverse_iterator it = rbegin(), ie = rend(); it != ie; ++it) + if ((*it)->getOption().matches(Id)) return *it; - } - } - return 0; } -Arg *ArgList::getLastArg(options::ID Id0, options::ID Id1, bool Claim) const { - Arg *Res, *A0 = getLastArg(Id0, false), *A1 = getLastArg(Id1, false); +Arg *ArgList::getLastArg(OptSpecifier Id) const { + Arg *A = getLastArgNoClaim(Id); + if (A) + A->claim(); + return A; +} + +Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1) const { + Arg *Res, *A0 = getLastArgNoClaim(Id0), *A1 = getLastArgNoClaim(Id1); if (A0 && A1) Res = A0->getIndex() > A1->getIndex() ? A0 : A1; else Res = A0 ? A0 : A1; - if (Claim && Res) + if (Res) Res->claim(); return Res; } -Arg *ArgList::getLastArg(options::ID Id0, options::ID Id1, options::ID Id2, - bool Claim) const { +Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1, + OptSpecifier Id2) const { Arg *Res = 0; - Arg *A0 = getLastArg(Id0, false); - Arg *A1 = getLastArg(Id1, false); - Arg *A2 = getLastArg(Id2, false); + Arg *A0 = getLastArgNoClaim(Id0); + Arg *A1 = getLastArgNoClaim(Id1); + Arg *A2 = getLastArgNoClaim(Id2); int A0Idx = A0 ? A0->getIndex() : -1; int A1Idx = A1 ? A1->getIndex() : -1; @@ -76,26 +79,26 @@ Arg *ArgList::getLastArg(options::ID Id0, options::ID Id1, options::ID Id2, Res = A2; } - if (Claim && Res) + if (Res) Res->claim(); return Res; } -bool ArgList::hasFlag(options::ID Pos, options::ID Neg, bool Default) const { +bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier Neg, bool Default) const { if (Arg *A = getLastArg(Pos, Neg)) return A->getOption().matches(Pos); return Default; } -void ArgList::AddLastArg(ArgStringList &Output, options::ID Id) const { +void ArgList::AddLastArg(ArgStringList &Output, OptSpecifier Id) const { if (Arg *A = getLastArg(Id)) { A->claim(); A->render(*this, Output); } } -void ArgList::AddAllArgs(ArgStringList &Output, options::ID Id0) const { +void ArgList::AddAllArgs(ArgStringList &Output, OptSpecifier Id0) const { // FIXME: Make fast. for (const_iterator it = begin(), ie = end(); it != ie; ++it) { const Arg *A = *it; @@ -106,8 +109,8 @@ void ArgList::AddAllArgs(ArgStringList &Output, options::ID Id0) const { } } -void ArgList::AddAllArgs(ArgStringList &Output, options::ID Id0, - options::ID Id1) const { +void ArgList::AddAllArgs(ArgStringList &Output, OptSpecifier Id0, + OptSpecifier Id1) const { // FIXME: Make fast. for (const_iterator it = begin(), ie = end(); it != ie; ++it) { const Arg *A = *it; @@ -118,8 +121,8 @@ void ArgList::AddAllArgs(ArgStringList &Output, options::ID Id0, } } -void ArgList::AddAllArgs(ArgStringList &Output, options::ID Id0, - options::ID Id1, options::ID Id2) const { +void ArgList::AddAllArgs(ArgStringList &Output, OptSpecifier Id0, + OptSpecifier Id1, OptSpecifier Id2) const { // FIXME: Make fast. for (const_iterator it = begin(), ie = end(); it != ie; ++it) { const Arg *A = *it; @@ -131,7 +134,7 @@ void ArgList::AddAllArgs(ArgStringList &Output, options::ID Id0, } } -void ArgList::AddAllArgValues(ArgStringList &Output, options::ID Id0) const { +void ArgList::AddAllArgValues(ArgStringList &Output, OptSpecifier Id0) const { // FIXME: Make fast. for (const_iterator it = begin(), ie = end(); it != ie; ++it) { const Arg *A = *it; @@ -143,8 +146,8 @@ void ArgList::AddAllArgValues(ArgStringList &Output, options::ID Id0) const { } } -void ArgList::AddAllArgValues(ArgStringList &Output, options::ID Id0, - options::ID Id1) const { +void ArgList::AddAllArgValues(ArgStringList &Output, OptSpecifier Id0, + OptSpecifier Id1) const { // FIXME: Make fast. for (const_iterator it = begin(), ie = end(); it != ie; ++it) { const Arg *A = *it; @@ -156,7 +159,7 @@ void ArgList::AddAllArgValues(ArgStringList &Output, options::ID Id0, } } -void ArgList::AddAllArgsTranslated(ArgStringList &Output, options::ID Id0, +void ArgList::AddAllArgsTranslated(ArgStringList &Output, OptSpecifier Id0, const char *Translation, bool Joined) const { // FIXME: Make fast. @@ -177,7 +180,7 @@ void ArgList::AddAllArgsTranslated(ArgStringList &Output, options::ID Id0, } } -void ArgList::ClaimAllArgs(options::ID Id0) const { +void ArgList::ClaimAllArgs(OptSpecifier Id0) const { // FIXME: Make fast. for (const_iterator it = begin(), ie = end(); it != ie; ++it) { const Arg *A = *it; diff --git a/lib/Driver/CC1Options.cpp b/lib/Driver/CC1Options.cpp new file mode 100644 index 0000000..672fe04 --- /dev/null +++ b/lib/Driver/CC1Options.cpp @@ -0,0 +1,43 @@ +//===--- CC1Options.cpp - Clang CC1 Options Table -----------------------*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/CC1Options.h" +#include "clang/Driver/OptTable.h" +#include "clang/Driver/Option.h" + +using namespace clang::driver; +using namespace clang::driver::options; +using namespace clang::driver::cc1options; + +static OptTable::Info CC1InfoTable[] = { + // The InputOption info + { "", 0, 0, Option::InputClass, DriverOption, 0, OPT_INVALID, OPT_INVALID }, + // The UnknownOption info + { "", 0, 0, Option::UnknownClass, 0, 0, OPT_INVALID, OPT_INVALID }, + +#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ + HELPTEXT, METAVAR) \ + { NAME, HELPTEXT, METAVAR, Option::KIND##Class, FLAGS, PARAM, \ + OPT_##GROUP, OPT_##ALIAS }, +#include "clang/Driver/CC1Options.inc" +}; + +namespace { + +class CC1OptTable : public OptTable { +public: + CC1OptTable() + : OptTable(CC1InfoTable, sizeof(CC1InfoTable) / sizeof(CC1InfoTable[0])) {} +}; + +} + +OptTable *clang::driver::createCC1OptTable() { + return new CC1OptTable(); +} diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt index b6998ab..60d8e9c 100644 --- a/lib/Driver/CMakeLists.txt +++ b/lib/Driver/CMakeLists.txt @@ -4,8 +4,10 @@ add_clang_library(clangDriver Action.cpp Arg.cpp ArgList.cpp + CC1Options.cpp Compilation.cpp Driver.cpp + DriverOptions.cpp HostInfo.cpp Job.cpp OptTable.cpp @@ -18,4 +20,4 @@ add_clang_library(clangDriver Types.cpp ) -add_dependencies(clangDriver ClangDiagnosticDriver) +add_dependencies(clangDriver ClangDiagnosticDriver ClangDriverOptions ClangCC1Options) diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp index c12f5aa..ffa627a 100644 --- a/lib/Driver/Compilation.cpp +++ b/lib/Driver/Compilation.cpp @@ -13,6 +13,7 @@ #include "clang/Driver/ArgList.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" #include "clang/Driver/ToolChain.h" #include "llvm/Support/raw_ostream.h" diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index b4693f2..b40dc27 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -16,6 +16,7 @@ #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/HostInfo.h" #include "clang/Driver/Job.h" +#include "clang/Driver/OptTable.h" #include "clang/Driver/Option.h" #include "clang/Driver/Options.h" #include "clang/Driver/Tool.h" @@ -44,7 +45,7 @@ Driver::Driver(const char *_Name, const char *_Dir, const char *_DefaultHostTriple, const char *_DefaultImageName, bool IsProduction, Diagnostic &_Diags) - : Opts(new OptTable()), Diags(_Diags), + : Opts(createDriverOptTable()), Diags(_Diags), Name(_Name), Dir(_Dir), DefaultHostTriple(_DefaultHostTriple), DefaultImageName(_DefaultImageName), Host(0), @@ -75,40 +76,23 @@ Driver::~Driver() { InputArgList *Driver::ParseArgStrings(const char **ArgBegin, const char **ArgEnd) { llvm::PrettyStackTraceString CrashInfo("Command line argument parsing"); - InputArgList *Args = new InputArgList(ArgBegin, ArgEnd); + unsigned MissingArgIndex, MissingArgCount; + InputArgList *Args = getOpts().ParseArgs(ArgBegin, ArgEnd, + MissingArgIndex, MissingArgCount); - // FIXME: Handle '@' args (or at least error on them). - - unsigned Index = 0, End = ArgEnd - ArgBegin; - while (Index < End) { - // gcc's handling of empty arguments doesn't make sense, but this is not a - // common use case. :) - // - // We just ignore them here (note that other things may still take them as - // arguments). - if (Args->getArgString(Index)[0] == '\0') { - ++Index; - continue; - } - - unsigned Prev = Index; - Arg *A = getOpts().ParseOneArg(*Args, Index); - assert(Index > Prev && "Parser failed to consume argument."); - - // Check for missing argument error. - if (!A) { - assert(Index >= End && "Unexpected parser error."); - Diag(clang::diag::err_drv_missing_argument) - << Args->getArgString(Prev) - << (Index - Prev - 1); - break; - } + // Check for missing argument error. + if (MissingArgCount) + Diag(clang::diag::err_drv_missing_argument) + << Args->getArgString(MissingArgIndex) << MissingArgCount; + // Check for unsupported options. + for (ArgList::const_iterator it = Args->begin(), ie = Args->end(); + it != ie; ++it) { + Arg *A = *it; if (A->getOption().isUnsupported()) { Diag(clang::diag::err_drv_unsupported_opt) << A->getAsString(*Args); continue; } - Args->append(A); } return Args; @@ -340,8 +324,8 @@ void Driver::PrintHelp(bool ShowHidden) const { // Render help text into (option, help) pairs. std::vector< std::pair > OptionHelp; - for (unsigned i = options::OPT_INPUT, e = options::LastOption; i != e; ++i) { - options::ID Id = (options::ID) i; + for (unsigned i = 0, e = getOpts().getNumOptions(); i != e; ++i) { + options::ID Id = (options::ID) (i + 1); if (const char *Text = getOpts().getOptionHelpText(Id)) OptionHelp.push_back(std::make_pair(getOptionHelpName(getOpts(), Id), Text)); @@ -591,7 +575,7 @@ void Driver::BuildUniversalActions(const ArgList &Args, it != ie; ++it) { Arg *A = *it; - if (A->getOption().getId() == options::OPT_arch) { + if (A->getOption().matches(options::OPT_arch)) { // Validate the option here; we don't save the type here because its // particular spelling may participate in other driver choices. llvm::Triple::ArchType Arch = @@ -686,7 +670,7 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { // // Otherwise emit an error but still use a valid type to avoid // spurious errors (e.g., no inputs). - if (!Args.hasArg(options::OPT_E, false)) + if (!Args.hasArgNoClaim(options::OPT_E)) Diag(clang::diag::err_drv_unknown_stdin_type); Ty = types::TY_C; } else { @@ -730,7 +714,7 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { // necessary. Inputs.push_back(std::make_pair(types::TY_Object, A)); - } else if (A->getOption().getId() == options::OPT_x) { + } else if (A->getOption().matches(options::OPT_x)) { InputTypeArg = A; InputType = types::lookupTypeForTypeSpecifier(A->getValue(Args)); @@ -984,7 +968,7 @@ void Driver::BuildJobs(Compilation &C) const { // FIXME: Use iterator. for (ArgList::const_iterator it = C.getArgs().begin(), ie = C.getArgs().end(); it != ie; ++it) { - if ((*it)->isClaimed() && (*it)->getOption().matches(Opt.getId())) { + if ((*it)->isClaimed() && (*it)->getOption().matches(&Opt)) { DuplicateClaimed = true; break; } diff --git a/lib/Driver/DriverOptions.cpp b/lib/Driver/DriverOptions.cpp new file mode 100644 index 0000000..eddaee0 --- /dev/null +++ b/lib/Driver/DriverOptions.cpp @@ -0,0 +1,42 @@ +//===--- DriverOptions.cpp - Driver Options Table -----------------------*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/Options.h" +#include "clang/Driver/OptTable.h" +#include "clang/Driver/Option.h" + +using namespace clang::driver; +using namespace clang::driver::options; + +static OptTable::Info InfoTable[] = { + // The InputOption info + { "", 0, 0, Option::InputClass, DriverOption, 0, OPT_INVALID, OPT_INVALID }, + // The UnknownOption info + { "", 0, 0, Option::UnknownClass, 0, 0, OPT_INVALID, OPT_INVALID }, + +#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ + HELPTEXT, METAVAR) \ + { NAME, HELPTEXT, METAVAR, Option::KIND##Class, FLAGS, PARAM, \ + OPT_##GROUP, OPT_##ALIAS }, +#include "clang/Driver/Options.inc" +}; + +namespace { + +class DriverOptTable : public OptTable { +public: + DriverOptTable() + : OptTable(InfoTable, sizeof(InfoTable) / sizeof(InfoTable[0])) {} +}; + +} + +OptTable *clang::driver::createDriverOptTable() { + return new DriverOptTable(); +} diff --git a/lib/Driver/HostInfo.cpp b/lib/Driver/HostInfo.cpp index 08c4ef4..ed73b17 100644 --- a/lib/Driver/HostInfo.cpp +++ b/lib/Driver/HostInfo.cpp @@ -122,7 +122,7 @@ ToolChain *DarwinHostInfo::CreateToolChain(const ArgList &Args, // // FIXME: Should this information be in llvm::Triple? if (Arg *A = Args.getLastArg(options::OPT_m32, options::OPT_m64)) { - if (A->getOption().getId() == options::OPT_m32) { + if (A->getOption().matches(options::OPT_m32)) { if (Arch == llvm::Triple::x86_64) Arch = llvm::Triple::x86; if (Arch == llvm::Triple::ppc64) @@ -205,11 +205,11 @@ ToolChain *UnknownHostInfo::CreateToolChain(const ArgList &Args, if (Triple.getArch() == llvm::Triple::x86 || Triple.getArch() == llvm::Triple::x86_64) { ArchName = - (A->getOption().getId() == options::OPT_m32) ? "i386" : "x86_64"; + (A->getOption().matches(options::OPT_m32)) ? "i386" : "x86_64"; } else if (Triple.getArch() == llvm::Triple::ppc || Triple.getArch() == llvm::Triple::ppc64) { ArchName = - (A->getOption().getId() == options::OPT_m32) ? "powerpc" : "powerpc64"; + (A->getOption().matches(options::OPT_m32)) ? "powerpc" : "powerpc64"; } } @@ -478,11 +478,11 @@ ToolChain *LinuxHostInfo::CreateToolChain(const ArgList &Args, if (Triple.getArch() == llvm::Triple::x86 || Triple.getArch() == llvm::Triple::x86_64) { ArchName = - (A->getOption().getId() == options::OPT_m32) ? "i386" : "x86_64"; + (A->getOption().matches(options::OPT_m32)) ? "i386" : "x86_64"; } else if (Triple.getArch() == llvm::Triple::ppc || Triple.getArch() == llvm::Triple::ppc64) { ArchName = - (A->getOption().getId() == options::OPT_m32) ? "powerpc" : "powerpc64"; + (A->getOption().matches(options::OPT_m32)) ? "powerpc" : "powerpc64"; } } diff --git a/lib/Driver/OptTable.cpp b/lib/Driver/OptTable.cpp index affd1c5..f68a1d8 100644 --- a/lib/Driver/OptTable.cpp +++ b/lib/Driver/OptTable.cpp @@ -1,4 +1,4 @@ -//===--- Options.cpp - Option info table --------------------------------*-===// +//===--- OptTable.cpp - Option Table Implementation ---------------------*-===// // // The LLVM Compiler Infrastructure // @@ -7,8 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Driver/Options.h" - +#include "clang/Driver/OptTable.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" #include "clang/Driver/Option.h" @@ -18,18 +17,6 @@ using namespace clang::driver; using namespace clang::driver::options; -struct Info { - const char *Name; - const char *Flags; - const char *HelpText; - const char *MetaVar; - - Option::OptionClass Kind; - unsigned GroupID; - unsigned AliasID; - unsigned Param; -}; - // Ordering on Info. The ordering is *almost* lexicographic, with two // exceptions. First, '\0' comes at the end of the alphabet instead of // the beginning (thus options preceed any other options which prefix @@ -56,7 +43,9 @@ static int StrCmpOptionName(const char *A, const char *B) { return (a < b) ? -1 : 1; } -static inline bool operator<(const Info &A, const Info &B) { +namespace clang { +namespace driver { +static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) { if (&A == &B) return false; @@ -70,57 +59,62 @@ static inline bool operator<(const Info &A, const Info &B) { return B.Kind == Option::JoinedClass; } +// Support lower_bound between info and an option name. +static inline bool operator<(const OptTable::Info &I, const char *Name) { + return StrCmpOptionName(I.Name, Name) == -1; +} +static inline bool operator<(const char *Name, const OptTable::Info &I) { + return StrCmpOptionName(Name, I.Name) == -1; +} +} +} + // -static Info OptionInfos[] = { - // The InputOption info - { "", "d", 0, 0, Option::InputClass, OPT_INVALID, OPT_INVALID, 0 }, - // The UnknownOption info - { "", "", 0, 0, Option::UnknownClass, OPT_INVALID, OPT_INVALID, 0 }, - -#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ - HELPTEXT, METAVAR) \ - { NAME, FLAGS, HELPTEXT, METAVAR, \ - Option::KIND##Class, OPT_##GROUP, OPT_##ALIAS, PARAM }, -#include "clang/Driver/Options.def" -}; -static const unsigned numOptions = sizeof(OptionInfos) / sizeof(OptionInfos[0]); - -static Info &getInfo(unsigned id) { - assert(id > 0 && id - 1 < numOptions && "Invalid Option ID."); - return OptionInfos[id - 1]; -} +OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {} -OptTable::OptTable() : Options(new Option*[numOptions]) { +// + +OptTable::OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos) + : OptionInfos(_OptionInfos), NumOptionInfos(_NumOptionInfos), + Options(new Option*[NumOptionInfos]), + TheInputOption(0), TheUnknownOption(0), FirstSearchableIndex(0) +{ // Explicitly zero initialize the error to work around a bug in array // value-initialization on MinGW with gcc 4.3.5. - memset(Options, 0, sizeof(*Options) * numOptions); + memset(Options, 0, sizeof(*Options) * NumOptionInfos); // Find start of normal options. - FirstSearchableOption = 0; - for (unsigned i = OPT_UNKNOWN + 1; i < LastOption; ++i) { - if (getInfo(i).Kind != Option::GroupClass) { - FirstSearchableOption = i; + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { + unsigned Kind = getInfo(i + 1).Kind; + if (Kind == Option::InputClass) { + assert(!TheInputOption && "Cannot have multiple input options!"); + TheInputOption = getOption(i + 1); + } else if (Kind == Option::UnknownClass) { + assert(!TheUnknownOption && "Cannot have multiple input options!"); + TheUnknownOption = getOption(i + 1); + } else if (Kind != Option::GroupClass) { + FirstSearchableIndex = i; break; } } - assert(FirstSearchableOption != 0 && "No searchable options?"); + assert(FirstSearchableIndex != 0 && "No searchable options?"); #ifndef NDEBUG // Check that everything after the first searchable option is a // regular option class. - for (unsigned i = FirstSearchableOption; i < LastOption; ++i) { - Option::OptionClass Kind = getInfo(i).Kind; + for (unsigned i = FirstSearchableIndex, e = getNumOptions(); i != e; ++i) { + Option::OptionClass Kind = (Option::OptionClass) getInfo(i + 1).Kind; assert((Kind != Option::InputClass && Kind != Option::UnknownClass && Kind != Option::GroupClass) && "Special options should be defined first!"); } // Check that options are in order. - for (unsigned i = FirstSearchableOption + 1; i < LastOption; ++i) { - if (!(getInfo(i - 1) < getInfo(i))) { - getOption((options::ID) (i - 1))->dump(); - getOption((options::ID) i)->dump(); + for (unsigned i = FirstSearchableIndex+1, e = getNumOptions(); i != e; ++i) { + if (!(getInfo(i) < getInfo(i + 1))) { + getOption(i)->dump(); + getOption(i + 1)->dump(); assert(0 && "Options are not in order!"); } } @@ -128,56 +122,23 @@ OptTable::OptTable() : Options(new Option*[numOptions]) { } OptTable::~OptTable() { - for (unsigned i = 0; i < numOptions; ++i) + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) delete Options[i]; delete[] Options; } -unsigned OptTable::getNumOptions() const { - return numOptions; -} - -const char *OptTable::getOptionName(options::ID id) const { - return getInfo(id).Name; -} - -unsigned OptTable::getOptionKind(options::ID id) const { - return getInfo(id).Kind; -} - -const char *OptTable::getOptionHelpText(options::ID id) const { - return getInfo(id).HelpText; -} - -const char *OptTable::getOptionMetaVar(options::ID id) const { - return getInfo(id).MetaVar; -} - -const Option *OptTable::getOption(options::ID id) const { - if (id == OPT_INVALID) - return 0; - - assert((unsigned) (id - 1) < numOptions && "Invalid ID."); - - Option *&Entry = Options[id - 1]; - if (!Entry) - Entry = constructOption(id); - - return Entry; -} - -Option *OptTable::constructOption(options::ID id) const { - Info &info = getInfo(id); +Option *OptTable::CreateOption(unsigned id) const { + const Info &info = getInfo(id); const OptionGroup *Group = - cast_or_null(getOption((options::ID) info.GroupID)); - const Option *Alias = getOption((options::ID) info.AliasID); + cast_or_null(getOption(info.GroupID)); + const Option *Alias = getOption(info.AliasID); Option *Opt = 0; switch (info.Kind) { case Option::InputClass: - Opt = new InputOption(); break; + Opt = new InputOption(id); break; case Option::UnknownClass: - Opt = new UnknownOption(); break; + Opt = new UnknownOption(id); break; case Option::GroupClass: Opt = new OptionGroup(id, info.Name, Group); break; case Option::FlagClass: @@ -196,44 +157,38 @@ Option *OptTable::constructOption(options::ID id) const { Opt = new JoinedAndSeparateOption(id, info.Name, Group, Alias); break; } - for (const char *s = info.Flags; *s; ++s) { - switch (*s) { - default: assert(0 && "Invalid option flag."); - case 'J': - assert(info.Kind == Option::SeparateClass && "Invalid option."); - Opt->setForceJoinedRender(true); break; - case 'S': - assert(info.Kind == Option::JoinedClass && "Invalid option."); - Opt->setForceSeparateRender(true); break; - case 'd': Opt->setDriverOption(true); break; - case 'i': Opt->setNoOptAsInput(true); break; - case 'l': Opt->setLinkerInput(true); break; - case 'q': Opt->setNoArgumentUnused(true); break; - case 'u': Opt->setUnsupported(true); break; - } + if (info.Flags & DriverOption) + Opt->setDriverOption(true); + if (info.Flags & LinkerInput) + Opt->setLinkerInput(true); + if (info.Flags & NoArgumentUnused) + Opt->setNoArgumentUnused(true); + if (info.Flags & RenderAsInput) + Opt->setNoOptAsInput(true); + if (info.Flags & RenderJoined) { + assert(info.Kind == Option::SeparateClass && "Invalid option."); + Opt->setForceJoinedRender(true); } + if (info.Flags & RenderSeparate) { + assert(info.Kind == Option::JoinedClass && "Invalid option."); + Opt->setForceSeparateRender(true); + } + if (info.Flags & Unsupported) + Opt->setUnsupported(true); return Opt; } -// Support lower_bound between info and an option name. -static inline bool operator<(struct Info &I, const char *Name) { - return StrCmpOptionName(I.Name, Name) == -1; -} -static inline bool operator<(const char *Name, struct Info &I) { - return StrCmpOptionName(Name, I.Name) == -1; -} - Arg *OptTable::ParseOneArg(const InputArgList &Args, unsigned &Index) const { unsigned Prev = Index; const char *Str = Args.getArgString(Index); // Anything that doesn't start with '-' is an input, as is '-' itself. if (Str[0] != '-' || Str[1] == '\0') - return new PositionalArg(getOption(OPT_INPUT), Index++); + return new PositionalArg(TheInputOption, Index++); - struct Info *Start = OptionInfos + FirstSearchableOption - 1; - struct Info *End = OptionInfos + LastOption - 1; + const Info *Start = OptionInfos + FirstSearchableIndex; + const Info *End = OptionInfos + getNumOptions(); // Search for the first next option which could be a prefix. Start = std::lower_bound(Start, End, Str); @@ -255,8 +210,7 @@ Arg *OptTable::ParseOneArg(const InputArgList &Args, unsigned &Index) const { break; // See if this option matches. - options::ID id = (options::ID) (Start - OptionInfos + 1); - if (Arg *A = getOption(id)->accept(Args, Index)) + if (Arg *A = getOption(Start - OptionInfos + 1)->accept(Args, Index)) return A; // Otherwise, see if this argument was missing values. @@ -264,6 +218,40 @@ Arg *OptTable::ParseOneArg(const InputArgList &Args, unsigned &Index) const { return 0; } - return new PositionalArg(getOption(OPT_UNKNOWN), Index++); + return new PositionalArg(TheUnknownOption, Index++); } +InputArgList *OptTable::ParseArgs(const char **ArgBegin, const char **ArgEnd, + unsigned &MissingArgIndex, + unsigned &MissingArgCount) const { + InputArgList *Args = new InputArgList(ArgBegin, ArgEnd); + + // FIXME: Handle '@' args (or at least error on them). + + MissingArgIndex = MissingArgCount = 0; + unsigned Index = 0, End = ArgEnd - ArgBegin; + while (Index < End) { + // Ignore empty arguments (other things may still take them as arguments). + if (Args->getArgString(Index)[0] == '\0') { + ++Index; + continue; + } + + unsigned Prev = Index; + Arg *A = ParseOneArg(*Args, Index); + assert(Index > Prev && "Parser failed to consume argument."); + + // Check for missing argument error. + if (!A) { + assert(Index >= End && "Unexpected parser error."); + assert(Index - Prev - 1 && "No missing arguments!"); + MissingArgIndex = Prev; + MissingArgCount = Index - Prev - 1; + break; + } + + Args->append(A); + } + + return Args; +} diff --git a/lib/Driver/Option.cpp b/lib/Driver/Option.cpp index c2ace05..17d00f5 100644 --- a/lib/Driver/Option.cpp +++ b/lib/Driver/Option.cpp @@ -16,9 +16,9 @@ #include using namespace clang::driver; -Option::Option(OptionClass _Kind, options::ID _ID, const char *_Name, +Option::Option(OptionClass _Kind, OptSpecifier _ID, const char *_Name, const OptionGroup *_Group, const Option *_Alias) - : Kind(_Kind), ID(_ID), Name(_Name), Group(_Group), Alias(_Alias), + : Kind(_Kind), ID(_ID.getID()), Name(_Name), Group(_Group), Alias(_Alias), Unsupported(false), LinkerInput(false), NoOptAsInput(false), ForceSeparateRender(false), ForceJoinedRender(false), DriverOption(false), NoArgumentUnused(false) { @@ -70,14 +70,13 @@ void Option::dump() const { llvm::errs() << ">\n"; } -bool Option::matches(const Option *Opt) const { - // Aliases are never considered in matching. - if (Opt->getAlias()) - return matches(Opt->getAlias()); +bool Option::matches(OptSpecifier Opt) const { + // Aliases are never considered in matching, look through them. if (Alias) return Alias->matches(Opt); - if (this == Opt) + // Check exact match. + if (ID == Opt) return true; if (Group) @@ -85,23 +84,7 @@ bool Option::matches(const Option *Opt) const { return false; } -bool Option::matches(options::ID Id) const { - // FIXME: Decide what to do here; we should either pull out the - // handling of alias on the option for Id from the other matches, or - // find some other solution (which hopefully doesn't require using - // the option table). - if (Alias) - return Alias->matches(Id); - - if (ID == Id) - return true; - - if (Group) - return Group->matches(Id); - return false; -} - -OptionGroup::OptionGroup(options::ID ID, const char *Name, +OptionGroup::OptionGroup(OptSpecifier ID, const char *Name, const OptionGroup *Group) : Option(Option::GroupClass, ID, Name, Group, 0) { } @@ -111,8 +94,8 @@ Arg *OptionGroup::accept(const InputArgList &Args, unsigned &Index) const { return 0; } -InputOption::InputOption() - : Option(Option::InputClass, options::OPT_INPUT, "", 0, 0) { +InputOption::InputOption(OptSpecifier ID) + : Option(Option::InputClass, ID, "", 0, 0) { } Arg *InputOption::accept(const InputArgList &Args, unsigned &Index) const { @@ -120,8 +103,8 @@ Arg *InputOption::accept(const InputArgList &Args, unsigned &Index) const { return 0; } -UnknownOption::UnknownOption() - : Option(Option::UnknownClass, options::OPT_UNKNOWN, "", 0, 0) { +UnknownOption::UnknownOption(OptSpecifier ID) + : Option(Option::UnknownClass, ID, "", 0, 0) { } Arg *UnknownOption::accept(const InputArgList &Args, unsigned &Index) const { @@ -129,7 +112,7 @@ Arg *UnknownOption::accept(const InputArgList &Args, unsigned &Index) const { return 0; } -FlagOption::FlagOption(options::ID ID, const char *Name, +FlagOption::FlagOption(OptSpecifier ID, const char *Name, const OptionGroup *Group, const Option *Alias) : Option(Option::FlagClass, ID, Name, Group, Alias) { } @@ -143,7 +126,7 @@ Arg *FlagOption::accept(const InputArgList &Args, unsigned &Index) const { return new FlagArg(this, Index++); } -JoinedOption::JoinedOption(options::ID ID, const char *Name, +JoinedOption::JoinedOption(OptSpecifier ID, const char *Name, const OptionGroup *Group, const Option *Alias) : Option(Option::JoinedClass, ID, Name, Group, Alias) { } @@ -153,7 +136,7 @@ Arg *JoinedOption::accept(const InputArgList &Args, unsigned &Index) const { return new JoinedArg(this, Index++); } -CommaJoinedOption::CommaJoinedOption(options::ID ID, const char *Name, +CommaJoinedOption::CommaJoinedOption(OptSpecifier ID, const char *Name, const OptionGroup *Group, const Option *Alias) : Option(Option::CommaJoinedClass, ID, Name, Group, Alias) { @@ -170,7 +153,7 @@ Arg *CommaJoinedOption::accept(const InputArgList &Args, return new CommaJoinedArg(this, Index++, Suffix); } -SeparateOption::SeparateOption(options::ID ID, const char *Name, +SeparateOption::SeparateOption(OptSpecifier ID, const char *Name, const OptionGroup *Group, const Option *Alias) : Option(Option::SeparateClass, ID, Name, Group, Alias) { } @@ -188,7 +171,7 @@ Arg *SeparateOption::accept(const InputArgList &Args, unsigned &Index) const { return new SeparateArg(this, Index - 2, 1); } -MultiArgOption::MultiArgOption(options::ID ID, const char *Name, +MultiArgOption::MultiArgOption(OptSpecifier ID, const char *Name, const OptionGroup *Group, const Option *Alias, unsigned _NumArgs) : Option(Option::MultiArgClass, ID, Name, Group, Alias), NumArgs(_NumArgs) { @@ -208,7 +191,7 @@ Arg *MultiArgOption::accept(const InputArgList &Args, unsigned &Index) const { return new SeparateArg(this, Index - 1 - NumArgs, NumArgs); } -JoinedOrSeparateOption::JoinedOrSeparateOption(options::ID ID, const char *Name, +JoinedOrSeparateOption::JoinedOrSeparateOption(OptSpecifier ID, const char *Name, const OptionGroup *Group, const Option *Alias) : Option(Option::JoinedOrSeparateClass, ID, Name, Group, Alias) { @@ -229,7 +212,7 @@ Arg *JoinedOrSeparateOption::accept(const InputArgList &Args, return new SeparateArg(this, Index - 2, 1); } -JoinedAndSeparateOption::JoinedAndSeparateOption(options::ID ID, +JoinedAndSeparateOption::JoinedAndSeparateOption(OptSpecifier ID, const char *Name, const OptionGroup *Group, const Option *Alias) diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index ae8119d..af63952 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -14,7 +14,9 @@ #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/HostInfo.h" +#include "clang/Driver/OptTable.h" #include "clang/Driver/Option.h" +#include "clang/Driver/Options.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/ErrorHandling.h" @@ -303,9 +305,9 @@ DerivedArgList *Darwin::TranslateArgs(InputArgList &Args, // and try to push it down into tool specific logic. Arg *OSXVersion = - Args.getLastArg(options::OPT_mmacosx_version_min_EQ, false); + Args.getLastArgNoClaim(options::OPT_mmacosx_version_min_EQ); Arg *iPhoneVersion = - Args.getLastArg(options::OPT_miphoneos_version_min_EQ, false); + Args.getLastArgNoClaim(options::OPT_miphoneos_version_min_EQ); if (OSXVersion && iPhoneVersion) { getHost().getDriver().Diag(clang::diag::err_drv_argument_not_allowed_with) << OSXVersion->getAsString(Args) @@ -365,8 +367,7 @@ DerivedArgList *Darwin::TranslateArgs(InputArgList &Args, // Sob. These is strictly gcc compatible for the time being. Apple // gcc translates options twice, which means that self-expanding // options add duplicates. - options::ID id = A->getOption().getId(); - switch (id) { + switch ((options::ID) A->getOption().getID()) { default: DAL->append(A); break; @@ -440,7 +441,7 @@ DerivedArgList *Darwin::TranslateArgs(InputArgList &Args, if (getTriple().getArch() == llvm::Triple::x86 || getTriple().getArch() == llvm::Triple::x86_64) - if (!Args.hasArg(options::OPT_mtune_EQ, false)) + if (!Args.hasArgNoClaim(options::OPT_mtune_EQ)) DAL->append(DAL->MakeJoinedArg(0, Opts.getOption(options::OPT_mtune_EQ), "core2")); diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 34154f3..5f0551b 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -18,6 +18,7 @@ #include "clang/Driver/Job.h" #include "clang/Driver/HostInfo.h" #include "clang/Driver/Option.h" +#include "clang/Driver/Options.h" #include "clang/Driver/ToolChain.h" #include "clang/Driver/Util.h" @@ -81,8 +82,8 @@ void Clang::AddPreprocessingOptions(const Driver &D, DepFile = Output.getFilename(); } else if (Arg *MF = Args.getLastArg(options::OPT_MF)) { DepFile = MF->getValue(Args); - } else if (A->getOption().getId() == options::OPT_M || - A->getOption().getId() == options::OPT_MM) { + } else if (A->getOption().matches(options::OPT_M) || + A->getOption().matches(options::OPT_MM)) { DepFile = "-"; } else { DepFile = darwin::CC1::getDependencyFileName(Args, Inputs); @@ -116,8 +117,8 @@ void Clang::AddPreprocessingOptions(const Driver &D, CmdArgs.push_back(DepTarget); } - if (A->getOption().getId() == options::OPT_M || - A->getOption().getId() == options::OPT_MD) + if (A->getOption().matches(options::OPT_M) || + A->getOption().matches(options::OPT_MD)) CmdArgs.push_back("-sys-header-deps"); } @@ -778,12 +779,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, break; } - if (Args.hasFlag(options::OPT_fmath_errno, + // -fmath-errno is default. + if (!Args.hasFlag(options::OPT_fmath_errno, options::OPT_fno_math_errno, getToolChain().IsMathErrnoDefault())) - CmdArgs.push_back("--fmath-errno=1"); - else - CmdArgs.push_back("--fmath-errno=0"); + CmdArgs.push_back("-fno-math-errno"); if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { CmdArgs.push_back("--limit-float-precision"); @@ -822,7 +822,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Manually translate -O to -O2 and -O4 to -O3; let clang reject // others. if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { - if (A->getOption().getId() == options::OPT_O4) + if (A->getOption().matches(options::OPT_O4)) CmdArgs.push_back("-O3"); else if (A->getValue(Args)[0] == '\0') CmdArgs.push_back("-O2"); @@ -864,7 +864,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue(Args)); } - if (Args.hasArg(options::OPT__relocatable_pch, true)) + if (Args.hasArg(options::OPT__relocatable_pch)) CmdArgs.push_back("--relocatable-pch"); if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) { @@ -922,7 +922,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fbuiltin is default. if (!Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin)) - CmdArgs.push_back("-fbuiltin=0"); + CmdArgs.push_back("-fno-builtin"); // -fblocks=0 is default. if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks, @@ -938,7 +938,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -frtti is default. if (!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti)) - CmdArgs.push_back("-frtti=0"); + CmdArgs.push_back("-fno-rtti"); // -fsigned-char is default. if (!Args.hasFlag(options::OPT_fsigned_char, @@ -2609,6 +2609,8 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding // the default system libraries. Just mimic this for now. CmdArgs.push_back("-lgcc"); + if (D.CCCIsCXX) + CmdArgs.push_back("-lstdc++"); if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-lgcc_eh"); } else { @@ -2638,10 +2640,6 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtendS.o"))); CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtn.o"))); - // FIXME: g++ is more complicated here, it tries to put -lstdc++ - // before -lm, for example. - if (D.CCCIsCXX) - CmdArgs.push_back("-lstdc++"); } const char *Exec = diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp index 30893e7..750286b 100644 --- a/lib/Driver/Types.cpp +++ b/lib/Driver/Types.cpp @@ -16,14 +16,14 @@ using namespace clang::driver; using namespace clang::driver::types; -struct Info { +struct TypeInfo { const char *Name; const char *Flags; const char *TempSuffix; ID PreprocessedType; }; -static Info TypeInfos[] = { +static TypeInfo TypeInfos[] = { #define TYPE(NAME, ID, PP_TYPE, TEMP_SUFFIX, FLAGS) \ { NAME, FLAGS, TEMP_SUFFIX, TY_##PP_TYPE, }, #include "clang/Driver/Types.def" @@ -31,7 +31,7 @@ static Info TypeInfos[] = { }; static const unsigned numTypes = sizeof(TypeInfos) / sizeof(TypeInfos[0]); -static Info &getInfo(unsigned id) { +static TypeInfo &getInfo(unsigned id) { assert(id > 0 && id - 1 < numTypes && "Invalid Type ID."); return TypeInfos[id - 1]; } diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index ed6d0b7..b4a79c6 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -14,7 +14,6 @@ using namespace clang; void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, const llvm::SmallVectorImpl &Args) { - llvm::llvm_report_error("FIXME: Not yet implemented!"); } static const char *getAnalysisName(Analyses Kind) { @@ -83,8 +82,8 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, Res.push_back("-analyzer-display-progress"); if (Opts.EagerlyAssume) Res.push_back("-analyzer-eagerly-assume"); - if (Opts.PurgeDead) - Res.push_back("-analyzer-purge-dead"); + if (!Opts.PurgeDead) + Res.push_back("-analyzer-no-purge-dead"); if (Opts.TrimGraph) Res.push_back("-trim-egraph"); if (Opts.VisualizeEGDot) @@ -238,7 +237,7 @@ static const char *getActionName(frontend::ActionKind Kind) { static void FrontendOptsToArgs(const FrontendOptions &Opts, std::vector &Res) { if (!Opts.DebugCodeCompletionPrinter) - Res.push_back("-code-completion-debug-printer=0"); + Res.push_back("-no-code-completion-debug-printer"); if (Opts.DisableFree) Res.push_back("-disable-free"); if (Opts.EmptyInputOnly) @@ -298,7 +297,7 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, std::vector &Res) { - if (Opts.Sysroot.empty()) { + if (Opts.Sysroot != "/") { Res.push_back("-isysroot"); Res.push_back(Opts.Sysroot); } @@ -394,8 +393,8 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-faltivec"); Res.push_back("-fexceptions"); Res.push_back(Opts.Exceptions ? "1" : "0"); - Res.push_back("-frtti"); - Res.push_back(Opts.Rtti ? "1" : "0"); + if (!Opts.Rtti) + Res.push_back("-fno-rtti"); if (!Opts.NeXTRuntime) Res.push_back("-fgnu-runtime"); if (Opts.Freestanding) @@ -411,7 +410,7 @@ static void LangOptsToArgs(const LangOptions &Opts, if (Opts.EmitAllDecls) Res.push_back("-femit-all-decls"); if (!Opts.MathErrno) - Res.push_back("-fmath-errno=0"); + Res.push_back("-fno-math-errno"); if (Opts.OverflowChecking) Res.push_back("-ftrapv"); if (Opts.HeinousExtensions) diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 4ee286d..b77c240 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -237,6 +237,13 @@ static void DefineType(const char *MacroName, TargetInfo::IntType Ty, DefineBuiltinMacro(Buf, MacroBuf); } +static void DefineTypeWidth(const char *MacroName, TargetInfo::IntType Ty, + const TargetInfo &TI, std::vector &Buf) { + char MacroBuf[60]; + sprintf(MacroBuf, "%s=%d", MacroName, TI.getTypeWidth(Ty)); + DefineBuiltinMacro(Buf, MacroBuf); +} + static void DefineExactWidthIntType(TargetInfo::IntType Ty, const TargetInfo &TI, std::vector &Buf) { char MacroBuf[60]; @@ -381,10 +388,10 @@ static void InitializePredefinedMacros(const TargetInfo &TI, DefineTypeSize("__WCHAR_MAX__", TI.getWCharType(), TI, Buf); DefineTypeSize("__INTMAX_MAX__", TI.getIntMaxType(), TI, Buf); - DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Buf); - DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Buf); + DefineTypeWidth("__INTMAX_WIDTH__", TI.getIntMaxType(), TI, Buf); DefineType("__PTRDIFF_TYPE__", TI.getPtrDiffType(0), Buf); DefineType("__INTPTR_TYPE__", TI.getIntPtrType(), Buf); + DefineTypeWidth("__INTPTR_WIDTH__", TI.getIntPtrType(), TI, Buf); DefineType("__SIZE_TYPE__", TI.getSizeType(), Buf); DefineType("__WCHAR_TYPE__", TI.getWCharType(), Buf); DefineType("__WINT_TYPE__", TI.getWIntType(), Buf); diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index ca7aa32..c9679b7 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -34,6 +34,7 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/System/Path.h" #include #include #include @@ -1086,11 +1087,9 @@ void PCHReader::MaybeAddSystemRootToFilename(std::string &Filename) { if (!RelocatablePCH) return; - if (Filename.empty() || Filename[0] == '/' || Filename[0] == '<') + if (Filename.empty() || llvm::sys::Path(Filename).isAbsolute()) return; - std::string FIXME = Filename; - if (isysroot == 0) { // If no system root was given, default to '/' Filename.insert(Filename.begin(), '/'); diff --git a/lib/Headers/stdint.h b/lib/Headers/stdint.h index bb81a6a..ccaf349 100644 --- a/lib/Headers/stdint.h +++ b/lib/Headers/stdint.h @@ -213,16 +213,19 @@ typedef __uint_least8_t uint_fast8_t; /* C99 7.18.1.4 Integer types capable of holding object pointers. */ +#define __stdint_join3(a,b,c) a ## b ## c +#define __stdint_exjoin3(a,b,c) __stdint_join3(a,b,c) + #ifndef __intptr_t_defined -typedef __INTPTR_TYPE__ intptr_t; +typedef __stdint_exjoin3( int, __INTPTR_WIDTH__, _t) intptr_t; #define __intptr_t_defined #endif -typedef unsigned __INTPTR_TYPE__ uintptr_t; +typedef __stdint_exjoin3(uint, __INTPTR_WIDTH__, _t) uintptr_t; /* C99 7.18.1.5 Greatest-width integer types. */ -typedef __INTMAX_TYPE__ intmax_t; -typedef __UINTMAX_TYPE__ uintmax_t; +typedef __stdint_exjoin3( int, __INTMAX_WIDTH__, _t) intmax_t; +typedef __stdint_exjoin3(uint, __INTMAX_WIDTH__, _t) uintmax_t; /* C99 7.18.4 Macros for minimum-width integer constants. * @@ -600,29 +603,24 @@ typedef __UINTMAX_TYPE__ uintmax_t; /* C99 7.18.2.4 Limits of integer types capable of holding object pointers. */ /* C99 7.18.3 Limits of other integer types. */ +#define INTPTR_MIN __stdint_exjoin3( INT, __INTPTR_WIDTH__, _MIN) +#define INTPTR_MAX __stdint_exjoin3( INT, __INTPTR_WIDTH__, _MAX) +#define UINTPTR_MAX __stdint_exjoin3(UINT, __INTPTR_WIDTH__, _MAX) + #if __POINTER_WIDTH__ == 64 -#define INTPTR_MIN INT64_MIN -#define INTPTR_MAX INT64_MAX -#define UINTPTR_MAX UINT64_MAX #define PTRDIFF_MIN INT64_MIN #define PTRDIFF_MAX INT64_MAX #define SIZE_MAX UINT64_MAX #elif __POINTER_WIDTH__ == 32 -#define INTPTR_MIN INT32_MIN -#define INTPTR_MAX INT32_MAX -#define UINTPTR_MAX UINT32_MAX #define PTRDIFF_MIN INT32_MIN #define PTRDIFF_MAX INT32_MAX #define SIZE_MAX UINT32_MAX #elif __POINTER_WIDTH__ == 16 -#define INTPTR_MIN INT16_MIN -#define INTPTR_MAX INT16_MAX -#define UINTPTR_MAX UINT16_MAX #define PTRDIFF_MIN INT16_MIN #define PTRDIFF_MAX INT16_MAX #define SIZE_MAX UINT16_MAX @@ -632,9 +630,9 @@ typedef __UINTMAX_TYPE__ uintmax_t; #endif /* C99 7.18.2.5 Limits of greatest-width integer types. */ -#define INTMAX_MIN (-__INTMAX_MAX__-1) -#define INTMAX_MAX __INTMAX_MAX__ -#define UINTMAX_MAX (__INTMAX_MAX__*2ULL+1ULL) +#define INTMAX_MIN __stdint_exjoin3( INT, __INTMAX_WIDTH__, _MIN) +#define INTMAX_MAX __stdint_exjoin3( INT, __INTMAX_WIDTH__, _MAX) +#define UINTMAX_MAX __stdint_exjoin3(UINT, __INTMAX_WIDTH__, _MAX) /* C99 7.18.3 Limits of other integer types. */ #define SIG_ATOMIC_MIN INT32_MIN @@ -653,8 +651,8 @@ typedef __UINTMAX_TYPE__ uintmax_t; #endif /* 7.18.4.2 Macros for greatest-width integer constants. */ -#define INTMAX_C(v) v##LL -#define UINTMAX_C(v) v##ULL +#define INTMAX_C(v) __stdint_exjoin3( INT, __INTMAX_WIDTH__, _C(v)) +#define UINTMAX_C(v) __stdint_exjoin3(UINT, __INTMAX_WIDTH__, _C(v)) #endif /* __STDC_HOSTED__ */ #endif /* __CLANG_STDINT_H */ diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 95a0e98..d2b3b84 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -341,17 +341,6 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { ColonLoc = ConsumeToken(); } - if ((OpToken.is(tok::periodstar) || OpToken.is(tok::arrowstar)) - && Tok.is(tok::identifier)) { - CXXScopeSpec SS; - if (Actions.getTypeName(*Tok.getIdentifierInfo(), - Tok.getLocation(), CurScope, &SS)) { - const char *Opc = OpToken.is(tok::periodstar) ? "'.*'" : "'->*'"; - Diag(OpToken, diag::err_pointer_to_member_type) << Opc; - return ExprError(); - } - - } // Parse another leaf here for the RHS of the operator. // ParseCastExpression works here because all RHS expressions in C have it // as a prefix, at least. However, in C++, an assignment-expression could diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 65bd79d..5ba1dd1 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -123,6 +123,12 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( "ParseObjCAtInterfaceDeclaration(): Expected @interface"); ConsumeToken(); // the "interface" identifier + // Code completion after '@interface'. + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCInterfaceDecl(CurScope); + ConsumeToken(); + } + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing class or category name. return DeclPtrTy(); @@ -137,6 +143,11 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( SourceLocation categoryLoc, rparenLoc; IdentifierInfo *categoryId = 0; + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCInterfaceCategory(CurScope, nameId); + ConsumeToken(); + } + // For ObjC2, the category name is optional (not an error). if (Tok.is(tok::identifier)) { categoryId = Tok.getIdentifierInfo(); @@ -181,6 +192,13 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( if (Tok.is(tok::colon)) { // a super class is specified. ConsumeToken(); + + // Code completion of superclass names. + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCSuperclass(CurScope, nameId); + ConsumeToken(); + } + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing super class name. return DeclPtrTy(); @@ -308,7 +326,8 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, ObjCDeclSpec OCDS; // Parse property attribute list, if any. if (Tok.is(tok::l_paren)) - ParseObjCPropertyAttribute(OCDS); + ParseObjCPropertyAttribute(OCDS, interfaceDecl, + allMethods.data(), allMethods.size()); struct ObjCPropertyCallback : FieldCallback { Parser &P; @@ -407,13 +426,15 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, /// copy /// nonatomic /// -void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { +void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, DeclPtrTy ClassDecl, + DeclPtrTy *Methods, + unsigned NumMethods) { assert(Tok.getKind() == tok::l_paren); SourceLocation LHSLoc = ConsumeParen(); // consume '(' while (1) { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCProperty(CurScope, DS); + Actions.CodeCompleteObjCPropertyFlags(CurScope, DS); ConsumeToken(); } const IdentifierInfo *II = Tok.getIdentifierInfo(); @@ -444,6 +465,16 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { tok::r_paren)) return; + if (Tok.is(tok::code_completion)) { + if (II->getNameStart()[0] == 's') + Actions.CodeCompleteObjCPropertySetter(CurScope, ClassDecl, + Methods, NumMethods); + else + Actions.CodeCompleteObjCPropertyGetter(CurScope, ClassDecl, + Methods, NumMethods); + ConsumeToken(); + } + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); SkipUntil(tok::r_paren); @@ -1078,6 +1109,12 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration( "ParseObjCAtImplementationDeclaration(): Expected @implementation"); ConsumeToken(); // the "implementation" identifier + // Code completion after '@implementation'. + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCImplementationDecl(CurScope); + ConsumeToken(); + } + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing class or category name. return DeclPtrTy(); @@ -1092,6 +1129,11 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration( SourceLocation categoryLoc, rparenLoc; IdentifierInfo *categoryId = 0; + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCImplementationCategory(CurScope, nameId); + ConsumeToken(); + } + if (Tok.is(tok::identifier)) { categoryId = Tok.getIdentifierInfo(); categoryLoc = ConsumeToken(); @@ -1202,18 +1244,32 @@ Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { assert(Tok.isObjCAtKeyword(tok::objc_synthesize) && "ParseObjCPropertyDynamic(): Expected '@synthesize'"); SourceLocation loc = ConsumeToken(); // consume synthesize - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); - return DeclPtrTy(); - } - while (Tok.is(tok::identifier)) { + while (true) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCPropertyDefinition(CurScope, ObjCImpDecl); + ConsumeToken(); + } + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_synthesized_property_name); + SkipUntil(tok::semi); + return DeclPtrTy(); + } + IdentifierInfo *propertyIvar = 0; IdentifierInfo *propertyId = Tok.getIdentifierInfo(); SourceLocation propertyLoc = ConsumeToken(); // consume property name if (Tok.is(tok::equal)) { // property '=' ivar-name ConsumeToken(); // consume '=' + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCPropertySynthesizeIvar(CurScope, propertyId, + ObjCImpDecl); + ConsumeToken(); + } + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); break; @@ -1227,8 +1283,10 @@ Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { break; ConsumeToken(); // consume ',' } - if (Tok.isNot(tok::semi)) + if (Tok.isNot(tok::semi)) { Diag(Tok, diag::err_expected_semi_after) << "@synthesize"; + SkipUntil(tok::semi); + } else ConsumeToken(); // consume ';' return DeclPtrTy(); @@ -1245,11 +1303,18 @@ Parser::DeclPtrTy Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { assert(Tok.isObjCAtKeyword(tok::objc_dynamic) && "ParseObjCPropertyDynamic(): Expected '@dynamic'"); SourceLocation loc = ConsumeToken(); // consume dynamic - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); - return DeclPtrTy(); - } - while (Tok.is(tok::identifier)) { + while (true) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCPropertyDefinition(CurScope, ObjCImpDecl); + ConsumeToken(); + } + + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + SkipUntil(tok::semi); + return DeclPtrTy(); + } + IdentifierInfo *propertyId = Tok.getIdentifierInfo(); SourceLocation propertyLoc = ConsumeToken(); // consume property name Actions.ActOnPropertyImplDecl(atLoc, propertyLoc, false, ObjCImpDecl, @@ -1580,11 +1645,14 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, ExprArg ReceiverExpr) { if (Tok.is(tok::code_completion)) { if (ReceiverName) - Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverName, NameLoc); + Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverName, NameLoc, + 0, 0); else - Actions.CodeCompleteObjCInstanceMessage(CurScope, ReceiverExpr.get()); + Actions.CodeCompleteObjCInstanceMessage(CurScope, ReceiverExpr.get(), + 0, 0); ConsumeToken(); } + // Parse objc-selector SourceLocation Loc; IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc); @@ -1622,6 +1690,19 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, // We have a valid expression. KeyExprs.push_back(Res.release()); + // Code completion after each argument. + if (Tok.is(tok::code_completion)) { + if (ReceiverName) + Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverName, NameLoc, + KeyIdents.data(), + KeyIdents.size()); + else + Actions.CodeCompleteObjCInstanceMessage(CurScope, ReceiverExpr.get(), + KeyIdents.data(), + KeyIdents.size()); + ConsumeToken(); + } + // Check for another keyword selector. selIdent = ParseObjCSelectorPiece(Loc); if (!selIdent && Tok.isNot(tok::colon)) diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 88ac4e4..a9d8301 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -117,6 +117,33 @@ CodeCompletionString::Chunk::CreateCurrentParameter( return Chunk(CK_CurrentParameter, CurrentParameter); } +CodeCompletionString::Chunk CodeCompletionString::Chunk::Clone() const { + switch (Kind) { + case CK_TypedText: + case CK_Text: + case CK_Placeholder: + case CK_Informative: + case CK_CurrentParameter: + case CK_LeftParen: + case CK_RightParen: + case CK_LeftBracket: + case CK_RightBracket: + case CK_LeftBrace: + case CK_RightBrace: + case CK_LeftAngle: + case CK_RightAngle: + case CK_Comma: + return Chunk(Kind, Text); + + case CK_Optional: { + std::auto_ptr Opt(Optional->Clone()); + return CreateOptional(Opt); + } + } + + // Silence GCC warning. + return Chunk(); +} void CodeCompletionString::Chunk::Destroy() { @@ -168,6 +195,20 @@ std::string CodeCompletionString::getAsString() const { return Result; } +const char *CodeCompletionString::getTypedText() const { + for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) + if (C->Kind == CK_TypedText) + return C->Text; + + return 0; +} + +CodeCompletionString *CodeCompletionString::Clone() const { + CodeCompletionString *Result = new CodeCompletionString; + for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) + Result->AddChunk(C->Clone()); + return Result; +} namespace { // Escape a string for XML-like formatting. @@ -473,6 +514,13 @@ CodeCompletionString *CodeCompletionString::Deserialize(llvm::StringRef &Str) { return Result; } +void CodeCompleteConsumer::Result::Destroy() { + if (Kind == RK_Pattern) { + delete Pattern; + Pattern = 0; + } +} + //===----------------------------------------------------------------------===// // Code completion overload candidate implementation //===----------------------------------------------------------------------===// @@ -545,6 +593,12 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, OS << '\n'; break; } + + case Result::RK_Pattern: { + OS << "Pattern : " << Results[I].Rank << " : " + << Results[I].Pattern->getAsString() << '\n'; + break; + } } } @@ -627,6 +681,13 @@ CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, OS << '\n'; break; } + + case Result::RK_Pattern: { + OS << "Pattern:"; + Results[I].Pattern->Serialize(OS); + OS << '\n'; + break; + } } } diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h index 6e72dce..10cc818 100644 --- a/lib/Sema/Lookup.h +++ b/lib/Sema/Lookup.h @@ -201,6 +201,13 @@ public: return getResultKind() == Ambiguous; } + /// Determines if this names a single result which is not an + /// unresolved value using decl. If so, it is safe to call + /// getFoundDecl(). + bool isSingleResult() const { + return getResultKind() == Found; + } + LookupResultKind getResultKind() const { sanity(); return ResultKind; @@ -248,12 +255,24 @@ public: Decls.set_size(N); } - /// \brief Resolves the kind of the lookup, possibly hiding decls. + /// \brief Resolves the result kind of the lookup, possibly hiding + /// decls. /// /// This should be called in any environment where lookup might /// generate multiple lookup results. void resolveKind(); + /// \brief Re-resolves the result kind of the lookup after a set of + /// removals has been performed. + void resolveKindAfterFilter() { + if (Decls.empty()) + ResultKind = NotFound; + else { + ResultKind = Found; + resolveKind(); + } + } + /// \brief Fetch this as an unambiguous single declaration /// (possibly an overloaded one). /// @@ -272,6 +291,12 @@ public: return Decls[0]->getUnderlyingDecl(); } + /// Fetches a representative decl. Useful for lazy diagnostics. + NamedDecl *getRepresentativeDecl() const { + assert(!Decls.empty() && "cannot get representative of empty set"); + return Decls[0]; + } + /// \brief Asks if the result is a single tag decl. bool isSingleTagDecl() const { return getResultKind() == Found && isa(getFoundDecl()); @@ -337,6 +362,65 @@ public: return NameLoc; } + /// A class for iterating through a result set and possibly + /// filtering out results. The results returned are possibly + /// sugared. + class Filter { + LookupResult &Results; + unsigned I; + bool ErasedAny; +#ifndef NDEBUG + bool CalledDone; +#endif + + friend class LookupResult; + Filter(LookupResult &Results) + : Results(Results), I(0), ErasedAny(false) +#ifndef NDEBUG + , CalledDone(false) +#endif + {} + + public: +#ifndef NDEBUG + ~Filter() { + assert(CalledDone && + "LookupResult::Filter destroyed without done() call"); + } +#endif + + bool hasNext() const { + return I != Results.Decls.size(); + } + + NamedDecl *next() { + assert(I < Results.Decls.size() && "next() called on empty filter"); + return Results.Decls[I++]; + } + + /// Erase the last element returned from this iterator. + void erase() { + Results.Decls[--I] = Results.Decls.back(); + Results.Decls.pop_back(); + ErasedAny = true; + } + + void done() { +#ifndef NDEBUG + assert(!CalledDone && "done() called twice"); + CalledDone = true; +#endif + + if (ErasedAny) + Results.resolveKindAfterFilter(); + } + }; + + /// Create a filter for this result set. + Filter makeFilter() { + return Filter(*this); + } + private: void diagnose() { if (isAmbiguous()) diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index b2bbac8..fe2d744 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -319,7 +319,7 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { &Context.Idents.get("Protocol"), SourceLocation(), true); Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl)); - PushOnScopeChains(ProtocolDecl, TUScope); + PushOnScopeChains(ProtocolDecl, TUScope, false); } // Create the built-in typedef for 'id'. if (Context.getObjCIdType().isNull()) { diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 3e186b2..ad4c90b 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -548,26 +548,32 @@ public: DeclPtrTy HandleDeclarator(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, bool IsFunctionDefinition); - void RegisterLocallyScopedExternCDecl(NamedDecl *ND, NamedDecl *PrevDecl, + void RegisterLocallyScopedExternCDecl(NamedDecl *ND, + const LookupResult &Previous, Scope *S); void DiagnoseFunctionSpecifiers(Declarator& D); + bool CheckRedeclaration(DeclContext *DC, + DeclarationName Name, + SourceLocation NameLoc, + unsigned Diagnostic); NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, DeclaratorInfo *DInfo, - NamedDecl* PrevDecl, bool &Redeclaration); + LookupResult &Previous, bool &Redeclaration); NamedDecl* ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, DeclaratorInfo *DInfo, - NamedDecl* PrevDecl, + LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool &Redeclaration); - void CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl, + void CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous, bool &Redeclaration); NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, DeclaratorInfo *DInfo, - NamedDecl* PrevDecl, + LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool IsFunctionDefinition, bool &Redeclaration); - void CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, + void AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); + void CheckFunctionDeclaration(FunctionDecl *NewFD, LookupResult &Previous, bool IsExplicitSpecialization, bool &Redeclaration, bool &OverloadableAttrRequired); @@ -779,15 +785,17 @@ public: /// Subroutines of ActOnDeclarator(). TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T, DeclaratorInfo *DInfo); - void MergeTypeDefDecl(TypedefDecl *New, Decl *Old); + void MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls); bool MergeFunctionDecl(FunctionDecl *New, Decl *Old); bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old); - void MergeVarDecl(VarDecl *New, Decl *Old); + void MergeVarDecl(VarDecl *New, LookupResult &OldDecls); bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old); /// C++ Overloading. - bool IsOverload(FunctionDecl *New, Decl* OldD, - OverloadedFunctionDecl::function_iterator &MatchedDecl); + bool IsOverload(FunctionDecl *New, LookupResult &OldDecls, + NamedDecl *&OldDecl); + bool IsOverload(FunctionDecl *New, FunctionDecl *Old); + ImplicitConversionSequence TryImplicitConversion(Expr* From, QualType ToType, bool SuppressUserConversions, @@ -822,7 +830,7 @@ public: bool AllowConversionFunctions, bool AllowExplicit, bool ForceRValue, bool UserCast = false); - bool DiagnoseAmbiguousUserDefinedConversion(Expr *From, QualType ToType); + bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType); ImplicitConversionSequence::CompareKind @@ -2324,8 +2332,8 @@ public: const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, SourceLocation RAngleLoc, - NamedDecl *&PrevDecl); - bool CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl); + LookupResult &Previous); + bool CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous); virtual DeclResult ActOnExplicitInstantiation(Scope *S, @@ -3638,14 +3646,38 @@ public: virtual void CodeCompleteNamespaceAliasDecl(Scope *S); virtual void CodeCompleteOperatorName(Scope *S); - virtual void CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS); + virtual void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS); + virtual void CodeCompleteObjCPropertyGetter(Scope *S, DeclPtrTy ClassDecl, + DeclPtrTy *Methods, + unsigned NumMethods); + virtual void CodeCompleteObjCPropertySetter(Scope *S, DeclPtrTy ClassDecl, + DeclPtrTy *Methods, + unsigned NumMethods); + virtual void CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName, - SourceLocation FNameLoc); - virtual void CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver); + SourceLocation FNameLoc, + IdentifierInfo **SelIdents, + unsigned NumSelIdents); + virtual void CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, + IdentifierInfo **SelIdents, + unsigned NumSelIdents); virtual void CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols, unsigned NumProtocols); virtual void CodeCompleteObjCProtocolDecl(Scope *S); - //@} + virtual void CodeCompleteObjCInterfaceDecl(Scope *S); + virtual void CodeCompleteObjCSuperclass(Scope *S, + IdentifierInfo *ClassName); + virtual void CodeCompleteObjCImplementationDecl(Scope *S); + virtual void CodeCompleteObjCInterfaceCategory(Scope *S, + IdentifierInfo *ClassName); + virtual void CodeCompleteObjCImplementationCategory(Scope *S, + IdentifierInfo *ClassName); + virtual void CodeCompleteObjCPropertyDefinition(Scope *S, + DeclPtrTy ObjCImpDecl); + virtual void CodeCompleteObjCPropertySynthesizeIvar(Scope *S, + IdentifierInfo *PropertyName, + DeclPtrTy ObjCImpDecl); + //@} //===--------------------------------------------------------------------===// // Extra semantic analysis beyond the C type system diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index e5ad338..6b4f87e 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -175,6 +175,30 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, return ExprError(); } +/// UnwrapDissimilarPointerTypes - Like Sema::UnwrapSimilarPointerTypes, +/// this removes one level of indirection from both types, provided that they're +/// the same kind of pointer (plain or to-member). Unlike the Sema function, +/// this one doesn't care if the two pointers-to-member don't point into the +/// same class. This is because CastsAwayConstness doesn't care. +bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) { + const PointerType *T1PtrType = T1->getAs(), + *T2PtrType = T2->getAs(); + if (T1PtrType && T2PtrType) { + T1 = T1PtrType->getPointeeType(); + T2 = T2PtrType->getPointeeType(); + return true; + } + + const MemberPointerType *T1MPType = T1->getAs(), + *T2MPType = T2->getAs(); + if (T1MPType && T2MPType) { + T1 = T1MPType->getPointeeType(); + T2 = T2MPType->getPointeeType(); + return true; + } + return false; +} + /// CastsAwayConstness - Check if the pointer conversion from SrcType to /// DestType casts away constness as defined in C++ 5.2.11p8ff. This is used by /// the cast checkers. Both arguments must denote pointer (possibly to member) @@ -195,7 +219,7 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) { llvm::SmallVector cv1, cv2; // Find the qualifications. - while (Self.UnwrapSimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) { + while (UnwrapDissimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) { cv1.push_back(UnwrappedSrcType.getQualifiers()); cv2.push_back(UnwrappedDestType.getQualifiers()); } diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 9cecdad..6dbb442 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -944,26 +944,50 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { return Result; } - Result->AddTypedTextChunk( - Sel.getIdentifierInfoForSlot(0)->getName().str() + std::string(":")); + std::string SelName = Sel.getIdentifierInfoForSlot(0)->getName().str(); + SelName += ':'; + if (StartParameter == 0) + Result->AddTypedTextChunk(SelName); + else { + Result->AddInformativeChunk(SelName); + + // If there is only one parameter, and we're past it, add an empty + // typed-text chunk since there is nothing to type. + if (Method->param_size() == 1) + Result->AddTypedTextChunk(""); + } unsigned Idx = 0; for (ObjCMethodDecl::param_iterator P = Method->param_begin(), PEnd = Method->param_end(); P != PEnd; (void)++P, ++Idx) { if (Idx > 0) { - std::string Keyword = " "; + std::string Keyword; + if (Idx > StartParameter) + Keyword = " "; if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Idx)) Keyword += II->getName().str(); Keyword += ":"; - Result->AddTextChunk(Keyword); + if (Idx < StartParameter || AllParametersAreInformative) { + Result->AddInformativeChunk(Keyword); + } else if (Idx == StartParameter) + Result->AddTypedTextChunk(Keyword); + else + Result->AddTextChunk(Keyword); } + + // If we're before the starting parameter, skip the placeholder. + if (Idx < StartParameter) + continue; std::string Arg; (*P)->getType().getAsStringInternal(Arg, S.Context.PrintingPolicy); Arg = "(" + Arg + ")"; if (IdentifierInfo *II = (*P)->getIdentifier()) Arg += II->getName().str(); - Result->AddPlaceholderChunk(Arg); + if (AllParametersAreInformative) + Result->AddInformativeChunk(Arg); + else + Result->AddPlaceholderChunk(Arg); } return Result; @@ -1066,6 +1090,17 @@ namespace { else if (X.Rank > Y.Rank) return false; + // We use a special ordering for keywords and patterns, based on the + // typed text. + if ((X.Kind == Result::RK_Keyword || X.Kind == Result::RK_Pattern) && + (Y.Kind == Result::RK_Keyword || Y.Kind == Result::RK_Pattern)) { + const char *XStr = (X.Kind == Result::RK_Keyword)? X.Keyword + : X.Pattern->getTypedText(); + const char *YStr = (Y.Kind == Result::RK_Keyword)? Y.Keyword + : Y.Pattern->getTypedText(); + return strcmp(XStr, YStr) < 0; + } + // Result kinds are ordered by decreasing importance. if (X.Kind < Y.Kind) return true; @@ -1087,12 +1122,14 @@ namespace { return isEarlierDeclarationName(X.Declaration->getDeclName(), Y.Declaration->getDeclName()); - case Result::RK_Keyword: - return strcmp(X.Keyword, Y.Keyword) < 0; - case Result::RK_Macro: return llvm::LowercaseString(X.Macro->getName()) < llvm::LowercaseString(Y.Macro->getName()); + + case Result::RK_Keyword: + case Result::RK_Pattern: + llvm::llvm_unreachable("Result kinds handled above"); + break; } // Silence GCC warning. @@ -1120,6 +1157,9 @@ static void HandleCodeCompleteResults(Sema *S, if (CodeCompleter) CodeCompleter->ProcessCodeCompleteResults(*S, Results, NumResults); + + for (unsigned I = 0; I != NumResults; ++I) + Results[I].Destroy(); } void Sema::CodeCompleteOrdinaryName(Scope *S) { @@ -1132,6 +1172,7 @@ void Sema::CodeCompleteOrdinaryName(Scope *S) { } static void AddObjCProperties(ObjCContainerDecl *Container, + bool AllowCategories, DeclContext *CurContext, ResultBuilder &Results) { typedef CodeCompleteConsumer::Result Result; @@ -1148,29 +1189,32 @@ static void AddObjCProperties(ObjCContainerDecl *Container, for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(), PEnd = Protocol->protocol_end(); P != PEnd; ++P) - AddObjCProperties(*P, CurContext, Results); + AddObjCProperties(*P, AllowCategories, CurContext, Results); } else if (ObjCInterfaceDecl *IFace = dyn_cast(Container)){ - // Look through categories. - for (ObjCCategoryDecl *Category = IFace->getCategoryList(); - Category; Category = Category->getNextClassCategory()) - AddObjCProperties(Category, CurContext, Results); + if (AllowCategories) { + // Look through categories. + for (ObjCCategoryDecl *Category = IFace->getCategoryList(); + Category; Category = Category->getNextClassCategory()) + AddObjCProperties(Category, AllowCategories, CurContext, Results); + } // Look through protocols. for (ObjCInterfaceDecl::protocol_iterator I = IFace->protocol_begin(), E = IFace->protocol_end(); I != E; ++I) - AddObjCProperties(*I, CurContext, Results); + AddObjCProperties(*I, AllowCategories, CurContext, Results); // Look in the superclass. if (IFace->getSuperClass()) - AddObjCProperties(IFace->getSuperClass(), CurContext, Results); + AddObjCProperties(IFace->getSuperClass(), AllowCategories, CurContext, + Results); } else if (const ObjCCategoryDecl *Category = dyn_cast(Container)) { // Look through protocols. for (ObjCInterfaceDecl::protocol_iterator P = Category->protocol_begin(), PEnd = Category->protocol_end(); P != PEnd; ++P) - AddObjCProperties(*P, CurContext, Results); + AddObjCProperties(*P, AllowCategories, CurContext, Results); } } @@ -1234,13 +1278,13 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, const ObjCObjectPointerType *ObjCPtr = BaseType->getAsObjCInterfacePointerType(); assert(ObjCPtr && "Non-NULL pointer guaranteed above!"); - AddObjCProperties(ObjCPtr->getInterfaceDecl(), CurContext, Results); + AddObjCProperties(ObjCPtr->getInterfaceDecl(), true, CurContext, Results); // Add properties from the protocols in a qualified interface. for (ObjCObjectPointerType::qual_iterator I = ObjCPtr->qual_begin(), E = ObjCPtr->qual_end(); I != E; ++I) - AddObjCProperties(*I, CurContext, Results); + AddObjCProperties(*I, true, CurContext, Results); // FIXME: We could (should?) also look for "implicit" properties, identified // only by the presence of nullary and unary selectors. @@ -1611,34 +1655,104 @@ void Sema::CodeCompleteOperatorName(Scope *S) { HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } -void Sema::CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS) { +/// \brief Determine whether the addition of the given flag to an Objective-C +/// property's attributes will cause a conflict. +static bool ObjCPropertyFlagConflicts(unsigned Attributes, unsigned NewFlag) { + // Check if we've already added this flag. + if (Attributes & NewFlag) + return true; + + Attributes |= NewFlag; + + // Check for collisions with "readonly". + if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) && + (Attributes & (ObjCDeclSpec::DQ_PR_readwrite | + ObjCDeclSpec::DQ_PR_assign | + ObjCDeclSpec::DQ_PR_copy | + ObjCDeclSpec::DQ_PR_retain))) + return true; + + // Check for more than one of { assign, copy, retain }. + unsigned AssignCopyRetMask = Attributes & (ObjCDeclSpec::DQ_PR_assign | + ObjCDeclSpec::DQ_PR_copy | + ObjCDeclSpec::DQ_PR_retain); + if (AssignCopyRetMask && + AssignCopyRetMask != ObjCDeclSpec::DQ_PR_assign && + AssignCopyRetMask != ObjCDeclSpec::DQ_PR_copy && + AssignCopyRetMask != ObjCDeclSpec::DQ_PR_retain) + return true; + + return false; +} + +void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) { if (!CodeCompleter) return; + unsigned Attributes = ODS.getPropertyAttributes(); typedef CodeCompleteConsumer::Result Result; ResultBuilder Results(*this); Results.EnterNewScope(); - if (!(Attributes & ObjCDeclSpec::DQ_PR_readonly)) + if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_readonly)) Results.MaybeAddResult(CodeCompleteConsumer::Result("readonly", 0)); - if (!(Attributes & ObjCDeclSpec::DQ_PR_assign)) + if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_assign)) Results.MaybeAddResult(CodeCompleteConsumer::Result("assign", 0)); - if (!(Attributes & ObjCDeclSpec::DQ_PR_readwrite)) + if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_readwrite)) Results.MaybeAddResult(CodeCompleteConsumer::Result("readwrite", 0)); - if (!(Attributes & ObjCDeclSpec::DQ_PR_retain)) + if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_retain)) Results.MaybeAddResult(CodeCompleteConsumer::Result("retain", 0)); - if (!(Attributes & ObjCDeclSpec::DQ_PR_copy)) + if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_copy)) Results.MaybeAddResult(CodeCompleteConsumer::Result("copy", 0)); - if (!(Attributes & ObjCDeclSpec::DQ_PR_nonatomic)) + if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_nonatomic)) Results.MaybeAddResult(CodeCompleteConsumer::Result("nonatomic", 0)); - if (!(Attributes & ObjCDeclSpec::DQ_PR_setter)) - Results.MaybeAddResult(CodeCompleteConsumer::Result("setter", 0)); - if (!(Attributes & ObjCDeclSpec::DQ_PR_getter)) - Results.MaybeAddResult(CodeCompleteConsumer::Result("getter", 0)); + if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_setter)) { + CodeCompletionString *Setter = new CodeCompletionString; + Setter->AddTypedTextChunk("setter"); + Setter->AddTextChunk(" = "); + Setter->AddPlaceholderChunk("method"); + Results.MaybeAddResult(CodeCompleteConsumer::Result(Setter, 0)); + } + if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_getter)) { + CodeCompletionString *Getter = new CodeCompletionString; + Getter->AddTypedTextChunk("getter"); + Getter->AddTextChunk(" = "); + Getter->AddPlaceholderChunk("method"); + Results.MaybeAddResult(CodeCompleteConsumer::Result(Getter, 0)); + } Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } +/// \brief Descripts the kind of Objective-C method that we want to find +/// via code completion. +enum ObjCMethodKind { + MK_Any, //< Any kind of method, provided it means other specified criteria. + MK_ZeroArgSelector, //< Zero-argument (unary) selector. + MK_OneArgSelector //< One-argument selector. +}; + +static bool isAcceptableObjCMethod(ObjCMethodDecl *Method, + ObjCMethodKind WantKind, + IdentifierInfo **SelIdents, + unsigned NumSelIdents) { + Selector Sel = Method->getSelector(); + if (NumSelIdents > Sel.getNumArgs()) + return false; + + switch (WantKind) { + case MK_Any: break; + case MK_ZeroArgSelector: return Sel.isUnarySelector(); + case MK_OneArgSelector: return Sel.getNumArgs() == 1; + } + + for (unsigned I = 0; I != NumSelIdents; ++I) + if (SelIdents[I] != Sel.getIdentifierInfoForSlot(I)) + return false; + + return true; +} + /// \brief Add all of the Objective-C methods in the given Objective-C /// container to the set of results. /// @@ -1658,14 +1772,26 @@ void Sema::CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS) { /// \param Results the structure into which we'll add results. static void AddObjCMethods(ObjCContainerDecl *Container, bool WantInstanceMethods, + ObjCMethodKind WantKind, + IdentifierInfo **SelIdents, + unsigned NumSelIdents, DeclContext *CurContext, ResultBuilder &Results) { typedef CodeCompleteConsumer::Result Result; for (ObjCContainerDecl::method_iterator M = Container->meth_begin(), MEnd = Container->meth_end(); M != MEnd; ++M) { - if ((*M)->isInstanceMethod() == WantInstanceMethods) - Results.MaybeAddResult(Result(*M, 0), CurContext); + if ((*M)->isInstanceMethod() == WantInstanceMethods) { + // Check whether the selector identifiers we've been given are a + // subset of the identifiers for this particular method. + if (!isAcceptableObjCMethod(*M, WantKind, SelIdents, NumSelIdents)) + continue; + + Result R = Result(*M, 0); + R.StartParameter = NumSelIdents; + R.AllParametersAreInformative = (WantKind != MK_Any); + Results.MaybeAddResult(R, CurContext); + } } ObjCInterfaceDecl *IFace = dyn_cast(Container); @@ -1677,12 +1803,14 @@ static void AddObjCMethods(ObjCContainerDecl *Container, for (ObjCList::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) - AddObjCMethods(*I, WantInstanceMethods, CurContext, Results); + AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, NumSelIdents, + CurContext, Results); // Add methods in categories. for (ObjCCategoryDecl *CatDecl = IFace->getCategoryList(); CatDecl; CatDecl = CatDecl->getNextClassCategory()) { - AddObjCMethods(CatDecl, WantInstanceMethods, CurContext, Results); + AddObjCMethods(CatDecl, WantInstanceMethods, WantKind, SelIdents, + NumSelIdents, CurContext, Results); // Add a categories protocol methods. const ObjCList &Protocols @@ -1690,25 +1818,110 @@ static void AddObjCMethods(ObjCContainerDecl *Container, for (ObjCList::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) - AddObjCMethods(*I, WantInstanceMethods, CurContext, Results); + AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, + NumSelIdents, CurContext, Results); // Add methods in category implementations. if (ObjCCategoryImplDecl *Impl = CatDecl->getImplementation()) - AddObjCMethods(Impl, WantInstanceMethods, CurContext, Results); + AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents, + NumSelIdents, CurContext, Results); } // Add methods in superclass. if (IFace->getSuperClass()) - AddObjCMethods(IFace->getSuperClass(), WantInstanceMethods, CurContext, - Results); + AddObjCMethods(IFace->getSuperClass(), WantInstanceMethods, WantKind, + SelIdents, NumSelIdents, CurContext, Results); // Add methods in our implementation, if any. if (ObjCImplementationDecl *Impl = IFace->getImplementation()) - AddObjCMethods(Impl, WantInstanceMethods, CurContext, Results); + AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents, + NumSelIdents, CurContext, Results); +} + + +void Sema::CodeCompleteObjCPropertyGetter(Scope *S, DeclPtrTy ClassDecl, + DeclPtrTy *Methods, + unsigned NumMethods) { + typedef CodeCompleteConsumer::Result Result; + + // Try to find the interface where getters might live. + ObjCInterfaceDecl *Class + = dyn_cast_or_null(ClassDecl.getAs()); + if (!Class) { + if (ObjCCategoryDecl *Category + = dyn_cast_or_null(ClassDecl.getAs())) + Class = Category->getClassInterface(); + + if (!Class) + return; + } + + // Find all of the potential getters. + ResultBuilder Results(*this); + Results.EnterNewScope(); + + // FIXME: We need to do this because Objective-C methods don't get + // pushed into DeclContexts early enough. Argh! + for (unsigned I = 0; I != NumMethods; ++I) { + if (ObjCMethodDecl *Method + = dyn_cast_or_null(Methods[I].getAs())) + if (Method->isInstanceMethod() && + isAcceptableObjCMethod(Method, MK_ZeroArgSelector, 0, 0)) { + Result R = Result(Method, 0); + R.AllParametersAreInformative = true; + Results.MaybeAddResult(R, CurContext); + } + } + + AddObjCMethods(Class, true, MK_ZeroArgSelector, 0, 0, CurContext, Results); + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter,Results.data(),Results.size()); +} + +void Sema::CodeCompleteObjCPropertySetter(Scope *S, DeclPtrTy ObjCImplDecl, + DeclPtrTy *Methods, + unsigned NumMethods) { + typedef CodeCompleteConsumer::Result Result; + + // Try to find the interface where setters might live. + ObjCInterfaceDecl *Class + = dyn_cast_or_null(ObjCImplDecl.getAs()); + if (!Class) { + if (ObjCCategoryDecl *Category + = dyn_cast_or_null(ObjCImplDecl.getAs())) + Class = Category->getClassInterface(); + + if (!Class) + return; + } + + // Find all of the potential getters. + ResultBuilder Results(*this); + Results.EnterNewScope(); + + // FIXME: We need to do this because Objective-C methods don't get + // pushed into DeclContexts early enough. Argh! + for (unsigned I = 0; I != NumMethods; ++I) { + if (ObjCMethodDecl *Method + = dyn_cast_or_null(Methods[I].getAs())) + if (Method->isInstanceMethod() && + isAcceptableObjCMethod(Method, MK_OneArgSelector, 0, 0)) { + Result R = Result(Method, 0); + R.AllParametersAreInformative = true; + Results.MaybeAddResult(R, CurContext); + } + } + + AddObjCMethods(Class, true, MK_OneArgSelector, 0, 0, CurContext, Results); + + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter,Results.data(),Results.size()); } void Sema::CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName, - SourceLocation FNameLoc) { + SourceLocation FNameLoc, + IdentifierInfo **SelIdents, + unsigned NumSelIdents) { typedef CodeCompleteConsumer::Result Result; ObjCInterfaceDecl *CDecl = 0; @@ -1734,7 +1947,8 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName, SuperTy = Context.getObjCObjectPointerType(SuperTy); OwningExprResult Super = Owned(new (Context) ObjCSuperExpr(FNameLoc, SuperTy)); - return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get()); + return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get(), + SelIdents, NumSelIdents); } // Okay, we're calling a factory method in our superclass. @@ -1756,21 +1970,25 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName, // probably calling an instance method. OwningExprResult Super = ActOnDeclarationNameExpr(S, FNameLoc, FName, false, 0, false); - return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get()); + return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get(), + SelIdents, NumSelIdents); } // Add all of the factory methods in this Objective-C class, its protocols, // superclasses, categories, implementation, etc. ResultBuilder Results(*this); Results.EnterNewScope(); - AddObjCMethods(CDecl, false, CurContext, Results); + AddObjCMethods(CDecl, false, MK_Any, SelIdents, NumSelIdents, CurContext, + Results); Results.ExitScope(); // This also suppresses remaining diagnostics. HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } -void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver) { +void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, + IdentifierInfo **SelIdents, + unsigned NumSelIdents) { typedef CodeCompleteConsumer::Result Result; Expr *RecExpr = static_cast(Receiver); @@ -1798,7 +2016,8 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver) { ReceiverType->isObjCQualifiedClassType()) { if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) { if (ObjCInterfaceDecl *ClassDecl = CurMethod->getClassInterface()) - AddObjCMethods(ClassDecl, false, CurContext, Results); + AddObjCMethods(ClassDecl, false, MK_Any, SelIdents, NumSelIdents, + CurContext, Results); } } // Handle messages to a qualified ID ("id"). @@ -1808,19 +2027,22 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver) { for (ObjCObjectPointerType::qual_iterator I = QualID->qual_begin(), E = QualID->qual_end(); I != E; ++I) - AddObjCMethods(*I, true, CurContext, Results); + AddObjCMethods(*I, true, MK_Any, SelIdents, NumSelIdents, CurContext, + Results); } // Handle messages to a pointer to interface type. else if (const ObjCObjectPointerType *IFacePtr = ReceiverType->getAsObjCInterfacePointerType()) { // Search the class, its superclasses, etc., for instance methods. - AddObjCMethods(IFacePtr->getInterfaceDecl(), true, CurContext, Results); + AddObjCMethods(IFacePtr->getInterfaceDecl(), true, MK_Any, SelIdents, + NumSelIdents, CurContext, Results); // Search protocols for instance methods. for (ObjCObjectPointerType::qual_iterator I = IFacePtr->qual_begin(), E = IFacePtr->qual_end(); I != E; ++I) - AddObjCMethods(*I, true, CurContext, Results); + AddObjCMethods(*I, true, MK_Any, SelIdents, NumSelIdents, CurContext, + Results); } Results.ExitScope(); @@ -1885,3 +2107,210 @@ void Sema::CodeCompleteObjCProtocolDecl(Scope *) { Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } + +/// \brief Add all of the Objective-C interface declarations that we find in +/// the given (translation unit) context. +static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext, + bool OnlyForwardDeclarations, + bool OnlyUnimplemented, + ResultBuilder &Results) { + typedef CodeCompleteConsumer::Result Result; + + for (DeclContext::decl_iterator D = Ctx->decls_begin(), + DEnd = Ctx->decls_end(); + D != DEnd; ++D) { + // Record any interfaces we find. + if (ObjCInterfaceDecl *Class = dyn_cast(*D)) + if ((!OnlyForwardDeclarations || Class->isForwardDecl()) && + (!OnlyUnimplemented || !Class->getImplementation())) + Results.MaybeAddResult(Result(Class, 0), CurContext); + + // Record any forward-declared interfaces we find. + if (ObjCClassDecl *Forward = dyn_cast(*D)) { + for (ObjCClassDecl::iterator C = Forward->begin(), CEnd = Forward->end(); + C != CEnd; ++C) + if ((!OnlyForwardDeclarations || C->getInterface()->isForwardDecl()) && + (!OnlyUnimplemented || !C->getInterface()->getImplementation())) + Results.MaybeAddResult(Result(C->getInterface(), 0), CurContext); + } + } +} + +void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) { + ResultBuilder Results(*this); + Results.EnterNewScope(); + + // Add all classes. + AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, true, + false, Results); + + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + +void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName) { + ResultBuilder Results(*this); + Results.EnterNewScope(); + + // Make sure that we ignore the class we're currently defining. + NamedDecl *CurClass + = LookupSingleName(TUScope, ClassName, LookupOrdinaryName); + if (CurClass && isa(CurClass)) + Results.Ignore(CurClass); + + // Add all classes. + AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false, + false, Results); + + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + +void Sema::CodeCompleteObjCImplementationDecl(Scope *S) { + ResultBuilder Results(*this); + Results.EnterNewScope(); + + // Add all unimplemented classes. + AddInterfaceResults(Context.getTranslationUnitDecl(), CurContext, false, + true, Results); + + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + +void Sema::CodeCompleteObjCInterfaceCategory(Scope *S, + IdentifierInfo *ClassName) { + typedef CodeCompleteConsumer::Result Result; + + ResultBuilder Results(*this); + + // Ignore any categories we find that have already been implemented by this + // interface. + llvm::SmallPtrSet CategoryNames; + NamedDecl *CurClass + = LookupSingleName(TUScope, ClassName, LookupOrdinaryName); + if (ObjCInterfaceDecl *Class = dyn_cast_or_null(CurClass)) + for (ObjCCategoryDecl *Category = Class->getCategoryList(); Category; + Category = Category->getNextClassCategory()) + CategoryNames.insert(Category->getIdentifier()); + + // Add all of the categories we know about. + Results.EnterNewScope(); + TranslationUnitDecl *TU = Context.getTranslationUnitDecl(); + for (DeclContext::decl_iterator D = TU->decls_begin(), + DEnd = TU->decls_end(); + D != DEnd; ++D) + if (ObjCCategoryDecl *Category = dyn_cast(*D)) + if (CategoryNames.insert(Category->getIdentifier())) + Results.MaybeAddResult(Result(Category, 0), CurContext); + Results.ExitScope(); + + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + +void Sema::CodeCompleteObjCImplementationCategory(Scope *S, + IdentifierInfo *ClassName) { + typedef CodeCompleteConsumer::Result Result; + + // Find the corresponding interface. If we couldn't find the interface, the + // program itself is ill-formed. However, we'll try to be helpful still by + // providing the list of all of the categories we know about. + NamedDecl *CurClass + = LookupSingleName(TUScope, ClassName, LookupOrdinaryName); + ObjCInterfaceDecl *Class = dyn_cast_or_null(CurClass); + if (!Class) + return CodeCompleteObjCInterfaceCategory(S, ClassName); + + ResultBuilder Results(*this); + + // Add all of the categories that have have corresponding interface + // declarations in this class and any of its superclasses, except for + // already-implemented categories in the class itself. + llvm::SmallPtrSet CategoryNames; + Results.EnterNewScope(); + bool IgnoreImplemented = true; + while (Class) { + for (ObjCCategoryDecl *Category = Class->getCategoryList(); Category; + Category = Category->getNextClassCategory()) + if ((!IgnoreImplemented || !Category->getImplementation()) && + CategoryNames.insert(Category->getIdentifier())) + Results.MaybeAddResult(Result(Category, 0), CurContext); + + Class = Class->getSuperClass(); + IgnoreImplemented = false; + } + Results.ExitScope(); + + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + +void Sema::CodeCompleteObjCPropertyDefinition(Scope *S, DeclPtrTy ObjCImpDecl) { + typedef CodeCompleteConsumer::Result Result; + ResultBuilder Results(*this); + + // Figure out where this @synthesize lives. + ObjCContainerDecl *Container + = dyn_cast_or_null(ObjCImpDecl.getAs()); + if (!Container || + (!isa(Container) && + !isa(Container))) + return; + + // Ignore any properties that have already been implemented. + for (DeclContext::decl_iterator D = Container->decls_begin(), + DEnd = Container->decls_end(); + D != DEnd; ++D) + if (ObjCPropertyImplDecl *PropertyImpl = dyn_cast(*D)) + Results.Ignore(PropertyImpl->getPropertyDecl()); + + // Add any properties that we find. + Results.EnterNewScope(); + if (ObjCImplementationDecl *ClassImpl + = dyn_cast(Container)) + AddObjCProperties(ClassImpl->getClassInterface(), false, CurContext, + Results); + else + AddObjCProperties(cast(Container)->getCategoryDecl(), + false, CurContext, Results); + Results.ExitScope(); + + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + +void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, + IdentifierInfo *PropertyName, + DeclPtrTy ObjCImpDecl) { + typedef CodeCompleteConsumer::Result Result; + ResultBuilder Results(*this); + + // Figure out where this @synthesize lives. + ObjCContainerDecl *Container + = dyn_cast_or_null(ObjCImpDecl.getAs()); + if (!Container || + (!isa(Container) && + !isa(Container))) + return; + + // Figure out which interface we're looking into. + ObjCInterfaceDecl *Class = 0; + if (ObjCImplementationDecl *ClassImpl + = dyn_cast(Container)) + Class = ClassImpl->getClassInterface(); + else + Class = cast(Container)->getCategoryDecl() + ->getClassInterface(); + + // Add all of the instance variables in this class and its superclasses. + Results.EnterNewScope(); + for(; Class; Class = Class->getSuperClass()) { + // FIXME: We could screen the type of each ivar for compatibility with + // the property, but is that being too paternal? + for (ObjCInterfaceDecl::ivar_iterator IVar = Class->ivar_begin(), + IVarEnd = Class->ivar_end(); + IVar != IVarEnd; ++IVar) + Results.MaybeAddResult(Result(*IVar, 0), CurContext); + } + Results.ExitScope(); + + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 57c101b..b5109f8 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -311,14 +311,16 @@ void Sema::ExitDeclaratorContext(Scope *S) { /// extension, in C when the previous function is already an /// overloaded function declaration or has the "overloadable" /// attribute. -static bool AllowOverloadingOfFunction(Decl *PrevDecl, ASTContext &Context) { +static bool AllowOverloadingOfFunction(LookupResult &Previous, + ASTContext &Context) { if (Context.getLangOptions().CPlusPlus) return true; - if (isa(PrevDecl)) + if (Previous.getResultKind() == LookupResult::FoundOverloaded) return true; - return PrevDecl->getAttr() != 0; + return (Previous.getResultKind() == LookupResult::Found + && Previous.getFoundDecl()->hasAttr()); } /// Add this decl to the scope shadowed decl chains. @@ -396,6 +398,48 @@ bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S) { return IdResolver.isDeclInScope(D, Ctx, Context, S); } +static bool isOutOfScopePreviousDeclaration(NamedDecl *, + DeclContext*, + ASTContext&); + +/// Filters out lookup results that don't fall within the given scope +/// as determined by isDeclInScope. +static void FilterLookupForScope(Sema &SemaRef, LookupResult &R, + DeclContext *Ctx, Scope *S, + bool ConsiderLinkage) { + LookupResult::Filter F = R.makeFilter(); + while (F.hasNext()) { + NamedDecl *D = F.next(); + + if (SemaRef.isDeclInScope(D, Ctx, S)) + continue; + + if (ConsiderLinkage && + isOutOfScopePreviousDeclaration(D, Ctx, SemaRef.Context)) + continue; + + F.erase(); + } + + F.done(); +} + +static bool isUsingDecl(NamedDecl *D) { + return isa(D) || + isa(D) || + isa(D); +} + +/// Removes using shadow declarations from the lookup results. +static void RemoveUsingDecls(LookupResult &R) { + LookupResult::Filter F = R.makeFilter(); + while (F.hasNext()) + if (isUsingDecl(F.next())) + F.erase(); + + F.done(); +} + static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { if (D->isUsed() || D->hasAttr()) return false; @@ -572,11 +616,10 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, /// how to resolve this situation, merging decls or emitting /// diagnostics as appropriate. If there was an error, set New to be invalid. /// -void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { - // If either decl is known invalid already, set the new one to be invalid and - // don't bother doing any merging checks. - if (New->isInvalidDecl() || OldD->isInvalidDecl()) - return New->setInvalidDecl(); +void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) { + // If the new decl is known invalid already, don't bother doing any + // merging checks. + if (New->isInvalidDecl()) return; // Allow multiple definitions for ObjC built-in typedefs. // FIXME: Verify the underlying types are equivalent! @@ -611,16 +654,25 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { } // Fall through - the typedef name was not a builtin type. } + // Verify the old decl was also a type. - TypeDecl *Old = dyn_cast(OldD); - if (!Old) { + TypeDecl *Old = 0; + if (!OldDecls.isSingleResult() || + !(Old = dyn_cast(OldDecls.getFoundDecl()))) { Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); + + NamedDecl *OldD = OldDecls.getRepresentativeDecl(); if (OldD->getLocation().isValid()) Diag(OldD->getLocation(), diag::note_previous_definition); + return New->setInvalidDecl(); } + // If the old declaration is invalid, just give up here. + if (Old->isInvalidDecl()) + return New->setInvalidDecl(); + // Determine the "old" type we'll use for checking and diagnostics. QualType OldType; if (TypedefDecl *OldTypedef = dyn_cast(Old)) @@ -977,18 +1029,19 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) { /// FinalizeDeclaratorGroup. Unfortunately, we can't analyze tentative /// definitions here, since the initializer hasn't been attached. /// -void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) { - // If either decl is invalid, make sure the new one is marked invalid and - // don't do any other checking. - if (New->isInvalidDecl() || OldD->isInvalidDecl()) - return New->setInvalidDecl(); +void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { + // If the new decl is already invalid, don't do any other checking. + if (New->isInvalidDecl()) + return; // Verify the old decl was also a variable. - VarDecl *Old = dyn_cast(OldD); - if (!Old) { + VarDecl *Old = 0; + if (!Previous.isSingleResult() || + !(Old = dyn_cast(Previous.getFoundDecl()))) { Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); - Diag(OldD->getLocation(), diag::note_previous_definition); + Diag(Previous.getRepresentativeDecl()->getLocation(), + diag::note_previous_definition); return New->setInvalidDecl(); } @@ -1403,6 +1456,33 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { return DeclPtrTy::make(Tag); } +/// We are trying to introduce the given name into the given context; +/// check if there's an existing declaration that can't be overloaded. +/// +/// \return true if this is a forbidden redeclaration +bool Sema::CheckRedeclaration(DeclContext *DC, + DeclarationName Name, + SourceLocation NameLoc, + unsigned diagnostic) { + LookupResult R(*this, Name, NameLoc, LookupOrdinaryName, + ForRedeclaration); + LookupQualifiedName(R, DC); + + if (R.empty()) return false; + + if (R.getResultKind() == LookupResult::Found && + isa(R.getFoundDecl())) + return false; + + // Pick a representative declaration. + NamedDecl *PrevDecl = (*R.begin())->getUnderlyingDecl(); + + Diag(NameLoc, diagnostic) << Name; + Diag(PrevDecl->getLocation(), diag::note_previous_declaration); + + return true; +} + /// InjectAnonymousStructOrUnionMembers - Inject the members of the /// anonymous struct or union AnonRecord into the owning context Owner /// and scope S. This routine will be invoked just after we realize @@ -1421,26 +1501,21 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { /// structs/unions into the owning context and scope as well. bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, RecordDecl *AnonRecord) { + unsigned diagKind + = AnonRecord->isUnion() ? diag::err_anonymous_union_member_redecl + : diag::err_anonymous_struct_member_redecl; + bool Invalid = false; for (RecordDecl::field_iterator F = AnonRecord->field_begin(), FEnd = AnonRecord->field_end(); F != FEnd; ++F) { if ((*F)->getDeclName()) { - LookupResult R(*this, (*F)->getDeclName(), SourceLocation(), - LookupOrdinaryName, ForRedeclaration); - LookupQualifiedName(R, Owner); - NamedDecl *PrevDecl = R.getAsSingleDecl(Context); - if (PrevDecl && !isa(PrevDecl)) { + if (CheckRedeclaration(Owner, (*F)->getDeclName(), + (*F)->getLocation(), diagKind)) { // C++ [class.union]p2: // The names of the members of an anonymous union shall be // distinct from the names of any other entity in the // scope in which the anonymous union is declared. - unsigned diagKind - = AnonRecord->isUnion()? diag::err_anonymous_union_member_redecl - : diag::err_anonymous_struct_member_redecl; - Diag((*F)->getLocation(), diagKind) - << (*F)->getDeclName(); - Diag(PrevDecl->getLocation(), diag::note_previous_declaration); Invalid = true; } else { // C++ [class.union]p2: @@ -1765,19 +1840,20 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, } DeclContext *DC; - NamedDecl *PrevDecl; NamedDecl *New; DeclaratorInfo *DInfo = 0; QualType R = GetTypeForDeclarator(D, S, &DInfo); + LookupResult Previous(*this, Name, D.getIdentifierLoc(), LookupOrdinaryName, + ForRedeclaration); + // See if this is a redefinition of a variable in the same scope. if (D.getCXXScopeSpec().isInvalid()) { DC = CurContext; - PrevDecl = 0; D.setInvalidType(); } else if (!D.getCXXScopeSpec().isSet()) { - LookupNameKind NameKind = LookupOrdinaryName; + bool IsLinkageLookup = false; // If the declaration we're planning to build will be a function // or object with linkage, then look for another declaration with @@ -1787,19 +1863,18 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, else if (R->isFunctionType()) { if (CurContext->isFunctionOrMethod() || D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) - NameKind = LookupRedeclarationWithLinkage; + IsLinkageLookup = true; } else if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern) - NameKind = LookupRedeclarationWithLinkage; + IsLinkageLookup = true; else if (CurContext->getLookupContext()->isTranslationUnit() && D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) - NameKind = LookupRedeclarationWithLinkage; + IsLinkageLookup = true; - DC = CurContext; - LookupResult R(*this, Name, D.getIdentifierLoc(), NameKind, - ForRedeclaration); + if (IsLinkageLookup) + Previous.clear(LookupRedeclarationWithLinkage); - LookupName(R, S, NameKind == LookupRedeclarationWithLinkage); - PrevDecl = R.getAsSingleDecl(Context); + DC = CurContext; + LookupName(Previous, S, /* CreateBuiltins = */ IsLinkageLookup); } else { // Something like "int foo::x;" DC = computeDeclContext(D.getCXXScopeSpec(), true); @@ -1819,10 +1894,11 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, RequireCompleteDeclContext(D.getCXXScopeSpec())) return DeclPtrTy(); - LookupResult Res(*this, Name, D.getIdentifierLoc(), LookupOrdinaryName, - ForRedeclaration); - LookupQualifiedName(Res, DC); - PrevDecl = Res.getAsSingleDecl(Context); + LookupQualifiedName(Previous, DC); + + // Don't consider using declarations as previous declarations for + // out-of-line members. + RemoveUsingDecls(Previous); // C++ 7.3.1.2p2: // Members (including explicit specializations of templates) of a named @@ -1870,23 +1946,25 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, } } - if (PrevDecl && PrevDecl->isTemplateParameter()) { + if (Previous.isSingleResult() && + Previous.getFoundDecl()->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. if (!D.isInvalidType()) - if (DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl)) + if (DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), + Previous.getFoundDecl())) D.setInvalidType(); // Just pretend that we didn't see the previous declaration. - PrevDecl = 0; + Previous.clear(); } // In C++, the previous declaration we find might be a tag type // (class or enum). In this case, the new declaration will hide the // tag type. Note that this does does not apply if we're declaring a // typedef (C++ [dcl.typedef]p4). - if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag && + if (Previous.isSingleTagDecl() && D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef) - PrevDecl = 0; + Previous.clear(); bool Redeclaration = false; if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) { @@ -1895,13 +1973,13 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, return DeclPtrTy(); } - New = ActOnTypedefDeclarator(S, D, DC, R, DInfo, PrevDecl, Redeclaration); + New = ActOnTypedefDeclarator(S, D, DC, R, DInfo, Previous, Redeclaration); } else if (R->isFunctionType()) { - New = ActOnFunctionDeclarator(S, D, DC, R, DInfo, PrevDecl, + New = ActOnFunctionDeclarator(S, D, DC, R, DInfo, Previous, move(TemplateParamLists), IsFunctionDefinition, Redeclaration); } else { - New = ActOnVariableDeclarator(S, D, DC, R, DInfo, PrevDecl, + New = ActOnVariableDeclarator(S, D, DC, R, DInfo, Previous, move(TemplateParamLists), Redeclaration); } @@ -1970,16 +2048,19 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T, /// \brief Register the given locally-scoped external C declaration so /// that it can be found later for redeclarations void -Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, NamedDecl *PrevDecl, +Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, + const LookupResult &Previous, Scope *S) { assert(ND->getLexicalDeclContext()->isFunctionOrMethod() && "Decl is not a locally-scoped decl!"); // Note that we have a locally-scoped external with this name. LocallyScopedExternalDecls[ND->getDeclName()] = ND; - if (!PrevDecl) + if (!Previous.isSingleResult()) return; + NamedDecl *PrevDecl = Previous.getFoundDecl(); + // If there was a previous declaration of this variable, it may be // in our identifier chain. Update the identifier chain with the new // declaration. @@ -2015,7 +2096,7 @@ void Sema::DiagnoseFunctionSpecifiers(Declarator& D) { NamedDecl* Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, DeclaratorInfo *DInfo, - NamedDecl* PrevDecl, bool &Redeclaration) { + LookupResult &Previous, bool &Redeclaration) { // Typedef declarators cannot be qualified (C++ [dcl.meaning]p1). if (D.getCXXScopeSpec().isSet()) { Diag(D.getIdentifierLoc(), diag::err_qualified_typedef_declarator) @@ -2040,11 +2121,13 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewTD, D); + // Merge the decl with the existing one if appropriate. If the decl is // in an outer scope, it isn't the same thing. - if (PrevDecl && isDeclInScope(PrevDecl, DC, S)) { + FilterLookupForScope(*this, Previous, DC, S, /*ConsiderLinkage*/ false); + if (!Previous.empty()) { Redeclaration = true; - MergeTypeDefDecl(NewTD, PrevDecl); + MergeTypeDefDecl(NewTD, Previous); } // C99 6.7.7p2: If a typedef name specifies a variably modified type @@ -2155,7 +2238,7 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC, NamedDecl* Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, DeclaratorInfo *DInfo, - NamedDecl* PrevDecl, + LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool &Redeclaration) { DeclarationName Name = GetNameForDeclarator(D); @@ -2285,22 +2368,21 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, SE->getByteLength()))); } - // If name lookup finds a previous declaration that is not in the - // same scope as the new declaration, this may still be an - // acceptable redeclaration. - if (PrevDecl && !isDeclInScope(PrevDecl, DC, S) && - !(NewVD->hasLinkage() && - isOutOfScopePreviousDeclaration(PrevDecl, DC, Context))) - PrevDecl = 0; + // Don't consider existing declarations that are in a different + // scope and are out-of-semantic-context declarations (if the new + // declaration has linkage). + FilterLookupForScope(*this, Previous, DC, S, NewVD->hasLinkage()); // Merge the decl with the existing one if appropriate. - if (PrevDecl) { - if (isa(PrevDecl) && D.getCXXScopeSpec().isSet()) { + if (!Previous.empty()) { + if (Previous.isSingleResult() && + isa(Previous.getFoundDecl()) && + D.getCXXScopeSpec().isSet()) { // The user tried to define a non-static data member // out-of-line (C++ [dcl.meaning]p1). Diag(NewVD->getLocation(), diag::err_nonstatic_member_out_of_line) << D.getCXXScopeSpec().getRange(); - PrevDecl = 0; + Previous.clear(); NewVD->setInvalidDecl(); } } else if (D.getCXXScopeSpec().isSet()) { @@ -2311,17 +2393,18 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, NewVD->setInvalidDecl(); } - CheckVariableDeclaration(NewVD, PrevDecl, Redeclaration); + CheckVariableDeclaration(NewVD, Previous, Redeclaration); // This is an explicit specialization of a static data member. Check it. if (isExplicitSpecialization && !NewVD->isInvalidDecl() && - CheckMemberSpecialization(NewVD, PrevDecl)) + CheckMemberSpecialization(NewVD, Previous)) NewVD->setInvalidDecl(); - + // attributes declared post-definition are currently ignored - if (PrevDecl) { - const VarDecl *Def = 0, *PrevVD = dyn_cast(PrevDecl); - if (PrevVD->getDefinition(Def) && D.hasAttributes()) { + if (Previous.isSingleResult()) { + const VarDecl *Def = 0; + VarDecl *PrevDecl = dyn_cast(Previous.getFoundDecl()); + if (PrevDecl && PrevDecl->getDefinition(Def) && D.hasAttributes()) { Diag(NewVD->getLocation(), diag::warn_attribute_precede_definition); Diag(Def->getLocation(), diag::note_previous_definition); } @@ -2331,7 +2414,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, // such variables. if (CurContext->isFunctionOrMethod() && NewVD->isExternC() && !NewVD->isInvalidDecl()) - RegisterLocallyScopedExternCDecl(NewVD, PrevDecl, S); + RegisterLocallyScopedExternCDecl(NewVD, Previous, S); return NewVD; } @@ -2346,7 +2429,8 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, /// that have been instantiated from a template. /// /// Sets NewVD->isInvalidDecl() if an error was encountered. -void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl, +void Sema::CheckVariableDeclaration(VarDecl *NewVD, + LookupResult &Previous, bool &Redeclaration) { // If the decl is already known invalid, don't check it. if (NewVD->isInvalidDecl()) @@ -2419,14 +2503,14 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl, NewVD->setType(FixedTy); } - if (!PrevDecl && NewVD->isExternC()) { + if (Previous.empty() && NewVD->isExternC()) { // Since we did not find anything by this name and we're declaring // an extern "C" variable, look for a non-visible extern "C" // declaration with the same name. llvm::DenseMap::iterator Pos = LocallyScopedExternalDecls.find(NewVD->getDeclName()); if (Pos != LocallyScopedExternalDecls.end()) - PrevDecl = Pos->second; + Previous.addDecl(Pos->second); } if (T->isVoidType() && !NewVD->hasExternalStorage()) { @@ -2445,18 +2529,12 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl, return NewVD->setInvalidDecl(); } - if (PrevDecl) { + if (!Previous.empty()) { Redeclaration = true; - MergeVarDecl(NewVD, PrevDecl); + MergeVarDecl(NewVD, Previous); } } -static bool isUsingDecl(Decl *D) { - return isa(D) || - isa(D) || - isa(D); -} - /// \brief Data used with FindOverriddenMethod struct FindOverriddenMethodData { Sema *S; @@ -2477,8 +2555,7 @@ static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier, Path.Decls.first != Path.Decls.second; ++Path.Decls.first) { if (CXXMethodDecl *MD = dyn_cast(*Path.Decls.first)) { - OverloadedFunctionDecl::function_iterator MatchedDecl; - if (MD->isVirtual() && !Data->S->IsOverload(Data->Method, MD, MatchedDecl)) + if (MD->isVirtual() && !Data->S->IsOverload(Data->Method, MD)) return true; } } @@ -2486,10 +2563,30 @@ static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier, return false; } +/// AddOverriddenMethods - See if a method overrides any in the base classes, +/// and if so, check that it's a valid override and remember it. +void Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { + // Look for virtual methods in base classes that this method might override. + CXXBasePaths Paths; + FindOverriddenMethodData Data; + Data.Method = MD; + Data.S = this; + if (DC->lookupInBases(&FindOverriddenMethod, &Data, Paths)) { + for (CXXBasePaths::decl_iterator I = Paths.found_decls_begin(), + E = Paths.found_decls_end(); I != E; ++I) { + if (CXXMethodDecl *OldMD = dyn_cast(*I)) { + if (!CheckOverridingFunctionReturnType(MD, OldMD) && + !CheckOverridingFunctionExceptionSpec(MD, OldMD)) + MD->addOverriddenMethod(OldMD); + } + } + } +} + NamedDecl* Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, DeclaratorInfo *DInfo, - NamedDecl* PrevDecl, + LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool IsFunctionDefinition, bool &Redeclaration) { assert(R.getTypePtr()->isFunctionType()); @@ -2554,10 +2651,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, FunctionDecl *NewFD; if (isFriend) { - // DC is the namespace in which the function is being declared. - assert((DC->isFileContext() || PrevDecl) && "previously-undeclared " - "friend function being created in a non-namespace context"); - // C++ [class.friend]p5 // A function can be defined in a friend declaration of a // class . . . . Such a function is implicitly inline. @@ -2733,37 +2826,29 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } } + // Filter out previous declarations that don't match the scope. + FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage()); + if (isFriend) { + // DC is the namespace in which the function is being declared. + assert((DC->isFileContext() || !Previous.empty()) && + "previously-undeclared friend function being created " + "in a non-namespace context"); + if (FunctionTemplate) { FunctionTemplate->setObjectOfFriendDecl( - /* PreviouslyDeclared= */ PrevDecl != NULL); + /* PreviouslyDeclared= */ !Previous.empty()); FunctionTemplate->setAccess(AS_public); } else - NewFD->setObjectOfFriendDecl(/* PreviouslyDeclared= */ PrevDecl != NULL); + NewFD->setObjectOfFriendDecl(/* PreviouslyDeclared= */ !Previous.empty()); NewFD->setAccess(AS_public); } - if (CXXMethodDecl *NewMD = dyn_cast(NewFD)) { - // Look for virtual methods in base classes that this method might override. - CXXBasePaths Paths; - FindOverriddenMethodData Data; - Data.Method = NewMD; - Data.S = this; - if (cast(DC)->lookupInBases(&FindOverriddenMethod, &Data, - Paths)) { - for (CXXBasePaths::decl_iterator I = Paths.found_decls_begin(), - E = Paths.found_decls_end(); I != E; ++I) { - if (CXXMethodDecl *OldMD = dyn_cast(*I)) { - if (!CheckOverridingFunctionReturnType(NewMD, OldMD) && - !CheckOverridingFunctionExceptionSpec(NewMD, OldMD)) - NewMD->addOverriddenMethod(OldMD); - } - } - } - } + if (CXXMethodDecl *NewMD = dyn_cast(NewFD)) + AddOverriddenMethods(cast(DC), NewMD); if (SC == FunctionDecl::Static && isa(NewFD) && !CurContext->isRecord()) { @@ -2847,14 +2932,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Finally, we know we have the right number of parameters, install them. NewFD->setParams(Context, Params.data(), Params.size()); - // If name lookup finds a previous declaration that is not in the - // same scope as the new declaration, this may still be an - // acceptable redeclaration. - if (PrevDecl && !isDeclInScope(PrevDecl, DC, S) && - !(NewFD->hasLinkage() && - isOutOfScopePreviousDeclaration(PrevDecl, DC, Context))) - PrevDecl = 0; - // If the declarator is a template-id, translate the parser's template // argument list into our AST format. bool HasExplicitTemplateArgs = false; @@ -2891,22 +2968,26 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, isFunctionTemplateSpecialization = true; } } - + if (isFunctionTemplateSpecialization) { if (CheckFunctionTemplateSpecialization(NewFD, HasExplicitTemplateArgs, LAngleLoc, TemplateArgs.data(), TemplateArgs.size(), RAngleLoc, - PrevDecl)) + Previous)) NewFD->setInvalidDecl(); } else if (isExplicitSpecialization && isa(NewFD) && - CheckMemberSpecialization(NewFD, PrevDecl)) + CheckMemberSpecialization(NewFD, Previous)) NewFD->setInvalidDecl(); // Perform semantic checking on the function declaration. bool OverloadableAttrRequired = false; // FIXME: HACK! - CheckFunctionDeclaration(NewFD, PrevDecl, isExplicitSpecialization, + CheckFunctionDeclaration(NewFD, Previous, isExplicitSpecialization, Redeclaration, /*FIXME:*/OverloadableAttrRequired); + assert((NewFD->isInvalidDecl() || !Redeclaration || + Previous.getResultKind() != LookupResult::FoundOverloaded) && + "previous declaration set still overloaded"); + if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) { // An out-of-line member function declaration must also be a // definition (C++ [dcl.meaning]p1). @@ -2918,7 +2999,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, Diag(NewFD->getLocation(), diag::err_out_of_line_declaration) << D.getCXXScopeSpec().getRange(); NewFD->setInvalidDecl(); - } else if (!Redeclaration && (!PrevDecl || !isUsingDecl(PrevDecl))) { + } else if (!Redeclaration) { // The user tried to provide an out-of-line definition for a // function that is a member of a class or namespace, but there // was no such member function declared (C++ [class.mfct]p2, @@ -2948,8 +3029,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, isNearlyMatchingFunction(Context, cast(*Func), NewFD)) Diag((*Func)->getLocation(), diag::note_member_def_close_match); } - - PrevDecl = 0; } } @@ -2960,8 +3039,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, ProcessDeclAttributes(S, NewFD, D); // attributes declared post-definition are currently ignored - if (Redeclaration && PrevDecl) { - const FunctionDecl *Def, *PrevFD = dyn_cast(PrevDecl); + if (Redeclaration && Previous.isSingleResult()) { + const FunctionDecl *Def; + FunctionDecl *PrevFD = dyn_cast(Previous.getFoundDecl()); if (PrevFD && PrevFD->getBody(Def) && D.hasAttributes()) { Diag(NewFD->getLocation(), diag::warn_attribute_precede_definition); Diag(Def->getLocation(), diag::note_previous_definition); @@ -2975,8 +3055,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // with that name must be marked "overloadable". Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing) << Redeclaration << NewFD; - if (PrevDecl) - Diag(PrevDecl->getLocation(), + if (!Previous.empty()) + Diag(Previous.getRepresentativeDecl()->getLocation(), diag::note_attribute_overloadable_prev_overload); NewFD->addAttr(::new (Context) OverloadableAttr()); } @@ -2985,7 +3065,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // map of such names. if (CurContext->isFunctionOrMethod() && NewFD->isExternC() && !NewFD->isInvalidDecl()) - RegisterLocallyScopedExternCDecl(NewFD, PrevDecl, S); + RegisterLocallyScopedExternCDecl(NewFD, Previous, S); // Set this FunctionDecl's range up to the right paren. NewFD->setLocEnd(D.getSourceRange().getEnd()); @@ -3013,7 +3093,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, /// an explicit specialization of the previous declaration. /// /// This sets NewFD->isInvalidDecl() to true if there was an error. -void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, +void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, + LookupResult &Previous, bool IsExplicitSpecialization, bool &Redeclaration, bool &OverloadableAttrRequired) { @@ -3032,27 +3113,26 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, CheckMain(NewFD); // Check for a previous declaration of this name. - if (!PrevDecl && NewFD->isExternC()) { + if (Previous.empty() && NewFD->isExternC()) { // Since we did not find anything by this name and we're declaring // an extern "C" function, look for a non-visible extern "C" // declaration with the same name. llvm::DenseMap::iterator Pos = LocallyScopedExternalDecls.find(NewFD->getDeclName()); if (Pos != LocallyScopedExternalDecls.end()) - PrevDecl = Pos->second; + Previous.addDecl(Pos->second); } // Merge or overload the declaration with an existing declaration of // the same name, if appropriate. - if (PrevDecl) { + if (!Previous.empty()) { // Determine whether NewFD is an overload of PrevDecl or // a declaration that requires merging. If it's an overload, // there's no more work to do here; we'll just add the new // function to the scope. - OverloadedFunctionDecl::function_iterator MatchedDecl; if (!getLangOptions().CPlusPlus && - AllowOverloadingOfFunction(PrevDecl, Context)) { + AllowOverloadingOfFunction(Previous, Context)) { OverloadableAttrRequired = true; // Functions marked "overloadable" must have a prototype (that @@ -3071,22 +3151,26 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, } } - if (PrevDecl && - (!AllowOverloadingOfFunction(PrevDecl, Context) || - !IsOverload(NewFD, PrevDecl, MatchedDecl)) && !isUsingDecl(PrevDecl)) { - Redeclaration = true; - Decl *OldDecl = PrevDecl; - - // If PrevDecl was an overloaded function, extract the - // FunctionDecl that matched. - if (isa(PrevDecl)) - OldDecl = *MatchedDecl; + NamedDecl *OldDecl = 0; + if (!Previous.empty()) { + if (!AllowOverloadingOfFunction(Previous, Context)) { + Redeclaration = true; + OldDecl = Previous.getFoundDecl(); + } else if (!IsOverload(NewFD, Previous, OldDecl)) { + if (!isUsingDecl(OldDecl)) + Redeclaration = true; + } + } + if (Redeclaration) { // NewFD and OldDecl represent declarations that need to be // merged. if (MergeFunctionDecl(NewFD, OldDecl)) return NewFD->setInvalidDecl(); + Previous.clear(); + Previous.addDecl(OldDecl); + if (FunctionTemplateDecl *OldTemplateDecl = dyn_cast(OldDecl)) { NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl()); @@ -4313,11 +4397,13 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, DeclContext *SearchDC = CurContext; DeclContext *DC = CurContext; - NamedDecl *PrevDecl = 0; bool isStdBadAlloc = false; bool Invalid = false; - RedeclarationKind Redecl = (RedeclarationKind) (TUK != TUK_Reference); + RedeclarationKind Redecl = (TUK != TUK_Reference ? ForRedeclaration + : NotForRedeclaration); + + LookupResult Previous(*this, Name, NameLoc, LookupTagName, Redecl); if (Name && SS.isNotEmpty()) { // We have a nested-name tag ('struct foo::bar'). @@ -4344,17 +4430,13 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, DC = computeDeclContext(SS, true); SearchDC = DC; // Look-up name inside 'foo::'. - LookupResult R(*this, Name, NameLoc, LookupTagName, Redecl); - LookupQualifiedName(R, DC); + LookupQualifiedName(Previous, DC); - if (R.isAmbiguous()) + if (Previous.isAmbiguous()) return DeclPtrTy(); - if (R.getResultKind() == LookupResult::Found) - PrevDecl = dyn_cast(R.getFoundDecl()); - // A tag 'foo::bar' must already exist. - if (!PrevDecl) { + if (Previous.empty()) { Diag(NameLoc, diag::err_not_tag_in_scope) << Name << SS.getRange(); Name = 0; Invalid = true; @@ -4366,19 +4448,11 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // FIXME: We're looking into outer scopes here, even when we // shouldn't be. Doing so can result in ambiguities that we // shouldn't be diagnosing. - LookupResult R(*this, Name, NameLoc, LookupTagName, Redecl); - LookupName(R, S); - if (R.isAmbiguous()) { - // FIXME: This is not best way to recover from case like: - // - // struct S s; - // - // causes needless "incomplete type" error later. - Name = 0; - PrevDecl = 0; - Invalid = true; - } else - PrevDecl = R.getAsSingleDecl(Context); + LookupName(Previous, S); + + // Note: there used to be some attempt at recovery here. + if (Previous.isAmbiguous()) + return DeclPtrTy(); if (!getLangOptions().CPlusPlus && TUK != TUK_Reference) { // FIXME: This makes sure that we ignore the contexts associated @@ -4390,11 +4464,12 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } } - if (PrevDecl && PrevDecl->isTemplateParameter()) { + if (Previous.isSingleResult() && + Previous.getFoundDecl()->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. - DiagnoseTemplateParameterShadow(NameLoc, PrevDecl); + DiagnoseTemplateParameterShadow(NameLoc, Previous.getFoundDecl()); // Just pretend that we didn't see the previous declaration. - PrevDecl = 0; + Previous.clear(); } if (getLangOptions().CPlusPlus && Name && DC && StdNamespace && @@ -4402,15 +4477,17 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // This is a declaration of or a reference to "std::bad_alloc". isStdBadAlloc = true; - if (!PrevDecl && StdBadAlloc) { + if (Previous.empty() && StdBadAlloc) { // std::bad_alloc has been implicitly declared (but made invisible to // name lookup). Fill in this implicit declaration as the previous // declaration, so that the declarations get chained appropriately. - PrevDecl = StdBadAlloc; + Previous.addDecl(StdBadAlloc); } } - - if (PrevDecl) { + + if (!Previous.empty()) { + assert(Previous.isSingleResult()); + NamedDecl *PrevDecl = Previous.getFoundDecl(); if (TagDecl *PrevTagDecl = dyn_cast(PrevDecl)) { // If this is a use of a previous tag, or if the tag is already declared // in the same scope (so that the definition/declaration completes or @@ -4430,14 +4507,14 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, PrevTagDecl->getKindName()); else Diag(KWLoc, diag::err_use_with_wrong_tag) << Name; - Diag(PrevDecl->getLocation(), diag::note_previous_use); + Diag(PrevTagDecl->getLocation(), diag::note_previous_use); if (SafeToContinue) Kind = PrevTagDecl->getTagKind(); else { // Recover by making this an anonymous redefinition. Name = 0; - PrevDecl = 0; + Previous.clear(); Invalid = true; } } @@ -4450,7 +4527,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // For our current ASTs this shouldn't be a problem, but will // need to be changed with DeclGroups. if (TUK == TUK_Reference || TUK == TUK_Friend) - return DeclPtrTy::make(PrevDecl); + return DeclPtrTy::make(PrevTagDecl); // Diagnose attempts to redefine a tag. if (TUK == TUK_Definition) { @@ -4468,7 +4545,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // struct be anonymous, which will make any later // references get the previous definition. Name = 0; - PrevDecl = 0; + Previous.clear(); Invalid = true; } } else { @@ -4480,7 +4557,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, Diag(PrevTagDecl->getLocation(), diag::note_previous_definition); Name = 0; - PrevDecl = 0; + Previous.clear(); Invalid = true; } } @@ -4497,7 +4574,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // scope, e.g. "struct foo; void bar() { struct foo; }", just create a // new decl/type. We set PrevDecl to NULL so that the entities // have distinct types. - PrevDecl = 0; + Previous.clear(); } // If we get here, we're going to create a new Decl. If PrevDecl // is non-NULL, it's a definition of the tag declared by @@ -4511,12 +4588,12 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, Diag(NameLoc, diag::err_redefinition_different_kind) << Name; Diag(PrevDecl->getLocation(), diag::note_previous_definition); Name = 0; - PrevDecl = 0; + Previous.clear(); Invalid = true; } else { // The existing declaration isn't relevant to us; we're in a // new scope, so clear out the previous declaration. - PrevDecl = 0; + Previous.clear(); } } } else if (TUK == TUK_Reference && SS.isEmpty() && Name && @@ -4570,6 +4647,10 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, CreateNewDecl: + TagDecl *PrevDecl = 0; + if (Previous.isSingleResult()) + PrevDecl = cast(Previous.getFoundDecl()); + // If there is an identifier, use the location of the identifier as the // location of the decl, otherwise use the location of the struct/union // keyword. @@ -4651,7 +4732,7 @@ CreateNewDecl: // If this is a specialization of a member class (of a class template), // check the specialization. - if (isExplicitSpecialization && CheckMemberSpecialization(New, PrevDecl)) + if (isExplicitSpecialization && CheckMemberSpecialization(New, Previous)) Invalid = true; if (Invalid) @@ -4671,7 +4752,7 @@ CreateNewDecl: // Mark this as a friend decl if applicable. if (TUK == TUK_Friend) - New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ PrevDecl != NULL); + New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ !Previous.empty()); // Set the access specifier. if (!Invalid && TUK != TUK_Friend) diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 237a869..bda1a69 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -4668,7 +4668,8 @@ Sema::ActOnFriendFunctionDecl(Scope *S, // FIXME: handle local classes // Recover from invalid scope qualifiers as if they just weren't there. - NamedDecl *PrevDecl = 0; + LookupResult Previous(*this, Name, D.getIdentifierLoc(), LookupOrdinaryName, + ForRedeclaration); if (!ScopeQual.isInvalid() && ScopeQual.isSet()) { // FIXME: RequireCompleteDeclContext DC = computeDeclContext(ScopeQual); @@ -4676,15 +4677,15 @@ Sema::ActOnFriendFunctionDecl(Scope *S, // FIXME: handle dependent contexts if (!DC) return DeclPtrTy(); - LookupResult R(*this, Name, Loc, LookupOrdinaryName, ForRedeclaration); - LookupQualifiedName(R, DC); - PrevDecl = R.getAsSingleDecl(Context); + LookupQualifiedName(Previous, DC); // If searching in that context implicitly found a declaration in // a different context, treat it like it wasn't found at all. // TODO: better diagnostics for this case. Suggesting the right // qualified scope would be nice... - if (!PrevDecl || !PrevDecl->getDeclContext()->Equals(DC)) { + // FIXME: getRepresentativeDecl() is not right here at all + if (Previous.empty() || + !Previous.getRepresentativeDecl()->getDeclContext()->Equals(DC)) { D.setInvalidType(); Diag(Loc, diag::err_qualified_friend_not_found) << Name << T; return DeclPtrTy(); @@ -4711,12 +4712,10 @@ Sema::ActOnFriendFunctionDecl(Scope *S, while (DC->isRecord()) DC = DC->getParent(); - LookupResult R(*this, Name, Loc, LookupOrdinaryName, ForRedeclaration); - LookupQualifiedName(R, DC); - PrevDecl = R.getAsSingleDecl(Context); + LookupQualifiedName(Previous, DC); // TODO: decide what we think about using declarations. - if (PrevDecl) + if (!Previous.empty()) break; if (DC->isFileContext()) break; @@ -4728,7 +4727,8 @@ Sema::ActOnFriendFunctionDecl(Scope *S, // C++0x changes this for both friend types and functions. // Most C++ 98 compilers do seem to give an error here, so // we do, too. - if (PrevDecl && DC->Equals(CurContext) && !getLangOptions().CPlusPlus0x) + if (!Previous.empty() && DC->Equals(CurContext) + && !getLangOptions().CPlusPlus0x) Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member); } @@ -4745,7 +4745,7 @@ Sema::ActOnFriendFunctionDecl(Scope *S, } bool Redeclaration = false; - NamedDecl *ND = ActOnFunctionDeclarator(S, D, DC, T, DInfo, PrevDecl, + NamedDecl *ND = ActOnFunctionDeclarator(S, D, DC, T, DInfo, Previous, move(TemplateParams), IsDefinition, Redeclaration); diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 0c5569c..7da37af 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -828,9 +828,10 @@ void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl, for (ObjCMethodDecl::param_iterator IM = ImpMethodDecl->param_begin(), IF = IntfMethodDecl->param_begin(), EM = ImpMethodDecl->param_end(); IM != EM; ++IM, ++IF) { - if (Context.typesAreCompatible((*IF)->getType(), (*IM)->getType()) || - Context.QualifiedIdConformsQualifiedId((*IF)->getType(), - (*IM)->getType())) + QualType ParmDeclTy = (*IF)->getType().getUnqualifiedType(); + QualType ParmImpTy = (*IM)->getType().getUnqualifiedType(); + if (Context.typesAreCompatible(ParmDeclTy, ParmImpTy) || + Context.QualifiedIdConformsQualifiedId(ParmDeclTy, ParmImpTy)) continue; Diag((*IM)->getLocation(), diag::warn_conflicting_param_types) diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 0eea169..462bf13 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1445,6 +1445,12 @@ QualType Sema::CheckPointerToMemberOperands( } } + if (isa(rex->IgnoreParens())) { + // Diagnose use of pointer-to-member type which when used as + // the functional cast in a pointer-to-member expression. + Diag(Loc, diag::err_pointer_to_member_type) << isIndirect; + return QualType(); + } // C++ 5.5p2 // The result is an object or a function of the type specified by the // second operand. diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 1f49b78..1957d7f 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -246,7 +246,11 @@ void LookupResult::resolveKind() { unsigned N = Decls.size(); // Fast case: no possible ambiguity. - if (N == 0) return; + if (N == 0) { + assert(ResultKind == NotFound); + return; + } + if (N == 1) { if (isa(Decls[0])) ResultKind = FoundUnresolvedValue; diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index adcd977..daf5b7f 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -284,100 +284,102 @@ void ImplicitConversionSequence::DebugPrint() const { // signature), IsOverload returns false and MatchedDecl will be set to // point to the FunctionDecl for #2. bool -Sema::IsOverload(FunctionDecl *New, Decl* OldD, - OverloadedFunctionDecl::function_iterator& MatchedDecl) { - if (OverloadedFunctionDecl* Ovl = dyn_cast(OldD)) { - // Is this new function an overload of every function in the - // overload set? - OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(), - FuncEnd = Ovl->function_end(); - for (; Func != FuncEnd; ++Func) { - if (!IsOverload(New, *Func, MatchedDecl)) { - MatchedDecl = Func; +Sema::IsOverload(FunctionDecl *New, LookupResult &Previous, NamedDecl *&Match) { + for (LookupResult::iterator I = Previous.begin(), E = Previous.end(); + I != E; ++I) { + NamedDecl *Old = (*I)->getUnderlyingDecl(); + if (FunctionTemplateDecl *OldT = dyn_cast(Old)) { + if (!IsOverload(New, OldT->getTemplatedDecl())) { + Match = Old; return false; } + } else if (FunctionDecl *OldF = dyn_cast(Old)) { + if (!IsOverload(New, OldF)) { + Match = Old; + return false; + } + } else { + // (C++ 13p1): + // Only function declarations can be overloaded; object and type + // declarations cannot be overloaded. + Match = Old; + return false; } + } - // This function overloads every function in the overload set. - return true; - } else if (FunctionTemplateDecl *Old = dyn_cast(OldD)) - return IsOverload(New, Old->getTemplatedDecl(), MatchedDecl); - else if (FunctionDecl* Old = dyn_cast(OldD)) { - FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate(); - FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate(); - - // C++ [temp.fct]p2: - // A function template can be overloaded with other function templates - // and with normal (non-template) functions. - if ((OldTemplate == 0) != (NewTemplate == 0)) - return true; + return true; +} - // Is the function New an overload of the function Old? - QualType OldQType = Context.getCanonicalType(Old->getType()); - QualType NewQType = Context.getCanonicalType(New->getType()); +bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old) { + FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate(); + FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate(); - // Compare the signatures (C++ 1.3.10) of the two functions to - // determine whether they are overloads. If we find any mismatch - // in the signature, they are overloads. + // C++ [temp.fct]p2: + // A function template can be overloaded with other function templates + // and with normal (non-template) functions. + if ((OldTemplate == 0) != (NewTemplate == 0)) + return true; - // If either of these functions is a K&R-style function (no - // prototype), then we consider them to have matching signatures. - if (isa(OldQType.getTypePtr()) || - isa(NewQType.getTypePtr())) - return false; + // Is the function New an overload of the function Old? + QualType OldQType = Context.getCanonicalType(Old->getType()); + QualType NewQType = Context.getCanonicalType(New->getType()); - FunctionProtoType* OldType = cast(OldQType); - FunctionProtoType* NewType = cast(NewQType); - - // The signature of a function includes the types of its - // parameters (C++ 1.3.10), which includes the presence or absence - // of the ellipsis; see C++ DR 357). - if (OldQType != NewQType && - (OldType->getNumArgs() != NewType->getNumArgs() || - OldType->isVariadic() != NewType->isVariadic() || - !std::equal(OldType->arg_type_begin(), OldType->arg_type_end(), - NewType->arg_type_begin()))) - return true; + // Compare the signatures (C++ 1.3.10) of the two functions to + // determine whether they are overloads. If we find any mismatch + // in the signature, they are overloads. - // C++ [temp.over.link]p4: - // The signature of a function template consists of its function - // signature, its return type and its template parameter list. The names - // of the template parameters are significant only for establishing the - // relationship between the template parameters and the rest of the - // signature. - // - // We check the return type and template parameter lists for function - // templates first; the remaining checks follow. - if (NewTemplate && - (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(), - OldTemplate->getTemplateParameters(), - false, TPL_TemplateMatch) || - OldType->getResultType() != NewType->getResultType())) - return true; + // If either of these functions is a K&R-style function (no + // prototype), then we consider them to have matching signatures. + if (isa(OldQType.getTypePtr()) || + isa(NewQType.getTypePtr())) + return false; - // If the function is a class member, its signature includes the - // cv-qualifiers (if any) on the function itself. - // - // As part of this, also check whether one of the member functions - // is static, in which case they are not overloads (C++ - // 13.1p2). While not part of the definition of the signature, - // this check is important to determine whether these functions - // can be overloaded. - CXXMethodDecl* OldMethod = dyn_cast(Old); - CXXMethodDecl* NewMethod = dyn_cast(New); - if (OldMethod && NewMethod && - !OldMethod->isStatic() && !NewMethod->isStatic() && - OldMethod->getTypeQualifiers() != NewMethod->getTypeQualifiers()) - return true; + FunctionProtoType* OldType = cast(OldQType); + FunctionProtoType* NewType = cast(NewQType); + + // The signature of a function includes the types of its + // parameters (C++ 1.3.10), which includes the presence or absence + // of the ellipsis; see C++ DR 357). + if (OldQType != NewQType && + (OldType->getNumArgs() != NewType->getNumArgs() || + OldType->isVariadic() != NewType->isVariadic() || + !std::equal(OldType->arg_type_begin(), OldType->arg_type_end(), + NewType->arg_type_begin()))) + return true; - // The signatures match; this is not an overload. - return false; - } else { - // (C++ 13p1): - // Only function declarations can be overloaded; object and type - // declarations cannot be overloaded. - return false; - } + // C++ [temp.over.link]p4: + // The signature of a function template consists of its function + // signature, its return type and its template parameter list. The names + // of the template parameters are significant only for establishing the + // relationship between the template parameters and the rest of the + // signature. + // + // We check the return type and template parameter lists for function + // templates first; the remaining checks follow. + if (NewTemplate && + (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(), + OldTemplate->getTemplateParameters(), + false, TPL_TemplateMatch) || + OldType->getResultType() != NewType->getResultType())) + return true; + + // If the function is a class member, its signature includes the + // cv-qualifiers (if any) on the function itself. + // + // As part of this, also check whether one of the member functions + // is static, in which case they are not overloads (C++ + // 13.1p2). While not part of the definition of the signature, + // this check is important to determine whether these functions + // can be overloaded. + CXXMethodDecl* OldMethod = dyn_cast(Old); + CXXMethodDecl* NewMethod = dyn_cast(New); + if (OldMethod && NewMethod && + !OldMethod->isStatic() && !NewMethod->isStatic() && + OldMethod->getTypeQualifiers() != NewMethod->getTypeQualifiers()) + return true; + + // The signatures match; this is not an overload. + return false; } /// TryImplicitConversion - Attempt to perform an implicit conversion @@ -1545,18 +1547,23 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion( } bool -Sema::DiagnoseAmbiguousUserDefinedConversion(Expr *From, QualType ToType) { +Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) { ImplicitConversionSequence ICS; OverloadCandidateSet CandidateSet; OverloadingResult OvResult = IsUserDefinedConversion(From, ToType, ICS.UserDefined, CandidateSet, true, false, false); - if (OvResult != OR_Ambiguous) + if (OvResult == OR_Ambiguous) + Diag(From->getSourceRange().getBegin(), + diag::err_typecheck_ambiguous_condition) + << From->getType() << ToType << From->getSourceRange(); + else if (OvResult == OR_No_Viable_Function && !CandidateSet.empty()) + Diag(From->getSourceRange().getBegin(), + diag::err_typecheck_nonviable_condition) + << From->getType() << ToType << From->getSourceRange(); + else return false; - Diag(From->getSourceRange().getBegin(), - diag::err_typecheck_ambiguous_condition) - << From->getType() << ToType << From->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); return true; } @@ -2072,7 +2079,7 @@ bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType, if (!PerformImplicitConversion(From, ToType, Flavor, /*AllowExplicit=*/false, Elidable)) return false; - if (!DiagnoseAmbiguousUserDefinedConversion(From, ToType)) + if (!DiagnoseMultipleUserDefinedConversion(From, ToType)) return Diag(From->getSourceRange().getBegin(), diag::err_typecheck_convert_incompatible) << ToType << From->getType() << Flavor << From->getSourceRange(); @@ -2085,8 +2092,11 @@ bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType, ImplicitConversionSequence Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) { QualType ClassType = Context.getTypeDeclType(Method->getParent()); - QualType ImplicitParamType - = Context.getCVRQualifiedType(ClassType, Method->getTypeQualifiers()); + // [class.dtor]p2: A destructor can be invoked for a const, volatile or + // const volatile object. + unsigned Quals = isa(Method) ? + Qualifiers::Const | Qualifiers::Volatile : Method->getTypeQualifiers(); + QualType ImplicitParamType = Context.getCVRQualifiedType(ClassType, Quals); // Set up the conversion sequence as a "bad" conversion, to allow us // to exit early. @@ -2101,7 +2111,7 @@ Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) { assert(FromType->isRecordType()); - // The implicit object parmeter is has the type "reference to cv X", + // The implicit object parameter is has the type "reference to cv X", // where X is the class of which the function is a member // (C++ [over.match.funcs]p4). However, when finding an implicit // conversion sequence for the argument, we are not allowed to @@ -2192,7 +2202,7 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) { if (!PerformImplicitConversion(From, Context.BoolTy, ICS, "converting")) return false; - if (!DiagnoseAmbiguousUserDefinedConversion(From, Context.BoolTy)) + if (!DiagnoseMultipleUserDefinedConversion(From, Context.BoolTy)) return Diag(From->getSourceRange().getBegin(), diag::err_typecheck_bool_condition) << From->getType() << From->getSourceRange(); @@ -3017,6 +3027,12 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty, assert(PointerTy && "type was not a pointer type!"); QualType PointeeTy = PointerTy->getPointeeType(); + // Don't add qualified variants of arrays. For one, they're not allowed + // (the qualifier would sink to the element type), and for another, the + // only overload situation where it matters is subscript or pointer +- int, + // and those shouldn't have qualifier variants anyway. + if (PointeeTy->isArrayType()) + return true; unsigned BaseCVR = PointeeTy.getCVRQualifiers(); if (const ConstantArrayType *Array =Context.getAsConstantArrayType(PointeeTy)) BaseCVR = Array->getElementType().getCVRQualifiers(); @@ -3057,6 +3073,12 @@ BuiltinCandidateTypeSet::AddMemberPointerWithMoreQualifiedTypeVariants( assert(PointerTy && "type was not a member pointer type!"); QualType PointeeTy = PointerTy->getPointeeType(); + // Don't add qualified variants of arrays. For one, they're not allowed + // (the qualifier would sink to the element type), and for another, the + // only overload situation where it matters is subscript or pointer +- int, + // and those shouldn't have qualifier variants anyway. + if (PointeeTy->isArrayType()) + return true; const Type *ClassTy = PointerTy->getClass(); // Iterate through all strict supersets of the pointee type's CVR @@ -4873,11 +4895,13 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, if (Opc == BinaryOperator::PtrMemD) return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); - // If this is one of the assignment operators, we only perform - // overload resolution if the left-hand side is a class or - // enumeration type (C++ [expr.ass]p3). - if (Opc >= BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign && - !Args[0]->getType()->isOverloadableType()) + // If this is the assignment operator, we only perform overload resolution + // if the left-hand side is a class or enumeration type. This is actually + // a hack. The standard requires that we do overload resolution between the + // various built-in candidates, but as DR507 points out, this can lead to + // problems. So we do it this way, which pretty much follows what GCC does. + // Note that we go the traditional code path for compound assignment forms. + if (Opc==BinaryOperator::Assign && !Args[0]->getType()->isOverloadableType()) return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); // Build an empty overload set. diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 466a0e3..31cd300 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3538,15 +3538,17 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, SourceLocation RAngleLoc, - NamedDecl *&PrevDecl) { + LookupResult &Previous) { // The set of function template specializations that could match this // explicit function template specialization. typedef llvm::SmallVector CandidateSet; CandidateSet Candidates; DeclContext *FDLookupContext = FD->getDeclContext()->getLookupContext(); - for (OverloadIterator Ovl(PrevDecl), OvlEnd; Ovl != OvlEnd; ++Ovl) { - if (FunctionTemplateDecl *FunTmpl = dyn_cast(*Ovl)) { + for (LookupResult::iterator I = Previous.begin(), E = Previous.end(); + I != E; ++I) { + NamedDecl *Ovl = (*I)->getUnderlyingDecl(); + if (FunctionTemplateDecl *FunTmpl = dyn_cast(Ovl)) { // Only consider templates found within the same semantic lookup scope as // FD. if (!FDLookupContext->Equals(Ovl->getDeclContext()->getLookupContext())) @@ -3637,7 +3639,8 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // The "previous declaration" for this function template specialization is // the prior function template specialization. - PrevDecl = Specialization; + Previous.clear(); + Previous.addDecl(Specialization); return false; } @@ -3652,10 +3655,11 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, /// \param Member the member declaration, which will be updated to become a /// specialization. /// -/// \param PrevDecl the set of declarations, one of which may be specialized -/// by this function specialization. +/// \param Previous the set of declarations, one of which may be specialized +/// by this function specialization; the set will be modified to contain the +/// redeclared member. bool -Sema::CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl) { +Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { assert(!isa(Member) && "Only for non-template members"); // Try to find the member we are instantiating. @@ -3663,11 +3667,13 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl) { NamedDecl *InstantiatedFrom = 0; MemberSpecializationInfo *MSInfo = 0; - if (!PrevDecl) { + if (Previous.empty()) { // Nowhere to look anyway. } else if (FunctionDecl *Function = dyn_cast(Member)) { - for (OverloadIterator Ovl(PrevDecl), OvlEnd; Ovl != OvlEnd; ++Ovl) { - if (CXXMethodDecl *Method = dyn_cast(*Ovl)) { + for (LookupResult::iterator I = Previous.begin(), E = Previous.end(); + I != E; ++I) { + NamedDecl *D = (*I)->getUnderlyingDecl(); + if (CXXMethodDecl *Method = dyn_cast(D)) { if (Context.hasSameType(Function->getType(), Method->getType())) { Instantiation = Method; InstantiatedFrom = Method->getInstantiatedFromMemberFunction(); @@ -3677,15 +3683,19 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl) { } } } else if (isa(Member)) { - if (VarDecl *PrevVar = dyn_cast(PrevDecl)) + VarDecl *PrevVar; + if (Previous.isSingleResult() && + (PrevVar = dyn_cast(Previous.getFoundDecl()))) if (PrevVar->isStaticDataMember()) { - Instantiation = PrevDecl; + Instantiation = PrevVar; InstantiatedFrom = PrevVar->getInstantiatedFromStaticDataMember(); MSInfo = PrevVar->getMemberSpecializationInfo(); } } else if (isa(Member)) { - if (CXXRecordDecl *PrevRecord = dyn_cast(PrevDecl)) { - Instantiation = PrevDecl; + CXXRecordDecl *PrevRecord; + if (Previous.isSingleResult() && + (PrevRecord = dyn_cast(Previous.getFoundDecl()))) { + Instantiation = PrevRecord; InstantiatedFrom = PrevRecord->getInstantiatedFromMemberClass(); MSInfo = PrevRecord->getMemberSpecializationInfo(); } @@ -3774,7 +3784,8 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl) { // Save the caller the trouble of having to figure out which declaration // this specialization matches. - PrevDecl = Instantiation; + Previous.clear(); + Previous.addDecl(Instantiation); return false; } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 7e618cd..3f40ffc 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -175,7 +175,10 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // FIXME: In theory, we could have a previous declaration for variables that // are not static data members. bool Redeclaration = false; - SemaRef.CheckVariableDeclaration(Var, 0, Redeclaration); + // FIXME: having to fake up a LookupResult is dumb. + LookupResult Previous(SemaRef, Var->getDeclName(), Var->getLocation(), + Sema::LookupOrdinaryName); + SemaRef.CheckVariableDeclaration(Var, Previous, Redeclaration); if (D->isOutOfLine()) { D->getLexicalDeclContext()->addDecl(Var); @@ -680,27 +683,24 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { bool Redeclaration = false; bool OverloadableAttrRequired = false; - NamedDecl *PrevDecl = 0; + LookupResult Previous(SemaRef, Function->getDeclName(), SourceLocation(), + Sema::LookupOrdinaryName, Sema::ForRedeclaration); + if (TemplateParams || !FunctionTemplate) { // Look only into the namespace where the friend would be declared to // find a previous declaration. This is the innermost enclosing namespace, // as described in ActOnFriendFunctionDecl. - LookupResult R(SemaRef, Function->getDeclName(), SourceLocation(), - Sema::LookupOrdinaryName, - Sema::ForRedeclaration); - SemaRef.LookupQualifiedName(R, DC); + SemaRef.LookupQualifiedName(Previous, DC); - PrevDecl = R.getAsSingleDecl(SemaRef.Context); - // In C++, the previous declaration we find might be a tag type // (class or enum). In this case, the new declaration will hide the // tag type. Note that this does does not apply if we're declaring a // typedef (C++ [dcl.typedef]p4). - if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag) - PrevDecl = 0; + if (Previous.isSingleTagDecl()) + Previous.clear(); } - SemaRef.CheckFunctionDeclaration(Function, PrevDecl, false, Redeclaration, + SemaRef.CheckFunctionDeclaration(Function, Previous, false, Redeclaration, /*FIXME:*/OverloadableAttrRequired); // If the original function was part of a friend declaration, @@ -709,6 +709,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { = TemplateParams? cast(D->getDescribedFunctionTemplate()) : D; if (FromFriendD->getFriendObjectKind()) { NamedDecl *ToFriendD = 0; + NamedDecl *PrevDecl; if (TemplateParams) { ToFriendD = cast(FunctionTemplate); PrevDecl = FunctionTemplate->getPreviousDeclaration(); @@ -843,32 +844,31 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, if (InitMethodInstantiation(Method, D)) Method->setInvalidDecl(); - NamedDecl *PrevDecl = 0; + LookupResult Previous(SemaRef, Name, SourceLocation(), + Sema::LookupOrdinaryName, Sema::ForRedeclaration); if (!FunctionTemplate || TemplateParams) { - LookupResult R(SemaRef, Name, SourceLocation(), - Sema::LookupOrdinaryName, - Sema::ForRedeclaration); - SemaRef.LookupQualifiedName(R, Owner); - PrevDecl = R.getAsSingleDecl(SemaRef.Context); + SemaRef.LookupQualifiedName(Previous, Owner); // In C++, the previous declaration we find might be a tag type // (class or enum). In this case, the new declaration will hide the // tag type. Note that this does does not apply if we're declaring a // typedef (C++ [dcl.typedef]p4). - if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag) - PrevDecl = 0; + if (Previous.isSingleTagDecl()) + Previous.clear(); } bool Redeclaration = false; bool OverloadableAttrRequired = false; - SemaRef.CheckFunctionDeclaration(Method, PrevDecl, false, Redeclaration, + SemaRef.CheckFunctionDeclaration(Method, Previous, false, Redeclaration, /*FIXME:*/OverloadableAttrRequired); - if (!FunctionTemplate && (!Method->isInvalidDecl() || !PrevDecl) && + if (!FunctionTemplate && (!Method->isInvalidDecl() || Previous.empty()) && !Method->getFriendObjectKind()) Owner->addDecl(Method); + SemaRef.AddOverriddenMethods(Record, Method); + return Method; } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 2bee32a..ca680c2 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -3037,18 +3037,21 @@ TreeTransform::TransformCompoundStmt(CompoundStmt *S, template Sema::OwningStmtResult TreeTransform::TransformCaseStmt(CaseStmt *S) { - // The case value expressions are not potentially evaluated. - EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); + OwningExprResult LHS(SemaRef), RHS(SemaRef); + { + // The case value expressions are not potentially evaluated. + EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); - // Transform the left-hand case value. - OwningExprResult LHS = getDerived().TransformExpr(S->getLHS()); - if (LHS.isInvalid()) - return SemaRef.StmtError(); + // Transform the left-hand case value. + LHS = getDerived().TransformExpr(S->getLHS()); + if (LHS.isInvalid()) + return SemaRef.StmtError(); - // Transform the right-hand case value (for the GNU case-range extension). - OwningExprResult RHS = getDerived().TransformExpr(S->getRHS()); - if (RHS.isInvalid()) - return SemaRef.StmtError(); + // Transform the right-hand case value (for the GNU case-range extension). + RHS = getDerived().TransformExpr(S->getRHS()); + if (RHS.isInvalid()) + return SemaRef.StmtError(); + } // Build the case statement. // Case statements are always rebuilt so that they will attached to their -- cgit v1.1