diff options
author | Roman Divacky <rdivacky@FreeBSD.org> | 2009-11-05 17:18:09 +0000 |
---|---|---|
committer | Roman Divacky <rdivacky@FreeBSD.org> | 2009-11-05 17:18:09 +0000 |
commit | 8f57cb0305232cb53fff00ef151ca716766f3437 (patch) | |
tree | 8b316eca843681b024034db1125707173b9adb4a /lib | |
parent | 51fb8b013e7734b795139f49d3b1f77c539be20a (diff) | |
download | src-8f57cb0305232cb53fff00ef151ca716766f3437.tar.gz src-8f57cb0305232cb53fff00ef151ca716766f3437.zip |
Update clang to r86140.
Notes
Notes:
svn path=/vendor/clang/dist/; revision=198954
Diffstat (limited to 'lib')
38 files changed, 838 insertions, 708 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index aef3d2989415..8562249479ca 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1374,7 +1374,7 @@ QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) { // If the pointee or class type isn't canonical, this won't be a canonical // type either, so fill in the canonical type field. QualType Canonical; - if (!T.isCanonical()) { + if (!T.isCanonical() || !Cls->isCanonicalUnqualified()) { Canonical = getMemberPointerType(getCanonicalType(T),getCanonicalType(Cls)); // Get the new insert position for the node we care about. @@ -1395,7 +1395,8 @@ QualType ASTContext::getConstantArrayType(QualType EltTy, const llvm::APInt &ArySizeIn, ArrayType::ArraySizeModifier ASM, unsigned EltTypeQuals) { - assert((EltTy->isDependentType() || EltTy->isConstantSizeType()) && + assert((EltTy->isDependentType() || + EltTy->isIncompleteType() || EltTy->isConstantSizeType()) && "Constant array of VLAs is illegal!"); // Convert the array size into a canonical width matching the pointer size for diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 56a597570dd0..8664c508615f 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/DeclarationName.h" #include "clang/AST/Type.h" +#include "clang/AST/TypeOrdering.h" #include "clang/AST/Decl.h" #include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/DenseMap.h" @@ -49,11 +50,50 @@ public: }; bool operator<(DeclarationName LHS, DeclarationName RHS) { - if (IdentifierInfo *LhsId = LHS.getAsIdentifierInfo()) - if (IdentifierInfo *RhsId = RHS.getAsIdentifierInfo()) - return LhsId->getName() < RhsId->getName(); - - return LHS.getAsOpaqueInteger() < RHS.getAsOpaqueInteger(); + if (LHS.getNameKind() != RHS.getNameKind()) + return LHS.getNameKind() < RHS.getNameKind(); + + switch (LHS.getNameKind()) { + case DeclarationName::Identifier: + return LHS.getAsIdentifierInfo()->getName() < + RHS.getAsIdentifierInfo()->getName(); + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: { + Selector LHSSelector = LHS.getObjCSelector(); + Selector RHSSelector = RHS.getObjCSelector(); + for (unsigned I = 0, + N = std::min(LHSSelector.getNumArgs(), RHSSelector.getNumArgs()); + I != N; ++I) { + IdentifierInfo *LHSId = LHSSelector.getIdentifierInfoForSlot(I); + IdentifierInfo *RHSId = RHSSelector.getIdentifierInfoForSlot(I); + if (!LHSId || !RHSId) + return LHSId && !RHSId; + + switch (LHSId->getName().compare(RHSId->getName())) { + case -1: return true; + case 1: return false; + default: break; + } + } + + return LHSSelector.getNumArgs() < RHSSelector.getNumArgs(); + } + + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + return QualTypeOrdering()(LHS.getCXXNameType(), RHS.getCXXNameType()); + + case DeclarationName::CXXOperatorName: + return LHS.getCXXOverloadedOperator() < RHS.getCXXOverloadedOperator(); + + case DeclarationName::CXXUsingDirective: + return false; + } + + return false; } } // end namespace clang diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 0b159c3a7bd8..021c53e9514f 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -174,9 +174,24 @@ void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) { LayoutBaseNonVirtually(RD, true); } -void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, +uint64_t ASTRecordLayoutBuilder::getBaseOffset(const CXXRecordDecl *Base) { + for (size_t i = 0; i < Bases.size(); ++i) { + if (Bases[i].first == Base) + return Bases[i].second; + } + for (size_t i = 0; i < VBases.size(); ++i) { + if (VBases[i].first == Base) + return VBases[i].second; + } + assert(0 && "missing base"); + return 0; +} + + +void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *Class, + const CXXRecordDecl *RD, const CXXRecordDecl *PB, - int64_t Offset, + uint64_t Offset, llvm::SmallSet<const CXXRecordDecl*, 32> &mark, llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary) { for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), @@ -185,20 +200,7 @@ void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, "Cannot layout class with dependent bases."); const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); -#if 0 - const ASTRecordLayout &L = Ctx.getASTRecordLayout(Base); - const CXXRecordDecl *PB = L.getPrimaryBase(); - if (PB && L.getPrimaryBaseWasVirtual() - && IndirectPrimary.count(PB)) { - int64_t BaseOffset; - // FIXME: calculate this. - BaseOffset = (1<<63) | (1<<31); - VBases.push_back(PB); - VBaseOffsets.push_back(BaseOffset); - } -#endif - int64_t BaseOffset = Offset;; - // FIXME: Calculate BaseOffset. + uint64_t BaseOffset = Offset; if (i->isVirtual()) { if (Base == PB) { // Only lay things out once. @@ -220,11 +222,20 @@ void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, LayoutVirtualBase(Base); BaseOffset = VBases.back().second; } + } else { + if (RD == Class) + BaseOffset = getBaseOffset(Base); + else { + const ASTRecordLayout &Layout + = Ctx.getASTRecordLayout(RD); + BaseOffset = Offset + Layout.getBaseClassOffset(Base); + } } + if (Base->getNumVBases()) { const ASTRecordLayout &L = Ctx.getASTRecordLayout(Base); const CXXRecordDecl *PB = L.getPrimaryBase(); - LayoutVirtualBases(Base, PB, BaseOffset, mark, IndirectPrimary); + LayoutVirtualBases(Class, Base, PB, BaseOffset, mark, IndirectPrimary); } } } @@ -295,7 +306,7 @@ bool ASTRecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD, const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD); uint64_t NumElements = Ctx.getConstantArrayElementCount(AT); - unsigned ElementOffset = Offset; + uint64_t ElementOffset = Offset; for (uint64_t I = 0; I != NumElements; ++I) { if (!canPlaceRecordAtOffset(RD, ElementOffset)) return false; @@ -366,7 +377,7 @@ ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD, const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD); uint64_t NumElements = Ctx.getConstantArrayElementCount(AT); - unsigned ElementOffset = Offset; + uint64_t ElementOffset = Offset; for (uint64_t I = 0; I != NumElements; ++I) { UpdateEmptyClassOffsets(RD, ElementOffset); @@ -419,29 +430,13 @@ uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) { void ASTRecordLayoutBuilder::LayoutBaseNonVirtually(const CXXRecordDecl *RD, bool IsVirtualBase) { // Layout the base. - unsigned Offset = LayoutBase(RD); + uint64_t Offset = LayoutBase(RD); // Add base class offsets. if (IsVirtualBase) VBases.push_back(std::make_pair(RD, Offset)); else Bases.push_back(std::make_pair(RD, Offset)); - -#if 0 - // And now add offsets for all our primary virtual bases as well, so - // they all have offsets. - const ASTRecordLayout *L = &BaseInfo; - const CXXRecordDecl *PB = L->getPrimaryBase(); - while (PB) { - if (L->getPrimaryBaseWasVirtual()) { - VBases.push_back(PB); - VBaseOffsets.push_back(Size); - } - PB = L->getPrimaryBase(); - if (PB) - L = &Ctx.getASTRecordLayout(PB); - } -#endif } void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { @@ -476,7 +471,7 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { if (RD) { llvm::SmallSet<const CXXRecordDecl*, 32> mark; - LayoutVirtualBases(RD, PrimaryBase, 0, mark, IndirectPrimaryBases); + LayoutVirtualBases(RD, RD, PrimaryBase, 0, mark, IndirectPrimaryBases); } // Finally, round the size of the total struct up to the alignment of the diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h index b57b37d0df4d..077072343b1b 100644 --- a/lib/AST/RecordLayoutBuilder.h +++ b/lib/AST/RecordLayoutBuilder.h @@ -99,9 +99,9 @@ class ASTRecordLayoutBuilder { void LayoutNonVirtualBases(const CXXRecordDecl *RD); void LayoutBaseNonVirtually(const CXXRecordDecl *RD, bool IsVBase); void LayoutVirtualBase(const CXXRecordDecl *RD); - void LayoutVirtualBases(const CXXRecordDecl *RD, const CXXRecordDecl *PB, - int64_t Offset, - llvm::SmallSet<const CXXRecordDecl*, 32> &mark, + void LayoutVirtualBases(const CXXRecordDecl *Class, const CXXRecordDecl *RD, + const CXXRecordDecl *PB, uint64_t Offset, + llvm::SmallSet<const CXXRecordDecl*, 32> &mark, llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary); /// canPlaceRecordAtOffset - Return whether a record (either a base class @@ -124,6 +124,9 @@ class ASTRecordLayoutBuilder { /// given offset. void UpdateEmptyClassOffsets(const FieldDecl *FD, uint64_t Offset); + /// getBaseOffset - Get the offset of a direct base class. + uint64_t getBaseOffset(const CXXRecordDecl *Base); + /// FinishLayout - Finalize record layout. Adjust record size based on the /// alignment. void FinishLayout(); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 3608d34c691d..779f6808b6c1 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -550,6 +550,12 @@ bool Type::isIncompleteType() const { // A tagged type (struct/union/enum/class) is incomplete if the decl is a // forward declaration, but not a full definition (C99 6.2.5p22). return !cast<TagType>(CanonicalType)->getDecl()->isDefinition(); + case ConstantArray: + // An array is incomplete if its element type is incomplete + // (C++ [dcl.array]p1). + // We don't handle variable arrays (they're not allowed in C++) or + // dependent-sized arrays (dependent types are never treated as incomplete). + return cast<ArrayType>(CanonicalType)->getElementType()->isIncompleteType(); case IncompleteArray: // An array of unknown size is an incomplete type (C99 6.2.5p22). return true; diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index c71882e4d888..212fea3a6bcc 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -141,7 +141,8 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, // FIXME: This is largely copy-paste from CheckerVisit(). Need to // unify. -void GRExprEngine::CheckerVisitBind(Stmt *S, ExplodedNodeSet &Dst, +void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, + ExplodedNodeSet &Dst, ExplodedNodeSet &Src, SVal location, SVal val, bool isPrevisit) { @@ -164,8 +165,8 @@ void GRExprEngine::CheckerVisitBind(Stmt *S, ExplodedNodeSet &Dst, for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); NI != NE; ++NI) - checker->GR_VisitBind(*CurrSet, *Builder, *this, S, *NI, tag, location, - val, isPrevisit); + checker->GR_VisitBind(*CurrSet, *Builder, *this, AssignE, StoreE, + *NI, tag, location, val, isPrevisit); // Update which NodeSet is the current one. PrevSet = CurrSet; @@ -1125,7 +1126,8 @@ void GRExprEngine::VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred, /// EvalBind - Handle the semantics of binding a value to a specific location. /// This method is used by EvalStore and (soon) VisitDeclStmt, and others. -void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, Stmt* Ex, ExplodedNode* Pred, +void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, Stmt *AssignE, + Stmt* StoreE, ExplodedNode* Pred, const GRState* state, SVal location, SVal Val, bool atDeclInit) { @@ -1133,7 +1135,7 @@ void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, Stmt* Ex, ExplodedNode* Pred, // Do a previsit of the bind. ExplodedNodeSet CheckedSet, Src; Src.Add(Pred); - CheckerVisitBind(Ex, CheckedSet, Src, location, Val, true); + CheckerVisitBind(AssignE, StoreE, CheckedSet, Src, location, Val, true); for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); I!=E; ++I) { @@ -1166,7 +1168,7 @@ void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, Stmt* Ex, ExplodedNode* Pred, // The next thing to do is check if the GRTransferFuncs object wants to // update the state based on the new binding. If the GRTransferFunc object // doesn't do anything, just auto-propagate the current state. - GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, newState, Ex, + GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, newState, StoreE, newState != state); getTF().EvalBind(BuilderRef, location, Val); @@ -1179,14 +1181,16 @@ void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, Stmt* Ex, ExplodedNode* Pred, /// @param state The current simulation state /// @param location The location to store the value /// @param Val The value to be stored -void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred, +void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, Expr *AssignE, + Expr* StoreE, + ExplodedNode* Pred, const GRState* state, SVal location, SVal Val, const void *tag) { - assert (Builder && "GRStmtNodeBuilder must be defined."); + assert(Builder && "GRStmtNodeBuilder must be defined."); // Evaluate the location (checks for bad dereferences). - Pred = EvalLocation(Ex, Pred, state, location, tag); + Pred = EvalLocation(StoreE, Pred, state, location, tag); if (!Pred) return; @@ -1199,7 +1203,7 @@ void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred, SaveAndRestore<const void*> OldTag(Builder->Tag); Builder->PointKind = ProgramPoint::PostStoreKind; Builder->Tag = tag; - EvalBind(Dst, Ex, Pred, state, location, Val); + EvalBind(Dst, AssignE, StoreE, Pred, state, location, Val); } void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred, @@ -1231,17 +1235,6 @@ void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred, } } -void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, Expr* Ex, Expr* StoreE, - ExplodedNode* Pred, const GRState* state, - SVal location, SVal Val, const void *tag) { - - ExplodedNodeSet TmpDst; - EvalStore(TmpDst, StoreE, Pred, state, location, Val, tag); - - for (ExplodedNodeSet::iterator I=TmpDst.begin(), E=TmpDst.end(); I!=E; ++I) - MakeNode(Dst, Ex, *I, (*I)->getState(), ProgramPoint::PostStmtKind, tag); -} - ExplodedNode* GRExprEngine::EvalLocation(Stmt* Ex, ExplodedNode* Pred, const GRState* state, SVal location, const void *tag) { @@ -1402,7 +1395,7 @@ static bool EvalOSAtomicCompareAndSwap(ExplodedNodeSet& Dst, newValueExpr->getType()); } - Engine.EvalStore(TmpStore, theValueExpr, N, stateEqual, location, + Engine.EvalStore(TmpStore, NULL, theValueExpr, N, stateEqual, location, val, OSAtomicStoreTag); // Now bind the result of the comparison. @@ -2147,8 +2140,8 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, Builder->getCurrentBlockCount()); } - EvalBind(Dst, DS, *I, state, loc::MemRegionVal(state->getRegion(VD, LC)), - InitVal, true); + EvalBind(Dst, DS, DS, *I, state, + loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true); } else { state = state->bindDeclWithNoInit(state->getRegion(VD, LC)); @@ -2570,7 +2563,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, state = state->BindExpr(U, U->isPostfix() ? V2 : Result); // Perform the store. - EvalStore(Dst, U, *I2, state, V1, Result); + EvalStore(Dst, NULL, U, *I2, state, V1, Result); } } } diff --git a/lib/Analysis/UndefinedAssignmentChecker.cpp b/lib/Analysis/UndefinedAssignmentChecker.cpp index c5b2401f47ce..2e3ac34913ab 100644 --- a/lib/Analysis/UndefinedAssignmentChecker.cpp +++ b/lib/Analysis/UndefinedAssignmentChecker.cpp @@ -22,14 +22,15 @@ void *UndefinedAssignmentChecker::getTag() { return &x; } -void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C, - const Stmt *S, +void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C, + const Stmt *AssignE, + const Stmt *StoreE, SVal location, SVal val) { if (!val.isUndef()) return; - ExplodedNode *N = C.GenerateNode(S, true); + ExplodedNode *N = C.GenerateNode(StoreE, true); if (!N) return; @@ -40,20 +41,20 @@ void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C, // Generate a report for this bug. EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName().c_str(), N); - const Expr *ex = 0; - - // FIXME: This check needs to be done on the expression doing the - // assignment, not the "store" expression. - if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) - ex = B->getRHS(); - else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) { - const VarDecl* VD = dyn_cast<VarDecl>(DS->getSingleDecl()); - ex = VD->getInit(); - } - if (ex) { - R->addRange(ex->getSourceRange()); - R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, ex); + if (AssignE) { + const Expr *ex = 0; + + if (const BinaryOperator *B = dyn_cast<BinaryOperator>(AssignE)) + ex = B->getRHS(); + else if (const DeclStmt *DS = dyn_cast<DeclStmt>(AssignE)) { + const VarDecl* VD = dyn_cast<VarDecl>(DS->getSingleDecl()); + ex = VD->getInit(); + } + if (ex) { + R->addRange(ex->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, ex); + } } C.EmitReport(R); diff --git a/lib/Analysis/VLASizeChecker.cpp b/lib/Analysis/VLASizeChecker.cpp index 76e4477449ed..0e731902f4bb 100644 --- a/lib/Analysis/VLASizeChecker.cpp +++ b/lib/Analysis/VLASizeChecker.cpp @@ -38,8 +38,8 @@ ExplodedNode *UndefSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred, if (ExplodedNode* N = Builder.generateNode(S, state, Pred)) { N->markAsSink(); if (!BT) - BT = new BugType("Declare variable-length array (VLA) of undefined " - "size", "Logic error"); + BT = new BugType("Declared variable-length array (VLA) uses a garbage" + " value as its size", "Logic error"); EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName().c_str(), N); @@ -81,7 +81,7 @@ ExplodedNode *ZeroSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred, if (ExplodedNode* N = Builder.generateNode(S, zeroState, Pred)) { N->markAsSink(); if (!BT) - BT = new BugType("Declare variable-length array (VLA) of zero size", + BT = new BugType("Declared variable-length array (VLA) has zero size", "Logic error"); EnhancedBugReport *R = diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 3e854ca279b6..cf172b1a1cb6 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -291,7 +291,7 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E) { const FunctionProtoType *FPT = MPT->getPointeeType()->getAs<FunctionProtoType>(); const CXXRecordDecl *RD = - cast<CXXRecordDecl>(cast<RecordType>(MPT->getClass())->getDecl()); + cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl()); const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT), @@ -810,8 +810,32 @@ llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, RValue RV = EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), Callee, CallArgs, MD); if (nv_r || v_r) { + bool CanBeZero = !(ResultType->isReferenceType() + // FIXME: attr nonnull can't be zero either + /* || ResultType->hasAttr<NonNullAttr>() */ ); // Do the return result adjustment. - RV = RValue::get(DynamicTypeAdjust(RV.getScalarVal(), nv_r, v_r)); + if (CanBeZero) { + llvm::BasicBlock *NonZeroBlock = createBasicBlock(); + llvm::BasicBlock *ZeroBlock = createBasicBlock(); + llvm::BasicBlock *ContBlock = createBasicBlock(); + + const llvm::Type *Ty = RV.getScalarVal()->getType(); + llvm::Value *Zero = llvm::Constant::getNullValue(Ty); + Builder.CreateCondBr(Builder.CreateICmpNE(RV.getScalarVal(), Zero), + NonZeroBlock, ZeroBlock); + EmitBlock(NonZeroBlock); + llvm::Value *NZ = DynamicTypeAdjust(RV.getScalarVal(), nv_r, v_r); + EmitBranch(ContBlock); + EmitBlock(ZeroBlock); + llvm::Value *Z = RV.getScalarVal(); + EmitBlock(ContBlock); + llvm::PHINode *RVOrZero = Builder.CreatePHI(Ty); + RVOrZero->reserveOperandSpace(2); + RVOrZero->addIncoming(NZ, NonZeroBlock); + RVOrZero->addIncoming(Z, ZeroBlock); + RV = RValue::get(RVOrZero); + } else + RV = RValue::get(DynamicTypeAdjust(RV.getScalarVal(), nv_r, v_r)); } if (!ResultType->isVoidType()) @@ -1421,6 +1445,8 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, if (FieldType->isReferenceType()) RHS = EmitReferenceBindingToExpr(RhsExpr, FieldType, /*IsInitializer=*/true); + else if (FieldType->isMemberFunctionPointerType()) + RHS = RValue::get(CGM.EmitConstantExpr(RhsExpr, FieldType, this)); else RHS = RValue::get(EmitScalarExpr(RhsExpr, true)); EmitStoreThroughLValue(RHS, LHS, FieldType); diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index b1ceb4627712..2021ced31683 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -515,18 +515,22 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { const CXXDestructorDecl *D = ClassDecl->getDestructor(getContext()); assert(D && "EmitLocalBlockVarDecl - destructor is nul"); - CleanupScope scope(*this); if (const ConstantArrayType *Array = getContext().getAsConstantArrayType(Ty)) { + CleanupScope Scope(*this); QualType BaseElementTy = getContext().getBaseElementType(Array); const llvm::Type *BasePtr = ConvertType(BaseElementTy); BasePtr = llvm::PointerType::getUnqual(BasePtr); llvm::Value *BaseAddrPtr = Builder.CreateBitCast(DeclPtr, BasePtr); EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); - } - else + + // Make sure to jump to the exit block. + EmitBranch(Scope.getCleanupExitBlock()); + } else { + CleanupScope Scope(*this); EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); + } } } diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 88beadf33140..4be341311ce4 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -665,8 +665,9 @@ llvm::Value* CodeGenFunction::EmitVAListRef(const Expr* E) { return EmitLValue(E).getAddress(); } -void CodeGenFunction::PushCleanupBlock(llvm::BasicBlock *CleanupBlock) { - CleanupEntries.push_back(CleanupEntry(CleanupBlock)); +void CodeGenFunction::PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock, + llvm::BasicBlock *CleanupExitBlock) { + CleanupEntries.push_back(CleanupEntry(CleanupEntryBlock, CleanupExitBlock)); } void CodeGenFunction::EmitCleanupBlocks(size_t OldCleanupStackSize) { @@ -680,7 +681,7 @@ void CodeGenFunction::EmitCleanupBlocks(size_t OldCleanupStackSize) { CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() { CleanupEntry &CE = CleanupEntries.back(); - llvm::BasicBlock *CleanupBlock = CE.CleanupBlock; + llvm::BasicBlock *CleanupEntryBlock = CE.CleanupEntryBlock; std::vector<llvm::BasicBlock *> Blocks; std::swap(Blocks, CE.Blocks); @@ -711,10 +712,11 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() { } } - llvm::BasicBlock *SwitchBlock = 0; + llvm::BasicBlock *SwitchBlock = CE.CleanupExitBlock; llvm::BasicBlock *EndBlock = 0; if (!BranchFixups.empty()) { - SwitchBlock = createBasicBlock("cleanup.switch"); + if (!SwitchBlock) + SwitchBlock = createBasicBlock("cleanup.switch"); EndBlock = createBasicBlock("cleanup.end"); llvm::BasicBlock *CurBB = Builder.GetInsertBlock(); @@ -745,7 +747,7 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() { llvm::BasicBlock *Dest = BI->getSuccessor(0); // Fixup the branch instruction to point to the cleanup block. - BI->setSuccessor(0, CleanupBlock); + BI->setSuccessor(0, CleanupEntryBlock); if (CleanupEntries.empty()) { llvm::ConstantInt *ID; @@ -802,7 +804,7 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() { BlockScopes.erase(Blocks[i]); } - return CleanupBlockInfo(CleanupBlock, SwitchBlock, EndBlock); + return CleanupBlockInfo(CleanupEntryBlock, SwitchBlock, EndBlock); } void CodeGenFunction::EmitCleanupBlock() { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 9bb219642ab4..fe8113e95332 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -108,11 +108,12 @@ public: /// PushCleanupBlock - Push a new cleanup entry on the stack and set the /// passed in block as the cleanup block. - void PushCleanupBlock(llvm::BasicBlock *CleanupBlock); + void PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock, + llvm::BasicBlock *CleanupExitBlock = 0); /// CleanupBlockInfo - A struct representing a popped cleanup block. struct CleanupBlockInfo { - /// CleanupBlock - the cleanup block + /// CleanupEntryBlock - the cleanup entry block llvm::BasicBlock *CleanupBlock; /// SwitchBlock - the block (if any) containing the switch instruction used @@ -138,17 +139,24 @@ public: class CleanupScope { CodeGenFunction& CGF; llvm::BasicBlock *CurBB; - llvm::BasicBlock *CleanupBB; - + llvm::BasicBlock *CleanupEntryBB; + llvm::BasicBlock *CleanupExitBB; + public: CleanupScope(CodeGenFunction &cgf) - : CGF(cgf), CurBB(CGF.Builder.GetInsertBlock()) { - CleanupBB = CGF.createBasicBlock("cleanup"); - CGF.Builder.SetInsertPoint(CleanupBB); + : CGF(cgf), CurBB(CGF.Builder.GetInsertBlock()), + CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0) { + CGF.Builder.SetInsertPoint(CleanupEntryBB); } + llvm::BasicBlock *getCleanupExitBlock() { + if (!CleanupExitBB) + CleanupExitBB = CGF.createBasicBlock("cleanup.exit"); + return CleanupExitBB; + } + ~CleanupScope() { - CGF.PushCleanupBlock(CleanupBB); + CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB); // FIXME: This is silly, move this into the builder. if (CurBB) CGF.Builder.SetInsertPoint(CurBB); @@ -250,9 +258,12 @@ private: bool DidCallStackSave; struct CleanupEntry { - /// CleanupBlock - The block of code that does the actual cleanup. - llvm::BasicBlock *CleanupBlock; + /// CleanupEntryBlock - The block of code that does the actual cleanup. + llvm::BasicBlock *CleanupEntryBlock; + /// CleanupExitBlock - The cleanup exit block. + llvm::BasicBlock *CleanupExitBlock; + /// Blocks - Basic blocks that were emitted in the current cleanup scope. std::vector<llvm::BasicBlock *> Blocks; @@ -260,8 +271,10 @@ private: /// inserted into the current function yet. std::vector<llvm::BranchInst *> BranchFixups; - explicit CleanupEntry(llvm::BasicBlock *cb) - : CleanupBlock(cb) {} + explicit CleanupEntry(llvm::BasicBlock *CleanupEntryBlock, + llvm::BasicBlock *CleanupExitBlock) + : CleanupEntryBlock(CleanupEntryBlock), + CleanupExitBlock(CleanupExitBlock) {} }; /// CleanupEntries - Stack of cleanup entries. diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp index 049f3bd3ea14..d2831fae566a 100644 --- a/lib/Frontend/AnalysisConsumer.cpp +++ b/lib/Frontend/AnalysisConsumer.cpp @@ -12,23 +12,24 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/AnalysisConsumer.h" -#include "clang/Frontend/PathDiagnosticClients.h" -#include "clang/Frontend/ManagerRegistry.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" -#include "clang/Analysis/CFG.h" +#include "clang/AST/ParentMap.h" +#include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/Analyses/LiveVariables.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/LocalCheckers.h" #include "clang/Analysis/PathDiagnostic.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/FileManager.h" -#include "clang/AST/ParentMap.h" #include "clang/Analysis/PathSensitive/AnalysisManager.h" #include "clang/Analysis/PathSensitive/BugReporter.h" -#include "clang/Analysis/Analyses/LiveVariables.h" -#include "clang/Analysis/LocalCheckers.h" -#include "clang/Analysis/PathSensitive/GRTransferFuncs.h" #include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Analysis/PathSensitive/GRTransferFuncs.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/ManagerRegistry.h" +#include "clang/Frontend/PathDiagnosticClients.h" +#include "clang/Lex/Preprocessor.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" @@ -52,12 +53,11 @@ namespace { //===----------------------------------------------------------------------===// static PathDiagnosticClient* -CreatePlistHTMLDiagnosticClient(const std::string& prefix, Preprocessor* PP, - PreprocessorFactory* PPF) { +CreatePlistHTMLDiagnosticClient(const std::string& prefix, + const Preprocessor &PP) { llvm::sys::Path F(prefix); - PathDiagnosticClientFactory *PF = - CreateHTMLDiagnosticClientFactory(F.getDirname(), PP, PPF); - return CreatePlistDiagnosticClient(prefix, PP, PPF, PF); + PathDiagnosticClient *PD = CreateHTMLDiagnosticClient(F.getDirname(), PP); + return CreatePlistDiagnosticClient(prefix, PP, PD); } //===----------------------------------------------------------------------===// @@ -74,11 +74,8 @@ namespace { Actions TranslationUnitActions; public: - const LangOptions& LOpts; - Diagnostic &Diags; ASTContext* Ctx; - Preprocessor* PP; - PreprocessorFactory* PPF; + const Preprocessor &PP; const std::string OutDir; AnalyzerOptions Opts; @@ -91,14 +88,11 @@ namespace { llvm::OwningPtr<AnalysisManager> Mgr; - AnalysisConsumer(Diagnostic &diags, Preprocessor* pp, - PreprocessorFactory* ppf, - const LangOptions& lopts, + AnalysisConsumer(const Preprocessor& pp, const std::string& outdir, const AnalyzerOptions& opts) - : LOpts(lopts), Diags(diags), - Ctx(0), PP(pp), PPF(ppf), - OutDir(outdir), Opts(opts), PD(0) { + : Ctx(0), PP(pp), OutDir(outdir), + Opts(opts), PD(0) { DigestAnalyzerOptions(); } @@ -108,7 +102,7 @@ namespace { switch (Opts.AnalysisDiagOpt) { default: #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \ - case PD_##NAME: PD = CREATEFN(OutDir, PP, PPF); break; + case PD_##NAME: PD = CREATEFN(OutDir, PP); break; #include "clang/Frontend/Analyses.def" } } @@ -155,7 +149,8 @@ namespace { virtual void Initialize(ASTContext &Context) { Ctx = &Context; - Mgr.reset(new AnalysisManager(*Ctx, Diags, LOpts, PD, + Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(), + PP.getLangOptions(), PD, CreateStoreMgr, CreateConstraintMgr, Opts.AnalyzerDisplayProgress, Opts.VisualizeEGDot, Opts.VisualizeEGUbi, @@ -263,7 +258,7 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) { // Don't run the actions if an error has occured with parsing the file. - if (Diags.hasErrorOccurred()) + if (PP.getDiagnostics().hasErrorOccurred()) return; // Don't run the actions on declarations in header files unless @@ -443,15 +438,10 @@ static void ActionInlineCall(AnalysisManager &mgr, Decl *D) { // AnalysisConsumer creation. //===----------------------------------------------------------------------===// -ASTConsumer* clang::CreateAnalysisConsumer(Diagnostic &diags, Preprocessor* pp, - PreprocessorFactory* ppf, - const LangOptions& lopts, +ASTConsumer* clang::CreateAnalysisConsumer(const Preprocessor& pp, const std::string& OutDir, const AnalyzerOptions& Opts) { - - llvm::OwningPtr<AnalysisConsumer> C(new AnalysisConsumer(diags, pp, ppf, - lopts, OutDir, - Opts)); + llvm::OwningPtr<AnalysisConsumer> C(new AnalysisConsumer(pp, OutDir, Opts)); for (unsigned i = 0; i < Opts.AnalysisList.size(); ++i) switch (Opts.AnalysisList[i]) { @@ -464,7 +454,7 @@ ASTConsumer* clang::CreateAnalysisConsumer(Diagnostic &diags, Preprocessor* pp, } // Last, disable the effects of '-Werror' when using the AnalysisConsumer. - diags.setWarningsAsErrors(false); + pp.getDiagnostics().setWarningsAsErrors(false); return C.take(); } diff --git a/lib/Frontend/HTMLDiagnostics.cpp b/lib/Frontend/HTMLDiagnostics.cpp index 9d6f96c69f5d..145d53f3fc6e 100644 --- a/lib/Frontend/HTMLDiagnostics.cpp +++ b/lib/Frontend/HTMLDiagnostics.cpp @@ -37,18 +37,20 @@ namespace { class VISIBILITY_HIDDEN HTMLDiagnostics : public PathDiagnosticClient { llvm::sys::Path Directory, FilePrefix; bool createdDir, noDir; - Preprocessor* PP; + const Preprocessor &PP; std::vector<const PathDiagnostic*> BatchedDiags; - llvm::SmallVectorImpl<std::string> *FilesMade; public: - HTMLDiagnostics(const std::string& prefix, Preprocessor* pp, - llvm::SmallVectorImpl<std::string> *filesMade = 0); - - virtual ~HTMLDiagnostics(); - - virtual void SetPreprocessor(Preprocessor *pp) { PP = pp; } + HTMLDiagnostics(const std::string& prefix, const Preprocessor &pp); + + virtual ~HTMLDiagnostics() { FlushDiagnostics(NULL); } + + virtual void FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade); virtual void HandlePathDiagnostic(const PathDiagnostic* D); + + virtual llvm::StringRef getName() const { + return "HTMLDiagnostics"; + } unsigned ProcessMacroPiece(llvm::raw_ostream& os, const PathDiagnosticMacroPiece& P, @@ -61,59 +63,24 @@ public: const char *HighlightStart = "<span class=\"mrange\">", const char *HighlightEnd = "</span>"); - void ReportDiag(const PathDiagnostic& D); + void ReportDiag(const PathDiagnostic& D, + llvm::SmallVectorImpl<std::string> *FilesMade); }; } // end anonymous namespace -HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix, Preprocessor* pp, - llvm::SmallVectorImpl<std::string>* filesMade) +HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix, + const Preprocessor &pp) : Directory(prefix), FilePrefix(prefix), createdDir(false), noDir(false), - PP(pp), FilesMade(filesMade) { - + PP(pp) { // All html files begin with "report" FilePrefix.appendComponent("report"); } PathDiagnosticClient* -clang::CreateHTMLDiagnosticClient(const std::string& prefix, Preprocessor* PP, - PreprocessorFactory*, - llvm::SmallVectorImpl<std::string>* FilesMade) -{ - return new HTMLDiagnostics(prefix, PP, FilesMade); -} - -//===----------------------------------------------------------------------===// -// Factory for HTMLDiagnosticClients -//===----------------------------------------------------------------------===// - -namespace { -class VISIBILITY_HIDDEN HTMLDiagnosticsFactory - : public PathDiagnosticClientFactory { - - std::string Prefix; - Preprocessor *PP; -public: - HTMLDiagnosticsFactory(const std::string& prefix, Preprocessor* pp) - : Prefix(prefix), PP(pp) {} - - virtual ~HTMLDiagnosticsFactory() {} - - const char *getName() const { return "HTMLDiagnostics"; } - - PathDiagnosticClient* - createPathDiagnosticClient(llvm::SmallVectorImpl<std::string> *FilesMade) { - - return new HTMLDiagnostics(Prefix, PP, FilesMade); - } -}; -} // end anonymous namespace - -PathDiagnosticClientFactory* -clang::CreateHTMLDiagnosticClientFactory(const std::string& prefix, - Preprocessor* PP, - PreprocessorFactory*) { - return new HTMLDiagnosticsFactory(prefix, PP); +clang::CreateHTMLDiagnosticClient(const std::string& prefix, + const Preprocessor &PP) { + return new HTMLDiagnostics(prefix, PP); } //===----------------------------------------------------------------------===// @@ -133,16 +100,19 @@ void HTMLDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) { BatchedDiags.push_back(D); } -HTMLDiagnostics::~HTMLDiagnostics() { +void +HTMLDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade) +{ while (!BatchedDiags.empty()) { const PathDiagnostic* D = BatchedDiags.back(); BatchedDiags.pop_back(); - ReportDiag(*D); + ReportDiag(*D, FilesMade); delete D; } } -void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D) { +void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, + llvm::SmallVectorImpl<std::string> *FilesMade){ // Create the HTML directory if it is missing. if (!createdDir) { createdDir = true; @@ -195,7 +165,7 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D) { return; // FIXME: Emit a warning? // Create a new rewriter to generate HTML. - Rewriter R(const_cast<SourceManager&>(SMgr), PP->getLangOptions()); + Rewriter R(const_cast<SourceManager&>(SMgr), PP.getLangOptions()); // Process the path. unsigned n = D.size(); @@ -215,14 +185,8 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D) { // We might not have a preprocessor if we come from a deserialized AST file, // for example. - if (PP) html::SyntaxHighlight(R, FID, *PP); - - // FIXME: We eventually want to use PPF to create a fresh Preprocessor, - // once we have worked out the bugs. - // - // if (PPF) html::HighlightMacros(R, FID, *PPF); - // - if (PP) html::HighlightMacros(R, FID, *PP); + html::SyntaxHighlight(R, FID, PP); + html::HighlightMacros(R, FID, PP); // Get the full directory name of the analyzed file. @@ -476,7 +440,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, assert(L.isFileID()); std::pair<const char*, const char*> BufferInfo = L.getBufferData(); const char* MacroName = L.getDecomposedLoc().second + BufferInfo.first; - Lexer rawLexer(L, PP->getLangOptions(), BufferInfo.first, + Lexer rawLexer(L, PP.getLangOptions(), BufferInfo.first, MacroName, BufferInfo.second); Token TheTok; diff --git a/lib/Frontend/HTMLPrint.cpp b/lib/Frontend/HTMLPrint.cpp index 8d93d70e83f4..75e6184572e5 100644 --- a/lib/Frontend/HTMLPrint.cpp +++ b/lib/Frontend/HTMLPrint.cpp @@ -13,13 +13,14 @@ #include "clang/Frontend/ASTConsumers.h" #include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" -#include "clang/Rewrite/Rewriter.h" -#include "clang/Rewrite/HTMLRewrite.h" #include "clang/Basic/Diagnostic.h" -#include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" -#include "clang/AST/ASTContext.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Rewrite/HTMLRewrite.h" +#include "clang/Rewrite/Rewriter.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -32,13 +33,14 @@ namespace { class HTMLPrinter : public ASTConsumer { Rewriter R; llvm::raw_ostream *Out; - Diagnostic &Diags; - Preprocessor *PP; - PreprocessorFactory *PPF; + Preprocessor &PP; + bool SyntaxHighlight, HighlightMacros; + public: - HTMLPrinter(llvm::raw_ostream *OS, Diagnostic &D, Preprocessor *pp, - PreprocessorFactory* ppf) - : Out(OS), Diags(D), PP(pp), PPF(ppf) {} + HTMLPrinter(llvm::raw_ostream *OS, Preprocessor &pp, + bool _SyntaxHighlight, bool _HighlightMacros) + : Out(OS), PP(pp), SyntaxHighlight(_SyntaxHighlight), + HighlightMacros(_HighlightMacros) {} virtual ~HTMLPrinter(); void Initialize(ASTContext &context); @@ -46,10 +48,10 @@ namespace { } ASTConsumer* clang::CreateHTMLPrinter(llvm::raw_ostream *OS, - Diagnostic &D, Preprocessor *PP, - PreprocessorFactory* PPF) { - - return new HTMLPrinter(OS, D, PP, PPF); + Preprocessor &PP, + bool SyntaxHighlight, + bool HighlightMacros) { + return new HTMLPrinter(OS, PP, SyntaxHighlight, HighlightMacros); } void HTMLPrinter::Initialize(ASTContext &context) { @@ -57,7 +59,7 @@ void HTMLPrinter::Initialize(ASTContext &context) { } HTMLPrinter::~HTMLPrinter() { - if (Diags.hasErrorOccurred()) + if (PP.getDiagnostics().hasErrorOccurred()) return; // Format the file. @@ -79,8 +81,8 @@ HTMLPrinter::~HTMLPrinter() { // We might not have a preprocessor if we come from a deserialized AST file, // for example. - if (PP) html::SyntaxHighlight(R, FID, *PP); - if (PPF) html::HighlightMacros(R, FID, *PP); + if (SyntaxHighlight) html::SyntaxHighlight(R, FID, PP); + if (HighlightMacros) html::HighlightMacros(R, FID, PP); html::EscapeText(R, FID, false, true); // Emit the HTML. diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index ec5c1061bb93..7139e55f0b60 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -442,9 +442,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI, /// InitializePreprocessor - Initialize the preprocessor getting it and the /// environment ready to process a single file. This returns true on error. /// -bool clang::InitializePreprocessor(Preprocessor &PP, - const PreprocessorInitOptions &InitOpts, - bool undef_macros) { +void clang::InitializePreprocessor(Preprocessor &PP, + const PreprocessorInitOptions &InitOpts) { std::vector<char> PredefineBuffer; const char *LineDirective = "# 1 \"<built-in>\" 3\n"; @@ -452,7 +451,7 @@ bool clang::InitializePreprocessor(Preprocessor &PP, LineDirective, LineDirective+strlen(LineDirective)); // Install things like __POWERPC__, __GNUC__, etc into the macro table. - if (!undef_macros) + if (InitOpts.getUsePredefines()) InitializePredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(), PredefineBuffer); @@ -489,7 +488,4 @@ bool clang::InitializePreprocessor(Preprocessor &PP, // Null terminate PredefinedBuffer and add it. PredefineBuffer.push_back(0); PP.setPredefines(&PredefineBuffer[0]); - - // Once we've read this, we're done. - return false; } diff --git a/lib/Frontend/PlistDiagnostics.cpp b/lib/Frontend/PlistDiagnostics.cpp index a83dca0a5ffa..1be9ea8b8c41 100644 --- a/lib/Frontend/PlistDiagnostics.cpp +++ b/lib/Frontend/PlistDiagnostics.cpp @@ -29,7 +29,6 @@ typedef llvm::DenseMap<FileID, unsigned> FIDMap; namespace clang { class Preprocessor; - class PreprocessorFactory; } namespace { @@ -37,14 +36,20 @@ namespace { std::vector<const PathDiagnostic*> BatchedDiags; const std::string OutputFile; const LangOptions &LangOpts; - llvm::OwningPtr<PathDiagnosticClientFactory> PF; - llvm::OwningPtr<PathDiagnosticClient> SubPDC; - llvm::SmallVector<std::string, 1> FilesMade; + llvm::OwningPtr<PathDiagnosticClient> SubPD; public: PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts, - PathDiagnosticClientFactory *pf); - ~PlistDiagnostics(); + PathDiagnosticClient *subPD); + + ~PlistDiagnostics() { FlushDiagnostics(NULL); } + + void FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade); + void HandlePathDiagnostic(const PathDiagnostic* D); + + virtual llvm::StringRef getName() const { + return "PlistDiagnostics"; + } PathGenerationScheme getGenerationScheme() const; bool supportsLogicalOpControlFlow() const { return true; } @@ -55,23 +60,18 @@ namespace { PlistDiagnostics::PlistDiagnostics(const std::string& output, const LangOptions &LO, - PathDiagnosticClientFactory *pf) - : OutputFile(output), LangOpts(LO), PF(pf) { - - if (PF) - SubPDC.reset(PF->createPathDiagnosticClient(&FilesMade)); -} + PathDiagnosticClient *subPD) + : OutputFile(output), LangOpts(LO), SubPD(subPD) {} PathDiagnosticClient* -clang::CreatePlistDiagnosticClient(const std::string& s, - Preprocessor *PP, PreprocessorFactory*, - PathDiagnosticClientFactory *PF) { - return new PlistDiagnostics(s, PP->getLangOptions(), PF); +clang::CreatePlistDiagnosticClient(const std::string& s, const Preprocessor &PP, + PathDiagnosticClient *subPD) { + return new PlistDiagnostics(s, PP.getLangOptions(), subPD); } PathDiagnosticClient::PathGenerationScheme PlistDiagnostics::getGenerationScheme() const { - if (const PathDiagnosticClient *PD = SubPDC.get()) + if (const PathDiagnosticClient *PD = SubPD.get()) return PD->getGenerationScheme(); return Extensive; @@ -308,7 +308,8 @@ void PlistDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) { BatchedDiags.push_back(D); } -PlistDiagnostics::~PlistDiagnostics() { +void PlistDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> + *FilesMade) { // Build up a set of FIDs that we use by scanning the locations and // ranges of the diagnostics. @@ -397,19 +398,16 @@ PlistDiagnostics::~PlistDiagnostics() { EmitLocation(o, *SM, LangOpts, D->getLocation(), FM, 2); // Output the diagnostic to the sub-diagnostic client, if any. - if (PF) { - if (!SubPDC.get()) - SubPDC.reset(PF->createPathDiagnosticClient(&FilesMade)); - - FilesMade.clear(); - SubPDC->HandlePathDiagnostic(OwnedD.take()); - SubPDC.reset(0); + if (SubPD) { + SubPD->HandlePathDiagnostic(OwnedD.take()); + llvm::SmallVector<std::string, 1> SubFilesMade; + SubPD->FlushDiagnostics(SubFilesMade); - if (!FilesMade.empty()) { - o << " <key>" << PF->getName() << "_files</key>\n"; + if (!SubFilesMade.empty()) { + o << " <key>" << SubPD->getName() << "_files</key>\n"; o << " <array>\n"; - for (size_t i = 0, n = FilesMade.size(); i < n ; ++i) - o << " <string>" << FilesMade[i] << "</string>\n"; + for (size_t i = 0, n = SubFilesMade.size(); i < n ; ++i) + o << " <string>" << SubFilesMade[i] << "</string>\n"; o << " </array>\n"; } } @@ -422,4 +420,7 @@ PlistDiagnostics::~PlistDiagnostics() { // Finish. o << "</dict>\n</plist>"; + + if (FilesMade) + FilesMade->push_back(OutputFile); } diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index b1d8800369e5..4f8c804844b0 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -268,6 +268,7 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, const CodeModificationHint *Hints, unsigned NumHints, unsigned Columns) { + assert(LangOpts && "Unexpected diagnostic outside source file processing"); assert(!Loc.isInvalid() && "must have a valid source location here"); // If this is a macro ID, first emit information about where this was diff --git a/lib/Headers/stdint.h b/lib/Headers/stdint.h index f79a0f4af557..f03c1777ab01 100644 --- a/lib/Headers/stdint.h +++ b/lib/Headers/stdint.h @@ -42,28 +42,23 @@ * Since we only support pow-2 targets, these map directly to exact width types. */ -#ifndef __int8_t_defined /* glibc does weird things with sys/types.h */ -#define __int8_t_defined -typedef signed __INT8_TYPE__ int8_t; -typedef __INT16_TYPE__ int16_t; -typedef __INT32_TYPE__ int32_t; +/* Some 16-bit targets do not have a 64-bit datatype. Only define the 64-bit + * typedefs if there is something to typedef them to. + */ #ifdef __INT64_TYPE__ +#ifndef __int8_t_defined /* glibc does weird things with sys/types.h */ typedef __INT64_TYPE__ int64_t; #endif +typedef unsigned __INT64_TYPE__ uint64_t; +typedef int64_t int_least64_t; +typedef uint64_t uint_least64_t; +typedef int64_t int_fast64_t; +typedef uint64_t uint_fast64_t; #endif -typedef unsigned __INT8_TYPE__ uint8_t; -typedef int8_t int_least8_t; -typedef uint8_t uint_least8_t; -typedef int8_t int_fast8_t; -typedef uint8_t uint_fast8_t; - -typedef unsigned __INT16_TYPE__ uint16_t; -typedef int16_t int_least16_t; -typedef uint16_t uint_least16_t; -typedef int16_t int_fast16_t; -typedef uint16_t uint_fast16_t; - +#ifndef __int8_t_defined /* glibc does weird things with sys/types.h */ +typedef __INT32_TYPE__ int32_t; +#endif #ifndef __uint32_t_defined /* more glibc compatibility */ #define __uint32_t_defined typedef unsigned __INT32_TYPE__ uint32_t; @@ -73,18 +68,31 @@ typedef uint32_t uint_least32_t; typedef int32_t int_fast32_t; typedef uint32_t uint_fast32_t; -/* Some 16-bit targets do not have a 64-bit datatype. Only define the 64-bit - * typedefs if there is something to typedef them to. - */ -#ifdef __INT64_TYPE__ -typedef unsigned __INT64_TYPE__ uint64_t; -typedef int64_t int_least64_t; -typedef uint64_t uint_least64_t; -typedef int64_t int_fast64_t; -typedef uint64_t uint_fast64_t; + +#ifndef __int8_t_defined /* glibc does weird things with sys/types.h */ +typedef __INT16_TYPE__ int16_t; #endif +typedef unsigned __INT16_TYPE__ uint16_t; +typedef int16_t int_least16_t; +typedef uint16_t uint_least16_t; +typedef int16_t int_fast16_t; +typedef uint16_t uint_fast16_t; +#ifndef __int8_t_defined /* glibc does weird things with sys/types.h */ +typedef signed __INT8_TYPE__ int8_t; +#endif +typedef unsigned __INT8_TYPE__ uint8_t; +typedef int8_t int_least8_t; +typedef uint8_t uint_least8_t; +typedef int8_t int_fast8_t; +typedef uint8_t uint_fast8_t; + +/* prevent glibc sys/types.h from defining conflicting types */ +#ifndef __int8_t_defined +# define __int8_t_defined +#endif /* __int8_t_defined */ + /* C99 7.18.1.4 Integer types capable of holding object pointers. */ #ifndef __intptr_t_defined @@ -98,6 +106,25 @@ typedef unsigned __INTPTR_TYPE__ uintptr_t; typedef __INTMAX_TYPE__ intmax_t; typedef __UINTMAX_TYPE__ uintmax_t; +/* C99 7.18.4 Macros for minimum-width integer constants. + * + * Note that C++ should not check __STDC_CONSTANT_MACROS here, contrary to the + * claims of the C standard (see C++ 18.3.1p2, [cstdint.syn]). + */ + +/* Only define the 64-bit size macros if we have 64-bit support. */ +#ifdef __INT64_TYPE__ +#define INT64_C(v) (v##LL) +#define UINT64_C(v) (v##ULL) +#endif + +#define INT32_C(v) (v) +#define UINT32_C(v) (v##U) +#define INT16_C(v) (v) +#define UINT16_C(v) (v##U) +#define INT8_C(v) (v) +#define UINT8_C(v) (v##U) + /* C99 7.18.2.1 Limits of exact-width integer types. * Fixed sized values have fixed size max/min. * C99 7.18.2.2 Limits of minimum-width integer types. @@ -108,36 +135,6 @@ typedef __UINTMAX_TYPE__ uintmax_t; * claims of the C standard (see C++ 18.3.1p2, [cstdint.syn]). */ -#define INT8_MAX 127 -#define INT8_MIN (-128) -#define UINT8_MAX 255 -#define INT_LEAST8_MIN INT8_MIN -#define INT_LEAST8_MAX INT8_MAX -#define UINT_LEAST8_MAX UINT8_MAX -#define INT_FAST8_MIN INT8_MIN -#define INT_FAST8_MAX INT8_MAX -#define UINT_FAST8_MAX UINT8_MAX - -#define INT16_MAX 32767 -#define INT16_MIN (-32768) -#define UINT16_MAX 65535 -#define INT_LEAST16_MIN INT16_MIN -#define INT_LEAST16_MAX INT16_MAX -#define UINT_LEAST16_MAX UINT16_MAX -#define INT_FAST16_MIN INT16_MIN -#define INT_FAST16_MAX INT16_MAX -#define UINT_FAST16_MAX UINT16_MAX - -#define INT32_MAX 2147483647 -#define INT32_MIN (-2147483647-1) -#define UINT32_MAX 4294967295U -#define INT_LEAST32_MIN INT32_MIN -#define INT_LEAST32_MAX INT32_MAX -#define UINT_LEAST32_MAX UINT32_MAX -#define INT_FAST32_MIN INT32_MIN -#define INT_FAST32_MAX INT32_MAX -#define UINT_FAST32_MAX UINT32_MAX - /* If we do not have 64-bit support, don't define the 64-bit size macros. */ #ifdef __INT64_TYPE__ #define INT64_MAX 9223372036854775807LL @@ -151,6 +148,36 @@ typedef __UINTMAX_TYPE__ uintmax_t; #define UINT_FAST64_MAX UINT64_MAX #endif +#define INT32_MAX 2147483647 +#define INT32_MIN (-2147483647-1) +#define UINT32_MAX 4294967295U +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define UINT_FAST32_MAX UINT32_MAX + +#define INT16_MAX 32767 +#define INT16_MIN (-32768) +#define UINT16_MAX 65535 +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define UINT_FAST16_MAX UINT16_MAX + +#define INT8_MAX 127 +#define INT8_MIN (-128) +#define UINT8_MAX 255 +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define UINT_FAST8_MAX UINT8_MAX + /* C99 7.18.2.4 Limits of integer types capable of holding object pointers. */ /* C99 7.18.3 Limits of other integer types. */ @@ -206,25 +233,6 @@ typedef __UINTMAX_TYPE__ uintmax_t; #define WCHAR_MIN (-__WCHAR_MAX__-1) #endif -/* C99 7.18.4 Macros for minimum-width integer constants. - * - * Note that C++ should not check __STDC_CONSTANT_MACROS here, contrary to the - * claims of the C standard (see C++ 18.3.1p2, [cstdint.syn]). - */ - -#define INT8_C(v) (v) -#define UINT8_C(v) (v##U) -#define INT16_C(v) (v) -#define UINT16_C(v) (v##U) -#define INT32_C(v) (v) -#define UINT32_C(v) (v##U) - -/* Only define the 64-bit size macros if we have 64-bit support. */ -#ifdef __INT64_TYPE__ -#define INT64_C(v) (v##LL) -#define UINT64_C(v) (v##ULL) -#endif - /* 7.18.4.2 Macros for greatest-width integer constants. */ #define INTMAX_C(v) (v##LL) #define UINTMAX_C(v) (v##ULL) diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index 7f3afc60764c..487b9d63c169 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -43,8 +43,6 @@ using namespace clang; //===----------------------------------------------------------------------===// -PreprocessorFactory::~PreprocessorFactory() {} - Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, TargetInfo &target, SourceManager &SM, HeaderSearch &Headers, @@ -403,7 +401,7 @@ void Preprocessor::EnterMainSourceFile() { /// LookUpIdentifierInfo - Given a tok::identifier token, look up the /// identifier information for the token and install it into the token. IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier, - const char *BufPtr) { + const char *BufPtr) const { assert(Identifier.is(tok::identifier) && "Not an identifier!"); assert(Identifier.getIdentifierInfo() == 0 && "Identinfo already exists!"); @@ -411,14 +409,14 @@ IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier, IdentifierInfo *II; if (BufPtr && !Identifier.needsCleaning()) { // No cleaning needed, just use the characters from the lexed buffer. - II = getIdentifierInfo(BufPtr, BufPtr+Identifier.getLength()); + II = getIdentifierInfo(llvm::StringRef(BufPtr, Identifier.getLength())); } else { // Cleaning needed, alloca a buffer, clean into it, then use the buffer. llvm::SmallVector<char, 64> IdentifierBuffer; IdentifierBuffer.resize(Identifier.getLength()); const char *TmpBuf = &IdentifierBuffer[0]; unsigned Size = getSpelling(Identifier, TmpBuf); - II = getIdentifierInfo(TmpBuf, TmpBuf+Size); + II = getIdentifierInfo(llvm::StringRef(TmpBuf, Size)); } Identifier.setIdentifierInfo(II); return II; diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index 3436900027e4..0a4e036e4399 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -334,6 +334,14 @@ bool DeclSpec::SetFriendSpec(SourceLocation Loc, const char *&PrevSpec, return false; } +bool DeclSpec::SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID) { + // 'constexpr constexpr' is ok. + Constexpr_specified = true; + ConstexprLoc = Loc; + return false; +} + void DeclSpec::setProtocolQualifiers(const ActionBase::DeclPtrTy *Protos, unsigned NP, SourceLocation *ProtoLocs, diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp index 1e7d397fdf37..bf05b2baccd4 100644 --- a/lib/Parse/MinimalAction.cpp +++ b/lib/Parse/MinimalAction.cpp @@ -42,14 +42,12 @@ Action::DeclPtrTy Action::ActOnUsingDirective(Scope *CurScope, return DeclPtrTy(); } -// Defined out-of-line here because of dependecy on AttributeList +// Defined out-of-line here because of dependency on AttributeList Action::DeclPtrTy Action::ActOnUsingDeclaration(Scope *CurScope, AccessSpecifier AS, SourceLocation UsingLoc, const CXXScopeSpec &SS, - SourceLocation IdentLoc, - IdentifierInfo *TargetName, - OverloadedOperatorKind Op, + UnqualifiedId &Name, AttributeList *AttrList, bool IsTypeName) { diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index e905553fd818..99752b59507f 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -769,6 +769,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, /// [C++] 'virtual' /// [C++] 'explicit' /// 'friend': [C++ dcl.friend] +/// 'constexpr': [C++0x dcl.constexpr] /// void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, @@ -1070,6 +1071,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, } break; + // constexpr + case tok::kw_constexpr: + isInvalid = DS.SetConstexprSpec(Loc, PrevSpec, DiagID); + break; + // type-specifier case tok::kw_short: isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec, diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 91f86864f81f..154c2923486e 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -285,6 +285,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, bool IsTypeName; // Ignore optional 'typename'. + // FIXME: This is wrong; we should parse this as a typename-specifier. if (Tok.is(tok::kw_typename)) { ConsumeToken(); IsTypeName = true; @@ -302,41 +303,21 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, SkipUntil(tok::semi); return DeclPtrTy(); } - if (Tok.is(tok::annot_template_id)) { - // C++0x N2914 [namespace.udecl]p5: - // A using-declaration shall not name a template-id. - Diag(Tok, diag::err_using_decl_can_not_refer_to_template_spec); - SkipUntil(tok::semi); - return DeclPtrTy(); - } - - IdentifierInfo *TargetName = 0; - OverloadedOperatorKind Op = OO_None; - SourceLocation IdentLoc; - if (Tok.is(tok::kw_operator)) { - IdentLoc = Tok.getLocation(); - - Op = TryParseOperatorFunctionId(); - if (!Op) { - // If there was an invalid operator, skip to end of decl, and eat ';'. - SkipUntil(tok::semi); - return DeclPtrTy(); - } - // FIXME: what about conversion functions? - } else if (Tok.is(tok::identifier)) { - // Parse identifier. - TargetName = Tok.getIdentifierInfo(); - IdentLoc = ConsumeToken(); - } else { - // FIXME: Use a better diagnostic here. - Diag(Tok, diag::err_expected_ident_in_using); - - // If there was invalid identifier, skip to end of decl, and eat ';'. + // Parse the unqualified-id. We allow parsing of both constructor and + // destructor names and allow the action module to diagnose any semantic + // errors. + UnqualifiedId Name; + if (ParseUnqualifiedId(SS, + /*EnteringContext=*/false, + /*AllowDestructorName=*/true, + /*AllowConstructorName=*/true, + /*ObjectType=*/0, + Name)) { SkipUntil(tok::semi); return DeclPtrTy(); } - + // Parse (optional) attributes (most likely GNU strong-using extension). if (Tok.is(tok::kw___attribute)) AttrList = ParseAttributes(); @@ -344,10 +325,10 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, // Eat ';'. DeclEnd = Tok.getLocation(); ExpectAndConsume(tok::semi, diag::err_expected_semi_after, - AttrList ? "attributes list" : "namespace name", tok::semi); + AttrList ? "attributes list" : "using declaration", + tok::semi); - return Actions.ActOnUsingDeclaration(CurScope, AS, UsingLoc, SS, - IdentLoc, TargetName, Op, + return Actions.ActOnUsingDeclaration(CurScope, AS, UsingLoc, SS, Name, AttrList, IsTypeName); } diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index a7ca0c54dbe6..a00dfb0b4c36 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -1196,141 +1196,6 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, return true; } -/// TryParseOperatorFunctionId - Attempts to parse a C++ overloaded -/// operator name (C++ [over.oper]). If successful, returns the -/// predefined identifier that corresponds to that overloaded -/// operator. Otherwise, returns NULL and does not consume any tokens. -/// -/// operator-function-id: [C++ 13.5] -/// 'operator' operator -/// -/// operator: one of -/// new delete new[] delete[] -/// + - * / % ^ & | ~ -/// ! = < > += -= *= /= %= -/// ^= &= |= << >> >>= <<= == != -/// <= >= && || ++ -- , ->* -> -/// () [] -OverloadedOperatorKind -Parser::TryParseOperatorFunctionId(SourceLocation *EndLoc) { - assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword"); - SourceLocation Loc; - - OverloadedOperatorKind Op = OO_None; - switch (NextToken().getKind()) { - case tok::kw_new: - ConsumeToken(); // 'operator' - Loc = ConsumeToken(); // 'new' - if (Tok.is(tok::l_square)) { - ConsumeBracket(); // '[' - Loc = Tok.getLocation(); - ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']' - Op = OO_Array_New; - } else { - Op = OO_New; - } - if (EndLoc) - *EndLoc = Loc; - return Op; - - case tok::kw_delete: - ConsumeToken(); // 'operator' - Loc = ConsumeToken(); // 'delete' - if (Tok.is(tok::l_square)) { - ConsumeBracket(); // '[' - Loc = Tok.getLocation(); - ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']' - Op = OO_Array_Delete; - } else { - Op = OO_Delete; - } - if (EndLoc) - *EndLoc = Loc; - return Op; - -#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ - case tok::Token: Op = OO_##Name; break; -#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly) -#include "clang/Basic/OperatorKinds.def" - - case tok::l_paren: - ConsumeToken(); // 'operator' - ConsumeParen(); // '(' - Loc = Tok.getLocation(); - ExpectAndConsume(tok::r_paren, diag::err_expected_rparen); // ')' - if (EndLoc) - *EndLoc = Loc; - return OO_Call; - - case tok::l_square: - ConsumeToken(); // 'operator' - ConsumeBracket(); // '[' - Loc = Tok.getLocation(); - ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']' - if (EndLoc) - *EndLoc = Loc; - return OO_Subscript; - - case tok::code_completion: { - // Code completion for the operator name. - Actions.CodeCompleteOperatorName(CurScope); - - // Consume the 'operator' token, then replace the code-completion token - // with an 'operator' token and try again. - SourceLocation OperatorLoc = ConsumeToken(); - Tok.setLocation(OperatorLoc); - Tok.setKind(tok::kw_operator); - return TryParseOperatorFunctionId(EndLoc); - } - - default: - return OO_None; - } - - ConsumeToken(); // 'operator' - Loc = ConsumeAnyToken(); // the operator itself - if (EndLoc) - *EndLoc = Loc; - return Op; -} - -/// ParseConversionFunctionId - Parse a C++ conversion-function-id, -/// which expresses the name of a user-defined conversion operator -/// (C++ [class.conv.fct]p1). Returns the type that this operator is -/// specifying a conversion for, or NULL if there was an error. -/// -/// conversion-function-id: [C++ 12.3.2] -/// operator conversion-type-id -/// -/// conversion-type-id: -/// type-specifier-seq conversion-declarator[opt] -/// -/// conversion-declarator: -/// ptr-operator conversion-declarator[opt] -Parser::TypeTy *Parser::ParseConversionFunctionId(SourceLocation *EndLoc) { - assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword"); - ConsumeToken(); // 'operator' - - // Parse the type-specifier-seq. - DeclSpec DS; - if (ParseCXXTypeSpecifierSeq(DS)) - return 0; - - // Parse the conversion-declarator, which is merely a sequence of - // ptr-operators. - Declarator D(DS, Declarator::TypeNameContext); - ParseDeclaratorInternal(D, /*DirectDeclParser=*/0); - if (EndLoc) - *EndLoc = D.getSourceRange().getEnd(); - - // Finish up the type. - Action::TypeResult Result = Actions.ActOnTypeName(CurScope, D); - if (Result.isInvalid()) - return 0; - else - return Result.get(); -} - /// ParseCXXNewExpression - Parse a C++ new-expression. New is used to allocate /// memory in a typesafe manner and call constructors. /// diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 045acd86ad0f..99578837c21c 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -809,12 +809,11 @@ void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) { Tok.setAnnotationValue(Type.isInvalid()? 0 : Type.get()); if (SS && SS->isNotEmpty()) // it was a C++ qualified type name. Tok.setLocation(SS->getBeginLoc()); + Tok.setAnnotationEndLoc(TemplateId->TemplateNameLoc); - // We might be backtracking, in which case we need to replace the - // template-id annotation token with the type annotation within the - // set of cached tokens. That way, we won't try to form the same - // class template specialization again. - PP.ReplaceLastTokenWithAnnotation(Tok); + // Replace the template-id annotation token, and possible the scope-specifier + // that precedes it, with the typename annotation token. + PP.AnnotateCachedTokens(Tok); TemplateId->Destroy(); } diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index eb6e93540566..7ac297710965 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -503,6 +503,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, /// function-specifier /// 'friend' /// 'typedef' +/// [C++0x] 'constexpr' /// [GNU] attributes declaration-specifiers[opt] /// /// storage-class-specifier: @@ -615,9 +616,11 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { // function-specifier // 'friend' // 'typedef' + // 'constexpr' case tok::kw_friend: case tok::kw_typedef: + case tok::kw_constexpr: // storage-class-specifier case tok::kw_register: case tok::kw_static: diff --git a/lib/Rewrite/HTMLRewrite.cpp b/lib/Rewrite/HTMLRewrite.cpp index 7326890ded76..b4bf419bc5f4 100644 --- a/lib/Rewrite/HTMLRewrite.cpp +++ b/lib/Rewrite/HTMLRewrite.cpp @@ -349,7 +349,7 @@ void html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, FileID FID, /// information about keywords, macro expansions etc. This uses the macro /// table state from the end of the file, so it won't be perfectly perfect, /// but it will be reasonably close. -void html::SyntaxHighlight(Rewriter &R, FileID FID, Preprocessor &PP) { +void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) { RewriteBuffer &RB = R.getEditBuffer(FID); const SourceManager &SM = PP.getSourceManager(); @@ -375,7 +375,8 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, Preprocessor &PP) { case tok::identifier: { // Fill in Result.IdentifierInfo, looking up the identifier in the // identifier table. - IdentifierInfo *II = PP.LookUpIdentifierInfo(Tok, BufferStart+TokOffs); + const IdentifierInfo *II = + PP.LookUpIdentifierInfo(Tok, BufferStart+TokOffs); // If this is a pp-identifier, for a keyword, highlight it as such. if (II->getTokenID() != tok::identifier) @@ -438,7 +439,7 @@ class IgnoringDiagClient : public DiagnosticClient { /// file, to re-expand macros and insert (into the HTML) information about the /// macro expansions. This won't be perfectly perfect, but it will be /// reasonably close. -void html::HighlightMacros(Rewriter &R, FileID FID, Preprocessor& PP) { +void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) { // Re-lex the raw token stream into a token buffer. const SourceManager &SM = PP.getSourceManager(); std::vector<Token> TokenStream; @@ -481,25 +482,29 @@ void html::HighlightMacros(Rewriter &R, FileID FID, Preprocessor& PP) { IgnoringDiagClient TmpDC; Diagnostic TmpDiags(&TmpDC); - Diagnostic *OldDiags = &PP.getDiagnostics(); - PP.setDiagnostics(TmpDiags); + // FIXME: This is a huge hack; we reuse the input preprocessor because we want + // its state, but we aren't actually changing it (we hope). This should really + // construct a copy of the preprocessor. + Preprocessor &TmpPP = const_cast<Preprocessor&>(PP); + Diagnostic *OldDiags = &TmpPP.getDiagnostics(); + TmpPP.setDiagnostics(TmpDiags); // Inform the preprocessor that we don't want comments. - PP.SetCommentRetentionState(false, false); + TmpPP.SetCommentRetentionState(false, false); // Enter the tokens we just lexed. This will cause them to be macro expanded // but won't enter sub-files (because we removed #'s). - PP.EnterTokenStream(&TokenStream[0], TokenStream.size(), false, false); + TmpPP.EnterTokenStream(&TokenStream[0], TokenStream.size(), false, false); - TokenConcatenation ConcatInfo(PP); + TokenConcatenation ConcatInfo(TmpPP); // Lex all the tokens. Token Tok; - PP.Lex(Tok); + TmpPP.Lex(Tok); while (Tok.isNot(tok::eof)) { // Ignore non-macro tokens. if (!Tok.getLocation().isMacroID()) { - PP.Lex(Tok); + TmpPP.Lex(Tok); continue; } @@ -511,19 +516,19 @@ void html::HighlightMacros(Rewriter &R, FileID FID, Preprocessor& PP) { // Ignore tokens whose instantiation location was not the main file. if (SM.getFileID(LLoc.first) != FID) { - PP.Lex(Tok); + TmpPP.Lex(Tok); continue; } assert(SM.getFileID(LLoc.second) == FID && "Start and end of expansion must be in the same ultimate file!"); - std::string Expansion = EscapeText(PP.getSpelling(Tok)); + std::string Expansion = EscapeText(TmpPP.getSpelling(Tok)); unsigned LineLen = Expansion.size(); Token PrevTok = Tok; // Okay, eat this token, getting the next one. - PP.Lex(Tok); + TmpPP.Lex(Tok); // Skip all the rest of the tokens that are part of this macro // instantiation. It would be really nice to pop up a window with all the @@ -545,11 +550,11 @@ void html::HighlightMacros(Rewriter &R, FileID FID, Preprocessor& PP) { Expansion += ' '; // Escape any special characters in the token text. - Expansion += EscapeText(PP.getSpelling(Tok)); + Expansion += EscapeText(TmpPP.getSpelling(Tok)); LineLen += Expansion.size(); PrevTok = Tok; - PP.Lex(Tok); + TmpPP.Lex(Tok); } @@ -562,12 +567,5 @@ void html::HighlightMacros(Rewriter &R, FileID FID, Preprocessor& PP) { } // Restore diagnostics object back to its own thing. - PP.setDiagnostics(*OldDiags); -} - -void html::HighlightMacros(Rewriter &R, FileID FID, - PreprocessorFactory &PPF) { - - llvm::OwningPtr<Preprocessor> PP(PPF.CreatePreprocessor()); - HighlightMacros(R, FID, *PP); + TmpPP.setDiagnostics(*OldDiags); } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 0f84b46ed405..c4de6be9eb2e 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1609,6 +1609,9 @@ public: void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, Expr **Args, unsigned NumArgs); + void CheckSignCompare(Expr *LHS, Expr *RHS, SourceLocation Loc, + const PartialDiagnostic &PD); + virtual ExpressionEvaluationContext PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext); @@ -1667,6 +1670,8 @@ public: OwningExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc, unsigned OpcIn, ExprArg InputArg); + OwningExprResult BuildUnaryOp(Scope *S, SourceLocation OpLoc, + UnaryOperator::Opcode Opc, ExprArg input); virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Op, ExprArg Input); @@ -1792,6 +1797,9 @@ public: virtual OwningExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc, tok::TokenKind Kind, ExprArg LHS, ExprArg RHS); + OwningExprResult BuildBinOp(Scope *S, SourceLocation OpLoc, + BinaryOperator::Opcode Opc, + Expr *lhs, Expr *rhs); OwningExprResult CreateBuiltinBinOp(SourceLocation TokLoc, unsigned Opc, Expr *lhs, Expr *rhs); @@ -1893,9 +1901,7 @@ public: AccessSpecifier AS, SourceLocation UsingLoc, const CXXScopeSpec &SS, - SourceLocation IdentLoc, - IdentifierInfo *TargetName, - OverloadedOperatorKind Op, + UnqualifiedId &Name, AttributeList *AttrList, bool IsTypeName); @@ -3645,7 +3651,8 @@ public: Ref_Compatible }; - ReferenceCompareResult CompareReferenceRelationship(QualType T1, QualType T2, + ReferenceCompareResult CompareReferenceRelationship(SourceLocation Loc, + QualType T1, QualType T2, bool& DerivedToBase); bool CheckReferenceInit(Expr *&simpleInit_or_initList, QualType declType, diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 8bb334855d02..76faddaa0384 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -527,7 +527,8 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, // this is the only cast possibility, so we issue an error if we fail now. // FIXME: Should allow casting away constness if CStyle. bool DerivedToBase; - if (Self.CompareReferenceRelationship(SrcExpr->getType(), R->getPointeeType(), + if (Self.CompareReferenceRelationship(SrcExpr->getLocStart(), + SrcExpr->getType(), R->getPointeeType(), DerivedToBase) < Sema::Ref_Compatible_With_Added_Qualification) { msg = diag::err_bad_lvalue_to_rvalue_cast; diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 10c138c7558f..ce3fb5f83c8f 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -22,6 +22,72 @@ #include "llvm/Support/raw_ostream.h" using namespace clang; +/// \brief Find the current instantiation that associated with the given type. +static CXXRecordDecl * +getCurrentInstantiationOf(ASTContext &Context, DeclContext *CurContext, + QualType T) { + if (T.isNull()) + return 0; + + T = Context.getCanonicalType(T); + + for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getParent()) { + // If we've hit a namespace or the global scope, then the + // nested-name-specifier can't refer to the current instantiation. + if (Ctx->isFileContext()) + return 0; + + // Skip non-class contexts. + CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx); + if (!Record) + continue; + + // If this record type is not dependent, + if (!Record->isDependentType()) + return 0; + + // C++ [temp.dep.type]p1: + // + // In the definition of a class template, a nested class of a + // class template, a member of a class template, or a member of a + // nested class of a class template, a name refers to the current + // instantiation if it is + // -- the injected-class-name (9) of the class template or + // nested class, + // -- in the definition of a primary class template, the name + // of the class template followed by the template argument + // list of the primary template (as described below) + // enclosed in <>, + // -- in the definition of a nested class of a class template, + // the name of the nested class referenced as a member of + // the current instantiation, or + // -- in the definition of a partial specialization, the name + // of the class template followed by the template argument + // list of the partial specialization enclosed in <>. If + // the nth template parameter is a parameter pack, the nth + // template argument is a pack expansion (14.6.3) whose + // pattern is the name of the parameter pack. + // (FIXME: parameter packs) + // + // All of these options come down to having the + // nested-name-specifier type that is equivalent to the + // injected-class-name of one of the types that is currently in + // our context. + if (Context.getCanonicalType(Context.getTypeDeclType(Record)) == T) + return Record; + + if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) { + QualType InjectedClassName + = Template->getInjectedClassNameType(Context); + if (T == Context.getCanonicalType(InjectedClassName)) + return Template->getTemplatedDecl(); + } + // FIXME: check for class template partial specializations + } + + return 0; +} + /// \brief Compute the DeclContext that is associated with the given type. /// /// \param T the type for which we are attempting to find a DeclContext. @@ -33,7 +99,7 @@ DeclContext *Sema::computeDeclContext(QualType T) { if (const TagType *Tag = T->getAs<TagType>()) return Tag->getDecl(); - return 0; + return ::getCurrentInstantiationOf(Context, CurContext, T); } /// \brief Compute the DeclContext that is associated with the given @@ -156,68 +222,7 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) { return 0; QualType T = QualType(NNS->getAsType(), 0); - // If the nested name specifier does not refer to a type, then it - // does not refer to the current instantiation. - if (T.isNull()) - return 0; - - T = Context.getCanonicalType(T); - - for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getParent()) { - // If we've hit a namespace or the global scope, then the - // nested-name-specifier can't refer to the current instantiation. - if (Ctx->isFileContext()) - return 0; - - // Skip non-class contexts. - CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx); - if (!Record) - continue; - - // If this record type is not dependent, - if (!Record->isDependentType()) - return 0; - - // C++ [temp.dep.type]p1: - // - // In the definition of a class template, a nested class of a - // class template, a member of a class template, or a member of a - // nested class of a class template, a name refers to the current - // instantiation if it is - // -- the injected-class-name (9) of the class template or - // nested class, - // -- in the definition of a primary class template, the name - // of the class template followed by the template argument - // list of the primary template (as described below) - // enclosed in <>, - // -- in the definition of a nested class of a class template, - // the name of the nested class referenced as a member of - // the current instantiation, or - // -- in the definition of a partial specialization, the name - // of the class template followed by the template argument - // list of the partial specialization enclosed in <>. If - // the nth template parameter is a parameter pack, the nth - // template argument is a pack expansion (14.6.3) whose - // pattern is the name of the parameter pack. - // (FIXME: parameter packs) - // - // All of these options come down to having the - // nested-name-specifier type that is equivalent to the - // injected-class-name of one of the types that is currently in - // our context. - if (Context.getCanonicalType(Context.getTypeDeclType(Record)) == T) - return Record; - - if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) { - QualType InjectedClassName - = Template->getInjectedClassNameType(Context); - if (T == Context.getCanonicalType(InjectedClassName)) - return Template->getTemplatedDecl(); - } - // FIXME: check for class template partial specializations - } - - return 0; + return ::getCurrentInstantiationOf(Context, CurContext, T); } /// \brief Require that the context specified by SS be complete. diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index bc255137fccf..b8977cfa142d 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -971,10 +971,70 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, RParenLoc, ClassDecl); } +/// Checks an initializer expression for use of uninitialized fields, such as +/// containing the field that is being initialized. Returns true if there is an +/// uninitialized field was used an updates the SourceLocation parameter; false +/// otherwise. +static bool InitExprContainsUninitializedFields(const Stmt* S, + const FieldDecl* LhsField, + SourceLocation* L) { + const MemberExpr* ME = dyn_cast<MemberExpr>(S); + if (ME) { + const NamedDecl* RhsField = ME->getMemberDecl(); + if (RhsField == LhsField) { + // Initializing a field with itself. Throw a warning. + // But wait; there are exceptions! + // Exception #1: The field may not belong to this record. + // e.g. Foo(const Foo& rhs) : A(rhs.A) {} + const Expr* base = ME->getBase(); + if (base != NULL && !isa<CXXThisExpr>(base->IgnoreParenCasts())) { + // Even though the field matches, it does not belong to this record. + return false; + } + // None of the exceptions triggered; return true to indicate an + // uninitialized field was used. + *L = ME->getMemberLoc(); + return true; + } + } + bool found = false; + for (Stmt::const_child_iterator it = S->child_begin(); + it != S->child_end() && found == false; + ++it) { + if (isa<CallExpr>(S)) { + // Do not descend into function calls or constructors, as the use + // of an uninitialized field may be valid. One would have to inspect + // the contents of the function/ctor to determine if it is safe or not. + // i.e. Pass-by-value is never safe, but pass-by-reference and pointers + // may be safe, depending on what the function/ctor does. + continue; + } + found = InitExprContainsUninitializedFields(*it, LhsField, L); + } + return found; +} + Sema::MemInitResult Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs, SourceLocation IdLoc, SourceLocation RParenLoc) { + // Diagnose value-uses of fields to initialize themselves, e.g. + // foo(foo) + // where foo is not also a parameter to the constructor. + // TODO: implement -Wuninitialized and fold this into that framework. + for (unsigned i = 0; i < NumArgs; ++i) { + SourceLocation L; + if (InitExprContainsUninitializedFields(Args[i], Member, &L)) { + // FIXME: Return true in the case when other fields are used before being + // uninitialized. For example, let this field be the i'th field. When + // initializing the i'th field, throw a warning if any of the >= i'th + // fields are used, as they are not yet initialized. + // Right now we are only handling the case where the i'th field uses + // itself in its initializer. + Diag(L, diag::warn_field_is_uninit); + } + } + bool HasDependentArg = false; for (unsigned i = 0; i < NumArgs; i++) HasDependentArg |= Args[i]->isTypeDependent(); @@ -985,7 +1045,9 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, FieldType = Array->getElementType(); if (FieldType->isDependentType()) { // Can't check init for dependent type. - } else if (FieldType->getAs<RecordType>()) { + } else if (FieldType->isRecordType()) { + // Member is a record (struct/union/class), so pass the initializer + // arguments down to the record's constructor. if (!HasDependentArg) { ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); @@ -1005,6 +1067,8 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, } } } else if (NumArgs != 1 && NumArgs != 0) { + // The member type is not a record type (or an array of record + // types), so it can be only be default- or copy-initialized. return Diag(IdLoc, diag::err_mem_initializer_mismatch) << Member->getDeclName() << SourceRange(IdLoc, RParenLoc); } else if (!HasDependentArg) { @@ -1158,7 +1222,7 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, // On seeing one dependent type, we should essentially exit this routine // while preserving user-declared initializer list. When this routine is // called during instantiatiation process, this routine will rebuild the - // oderdered initializer list correctly. + // ordered initializer list correctly. // If we have a dependent base initialization, we can't determine the // association between initializers and bases; just dump the known @@ -1293,11 +1357,16 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, continue; } + if ((*Field)->getType()->isDependentType()) { + Fields.push_back(*Field); + continue; + } + QualType FT = Context.getBaseElementType((*Field)->getType()); if (const RecordType* RT = FT->getAs<RecordType>()) { CXXConstructorDecl *Ctor = cast<CXXRecordDecl>(RT->getDecl())->getDefaultConstructor(Context); - if (!Ctor && !FT->isDependentType()) { + if (!Ctor) { Fields.push_back(*Field); continue; } @@ -1357,12 +1426,16 @@ Sema::BuildBaseOrMemberInitializers(ASTContext &C, SetBaseOrMemberInitializers(Constructor, Initializers, NumInitializers, Bases, Members); - for (unsigned int i = 0; i < Bases.size(); i++) - Diag(Bases[i]->getSourceRange().getBegin(), - diag::err_missing_default_constructor) << 0 << Bases[i]->getType(); - for (unsigned int i = 0; i < Members.size(); i++) - Diag(Members[i]->getLocation(), diag::err_missing_default_constructor) - << 1 << Members[i]->getType(); + for (unsigned int i = 0; i < Bases.size(); i++) { + if (!Bases[i]->getType()->isDependentType()) + Diag(Bases[i]->getSourceRange().getBegin(), + diag::err_missing_default_constructor) << 0 << Bases[i]->getType(); + } + for (unsigned int i = 0; i < Members.size(); i++) { + if (!Members[i]->getType()->isDependentType()) + Diag(Members[i]->getLocation(), diag::err_missing_default_constructor) + << 1 << Members[i]->getType(); + } } static void *GetKeyForTopLevelField(FieldDecl *Field) { @@ -1405,6 +1478,7 @@ static void *GetKeyForMember(CXXBaseOrMemberInitializer *Member, return GetKeyForBase(QualType(Member->getBaseClass(), 0)); } +/// ActOnMemInitializers - Handle the member initializers for a constructor. void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, SourceLocation ColonLoc, MemInitTy **MemInits, unsigned NumMemInits) { @@ -2700,22 +2774,37 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, const CXXScopeSpec &SS, - SourceLocation IdentLoc, - IdentifierInfo *TargetName, - OverloadedOperatorKind Op, + UnqualifiedId &Name, AttributeList *AttrList, bool IsTypeName) { - assert((TargetName || Op) && "Invalid TargetName."); assert(S->getFlags() & Scope::DeclScope && "Invalid Scope."); - DeclarationName Name; - if (TargetName) - Name = TargetName; - else - Name = Context.DeclarationNames.getCXXOperatorName(Op); - - NamedDecl *UD = BuildUsingDeclaration(UsingLoc, SS, IdentLoc, - Name, AttrList, IsTypeName); + switch (Name.getKind()) { + case UnqualifiedId::IK_Identifier: + case UnqualifiedId::IK_OperatorFunctionId: + case UnqualifiedId::IK_ConversionFunctionId: + break; + + case UnqualifiedId::IK_ConstructorName: + Diag(Name.getSourceRange().getBegin(), diag::err_using_decl_constructor) + << SS.getRange(); + return DeclPtrTy(); + + case UnqualifiedId::IK_DestructorName: + Diag(Name.getSourceRange().getBegin(), diag::err_using_decl_destructor) + << SS.getRange(); + return DeclPtrTy(); + + case UnqualifiedId::IK_TemplateId: + Diag(Name.getSourceRange().getBegin(), diag::err_using_decl_template_id) + << SourceRange(Name.TemplateId->LAngleLoc, Name.TemplateId->RAngleLoc); + return DeclPtrTy(); + } + + DeclarationName TargetName = GetNameFromUnqualifiedId(Name); + NamedDecl *UD = BuildUsingDeclaration(UsingLoc, SS, + Name.getSourceRange().getBegin(), + TargetName, AttrList, IsTypeName); if (UD) { PushOnScopeChains(UD, S); UD->setAccess(AS); @@ -3515,14 +3604,15 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, /// type, and the first type (T1) is the pointee type of the reference /// type being initialized. Sema::ReferenceCompareResult -Sema::CompareReferenceRelationship(QualType T1, QualType T2, +Sema::CompareReferenceRelationship(SourceLocation Loc, + QualType OrigT1, QualType OrigT2, bool& DerivedToBase) { - assert(!T1->isReferenceType() && + assert(!OrigT1->isReferenceType() && "T1 must be the pointee type of the reference type"); - assert(!T2->isReferenceType() && "T2 cannot be a reference type"); + assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type"); - T1 = Context.getCanonicalType(T1); - T2 = Context.getCanonicalType(T2); + QualType T1 = Context.getCanonicalType(OrigT1); + QualType T2 = Context.getCanonicalType(OrigT2); QualType UnqualT1 = T1.getUnqualifiedType(); QualType UnqualT2 = T2.getUnqualifiedType(); @@ -3532,7 +3622,9 @@ Sema::CompareReferenceRelationship(QualType T1, QualType T2, // T1 is a base class of T2. if (UnqualT1 == UnqualT2) DerivedToBase = false; - else if (IsDerivedFrom(UnqualT2, UnqualT1)) + else if (!RequireCompleteType(Loc, OrigT1, PDiag()) && + !RequireCompleteType(Loc, OrigT2, PDiag()) && + IsDerivedFrom(UnqualT2, UnqualT1)) DerivedToBase = true; else return Ref_Incompatible; @@ -3608,7 +3700,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, Expr::isLvalueResult InitLvalue = ForceRValue ? Expr::LV_InvalidExpression : Init->isLvalue(Context); ReferenceCompareResult RefRelationship - = CompareReferenceRelationship(T1, T2, DerivedToBase); + = CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase); // Most paths end in a failed conversion. if (ICS) diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index ac7cced2eaef..f1d6f2bb17ce 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -3340,6 +3340,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (getLangOptions().CPlusPlus) return CXXCheckConditionalOperands(Cond, LHS, RHS, QuestionLoc); + CheckSignCompare(LHS, RHS, QuestionLoc, diag::warn_mixed_sign_conditional); + UsualUnaryConversions(Cond); UsualUnaryConversions(LHS); UsualUnaryConversions(RHS); @@ -4427,6 +4429,41 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, return LHSTy; } +/// Implements -Wsign-compare. +void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc, + const PartialDiagnostic &PD) { + QualType lt = lex->getType(), rt = rex->getType(); + + // Only warn if both operands are integral. + if (!lt->isIntegerType() || !rt->isIntegerType()) + return; + + // The rule is that the signed operand becomes unsigned, so isolate the + // signed operand. + Expr *signedOperand; + if (lt->isSignedIntegerType()) { + if (rt->isSignedIntegerType()) return; + signedOperand = lex; + } else { + if (!rt->isSignedIntegerType()) return; + signedOperand = rex; + } + + // If the value is a non-negative integer constant, then the + // signed->unsigned conversion won't change it. + llvm::APSInt value; + if (signedOperand->isIntegerConstantExpr(value, Context)) { + assert(value.isSigned() && "result of signed expression not signed"); + + if (value.isNonNegative()) + return; + } + + Diag(OpLoc, PD) + << lex->getType() << rex->getType() + << lex->getSourceRange() << rex->getSourceRange(); +} + // C99 6.5.8, C++ [expr.rel] QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, unsigned OpaqueOpc, bool isRelational) { @@ -4435,6 +4472,8 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) return CheckVectorCompareOperands(lex, rex, Loc, isRelational); + CheckSignCompare(lex, rex, Loc, diag::warn_mixed_sign_comparison); + // C99 6.5.8p3 / C99 6.5.9p4 if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) UsualArithmeticConversions(lex, rex); @@ -5472,6 +5511,12 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, // Emit warnings for tricky precedence issues, e.g. "bitfield & 0x4 == 0" DiagnoseBinOpPrecedence(*this, Opc, TokLoc, lhs, rhs); + return BuildBinOp(S, TokLoc, Opc, lhs, rhs); +} + +Action::OwningExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, + BinaryOperator::Opcode Opc, + Expr *lhs, Expr *rhs) { if (getLangOptions().CPlusPlus && (lhs->getType()->isOverloadableType() || rhs->getType()->isOverloadableType())) { @@ -5482,21 +5527,22 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, FunctionSet Functions; OverloadedOperatorKind OverOp = BinaryOperator::getOverloadedOperator(Opc); if (OverOp != OO_None) { - LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(), - Functions); + if (S) + LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(), + Functions); Expr *Args[2] = { lhs, rhs }; DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OverOp); ArgumentDependentLookup(OpName, /*Operator*/true, Args, 2, Functions); } - + // Build the (potentially-overloaded, potentially-dependent) // binary operation. - return CreateOverloadedBinOp(TokLoc, Opc, Functions, lhs, rhs); + return CreateOverloadedBinOp(OpLoc, Opc, Functions, lhs, rhs); } - + // Build a built-in binary operation. - return CreateBuiltinBinOp(TokLoc, Opc, lhs, rhs); + return CreateBuiltinBinOp(OpLoc, Opc, lhs, rhs); } Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, @@ -5587,12 +5633,10 @@ Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, return Owned(new (Context) UnaryOperator(Input, Opc, resultType, OpLoc)); } -// Unary Operators. 'Tok' is the token for the operator. -Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, - tok::TokenKind Op, ExprArg input) { +Action::OwningExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, + UnaryOperator::Opcode Opc, + ExprArg input) { Expr *Input = (Expr*)input.get(); - UnaryOperator::Opcode Opc = ConvertTokenKindToUnaryOpcode(Op); - if (getLangOptions().CPlusPlus && Input->getType()->isOverloadableType()) { // Find all of the overloaded operators visible from this // point. We perform both an operator-name lookup from the local @@ -5601,19 +5645,26 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, FunctionSet Functions; OverloadedOperatorKind OverOp = UnaryOperator::getOverloadedOperator(Opc); if (OverOp != OO_None) { - LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(), - Functions); + if (S) + LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(), + Functions); DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OverOp); ArgumentDependentLookup(OpName, /*Operator*/true, &Input, 1, Functions); } - + return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(input)); } - + return CreateBuiltinUnaryOp(OpLoc, Opc, move(input)); } +// Unary Operators. 'Tok' is the token for the operator. +Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, + tok::TokenKind Op, ExprArg input) { + return BuildUnaryOp(S, OpLoc, ConvertTokenKindToUnaryOpcode(Op), move(input)); +} + /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". Sema::OwningExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 4868c14835f4..dc5768157356 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1603,6 +1603,8 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (LHS->isTypeDependent() || RHS->isTypeDependent()) return Context.DependentTy; + CheckSignCompare(LHS, RHS, QuestionLoc, diag::warn_mixed_sign_conditional); + // C++0x 5.16p2 // If either the second or the third operand has type (cv) void, ... QualType LTy = LHS->getType(); @@ -2030,7 +2032,13 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, QualType BaseType = BaseExpr->getType(); if (BaseType->isDependentType()) { - // FIXME: member of the current instantiation + // If we have a pointer to a dependent type and are using the -> operator, + // the object type is the type that the pointer points to. We might still + // have enough information about that type to do something useful. + if (OpKind == tok::arrow) + if (const PointerType *Ptr = BaseType->getAs<PointerType>()) + BaseType = Ptr->getPointeeType(); + ObjectType = BaseType.getAsOpaquePtr(); return move(Base); } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 946e28269eb6..3e6778bc4770 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1387,8 +1387,10 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion( bool AllowExplicit, bool ForceRValue, bool UserCast) { if (const RecordType *ToRecordType = ToType->getAs<RecordType>()) { - if (CXXRecordDecl *ToRecordDecl - = dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) { + if (RequireCompleteType(From->getLocStart(), ToType, PDiag())) { + // We're not going to find any constructors. + } else if (CXXRecordDecl *ToRecordDecl + = dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) { // C++ [over.match.ctor]p1: // When objects of class type are direct-initialized (8.5), or // copy-initialized from an expression of the same or a @@ -2097,8 +2099,8 @@ Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) { // First check the qualifiers. We don't care about lvalue-vs-rvalue // with the implicit object parameter (C++ [over.match.funcs]p5). QualType FromTypeCanon = Context.getCanonicalType(FromType); - if (ImplicitParamType.getCVRQualifiers() != FromType.getCVRQualifiers() && - !ImplicitParamType.isAtLeastAsQualifiedAs(FromType)) + if (ImplicitParamType.getCVRQualifiers() != FromTypeCanon.getCVRQualifiers() && + !ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) return ICS; // Check that we have either the same type or a derived type. It @@ -3050,6 +3052,10 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, // We don't care about qualifiers on the type. Ty = Ty.getUnqualifiedType(); + // If we're dealing with an array type, decay to the pointer. + if (Ty->isArrayType()) + Ty = SemaRef.Context.getArrayDecayedType(Ty); + if (const PointerType *PointerTy = Ty->getAs<PointerType>()) { QualType PointeeTy = PointerTy->getPointeeType(); @@ -4787,11 +4793,20 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // If either side is type-dependent, create an appropriate dependent // expression. if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) { - // .* cannot be overloaded. - if (Opc == BinaryOperator::PtrMemD) - return Owned(new (Context) BinaryOperator(Args[0], Args[1], Opc, - Context.DependentTy, OpLoc)); - + if (Functions.empty()) { + // If there are no functions to store, just build a dependent + // BinaryOperator or CompoundAssignment. + if (Opc <= BinaryOperator::Assign || Opc > BinaryOperator::OrAssign) + return Owned(new (Context) BinaryOperator(Args[0], Args[1], Opc, + Context.DependentTy, OpLoc)); + + return Owned(new (Context) CompoundAssignOperator(Args[0], Args[1], Opc, + Context.DependentTy, + Context.DependentTy, + Context.DependentTy, + OpLoc)); + } + OverloadedFunctionDecl *Overloads = OverloadedFunctionDecl::Create(Context, CurContext, OpName); for (FunctionSet::iterator Func = Functions.begin(), diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 3c56358d5a94..5ef370104dd9 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1995,7 +1995,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, ArgType = Context.getCanonicalType(ArgType).getUnqualifiedType(); // Try to convert the argument to the parameter's type. - if (ParamType == ArgType) { + if (Context.hasSameType(ParamType, ArgType)) { // Okay: no conversion necessary } else if (IsIntegralPromotion(Arg, ArgType, ParamType) || !ParamType->isEnumeralType()) { diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 0003b1b0c419..f003127f149f 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -22,6 +22,7 @@ #include "clang/Basic/PartialDiagnostic.h" #include "clang/Parse/DeclSpec.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Support/ErrorHandling.h" using namespace clang; /// \brief Perform adjustment on the parameter type of a function. @@ -562,9 +563,17 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, SourceLocation Loc = Brackets.getBegin(); // C99 6.7.5.2p1: If the element type is an incomplete or function type, // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]()) - if (RequireCompleteType(Loc, T, - diag::err_illegal_decl_array_incomplete_type)) - return QualType(); + // Not in C++, though. There we only dislike void. + if (getLangOptions().CPlusPlus) { + if (T->isVoidType()) { + Diag(Loc, diag::err_illegal_decl_array_incomplete_type) << T; + return QualType(); + } + } else { + if (RequireCompleteType(Loc, T, + diag::err_illegal_decl_array_incomplete_type)) + return QualType(); + } if (T->isFunctionType()) { Diag(Loc, diag::err_illegal_decl_array_of_functions) @@ -612,24 +621,24 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, } else if (ArraySize->isValueDependent()) { T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals, Brackets); } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) || - (!T->isDependentType() && !T->isConstantSizeType())) { + (!T->isDependentType() && !T->isIncompleteType() && + !T->isConstantSizeType())) { // Per C99, a variable array is an array with either a non-constant // size or an element type that has a non-constant-size T = Context.getVariableArrayType(T, ArraySize, ASM, Quals, Brackets); } else { // C99 6.7.5.2p1: If the expression is a constant expression, it shall // have a value greater than zero. - if (ConstVal.isSigned()) { - if (ConstVal.isNegative()) { - Diag(ArraySize->getLocStart(), - diag::err_typecheck_negative_array_size) - << ArraySize->getSourceRange(); - return QualType(); - } else if (ConstVal == 0) { - // GCC accepts zero sized static arrays. - Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size) - << ArraySize->getSourceRange(); - } + if (ConstVal.isSigned() && ConstVal.isNegative()) { + Diag(ArraySize->getLocStart(), + diag::err_typecheck_negative_array_size) + << ArraySize->getSourceRange(); + return QualType(); + } + if (ConstVal == 0) { + // GCC accepts zero sized static arrays. + Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size) + << ArraySize->getSourceRange(); } T = Context.getConstantArrayType(T, ConstVal, ASM, Quals); } @@ -1162,15 +1171,29 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } // The scope spec must refer to a class, or be dependent. QualType ClsType; - if (isDependentScopeSpecifier(DeclType.Mem.Scope())) { + if (isDependentScopeSpecifier(DeclType.Mem.Scope()) + || dyn_cast_or_null<CXXRecordDecl>( + computeDeclContext(DeclType.Mem.Scope()))) { NestedNameSpecifier *NNS = (NestedNameSpecifier *)DeclType.Mem.Scope().getScopeRep(); - assert(NNS->getAsType() && "Nested-name-specifier must name a type"); - ClsType = QualType(NNS->getAsType(), 0); - } else if (CXXRecordDecl *RD - = dyn_cast_or_null<CXXRecordDecl>( - computeDeclContext(DeclType.Mem.Scope()))) { - ClsType = Context.getTagDeclType(RD); + NestedNameSpecifier *NNSPrefix = NNS->getPrefix(); + switch (NNS->getKind()) { + case NestedNameSpecifier::Identifier: + ClsType = Context.getTypenameType(NNSPrefix, NNS->getAsIdentifier()); + break; + + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::Global: + llvm::llvm_unreachable("Nested-name-specifier must name a type"); + break; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + ClsType = QualType(NNS->getAsType(), 0); + if (NNSPrefix) + ClsType = Context.getQualifiedNameType(NNSPrefix, ClsType); + break; + } } else { Diag(DeclType.Mem.Scope().getBeginLoc(), diag::err_illegal_decl_mempointer_in_nonclass) @@ -1677,8 +1700,12 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, return false; // If we have a class template specialization or a class member of a - // class template specialization, try to instantiate it. - if (const RecordType *Record = T->getAs<RecordType>()) { + // class template specialization, or an array with known size of such, + // try to instantiate it. + QualType MaybeTemplate = T; + if (const ConstantArrayType *Array = T->getAs<ConstantArrayType>()) + MaybeTemplate = Array->getElementType(); + if (const RecordType *Record = MaybeTemplate->getAs<RecordType>()) { if (ClassTemplateSpecializationDecl *ClassTemplateSpec = dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) { if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 5713da9fa590..767725a1f318 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -877,7 +877,7 @@ public: OwningExprResult RebuildUnaryOperator(SourceLocation OpLoc, UnaryOperator::Opcode Opc, ExprArg SubExpr) { - return getSema().CreateBuiltinUnaryOp(OpLoc, Opc, move(SubExpr)); + return getSema().BuildUnaryOp(/*Scope=*/0, OpLoc, Opc, move(SubExpr)); } /// \brief Build a new sizeof or alignof expression with a type argument. @@ -941,7 +941,13 @@ public: NestedNameSpecifier *Qualifier, SourceRange QualifierRange, SourceLocation MemberLoc, - NamedDecl *Member) { + NamedDecl *Member, + bool HasExplicitTemplateArgs, + SourceLocation LAngleLoc, + const TemplateArgumentLoc *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + SourceLocation RAngleLoc, + NamedDecl *FirstQualifierInScope) { if (!Member->getDeclName()) { // We have a reference to an unnamed field. assert(!Qualifier && "Can't have an unnamed field with a qualifier!"); @@ -963,8 +969,14 @@ public: isArrow? tok::arrow : tok::period, MemberLoc, Member->getDeclName(), + HasExplicitTemplateArgs, + LAngleLoc, + ExplicitTemplateArgs, + NumExplicitTemplateArgs, + RAngleLoc, /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0), - &SS); + &SS, + FirstQualifierInScope); } /// \brief Build a new binary operator expression. @@ -974,15 +986,8 @@ public: OwningExprResult RebuildBinaryOperator(SourceLocation OpLoc, BinaryOperator::Opcode Opc, ExprArg LHS, ExprArg RHS) { - OwningExprResult Result - = getSema().CreateBuiltinBinOp(OpLoc, Opc, (Expr *)LHS.get(), - (Expr *)RHS.get()); - if (Result.isInvalid()) - return SemaRef.ExprError(); - - LHS.release(); - RHS.release(); - return move(Result); + return getSema().BuildBinOp(/*Scope=*/0, OpLoc, Opc, + LHS.takeAs<Expr>(), RHS.takeAs<Expr>()); } /// \brief Build a new conditional operator expression. @@ -3656,9 +3661,20 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E, if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase() && Qualifier == E->getQualifier() && - Member == E->getMemberDecl()) + Member == E->getMemberDecl() && + !E->hasExplicitTemplateArgumentList()) return SemaRef.Owned(E->Retain()); + llvm::SmallVector<TemplateArgumentLoc, 4> TransArgs; + if (E->hasExplicitTemplateArgumentList()) { + TransArgs.resize(E->getNumTemplateArgs()); + for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { + if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], + TransArgs[I])) + return SemaRef.ExprError(); + } + } + // FIXME: Bogus source location for the operator SourceLocation FakeOperatorLoc = SemaRef.PP.getLocForEndOfToken(E->getBase()->getSourceRange().getEnd()); @@ -3668,7 +3684,13 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E, Qualifier, E->getQualifierRange(), E->getMemberLoc(), - Member); + Member, + E->hasExplicitTemplateArgumentList(), + E->getLAngleLoc(), + TransArgs.data(), + TransArgs.size(), + E->getRAngleLoc(), + 0); } template<typename Derived> |