diff options
author | Roman Divacky <rdivacky@FreeBSD.org> | 2009-11-18 14:59:57 +0000 |
---|---|---|
committer | Roman Divacky <rdivacky@FreeBSD.org> | 2009-11-18 14:59:57 +0000 |
commit | b3d5a323a5ca92ea73443499cee2f15db1ff0fb3 (patch) | |
tree | 60a1694bec5a44d15456acc880cb2f91619f66aa /lib | |
parent | 8f57cb0305232cb53fff00ef151ca716766f3437 (diff) | |
download | src-b3d5a323a5ca92ea73443499cee2f15db1ff0fb3.tar.gz src-b3d5a323a5ca92ea73443499cee2f15db1ff0fb3.zip |
Update clang to r89205.
Notes
Notes:
svn path=/vendor/clang/dist/; revision=199482
Diffstat (limited to 'lib')
173 files changed, 13844 insertions, 5596 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 8562249479ca..dc13e7f4688c 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -35,7 +35,7 @@ enum FloatingRank { }; ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, - TargetInfo &t, + const TargetInfo &t, IdentifierTable &idents, SelectorTable &sels, Builtin::Context &builtins, bool FreeMem, unsigned size_reserve) : @@ -256,9 +256,9 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl, = new (*this) MemberSpecializationInfo(Tmpl, TSK); } -UnresolvedUsingDecl * +NamedDecl * ASTContext::getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD) { - llvm::DenseMap<UsingDecl *, UnresolvedUsingDecl *>::iterator Pos + llvm::DenseMap<UsingDecl *, NamedDecl *>::const_iterator Pos = InstantiatedFromUnresolvedUsingDecl.find(UUD); if (Pos == InstantiatedFromUnresolvedUsingDecl.end()) return 0; @@ -268,7 +268,10 @@ ASTContext::getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD) { void ASTContext::setInstantiatedFromUnresolvedUsingDecl(UsingDecl *UD, - UnresolvedUsingDecl *UUD) { + NamedDecl *UUD) { + assert((isa<UnresolvedUsingValueDecl>(UUD) || + isa<UnresolvedUsingTypenameDecl>(UUD)) && + "original declaration is not an unresolved using decl"); assert(!InstantiatedFromUnresolvedUsingDecl[UD] && "Already noted what using decl what instantiated from"); InstantiatedFromUnresolvedUsingDecl[UD] = UUD; @@ -1186,7 +1189,7 @@ QualType ASTContext::getNoReturnType(QualType T) { } } - return getQualifiedType(ResultType, T.getQualifiers()); + return getQualifiedType(ResultType, T.getLocalQualifiers()); } /// getComplexType - Return the uniqued reference to the type for a complex @@ -2350,6 +2353,12 @@ TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) { return DTN->CanonicalTemplateName; } +bool ASTContext::hasSameTemplateName(TemplateName X, TemplateName Y) { + X = getCanonicalTemplateName(X); + Y = getCanonicalTemplateName(Y); + return X.getAsVoidPointer() == Y.getAsVoidPointer(); +} + TemplateArgument ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) { switch (Arg.getKind()) { @@ -2357,12 +2366,14 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) { return Arg; case TemplateArgument::Expression: - // FIXME: Build canonical expression? return Arg; case TemplateArgument::Declaration: return TemplateArgument(Arg.getAsDecl()->getCanonicalDecl()); + case TemplateArgument::Template: + return TemplateArgument(getCanonicalTemplateName(Arg.getAsTemplate())); + case TemplateArgument::Integral: return TemplateArgument(*Arg.getAsIntegral(), getCanonicalType(Arg.getIntegralType())); @@ -2427,7 +2438,7 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) { const ArrayType *ASTContext::getAsArrayType(QualType T) { // Handle the non-qualified case efficiently. - if (!T.hasQualifiers()) { + if (!T.hasLocalQualifiers()) { // Handle the common positive case fast. if (const ArrayType *AT = dyn_cast<ArrayType>(T)) return AT; @@ -2732,12 +2743,22 @@ int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) { return 1; } +static RecordDecl * +CreateRecordDecl(ASTContext &Ctx, RecordDecl::TagKind TK, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id) { + if (Ctx.getLangOptions().CPlusPlus) + return CXXRecordDecl::Create(Ctx, TK, DC, L, Id); + else + return RecordDecl::Create(Ctx, TK, DC, L, Id); +} + // getCFConstantStringType - Return the type used for constant CFStrings. QualType ASTContext::getCFConstantStringType() { if (!CFConstantStringTypeDecl) { CFConstantStringTypeDecl = - RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), - &Idents.get("NSConstantString")); + CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + &Idents.get("NSConstantString")); + QualType FieldTypes[4]; // const int *isa; @@ -2774,8 +2795,8 @@ void ASTContext::setCFConstantStringType(QualType T) { QualType ASTContext::getObjCFastEnumerationStateType() { if (!ObjCFastEnumerationStateTypeDecl) { ObjCFastEnumerationStateTypeDecl = - RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), - &Idents.get("__objcFastEnumerationState")); + CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + &Idents.get("__objcFastEnumerationState")); QualType FieldTypes[] = { UnsignedLongTy, @@ -2807,8 +2828,8 @@ QualType ASTContext::getBlockDescriptorType() { RecordDecl *T; // FIXME: Needs the FlagAppleBlock bit. - T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), - &Idents.get("__block_descriptor")); + T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + &Idents.get("__block_descriptor")); QualType FieldTypes[] = { UnsignedLongTy, @@ -2850,8 +2871,8 @@ QualType ASTContext::getBlockDescriptorExtendedType() { RecordDecl *T; // FIXME: Needs the FlagAppleBlock bit. - T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), - &Idents.get("__block_descriptor_withcopydispose")); + T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + &Idents.get("__block_descriptor_withcopydispose")); QualType FieldTypes[] = { UnsignedLongTy, @@ -2920,8 +2941,8 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) { llvm::raw_svector_ostream(Name) << "__Block_byref_" << ++UniqueBlockByRefTypeID << '_' << DeclName; RecordDecl *T; - T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), - &Idents.get(Name.str())); + T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + &Idents.get(Name.str())); T->startDefinition(); QualType Int32Ty = IntTy; assert(getIntWidth(IntTy) == 32 && "non-32bit int not supported"); @@ -2970,8 +2991,8 @@ QualType ASTContext::getBlockParmType( llvm::raw_svector_ostream(Name) << "__block_literal_" << ++UniqueBlockParmTypeID; RecordDecl *T; - T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), - &Idents.get(Name.str())); + T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + &Idents.get(Name.str())); QualType FieldTypes[] = { getPointerType(VoidPtrTy), IntTy, @@ -3053,6 +3074,54 @@ int ASTContext::getObjCEncodingTypeSize(QualType type) { return sz / getTypeSize(CharTy); } +/// getObjCEncodingForBlockDecl - Return the encoded type for this method +/// declaration. +void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr, + std::string& S) { + const BlockDecl *Decl = Expr->getBlockDecl(); + QualType BlockTy = + Expr->getType()->getAs<BlockPointerType>()->getPointeeType(); + // Encode result type. + getObjCEncodingForType(cast<FunctionType>(BlockTy)->getResultType(), S); + // Compute size of all parameters. + // Start with computing size of a pointer in number of bytes. + // FIXME: There might(should) be a better way of doing this computation! + SourceLocation Loc; + int PtrSize = getTypeSize(VoidPtrTy) / getTypeSize(CharTy); + int ParmOffset = PtrSize; + for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(), + E = Decl->param_end(); PI != E; ++PI) { + QualType PType = (*PI)->getType(); + int sz = getObjCEncodingTypeSize(PType); + assert (sz > 0 && "BlockExpr - Incomplete param type"); + ParmOffset += sz; + } + // Size of the argument frame + S += llvm::utostr(ParmOffset); + // Block pointer and offset. + S += "@?0"; + ParmOffset = PtrSize; + + // Argument types. + ParmOffset = PtrSize; + for (BlockDecl::param_const_iterator PI = Decl->param_begin(), E = + Decl->param_end(); PI != E; ++PI) { + ParmVarDecl *PVDecl = *PI; + QualType PType = PVDecl->getOriginalType(); + if (const ArrayType *AT = + dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) { + // Use array's original type only if it has known number of + // elements. + if (!isa<ConstantArrayType>(AT)) + PType = PVDecl->getType(); + } else if (PType->isFunctionType()) + PType = PVDecl->getType(); + getObjCEncodingForType(PType, S); + S += llvm::utostr(ParmOffset); + ParmOffset += getObjCEncodingTypeSize(PType); + } +} + /// getObjCEncodingForMethodDecl - Return the encoded type for this method /// declaration. void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, @@ -4186,8 +4255,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { return LHS; // If the qualifiers are different, the types aren't compatible... mostly. - Qualifiers LQuals = LHSCan.getQualifiers(); - Qualifiers RQuals = RHSCan.getQualifiers(); + Qualifiers LQuals = LHSCan.getLocalQualifiers(); + Qualifiers RQuals = RHSCan.getLocalQualifiers(); if (LQuals != RQuals) { // If any of these qualifiers are different, we have a type // mismatch. @@ -4394,7 +4463,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { //===----------------------------------------------------------------------===// unsigned ASTContext::getIntWidth(QualType T) { - if (T == BoolTy) + if (T->isBooleanType()) return 1; if (FixedWidthIntType *FWIT = dyn_cast<FixedWidthIntType>(T)) { return FWIT->getWidth(); diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index e541406790a6..0f0b22d65f6f 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -30,6 +30,7 @@ add_clang_library(clangAST TemplateName.cpp Type.cpp TypeLoc.cpp + TypePrinter.cpp ) add_dependencies(clangAST ClangDiagnosticAST) diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index b59b45f6467e..023bca436339 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -76,31 +76,31 @@ void CXXBasePaths::swap(CXXBasePaths &Other) { std::swap(DetectedVirtual, Other.DetectedVirtual); } -bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base) { +bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base) const { CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false, /*DetectVirtual=*/false); return isDerivedFrom(Base, Paths); } -bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) { +bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) const { if (getCanonicalDecl() == Base->getCanonicalDecl()) return false; - Paths.setOrigin(this); + Paths.setOrigin(const_cast<CXXRecordDecl*>(this)); return lookupInBases(&FindBaseClass, Base->getCanonicalDecl(), Paths); } bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, void *UserData, - CXXBasePaths &Paths) { + CXXBasePaths &Paths) const { bool FoundPath = false; ASTContext &Context = getASTContext(); - for (base_class_iterator BaseSpec = bases_begin(), BaseSpecEnd = bases_end(); - BaseSpec != BaseSpecEnd; ++BaseSpec) { + for (base_class_const_iterator BaseSpec = bases_begin(), + BaseSpecEnd = bases_end(); BaseSpec != BaseSpecEnd; ++BaseSpec) { // Find the record of the base class subobjects for this type. - QualType BaseType = Context.getCanonicalType(BaseSpec->getType()); - BaseType = BaseType.getUnqualifiedType(); + QualType BaseType = Context.getCanonicalType(BaseSpec->getType()) + .getUnqualifiedType(); // C++ [temp.dep]p3: // In the definition of a class template or a member of a class template, @@ -183,7 +183,7 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, return FoundPath; } -bool CXXRecordDecl::FindBaseClass(CXXBaseSpecifier *Specifier, +bool CXXRecordDecl::FindBaseClass(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, void *BaseRecord) { assert(((Decl *)BaseRecord)->getCanonicalDecl() == BaseRecord && @@ -192,7 +192,7 @@ bool CXXRecordDecl::FindBaseClass(CXXBaseSpecifier *Specifier, ->getCanonicalDecl() == BaseRecord; } -bool CXXRecordDecl::FindTagMember(CXXBaseSpecifier *Specifier, +bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, void *Name) { RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); @@ -208,7 +208,7 @@ bool CXXRecordDecl::FindTagMember(CXXBaseSpecifier *Specifier, return false; } -bool CXXRecordDecl::FindOrdinaryMember(CXXBaseSpecifier *Specifier, +bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, void *Name) { RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); @@ -225,9 +225,10 @@ bool CXXRecordDecl::FindOrdinaryMember(CXXBaseSpecifier *Specifier, return false; } -bool CXXRecordDecl::FindNestedNameSpecifierMember(CXXBaseSpecifier *Specifier, - CXXBasePath &Path, - void *Name) { +bool CXXRecordDecl:: +FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *Name) { RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); DeclarationName N = DeclarationName::getFromOpaquePtr(Name); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index a6996a4bfe5c..bdc804722c41 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -289,6 +289,10 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { if (isa<ObjCInterfaceDecl>(this) && isa<ObjCCompatibleAliasDecl>(OldD)) return true; + if (isa<UsingShadowDecl>(this) && isa<UsingShadowDecl>(OldD)) + return cast<UsingShadowDecl>(this)->getTargetDecl() == + cast<UsingShadowDecl>(OldD)->getTargetDecl(); + // For non-function declarations, if the declarations are of the // same kind then this must be a redeclaration, or semantic analysis // would not have given us the new declaration. @@ -308,7 +312,7 @@ bool NamedDecl::hasLinkage() const { NamedDecl *NamedDecl::getUnderlyingDecl() { NamedDecl *ND = this; while (true) { - if (UsingDecl *UD = dyn_cast<UsingDecl>(ND)) + if (UsingShadowDecl *UD = dyn_cast<UsingShadowDecl>(ND)) ND = UD->getTargetDecl(); else if (ObjCCompatibleAliasDecl *AD = dyn_cast<ObjCCompatibleAliasDecl>(ND)) diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 6cfdcdd3e50e..831f552489f9 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -97,7 +97,7 @@ bool Decl::isTemplateParameterPack() const { } bool Decl::isFunctionOrFunctionTemplate() const { - if (const UsingDecl *UD = dyn_cast<UsingDecl>(this)) + if (const UsingShadowDecl *UD = dyn_cast<UsingShadowDecl>(this)) return UD->getTargetDecl()->isFunctionOrFunctionTemplate(); return isa<FunctionDecl>(this) || isa<FunctionTemplateDecl>(this); @@ -189,10 +189,11 @@ ASTContext &Decl::getASTContext() const { unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { switch (DeclKind) { - default: - if (DeclKind >= FunctionFirst && DeclKind <= FunctionLast) - return IDNS_Ordinary; - assert(0 && "Unknown decl kind!"); + case Function: + case CXXMethod: + case CXXConstructor: + case CXXDestructor: + case CXXConversion: case OverloadedFunction: case Typedef: case EnumConstant: @@ -200,8 +201,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ImplicitParam: case ParmVar: case NonTypeTemplateParm: - case Using: - case UnresolvedUsing: case ObjCMethod: case ObjCContainer: case ObjCCategory: @@ -210,6 +209,16 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ObjCCompatibleAlias: return IDNS_Ordinary; + case UsingShadow: + return 0; // we'll actually overwrite this later + + case UnresolvedUsingValue: + case UnresolvedUsingTypename: + return IDNS_Ordinary | IDNS_Using; + + case Using: + return IDNS_Using; + case ObjCProtocol: return IDNS_ObjCProtocol; @@ -256,6 +265,8 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ClassTemplatePartialSpecialization: return 0; } + + return 0; } void Decl::addAttr(Attr *NewAttr) { @@ -663,6 +674,13 @@ void DeclContext::buildLookup(DeclContext *DCtx) { if (D->getDeclContext() == DCtx) makeDeclVisibleInContextImpl(ND); + // Insert any forward-declared Objective-C interfaces into the lookup + // data structure. + if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(*D)) + for (ObjCClassDecl::iterator I = Class->begin(), IEnd = Class->end(); + I != IEnd; ++I) + makeDeclVisibleInContextImpl(I->getInterface()); + // If this declaration is itself a transparent declaration context, // add its members (recursively). if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D)) diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index b4c0c59733e5..a21c93ffcdc9 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -211,7 +211,7 @@ bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context, if (!ArgType.isConstQualified()) AcceptsConst = false; } - if (Context.getCanonicalType(ArgType).getUnqualifiedType() != ClassType) + if (!Context.hasSameUnqualifiedType(ArgType, ClassType)) continue; MD = Method; // We have a single argument of type cv X or cv X&, i.e. we've found the @@ -276,10 +276,13 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context, QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( const_cast<CXXRecordDecl*>(this))); - if (ClassType != Context.getCanonicalType(ArgType)) + if (!Context.hasSameUnqualifiedType(ClassType, ArgType)) return; // This is a copy assignment operator. + // Note on the decl that it is a copy assignment operator. + OpDecl->setCopyAssignment(true); + // Suppress the implicit declaration of a copy constructor. UserDeclaredCopyAssignment = true; @@ -749,6 +752,33 @@ bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) const { (getNumParams() > 1 && getParamDecl(1)->hasDefaultArg()); } +bool CXXConstructorDecl::isCopyConstructorLikeSpecialization() const { + if ((getNumParams() < 1) || + (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) || + (getPrimaryTemplate() == 0) || + (getDescribedFunctionTemplate() != 0)) + return false; + + const ParmVarDecl *Param = getParamDecl(0); + + ASTContext &Context = getASTContext(); + CanQualType ParamType = Context.getCanonicalType(Param->getType()); + + // Strip off the lvalue reference, if any. + if (CanQual<LValueReferenceType> ParamRefType + = ParamType->getAs<LValueReferenceType>()) + ParamType = ParamRefType->getPointeeType(); + + + // Is it the same as our our class type? + CanQualType ClassTy + = Context.getCanonicalType(Context.getTagDeclType(getParent())); + if (ParamType.getUnqualifiedType() != ClassTy) + return false; + + return true; +} + CXXDestructorDecl * CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, @@ -761,12 +791,6 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, } void -CXXDestructorDecl::Destroy(ASTContext& C) { - C.Deallocate(BaseOrMemberDestructions); - CXXMethodDecl::Destroy(C); -} - -void CXXConstructorDecl::Destroy(ASTContext& C) { C.Deallocate(BaseOrMemberInitializers); CXXMethodDecl::Destroy(C); @@ -890,22 +914,36 @@ NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, } UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, SourceRange NNR, SourceLocation TargetNL, - SourceLocation UL, NamedDecl* Target, - NestedNameSpecifier* TargetNNS, bool IsTypeNameArg) { - return new (C) UsingDecl(DC, L, NNR, TargetNL, UL, Target, - TargetNNS, IsTypeNameArg); -} - -UnresolvedUsingDecl *UnresolvedUsingDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation UsingLoc, - SourceRange TargetNNR, - NestedNameSpecifier *TargetNNS, - SourceLocation TargetNameLoc, - DeclarationName TargetName, - bool IsTypeNameArg) { - return new (C) UnresolvedUsingDecl(DC, UsingLoc, TargetNNR, TargetNNS, - TargetNameLoc, TargetName, IsTypeNameArg); + SourceLocation L, SourceRange NNR, SourceLocation UL, + NestedNameSpecifier* TargetNNS, DeclarationName Name, + bool IsTypeNameArg) { + return new (C) UsingDecl(DC, L, NNR, UL, TargetNNS, Name, IsTypeNameArg); +} + +UnresolvedUsingValueDecl * +UnresolvedUsingValueDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation UsingLoc, + SourceRange TargetNNR, + NestedNameSpecifier *TargetNNS, + SourceLocation TargetNameLoc, + DeclarationName TargetName) { + return new (C) UnresolvedUsingValueDecl(DC, C.DependentTy, UsingLoc, + TargetNNR, TargetNNS, + TargetNameLoc, TargetName); +} + +UnresolvedUsingTypenameDecl * +UnresolvedUsingTypenameDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation UsingLoc, + SourceLocation TypenameLoc, + SourceRange TargetNNR, + NestedNameSpecifier *TargetNNS, + SourceLocation TargetNameLoc, + DeclarationName TargetName) { + return new (C) UnresolvedUsingTypenameDecl(DC, UsingLoc, TypenameLoc, + TargetNNR, TargetNNS, + TargetNameLoc, + TargetName.getAsIdentifierInfo()); } StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC, diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 7b48b724c0eb..c33720f5633a 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -571,34 +571,55 @@ ObjCMethodDecl *ObjCProtocolDecl::lookupMethod(Selector Sel, //===----------------------------------------------------------------------===// ObjCClassDecl::ObjCClassDecl(DeclContext *DC, SourceLocation L, - ObjCInterfaceDecl *const *Elts, unsigned nElts, + ObjCInterfaceDecl *const *Elts, + const SourceLocation *Locs, + unsigned nElts, ASTContext &C) : Decl(ObjCClass, DC, L) { - ForwardDecls.set(Elts, nElts, C); + setClassList(C, Elts, Locs, nElts); } +void ObjCClassDecl::setClassList(ASTContext &C, ObjCInterfaceDecl*const*List, + const SourceLocation *Locs, unsigned Num) { + ForwardDecls = (ObjCClassRef*) C.Allocate(sizeof(ObjCClassRef)*Num, + llvm::alignof<ObjCClassRef>()); + for (unsigned i = 0; i < Num; ++i) + new (&ForwardDecls[i]) ObjCClassRef(List[i], Locs[i]); + + NumDecls = Num; +} ObjCClassDecl *ObjCClassDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, ObjCInterfaceDecl *const *Elts, + const SourceLocation *Locs, unsigned nElts) { - return new (C) ObjCClassDecl(DC, L, Elts, nElts, C); + return new (C) ObjCClassDecl(DC, L, Elts, Locs, nElts, C); } void ObjCClassDecl::Destroy(ASTContext &C) { - - // FIXME: There is no clear ownership policy now for referenced - // ObjCInterfaceDecls. Some of them can be forward declarations that - // are never later defined (in which case the ObjCClassDecl owns them) - // or the ObjCInterfaceDecl later becomes a real definition later. Ideally - // we should have separate objects for forward declarations and definitions, - // obviating this problem. Because of this situation, referenced - // ObjCInterfaceDecls are destroyed in ~TranslationUnit. - - ForwardDecls.Destroy(C); + // ObjCInterfaceDecls registered with a DeclContext will get destroyed + // when the DeclContext is destroyed. For those created only by a forward + // declaration, the first @class that created the ObjCInterfaceDecl gets + // to destroy it. + // FIXME: Note that this ownership role is very brittle; a better + // polict is surely need in the future. + for (iterator I = begin(), E = end(); I !=E ; ++I) { + ObjCInterfaceDecl *ID = I->getInterface(); + if (ID->isForwardDecl() && ID->getLocStart() == getLocStart()) + ID->Destroy(C); + } + + C.Deallocate(ForwardDecls); Decl::Destroy(C); } +SourceRange ObjCClassDecl::getSourceRange() const { + // FIXME: We should include the semicolon + assert(NumDecls); + return SourceRange(getLocation(), ForwardDecls[NumDecls-1].getLocation()); +} + //===----------------------------------------------------------------------===// // ObjCForwardProtocolDecl //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index d9d195016bf3..131de8b2e11b 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -71,8 +71,10 @@ namespace { void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D); void VisitObjCPropertyDecl(ObjCPropertyDecl *D); void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); - void VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D); + void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); + void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); void VisitUsingDecl(UsingDecl *D); + void VisitUsingShadowDecl(UsingShadowDecl *D); }; } @@ -401,37 +403,6 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { } } } - else if (CXXDestructorDecl *DDecl = dyn_cast<CXXDestructorDecl>(D)) { - if (DDecl->getNumBaseOrMemberDestructions() > 0) { - // List order of base/member destruction for visualization purposes. - assert (D->isThisDeclarationADefinition() && "Destructor with dtor-list"); - Proto += "/* : "; - for (CXXDestructorDecl::destr_const_iterator *B = DDecl->destr_begin(), - *E = DDecl->destr_end(); - B != E; ++B) { - uintptr_t BaseOrMember = (*B); - if (B != DDecl->destr_begin()) - Proto += ", "; - - if (DDecl->isMemberToDestroy(BaseOrMember)) { - FieldDecl *FD = DDecl->getMemberToDestroy(BaseOrMember); - Proto += "~"; - Proto += FD->getNameAsString(); - } - else // FIXME. skip dependent types for now. - if (const RecordType *RT = - DDecl->getAnyBaseClassToDestroy(BaseOrMember) - ->getAs<RecordType>()) { - const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(RT->getDecl()); - Proto += "~"; - Proto += BaseDecl->getNameAsString(); - } - Proto += "()"; - } - Proto += " */"; - } - } else AFT->getResultType().getAsStringInternal(Proto, Policy); } else { @@ -654,7 +625,7 @@ void DeclPrinter::VisitObjCClassDecl(ObjCClassDecl *D) { for (ObjCClassDecl::iterator I = D->begin(), E = D->end(); I != E; ++I) { if (I != D->begin()) Out << ", "; - Out << (*I)->getNameAsString(); + Out << I->getInterface()->getNameAsString(); } } @@ -856,11 +827,22 @@ void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) { void DeclPrinter::VisitUsingDecl(UsingDecl *D) { Out << "using "; D->getTargetNestedNameDecl()->print(Out, Policy); - Out << D->getTargetDecl()->getNameAsString(); + Out << D->getNameAsString(); +} + +void +DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { + Out << "using typename "; + D->getTargetNestedNameSpecifier()->print(Out, Policy); + Out << D->getDeclName().getAsString(); } -void DeclPrinter::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) { +void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { Out << "using "; D->getTargetNestedNameSpecifier()->print(Out, Policy); - Out << D->getTargetName().getAsString(); + Out << D->getDeclName().getAsString(); +} + +void DeclPrinter::VisitUsingShadowDecl(UsingShadowDecl *D) { + // ignore } diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 9ebc91afe142..0c14714812f5 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -220,7 +220,7 @@ QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) { TemplateArgs.push_back(TemplateArgument(E)); } else { TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param); - TemplateArgs.push_back(TemplateArgument(TTP)); + TemplateArgs.push_back(TemplateArgument(TemplateName(TTP))); } } @@ -285,11 +285,6 @@ TemplateTemplateParmDecl::Create(ASTContext &C, DeclContext *DC, return new (C) TemplateTemplateParmDecl(DC, L, D, P, Id, Params); } -SourceLocation TemplateTemplateParmDecl::getDefaultArgumentLoc() const { - return DefaultArgument? DefaultArgument->getSourceRange().getBegin() - : SourceLocation(); -} - //===----------------------------------------------------------------------===// // TemplateArgumentListBuilder Implementation //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 8664c508615f..1ff068c9862c 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -18,6 +18,7 @@ #include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" +#include <cstdio> using namespace clang; namespace clang { @@ -310,6 +311,10 @@ DeclarationName DeclarationName::getUsingDirectiveName() { return DeclarationName(Ptr); } +void DeclarationName::dump() const { + fprintf(stderr, "%s\n", getAsString().c_str()); +} + DeclarationNameTable::DeclarationNameTable() { CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>; diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index a8ea752a4a7e..90b50c61f989 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -490,6 +490,8 @@ const char *CastExpr::getCastKindName() const { return "BitCast"; case CastExpr::CK_NoOp: return "NoOp"; + case CastExpr::CK_BaseToDerived: + return "BaseToDerived"; case CastExpr::CK_DerivedToBase: return "DerivedToBase"; case CastExpr::CK_Dynamic: @@ -812,6 +814,11 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, } return false; } + + case CXXTemporaryObjectExprClass: + case CXXConstructExprClass: + return false; + case ObjCMessageExprClass: return false; @@ -853,15 +860,19 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, Loc = cast<CStyleCastExpr>(this)->getLParenLoc(); R1 = cast<CStyleCastExpr>(this)->getSubExpr()->getSourceRange(); return true; - case CXXFunctionalCastExprClass: - // If this is a cast to void, check the operand. Otherwise, the result of - // the cast is unused. - if (getType()->isVoidType()) + case CXXFunctionalCastExprClass: { + const CastExpr *CE = cast<CastExpr>(this); + + // If this is a cast to void or a constructor conversion, check the operand. + // Otherwise, the result of the cast is unused. + if (CE->getCastKind() == CastExpr::CK_ToVoid || + CE->getCastKind() == CastExpr::CK_ConstructorConversion) return (cast<CastExpr>(this)->getSubExpr() ->isUnusedResultAWarning(Loc, R1, R2, Ctx)); Loc = cast<CXXFunctionalCastExpr>(this)->getTypeBeginLoc(); R1 = cast<CXXFunctionalCastExpr>(this)->getSubExpr()->getSourceRange(); return true; + } case ImplicitCastExprClass: // Check the operand, since implicit casts are inserted by Sema diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 7c6fc41ef12b..0ba4608ee198 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -323,6 +323,14 @@ Expr *CXXMemberCallExpr::getImplicitObjectArgument() { return 0; } +SourceRange CXXMemberCallExpr::getSourceRange() const { + SourceLocation LocStart = getCallee()->getLocStart(); + if (LocStart.isInvalid() && getNumArgs() > 0) + LocStart = getArg(0)->getLocStart(); + return SourceRange(LocStart, getRParenLoc()); +} + + //===----------------------------------------------------------------------===// // Named casts //===----------------------------------------------------------------------===// diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 7862c57c2d47..2689859e8e4a 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -204,13 +204,6 @@ public: bool VisitUnaryOperator(UnaryOperator *E) { return Visit(E->getSubExpr()); } }; -bool HasSideEffects(const Expr* E, ASTContext &Ctx) { - Expr::EvalResult Result; - EvalInfo Info(Ctx, Result); - - return HasSideEffect(Info).Visit(const_cast<Expr*>(E)); -} - } // end anonymous namespace //===----------------------------------------------------------------------===// @@ -964,7 +957,7 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { } } - if (HasSideEffects(E->getArg(0), Info.Ctx)) { + if (E->getArg(0)->HasSideEffects(Info.Ctx)) { if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() < 2) return Success(-1ULL, E); return Success(0, E); @@ -1495,7 +1488,7 @@ public: // FIXME: Missing: __real__/__imag__, array subscript of vector, // member of vector, ImplicitValueInitExpr, - // conditional ?:, comma + // conditional ?: }; } // end anonymous namespace @@ -1584,6 +1577,18 @@ bool FloatExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { } bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { + if (E->getOpcode() == BinaryOperator::Comma) { + if (!EvaluateFloat(E->getRHS(), Result, Info)) + return false; + + // If we can't evaluate the LHS, it might have side effects; + // conservatively mark it. + if (!E->getLHS()->isEvaluatable(Info.Ctx)) + Info.EvalResult.HasSideEffects = true; + + return true; + } + // FIXME: Diagnostics? I really don't understand how the warnings // and errors are supposed to work. APFloat RHS(0.0); @@ -1947,6 +1952,12 @@ bool Expr::isEvaluatable(ASTContext &Ctx) const { return Evaluate(Result, Ctx) && !Result.HasSideEffects; } +bool Expr::HasSideEffects(ASTContext &Ctx) const { + Expr::EvalResult Result; + EvalInfo Info(Ctx, Result); + return HasSideEffect(Info).Visit(const_cast<Expr*>(this)); +} + APSInt Expr::EvaluateAsInt(ASTContext &Ctx) const { EvalResult EvalResult; bool Result = Evaluate(EvalResult, Ctx); diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp index d969776aa0ee..e26c0bba4934 100644 --- a/lib/AST/NestedNameSpecifier.cpp +++ b/lib/AST/NestedNameSpecifier.cpp @@ -167,7 +167,7 @@ NestedNameSpecifier::print(llvm::raw_ostream &OS, InnerPolicy); } else { // Print the type normally - T->getAsStringInternal(TypeStr, InnerPolicy); + TypeStr = QualType(T, 0).getAsString(InnerPolicy); } OS << TypeStr; break; diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 021c53e9514f..b9cfcfec74f0 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -226,8 +226,7 @@ void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *Class, if (RD == Class) BaseOffset = getBaseOffset(Base); else { - const ASTRecordLayout &Layout - = Ctx.getASTRecordLayout(RD); + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); BaseOffset = Offset + Layout.getBaseClassOffset(Base); } } diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index cf71d6b986a2..93bf8755d580 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -115,6 +115,7 @@ namespace { // Exprs void VisitExpr(Expr *Node); void VisitCastExpr(CastExpr *Node); + void VisitImplicitCastExpr(ImplicitCastExpr *Node); void VisitDeclRefExpr(DeclRefExpr *Node); void VisitPredefinedExpr(PredefinedExpr *Node); void VisitCharacterLiteral(CharacterLiteral *Node); @@ -301,6 +302,12 @@ void StmtDumper::VisitCastExpr(CastExpr *Node) { fprintf(F, " <%s>", Node->getCastKindName()); } +void StmtDumper::VisitImplicitCastExpr(ImplicitCastExpr *Node) { + VisitCastExpr(Node); + if (Node->isLvalueCast()) + fprintf(F, " lvalue"); +} + void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) { DumpExpr(Node); diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 02e0c74bb63a..4458c2b9cd25 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -695,6 +695,10 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) { VisitType(Arg.getAsType()); break; + case TemplateArgument::Template: + VisitTemplateName(Arg.getAsTemplate()); + break; + case TemplateArgument::Declaration: VisitDecl(Arg.getAsDecl()); break; diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp index 94e1ca1e06e7..ff02f9a31cb2 100644 --- a/lib/AST/TemplateBase.cpp +++ b/lib/AST/TemplateBase.cpp @@ -58,6 +58,11 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID, ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : 0); break; + case Template: + ID.AddPointer(Context.getCanonicalTemplateName(getAsTemplate()) + .getAsVoidPointer()); + break; + case Integral: getAsIntegral()->Profile(ID); getIntegralType().Profile(ID); @@ -82,10 +87,19 @@ SourceRange TemplateArgumentLoc::getSourceRange() const { switch (Argument.getKind()) { case TemplateArgument::Expression: return getSourceExpression()->getSourceRange(); + case TemplateArgument::Declaration: return getSourceDeclExpression()->getSourceRange(); + case TemplateArgument::Type: return getSourceDeclaratorInfo()->getTypeLoc().getFullSourceRange(); + + case TemplateArgument::Template: + if (getTemplateQualifierRange().isValid()) + return SourceRange(getTemplateQualifierRange().getBegin(), + getTemplateNameLoc()); + return SourceRange(getTemplateNameLoc()); + case TemplateArgument::Integral: case TemplateArgument::Pack: case TemplateArgument::Null: diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 779f6808b6c1..297534eaf1fc 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -98,6 +98,44 @@ const Type *Type::getArrayElementTypeNoTypeQual() const { ->getElementType().getTypePtr(); } +/// \brief Retrieve the unqualified variant of the given type, removing as +/// little sugar as possible. +/// +/// This routine looks through various kinds of sugar to find the +/// least-desuraged type that is unqualified. For example, given: +/// +/// \code +/// typedef int Integer; +/// typedef const Integer CInteger; +/// typedef CInteger DifferenceType; +/// \endcode +/// +/// Executing \c getUnqualifiedTypeSlow() on the type \c DifferenceType will +/// desugar until we hit the type \c Integer, which has no qualifiers on it. +QualType QualType::getUnqualifiedTypeSlow() const { + QualType Cur = *this; + while (true) { + if (!Cur.hasQualifiers()) + return Cur; + + const Type *CurTy = Cur.getTypePtr(); + switch (CurTy->getTypeClass()) { +#define ABSTRACT_TYPE(Class, Parent) +#define TYPE(Class, Parent) \ + case Type::Class: { \ + const Class##Type *Ty = cast<Class##Type>(CurTy); \ + if (!Ty->isSugared()) \ + return Cur.getLocalUnqualifiedType(); \ + Cur = Ty->desugar(); \ + break; \ + } +#include "clang/AST/TypeNodes.def" + } + } + + return Cur.getUnqualifiedType(); +} + /// getDesugaredType - Return the specified type with any "sugar" removed from /// the type. This takes off typedefs, typeof's etc. If the outer level of /// the type is already concrete, it returns it unmodified. This is similar @@ -425,7 +463,7 @@ bool Type::isSignedIntegerType() const { bool Type::isUnsignedIntegerType() const { if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) { return BT->getKind() >= BuiltinType::Bool && - BT->getKind() <= BuiltinType::ULongLong; + BT->getKind() <= BuiltinType::UInt128; } if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) @@ -453,8 +491,7 @@ bool Type::isFloatingType() const { bool Type::isRealFloatingType() const { if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) - return BT->getKind() >= BuiltinType::Float && - BT->getKind() <= BuiltinType::LongDouble; + return BT->isFloatingPoint(); if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) return VT->getElementType()->isRealFloatingType(); return false; @@ -808,6 +845,9 @@ static bool isDependent(const TemplateArgument &Arg) { case TemplateArgument::Type: return Arg.getAsType()->isDependentType(); + case TemplateArgument::Template: + return Arg.getAsTemplate().isDependent(); + case TemplateArgument::Declaration: case TemplateArgument::Integral: // Never dependent @@ -907,539 +947,6 @@ QualType QualifierCollector::apply(const Type *T) const { return Context->getQualifiedType(T, *this); } - -//===----------------------------------------------------------------------===// -// Type Printing -//===----------------------------------------------------------------------===// - -void QualType::dump(const char *msg) const { - std::string R = "identifier"; - LangOptions LO; - getAsStringInternal(R, PrintingPolicy(LO)); - if (msg) - fprintf(stderr, "%s: %s\n", msg, R.c_str()); - else - fprintf(stderr, "%s\n", R.c_str()); -} -void QualType::dump() const { - dump(""); -} - -void Type::dump() const { - std::string S = "identifier"; - LangOptions LO; - getAsStringInternal(S, PrintingPolicy(LO)); - fprintf(stderr, "%s\n", S.c_str()); -} - - - -static void AppendTypeQualList(std::string &S, unsigned TypeQuals) { - if (TypeQuals & Qualifiers::Const) { - if (!S.empty()) S += ' '; - S += "const"; - } - if (TypeQuals & Qualifiers::Volatile) { - if (!S.empty()) S += ' '; - S += "volatile"; - } - if (TypeQuals & Qualifiers::Restrict) { - if (!S.empty()) S += ' '; - S += "restrict"; - } -} - -std::string Qualifiers::getAsString() const { - LangOptions LO; - return getAsString(PrintingPolicy(LO)); -} - -// Appends qualifiers to the given string, separated by spaces. Will -// prefix a space if the string is non-empty. Will not append a final -// space. -void Qualifiers::getAsStringInternal(std::string &S, - const PrintingPolicy&) const { - AppendTypeQualList(S, getCVRQualifiers()); - if (unsigned AddressSpace = getAddressSpace()) { - if (!S.empty()) S += ' '; - S += "__attribute__((address_space("; - S += llvm::utostr_32(AddressSpace); - S += ")))"; - } - if (Qualifiers::GC GCAttrType = getObjCGCAttr()) { - if (!S.empty()) S += ' '; - S += "__attribute__((objc_gc("; - if (GCAttrType == Qualifiers::Weak) - S += "weak"; - else - S += "strong"; - S += ")))"; - } -} - -std::string QualType::getAsString() const { - std::string S; - LangOptions LO; - getAsStringInternal(S, PrintingPolicy(LO)); - return S; -} - -void -QualType::getAsStringInternal(std::string &S, - const PrintingPolicy &Policy) const { - if (isNull()) { - S += "NULL TYPE"; - return; - } - - if (Policy.SuppressSpecifiers && getTypePtr()->isSpecifierType()) - return; - - // Print qualifiers as appropriate. - Qualifiers Quals = getQualifiers(); - if (!Quals.empty()) { - std::string TQS; - Quals.getAsStringInternal(TQS, Policy); - - if (!S.empty()) { - TQS += ' '; - TQS += S; - } - std::swap(S, TQS); - } - - getTypePtr()->getAsStringInternal(S, Policy); -} - -void BuiltinType::getAsStringInternal(std::string &S, - const PrintingPolicy &Policy) const { - if (S.empty()) { - S = getName(Policy.LangOpts); - } else { - // Prefix the basic type, e.g. 'int X'. - S = ' ' + S; - S = getName(Policy.LangOpts) + S; - } -} - -void FixedWidthIntType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - // FIXME: Once we get bitwidth attribute, write as - // "int __attribute__((bitwidth(x)))". - std::string prefix = "__clang_fixedwidth"; - prefix += llvm::utostr_32(Width); - prefix += (char)(Signed ? 'S' : 'U'); - if (S.empty()) { - S = prefix; - } else { - // Prefix the basic type, e.g. 'int X'. - S = prefix + S; - } -} - - -void ComplexType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - ElementType->getAsStringInternal(S, Policy); - S = "_Complex " + S; -} - -void PointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - S = '*' + S; - - // Handle things like 'int (*A)[4];' correctly. - // FIXME: this should include vectors, but vectors use attributes I guess. - if (isa<ArrayType>(getPointeeType())) - S = '(' + S + ')'; - - getPointeeType().getAsStringInternal(S, Policy); -} - -void BlockPointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - S = '^' + S; - PointeeType.getAsStringInternal(S, Policy); -} - -void LValueReferenceType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - S = '&' + S; - - // Handle things like 'int (&A)[4];' correctly. - // FIXME: this should include vectors, but vectors use attributes I guess. - if (isa<ArrayType>(getPointeeTypeAsWritten())) - S = '(' + S + ')'; - - getPointeeTypeAsWritten().getAsStringInternal(S, Policy); -} - -void RValueReferenceType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - S = "&&" + S; - - // Handle things like 'int (&&A)[4];' correctly. - // FIXME: this should include vectors, but vectors use attributes I guess. - if (isa<ArrayType>(getPointeeTypeAsWritten())) - S = '(' + S + ')'; - - getPointeeTypeAsWritten().getAsStringInternal(S, Policy); -} - -void MemberPointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - std::string C; - Class->getAsStringInternal(C, Policy); - C += "::*"; - S = C + S; - - // Handle things like 'int (Cls::*A)[4];' correctly. - // FIXME: this should include vectors, but vectors use attributes I guess. - if (isa<ArrayType>(getPointeeType())) - S = '(' + S + ')'; - - getPointeeType().getAsStringInternal(S, Policy); -} - -void ConstantArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - S += '['; - S += llvm::utostr(getSize().getZExtValue()); - S += ']'; - - getElementType().getAsStringInternal(S, Policy); -} - -void IncompleteArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - S += "[]"; - - getElementType().getAsStringInternal(S, Policy); -} - -void VariableArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - S += '['; - - if (getIndexTypeQualifiers().hasQualifiers()) { - AppendTypeQualList(S, getIndexTypeCVRQualifiers()); - S += ' '; - } - - if (getSizeModifier() == Static) - S += "static"; - else if (getSizeModifier() == Star) - S += '*'; - - if (getSizeExpr()) { - std::string SStr; - llvm::raw_string_ostream s(SStr); - getSizeExpr()->printPretty(s, 0, Policy); - S += s.str(); - } - S += ']'; - - getElementType().getAsStringInternal(S, Policy); -} - -void DependentSizedArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - S += '['; - - if (getIndexTypeQualifiers().hasQualifiers()) { - AppendTypeQualList(S, getIndexTypeCVRQualifiers()); - S += ' '; - } - - if (getSizeModifier() == Static) - S += "static"; - else if (getSizeModifier() == Star) - S += '*'; - - if (getSizeExpr()) { - std::string SStr; - llvm::raw_string_ostream s(SStr); - getSizeExpr()->printPretty(s, 0, Policy); - S += s.str(); - } - S += ']'; - - getElementType().getAsStringInternal(S, Policy); -} - -void DependentSizedExtVectorType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - getElementType().getAsStringInternal(S, Policy); - - S += " __attribute__((ext_vector_type("; - if (getSizeExpr()) { - std::string SStr; - llvm::raw_string_ostream s(SStr); - getSizeExpr()->printPretty(s, 0, Policy); - S += s.str(); - } - S += ")))"; -} - -void VectorType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - // FIXME: We prefer to print the size directly here, but have no way - // to get the size of the type. - S += " __attribute__((__vector_size__("; - S += llvm::utostr_32(NumElements); // convert back to bytes. - S += " * sizeof(" + ElementType.getAsString() + "))))"; - ElementType.getAsStringInternal(S, Policy); -} - -void ExtVectorType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - S += " __attribute__((ext_vector_type("; - S += llvm::utostr_32(NumElements); - S += ")))"; - ElementType.getAsStringInternal(S, Policy); -} - -void TypeOfExprType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { - if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(e) X'. - InnerString = ' ' + InnerString; - std::string Str; - llvm::raw_string_ostream s(Str); - getUnderlyingExpr()->printPretty(s, 0, Policy); - InnerString = "typeof " + s.str() + InnerString; -} - -void TypeOfType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { - if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(t) X'. - InnerString = ' ' + InnerString; - std::string Tmp; - getUnderlyingType().getAsStringInternal(Tmp, Policy); - InnerString = "typeof(" + Tmp + ")" + InnerString; -} - -void DecltypeType::getAsStringInternal(std::string &InnerString, - const PrintingPolicy &Policy) const { - if (!InnerString.empty()) // Prefix the basic type, e.g. 'decltype(t) X'. - InnerString = ' ' + InnerString; - std::string Str; - llvm::raw_string_ostream s(Str); - getUnderlyingExpr()->printPretty(s, 0, Policy); - InnerString = "decltype(" + s.str() + ")" + InnerString; -} - -void FunctionNoProtoType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - // If needed for precedence reasons, wrap the inner part in grouping parens. - if (!S.empty()) - S = "(" + S + ")"; - - S += "()"; - if (getNoReturnAttr()) - S += " __attribute__((noreturn))"; - getResultType().getAsStringInternal(S, Policy); -} - -void FunctionProtoType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - // If needed for precedence reasons, wrap the inner part in grouping parens. - if (!S.empty()) - S = "(" + S + ")"; - - S += "("; - std::string Tmp; - PrintingPolicy ParamPolicy(Policy); - ParamPolicy.SuppressSpecifiers = false; - for (unsigned i = 0, e = getNumArgs(); i != e; ++i) { - if (i) S += ", "; - getArgType(i).getAsStringInternal(Tmp, ParamPolicy); - S += Tmp; - Tmp.clear(); - } - - if (isVariadic()) { - if (getNumArgs()) - S += ", "; - S += "..."; - } else if (getNumArgs() == 0 && !Policy.LangOpts.CPlusPlus) { - // Do not emit int() if we have a proto, emit 'int(void)'. - S += "void"; - } - - S += ")"; - if (getNoReturnAttr()) - S += " __attribute__((noreturn))"; - getResultType().getAsStringInternal(S, Policy); -} - - -void TypedefType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { - if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. - InnerString = ' ' + InnerString; - InnerString = getDecl()->getIdentifier()->getName().str() + InnerString; -} - -void TemplateTypeParmType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { - if (!InnerString.empty()) // Prefix the basic type, e.g. 'parmname X'. - InnerString = ' ' + InnerString; - - if (!Name) - InnerString = "type-parameter-" + llvm::utostr_32(Depth) + '-' + - llvm::utostr_32(Index) + InnerString; - else - InnerString = Name->getName().str() + InnerString; -} - -void SubstTemplateTypeParmType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { - getReplacementType().getAsStringInternal(InnerString, Policy); -} - -static void PrintTemplateArgument(std::string &Buffer, - const TemplateArgument &Arg, - const PrintingPolicy &Policy) { - switch (Arg.getKind()) { - case TemplateArgument::Null: - assert(false && "Null template argument"); - break; - - case TemplateArgument::Type: - Arg.getAsType().getAsStringInternal(Buffer, Policy); - break; - - case TemplateArgument::Declaration: - Buffer = cast<NamedDecl>(Arg.getAsDecl())->getNameAsString(); - break; - - case TemplateArgument::Integral: - Buffer = Arg.getAsIntegral()->toString(10, true); - break; - - case TemplateArgument::Expression: { - llvm::raw_string_ostream s(Buffer); - Arg.getAsExpr()->printPretty(s, 0, Policy); - break; - } - - case TemplateArgument::Pack: - assert(0 && "FIXME: Implement!"); - break; - } -} - -std::string -TemplateSpecializationType::PrintTemplateArgumentList( - const TemplateArgument *Args, - unsigned NumArgs, - const PrintingPolicy &Policy) { - std::string SpecString; - SpecString += '<'; - for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { - if (Arg) - SpecString += ", "; - - // Print the argument into a string. - std::string ArgString; - PrintTemplateArgument(ArgString, Args[Arg], Policy); - - // If this is the first argument and its string representation - // begins with the global scope specifier ('::foo'), add a space - // to avoid printing the diagraph '<:'. - if (!Arg && !ArgString.empty() && ArgString[0] == ':') - SpecString += ' '; - - SpecString += ArgString; - } - - // If the last character of our string is '>', add another space to - // keep the two '>''s separate tokens. We don't *have* to do this in - // C++0x, but it's still good hygiene. - if (SpecString[SpecString.size() - 1] == '>') - SpecString += ' '; - - SpecString += '>'; - - return SpecString; -} - -// Sadly, repeat all that with TemplateArgLoc. -std::string TemplateSpecializationType:: -PrintTemplateArgumentList(const TemplateArgumentLoc *Args, unsigned NumArgs, - const PrintingPolicy &Policy) { - std::string SpecString; - SpecString += '<'; - for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { - if (Arg) - SpecString += ", "; - - // Print the argument into a string. - std::string ArgString; - PrintTemplateArgument(ArgString, Args[Arg].getArgument(), Policy); - - // If this is the first argument and its string representation - // begins with the global scope specifier ('::foo'), add a space - // to avoid printing the diagraph '<:'. - if (!Arg && !ArgString.empty() && ArgString[0] == ':') - SpecString += ' '; - - SpecString += ArgString; - } - - // If the last character of our string is '>', add another space to - // keep the two '>''s separate tokens. We don't *have* to do this in - // C++0x, but it's still good hygiene. - if (SpecString[SpecString.size() - 1] == '>') - SpecString += ' '; - - SpecString += '>'; - - return SpecString; -} - -void -TemplateSpecializationType:: -getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { - std::string SpecString; - - { - llvm::raw_string_ostream OS(SpecString); - Template.print(OS, Policy); - } - - SpecString += PrintTemplateArgumentList(getArgs(), getNumArgs(), Policy); - if (InnerString.empty()) - InnerString.swap(SpecString); - else - InnerString = SpecString + ' ' + InnerString; -} - -void QualifiedNameType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { - std::string MyString; - - { - llvm::raw_string_ostream OS(MyString); - NNS->print(OS, Policy); - } - - std::string TypeStr; - PrintingPolicy InnerPolicy(Policy); - InnerPolicy.SuppressTagKind = true; - InnerPolicy.SuppressScope = true; - NamedType.getAsStringInternal(TypeStr, InnerPolicy); - - MyString += TypeStr; - if (InnerString.empty()) - InnerString.swap(MyString); - else - InnerString = MyString + ' ' + InnerString; -} - -void TypenameType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { - std::string MyString; - - { - llvm::raw_string_ostream OS(MyString); - OS << "typename "; - NNS->print(OS, Policy); - - if (const IdentifierInfo *Ident = getIdentifier()) - OS << Ident->getName(); - else if (const TemplateSpecializationType *Spec = getTemplateId()) { - Spec->getTemplateName().print(OS, Policy, true); - OS << TemplateSpecializationType::PrintTemplateArgumentList( - Spec->getArgs(), - Spec->getNumArgs(), - Policy); - } - } - - if (InnerString.empty()) - InnerString.swap(MyString); - else - InnerString = MyString + ' ' + InnerString; -} - void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID, const ObjCInterfaceDecl *Decl, ObjCProtocolDecl **protocols, @@ -1455,134 +962,3 @@ void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID) { else Profile(ID, getDecl(), 0, 0); } - -void ObjCInterfaceType::getAsStringInternal(std::string &InnerString, - const PrintingPolicy &Policy) const { - if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. - InnerString = ' ' + InnerString; - - std::string ObjCQIString = getDecl()->getNameAsString(); - if (getNumProtocols()) { - ObjCQIString += '<'; - bool isFirst = true; - for (qual_iterator I = qual_begin(), E = qual_end(); I != E; ++I) { - if (isFirst) - isFirst = false; - else - ObjCQIString += ','; - ObjCQIString += (*I)->getNameAsString(); - } - ObjCQIString += '>'; - } - InnerString = ObjCQIString + InnerString; -} - -void ObjCObjectPointerType::getAsStringInternal(std::string &InnerString, - const PrintingPolicy &Policy) const { - std::string ObjCQIString; - - if (isObjCIdType() || isObjCQualifiedIdType()) - ObjCQIString = "id"; - else if (isObjCClassType() || isObjCQualifiedClassType()) - ObjCQIString = "Class"; - else - ObjCQIString = getInterfaceDecl()->getNameAsString(); - - if (!qual_empty()) { - ObjCQIString += '<'; - for (qual_iterator I = qual_begin(), E = qual_end(); I != E; ++I) { - ObjCQIString += (*I)->getNameAsString(); - if (I+1 != E) - ObjCQIString += ','; - } - ObjCQIString += '>'; - } - - PointeeType.getQualifiers().getAsStringInternal(ObjCQIString, Policy); - - if (!isObjCIdType() && !isObjCQualifiedIdType()) - ObjCQIString += " *"; // Don't forget the implicit pointer. - else if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. - InnerString = ' ' + InnerString; - - InnerString = ObjCQIString + InnerString; -} - -void ElaboratedType::getAsStringInternal(std::string &InnerString, - const PrintingPolicy &Policy) const { - std::string TypeStr; - PrintingPolicy InnerPolicy(Policy); - InnerPolicy.SuppressTagKind = true; - UnderlyingType.getAsStringInternal(InnerString, InnerPolicy); - - InnerString = std::string(getNameForTagKind(getTagKind())) + ' ' + InnerString; -} - -void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { - if (Policy.SuppressTag) - return; - - if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. - InnerString = ' ' + InnerString; - - const char *Kind = Policy.SuppressTagKind? 0 : getDecl()->getKindName(); - const char *ID; - if (const IdentifierInfo *II = getDecl()->getIdentifier()) - ID = II->getNameStart(); - else if (TypedefDecl *Typedef = getDecl()->getTypedefForAnonDecl()) { - Kind = 0; - assert(Typedef->getIdentifier() && "Typedef without identifier?"); - ID = Typedef->getIdentifier()->getNameStart(); - } else - ID = "<anonymous>"; - - // If this is a class template specialization, print the template - // arguments. - if (ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(getDecl())) { - const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); - std::string TemplateArgsStr - = TemplateSpecializationType::PrintTemplateArgumentList( - TemplateArgs.getFlatArgumentList(), - TemplateArgs.flat_size(), - Policy); - InnerString = TemplateArgsStr + InnerString; - } - - if (!Policy.SuppressScope) { - // Compute the full nested-name-specifier for this type. In C, - // this will always be empty. - std::string ContextStr; - for (DeclContext *DC = getDecl()->getDeclContext(); - !DC->isTranslationUnit(); DC = DC->getParent()) { - std::string MyPart; - if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) { - if (NS->getIdentifier()) - MyPart = NS->getNameAsString(); - } else if (ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(DC)) { - const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); - std::string TemplateArgsStr - = TemplateSpecializationType::PrintTemplateArgumentList( - TemplateArgs.getFlatArgumentList(), - TemplateArgs.flat_size(), - Policy); - MyPart = Spec->getIdentifier()->getName().str() + TemplateArgsStr; - } else if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) { - if (TypedefDecl *Typedef = Tag->getTypedefForAnonDecl()) - MyPart = Typedef->getIdentifier()->getName(); - else if (Tag->getIdentifier()) - MyPart = Tag->getIdentifier()->getName(); - } - - if (!MyPart.empty()) - ContextStr = MyPart + "::" + ContextStr; - } - - if (Kind) - InnerString = std::string(Kind) + ' ' + ContextStr + ID + InnerString; - else - InnerString = ContextStr + ID + InnerString; - } else - InnerString = ID + InnerString; -} diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp new file mode 100644 index 000000000000..a48233378286 --- /dev/null +++ b/lib/AST/TypePrinter.cpp @@ -0,0 +1,728 @@ +//===--- TypePrinter.cpp - Pretty-Print Clang Types -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code to print types from Clang's type system. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/Basic/LangOptions.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +namespace { + class TypePrinter { + PrintingPolicy Policy; + + public: + explicit TypePrinter(const PrintingPolicy &Policy) : Policy(Policy) { } + + void Print(QualType T, std::string &S); + void PrintTag(const TagType *T, std::string &S); +#define ABSTRACT_TYPE(CLASS, PARENT) +#define TYPE(CLASS, PARENT) \ + void Print##CLASS(const CLASS##Type *T, std::string &S); +#include "clang/AST/TypeNodes.def" + }; +} + +static void AppendTypeQualList(std::string &S, unsigned TypeQuals) { + if (TypeQuals & Qualifiers::Const) { + if (!S.empty()) S += ' '; + S += "const"; + } + if (TypeQuals & Qualifiers::Volatile) { + if (!S.empty()) S += ' '; + S += "volatile"; + } + if (TypeQuals & Qualifiers::Restrict) { + if (!S.empty()) S += ' '; + S += "restrict"; + } +} + +void TypePrinter::Print(QualType T, std::string &S) { + if (T.isNull()) { + S += "NULL TYPE"; + return; + } + + if (Policy.SuppressSpecifiers && T->isSpecifierType()) + return; + + // Print qualifiers as appropriate. + Qualifiers Quals = T.getLocalQualifiers(); + if (!Quals.empty()) { + std::string TQS; + Quals.getAsStringInternal(TQS, Policy); + + if (!S.empty()) { + TQS += ' '; + TQS += S; + } + std::swap(S, TQS); + } + + switch (T->getTypeClass()) { +#define ABSTRACT_TYPE(CLASS, PARENT) +#define TYPE(CLASS, PARENT) case Type::CLASS: \ + Print##CLASS(cast<CLASS##Type>(T.getTypePtr()), S); \ + break; +#include "clang/AST/TypeNodes.def" + } +} + +void TypePrinter::PrintBuiltin(const BuiltinType *T, std::string &S) { + if (S.empty()) { + S = T->getName(Policy.LangOpts); + } else { + // Prefix the basic type, e.g. 'int X'. + S = ' ' + S; + S = T->getName(Policy.LangOpts) + S; + } +} + +void TypePrinter::PrintFixedWidthInt(const FixedWidthIntType *T, + std::string &S) { + // FIXME: Once we get bitwidth attribute, write as + // "int __attribute__((bitwidth(x)))". + std::string prefix = "__clang_fixedwidth"; + prefix += llvm::utostr_32(T->getWidth()); + prefix += (char)(T->isSigned() ? 'S' : 'U'); + if (S.empty()) { + S = prefix; + } else { + // Prefix the basic type, e.g. 'int X'. + S = prefix + S; + } +} + +void TypePrinter::PrintComplex(const ComplexType *T, std::string &S) { + Print(T->getElementType(), S); + S = "_Complex " + S; +} + +void TypePrinter::PrintPointer(const PointerType *T, std::string &S) { + S = '*' + S; + + // Handle things like 'int (*A)[4];' correctly. + // FIXME: this should include vectors, but vectors use attributes I guess. + if (isa<ArrayType>(T->getPointeeType())) + S = '(' + S + ')'; + + Print(T->getPointeeType(), S); +} + +void TypePrinter::PrintBlockPointer(const BlockPointerType *T, std::string &S) { + S = '^' + S; + Print(T->getPointeeType(), S); +} + +void TypePrinter::PrintLValueReference(const LValueReferenceType *T, + std::string &S) { + S = '&' + S; + + // Handle things like 'int (&A)[4];' correctly. + // FIXME: this should include vectors, but vectors use attributes I guess. + if (isa<ArrayType>(T->getPointeeTypeAsWritten())) + S = '(' + S + ')'; + + Print(T->getPointeeTypeAsWritten(), S); +} + +void TypePrinter::PrintRValueReference(const RValueReferenceType *T, + std::string &S) { + S = "&&" + S; + + // Handle things like 'int (&&A)[4];' correctly. + // FIXME: this should include vectors, but vectors use attributes I guess. + if (isa<ArrayType>(T->getPointeeTypeAsWritten())) + S = '(' + S + ')'; + + Print(T->getPointeeTypeAsWritten(), S); +} + +void TypePrinter::PrintMemberPointer(const MemberPointerType *T, + std::string &S) { + std::string C; + Print(QualType(T->getClass(), 0), C); + C += "::*"; + S = C + S; + + // Handle things like 'int (Cls::*A)[4];' correctly. + // FIXME: this should include vectors, but vectors use attributes I guess. + if (isa<ArrayType>(T->getPointeeType())) + S = '(' + S + ')'; + + Print(T->getPointeeType(), S); +} + +void TypePrinter::PrintConstantArray(const ConstantArrayType *T, + std::string &S) { + S += '['; + S += llvm::utostr(T->getSize().getZExtValue()); + S += ']'; + + Print(T->getElementType(), S); +} + +void TypePrinter::PrintIncompleteArray(const IncompleteArrayType *T, + std::string &S) { + S += "[]"; + Print(T->getElementType(), S); +} + +void TypePrinter::PrintVariableArray(const VariableArrayType *T, + std::string &S) { + S += '['; + + if (T->getIndexTypeQualifiers().hasQualifiers()) { + AppendTypeQualList(S, T->getIndexTypeCVRQualifiers()); + S += ' '; + } + + if (T->getSizeModifier() == VariableArrayType::Static) + S += "static"; + else if (T->getSizeModifier() == VariableArrayType::Star) + S += '*'; + + if (T->getSizeExpr()) { + std::string SStr; + llvm::raw_string_ostream s(SStr); + T->getSizeExpr()->printPretty(s, 0, Policy); + S += s.str(); + } + S += ']'; + + Print(T->getElementType(), S); +} + +void TypePrinter::PrintDependentSizedArray(const DependentSizedArrayType *T, + std::string &S) { + S += '['; + + if (T->getSizeExpr()) { + std::string SStr; + llvm::raw_string_ostream s(SStr); + T->getSizeExpr()->printPretty(s, 0, Policy); + S += s.str(); + } + S += ']'; + + Print(T->getElementType(), S); +} + +void TypePrinter::PrintDependentSizedExtVector( + const DependentSizedExtVectorType *T, + std::string &S) { + Print(T->getElementType(), S); + + S += " __attribute__((ext_vector_type("; + if (T->getSizeExpr()) { + std::string SStr; + llvm::raw_string_ostream s(SStr); + T->getSizeExpr()->printPretty(s, 0, Policy); + S += s.str(); + } + S += ")))"; +} + +void TypePrinter::PrintVector(const VectorType *T, std::string &S) { + // FIXME: We prefer to print the size directly here, but have no way + // to get the size of the type. + S += " __attribute__((__vector_size__("; + S += llvm::utostr_32(T->getNumElements()); // convert back to bytes. + std::string ET; + Print(T->getElementType(), ET); + S += " * sizeof(" + ET + "))))"; + Print(T->getElementType(), S); +} + +void TypePrinter::PrintExtVector(const ExtVectorType *T, std::string &S) { + S += " __attribute__((ext_vector_type("; + S += llvm::utostr_32(T->getNumElements()); + S += ")))"; + Print(T->getElementType(), S); +} + +void TypePrinter::PrintFunctionProto(const FunctionProtoType *T, + std::string &S) { + // If needed for precedence reasons, wrap the inner part in grouping parens. + if (!S.empty()) + S = "(" + S + ")"; + + S += "("; + std::string Tmp; + PrintingPolicy ParamPolicy(Policy); + ParamPolicy.SuppressSpecifiers = false; + for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i) { + if (i) S += ", "; + Print(T->getArgType(i), Tmp); + S += Tmp; + Tmp.clear(); + } + + if (T->isVariadic()) { + if (T->getNumArgs()) + S += ", "; + S += "..."; + } else if (T->getNumArgs() == 0 && !Policy.LangOpts.CPlusPlus) { + // Do not emit int() if we have a proto, emit 'int(void)'. + S += "void"; + } + + S += ")"; + if (T->getNoReturnAttr()) + S += " __attribute__((noreturn))"; + Print(T->getResultType(), S); + +} + +void TypePrinter::PrintFunctionNoProto(const FunctionNoProtoType *T, + std::string &S) { + // If needed for precedence reasons, wrap the inner part in grouping parens. + if (!S.empty()) + S = "(" + S + ")"; + + S += "()"; + if (T->getNoReturnAttr()) + S += " __attribute__((noreturn))"; + Print(T->getResultType(), S); +} + +void TypePrinter::PrintTypedef(const TypedefType *T, std::string &S) { + if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'. + S = ' ' + S; + S = T->getDecl()->getIdentifier()->getName().str() + S; +} + +void TypePrinter::PrintTypeOfExpr(const TypeOfExprType *T, std::string &S) { + if (!S.empty()) // Prefix the basic type, e.g. 'typeof(e) X'. + S = ' ' + S; + std::string Str; + llvm::raw_string_ostream s(Str); + T->getUnderlyingExpr()->printPretty(s, 0, Policy); + S = "typeof " + s.str() + S; +} + +void TypePrinter::PrintTypeOf(const TypeOfType *T, std::string &S) { + if (!S.empty()) // Prefix the basic type, e.g. 'typeof(t) X'. + S = ' ' + S; + std::string Tmp; + Print(T->getUnderlyingType(), Tmp); + S = "typeof(" + Tmp + ")" + S; +} + +void TypePrinter::PrintDecltype(const DecltypeType *T, std::string &S) { + if (!S.empty()) // Prefix the basic type, e.g. 'decltype(t) X'. + S = ' ' + S; + std::string Str; + llvm::raw_string_ostream s(Str); + T->getUnderlyingExpr()->printPretty(s, 0, Policy); + S = "decltype(" + s.str() + ")" + S; +} + +void TypePrinter::PrintTag(const TagType *T, std::string &InnerString) { + if (Policy.SuppressTag) + return; + + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. + InnerString = ' ' + InnerString; + + const char *Kind = Policy.SuppressTagKind? 0 : T->getDecl()->getKindName(); + const char *ID; + if (const IdentifierInfo *II = T->getDecl()->getIdentifier()) + ID = II->getNameStart(); + else if (TypedefDecl *Typedef = T->getDecl()->getTypedefForAnonDecl()) { + Kind = 0; + assert(Typedef->getIdentifier() && "Typedef without identifier?"); + ID = Typedef->getIdentifier()->getNameStart(); + } else + ID = "<anonymous>"; + + // If this is a class template specialization, print the template + // arguments. + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(T->getDecl())) { + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + std::string TemplateArgsStr + = TemplateSpecializationType::PrintTemplateArgumentList( + TemplateArgs.getFlatArgumentList(), + TemplateArgs.flat_size(), + Policy); + InnerString = TemplateArgsStr + InnerString; + } + + if (!Policy.SuppressScope) { + // Compute the full nested-name-specifier for this type. In C, + // this will always be empty. + std::string ContextStr; + for (DeclContext *DC = T->getDecl()->getDeclContext(); + !DC->isTranslationUnit(); DC = DC->getParent()) { + std::string MyPart; + if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) { + if (NS->getIdentifier()) + MyPart = NS->getNameAsString(); + } else if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(DC)) { + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + std::string TemplateArgsStr + = TemplateSpecializationType::PrintTemplateArgumentList( + TemplateArgs.getFlatArgumentList(), + TemplateArgs.flat_size(), + Policy); + MyPart = Spec->getIdentifier()->getName().str() + TemplateArgsStr; + } else if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) { + if (TypedefDecl *Typedef = Tag->getTypedefForAnonDecl()) + MyPart = Typedef->getIdentifier()->getName(); + else if (Tag->getIdentifier()) + MyPart = Tag->getIdentifier()->getName(); + } + + if (!MyPart.empty()) + ContextStr = MyPart + "::" + ContextStr; + } + + if (Kind) + InnerString = std::string(Kind) + ' ' + ContextStr + ID + InnerString; + else + InnerString = ContextStr + ID + InnerString; + } else + InnerString = ID + InnerString; +} + +void TypePrinter::PrintRecord(const RecordType *T, std::string &S) { + PrintTag(T, S); +} + +void TypePrinter::PrintEnum(const EnumType *T, std::string &S) { + PrintTag(T, S); +} + +void TypePrinter::PrintElaborated(const ElaboratedType *T, std::string &S) { + std::string TypeStr; + PrintingPolicy InnerPolicy(Policy); + InnerPolicy.SuppressTagKind = true; + TypePrinter(InnerPolicy).Print(T->getUnderlyingType(), S); + + S = std::string(T->getNameForTagKind(T->getTagKind())) + ' ' + S; +} + +void TypePrinter::PrintTemplateTypeParm(const TemplateTypeParmType *T, + std::string &S) { + if (!S.empty()) // Prefix the basic type, e.g. 'parmname X'. + S = ' ' + S; + + if (!T->getName()) + S = "type-parameter-" + llvm::utostr_32(T->getDepth()) + '-' + + llvm::utostr_32(T->getIndex()) + S; + else + S = T->getName()->getName().str() + S; +} + +void TypePrinter::PrintSubstTemplateTypeParm(const SubstTemplateTypeParmType *T, + std::string &S) { + Print(T->getReplacementType(), S); +} + +void TypePrinter::PrintTemplateSpecialization( + const TemplateSpecializationType *T, + std::string &S) { + std::string SpecString; + + { + llvm::raw_string_ostream OS(SpecString); + T->getTemplateName().print(OS, Policy); + } + + SpecString += TemplateSpecializationType::PrintTemplateArgumentList( + T->getArgs(), + T->getNumArgs(), + Policy); + if (S.empty()) + S.swap(SpecString); + else + S = SpecString + ' ' + S; +} + +void TypePrinter::PrintQualifiedName(const QualifiedNameType *T, + std::string &S) { + std::string MyString; + + { + llvm::raw_string_ostream OS(MyString); + T->getQualifier()->print(OS, Policy); + } + + std::string TypeStr; + PrintingPolicy InnerPolicy(Policy); + InnerPolicy.SuppressTagKind = true; + InnerPolicy.SuppressScope = true; + TypePrinter(InnerPolicy).Print(T->getNamedType(), TypeStr); + + MyString += TypeStr; + if (S.empty()) + S.swap(MyString); + else + S = MyString + ' ' + S; +} + +void TypePrinter::PrintTypename(const TypenameType *T, std::string &S) { + std::string MyString; + + { + llvm::raw_string_ostream OS(MyString); + OS << "typename "; + T->getQualifier()->print(OS, Policy); + + if (const IdentifierInfo *Ident = T->getIdentifier()) + OS << Ident->getName(); + else if (const TemplateSpecializationType *Spec = T->getTemplateId()) { + Spec->getTemplateName().print(OS, Policy, true); + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Spec->getArgs(), + Spec->getNumArgs(), + Policy); + } + } + + if (S.empty()) + S.swap(MyString); + else + S = MyString + ' ' + S; +} + +void TypePrinter::PrintObjCInterface(const ObjCInterfaceType *T, + std::string &S) { + if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'. + S = ' ' + S; + + std::string ObjCQIString = T->getDecl()->getNameAsString(); + if (T->getNumProtocols()) { + ObjCQIString += '<'; + bool isFirst = true; + for (ObjCInterfaceType::qual_iterator I = T->qual_begin(), + E = T->qual_end(); + I != E; ++I) { + if (isFirst) + isFirst = false; + else + ObjCQIString += ','; + ObjCQIString += (*I)->getNameAsString(); + } + ObjCQIString += '>'; + } + S = ObjCQIString + S; +} + +void TypePrinter::PrintObjCObjectPointer(const ObjCObjectPointerType *T, + std::string &S) { + std::string ObjCQIString; + + if (T->isObjCIdType() || T->isObjCQualifiedIdType()) + ObjCQIString = "id"; + else if (T->isObjCClassType() || T->isObjCQualifiedClassType()) + ObjCQIString = "Class"; + else + ObjCQIString = T->getInterfaceDecl()->getNameAsString(); + + if (!T->qual_empty()) { + ObjCQIString += '<'; + for (ObjCObjectPointerType::qual_iterator I = T->qual_begin(), + E = T->qual_end(); + I != E; ++I) { + ObjCQIString += (*I)->getNameAsString(); + if (I+1 != E) + ObjCQIString += ','; + } + ObjCQIString += '>'; + } + + T->getPointeeType().getLocalQualifiers().getAsStringInternal(ObjCQIString, + Policy); + + if (!T->isObjCIdType() && !T->isObjCQualifiedIdType()) + ObjCQIString += " *"; // Don't forget the implicit pointer. + else if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'. + S = ' ' + S; + + S = ObjCQIString + S; +} + +static void PrintTemplateArgument(std::string &Buffer, + const TemplateArgument &Arg, + const PrintingPolicy &Policy) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + assert(false && "Null template argument"); + break; + + case TemplateArgument::Type: + Arg.getAsType().getAsStringInternal(Buffer, Policy); + break; + + case TemplateArgument::Declaration: + Buffer = cast<NamedDecl>(Arg.getAsDecl())->getNameAsString(); + break; + + case TemplateArgument::Template: { + llvm::raw_string_ostream s(Buffer); + Arg.getAsTemplate().print(s, Policy); + break; + } + + case TemplateArgument::Integral: + Buffer = Arg.getAsIntegral()->toString(10, true); + break; + + case TemplateArgument::Expression: { + llvm::raw_string_ostream s(Buffer); + Arg.getAsExpr()->printPretty(s, 0, Policy); + break; + } + + case TemplateArgument::Pack: + assert(0 && "FIXME: Implement!"); + break; + } +} + +std::string +TemplateSpecializationType::PrintTemplateArgumentList( + const TemplateArgument *Args, + unsigned NumArgs, + const PrintingPolicy &Policy) { + std::string SpecString; + SpecString += '<'; + for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { + if (Arg) + SpecString += ", "; + + // Print the argument into a string. + std::string ArgString; + PrintTemplateArgument(ArgString, Args[Arg], Policy); + + // If this is the first argument and its string representation + // begins with the global scope specifier ('::foo'), add a space + // to avoid printing the diagraph '<:'. + if (!Arg && !ArgString.empty() && ArgString[0] == ':') + SpecString += ' '; + + SpecString += ArgString; + } + + // If the last character of our string is '>', add another space to + // keep the two '>''s separate tokens. We don't *have* to do this in + // C++0x, but it's still good hygiene. + if (SpecString[SpecString.size() - 1] == '>') + SpecString += ' '; + + SpecString += '>'; + + return SpecString; +} + +// Sadly, repeat all that with TemplateArgLoc. +std::string TemplateSpecializationType:: +PrintTemplateArgumentList(const TemplateArgumentLoc *Args, unsigned NumArgs, + const PrintingPolicy &Policy) { + std::string SpecString; + SpecString += '<'; + for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { + if (Arg) + SpecString += ", "; + + // Print the argument into a string. + std::string ArgString; + PrintTemplateArgument(ArgString, Args[Arg].getArgument(), Policy); + + // If this is the first argument and its string representation + // begins with the global scope specifier ('::foo'), add a space + // to avoid printing the diagraph '<:'. + if (!Arg && !ArgString.empty() && ArgString[0] == ':') + SpecString += ' '; + + SpecString += ArgString; + } + + // If the last character of our string is '>', add another space to + // keep the two '>''s separate tokens. We don't *have* to do this in + // C++0x, but it's still good hygiene. + if (SpecString[SpecString.size() - 1] == '>') + SpecString += ' '; + + SpecString += '>'; + + return SpecString; +} + +void QualType::dump(const char *msg) const { + std::string R = "identifier"; + LangOptions LO; + getAsStringInternal(R, PrintingPolicy(LO)); + if (msg) + fprintf(stderr, "%s: %s\n", msg, R.c_str()); + else + fprintf(stderr, "%s\n", R.c_str()); +} +void QualType::dump() const { + dump(""); +} + +void Type::dump() const { + QualType(this, 0).dump(); +} + +std::string Qualifiers::getAsString() const { + LangOptions LO; + return getAsString(PrintingPolicy(LO)); +} + +// Appends qualifiers to the given string, separated by spaces. Will +// prefix a space if the string is non-empty. Will not append a final +// space. +void Qualifiers::getAsStringInternal(std::string &S, + const PrintingPolicy&) const { + AppendTypeQualList(S, getCVRQualifiers()); + if (unsigned AddressSpace = getAddressSpace()) { + if (!S.empty()) S += ' '; + S += "__attribute__((address_space("; + S += llvm::utostr_32(AddressSpace); + S += ")))"; + } + if (Qualifiers::GC GCAttrType = getObjCGCAttr()) { + if (!S.empty()) S += ' '; + S += "__attribute__((objc_gc("; + if (GCAttrType == Qualifiers::Weak) + S += "weak"; + else + S += "strong"; + S += ")))"; + } +} + +std::string QualType::getAsString() const { + std::string S; + LangOptions LO; + getAsStringInternal(S, PrintingPolicy(LO)); + return S; +} + +void QualType::getAsStringInternal(std::string &S, + const PrintingPolicy &Policy) const { + TypePrinter Printer(Policy); + Printer.Print(*this, S); +} + diff --git a/lib/Analysis/AnalysisManager.cpp b/lib/Analysis/AnalysisManager.cpp deleted file mode 100644 index c2733faa683c..000000000000 --- a/lib/Analysis/AnalysisManager.cpp +++ /dev/null @@ -1,35 +0,0 @@ -//== AnalysisManager.cpp - Path sensitive analysis data manager ----*- C++ -*-// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the AnalysisManager class. -// -//===----------------------------------------------------------------------===// - -#include "clang/Analysis/PathSensitive/AnalysisManager.h" -#include "clang/Basic/SourceManager.h" - -using namespace clang; - -void AnalysisManager::DisplayFunction(Decl *D) { - - if (DisplayedFunction) - return; - - DisplayedFunction = true; - - // FIXME: Is getCodeDecl() always a named decl? - if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) { - const NamedDecl *ND = cast<NamedDecl>(D); - SourceManager &SM = getASTContext().getSourceManager(); - (llvm::errs() << "ANALYZE: " - << SM.getPresumedLoc(ND->getLocation()).getFilename() - << ' ' << ND->getNameAsString() << '\n').flush(); - } -} - diff --git a/lib/Analysis/ArrayBoundChecker.cpp b/lib/Analysis/ArrayBoundChecker.cpp new file mode 100644 index 000000000000..549a22bec172 --- /dev/null +++ b/lib/Analysis/ArrayBoundChecker.cpp @@ -0,0 +1,86 @@ +//== ArrayBoundChecker.cpp ------------------------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines ArrayBoundChecker, which is a path-sensitive check +// which looks for an out-of-bound array element access. +// +//===----------------------------------------------------------------------===// + +#include "GRExprEngineInternalChecks.h" +#include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" + +using namespace clang; + +namespace { +class VISIBILITY_HIDDEN ArrayBoundChecker : + public CheckerVisitor<ArrayBoundChecker> { + BuiltinBug *BT; +public: + ArrayBoundChecker() : BT(0) {} + static void *getTag(); + void VisitLocation(CheckerContext &C, const Stmt *S, SVal l); +}; +} + +void clang::RegisterArrayBoundChecker(GRExprEngine &Eng) { + Eng.registerCheck(new ArrayBoundChecker()); +} + +void *ArrayBoundChecker::getTag() { + static int x = 0; return &x; +} + +void ArrayBoundChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l){ + // Check for out of bound array element access. + const MemRegion *R = l.getAsRegion(); + if (!R) + return; + + R = R->StripCasts(); + + const ElementRegion *ER = dyn_cast<ElementRegion>(R); + if (!ER) + return; + + // Get the index of the accessed element. + DefinedOrUnknownSVal &Idx = cast<DefinedOrUnknownSVal>(ER->getIndex()); + + const GRState *state = C.getState(); + + // Get the size of the array. + DefinedOrUnknownSVal NumElements + = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion()); + + const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true); + const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false); + if (StOutBound && !StInBound) { + ExplodedNode *N = C.GenerateNode(S, StOutBound, true); + + if (!N) + return; + + if (!BT) + BT = new BuiltinBug("Out-of-bound array access", + "Access out-of-bound array element (buffer overflow)"); + + // FIXME: It would be nice to eventually make this diagnostic more clear, + // e.g., by referencing the original declaration or by saying *why* this + // reference is outside the range. + + // Generate a report for this bug. + RangedBugReport *report = + new RangedBugReport(*BT, BT->getDescription(), N); + + report->addRange(S->getSourceRange()); + + C.EmitReport(report); + } +} diff --git a/lib/Analysis/AttrNonNullChecker.cpp b/lib/Analysis/AttrNonNullChecker.cpp index 1cf5d0c4af2d..01e1a1fcf69b 100644 --- a/lib/Analysis/AttrNonNullChecker.cpp +++ b/lib/Analysis/AttrNonNullChecker.cpp @@ -12,14 +12,28 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/Checkers/AttrNonNullChecker.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" #include "clang/Analysis/PathSensitive/BugReporter.h" +#include "GRExprEngineInternalChecks.h" using namespace clang; -void *AttrNonNullChecker::getTag() { - static int x = 0; - return &x; +namespace { +class VISIBILITY_HIDDEN AttrNonNullChecker + : public CheckerVisitor<AttrNonNullChecker> { + BugType *BT; +public: + AttrNonNullChecker() : BT(0) {} + static void *getTag() { + static int x = 0; + return &x; + } + void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); +}; +} // end anonymous namespace + +void clang::RegisterAttrNonNullChecker(GRExprEngine &Eng) { + Eng.registerCheck(new AttrNonNullChecker()); } void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C, diff --git a/lib/Analysis/BadCallChecker.cpp b/lib/Analysis/BadCallChecker.cpp index 33bb5158d2b9..7a7ea188ba59 100644 --- a/lib/Analysis/BadCallChecker.cpp +++ b/lib/Analysis/BadCallChecker.cpp @@ -12,14 +12,27 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/Checkers/BadCallChecker.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" #include "clang/Analysis/PathSensitive/BugReporter.h" +#include "GRExprEngineInternalChecks.h" using namespace clang; -void *BadCallChecker::getTag() { - static int x = 0; - return &x; +namespace { +class VISIBILITY_HIDDEN BadCallChecker : public CheckerVisitor<BadCallChecker> { + BuiltinBug *BT; +public: + BadCallChecker() : BT(0) {} + static void *getTag() { + static int x = 0; + return &x; + } + void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); +}; +} // end anonymous namespace + +void clang::RegisterBadCallChecker(GRExprEngine &Eng) { + Eng.registerCheck(new BadCallChecker()); } void BadCallChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { @@ -29,11 +42,11 @@ void BadCallChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { if (L.isUndef() || isa<loc::ConcreteInt>(L)) { if (ExplodedNode *N = C.GenerateNode(CE, true)) { if (!BT) - BT = new BuiltinBug(0, "Invalid function call", + BT = new BuiltinBug("Invalid function call", "Called function pointer is a null or undefined pointer value"); EnhancedBugReport *R = - new EnhancedBugReport(*BT, BT->getDescription().c_str(), N); + new EnhancedBugReport(*BT, BT->getDescription(), N); R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, bugreporter::GetCalleeExpr(N)); diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp index 4781d5ec243e..c2ecfa1f417f 100644 --- a/lib/Analysis/BasicObjCFoundationChecks.cpp +++ b/lib/Analysis/BasicObjCFoundationChecks.cpp @@ -384,7 +384,7 @@ bool AuditCFNumberCreate::Audit(ExplodedNode* N,GRStateManager&){ if (!LV) return false; - const TypedRegion* R = dyn_cast<TypedRegion>(LV->getBaseRegion()); + const TypedRegion* R = dyn_cast<TypedRegion>(LV->StripCasts()); if (!R) return false; diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp index 888af9bd57a4..800a76fb0aee 100644 --- a/lib/Analysis/BasicStore.cpp +++ b/lib/Analysis/BasicStore.cpp @@ -268,20 +268,6 @@ SValuator::CastResult BasicStoreManager::Retrieve(const GRState *state, case loc::MemRegionKind: { const MemRegion* R = cast<loc::MemRegionVal>(loc).getRegion(); - if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { - // Just support void**, void***, intptr_t*, intptr_t**, etc., for now. - // This is needed to handle OSCompareAndSwapPtr() and friends. - ASTContext &Ctx = StateMgr.getContext(); - QualType T = ER->getLocationType(Ctx); - - if (!isHigherOrderRawPtr(T, Ctx)) - return SValuator::CastResult(state, UnknownVal()); - - // FIXME: Should check for element 0. - // Otherwise, strip the element region. - R = ER->getSuperRegion(); - } - if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R))) return SValuator::CastResult(state, UnknownVal()); @@ -291,7 +277,8 @@ SValuator::CastResult BasicStoreManager::Retrieve(const GRState *state, if (!Val) break; - return CastRetrievedVal(*Val, state, cast<TypedRegion>(R), T); + return SValuator::CastResult(state, + CastRetrievedVal(*Val, cast<TypedRegion>(R), T)); } case loc::ConcreteIntKind: @@ -624,7 +611,7 @@ const GRState *BasicStoreManager::InvalidateRegion(const GRState *state, const Expr *E, unsigned Count, InvalidatedSymbols *IS) { - R = R->getBaseRegion(); + R = R->StripCasts(); if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R))) return state; diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index 03614e83398f..55e5f174cb9f 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -308,7 +308,234 @@ public: } }; +//===----------------------------------------------------------------------===// +// Reference-counting logic (typestate + counts). +//===----------------------------------------------------------------------===// +class VISIBILITY_HIDDEN RefVal { +public: + enum Kind { + Owned = 0, // Owning reference. + NotOwned, // Reference is not owned by still valid (not freed). + Released, // Object has been released. + ReturnedOwned, // Returned object passes ownership to caller. + ReturnedNotOwned, // Return object does not pass ownership to caller. + ERROR_START, + ErrorDeallocNotOwned, // -dealloc called on non-owned object. + ErrorDeallocGC, // Calling -dealloc with GC enabled. + ErrorUseAfterRelease, // Object used after released. + ErrorReleaseNotOwned, // Release of an object that was not owned. + ERROR_LEAK_START, + ErrorLeak, // A memory leak due to excessive reference counts. + ErrorLeakReturned, // A memory leak due to the returning method not having + // the correct naming conventions. + ErrorGCLeakReturned, + ErrorOverAutorelease, + ErrorReturnedNotOwned + }; + +private: + Kind kind; + RetEffect::ObjKind okind; + unsigned Cnt; + unsigned ACnt; + QualType T; + + RefVal(Kind k, RetEffect::ObjKind o, unsigned cnt, unsigned acnt, QualType t) + : kind(k), okind(o), Cnt(cnt), ACnt(acnt), T(t) {} + + RefVal(Kind k, unsigned cnt = 0) + : kind(k), okind(RetEffect::AnyObj), Cnt(cnt), ACnt(0) {} + +public: + Kind getKind() const { return kind; } + + RetEffect::ObjKind getObjKind() const { return okind; } + + unsigned getCount() const { return Cnt; } + unsigned getAutoreleaseCount() const { return ACnt; } + unsigned getCombinedCounts() const { return Cnt + ACnt; } + void clearCounts() { Cnt = 0; ACnt = 0; } + void setCount(unsigned i) { Cnt = i; } + void setAutoreleaseCount(unsigned i) { ACnt = i; } + + QualType getType() const { return T; } + + // Useful predicates. + + static bool isError(Kind k) { return k >= ERROR_START; } + + static bool isLeak(Kind k) { return k >= ERROR_LEAK_START; } + + bool isOwned() const { + return getKind() == Owned; + } + + bool isNotOwned() const { + return getKind() == NotOwned; + } + + bool isReturnedOwned() const { + return getKind() == ReturnedOwned; + } + + bool isReturnedNotOwned() const { + return getKind() == ReturnedNotOwned; + } + + bool isNonLeakError() const { + Kind k = getKind(); + return isError(k) && !isLeak(k); + } + + static RefVal makeOwned(RetEffect::ObjKind o, QualType t, + unsigned Count = 1) { + return RefVal(Owned, o, Count, 0, t); + } + + static RefVal makeNotOwned(RetEffect::ObjKind o, QualType t, + unsigned Count = 0) { + return RefVal(NotOwned, o, Count, 0, t); + } + + // Comparison, profiling, and pretty-printing. + + bool operator==(const RefVal& X) const { + return kind == X.kind && Cnt == X.Cnt && T == X.T && ACnt == X.ACnt; + } + + RefVal operator-(size_t i) const { + return RefVal(getKind(), getObjKind(), getCount() - i, + getAutoreleaseCount(), getType()); + } + + RefVal operator+(size_t i) const { + return RefVal(getKind(), getObjKind(), getCount() + i, + getAutoreleaseCount(), getType()); + } + + RefVal operator^(Kind k) const { + return RefVal(k, getObjKind(), getCount(), getAutoreleaseCount(), + getType()); + } + + RefVal autorelease() const { + return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount()+1, + getType()); + } + + void Profile(llvm::FoldingSetNodeID& ID) const { + ID.AddInteger((unsigned) kind); + ID.AddInteger(Cnt); + ID.AddInteger(ACnt); + ID.Add(T); + } + + void print(llvm::raw_ostream& Out) const; +}; + +void RefVal::print(llvm::raw_ostream& Out) const { + if (!T.isNull()) + Out << "Tracked Type:" << T.getAsString() << '\n'; + + switch (getKind()) { + default: assert(false); + case Owned: { + Out << "Owned"; + unsigned cnt = getCount(); + if (cnt) Out << " (+ " << cnt << ")"; + break; + } + + case NotOwned: { + Out << "NotOwned"; + unsigned cnt = getCount(); + if (cnt) Out << " (+ " << cnt << ")"; + break; + } + + case ReturnedOwned: { + Out << "ReturnedOwned"; + unsigned cnt = getCount(); + if (cnt) Out << " (+ " << cnt << ")"; + break; + } + + case ReturnedNotOwned: { + Out << "ReturnedNotOwned"; + unsigned cnt = getCount(); + if (cnt) Out << " (+ " << cnt << ")"; + break; + } + + case Released: + Out << "Released"; + break; + + case ErrorDeallocGC: + Out << "-dealloc (GC)"; + break; + + case ErrorDeallocNotOwned: + Out << "-dealloc (not-owned)"; + break; + + case ErrorLeak: + Out << "Leaked"; + break; + + case ErrorLeakReturned: + Out << "Leaked (Bad naming)"; + break; + + case ErrorGCLeakReturned: + Out << "Leaked (GC-ed at return)"; + break; + + case ErrorUseAfterRelease: + Out << "Use-After-Release [ERROR]"; + break; + + case ErrorReleaseNotOwned: + Out << "Release of Not-Owned [ERROR]"; + break; + + case RefVal::ErrorOverAutorelease: + Out << "Over autoreleased"; + break; + + case RefVal::ErrorReturnedNotOwned: + Out << "Non-owned object returned instead of owned"; + break; + } + + if (ACnt) { + Out << " [ARC +" << ACnt << ']'; + } +} +} //end anonymous namespace + +//===----------------------------------------------------------------------===// +// RefBindings - State used to track object reference counts. +//===----------------------------------------------------------------------===// + +typedef llvm::ImmutableMap<SymbolRef, RefVal> RefBindings; + +namespace clang { + template<> + struct GRStateTrait<RefBindings> : public GRStatePartialTrait<RefBindings> { + static void* GDMIndex() { + static int RefBIndex = 0; + return &RefBIndex; + } + }; +} + +//===----------------------------------------------------------------------===// +// Summaries +//===----------------------------------------------------------------------===// + +namespace { class VISIBILITY_HIDDEN RetainSummary { /// Args - an ordered vector of (index, ArgEffect) pairs, where index /// specifies the argument (starting from 0). This can be sparsely @@ -757,7 +984,11 @@ public: RetainSummary* getSummary(FunctionDecl* FD); - RetainSummary* getInstanceMethodSummary(ObjCMessageExpr* ME, + RetainSummary *getInstanceMethodSummary(const ObjCMessageExpr *ME, + const GRState *state, + const LocationContext *LC); + + RetainSummary* getInstanceMethodSummary(const ObjCMessageExpr* ME, const ObjCInterfaceDecl* ID) { return getInstanceMethodSummary(ME->getSelector(), ME->getClassName(), ID, ME->getMethodDecl(), ME->getType()); @@ -773,7 +1004,7 @@ public: const ObjCMethodDecl *MD, QualType RetTy); - RetainSummary *getClassMethodSummary(ObjCMessageExpr *ME) { + RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME) { return getClassMethodSummary(ME->getSelector(), ME->getClassName(), ME->getClassInfo().first, ME->getMethodDecl(), ME->getType()); @@ -1306,7 +1537,7 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD, E = MD->param_end(); I != E; ++I, ++i) if (ParmVarDecl *PD = *I) { QualType Ty = Ctx.getCanonicalType(PD->getType()); - if (Ty.getUnqualifiedType() == Ctx.VoidPtrTy) + if (Ty.getLocalUnqualifiedType() == Ctx.VoidPtrTy) ScratchArgs = AF.Add(ScratchArgs, i, StopTracking); } } @@ -1350,6 +1581,61 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD, } RetainSummary* +RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME, + const GRState *state, + const LocationContext *LC) { + + // We need the type-information of the tracked receiver object + // Retrieve it from the state. + const Expr *Receiver = ME->getReceiver(); + const ObjCInterfaceDecl* ID = 0; + + // FIXME: Is this really working as expected? There are cases where + // we just use the 'ID' from the message expression. + SVal receiverV = state->getSValAsScalarOrLoc(Receiver); + + // FIXME: Eventually replace the use of state->get<RefBindings> with + // a generic API for reasoning about the Objective-C types of symbolic + // objects. + if (SymbolRef Sym = receiverV.getAsLocSymbol()) + if (const RefVal *T = state->get<RefBindings>(Sym)) + if (const ObjCObjectPointerType* PT = + T->getType()->getAs<ObjCObjectPointerType>()) + ID = PT->getInterfaceDecl(); + + // FIXME: this is a hack. This may or may not be the actual method + // that is called. + if (!ID) { + if (const ObjCObjectPointerType *PT = + Receiver->getType()->getAs<ObjCObjectPointerType>()) + ID = PT->getInterfaceDecl(); + } + + // FIXME: The receiver could be a reference to a class, meaning that + // we should use the class method. + RetainSummary *Summ = getInstanceMethodSummary(ME, ID); + + // Special-case: are we sending a mesage to "self"? + // This is a hack. When we have full-IP this should be removed. + if (isa<ObjCMethodDecl>(LC->getDecl())) { + if (const loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&receiverV)) { + // Get the region associated with 'self'. + if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) { + SVal SelfVal = state->getSVal(state->getRegion(SelfDecl, LC)); + if (L->StripCasts() == SelfVal.getAsRegion()) { + // Update the summary to make the default argument effect + // 'StopTracking'. + Summ = copySummary(Summ); + Summ->setDefaultArgEffect(StopTracking); + } + } + } + } + + return Summ ? Summ : getDefaultSummary(); +} + +RetainSummary* RetainSummaryManager::getInstanceMethodSummary(Selector S, IdentifierInfo *ClsName, const ObjCInterfaceDecl* ID, @@ -1569,230 +1855,6 @@ void RetainSummaryManager::InitializeMethodSummaries() { } //===----------------------------------------------------------------------===// -// Reference-counting logic (typestate + counts). -//===----------------------------------------------------------------------===// - -namespace { - -class VISIBILITY_HIDDEN RefVal { -public: - enum Kind { - Owned = 0, // Owning reference. - NotOwned, // Reference is not owned by still valid (not freed). - Released, // Object has been released. - ReturnedOwned, // Returned object passes ownership to caller. - ReturnedNotOwned, // Return object does not pass ownership to caller. - ERROR_START, - ErrorDeallocNotOwned, // -dealloc called on non-owned object. - ErrorDeallocGC, // Calling -dealloc with GC enabled. - ErrorUseAfterRelease, // Object used after released. - ErrorReleaseNotOwned, // Release of an object that was not owned. - ERROR_LEAK_START, - ErrorLeak, // A memory leak due to excessive reference counts. - ErrorLeakReturned, // A memory leak due to the returning method not having - // the correct naming conventions. - ErrorGCLeakReturned, - ErrorOverAutorelease, - ErrorReturnedNotOwned - }; - -private: - Kind kind; - RetEffect::ObjKind okind; - unsigned Cnt; - unsigned ACnt; - QualType T; - - RefVal(Kind k, RetEffect::ObjKind o, unsigned cnt, unsigned acnt, QualType t) - : kind(k), okind(o), Cnt(cnt), ACnt(acnt), T(t) {} - - RefVal(Kind k, unsigned cnt = 0) - : kind(k), okind(RetEffect::AnyObj), Cnt(cnt), ACnt(0) {} - -public: - Kind getKind() const { return kind; } - - RetEffect::ObjKind getObjKind() const { return okind; } - - unsigned getCount() const { return Cnt; } - unsigned getAutoreleaseCount() const { return ACnt; } - unsigned getCombinedCounts() const { return Cnt + ACnt; } - void clearCounts() { Cnt = 0; ACnt = 0; } - void setCount(unsigned i) { Cnt = i; } - void setAutoreleaseCount(unsigned i) { ACnt = i; } - - QualType getType() const { return T; } - - // Useful predicates. - - static bool isError(Kind k) { return k >= ERROR_START; } - - static bool isLeak(Kind k) { return k >= ERROR_LEAK_START; } - - bool isOwned() const { - return getKind() == Owned; - } - - bool isNotOwned() const { - return getKind() == NotOwned; - } - - bool isReturnedOwned() const { - return getKind() == ReturnedOwned; - } - - bool isReturnedNotOwned() const { - return getKind() == ReturnedNotOwned; - } - - bool isNonLeakError() const { - Kind k = getKind(); - return isError(k) && !isLeak(k); - } - - static RefVal makeOwned(RetEffect::ObjKind o, QualType t, - unsigned Count = 1) { - return RefVal(Owned, o, Count, 0, t); - } - - static RefVal makeNotOwned(RetEffect::ObjKind o, QualType t, - unsigned Count = 0) { - return RefVal(NotOwned, o, Count, 0, t); - } - - // Comparison, profiling, and pretty-printing. - - bool operator==(const RefVal& X) const { - return kind == X.kind && Cnt == X.Cnt && T == X.T && ACnt == X.ACnt; - } - - RefVal operator-(size_t i) const { - return RefVal(getKind(), getObjKind(), getCount() - i, - getAutoreleaseCount(), getType()); - } - - RefVal operator+(size_t i) const { - return RefVal(getKind(), getObjKind(), getCount() + i, - getAutoreleaseCount(), getType()); - } - - RefVal operator^(Kind k) const { - return RefVal(k, getObjKind(), getCount(), getAutoreleaseCount(), - getType()); - } - - RefVal autorelease() const { - return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount()+1, - getType()); - } - - void Profile(llvm::FoldingSetNodeID& ID) const { - ID.AddInteger((unsigned) kind); - ID.AddInteger(Cnt); - ID.AddInteger(ACnt); - ID.Add(T); - } - - void print(llvm::raw_ostream& Out) const; -}; - -void RefVal::print(llvm::raw_ostream& Out) const { - if (!T.isNull()) - Out << "Tracked Type:" << T.getAsString() << '\n'; - - switch (getKind()) { - default: assert(false); - case Owned: { - Out << "Owned"; - unsigned cnt = getCount(); - if (cnt) Out << " (+ " << cnt << ")"; - break; - } - - case NotOwned: { - Out << "NotOwned"; - unsigned cnt = getCount(); - if (cnt) Out << " (+ " << cnt << ")"; - break; - } - - case ReturnedOwned: { - Out << "ReturnedOwned"; - unsigned cnt = getCount(); - if (cnt) Out << " (+ " << cnt << ")"; - break; - } - - case ReturnedNotOwned: { - Out << "ReturnedNotOwned"; - unsigned cnt = getCount(); - if (cnt) Out << " (+ " << cnt << ")"; - break; - } - - case Released: - Out << "Released"; - break; - - case ErrorDeallocGC: - Out << "-dealloc (GC)"; - break; - - case ErrorDeallocNotOwned: - Out << "-dealloc (not-owned)"; - break; - - case ErrorLeak: - Out << "Leaked"; - break; - - case ErrorLeakReturned: - Out << "Leaked (Bad naming)"; - break; - - case ErrorGCLeakReturned: - Out << "Leaked (GC-ed at return)"; - break; - - case ErrorUseAfterRelease: - Out << "Use-After-Release [ERROR]"; - break; - - case ErrorReleaseNotOwned: - Out << "Release of Not-Owned [ERROR]"; - break; - - case RefVal::ErrorOverAutorelease: - Out << "Over autoreleased"; - break; - - case RefVal::ErrorReturnedNotOwned: - Out << "Non-owned object returned instead of owned"; - break; - } - - if (ACnt) { - Out << " [ARC +" << ACnt << ']'; - } -} - -} // end anonymous namespace - -//===----------------------------------------------------------------------===// -// RefBindings - State used to track object reference counts. -//===----------------------------------------------------------------------===// - -typedef llvm::ImmutableMap<SymbolRef, RefVal> RefBindings; -static int RefBIndex = 0; - -namespace clang { - template<> - struct GRStateTrait<RefBindings> : public GRStatePartialTrait<RefBindings> { - static inline void* GDMIndex() { return &RefBIndex; } - }; -} - -//===----------------------------------------------------------------------===// // AutoreleaseBindings - State used to track objects in autorelease pools. //===----------------------------------------------------------------------===// @@ -3004,69 +3066,14 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, GRStmtNodeBuilder& Builder, ObjCMessageExpr* ME, ExplodedNode* Pred) { - RetainSummary* Summ = 0; - - if (Expr* Receiver = ME->getReceiver()) { - // We need the type-information of the tracked receiver object - // Retrieve it from the state. - const ObjCInterfaceDecl* ID = 0; - - // FIXME: Wouldn't it be great if this code could be reduced? It's just - // a chain of lookups. - // FIXME: Is this really working as expected? There are cases where - // we just use the 'ID' from the message expression. - const GRState* St = Builder.GetState(Pred); - SVal V = St->getSValAsScalarOrLoc(Receiver); - - SymbolRef Sym = V.getAsLocSymbol(); - - if (Sym) { - if (const RefVal* T = St->get<RefBindings>(Sym)) { - if (const ObjCObjectPointerType* PT = - T->getType()->getAs<ObjCObjectPointerType>()) - ID = PT->getInterfaceDecl(); - } - } - - // FIXME: this is a hack. This may or may not be the actual method - // that is called. - if (!ID) { - if (const ObjCObjectPointerType *PT = - Receiver->getType()->getAs<ObjCObjectPointerType>()) - ID = PT->getInterfaceDecl(); - } - - // FIXME: The receiver could be a reference to a class, meaning that - // we should use the class method. - Summ = Summaries.getInstanceMethodSummary(ME, ID); - - // Special-case: are we sending a mesage to "self"? - // This is a hack. When we have full-IP this should be removed. - if (isa<ObjCMethodDecl>(Pred->getLocationContext()->getDecl())) { - if (Expr* Receiver = ME->getReceiver()) { - SVal X = St->getSValAsScalarOrLoc(Receiver); - if (loc::MemRegionVal* L = dyn_cast<loc::MemRegionVal>(&X)) { - // Get the region associated with 'self'. - const LocationContext *LC = Pred->getLocationContext(); - if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) { - SVal SelfVal = St->getSVal(St->getRegion(SelfDecl, LC)); - if (L->getBaseRegion() == SelfVal.getAsRegion()) { - // Update the summary to make the default argument effect - // 'StopTracking'. - Summ = Summaries.copySummary(Summ); - Summ->setDefaultArgEffect(StopTracking); - } - } - } - } - } - } - else - Summ = Summaries.getClassMethodSummary(ME); - - if (!Summ) - Summ = Summaries.getDefaultSummary(); + + RetainSummary *Summ = + ME->getReceiver() + ? Summaries.getInstanceMethodSummary(ME, Builder.GetState(Pred), + Pred->getLocationContext()) + : Summaries.getClassMethodSummary(ME); + assert(Summ && "RetainSummary is null"); EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ, ME->arg_begin(), ME->arg_end(), Pred); } diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index cd4697f2f324..8e8c1e7b25ed 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -2,7 +2,7 @@ set(LLVM_NO_RTTI 1) add_clang_library(clangAnalysis AnalysisContext.cpp - AnalysisManager.cpp + ArrayBoundChecker.cpp AttrNonNullChecker.cpp BadCallChecker.cpp BasicConstraintManager.cpp @@ -15,27 +15,39 @@ add_clang_library(clangAnalysis CFRefCount.cpp CallGraph.cpp CallInliner.cpp + CastToStructChecker.cpp CheckDeadStores.cpp CheckObjCDealloc.cpp CheckObjCInstMethSignature.cpp CheckObjCUnusedIVars.cpp CheckSecuritySyntaxOnly.cpp + CheckSizeofPointer.cpp DereferenceChecker.cpp DivZeroChecker.cpp Environment.cpp ExplodedGraph.cpp + FixedAddressChecker.cpp GRBlockCounter.cpp GRCoreEngine.cpp GRExprEngine.cpp + GRExprEngineExperimentalChecks.cpp GRExprEngineInternalChecks.cpp GRState.cpp LiveVariables.cpp + MallocChecker.cpp + ManagerRegistry.cpp MemRegion.cpp NSAutoreleasePoolChecker.cpp NSErrorChecker.cpp PathDiagnostic.cpp + PointerArithChecker.cpp + PointerSubChecker.cpp + PthreadLockChecker.cpp RangeConstraintManager.cpp RegionStore.cpp + ReturnPointerRangeChecker.cpp + ReturnStackAddressChecker.cpp + ReturnUndefChecker.cpp SVals.cpp SValuator.cpp SimpleConstraintManager.cpp @@ -43,10 +55,11 @@ add_clang_library(clangAnalysis Store.cpp SymbolManager.cpp UndefinedArgChecker.cpp + UndefinedArraySubscriptChecker.cpp UndefinedAssignmentChecker.cpp UninitializedValues.cpp - ValueManager.cpp VLASizeChecker.cpp + ValueManager.cpp ) add_dependencies(clangAnalysis ClangDiagnosticAnalysis) diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp index 17dc0685f82f..06e3317691e3 100644 --- a/lib/Analysis/CallGraph.cpp +++ b/lib/Analysis/CallGraph.cpp @@ -117,7 +117,7 @@ void CallGraph::print(llvm::raw_ostream &os) { << " calls:\n"; for (CallGraphNode::iterator CI = I->second->begin(), CE = I->second->end(); CI != CE; ++CI) { - os << " " << CI->second->getName().c_str(); + os << " " << CI->second->getName(); } os << '\n'; } diff --git a/lib/Analysis/CastToStructChecker.cpp b/lib/Analysis/CastToStructChecker.cpp new file mode 100644 index 000000000000..ccd4a3333e22 --- /dev/null +++ b/lib/Analysis/CastToStructChecker.cpp @@ -0,0 +1,77 @@ +//=== CastToStructChecker.cpp - Fixed address usage checker ----*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This files defines CastToStructChecker, a builtin checker that checks for +// assignment of a fixed address to a pointer. +// This check corresponds to CWE-588. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "GRExprEngineInternalChecks.h" + +using namespace clang; + +namespace { +class VISIBILITY_HIDDEN CastToStructChecker + : public CheckerVisitor<CastToStructChecker> { + BuiltinBug *BT; +public: + CastToStructChecker() : BT(0) {} + static void *getTag(); + void PreVisitCastExpr(CheckerContext &C, const CastExpr *B); +}; +} + +void *CastToStructChecker::getTag() { + static int x; + return &x; +} + +void CastToStructChecker::PreVisitCastExpr(CheckerContext &C, + const CastExpr *CE) { + const Expr *E = CE->getSubExpr(); + ASTContext &Ctx = C.getASTContext(); + QualType OrigTy = Ctx.getCanonicalType(E->getType()); + QualType ToTy = Ctx.getCanonicalType(CE->getType()); + + PointerType *OrigPTy = dyn_cast<PointerType>(OrigTy.getTypePtr()); + PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr()); + + if (!ToPTy || !OrigPTy) + return; + + QualType OrigPointeeTy = OrigPTy->getPointeeType(); + QualType ToPointeeTy = ToPTy->getPointeeType(); + + if (!ToPointeeTy->isStructureType()) + return; + + // We allow cast from void*. + if (OrigPointeeTy->isVoidType()) + return; + + // Now the cast-to-type is struct pointer, the original type is not void*. + if (!OrigPointeeTy->isRecordType()) { + if (ExplodedNode *N = C.GenerateNode(CE)) { + if (!BT) + BT = new BuiltinBug("Cast from non-struct type to struct type", + "Casting a non-structure type to a structure type " + "and accessing a field can lead to memory access " + "errors or data corruption."); + RangedBugReport *R = new RangedBugReport(*BT,BT->getDescription(), N); + R->addRange(CE->getSourceRange()); + C.EmitReport(R); + } + } +} + +void clang::RegisterCastToStructChecker(GRExprEngine &Eng) { + Eng.registerCheck(new CastToStructChecker()); +} diff --git a/lib/Analysis/CheckSecuritySyntaxOnly.cpp b/lib/Analysis/CheckSecuritySyntaxOnly.cpp index 9f0d059cb66e..f1b9c2194f8b 100644 --- a/lib/Analysis/CheckSecuritySyntaxOnly.cpp +++ b/lib/Analysis/CheckSecuritySyntaxOnly.cpp @@ -23,6 +23,7 @@ namespace { class VISIBILITY_HIDDEN WalkAST : public StmtVisitor<WalkAST> { BugReporter &BR; IdentifierInfo *II_gets; + IdentifierInfo *II_getpw; enum { num_rands = 9 }; IdentifierInfo *II_rand[num_rands]; IdentifierInfo *II_random; @@ -31,7 +32,7 @@ class VISIBILITY_HIDDEN WalkAST : public StmtVisitor<WalkAST> { public: WalkAST(BugReporter &br) : BR(br), - II_gets(0), II_rand(), II_random(0), II_setid() {} + II_gets(0), II_getpw(0), II_rand(), II_random(0), II_setid() {} // Statement visitor methods. void VisitCallExpr(CallExpr *CE); @@ -47,6 +48,7 @@ public: // Checker-specific methods. void CheckLoopConditionForFloat(const ForStmt *FS); void CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD); + void CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD); void CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD); void CheckCall_random(const CallExpr *CE, const FunctionDecl *FD); void CheckUncheckedReturnValue(CallExpr *CE); @@ -77,6 +79,7 @@ void WalkAST::VisitChildren(Stmt *S) { void WalkAST::VisitCallExpr(CallExpr *CE) { if (const FunctionDecl *FD = CE->getDirectCallee()) { CheckCall_gets(CE, FD); + CheckCall_getpw(CE, FD); CheckCall_rand(CE, FD); CheckCall_random(CE, FD); } @@ -215,22 +218,23 @@ void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) { // Check: Any use of 'gets' is insecure. // Originally: <rdar://problem/6335715> // Implements (part of): 300-BSI (buildsecurityin.us-cert.gov) +// CWE-242: Use of Inherently Dangerous Function //===----------------------------------------------------------------------===// void WalkAST::CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD) { if (FD->getIdentifier() != GetIdentifier(II_gets, "gets")) return; - const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FD->getType()); - if (!FTP) + const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FD->getType()); + if (!FPT) return; // Verify that the function takes a single argument. - if (FTP->getNumArgs() != 1) + if (FPT->getNumArgs() != 1) return; // Is the argument a 'char*'? - const PointerType *PT = dyn_cast<PointerType>(FTP->getArgType(0)); + const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(0)); if (!PT) return; @@ -247,6 +251,44 @@ void WalkAST::CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD) { } //===----------------------------------------------------------------------===// +// Check: Any use of 'getpwd' is insecure. +// CWE-477: Use of Obsolete Functions +//===----------------------------------------------------------------------===// + +void WalkAST::CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD) { + if (FD->getIdentifier() != GetIdentifier(II_getpw, "getpw")) + return; + + const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FD->getType()); + if (!FPT) + return; + + // Verify that the function takes two arguments. + if (FPT->getNumArgs() != 2) + return; + + // Verify the first argument type is integer. + if (!FPT->getArgType(0)->isIntegerType()) + return; + + // Verify the second argument type is char*. + const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(1)); + if (!PT) + return; + + if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy) + return; + + // Issue a warning. + SourceRange R = CE->getCallee()->getSourceRange(); + BR.EmitBasicReport("Potential buffer overflow in call to 'getpw'", + "Security", + "The getpw() function is dangerous as it may overflow the " + "provided buffer. It is obsoleted by getpwuid().", + CE->getLocStart(), &R, 1); +} + +//===----------------------------------------------------------------------===// // Check: Linear congruent random number generators should not be used // Originally: <rdar://problem/63371000> // CWE-338: Use of cryptographically weak prng diff --git a/lib/Analysis/CheckSizeofPointer.cpp b/lib/Analysis/CheckSizeofPointer.cpp new file mode 100644 index 000000000000..174beefbca45 --- /dev/null +++ b/lib/Analysis/CheckSizeofPointer.cpp @@ -0,0 +1,72 @@ +//==- CheckSizeofPointer.cpp - Check for sizeof on pointers ------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a check for unintended use of sizeof() on pointer +// expressions. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Analysis/LocalCheckers.h" +#include "llvm/Support/Compiler.h" + +using namespace clang; + +namespace { +class VISIBILITY_HIDDEN WalkAST : public StmtVisitor<WalkAST> { + BugReporter &BR; + +public: + WalkAST(BugReporter &br) : BR(br) {} + void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); + void VisitStmt(Stmt *S) { VisitChildren(S); } + void VisitChildren(Stmt *S); +}; +} + +void WalkAST::VisitChildren(Stmt *S) { + for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I) + if (Stmt *child = *I) + Visit(child); +} + +// CWE-467: Use of sizeof() on a Pointer Type +void WalkAST::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { + if (!E->isSizeOf()) + return; + + // If an explicit type is used in the code, usually the coder knows what he is + // doing. + if (E->isArgumentType()) + return; + + QualType T = E->getTypeOfArgument(); + if (T->isPointerType()) { + + // Many false positives have the form 'sizeof *p'. This is reasonable + // because people know what they are doing when they intentionally + // dereference the pointer. + Expr *ArgEx = E->getArgumentExpr(); + if (!isa<DeclRefExpr>(ArgEx->IgnoreParens())) + return; + + SourceRange R = ArgEx->getSourceRange(); + BR.EmitBasicReport("Potential unintended use of sizeof() on pointer type", + "Logic", + "The code calls sizeof() on a pointer type. " + "This can produce an unexpected result.", + E->getLocStart(), &R, 1); + } +} + +void clang::CheckSizeofPointer(const Decl *D, BugReporter &BR) { + WalkAST walker(BR); + walker.Visit(D->getBody()); +} diff --git a/lib/Analysis/DereferenceChecker.cpp b/lib/Analysis/DereferenceChecker.cpp index 33c85d507463..c3aa8f3a2879 100644 --- a/lib/Analysis/DereferenceChecker.cpp +++ b/lib/Analysis/DereferenceChecker.cpp @@ -13,100 +13,103 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h" +#include "clang/Analysis/PathSensitive/Checker.h" #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/BugReporter.h" +#include "GRExprEngineInternalChecks.h" using namespace clang; -void *NullDerefChecker::getTag() { - static int x = 0; - return &x; -} - -ExplodedNode *NullDerefChecker::CheckLocation(const Stmt *S, ExplodedNode *Pred, - const GRState *state, SVal V, - GRExprEngine &Eng) { - Loc *LV = dyn_cast<Loc>(&V); - - // If the value is not a location, don't touch the node. - if (!LV) - return Pred; - - const GRState *NotNullState = state->Assume(*LV, true); - const GRState *NullState = state->Assume(*LV, false); +namespace { +class VISIBILITY_HIDDEN DereferenceChecker : public Checker { + BuiltinBug *BT_null; + BuiltinBug *BT_undef; + llvm::SmallVector<ExplodedNode*, 2> ImplicitNullDerefNodes; +public: + DereferenceChecker() : BT_null(0), BT_undef(0) {} + static void *getTag() { static int tag = 0; return &tag; } + void VisitLocation(CheckerContext &C, const Stmt *S, SVal location); - GRStmtNodeBuilder &Builder = Eng.getBuilder(); - BugReporter &BR = Eng.getBugReporter(); - - // The explicit NULL case. - if (NullState) { - // Use the GDM to mark in the state what lval was null. - const SVal *PersistentLV = Eng.getBasicVals().getPersistentSVal(*LV); - NullState = NullState->set<GRState::NullDerefTag>(PersistentLV); - - ExplodedNode *N = Builder.generateNode(S, NullState, Pred, - ProgramPoint::PostNullCheckFailedKind); - if (N) { - N->markAsSink(); - - if (!NotNullState) { // Explicit null case. - if (!BT) - BT = new BuiltinBug(NULL, "Null dereference", - "Dereference of null pointer"); - - EnhancedBugReport *R = - new EnhancedBugReport(*BT, BT->getDescription().c_str(), N); - - R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, - bugreporter::GetDerefExpr(N)); - - BR.EmitReport(R); - - return 0; - } else // Implicit null case. - ImplicitNullDerefNodes.push_back(N); - } + std::pair<ExplodedNode * const*, ExplodedNode * const*> + getImplicitNodes() const { + return std::make_pair(ImplicitNullDerefNodes.data(), + ImplicitNullDerefNodes.data() + + ImplicitNullDerefNodes.size()); } - - if (!NotNullState) - return 0; +}; +} // end anonymous namespace - return Builder.generateNode(S, NotNullState, Pred, - ProgramPoint::PostLocationChecksSucceedKind); +void clang::RegisterDereferenceChecker(GRExprEngine &Eng) { + Eng.registerCheck(new DereferenceChecker()); } - -void *UndefDerefChecker::getTag() { - static int x = 0; - return &x; +std::pair<ExplodedNode * const *, ExplodedNode * const *> +clang::GetImplicitNullDereferences(GRExprEngine &Eng) { + DereferenceChecker *checker = Eng.getChecker<DereferenceChecker>(); + if (!checker) + return std::make_pair((ExplodedNode * const *) 0, + (ExplodedNode * const *) 0); + return checker->getImplicitNodes(); } -ExplodedNode *UndefDerefChecker::CheckLocation(const Stmt *S, - ExplodedNode *Pred, - const GRState *state, SVal V, - GRExprEngine &Eng) { - GRStmtNodeBuilder &Builder = Eng.getBuilder(); - BugReporter &BR = Eng.getBugReporter(); - - if (V.isUndef()) { - ExplodedNode *N = Builder.generateNode(S, state, Pred, - ProgramPoint::PostUndefLocationCheckFailedKind); +void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S, + SVal l) { + // Check for dereference of an undefined value. + if (l.isUndef()) { + ExplodedNode *N = C.GenerateNode(S, true); if (N) { - N->markAsSink(); + if (!BT_undef) + BT_undef = new BuiltinBug("Dereference of undefined pointer value"); + + EnhancedBugReport *report = + new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N); + report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, + bugreporter::GetDerefExpr(N)); + C.EmitReport(report); + } + return; + } + + DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l); + + // Check for null dereferences. + if (!isa<Loc>(location)) + return; + + const GRState *state = C.getState(); + const GRState *notNullState, *nullState; + llvm::tie(notNullState, nullState) = state->Assume(location); + + // The explicit NULL case. + if (nullState) { + // Generate an error node. + ExplodedNode *N = C.GenerateNode(S, nullState, true); + if (N) { + if (!notNullState) { + // We know that 'location' cannot be non-null. This is what + // we call an "explicit" null dereference. + if (!BT_null) + BT_null = new BuiltinBug("Null pointer dereference", + "Dereference of null pointer"); - if (!BT) - BT = new BuiltinBug(0, "Undefined dereference", - "Dereference of undefined pointer value"); + EnhancedBugReport *report = + new EnhancedBugReport(*BT_null, BT_null->getDescription(), N); + report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, + bugreporter::GetDerefExpr(N)); + + C.EmitReport(report); + return; + } - EnhancedBugReport *R = - new EnhancedBugReport(*BT, BT->getDescription().c_str(), N); - R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, - bugreporter::GetDerefExpr(N)); - BR.EmitReport(R); + // Otherwise, we have the case where the location could either be + // null or not-null. Record the error node as an "implicit" null + // dereference. + ImplicitNullDerefNodes.push_back(N); } - return 0; } - - return Pred; + + // From this point forward, we know that the location is not null. + assert(notNullState); + C.addTransition(state != nullState ? C.GenerateNode(S, notNullState) : + C.getPredecessor()); } - diff --git a/lib/Analysis/DivZeroChecker.cpp b/lib/Analysis/DivZeroChecker.cpp index 9c2359f3b075..a8630f10088e 100644 --- a/lib/Analysis/DivZeroChecker.cpp +++ b/lib/Analysis/DivZeroChecker.cpp @@ -12,10 +12,25 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/Checkers/DivZeroChecker.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "GRExprEngineInternalChecks.h" using namespace clang; +namespace { +class VISIBILITY_HIDDEN DivZeroChecker : public CheckerVisitor<DivZeroChecker> { + BuiltinBug *BT; +public: + DivZeroChecker() : BT(0) {} + static void *getTag(); + void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B); +}; +} // end anonymous namespace + +void clang::RegisterDivZeroChecker(GRExprEngine &Eng) { + Eng.registerCheck(new DivZeroChecker()); +} + void *DivZeroChecker::getTag() { static int x; return &x; @@ -50,10 +65,10 @@ void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C, if (stateZero && !stateNotZero) { if (ExplodedNode *N = C.GenerateNode(B, stateZero, true)) { if (!BT) - BT = new BuiltinBug(0, "Division by zero"); + BT = new BuiltinBug("Division by zero"); EnhancedBugReport *R = - new EnhancedBugReport(*BT, BT->getDescription().c_str(), N); + new EnhancedBugReport(*BT, BT->getDescription(), N); R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, bugreporter::GetDenomExpr(N)); diff --git a/lib/Analysis/ExplodedGraph.cpp b/lib/Analysis/ExplodedGraph.cpp index 0dc81a4225a8..3b339ffc0dfe 100644 --- a/lib/Analysis/ExplodedGraph.cpp +++ b/lib/Analysis/ExplodedGraph.cpp @@ -273,7 +273,7 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources, ExplodedNode* InterExplodedGraphMap::getMappedNode(const ExplodedNode* N) const { - llvm::DenseMap<const ExplodedNode*, ExplodedNode*>::iterator I = + llvm::DenseMap<const ExplodedNode*, ExplodedNode*>::const_iterator I = M.find(N); return I == M.end() ? 0 : I->second; diff --git a/lib/Analysis/FixedAddressChecker.cpp b/lib/Analysis/FixedAddressChecker.cpp new file mode 100644 index 000000000000..80096dcb70d0 --- /dev/null +++ b/lib/Analysis/FixedAddressChecker.cpp @@ -0,0 +1,70 @@ +//=== FixedAddressChecker.cpp - Fixed address usage checker ----*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This files defines FixedAddressChecker, a builtin checker that checks for +// assignment of a fixed address to a pointer. +// This check corresponds to CWE-587. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "GRExprEngineInternalChecks.h" + +using namespace clang; + +namespace { +class VISIBILITY_HIDDEN FixedAddressChecker + : public CheckerVisitor<FixedAddressChecker> { + BuiltinBug *BT; +public: + FixedAddressChecker() : BT(0) {} + static void *getTag(); + void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B); +}; +} + +void *FixedAddressChecker::getTag() { + static int x; + return &x; +} + +void FixedAddressChecker::PreVisitBinaryOperator(CheckerContext &C, + const BinaryOperator *B) { + // Using a fixed address is not portable because that address will probably + // not be valid in all environments or platforms. + + if (B->getOpcode() != BinaryOperator::Assign) + return; + + QualType T = B->getType(); + if (!T->isPointerType()) + return; + + const GRState *state = C.getState(); + + SVal RV = state->getSVal(B->getRHS()); + + if (!RV.isConstant() || RV.isZeroConstant()) + return; + + if (ExplodedNode *N = C.GenerateNode(B)) { + if (!BT) + BT = new BuiltinBug("Use fixed address", + "Using a fixed address is not portable because that " + "address will probably not be valid in all " + "environments or platforms."); + RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N); + R->addRange(B->getRHS()->getSourceRange()); + C.EmitReport(R); + } +} + +void clang::RegisterFixedAddressChecker(GRExprEngine &Eng) { + Eng.registerCheck(new FixedAddressChecker()); +} diff --git a/lib/Analysis/GRCoreEngine.cpp b/lib/Analysis/GRCoreEngine.cpp index 87472472fdee..b99ba4f257ef 100644 --- a/lib/Analysis/GRCoreEngine.cpp +++ b/lib/Analysis/GRCoreEngine.cpp @@ -418,51 +418,38 @@ void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) { Eng.WList->Enqueue(Succ, B, Idx+1); } -static inline PostStmt GetPostLoc(const Stmt* S, ProgramPoint::Kind K, - const LocationContext *L, const void *tag) { +static ProgramPoint GetProgramPoint(const Stmt *S, ProgramPoint::Kind K, + const LocationContext *LC, const void *tag){ switch (K) { default: - assert(false && "Invalid PostXXXKind."); - + assert(false && "Unhandled ProgramPoint kind"); + case ProgramPoint::PreStmtKind: + return PreStmt(S, LC, tag); case ProgramPoint::PostStmtKind: - return PostStmt(S, L, tag); - + return PostStmt(S, LC, tag); + case ProgramPoint::PreLoadKind: + return PreLoad(S, LC, tag); case ProgramPoint::PostLoadKind: - return PostLoad(S, L, tag); - - case ProgramPoint::PostUndefLocationCheckFailedKind: - return PostUndefLocationCheckFailed(S, L, tag); - - case ProgramPoint::PostLocationChecksSucceedKind: - return PostLocationChecksSucceed(S, L, tag); - - case ProgramPoint::PostOutOfBoundsCheckFailedKind: - return PostOutOfBoundsCheckFailed(S, L, tag); - - case ProgramPoint::PostNullCheckFailedKind: - return PostNullCheckFailed(S, L, tag); - + return PostLoad(S, LC, tag); + case ProgramPoint::PreStoreKind: + return PreStore(S, LC, tag); case ProgramPoint::PostStoreKind: - return PostStore(S, L, tag); - + return PostStore(S, LC, tag); case ProgramPoint::PostLValueKind: - return PostLValue(S, L, tag); - + return PostLValue(S, LC, tag); case ProgramPoint::PostPurgeDeadSymbolsKind: - return PostPurgeDeadSymbols(S, L, tag); + return PostPurgeDeadSymbols(S, LC, tag); } } ExplodedNode* -GRStmtNodeBuilder::generateNodeInternal(const Stmt* S, const GRState* State, +GRStmtNodeBuilder::generateNodeInternal(const Stmt* S, const GRState* state, ExplodedNode* Pred, ProgramPoint::Kind K, const void *tag) { - return K == ProgramPoint::PreStmtKind - ? generateNodeInternal(PreStmt(S, Pred->getLocationContext(),tag), - State, Pred) - : generateNodeInternal(GetPostLoc(S, K, Pred->getLocationContext(), tag), - State, Pred); + + const ProgramPoint &L = GetProgramPoint(S, K, Pred->getLocationContext(),tag); + return generateNodeInternal(L, state, Pred); } ExplodedNode* diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 212fea3a6bcc..26331776141f 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -293,9 +293,7 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) { Builder = &builder; EntryNode = builder.getLastNode(); - // FIXME: Consolidate. CurrentStmt = S; - StateMgr.CurrentStmt = S; // Set up our simple checks. if (BatchAuditor) @@ -320,9 +318,32 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) { SaveAndRestore<bool> OldPurgeDeadSymbols(Builder->PurgingDeadSymbols); Builder->PurgingDeadSymbols = true; - getTF().EvalDeadSymbols(Tmp, *this, *Builder, EntryNode, S, + // FIXME: This should soon be removed. + ExplodedNodeSet Tmp2; + getTF().EvalDeadSymbols(Tmp2, *this, *Builder, EntryNode, S, CleanedState, SymReaper); + if (Checkers.empty()) + Tmp = Tmp2; + else { + ExplodedNodeSet Tmp3; + ExplodedNodeSet *SrcSet = &Tmp2; + for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end(); + I != E; ++I) { + ExplodedNodeSet *DstSet = (I+1 == E) ? &Tmp + : (SrcSet == &Tmp2) ? &Tmp3 + : &Tmp2; + DstSet->clear(); + void *tag = I->first; + Checker *checker = I->second; + for (ExplodedNodeSet::iterator NI = SrcSet->begin(), NE = SrcSet->end(); + NI != NE; ++NI) + checker->GR_EvalDeadSymbols(*DstSet, *Builder, *this, S, *NI, + SymReaper, tag); + SrcSet = DstSet; + } + } + if (!Builder->BuildSinks && !Builder->HasGeneratedNode) Tmp.Add(EntryNode); } @@ -353,8 +374,6 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) { CleanedState = NULL; EntryNode = NULL; - // FIXME: Consolidate. - StateMgr.CurrentStmt = 0; CurrentStmt = 0; Builder = NULL; @@ -878,6 +897,18 @@ void GRExprEngine::VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, X, true)); } +/// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path +/// nodes when the control reaches the end of a function. +void GRExprEngine::ProcessEndPath(GREndPathNodeBuilder& builder) { + getTF().EvalEndPath(*this, builder); + StateMgr.EndPath(builder.getState()); + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E;++I){ + void *tag = I->first; + Checker *checker = I->second; + checker->EvalEndPath(builder, tag, *this); + } +} + /// ProcessSwitch - Called by GRCoreEngine. Used to generate successor /// nodes by processing the 'effects' of a switch statement. void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) { @@ -1080,7 +1111,10 @@ void GRExprEngine::VisitArraySubscriptExpr(ArraySubscriptExpr* A, ExplodedNodeSet Tmp2; Visit(Idx, *I1, Tmp2); // Evaluate the index. - for (ExplodedNodeSet::iterator I2=Tmp2.begin(),E2=Tmp2.end();I2!=E2; ++I2) { + ExplodedNodeSet Tmp3; + CheckerVisit(A, Tmp3, Tmp2, true); + + for (ExplodedNodeSet::iterator I2=Tmp3.begin(),E2=Tmp3.end();I2!=E2; ++I2) { const GRState* state = GetState(*I2); SVal V = state->getLValue(A->getType(), state->getSVal(Idx), state->getSVal(Base)); @@ -1190,112 +1224,87 @@ void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, Expr *AssignE, assert(Builder && "GRStmtNodeBuilder must be defined."); // Evaluate the location (checks for bad dereferences). - Pred = EvalLocation(StoreE, Pred, state, location, tag); + ExplodedNodeSet Tmp; + EvalLocation(Tmp, StoreE, Pred, state, location, tag, false); - if (!Pred) + if (Tmp.empty()) return; - assert (!location.isUndef()); - state = GetState(Pred); + assert(!location.isUndef()); + SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind, + ProgramPoint::PostStoreKind); + SaveAndRestore<const void*> OldTag(Builder->Tag, tag); + // Proceed with the store. - SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind); - SaveAndRestore<const void*> OldTag(Builder->Tag); - Builder->PointKind = ProgramPoint::PostStoreKind; - Builder->Tag = tag; - EvalBind(Dst, AssignE, StoreE, Pred, state, location, Val); + for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) + EvalBind(Dst, AssignE, StoreE, *NI, GetState(*NI), location, Val); } -void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred, +void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr *Ex, ExplodedNode* Pred, const GRState* state, SVal location, - const void *tag) { + const void *tag, QualType LoadTy) { // Evaluate the location (checks for bad dereferences). - Pred = EvalLocation(Ex, Pred, state, location, tag); + ExplodedNodeSet Tmp; + EvalLocation(Tmp, Ex, Pred, state, location, tag, true); - if (!Pred) + if (Tmp.empty()) return; - - state = GetState(Pred); + + assert(!location.isUndef()); + + SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind); + SaveAndRestore<const void*> OldTag(Builder->Tag); // Proceed with the load. - ProgramPoint::Kind K = ProgramPoint::PostLoadKind; - - // FIXME: Currently symbolic analysis "generates" new symbols - // for the contents of values. We need a better approach. - - if (location.isUnknown()) { - // This is important. We must nuke the old binding. - MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, UnknownVal()), - K, tag); - } - else { - SVal V = state->getSVal(cast<Loc>(location), Ex->getType()); - MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V), K, tag); + for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) { + state = GetState(*NI); + if (location.isUnknown()) { + // This is important. We must nuke the old binding. + MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, UnknownVal()), + ProgramPoint::PostLoadKind, tag); + } + else { + SVal V = state->getSVal(cast<Loc>(location), LoadTy.isNull() ? + Ex->getType() : LoadTy); + MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, V), ProgramPoint::PostLoadKind, + tag); + } } } -ExplodedNode* GRExprEngine::EvalLocation(Stmt* Ex, ExplodedNode* Pred, - const GRState* state, SVal location, - const void *tag) { - - SaveAndRestore<const void*> OldTag(Builder->Tag); - Builder->Tag = tag; +void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S, + ExplodedNode* Pred, + const GRState* state, SVal location, + const void *tag, bool isLoad) { - if (location.isUnknown() || Checkers.empty()) - return Pred; - - - for (CheckersOrdered::iterator I=Checkers.begin(), E=Checkers.end(); I!=E;++I) - { - Pred = I->second->CheckLocation(Ex, Pred, state, location, *this); - if (!Pred) - break; + if (location.isUnknown() || Checkers.empty()) { + Dst.Add(Pred); + return; } - return Pred; - - // FIXME: Temporarily disable out-of-bounds checking until we make - // the logic reflect recent changes to CastRegion and friends. -#if 0 - // Check for out-of-bound array access. - if (isa<loc::MemRegionVal>(LV)) { - const MemRegion* R = cast<loc::MemRegionVal>(LV).getRegion(); - if (const ElementRegion* ER = dyn_cast<ElementRegion>(R)) { - // Get the index of the accessed element. - SVal Idx = ER->getIndex(); - // Get the extent of the array. - SVal NumElements = getStoreManager().getSizeInElements(StNotNull, - ER->getSuperRegion()); - - const GRState * StInBound = StNotNull->AssumeInBound(Idx, NumElements, - true); - const GRState* StOutBound = StNotNull->AssumeInBound(Idx, NumElements, - false); - - if (StOutBound) { - // Report warning. Make sink node manually. - ExplodedNode* OOBNode = - Builder->generateNode(Ex, StOutBound, Pred, - ProgramPoint::PostOutOfBoundsCheckFailedKind); - - if (OOBNode) { - OOBNode->markAsSink(); - - if (StInBound) - ImplicitOOBMemAccesses.insert(OOBNode); - else - ExplicitOOBMemAccesses.insert(OOBNode); - } - } - - if (!StInBound) - return NULL; - - StNotNull = StInBound; - } + ExplodedNodeSet Src, Tmp; + Src.Add(Pred); + ExplodedNodeSet *PrevSet = &Src; + + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) + { + ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst + : (PrevSet == &Tmp) ? &Src : &Tmp; + + CurrSet->clear(); + void *tag = I->first; + Checker *checker = I->second; + + for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); + NI != NE; ++NI) + checker->GR_VisitLocation(*CurrSet, *Builder, *this, S, *NI, state, + location, tag, isLoad); + + // Update which NodeSet is the current one. + PrevSet = CurrSet; } -#endif } //===----------------------------------------------------------------------===// @@ -1311,8 +1320,7 @@ ExplodedNode* GRExprEngine::EvalLocation(Stmt* Ex, ExplodedNode* Pred, static bool EvalOSAtomicCompareAndSwap(ExplodedNodeSet& Dst, GRExprEngine& Engine, GRStmtNodeBuilder& Builder, - CallExpr* CE, SVal L, - ExplodedNode* Pred) { + CallExpr* CE, ExplodedNode* Pred) { // Not enough arguments to match OSAtomicCompareAndSwap? if (CE->getNumArgs() != 3) @@ -1354,7 +1362,13 @@ static bool EvalOSAtomicCompareAndSwap(ExplodedNodeSet& Dst, const GRState *state = Pred->getState(); ExplodedNodeSet Tmp; SVal location = state->getSVal(theValueExpr); - Engine.EvalLoad(Tmp, theValueExpr, Pred, state, location, OSAtomicLoadTag); + // Here we should use the value type of the region as the load type. + const MemRegion *R = location.getAsRegion(); + QualType LoadTy; + if (R) + LoadTy = cast<TypedRegion>(R)->getValueType(C); + Engine.EvalLoad(Tmp, theValueExpr, Pred, state, location, OSAtomicLoadTag, + LoadTy); for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { @@ -1432,7 +1446,7 @@ static bool EvalOSAtomic(ExplodedNodeSet& Dst, // Check for compare and swap. if (strncmp(FName, "OSAtomicCompareAndSwap", 22) == 0 || strncmp(FName, "objc_atomicCompareAndSwap", 25) == 0) - return EvalOSAtomicCompareAndSwap(Dst, Engine, Builder, CE, L, Pred); + return EvalOSAtomicCompareAndSwap(Dst, Engine, Builder, CE, Pred); // FIXME: Other atomics. return false; @@ -1521,17 +1535,6 @@ bool GRExprEngine::EvalBuiltinFunction(const FunctionDecl *FD, CallExpr *CE, return false; } -void GRExprEngine::EvalCall(ExplodedNodeSet& Dst, CallExpr* CE, SVal L, - ExplodedNode* Pred) { - assert (Builder && "GRStmtNodeBuilder must be defined."); - - // FIXME: Allow us to chain together transfer functions. - if (EvalOSAtomic(Dst, *this, *Builder, CE, L, Pred)) - return; - - getTF().EvalCall(Dst, *this, *Builder, CE, L, Pred); -} - void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, @@ -1609,17 +1612,25 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, ExplodedNode* Pred, continue; // Dispatch to the plug-in transfer function. - - unsigned size = Dst.size(); SaveOr OldHasGen(Builder->HasGeneratedNode); - EvalCall(Dst, CE, L, *DI); + Pred = *DI; + + // Dispatch to transfer function logic to handle the call itself. + // FIXME: Allow us to chain together transfer functions. + assert(Builder && "GRStmtNodeBuilder must be defined."); + ExplodedNodeSet DstTmp; + + if (!EvalOSAtomic(DstTmp, *this, *Builder, CE, L, Pred)) + getTF().EvalCall(DstTmp, *this, *Builder, CE, L, Pred); // Handle the case where no nodes where generated. Auto-generate that // contains the updated state if we aren't generating sinks. - - if (!Builder->BuildSinks && Dst.size() == size && + if (!Builder->BuildSinks && DstTmp.empty() && !Builder->HasGeneratedNode) - MakeNode(Dst, CE, *DI, state); + MakeNode(DstTmp, CE, Pred, state); + + // Perform the post-condition check of the CallExpr. + CheckerVisit(CE, Dst, DstTmp, false); } } @@ -1749,46 +1760,47 @@ void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst, SVal ElementV) { - - - // Get the current state. Use 'EvalLocation' to determine if it is a null - // pointer, etc. + // Check if the location we are writing back to is a null pointer. Stmt* elem = S->getElement(); - - Pred = EvalLocation(elem, Pred, GetState(Pred), ElementV); - if (!Pred) + ExplodedNodeSet Tmp; + EvalLocation(Tmp, elem, Pred, GetState(Pred), ElementV, NULL, false); + + if (Tmp.empty()) return; + + for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) { + Pred = *NI; + const GRState *state = GetState(Pred); + + // Handle the case where the container still has elements. + SVal TrueV = ValMgr.makeTruthVal(1); + const GRState *hasElems = state->BindExpr(S, TrueV); + + // Handle the case where the container has no elements. + SVal FalseV = ValMgr.makeTruthVal(0); + const GRState *noElems = state->BindExpr(S, FalseV); + + if (loc::MemRegionVal* MV = dyn_cast<loc::MemRegionVal>(&ElementV)) + if (const TypedRegion* R = dyn_cast<TypedRegion>(MV->getRegion())) { + // FIXME: The proper thing to do is to really iterate over the + // container. We will do this with dispatch logic to the store. + // For now, just 'conjure' up a symbolic value. + QualType T = R->getValueType(getContext()); + assert(Loc::IsLocType(T)); + unsigned Count = Builder->getCurrentBlockCount(); + SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count); + SVal V = ValMgr.makeLoc(Sym); + hasElems = hasElems->bindLoc(ElementV, V); + + // Bind the location to 'nil' on the false branch. + SVal nilV = ValMgr.makeIntVal(0, T); + noElems = noElems->bindLoc(ElementV, nilV); + } - const GRState *state = GetState(Pred); - - // Handle the case where the container still has elements. - SVal TrueV = ValMgr.makeTruthVal(1); - const GRState *hasElems = state->BindExpr(S, TrueV); - - // Handle the case where the container has no elements. - SVal FalseV = ValMgr.makeTruthVal(0); - const GRState *noElems = state->BindExpr(S, FalseV); - - if (loc::MemRegionVal* MV = dyn_cast<loc::MemRegionVal>(&ElementV)) - if (const TypedRegion* R = dyn_cast<TypedRegion>(MV->getRegion())) { - // FIXME: The proper thing to do is to really iterate over the - // container. We will do this with dispatch logic to the store. - // For now, just 'conjure' up a symbolic value. - QualType T = R->getValueType(getContext()); - assert (Loc::IsLocType(T)); - unsigned Count = Builder->getCurrentBlockCount(); - SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count); - SVal V = ValMgr.makeLoc(Sym); - hasElems = hasElems->bindLoc(ElementV, V); - - // Bind the location to 'nil' on the false branch. - SVal nilV = ValMgr.makeIntVal(0, T); - noElems = noElems->bindLoc(ElementV, nilV); - } - - // Create the new nodes. - MakeNode(Dst, S, Pred, hasElems); - MakeNode(Dst, S, Pred, noElems); + // Create the new nodes. + MakeNode(Dst, S, Pred, hasElems); + MakeNode(Dst, S, Pred, noElems); + } } //===----------------------------------------------------------------------===// @@ -2035,7 +2047,8 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, // Transfer functions: Miscellaneous statements. //===----------------------------------------------------------------------===// -void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst){ +void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, + ExplodedNodeSet& Dst){ ExplodedNodeSet S1; QualType T = CastE->getType(); QualType ExTy = Ex->getType(); @@ -2048,16 +2061,18 @@ void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, Exploded else Visit(Ex, Pred, S1); + ExplodedNodeSet S2; + CheckerVisit(CastE, S2, S1, true); + // Check for casting to "void". if (T->isVoidType()) { - for (ExplodedNodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) - Dst.Add(*I1); - + for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) + Dst.Add(*I); return; } - for (ExplodedNodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) { - ExplodedNode* N = *I1; + for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { + ExplodedNode* N = *I; const GRState* state = GetState(N); SVal V = state->getSVal(Ex); const SValuator::CastResult &Res = SVator.EvalCast(V, state, T, ExTy); @@ -2107,23 +2122,12 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, else Tmp.Add(Pred); - for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + ExplodedNodeSet Tmp2; + CheckerVisit(DS, Tmp2, Tmp, true); + + for (ExplodedNodeSet::iterator I=Tmp2.begin(), E=Tmp2.end(); I!=E; ++I) { ExplodedNode *N = *I; - const GRState *state; - - for (CheckersOrdered::iterator CI = Checkers.begin(), CE = Checkers.end(); - CI != CE; ++CI) { - state = GetState(N); - N = CI->second->CheckType(getContext().getCanonicalType(VD->getType()), - N, state, DS, *this); - if (!N) - break; - } - - if (!N) - continue; - - state = GetState(N); + const GRState *state = GetState(N); // Decls without InitExpr are not initialized explicitly. const LocationContext *LC = N->getLocationContext(); @@ -2628,63 +2632,37 @@ void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A, VisitAsmStmtHelperInputs(A, I, E, *NI, Dst); } -void GRExprEngine::EvalReturn(ExplodedNodeSet& Dst, ReturnStmt* S, - ExplodedNode* Pred) { - assert (Builder && "GRStmtNodeBuilder must be defined."); - - unsigned size = Dst.size(); - - SaveAndRestore<bool> OldSink(Builder->BuildSinks); - SaveOr OldHasGen(Builder->HasGeneratedNode); - - getTF().EvalReturn(Dst, *this, *Builder, S, Pred); - - // Handle the case where no nodes where generated. - - if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode) - MakeNode(Dst, S, Pred, GetState(Pred)); -} - -void GRExprEngine::VisitReturnStmt(ReturnStmt* S, ExplodedNode* Pred, - ExplodedNodeSet& Dst) { - - Expr* R = S->getRetValue(); - - if (!R) { - EvalReturn(Dst, S, Pred); - return; +void GRExprEngine::VisitReturnStmt(ReturnStmt *RS, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + + ExplodedNodeSet Src; + if (Expr *RetE = RS->getRetValue()) { + Visit(RetE, Pred, Src); } + else { + Src.Add(Pred); + } + + ExplodedNodeSet CheckedSet; + CheckerVisit(RS, CheckedSet, Src, true); + + for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); + I != E; ++I) { - ExplodedNodeSet Tmp; - Visit(R, Pred, Tmp); - - for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { - SVal X = (*I)->getState()->getSVal(R); - - // Check if we return the address of a stack variable. - if (isa<loc::MemRegionVal>(X)) { - // Determine if the value is on the stack. - const MemRegion* R = cast<loc::MemRegionVal>(&X)->getRegion(); - - if (R && R->hasStackStorage()) { - // Create a special node representing the error. - if (ExplodedNode* N = Builder->generateNode(S, GetState(*I), *I)) { - N->markAsSink(); - RetsStackAddr.insert(N); - } - continue; - } - } - // Check if we return an undefined value. - else if (X.isUndef()) { - if (ExplodedNode* N = Builder->generateNode(S, GetState(*I), *I)) { - N->markAsSink(); - RetsUndef.insert(N); - } - continue; - } - - EvalReturn(Dst, S, *I); + assert(Builder && "GRStmtNodeBuilder must be defined."); + + Pred = *I; + unsigned size = Dst.size(); + + SaveAndRestore<bool> OldSink(Builder->BuildSinks); + SaveOr OldHasGen(Builder->HasGeneratedNode); + + getTF().EvalReturn(Dst, *this, *Builder, RS, Pred); + + // Handle the case where no nodes where generated. + if (!Builder->BuildSinks && Dst.size() == size && + !Builder->HasGeneratedNode) + MakeNode(Dst, RS, Pred, GetState(Pred)); } } @@ -2878,7 +2856,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, //===----------------------------------------------------------------------===// Checker *GRExprEngine::lookupChecker(void *tag) const { - CheckerMap::iterator I = CheckerM.find(tag); + CheckerMap::const_iterator I = CheckerM.find(tag); return (I == CheckerM.end()) ? NULL : Checkers[I->second].second; } @@ -2898,6 +2876,9 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> : // work. static std::string getNodeAttributes(const ExplodedNode* N, void*) { +#if 0 + // FIXME: Replace with a general scheme to tell if the node is + // an error node. if (GraphPrintCheckerState->isImplicitNullDeref(N) || GraphPrintCheckerState->isExplicitNullDeref(N) || GraphPrintCheckerState->isUndefDeref(N) || @@ -2907,6 +2888,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> : GraphPrintCheckerState->isBadCall(N) || GraphPrintCheckerState->isUndefArg(N)) return "color=\"red\",style=\"filled\""; +#endif if (GraphPrintCheckerState->isNoReturnCall(N)) return "color=\"blue\",style=\"filled\""; @@ -2957,11 +2939,10 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> : Out << "\\lPostStore\\l"; else if (isa<PostLValue>(Loc)) Out << "\\lPostLValue\\l"; - else if (isa<PostLocationChecksSucceed>(Loc)) - Out << "\\lPostLocationChecksSucceed\\l"; - else if (isa<PostNullCheckFailed>(Loc)) - Out << "\\lPostNullCheckFailed\\l"; +#if 0 + // FIXME: Replace with a general scheme to determine + // the name of the check. if (GraphPrintCheckerState->isImplicitNullDeref(N)) Out << "\\|Implicit-Null Dereference.\\l"; else if (GraphPrintCheckerState->isExplicitNullDeref(N)) @@ -2978,6 +2959,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> : Out << "\\|Call to NULL/Undefined."; else if (GraphPrintCheckerState->isUndefArg(N)) Out << "\\|Argument in call is undefined"; +#endif break; } @@ -3039,9 +3021,13 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> : Out << "\\l"; } +#if 0 + // FIXME: Replace with a general scheme to determine + // the name of the check. if (GraphPrintCheckerState->isUndefControlFlow(N)) { Out << "\\|Control-flow based on\\lUndefined value.\\l"; } +#endif } } diff --git a/lib/Analysis/GRExprEngineExperimentalChecks.cpp b/lib/Analysis/GRExprEngineExperimentalChecks.cpp new file mode 100644 index 000000000000..2fb7e9fa482f --- /dev/null +++ b/lib/Analysis/GRExprEngineExperimentalChecks.cpp @@ -0,0 +1,38 @@ +//=-- GRExprEngineExperimentalChecks.h ------------------------------*- C++ -*-= +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines functions to instantiate and register experimental +// checks in GRExprEngine. +// +//===----------------------------------------------------------------------===// + +#include "GRExprEngineInternalChecks.h" +#include "GRExprEngineExperimentalChecks.h" +#include "clang/Analysis/LocalCheckers.h" + +using namespace clang; + +void clang::RegisterExperimentalChecks(GRExprEngine &Eng) { + // These are checks that never belong as internal checks + // within GRExprEngine. + RegisterPthreadLockChecker(Eng); + RegisterMallocChecker(Eng); +} + +void clang::RegisterExperimentalInternalChecks(GRExprEngine &Eng) { + // These are internal checks that should eventually migrate to + // RegisterInternalChecks() once they have been further tested. + + // Note that this must be registered after ReturnStackAddresEngsChecker. + RegisterReturnPointerRangeChecker(Eng); + RegisterPointerSubChecker(Eng); + RegisterPointerArithChecker(Eng); + RegisterCastToStructChecker(Eng); + RegisterArrayBoundChecker(Eng); +} diff --git a/lib/Analysis/GRExprEngineExperimentalChecks.h b/lib/Analysis/GRExprEngineExperimentalChecks.h new file mode 100644 index 000000000000..9a9da32e556e --- /dev/null +++ b/lib/Analysis/GRExprEngineExperimentalChecks.h @@ -0,0 +1,26 @@ +//=-- GRExprEngineExperimentalChecks.h ------------------------------*- C++ -*-= +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines functions to instantiate and register experimental +// checks in GRExprEngine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GREXPRENGINE_EXPERIMENTAL_CHECKS +#define LLVM_CLANG_GREXPRENGINE_EXPERIMENTAL_CHECKS + +namespace clang { + +class GRExprEngine; + +void RegisterPthreadLockChecker(GRExprEngine &Eng); +void RegisterMallocChecker(GRExprEngine &Eng); + +} // end clang namespace +#endif diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp index 695f0b02e597..d0f60fde5b1b 100644 --- a/lib/Analysis/GRExprEngineInternalChecks.cpp +++ b/lib/Analysis/GRExprEngineInternalChecks.cpp @@ -12,16 +12,11 @@ // //===----------------------------------------------------------------------===// +#include "GRExprEngineInternalChecks.h" #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/CheckerVisitor.h" -#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h" -#include "clang/Analysis/PathSensitive/Checkers/DivZeroChecker.h" -#include "clang/Analysis/PathSensitive/Checkers/BadCallChecker.h" -#include "clang/Analysis/PathSensitive/Checkers/UndefinedArgChecker.h" #include "clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h" -#include "clang/Analysis/PathSensitive/Checkers/AttrNonNullChecker.h" -#include "clang/Analysis/PathSensitive/Checkers/VLASizeChecker.h" #include "clang/Analysis/PathDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/Compiler.h" @@ -290,79 +285,6 @@ public: } }; -class VISIBILITY_HIDDEN RetStack : public BuiltinBug { -public: - RetStack(GRExprEngine* eng) - : BuiltinBug(eng, "Return of address to stack-allocated memory") {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - for (GRExprEngine::ret_stackaddr_iterator I=Eng.ret_stackaddr_begin(), - End = Eng.ret_stackaddr_end(); I!=End; ++I) { - - ExplodedNode* N = *I; - const Stmt *S = cast<PostStmt>(N->getLocation()).getStmt(); - const Expr* E = cast<ReturnStmt>(S)->getRetValue(); - assert(E && "Return expression cannot be NULL"); - - // Get the value associated with E. - loc::MemRegionVal V = cast<loc::MemRegionVal>(N->getState()->getSVal(E)); - - // Generate a report for this bug. - std::string buf; - llvm::raw_string_ostream os(buf); - SourceRange R; - - // Check if the region is a compound literal. - if (const CompoundLiteralRegion* CR = - dyn_cast<CompoundLiteralRegion>(V.getRegion())) { - - const CompoundLiteralExpr* CL = CR->getLiteralExpr(); - os << "Address of stack memory associated with a compound literal " - "declared on line " - << BR.getSourceManager() - .getInstantiationLineNumber(CL->getLocStart()) - << " returned."; - - R = CL->getSourceRange(); - } - else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(V.getRegion())) { - const Expr* ARE = AR->getExpr(); - SourceLocation L = ARE->getLocStart(); - R = ARE->getSourceRange(); - - os << "Address of stack memory allocated by call to alloca() on line " - << BR.getSourceManager().getInstantiationLineNumber(L) - << " returned."; - } - else { - os << "Address of stack memory associated with local variable '" - << V.getRegion()->getString() << "' returned."; - } - - RangedBugReport *report = new RangedBugReport(*this, os.str().c_str(), N); - report->addRange(E->getSourceRange()); - if (R.isValid()) report->addRange(R); - BR.EmitReport(report); - } - } -}; - -class VISIBILITY_HIDDEN RetUndef : public BuiltinBug { -public: - RetUndef(GRExprEngine* eng) : BuiltinBug(eng, "Garbage return value", - "Undefined or garbage value returned to caller") {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - Emit(BR, Eng.ret_undef_begin(), Eng.ret_undef_end()); - } - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - registerTrackNullOrUndefValue(BRC, GetRetValExpr(N), N); - } -}; - class VISIBILITY_HIDDEN UndefBranch : public BuiltinBug { struct VISIBILITY_HIDDEN FindUndefExpr { GRStateManager& VM; @@ -439,17 +361,6 @@ public: } }; -class VISIBILITY_HIDDEN OutOfBoundMemoryAccess : public BuiltinBug { -public: - OutOfBoundMemoryAccess(GRExprEngine* eng) - : BuiltinBug(eng,"Out-of-bounds memory access", - "Load or store into an out-of-bound memory position.") {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - Emit(BR, Eng.explicit_oob_memacc_begin(), Eng.explicit_oob_memacc_end()); - } -}; - } // end clang namespace //===----------------------------------------------------------------------===// @@ -464,11 +375,8 @@ void GRExprEngine::RegisterInternalChecks() { // to 'FlushReports' from BugReporter. BR.Register(new UndefBranch(this)); BR.Register(new UndefResult(this)); - BR.Register(new RetStack(this)); - BR.Register(new RetUndef(this)); BR.Register(new BadMsgExprArg(this)); BR.Register(new BadReceiver(this)); - BR.Register(new OutOfBoundMemoryAccess(this)); BR.Register(new NilReceiverStructRet(this)); BR.Register(new NilReceiverLargerThanVoidPtrRet(this)); @@ -476,14 +384,17 @@ void GRExprEngine::RegisterInternalChecks() { // explicitly registered with the BugReporter. If they issue any BugReports, // their associated BugType will get registered with the BugReporter // automatically. Note that the check itself is owned by the GRExprEngine - // object. - registerCheck(new AttrNonNullChecker()); - registerCheck(new UndefinedArgChecker()); + // object. registerCheck(new UndefinedAssignmentChecker()); - registerCheck(new BadCallChecker()); - registerCheck(new DivZeroChecker()); - registerCheck(new UndefDerefChecker()); - registerCheck(new NullDerefChecker()); - registerCheck(new UndefSizedVLAChecker()); - registerCheck(new ZeroSizedVLAChecker()); + + RegisterAttrNonNullChecker(*this); + RegisterUndefinedArgChecker(*this); + RegisterBadCallChecker(*this); + RegisterDereferenceChecker(*this); + RegisterVLASizeChecker(*this); + RegisterDivZeroChecker(*this); + RegisterReturnStackAddressChecker(*this); + RegisterReturnUndefChecker(*this); + RegisterFixedAddressChecker(*this); + RegisterUndefinedArraySubscriptChecker(*this); } diff --git a/lib/Analysis/GRExprEngineInternalChecks.h b/lib/Analysis/GRExprEngineInternalChecks.h new file mode 100644 index 000000000000..a9077bf75715 --- /dev/null +++ b/lib/Analysis/GRExprEngineInternalChecks.h @@ -0,0 +1,39 @@ +//=-- GRExprEngineInternalChecks.h- Builtin GRExprEngine Checks -----*- C++ -*-= +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines functions to instantiate and register the "built-in" +// checks in GRExprEngine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GREXPRENGINE_INTERNAL_CHECKS +#define LLVM_CLANG_GREXPRENGINE_INTERNAL_CHECKS + +namespace clang { + +class GRExprEngine; + +void RegisterAttrNonNullChecker(GRExprEngine &Eng); +void RegisterBadCallChecker(GRExprEngine &Eng); +void RegisterDereferenceChecker(GRExprEngine &Eng); +void RegisterDivZeroChecker(GRExprEngine &Eng); +void RegisterReturnPointerRangeChecker(GRExprEngine &Eng); +void RegisterReturnStackAddressChecker(GRExprEngine &Eng); +void RegisterReturnUndefChecker(GRExprEngine &Eng); +void RegisterVLASizeChecker(GRExprEngine &Eng); +void RegisterPointerSubChecker(GRExprEngine &Eng); +void RegisterPointerArithChecker(GRExprEngine &Eng); +void RegisterFixedAddressChecker(GRExprEngine &Eng); +void RegisterCastToStructChecker(GRExprEngine &Eng); +void RegisterUndefinedArgChecker(GRExprEngine &Eng); +void RegisterArrayBoundChecker(GRExprEngine &Eng); +void RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng); + +} // end clang namespace +#endif diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp index f269824d5477..23ee0b2258bd 100644 --- a/lib/Analysis/GRState.cpp +++ b/lib/Analysis/GRState.cpp @@ -332,9 +332,3 @@ bool GRStateManager::isEqual(const GRState* state, const Expr* Ex, bool GRStateManager::isEqual(const GRState* state, const Expr* Ex, uint64_t x) { return isEqual(state, Ex, getBasicVals().getValue(x, Ex->getType())); } - -//===----------------------------------------------------------------------===// -// Persistent values for indexing into the Generic Data Map. - -int GRState::NullDerefTag::TagInt = 0; - diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp index ae78d1f35ff6..2510445a7f31 100644 --- a/lib/Analysis/LiveVariables.cpp +++ b/lib/Analysis/LiveVariables.cpp @@ -18,6 +18,7 @@ #include "clang/Analysis/CFG.h" #include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" #include "clang/Analysis/FlowSensitive/DataflowSolver.h" +#include "clang/Analysis/Support/SaveAndRestore.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Compiler.h" @@ -301,10 +302,9 @@ void LiveVariables::runOnAllBlocks(const CFG& cfg, LiveVariables::ObserverTy* Obs, bool recordStmtValues) { Solver S(*this); - ObserverTy* OldObserver = getAnalysisData().Observer; - getAnalysisData().Observer = Obs; + SaveAndRestore<LiveVariables::ObserverTy*> SRObs(getAnalysisData().Observer, + Obs); S.runOnAllBlocks(cfg, recordStmtValues); - getAnalysisData().Observer = OldObserver; } //===----------------------------------------------------------------------===// @@ -333,7 +333,7 @@ bool LiveVariables::isLive(const Stmt* Loc, const VarDecl* D) const { // printing liveness state for debugging // -void LiveVariables::dumpLiveness(const ValTy& V, SourceManager& SM) const { +void LiveVariables::dumpLiveness(const ValTy& V, const SourceManager& SM) const { const AnalysisDataTy& AD = getAnalysisData(); for (AnalysisDataTy::decl_iterator I = AD.begin_decl(), @@ -345,8 +345,8 @@ void LiveVariables::dumpLiveness(const ValTy& V, SourceManager& SM) const { } } -void LiveVariables::dumpBlockLiveness(SourceManager& M) const { - for (BlockDataMapTy::iterator I = getBlockDataMap().begin(), +void LiveVariables::dumpBlockLiveness(const SourceManager& M) const { + for (BlockDataMapTy::const_iterator I = getBlockDataMap().begin(), E = getBlockDataMap().end(); I!=E; ++I) { llvm::errs() << "\n[ B" << I->first->getBlockID() << " (live variables at block exit) ]\n"; diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Analysis/MallocChecker.cpp new file mode 100644 index 000000000000..93e708332ed7 --- /dev/null +++ b/lib/Analysis/MallocChecker.cpp @@ -0,0 +1,218 @@ +//=== MallocChecker.cpp - A malloc/free checker -------------------*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines malloc/free checker, which checks for potential memory +// leaks, double free, and use-after-free problems. +// +//===----------------------------------------------------------------------===// + +#include "GRExprEngineExperimentalChecks.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Analysis/PathSensitive/GRStateTrait.h" +#include "clang/Analysis/PathSensitive/SymbolManager.h" +#include "llvm/ADT/ImmutableMap.h" +using namespace clang; + +namespace { + +struct RefState { + enum Kind { Allocated, Released, Escaped } K; + const Stmt *S; + + RefState(Kind k, const Stmt *s) : K(k), S(s) {} + + bool isAllocated() const { return K == Allocated; } + bool isReleased() const { return K == Released; } + bool isEscaped() const { return K == Escaped; } + + bool operator==(const RefState &X) const { + return K == X.K && S == X.S; + } + + static RefState getAllocated(const Stmt *s) { return RefState(Allocated, s); } + static RefState getReleased(const Stmt *s) { return RefState(Released, s); } + static RefState getEscaped(const Stmt *s) { return RefState(Escaped, s); } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(K); + ID.AddPointer(S); + } +}; + +class VISIBILITY_HIDDEN RegionState {}; + +class VISIBILITY_HIDDEN MallocChecker : public CheckerVisitor<MallocChecker> { + BuiltinBug *BT_DoubleFree; + BuiltinBug *BT_Leak; + IdentifierInfo *II_malloc; + IdentifierInfo *II_free; + +public: + MallocChecker() : BT_DoubleFree(0), BT_Leak(0), II_malloc(0), II_free(0) {} + static void *getTag(); + void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE); + void EvalDeadSymbols(CheckerContext &C,const Stmt *S,SymbolReaper &SymReaper); + void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng); + void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S); +private: + void MallocMem(CheckerContext &C, const CallExpr *CE); + void FreeMem(CheckerContext &C, const CallExpr *CE); +}; +} + +namespace clang { + template <> + struct GRStateTrait<RegionState> + : public GRStatePartialTrait<llvm::ImmutableMap<SymbolRef, RefState> > { + static void *GDMIndex() { return MallocChecker::getTag(); } + }; +} + +void clang::RegisterMallocChecker(GRExprEngine &Eng) { + Eng.registerCheck(new MallocChecker()); +} + +void *MallocChecker::getTag() { + static int x; + return &x; +} + +void MallocChecker::PostVisitCallExpr(CheckerContext &C, const CallExpr *CE) { + const FunctionDecl *FD = CE->getDirectCallee(); + if (!FD) + return; + + ASTContext &Ctx = C.getASTContext(); + if (!II_malloc) + II_malloc = &Ctx.Idents.get("malloc"); + if (!II_free) + II_free = &Ctx.Idents.get("free"); + + if (FD->getIdentifier() == II_malloc) { + MallocMem(C, CE); + return; + } + + if (FD->getIdentifier() == II_free) { + FreeMem(C, CE); + return; + } +} + +void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) { + const GRState *state = C.getState(); + SVal CallVal = state->getSVal(CE); + SymbolRef Sym = CallVal.getAsLocSymbol(); + assert(Sym); + // Set the symbol's state to Allocated. + const GRState *AllocState + = state->set<RegionState>(Sym, RefState::getAllocated(CE)); + C.addTransition(C.GenerateNode(CE, AllocState)); +} + +void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) { + const GRState *state = C.getState(); + SVal ArgVal = state->getSVal(CE->getArg(0)); + SymbolRef Sym = ArgVal.getAsLocSymbol(); + assert(Sym); + + const RefState *RS = state->get<RegionState>(Sym); + assert(RS); + + // Check double free. + if (RS->isReleased()) { + ExplodedNode *N = C.GenerateNode(CE, true); + if (N) { + if (!BT_DoubleFree) + BT_DoubleFree = new BuiltinBug("Double free", + "Try to free a memory block that has been released"); + // FIXME: should find where it's freed last time. + BugReport *R = new BugReport(*BT_DoubleFree, + BT_DoubleFree->getDescription(), N); + C.EmitReport(R); + } + return; + } + + // Normal free. + const GRState *FreedState + = state->set<RegionState>(Sym, RefState::getReleased(CE)); + C.addTransition(C.GenerateNode(CE, FreedState)); +} + +void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S, + SymbolReaper &SymReaper) { + for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), + E = SymReaper.dead_end(); I != E; ++I) { + SymbolRef Sym = *I; + const GRState *state = C.getState(); + const RefState *RS = state->get<RegionState>(Sym); + if (!RS) + return; + + if (RS->isAllocated()) { + ExplodedNode *N = C.GenerateNode(S, true); + if (N) { + if (!BT_Leak) + BT_Leak = new BuiltinBug("Memory leak", + "Allocated memory never released. Potential memory leak."); + // FIXME: where it is allocated. + BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N); + C.EmitReport(R); + } + } + } +} + +void MallocChecker::EvalEndPath(GREndPathNodeBuilder &B, void *tag, + GRExprEngine &Eng) { + const GRState *state = B.getState(); + typedef llvm::ImmutableMap<SymbolRef, RefState> SymMap; + SymMap M = state->get<RegionState>(); + + for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) { + RefState RS = I->second; + if (RS.isAllocated()) { + ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor()); + if (N) { + if (!BT_Leak) + BT_Leak = new BuiltinBug("Memory leak", + "Allocated memory never released. Potential memory leak."); + BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N); + Eng.getBugReporter().EmitReport(R); + } + } + } +} + +void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) { + const Expr *RetE = S->getRetValue(); + if (!RetE) + return; + + const GRState *state = C.getState(); + + SymbolRef Sym = state->getSVal(RetE).getAsSymbol(); + + if (!Sym) + return; + + const RefState *RS = state->get<RegionState>(Sym); + if (!RS) + return; + + // FIXME: check other cases. + if (RS->isAllocated()) + state = state->set<RegionState>(Sym, RefState::getEscaped(S)); + + ExplodedNode *N = C.GenerateNode(S, state); + if (N) + C.addTransition(N); +} diff --git a/lib/Frontend/ManagerRegistry.cpp b/lib/Analysis/ManagerRegistry.cpp index 79f1e8178e10..8943db2a2343 100644 --- a/lib/Frontend/ManagerRegistry.cpp +++ b/lib/Analysis/ManagerRegistry.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Frontend/ManagerRegistry.h" +#include "clang/Analysis/ManagerRegistry.h" using namespace clang; diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp index 353e63240294..8c0b85c0c729 100644 --- a/lib/Analysis/MemRegion.cpp +++ b/lib/Analysis/MemRegion.cpp @@ -378,11 +378,29 @@ bool MemRegion::hasGlobalsOrParametersStorage() const { return false; } +// getBaseRegion strips away all elements and fields, and get the base region +// of them. +const MemRegion *MemRegion::getBaseRegion() const { + const MemRegion *R = this; + while (true) { + if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { + R = ER->getSuperRegion(); + continue; + } + if (const FieldRegion *FR = dyn_cast<FieldRegion>(R)) { + R = FR->getSuperRegion(); + continue; + } + break; + } + return R; +} + //===----------------------------------------------------------------------===// // View handling. //===----------------------------------------------------------------------===// -const MemRegion *MemRegion::getBaseRegion() const { +const MemRegion *MemRegion::StripCasts() const { const MemRegion *R = this; while (true) { if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { diff --git a/lib/Analysis/NSErrorChecker.cpp b/lib/Analysis/NSErrorChecker.cpp index 307686ff57b3..93b617b115d9 100644 --- a/lib/Analysis/NSErrorChecker.cpp +++ b/lib/Analysis/NSErrorChecker.cpp @@ -209,15 +209,12 @@ void NSErrorChecker::CheckParamDeref(const VarDecl *Param, return; // Iterate over the implicit-null dereferences. - NullDerefChecker *Checker = Eng.getChecker<NullDerefChecker>(); - assert(Checker && "NullDerefChecker not exist."); - for (NullDerefChecker::iterator I = Checker->implicit_nodes_begin(), - E = Checker->implicit_nodes_end(); I != E; ++I) { - + ExplodedNode *const* I, *const* E; + llvm::tie(I, E) = GetImplicitNullDereferences(Eng); + for ( ; I != E; ++I) { const GRState *state = (*I)->getState(); - const SVal* X = state->get<GRState::NullDerefTag>(); - - if (!X || X->getAsSymbol() != ParamSym) + SVal location = state->getSVal((*I)->getLocationAs<StmtPoint>()->getStmt()); + if (location.getAsSymbol() != ParamSym) continue; // Emit an error. diff --git a/lib/Analysis/PointerArithChecker.cpp b/lib/Analysis/PointerArithChecker.cpp new file mode 100644 index 000000000000..93823484e1d0 --- /dev/null +++ b/lib/Analysis/PointerArithChecker.cpp @@ -0,0 +1,71 @@ +//=== PointerArithChecker.cpp - Pointer arithmetic checker -----*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This files defines PointerArithChecker, a builtin checker that checks for +// pointer arithmetic on locations other than array elements. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "GRExprEngineInternalChecks.h" + +using namespace clang; + +namespace { +class VISIBILITY_HIDDEN PointerArithChecker + : public CheckerVisitor<PointerArithChecker> { + BuiltinBug *BT; +public: + PointerArithChecker() : BT(0) {} + static void *getTag(); + void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B); +}; +} + +void *PointerArithChecker::getTag() { + static int x; + return &x; +} + +void PointerArithChecker::PreVisitBinaryOperator(CheckerContext &C, + const BinaryOperator *B) { + if (B->getOpcode() != BinaryOperator::Sub && + B->getOpcode() != BinaryOperator::Add) + return; + + const GRState *state = C.getState(); + SVal LV = state->getSVal(B->getLHS()); + SVal RV = state->getSVal(B->getRHS()); + + const MemRegion *LR = LV.getAsRegion(); + + if (!LR || !RV.isConstant()) + return; + + // If pointer arithmetic is done on variables of non-array type, this often + // means behavior rely on memory organization, which is dangerous. + if (isa<VarRegion>(LR) || isa<CodeTextRegion>(LR) || + isa<CompoundLiteralRegion>(LR)) { + + if (ExplodedNode *N = C.GenerateNode(B)) { + if (!BT) + BT = new BuiltinBug("Dangerous pointer arithmetic", + "Pointer arithmetic done on non-array variables " + "means reliance on memory layout, which is " + "dangerous."); + RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N); + R->addRange(B->getSourceRange()); + C.EmitReport(R); + } + } +} + +void clang::RegisterPointerArithChecker(GRExprEngine &Eng) { + Eng.registerCheck(new PointerArithChecker()); +} diff --git a/lib/Analysis/PointerSubChecker.cpp b/lib/Analysis/PointerSubChecker.cpp new file mode 100644 index 000000000000..4c7906f4beba --- /dev/null +++ b/lib/Analysis/PointerSubChecker.cpp @@ -0,0 +1,77 @@ +//=== PointerSubChecker.cpp - Pointer subtraction checker ------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This files defines PointerSubChecker, a builtin checker that checks for +// pointer subtractions on two pointers pointing to different memory chunks. +// This check corresponds to CWE-469. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "GRExprEngineInternalChecks.h" + +using namespace clang; + +namespace { +class VISIBILITY_HIDDEN PointerSubChecker + : public CheckerVisitor<PointerSubChecker> { + BuiltinBug *BT; +public: + PointerSubChecker() : BT(0) {} + static void *getTag(); + void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B); +}; +} + +void *PointerSubChecker::getTag() { + static int x; + return &x; +} + +void PointerSubChecker::PreVisitBinaryOperator(CheckerContext &C, + const BinaryOperator *B) { + // When doing pointer subtraction, if the two pointers do not point to the + // same memory chunk, emit a warning. + if (B->getOpcode() != BinaryOperator::Sub) + return; + + const GRState *state = C.getState(); + SVal LV = state->getSVal(B->getLHS()); + SVal RV = state->getSVal(B->getRHS()); + + const MemRegion *LR = LV.getAsRegion(); + const MemRegion *RR = RV.getAsRegion(); + + if (!(LR && RR)) + return; + + const MemRegion *BaseLR = LR->getBaseRegion(); + const MemRegion *BaseRR = RR->getBaseRegion(); + + if (BaseLR == BaseRR) + return; + + // Allow arithmetic on different symbolic regions. + if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(BaseRR)) + return; + + if (ExplodedNode *N = C.GenerateNode(B)) { + if (!BT) + BT = new BuiltinBug("Pointer subtraction", + "Subtraction of two pointers that do not point to " + "the same memory chunk may cause incorrect result."); + RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N); + R->addRange(B->getSourceRange()); + C.EmitReport(R); + } +} + +void clang::RegisterPointerSubChecker(GRExprEngine &Eng) { + Eng.registerCheck(new PointerSubChecker()); +} diff --git a/lib/Analysis/PthreadLockChecker.cpp b/lib/Analysis/PthreadLockChecker.cpp new file mode 100644 index 000000000000..66206616b008 --- /dev/null +++ b/lib/Analysis/PthreadLockChecker.cpp @@ -0,0 +1,141 @@ +//===--- PthreadLockChecker.h - Undefined arguments checker ----*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines PthreadLockChecker, a simple lock -> unlock checker. Eventually +// this shouldn't be registered with GRExprEngineInternalChecks. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/Analysis/PathSensitive/GRStateTrait.h" +#include "GRExprEngineExperimentalChecks.h" +#include "llvm/ADT/ImmutableSet.h" + +using namespace clang; + +namespace { +class VISIBILITY_HIDDEN PthreadLockChecker + : public CheckerVisitor<PthreadLockChecker> { + BugType *BT; +public: + PthreadLockChecker() : BT(0) {} + static void *getTag() { + static int x = 0; + return &x; + } + void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE); + + void AcquireLock(CheckerContext &C, const CallExpr *CE, + SVal lock, bool isTryLock); + + void ReleaseLock(CheckerContext &C, const CallExpr *CE, + SVal lock); + +}; +} // end anonymous namespace + +// GDM Entry for tracking lock state. +namespace { class VISIBILITY_HIDDEN LockSet {}; } +namespace clang { +template <> struct GRStateTrait<LockSet> : + public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > { + static void* GDMIndex() { return PthreadLockChecker::getTag(); } +}; +} // end clang namespace + +void clang::RegisterPthreadLockChecker(GRExprEngine &Eng) { + Eng.registerCheck(new PthreadLockChecker()); +} + + +void PthreadLockChecker::PostVisitCallExpr(CheckerContext &C, + const CallExpr *CE) { + const GRState *state = C.getState(); + const Expr *Callee = CE->getCallee(); + const CodeTextRegion *R = + dyn_cast_or_null<CodeTextRegion>(state->getSVal(Callee).getAsRegion()); + + if (!R) + return; + + llvm::StringRef FName = R->getDecl()->getName(); + + if (FName == "pthread_mutex_lock") { + if (CE->getNumArgs() != 1) + return; + AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false); + } + else if (FName == "pthread_mutex_trylock") { + if (CE->getNumArgs() != 1) + return; + AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true); + } + else if (FName == "pthread_mutex_unlock") { + if (CE->getNumArgs() != 1) + return; + ReleaseLock(C, CE, state->getSVal(CE->getArg(0))); + } +} + +void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE, + SVal lock, bool isTryLock) { + + const MemRegion *lockR = lock.getAsRegion(); + if (!lockR) + return; + + const GRState *state = C.getState(); + + SVal X = state->getSVal(CE); + if (X.isUnknownOrUndef()) + return; + + DefinedSVal retVal = cast<DefinedSVal>(X); + const GRState *lockSucc = state; + + if (isTryLock) { + // Bifurcate the state, and allow a mode where the lock acquisition fails. + const GRState *lockFail; + llvm::tie(lockFail, lockSucc) = state->Assume(retVal); + assert(lockFail && lockSucc); + C.addTransition(C.GenerateNode(CE, lockFail)); + } + else { + // Assume that the return value was 0. + lockSucc = state->Assume(retVal, false); + assert(lockSucc); + } + + // Record that the lock was acquired. + lockSucc = lockSucc->add<LockSet>(lockR); + + C.addTransition(lockSucc != state ? C.GenerateNode(CE, lockSucc) : + C.getPredecessor()); +} + +void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE, + SVal lock) { + + const MemRegion *lockR = lock.getAsRegion(); + if (!lockR) + return; + + const GRState *state = C.getState(); + + // Record that the lock was released. + // FIXME: Handle unlocking locks that were never acquired. This may + // require IPA for wrappers. + const GRState *unlockState = state->remove<LockSet>(lockR); + + if (state == unlockState) + return; + + C.addTransition(C.GenerateNode(CE, unlockState)); +} diff --git a/lib/Analysis/RangeConstraintManager.cpp b/lib/Analysis/RangeConstraintManager.cpp index 73b445e6ab36..f5cae698f924 100644 --- a/lib/Analysis/RangeConstraintManager.cpp +++ b/lib/Analysis/RangeConstraintManager.cpp @@ -16,7 +16,7 @@ #include "clang/Analysis/PathSensitive/GRState.h" #include "clang/Analysis/PathSensitive/GRStateTrait.h" #include "clang/Analysis/PathSensitive/GRTransferFuncs.h" -#include "clang/Frontend/ManagerRegistry.h" +#include "clang/Analysis/ManagerRegistry.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/ADT/FoldingSet.h" diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index dbf8c42d273e..ae3fa14c2a26 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -164,7 +164,7 @@ public: ~RegionStoreSubRegionMap() {} bool iterSubRegions(const MemRegion* Parent, Visitor& V) const { - Map::iterator I = M.find(Parent); + Map::const_iterator I = M.find(Parent); if (I == M.end()) return true; @@ -360,7 +360,8 @@ public: //===------------------------------------------------------------------===// const GRState *setExtent(const GRState *state, const MemRegion* R, SVal Extent); - SVal getSizeInElements(const GRState *state, const MemRegion* R); + DefinedOrUnknownSVal getSizeInElements(const GRState *state, + const MemRegion* R); //===------------------------------------------------------------------===// // Utility methods. @@ -461,7 +462,7 @@ const GRState *RegionStoreManager::InvalidateRegion(const GRState *state, ASTContext& Ctx = StateMgr.getContext(); // Strip away casts. - R = R->getBaseRegion(); + R = R->StripCasts(); // Get the mapping of regions -> subregions. llvm::OwningPtr<RegionStoreSubRegionMap> @@ -696,8 +697,8 @@ SVal RegionStoreManager::getLValueElement(QualType elementType, SVal Offset, // Extents for regions. //===----------------------------------------------------------------------===// -SVal RegionStoreManager::getSizeInElements(const GRState *state, - const MemRegion *R) { +DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, + const MemRegion *R) { switch (R->getKind()) { case MemRegion::MemSpaceRegionKind: @@ -1028,16 +1029,20 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { return SValuator::CastResult(state, UnknownVal()); if (const FieldRegion* FR = dyn_cast<FieldRegion>(R)) - return CastRetrievedVal(RetrieveField(state, FR), state, FR, T); + return SValuator::CastResult(state, + CastRetrievedVal(RetrieveField(state, FR), FR, T)); if (const ElementRegion* ER = dyn_cast<ElementRegion>(R)) - return CastRetrievedVal(RetrieveElement(state, ER), state, ER, T); + return SValuator::CastResult(state, + CastRetrievedVal(RetrieveElement(state, ER), ER, T)); if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) - return CastRetrievedVal(RetrieveObjCIvar(state, IVR), state, IVR, T); + return SValuator::CastResult(state, + CastRetrievedVal(RetrieveObjCIvar(state, IVR), IVR, T)); if (const VarRegion *VR = dyn_cast<VarRegion>(R)) - return CastRetrievedVal(RetrieveVar(state, VR), state, VR, T); + return SValuator::CastResult(state, + CastRetrievedVal(RetrieveVar(state, VR), VR, T)); RegionBindings B = GetRegionBindings(state->getStore()); RegionBindings::data_type* V = B.lookup(R); @@ -1109,7 +1114,7 @@ SVal RegionStoreManager::RetrieveElement(const GRState* state, // FIXME: Handle loads from strings where the literal is treated as // an integer, e.g., *((unsigned int*)"hello") ASTContext &Ctx = getContext(); - QualType T = StrR->getValueType(Ctx)->getAs<ArrayType>()->getElementType(); + QualType T = Ctx.getAsArrayType(StrR->getValueType(Ctx))->getElementType(); if (T != Ctx.getCanonicalType(R->getElementType())) return UnknownVal(); diff --git a/lib/Analysis/ReturnPointerRangeChecker.cpp b/lib/Analysis/ReturnPointerRangeChecker.cpp new file mode 100644 index 000000000000..44887b2625da --- /dev/null +++ b/lib/Analysis/ReturnPointerRangeChecker.cpp @@ -0,0 +1,97 @@ +//== ReturnPointerRangeChecker.cpp ------------------------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines ReturnPointerRangeChecker, which is a path-sensitive check +// which looks for an out-of-bound pointer being returned to callers. +// +//===----------------------------------------------------------------------===// + +#include "GRExprEngineInternalChecks.h" +#include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" + +using namespace clang; + +namespace { +class VISIBILITY_HIDDEN ReturnPointerRangeChecker : + public CheckerVisitor<ReturnPointerRangeChecker> { + BuiltinBug *BT; +public: + ReturnPointerRangeChecker() : BT(0) {} + static void *getTag(); + void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS); +}; +} + +void clang::RegisterReturnPointerRangeChecker(GRExprEngine &Eng) { + Eng.registerCheck(new ReturnPointerRangeChecker()); +} + +void *ReturnPointerRangeChecker::getTag() { + static int x = 0; return &x; +} + +void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C, + const ReturnStmt *RS) { + const GRState *state = C.getState(); + + const Expr *RetE = RS->getRetValue(); + if (!RetE) + return; + + SVal V = state->getSVal(RetE); + const MemRegion *R = V.getAsRegion(); + if (!R) + return; + + R = R->StripCasts(); + if (!R) + return; + + const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(R); + if (!ER) + return; + + DefinedOrUnknownSVal &Idx = cast<DefinedOrUnknownSVal>(ER->getIndex()); + + // FIXME: All of this out-of-bounds checking should eventually be refactored + // into a common place. + + DefinedOrUnknownSVal NumElements + = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion()); + + const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true); + const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false); + if (StOutBound && !StInBound) { + ExplodedNode *N = C.GenerateNode(RS, StOutBound, true); + + if (!N) + return; + + // FIXME: This bug correspond to CWE-466. Eventually we should have bug + // types explicitly reference such exploit categories (when applicable). + if (!BT) + BT = new BuiltinBug("Return of pointer value outside of expected range", + "Returned pointer value points outside the original object " + "(potential buffer overflow)"); + + // FIXME: It would be nice to eventually make this diagnostic more clear, + // e.g., by referencing the original declaration or by saying *why* this + // reference is outside the range. + + // Generate a report for this bug. + RangedBugReport *report = + new RangedBugReport(*BT, BT->getDescription(), N); + + report->addRange(RetE->getSourceRange()); + + C.EmitReport(report); + } +} diff --git a/lib/Analysis/ReturnStackAddressChecker.cpp b/lib/Analysis/ReturnStackAddressChecker.cpp new file mode 100644 index 000000000000..e4be8712d09b --- /dev/null +++ b/lib/Analysis/ReturnStackAddressChecker.cpp @@ -0,0 +1,97 @@ +//== ReturnStackAddressChecker.cpp ------------------------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines ReturnStackAddressChecker, which is a path-sensitive +// check which looks for the addresses of stack variables being returned to +// callers. +// +//===----------------------------------------------------------------------===// + +#include "GRExprEngineInternalChecks.h" +#include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "llvm/ADT/SmallString.h" + +using namespace clang; + +namespace { +class VISIBILITY_HIDDEN ReturnStackAddressChecker : + public CheckerVisitor<ReturnStackAddressChecker> { + BuiltinBug *BT; +public: + ReturnStackAddressChecker() : BT(0) {} + static void *getTag(); + void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS); +}; +} + +void clang::RegisterReturnStackAddressChecker(GRExprEngine &Eng) { + Eng.registerCheck(new ReturnStackAddressChecker()); +} + +void *ReturnStackAddressChecker::getTag() { + static int x = 0; return &x; +} + +void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C, + const ReturnStmt *RS) { + + const Expr *RetE = RS->getRetValue(); + if (!RetE) + return; + + SVal V = C.getState()->getSVal(RetE); + const MemRegion *R = V.getAsRegion(); + + if (!R || !R->hasStackStorage()) + return; + + ExplodedNode *N = C.GenerateNode(RS, C.getState(), true); + + if (!N) + return; + + if (!BT) + BT = new BuiltinBug("Return of address to stack-allocated memory"); + + // Generate a report for this bug. + llvm::SmallString<100> buf; + llvm::raw_svector_ostream os(buf); + SourceRange range; + + // Check if the region is a compound literal. + if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) { + const CompoundLiteralExpr* CL = CR->getLiteralExpr(); + os << "Address of stack memory associated with a compound literal " + "declared on line " + << C.getSourceManager().getInstantiationLineNumber(CL->getLocStart()) + << " returned to caller"; + range = CL->getSourceRange(); + } + else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) { + const Expr* ARE = AR->getExpr(); + SourceLocation L = ARE->getLocStart(); + range = ARE->getSourceRange(); + os << "Address of stack memory allocated by call to alloca() on line " + << C.getSourceManager().getInstantiationLineNumber(L) + << " returned to caller"; + } + else { + os << "Address of stack memory associated with local variable '" + << R->getString() << "' returned."; + } + + RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); + report->addRange(RS->getSourceRange()); + if (range.isValid()) + report->addRange(range); + + C.EmitReport(report); +} diff --git a/lib/Analysis/ReturnUndefChecker.cpp b/lib/Analysis/ReturnUndefChecker.cpp new file mode 100644 index 000000000000..796c7608c86d --- /dev/null +++ b/lib/Analysis/ReturnUndefChecker.cpp @@ -0,0 +1,68 @@ +//== ReturnUndefChecker.cpp -------------------------------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines ReturnUndefChecker, which is a path-sensitive +// check which looks for undefined or garbage values being returned to the +// caller. +// +//===----------------------------------------------------------------------===// + +#include "GRExprEngineInternalChecks.h" +#include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "llvm/ADT/SmallString.h" + +using namespace clang; + +namespace { +class VISIBILITY_HIDDEN ReturnUndefChecker : + public CheckerVisitor<ReturnUndefChecker> { + BuiltinBug *BT; +public: + ReturnUndefChecker() : BT(0) {} + static void *getTag(); + void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS); +}; +} + +void clang::RegisterReturnUndefChecker(GRExprEngine &Eng) { + Eng.registerCheck(new ReturnUndefChecker()); +} + +void *ReturnUndefChecker::getTag() { + static int x = 0; return &x; +} + +void ReturnUndefChecker::PreVisitReturnStmt(CheckerContext &C, + const ReturnStmt *RS) { + + const Expr *RetE = RS->getRetValue(); + if (!RetE) + return; + + if (!C.getState()->getSVal(RetE).isUndef()) + return; + + ExplodedNode *N = C.GenerateNode(RS, C.getState(), true); + + if (!N) + return; + + if (!BT) + BT = new BuiltinBug("Garbage return value", + "Undefined or garbage value returned to caller"); + + EnhancedBugReport *report = + new EnhancedBugReport(*BT, BT->getDescription(), N); + + report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, RetE); + + C.EmitReport(report); +} diff --git a/lib/Analysis/SVals.cpp b/lib/Analysis/SVals.cpp index 688b7ff6e1e3..d5d36e3b9090 100644 --- a/lib/Analysis/SVals.cpp +++ b/lib/Analysis/SVals.cpp @@ -63,7 +63,7 @@ const FunctionDecl *SVal::getAsFunctionDecl() const { // FIXME: should we consider SymbolRef wrapped in CodeTextRegion? SymbolRef SVal::getAsLocSymbol() const { if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this)) { - const MemRegion *R = X->getBaseRegion(); + const MemRegion *R = X->StripCasts(); if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R)) return SymR->getSymbol(); } @@ -100,9 +100,9 @@ const MemRegion *SVal::getAsRegion() const { return 0; } -const MemRegion *loc::MemRegionVal::getBaseRegion() const { +const MemRegion *loc::MemRegionVal::StripCasts() const { const MemRegion *R = getRegion(); - return R ? R->getBaseRegion() : NULL; + return R ? R->StripCasts() : NULL; } bool SVal::symbol_iterator::operator==(const symbol_iterator &X) const { @@ -173,6 +173,10 @@ nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const { // Useful predicates. //===----------------------------------------------------------------------===// +bool SVal::isConstant() const { + return isa<nonloc::ConcreteInt>(this) || isa<loc::ConcreteInt>(this); +} + bool SVal::isZeroConstant() const { if (isa<loc::ConcreteInt>(*this)) return cast<loc::ConcreteInt>(*this).getValue() == 0; diff --git a/lib/Analysis/SValuator.cpp b/lib/Analysis/SValuator.cpp index 573cac315b3a..ac727b0ac696 100644 --- a/lib/Analysis/SValuator.cpp +++ b/lib/Analysis/SValuator.cpp @@ -62,8 +62,7 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state, ASTContext &C = ValMgr.getContext(); // For const casts, just propagate the value. - if (C.getCanonicalType(castTy).getUnqualifiedType() == - C.getCanonicalType(originalTy).getUnqualifiedType()) + if (C.hasSameUnqualifiedType(castTy, originalTy)) return CastResult(state, val); // Check for casts from pointers to integers. diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp index 4b4ae6580820..2fd72ac0a148 100644 --- a/lib/Analysis/Store.cpp +++ b/lib/Analysis/Store.cpp @@ -21,7 +21,7 @@ StoreManager::StoreManager(GRStateManager &stateMgr) MRMgr(ValMgr.getRegionManager()) {} const MemRegion *StoreManager::MakeElementRegion(const MemRegion *Base, - QualType EleTy, uint64_t index) { + QualType EleTy, uint64_t index) { SVal idx = ValMgr.makeArrayIndex(index); return MRMgr.getElementRegion(EleTy, idx, Base, ValMgr.getContext()); } @@ -43,7 +43,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) // Handle casts to Objective-C objects. if (CastToTy->isObjCObjectPointerType()) - return R->getBaseRegion(); + return R->StripCasts(); if (CastToTy->isBlockPointerType()) { // FIXME: We may need different solutions, depending on the symbol @@ -64,7 +64,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) QualType CanonPointeeTy = Ctx.getCanonicalType(PointeeTy); // Handle casts to void*. We just pass the region through. - if (CanonPointeeTy.getUnqualifiedType() == Ctx.VoidTy) + if (CanonPointeeTy.getLocalUnqualifiedType() == Ctx.VoidTy) return R; // Handle casts from compatible types. @@ -192,14 +192,14 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) /// CastRetrievedVal - Used by subclasses of StoreManager to implement /// implicit casts that arise from loads from regions that are reinterpreted /// as another region. -SValuator::CastResult StoreManager::CastRetrievedVal(SVal V, - const GRState *state, - const TypedRegion *R, - QualType castTy) { - if (castTy.isNull()) - return SValuator::CastResult(state, V); - +SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R, + QualType castTy) { ASTContext &Ctx = ValMgr.getContext(); - return ValMgr.getSValuator().EvalCast(V, state, castTy, R->getValueType(Ctx)); + + if (castTy.isNull()) + return V; + + assert(Ctx.hasSameUnqualifiedType(castTy, R->getValueType(Ctx))); + return V; } diff --git a/lib/Analysis/UndefinedArgChecker.cpp b/lib/Analysis/UndefinedArgChecker.cpp index a229f55ff6d9..923a7e1bed0b 100644 --- a/lib/Analysis/UndefinedArgChecker.cpp +++ b/lib/Analysis/UndefinedArgChecker.cpp @@ -12,14 +12,28 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/Checkers/UndefinedArgChecker.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" #include "clang/Analysis/PathSensitive/BugReporter.h" +#include "GRExprEngineInternalChecks.h" using namespace clang; -void *UndefinedArgChecker::getTag() { - static int x = 0; - return &x; +namespace { +class VISIBILITY_HIDDEN UndefinedArgChecker + : public CheckerVisitor<UndefinedArgChecker> { + BugType *BT; +public: + UndefinedArgChecker() : BT(0) {} + static void *getTag() { + static int x = 0; + return &x; + } + void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); +}; +} // end anonymous namespace + +void clang::RegisterUndefinedArgChecker(GRExprEngine &Eng) { + Eng.registerCheck(new UndefinedArgChecker()); } void UndefinedArgChecker::PreVisitCallExpr(CheckerContext &C, @@ -29,11 +43,10 @@ void UndefinedArgChecker::PreVisitCallExpr(CheckerContext &C, if (C.getState()->getSVal(*I).isUndef()) { if (ExplodedNode *N = C.GenerateNode(CE, true)) { if (!BT) - BT = new BugType("Pass-by-value argument in function call is " - "undefined", "Logic error"); + BT = new BuiltinBug("Pass-by-value argument in function call is " + "undefined"); // Generate a report for this bug. - EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName().c_str(), - N); + EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N); R->addRange((*I)->getSourceRange()); R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I); C.EmitReport(R); diff --git a/lib/Analysis/UndefinedArraySubscriptChecker.cpp b/lib/Analysis/UndefinedArraySubscriptChecker.cpp new file mode 100644 index 000000000000..887c7755fe45 --- /dev/null +++ b/lib/Analysis/UndefinedArraySubscriptChecker.cpp @@ -0,0 +1,56 @@ +//===--- UndefinedArraySubscriptChecker.h ----------------------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines UndefinedArraySubscriptChecker, a builtin check in GRExprEngine +// that performs checks for undefined array subscripts. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "GRExprEngineInternalChecks.h" + +using namespace clang; + +namespace { +class VISIBILITY_HIDDEN UndefinedArraySubscriptChecker + : public CheckerVisitor<UndefinedArraySubscriptChecker> { + BugType *BT; +public: + UndefinedArraySubscriptChecker() : BT(0) {} + static void *getTag() { + static int x = 0; + return &x; + } + void PreVisitArraySubscriptExpr(CheckerContext &C, + const ArraySubscriptExpr *A); +}; +} // end anonymous namespace + +void clang::RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng) { + Eng.registerCheck(new UndefinedArraySubscriptChecker()); +} + +void +UndefinedArraySubscriptChecker::PreVisitArraySubscriptExpr(CheckerContext &C, + const ArraySubscriptExpr *A) { + if (C.getState()->getSVal(A->getIdx()).isUndef()) { + if (ExplodedNode *N = C.GenerateNode(A, true)) { + if (!BT) + BT = new BuiltinBug("Array subscript is undefined"); + + // Generate a report for this bug. + EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N); + R->addRange(A->getIdx()->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, + A->getIdx()); + C.EmitReport(R); + } + } +} diff --git a/lib/Analysis/UndefinedAssignmentChecker.cpp b/lib/Analysis/UndefinedAssignmentChecker.cpp index 2e3ac34913ab..b8062f359562 100644 --- a/lib/Analysis/UndefinedAssignmentChecker.cpp +++ b/lib/Analysis/UndefinedAssignmentChecker.cpp @@ -36,11 +36,10 @@ void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C, return; if (!BT) - BT = new BugType("Assigned value is garbage or undefined", - "Logic error"); + BT = new BuiltinBug("Assigned value is garbage or undefined"); // Generate a report for this bug. - EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName().c_str(), N); + EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N); if (AssignE) { const Expr *ex = 0; diff --git a/lib/Analysis/VLASizeChecker.cpp b/lib/Analysis/VLASizeChecker.cpp index 0e731902f4bb..799a73e293c8 100644 --- a/lib/Analysis/VLASizeChecker.cpp +++ b/lib/Analysis/VLASizeChecker.cpp @@ -7,96 +7,91 @@ // //===----------------------------------------------------------------------===// // -// This defines two VLASizeCheckers, a builtin check in GRExprEngine that +// This defines VLASizeChecker, a builtin check in GRExprEngine that // performs checks for declaration of VLA of undefined or zero size. // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/Checkers/VLASizeChecker.h" +#include "GRExprEngineInternalChecks.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/BugReporter.h" using namespace clang; -void *UndefSizedVLAChecker::getTag() { - static int x = 0; - return &x; +namespace { +class VISIBILITY_HIDDEN VLASizeChecker : public CheckerVisitor<VLASizeChecker> { + BugType *BT_zero; + BugType *BT_undef; + +public: + VLASizeChecker() : BT_zero(0), BT_undef(0) {} + static void *getTag() { static int tag = 0; return &tag; } + void PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS); +}; +} // end anonymous namespace + +void clang::RegisterVLASizeChecker(GRExprEngine &Eng) { + Eng.registerCheck(new VLASizeChecker()); } -ExplodedNode *UndefSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred, - const GRState *state, - Stmt *S, GRExprEngine &Eng) { - GRStmtNodeBuilder &Builder = Eng.getBuilder(); - BugReporter &BR = Eng.getBugReporter(); - - if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) { - // FIXME: Handle multi-dimensional VLAs. - Expr* SE = VLA->getSizeExpr(); - SVal Size_untested = state->getSVal(SE); - - if (Size_untested.isUndef()) { - if (ExplodedNode* N = Builder.generateNode(S, state, Pred)) { - N->markAsSink(); - if (!BT) - 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); - R->addRange(SE->getSourceRange()); - R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE); - BR.EmitReport(R); - } - return 0; - } +void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) { + if (!DS->isSingleDecl()) + return; + + const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl()); + if (!VD) + return; + + const VariableArrayType *VLA + = C.getASTContext().getAsVariableArrayType(VD->getType()); + if (!VLA) + return; + + // FIXME: Handle multi-dimensional VLAs. + const Expr* SE = VLA->getSizeExpr(); + const GRState *state = C.getState(); + SVal sizeV = state->getSVal(SE); + + if (sizeV.isUndef()) { + // Generate an error node. + ExplodedNode *N = C.GenerateNode(DS, true); + if (!N) + return; + + if (!BT_undef) + BT_undef = new BuiltinBug("Declared variable-length array (VLA) uses a " + "garbage value as its size"); + + EnhancedBugReport *report = + new EnhancedBugReport(*BT_undef, BT_undef->getName(), N); + report->addRange(SE->getSourceRange()); + report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE); + C.EmitReport(report); + return; } - return Pred; -} - -void *ZeroSizedVLAChecker::getTag() { - static int x; - return &x; -} - -ExplodedNode *ZeroSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred, - const GRState *state, Stmt *S, - GRExprEngine &Eng) { - GRStmtNodeBuilder &Builder = Eng.getBuilder(); - BugReporter &BR = Eng.getBugReporter(); - - if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) { - // FIXME: Handle multi-dimensional VLAs. - Expr* SE = VLA->getSizeExpr(); - SVal Size_untested = state->getSVal(SE); - - DefinedOrUnknownSVal *Size = dyn_cast<DefinedOrUnknownSVal>(&Size_untested); - // Undefined size is checked in another checker. - if (!Size) - return Pred; - - const GRState *zeroState = state->Assume(*Size, false); - state = state->Assume(*Size, true); - - if (zeroState && !state) { - if (ExplodedNode* N = Builder.generateNode(S, zeroState, Pred)) { - N->markAsSink(); - if (!BT) - BT = new BugType("Declared variable-length array (VLA) has zero size", - "Logic error"); - - EnhancedBugReport *R = - new EnhancedBugReport(*BT, BT->getName().c_str(), N); - R->addRange(SE->getSourceRange()); - R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE); - BR.EmitReport(R); - } - } - if (!state) - return 0; - - return Builder.generateNode(S, state, Pred); + + // Check if the size is zero. + DefinedOrUnknownSVal sizeD = cast<DefinedOrUnknownSVal>(sizeV); + + const GRState *stateNotZero, *stateZero; + llvm::tie(stateNotZero, stateZero) = state->Assume(sizeD); + + if (stateZero && !stateNotZero) { + ExplodedNode* N = C.GenerateNode(DS, stateZero, true); + if (!BT_zero) + BT_zero = new BuiltinBug("Declared variable-length array (VLA) has zero " + "size"); + + EnhancedBugReport *report = + new EnhancedBugReport(*BT_zero, BT_zero->getName(), N); + report->addRange(SE->getSourceRange()); + report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE); + C.EmitReport(report); + return; } - else - return Pred; + + // From this point on, assume that the size is not zero. + if (state != stateNotZero) + C.addTransition(C.GenerateNode(DS, stateNotZero)); } - diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index 962cb4c42a8a..a85bef0f29ed 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -715,8 +715,8 @@ unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc) const { -static void ComputeLineNumbers(ContentCache* FI, - llvm::BumpPtrAllocator &Alloc) DISABLE_INLINE; +static DISABLE_INLINE void ComputeLineNumbers(ContentCache* FI, + llvm::BumpPtrAllocator &Alloc); static void ComputeLineNumbers(ContentCache* FI, llvm::BumpPtrAllocator &Alloc){ // Note that calling 'getBuffer()' may lazily page in the file. const MemoryBuffer *Buffer = FI->getBuffer(); diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index 12caf0c8e512..b6c4df87f272 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/TargetInfo.h" +#include "clang/Basic/LangOptions.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/STLExtras.h" #include <cstdlib> @@ -24,9 +25,6 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { // These should be overridden by concrete targets as needed. TLSSupported = true; PointerWidth = PointerAlign = 32; - WCharWidth = WCharAlign = 32; - Char16Width = Char16Align = 16; - Char32Width = Char32Align = 32; IntWidth = IntAlign = 32; LongWidth = LongAlign = 32; LongLongWidth = LongLongAlign = 64; @@ -36,7 +34,6 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { DoubleAlign = 64; LongDoubleWidth = 64; LongDoubleAlign = 64; - IntMaxTWidth = 64; SizeType = UnsignedLong; PtrDiffType = SignedLong; IntMaxType = SignedLongLong; @@ -51,7 +48,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { DoubleFormat = &llvm::APFloat::IEEEdouble; LongDoubleFormat = &llvm::APFloat::IEEEdouble; DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" - "i64:64:64-f32:32:32-f64:64:64"; + "i64:64:64-f32:32:32-f64:64:64-n32"; UserLabelPrefix = "_"; } @@ -95,17 +92,33 @@ const char *TargetInfo::getTypeConstantSuffix(IntType T) { unsigned TargetInfo::getTypeWidth(IntType T) const { switch (T) { default: assert(0 && "not an integer!"); - case SignedShort: return getShortWidth(); + case SignedShort: case UnsignedShort: return getShortWidth(); - case SignedInt: return getIntWidth(); + case SignedInt: case UnsignedInt: return getIntWidth(); - case SignedLong: return getLongWidth(); + case SignedLong: case UnsignedLong: return getLongWidth(); - case SignedLongLong: return getLongLongWidth(); + case SignedLongLong: case UnsignedLongLong: return getLongLongWidth(); }; } +/// getTypeAlign - Return the alignment (in bits) of the specified integer type +/// enum. For example, SignedInt -> getIntAlign(). +unsigned TargetInfo::getTypeAlign(IntType T) const { + switch (T) { + default: assert(0 && "not an integer!"); + case SignedShort: + case UnsignedShort: return getShortAlign(); + case SignedInt: + case UnsignedInt: return getIntAlign(); + case SignedLong: + case UnsignedLong: return getLongAlign(); + case SignedLongLong: + case UnsignedLongLong: return getLongLongAlign(); + }; +} + /// isTypeSigned - Return whether an integer types is signed. Returns true if /// the type is signed; false otherwise. bool TargetInfo::isTypeSigned(IntType T) const { @@ -124,6 +137,14 @@ bool TargetInfo::isTypeSigned(IntType T) const { }; } +/// setForcedLangOptions - Set forced language options. +/// Apply changes to the target information with respect to certain +/// language options which change the target configuration. +void TargetInfo::setForcedLangOptions(LangOptions &Opts) { + if (Opts.ShortWChar) { + WCharType = UnsignedShort; + } +} //===----------------------------------------------------------------------===// diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index f418c5a81c12..07c2bb960bcf 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -12,14 +12,18 @@ // //===----------------------------------------------------------------------===// -#include "clang/Basic/Builtins.h" -#include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/TargetBuiltins.h" +#include "clang/Basic/TargetOptions.h" #include "llvm/ADT/APFloat.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/MC/MCSectionMachO.h" using namespace clang; @@ -151,29 +155,6 @@ static void getDarwinIPhoneOSDefines(std::vector<char> &Defs, iPhoneOSStr); } -/// GetDarwinLanguageOptions - Set the default language options for darwin. -static void GetDarwinLanguageOptions(LangOptions &Opts, - const llvm::Triple &Triple) { - Opts.NeXTRuntime = true; - - if (Triple.getOS() != llvm::Triple::Darwin) - return; - - unsigned MajorVersion = Triple.getDarwinMajorNumber(); - - // Blocks and stack protectors default to on for 10.6 (darwin10) and beyond. - if (MajorVersion > 9) { - Opts.Blocks = 1; - Opts.setStackProtectorMode(LangOptions::SSPOn); - } - - // Non-fragile ABI (in 64-bit mode) default to on for 10.5 (darwin9) and - // beyond. - if (MajorVersion >= 9 && Opts.ObjC1 && - Triple.getArch() == llvm::Triple::x86_64) - Opts.ObjCNonFragileABI = 1; -} - namespace { template<typename Target> class DarwinTargetInfo : public OSTargetInfo<Target> { @@ -184,13 +165,6 @@ protected: getDarwinOSXDefines(Defines, Triple); } - /// getDefaultLangOptions - Allow the target to specify default settings for - /// various language options. These may be overridden by command line - /// options. - virtual void getDefaultLangOptions(LangOptions &Opts) { - TargetInfo::getDefaultLangOptions(Opts); - GetDarwinLanguageOptions(Opts, TargetInfo::getTriple()); - } public: DarwinTargetInfo(const std::string& triple) : OSTargetInfo<Target>(triple) { @@ -320,6 +294,25 @@ public: : OSTargetInfo<Target>(triple) {} }; +// PSP Target +template<typename Target> +class PSPTargetInfo : public OSTargetInfo<Target> { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + std::vector<char> &Defs) const { + // PSP defines; list based on the output of the pspdev gcc toolchain. + Define(Defs, "PSP", "1"); + Define(Defs, "_PSP", "1"); + Define(Defs, "__psp__", "1"); + Define(Defs, "__ELF__", "1"); + } +public: + PSPTargetInfo(const std::string& triple) + : OSTargetInfo<Target>(triple) { + this->UserLabelPrefix = ""; + } +}; + // AuroraUX target template<typename Target> class AuroraUXTargetInfo : public OSTargetInfo<Target> { @@ -413,10 +406,6 @@ public: return true; } } - virtual void getDefaultLangOptions(LangOptions &Opts) { - TargetInfo::getDefaultLangOptions(Opts); - Opts.CharIsSigned = false; - } virtual const char *getClobbers() const { return ""; } @@ -568,7 +557,7 @@ class PPC32TargetInfo : public PPCTargetInfo { public: PPC32TargetInfo(const std::string& triple) : PPCTargetInfo(triple) { DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" - "i64:64:64-f32:32:32-f64:64:64-v128:128:128"; + "i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32"; } }; } // end anonymous namespace. @@ -582,7 +571,7 @@ public: UIntMaxType = UnsignedLong; Int64Type = SignedLong; DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" - "i64:64:64-f32:32:32-f64:64:64-v128:128:128"; + "i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32:64"; } }; } // end anonymous namespace. @@ -655,7 +644,7 @@ public: bool Enabled) const; virtual void getDefaultFeatures(const std::string &CPU, llvm::StringMap<bool> &Features) const; - virtual void HandleTargetFeatures(const llvm::StringMap<bool> &Features); + virtual void HandleTargetFeatures(const std::vector<std::string> &Features); }; void X86TargetInfo::getDefaultFeatures(const std::string &CPU, @@ -772,21 +761,25 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, /// HandleTargetOptions - Perform initialization based on the user /// configured set of features. -void X86TargetInfo::HandleTargetFeatures(const llvm::StringMap<bool>&Features) { - if (Features.lookup("sse42")) - SSELevel = SSE42; - else if (Features.lookup("sse41")) - SSELevel = SSE41; - else if (Features.lookup("ssse3")) - SSELevel = SSSE3; - else if (Features.lookup("sse3")) - SSELevel = SSE3; - else if (Features.lookup("sse2")) - SSELevel = SSE2; - else if (Features.lookup("sse")) - SSELevel = SSE1; - else if (Features.lookup("mmx")) - SSELevel = MMX; +void +X86TargetInfo::HandleTargetFeatures(const std::vector<std::string> &Features) { + // Remember the maximum enabled sselevel. + for (unsigned i = 0, e = Features.size(); i !=e; ++i) { + // Ignore disabled features. + if (Features[i][0] == '-') + continue; + + assert(Features[i][0] == '+' && "Invalid target feature!"); + X86SSEEnum Level = llvm::StringSwitch<X86SSEEnum>(Features[i].substr(1)) + .Case("sse42", SSE42) + .Case("sse41", SSE41) + .Case("ssse3", SSSE3) + .Case("sse2", SSE2) + .Case("sse", SSE1) + .Case("mmx", MMX) + .Default(NoMMXSSE); + SSELevel = std::max(SSELevel, Level); + } } /// X86TargetInfo::getTargetDefines - Return a set of the X86-specific #defines @@ -902,7 +895,7 @@ public: LongDoubleAlign = 32; DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" "i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-" - "a0:0:64-f80:32:32"; + "a0:0:64-f80:32:32-n8:16:32"; SizeType = UnsignedInt; PtrDiffType = SignedInt; IntPtrType = SignedInt; @@ -943,7 +936,7 @@ public: IntPtrType = SignedLong; DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" "i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-" - "a0:0:64-f80:128:128"; + "a0:0:64-f80:128:128-n8:16:32"; } }; @@ -957,11 +950,10 @@ public: : X86_32TargetInfo(triple) { TLSSupported = false; WCharType = UnsignedShort; - WCharWidth = WCharAlign = 16; DoubleAlign = LongLongAlign = 64; DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" - "a0:0:64-f80:32:32"; + "a0:0:64-f80:32:32-n8:16:32"; } virtual void getTargetDefines(const LangOptions &Opts, std::vector<char> &Defines) const { @@ -977,11 +969,6 @@ public: namespace { -/// GetWindowsVisualStudioLanguageOptions - Set the default language options for Windows. -static void GetWindowsVisualStudioLanguageOptions(LangOptions &Opts) { - Opts.Microsoft = true; -} - // x86-32 Windows Visual Studio target class VisualStudioWindowsX86_32TargetInfo : public WindowsX86_32TargetInfo { public: @@ -996,10 +983,6 @@ public: // We lost the original triple, so we use the default. Define(Defines, "_M_IX86", "600"); } - virtual void getDefaultLangOptions(LangOptions &Opts) { - WindowsX86_32TargetInfo::getDefaultLangOptions(Opts); - GetWindowsVisualStudioLanguageOptions(Opts); - } }; } // end anonymous namespace @@ -1028,11 +1011,10 @@ public: : X86_32TargetInfo(triple) { TLSSupported = false; WCharType = UnsignedShort; - WCharWidth = WCharAlign = 16; DoubleAlign = LongLongAlign = 64; DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" - "a0:0:64-f80:32:32"; + "a0:0:64-f80:32:32-n8:16:32"; } virtual void getTargetDefines(const LangOptions &Opts, std::vector<char> &Defines) const { @@ -1059,7 +1041,7 @@ public: DescriptionString = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" - "a0:0:64-s0:64:64-f80:128:128"; + "a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"; } virtual const char *getVAListDeclaration() const { return "typedef struct __va_list_tag {" @@ -1087,7 +1069,6 @@ public: : X86_64TargetInfo(triple) { TLSSupported = false; WCharType = UnsignedShort; - WCharWidth = WCharAlign = 16; LongWidth = LongAlign = 32; DoubleAlign = LongLongAlign = 64; } @@ -1208,11 +1189,11 @@ public: if (IsThumb) { DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-" "i64:64:64-f32:32:32-f64:64:64-" - "v64:64:64-v128:128:128-a0:0:32"); + "v64:64:64-v128:128:128-a0:0:32-n32"); } else { DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" "i64:64:64-f32:32:32-f64:64:64-" - "v64:64:64-v128:128:128-a0:0:64"); + "v64:64:64-v128:128:128-a0:0:64-n32"); } } virtual const char *getABI() const { return ABI.c_str(); } @@ -1230,11 +1211,11 @@ public: if (IsThumb) { DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-" "i64:32:32-f32:32:32-f64:32:32-" - "v64:64:64-v128:128:128-a0:0:32"); + "v64:64:64-v128:128:128-a0:0:32-n32"); } else { DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" "i64:32:32-f32:32:32-f64:32:32-" - "v64:64:64-v128:128:128-a0:0:64"); + "v64:64:64-v128:128:128-a0:0:64-n32"); } // FIXME: Override "preferred align" for double and long long. @@ -1391,7 +1372,7 @@ public: SparcV8TargetInfo(const std::string& triple) : TargetInfo(triple) { // FIXME: Support Sparc quad-precision long double? DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" - "i64:64:64-f32:32:32-f64:64:64-v64:64:64"; + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32"; } virtual void getTargetDefines(const LangOptions &Opts, std::vector<char> &Defines) const { @@ -1502,7 +1483,6 @@ namespace { TLSSupported = false; IntWidth = 16; LongWidth = LongLongWidth = 32; - IntMaxTWidth = 32; PointerWidth = 16; IntAlign = 8; LongAlign = LongLongAlign = 8; @@ -1521,7 +1501,7 @@ namespace { FloatFormat = &llvm::APFloat::IEEEsingle; DoubleFormat = &llvm::APFloat::IEEEsingle; LongDoubleFormat = &llvm::APFloat::IEEEsingle; - DescriptionString = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-f32:32:32"; + DescriptionString = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-f32:32:32-n8"; } virtual uint64_t getPointerWidthV(unsigned AddrSpace) const { return 16; } @@ -1570,7 +1550,6 @@ namespace { TLSSupported = false; IntWidth = 16; LongWidth = LongLongWidth = 32; - IntMaxTWidth = 32; PointerWidth = 16; IntAlign = 8; LongAlign = LongLongAlign = 8; @@ -1580,7 +1559,7 @@ namespace { UIntMaxType = UnsignedLong; IntPtrType = SignedShort; PtrDiffType = SignedInt; - DescriptionString = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8"; + DescriptionString = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-n8:16"; } virtual void getTargetDefines(const LangOptions &Opts, std::vector<char> &Defines) const { @@ -1639,7 +1618,8 @@ namespace { IntWidth = IntAlign = 32; LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64; PointerWidth = PointerAlign = 64; - DescriptionString = "E-p:64:64:64-i8:8:16-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f128:128:128-a0:16:16"; + DescriptionString = "E-p:64:64:64-i8:8:16-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-f128:128:128-a0:16:16-n32:64"; } virtual void getTargetDefines(const LangOptions &Opts, std::vector<char> &Defines) const { @@ -1653,11 +1633,6 @@ namespace { NumRecords = 0; } - virtual void getDefaultLangOptions(LangOptions &Opts) { - TargetInfo::getDefaultLangOptions(Opts); - Opts.CharIsSigned = false; - } - virtual void getGCCRegNames(const char * const *&Names, unsigned &NumNames) const; virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, @@ -1702,7 +1677,7 @@ namespace { DoubleAlign = 32; LongLongAlign = 32; LongDoubleAlign = 32; - DescriptionString = "e-p:32:32-i64:32-f64:32"; + DescriptionString = "e-p:32:32-i64:32-f64:32-n32"; } virtual void getTargetDefines(const LangOptions &Opts, @@ -1783,7 +1758,6 @@ namespace { TLSSupported = false; IntWidth = 32; LongWidth = LongLongWidth = 32; - IntMaxTWidth = 32; PointerWidth = 32; IntAlign = 32; LongAlign = LongLongAlign = 32; @@ -1804,7 +1778,7 @@ namespace { LongDoubleFormat = &llvm::APFloat::IEEEsingle; DescriptionString = "E-p:32:32:32-a0:32:32" "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64" - "-f32:32:32-f64:32:64"; + "-f32:32:32-f64:32:64-n32"; } virtual void getTargetDefines(const LangOptions &Opts, @@ -1832,13 +1806,141 @@ namespace { }; } +namespace { +class MipsTargetInfo : public TargetInfo { + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + static const char * const GCCRegNames[]; +public: + MipsTargetInfo(const std::string& triple) : TargetInfo(triple) { + DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-" + "i64:32:64-f32:32:32-f64:64:64-v64:64:64-n32"; + } + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defines) const { + DefineStd(Defines, "mips", Opts); + Define(Defines, "_mips"); + DefineStd(Defines, "MIPSEB", Opts); + Define(Defines, "_MIPSEB"); + Define(Defines, "__REGISTER_PREFIX__", ""); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + // FIXME: Implement! + } + virtual const char *getVAListDeclaration() const { + return "typedef void* __builtin_va_list;"; + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const; + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const; + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const { + switch (*Name) { + default: + case 'r': // CPU registers. + case 'd': // Equivalent to "r" unless generating MIPS16 code. + case 'y': // Equivalent to "r", backwards compatibility only. + case 'f': // floating-point registers. + Info.setAllowsRegister(); + return true; + } + return false; + } + + virtual const char *getClobbers() const { + // FIXME: Implement! + return ""; + } +}; + +const char * const MipsTargetInfo::GCCRegNames[] = { + "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", "$26", "$27", "$28", "$sp", "$fp", "$31", + "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", + "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", + "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", + "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", + "hi", "lo", "", "$fcc0","$fcc1","$fcc2","$fcc3","$fcc4", + "$fcc5","$fcc6","$fcc7" +}; + +void MipsTargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); +} + +const TargetInfo::GCCRegAlias MipsTargetInfo::GCCRegAliases[] = { + { { "at" }, "$1" }, + { { "v0" }, "$2" }, + { { "v1" }, "$3" }, + { { "a0" }, "$4" }, + { { "a1" }, "$5" }, + { { "a2" }, "$6" }, + { { "a3" }, "$7" }, + { { "t0" }, "$8" }, + { { "t1" }, "$9" }, + { { "t2" }, "$10" }, + { { "t3" }, "$11" }, + { { "t4" }, "$12" }, + { { "t5" }, "$13" }, + { { "t6" }, "$14" }, + { { "t7" }, "$15" }, + { { "s0" }, "$16" }, + { { "s1" }, "$17" }, + { { "s2" }, "$18" }, + { { "s3" }, "$19" }, + { { "s4" }, "$20" }, + { { "s5" }, "$21" }, + { { "s6" }, "$22" }, + { { "s7" }, "$23" }, + { { "t8" }, "$24" }, + { { "t9" }, "$25" }, + { { "k0" }, "$26" }, + { { "k1" }, "$27" }, + { { "gp" }, "$28" }, + { { "sp" }, "$29" }, + { { "fp" }, "$30" }, + { { "ra" }, "$31" } +}; + +void MipsTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + Aliases = GCCRegAliases; + NumAliases = llvm::array_lengthof(GCCRegAliases); +} +} // end anonymous namespace. + +namespace { +class MipselTargetInfo : public MipsTargetInfo { +public: + MipselTargetInfo(const std::string& triple) : MipsTargetInfo(triple) { + DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-" + "i64:32:64-f32:32:32-f64:64:64-v64:64:64-n32"; + } + + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defines) const; +}; + +void MipselTargetInfo::getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defines) const { + DefineStd(Defines, "mips", Opts); + Define(Defines, "_mips"); + DefineStd(Defines, "MIPSEL", Opts); + Define(Defines, "_MIPSEL"); + Define(Defines, "__REGISTER_PREFIX__", ""); +} +} // end anonymous namespace. + //===----------------------------------------------------------------------===// // Driver code //===----------------------------------------------------------------------===// -/// CreateTargetInfo - Return the target info object for the specified target -/// triple. -TargetInfo* TargetInfo::CreateTargetInfo(const std::string &T) { +static TargetInfo *AllocateTarget(const std::string &T) { llvm::Triple Triple(T); llvm::Triple::OSType os = Triple.getOS(); @@ -1863,6 +1965,20 @@ TargetInfo* TargetInfo::CreateTargetInfo(const std::string &T) { case llvm::Triple::msp430: return new MSP430TargetInfo(T); + case llvm::Triple::mips: + if (os == llvm::Triple::Psp) + return new PSPTargetInfo<MipsTargetInfo>(T); + if (os == llvm::Triple::Linux) + return new LinuxTargetInfo<MipsTargetInfo>(T); + return new MipsTargetInfo(T); + + case llvm::Triple::mipsel: + if (os == llvm::Triple::Psp) + return new PSPTargetInfo<MipselTargetInfo>(T); + if (os == llvm::Triple::Linux) + return new LinuxTargetInfo<MipselTargetInfo>(T); + return new MipselTargetInfo(T); + case llvm::Triple::pic16: return new PIC16TargetInfo(T); @@ -1942,3 +2058,53 @@ TargetInfo* TargetInfo::CreateTargetInfo(const std::string &T) { } } } + +/// CreateTargetInfo - Return the target info object for the specified target +/// triple. +TargetInfo *TargetInfo::CreateTargetInfo(Diagnostic &Diags, + const TargetOptions &Opts) { + llvm::Triple Triple(Opts.Triple); + + // Construct the target + llvm::OwningPtr<TargetInfo> Target(AllocateTarget(Triple.str())); + if (!Target) { + Diags.Report(diag::err_target_unknown_triple) << Triple.str(); + return 0; + } + + // Set the target ABI if specified. + if (!Opts.ABI.empty() && !Target->setABI(Opts.ABI)) { + Diags.Report(diag::err_target_unknown_abi) << Opts.ABI; + return 0; + } + + // Compute the default target features, we need the target to handle this + // because features may have dependencies on one another. + llvm::StringMap<bool> Features; + Target->getDefaultFeatures(Opts.CPU, Features); + + // Apply the user specified deltas. + for (std::vector<std::string>::const_iterator it = Opts.Features.begin(), + ie = Opts.Features.end(); it != ie; ++it) { + const char *Name = it->c_str(); + + // Apply the feature via the target. + if ((Name[0] != '-' && Name[0] != '+') || + !Target->setFeatureEnabled(Features, Name + 1, (Name[0] == '+'))) { + Diags.Report(diag::err_target_invalid_feature) << Name; + return 0; + } + } + + // Add the features to the compile options. + // + // FIXME: If we are completely confident that we have the right set, we only + // need to pass the minuses. + std::vector<std::string> StrFeatures; + for (llvm::StringMap<bool>::const_iterator it = Features.begin(), + ie = Features.end(); it != ie; ++it) + StrFeatures.push_back(std::string(it->second ? "+" : "-") + it->first()); + Target->HandleTargetFeatures(StrFeatures); + + return Target.take(); +} diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp index 30383f6251f6..ba31544384cb 100644 --- a/lib/Basic/Version.cpp +++ b/lib/Basic/Version.cpp @@ -26,6 +26,10 @@ const char *getClangSubversionPath() { if (End) *End = 0; + End = strstr(URL, "/clang/tools/clang"); + if (End) + *End = 0; + char *Begin = strstr(URL, "cfe/"); if (Begin) { Path = Begin + 4; diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 682cf5da1e72..bc9eb67674ff 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -146,7 +146,23 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { if (0 && CanBlockBeGlobal(Info)) return CGM.GetAddrOfGlobalBlock(BE, Name.c_str()); - std::vector<llvm::Constant*> Elts(5); + size_t BlockFields = 5; + + bool hasIntrospection = CGM.getContext().getLangOptions().BlockIntrospection; + + if (hasIntrospection) { + BlockFields++; + } + std::vector<llvm::Constant*> Elts(BlockFields); + + if (hasIntrospection) { + std::string BlockTypeEncoding; + CGM.getContext().getObjCEncodingForBlock(BE, BlockTypeEncoding); + + Elts[5] = llvm::ConstantExpr::getBitCast( + CGM.GetAddrOfConstantCString(BlockTypeEncoding), PtrToInt8Ty); + } + llvm::Constant *C; llvm::Value *V; @@ -154,6 +170,9 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { // C = BuildBlockStructInitlist(); unsigned int flags = BLOCK_HAS_DESCRIPTOR; + if (hasIntrospection) + flags |= BLOCK_HAS_OBJC_TYPE; + // We run this first so that we set BlockHasCopyDispose from the entire // block literal. // __invoke @@ -211,19 +230,21 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { return C; } - std::vector<const llvm::Type *> Types(5+subBlockDeclRefDecls.size()); + std::vector<const llvm::Type *> Types(BlockFields+subBlockDeclRefDecls.size()); for (int i=0; i<4; ++i) Types[i] = Elts[i]->getType(); Types[4] = PtrToInt8Ty; + if (hasIntrospection) + Types[5] = PtrToInt8Ty; for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i) { const Expr *E = subBlockDeclRefDecls[i]; const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E); QualType Ty = E->getType(); if (BDRE && BDRE->isByRef()) { - Types[i+5] = llvm::PointerType::get(BuildByRefType(BDRE->getDecl()), 0); + Types[i+BlockFields] = llvm::PointerType::get(BuildByRefType(BDRE->getDecl()), 0); } else - Types[i+5] = ConvertType(Ty); + Types[i+BlockFields] = ConvertType(Ty); } llvm::StructType *Ty = llvm::StructType::get(VMContext, Types, true); @@ -237,6 +258,8 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { for (unsigned i=0; i<4; ++i) Builder.CreateStore(Elts[i], Builder.CreateStructGEP(V, i, "block.tmp")); + if (hasIntrospection) + Builder.CreateStore(Elts[5], Builder.CreateStructGEP(V, 5, "block.tmp")); for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i) { @@ -252,7 +275,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E); VD = BDRE->getDecl(); - llvm::Value* Addr = Builder.CreateStructGEP(V, i+5, "tmp"); + llvm::Value* Addr = Builder.CreateStructGEP(V, i+BlockFields, "tmp"); NoteForHelper[helpersize].index = i+5; NoteForHelper[helpersize].RequiresCopying = BlockRequiresCopying(VD->getType()); @@ -291,7 +314,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { RValue r = EmitAnyExpr(E, Addr, false); if (r.isScalar()) { llvm::Value *Loc = r.getScalarVal(); - const llvm::Type *Ty = Types[i+5]; + const llvm::Type *Ty = Types[i+BlockFields]; if (BDRE->isByRef()) { // E is now the address of the value field, instead, we want the // address of the actual ByRef struct. We optimize this slightly @@ -375,8 +398,20 @@ const llvm::Type *BlockModule::getGenericBlockLiteralType() { // int __reserved; // void (*__invoke)(void *); // struct __block_descriptor *__descriptor; + // // GNU runtime only: + // const char *types; // }; - GenericBlockLiteralType = llvm::StructType::get(IntTy->getContext(), + if (CGM.getContext().getLangOptions().BlockIntrospection) + GenericBlockLiteralType = llvm::StructType::get(IntTy->getContext(), + PtrToInt8Ty, + IntTy, + IntTy, + PtrToInt8Ty, + BlockDescPtrTy, + PtrToInt8Ty, + NULL); + else + GenericBlockLiteralType = llvm::StructType::get(IntTy->getContext(), PtrToInt8Ty, IntTy, IntTy, @@ -571,8 +606,12 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { llvm::GlobalVariable::InternalLinkage, DescriptorStruct, "__block_descriptor_global"); + int FieldCount = 5; // Generate the constants for the block literal. - llvm::Constant *LiteralFields[5]; + if (CGM.getContext().getLangOptions().BlockIntrospection) + FieldCount = 6; + + std::vector<llvm::Constant*> LiteralFields(FieldCount); CodeGenFunction::BlockInfo Info(0, n); uint64_t subBlockSize, subBlockAlign; @@ -592,7 +631,9 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { LiteralFields[0] = getNSConcreteGlobalBlock(); // Flags - LiteralFields[1] = + LiteralFields[1] = CGM.getContext().getLangOptions().BlockIntrospection ? + llvm::ConstantInt::get(IntTy, BLOCK_IS_GLOBAL | BLOCK_HAS_DESCRIPTOR | + BLOCK_HAS_OBJC_TYPE) : llvm::ConstantInt::get(IntTy, BLOCK_IS_GLOBAL | BLOCK_HAS_DESCRIPTOR); // Reserved @@ -603,9 +644,17 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { // Descriptor LiteralFields[4] = Descriptor; + + // Type encoding + if (CGM.getContext().getLangOptions().BlockIntrospection) { + std::string BlockTypeEncoding; + CGM.getContext().getObjCEncodingForBlock(BE, BlockTypeEncoding); + + LiteralFields[5] = CGM.GetAddrOfConstantCString(BlockTypeEncoding); + } llvm::Constant *BlockLiteralStruct = - llvm::ConstantStruct::get(VMContext, &LiteralFields[0], 5, false); + llvm::ConstantStruct::get(VMContext, LiteralFields, false); llvm::GlobalVariable *BlockLiteral = new llvm::GlobalVariable(getModule(), BlockLiteralStruct->getType(), true, diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h index 3ab4efb71bee..38e02a70a4e2 100644 --- a/lib/CodeGen/CGBlocks.h +++ b/lib/CodeGen/CGBlocks.h @@ -55,7 +55,8 @@ public: BLOCK_HAS_CXX_OBJ = (1 << 26), BLOCK_IS_GC = (1 << 27), BLOCK_IS_GLOBAL = (1 << 28), - BLOCK_HAS_DESCRIPTOR = (1 << 29) + BLOCK_HAS_DESCRIPTOR = (1 << 29), + BLOCK_HAS_OBJC_TYPE = (1 << 30) }; }; diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index c26921969a88..399b8733e720 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -121,7 +121,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, const llvm::Type *ResultType = ConvertType(E->getType()); Value *Result = Builder.CreateCall(F, ArgValue, "tmp"); if (Result->getType() != ResultType) - Result = Builder.CreateIntCast(Result, ResultType, "cast"); + Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true, + "cast"); return RValue::get(Result); } case Builtin::BI__builtin_clz: @@ -135,7 +136,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, const llvm::Type *ResultType = ConvertType(E->getType()); Value *Result = Builder.CreateCall(F, ArgValue, "tmp"); if (Result->getType() != ResultType) - Result = Builder.CreateIntCast(Result, ResultType, "cast"); + Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true, + "cast"); return RValue::get(Result); } case Builtin::BI__builtin_ffs: @@ -154,7 +156,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero, "iszero"); Value *Result = Builder.CreateSelect(IsZero, Zero, Tmp, "ffs"); if (Result->getType() != ResultType) - Result = Builder.CreateIntCast(Result, ResultType, "cast"); + Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true, + "cast"); return RValue::get(Result); } case Builtin::BI__builtin_parity: @@ -171,7 +174,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *Result = Builder.CreateAnd(Tmp, llvm::ConstantInt::get(ArgType, 1), "tmp"); if (Result->getType() != ResultType) - Result = Builder.CreateIntCast(Result, ResultType, "cast"); + Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true, + "cast"); return RValue::get(Result); } case Builtin::BI__builtin_popcount: @@ -185,7 +189,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, const llvm::Type *ResultType = ConvertType(E->getType()); Value *Result = Builder.CreateCall(F, ArgValue, "tmp"); if (Result->getType() != ResultType) - Result = Builder.CreateIntCast(Result, ResultType, "cast"); + Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true, + "cast"); return RValue::get(Result); } case Builtin::BI__builtin_expect: @@ -199,8 +204,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Builder.CreateCall(F, ArgValue, "tmp")); } case Builtin::BI__builtin_object_size: { - // FIXME: We're awaiting the llvm intrincis. -#if 0 +#if 1 // We pass this builtin onto the optimizer so that it can // figure out the object size in more complex cases. const llvm::Type *ResType[] = { @@ -211,8 +215,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1)))); #else - // FIXME: Implement. For now we just always fail and pretend we - // don't know the object size. + // FIXME: Remove after testing. llvm::APSInt TypeArg = E->getArg(1)->EvaluateAsInt(CGM.getContext()); const llvm::Type *ResType = ConvertType(E->getType()); // bool UseSubObject = TypeArg.getZExtValue() & 1; diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index cf172b1a1cb6..8f5cff4efafe 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -27,7 +27,7 @@ using namespace clang; using namespace CodeGen; void -CodeGenFunction::EmitCXXGlobalDtorRegistration(const CXXDestructorDecl *Dtor, +CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, llvm::Constant *DeclPtr) { const llvm::Type *Int8PtrTy = llvm::Type::getInt8Ty(VMContext)->getPointerTo(); @@ -55,9 +55,6 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(const CXXDestructorDecl *Dtor, llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy, "__dso_handle"); - - llvm::Constant *DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete); - llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy), llvm::ConstantExpr::getBitCast(DeclPtr, Int8PtrTy), llvm::ConstantExpr::getBitCast(Handle, Int8PtrTy) }; @@ -82,11 +79,29 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile); } else { EmitAggExpr(Init, DeclPtr, isVolatile); - + // Avoid generating destructor(s) for initialized objects. + if (!isa<CXXConstructExpr>(Init)) + return; + const ConstantArrayType *Array = getContext().getAsConstantArrayType(T); + if (Array) + T = getContext().getBaseElementType(Array); + if (const RecordType *RT = T->getAs<RecordType>()) { CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - if (!RD->hasTrivialDestructor()) - EmitCXXGlobalDtorRegistration(RD->getDestructor(getContext()), DeclPtr); + if (!RD->hasTrivialDestructor()) { + llvm::Constant *DtorFn; + if (Array) { + DtorFn = CodeGenFunction(CGM).GenerateCXXAggrDestructorHelper( + RD->getDestructor(getContext()), + Array, DeclPtr); + DeclPtr = + llvm::Constant::getNullValue(llvm::Type::getInt8PtrTy(VMContext)); + } + else + DtorFn = CGM.GetAddrOfCXXDestructor(RD->getDestructor(getContext()), + Dtor_Complete); + EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr); + } } } } @@ -267,14 +282,20 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) { // We also don't emit a virtual call if the base expression has a record type // because then we know what the type is. llvm::Value *Callee; - if (MD->isVirtual() && !ME->hasQualifier() && - !canDevirtualizeMemberFunctionCalls(ME->getBase())) - Callee = BuildVirtualCall(MD, This, Ty); - else if (const CXXDestructorDecl *Destructor - = dyn_cast<CXXDestructorDecl>(MD)) - Callee = CGM.GetAddrOfFunction(GlobalDecl(Destructor, Dtor_Complete), Ty); - else + if (const CXXDestructorDecl *Destructor + = dyn_cast<CXXDestructorDecl>(MD)) { + if (MD->isVirtual() && !ME->hasQualifier() && + !canDevirtualizeMemberFunctionCalls(ME->getBase())) { + Callee = BuildVirtualCall(Destructor, Dtor_Complete, This, Ty); + } else { + Callee = CGM.GetAddrOfFunction(GlobalDecl(Destructor, Dtor_Complete), Ty); + } + } else if (MD->isVirtual() && !ME->hasQualifier() && + !canDevirtualizeMemberFunctionCalls(ME->getBase())) { + Callee = BuildVirtualCall(MD, This, Ty); + } else { Callee = CGM.GetAddrOfFunction(MD, Ty); + } return EmitCXXMemberCall(MD, Callee, This, CE->arg_begin(), CE->arg_end()); @@ -410,10 +431,15 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, const llvm::Type *Ty = CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), FPT->isVariadic()); - llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, Ty); llvm::Value *This = EmitLValue(E->getArg(0)).getAddress(); + llvm::Value *Callee; + if (MD->isVirtual() && !canDevirtualizeMemberFunctionCalls(E->getArg(0))) + Callee = BuildVirtualCall(MD, This, Ty); + else + Callee = CGM.GetAddrOfFunction(MD, Ty); + return EmitCXXMemberCall(MD, Callee, This, E->arg_begin() + 1, E->arg_end()); } @@ -506,16 +532,25 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, llvm::Value *This) { const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array); assert(CA && "Do we support VLA for destruction ?"); + uint64_t ElementCount = getContext().getConstantArrayElementCount(CA); + llvm::Value* ElementCountPtr = + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), ElementCount); + EmitCXXAggrDestructorCall(D, ElementCountPtr, This); +} + +/// EmitCXXAggrDestructorCall - calls the default destructor on array +/// elements in reverse order of construction. +void +CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, + llvm::Value *UpperCount, + llvm::Value *This) { llvm::Value *One = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), 1); - uint64_t ElementCount = getContext().getConstantArrayElementCount(CA); // Create a temporary for the loop index and initialize it with count of // array elements. llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext), "loop.index"); // Index = ElementCount; - llvm::Value* UpperCount = - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), ElementCount); Builder.CreateStore(UpperCount, IndexPtr, false); // Start the loop with a block that tests the condition. @@ -543,7 +578,16 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, Counter = Builder.CreateLoad(IndexPtr); Counter = Builder.CreateSub(Counter, One); llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx"); - EmitCXXDestructorCall(D, Dtor_Complete, Address); + if (D->isVirtual()) { + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(D), + /*isVariadic=*/false); + + llvm::Value *Callee = BuildVirtualCall(D, Dtor_Deleting, Address, Ty); + EmitCXXMemberCall(D, Callee, Address, 0, 0); + } + else + EmitCXXDestructorCall(D, Dtor_Complete, Address); EmitBlock(ContinueBlock); @@ -559,6 +603,50 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, EmitBlock(AfterFor, true); } +/// GenerateCXXAggrDestructorHelper - Generates a helper function which when invoked, +/// calls the default destructor on array elements in reverse order of +/// construction. +llvm::Constant * +CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, + const ArrayType *Array, + llvm::Value *This) { + static int UniqueCount; + FunctionArgList Args; + ImplicitParamDecl *Dst = + ImplicitParamDecl::Create(getContext(), 0, + SourceLocation(), 0, + getContext().getPointerType(getContext().VoidTy)); + Args.push_back(std::make_pair(Dst, Dst->getType())); + + llvm::SmallString<16> Name; + llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueCount); + QualType R = getContext().VoidTy; + const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args); + const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false); + llvm::Function *Fn = + llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, + Name.c_str(), + &CGM.getModule()); + IdentifierInfo *II + = &CGM.getContext().Idents.get(Name.c_str()); + FunctionDecl *FD = FunctionDecl::Create(getContext(), + getContext().getTranslationUnitDecl(), + SourceLocation(), II, R, 0, + FunctionDecl::Static, + false, true); + StartFunction(FD, R, Fn, Args, SourceLocation()); + QualType BaseElementTy = getContext().getBaseElementType(Array); + const llvm::Type *BasePtr = ConvertType(BaseElementTy); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = Builder.CreateBitCast(This, BasePtr); + EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); + FinishFunction(); + llvm::Type *Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), + 0); + llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty); + return m; +} + void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type, @@ -612,8 +700,13 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, // Code gen optimization to eliminate copy constructor and return // its first argument instead. if (getContext().getLangOptions().ElideConstructors && E->isElidable()) { - CXXConstructExpr::const_arg_iterator i = E->arg_begin(); - EmitAggExpr((*i), Dest, false); + const Expr *Arg = E->getArg(0); + + if (const CXXBindTemporaryExpr *BindExpr = + dyn_cast<CXXBindTemporaryExpr>(Arg)) + Arg = BindExpr->getSubExpr(); + + EmitAggExpr(Arg, Dest, false); return; } if (Array) { @@ -649,8 +742,10 @@ void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *D, llvm::Function * CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D, CXXCtorType Type) { + const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>(); const llvm::FunctionType *FTy = - getTypes().GetFunctionType(getTypes().getFunctionInfo(D), false); + getTypes().GetFunctionType(getTypes().getFunctionInfo(D), + FPT->isVariadic()); const char *Name = getMangledCXXCtorName(D, Type); return cast<llvm::Function>( @@ -668,6 +763,8 @@ const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D, } void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) { + if (D->isVirtual()) + EmitCXXDestructor(D, Dtor_Deleting); EmitCXXDestructor(D, Dtor_Complete); EmitCXXDestructor(D, Dtor_Base); } @@ -919,20 +1016,35 @@ CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This, return VBaseOffset; } +static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, int64_t VtableIndex, + llvm::Value *This, const llvm::Type *Ty) { + Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo(); + + llvm::Value *Vtable = CGF.Builder.CreateBitCast(This, Ty); + Vtable = CGF.Builder.CreateLoad(Vtable); + + llvm::Value *VFuncPtr = + CGF.Builder.CreateConstInBoundsGEP1_64(Vtable, VtableIndex, "vfn"); + return CGF.Builder.CreateLoad(VFuncPtr); +} + llvm::Value * -CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *&This, +CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This, const llvm::Type *Ty) { - int64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD); + MD = MD->getCanonicalDecl(); + int64_t VtableIndex = CGM.getVtableInfo().getMethodVtableIndex(MD); - Ty = llvm::PointerType::get(Ty, 0); - Ty = llvm::PointerType::get(Ty, 0); - Ty = llvm::PointerType::get(Ty, 0); - llvm::Value *vtbl = Builder.CreateBitCast(This, Ty); - vtbl = Builder.CreateLoad(vtbl); - llvm::Value *vfn = Builder.CreateConstInBoundsGEP1_64(vtbl, - Index, "vfn"); - vfn = Builder.CreateLoad(vfn); - return vfn; + return ::BuildVirtualCall(*this, VtableIndex, This, Ty); +} + +llvm::Value * +CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type, + llvm::Value *&This, const llvm::Type *Ty) { + DD = cast<CXXDestructorDecl>(DD->getCanonicalDecl()); + int64_t VtableIndex = + CGM.getVtableInfo().getMethodVtableIndex(GlobalDecl(DD, Type)); + + return ::BuildVirtualCall(*this, VtableIndex, This, Ty); } /// EmitClassAggrMemberwiseCopy - This routine generates code to copy a class @@ -1269,8 +1381,16 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, // Do a built-in assignment of scalar data members. LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0); - RValue RVRHS = EmitLoadOfLValue(RHS, FieldType); - EmitStoreThroughLValue(RVRHS, LHS, FieldType); + if (!hasAggregateLLVMType(Field->getType())) { + RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType()); + EmitStoreThroughLValue(RVRHS, LHS, Field->getType()); + } else if (Field->getType()->isAnyComplexType()) { + ComplexPairTy Pair = LoadComplexFromAddr(RHS.getAddress(), + RHS.isVolatileQualified()); + StoreComplexToAddr(Pair, LHS.getAddress(), LHS.isVolatileQualified()); + } else { + EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType()); + } } FinishFunction(); } @@ -1366,12 +1486,122 @@ void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD, FinishFunction(); } +static void EmitBaseInitializer(CodeGenFunction &CGF, + const CXXRecordDecl *ClassDecl, + CXXBaseOrMemberInitializer *BaseInit, + CXXCtorType CtorType) { + assert(BaseInit->isBaseInitializer() && + "Must have base initializer!"); + + llvm::Value *ThisPtr = CGF.LoadCXXThis(); + + const Type *BaseType = BaseInit->getBaseClass(); + CXXRecordDecl *BaseClassDecl = + cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl()); + llvm::Value *V = CGF.GetAddressCXXOfBaseClass(ThisPtr, ClassDecl, + BaseClassDecl, + /*NullCheckValue=*/false); + CGF.EmitCXXConstructorCall(BaseInit->getConstructor(), + CtorType, V, + BaseInit->const_arg_begin(), + BaseInit->const_arg_end()); +} + +static void EmitMemberInitializer(CodeGenFunction &CGF, + const CXXRecordDecl *ClassDecl, + CXXBaseOrMemberInitializer *MemberInit) { + assert(MemberInit->isMemberInitializer() && + "Must have member initializer!"); + + // non-static data member initializers. + FieldDecl *Field = MemberInit->getMember(); + QualType FieldType = CGF.getContext().getCanonicalType(Field->getType()); + + llvm::Value *ThisPtr = CGF.LoadCXXThis(); + LValue LHS; + if (FieldType->isReferenceType()) { + // FIXME: This is really ugly; should be refactored somehow + unsigned idx = CGF.CGM.getTypes().getLLVMFieldNo(Field); + llvm::Value *V = CGF.Builder.CreateStructGEP(ThisPtr, idx, "tmp"); + assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs"); + LHS = LValue::MakeAddr(V, CGF.MakeQualifiers(FieldType)); + } else { + LHS = CGF.EmitLValueForField(ThisPtr, Field, ClassDecl->isUnion(), 0); + } + + // If we are initializing an anonymous union field, drill down to the field. + if (MemberInit->getAnonUnionMember()) { + Field = MemberInit->getAnonUnionMember(); + LHS = CGF.EmitLValueForField(LHS.getAddress(), Field, + /*IsUnion=*/true, 0); + FieldType = Field->getType(); + } + + // If the field is an array, branch based on the element type. + const ConstantArrayType *Array = + CGF.getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = CGF.getContext().getBaseElementType(FieldType); + + // We lose the constructor for anonymous union members, so handle them + // explicitly. + // FIXME: This is somwhat ugly. + if (MemberInit->getAnonUnionMember() && FieldType->getAs<RecordType>()) { + if (MemberInit->getNumArgs()) + CGF.EmitAggExpr(*MemberInit->arg_begin(), LHS.getAddress(), + LHS.isVolatileQualified()); + else + CGF.EmitAggregateClear(LHS.getAddress(), Field->getType()); + return; + } + + if (FieldType->getAs<RecordType>()) { + assert(MemberInit->getConstructor() && + "EmitCtorPrologue - no constructor to initialize member"); + if (Array) { + const llvm::Type *BasePtr = CGF.ConvertType(FieldType); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr); + CGF.EmitCXXAggrConstructorCall(MemberInit->getConstructor(), + Array, BaseAddrPtr); + } + else + CGF.EmitCXXConstructorCall(MemberInit->getConstructor(), + Ctor_Complete, LHS.getAddress(), + MemberInit->const_arg_begin(), + MemberInit->const_arg_end()); + return; + } + + assert(MemberInit->getNumArgs() == 1 && "Initializer count must be 1 only"); + Expr *RhsExpr = *MemberInit->arg_begin(); + RValue RHS; + if (FieldType->isReferenceType()) { + RHS = CGF.EmitReferenceBindingToExpr(RhsExpr, FieldType, + /*IsInitializer=*/true); + CGF.EmitStoreThroughLValue(RHS, LHS, FieldType); + } else if (Array) { + CGF.EmitMemSetToZero(LHS.getAddress(), Field->getType()); + } else if (!CGF.hasAggregateLLVMType(RhsExpr->getType())) { + RHS = RValue::get(CGF.EmitScalarExpr(RhsExpr, true)); + CGF.EmitStoreThroughLValue(RHS, LHS, FieldType); + } else if (RhsExpr->getType()->isAnyComplexType()) { + CGF.EmitComplexExprIntoAddr(RhsExpr, LHS.getAddress(), + LHS.isVolatileQualified()); + } else { + // Handle member function pointers; other aggregates shouldn't get this far. + CGF.EmitAggExpr(RhsExpr, LHS.getAddress(), LHS.isVolatileQualified()); + } +} + /// EmitCtorPrologue - This routine generates necessary code to initialize /// base classes and non-static data members belonging to this constructor. /// FIXME: This needs to take a CXXCtorType. void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType CtorType) { - const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext()); + const CXXRecordDecl *ClassDecl = CD->getParent(); + // FIXME: Add vbase initialization llvm::Value *LoadOfThis = 0; @@ -1379,136 +1609,18 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, E = CD->init_end(); B != E; ++B) { CXXBaseOrMemberInitializer *Member = (*B); - if (Member->isBaseInitializer()) { - LoadOfThis = LoadCXXThis(); - Type *BaseType = Member->getBaseClass(); - CXXRecordDecl *BaseClassDecl = - cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl()); - llvm::Value *V = GetAddressCXXOfBaseClass(LoadOfThis, ClassDecl, - BaseClassDecl, - /*NullCheckValue=*/false); - EmitCXXConstructorCall(Member->getConstructor(), - CtorType, V, - Member->const_arg_begin(), - Member->const_arg_end()); - } else { - // non-static data member initilaizers. - FieldDecl *Field = Member->getMember(); - QualType FieldType = getContext().getCanonicalType((Field)->getType()); - const ConstantArrayType *Array = - getContext().getAsConstantArrayType(FieldType); - if (Array) - FieldType = getContext().getBaseElementType(FieldType); + + assert(LiveTemporaries.empty() && + "Should not have any live temporaries at initializer start!"); - LoadOfThis = LoadCXXThis(); - LValue LHS; - if (FieldType->isReferenceType()) { - // FIXME: This is really ugly; should be refactored somehow - unsigned idx = CGM.getTypes().getLLVMFieldNo(Field); - llvm::Value *V = Builder.CreateStructGEP(LoadOfThis, idx, "tmp"); - assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs"); - LHS = LValue::MakeAddr(V, MakeQualifiers(FieldType)); - } else { - LHS = EmitLValueForField(LoadOfThis, Field, false, 0); - } - if (FieldType->getAs<RecordType>()) { - if (!Field->isAnonymousStructOrUnion()) { - assert(Member->getConstructor() && - "EmitCtorPrologue - no constructor to initialize member"); - if (Array) { - const llvm::Type *BasePtr = ConvertType(FieldType); - BasePtr = llvm::PointerType::getUnqual(BasePtr); - llvm::Value *BaseAddrPtr = - Builder.CreateBitCast(LHS.getAddress(), BasePtr); - EmitCXXAggrConstructorCall(Member->getConstructor(), - Array, BaseAddrPtr); - } - else - EmitCXXConstructorCall(Member->getConstructor(), - Ctor_Complete, LHS.getAddress(), - Member->const_arg_begin(), - Member->const_arg_end()); - continue; - } - else { - // Initializing an anonymous union data member. - FieldDecl *anonMember = Member->getAnonUnionMember(); - LHS = EmitLValueForField(LHS.getAddress(), anonMember, - /*IsUnion=*/true, 0); - FieldType = anonMember->getType(); - } - } + if (Member->isBaseInitializer()) + EmitBaseInitializer(*this, ClassDecl, Member, CtorType); + else + EmitMemberInitializer(*this, ClassDecl, Member); - assert(Member->getNumArgs() == 1 && "Initializer count must be 1 only"); - Expr *RhsExpr = *Member->arg_begin(); - RValue RHS; - 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); - } - } - - if (!CD->getNumBaseOrMemberInitializers() && !CD->isTrivial()) { - // Nontrivial default constructor with no initializer list. It may still - // have bases classes and/or contain non-static data members which require - // construction. - for (CXXRecordDecl::base_class_const_iterator Base = - ClassDecl->bases_begin(); - Base != ClassDecl->bases_end(); ++Base) { - // FIXME. copy assignment of virtual base NYI - if (Base->isVirtual()) - continue; - - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - if (BaseClassDecl->hasTrivialConstructor()) - continue; - if (CXXConstructorDecl *BaseCX = - BaseClassDecl->getDefaultConstructor(getContext())) { - LoadOfThis = LoadCXXThis(); - llvm::Value *V = GetAddressCXXOfBaseClass(LoadOfThis, ClassDecl, - BaseClassDecl, - /*NullCheckValue=*/false); - EmitCXXConstructorCall(BaseCX, Ctor_Complete, V, 0, 0); - } - } - - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - FieldEnd = ClassDecl->field_end(); - Field != FieldEnd; ++Field) { - QualType FieldType = getContext().getCanonicalType((*Field)->getType()); - const ConstantArrayType *Array = - getContext().getAsConstantArrayType(FieldType); - if (Array) - FieldType = getContext().getBaseElementType(FieldType); - if (!FieldType->getAs<RecordType>() || Field->isAnonymousStructOrUnion()) - continue; - const RecordType *ClassRec = FieldType->getAs<RecordType>(); - CXXRecordDecl *MemberClassDecl = - dyn_cast<CXXRecordDecl>(ClassRec->getDecl()); - if (!MemberClassDecl || MemberClassDecl->hasTrivialConstructor()) - continue; - if (CXXConstructorDecl *MamberCX = - MemberClassDecl->getDefaultConstructor(getContext())) { - LoadOfThis = LoadCXXThis(); - LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0); - if (Array) { - const llvm::Type *BasePtr = ConvertType(FieldType); - BasePtr = llvm::PointerType::getUnqual(BasePtr); - llvm::Value *BaseAddrPtr = - Builder.CreateBitCast(LHS.getAddress(), BasePtr); - EmitCXXAggrConstructorCall(MamberCX, Array, BaseAddrPtr); - } - else - EmitCXXConstructorCall(MamberCX, Ctor_Complete, LHS.getAddress(), - 0, 0); - } - } + // Pop any live temporaries that the initializers might have pushed. + while (!LiveTemporaries.empty()) + PopCXXTemporary(); } // Initialize the vtable pointer @@ -1520,7 +1632,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); PtrPtr8Ty = llvm::PointerType::get(Ptr8Ty, 0); VtableField = Builder.CreateBitCast(LoadOfThis, PtrPtr8Ty); - llvm::Value *vtable = GenerateVtable(ClassDecl); + llvm::Value *vtable = CGM.getVtableInfo().getVtable(ClassDecl); Builder.CreateStore(vtable, VtableField); } } @@ -1531,138 +1643,117 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, /// FIXME: This needs to take a CXXDtorType. void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, CXXDtorType DtorType) { - const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(DD->getDeclContext()); - assert(!ClassDecl->getNumVBases() && - "FIXME: Destruction of virtual bases not supported"); - (void)ClassDecl; // prevent warning. - - for (CXXDestructorDecl::destr_const_iterator *B = DD->destr_begin(), - *E = DD->destr_end(); B != E; ++B) { - uintptr_t BaseOrMember = (*B); - if (DD->isMemberToDestroy(BaseOrMember)) { - FieldDecl *FD = DD->getMemberToDestroy(BaseOrMember); - QualType FieldType = getContext().getCanonicalType((FD)->getType()); - const ConstantArrayType *Array = - getContext().getAsConstantArrayType(FieldType); - if (Array) - FieldType = getContext().getBaseElementType(FieldType); - const RecordType *RT = FieldType->getAs<RecordType>(); - CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl()); - if (FieldClassDecl->hasTrivialDestructor()) - continue; - llvm::Value *LoadOfThis = LoadCXXThis(); - LValue LHS = EmitLValueForField(LoadOfThis, FD, false, 0); - if (Array) { - const llvm::Type *BasePtr = ConvertType(FieldType); - BasePtr = llvm::PointerType::getUnqual(BasePtr); - llvm::Value *BaseAddrPtr = - Builder.CreateBitCast(LHS.getAddress(), BasePtr); - EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()), - Array, BaseAddrPtr); - } - else - EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()), - Dtor_Complete, LHS.getAddress()); - } else { - const RecordType *RT = - DD->getAnyBaseClassToDestroy(BaseOrMember)->getAs<RecordType>(); - CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl()); - if (BaseClassDecl->hasTrivialDestructor()) - continue; - llvm::Value *V = GetAddressCXXOfBaseClass(LoadCXXThis(), - ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - EmitCXXDestructorCall(BaseClassDecl->getDestructor(getContext()), - DtorType, V); - } - } - if (DD->getNumBaseOrMemberDestructions() || DD->isTrivial()) - return; - // Case of destructor synthesis with fields and base classes - // which have non-trivial destructors. They must be destructed in - // reverse order of their construction. - llvm::SmallVector<FieldDecl *, 16> DestructedFields; + assert(!DD->isTrivial() && + "Should not emit dtor epilogue for trivial dtor!"); - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - FieldEnd = ClassDecl->field_end(); - Field != FieldEnd; ++Field) { - QualType FieldType = getContext().getCanonicalType((*Field)->getType()); - if (getContext().getAsConstantArrayType(FieldType)) - FieldType = getContext().getBaseElementType(FieldType); - if (const RecordType *RT = FieldType->getAs<RecordType>()) { - CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl()); - if (FieldClassDecl->hasTrivialDestructor()) + const CXXRecordDecl *ClassDecl = DD->getParent(); + + // Collect the fields. + llvm::SmallVector<const FieldDecl *, 16> FieldDecls; + for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(), + E = ClassDecl->field_end(); I != E; ++I) { + const FieldDecl *Field = *I; + + QualType FieldType = getContext().getCanonicalType(Field->getType()); + FieldType = getContext().getBaseElementType(FieldType); + + const RecordType *RT = FieldType->getAs<RecordType>(); + if (!RT) + continue; + + CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl()); + if (FieldClassDecl->hasTrivialDestructor()) continue; - DestructedFields.push_back(*Field); - } + + FieldDecls.push_back(Field); } - if (!DestructedFields.empty()) - for (int i = DestructedFields.size() -1; i >= 0; --i) { - FieldDecl *Field = DestructedFields[i]; - QualType FieldType = Field->getType(); - const ConstantArrayType *Array = - getContext().getAsConstantArrayType(FieldType); - if (Array) - FieldType = getContext().getBaseElementType(FieldType); - const RecordType *RT = FieldType->getAs<RecordType>(); - CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl()); - llvm::Value *LoadOfThis = LoadCXXThis(); - LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0); - if (Array) { - const llvm::Type *BasePtr = ConvertType(FieldType); - BasePtr = llvm::PointerType::getUnqual(BasePtr); - llvm::Value *BaseAddrPtr = + + // Now destroy the fields. + for (size_t i = FieldDecls.size(); i > 0; --i) { + const FieldDecl *Field = FieldDecls[i - 1]; + + QualType FieldType = Field->getType(); + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = getContext().getBaseElementType(FieldType); + + const RecordType *RT = FieldType->getAs<RecordType>(); + CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl()); + + llvm::Value *ThisPtr = LoadCXXThis(); + + LValue LHS = EmitLValueForField(ThisPtr, Field, + /*isUnion=*/false, + // FIXME: Qualifiers? + /*CVRQualifiers=*/0); + if (Array) { + const llvm::Type *BasePtr = ConvertType(FieldType); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = Builder.CreateBitCast(LHS.getAddress(), BasePtr); - EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()), - Array, BaseAddrPtr); - } - else - EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()), - Dtor_Complete, LHS.getAddress()); - } + EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()), + Array, BaseAddrPtr); + } else + EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()), + Dtor_Complete, LHS.getAddress()); + } - llvm::SmallVector<CXXRecordDecl*, 4> DestructedBases; - for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); - Base != ClassDecl->bases_end(); ++Base) { - // FIXME. copy assignment of virtual base NYI - if (Base->isVirtual()) + // Destroy non-virtual bases. + for (CXXRecordDecl::reverse_base_class_const_iterator I = + ClassDecl->bases_rbegin(), E = ClassDecl->bases_rend(); I != E; ++I) { + const CXXBaseSpecifier &Base = *I; + + // Ignore virtual bases. + if (Base.isVirtual()) continue; - + CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); + + // Ignore trivial destructors. if (BaseClassDecl->hasTrivialDestructor()) continue; - DestructedBases.push_back(BaseClassDecl); - } - if (DestructedBases.empty()) - return; - for (int i = DestructedBases.size() -1; i >= 0; --i) { - CXXRecordDecl *BaseClassDecl = DestructedBases[i]; + llvm::Value *V = GetAddressCXXOfBaseClass(LoadCXXThis(), - ClassDecl,BaseClassDecl, + ClassDecl, BaseClassDecl, /*NullCheckValue=*/false); EmitCXXDestructorCall(BaseClassDecl->getDestructor(getContext()), - Dtor_Complete, V); + Dtor_Base, V); } + + // If we're emitting a base destructor, we don't want to emit calls to the + // virtual bases. + if (DtorType == Dtor_Base) + return; + + // FIXME: Handle virtual bases. + for (CXXRecordDecl::reverse_base_class_const_iterator I = + ClassDecl->vbases_rbegin(), E = ClassDecl->vbases_rend(); I != E; ++I) { + assert(false && "FIXME: Handle virtual bases."); + } + + // If we have a deleting destructor, emit a call to the delete operator. + if (DtorType == Dtor_Deleting) + EmitDeleteCall(DD->getOperatorDelete(), LoadCXXThis(), + getContext().getTagDeclType(ClassDecl)); } void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor, CXXDtorType DtorType, llvm::Function *Fn, const FunctionArgList &Args) { - - const CXXRecordDecl *ClassDecl = Dtor->getParent(); - assert(!ClassDecl->hasUserDeclaredDestructor() && + assert(!Dtor->getParent()->hasUserDeclaredDestructor() && "SynthesizeDefaultDestructor - destructor has user declaration"); - (void) ClassDecl; StartFunction(GlobalDecl(Dtor, DtorType), Dtor->getResultType(), Fn, Args, SourceLocation()); + EmitDtorEpilogue(Dtor, DtorType); FinishFunction(); } -// FIXME: Move this to CGCXXStmt.cpp +// FIXME: Move this to CGStmtCXX.cpp void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { // FIXME: We need to do more here. EmitStmt(S.getTryBlock()); diff --git a/lib/CodeGen/CGCXXClass.cpp b/lib/CodeGen/CGCXXClass.cpp index 56a28fc9a007..533aabc8616e 100644 --- a/lib/CodeGen/CGCXXClass.cpp +++ b/lib/CodeGen/CGCXXClass.cpp @@ -31,6 +31,9 @@ ComputeNonVirtualBaseClassOffset(ASTContext &Context, CXXBasePaths &Paths, const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class); const CXXBaseSpecifier *BS = Element.Base; + // FIXME: enable test3 from virt.cc to not abort. + if (BS->isVirtual()) + return 0; assert(!BS->isVirtual() && "Should not see virtual bases here!"); const CXXRecordDecl *Base = diff --git a/lib/CodeGen/CGCXXExpr.cpp b/lib/CodeGen/CGCXXExpr.cpp index 2d62df6c58a4..cd7d21b3b951 100644 --- a/lib/CodeGen/CGCXXExpr.cpp +++ b/lib/CodeGen/CGCXXExpr.cpp @@ -218,6 +218,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { if (NullCheckResult) { Builder.CreateBr(NewEnd); + NewNotNull = Builder.GetInsertBlock(); EmitBlock(NewNull); Builder.CreateBr(NewEnd); EmitBlock(NewEnd); @@ -233,12 +234,35 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { return NewPtr; } -void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { - if (E->isArrayForm()) { - ErrorUnsupported(E, "delete[] expression"); - return; - }; +void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, + llvm::Value *Ptr, + QualType DeleteTy) { + const FunctionProtoType *DeleteFTy = + DeleteFD->getType()->getAs<FunctionProtoType>(); + + CallArgList DeleteArgs; + + QualType ArgTy = DeleteFTy->getArgType(0); + llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy)); + DeleteArgs.push_back(std::make_pair(RValue::get(DeletePtr), ArgTy)); + + if (DeleteFTy->getNumArgs() == 2) { + QualType SizeTy = DeleteFTy->getArgType(1); + uint64_t SizeVal = getContext().getTypeSize(DeleteTy) / 8; + llvm::Constant *Size = llvm::ConstantInt::get(ConvertType(SizeTy), + SizeVal); + DeleteArgs.push_back(std::make_pair(RValue::get(Size), SizeTy)); + } + + // Emit the call to delete. + EmitCall(CGM.getTypes().getFunctionInfo(DeleteFTy->getResultType(), + DeleteArgs), + CGM.GetAddrOfFunction(DeleteFD), + DeleteArgs, DeleteFD); +} +void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { + // Get at the argument before we performed the implicit conversion // to void*. const Expr *Arg = E->getArgument(); @@ -264,41 +288,237 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { Builder.CreateCondBr(IsNull, DeleteEnd, DeleteNotNull); EmitBlock(DeleteNotNull); - + + bool ShouldCallDelete = true; + // Call the destructor if necessary. if (const RecordType *RT = DeleteTy->getAs<RecordType>()) { if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) { if (!RD->hasTrivialDestructor()) { const CXXDestructorDecl *Dtor = RD->getDestructor(getContext()); - if (Dtor->isVirtual()) { + if (E->isArrayForm()) { + QualType SizeTy = getContext().getSizeType(); + uint64_t CookiePadding = std::max(getContext().getTypeSize(SizeTy), + static_cast<uint64_t>(getContext().getTypeAlign(DeleteTy))) / 8; + if (CookiePadding) { + llvm::Type *Ptr8Ty = + llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); + uint64_t CookieOffset = + CookiePadding - getContext().getTypeSize(SizeTy) / 8; + llvm::Value *AllocatedObjectPtr = + Builder.CreateConstInBoundsGEP1_64( + Builder.CreateBitCast(Ptr, Ptr8Ty), -CookiePadding); + llvm::Value *NumElementsPtr = + Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr, + CookieOffset); + NumElementsPtr = Builder.CreateBitCast(NumElementsPtr, + ConvertType(SizeTy)->getPointerTo()); + + llvm::Value *NumElements = + Builder.CreateLoad(NumElementsPtr); + NumElements = + Builder.CreateIntCast(NumElements, + llvm::Type::getInt64Ty(VMContext), false, + "count.tmp"); + EmitCXXAggrDestructorCall(Dtor, NumElements, Ptr); + Ptr = AllocatedObjectPtr; + } + } + else if (Dtor->isVirtual()) { const llvm::Type *Ty = CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(Dtor), /*isVariadic=*/false); - llvm::Value *Callee = BuildVirtualCall(Dtor, Ptr, Ty); + llvm::Value *Callee = BuildVirtualCall(Dtor, Dtor_Deleting, Ptr, Ty); EmitCXXMemberCall(Dtor, Callee, Ptr, 0, 0); + + // The dtor took care of deleting the object. + ShouldCallDelete = false; } else EmitCXXDestructorCall(Dtor, Dtor_Complete, Ptr); } } } - // Call delete. - FunctionDecl *DeleteFD = E->getOperatorDelete(); - const FunctionProtoType *DeleteFTy = - DeleteFD->getType()->getAs<FunctionProtoType>(); + if (ShouldCallDelete) + EmitDeleteCall(E->getOperatorDelete(), Ptr, DeleteTy); - CallArgList DeleteArgs; + EmitBlock(DeleteEnd); +} - QualType ArgTy = DeleteFTy->getArgType(0); - llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy)); - DeleteArgs.push_back(std::make_pair(RValue::get(DeletePtr), ArgTy)); +llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) { + QualType Ty = E->getType(); + const llvm::Type *LTy = ConvertType(Ty)->getPointerTo(); + if (E->isTypeOperand()) { + Ty = E->getTypeOperand(); + CanQualType CanTy = CGM.getContext().getCanonicalType(Ty); + Ty = CanTy.getUnqualifiedType().getNonReferenceType(); + if (const RecordType *RT = Ty->getAs<RecordType>()) { + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + if (RD->isPolymorphic()) + return Builder.CreateBitCast(CGM.GenerateRttiRef(RD), LTy); + return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy); + } + return Builder.CreateBitCast(CGM.GenerateRttiNonClass(Ty), LTy); + } + Expr *subE = E->getExprOperand(); + Ty = subE->getType(); + CanQualType CanTy = CGM.getContext().getCanonicalType(Ty); + Ty = CanTy.getUnqualifiedType().getNonReferenceType(); + if (const RecordType *RT = Ty->getAs<RecordType>()) { + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + if (RD->isPolymorphic()) { + // FIXME: if subE is an lvalue do + LValue Obj = EmitLValue(subE); + llvm::Value *This = Obj.getAddress(); + LTy = LTy->getPointerTo()->getPointerTo(); + llvm::Value *V = Builder.CreateBitCast(This, LTy); + // We need to do a zero check for *p, unless it has NonNullAttr. + // FIXME: PointerType->hasAttr<NonNullAttr>() + bool CanBeZero = false; + if (UnaryOperator *UO = dyn_cast<UnaryOperator>(subE->IgnoreParens())) + if (UO->getOpcode() == UnaryOperator::Deref) + CanBeZero = true; + if (CanBeZero) { + llvm::BasicBlock *NonZeroBlock = createBasicBlock(); + llvm::BasicBlock *ZeroBlock = createBasicBlock(); + + llvm::Value *Zero = llvm::Constant::getNullValue(LTy); + Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero), + NonZeroBlock, ZeroBlock); + EmitBlock(ZeroBlock); + /// Call __cxa_bad_typeid + const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext); + const llvm::FunctionType *FTy; + FTy = llvm::FunctionType::get(ResultType, false); + llvm::Value *F = CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid"); + Builder.CreateCall(F)->setDoesNotReturn(); + Builder.CreateUnreachable(); + EmitBlock(NonZeroBlock); + } + V = Builder.CreateLoad(V, "vtable"); + V = Builder.CreateConstInBoundsGEP1_64(V, -1ULL); + V = Builder.CreateLoad(V); + return V; + } + return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy); + } + return Builder.CreateBitCast(CGM.GenerateRttiNonClass(Ty), LTy); +} - // Emit the call to delete. - EmitCall(CGM.getTypes().getFunctionInfo(DeleteFTy->getResultType(), - DeleteArgs), - CGM.GetAddrOfFunction(DeleteFD), - DeleteArgs, DeleteFD); +llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V, + const CXXDynamicCastExpr *DCE) { + QualType CastTy = DCE->getTypeAsWritten(); + QualType InnerType = CastTy->getPointeeType(); + QualType ArgTy = DCE->getSubExpr()->getType(); + const llvm::Type *LArgTy = ConvertType(ArgTy); + const llvm::Type *LTy = ConvertType(DCE->getType()); + + bool CanBeZero = false; + bool ToVoid = false; + bool ThrowOnBad = false; + if (CastTy->isPointerType()) { + // FIXME: if PointerType->hasAttr<NonNullAttr>(), we don't set this + CanBeZero = true; + if (InnerType->isVoidType()) + ToVoid = true; + } else { + LTy = LTy->getPointerTo(); + ThrowOnBad = true; + } - EmitBlock(DeleteEnd); + CXXRecordDecl *SrcTy; + QualType Ty = ArgTy; + if (ArgTy.getTypePtr()->isPointerType() + || ArgTy.getTypePtr()->isReferenceType()) + Ty = Ty.getTypePtr()->getPointeeType(); + CanQualType CanTy = CGM.getContext().getCanonicalType(Ty); + Ty = CanTy.getUnqualifiedType(); + SrcTy = cast<CXXRecordDecl>(Ty->getAs<RecordType>()->getDecl()); + + llvm::BasicBlock *ContBlock = createBasicBlock(); + llvm::BasicBlock *NullBlock = 0; + llvm::BasicBlock *NonZeroBlock = 0; + if (CanBeZero) { + NonZeroBlock = createBasicBlock(); + NullBlock = createBasicBlock(); + llvm::Value *Zero = llvm::Constant::getNullValue(LArgTy); + Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero), + NonZeroBlock, NullBlock); + EmitBlock(NonZeroBlock); + } + + llvm::BasicBlock *BadCastBlock = 0; + + const llvm::Type *PtrDiffTy = ConvertType(getContext().getSizeType()); + + // See if this is a dynamic_cast(void*) + if (ToVoid) { + llvm::Value *This = V; + V = Builder.CreateBitCast(This, PtrDiffTy->getPointerTo()->getPointerTo()); + V = Builder.CreateLoad(V, "vtable"); + V = Builder.CreateConstInBoundsGEP1_64(V, -2ULL); + V = Builder.CreateLoad(V, "offset to top"); + This = Builder.CreateBitCast(This, llvm::Type::getInt8PtrTy(VMContext)); + V = Builder.CreateInBoundsGEP(This, V); + V = Builder.CreateBitCast(V, LTy); + } else { + /// Call __dynamic_cast + const llvm::Type *ResultType = llvm::Type::getInt8PtrTy(VMContext); + const llvm::FunctionType *FTy; + std::vector<const llvm::Type*> ArgTys; + const llvm::Type *PtrToInt8Ty + = llvm::Type::getInt8Ty(VMContext)->getPointerTo(); + ArgTys.push_back(PtrToInt8Ty); + ArgTys.push_back(PtrToInt8Ty); + ArgTys.push_back(PtrToInt8Ty); + ArgTys.push_back(PtrDiffTy); + FTy = llvm::FunctionType::get(ResultType, ArgTys, false); + CXXRecordDecl *DstTy; + Ty = CastTy.getTypePtr()->getPointeeType(); + CanTy = CGM.getContext().getCanonicalType(Ty); + Ty = CanTy.getUnqualifiedType(); + DstTy = cast<CXXRecordDecl>(Ty->getAs<RecordType>()->getDecl()); + + // FIXME: Calculate better hint. + llvm::Value *hint = llvm::ConstantInt::get(PtrDiffTy, -1ULL); + llvm::Value *SrcArg = CGM.GenerateRttiRef(SrcTy); + llvm::Value *DstArg = CGM.GenerateRttiRef(DstTy); + V = Builder.CreateBitCast(V, PtrToInt8Ty); + V = Builder.CreateCall4(CGM.CreateRuntimeFunction(FTy, "__dynamic_cast"), + V, SrcArg, DstArg, hint); + V = Builder.CreateBitCast(V, LTy); + + if (ThrowOnBad) { + BadCastBlock = createBasicBlock(); + + llvm::Value *Zero = llvm::Constant::getNullValue(LTy); + Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero), + ContBlock, BadCastBlock); + EmitBlock(BadCastBlock); + /// Call __cxa_bad_cast + ResultType = llvm::Type::getVoidTy(VMContext); + const llvm::FunctionType *FBadTy; + FBadTy = llvm::FunctionType::get(ResultType, false); + llvm::Value *F = CGM.CreateRuntimeFunction(FBadTy, "__cxa_bad_cast"); + Builder.CreateCall(F)->setDoesNotReturn(); + Builder.CreateUnreachable(); + } + } + + if (CanBeZero) { + Builder.CreateBr(ContBlock); + EmitBlock(NullBlock); + Builder.CreateBr(ContBlock); + } + EmitBlock(ContBlock); + if (CanBeZero) { + llvm::PHINode *PHI = Builder.CreatePHI(LTy); + PHI->reserveOperandSpace(2); + PHI->addIncoming(V, NonZeroBlock); + PHI->addIncoming(llvm::Constant::getNullValue(LTy), NullBlock); + V = PHI; + } + + return V; } diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 06cd05cc75a8..d0c7d03f20ef 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -19,7 +19,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" -#include "clang/Frontend/CompileOptions.h" +#include "clang/CodeGen/CodeGenOptions.h" #include "llvm/Attributes.h" #include "llvm/Support/CallSite.h" #include "llvm/Target/TargetData.h" @@ -441,18 +441,13 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, RetAttrs |= llvm::Attribute::NoAlias; } - if (CompileOpts.OptimizeSize) + if (CodeGenOpts.OptimizeSize) FuncAttrs |= llvm::Attribute::OptimizeForSize; - if (CompileOpts.DisableRedZone) + if (CodeGenOpts.DisableRedZone) FuncAttrs |= llvm::Attribute::NoRedZone; - if (CompileOpts.NoImplicitFloat) + if (CodeGenOpts.NoImplicitFloat) FuncAttrs |= llvm::Attribute::NoImplicitFloat; - if (Features.getStackProtectorMode() == LangOptions::SSPOn) - FuncAttrs |= llvm::Attribute::StackProtect; - else if (Features.getStackProtectorMode() == LangOptions::SSPReq) - FuncAttrs |= llvm::Attribute::StackProtectReq; - QualType RetTy = FI.getReturnType(); unsigned Index = 1; const ABIArgInfo &RetAI = FI.getReturnInfo(); diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 1b01e1537b42..055166721085 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -21,7 +21,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/Version.h" -#include "clang/Frontend/CompileOptions.h" +#include "clang/CodeGen/CodeGenOptions.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Instructions.h" @@ -57,7 +57,7 @@ llvm::DIDescriptor CGDebugInfo::getContext(const VarDecl *Decl, if (Decl->getDeclContext()->isFunctionOrMethod()) { // Find the last subprogram in region stack. for (unsigned RI = RegionStack.size(), RE = 0; RI != RE; --RI) { - llvm::DIDescriptor R = RegionStack[RI - 1]; + llvm::DIDescriptor R(RegionStack[RI - 1]); if (R.isSubprogram()) return R; } @@ -136,10 +136,11 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { RuntimeVers = LO.ObjCNonFragileABI ? 2 : 1; // Create new compile unit. - return Unit = DebugFactory.CreateCompileUnit(LangTag, AbsFileName.getLast(), - AbsFileName.getDirname(), - Producer, isMain, isOptimized, - Flags, RuntimeVers); + return Unit = DebugFactory.CreateCompileUnit(LangTag, + AbsFileName.getLast().c_str(), + AbsFileName.getDirname().c_str(), + Producer.c_str(), isMain, + isOptimized, Flags, RuntimeVers); } /// CreateType - Get the Basic type from the cache or create a new @@ -178,8 +179,6 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT, BT->getName(M->getContext().getLangOptions()), Unit, 0, Size, Align, Offset, /*flags*/ 0, Encoding); - - TypeCache[QualType(BT, 0).getAsOpaquePtr()] = DbgTy.getNode(); return DbgTy; } @@ -198,7 +197,6 @@ llvm::DIType CGDebugInfo::CreateType(const ComplexType *Ty, DebugFactory.CreateBasicType(Unit, "complex", Unit, 0, Size, Align, Offset, /*flags*/ 0, Encoding); - TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode(); return DbgTy; } @@ -236,38 +234,41 @@ llvm::DIType CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DICompileUnit U llvm::DIType DbgTy = DebugFactory.CreateDerivedType(Tag, Unit, "", llvm::DICompileUnit(), 0, 0, 0, 0, 0, FromTy); - TypeCache[Ty.getAsOpaquePtr()] = DbgTy.getNode(); return DbgTy; } llvm::DIType CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty, llvm::DICompileUnit Unit) { - llvm::DIType EltTy = getOrCreateType(Ty->getPointeeType(), Unit); - - // Bit size, align and offset of the type. - uint64_t Size = M->getContext().getTypeSize(Ty); - uint64_t Align = M->getContext().getTypeAlign(Ty); - llvm::DIType DbgTy = - DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit, - "", llvm::DICompileUnit(), - 0, Size, Align, 0, 0, EltTy); - TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode(); + CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty, + Ty->getPointeeType(), Unit); return DbgTy; } llvm::DIType CGDebugInfo::CreateType(const PointerType *Ty, llvm::DICompileUnit Unit) { - llvm::DIType EltTy = getOrCreateType(Ty->getPointeeType(), Unit); + return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty, + Ty->getPointeeType(), Unit); +} + +llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag, + const Type *Ty, + QualType PointeeTy, + llvm::DICompileUnit Unit) { + llvm::DIType EltTy = getOrCreateType(PointeeTy, Unit); // Bit size, align and offset of the type. - uint64_t Size = M->getContext().getTypeSize(Ty); + + // Size is always the size of a pointer. We can't use getTypeSize here + // because that does not return the correct value for references. + uint64_t Size = + M->getContext().Target.getPointerWidth(PointeeTy.getAddressSpace()); uint64_t Align = M->getContext().getTypeAlign(Ty); return - DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit, - "", llvm::DICompileUnit(), + DebugFactory.CreateDerivedType(Tag, Unit, "", llvm::DICompileUnit(), 0, Size, Align, 0, 0, EltTy); + } llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, @@ -407,7 +408,6 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, // We don't set size information, but do specify where the typedef was // declared. - std::string TyName = Ty->getDecl()->getNameAsString(); SourceLocation DefLoc = Ty->getDecl()->getLocation(); llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(DefLoc); @@ -417,8 +417,8 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, llvm::DIType DbgTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_typedef, Unit, - TyName, DefUnit, Line, 0, 0, 0, 0, Src); - TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode(); + Ty->getDecl()->getNameAsCString(), + DefUnit, Line, 0, 0, 0, 0, Src); return DbgTy; } @@ -446,7 +446,6 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty, Unit, "", llvm::DICompileUnit(), 0, 0, 0, 0, 0, llvm::DIType(), EltTypeArray); - TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode(); return DbgTy; } @@ -468,8 +467,6 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, SourceManager &SM = M->getContext().getSourceManager(); // Get overall information about the record type for the debug info. - std::string Name = Decl->getNameAsString(); - PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); llvm::DICompileUnit DefUnit; unsigned Line = 0; @@ -485,13 +482,15 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, // may refer to the forward decl if the struct is recursive) and replace all // uses of the forward declaration with the final definition. llvm::DICompositeType FwdDecl = - DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, 0, 0, 0, 0, + DebugFactory.CreateCompositeType(Tag, Unit, Decl->getNameAsString().data(), + DefUnit, Line, 0, 0, 0, 0, llvm::DIType(), llvm::DIArray()); // If this is just a forward declaration, return it. if (!Decl->getDefinition(M->getContext())) return FwdDecl; + llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode(); // Otherwise, insert it into the TypeCache so that recursive uses will find // it. TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl.getNode(); @@ -508,10 +507,10 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, FieldDecl *Field = *I; llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit); - std::string FieldName = Field->getNameAsString(); + const char *FieldName = Field->getNameAsCString(); // Ignore unnamed fields. - if (FieldName.empty()) + if (!FieldName) continue; // Get the location for the field. @@ -559,15 +558,13 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, uint64_t Align = M->getContext().getTypeAlign(Ty); llvm::DICompositeType RealDecl = - DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, Size, - Align, 0, 0, llvm::DIType(), Elements); - - // Update TypeCache. - TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl.getNode(); + DebugFactory.CreateCompositeType(Tag, Unit, Decl->getNameAsString().data(), + DefUnit, Line, Size, Align, 0, 0, + llvm::DIType(), Elements); // Now that we have a real decl for the struct, replace anything using the // old decl with the new one. This will recursively update the debug info. - FwdDecl.replaceAllUsesWith(RealDecl); + llvm::DIDerivedType(FwdDeclNode).replaceAllUsesWith(RealDecl); return RealDecl; } @@ -581,8 +578,6 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, SourceManager &SM = M->getContext().getSourceManager(); // Get overall information about the record type for the debug info. - std::string Name = Decl->getNameAsString(); - llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(Decl->getLocation()); PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine(); @@ -597,7 +592,8 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, // may refer to the forward decl if the struct is recursive) and replace all // uses of the forward declaration with the final definition. llvm::DICompositeType FwdDecl = - DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, 0, 0, 0, 0, + DebugFactory.CreateCompositeType(Tag, Unit, Decl->getNameAsCString(), + DefUnit, Line, 0, 0, 0, 0, llvm::DIType(), llvm::DIArray(), RuntimeLang); @@ -605,6 +601,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, if (Decl->isForwardDecl()) return FwdDecl; + llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode(); // Otherwise, insert it into the TypeCache so that recursive uses will find // it. TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl.getNode(); @@ -631,10 +628,10 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, ObjCIvarDecl *Field = *I; llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit); - std::string FieldName = Field->getNameAsString(); + const char *FieldName = Field->getNameAsCString(); // Ignore unnamed fields. - if (FieldName.empty()) + if (!FieldName) continue; // Get the location for the field. @@ -685,16 +682,13 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, uint64_t Align = M->getContext().getTypeAlign(Ty); llvm::DICompositeType RealDecl = - DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, Size, - Align, 0, 0, llvm::DIType(), Elements, - RuntimeLang); - - // Update TypeCache. - TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl.getNode(); + DebugFactory.CreateCompositeType(Tag, Unit, Decl->getNameAsCString(), DefUnit, + Line, Size, Align, 0, 0, llvm::DIType(), + Elements, RuntimeLang); // Now that we have a real decl for the struct, replace anything using the // old decl with the new one. This will recursively update the debug info. - FwdDecl.replaceAllUsesWith(RealDecl); + llvm::DIDerivedType(FwdDeclNode).replaceAllUsesWith(RealDecl); return RealDecl; } @@ -709,7 +703,7 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty, for (EnumDecl::enumerator_iterator Enum = Decl->enumerator_begin(), EnumEnd = Decl->enumerator_end(); Enum != EnumEnd; ++Enum) { - Enumerators.push_back(DebugFactory.CreateEnumerator(Enum->getNameAsString(), + Enumerators.push_back(DebugFactory.CreateEnumerator(Enum->getNameAsCString(), Enum->getInitVal().getZExtValue())); } @@ -717,7 +711,6 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty, llvm::DIArray EltArray = DebugFactory.GetOrCreateArray(Enumerators.data(), Enumerators.size()); - std::string EnumName = Decl->getNameAsString(); SourceLocation DefLoc = Decl->getLocation(); llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(DefLoc); SourceManager &SM = M->getContext().getSourceManager(); @@ -735,11 +728,9 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty, llvm::DIType DbgTy = DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_enumeration_type, - Unit, EnumName, DefUnit, Line, + Unit, Decl->getNameAsCString(), DefUnit, Line, Size, Align, 0, 0, llvm::DIType(), EltArray); - - TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode(); return DbgTy; } @@ -797,11 +788,37 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty, 0, Size, Align, 0, 0, getOrCreateType(EltTy, Unit), SubscriptArray); - - TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode(); return DbgTy; } +llvm::DIType CGDebugInfo::CreateType(const LValueReferenceType *Ty, + llvm::DICompileUnit Unit) { + return CreatePointerLikeType(llvm::dwarf::DW_TAG_reference_type, + Ty, Ty->getPointeeType(), Unit); +} + +static QualType CanonicalizeTypeForDebugInfo(QualType T) { + switch (T->getTypeClass()) { + default: + return T; + case Type::TemplateSpecialization: + return cast<TemplateSpecializationType>(T)->desugar(); + case Type::TypeOfExpr: { + TypeOfExprType *Ty = cast<TypeOfExprType>(T); + return CanonicalizeTypeForDebugInfo(Ty->getUnderlyingExpr()->getType()); + } + case Type::TypeOf: + return cast<TypeOfType>(T)->getUnderlyingType(); + case Type::Decltype: + return cast<DecltypeType>(T)->getUnderlyingType(); + case Type::QualifiedName: + return cast<QualifiedNameType>(T)->getNamedType(); + case Type::SubstTemplateTypeParm: + return cast<SubstTemplateTypeParmType>(T)->getReplacementType(); + case Type::Elaborated: + return cast<ElaboratedType>(T)->getUnderlyingType(); + } +} /// getOrCreateType - Get the type from the cache or create a new /// one if necessary. @@ -810,6 +827,9 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, if (Ty.isNull()) return llvm::DIType(); + // Canonicalize the type. + Ty = CanonicalizeTypeForDebugInfo(Ty); + // Check for existing entry. std::map<void *, llvm::WeakVH>::iterator it = TypeCache.find(Ty.getAsOpaquePtr()); @@ -821,15 +841,17 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, // Otherwise create the type. llvm::DIType Res = CreateTypeNode(Ty, Unit); + + // And update the type cache. + TypeCache[Ty.getAsOpaquePtr()] = Res.getNode(); return Res; } -/// getOrCreateTypeNode - Get the type metadata node from the cache or create a -/// new one if necessary. +/// CreateTypeNode - Create a new debug type node. llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DICompileUnit Unit) { // Handle qualifiers, which recursively handles what they refer to. - if (Ty.hasQualifiers()) + if (Ty.hasLocalQualifiers()) return CreateQualifiedType(Ty, Unit); // Work out details of type. @@ -841,16 +863,13 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, #include "clang/AST/TypeNodes.def" assert(false && "Dependent types cannot show up in debug information"); - default: - case Type::LValueReference: - case Type::RValueReference: - case Type::Vector: + // FIXME: Handle these. case Type::ExtVector: + case Type::Vector: case Type::FixedWidthInt: - case Type::MemberPointer: - case Type::TemplateSpecialization: - case Type::QualifiedName: - // Unsupported types + return llvm::DIType(); + default: + assert(false && "Unhandled type class!"); return llvm::DIType(); case Type::ObjCObjectPointer: return CreateType(cast<ObjCObjectPointerType>(Ty), Unit); @@ -868,21 +887,14 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, case Type::FunctionProto: case Type::FunctionNoProto: return CreateType(cast<FunctionType>(Ty), Unit); - case Type::Elaborated: - return getOrCreateType(cast<ElaboratedType>(Ty)->getUnderlyingType(), - Unit); - case Type::ConstantArray: case Type::VariableArray: case Type::IncompleteArray: return CreateType(cast<ArrayType>(Ty), Unit); - case Type::TypeOfExpr: - return getOrCreateType(cast<TypeOfExprType>(Ty)->getUnderlyingExpr() - ->getType(), Unit); - case Type::TypeOf: - return getOrCreateType(cast<TypeOfType>(Ty)->getUnderlyingType(), Unit); - case Type::Decltype: - return getOrCreateType(cast<DecltypeType>(Ty)->getUnderlyingType(), Unit); + + case Type::LValueReference: + return CreateType(cast<LValueReferenceType>(Ty), Unit); + } } @@ -909,12 +921,8 @@ void CGDebugInfo::EmitFunctionStart(const char *Name, QualType FnType, getOrCreateType(FnType, Unit), Fn->hasInternalLinkage(), true/*definition*/); -#ifndef ATTACH_DEBUG_INFO_TO_AN_INSN - DebugFactory.InsertSubprogramStart(SP, Builder.GetInsertBlock()); -#endif - // Push function on region stack. - RegionStack.push_back(SP); + RegionStack.push_back(SP.getNode()); } @@ -936,31 +944,23 @@ void CGDebugInfo::EmitStopPoint(llvm::Function *Fn, CGBuilderTy &Builder) { llvm::DICompileUnit Unit = getOrCreateCompileUnit(CurLoc); PresumedLoc PLoc = SM.getPresumedLoc(CurLoc); -#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN - llvm::DIDescriptor DR = RegionStack.back(); + llvm::DIDescriptor DR(RegionStack.back()); llvm::DIScope DS = llvm::DIScope(DR.getNode()); llvm::DILocation DO(NULL); llvm::DILocation DL = DebugFactory.CreateLocation(PLoc.getLine(), PLoc.getColumn(), DS, DO); Builder.SetCurrentDebugLocation(DL.getNode()); -#else - DebugFactory.InsertStopPoint(Unit, PLoc.getLine(), PLoc.getColumn(), - Builder.GetInsertBlock()); -#endif } /// EmitRegionStart- Constructs the debug code for entering a declarative /// region - "llvm.dbg.region.start.". void CGDebugInfo::EmitRegionStart(llvm::Function *Fn, CGBuilderTy &Builder) { - llvm::DIDescriptor D; - if (!RegionStack.empty()) - D = RegionStack.back(); - D = DebugFactory.CreateLexicalBlock(D); - RegionStack.push_back(D); -#ifndef ATTACH_DEBUG_INFO_TO_AN_INSN - DebugFactory.InsertRegionStart(D, Builder.GetInsertBlock()); -#endif + llvm::DIDescriptor D = + DebugFactory.CreateLexicalBlock(RegionStack.empty() ? + llvm::DIDescriptor() : + llvm::DIDescriptor(RegionStack.back())); + RegionStack.push_back(D.getNode()); } /// EmitRegionEnd - Constructs the debug code for exiting a declarative @@ -971,9 +971,6 @@ void CGDebugInfo::EmitRegionEnd(llvm::Function *Fn, CGBuilderTy &Builder) { // Provide an region stop point. EmitStopPoint(Fn, Builder); -#ifndef ATTACH_DEBUG_INFO_TO_AN_INSN - DebugFactory.InsertRegionEnd(RegionStack.back(), Builder.GetInsertBlock()); -#endif RegionStack.pop_back(); } @@ -985,8 +982,8 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, // Do not emit variable debug information while generating optimized code. // The llvm optimizer and code generator are not yet ready to support // optimized code debugging. - const CompileOptions &CO = M->getCompileOpts(); - if (CO.OptimizationLevel) + const CodeGenOptions &CGO = M->getCodeGenOpts(); + if (CGO.OptimizationLevel) return; llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation()); @@ -1105,10 +1102,9 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); FieldSize = M->getContext().getTypeSize(FType); FieldAlign = Align*8; - std::string Name = Decl->getNameAsString(); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - Name, DefUnit, + Decl->getNameAsCString(), DefUnit, 0, FieldSize, FieldAlign, FieldOffset, 0, FieldTy); EltTys.push_back(FieldTy); @@ -1128,18 +1124,28 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, SourceManager &SM = M->getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); unsigned Line = 0; - if (!PLoc.isInvalid()) + unsigned Column = 0; + if (!PLoc.isInvalid()) { Line = PLoc.getLine(); - else + Column = PLoc.getColumn(); + } else { Unit = llvm::DICompileUnit(); - + } // Create the descriptor for the variable. llvm::DIVariable D = - DebugFactory.CreateVariable(Tag, RegionStack.back(),Decl->getNameAsString(), + DebugFactory.CreateVariable(Tag, llvm::DIDescriptor(RegionStack.back()), + Decl->getNameAsCString(), Unit, Line, Ty); // Insert an llvm.dbg.declare into the current block. - DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertBlock()); + llvm::Instruction *Call = + DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertBlock()); + + llvm::DIScope DS(RegionStack.back()); + llvm::DILocation DO(NULL); + llvm::DILocation DL = + DebugFactory.CreateLocation(Line, Column, DS, DO); + Builder.SetDebugLocation(Call, DL.getNode()); } /// EmitDeclare - Emit local variable declaration debug info. @@ -1152,8 +1158,8 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, // Do not emit variable debug information while generating optimized code. // The llvm optimizer and code generator are not yet ready to support // optimized code debugging. - const CompileOptions &CO = M->getCompileOpts(); - if (CO.OptimizationLevel || Builder.GetInsertBlock() == 0) + const CodeGenOptions &CGO = M->getCodeGenOpts(); + if (CGO.OptimizationLevel || Builder.GetInsertBlock() == 0) return; uint64_t XOffset = 0; @@ -1273,11 +1279,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); FieldSize = M->getContext().getTypeSize(FType); FieldAlign = Align*8; - std::string Name = Decl->getNameAsString(); XOffset = FieldOffset; FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - Name, DefUnit, + Decl->getNameAsCString(), DefUnit, 0, FieldSize, FieldAlign, FieldOffset, 0, FieldTy); EltTys.push_back(FieldTy); @@ -1330,11 +1335,18 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, // Create the descriptor for the variable. llvm::DIVariable D = - DebugFactory.CreateComplexVariable(Tag, RegionStack.back(), - Decl->getNameAsString(), Unit, Line, Ty, + DebugFactory.CreateComplexVariable(Tag, llvm::DIDescriptor(RegionStack.back()), + Decl->getNameAsCString(), Unit, Line, Ty, addr); // Insert an llvm.dbg.declare into the current block. - DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertPoint()); + llvm::Instruction *Call = + DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertPoint()); + + llvm::DIScope DS(RegionStack.back()); + llvm::DILocation DO(NULL); + llvm::DILocation DL = + DebugFactory.CreateLocation(Line, PLoc.getColumn(), DS, DO); + Builder.SetDebugLocation(Call, DL.getNode()); } void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *Decl, @@ -1362,21 +1374,12 @@ void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI, void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, const VarDecl *Decl) { - // Do not emit variable debug information while generating optimized code. - // The llvm optimizer and code generator are not yet ready to support - // optimized code debugging. - const CompileOptions &CO = M->getCompileOpts(); - if (CO.OptimizationLevel) - return; - // Create global variable debug descriptor. llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation()); SourceManager &SM = M->getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine(); - std::string Name = Var->getName(); - QualType T = Decl->getType(); if (T->isIncompleteArrayType()) { @@ -1389,9 +1392,9 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, T = M->getContext().getConstantArrayType(ET, ConstVal, ArrayType::Normal, 0); } - - DebugFactory.CreateGlobalVariable(getContext(Decl, Unit), - Name, Name, Name, Unit, LineNo, + const char *DeclName = Decl->getNameAsCString(); + DebugFactory.CreateGlobalVariable(getContext(Decl, Unit), DeclName, DeclName, + NULL, Unit, LineNo, getOrCreateType(T, Unit), Var->hasInternalLinkage(), true/*definition*/, Var); @@ -1406,7 +1409,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine(); - std::string Name = Decl->getNameAsString(); + const char *Name = Decl->getNameAsCString(); QualType T = M->getContext().getObjCInterfaceType(Decl); if (T->isIncompleteArrayType()) { diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index 2e44e09d2590..af86e2b263fd 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -56,7 +56,7 @@ class CGDebugInfo { bool BlockLiteralGenericSet; llvm::DIType BlockLiteralGeneric; - std::vector<llvm::DIDescriptor> RegionStack; + std::vector<llvm::TrackingVH<llvm::MDNode> > RegionStack; /// Helper functions for getOrCreateType. llvm::DIType CreateType(const BuiltinType *Ty, llvm::DICompileUnit U); @@ -73,7 +73,11 @@ class CGDebugInfo { llvm::DIType CreateType(const ObjCInterfaceType *Ty, llvm::DICompileUnit U); llvm::DIType CreateType(const EnumType *Ty, llvm::DICompileUnit U); llvm::DIType CreateType(const ArrayType *Ty, llvm::DICompileUnit U); + llvm::DIType CreateType(const LValueReferenceType *Ty, llvm::DICompileUnit U); + llvm::DIType CreatePointerLikeType(unsigned Tag, + const Type *Ty, QualType PointeeTy, + llvm::DICompileUnit U); public: CGDebugInfo(CodeGenModule *m); ~CGDebugInfo(); diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 2021ced31683..1d2040bae203 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -19,7 +19,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" -#include "clang/Frontend/CompileOptions.h" +#include "clang/CodeGen/CodeGenOptions.h" #include "llvm/GlobalVariable.h" #include "llvm/Intrinsics.h" #include "llvm/Target/TargetData.h" @@ -320,7 +320,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { // All constant structs and arrays should be global if // their initializer is constant and if the element type is POD. - if (CGM.getCompileOpts().MergeAllConstants) { + if (CGM.getCodeGenOpts().MergeAllConstants) { if (Ty.isConstant(getContext()) && (Ty->isArrayType() || Ty->isRecordType()) && (D.getInit() @@ -507,7 +507,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { // Handle CXX destruction of variables. QualType DtorTy(Ty); - if (const ArrayType *Array = DtorTy->getAs<ArrayType>()) + while (const ArrayType *Array = getContext().getAsArrayType(DtorTy)) DtorTy = getContext().getBaseElementType(Array); if (const RecordType *RT = DtorTy->getAs<RecordType>()) if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index d9dd70ac9e49..2a544c560931 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -267,6 +267,12 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { return EmitCXXBindTemporaryLValue(cast<CXXBindTemporaryExpr>(E)); case Expr::CXXExprWithTemporariesClass: return EmitCXXExprWithTemporariesLValue(cast<CXXExprWithTemporaries>(E)); + case Expr::CXXZeroInitValueExprClass: + return EmitNullInitializationLValue(cast<CXXZeroInitValueExpr>(E)); + case Expr::CXXDefaultArgExprClass: + return EmitLValue(cast<CXXDefaultArgExpr>(E)->getExpr()); + case Expr::CXXTypeidExprClass: + return EmitCXXTypeidLValue(cast<CXXTypeidExpr>(E)); case Expr::ObjCMessageExprClass: return EmitObjCMessageExprLValue(cast<ObjCMessageExpr>(E)); @@ -303,8 +309,6 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { case Expr::CXXReinterpretCastExprClass: case Expr::CXXConstCastExprClass: return EmitCastLValue(cast<CastExpr>(E)); - case Expr::CXXZeroInitValueExprClass: - return EmitNullInitializationLValue(cast<CXXZeroInitValueExpr>(E)); } } @@ -813,53 +817,53 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, } } +static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF, + const Expr *E, const VarDecl *VD) { + assert((VD->hasExternalStorage() || VD->isFileVarDecl()) && + "Var decl must have external storage or be a file var decl!"); + + llvm::Value *V = CGF.CGM.GetAddrOfGlobalVar(VD); + if (VD->getType()->isReferenceType()) + V = CGF.Builder.CreateLoad(V, "tmp"); + LValue LV = LValue::MakeAddr(V, CGF.MakeQualifiers(E->getType())); + setObjCGCLValueClass(CGF.getContext(), E, LV); + return LV; +} + LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { - const VarDecl *VD = dyn_cast<VarDecl>(E->getDecl()); - - if (VD && (VD->isBlockVarDecl() || isa<ParmVarDecl>(VD) || - isa<ImplicitParamDecl>(VD))) { - LValue LV; - bool NonGCable = VD->hasLocalStorage() && - !VD->hasAttr<BlocksAttr>(); - if (VD->hasExternalStorage()) { - llvm::Value *V = CGM.GetAddrOfGlobalVar(VD); - if (VD->getType()->isReferenceType()) - V = Builder.CreateLoad(V, "tmp"); - LV = LValue::MakeAddr(V, MakeQualifiers(E->getType())); - } else { - llvm::Value *V = LocalDeclMap[VD]; - assert(V && "DeclRefExpr not entered in LocalDeclMap?"); - - Qualifiers Quals = MakeQualifiers(E->getType()); - // local variables do not get their gc attribute set. - // local static? - if (NonGCable) Quals.removeObjCGCAttr(); - - if (VD->hasAttr<BlocksAttr>()) { - V = Builder.CreateStructGEP(V, 1, "forwarding"); - V = Builder.CreateLoad(V, false); - V = Builder.CreateStructGEP(V, getByRefValueLLVMField(VD), - VD->getNameAsString()); - } - if (VD->getType()->isReferenceType()) - V = Builder.CreateLoad(V, "tmp"); - LV = LValue::MakeAddr(V, Quals); + const NamedDecl *ND = E->getDecl(); + + if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) { + + // Check if this is a global variable. + if (VD->hasExternalStorage() || VD->isFileVarDecl()) + return EmitGlobalVarDeclLValue(*this, E, VD); + + bool NonGCable = VD->hasLocalStorage() && !VD->hasAttr<BlocksAttr>(); + + llvm::Value *V = LocalDeclMap[VD]; + assert(V && "DeclRefExpr not entered in LocalDeclMap?"); + + Qualifiers Quals = MakeQualifiers(E->getType()); + // local variables do not get their gc attribute set. + // local static? + if (NonGCable) Quals.removeObjCGCAttr(); + + if (VD->hasAttr<BlocksAttr>()) { + V = Builder.CreateStructGEP(V, 1, "forwarding"); + V = Builder.CreateLoad(V, false); + V = Builder.CreateStructGEP(V, getByRefValueLLVMField(VD), + VD->getNameAsString()); } - LValue::SetObjCNonGC(LV, NonGCable); - setObjCGCLValueClass(getContext(), E, LV); - return LV; - } - - if (VD && VD->isFileVarDecl()) { - llvm::Value *V = CGM.GetAddrOfGlobalVar(VD); if (VD->getType()->isReferenceType()) V = Builder.CreateLoad(V, "tmp"); - LValue LV = LValue::MakeAddr(V, MakeQualifiers(E->getType())); + LValue LV = LValue::MakeAddr(V, Quals); + LValue::SetObjCNonGC(LV, NonGCable); setObjCGCLValueClass(getContext(), E, LV); return LV; } - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(E->getDecl())) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { llvm::Value* V = CGM.GetAddrOfFunction(FD); if (!FD->hasPrototype()) { if (const FunctionProtoType *Proto = @@ -876,20 +880,15 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { return LValue::MakeAddr(V, MakeQualifiers(E->getType())); } - if (const ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(E->getDecl())){ - llvm::Value *V = LocalDeclMap[IPD]; - assert(V && "BlockVarDecl not entered in LocalDeclMap?"); - return LValue::MakeAddr(V, MakeQualifiers(E->getType())); - } - if (E->getQualifier()) { // FIXME: the qualifier check does not seem sufficient here - return EmitPointerToDataMemberLValue(E); + return EmitPointerToDataMemberLValue(cast<FieldDecl>(ND)); } - assert(0 && "Unimp declref"); - //an invalid LValue, but the assert will - //ensure that this point is never reached. + assert(false && "Unhandled DeclRefExpr"); + + // an invalid LValue, but the assert will + // ensure that this point is never reached. return LValue(); } @@ -924,13 +923,17 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { return LV; } case UnaryOperator::Real: - case UnaryOperator::Imag: + case UnaryOperator::Imag: { LValue LV = EmitLValue(E->getSubExpr()); unsigned Idx = E->getOpcode() == UnaryOperator::Imag; return LValue::MakeAddr(Builder.CreateStructGEP(LV.getAddress(), Idx, "idx"), MakeQualifiers(ExprTy)); } + case UnaryOperator::PreInc: + case UnaryOperator::PreDec: + return EmitUnsupportedLValue(E, "pre-inc/dec expression"); + } } LValue CodeGenFunction::EmitStringLiteralLValue(const StringLiteral *E) { @@ -1151,18 +1154,24 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { BaseQuals = BaseTy.getQualifiers(); } - FieldDecl *Field = dyn_cast<FieldDecl>(E->getMemberDecl()); - // FIXME: Handle non-field member expressions - assert(Field && "No code generation for non-field member references"); - LValue MemExpLV = EmitLValueForField(BaseValue, Field, isUnion, - BaseQuals.getCVRQualifiers()); - LValue::SetObjCNonGC(MemExpLV, isNonGC); - setObjCGCLValueClass(getContext(), E, MemExpLV); - return MemExpLV; + NamedDecl *ND = E->getMemberDecl(); + if (FieldDecl *Field = dyn_cast<FieldDecl>(ND)) { + LValue LV = EmitLValueForField(BaseValue, Field, isUnion, + BaseQuals.getCVRQualifiers()); + LValue::SetObjCNonGC(LV, isNonGC); + setObjCGCLValueClass(getContext(), E, LV); + return LV; + } + + if (VarDecl *VD = dyn_cast<VarDecl>(ND)) + return EmitGlobalVarDeclLValue(*this, E, VD); + + assert(false && "Unhandled member declaration!"); + return LValue(); } LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue, - FieldDecl* Field, + const FieldDecl* Field, unsigned CVRQualifiers) { CodeGenTypes::BitFieldInfo Info = CGM.getTypes().getBitFieldInfo(Field); @@ -1187,7 +1196,7 @@ LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue, } LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue, - FieldDecl* Field, + const FieldDecl* Field, bool isUnion, unsigned CVRQualifiers) { if (Field->isBitField()) @@ -1281,22 +1290,26 @@ CodeGenFunction::EmitConditionalOperatorLValue(const ConditionalOperator* E) { return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); } -/// EmitCastLValue - Casts are never lvalues. If a cast is needed by the code -/// generator in an lvalue context, then it must mean that we need the address -/// of an aggregate in order to access one of its fields. This can happen for -/// all the reasons that casts are permitted with aggregate result, including -/// noop aggregate casts, and cast from scalar to union. +/// EmitCastLValue - Casts are never lvalues unless that cast is a dynamic_cast. +/// If the cast is a dynamic_cast, we can have the usual lvalue result, +/// otherwise if a cast is needed by the code generator in an lvalue context, +/// then it must mean that we need the address of an aggregate in order to +/// access one of its fields. This can happen for all the reasons that casts +/// are permitted with aggregate result, including noop aggregate casts, and +/// cast from scalar to union. LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { switch (E->getCastKind()) { default: - // If this is an lvalue cast, treat it as a no-op. - // FIXME: We shouldn't need to check for this explicitly! - if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) - if (ICE->isLvalueCast()) - return EmitLValue(E->getSubExpr()); - - assert(0 && "Unhandled cast!"); - + return EmitUnsupportedLValue(E, "unexpected cast lvalue"); + + case CastExpr::CK_Dynamic: { + LValue LV = EmitLValue(E->getSubExpr()); + llvm::Value *V = LV.getAddress(); + const CXXDynamicCastExpr *DCE = cast<CXXDynamicCastExpr>(E); + return LValue::MakeAddr(EmitDynamicCast(V, DCE), + MakeQualifiers(E->getType())); + } + case CastExpr::CK_NoOp: case CastExpr::CK_ConstructorConversion: case CastExpr::CK_UserDefinedConversion: @@ -1320,13 +1333,24 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { return LValue::MakeAddr(Base, MakeQualifiers(E->getType())); } - case CastExpr::CK_ToUnion: { llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType())); EmitAnyExpr(E->getSubExpr(), Temp, false); return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); - } + } + case CastExpr::CK_BaseToDerived: { + return EmitUnsupportedLValue(E, "base-to-derived cast lvalue"); + } + case CastExpr::CK_BitCast: { + // This must be a reinterpret_cast (or c-style equivalent). + const ExplicitCastExpr *CE = cast<ExplicitCastExpr>(E); + + LValue LV = EmitLValue(E->getSubExpr()); + llvm::Value *V = Builder.CreateBitCast(LV.getAddress(), + ConvertType(CE->getTypeAsWritten())); + return LValue::MakeAddr(V, MakeQualifiers(E->getType())); + } } } @@ -1449,6 +1473,12 @@ LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) { } LValue +CodeGenFunction::EmitCXXTypeidLValue(const CXXTypeidExpr *E) { + llvm::Value *Temp = EmitCXXTypeidExpr(E); + return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); +} + +LValue CodeGenFunction::EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E) { LValue LV = EmitLValue(E->getSubExpr()); PushCXXTemporary(E->getTemporary(), LV.getAddress()); @@ -1526,19 +1556,18 @@ LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) { } -LValue CodeGenFunction::EmitPointerToDataMemberLValue(const DeclRefExpr *E) { - const FieldDecl *Field = cast<FieldDecl>(E->getDecl()); +LValue CodeGenFunction::EmitPointerToDataMemberLValue(const FieldDecl *Field) { const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Field->getDeclContext()); QualType NNSpecTy = getContext().getCanonicalType( getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(ClassDecl))); NNSpecTy = getContext().getPointerType(NNSpecTy); llvm::Value *V = llvm::Constant::getNullValue(ConvertType(NNSpecTy)); - LValue MemExpLV = EmitLValueForField(V, const_cast<FieldDecl*>(Field), - /*isUnion*/false, /*Qualifiers*/0); + LValue MemExpLV = EmitLValueForField(V, Field, /*isUnion=*/false, + /*Qualifiers=*/0); const llvm::Type *ResultType = ConvertType(getContext().getPointerDiffType()); V = Builder.CreatePtrToInt(MemExpLV.getAddress(), ResultType, "datamember"); - return LValue::MakeAddr(V, MakeQualifiers(E->getType())); + return LValue::MakeAddr(V, MakeQualifiers(Field->getType())); } RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType, @@ -1571,16 +1600,14 @@ RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType, LValue CodeGenFunction:: EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) { - llvm::Value *BaseV = EmitLValue(E->getLHS()).getAddress(); + llvm::Value *BaseV; if (E->getOpcode() == BinaryOperator::PtrMemI) - BaseV = Builder.CreateLoad(BaseV, "indir.ptr"); + BaseV = EmitScalarExpr(E->getLHS()); + else + BaseV = EmitLValue(E->getLHS()).getAddress(); const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(getLLVMContext()); BaseV = Builder.CreateBitCast(BaseV, i8Ty); - LValue RHSLV = EmitLValue(E->getRHS()); - llvm::Value *OffsetV = - EmitLoadOfLValue(RHSLV, E->getRHS()->getType()).getScalarVal(); - const llvm::Type* ResultType = ConvertType(getContext().getPointerDiffType()); - OffsetV = Builder.CreateBitCast(OffsetV, ResultType); + llvm::Value *OffsetV = EmitScalarExpr(E->getRHS()); llvm::Value *AddV = Builder.CreateInBoundsGEP(BaseV, OffsetV, "add.ptr"); QualType Ty = E->getRHS()->getType(); diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 901f867a5913..0e10368ab04e 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -114,6 +114,7 @@ public: void VisitCXXConstructExpr(const CXXConstructExpr *E); void VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E); void VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E); + void VisitCXXTypeidExpr(CXXTypeidExpr *E) { EmitAggLoadOfLValue(E); } void VisitVAArgExpr(VAArgExpr *E); diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 9145d92128a1..40b845dba050 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -262,7 +262,7 @@ class VISIBILITY_HIDDEN ConstStructBuilder { uint64_t NumBytes = AlignedElementOffsetInBytes - ElementOffsetInBytes; - const llvm::Type *Ty = llvm::Type::getInt8Ty(CGF->getLLVMContext()); + const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); if (NumBytes > 1) Ty = llvm::ArrayType::get(Ty, NumBytes); @@ -766,27 +766,21 @@ public: return llvm::ConstantExpr::getBitCast(C, ConvertType(E->getType())); } case Expr::PredefinedExprClass: { - // __func__/__FUNCTION__ -> "". __PRETTY_FUNCTION__ -> "top level". - std::string Str; - if (cast<PredefinedExpr>(E)->getIdentType() == - PredefinedExpr::PrettyFunction) - Str = "top level"; + unsigned Type = cast<PredefinedExpr>(E)->getIdentType(); + if (CGF) { + LValue Res = CGF->EmitPredefinedFunctionName(Type); + return cast<llvm::Constant>(Res.getAddress()); + } else if (Type == PredefinedExpr::PrettyFunction) { + return CGM.GetAddrOfConstantCString("top level", ".tmp"); + } - return CGM.GetAddrOfConstantCString(Str, ".tmp"); + return CGM.GetAddrOfConstantCString("", ".tmp"); } case Expr::AddrLabelExprClass: { assert(CGF && "Invalid address of label expression outside function."); -#ifndef USEINDIRECTBRANCH - unsigned id = - CGF->GetIDForAddrOfLabel(cast<AddrLabelExpr>(E)->getLabel()); - llvm::Constant *C = - llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), id); - return llvm::ConstantExpr::getIntToPtr(C, ConvertType(E->getType())); -#else llvm::Constant *Ptr = CGF->GetAddrOfLabel(cast<AddrLabelExpr>(E)->getLabel()); return llvm::ConstantExpr::getBitCast(Ptr, ConvertType(E->getType())); -#endif } case Expr::CallExprClass: { CallExpr* CE = cast<CallExpr>(E); @@ -827,9 +821,7 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, else Success = E->Evaluate(Result, Context); - if (Success) { - assert(!Result.HasSideEffects && - "Constant expr should not have any side effects!"); + if (Success && !Result.HasSideEffects) { switch (Result.Val.getKind()) { case APValue::Uninitialized: assert(0 && "Constant expressions should be initialized."); diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 96b58d8995ae..e9bbf35fcd8d 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -135,16 +135,8 @@ public: } Value *VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E); Value *VisitAddrLabelExpr(const AddrLabelExpr *E) { -#ifndef USEINDIRECTBRANCH - llvm::Value *V = - llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()), - CGF.GetIDForAddrOfLabel(E->getLabel())); - - return Builder.CreateIntToPtr(V, ConvertType(E->getType())); -#else llvm::Value *V = CGF.GetAddrOfLabel(E->getLabel()); return Builder.CreateBitCast(V, ConvertType(E->getType())); -#endif } // l-values. @@ -356,6 +348,9 @@ public: Value *VisitBinLOr (const BinaryOperator *E); Value *VisitBinComma (const BinaryOperator *E); + Value *VisitBinPtrMemD(const Expr *E) { return EmitLoadOfLValue(E); } + Value *VisitBinPtrMemI(const Expr *E) { return EmitLoadOfLValue(E); } + // Other Operators. Value *VisitBlockExpr(const BlockExpr *BE); Value *VisitConditionalOperator(const ConditionalOperator *CO); @@ -547,13 +542,6 @@ EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src, //===----------------------------------------------------------------------===// Value *ScalarExprEmitter::VisitExpr(Expr *E) { - if (const BinaryOperator *BExpr = dyn_cast<BinaryOperator>(E)) - if (BExpr->getOpcode() == BinaryOperator::PtrMemD) { - LValue LV = CGF.EmitPointerToDataMemberBinaryExpr(BExpr); - Value *InVal = CGF.EmitLoadOfLValue(LV, E->getType()).getScalarVal(); - return InVal; - } - CGF.ErrorUnsupported(E, "scalar expression"); if (E->getType()->isVoidType()) return 0; @@ -773,49 +761,20 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) { switch (Kind) { default: - // FIXME: Assert here. - // assert(0 && "Unhandled cast kind!"); + //return CGF.ErrorUnsupported(E, "type of cast"); break; + case CastExpr::CK_Unknown: - // FIXME: We should really assert here - Unknown casts should never get - // as far as to codegen. + //assert(0 && "Unknown cast kind!"); break; + case CastExpr::CK_BitCast: { Value *Src = Visit(const_cast<Expr*>(E)); return Builder.CreateBitCast(Src, ConvertType(DestTy)); } - case CastExpr::CK_ArrayToPointerDecay: { - assert(E->getType()->isArrayType() && - "Array to pointer decay must have array source type!"); - - Value *V = EmitLValue(E).getAddress(); // Bitfields can't be arrays. + case CastExpr::CK_NoOp: + return Visit(const_cast<Expr*>(E)); - // Note that VLA pointers are always decayed, so we don't need to do - // anything here. - if (!E->getType()->isVariableArrayType()) { - assert(isa<llvm::PointerType>(V->getType()) && "Expected pointer"); - assert(isa<llvm::ArrayType>(cast<llvm::PointerType>(V->getType()) - ->getElementType()) && - "Expected pointer to array"); - V = Builder.CreateStructGEP(V, 0, "arraydecay"); - } - - // The resultant pointer type can be implicitly casted to other pointer - // types as well (e.g. void*) and can be implicitly converted to integer. - const llvm::Type *DestLTy = ConvertType(DestTy); - if (V->getType() != DestLTy) { - if (isa<llvm::PointerType>(DestLTy)) - V = Builder.CreateBitCast(V, DestLTy, "ptrconv"); - else { - assert(isa<llvm::IntegerType>(DestLTy) && "Unknown array decay"); - V = Builder.CreatePtrToInt(V, DestLTy, "ptrconv"); - } - } - return V; - } - case CastExpr::CK_NullToMemberPointer: - return CGF.CGM.EmitNullConstant(DestTy); - case CastExpr::CK_DerivedToBase: { const RecordType *DerivedClassTy = E->getType()->getAs<PointerType>()->getPointeeType()->getAs<RecordType>(); @@ -841,6 +800,33 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) { return CGF.GetAddressCXXOfBaseClass(Src, DerivedClassDecl, BaseClassDecl, NullCheckValue); } + case CastExpr::CK_ToUnion: { + assert(0 && "Should be unreachable!"); + break; + } + case CastExpr::CK_ArrayToPointerDecay: { + assert(E->getType()->isArrayType() && + "Array to pointer decay must have array source type!"); + + Value *V = EmitLValue(E).getAddress(); // Bitfields can't be arrays. + + // Note that VLA pointers are always decayed, so we don't need to do + // anything here. + if (!E->getType()->isVariableArrayType()) { + assert(isa<llvm::PointerType>(V->getType()) && "Expected pointer"); + assert(isa<llvm::ArrayType>(cast<llvm::PointerType>(V->getType()) + ->getElementType()) && + "Expected pointer to array"); + V = Builder.CreateStructGEP(V, 0, "arraydecay"); + } + + return V; + } + case CastExpr::CK_FunctionToPointerDecay: + return EmitLValue(E).getAddress(); + + case CastExpr::CK_NullToMemberPointer: + return CGF.CGM.EmitNullConstant(DestTy); case CastExpr::CK_IntegralToPointer: { Value *Src = Visit(const_cast<Expr*>(E)); @@ -860,7 +846,40 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) { Value *Src = Visit(const_cast<Expr*>(E)); return Builder.CreatePtrToInt(Src, ConvertType(DestTy)); } - + + case CastExpr::CK_ToVoid: { + CGF.EmitAnyExpr(E, 0, false, true); + return 0; + } + + case CastExpr::CK_Dynamic: { + Value *V = Visit(const_cast<Expr*>(E)); + const CXXDynamicCastExpr *DCE = cast<CXXDynamicCastExpr>(CE); + return CGF.EmitDynamicCast(V, DCE); + } + + case CastExpr::CK_VectorSplat: { + const llvm::Type *DstTy = ConvertType(DestTy); + Value *Elt = Visit(const_cast<Expr*>(E)); + + // Insert the element in element zero of an undef vector + llvm::Value *UnV = llvm::UndefValue::get(DstTy); + llvm::Value *Idx = + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0); + UnV = Builder.CreateInsertElement(UnV, Elt, Idx, "tmp"); + + // Splat the element across to all elements + llvm::SmallVector<llvm::Constant*, 16> Args; + unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements(); + for (unsigned i = 0; i < NumElements; i++) + Args.push_back(llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), 0)); + + llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], NumElements); + llvm::Value *Yay = Builder.CreateShuffleVector(UnV, UnV, Mask, "splat"); + return Yay; + } + } // Handle cases where the source is an non-complex type. diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index f348bfffcb86..b431daa958f0 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -608,6 +608,8 @@ llvm::Constant *CGObjCGNU::GenerateIvarList( const llvm::SmallVectorImpl<llvm::Constant *> &IvarNames, const llvm::SmallVectorImpl<llvm::Constant *> &IvarTypes, const llvm::SmallVectorImpl<llvm::Constant *> &IvarOffsets) { + if (IvarNames.size() == 0) + return NULLPtr; // Get the method structure type. llvm::StructType *ObjCIvarTy = llvm::StructType::get(VMContext, PtrToInt8Ty, @@ -1189,8 +1191,8 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { Context.getObjCEncodingForType((*iter)->getType(), TypeStr); IvarTypes.push_back(MakeConstantString(TypeStr)); // Get the offset - uint64_t Offset = 0; uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, ClassDecl, *iter); + uint64_t Offset = BaseOffset; if (CGM.getContext().getLangOptions().ObjCNonFragileABI) { Offset = BaseOffset - superInstanceSize; } @@ -1301,7 +1303,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { } //Generate metaclass for class methods llvm::Constant *MetaClassStruct = GenerateClassStructure(NULLPtr, - NULLPtr, 0x12L, /*name*/"", 0, Zeros[0], GenerateIvarList( + NULLPtr, 0x12L, ClassName.c_str(), 0, Zeros[0], GenerateIvarList( empty, empty, empty), ClassMethodList, NULLPtr, NULLPtr, NULLPtr); // Generate the class structure diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 9b2f4a1faee7..4355e66feecd 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -991,6 +991,9 @@ private: /// for the given class. llvm::Value *EmitClassRef(CGBuilderTy &Builder, const ObjCInterfaceDecl *ID); + + /// EmitSuperClassRef - Emits reference to class's main metadata class. + llvm::Value *EmitSuperClassRef(const ObjCInterfaceDecl *ID); CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF, QualType ResultType, @@ -1167,6 +1170,9 @@ private: /// legacy messaging dispatch. llvm::DenseSet<Selector> NonLegacyDispatchMethods; + /// DefinedMetaClasses - List of defined meta-classes. + std::vector<llvm::GlobalValue*> DefinedMetaClasses; + /// LegacyDispatchedSelector - Returns true if SEL is not in the list of /// NonLegacyDispatchMethods; false otherwise. bool LegacyDispatchedSelector(Selector Sel); @@ -1485,8 +1491,13 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, llvm::Value *Super = CGF.Builder.CreateLoad(SuperPtr); Target = Super; } - } else { + } + else if (isCategoryImpl) Target = EmitClassRef(CGF.Builder, Class->getSuperClass()); + else { + llvm::Value *ClassPtr = EmitSuperClassRef(Class); + ClassPtr = CGF.Builder.CreateStructGEP(ClassPtr, 1); + Target = CGF.Builder.CreateLoad(ClassPtr); } // FIXME: We shouldn't need to do this cast, rectify the ASTContext and // ObjCTypes types. @@ -2051,11 +2062,22 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { Values[11] = EmitClassExtension(ID); llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassTy, Values); - - llvm::GlobalVariable *GV = - CreateMetadataVar("\01L_OBJC_CLASS_" + ClassName, Init, - "__OBJC,__class,regular,no_dead_strip", - 4, true); + std::string Name("\01L_OBJC_CLASS_"); + Name += ClassName; + const char *Section = "__OBJC,__class,regular,no_dead_strip"; + // Check for a forward reference. + llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name); + if (GV) { + assert(GV->getType()->getElementType() == ObjCTypes.ClassTy && + "Forward metaclass reference has incorrect type."); + GV->setLinkage(llvm::GlobalValue::InternalLinkage); + GV->setInitializer(Init); + GV->setSection(Section); + GV->setAlignment(4); + CGM.AddUsedGlobal(GV); + } + else + GV = CreateMetadataVar(Name, Init, Section, 4, true); DefinedClasses.push_back(GV); } @@ -2154,6 +2176,22 @@ llvm::Constant *CGObjCMac::EmitMetaClassRef(const ObjCInterfaceDecl *ID) { } } +llvm::Value *CGObjCMac::EmitSuperClassRef(const ObjCInterfaceDecl *ID) { + std::string Name = "\01L_OBJC_CLASS_" + ID->getNameAsString(); + + if (llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name, + true)) { + assert(GV->getType()->getElementType() == ObjCTypes.ClassTy && + "Forward class metadata reference has incorrect type."); + return GV; + } else { + return new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassTy, false, + llvm::GlobalValue::ExternalLinkage, + 0, + Name); + } +} + /* struct objc_class_ext { uint32_t size; @@ -4095,6 +4133,25 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() { AddModuleClassList(DefinedClasses, "\01L_OBJC_LABEL_CLASS_$", "__DATA, __objc_classlist, regular, no_dead_strip"); + + bool hasWeakImport = false; + for (unsigned i = 0; i < DefinedClasses.size(); i++) { + llvm::GlobalValue *IMPLGV = DefinedClasses[i]; + if (IMPLGV->getLinkage() != llvm::GlobalValue::ExternalWeakLinkage) + continue; + IMPLGV->setLinkage(llvm::GlobalValue::ExternalLinkage); + hasWeakImport = true; + } + + if (hasWeakImport) { + for (unsigned i = 0; i < DefinedMetaClasses.size(); i++) { + llvm::GlobalValue *IMPLGV = DefinedMetaClasses[i]; + if (IMPLGV->getLinkage() != llvm::GlobalValue::ExternalWeakLinkage) + continue; + IMPLGV->setLinkage(llvm::GlobalValue::ExternalLinkage); + } + } + AddModuleClassList(DefinedNonLazyClasses, "\01L_OBJC_LABEL_NONLAZY_CLASS_$", "__DATA, __objc_nlclslist, regular, no_dead_strip"); @@ -4384,6 +4441,8 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { std::string SuperClassName = ObjCMetaClassName + ID->getClassInterface()->getSuperClass()->getNameAsString(); SuperClassGV = GetClassGlobal(SuperClassName); + if (ID->getClassInterface()->getSuperClass()->hasAttr<WeakImportAttr>()) + SuperClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); } llvm::GlobalVariable *CLASS_RO_GV = BuildClassRoTInitializer(flags, InstanceStart, @@ -4392,6 +4451,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { llvm::GlobalVariable *MetaTClass = BuildClassMetaData(TClassName, IsAGV, SuperClassGV, CLASS_RO_GV, classIsHidden); + DefinedMetaClasses.push_back(MetaTClass); // Metadata for the class flags = CLS; @@ -4409,6 +4469,8 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { std::string RootClassName = ID->getClassInterface()->getSuperClass()->getNameAsString(); SuperClassGV = GetClassGlobal(ObjCClassName + RootClassName); + if (ID->getClassInterface()->getSuperClass()->hasAttr<WeakImportAttr>()) + SuperClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); } GetClassSizeInfo(ID, InstanceStart, InstanceSize); CLASS_RO_GV = BuildClassRoTInitializer(flags, @@ -4489,6 +4551,9 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { Values[0] = GetClassName(OCD->getIdentifier()); // meta-class entry symbol llvm::GlobalVariable *ClassGV = GetClassGlobal(ExtClassName); + if (Interface->hasAttr<WeakImportAttr>()) + ClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); + Values[1] = ClassGV; std::vector<llvm::Constant*> Methods; std::string MethodListName(Prefix); @@ -5178,6 +5243,12 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder, /// decl. llvm::Value *CGObjCNonFragileABIMac::GetClass(CGBuilderTy &Builder, const ObjCInterfaceDecl *ID) { + if (ID->hasAttr<WeakImportAttr>()) { + std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString()); + llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName); + ClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); + } + return EmitClassRef(Builder, ID); } diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index 7baf69d87689..8e0864b8dd83 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -208,7 +208,11 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) { Align = 1; } } - + if (!Align) { + assert((D->field_begin() == D->field_end()) && "LayoutUnion - Align 0"); + Align = 1; + } + // Append tail padding. if (Layout.getSize() / 8 > Size) AppendPadding(Layout.getSize() / 8, Align); diff --git a/lib/CodeGen/CGRtti.cpp b/lib/CodeGen/CGRtti.cpp index 7af15f0a8ca4..e18843d5cf3f 100644 --- a/lib/CodeGen/CGRtti.cpp +++ b/lib/CodeGen/CGRtti.cpp @@ -11,36 +11,378 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/Type.h" +#include "clang/AST/RecordLayout.h" #include "CodeGenModule.h" using namespace clang; using namespace CodeGen; +class RttiBuilder { + CodeGenModule &CGM; // Per-module state. + llvm::LLVMContext &VMContext; + const llvm::Type *Int8PtrTy; + llvm::SmallSet<const CXXRecordDecl *, 16> SeenVBase; + llvm::SmallSet<const CXXRecordDecl *, 32> SeenBase; +public: + RttiBuilder(CodeGenModule &cgm) + : CGM(cgm), VMContext(cgm.getModule().getContext()), + Int8PtrTy(llvm::Type::getInt8PtrTy(VMContext)) { } + + /// BuildVtableRef - Build a reference to a vtable. + llvm::Constant *BuildVtableRef(const char *Name) { + // Build a descriptor for Name + llvm::Constant *GV = CGM.getModule().getGlobalVariable(Name); + if (GV) + GV = llvm::ConstantExpr::getBitCast(GV, + llvm::PointerType::get(Int8PtrTy, 0)); + else { + llvm::GlobalVariable::LinkageTypes linktype; + linktype = llvm::GlobalValue::ExternalLinkage; + GV = new llvm::GlobalVariable(CGM.getModule(), Int8PtrTy, + true, linktype, 0, Name); + } + llvm::Constant *C; + C = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), 2); + C = llvm::ConstantExpr::getInBoundsGetElementPtr(GV, &C, 1); + return llvm::ConstantExpr::getBitCast(C, Int8PtrTy); + } + + llvm::Constant *BuildName(QualType Ty, bool Hidden) { + llvm::SmallString<256> OutName; + llvm::raw_svector_ostream Out(OutName); + mangleCXXRttiName(CGM.getMangleContext(), Ty, Out); + + llvm::GlobalVariable::LinkageTypes linktype; + linktype = llvm::GlobalValue::LinkOnceODRLinkage; + + llvm::Constant *C; + C = llvm::ConstantArray::get(VMContext, Out.str().substr(4)); + + llvm::GlobalVariable * GV = new llvm::GlobalVariable(CGM.getModule(), + C->getType(), + true, linktype, C, + Out.str()); + if (Hidden) + GV->setVisibility(llvm::GlobalVariable::HiddenVisibility); + return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); + }; + + /// - BuildFlags - Build a psABI __flags value for __vmi_class_type_info. + llvm::Constant *BuildFlags(int f) { + return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), f); + } + + /// BuildBaseCount - Build a psABI __base_count value for + /// __vmi_class_type_info. + llvm::Constant *BuildBaseCount(unsigned c) { + return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), c); + } + + llvm::Constant *BuildTypeRef(QualType Ty) { + llvm::Constant *C; + + if (!CGM.getContext().getLangOptions().Rtti) + return llvm::Constant::getNullValue(Int8PtrTy); + + llvm::SmallString<256> OutName; + llvm::raw_svector_ostream Out(OutName); + mangleCXXRtti(CGM.getMangleContext(), Ty, Out); + + C = CGM.getModule().getGlobalVariable(Out.str()); + if (C) + return llvm::ConstantExpr::getBitCast(C, Int8PtrTy); + + llvm::GlobalVariable::LinkageTypes linktype; + linktype = llvm::GlobalValue::ExternalLinkage;; + + C = new llvm::GlobalVariable(CGM.getModule(), Int8PtrTy, true, linktype, + 0, Out.str()); + return llvm::ConstantExpr::getBitCast(C, Int8PtrTy); + } + + llvm::Constant *Buildclass_type_infoRef(const CXXRecordDecl *RD) { + return BuildTypeRef(CGM.getContext().getTagDeclType(RD)); + } + + /// CalculateFlags - Calculate the flags for the __vmi_class_type_info + /// datastructure. 1 for non-diamond repeated inheritance, 2 for a dimond + /// shaped class. + int CalculateFlags(const CXXRecordDecl*RD) { + int flags = 0; + if (SeenBase.count(RD)) + flags |= 1; + else + SeenBase.insert(RD); + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + if (i->isVirtual()) { + if (SeenVBase.count(Base)) + flags |= 2; + else + SeenVBase.insert(Base); + } + flags |= CalculateFlags(Base); + } + return flags; + } + + bool SimpleInheritance(const CXXRecordDecl *RD) { + if (RD->getNumBases() != 1) + return false; + CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(); + if (i->isVirtual()) + return false; + if (i->getAccessSpecifier() != AS_public) + return false; + + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + if (Layout.getBaseClassOffset(Base) != 0) + return false; + return true; + } + + llvm::Constant *finish(std::vector<llvm::Constant *> &info, + llvm::GlobalVariable *GV, + llvm::StringRef Name, bool Hidden) { + llvm::GlobalVariable::LinkageTypes linktype; + linktype = llvm::GlobalValue::LinkOnceODRLinkage; + + llvm::Constant *C; + C = llvm::ConstantStruct::get(VMContext, &info[0], info.size(), false); + + if (GV == 0) + GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, + linktype, C, Name); + else { + llvm::GlobalVariable *OGV = GV; + GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, + linktype, C, Name); + GV->takeName(OGV); + llvm::Constant *NewPtr = llvm::ConstantExpr::getBitCast(GV, + OGV->getType()); + OGV->replaceAllUsesWith(NewPtr); + OGV->eraseFromParent(); + } + if (Hidden) + GV->setVisibility(llvm::GlobalVariable::HiddenVisibility); + return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); + } + + + llvm::Constant *Buildclass_type_info(const CXXRecordDecl *RD) { + if (!CGM.getContext().getLangOptions().Rtti) + return llvm::Constant::getNullValue(Int8PtrTy); + + llvm::Constant *C; + + llvm::SmallString<256> OutName; + llvm::raw_svector_ostream Out(OutName); + mangleCXXRtti(CGM.getMangleContext(), CGM.getContext().getTagDeclType(RD), + Out); + + llvm::GlobalVariable *GV; + GV = CGM.getModule().getGlobalVariable(Out.str()); + if (GV && !GV->isDeclaration()) + return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); + + std::vector<llvm::Constant *> info; + + bool Hidden = CGM.getDeclVisibilityMode(RD) == LangOptions::Hidden; + + bool simple = false; + if (RD->getNumBases() == 0) + C = BuildVtableRef("_ZTVN10__cxxabiv117__class_type_infoE"); + else if (SimpleInheritance(RD)) { + simple = true; + C = BuildVtableRef("_ZTVN10__cxxabiv120__si_class_type_infoE"); + } else + C = BuildVtableRef("_ZTVN10__cxxabiv121__vmi_class_type_infoE"); + info.push_back(C); + info.push_back(BuildName(CGM.getContext().getTagDeclType(RD), Hidden)); + + // If we have no bases, there are no more fields. + if (RD->getNumBases()) { + if (!simple) { + info.push_back(BuildFlags(CalculateFlags(RD))); + info.push_back(BuildBaseCount(RD->getNumBases())); + } + + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + info.push_back(CGM.GenerateRttiRef(Base)); + if (simple) + break; + int64_t offset; + if (!i->isVirtual()) + offset = Layout.getBaseClassOffset(Base)/8; + else + offset = CGM.getVtableInfo().getVirtualBaseOffsetIndex(RD, Base); + offset <<= 8; + // Now set the flags. + offset += i->isVirtual() ? 1 : 0;; + offset += i->getAccessSpecifier() == AS_public ? 2 : 0; + const llvm::Type *LongTy = + CGM.getTypes().ConvertType(CGM.getContext().LongTy); + C = llvm::ConstantInt::get(LongTy, offset); + info.push_back(C); + } + } + + return finish(info, GV, Out.str(), Hidden); + } + + /// - BuildFlags - Build a __flags value for __pbase_type_info. + llvm::Constant *BuildInt(int f) { + return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), f); + } + + llvm::Constant *BuildType2(QualType Ty) { + if (const RecordType *RT = Ty.getTypePtr()->getAs<RecordType>()) + if (const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl())) + return Buildclass_type_info(RD); + return BuildType(Ty); + } + + llvm::Constant *BuildPointerType(QualType Ty) { + llvm::Constant *C; + + llvm::SmallString<256> OutName; + llvm::raw_svector_ostream Out(OutName); + mangleCXXRtti(CGM.getMangleContext(), Ty, Out); + + llvm::GlobalVariable *GV; + GV = CGM.getModule().getGlobalVariable(Out.str()); + if (GV && !GV->isDeclaration()) + return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); + + std::vector<llvm::Constant *> info; + + // FIXME: pointer to hidden should be hidden, we should be able to + // grab a bit off the type for this. + bool Hidden = false; + + QualType PTy = Ty->getPointeeType(); + QualType BTy; + bool PtrMem = false; + if (const MemberPointerType *MPT = dyn_cast<MemberPointerType>(Ty)) { + PtrMem = true; + BTy = QualType(MPT->getClass(), 0); + PTy = MPT->getPointeeType(); + } + + if (PtrMem) + C = BuildVtableRef("_ZTVN10__cxxabiv129__pointer_to_member_type_infoE"); + else + C = BuildVtableRef("_ZTVN10__cxxabiv119__pointer_type_infoE"); + info.push_back(C); + info.push_back(BuildName(Ty, Hidden)); + Qualifiers Q = PTy.getQualifiers(); + PTy = CGM.getContext().getCanonicalType(PTy).getUnqualifiedType(); + int flags = 0; + flags += Q.hasConst() ? 0x1 : 0; + flags += Q.hasVolatile() ? 0x2 : 0; + flags += Q.hasRestrict() ? 0x4 : 0; + flags += Ty.getTypePtr()->isIncompleteType() ? 0x8 : 0; + if (PtrMem && BTy.getTypePtr()->isIncompleteType()) + flags += 0x10; + + info.push_back(BuildInt(flags)); + info.push_back(BuildInt(0)); + info.push_back(BuildType2(PTy)); + + if (PtrMem) + info.push_back(BuildType2(BTy)); + + return finish(info, GV, Out.str(), true); + } + + llvm::Constant *BuildSimpleType(QualType Ty, const char *vtbl) { + llvm::Constant *C; + + llvm::SmallString<256> OutName; + llvm::raw_svector_ostream Out(OutName); + mangleCXXRtti(CGM.getMangleContext(), Ty, Out); + + llvm::GlobalVariable *GV; + GV = CGM.getModule().getGlobalVariable(Out.str()); + if (GV && !GV->isDeclaration()) + return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); + + std::vector<llvm::Constant *> info; + + // FIXME: pointer to hidden should be hidden, we should be able to + // grab a bit off the type for this. + bool Hidden = false; + + C = BuildVtableRef(vtbl); + info.push_back(C); + info.push_back(BuildName(Ty, Hidden)); + + return finish(info, GV, Out.str(), true); + } + + llvm::Constant *BuildType(QualType Ty) { + const clang::Type &Type + = *CGM.getContext().getCanonicalType(Ty).getTypePtr(); + switch (Type.getTypeClass()) { + default: { + assert(0 && "typeid expression"); + return llvm::Constant::getNullValue(Int8PtrTy); + } + + case Type::Builtin: { + // We expect all type_info objects for builtin types to be in the library. + return BuildTypeRef(Ty); + } + + case Type::Pointer: { + QualType PTy = Ty->getPointeeType(); + Qualifiers Q = PTy.getQualifiers(); + Q.removeConst(); + // T* and const T* for all builtin types T are expected in the library. + if (isa<BuiltinType>(PTy) && Q.empty()) + return BuildTypeRef(Ty); + + return BuildPointerType(Ty); + } + case Type::MemberPointer: + return BuildPointerType(Ty); + case Type::FunctionProto: + case Type::FunctionNoProto: + return BuildSimpleType(Ty, "_ZTVN10__cxxabiv120__function_type_infoE"); + case Type::ConstantArray: + case Type::IncompleteArray: + case Type::VariableArray: + case Type::Vector: + case Type::ExtVector: + return BuildSimpleType(Ty, "_ZTVN10__cxxabiv117__array_type_infoE"); + case Type::Enum: + return BuildSimpleType(Ty, "_ZTVN10__cxxabiv116__enum_type_infoE"); + } + } +}; + +llvm::Constant *CodeGenModule::GenerateRttiRef(const CXXRecordDecl *RD) { + RttiBuilder b(*this); + + return b.Buildclass_type_infoRef(RD); +} + llvm::Constant *CodeGenModule::GenerateRtti(const CXXRecordDecl *RD) { - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); - - if (!getContext().getLangOptions().Rtti) - return llvm::Constant::getNullValue(Int8PtrTy); - - llvm::SmallString<256> OutName; - llvm::raw_svector_ostream Out(OutName); - mangleCXXRtti(getMangleContext(), Context.getTagDeclType(RD), Out); - - llvm::GlobalVariable::LinkageTypes linktype; - linktype = llvm::GlobalValue::WeakAnyLinkage; - std::vector<llvm::Constant *> info; - // assert(0 && "FIXME: implement rtti descriptor"); - // FIXME: descriptor - info.push_back(llvm::Constant::getNullValue(Int8PtrTy)); - // assert(0 && "FIXME: implement rtti ts"); - // FIXME: TS - info.push_back(llvm::Constant::getNullValue(Int8PtrTy)); - - llvm::Constant *C; - llvm::ArrayType *type = llvm::ArrayType::get(Int8PtrTy, info.size()); - C = llvm::ConstantArray::get(type, info); - llvm::Constant *Rtti = - new llvm::GlobalVariable(getModule(), type, true, linktype, C, - Out.str()); - Rtti = llvm::ConstantExpr::getBitCast(Rtti, Int8PtrTy); - return Rtti; + RttiBuilder b(*this); + + return b.Buildclass_type_info(RD); +} + +llvm::Constant *CodeGenModule::GenerateRttiNonClass(QualType Ty) { + RttiBuilder b(*this); + + return b.BuildType(Ty); } diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 9126c2c99cdf..b6d7b3990452 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -148,13 +148,8 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, CGDebugInfo *DI = getDebugInfo(); if (DI) { -#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN DI->setLocation(S.getLBracLoc()); DI->EmitRegionStart(CurFn, Builder); -#else - EnsureInsertPoint(); - DI->setLocation(S.getLBracLoc()); -#endif } // Keep track of the current cleanup stack depth. @@ -167,13 +162,8 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, EmitStmt(*I); if (DI) { -#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN DI->setLocation(S.getLBracLoc()); DI->EmitRegionEnd(CurFn, Builder); -#else - EnsureInsertPoint(); - DI->setLocation(S.getLBracLoc()); -#endif } RValue RV; @@ -284,16 +274,9 @@ void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) { void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) { - // Emit initial switch which will be patched up later by - // EmitIndirectSwitches(). We need a default dest, so we use the - // current BB, but this is overwritten. -#ifndef USEINDIRECTBRANCH - llvm::Value *V = Builder.CreatePtrToInt(EmitScalarExpr(S.getTarget()), - llvm::Type::getInt32Ty(VMContext), -#else + // Ensure that we have an i8* for our PHI node. llvm::Value *V = Builder.CreateBitCast(EmitScalarExpr(S.getTarget()), llvm::Type::getInt8PtrTy(VMContext), -#endif "addr"); llvm::BasicBlock *CurBB = Builder.GetInsertBlock(); @@ -491,13 +474,11 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) { BreakContinueStack.push_back(BreakContinue(AfterFor, ContinueBlock)); // If the condition is true, execute the body of the for stmt. -#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN CGDebugInfo *DI = getDebugInfo(); if (DI) { DI->setLocation(S.getSourceRange().getBegin()); DI->EmitRegionStart(CurFn, Builder); } -#endif EmitStmt(S.getBody()); BreakContinueStack.pop_back(); @@ -510,12 +491,10 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) { // Finally, branch back up to the condition for the next iteration. EmitBranch(CondBlock); -#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN if (DI) { DI->setLocation(S.getSourceRange().getEnd()); DI->EmitRegionEnd(CurFn, Builder); } -#endif // Emit the fall-through block. EmitBlock(AfterFor, true); @@ -758,7 +737,7 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) { } static std::string -SimplifyConstraint(const char *Constraint, TargetInfo &Target, +SimplifyConstraint(const char *Constraint, const TargetInfo &Target, llvm::SmallVectorImpl<TargetInfo::ConstraintInfo> *OutCons=0) { std::string Result; diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index e2e11478de26..4c97a9bdeebf 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -15,6 +15,7 @@ #include "CodeGenFunction.h" #include "clang/AST/RecordLayout.h" +#include <cstdio> using namespace clang; using namespace CodeGen; @@ -29,6 +30,11 @@ private: llvm::Type *Ptr8Ty; /// Class - The most derived class that this vtable is being built for. const CXXRecordDecl *Class; + /// LayoutClass - The most derived class used for virtual base layout + /// information. + const CXXRecordDecl *LayoutClass; + /// LayoutOffset - The offset for Class in LayoutClass. + uint64_t LayoutOffset; /// BLayout - Layout for the most derived class that this vtable is being /// built for. const ASTRecordLayout &BLayout; @@ -39,38 +45,45 @@ private: CodeGenModule &CGM; // Per-module state. /// Index - Maps a method decl into a vtable index. Useful for virtual /// dispatch codegen. - llvm::DenseMap<const CXXMethodDecl *, Index_t> Index; - llvm::DenseMap<const CXXMethodDecl *, Index_t> VCall; - llvm::DenseMap<const CXXMethodDecl *, Index_t> VCallOffset; + llvm::DenseMap<GlobalDecl, Index_t> Index; + llvm::DenseMap<GlobalDecl, Index_t> VCall; + llvm::DenseMap<GlobalDecl, Index_t> VCallOffset; + // This is the offset to the nearest virtual base + llvm::DenseMap<GlobalDecl, Index_t> NonVirtualOffset; llvm::DenseMap<const CXXRecordDecl *, Index_t> VBIndex; - typedef llvm::DenseMap<const CXXMethodDecl *, int> Pures_t; + typedef llvm::DenseMap<GlobalDecl, int> Pures_t; Pures_t Pures; typedef std::pair<Index_t, Index_t> CallOffset; - typedef llvm::DenseMap<const CXXMethodDecl *, CallOffset> Thunks_t; + typedef llvm::DenseMap<GlobalDecl, CallOffset> Thunks_t; Thunks_t Thunks; - typedef llvm::DenseMap<const CXXMethodDecl *, + typedef llvm::DenseMap<GlobalDecl, std::pair<std::pair<CallOffset, CallOffset>, CanQualType> > CovariantThunks_t; CovariantThunks_t CovariantThunks; std::vector<Index_t> VCalls; + + typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t; + // CtorVtable - Used to hold the AddressPoints (offsets) into the built vtable + // for use in computing the initializers for the VTT. + llvm::DenseMap<CtorVtable_t, int64_t> &AddressPoints; + typedef CXXRecordDecl::method_iterator method_iter; // FIXME: Linkage should follow vtable const bool Extern; const uint32_t LLVMPointerWidth; Index_t extra; - int CurrentVBaseOffset; typedef std::vector<std::pair<const CXXRecordDecl *, int64_t> > Path_t; llvm::Constant *cxa_pure; public: - VtableBuilder(std::vector<llvm::Constant *> &meth, - const CXXRecordDecl *c, - CodeGenModule &cgm) - : methods(meth), Class(c), BLayout(cgm.getContext().getASTRecordLayout(c)), - rtti(cgm.GenerateRtti(c)), VMContext(cgm.getModule().getContext()), - CGM(cgm), Extern(true), - LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)), - CurrentVBaseOffset(0) { + VtableBuilder(std::vector<llvm::Constant *> &meth, const CXXRecordDecl *c, + const CXXRecordDecl *l, uint64_t lo, CodeGenModule &cgm) + : methods(meth), Class(c), LayoutClass(l), LayoutOffset(lo), + BLayout(cgm.getContext().getASTRecordLayout(l)), + rtti(cgm.GenerateRttiRef(c)), VMContext(cgm.getModule().getContext()), + CGM(cgm), AddressPoints(*new llvm::DenseMap<CtorVtable_t, int64_t>), + Extern(true), + LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) { Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); // Calculate pointer for ___cxa_pure_virtual. @@ -81,10 +94,13 @@ public: cxa_pure = wrap(CGM.CreateRuntimeFunction(FTy, "__cxa_pure_virtual")); } - llvm::DenseMap<const CXXMethodDecl *, Index_t> &getIndex() { return Index; } + llvm::DenseMap<GlobalDecl, Index_t> &getIndex() { return Index; } llvm::DenseMap<const CXXRecordDecl *, Index_t> &getVBIndex() { return VBIndex; } + llvm::DenseMap<CtorVtable_t, int64_t> *getAddressPoints() + { return &AddressPoints; } + llvm::Constant *wrap(Index_t i) { llvm::Constant *m; m = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), i); @@ -95,8 +111,8 @@ public: return llvm::ConstantExpr::getBitCast(m, Ptr8Ty); } -#define D1(x) -//#define D1(X) do { if (getenv("DEBUG")) { X; } } while (0) +//#define D1(x) +#define D1(X) do { if (getenv("DEBUG")) { X; } } while (0) void GenerateVBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset, bool updateVBIndex, Index_t current_vbindex) { @@ -189,9 +205,11 @@ public: return 0; } - bool OverrideMethod(const CXXMethodDecl *MD, llvm::Constant *m, + bool OverrideMethod(GlobalDecl GD, llvm::Constant *m, bool MorallyVirtual, Index_t OverrideOffset, - Index_t Offset) { + Index_t Offset, int64_t CurrentVBaseOffset) { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + const bool isPure = MD->isPure(); typedef CXXMethodDecl::method_iterator meth_iter; // FIXME: Should OverrideOffset's be Offset? @@ -204,9 +222,16 @@ public: for (meth_iter mi = MD->begin_overridden_methods(), e = MD->end_overridden_methods(); mi != e; ++mi) { + GlobalDecl OGD; + const CXXMethodDecl *OMD = *mi; + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(OMD)) + OGD = GlobalDecl(DD, GD.getDtorType()); + else + OGD = OMD; + llvm::Constant *om; - om = CGM.GetAddrOfFunction(OMD, Ptr8Ty); + om = WrapAddrOf(OGD); om = llvm::ConstantExpr::getBitCast(om, Ptr8Ty); for (Index_t i = 0, e = submethods.size(); @@ -229,57 +254,60 @@ public: Index_t nv = getNVOffset(oret, ret)/8; ReturnOffset = std::make_pair(nv, getVbaseOffset(oret, ret)); } - Index[MD] = i; + Index[GD] = i; submethods[i] = m; if (isPure) - Pures[MD] = 1; - Pures.erase(OMD); - Thunks.erase(OMD); - if (MorallyVirtual) { - Index_t &idx = VCall[OMD]; + Pures[GD] = 1; + Pures.erase(OGD); + Thunks.erase(OGD); + if (MorallyVirtual || VCall.count(OGD)) { + Index_t &idx = VCall[OGD]; if (idx == 0) { - VCallOffset[MD] = OverrideOffset/8; + NonVirtualOffset[GD] = -OverrideOffset/8 + CurrentVBaseOffset/8; + VCallOffset[GD] = OverrideOffset/8; idx = VCalls.size()+1; VCalls.push_back(0); D1(printf(" vcall for %s at %d with delta %d most derived %s\n", - MD->getNameAsCString(), - (int)-VCalls.size()-3, (int)VCallOffset[MD], - Class->getNameAsCString())); + MD->getNameAsString().c_str(), (int)-idx-3, + (int)VCalls[idx-1], Class->getNameAsCString())); } else { - VCallOffset[MD] = VCallOffset[OMD]; - VCalls[idx-1] = -VCallOffset[OMD] + OverrideOffset/8; + NonVirtualOffset[GD] = NonVirtualOffset[OGD]; + VCallOffset[GD] = VCallOffset[OGD]; + VCalls[idx-1] = -VCallOffset[OGD] + OverrideOffset/8; D1(printf(" vcall patch for %s at %d with delta %d most derived %s\n", - MD->getNameAsCString(), - (int)-VCalls.size()-3, (int)VCallOffset[MD], - Class->getNameAsCString())); + MD->getNameAsString().c_str(), (int)-idx-3, + (int)VCalls[idx-1], Class->getNameAsCString())); } - VCall[MD] = idx; - CallOffset ThisOffset; - ThisOffset = std::make_pair(CurrentVBaseOffset/8 - Offset/8, - -((idx+extra+2)*LLVMPointerWidth/8)); + VCall[GD] = idx; + int64_t O = NonVirtualOffset[GD]; + int v = -((idx+extra+2)*LLVMPointerWidth/8); + // Optimize out virtual adjustments of 0. + if (VCalls[idx-1] == 0) + v = 0; + CallOffset ThisOffset = std::make_pair(O, v); // FIXME: Do we always have to build a covariant thunk to save oret, // which is the containing virtual base class? if (ReturnOffset.first || ReturnOffset.second) - CovariantThunks[MD] = std::make_pair(std::make_pair(ThisOffset, + CovariantThunks[GD] = std::make_pair(std::make_pair(ThisOffset, ReturnOffset), oret); - else if (!isPure) - Thunks[MD] = ThisOffset; + else if (!isPure && (ThisOffset.first || ThisOffset.second)) + Thunks[GD] = ThisOffset; return true; } // FIXME: finish off - int64_t O = VCallOffset[OMD] - OverrideOffset/8; - // int64_t O = CurrentVBaseOffset/8 - OverrideOffset/8; + int64_t O = VCallOffset[OGD] - OverrideOffset/8; + if (O || ReturnOffset.first || ReturnOffset.second) { CallOffset ThisOffset = std::make_pair(O, 0); if (ReturnOffset.first || ReturnOffset.second) - CovariantThunks[MD] = std::make_pair(std::make_pair(ThisOffset, + CovariantThunks[GD] = std::make_pair(std::make_pair(ThisOffset, ReturnOffset), oret); else if (!isPure) - Thunks[MD] = ThisOffset; + Thunks[GD] = ThisOffset; } return true; } @@ -291,9 +319,10 @@ public: void InstallThunks() { for (Thunks_t::iterator i = Thunks.begin(), e = Thunks.end(); i != e; ++i) { - const CXXMethodDecl *MD = i->first; + GlobalDecl GD = i->first; + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); assert(!MD->isPure() && "Trying to thunk a pure"); - Index_t idx = Index[MD]; + Index_t idx = Index[GD]; Index_t nv_O = i->second.first; Index_t v_O = i->second.second; submethods[idx] = CGM.BuildThunk(MD, Extern, nv_O, v_O); @@ -302,10 +331,11 @@ public: for (CovariantThunks_t::iterator i = CovariantThunks.begin(), e = CovariantThunks.end(); i != e; ++i) { - const CXXMethodDecl *MD = i->first; + GlobalDecl GD = i->first; + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); if (MD->isPure()) continue; - Index_t idx = Index[MD]; + Index_t idx = Index[GD]; Index_t nv_t = i->second.first.first.first; Index_t v_t = i->second.first.first.second; Index_t nv_r = i->second.first.second.first; @@ -316,16 +346,18 @@ public: CovariantThunks.clear(); for (Pures_t::iterator i = Pures.begin(), e = Pures.end(); i != e; ++i) { - const CXXMethodDecl *MD = i->first; - Index_t idx = Index[MD]; + GlobalDecl GD = i->first; + Index_t idx = Index[GD]; submethods[idx] = cxa_pure; } Pures.clear(); } - llvm::Constant *WrapAddrOf(const CXXMethodDecl *MD) { + llvm::Constant *WrapAddrOf(GlobalDecl GD) { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) - return wrap(CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete)); + return wrap(CGM.GetAddrOfCXXDestructor(Dtor, GD.getDtorType())); const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); const llvm::Type *Ty = @@ -335,63 +367,95 @@ public: return wrap(CGM.GetAddrOfFunction(MD, Ty)); } - void OverrideMethods(Path_t *Path, bool MorallyVirtual, int64_t Offset) { + void OverrideMethods(Path_t *Path, bool MorallyVirtual, int64_t Offset, + int64_t CurrentVBaseOffset) { for (Path_t::reverse_iterator i = Path->rbegin(), e = Path->rend(); i != e; ++i) { const CXXRecordDecl *RD = i->first; int64_t OverrideOffset = i->second; for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me; ++mi) { - if (!mi->isVirtual()) + const CXXMethodDecl *MD = *mi; + + if (!MD->isVirtual()) continue; - const CXXMethodDecl *MD = *mi; - llvm::Constant *m = WrapAddrOf(MD); - OverrideMethod(MD, m, MorallyVirtual, OverrideOffset, Offset); + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { + // Override both the complete and the deleting destructor. + GlobalDecl CompDtor(DD, Dtor_Complete); + OverrideMethod(CompDtor, WrapAddrOf(CompDtor), MorallyVirtual, + OverrideOffset, Offset, CurrentVBaseOffset); + + GlobalDecl DeletingDtor(DD, Dtor_Deleting); + OverrideMethod(DeletingDtor, WrapAddrOf(DeletingDtor), MorallyVirtual, + OverrideOffset, Offset, CurrentVBaseOffset); + } else { + OverrideMethod(MD, WrapAddrOf(MD), MorallyVirtual, OverrideOffset, + Offset, CurrentVBaseOffset); + } } } } - void AddMethod(const CXXMethodDecl *MD, bool MorallyVirtual, Index_t Offset, - bool ForVirtualBase) { - llvm::Constant *m = WrapAddrOf(MD); + void AddMethod(const GlobalDecl GD, bool MorallyVirtual, Index_t Offset, + bool ForVirtualBase, int64_t CurrentVBaseOffset) { + llvm::Constant *m = WrapAddrOf(GD); // If we can find a previously allocated slot for this, reuse it. - if (OverrideMethod(MD, m, MorallyVirtual, Offset, Offset)) + if (OverrideMethod(GD, m, MorallyVirtual, Offset, Offset, + CurrentVBaseOffset)) return; + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + // else allocate a new slot. - Index[MD] = submethods.size(); + Index[GD] = submethods.size(); submethods.push_back(m); - D1(printf(" vfn for %s at %d\n", MD->getNameAsCString(), (int)Index[MD])); + D1(printf(" vfn for %s at %d\n", MD->getNameAsString().c_str(), + (int)Index[GD])); if (MD->isPure()) - Pures[MD] = 1; + Pures[GD] = 1; if (MorallyVirtual) { - VCallOffset[MD] = Offset/8; - Index_t &idx = VCall[MD]; + VCallOffset[GD] = Offset/8; + Index_t &idx = VCall[GD]; // Allocate the first one, after that, we reuse the previous one. if (idx == 0) { + NonVirtualOffset[GD] = CurrentVBaseOffset/8 - Offset/8; idx = VCalls.size()+1; VCalls.push_back(0); D1(printf(" vcall for %s at %d with delta %d\n", - MD->getNameAsCString(), (int)-VCalls.size()-3, - (int)VCallOffset[MD])); + MD->getNameAsString().c_str(), (int)-VCalls.size()-3, 0)); } } } void AddMethods(const CXXRecordDecl *RD, bool MorallyVirtual, - Index_t Offset, bool RDisVirtualBase) { + Index_t Offset, bool RDisVirtualBase, + int64_t CurrentVBaseOffset) { for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me; - ++mi) - if (mi->isVirtual()) - AddMethod(*mi, MorallyVirtual, Offset, RDisVirtualBase); + ++mi) { + const CXXMethodDecl *MD = *mi; + if (!MD->isVirtual()) + continue; + + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { + // For destructors, add both the complete and the deleting destructor + // to the vtable. + AddMethod(GlobalDecl(DD, Dtor_Complete), MorallyVirtual, Offset, + RDisVirtualBase, CurrentVBaseOffset); + AddMethod(GlobalDecl(DD, Dtor_Deleting), MorallyVirtual, Offset, + RDisVirtualBase, CurrentVBaseOffset); + } else + AddMethod(MD, MorallyVirtual, Offset, RDisVirtualBase, + CurrentVBaseOffset); + } } void NonVirtualBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout, const CXXRecordDecl *PrimaryBase, bool PrimaryBaseWasVirtual, bool MorallyVirtual, - int64_t Offset, Path_t *Path) { + int64_t Offset, int64_t CurrentVBaseOffset, + Path_t *Path) { Path->push_back(std::make_pair(RD, Offset)); for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { @@ -402,8 +466,8 @@ public: if (Base != PrimaryBase || PrimaryBaseWasVirtual) { uint64_t o = Offset + Layout.getBaseClassOffset(Base); StartNewTable(); - CurrentVBaseOffset = Offset; - GenerateVtableForBase(Base, MorallyVirtual, o, false, Path); + GenerateVtableForBase(Base, o, MorallyVirtual, false, + CurrentVBaseOffset, Path); } } Path->pop_back(); @@ -424,11 +488,39 @@ public: i != e; ++i) methods[InsertionPoint++] = wrap((0?600:0) + *i); VCalls.clear(); + VCall.clear(); } + void AddAddressPoints(const CXXRecordDecl *RD, uint64_t Offset, + Index_t AddressPoint) { + D1(printf("XXX address point for %s in %s layout %s at offset %d is %d\n", + RD->getNameAsCString(), Class->getNameAsCString(), + LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint)); + AddressPoints[std::make_pair(RD, Offset)] = AddressPoint; + + // Now also add the address point for all our primary bases. + while (1) { + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + RD = Layout.getPrimaryBase(); + const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); + // FIXME: Double check this. + if (RD == 0) + break; + if (PrimaryBaseWasVirtual && + BLayout.getVBaseClassOffset(RD) != Offset) + break; + D1(printf("XXX address point for %s in %s layout %s at offset %d is %d\n", + RD->getNameAsCString(), Class->getNameAsCString(), + LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint)); + AddressPoints[std::make_pair(RD, Offset)] = AddressPoint; + } + } + + Index_t end(const CXXRecordDecl *RD, const ASTRecordLayout &Layout, const CXXRecordDecl *PrimaryBase, bool PrimaryBaseWasVirtual, bool MorallyVirtual, int64_t Offset, bool ForVirtualBase, + int64_t CurrentVBaseOffset, Path_t *Path) { bool alloc = false; if (Path == 0) { @@ -446,7 +538,7 @@ public: // FIXME: just for extra, or for all uses of VCalls.size post this? extra = -VCalls.size(); - methods.push_back(wrap(-(Offset/8))); + methods.push_back(wrap(-((Offset-LayoutOffset)/8))); methods.push_back(rtti); Index_t AddressPoint = methods.size(); @@ -457,13 +549,22 @@ public: // and then the non-virtual bases. NonVirtualBases(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, - MorallyVirtual, Offset, Path); + MorallyVirtual, Offset, CurrentVBaseOffset, Path); if (ForVirtualBase) { - insertVCalls(VCallInsertionPoint); + // FIXME: We're adding to VCalls in callers, we need to do the overrides + // in the inner part, so that we know the complete set of vcalls during + // the build and don't have to insert into methods. Saving out the + // AddressPoint here, would need to be fixed, if we didn't do that. Also + // retroactively adding vcalls for overrides later wind up in the wrong + // place, the vcall slot has to be alloted during the walk of the base + // when the function is first introduces. AddressPoint += VCalls.size(); + insertVCalls(VCallInsertionPoint); } + AddAddressPoints(RD, Offset, AddressPoint); + if (alloc) { delete Path; } @@ -472,7 +573,7 @@ public: void Primaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset, bool updateVBIndex, Index_t current_vbindex, - bool RDisVirtualBase) { + bool RDisVirtualBase, int64_t CurrentVBaseOffset) { if (!RD->isDynamicClass()) return; @@ -485,21 +586,27 @@ public: D1(printf(" doing primaries for %s most derived %s\n", RD->getNameAsCString(), Class->getNameAsCString())); + int BaseCurrentVBaseOffset = CurrentVBaseOffset; + if (PrimaryBaseWasVirtual) + BaseCurrentVBaseOffset = BLayout.getVBaseClassOffset(PrimaryBase); + if (!PrimaryBaseWasVirtual) Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset, - updateVBIndex, current_vbindex, PrimaryBaseWasVirtual); + updateVBIndex, current_vbindex, PrimaryBaseWasVirtual, + BaseCurrentVBaseOffset); } D1(printf(" doing vcall entries for %s most derived %s\n", RD->getNameAsCString(), Class->getNameAsCString())); // And add the virtuals for the class to the primary vtable. - AddMethods(RD, MorallyVirtual, Offset, RDisVirtualBase); + AddMethods(RD, MorallyVirtual, Offset, RDisVirtualBase, CurrentVBaseOffset); } void VBPrimaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset, bool updateVBIndex, Index_t current_vbindex, - bool RDisVirtualBase, bool bottom=false) { + bool RDisVirtualBase, int64_t CurrentVBaseOffset, + bool bottom=false) { if (!RD->isDynamicClass()) return; @@ -509,14 +616,18 @@ public: // vtables are composed from the chain of primaries. if (PrimaryBase) { - if (PrimaryBaseWasVirtual) + int BaseCurrentVBaseOffset = CurrentVBaseOffset; + if (PrimaryBaseWasVirtual) { IndirectPrimary.insert(PrimaryBase); + BaseCurrentVBaseOffset = BLayout.getVBaseClassOffset(PrimaryBase); + } D1(printf(" doing primaries for %s most derived %s\n", RD->getNameAsCString(), Class->getNameAsCString())); VBPrimaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset, - updateVBIndex, current_vbindex, PrimaryBaseWasVirtual); + updateVBIndex, current_vbindex, PrimaryBaseWasVirtual, + BaseCurrentVBaseOffset); } D1(printf(" doing vbase entries for %s most derived %s\n", @@ -525,17 +636,23 @@ public: if (RDisVirtualBase || bottom) { Primaries(RD, MorallyVirtual, Offset, updateVBIndex, current_vbindex, - RDisVirtualBase); + RDisVirtualBase, CurrentVBaseOffset); } } - int64_t GenerateVtableForBase(const CXXRecordDecl *RD, - bool MorallyVirtual = false, int64_t Offset = 0, + int64_t GenerateVtableForBase(const CXXRecordDecl *RD, int64_t Offset = 0, + bool MorallyVirtual = false, bool ForVirtualBase = false, + int CurrentVBaseOffset = 0, Path_t *Path = 0) { if (!RD->isDynamicClass()) return 0; + // Construction vtable don't need parts that have no virtual bases and + // aren't morally virtual. + if ((LayoutClass != Class) && RD->getNumVBases() == 0 && !MorallyVirtual) + return 0; + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); @@ -548,13 +665,13 @@ public: extra = VCalls.size(); VBPrimaries(RD, MorallyVirtual, Offset, !ForVirtualBase, 0, ForVirtualBase, - true); + CurrentVBaseOffset, true); if (Path) - OverrideMethods(Path, MorallyVirtual, Offset); + OverrideMethods(Path, MorallyVirtual, Offset, CurrentVBaseOffset); return end(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, MorallyVirtual, - Offset, ForVirtualBase, Path); + Offset, ForVirtualBase, CurrentVBaseOffset, Path); } void GenerateVtableForVBases(const CXXRecordDecl *RD, @@ -578,16 +695,21 @@ public: StartNewTable(); VCall.clear(); int64_t BaseOffset = BLayout.getVBaseClassOffset(Base); - CurrentVBaseOffset = BaseOffset; + int64_t CurrentVBaseOffset = BaseOffset; D1(printf("vtable %s virtual base %s\n", Class->getNameAsCString(), Base->getNameAsCString())); - GenerateVtableForBase(Base, true, BaseOffset, true, Path); + GenerateVtableForBase(Base, BaseOffset, true, true, CurrentVBaseOffset, + Path); } - int64_t BaseOffset = Offset; + int64_t BaseOffset; if (i->isVirtual()) BaseOffset = BLayout.getVBaseClassOffset(Base); + else { + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + BaseOffset = Offset + Layout.getBaseClassOffset(Base); + } + if (Base->getNumVBases()) { - CurrentVBaseOffset = BaseOffset; GenerateVtableForVBases(Base, BaseOffset, Path); } } @@ -603,19 +725,17 @@ VtableBuilder::Index_t VtableBuilder::VBlookup(CXXRecordDecl *D, return CGM.getVtableInfo().getVirtualBaseOffsetIndex(D, B); } -int64_t CGVtableInfo::getMethodVtableIndex(const CXXMethodDecl *MD) { - MD = MD->getCanonicalDecl(); - - MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(MD); +int64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) { + MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(GD); if (I != MethodVtableIndices.end()) return I->second; - const CXXRecordDecl *RD = MD->getParent(); + const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent(); std::vector<llvm::Constant *> methods; // FIXME: This seems expensive. Can we do a partial job to get // just this data. - VtableBuilder b(methods, RD, CGM); + VtableBuilder b(methods, RD, RD, 0, CGM); D1(printf("vtable %s\n", RD->getNameAsCString())); b.GenerateVtableForBase(RD); b.GenerateVtableForVBases(RD); @@ -623,7 +743,7 @@ int64_t CGVtableInfo::getMethodVtableIndex(const CXXMethodDecl *MD) { MethodVtableIndices.insert(b.getIndex().begin(), b.getIndex().end()); - I = MethodVtableIndices.find(MD); + I = MethodVtableIndices.find(GD); assert(I != MethodVtableIndices.end() && "Did not find index!"); return I->second; } @@ -640,7 +760,7 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, std::vector<llvm::Constant *> methods; // FIXME: This seems expensive. Can we do a partial job to get // just this data. - VtableBuilder b(methods, RD, CGM); + VtableBuilder b(methods, RD, RD, 0, CGM); D1(printf("vtable %s\n", RD->getNameAsCString())); b.GenerateVtableForBase(RD); b.GenerateVtableForVBases(RD); @@ -659,10 +779,15 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, return I->second; } -llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) { +llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass, + const CXXRecordDecl *RD, + uint64_t Offset) { llvm::SmallString<256> OutName; llvm::raw_svector_ostream Out(OutName); - mangleCXXVtable(CGM.getMangleContext(), RD, Out); + if (LayoutClass != RD) + mangleCXXCtorVtable(getMangleContext(), LayoutClass, Offset/8, RD, Out); + else + mangleCXXVtable(getMangleContext(), RD, Out); llvm::GlobalVariable::LinkageTypes linktype; linktype = llvm::GlobalValue::LinkOnceODRLinkage; @@ -670,23 +795,245 @@ llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) { llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0); int64_t AddressPoint; - VtableBuilder b(methods, RD, CGM); + VtableBuilder b(methods, RD, LayoutClass, Offset, *this); D1(printf("vtable %s\n", RD->getNameAsCString())); // First comes the vtables for all the non-virtual bases... - AddressPoint = b.GenerateVtableForBase(RD); + AddressPoint = b.GenerateVtableForBase(RD, Offset); // then the vtables for all the virtual bases. - b.GenerateVtableForVBases(RD); + b.GenerateVtableForVBases(RD, Offset); + + CodeGenModule::AddrMap_t *&ref = AddressPoints[LayoutClass]; + if (ref == 0) + ref = new CodeGenModule::AddrMap_t; + + (*ref)[RD] = b.getAddressPoints(); llvm::Constant *C; llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, methods.size()); C = llvm::ConstantArray::get(type, methods); - llvm::Value *vtable = new llvm::GlobalVariable(CGM.getModule(), type, true, - linktype, C, Out.str()); - vtable = Builder.CreateBitCast(vtable, Ptr8Ty); - vtable = Builder.CreateGEP(vtable, - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - AddressPoint*LLVMPointerWidth/8)); + llvm::GlobalVariable *GV = new llvm::GlobalVariable(getModule(), type, + true, linktype, C, + Out.str()); + bool Hidden = getDeclVisibilityMode(RD) == LangOptions::Hidden; + if (Hidden) + GV->setVisibility(llvm::GlobalVariable::HiddenVisibility); + llvm::Constant *vtable = llvm::ConstantExpr::getBitCast(GV, Ptr8Ty); + llvm::Constant *AddressPointC; + uint32_t LLVMPointerWidth = getContext().Target.getPointerWidth(0); + AddressPointC = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), + AddressPoint*LLVMPointerWidth/8); + vtable = llvm::ConstantExpr::getInBoundsGetElementPtr(vtable, &AddressPointC, + 1); + return vtable; } + +class VTTBuilder { + /// Inits - The list of values built for the VTT. + std::vector<llvm::Constant *> &Inits; + /// Class - The most derived class that this vtable is being built for. + const CXXRecordDecl *Class; + CodeGenModule &CGM; // Per-module state. + llvm::SmallSet<const CXXRecordDecl *, 32> SeenVBase; + /// BLayout - Layout for the most derived class that this vtable is being + /// built for. + const ASTRecordLayout &BLayout; + CodeGenModule::AddrMap_t &AddressPoints; + // vtbl - A pointer to the vtable for Class. + llvm::Constant *ClassVtbl; + llvm::LLVMContext &VMContext; + + /// BuildVtablePtr - Build up a referene to the given secondary vtable + llvm::Constant *BuildVtablePtr(llvm::Constant *vtbl, + const CXXRecordDecl *VtblClass, + const CXXRecordDecl *RD, + uint64_t Offset) { + int64_t AddressPoint; + AddressPoint = (*AddressPoints[VtblClass])[std::make_pair(RD, Offset)]; + // FIXME: We can never have 0 address point. Do this for now so gepping + // retains the same structure. + if (AddressPoint == 0) + AddressPoint = 1; + D1(printf("XXX address point for %s in %s layout %s at offset %d was %d\n", + RD->getNameAsCString(), VtblClass->getNameAsCString(), + Class->getNameAsCString(), (int)Offset, (int)AddressPoint)); + uint32_t LLVMPointerWidth = CGM.getContext().Target.getPointerWidth(0); + llvm::Constant *init; + init = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), + AddressPoint*LLVMPointerWidth/8); + init = llvm::ConstantExpr::getInBoundsGetElementPtr(vtbl, &init, 1); + return init; + } + + /// Secondary - Add the secondary vtable pointers to Inits. Offset is the + /// current offset in bits to the object we're working on. + void Secondary(const CXXRecordDecl *RD, llvm::Constant *vtbl, + const CXXRecordDecl *VtblClass, uint64_t Offset=0, + bool MorallyVirtual=false) { + if (RD->getNumVBases() == 0 && ! MorallyVirtual) + return; + + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); + bool NonVirtualPrimaryBase; + NonVirtualPrimaryBase = !PrimaryBaseWasVirtual && Base == PrimaryBase; + bool BaseMorallyVirtual = MorallyVirtual | i->isVirtual(); + uint64_t BaseOffset; + if (!i->isVirtual()) { + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + BaseOffset = Offset + Layout.getBaseClassOffset(Base); + } else + BaseOffset = BLayout.getVBaseClassOffset(Base); + llvm::Constant *subvtbl = vtbl; + const CXXRecordDecl *subVtblClass = VtblClass; + if ((Base->getNumVBases() || BaseMorallyVirtual) + && !NonVirtualPrimaryBase) { + // FIXME: Slightly too many of these for __ZTT8test8_B2 + llvm::Constant *init; + if (BaseMorallyVirtual) + init = BuildVtablePtr(vtbl, VtblClass, RD, Offset); + else { + init = CGM.getVtableInfo().getCtorVtable(Class, Base, BaseOffset); + subvtbl = dyn_cast<llvm::Constant>(init->getOperand(0)); + subVtblClass = Base; + } + Inits.push_back(init); + } + Secondary(Base, subvtbl, subVtblClass, BaseOffset, BaseMorallyVirtual); + } + } + + /// BuiltVTT - Add the VTT to Inits. Offset is the offset in bits to the + /// currnet object we're working on. + void BuildVTT(const CXXRecordDecl *RD, uint64_t Offset, bool MorallyVirtual) { + if (RD->getNumVBases() == 0 && !MorallyVirtual) + return; + + llvm::Constant *init; + const CXXRecordDecl *VtblClass; + + // First comes the primary virtual table pointer... + if (MorallyVirtual) { + init = BuildVtablePtr(ClassVtbl, Class, RD, Offset); + VtblClass = Class; + } else { + init = CGM.getVtableInfo().getCtorVtable(Class, RD, Offset); + VtblClass = RD; + } + llvm::Constant *vtbl = dyn_cast<llvm::Constant>(init->getOperand(0)); + Inits.push_back(init); + + // then the secondary VTTs.... + SecondaryVTTs(RD, Offset, MorallyVirtual); + + // and last the secondary vtable pointers. + Secondary(RD, vtbl, VtblClass, Offset, MorallyVirtual); + } + + /// SecondaryVTTs - Add the secondary VTTs to Inits. The secondary VTTs are + /// built from each direct non-virtual proper base that requires a VTT in + /// declaration order. + void SecondaryVTTs(const CXXRecordDecl *RD, uint64_t Offset=0, + bool MorallyVirtual=false) { + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + if (i->isVirtual()) + continue; + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base); + BuildVTT(Base, BaseOffset, MorallyVirtual); + } + } + + /// VirtualVTTs - Add the VTT for each proper virtual base in inheritance + /// graph preorder. + void VirtualVTTs(const CXXRecordDecl *RD) { + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + if (i->isVirtual() && !SeenVBase.count(Base)) { + SeenVBase.insert(Base); + uint64_t BaseOffset = BLayout.getVBaseClassOffset(Base); + BuildVTT(Base, BaseOffset, true); + } + VirtualVTTs(Base); + } + } +public: + VTTBuilder(std::vector<llvm::Constant *> &inits, const CXXRecordDecl *c, + CodeGenModule &cgm) + : Inits(inits), Class(c), CGM(cgm), + BLayout(cgm.getContext().getASTRecordLayout(c)), + AddressPoints(*cgm.AddressPoints[c]), + VMContext(cgm.getModule().getContext()) { + + // First comes the primary virtual table pointer for the complete class... + ClassVtbl = CGM.getVtableInfo().getVtable(Class); + Inits.push_back(ClassVtbl); + ClassVtbl = dyn_cast<llvm::Constant>(ClassVtbl->getOperand(0)); + + // then the secondary VTTs... + SecondaryVTTs(Class); + + // then the secondary vtable pointers... + Secondary(Class, ClassVtbl, Class); + + // and last, the virtual VTTs. + VirtualVTTs(Class); + } +}; + +llvm::Constant *CodeGenModule::GenerateVTT(const CXXRecordDecl *RD) { + // Only classes that have virtual bases need a VTT. + if (RD->getNumVBases() == 0) + return 0; + + llvm::SmallString<256> OutName; + llvm::raw_svector_ostream Out(OutName); + mangleCXXVTT(getMangleContext(), RD, Out); + + llvm::GlobalVariable::LinkageTypes linktype; + linktype = llvm::GlobalValue::LinkOnceODRLinkage; + std::vector<llvm::Constant *> inits; + llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0); + + D1(printf("vtt %s\n", RD->getNameAsCString())); + + VTTBuilder b(inits, RD, *this); + + llvm::Constant *C; + llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, inits.size()); + C = llvm::ConstantArray::get(type, inits); + llvm::GlobalVariable *vtt = new llvm::GlobalVariable(getModule(), type, true, + linktype, C, Out.str()); + bool Hidden = getDeclVisibilityMode(RD) == LangOptions::Hidden; + if (Hidden) + vtt->setVisibility(llvm::GlobalVariable::HiddenVisibility); + return llvm::ConstantExpr::getBitCast(vtt, Ptr8Ty); +} + +llvm::Constant *CGVtableInfo::getVtable(const CXXRecordDecl *RD) { + llvm::Constant *&vtbl = Vtables[RD]; + if (vtbl) + return vtbl; + vtbl = CGM.GenerateVtable(RD, RD); + CGM.GenerateRtti(RD); + CGM.GenerateVTT(RD); + return vtbl; +} + +llvm::Constant *CGVtableInfo::getCtorVtable(const CXXRecordDecl *LayoutClass, + const CXXRecordDecl *RD, + uint64_t Offset) { + return CGM.GenerateVtable(LayoutClass, RD, Offset); +} diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h index 69fb1f100599..f9ddf44284b1 100644 --- a/lib/CodeGen/CGVtable.h +++ b/lib/CodeGen/CGVtable.h @@ -15,6 +15,7 @@ #define CLANG_CODEGEN_CGVTABLE_H #include "llvm/ADT/DenseMap.h" +#include "GlobalDecl.h" namespace clang { class CXXMethodDecl; @@ -28,7 +29,7 @@ class CGVtableInfo { /// MethodVtableIndices - Contains the index (relative to the vtable address /// point) where the function pointer for a virtual function is stored. - typedef llvm::DenseMap<const CXXMethodDecl *, int64_t> MethodVtableIndicesTy; + typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVtableIndicesTy; MethodVtableIndicesTy MethodVtableIndices; typedef std::pair<const CXXRecordDecl *, @@ -38,6 +39,8 @@ class CGVtableInfo { /// offsets for virtual bases of a class are stored. typedef llvm::DenseMap<ClassPairTy, int64_t> VirtualBaseClassIndiciesTy; VirtualBaseClassIndiciesTy VirtualBaseClassIndicies; + + llvm::DenseMap<const CXXRecordDecl *, llvm::Constant *> Vtables; public: CGVtableInfo(CodeGenModule &CGM) : CGM(CGM) { } @@ -45,7 +48,7 @@ public: /// getMethodVtableIndex - Return the index (relative to the vtable address /// point) where the function pointer for the given virtual function is /// stored. - int64_t getMethodVtableIndex(const CXXMethodDecl *MD); + int64_t getMethodVtableIndex(GlobalDecl GD); /// getVirtualBaseOffsetIndex - Return the index (relative to the vtable /// address point) where the offset of the virtual base that contains the @@ -54,6 +57,10 @@ public: /// base. int64_t getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, const CXXRecordDecl *VBase); + + llvm::Constant *getVtable(const CXXRecordDecl *RD); + llvm::Constant *getCtorVtable(const CXXRecordDecl *RD, + const CXXRecordDecl *Class, uint64_t Offset); }; } diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 4be341311ce4..475c7bfefd1d 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -27,11 +27,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) : BlockFunction(cgm, *this, Builder), CGM(cgm), Target(CGM.getContext().Target), Builder(cgm.getModule().getContext()), -#ifndef USEINDIRECTBRANCH - DebugInfo(0), IndirectGotoSwitch(0), -#else DebugInfo(0), IndirectBranch(0), -#endif SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0), CXXThisDecl(0) { LLVMIntTy = ConvertType(getContext().IntTy); @@ -134,7 +130,6 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { EmitFunctionEpilog(*CurFnInfo, ReturnValue); -#ifdef USEINDIRECTBRANCH // If someone did an indirect goto, emit the indirect goto block at the end of // the function. if (IndirectBranch) { @@ -142,13 +137,10 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { Builder.ClearInsertionPoint(); } - -#endif // Remove the AllocaInsertPt instruction, which is just a convenience for us. llvm::Instruction *Ptr = AllocaInsertPt; AllocaInsertPt = 0; Ptr->eraseFromParent(); -#ifdef USEINDIRECTBRANCH // If someone took the address of a label but never did an indirect goto, we // made a zero entry PHI node, which is illegal, zap it now. @@ -159,8 +151,6 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { PN->eraseFromParent(); } } - -#endif } void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, @@ -260,19 +250,21 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, // FIXME: Support CXXTryStmt here, too. if (const CompoundStmt *S = FD->getCompoundBody()) { StartFunction(GD, FD->getResultType(), Fn, Args, S->getLBracLoc()); - const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD); - llvm::BasicBlock *DtorEpilogue = 0; - if (DD) { - DtorEpilogue = createBasicBlock("dtor.epilogue"); - - PushCleanupBlock(DtorEpilogue); - } - - if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) + + if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) { EmitCtorPrologue(CD, GD.getCtorType()); - EmitStmt(S); + EmitStmt(S); + + // If any of the member initializers are temporaries bound to references + // make sure to emit their destructors. + EmitCleanupBlocks(0); + + } else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) { + llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue"); + PushCleanupBlock(DtorEpilogue); + + EmitStmt(S); - if (DD) { CleanupBlockInfo Info = PopCleanupBlock(); assert(Info.CleanupBlock == DtorEpilogue && "Block mismatch!"); @@ -283,7 +275,11 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, EmitBlock(Info.SwitchBlock); if (Info.EndBlock) EmitBlock(Info.EndBlock); + } else { + // Just a regular function, emit its body. + EmitStmt(S); } + FinishFunction(S->getRBracLoc()); } else if (FD->isImplicit()) { const CXXRecordDecl *ClassDecl = @@ -493,121 +489,32 @@ void CodeGenFunction::EmitMemSetToZero(llvm::Value *DestPtr, QualType Ty) { TypeInfo.second/8)); } -#ifndef USEINDIRECTBRANCH -unsigned CodeGenFunction::GetIDForAddrOfLabel(const LabelStmt *L) { - // Use LabelIDs.size()+1 as the new ID if one hasn't been assigned. - unsigned &Entry = LabelIDs[L]; - if (Entry) return Entry; -#else - llvm::BlockAddress *CodeGenFunction::GetAddrOfLabel(const LabelStmt *L) { // Make sure that there is a block for the indirect goto. if (IndirectBranch == 0) GetIndirectGotoBlock(); -#endif -#ifndef USEINDIRECTBRANCH - Entry = LabelIDs.size(); -#else llvm::BasicBlock *BB = getBasicBlockForLabel(L); -#endif - -#ifndef USEINDIRECTBRANCH - // If this is the first "address taken" of a label and the indirect goto has - // already been seen, add this to it. - if (IndirectGotoSwitch) { - // If this is the first address-taken label, set it as the default dest. - if (Entry == 1) - IndirectGotoSwitch->setSuccessor(0, getBasicBlockForLabel(L)); - else { - // Otherwise add it to the switch as a new dest. - const llvm::IntegerType *Int32Ty = llvm::Type::getInt32Ty(VMContext); - IndirectGotoSwitch->addCase(llvm::ConstantInt::get(Int32Ty, Entry), - getBasicBlockForLabel(L)); - } - } - return Entry; -#else // Make sure the indirect branch includes all of the address-taken blocks. IndirectBranch->addDestination(BB); return llvm::BlockAddress::get(CurFn, BB); -#endif } llvm::BasicBlock *CodeGenFunction::GetIndirectGotoBlock() { -#ifndef USEINDIRECTBRANCH - // If we already made the switch stmt for indirect goto, return its block. - if (IndirectGotoSwitch) return IndirectGotoSwitch->getParent(); -#else // If we already made the indirect branch for indirect goto, return its block. if (IndirectBranch) return IndirectBranch->getParent(); -#endif -#ifndef USEINDIRECTBRANCH - EmitBlock(createBasicBlock("indirectgoto")); -#else CGBuilderTy TmpBuilder(createBasicBlock("indirectgoto")); -#endif -#ifndef USEINDIRECTBRANCH - const llvm::IntegerType *Int32Ty = llvm::Type::getInt32Ty(VMContext); -#else const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); -#endif // Create the PHI node that indirect gotos will add entries to. -#ifndef USEINDIRECTBRANCH - llvm::Value *DestVal = Builder.CreatePHI(Int32Ty, "indirect.goto.dest"); -#else llvm::Value *DestVal = TmpBuilder.CreatePHI(Int8PtrTy, "indirect.goto.dest"); -#endif - -#ifndef USEINDIRECTBRANCH - // Create the switch instruction. For now, set the insert block to this block - // which will be fixed as labels are added. - IndirectGotoSwitch = Builder.CreateSwitch(DestVal, Builder.GetInsertBlock()); - - // Clear the insertion point to indicate we are in unreachable code. - Builder.ClearInsertionPoint(); - // If we already have labels created, add them. - if (!LabelIDs.empty()) { - // Invert LabelID's so that the order is determinstic. - std::vector<const LabelStmt*> AddrTakenLabelsByID; - AddrTakenLabelsByID.resize(LabelIDs.size()); - - for (std::map<const LabelStmt*,unsigned>::iterator - LI = LabelIDs.begin(), LE = LabelIDs.end(); LI != LE; ++LI) { - assert(LI->second-1 < AddrTakenLabelsByID.size() && - "Numbering inconsistent"); - AddrTakenLabelsByID[LI->second-1] = LI->first; - } - - // Set the default entry as the first block. - IndirectGotoSwitch->setSuccessor(0, - getBasicBlockForLabel(AddrTakenLabelsByID[0])); - - // FIXME: The iteration order of this is nondeterminstic! - for (unsigned i = 1, e = AddrTakenLabelsByID.size(); i != e; ++i) - IndirectGotoSwitch->addCase(llvm::ConstantInt::get(Int32Ty, i+1), - getBasicBlockForLabel(AddrTakenLabelsByID[i])); - } else { - // Otherwise, create a dead block and set it as the default dest. This will - // be removed by the optimizers after the indirect goto is set up. - llvm::BasicBlock *Dummy = createBasicBlock("indgoto.dummy"); - EmitBlock(Dummy); - IndirectGotoSwitch->setSuccessor(0, Dummy); - Builder.CreateUnreachable(); - Builder.ClearInsertionPoint(); - } - - return IndirectGotoSwitch->getParent(); -#else // Create the indirect branch instruction. IndirectBranch = TmpBuilder.CreateIndirectBr(DestVal); return IndirectBranch->getParent(); -#endif } llvm::Value *CodeGenFunction::GetVLASize(const VariableArrayType *VAT) { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index fe8113e95332..d96c3551010e 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -74,7 +74,7 @@ class CodeGenFunction : public BlockFunction { void operator=(const CodeGenFunction&); // DO NOT IMPLEMENT public: CodeGenModule &CGM; // Per-module state. - TargetInfo &Target; + const TargetInfo &Target; typedef std::pair<llvm::Value *, llvm::Value *> ComplexPairTy; CGBuilderTy Builder; @@ -193,28 +193,12 @@ public: private: CGDebugInfo *DebugInfo; -#ifndef USEINDIRECTBRANCH - /// LabelIDs - Track arbitrary ids assigned to labels for use in implementing - /// the GCC address-of-label extension and indirect goto. IDs are assigned to - /// labels inside getIDForAddrOfLabel(). - std::map<const LabelStmt*, unsigned> LabelIDs; -#else /// IndirectBranch - The first time an indirect goto is seen we create a /// block with an indirect branch. Every time we see the address of a label /// taken, we add the label to the indirect goto. Every subsequent indirect /// goto is codegen'd as a jump to the IndirectBranch's basic block. llvm::IndirectBrInst *IndirectBranch; -#endif - -#ifndef USEINDIRECTBRANCH - /// IndirectGotoSwitch - The first time an indirect goto is seen we create a - /// block with the switch for the indirect gotos. Every time we see the - /// address of a label taken, we add the label to the indirect goto. Every - /// subsequent indirect goto is codegen'd as a jump to the - /// IndirectGotoSwitch's basic block. - llvm::SwitchInst *IndirectGotoSwitch; -#endif /// LocalDeclMap - This keeps track of the LLVM allocas or globals for local C /// decls. llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap; @@ -397,9 +381,6 @@ public: /// legal to call this function even if there is no current insertion point. void FinishFunction(SourceLocation EndLoc=SourceLocation()); - /// GenerateVtable - Generate the vtable for the given type. - llvm::Value *GenerateVtable(const CXXRecordDecl *RD); - /// DynamicTypeAdjust - Do the non-virtual and virtual adjustments on an /// object pointer to alter the dynamic type of the pointer. Used by /// GenerateCovariantThunk for building thunks. @@ -586,11 +567,7 @@ public: /// the input field number being accessed. static unsigned getAccessedFieldNo(unsigned Idx, const llvm::Constant *Elts); -#ifndef USEINDIRECTBRANCH - unsigned GetIDForAddrOfLabel(const LabelStmt *L); -#else llvm::BlockAddress *GetAddrOfLabel(const LabelStmt *L); -#endif llvm::BasicBlock *GetIndirectGotoBlock(); /// EmitMemSetToZero - Generate code to memset a value of the given type to 0. @@ -669,6 +646,14 @@ public: const ArrayType *Array, llvm::Value *This); + void EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, + llvm::Value *NumElements, + llvm::Value *This); + + llvm::Constant * GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, + const ArrayType *Array, + llvm::Value *This); + void EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type, llvm::Value *This); @@ -678,6 +663,12 @@ public: llvm::Value *EmitCXXNewExpr(const CXXNewExpr *E); void EmitCXXDeleteExpr(const CXXDeleteExpr *E); + void EmitDeleteCall(const FunctionDecl *DeleteFD, llvm::Value *Ptr, + QualType DeleteTy); + + llvm::Value* EmitCXXTypeidExpr(const CXXTypeidExpr *E); + llvm::Value *EmitDynamicCast(llvm::Value *V, const CXXDynamicCastExpr *DCE); + //===--------------------------------------------------------------------===// // Declaration Emission //===--------------------------------------------------------------------===// @@ -851,17 +842,18 @@ public: LValue EmitConditionalOperatorLValue(const ConditionalOperator *E); LValue EmitCastLValue(const CastExpr *E); LValue EmitNullInitializationLValue(const CXXZeroInitValueExpr *E); - LValue EmitPointerToDataMemberLValue(const DeclRefExpr *E); + + LValue EmitPointerToDataMemberLValue(const FieldDecl *Field); llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar); - LValue EmitLValueForField(llvm::Value* Base, FieldDecl* Field, + LValue EmitLValueForField(llvm::Value* Base, const FieldDecl* Field, bool isUnion, unsigned CVRQualifiers); LValue EmitLValueForIvar(QualType ObjectTy, llvm::Value* Base, const ObjCIvarDecl *Ivar, unsigned CVRQualifiers); - LValue EmitLValueForBitfield(llvm::Value* Base, FieldDecl* Field, + LValue EmitLValueForBitfield(llvm::Value* Base, const FieldDecl* Field, unsigned CVRQualifiers); LValue EmitBlockDeclRefLValue(const BlockDeclRefExpr *E); @@ -870,6 +862,7 @@ public: LValue EmitCXXConstructLValue(const CXXConstructExpr *E); LValue EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E); LValue EmitCXXExprWithTemporariesLValue(const CXXExprWithTemporaries *E); + LValue EmitCXXTypeidLValue(const CXXTypeidExpr *E); LValue EmitObjCMessageExprLValue(const ObjCMessageExpr *E); LValue EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E); @@ -901,8 +894,11 @@ public: const Decl *TargetDecl = 0); RValue EmitCallExpr(const CallExpr *E); - llvm::Value *BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *&This, + llvm::Value *BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This, const llvm::Type *Ty); + llvm::Value *BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type, + llvm::Value *&This, const llvm::Type *Ty); + RValue EmitCXXMemberCall(const CXXMethodDecl *MD, llvm::Value *Callee, llvm::Value *This, @@ -1016,7 +1012,7 @@ public: /// EmitCXXGlobalDtorRegistration - Emits a call to register the global ptr /// with the C++ runtime so that its destructor will be called at exit. - void EmitCXXGlobalDtorRegistration(const CXXDestructorDecl *Dtor, + void EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, llvm::Constant *DeclPtr); /// GenerateCXXGlobalInitFunc - Generates code for initializing global @@ -1033,7 +1029,7 @@ public: bool IsInitializer = false); void EmitCXXThrowExpr(const CXXThrowExpr *E); - + //===--------------------------------------------------------------------===// // Internal Helpers //===--------------------------------------------------------------------===// @@ -1101,6 +1097,7 @@ private: if (CallArgTypeInfo) { for (typename T::arg_type_iterator I = CallArgTypeInfo->arg_type_begin(), E = CallArgTypeInfo->arg_type_end(); I != E; ++I, ++Arg) { + assert(Arg != ArgEnd && "Running over edge of argument list!"); QualType ArgType = *I; assert(getContext().getCanonicalType(ArgType.getNonReferenceType()). diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index db609f62453c..0e6f4a63a42c 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -17,7 +17,7 @@ #include "CGCall.h" #include "CGObjCRuntime.h" #include "Mangle.h" -#include "clang/Frontend/CompileOptions.h" +#include "clang/CodeGen/CodeGenOptions.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclCXX.h" @@ -30,15 +30,16 @@ #include "llvm/Module.h" #include "llvm/Intrinsics.h" #include "llvm/Target/TargetData.h" +#include "llvm/Support/ErrorHandling.h" using namespace clang; using namespace CodeGen; -CodeGenModule::CodeGenModule(ASTContext &C, const CompileOptions &compileOpts, +CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, llvm::Module &M, const llvm::TargetData &TD, Diagnostic &diags) : BlockModule(C, M, TD, Types, *this), Context(C), - Features(C.getLangOptions()), CompileOpts(compileOpts), TheModule(M), + Features(C.getLangOptions()), CodeGenOpts(CGO), TheModule(M), TheTargetData(TD), Diags(diags), Types(C, M, TD), MangleCtx(C), VtableInfo(*this), Runtime(0), MemCpyFn(0), MemMoveFn(0), MemSetFn(0), CFConstantStringClassRef(0), @@ -54,7 +55,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CompileOptions &compileOpts, Runtime = CreateMacObjCRuntime(*this); // If debug info generation is enabled, create the CGDebugInfo object. - DebugInfo = CompileOpts.DebugInfo ? new CGDebugInfo(this) : 0; + DebugInfo = CodeGenOpts.DebugInfo ? new CGDebugInfo(this) : 0; } CodeGenModule::~CodeGenModule() { @@ -347,6 +348,11 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, if (D->hasAttr<NoInlineAttr>()) F->addFnAttr(llvm::Attribute::NoInline); + if (Features.getStackProtectorMode() == LangOptions::SSPOn) + F->addFnAttr(llvm::Attribute::StackProtect); + else if (Features.getStackProtectorMode() == LangOptions::SSPReq) + F->addFnAttr(llvm::Attribute::StackProtectReq); + if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) F->setAlignment(AA->getAlignment()/8); // C++ ABI requires 2-byte alignment for member functions. @@ -543,10 +549,15 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) { // Static data may be deferred, but out-of-line static data members // cannot be. - // FIXME: What if the initializer has side effects? - return VD->isInAnonymousNamespace() || - (VD->getStorageClass() == VarDecl::Static && - !(VD->isStaticDataMember() && VD->isOutOfLine())); + if (VD->isInAnonymousNamespace()) + return true; + if (VD->getStorageClass() == VarDecl::Static) { + // Initializer has side effects? + if (VD->getInit() && VD->getInit()->HasSideEffects(Context)) + return false; + return !(VD->isStaticDataMember() && VD->isOutOfLine()); + } + return false; } void CodeGenModule::EmitGlobal(GlobalDecl GD) { @@ -639,6 +650,24 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName, return llvm::ConstantExpr::getBitCast(Entry, PTy); } + // This function doesn't have a complete type (for example, the return + // type is an incomplete struct). Use a fake type instead, and make + // sure not to try to set attributes. + bool IsIncompleteFunction = false; + if (!isa<llvm::FunctionType>(Ty)) { + Ty = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), + std::vector<const llvm::Type*>(), false); + IsIncompleteFunction = true; + } + llvm::Function *F = llvm::Function::Create(cast<llvm::FunctionType>(Ty), + llvm::Function::ExternalLinkage, + "", &getModule()); + F->setName(MangledName); + if (D.getDecl()) + SetFunctionAttributes(cast<FunctionDecl>(D.getDecl()), F, + IsIncompleteFunction); + Entry = F; + // This is the first use or definition of a mangled name. If there is a // deferred decl with this name, remember that we need to emit it at the end // of the file. @@ -672,23 +701,6 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName, DeferredCopyAssignmentToEmit(D); } - // This function doesn't have a complete type (for example, the return - // type is an incomplete struct). Use a fake type instead, and make - // sure not to try to set attributes. - bool IsIncompleteFunction = false; - if (!isa<llvm::FunctionType>(Ty)) { - Ty = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), - std::vector<const llvm::Type*>(), false); - IsIncompleteFunction = true; - } - llvm::Function *F = llvm::Function::Create(cast<llvm::FunctionType>(Ty), - llvm::Function::ExternalLinkage, - "", &getModule()); - F->setName(MangledName); - if (D.getDecl()) - SetFunctionAttributes(cast<FunctionDecl>(D.getDecl()), F, - IsIncompleteFunction); - Entry = F; return F; } @@ -1075,7 +1087,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage); } else if (Linkage == GVA_TemplateInstantiation) GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage); - else if (!CompileOpts.NoCommon && + else if (!CodeGenOpts.NoCommon && !D->hasExternalStorage() && !D->getInit() && !D->getAttr<SectionAttr>()) { GV->setLinkage(llvm::GlobalVariable::CommonLinkage); @@ -1548,7 +1560,14 @@ std::string CodeGenModule::GetStringForStringLiteral(const StringLiteral *E) { llvm::Constant * CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S) { // FIXME: This can be more efficient. - return GetAddrOfConstantString(GetStringForStringLiteral(S)); + // FIXME: We shouldn't need to bitcast the constant in the wide string case. + llvm::Constant *C = GetAddrOfConstantString(GetStringForStringLiteral(S)); + if (S->isWide()) { + llvm::Type *DestTy = + llvm::PointerType::getUnqual(getTypes().ConvertType(S->getType())); + C = llvm::ConstantExpr::getBitCast(C, DestTy); + } + return C; } /// GetAddrOfConstantStringFromObjCEncode - Return a pointer to a constant @@ -1697,6 +1716,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { EmitNamespace(cast<NamespaceDecl>(D)); break; // No code generation needed. + case Decl::UsingShadow: case Decl::Using: case Decl::UsingDirective: case Decl::ClassTemplate: diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 2e58337ee52d..c8562d6745eb 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -23,6 +23,7 @@ #include "CGCXX.h" #include "CGVtable.h" #include "CodeGenTypes.h" +#include "GlobalDecl.h" #include "Mangle.h" #include "llvm/Module.h" #include "llvm/ADT/DenseMap.h" @@ -31,8 +32,6 @@ #include "llvm/Support/ValueHandle.h" #include <list> -#define ATTACH_DEBUG_INFO_TO_AN_INSN 1 - namespace llvm { class Module; class Constant; @@ -61,7 +60,7 @@ namespace clang { class ValueDecl; class VarDecl; class LangOptions; - class CompileOptions; + class CodeGenOptions; class Diagnostic; class AnnotateAttr; class CXXDestructorDecl; @@ -72,46 +71,7 @@ namespace CodeGen { class CGDebugInfo; class CGObjCRuntime; -/// GlobalDecl - represents a global declaration. This can either be a -/// CXXConstructorDecl and the constructor type (Base, Complete). -/// a CXXDestructorDecl and the destructor type (Base, Complete) or -/// a VarDecl, a FunctionDecl or a BlockDecl. -class GlobalDecl { - llvm::PointerIntPair<const Decl*, 2> Value; - - void Init(const Decl *D) { - assert(!isa<CXXConstructorDecl>(D) && "Use other ctor with ctor decls!"); - assert(!isa<CXXDestructorDecl>(D) && "Use other ctor with dtor decls!"); - - Value.setPointer(D); - } -public: - GlobalDecl() {} - - GlobalDecl(const VarDecl *D) { Init(D);} - GlobalDecl(const FunctionDecl *D) { Init(D); } - GlobalDecl(const BlockDecl *D) { Init(D); } - GlobalDecl(const ObjCMethodDecl *D) { Init(D); } - - GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type) - : Value(D, Type) {} - GlobalDecl(const CXXDestructorDecl *D, CXXDtorType Type) - : Value(D, Type) {} - - const Decl *getDecl() const { return Value.getPointer(); } - - CXXCtorType getCtorType() const { - assert(isa<CXXConstructorDecl>(getDecl()) && "Decl is not a ctor!"); - return static_cast<CXXCtorType>(Value.getInt()); - } - - CXXDtorType getDtorType() const { - assert(isa<CXXDestructorDecl>(getDecl()) && "Decl is not a dtor!"); - return static_cast<CXXDtorType>(Value.getInt()); - } -}; - /// CodeGenModule - This class organizes the cross-function state that is used /// while generating LLVM code. class CodeGenModule : public BlockModule { @@ -122,7 +82,7 @@ class CodeGenModule : public BlockModule { ASTContext &Context; const LangOptions &Features; - const CompileOptions &CompileOpts; + const CodeGenOptions &CodeGenOpts; llvm::Module &TheModule; const llvm::TargetData &TheTargetData; Diagnostic &Diags; @@ -201,7 +161,7 @@ class CodeGenModule : public BlockModule { llvm::LLVMContext &VMContext; public: - CodeGenModule(ASTContext &C, const CompileOptions &CompileOpts, + CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts, llvm::Module &M, const llvm::TargetData &TD, Diagnostic &Diags); ~CodeGenModule(); @@ -222,7 +182,7 @@ public: CGDebugInfo *getDebugInfo() { return DebugInfo; } ASTContext &getContext() const { return Context; } - const CompileOptions &getCompileOpts() const { return CompileOpts; } + const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; } const LangOptions &getLangOptions() const { return Features; } llvm::Module &getModule() const { return TheModule; } CodeGenTypes &getTypes() { return Types; } @@ -252,8 +212,26 @@ public: llvm::Constant *GetAddrOfFunction(GlobalDecl GD, const llvm::Type *Ty = 0); + /// GenerateVtable - Generate the vtable for the given type. LayoutClass is + /// the class to use for the virtual base layout information. For + /// non-construction vtables, this is always the same as RD. Offset is the + /// offset in bits for the RD object in the LayoutClass, if we're generating a + /// construction vtable, otherwise 0. + llvm::Constant *GenerateVtable(const CXXRecordDecl *LayoutClass, + const CXXRecordDecl *RD, + uint64_t Offset=0); + + /// GenerateVTT - Generate the VTT for the given type. + llvm::Constant *GenerateVTT(const CXXRecordDecl *RD); + /// GenerateRtti - Generate the rtti information for the given type. llvm::Constant *GenerateRtti(const CXXRecordDecl *RD); + /// GenerateRttiRef - Generate a reference to the rtti information for the + /// given type. + llvm::Constant *GenerateRttiRef(const CXXRecordDecl *RD); + /// GenerateRttiNonClass - Generate the rtti information for the given + /// non-class type. + llvm::Constant *GenerateRttiNonClass(QualType Ty); /// BuildThunk - Build a thunk for the given method llvm::Constant *BuildThunk(const CXXMethodDecl *MD, bool Extern, int64_t nv, @@ -263,6 +241,11 @@ public: int64_t nv_t, int64_t v_t, int64_t nv_r, int64_t v_r); + typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t; + typedef llvm::DenseMap<const CXXRecordDecl *, + llvm::DenseMap<CtorVtable_t, int64_t>*> AddrMap_t; + llvm::DenseMap<const CXXRecordDecl *, AddrMap_t*> AddressPoints; + /// GetCXXBaseClassOffset - Returns the offset from a derived class to its /// base class. Returns null if the offset is 0. llvm::Constant *GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl, @@ -499,7 +482,7 @@ private: /// EmitCXXGlobalInitFunc - Emit a function that initializes C++ globals. void EmitCXXGlobalInitFunc(); - + // FIXME: Hardcoding priority here is gross. void AddGlobalCtor(llvm::Function *Ctor, int Priority=65535); void AddGlobalDtor(llvm::Function *Dtor, int Priority=65535); diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index d43d13e26bbb..1f83f37e0479 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -492,7 +492,7 @@ const CGRecordLayout & CodeGenTypes::getCGRecordLayout(const TagDecl *TD) const { const Type *Key = Context.getTagDeclType(TD).getTypePtr(); - llvm::DenseMap<const Type*, CGRecordLayout *>::iterator I + llvm::DenseMap<const Type*, CGRecordLayout *>::const_iterator I = CGRecordLayouts.find(Key); assert (I != CGRecordLayouts.end() && "Unable to find record layout information for type"); diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index a92a019b988e..f447549f669c 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -91,7 +91,7 @@ namespace CodeGen { /// while lowering AST types to LLVM types. class CodeGenTypes { ASTContext &Context; - TargetInfo &Target; + const TargetInfo &Target; llvm::Module& TheModule; const llvm::TargetData& TheTargetData; mutable const ABIInfo* TheABIInfo; @@ -153,7 +153,7 @@ public: ~CodeGenTypes(); const llvm::TargetData &getTargetData() const { return TheTargetData; } - TargetInfo &getTarget() const { return Target; } + const TargetInfo &getTarget() const { return Target; } ASTContext &getContext() const { return Context; } const ABIInfo &getABIInfo() const; llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); } diff --git a/lib/CodeGen/GlobalDecl.h b/lib/CodeGen/GlobalDecl.h new file mode 100644 index 000000000000..b812020f2aa4 --- /dev/null +++ b/lib/CodeGen/GlobalDecl.h @@ -0,0 +1,110 @@ +//===--- GlobalDecl.h - Global declaration holder ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// A GlobalDecl can hold either a regular variable/function or a C++ ctor/dtor +// together with its type. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CODEGEN_GLOBALDECL_H +#define CLANG_CODEGEN_GLOBALDECL_H + +namespace clang { + +namespace CodeGen { + +/// GlobalDecl - represents a global declaration. This can either be a +/// CXXConstructorDecl and the constructor type (Base, Complete). +/// a CXXDestructorDecl and the destructor type (Base, Complete) or +/// a VarDecl, a FunctionDecl or a BlockDecl. +class GlobalDecl { + llvm::PointerIntPair<const Decl*, 2> Value; + + void Init(const Decl *D) { + assert(!isa<CXXConstructorDecl>(D) && "Use other ctor with ctor decls!"); + assert(!isa<CXXDestructorDecl>(D) && "Use other ctor with dtor decls!"); + + Value.setPointer(D); + } + +public: + GlobalDecl() {} + + GlobalDecl(const VarDecl *D) { Init(D);} + GlobalDecl(const FunctionDecl *D) { Init(D); } + GlobalDecl(const BlockDecl *D) { Init(D); } + GlobalDecl(const ObjCMethodDecl *D) { Init(D); } + + GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type) + : Value(D, Type) {} + GlobalDecl(const CXXDestructorDecl *D, CXXDtorType Type) + : Value(D, Type) {} + + const Decl *getDecl() const { return Value.getPointer(); } + + CXXCtorType getCtorType() const { + assert(isa<CXXConstructorDecl>(getDecl()) && "Decl is not a ctor!"); + return static_cast<CXXCtorType>(Value.getInt()); + } + + CXXDtorType getDtorType() const { + assert(isa<CXXDestructorDecl>(getDecl()) && "Decl is not a dtor!"); + return static_cast<CXXDtorType>(Value.getInt()); + } + + friend bool operator==(const GlobalDecl &LHS, const GlobalDecl &RHS) { + return LHS.Value == RHS.Value; + } + + void *getAsOpaquePtr() const { return Value.getOpaqueValue(); } + + static GlobalDecl getFromOpaquePtr(void *P) { + GlobalDecl GD; + GD.Value.setFromOpaqueValue(P); + return GD; + } +}; + +} // end namespace CodeGen +} // end namespace clang + +namespace llvm { + template<class> struct DenseMapInfo; + + template<> struct DenseMapInfo<clang::CodeGen::GlobalDecl> { + static inline clang::CodeGen::GlobalDecl getEmptyKey() { + return clang::CodeGen::GlobalDecl(); + } + + static inline clang::CodeGen::GlobalDecl getTombstoneKey() { + return clang::CodeGen::GlobalDecl:: + getFromOpaquePtr(reinterpret_cast<void*>(-1)); + } + + static unsigned getHashValue(clang::CodeGen::GlobalDecl GD) { + return DenseMapInfo<void*>::getHashValue(GD.getAsOpaquePtr()); + } + + static bool isEqual(clang::CodeGen::GlobalDecl LHS, + clang::CodeGen::GlobalDecl RHS) { + return LHS == RHS; + } + + static bool isPod() { + // GlobalDecl isn't *technically* a POD type. However, we can get + // away with calling it a POD type since its copy constructor, + // copy assignment operator, and destructor are all trivial. + return true; + } + + }; + +} + +#endif diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index a5b34527969b..0a7124de3621 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -53,7 +53,10 @@ namespace { void mangleCXXVtable(const CXXRecordDecl *RD); void mangleCXXVTT(const CXXRecordDecl *RD); + void mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset, + const CXXRecordDecl *Type); void mangleCXXRtti(QualType Ty); + void mangleCXXRttiName(QualType Ty); void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type); void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type); @@ -65,6 +68,8 @@ namespace { bool mangleStandardSubstitution(const NamedDecl *ND); void addSubstitution(const NamedDecl *ND) { + ND = cast<NamedDecl>(ND->getCanonicalDecl()); + addSubstitution(reinterpret_cast<uintptr_t>(ND)); } void addSubstitution(QualType T); @@ -127,8 +132,10 @@ static bool isInCLinkageSpecification(const Decl *D) { bool CXXNameMangler::mangleFunctionDecl(const FunctionDecl *FD) { // Clang's "overloadable" attribute extension to C/C++ implies name mangling - // (always). - if (!FD->hasAttr<OverloadableAttr>()) { + // (always) as does passing a C++ member function and a function + // whose name is not a simple identifier. + if (!FD->hasAttr<OverloadableAttr>() && !isa<CXXMethodDecl>(FD) && + FD->getDeclName().isIdentifier()) { // C functions are not mangled, and "main" is never mangled. if (!Context.getASTContext().getLangOptions().CPlusPlus || FD->isMain()) return false; @@ -140,7 +147,7 @@ bool CXXNameMangler::mangleFunctionDecl(const FunctionDecl *FD) { return false; // No name mangling in a C linkage specification. - if (!isa<CXXMethodDecl>(FD) && isInCLinkageSpecification(FD)) + if (isInCLinkageSpecification(FD)) return false; } @@ -212,6 +219,17 @@ void CXXNameMangler::mangleCXXVTT(const CXXRecordDecl *RD) { mangleName(RD); } +void CXXNameMangler::mangleCXXCtorVtable(const CXXRecordDecl *RD, + int64_t Offset, + const CXXRecordDecl *Type) { + // <special-name> ::= TC <type> <offset number> _ <base type> + Out << "_ZTC"; + mangleName(RD); + Out << Offset; + Out << "_"; + mangleName(Type); +} + void CXXNameMangler::mangleCXXRtti(QualType Ty) { // <special-name> ::= TI <type> # typeinfo structure Out << "_ZTI"; @@ -219,6 +237,13 @@ void CXXNameMangler::mangleCXXRtti(QualType Ty) { mangleType(Ty); } +void CXXNameMangler::mangleCXXRttiName(QualType Ty) { + // <special-name> ::= TS <type> # typeinfo name (null terminated byte string) + Out << "_ZTS"; + + mangleType(Ty); +} + void CXXNameMangler::mangleGuardVariable(const VarDecl *D) { // <special-name> ::= GV <object name> # Guard variable for one-time // # initialization @@ -719,15 +744,15 @@ void CXXNameMangler::mangleType(QualType T) { // Only operate on the canonical type! T = Context.getASTContext().getCanonicalType(T); - bool IsSubstitutable = T.hasQualifiers() || !isa<BuiltinType>(T); + bool IsSubstitutable = T.hasLocalQualifiers() || !isa<BuiltinType>(T); if (IsSubstitutable && mangleSubstitution(T)) return; - if (Qualifiers Quals = T.getQualifiers()) { + if (Qualifiers Quals = T.getLocalQualifiers()) { mangleQualifiers(Quals); // Recurse: even if the qualified type isn't yet substitutable, // the unqualified type might be. - mangleType(T.getUnqualifiedType()); + mangleType(T.getLocalUnqualifiedType()); } else { switch (T->getTypeClass()) { #define ABSTRACT_TYPE(CLASS, PARENT) @@ -1015,6 +1040,11 @@ void CXXNameMangler::mangleExpression(const Expr *E) { // ::= <expr-primary> switch (E->getStmtClass()) { default: assert(false && "Unhandled expression kind!"); + + case Expr::ParenExprClass: + mangleExpression(cast<ParenExpr>(E)->getSubExpr()); + break; + case Expr::DeclRefExprClass: { const Decl *D = cast<DeclRefExpr>(E)->getDecl(); @@ -1169,6 +1199,7 @@ bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) { if (mangleStandardSubstitution(ND)) return true; + ND = cast<NamedDecl>(ND->getCanonicalDecl()); return mangleSubstitution(reinterpret_cast<uintptr_t>(ND)); } @@ -1255,6 +1286,8 @@ static bool isCharSpecialization(QualType T, const char *Name) { bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { // <substitution> ::= St # ::std:: + // FIXME: type_info == comes out as __ZNK3std9type_infoeqERKS0_ instead of + // __ZNKSt9type_infoeqERKS_ if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) { if (isStdNamespace(NS)) { Out << "St"; @@ -1433,6 +1466,23 @@ namespace clang { os.flush(); } + void mangleCXXVTT(MangleContext &Context, const CXXRecordDecl *RD, + llvm::raw_ostream &os) { + CXXNameMangler Mangler(Context, os); + Mangler.mangleCXXVTT(RD); + + os.flush(); + } + + void mangleCXXCtorVtable(MangleContext &Context, const CXXRecordDecl *RD, + int64_t Offset, const CXXRecordDecl *Type, + llvm::raw_ostream &os) { + CXXNameMangler Mangler(Context, os); + Mangler.mangleCXXCtorVtable(RD, Offset, Type); + + os.flush(); + } + void mangleCXXRtti(MangleContext &Context, QualType Ty, llvm::raw_ostream &os) { CXXNameMangler Mangler(Context, os); @@ -1440,4 +1490,12 @@ namespace clang { os.flush(); } + + void mangleCXXRttiName(MangleContext &Context, QualType Ty, + llvm::raw_ostream &os) { + CXXNameMangler Mangler(Context, os); + Mangler.mangleCXXRttiName(Ty); + + os.flush(); + } } diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h index 7f46a106f32a..458708fca6ad 100644 --- a/lib/CodeGen/Mangle.h +++ b/lib/CodeGen/Mangle.h @@ -67,8 +67,13 @@ namespace clang { llvm::raw_ostream &os); void mangleCXXVTT(MangleContext &Context, const CXXRecordDecl *RD, llvm::raw_ostream &os); + void mangleCXXCtorVtable(MangleContext &Context, const CXXRecordDecl *RD, + int64_t Offset, const CXXRecordDecl *Type, + llvm::raw_ostream &os); void mangleCXXRtti(MangleContext &Context, QualType T, llvm::raw_ostream &os); + void mangleCXXRttiName(MangleContext &Context, QualType T, + llvm::raw_ostream &os); void mangleCXXCtor(MangleContext &Context, const CXXConstructorDecl *D, CXXCtorType Type, llvm::raw_ostream &os); void mangleCXXDtor(MangleContext &Context, const CXXDestructorDecl *D, diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp index c8f686a06f50..1d8f31dd9b24 100644 --- a/lib/CodeGen/ModuleBuilder.cpp +++ b/lib/CodeGen/ModuleBuilder.cpp @@ -13,7 +13,7 @@ #include "clang/CodeGen/ModuleBuilder.h" #include "CodeGenModule.h" -#include "clang/Frontend/CompileOptions.h" +#include "clang/CodeGen/CodeGenOptions.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" @@ -32,14 +32,14 @@ namespace { Diagnostic &Diags; llvm::OwningPtr<const llvm::TargetData> TD; ASTContext *Ctx; - const CompileOptions CompileOpts; // Intentionally copied in. + const CodeGenOptions CodeGenOpts; // Intentionally copied in. protected: llvm::OwningPtr<llvm::Module> M; llvm::OwningPtr<CodeGen::CodeGenModule> Builder; public: CodeGeneratorImpl(Diagnostic &diags, const std::string& ModuleName, - const CompileOptions &CO, llvm::LLVMContext& C) - : Diags(diags), CompileOpts(CO), M(new llvm::Module(ModuleName, C)) {} + const CodeGenOptions &CGO, llvm::LLVMContext& C) + : Diags(diags), CodeGenOpts(CGO), M(new llvm::Module(ModuleName, C)) {} virtual ~CodeGeneratorImpl() {} @@ -57,7 +57,7 @@ namespace { M->setTargetTriple(Ctx->Target.getTriple().getTriple()); M->setDataLayout(Ctx->Target.getTargetDescription()); TD.reset(new llvm::TargetData(Ctx->Target.getTargetDescription())); - Builder.reset(new CodeGen::CodeGenModule(Context, CompileOpts, + Builder.reset(new CodeGen::CodeGenModule(Context, CodeGenOpts, *M, *TD, Diags)); } @@ -96,7 +96,7 @@ namespace { CodeGenerator *clang::CreateLLVMCodeGen(Diagnostic &Diags, const std::string& ModuleName, - const CompileOptions &CO, + const CodeGenOptions &CGO, llvm::LLVMContext& C) { - return new CodeGeneratorImpl(Diags, ModuleName, CO, C); + return new CodeGeneratorImpl(Diags, ModuleName, CGO, C); } diff --git a/lib/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp index 852bba4ef033..ba0bc6668e27 100644 --- a/lib/CodeGen/TargetABIInfo.cpp +++ b/lib/CodeGen/TargetABIInfo.cpp @@ -168,8 +168,28 @@ static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) { return Size == 32 || Size == 64; } -static bool areAllFields32Or64BitBasicType(const RecordDecl *RD, - ASTContext &Context) { +/// canExpandIndirectArgument - Test whether an argument type which is to be +/// passed indirectly (on the stack) would have the equivalent layout if it was +/// expanded into separate arguments. If so, we prefer to do the latter to avoid +/// inhibiting optimizations. +/// +// FIXME: This predicate is missing many cases, currently it just follows +// llvm-gcc (checks that all fields are 32-bit or 64-bit primitive types). We +// should probably make this smarter, or better yet make the LLVM backend +// capable of handling it. +static bool canExpandIndirectArgument(QualType Ty, ASTContext &Context) { + // We can only expand structure types. + const RecordType *RT = Ty->getAs<RecordType>(); + if (!RT) + return false; + + // We can only expand (C) structures. + // + // FIXME: This needs to be generalized to handle classes as well. + const RecordDecl *RD = RT->getDecl(); + if (!RD->isStruct() || isa<CXXRecordDecl>(RD)) + return false; + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i) { const FieldDecl *FD = *i; @@ -442,14 +462,13 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, if (Ty->isStructureType() && Context.getTypeSize(Ty) == 0) return ABIArgInfo::getIgnore(); - // Expand structs with size <= 128-bits which consist only of - // basic types (int, long long, float, double, xxx*). This is - // non-recursive and does not ignore empty fields. - if (const RecordType *RT = Ty->getAsStructureType()) { - if (Context.getTypeSize(Ty) <= 4*32 && - areAllFields32Or64BitBasicType(RT->getDecl(), Context)) - return ABIArgInfo::getExpand(); - } + // Expand small (<= 128-bit) record types when we know that the stack layout + // of those arguments will match the struct. This is important because the + // LLVM backend isn't smart enough to remove byval, which inhibits many + // optimizations. + if (Context.getTypeSize(Ty) <= 4*32 && + canExpandIndirectArgument(Ty, Context)) + return ABIArgInfo::getExpand(); return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty, Context)); } else { diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 6088d9617cf0..fcd96f1e5c8c 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -137,7 +137,20 @@ public: virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; virtual bool IsMathErrnoDefault() const; + virtual bool IsBlocksDefault() const { + // Blocks default to on for 10.6 (darwin10) and beyond. + return (DarwinVersion[0] > 9); + } + virtual bool IsObjCNonFragileABIDefault() const { + // Non-fragile ABI default to on for 10.5 (darwin9) and beyond on x86-64. + return (DarwinVersion[0] >= 9 && + getTriple().getArch() == llvm::Triple::x86_64); + } virtual bool IsUnwindTablesDefault() const; + virtual unsigned GetDefaultStackProtectorLevel() const { + // Stack protectors default to on for 10.6 (darwin10) and beyond. + return (DarwinVersion[0] > 9) ? 1 : 0; + } virtual const char *GetDefaultRelocationModel() const; virtual const char *GetForcedPicModel() const; diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 808c31c64828..34154f3a3dce 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -26,6 +26,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/System/Host.h" #include "llvm/System/Process.h" #include "InputInfo.h" @@ -320,6 +321,23 @@ static std::string getLLVMTriple(const ToolChain &TC, const ArgList &Args) { } } +// FIXME: Move to target hook. +static bool isSignedCharDefault(const llvm::Triple &Triple) { + switch (Triple.getArch()) { + default: + return true; + + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + if (Triple.getOS() == llvm::Triple::Darwin) + return true; + return false; + + case llvm::Triple::systemz: + return false; + } +} + void Clang::AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getHost().getDriver(); @@ -428,28 +446,42 @@ void Clang::AddX86TargetArgs(const ArgList &Args, false)) CmdArgs.push_back("--no-implicit-float"); + const char *CPUName = 0; if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { - // FIXME: We may need some translation here from the options gcc takes to - // names the LLVM backend understand? - CmdArgs.push_back("-mcpu"); - CmdArgs.push_back(A->getValue(Args)); - } else { - // Select default CPU. + if (llvm::StringRef(A->getValue(Args)) == "native") { + // FIXME: Reject attempts to use -march=native unless the target matches + // the host. + // + // FIXME: We should also incorporate the detected target features for use + // with -native. + std::string CPU = llvm::sys::getHostCPUName(); + if (!CPU.empty()) + CPUName = Args.MakeArgString(CPU); + } else + CPUName = A->getValue(Args); + } + // Select the default CPU if none was given (or detection failed). + if (!CPUName) { // FIXME: Need target hooks. if (memcmp(getToolChain().getOS().c_str(), "darwin", 6) == 0) { if (getToolChain().getArchName() == "x86_64") - CmdArgs.push_back("--mcpu=core2"); + CPUName = "core2"; else if (getToolChain().getArchName() == "i386") - CmdArgs.push_back("--mcpu=yonah"); + CPUName = "yonah"; } else { if (getToolChain().getArchName() == "x86_64") - CmdArgs.push_back("--mcpu=x86-64"); + CPUName = "x86-64"; else if (getToolChain().getArchName() == "i386") - CmdArgs.push_back("--mcpu=pentium4"); + CPUName = "pentium4"; } } + if (CPUName) { + CmdArgs.push_back("--mcpu"); + CmdArgs.push_back(CPUName); + } + // FIXME: Use iterator. for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) { @@ -855,18 +887,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); Args.AddLastArg(CmdArgs, options::OPT_ffreestanding); Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); - Args.AddLastArg(CmdArgs, options::OPT_fgnu_runtime); Args.AddLastArg(CmdArgs, options::OPT_flax_vector_conversions); - Args.AddLastArg(CmdArgs, options::OPT_fms_extensions); - Args.AddLastArg(CmdArgs, options::OPT_fnext_runtime); Args.AddLastArg(CmdArgs, options::OPT_fno_caret_diagnostics); Args.AddLastArg(CmdArgs, options::OPT_fno_show_column); Args.AddLastArg(CmdArgs, options::OPT_fobjc_gc_only); Args.AddLastArg(CmdArgs, options::OPT_fobjc_gc); Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch); - // FIXME: Should we remove this? - Args.AddLastArg(CmdArgs, options::OPT_fobjc_nonfragile_abi); - Args.AddLastArg(CmdArgs, options::OPT_fobjc_tight_layout); Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info); Args.AddLastArg(CmdArgs, options::OPT_ftime_report); Args.AddLastArg(CmdArgs, options::OPT_ftrapv); @@ -875,32 +901,34 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_pthread); - // Forward stack protector flags. + // -stack-protector=0 is default. + unsigned StackProtectorLevel = 0; if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector, options::OPT_fstack_protector_all, options::OPT_fstack_protector)) { - if (A->getOption().matches(options::OPT_fno_stack_protector)) - CmdArgs.push_back("--stack-protector=0"); - else if (A->getOption().matches(options::OPT_fstack_protector)) - CmdArgs.push_back("--stack-protector=1"); - else - CmdArgs.push_back("--stack-protector=2"); + if (A->getOption().matches(options::OPT_fstack_protector)) + StackProtectorLevel = 1; + else if (A->getOption().matches(options::OPT_fstack_protector_all)) + StackProtectorLevel = 2; + } else + StackProtectorLevel = getToolChain().GetDefaultStackProtectorLevel(); + if (StackProtectorLevel) { + CmdArgs.push_back("-stack-protector"); + CmdArgs.push_back(Args.MakeArgString(llvm::Twine(StackProtectorLevel))); } // Forward -f options with positive and negative forms; we translate // these by hand. - // -fbuiltin is default, only pass non-default. + // -fbuiltin is default. if (!Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin)) CmdArgs.push_back("-fbuiltin=0"); - // -fblocks default varies depending on platform and language; only - // pass if specified. - if (Arg *A = Args.getLastArg(options::OPT_fblocks, options::OPT_fno_blocks)) { - if (A->getOption().matches(options::OPT_fblocks)) - CmdArgs.push_back("-fblocks"); - else - CmdArgs.push_back("-fblocks=0"); + // -fblocks=0 is default. + if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks, + getToolChain().IsBlocksDefault())) { + Args.AddLastArg(CmdArgs, options::OPT_fblock_introspection); + CmdArgs.push_back("-fblocks"); } if (needsExceptions(Args, InputType, getToolChain().getTriple())) @@ -908,18 +936,40 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("-fexceptions=0"); - // -frtti is default, only pass non-default. + // -frtti is default. if (!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti)) CmdArgs.push_back("-frtti=0"); - // -fsigned-char/-funsigned-char default varies depending on platform; only + // -fsigned-char is default. + if (!Args.hasFlag(options::OPT_fsigned_char, + options::OPT_funsigned_char, + isSignedCharDefault(getToolChain().getTriple()))) + CmdArgs.push_back("-fsigned-char=0"); + + // -fms-extensions=0 is default. + if (Args.hasFlag(options::OPT_fms_extensions, + options::OPT_fno_ms_extensions, + getToolChain().getTriple().getOS() == llvm::Triple::Win32)) + CmdArgs.push_back("-fms-extensions"); + + // -fnext-runtime is default. + if (!Args.hasFlag(options::OPT_fnext_runtime, + options::OPT_fgnu_runtime, + getToolChain().getTriple().getOS() == llvm::Triple::Darwin)) + CmdArgs.push_back("-fgnu-runtime"); + + // -fobjc-nonfragile-abi=0 is default. + if (types::isObjC(InputType)) { + if (Args.hasArg(options::OPT_fobjc_nonfragile_abi) || + getToolChain().IsObjCNonFragileABIDefault()) + CmdArgs.push_back("-fobjc-nonfragile-abi"); + } + + // -fshort-wchar default varies depending on platform; only // pass if specified. - if (Arg *A = Args.getLastArg(options::OPT_fsigned_char, - options::OPT_funsigned_char)) { - if (A->getOption().matches(options::OPT_fsigned_char)) - CmdArgs.push_back("-fsigned-char"); - else - CmdArgs.push_back("-fsigned-char=0"); + if (Arg *A = Args.getLastArg(options::OPT_fshort_wchar)) { + if (A->getOption().matches(options::OPT_fshort_wchar)) + CmdArgs.push_back("-fshort-wchar"); } // -fno-pascal-strings is default, only pass non-default. If the tool chain @@ -2588,6 +2638,10 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtendS.o"))); CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtn.o"))); + // FIXME: g++ is more complicated here, it tries to put -lstdc++ + // before -lm, for example. + if (D.CCCIsCXX) + CmdArgs.push_back("-lstdc++"); } const char *Exec = diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp index c616c6a5bf4b..30893e7cc0cc 100644 --- a/lib/Driver/Types.cpp +++ b/lib/Driver/Types.cpp @@ -89,6 +89,19 @@ bool types::isAcceptedByClang(ID Id) { } } +bool types::isObjC(ID Id) { + switch (Id) { + default: + return false; + + case TY_ObjC: case TY_PP_ObjC: + case TY_ObjCXX: case TY_PP_ObjCXX: + case TY_ObjCHeader: case TY_PP_ObjCHeader: + case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: + return true; + } +} + bool types::isCXX(ID Id) { switch (Id) { default: diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index c0415bf550f8..e3cd6ddd08d6 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -18,6 +18,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Basic/TargetOptions.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Diagnostic.h" #include "llvm/Support/Compiler.h" @@ -61,14 +62,14 @@ public: return false; } - virtual bool ReadTargetTriple(const std::string &Triple) { + virtual bool ReadTargetTriple(llvm::StringRef Triple) { TargetTriple = Triple; return false; } - virtual bool ReadPredefinesBuffer(const char *PCHPredef, - unsigned PCHPredefLen, + virtual bool ReadPredefinesBuffer(llvm::StringRef PCHPredef, FileID PCHBufferID, + llvm::StringRef OriginalFileName, std::string &SuggestedPredefines) { Predefines = PCHPredef; return false; @@ -132,7 +133,14 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, // PCH loaded successfully. Now create the preprocessor. // Get information about the target being compiled for. - AST->Target.reset(TargetInfo::CreateTargetInfo(TargetTriple)); + // + // FIXME: This is broken, we should store the TargetOptions in the PCH. + TargetOptions TargetOpts; + TargetOpts.ABI = ""; + TargetOpts.CPU = ""; + TargetOpts.Features.clear(); + TargetOpts.Triple = TargetTriple; + AST->Target.reset(TargetInfo::CreateTargetInfo(AST->Diags, TargetOpts)); AST->PP.reset(new Preprocessor(AST->Diags, LangInfo, *AST->Target.get(), AST->getSourceManager(), HeaderInfo)); Preprocessor &PP = *AST->PP.get(); diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp index d2831fae566a..ede3d474c848 100644 --- a/lib/Frontend/AnalysisConsumer.cpp +++ b/lib/Frontend/AnalysisConsumer.cpp @@ -20,6 +20,7 @@ #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/LocalCheckers.h" +#include "clang/Analysis/ManagerRegistry.h" #include "clang/Analysis/PathDiagnostic.h" #include "clang/Analysis/PathSensitive/AnalysisManager.h" #include "clang/Analysis/PathSensitive/BugReporter.h" @@ -27,7 +28,6 @@ #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" @@ -44,10 +44,6 @@ static ExplodedNode::Auditor* CreateUbiViz(); // Basic type definitions. //===----------------------------------------------------------------------===// -namespace { - typedef void (*CodeAction)(AnalysisManager& Mgr, Decl *D); -} // end anonymous namespace - //===----------------------------------------------------------------------===// // Special PathDiagnosticClients. //===----------------------------------------------------------------------===// @@ -66,116 +62,135 @@ CreatePlistHTMLDiagnosticClient(const std::string& prefix, namespace { - class VISIBILITY_HIDDEN AnalysisConsumer : public ASTConsumer { - typedef std::vector<CodeAction> Actions; - Actions FunctionActions; - Actions ObjCMethodActions; - Actions ObjCImplementationActions; - Actions TranslationUnitActions; + class VISIBILITY_HIDDEN AnalysisConsumer : public ASTConsumer { + public: + typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D); + + private: + typedef std::vector<CodeAction> Actions; + Actions FunctionActions; + Actions ObjCMethodActions; + Actions ObjCImplementationActions; + Actions TranslationUnitActions; - public: - ASTContext* Ctx; - const Preprocessor &PP; - const std::string OutDir; - AnalyzerOptions Opts; +public: + ASTContext* Ctx; + const Preprocessor &PP; + const std::string OutDir; + AnalyzerOptions Opts; + bool declDisplayed; - // PD is owned by AnalysisManager. - PathDiagnosticClient *PD; + // PD is owned by AnalysisManager. + PathDiagnosticClient *PD; - StoreManagerCreator CreateStoreMgr; - ConstraintManagerCreator CreateConstraintMgr; + StoreManagerCreator CreateStoreMgr; + ConstraintManagerCreator CreateConstraintMgr; - llvm::OwningPtr<AnalysisManager> Mgr; + llvm::OwningPtr<AnalysisManager> Mgr; - AnalysisConsumer(const Preprocessor& pp, - const std::string& outdir, - const AnalyzerOptions& opts) - : Ctx(0), PP(pp), OutDir(outdir), - Opts(opts), PD(0) { - DigestAnalyzerOptions(); - } + AnalysisConsumer(const Preprocessor& pp, + const std::string& outdir, + const AnalyzerOptions& opts) + : Ctx(0), PP(pp), OutDir(outdir), + Opts(opts), declDisplayed(false), PD(0) { + DigestAnalyzerOptions(); + } - void DigestAnalyzerOptions() { - // Create the PathDiagnosticClient. - if (!OutDir.empty()) { - switch (Opts.AnalysisDiagOpt) { - default: + void DigestAnalyzerOptions() { + // Create the PathDiagnosticClient. + if (!OutDir.empty()) { + switch (Opts.AnalysisDiagOpt) { + default: #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \ - case PD_##NAME: PD = CREATEFN(OutDir, PP); break; + case PD_##NAME: PD = CREATEFN(OutDir, PP); break; #include "clang/Frontend/Analyses.def" - } } + } - // Create the analyzer component creators. - if (ManagerRegistry::StoreMgrCreator != 0) { - CreateStoreMgr = ManagerRegistry::StoreMgrCreator; - } - else { - switch (Opts.AnalysisStoreOpt) { - default: - assert(0 && "Unknown store manager."); + // Create the analyzer component creators. + if (ManagerRegistry::StoreMgrCreator != 0) { + CreateStoreMgr = ManagerRegistry::StoreMgrCreator; + } + else { + switch (Opts.AnalysisStoreOpt) { + default: + assert(0 && "Unknown store manager."); #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \ - case NAME##Model: CreateStoreMgr = CREATEFN; break; + case NAME##Model: CreateStoreMgr = CREATEFN; break; #include "clang/Frontend/Analyses.def" - } } + } - if (ManagerRegistry::ConstraintMgrCreator != 0) - CreateConstraintMgr = ManagerRegistry::ConstraintMgrCreator; - else { - switch (Opts.AnalysisConstraintsOpt) { - default: - assert(0 && "Unknown store manager."); + if (ManagerRegistry::ConstraintMgrCreator != 0) + CreateConstraintMgr = ManagerRegistry::ConstraintMgrCreator; + else { + switch (Opts.AnalysisConstraintsOpt) { + default: + assert(0 && "Unknown store manager."); #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \ - case NAME##Model: CreateConstraintMgr = CREATEFN; break; + case NAME##Model: CreateConstraintMgr = CREATEFN; break; #include "clang/Frontend/Analyses.def" - } } } - - void addCodeAction(CodeAction action) { - FunctionActions.push_back(action); - ObjCMethodActions.push_back(action); - } - - void addObjCImplementationAction(CodeAction action) { - ObjCImplementationActions.push_back(action); - } - - void addTranslationUnitAction(CodeAction action) { - TranslationUnitActions.push_back(action); + } + + void DisplayFunction(const Decl *D) { + if (!Opts.AnalyzerDisplayProgress || declDisplayed) + return; + + declDisplayed = true; + // FIXME: Is getCodeDecl() always a named decl? + if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) { + const NamedDecl *ND = cast<NamedDecl>(D); + SourceManager &SM = Mgr->getASTContext().getSourceManager(); + llvm::errs() << "ANALYZE: " + << SM.getPresumedLoc(ND->getLocation()).getFilename() + << ' ' << ND->getNameAsString() << '\n'; } + } - virtual void Initialize(ASTContext &Context) { - Ctx = &Context; - Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(), - PP.getLangOptions(), PD, - CreateStoreMgr, CreateConstraintMgr, - Opts.AnalyzerDisplayProgress, - Opts.VisualizeEGDot, Opts.VisualizeEGUbi, - Opts.PurgeDead, Opts.EagerlyAssume, - Opts.TrimGraph)); - } + void addCodeAction(CodeAction action) { + FunctionActions.push_back(action); + ObjCMethodActions.push_back(action); + } - virtual void HandleTopLevelDecl(DeclGroupRef D) { - for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) - HandleTopLevelSingleDecl(*I); - } + void addObjCImplementationAction(CodeAction action) { + ObjCImplementationActions.push_back(action); + } - void HandleTopLevelSingleDecl(Decl *D); - virtual void HandleTranslationUnit(ASTContext &C); + void addTranslationUnitAction(CodeAction action) { + TranslationUnitActions.push_back(action); + } - void HandleCode(Decl* D, Stmt* Body, Actions& actions); - }; + virtual void Initialize(ASTContext &Context) { + Ctx = &Context; + Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(), + PP.getLangOptions(), PD, + CreateStoreMgr, CreateConstraintMgr, + Opts.AnalyzerDisplayProgress, + Opts.VisualizeEGDot, Opts.VisualizeEGUbi, + Opts.PurgeDead, Opts.EagerlyAssume, + Opts.TrimGraph)); + } + virtual void HandleTopLevelDecl(DeclGroupRef D) { + declDisplayed = false; + for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) + HandleTopLevelSingleDecl(*I); + } + void HandleTopLevelSingleDecl(Decl *D); + virtual void HandleTranslationUnit(ASTContext &C); + void HandleCode(Decl* D, Stmt* Body, Actions& actions); +}; } // end anonymous namespace namespace llvm { - template <> struct FoldingSetTrait<CodeAction> { - static inline void Profile(CodeAction X, FoldingSetNodeID& ID) { + template <> struct FoldingSetTrait<AnalysisConsumer::CodeAction> { + static inline void Profile(AnalysisConsumer::CodeAction X, + FoldingSetNodeID& ID) { ID.AddPointer(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(X))); } }; @@ -238,7 +253,7 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { for (Actions::iterator I = TranslationUnitActions.begin(), E = TranslationUnitActions.end(); I != E; ++I) - (*I)(*Mgr, FD); + (*I)(*this, *Mgr, FD); } if (!ObjCImplementationActions.empty()) { @@ -272,34 +287,38 @@ void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) { // Dispatch on the actions. for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I) - (*I)(*Mgr, D); + (*I)(*this, *Mgr, D); } //===----------------------------------------------------------------------===// // Analyses //===----------------------------------------------------------------------===// -static void ActionWarnDeadStores(AnalysisManager& mgr, Decl *D) { +static void ActionWarnDeadStores(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D) { if (LiveVariables *L = mgr.getLiveVariables(D)) { + C.DisplayFunction(D); BugReporter BR(mgr); CheckDeadStores(*mgr.getCFG(D), *L, mgr.getParentMap(D), BR); } } -static void ActionWarnUninitVals(AnalysisManager& mgr, Decl *D) { - if (CFG* c = mgr.getCFG(D)) +static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D) { + if (CFG* c = mgr.getCFG(D)) { + C.DisplayFunction(D); CheckUninitializedValues(*c, mgr.getASTContext(), mgr.getDiagnostic()); + } } -static void ActionGRExprEngine(AnalysisManager& mgr, Decl *D, +static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D, GRTransferFuncs* tf) { - llvm::OwningPtr<GRTransferFuncs> TF(tf); // Display progress. - mgr.DisplayFunction(D); + C.DisplayFunction(D); // Construct the analysis engine. We first query for the LiveVariables // information to see if the CFG is valid. @@ -312,8 +331,14 @@ static void ActionGRExprEngine(AnalysisManager& mgr, Decl *D, Eng.setTransferFunctions(tf); Eng.RegisterInternalChecks(); // FIXME: Internal checks should just // automatically register. + + if (C.Opts.EnableExperimentalInternalChecks) + RegisterExperimentalInternalChecks(Eng); + RegisterAppleChecks(Eng, *D); - + + if (C.Opts.EnableExperimentalChecks) + RegisterExperimentalChecks(Eng); // Set the graph auditor. llvm::OwningPtr<ExplodedNode::Auditor> Auditor; @@ -337,85 +362,103 @@ static void ActionGRExprEngine(AnalysisManager& mgr, Decl *D, Eng.getBugReporter().FlushReports(); } -static void ActionCheckerCFRefAux(AnalysisManager& mgr, Decl *D, - bool GCEnabled) { +static void ActionCheckerCFRefAux(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D, bool GCEnabled) { GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getASTContext(), GCEnabled, mgr.getLangOptions()); - ActionGRExprEngine(mgr, D, TF); + ActionGRExprEngine(C, mgr, D, TF); } -static void ActionCheckerCFRef(AnalysisManager& mgr, Decl *D) { +static void ActionCheckerCFRef(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D) { switch (mgr.getLangOptions().getGCMode()) { default: assert (false && "Invalid GC mode."); case LangOptions::NonGC: - ActionCheckerCFRefAux(mgr, D, false); + ActionCheckerCFRefAux(C, mgr, D, false); break; case LangOptions::GCOnly: - ActionCheckerCFRefAux(mgr, D, true); + ActionCheckerCFRefAux(C, mgr, D, true); break; case LangOptions::HybridGC: - ActionCheckerCFRefAux(mgr, D, false); - ActionCheckerCFRefAux(mgr, D, true); + ActionCheckerCFRefAux(C, mgr, D, false); + ActionCheckerCFRefAux(C, mgr, D, true); break; } } -static void ActionDisplayLiveVariables(AnalysisManager& mgr, Decl *D) { +static void ActionDisplayLiveVariables(AnalysisConsumer &C, + AnalysisManager& mgr, Decl *D) { if (LiveVariables* L = mgr.getLiveVariables(D)) { - mgr.DisplayFunction(D); + C.DisplayFunction(D); L->dumpBlockLiveness(mgr.getSourceManager()); } } -static void ActionCFGDump(AnalysisManager& mgr, Decl *D) { - if (CFG* c = mgr.getCFG(D)) { - mgr.DisplayFunction(D); - c->dump(mgr.getLangOptions()); +static void ActionCFGDump(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { + if (CFG *cfg = mgr.getCFG(D)) { + C.DisplayFunction(D); + cfg->dump(mgr.getLangOptions()); } } -static void ActionCFGView(AnalysisManager& mgr, Decl *D) { - if (CFG* c = mgr.getCFG(D)) { - mgr.DisplayFunction(D); - c->viewCFG(mgr.getLangOptions()); +static void ActionCFGView(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { + if (CFG *cfg = mgr.getCFG(D)) { + C.DisplayFunction(D); + cfg->viewCFG(mgr.getLangOptions()); } } -static void ActionSecuritySyntacticChecks(AnalysisManager &mgr, Decl *D) { +static void ActionSecuritySyntacticChecks(AnalysisConsumer &C, + AnalysisManager &mgr, Decl *D) { + C.DisplayFunction(D); BugReporter BR(mgr); CheckSecuritySyntaxOnly(D, BR); } -static void ActionWarnObjCDealloc(AnalysisManager& mgr, Decl *D) { +static void ActionWarnObjCDealloc(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D) { if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly) return; + C.DisplayFunction(D); BugReporter BR(mgr); - CheckObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR); + CheckObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR); } -static void ActionWarnObjCUnusedIvars(AnalysisManager& mgr, Decl *D) { +static void ActionWarnObjCUnusedIvars(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D) { + C.DisplayFunction(D); BugReporter BR(mgr); - CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(D), BR); + CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(D), BR); } -static void ActionWarnObjCMethSigs(AnalysisManager& mgr, Decl *D) { +static void ActionWarnObjCMethSigs(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D) { + C.DisplayFunction(D); BugReporter BR(mgr); - CheckObjCInstMethSignature(cast<ObjCImplementationDecl>(D), BR); } -static void ActionInlineCall(AnalysisManager &mgr, Decl *D) { +static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr, + Decl *D) { + C.DisplayFunction(D); + BugReporter BR(mgr); + CheckSizeofPointer(D, BR); +} + +static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr, + Decl *D) { if (!D) return; + C.DisplayFunction(D); llvm::OwningPtr<GRTransferFuncs> TF(CreateCallInliner(mgr.getASTContext())); // Construct the analysis engine. diff --git a/lib/Frontend/Backend.cpp b/lib/Frontend/Backend.cpp index 13aecf171718..bc56029e73d2 100644 --- a/lib/Frontend/Backend.cpp +++ b/lib/Frontend/Backend.cpp @@ -8,12 +8,13 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/ASTConsumers.h" -#include "clang/CodeGen/ModuleBuilder.h" -#include "clang/Frontend/CompileOptions.h" -#include "clang/AST/ASTContext.h" #include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/DeclGroup.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "clang/CodeGen/CodeGenOptions.h" +#include "clang/CodeGen/ModuleBuilder.h" #include "llvm/Module.h" #include "llvm/ModuleProvider.h" #include "llvm/PassManager.h" @@ -40,7 +41,8 @@ using namespace llvm; namespace { class VISIBILITY_HIDDEN BackendConsumer : public ASTConsumer { BackendAction Action; - CompileOptions CompileOpts; + CodeGenOptions CodeGenOpts; + TargetOptions TargetOpts; llvm::raw_ostream *AsmOutStream; llvm::formatted_raw_ostream FormattedOutStream; ASTContext *Context; @@ -75,11 +77,12 @@ namespace { public: BackendConsumer(BackendAction action, Diagnostic &Diags, - const LangOptions &langopts, const CompileOptions &compopts, - const std::string &infile, llvm::raw_ostream* OS, - LLVMContext& C) : + const LangOptions &langopts, const CodeGenOptions &compopts, + const TargetOptions &targetopts, const std::string &infile, + llvm::raw_ostream* OS, LLVMContext& C) : Action(action), - CompileOpts(compopts), + CodeGenOpts(compopts), + TargetOpts(targetopts), AsmOutStream(OS), LLVMIRGeneration("LLVM IR Generation Time"), CodeGenerationTime("Code Generation Time"), @@ -92,7 +95,7 @@ namespace { formatted_raw_ostream::PRESERVE_STREAM); // Enable -time-passes if -ftime-report is enabled. - llvm::TimePassesIsEnabled = CompileOpts.TimePasses; + llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses; } ~BackendConsumer() { @@ -106,7 +109,7 @@ namespace { virtual void Initialize(ASTContext &Ctx) { Context = &Ctx; - if (CompileOpts.TimePasses) + if (CodeGenOpts.TimePasses) LLVMIRGeneration.startTimer(); Gen->Initialize(Ctx); @@ -115,7 +118,7 @@ namespace { ModuleProvider = new ExistingModuleProvider(TheModule); TheTargetData = new llvm::TargetData(Ctx.Target.getTargetDescription()); - if (CompileOpts.TimePasses) + if (CodeGenOpts.TimePasses) LLVMIRGeneration.stopTimer(); } @@ -124,24 +127,24 @@ namespace { Context->getSourceManager(), "LLVM IR generation of declaration"); - if (CompileOpts.TimePasses) + if (CodeGenOpts.TimePasses) LLVMIRGeneration.startTimer(); Gen->HandleTopLevelDecl(D); - if (CompileOpts.TimePasses) + if (CodeGenOpts.TimePasses) LLVMIRGeneration.stopTimer(); } virtual void HandleTranslationUnit(ASTContext &C) { { PrettyStackTraceString CrashInfo("Per-file LLVM IR generation"); - if (CompileOpts.TimePasses) + if (CodeGenOpts.TimePasses) LLVMIRGeneration.startTimer(); Gen->HandleTranslationUnit(C); - if (CompileOpts.TimePasses) + if (CodeGenOpts.TimePasses) LLVMIRGeneration.stopTimer(); } @@ -202,7 +205,7 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) { } else if (Action == Backend_EmitLL) { getPerModulePasses()->add(createPrintModulePass(&FormattedOutStream)); } else { - bool Fast = CompileOpts.OptimizationLevel == 0; + bool Fast = CodeGenOpts.OptimizationLevel == 0; // Create the TargetMachine for generating code. std::string Triple = TheModule->getTargetTriple(); @@ -213,12 +216,12 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) { } std::string FeaturesStr; - if (CompileOpts.CPU.size() || CompileOpts.Features.size()) { + if (TargetOpts.CPU.size() || TargetOpts.Features.size()) { SubtargetFeatures Features; - Features.setCPU(CompileOpts.CPU); + Features.setCPU(TargetOpts.CPU); for (std::vector<std::string>::iterator - it = CompileOpts.Features.begin(), - ie = CompileOpts.Features.end(); it != ie; ++it) + it = TargetOpts.Features.begin(), + ie = TargetOpts.Features.end(); it != ie; ++it) Features.AddFeature(*it); FeaturesStr = Features.getString(); } @@ -237,7 +240,7 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) { FunctionPassManager *PM = getCodeGenPasses(); CodeGenOpt::Level OptLevel = CodeGenOpt::Default; - switch (CompileOpts.OptimizationLevel) { + switch (CodeGenOpts.OptimizationLevel) { default: break; case 0: OptLevel = CodeGenOpt::None; break; case 3: OptLevel = CodeGenOpt::Aggressive; break; @@ -266,37 +269,44 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) { } void BackendConsumer::CreatePasses() { + unsigned OptLevel = CodeGenOpts.OptimizationLevel; + CodeGenOptions::InliningMethod Inlining = CodeGenOpts.Inlining; + + // Handle disabling of LLVM optimization, where we want to preserve the + // internal module before any optimization. + if (CodeGenOpts.DisableLLVMOpts) { + OptLevel = 0; + Inlining = CodeGenOpts.NoInlining; + } + // In -O0 if checking is disabled, we don't even have per-function passes. - if (CompileOpts.VerifyModule) + if (CodeGenOpts.VerifyModule) getPerFunctionPasses()->add(createVerifierPass()); // Assume that standard function passes aren't run for -O0. - if (CompileOpts.OptimizationLevel > 0) - llvm::createStandardFunctionPasses(getPerFunctionPasses(), - CompileOpts.OptimizationLevel); + if (OptLevel > 0) + llvm::createStandardFunctionPasses(getPerFunctionPasses(), OptLevel); llvm::Pass *InliningPass = 0; - switch (CompileOpts.Inlining) { - case CompileOptions::NoInlining: break; - case CompileOptions::NormalInlining: { + switch (Inlining) { + case CodeGenOptions::NoInlining: break; + case CodeGenOptions::NormalInlining: { // Inline small functions - unsigned Threshold = (CompileOpts.OptimizeSize || - CompileOpts.OptimizationLevel < 3) ? 50 : 200; + unsigned Threshold = (CodeGenOpts.OptimizeSize || OptLevel < 3) ? 50 : 200; InliningPass = createFunctionInliningPass(Threshold); break; } - case CompileOptions::OnlyAlwaysInlining: + case CodeGenOptions::OnlyAlwaysInlining: InliningPass = createAlwaysInlinerPass(); // Respect always_inline break; } // For now we always create per module passes. PassManager *PM = getPerModulePasses(); - llvm::createStandardModulePasses(PM, CompileOpts.OptimizationLevel, - CompileOpts.OptimizeSize, - CompileOpts.UnitAtATime, - CompileOpts.UnrollLoops, - CompileOpts.SimplifyLibCalls, + llvm::createStandardModulePasses(PM, OptLevel, CodeGenOpts.OptimizeSize, + CodeGenOpts.UnitAtATime, + CodeGenOpts.UnrollLoops, + CodeGenOpts.SimplifyLibCalls, /*HaveExceptions=*/true, InliningPass); } @@ -308,7 +318,7 @@ void BackendConsumer::EmitAssembly() { if (!TheModule || !TheTargetData) return; - TimeRegion Region(CompileOpts.TimePasses ? &CodeGenerationTime : 0); + TimeRegion Region(CodeGenOpts.TimePasses ? &CodeGenerationTime : 0); // Make sure IR generation is happy with the module. This is // released by the module provider. @@ -363,10 +373,11 @@ void BackendConsumer::EmitAssembly() { ASTConsumer *clang::CreateBackendConsumer(BackendAction Action, Diagnostic &Diags, const LangOptions &LangOpts, - const CompileOptions &CompileOpts, + const CodeGenOptions &CodeGenOpts, + const TargetOptions &TargetOpts, const std::string& InFile, llvm::raw_ostream* OS, LLVMContext& C) { - return new BackendConsumer(Action, Diags, LangOpts, CompileOpts, - InFile, OS, C); + return new BackendConsumer(Action, Diags, LangOpts, CodeGenOpts, + TargetOpts, InFile, OS, C); } diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt index e3ec78627da0..3f0f43099c69 100644 --- a/lib/Frontend/CMakeLists.txt +++ b/lib/Frontend/CMakeLists.txt @@ -6,17 +6,21 @@ add_clang_library(clangFrontend AnalysisConsumer.cpp Backend.cpp CacheTokens.cpp + CompilerInstance.cpp + CompilerInvocation.cpp DeclXML.cpp DependencyFile.cpp DiagChecker.cpp DocumentXML.cpp FixItRewriter.cpp + FrontendAction.cpp + FrontendActions.cpp + FrontendOptions.cpp GeneratePCH.cpp HTMLDiagnostics.cpp HTMLPrint.cpp InitHeaderSearch.cpp InitPreprocessor.cpp - ManagerRegistry.cpp PCHReader.cpp PCHReaderDecl.cpp PCHReaderStmt.cpp @@ -34,6 +38,7 @@ add_clang_library(clangFrontend TextDiagnosticBuffer.cpp TextDiagnosticPrinter.cpp TypeXML.cpp + VerifyDiagnosticsClient.cpp Warnings.cpp ) diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp new file mode 100644 index 000000000000..0365761c840e --- /dev/null +++ b/lib/Frontend/CompilerInstance.cpp @@ -0,0 +1,403 @@ +//===--- CompilerInstance.cpp ---------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/CompilerInstance.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PTHManager.h" +#include "clang/Frontend/ChainedDiagnosticClient.h" +#include "clang/Frontend/PCHReader.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Frontend/VerifyDiagnosticsClient.h" +#include "clang/Frontend/Utils.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/LLVMContext.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Path.h" +using namespace clang; + +CompilerInstance::CompilerInstance(llvm::LLVMContext *_LLVMContext, + bool _OwnsLLVMContext) + : LLVMContext(_LLVMContext), + OwnsLLVMContext(_OwnsLLVMContext) { + } + +CompilerInstance::~CompilerInstance() { + if (OwnsLLVMContext) + delete LLVMContext; +} + +void CompilerInstance::setDiagnostics(Diagnostic *Value) { + Diagnostics.reset(Value); +} + +void CompilerInstance::setDiagnosticClient(DiagnosticClient *Value) { + DiagClient.reset(Value); +} + +void CompilerInstance::setTarget(TargetInfo *Value) { + Target.reset(Value); +} + +void CompilerInstance::setFileManager(FileManager *Value) { + FileMgr.reset(Value); +} + +void CompilerInstance::setSourceManager(SourceManager *Value) { + SourceMgr.reset(Value); +} + +void CompilerInstance::setPreprocessor(Preprocessor *Value) { + PP.reset(Value); +} + +void CompilerInstance::setASTContext(ASTContext *Value) { + Context.reset(Value); +} + +void CompilerInstance::setASTConsumer(ASTConsumer *Value) { + Consumer.reset(Value); +} + +void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) { + CompletionConsumer.reset(Value); +} + +// Diagnostics + +static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, + unsigned argc, char **argv, + llvm::OwningPtr<DiagnosticClient> &DiagClient) { + std::string ErrorInfo; + llvm::raw_ostream *OS = + new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo); + if (!ErrorInfo.empty()) { + // FIXME: Do not fail like this. + llvm::errs() << "error opening -dump-build-information file '" + << DiagOpts.DumpBuildInformation << "', option ignored!\n"; + delete OS; + return; + } + + (*OS) << "clang-cc command line arguments: "; + for (unsigned i = 0; i != argc; ++i) + (*OS) << argv[i] << ' '; + (*OS) << '\n'; + + // Chain in a diagnostic client which will log the diagnostics. + DiagnosticClient *Logger = + new TextDiagnosticPrinter(*OS, DiagOpts, /*OwnsOutputStream=*/true); + DiagClient.reset(new ChainedDiagnosticClient(DiagClient.take(), Logger)); +} + +void CompilerInstance::createDiagnostics(int Argc, char **Argv) { + Diagnostics.reset(createDiagnostics(getDiagnosticOpts(), Argc, Argv)); + + if (Diagnostics) + DiagClient.reset(Diagnostics->getClient()); +} + +Diagnostic *CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, + int Argc, char **Argv) { + llvm::OwningPtr<Diagnostic> Diags(new Diagnostic()); + + // Create the diagnostic client for reporting errors or for + // implementing -verify. + llvm::OwningPtr<DiagnosticClient> DiagClient( + new TextDiagnosticPrinter(llvm::errs(), Opts)); + + // Chain in -verify checker, if requested. + if (Opts.VerifyDiagnostics) + DiagClient.reset(new VerifyDiagnosticsClient(*Diags, DiagClient.take())); + + if (!Opts.DumpBuildInformation.empty()) + SetUpBuildDumpLog(Opts, Argc, Argv, DiagClient); + + // Configure our handling of diagnostics. + Diags->setClient(DiagClient.take()); + if (ProcessWarningOptions(*Diags, Opts)) + return 0; + + return Diags.take(); +} + +// File Manager + +void CompilerInstance::createFileManager() { + FileMgr.reset(new FileManager()); +} + +// Source Manager + +void CompilerInstance::createSourceManager() { + SourceMgr.reset(new SourceManager()); +} + +// Preprocessor + +void CompilerInstance::createPreprocessor() { + PP.reset(createPreprocessor(getDiagnostics(), getLangOpts(), + getPreprocessorOpts(), getHeaderSearchOpts(), + getDependencyOutputOpts(), getTarget(), + getSourceManager(), getFileManager())); +} + +Preprocessor * +CompilerInstance::createPreprocessor(Diagnostic &Diags, + const LangOptions &LangInfo, + const PreprocessorOptions &PPOpts, + const HeaderSearchOptions &HSOpts, + const DependencyOutputOptions &DepOpts, + const TargetInfo &Target, + SourceManager &SourceMgr, + FileManager &FileMgr) { + // Create a PTH manager if we are using some form of a token cache. + PTHManager *PTHMgr = 0; + if (!PPOpts.TokenCache.empty()) + PTHMgr = PTHManager::Create(PPOpts.TokenCache, Diags); + + // FIXME: Don't fail like this. + if (Diags.hasErrorOccurred()) + exit(1); + + // Create the Preprocessor. + HeaderSearch *HeaderInfo = new HeaderSearch(FileMgr); + Preprocessor *PP = new Preprocessor(Diags, LangInfo, Target, + SourceMgr, *HeaderInfo, PTHMgr, + /*OwnsHeaderSearch=*/true); + + // Note that this is different then passing PTHMgr to Preprocessor's ctor. + // That argument is used as the IdentifierInfoLookup argument to + // IdentifierTable's ctor. + if (PTHMgr) { + PTHMgr->setPreprocessor(PP); + PP->setPTHManager(PTHMgr); + } + + InitializePreprocessor(*PP, PPOpts, HSOpts); + + // Handle generating dependencies, if requested. + if (!DepOpts.OutputFile.empty()) + AttachDependencyFileGen(*PP, DepOpts); + + return PP; +} + +// ASTContext + +void CompilerInstance::createASTContext() { + Preprocessor &PP = getPreprocessor(); + Context.reset(new ASTContext(getLangOpts(), PP.getSourceManager(), + getTarget(), PP.getIdentifierTable(), + PP.getSelectorTable(), PP.getBuiltinInfo(), + /*FreeMemory=*/ !getFrontendOpts().DisableFree, + /*size_reserve=*/ 0)); +} + +// ExternalASTSource + +void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path) { + llvm::OwningPtr<ExternalASTSource> Source; + Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot, + getPreprocessor(), getASTContext())); + getASTContext().setExternalSource(Source); +} + +ExternalASTSource * +CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, + const std::string &Sysroot, + Preprocessor &PP, + ASTContext &Context) { + llvm::OwningPtr<PCHReader> Reader; + Reader.reset(new PCHReader(PP, &Context, + Sysroot.empty() ? 0 : Sysroot.c_str())); + + switch (Reader->ReadPCH(Path)) { + case PCHReader::Success: + // Set the predefines buffer as suggested by the PCH reader. Typically, the + // predefines buffer will be empty. + PP.setPredefines(Reader->getSuggestedPredefines()); + return Reader.take(); + + case PCHReader::Failure: + // Unrecoverable failure: don't even try to process the input file. + break; + + case PCHReader::IgnorePCH: + // No suitable PCH file could be found. Return an error. + break; + } + + return 0; +} + +// Code Completion + +void CompilerInstance::createCodeCompletionConsumer() { + const ParsedSourceLocation &Loc = getFrontendOpts().CodeCompletionAt; + CompletionConsumer.reset( + createCodeCompletionConsumer(getPreprocessor(), + Loc.FileName, Loc.Line, Loc.Column, + getFrontendOpts().DebugCodeCompletionPrinter, + getFrontendOpts().ShowMacrosInCodeCompletion, + llvm::outs())); +} + +CodeCompleteConsumer * +CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, + const std::string &Filename, + unsigned Line, + unsigned Column, + bool UseDebugPrinter, + bool ShowMacros, + llvm::raw_ostream &OS) { + // Tell the source manager to chop off the given file at a specific + // line and column. + const FileEntry *Entry = PP.getFileManager().getFile(Filename); + if (!Entry) { + PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file) + << Filename; + return 0; + } + + // Truncate the named file at the given line/column. + PP.getSourceManager().truncateFileAt(Entry, Line, Column); + + // Set up the creation routine for code-completion. + if (UseDebugPrinter) + return new PrintingCodeCompleteConsumer(ShowMacros, OS); + else + return new CIndexCodeCompleteConsumer(ShowMacros, OS); +} + +// Output Files + +void CompilerInstance::addOutputFile(llvm::StringRef Path, + llvm::raw_ostream *OS) { + assert(OS && "Attempt to add empty stream to output list!"); + OutputFiles.push_back(std::make_pair(Path, OS)); +} + +void CompilerInstance::ClearOutputFiles(bool EraseFiles) { + for (std::list< std::pair<std::string, llvm::raw_ostream*> >::iterator + it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) { + delete it->second; + if (EraseFiles && !it->first.empty()) + llvm::sys::Path(it->first).eraseFromDisk(); + } + OutputFiles.clear(); +} + +llvm::raw_fd_ostream * +CompilerInstance::createDefaultOutputFile(bool Binary, + llvm::StringRef InFile, + llvm::StringRef Extension) { + return createOutputFile(getFrontendOpts().OutputFile, Binary, + InFile, Extension); +} + +llvm::raw_fd_ostream * +CompilerInstance::createOutputFile(llvm::StringRef OutputPath, + bool Binary, + llvm::StringRef InFile, + llvm::StringRef Extension) { + std::string Error, OutputPathName; + llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary, + InFile, Extension, + &OutputPathName); + if (!OS) { + // FIXME: Don't fail this way. + llvm::errs() << "ERROR: " << Error << "\n"; + ::exit(1); + } + + // Add the output file -- but don't try to remove "-", since this means we are + // using stdin. + addOutputFile((OutputPathName != "-") ? OutputPathName : "", OS); + + return OS; +} + +llvm::raw_fd_ostream * +CompilerInstance::createOutputFile(llvm::StringRef OutputPath, + std::string &Error, + bool Binary, + llvm::StringRef InFile, + llvm::StringRef Extension, + std::string *ResultPathName) { + std::string OutFile; + if (!OutputPath.empty()) { + OutFile = OutputPath; + } else if (InFile == "-") { + OutFile = "-"; + } else if (!Extension.empty()) { + llvm::sys::Path Path(InFile); + Path.eraseSuffix(); + Path.appendSuffix(Extension); + OutFile = Path.str(); + } else { + OutFile = "-"; + } + + llvm::raw_fd_ostream *OS = + new llvm::raw_fd_ostream(OutFile.c_str(), Error, + (Binary ? llvm::raw_fd_ostream::F_Binary : 0)); + if (!OS) + return 0; + + if (ResultPathName) + *ResultPathName = OutFile; + + return OS; +} + +// Initialization Utilities + +bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile) { + return InitializeSourceManager(InputFile, getDiagnostics(), getFileManager(), + getSourceManager(), getFrontendOpts()); +} + +bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile, + Diagnostic &Diags, + FileManager &FileMgr, + SourceManager &SourceMgr, + const FrontendOptions &Opts) { + // Figure out where to get and map in the main file. + if (Opts.EmptyInputOnly) { + const char *EmptyStr = ""; + llvm::MemoryBuffer *SB = + llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<empty input>"); + SourceMgr.createMainFileIDForMemBuffer(SB); + } else if (InputFile != "-") { + const FileEntry *File = FileMgr.getFile(InputFile); + if (File) SourceMgr.createMainFileID(File, SourceLocation()); + if (SourceMgr.getMainFileID().isInvalid()) { + Diags.Report(diag::err_fe_error_reading) << InputFile; + return false; + } + } else { + llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getSTDIN(); + SourceMgr.createMainFileIDForMemBuffer(SB); + if (SourceMgr.getMainFileID().isInvalid()) { + Diags.Report(diag::err_fe_error_reading_stdin); + return false; + } + } + + return true; +} diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp new file mode 100644 index 000000000000..ed6d0b71a51b --- /dev/null +++ b/lib/Frontend/CompilerInvocation.cpp @@ -0,0 +1,548 @@ +//===--- CompilerInvocation.cpp -------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/CompilerInvocation.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/ErrorHandling.h" +using namespace clang; + +void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, + const llvm::SmallVectorImpl<llvm::StringRef> &Args) { + llvm::llvm_report_error("FIXME: Not yet implemented!"); +} + +static const char *getAnalysisName(Analyses Kind) { + switch (Kind) { + default: + llvm::llvm_unreachable("Unknown analysis store!"); +#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)\ + case NAME: return CMDFLAG; +#include "clang/Frontend/Analyses.def" + } +} + +static const char *getAnalysisStoreName(AnalysisStores Kind) { + switch (Kind) { + default: + llvm::llvm_unreachable("Unknown analysis store!"); +#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \ + case NAME##Model: return CMDFLAG; +#include "clang/Frontend/Analyses.def" + } +} + +static const char *getAnalysisConstraintName(AnalysisConstraints Kind) { + switch (Kind) { + default: + llvm::llvm_unreachable("Unknown analysis constraints!"); +#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \ + case NAME##Model: return CMDFLAG; +#include "clang/Frontend/Analyses.def" + } +} + +static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) { + switch (Kind) { + default: + llvm::llvm_unreachable("Unknown analysis client!"); +#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREATE) \ + case PD_##NAME: return CMDFLAG; +#include "clang/Frontend/Analyses.def" + } +} + +static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, + std::vector<std::string> &Res) { + for (unsigned i = 0, e = Opts.AnalysisList.size(); i != e; ++i) + Res.push_back(getAnalysisName(Opts.AnalysisList[i])); + if (Opts.AnalysisStoreOpt != BasicStoreModel) { + Res.push_back("-analyzer-store"); + Res.push_back(getAnalysisStoreName(Opts.AnalysisStoreOpt)); + } + if (Opts.AnalysisConstraintsOpt != RangeConstraintsModel) { + Res.push_back("-analyzer-constraints"); + Res.push_back(getAnalysisConstraintName(Opts.AnalysisConstraintsOpt)); + } + if (Opts.AnalysisDiagOpt != PD_HTML) { + Res.push_back("-analyzer-output"); + Res.push_back(getAnalysisDiagClientName(Opts.AnalysisDiagOpt)); + } + if (!Opts.AnalyzeSpecificFunction.empty()) { + Res.push_back("-analyze-function"); + Res.push_back(Opts.AnalyzeSpecificFunction); + } + if (Opts.AnalyzeAll) + Res.push_back("-analyzer-opt-analyze-headers"); + if (Opts.AnalyzerDisplayProgress) + Res.push_back("-analyzer-display-progress"); + if (Opts.EagerlyAssume) + Res.push_back("-analyzer-eagerly-assume"); + if (Opts.PurgeDead) + Res.push_back("-analyzer-purge-dead"); + if (Opts.TrimGraph) + Res.push_back("-trim-egraph"); + if (Opts.VisualizeEGDot) + Res.push_back("-analyzer-viz-egraph-graphviz"); + if (Opts.VisualizeEGDot) + Res.push_back("-analyzer-viz-egraph-ubigraph"); + if (Opts.EnableExperimentalChecks) + Res.push_back("-analyzer-experimental-checks"); + if (Opts.EnableExperimentalInternalChecks) + Res.push_back("-analyzer-experimental-internal-checls"); +} + +static void CodeGenOptsToArgs(const CodeGenOptions &Opts, + std::vector<std::string> &Res) { + if (Opts.DebugInfo) + Res.push_back("-g"); + if (Opts.DisableLLVMOpts) + Res.push_back("-disable-llvm-optzns"); + if (Opts.DisableRedZone) + Res.push_back("-disable-red-zone"); + if (!Opts.MergeAllConstants) + Res.push_back("-fno-merge-all-constants"); + // NoCommon is only derived. + if (Opts.NoImplicitFloat) + Res.push_back("-no-implicit-float"); + if (Opts.OptimizeSize) { + assert(Opts.OptimizationLevel == 2 && "Invalid options!"); + Res.push_back("-Os"); + } else if (Opts.OptimizationLevel == 0) + Res.push_back("-O" + Opts.OptimizationLevel); + // SimplifyLibCalls is only derived. + // TimePasses is only derived. + // UnitAtATime is unused. + // UnrollLoops is only derived. + // VerifyModule is only derived. + // Inlining is only derived. +} + +static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts, + std::vector<std::string> &Res) { + if (Opts.IncludeSystemHeaders) + Res.push_back("-sys-header-deps"); + if (Opts.UsePhonyTargets) + Res.push_back("-MP"); + if (!Opts.OutputFile.empty()) { + Res.push_back("-dependency-file"); + Res.push_back(Opts.OutputFile); + } + for (unsigned i = 0, e = Opts.Targets.size(); i != e; ++i) { + Res.push_back("-MT"); + Res.push_back(Opts.Targets[i]); + } +} + +static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts, + std::vector<std::string> &Res) { + if (Opts.IgnoreWarnings) + Res.push_back("-w"); + if (Opts.NoRewriteMacros) + Res.push_back("-Wno-rewrite-macros"); + if (Opts.Pedantic) + Res.push_back("-pedantic"); + if (Opts.PedanticErrors) + Res.push_back("-pedantic-errors"); + if (!Opts.ShowColumn) + Res.push_back("-fno-show-column"); + if (!Opts.ShowLocation) + Res.push_back("-fno-show-source-location"); + if (!Opts.ShowCarets) + Res.push_back("-fno-caret-diagnostics"); + if (!Opts.ShowFixits) + Res.push_back("-fno-diagnostics-fixit-info"); + if (Opts.ShowSourceRanges) + Res.push_back("-fdiagnostics-print-source-range-info"); + if (Opts.ShowColors) + Res.push_back("-fcolor-diagnostics"); + if (Opts.VerifyDiagnostics) + Res.push_back("-verify"); + if (Opts.ShowOptionNames) + Res.push_back("-fdiagnostics-show-option"); + if (Opts.MessageLength) { + Res.push_back("-fmessage-length"); + Res.push_back(llvm::utostr(Opts.MessageLength)); + } + if (!Opts.DumpBuildInformation.empty()) { + Res.push_back("-dump-build-information"); + Res.push_back(Opts.DumpBuildInformation); + } + for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) + Res.push_back("-W" + Opts.Warnings[i]); +} + +static const char *getInputKindName(FrontendOptions::InputKind Kind) { + switch (Kind) { + case FrontendOptions::IK_None: break; + case FrontendOptions::IK_AST: return "ast"; + case FrontendOptions::IK_Asm: return "assembler-with-cpp"; + case FrontendOptions::IK_C: return "c"; + case FrontendOptions::IK_CXX: return "c++"; + case FrontendOptions::IK_ObjC: return "objective-c"; + case FrontendOptions::IK_ObjCXX: return "objective-c++"; + case FrontendOptions::IK_OpenCL: return "cl"; + case FrontendOptions::IK_PreprocessedC: return "cpp-output"; + case FrontendOptions::IK_PreprocessedCXX: return "c++-cpp-output"; + case FrontendOptions::IK_PreprocessedObjC: return "objective-c-cpp-output"; + case FrontendOptions::IK_PreprocessedObjCXX: return "objective-c++-cpp-output"; + } + + llvm::llvm_unreachable("Unexpected language kind!"); + return 0; +} + +static const char *getActionName(frontend::ActionKind Kind) { + switch (Kind) { + case frontend::PluginAction: + case frontend::InheritanceView: + llvm::llvm_unreachable("Invalid kind!"); + + case frontend::ASTDump: return "-ast-dump"; + case frontend::ASTPrint: return "-ast-print"; + case frontend::ASTPrintXML: return "-ast-print-xml"; + case frontend::ASTView: return "-ast-view"; + case frontend::DumpRawTokens: return "-dump-raw-tokens"; + case frontend::DumpRecordLayouts: return "-dump-record-layouts"; + case frontend::DumpTokens: return "-dump-tokens"; + case frontend::EmitAssembly: return "-S"; + case frontend::EmitBC: return "-emit-llvm-bc"; + case frontend::EmitHTML: return "-emit-html"; + case frontend::EmitLLVM: return "-emit-llvm"; + case frontend::EmitLLVMOnly: return "-emit-llvm-only"; + case frontend::FixIt: return "-fixit"; + case frontend::GeneratePCH: return "-emit-pch"; + case frontend::GeneratePTH: return "-emit-pth"; + case frontend::ParseNoop: return "-parse-noop"; + case frontend::ParsePrintCallbacks: return "-parse-print-callbacks"; + case frontend::ParseSyntaxOnly: return "-fsyntax-only"; + case frontend::PrintDeclContext: return "-print-decl-contexts"; + case frontend::PrintPreprocessedInput: return "-E"; + case frontend::RewriteBlocks: return "-rewrite-blocks"; + case frontend::RewriteMacros: return "-rewrite-macros"; + case frontend::RewriteObjC: return "-rewrite-objc"; + case frontend::RewriteTest: return "-rewrite-test"; + case frontend::RunAnalysis: return "-analyze"; + case frontend::RunPreprocessorOnly: return "-Eonly"; + } + + llvm::llvm_unreachable("Unexpected language kind!"); + return 0; +} + +static void FrontendOptsToArgs(const FrontendOptions &Opts, + std::vector<std::string> &Res) { + if (!Opts.DebugCodeCompletionPrinter) + Res.push_back("-code-completion-debug-printer=0"); + if (Opts.DisableFree) + Res.push_back("-disable-free"); + if (Opts.EmptyInputOnly) + Res.push_back("-empty-input-only"); + if (Opts.RelocatablePCH) + Res.push_back("-relocatable-pch"); + if (Opts.ShowMacrosInCodeCompletion) + Res.push_back("-code-completion-macros"); + if (Opts.ShowStats) + Res.push_back("-stats"); + if (Opts.ShowTimers) + Res.push_back("-ftime-report"); + + bool NeedLang = false; + for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) + if (FrontendOptions::getInputKindForExtension(Opts.Inputs[i].second) != + Opts.Inputs[i].first) + NeedLang = true; + if (NeedLang) { + Res.push_back("-x"); + Res.push_back(getInputKindName(Opts.Inputs[0].first)); + } + for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) { + assert((!NeedLang || Opts.Inputs[i].first == Opts.Inputs[0].first) && + "Unable to represent this input vector!"); + Res.push_back(Opts.Inputs[i].second); + } + + if (!Opts.OutputFile.empty()) { + Res.push_back("-o"); + Res.push_back(Opts.OutputFile); + } + if (!Opts.ViewClassInheritance.empty()) { + Res.push_back("-cxx-inheritance-view"); + Res.push_back(Opts.ViewClassInheritance); + } + for (unsigned i = 0, e = Opts.FixItLocations.size(); i != e; ++i) { + Res.push_back("-fixit-at"); + Res.push_back(Opts.FixItLocations[i].FileName + ":" + + llvm::utostr(Opts.FixItLocations[i].Line) + ":" + + llvm::utostr(Opts.FixItLocations[i].Column)); + } + if (!Opts.CodeCompletionAt.FileName.empty()) { + Res.push_back("-code-completion-at"); + Res.push_back(Opts.CodeCompletionAt.FileName + ":" + + llvm::utostr(Opts.CodeCompletionAt.Line) + ":" + + llvm::utostr(Opts.CodeCompletionAt.Column)); + } + if (Opts.ProgramAction != frontend::InheritanceView && + Opts.ProgramAction != frontend::PluginAction) + Res.push_back(getActionName(Opts.ProgramAction)); + if (!Opts.ActionName.empty()) { + Res.push_back("-plugin"); + Res.push_back(Opts.ActionName); + } +} + +static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, + std::vector<std::string> &Res) { + if (Opts.Sysroot.empty()) { + Res.push_back("-isysroot"); + Res.push_back(Opts.Sysroot); + } + + /// User specified include entries. + for (unsigned i = 0, e = Opts.UserEntries.size(); i != e; ++i) { + const HeaderSearchOptions::Entry &E = Opts.UserEntries[i]; + if (E.IsFramework && (E.Group != frontend::Angled || E.IsUserSupplied)) + llvm::llvm_report_error("Invalid option set!"); + if (E.IsUserSupplied) { + if (E.Group == frontend::After) { + Res.push_back("-idirafter"); + } else if (E.Group == frontend::Quoted) { + Res.push_back("-iquoted"); + } else if (E.Group == frontend::System) { + Res.push_back("-isystem"); + } else { + assert(E.Group == frontend::Angled && "Invalid group!"); + Res.push_back(E.IsFramework ? "-F" : "-I"); + } + } else { + if (E.Group != frontend::Angled && E.Group != frontend::System) + llvm::llvm_report_error("Invalid option set!"); + Res.push_back(E.Group == frontend::Angled ? "-iwithprefixbefore" : + "-iwithprefix"); + } + Res.push_back(E.Path); + } + + if (!Opts.EnvIncPath.empty()) { + // FIXME: Provide an option for this, and move env detection to driver. + llvm::llvm_report_error("Not yet implemented!"); + } + if (!Opts.CEnvIncPath.empty()) { + // FIXME: Provide an option for this, and move env detection to driver. + llvm::llvm_report_error("Not yet implemented!"); + } + if (!Opts.ObjCEnvIncPath.empty()) { + // FIXME: Provide an option for this, and move env detection to driver. + llvm::llvm_report_error("Not yet implemented!"); + } + if (!Opts.CXXEnvIncPath.empty()) { + // FIXME: Provide an option for this, and move env detection to driver. + llvm::llvm_report_error("Not yet implemented!"); + } + if (!Opts.ObjCXXEnvIncPath.empty()) { + // FIXME: Provide an option for this, and move env detection to driver. + llvm::llvm_report_error("Not yet implemented!"); + } + if (!Opts.BuiltinIncludePath.empty()) { + // FIXME: Provide an option for this, and move to driver. + } + if (!Opts.UseStandardIncludes) + Res.push_back("-nostdinc"); + if (Opts.Verbose) + Res.push_back("-v"); +} + +static void LangOptsToArgs(const LangOptions &Opts, + std::vector<std::string> &Res) { + LangOptions DefaultLangOpts; + + // FIXME: Need to set -std to get all the implicit options. + + // FIXME: We want to only pass options relative to the defaults, which + // requires constructing a target. :( + // + // It would be better to push the all target specific choices into the driver, + // so that everything below that was more uniform. + + if (Opts.Trigraphs) + Res.push_back("-trigraphs"); + // Implicit based on the input kind: + // AsmPreprocessor, CPlusPlus, ObjC1, ObjC2, OpenCL + // Implicit based on the input language standard: + // BCPLComment, C99, CPlusPlus0x, Digraphs, GNUInline, ImplicitInt, GNUMode + if (Opts.DollarIdents) + Res.push_back("-fdollars-in-identifiers"); + if (Opts.Microsoft) + Res.push_back("-fms-extensions=1"); + if (Opts.ObjCNonFragileABI) + Res.push_back("-fobjc-nonfragile-abi"); + // NoInline is implicit. + if (!Opts.CXXOperatorNames) + Res.push_back("-fno-operator-names"); + if (Opts.PascalStrings) + Res.push_back("-fpascal-strings"); + if (Opts.WritableStrings) + Res.push_back("-fwritable-strings"); + if (!Opts.LaxVectorConversions) + Res.push_back("-fno-lax-vector-conversions"); + if (Opts.AltiVec) + Res.push_back("-faltivec"); + Res.push_back("-fexceptions"); + Res.push_back(Opts.Exceptions ? "1" : "0"); + Res.push_back("-frtti"); + Res.push_back(Opts.Rtti ? "1" : "0"); + if (!Opts.NeXTRuntime) + Res.push_back("-fgnu-runtime"); + if (Opts.Freestanding) + Res.push_back("-ffreestanding"); + if (Opts.NoBuiltin) + Res.push_back("-fno-builtin"); + if (Opts.ThreadsafeStatics) + llvm::llvm_report_error("FIXME: Not yet implemented!"); + if (Opts.POSIXThreads) + Res.push_back("-pthread"); + if (Opts.Blocks) + Res.push_back("-fblocks=1"); + if (Opts.EmitAllDecls) + Res.push_back("-femit-all-decls"); + if (!Opts.MathErrno) + Res.push_back("-fmath-errno=0"); + if (Opts.OverflowChecking) + Res.push_back("-ftrapv"); + if (Opts.HeinousExtensions) + Res.push_back("-fheinous-gnu-extensions"); + // Optimize is implicit. + // OptimizeSize is implicit. + if (Opts.Static) + Res.push_back("-static-define"); + if (Opts.PICLevel) { + Res.push_back("-pic-level"); + Res.push_back(llvm::utostr(Opts.PICLevel)); + } + if (Opts.ObjCGCBitmapPrint) + Res.push_back("-print-ivar-layout"); + Res.push_back("-faccess-control"); + Res.push_back(Opts.AccessControl ? "1" : "0"); + Res.push_back("-fsigned-char"); + Res.push_back(Opts.CharIsSigned ? "1" : "0"); + Res.push_back("-fshort-wchar"); + Res.push_back(Opts.ShortWChar ? "1" : "0"); + if (!Opts.ElideConstructors) + Res.push_back("-fno-elide-constructors"); + if (Opts.getGCMode() != LangOptions::NonGC) { + if (Opts.getGCMode() == LangOptions::HybridGC) { + Res.push_back("-fobjc-gc"); + } else { + assert(Opts.getGCMode() == LangOptions::GCOnly && "Invalid GC mode!"); + Res.push_back("-fobjc-gc-only"); + } + } + if (Opts.getVisibilityMode() != LangOptions::Default) { + Res.push_back("-fvisibility"); + if (Opts.getVisibilityMode() == LangOptions::Hidden) { + Res.push_back("default"); + } else { + assert(Opts.getVisibilityMode() == LangOptions::Protected && + "Invalid visibility!"); + Res.push_back("protected"); + } + } + if (Opts.getStackProtectorMode() != 0) { + Res.push_back("-stack-protector"); + Res.push_back(llvm::utostr(Opts.getStackProtectorMode())); + } + if (Opts.getMainFileName()) { + Res.push_back("-main-file-name"); + Res.push_back(Opts.getMainFileName()); + } + if (Opts.InstantiationDepth != DefaultLangOpts.InstantiationDepth) { + Res.push_back("-ftemplate-depth"); + Res.push_back(llvm::utostr(Opts.InstantiationDepth)); + } + if (Opts.ObjCConstantStringClass) { + Res.push_back("-fconstant-string-class"); + Res.push_back(Opts.ObjCConstantStringClass); + } +} + +static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts, + std::vector<std::string> &Res) { + for (unsigned i = 0, e = Opts.Macros.size(); i != e; ++i) + Res.push_back((Opts.Macros[i].second ? "-U" : "-D") + Opts.Macros[i].first); + for (unsigned i = 0, e = Opts.Includes.size(); i != e; ++i) { + Res.push_back("-include"); + Res.push_back(Opts.Includes[i]); + } + for (unsigned i = 0, e = Opts.MacroIncludes.size(); i != e; ++i) { + Res.push_back("-imacros"); + Res.push_back(Opts.Includes[i]); + } + if (!Opts.UsePredefines) + Res.push_back("-undef"); + if (!Opts.ImplicitPCHInclude.empty()) { + Res.push_back("-implicit-pch-include"); + Res.push_back(Opts.ImplicitPCHInclude); + } + if (!Opts.ImplicitPTHInclude.empty()) { + Res.push_back("-implicit-pth-include"); + Res.push_back(Opts.ImplicitPTHInclude); + } + if (!Opts.TokenCache.empty()) { + Res.push_back("-token-cache"); + Res.push_back(Opts.TokenCache); + } +} + +static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts, + std::vector<std::string> &Res) { + if (!Opts.ShowCPP && !Opts.ShowMacros) + llvm::llvm_report_error("Invalid option combination!"); + + if (Opts.ShowCPP && Opts.ShowMacros) + Res.push_back("-dD"); + else if (!Opts.ShowCPP && Opts.ShowMacros) + Res.push_back("-dM"); + + if (!Opts.ShowLineMarkers) + Res.push_back("-P"); + if (Opts.ShowComments) + Res.push_back("-C"); + if (Opts.ShowMacroComments) + Res.push_back("-CC"); +} + +static void TargetOptsToArgs(const TargetOptions &Opts, + std::vector<std::string> &Res) { + Res.push_back("-triple"); + Res.push_back(Opts.Triple); + if (!Opts.CPU.empty()) { + Res.push_back("-target-cpu"); + Res.push_back(Opts.CPU); + } + if (!Opts.ABI.empty()) { + Res.push_back("-target-abi"); + Res.push_back(Opts.ABI); + } + for (unsigned i = 0, e = Opts.Features.size(); i != e; ++i) { + Res.push_back("-target-feature"); + Res.push_back(Opts.Features[i]); + } +} + +void CompilerInvocation::toArgs(std::vector<std::string> &Res) { + AnalyzerOptsToArgs(getAnalyzerOpts(), Res); + CodeGenOptsToArgs(getCodeGenOpts(), Res); + DependencyOutputOptsToArgs(getDependencyOutputOpts(), Res); + DiagnosticOptsToArgs(getDiagnosticOpts(), Res); + FrontendOptsToArgs(getFrontendOpts(), Res); + HeaderSearchOptsToArgs(getHeaderSearchOpts(), Res); + LangOptsToArgs(getLangOpts(), Res); + PreprocessorOptsToArgs(getPreprocessorOpts(), Res); + PreprocessorOutputOptsToArgs(getPreprocessorOutputOpts(), Res); + TargetOptsToArgs(getTargetOpts(), Res); +} diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp index 81d1179f28e3..c7f93595e1ea 100644 --- a/lib/Frontend/DependencyFile.cpp +++ b/lib/Frontend/DependencyFile.cpp @@ -12,12 +12,14 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/Utils.h" -#include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Lex/PPCallbacks.h" -#include "clang/Lex/DirectoryLookup.h" #include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/DependencyOutputOptions.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Lex/DirectoryLookup.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/Preprocessor.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" @@ -42,11 +44,10 @@ private: public: DependencyFileCallback(const Preprocessor *_PP, llvm::raw_ostream *_OS, - const std::vector<std::string> &_Targets, - bool _IncludeSystemHeaders, - bool _PhonyTarget) - : PP(_PP), Targets(_Targets), OS(_OS), - IncludeSystemHeaders(_IncludeSystemHeaders), PhonyTarget(_PhonyTarget) {} + const DependencyOutputOptions &Opts) + : PP(_PP), Targets(Opts.Targets), OS(_OS), + IncludeSystemHeaders(Opts.IncludeSystemHeaders), + PhonyTarget(Opts.UsePhonyTargets) {} ~DependencyFileCallback() { OutputDependencyFile(); @@ -59,18 +60,23 @@ public: }; } +void clang::AttachDependencyFileGen(Preprocessor &PP, + const DependencyOutputOptions &Opts) { + if (Opts.Targets.empty()) { + PP.getDiagnostics().Report(diag::err_fe_dependency_file_requires_MT); + return; + } + std::string Err; + llvm::raw_ostream *OS(new llvm::raw_fd_ostream(Opts.OutputFile.c_str(), Err)); + if (!Err.empty()) { + PP.getDiagnostics().Report(diag::err_fe_error_opening) + << Opts.OutputFile << Err; + return; + } -void clang::AttachDependencyFileGen(Preprocessor *PP, llvm::raw_ostream *OS, - std::vector<std::string> &Targets, - bool IncludeSystemHeaders, - bool PhonyTarget) { - assert(!Targets.empty() && "Target required for dependency generation"); - - DependencyFileCallback *PPDep = - new DependencyFileCallback(PP, OS, Targets, IncludeSystemHeaders, - PhonyTarget); - PP->setPPCallbacks(PPDep); + assert(!PP.getPPCallbacks() && "Preprocessor callbacks already registered!"); + PP.setPPCallbacks(new DependencyFileCallback(&PP, OS, Opts)); } /// FileMatchesDepCriteria - Determine whether the given Filename should be diff --git a/lib/Frontend/DocumentXML.cpp b/lib/Frontend/DocumentXML.cpp index d92d4cb7b8de..0263c30bfd57 100644 --- a/lib/Frontend/DocumentXML.cpp +++ b/lib/Frontend/DocumentXML.cpp @@ -135,7 +135,7 @@ void DocumentXML::finalize() { for (XML::IdMap<QualType>::iterator i = Types.begin(), e = Types.end(); i != e; ++i) { - if (i->first.hasQualifiers()) { + if (i->first.hasLocalQualifiers()) { writeTypeToXML(i->first); addAttribute("id", getPrefixedId(i->second, ID_NORMAL)); toParent(); @@ -205,7 +205,7 @@ void DocumentXML::addTypeRecursively(const QualType& pType) { addTypeRecursively(pType.getTypePtr()); // beautifier: a non-qualified type shall be transparent - if (!pType.hasQualifiers()) + if (!pType.hasLocalQualifiers()) { Types[pType] = BasicTypes[pType.getTypePtr()]; } diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp new file mode 100644 index 000000000000..ff63a0dab5f9 --- /dev/null +++ b/lib/Frontend/FrontendAction.cpp @@ -0,0 +1,225 @@ +//===--- FrontendAction.cpp -----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/FrontendAction.h" +#include "clang/AST/ASTContext.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Sema/ParseAST.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Timer.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +FrontendAction::FrontendAction() : Instance(0), CurrentTimer(0) {} + +FrontendAction::~FrontendAction() {} + +void FrontendAction::setCurrentFile(llvm::StringRef Value, ASTUnit *AST) { + CurrentFile = Value; + CurrentASTUnit.reset(AST); +} + +bool FrontendAction::BeginSourceFile(CompilerInstance &CI, + llvm::StringRef Filename, + bool IsAST) { + assert(!Instance && "Already processing a source file!"); + assert(!Filename.empty() && "Unexpected empty filename!"); + setCurrentFile(Filename); + setCompilerInstance(&CI); + + // AST files follow a very different path, since they share objects via the + // AST unit. + if (IsAST) { + assert(!usesPreprocessorOnly() && + "Attempt to pass AST file to preprocessor only action!"); + assert(hasASTSupport() && "This action does not have AST support!"); + + std::string Error; + ASTUnit *AST = ASTUnit::LoadFromPCHFile(Filename, &Error); + if (!AST) { + CI.getDiagnostics().Report(diag::err_fe_invalid_ast_file) << Error; + goto failure; + } + + setCurrentFile(Filename, AST); + + // Set the shared objects, these are reset when we finish processing the + // file, otherwise the CompilerInstance will happily destroy them. + CI.setFileManager(&AST->getFileManager()); + CI.setSourceManager(&AST->getSourceManager()); + CI.setPreprocessor(&AST->getPreprocessor()); + CI.setASTContext(&AST->getASTContext()); + + // Initialize the action. + if (!BeginSourceFileAction(CI, Filename)) + goto failure; + + /// Create the AST consumer. + CI.setASTConsumer(CreateASTConsumer(CI, Filename)); + if (!CI.hasASTConsumer()) + goto failure; + + return true; + } + + // Inform the diagnostic client we are processing a source file. + CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), + &CI.getPreprocessor()); + + // Initialize the action. + if (!BeginSourceFileAction(CI, Filename)) + goto failure; + + /// Create the AST context and consumer unless this is a preprocessor only + /// action. + if (!usesPreprocessorOnly()) { + CI.createASTContext(); + CI.setASTConsumer(CreateASTConsumer(CI, Filename)); + if (!CI.hasASTConsumer()) + goto failure; + + /// Use PCH? + if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { + assert(hasPCHSupport() && "This action does not have PCH support!"); + CI.createPCHExternalASTSource( + CI.getPreprocessorOpts().ImplicitPCHInclude); + if (!CI.getASTContext().getExternalSource()) + goto failure; + } + } + + // Initialize builtin info as long as we aren't using an external AST + // source. + if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) { + Preprocessor &PP = CI.getPreprocessor(); + PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(), + PP.getLangOptions().NoBuiltin); + } + + return true; + + // If we failed, reset state since the client will not end up calling the + // matching EndSourceFile(). + failure: + if (isCurrentFileAST()) { + CI.takeASTContext(); + CI.takePreprocessor(); + CI.takeSourceManager(); + CI.takeFileManager(); + } + + CI.getDiagnosticClient().EndSourceFile(); + setCurrentFile(""); + setCompilerInstance(0); + return false; +} + +void FrontendAction::Execute() { + CompilerInstance &CI = getCompilerInstance(); + + // Initialize the main file entry. This needs to be delayed until after PCH + // has loaded. + if (isCurrentFileAST()) { + // Set the main file ID to an empty file. + // + // FIXME: We probably shouldn't need this, but for now this is the + // simplest way to reuse the logic in ParseAST. + const char *EmptyStr = ""; + llvm::MemoryBuffer *SB = + llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<dummy input>"); + CI.getSourceManager().createMainFileIDForMemBuffer(SB); + } else { + if (!CI.InitializeSourceManager(getCurrentFile())) + return; + } + + llvm::TimeRegion Timer(CurrentTimer); + ExecuteAction(); +} + +void FrontendAction::EndSourceFile() { + CompilerInstance &CI = getCompilerInstance(); + + // Finalize the action. + EndSourceFileAction(); + + // Release the consumer and the AST, in that order since the consumer may + // perform actions in its destructor which require the context. + // + // FIXME: There is more per-file stuff we could just drop here? + if (CI.getFrontendOpts().DisableFree) { + CI.takeASTConsumer(); + if (!isCurrentFileAST()) + CI.takeASTContext(); + } else { + CI.setASTConsumer(0); + if (!isCurrentFileAST()) + CI.setASTContext(0); + } + + if (CI.getFrontendOpts().ShowStats) { + llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n"; + CI.getPreprocessor().PrintStats(); + CI.getPreprocessor().getIdentifierTable().PrintStats(); + CI.getPreprocessor().getHeaderSearchInfo().PrintStats(); + CI.getSourceManager().PrintStats(); + llvm::errs() << "\n"; + } + + // Cleanup the output streams, and erase the output files if we encountered + // an error. + CI.ClearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().getNumErrors()); + + // Inform the diagnostic client we are done with this source file. + CI.getDiagnosticClient().EndSourceFile(); + + if (isCurrentFileAST()) { + CI.takeASTContext(); + CI.takePreprocessor(); + CI.takeSourceManager(); + CI.takeFileManager(); + } + + setCompilerInstance(0); + setCurrentFile(""); +} + +//===----------------------------------------------------------------------===// +// Utility Actions +//===----------------------------------------------------------------------===// + +void ASTFrontendAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + + // FIXME: Move the truncation aspect of this into Sema, we delayed this till + // here so the source manager would be initialized. + if (hasCodeCompletionSupport() && + !CI.getFrontendOpts().CodeCompletionAt.FileName.empty()) + CI.createCodeCompletionConsumer(); + + // Use a code completion consumer? + CodeCompleteConsumer *CompletionConsumer = 0; + if (CI.hasCodeCompletionConsumer()) + CompletionConsumer = &CI.getCodeCompletionConsumer(); + + ParseAST(CI.getPreprocessor(), &CI.getASTConsumer(), CI.getASTContext(), + CI.getFrontendOpts().ShowStats, + usesCompleteTranslationUnit(), CompletionConsumer); +} + +ASTConsumer * +PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + llvm::llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!"); +} diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp new file mode 100644 index 000000000000..7a7537bce40f --- /dev/null +++ b/lib/Frontend/FrontendActions.cpp @@ -0,0 +1,281 @@ +//===--- FrontendActions.cpp ----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/FrontendActions.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Parse/Parser.h" +#include "clang/Basic/FileManager.h" +#include "clang/Frontend/AnalysisConsumer.h" +#include "clang/Frontend/ASTConsumers.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FixItRewriter.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/Utils.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// AST Consumer Actions +//===----------------------------------------------------------------------===// + +ASTConsumer *AnalysisAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateAnalysisConsumer(CI.getPreprocessor(), + CI.getFrontendOpts().OutputFile, + CI.getAnalyzerOpts()); +} + +ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateASTPrinter(CI.createDefaultOutputFile(false, InFile)); +} + +ASTConsumer *ASTPrintXMLAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateASTPrinterXML(CI.createDefaultOutputFile(false, InFile, + "xml")); +} + +ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateASTDumper(); +} + +ASTConsumer *ASTViewAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateASTViewer(); +} + +ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateDeclContextPrinter(); +} + +ASTConsumer *DumpRecordAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateRecordLayoutDumper(); +} + +ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot; + if (CI.getFrontendOpts().RelocatablePCH && + Sysroot.empty()) { + CI.getDiagnostics().Report(diag::err_relocatable_without_without_isysroot); + return 0; + } + + llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, InFile); + if (CI.getFrontendOpts().RelocatablePCH) + return CreatePCHGenerator(CI.getPreprocessor(), OS, Sysroot.c_str()); + + return CreatePCHGenerator(CI.getPreprocessor(), OS); +} + +ASTConsumer *HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateHTMLPrinter(CI.createDefaultOutputFile(false, InFile), + CI.getPreprocessor()); +} + +ASTConsumer *InheritanceViewAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateInheritanceViewer(CI.getFrontendOpts().ViewClassInheritance); +} + +FixItAction::FixItAction() {} +FixItAction::~FixItAction() {} + +ASTConsumer *FixItAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return new ASTConsumer(); +} + +/// AddFixItLocations - Add any individual user specified "fix-it" locations, +/// and return true on success. +static bool AddFixItLocations(CompilerInstance &CI, + FixItRewriter &FixItRewrite) { + const std::vector<ParsedSourceLocation> &Locs = + CI.getFrontendOpts().FixItLocations; + for (unsigned i = 0, e = Locs.size(); i != e; ++i) { + const FileEntry *File = CI.getFileManager().getFile(Locs[i].FileName); + if (!File) { + CI.getDiagnostics().Report(diag::err_fe_unable_to_find_fixit_file) + << Locs[i].FileName; + return false; + } + + RequestedSourceLocation Requested; + Requested.File = File; + Requested.Line = Locs[i].Line; + Requested.Column = Locs[i].Column; + FixItRewrite.addFixItLocation(Requested); + } + + return true; +} + +bool FixItAction::BeginSourceFileAction(CompilerInstance &CI, + llvm::StringRef Filename) { + Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(), + CI.getLangOpts())); + if (!AddFixItLocations(CI, *Rewriter)) + return false; + + return true; +} + +void FixItAction::EndSourceFileAction() { + const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts(); + Rewriter->WriteFixedFile(getCurrentFile(), FEOpts.OutputFile); +} + +ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateObjCRewriter(InFile, + CI.createDefaultOutputFile(true, InFile, "cpp"), + CI.getDiagnostics(), CI.getLangOpts(), + CI.getDiagnosticOpts().NoRewriteMacros); +} + +ASTConsumer *RewriteBlocksAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateBlockRewriter(InFile, CI.getDiagnostics(), CI.getLangOpts()); +} + +ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return new ASTConsumer(); +} + +CodeGenAction::CodeGenAction(unsigned _Act) : Act(_Act) {} + +ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + BackendAction BA = static_cast<BackendAction>(Act); + llvm::OwningPtr<llvm::raw_ostream> OS; + if (BA == Backend_EmitAssembly) + OS.reset(CI.createDefaultOutputFile(false, InFile, "s")); + else if (BA == Backend_EmitLL) + OS.reset(CI.createDefaultOutputFile(false, InFile, "ll")); + else if (BA == Backend_EmitBC) + OS.reset(CI.createDefaultOutputFile(true, InFile, "bc")); + + return CreateBackendConsumer(BA, CI.getDiagnostics(), CI.getLangOpts(), + CI.getCodeGenOpts(), CI.getTargetOpts(), InFile, + OS.take(), CI.getLLVMContext()); +} + +EmitAssemblyAction::EmitAssemblyAction() + : CodeGenAction(Backend_EmitAssembly) {} + +EmitBCAction::EmitBCAction() : CodeGenAction(Backend_EmitBC) {} + +EmitLLVMAction::EmitLLVMAction() : CodeGenAction(Backend_EmitLL) {} + +EmitLLVMOnlyAction::EmitLLVMOnlyAction() : CodeGenAction(Backend_EmitNothing) {} + +//===----------------------------------------------------------------------===// +// Preprocessor Actions +//===----------------------------------------------------------------------===// + +void DumpRawTokensAction::ExecuteAction() { + Preprocessor &PP = getCompilerInstance().getPreprocessor(); + SourceManager &SM = PP.getSourceManager(); + + // Start lexing the specified input file. + Lexer RawLex(SM.getMainFileID(), SM, PP.getLangOptions()); + RawLex.SetKeepWhitespaceMode(true); + + Token RawTok; + RawLex.LexFromRawLexer(RawTok); + while (RawTok.isNot(tok::eof)) { + PP.DumpToken(RawTok, true); + fprintf(stderr, "\n"); + RawLex.LexFromRawLexer(RawTok); + } +} + +void DumpTokensAction::ExecuteAction() { + Preprocessor &PP = getCompilerInstance().getPreprocessor(); + // Start preprocessing the specified input file. + Token Tok; + PP.EnterMainSourceFile(); + do { + PP.Lex(Tok); + PP.DumpToken(Tok, true); + fprintf(stderr, "\n"); + } while (Tok.isNot(tok::eof)); +} + +void GeneratePTHAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + if (CI.getFrontendOpts().OutputFile.empty() || + CI.getFrontendOpts().OutputFile == "-") { + // FIXME: Don't fail this way. + // FIXME: Verify that we can actually seek in the given file. + llvm::errs() << "ERROR: PTH requires an seekable file for output!\n"; + ::exit(1); + } + llvm::raw_fd_ostream *OS = + CI.createDefaultOutputFile(true, getCurrentFile()); + CacheTokens(CI.getPreprocessor(), OS); +} + +void ParseOnlyAction::ExecuteAction() { + Preprocessor &PP = getCompilerInstance().getPreprocessor(); + llvm::OwningPtr<Action> PA(new MinimalAction(PP)); + + Parser P(PP, *PA); + PP.EnterMainSourceFile(); + P.ParseTranslationUnit(); +} + +void PreprocessOnlyAction::ExecuteAction() { + Preprocessor &PP = getCompilerInstance().getPreprocessor(); + + Token Tok; + // Start parsing the specified input file. + PP.EnterMainSourceFile(); + do { + PP.Lex(Tok); + } while (Tok.isNot(tok::eof)); +} + +void PrintParseAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + Preprocessor &PP = getCompilerInstance().getPreprocessor(); + llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); + llvm::OwningPtr<Action> PA(CreatePrintParserActionsAction(PP, OS)); + + Parser P(PP, *PA); + PP.EnterMainSourceFile(); + P.ParseTranslationUnit(); +} + +void PrintPreprocessedAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); + DoPrintPreprocessedInput(CI.getPreprocessor(), OS, + CI.getPreprocessorOutputOpts()); +} + +void RewriteMacrosAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); + RewriteMacrosInInput(CI.getPreprocessor(), OS); +} + +void RewriteTestAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); + DoRewriteTest(CI.getPreprocessor(), OS); +} diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp new file mode 100644 index 000000000000..bd916386056b --- /dev/null +++ b/lib/Frontend/FrontendOptions.cpp @@ -0,0 +1,31 @@ +//===--- FrontendOptions.cpp ----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/FrontendOptions.h" +#include "llvm/ADT/StringSwitch.h" +using namespace clang; + +FrontendOptions::InputKind +FrontendOptions::getInputKindForExtension(llvm::StringRef Extension) { + return llvm::StringSwitch<InputKind>(Extension) + .Case("ast", IK_AST) + .Case("c", IK_C) + .Cases("S", "s", IK_Asm) + .Case("i", IK_PreprocessedC) + .Case("ii", IK_PreprocessedCXX) + .Case("m", IK_ObjC) + .Case("mi", IK_PreprocessedObjC) + .Cases("mm", "M", IK_ObjCXX) + .Case("mii", IK_PreprocessedObjCXX) + .Case("C", IK_CXX) + .Cases("C", "cc", "cp", IK_CXX) + .Cases("cpp", "CPP", "c++", "cxx", "hpp", IK_CXX) + .Case("cl", IK_OpenCL) + .Default(IK_C); +} diff --git a/lib/Frontend/HTMLDiagnostics.cpp b/lib/Frontend/HTMLDiagnostics.cpp index 145d53f3fc6e..3ba7abf38168 100644 --- a/lib/Frontend/HTMLDiagnostics.cpp +++ b/lib/Frontend/HTMLDiagnostics.cpp @@ -109,6 +109,8 @@ HTMLDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade) ReportDiag(*D, FilesMade); delete D; } + + BatchedDiags.clear(); } void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index c0b4ebaab03b..d19ae9861ed6 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -11,12 +11,16 @@ // //===----------------------------------------------------------------------===// -#include "clang/Frontend/InitHeaderSearch.h" -#include "clang/Lex/HeaderSearch.h" +#include "clang/Frontend/Utils.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/LangOptions.h" +#include "clang/Frontend/HeaderSearchOptions.h" +#include "clang/Lex/HeaderSearch.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Triple.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" #include "llvm/Config/config.h" @@ -26,6 +30,66 @@ #include <windows.h> #endif using namespace clang; +using namespace clang::frontend; + +namespace { + +/// InitHeaderSearch - This class makes it easier to set the search paths of +/// a HeaderSearch object. InitHeaderSearch stores several search path lists +/// internally, which can be sent to a HeaderSearch object in one swoop. +class InitHeaderSearch { + std::vector<DirectoryLookup> IncludeGroup[4]; + HeaderSearch& Headers; + bool Verbose; + std::string isysroot; + +public: + + InitHeaderSearch(HeaderSearch &HS, + bool verbose = false, const std::string &iSysroot = "") + : Headers(HS), Verbose(verbose), isysroot(iSysroot) {} + + /// AddPath - Add the specified path to the specified group list. + void AddPath(const llvm::StringRef &Path, IncludeDirGroup Group, + bool isCXXAware, bool isUserSupplied, + bool isFramework, bool IgnoreSysRoot = false); + + /// AddGnuCPlusPlusIncludePaths - Add the necessary paths to suport a gnu + /// libstdc++. + void AddGnuCPlusPlusIncludePaths(const std::string &Base, + const char *ArchDir, + const char *Dir32, + const char *Dir64, + const llvm::Triple &triple); + + /// AddMinGWCPlusPlusIncludePaths - Add the necessary paths to suport a MinGW + /// libstdc++. + void AddMinGWCPlusPlusIncludePaths(const std::string &Base, + const char *Arch, + const char *Version); + + /// AddDelimitedPaths - Add a list of paths delimited by the system PATH + /// separator. The processing follows that of the CPATH variable for gcc. + void AddDelimitedPaths(const char *String); + + // AddDefaultCIncludePaths - Add paths that should always be searched. + void AddDefaultCIncludePaths(const llvm::Triple &triple); + + // AddDefaultCPlusPlusIncludePaths - Add paths that should be searched when + // compiling c++. + void AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple); + + /// AddDefaultSystemIncludePaths - Adds the default system include paths so + /// that e.g. stdio.h is found. + void AddDefaultSystemIncludePaths(const LangOptions &Lang, + const llvm::Triple &triple); + + /// Realize - Merges all search path lists into one list and send it to + /// HeaderSearch. + void Realize(); +}; + +} void InitHeaderSearch::AddPath(const llvm::StringRef &Path, IncludeDirGroup Group, bool isCXXAware, @@ -82,9 +146,8 @@ void InitHeaderSearch::AddPath(const llvm::StringRef &Path, } -void InitHeaderSearch::AddEnvVarPaths(const char *Name) { - const char* at = getenv(Name); - if (!at || *at == 0) // Empty string should not add '.' path. +void InitHeaderSearch::AddDelimitedPaths(const char *at) { + if (*at == 0) // Empty string should not add '.' path. return; const char* delim = strchr(at, llvm::sys::PathSeparator); @@ -103,27 +166,30 @@ void InitHeaderSearch::AddEnvVarPaths(const char *Name) { } void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(const std::string &Base, + const char *ArchDir, const char *Dir32, const char *Dir64, const llvm::Triple &triple) { + // Add the common dirs + AddPath(Base, System, true, false, false); + AddPath(Base + "/backward", System, true, false, false); + + // Add the multilib dirs llvm::Triple::ArchType arch = triple.getArch(); bool is64bit = arch == llvm::Triple::ppc64 || arch == llvm::Triple::x86_64; - - AddPath(Base, System, true, false, false); if (is64bit) - AddPath(Base + "/" + Dir64, System, true, false, false); + AddPath(Base + "/" + ArchDir + "/" + Dir64, System, true, false, false); else - AddPath(Base + "/" + Dir32, System, true, false, false); - AddPath(Base + "/backward", System, true, false, false); + AddPath(Base + "/" + ArchDir + "/" + Dir32, System, true, false, false); } void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(const std::string &Base, const char *Arch, const char *Version) { - std::string localBase = Base + "/" + Arch + "/" + Version + "/include"; - AddPath(localBase, System, true, false, false); - AddPath(localBase + "/c++", System, true, false, false); - AddPath(localBase + "/c++/backward", System, true, false, false); + std::string localBase = Base + "/" + Arch + "/" + Version + "/include"; + AddPath(localBase, System, true, false, false); + AddPath(localBase + "/c++", System, true, false, false); + AddPath(localBase + "/c++/backward", System, true, false, false); } // FIXME: This probably should goto to some platform utils place. @@ -243,6 +309,16 @@ bool getVisualStudioDir(std::string &path) { void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple) { // FIXME: temporary hack: hard-coded paths. + llvm::StringRef CIncludeDirs(C_INCLUDE_DIRS); + if (CIncludeDirs != "") { + llvm::SmallVector<llvm::StringRef, 5> dirs; + CIncludeDirs.split(dirs, ":"); + for (llvm::SmallVectorImpl<llvm::StringRef>::iterator i = dirs.begin(); + i != dirs.end(); + ++i) + AddPath(*i, System, false, false, false); + return; + } llvm::Triple::OSType os = triple.getOS(); switch (os) { case llvm::Triple::Win32: @@ -288,6 +364,17 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple) { void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { llvm::Triple::OSType os = triple.getOS(); + llvm::StringRef CxxIncludeRoot(CXX_INCLUDE_ROOT); + if (CxxIncludeRoot != "") { + llvm::StringRef CxxIncludeArch(CXX_INCLUDE_ARCH); + if (CxxIncludeArch == "") + AddGnuCPlusPlusIncludePaths(CxxIncludeRoot, triple.str().c_str(), + CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR, triple); + else + AddGnuCPlusPlusIncludePaths(CxxIncludeRoot, CXX_INCLUDE_ARCH, + CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR, triple); + return; + } // FIXME: temporary hack: hard-coded paths. switch (os) { case llvm::Triple::Cygwin: @@ -310,113 +397,77 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl break; case llvm::Triple::Darwin: AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", - "i686-apple-darwin10", - "i686-apple-darwin10/x86_64", - triple); + "i686-apple-darwin10", "", "x86_64", triple); AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0", - "i686-apple-darwin8", - "i686-apple-darwin8", - triple); + "i686-apple-darwin8", "", "", triple); break; case llvm::Triple::Linux: // Ubuntu 7.10 - Gutsy Gibbon AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.3", - "i486-linux-gnu", - "i486-linux-gnu", - triple); + "i486-linux-gnu", "", "", triple); // Ubuntu 9.04 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.3", - "x86_64-linux-gnu/32", - "x86_64-linux-gnu", - triple); + "x86_64-linux-gnu","32", "", triple); + // Ubuntu 9.10 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1", + "x86_64-linux-gnu", "32", "", triple); // Fedora 8 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2", - "i386-redhat-linux", - "i386-redhat-linux", - triple); + "i386-redhat-linux", "", "", triple); // Fedora 9 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.0", - "i386-redhat-linux", - "i386-redhat-linux", - triple); + "i386-redhat-linux", "", "", triple); // Fedora 10 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2", - "i386-redhat-linux", - "i386-redhat-linux", - triple); + "i386-redhat-linux","", "", triple); + + // Fedora 11 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1", + "i586-redhat-linux","", "", triple); + // openSUSE 11.1 32 bit AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "i586-suse-linux", - "i586-suse-linux", - triple); + "i586-suse-linux", "", "", triple); // openSUSE 11.1 64 bit AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "x86_64-suse-linux/32", - "x86_64-suse-linux", - triple); + "x86_64-suse-linux", "32", "", triple); // openSUSE 11.2 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", - "i586-suse-linux", - "i586-suse-linux", - triple); + "i586-suse-linux", "", "", triple); AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", - "x86_64-suse-linux", - "x86_64-suse-linux", - triple); + "x86_64-suse-linux", "", "", triple); // Arch Linux 2008-06-24 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1", - "i686-pc-linux-gnu", - "i686-pc-linux-gnu", - triple); + "i686-pc-linux-gnu", "", "", triple); AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1", - "x86_64-unknown-linux-gnu", - "x86_64-unknown-linux-gnu", - triple); + "x86_64-unknown-linux-gnu", "", "", triple); // Gentoo x86 2009.1 stable AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4", - "i686-pc-linux-gnu", - "i686-pc-linux-gnu", - triple); + "/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4", + "i686-pc-linux-gnu", "", "", triple); // Gentoo x86 2009.0 stable AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/i686-pc-linux-gnu/4.3.2/include/g++-v4", - "i686-pc-linux-gnu", - "i686-pc-linux-gnu", - triple); + "/usr/lib/gcc/i686-pc-linux-gnu/4.3.2/include/g++-v4", + "i686-pc-linux-gnu", "", "", triple); // Gentoo x86 2008.0 stable AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4", - "i686-pc-linux-gnu", - "i686-pc-linux-gnu", - triple); + "/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4", + "i686-pc-linux-gnu", "", "", triple); // Ubuntu 8.10 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "i486-pc-linux-gnu", - "i486-pc-linux-gnu", - triple); + "i486-pc-linux-gnu", "", "", triple); // Ubuntu 9.04 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "i486-linux-gnu", - "i486-linux-gnu", - triple); + "i486-linux-gnu","", "", triple); // Gentoo amd64 stable AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4", - "i686-pc-linux-gnu", - "i686-pc-linux-gnu", - triple); + "i686-pc-linux-gnu", "", "", triple); // Exherbo (2009-10-26) - AddGnuCPlusPlusIncludePaths( - "/usr/include/c++/4.4.2", - "x86_64-pc-linux-gnu/32", - "x86_64-pc-linux-gnu", - triple); - AddGnuCPlusPlusIncludePaths( - "/usr/include/c++/4.4.2", - "i686-pc-linux-gnu", - "i686-pc-linux-gnu", - triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", + "x86_64-pc-linux-gnu", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", + "i686-pc-linux-gnu", "", "", triple); break; case llvm::Triple::FreeBSD: // DragonFly @@ -429,44 +480,27 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl case llvm::Triple::AuroraUX: // AuroraUX AddGnuCPlusPlusIncludePaths("/opt/gcc4/include/c++/4.2.4", - "i386-pc-solaris2.11", - "i386-pc-solaris2.11", - triple); + "i386-pc-solaris2.11", "", "", triple); break; default: break; } } -void InitHeaderSearch::AddDefaultFrameworkIncludePaths(const llvm::Triple &triple) { - llvm::Triple::OSType os = triple.getOS(); - if (os != llvm::Triple::Darwin) - return; - AddPath("/System/Library/Frameworks", System, true, false, true); - AddPath("/Library/Frameworks", System, true, false, true); -} - void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, const llvm::Triple &triple) { AddDefaultCIncludePaths(triple); - AddDefaultFrameworkIncludePaths(triple); + + // Add the default framework include paths on Darwin. + if (triple.getOS() == llvm::Triple::Darwin) { + AddPath("/System/Library/Frameworks", System, true, false, true); + AddPath("/Library/Frameworks", System, true, false, true); + } + if (Lang.CPlusPlus) AddDefaultCPlusPlusIncludePaths(triple); } -void InitHeaderSearch::AddDefaultEnvVarPaths(const LangOptions &Lang) { - AddEnvVarPaths("CPATH"); - if (Lang.CPlusPlus && Lang.ObjC1) - AddEnvVarPaths("OBJCPLUS_INCLUDE_PATH"); - else if (Lang.CPlusPlus) - AddEnvVarPaths("CPLUS_INCLUDE_PATH"); - else if (Lang.ObjC1) - AddEnvVarPaths("OBJC_INCLUDE_PATH"); - else - AddEnvVarPaths("C_INCLUDE_PATH"); -} - - /// RemoveDuplicates - If there are duplicate directory entries in the specified /// search list, remove the later (dead) ones. static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList, @@ -591,3 +625,40 @@ void InitHeaderSearch::Realize() { fprintf(stderr, "End of search list.\n"); } } + +void clang::ApplyHeaderSearchOptions(HeaderSearch &HS, + const HeaderSearchOptions &HSOpts, + const LangOptions &Lang, + const llvm::Triple &Triple) { + InitHeaderSearch Init(HS, HSOpts.Verbose, HSOpts.Sysroot); + + // Add the user defined entries. + for (unsigned i = 0, e = HSOpts.UserEntries.size(); i != e; ++i) { + const HeaderSearchOptions::Entry &E = HSOpts.UserEntries[i]; + Init.AddPath(E.Path, E.Group, false, E.IsUserSupplied, E.IsFramework, + false); + } + + // Add entries from CPATH and friends. + Init.AddDelimitedPaths(HSOpts.EnvIncPath.c_str()); + if (Lang.CPlusPlus && Lang.ObjC1) + Init.AddDelimitedPaths(HSOpts.ObjCXXEnvIncPath.c_str()); + else if (Lang.CPlusPlus) + Init.AddDelimitedPaths(HSOpts.CXXEnvIncPath.c_str()); + else if (Lang.ObjC1) + Init.AddDelimitedPaths(HSOpts.ObjCEnvIncPath.c_str()); + else + Init.AddDelimitedPaths(HSOpts.CEnvIncPath.c_str()); + + if (!HSOpts.BuiltinIncludePath.empty()) { + // Ignore the sys root, we *always* look for clang headers relative to + // supplied path. + Init.AddPath(HSOpts.BuiltinIncludePath, System, + false, false, false, /*IgnoreSysRoot=*/ true); + } + + if (HSOpts.UseStandardIncludes) + Init.AddDefaultSystemIncludePaths(Lang, Triple); + + Init.Realize(); +} diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 7139e55f0b60..4ee286dd265d 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -11,8 +11,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Frontend/InitPreprocessor.h" +#include "clang/Frontend/Utils.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Frontend/PreprocessorOptions.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/STLExtras.h" @@ -60,9 +61,7 @@ static void UndefineBuiltinMacro(std::vector<char> &Buf, const char *Macro) { Buf.push_back('\n'); } -/// Add the quoted name of an implicit include file. -static void AddQuotedIncludePath(std::vector<char> &Buf, - const std::string &File) { +std::string clang::NormalizeDashIncludePath(llvm::StringRef File) { // Implicit include paths should be resolved relative to the current // working directory first, and then use the regular header search // mechanism. The proper way to handle this is to have the @@ -75,9 +74,16 @@ static void AddQuotedIncludePath(std::vector<char> &Buf, if (!Path.exists()) Path = File; + return Lexer::Stringify(Path.str()); +} + +/// Add the quoted name of an implicit include file. +static void AddQuotedIncludePath(std::vector<char> &Buf, + const std::string &File) { + // Escape double quotes etc. Buf.push_back('"'); - std::string EscapedFile = Lexer::Stringify(Path.str()); + std::string EscapedFile = NormalizeDashIncludePath(File); Buf.insert(Buf.end(), EscapedFile.begin(), EscapedFile.end()); Buf.push_back('"'); } @@ -216,6 +222,14 @@ static void DefineTypeSize(const char *MacroName, unsigned TypeWidth, DefineBuiltinMacro(Buf, MacroBuf); } +/// DefineTypeSize - An overloaded helper that uses TargetInfo to determine +/// the width, suffix, and signedness of the given type +static void DefineTypeSize(const char *MacroName, TargetInfo::IntType Ty, + const TargetInfo &TI, std::vector<char> &Buf) { + DefineTypeSize(MacroName, TI.getTypeWidth(Ty), TI.getTypeConstantSuffix(Ty), + TI.isTypeSigned(Ty), Buf); +} + static void DefineType(const char *MacroName, TargetInfo::IntType Ty, std::vector<char> &Buf) { char MacroBuf[60]; @@ -223,6 +237,20 @@ static void DefineType(const char *MacroName, TargetInfo::IntType Ty, DefineBuiltinMacro(Buf, MacroBuf); } +static void DefineExactWidthIntType(TargetInfo::IntType Ty, + const TargetInfo &TI, std::vector<char> &Buf) { + char MacroBuf[60]; + int TypeWidth = TI.getTypeWidth(Ty); + sprintf(MacroBuf, "__INT%d_TYPE__", TypeWidth); + DefineType(MacroBuf, Ty, Buf); + + + const char *ConstSuffix = TargetInfo::getTypeConstantSuffix(Ty); + if (strlen(ConstSuffix) > 0) { + sprintf(MacroBuf, "__INT%d_C_SUFFIX__=%s", TypeWidth, ConstSuffix); + DefineBuiltinMacro(Buf, MacroBuf); + } +} static void InitializePredefinedMacros(const TargetInfo &TI, const LangOptions &LangOpts, @@ -346,14 +374,12 @@ static void InitializePredefinedMacros(const TargetInfo &TI, DefineBuiltinMacro(Buf, "__CHAR_BIT__=8"); DefineTypeSize("__SCHAR_MAX__", TI.getCharWidth(), "", true, Buf); - DefineTypeSize("__SHRT_MAX__", TI.getShortWidth(), "", true, Buf); - DefineTypeSize("__INT_MAX__", TI.getIntWidth(), "", true, Buf); - DefineTypeSize("__LONG_MAX__", TI.getLongWidth(), "L", true, Buf); - DefineTypeSize("__LONG_LONG_MAX__", TI.getLongLongWidth(), "LL", true, Buf); - DefineTypeSize("__WCHAR_MAX__", TI.getWCharWidth(), "", true, Buf); - TargetInfo::IntType IntMaxType = TI.getIntMaxType(); - DefineTypeSize("__INTMAX_MAX__", TI.getTypeWidth(IntMaxType), - TI.getTypeConstantSuffix(IntMaxType), true, Buf); + DefineTypeSize("__SHRT_MAX__", TargetInfo::SignedShort, TI, Buf); + DefineTypeSize("__INT_MAX__", TargetInfo::SignedInt, TI, Buf); + DefineTypeSize("__LONG_MAX__", TargetInfo::SignedLong, TI, Buf); + DefineTypeSize("__LONG_LONG_MAX__", TargetInfo::SignedLongLong, TI, Buf); + DefineTypeSize("__WCHAR_MAX__", TI.getWCharType(), TI, Buf); + DefineTypeSize("__INTMAX_MAX__", TI.getIntMaxType(), TI, Buf); DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Buf); DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Buf); @@ -374,23 +400,22 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (!LangOpts.CharIsSigned) DefineBuiltinMacro(Buf, "__CHAR_UNSIGNED__"); - // Define fixed-sized integer types for stdint.h - assert(TI.getCharWidth() == 8 && "unsupported target types"); - assert(TI.getShortWidth() == 16 && "unsupported target types"); - DefineBuiltinMacro(Buf, "__INT8_TYPE__=char"); - DefineBuiltinMacro(Buf, "__INT16_TYPE__=short"); - - if (TI.getIntWidth() == 32) - DefineBuiltinMacro(Buf, "__INT32_TYPE__=int"); - else { - assert(TI.getLongLongWidth() == 32 && "unsupported target types"); - DefineBuiltinMacro(Buf, "__INT32_TYPE__=long long"); - } - - // 16-bit targets doesn't necessarily have a 64-bit type. - if (TI.getLongLongWidth() == 64) - DefineType("__INT64_TYPE__", TI.getInt64Type(), Buf); + // Define exact-width integer types for stdint.h + sprintf(MacroBuf, "__INT%d_TYPE__=char", TI.getCharWidth()); + DefineBuiltinMacro(Buf, MacroBuf); + if (TI.getShortWidth() > TI.getCharWidth()) + DefineExactWidthIntType(TargetInfo::SignedShort, TI, Buf); + + if (TI.getIntWidth() > TI.getShortWidth()) + DefineExactWidthIntType(TargetInfo::SignedInt, TI, Buf); + + if (TI.getLongWidth() > TI.getIntWidth()) + DefineExactWidthIntType(TargetInfo::SignedLong, TI, Buf); + + if (TI.getLongLongWidth() > TI.getLongWidth()) + DefineExactWidthIntType(TargetInfo::SignedLongLong, TI, Buf); + // Add __builtin_va_list typedef. { const char *VAList = TI.getVAListDeclaration(); @@ -443,7 +468,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI, /// environment ready to process a single file. This returns true on error. /// void clang::InitializePreprocessor(Preprocessor &PP, - const PreprocessorInitOptions &InitOpts) { + const PreprocessorOptions &InitOpts, + const HeaderSearchOptions &HSOpts) { std::vector<char> PredefineBuffer; const char *LineDirective = "# 1 \"<built-in>\" 3\n"; @@ -451,7 +477,7 @@ void clang::InitializePreprocessor(Preprocessor &PP, LineDirective, LineDirective+strlen(LineDirective)); // Install things like __POWERPC__, __GNUC__, etc into the macro table. - if (InitOpts.getUsePredefines()) + if (InitOpts.UsePredefines) InitializePredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(), PredefineBuffer); @@ -462,30 +488,33 @@ void clang::InitializePreprocessor(Preprocessor &PP, LineDirective, LineDirective+strlen(LineDirective)); // Process #define's and #undef's in the order they are given. - for (PreprocessorInitOptions::macro_iterator I = InitOpts.macro_begin(), - E = InitOpts.macro_end(); I != E; ++I) { - if (I->second) // isUndef - UndefineBuiltinMacro(PredefineBuffer, I->first.c_str()); + for (unsigned i = 0, e = InitOpts.Macros.size(); i != e; ++i) { + if (InitOpts.Macros[i].second) // isUndef + UndefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str()); else - DefineBuiltinMacro(PredefineBuffer, I->first.c_str()); + DefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str()); } // If -imacros are specified, include them now. These are processed before // any -include directives. - for (PreprocessorInitOptions::imacro_iterator I = InitOpts.imacro_begin(), - E = InitOpts.imacro_end(); I != E; ++I) - AddImplicitIncludeMacros(PredefineBuffer, *I); + for (unsigned i = 0, e = InitOpts.MacroIncludes.size(); i != e; ++i) + AddImplicitIncludeMacros(PredefineBuffer, InitOpts.MacroIncludes[i]); // Process -include directives. - for (PreprocessorInitOptions::include_iterator I = InitOpts.include_begin(), - E = InitOpts.include_end(); I != E; ++I) { - if (I->second) // isPTH - AddImplicitIncludePTH(PredefineBuffer, PP, I->first); + for (unsigned i = 0, e = InitOpts.Includes.size(); i != e; ++i) { + const std::string &Path = InitOpts.Includes[i]; + if (Path == InitOpts.ImplicitPTHInclude) + AddImplicitIncludePTH(PredefineBuffer, PP, Path); else - AddImplicitInclude(PredefineBuffer, I->first); + AddImplicitInclude(PredefineBuffer, Path); } // Null terminate PredefinedBuffer and add it. PredefineBuffer.push_back(0); PP.setPredefines(&PredefineBuffer[0]); + + // Initialize the header search object. + ApplyHeaderSearchOptions(PP.getHeaderSearchInfo(), HSOpts, + PP.getLangOptions(), + PP.getTargetInfo().getTriple()); } diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 26f426ba329b..ca7aa3260c62 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -13,6 +13,7 @@ #include "clang/Frontend/PCHReader.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/Utils.h" #include "../Sema/Sema.h" // FIXME: move Sema headers elsewhere #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -104,6 +105,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) { PARSE_LANGOPT_IMPORTANT(NoInline, diag::warn_pch_no_inline); PARSE_LANGOPT_IMPORTANT(AccessControl, diag::warn_pch_access_control); PARSE_LANGOPT_IMPORTANT(CharIsSigned, diag::warn_pch_char_signed); + PARSE_LANGOPT_IMPORTANT(ShortWChar, diag::warn_pch_short_wchar); if ((PPLangOpts.getGCMode() != 0) != (LangOpts.getGCMode() != 0)) { Reader.Diag(diag::warn_pch_gc_mode) << LangOpts.getGCMode() << PPLangOpts.getGCMode(); @@ -121,83 +123,56 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) { return false; } -bool PCHValidator::ReadTargetTriple(const std::string &Triple) { - if (Triple != PP.getTargetInfo().getTriple().getTriple()) { - Reader.Diag(diag::warn_pch_target_triple) - << Triple << PP.getTargetInfo().getTriple().getTriple(); - return true; - } - return false; -} - -/// \brief Split the given string into a vector of lines, eliminating -/// any empty lines in the process. -/// -/// \param Str the string to split. -/// \param Len the length of Str. -/// \param KeepEmptyLines true if empty lines should be included -/// \returns a vector of lines, with the line endings removed -static std::vector<std::string> splitLines(const char *Str, unsigned Len, - bool KeepEmptyLines = false) { - std::vector<std::string> Lines; - for (unsigned LineStart = 0; LineStart < Len; ++LineStart) { - unsigned LineEnd = LineStart; - while (LineEnd < Len && Str[LineEnd] != '\n') - ++LineEnd; - if (LineStart != LineEnd || KeepEmptyLines) - Lines.push_back(std::string(&Str[LineStart], &Str[LineEnd])); - LineStart = LineEnd; - } - return Lines; -} - -/// \brief Determine whether the string Haystack starts with the -/// substring Needle. -static bool startsWith(const std::string &Haystack, const char *Needle) { - for (unsigned I = 0, N = Haystack.size(); Needle[I] != 0; ++I) { - if (I == N) - return false; - if (Haystack[I] != Needle[I]) - return false; - } +bool PCHValidator::ReadTargetTriple(llvm::StringRef Triple) { + if (Triple == PP.getTargetInfo().getTriple().str()) + return false; + Reader.Diag(diag::warn_pch_target_triple) + << Triple << PP.getTargetInfo().getTriple().str(); return true; } -/// \brief Determine whether the string Haystack starts with the -/// substring Needle. -static inline bool startsWith(const std::string &Haystack, - const std::string &Needle) { - return startsWith(Haystack, Needle.c_str()); -} - -bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef, - unsigned PCHPredefLen, +bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef, FileID PCHBufferID, + llvm::StringRef OriginalFileName, std::string &SuggestedPredefines) { - const char *Predef = PP.getPredefines().c_str(); - unsigned PredefLen = PP.getPredefines().size(); - - // If the two predefines buffers compare equal, we're done! - if (PredefLen == PCHPredefLen && - strncmp(Predef, PCHPredef, PCHPredefLen) == 0) + // We are in the context of an implicit include, so the predefines buffer will + // have a #include entry for the PCH file itself (as normalized by the + // preprocessor initialization). Find it and skip over it in the checking + // below. + llvm::SmallString<256> PCHInclude; + PCHInclude += "#include \""; + PCHInclude += NormalizeDashIncludePath(OriginalFileName); + PCHInclude += "\"\n"; + std::pair<llvm::StringRef,llvm::StringRef> Split = + llvm::StringRef(PP.getPredefines()).split(PCHInclude.str()); + llvm::StringRef Left = Split.first, Right = Split.second; + assert(Left != PP.getPredefines() && "Missing PCH include entry!"); + + // If the predefines is equal to the joined left and right halves, we're done! + if (Left.size() + Right.size() == PCHPredef.size() && + PCHPredef.startswith(Left) && PCHPredef.endswith(Right)) return false; SourceManager &SourceMgr = PP.getSourceManager(); - // The predefines buffers are different. Determine what the - // differences are, and whether they require us to reject the PCH - // file. - std::vector<std::string> CmdLineLines = splitLines(Predef, PredefLen); - std::vector<std::string> PCHLines = splitLines(PCHPredef, PCHPredefLen); + // The predefines buffers are different. Determine what the differences are, + // and whether they require us to reject the PCH file. + llvm::SmallVector<llvm::StringRef, 8> PCHLines; + PCHPredef.split(PCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); + + llvm::SmallVector<llvm::StringRef, 8> CmdLineLines; + Left.split(CmdLineLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); + Right.split(CmdLineLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); - // Sort both sets of predefined buffer lines, since + // Sort both sets of predefined buffer lines, since we allow some extra + // definitions and they may appear at any point in the output. std::sort(CmdLineLines.begin(), CmdLineLines.end()); std::sort(PCHLines.begin(), PCHLines.end()); - // Determine which predefines that where used to build the PCH file - // are missing from the command line. - std::vector<std::string> MissingPredefines; + // Determine which predefines that were used to build the PCH file are missing + // from the command line. + std::vector<llvm::StringRef> MissingPredefines; std::set_difference(PCHLines.begin(), PCHLines.end(), CmdLineLines.begin(), CmdLineLines.end(), std::back_inserter(MissingPredefines)); @@ -205,31 +180,30 @@ bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef, bool MissingDefines = false; bool ConflictingDefines = false; for (unsigned I = 0, N = MissingPredefines.size(); I != N; ++I) { - const std::string &Missing = MissingPredefines[I]; - if (!startsWith(Missing, "#define ") != 0) { + llvm::StringRef Missing = MissingPredefines[I]; + if (!Missing.startswith("#define ")) { Reader.Diag(diag::warn_pch_compiler_options_mismatch); return true; } - // This is a macro definition. Determine the name of the macro - // we're defining. + // This is a macro definition. Determine the name of the macro we're + // defining. std::string::size_type StartOfMacroName = strlen("#define "); std::string::size_type EndOfMacroName = Missing.find_first_of("( \n\r", StartOfMacroName); assert(EndOfMacroName != std::string::npos && "Couldn't find the end of the macro name"); - std::string MacroName = Missing.substr(StartOfMacroName, - EndOfMacroName - StartOfMacroName); + llvm::StringRef MacroName = Missing.slice(StartOfMacroName, EndOfMacroName); - // Determine whether this macro was given a different definition - // on the command line. - std::string MacroDefStart = "#define " + MacroName; + // Determine whether this macro was given a different definition on the + // command line. + std::string MacroDefStart = "#define " + MacroName.str(); std::string::size_type MacroDefLen = MacroDefStart.size(); - std::vector<std::string>::iterator ConflictPos + llvm::SmallVector<llvm::StringRef, 8>::iterator ConflictPos = std::lower_bound(CmdLineLines.begin(), CmdLineLines.end(), MacroDefStart); for (; ConflictPos != CmdLineLines.end(); ++ConflictPos) { - if (!startsWith(*ConflictPos, MacroDefStart)) { + if (!ConflictPos->startswith(MacroDefStart)) { // Different macro; we're done. ConflictPos = CmdLineLines.end(); break; @@ -250,21 +224,18 @@ bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef, << MacroName; // Show the definition of this macro within the PCH file. - const char *MissingDef = strstr(PCHPredef, Missing.c_str()); - unsigned Offset = MissingDef - PCHPredef; - SourceLocation PCHMissingLoc - = SourceMgr.getLocForStartOfFile(PCHBufferID) - .getFileLocWithOffset(Offset); - Reader.Diag(PCHMissingLoc, diag::note_pch_macro_defined_as) - << MacroName; + llvm::StringRef::size_type Offset = PCHPredef.find(Missing); + assert(Offset != llvm::StringRef::npos && "Unable to find macro!"); + SourceLocation PCHMissingLoc = SourceMgr.getLocForStartOfFile(PCHBufferID) + .getFileLocWithOffset(Offset); + Reader.Diag(PCHMissingLoc, diag::note_pch_macro_defined_as) << MacroName; ConflictingDefines = true; continue; } - // If the macro doesn't conflict, then we'll just pick up the - // macro definition from the PCH file. Warn the user that they - // made a mistake. + // If the macro doesn't conflict, then we'll just pick up the macro + // definition from the PCH file. Warn the user that they made a mistake. if (ConflictingDefines) continue; // Don't complain if there are already conflicting defs @@ -274,10 +245,9 @@ bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef, } // Show the definition of this macro within the PCH file. - const char *MissingDef = strstr(PCHPredef, Missing.c_str()); - unsigned Offset = MissingDef - PCHPredef; - SourceLocation PCHMissingLoc - = SourceMgr.getLocForStartOfFile(PCHBufferID) + llvm::StringRef::size_type Offset = PCHPredef.find(Missing); + assert(Offset != llvm::StringRef::npos && "Unable to find macro!"); + SourceLocation PCHMissingLoc = SourceMgr.getLocForStartOfFile(PCHBufferID) .getFileLocWithOffset(Offset); Reader.Diag(PCHMissingLoc, diag::note_using_macro_def_from_pch); } @@ -289,13 +259,13 @@ bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef, // parameters that were not present when building the PCH // file. Extra #defines are okay, so long as the identifiers being // defined were not used within the precompiled header. - std::vector<std::string> ExtraPredefines; + std::vector<llvm::StringRef> ExtraPredefines; std::set_difference(CmdLineLines.begin(), CmdLineLines.end(), PCHLines.begin(), PCHLines.end(), std::back_inserter(ExtraPredefines)); for (unsigned I = 0, N = ExtraPredefines.size(); I != N; ++I) { - const std::string &Extra = ExtraPredefines[I]; - if (!startsWith(Extra, "#define ") != 0) { + llvm::StringRef &Extra = ExtraPredefines[I]; + if (!Extra.startswith("#define ")) { Reader.Diag(diag::warn_pch_compiler_options_mismatch); return true; } @@ -307,16 +277,13 @@ bool PCHValidator::ReadPredefinesBuffer(const char *PCHPredef, = Extra.find_first_of("( \n\r", StartOfMacroName); assert(EndOfMacroName != std::string::npos && "Couldn't find the end of the macro name"); - std::string MacroName = Extra.substr(StartOfMacroName, - EndOfMacroName - StartOfMacroName); + llvm::StringRef MacroName = Extra.slice(StartOfMacroName, EndOfMacroName); // Check whether this name was used somewhere in the PCH file. If // so, defining it as a macro could change behavior, so we reject // the PCH file. - if (IdentifierInfo *II = Reader.get(MacroName.c_str(), - MacroName.c_str() + MacroName.size())) { - Reader.Diag(diag::warn_macro_name_used_in_pch) - << II; + if (IdentifierInfo *II = Reader.get(MacroName)) { + Reader.Diag(diag::warn_macro_name_used_in_pch) << II; return true; } @@ -650,11 +617,11 @@ bool PCHReader::Error(const char *Msg) { /// /// \returns true if there was a mismatch (in which case the PCH file /// should be ignored), or false otherwise. -bool PCHReader::CheckPredefinesBuffer(const char *PCHPredef, - unsigned PCHPredefLen, +bool PCHReader::CheckPredefinesBuffer(llvm::StringRef PCHPredef, FileID PCHBufferID) { if (Listener) - return Listener->ReadPredefinesBuffer(PCHPredef, PCHPredefLen, PCHBufferID, + return Listener->ReadPredefinesBuffer(PCHPredef, PCHBufferID, + ActualOriginalFileName, SuggestedPredefines); return false; } @@ -1364,7 +1331,8 @@ PCHReader::ReadPCHBlock() { break; case pch::ORIGINAL_FILE_NAME: - OriginalFileName.assign(BlobStart, BlobLen); + ActualOriginalFileName.assign(BlobStart, BlobLen); + OriginalFileName = ActualOriginalFileName; MaybeAddSystemRootToFilename(OriginalFileName); break; @@ -1403,10 +1371,7 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { // // FIXME: This shouldn't be here, we should just take a raw_ostream. std::string ErrStr; - if (FileName == "-") - Buffer.reset(llvm::MemoryBuffer::getSTDIN()); - else - Buffer.reset(llvm::MemoryBuffer::getFile(FileName.c_str(), &ErrStr)); + Buffer.reset(llvm::MemoryBuffer::getFileOrSTDIN(FileName, &ErrStr)); if (!Buffer) { Error(ErrStr.c_str()); return IgnorePCH; @@ -1478,7 +1443,7 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { } // Check the predefines buffer. - if (CheckPredefinesBuffer(PCHPredefines, PCHPredefinesLen, + if (CheckPredefinesBuffer(llvm::StringRef(PCHPredefines, PCHPredefinesLen), PCHPredefinesBufferID)) return IgnorePCH; @@ -1741,6 +1706,7 @@ bool PCHReader::ParseLanguageOptions( PARSE_LANGOPT(NoInline); PARSE_LANGOPT(AccessControl); PARSE_LANGOPT(CharIsSigned); + PARSE_LANGOPT(ShortWChar); LangOpts.setGCMode((LangOptions::GCMode)Record[Idx]); ++Idx; LangOpts.setVisibilityMode((LangOptions::VisibilityMode)Record[Idx]); @@ -2213,6 +2179,14 @@ PCHReader::GetTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, return ReadDeclExpr(); case TemplateArgument::Type: return GetDeclaratorInfo(Record, Index); + case TemplateArgument::Template: { + SourceLocation + QualStart = SourceLocation::getFromRawEncoding(Record[Index++]), + QualEnd = SourceLocation::getFromRawEncoding(Record[Index++]), + TemplateNameLoc = SourceLocation::getFromRawEncoding(Record[Index++]); + return TemplateArgumentLocInfo(SourceRange(QualStart, QualEnd), + TemplateNameLoc); + } case TemplateArgument::Null: case TemplateArgument::Integral: case TemplateArgument::Declaration: diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index b9ece21f74c3..6a92a2db51a8 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -264,7 +264,12 @@ void PCHDeclReader::VisitObjCClassDecl(ObjCClassDecl *CD) { ClassRefs.reserve(NumClassRefs); for (unsigned I = 0; I != NumClassRefs; ++I) ClassRefs.push_back(cast<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++]))); - CD->setClassList(*Reader.getContext(), ClassRefs.data(), NumClassRefs); + llvm::SmallVector<SourceLocation, 16> SLocs; + SLocs.reserve(NumClassRefs); + for (unsigned I = 0; I != NumClassRefs; ++I) + SLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++])); + CD->setClassList(*Reader.getContext(), ClassRefs.data(), SLocs.data(), + NumClassRefs); } void PCHDeclReader::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *FPD) { @@ -442,6 +447,8 @@ Attr *PCHReader::ReadAttributes() { (BlocksAttr::BlocksAttrTypes)Record[Idx++]); break; + SIMPLE_ATTR(CDecl); + case Attr::Cleanup: New = ::new (*Context) CleanupAttr( cast<FunctionDecl>(GetDecl(Record[Idx++]))); diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index de56166125ed..8a45ebce1b9d 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -765,6 +765,7 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) { // be enabled. Record.push_back(LangOpts.CharIsSigned); // Whether char is a signed or // unsigned type + Record.push_back(LangOpts.ShortWChar); // force wchar_t to be unsigned short Record.push_back(LangOpts.getGCMode()); Record.push_back(LangOpts.getVisibilityMode()); Record.push_back(LangOpts.getStackProtectorMode()); @@ -1247,9 +1248,9 @@ void PCHWriter::WriteType(QualType T) { // Emit the type's representation. PCHTypeWriter W(*this, Record); - if (T.hasNonFastQualifiers()) { - Qualifiers Qs = T.getQualifiers(); - AddTypeRef(T.getUnqualifiedType(), Record); + if (T.hasLocalNonFastQualifiers()) { + Qualifiers Qs = T.getLocalQualifiers(); + AddTypeRef(T.getLocalUnqualifiedType(), Record); Record.push_back(Qs.getAsOpaqueValue()); W.Code = pch::TYPE_EXT_QUAL; } else { @@ -1767,6 +1768,9 @@ void PCHWriter::WriteAttributeRecord(const Attr *Attr) { Record.push_back(cast<BlocksAttr>(Attr)->getType()); // FIXME: stable break; + case Attr::CDecl: + break; + case Attr::Cleanup: AddDeclRef(cast<CleanupAttr>(Attr)->getFunctionDecl(), Record); break; @@ -2118,6 +2122,12 @@ void PCHWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg, case TemplateArgument::Type: AddDeclaratorInfo(Arg.getLocInfo().getAsDeclaratorInfo(), Record); break; + case TemplateArgument::Template: + Record.push_back( + Arg.getTemplateQualifierRange().getBegin().getRawEncoding()); + Record.push_back(Arg.getTemplateQualifierRange().getEnd().getRawEncoding()); + Record.push_back(Arg.getTemplateNameLoc().getRawEncoding()); + break; case TemplateArgument::Null: case TemplateArgument::Integral: case TemplateArgument::Declaration: @@ -2144,10 +2154,10 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) { return; } - unsigned FastQuals = T.getFastQualifiers(); + unsigned FastQuals = T.getLocalFastQualifiers(); T.removeFastQualifiers(); - if (T.hasNonFastQualifiers()) { + if (T.hasLocalNonFastQualifiers()) { pch::TypeID &ID = TypeIDs[T]; if (ID == 0) { // We haven't seen these qualifiers applied to this type before. @@ -2162,7 +2172,7 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) { return; } - assert(!T.hasQualifiers()); + assert(!T.hasLocalQualifiers()); if (const BuiltinType *BT = dyn_cast<BuiltinType>(T.getTypePtr())) { pch::TypeID ID = 0; diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index 8997e661a5a1..c7bfee2c8bcd 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -260,7 +260,9 @@ void PCHDeclWriter::VisitObjCClassDecl(ObjCClassDecl *D) { VisitDecl(D); Record.push_back(D->size()); for (ObjCClassDecl::iterator I = D->begin(), IEnd = D->end(); I != IEnd; ++I) - Writer.AddDeclRef(*I, Record); + Writer.AddDeclRef(I->getInterface(), Record); + for (ObjCClassDecl::iterator I = D->begin(), IEnd = D->end(); I != IEnd; ++I) + Writer.AddSourceLocation(I->getLocation(), Record); Code = pch::DECL_OBJC_CLASS; } diff --git a/lib/Frontend/PlistDiagnostics.cpp b/lib/Frontend/PlistDiagnostics.cpp index 1be9ea8b8c41..6bcf39a92a24 100644 --- a/lib/Frontend/PlistDiagnostics.cpp +++ b/lib/Frontend/PlistDiagnostics.cpp @@ -37,6 +37,7 @@ namespace { const std::string OutputFile; const LangOptions &LangOpts; llvm::OwningPtr<PathDiagnosticClient> SubPD; + bool flushed; public: PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts, PathDiagnosticClient *subPD); @@ -61,7 +62,7 @@ namespace { PlistDiagnostics::PlistDiagnostics(const std::string& output, const LangOptions &LO, PathDiagnosticClient *subPD) - : OutputFile(output), LangOpts(LO), SubPD(subPD) {} + : OutputFile(output), LangOpts(LO), SubPD(subPD), flushed(false) {} PathDiagnosticClient* clang::CreatePlistDiagnosticClient(const std::string& s, const Preprocessor &PP, @@ -310,6 +311,11 @@ void PlistDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) { void PlistDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade) { + + if (flushed) + return; + + flushed = true; // Build up a set of FIDs that we use by scanning the locations and // ranges of the diagnostics. @@ -423,4 +429,6 @@ void PlistDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> if (FilesMade) FilesMade->push_back(OutputFile); + + BatchedDiags.clear(); } diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp index 25b40c78183c..deb5498b906e 100644 --- a/lib/Frontend/PrintParserCallbacks.cpp +++ b/lib/Frontend/PrintParserCallbacks.cpp @@ -79,10 +79,11 @@ namespace { /// Scope will always be top level file scope. Action::DeclPtrTy ActOnForwardClassDeclaration(SourceLocation AtClassLoc, IdentifierInfo **IdentList, + SourceLocation *IdentLocs, unsigned NumElts) { Out << __FUNCTION__ << "\n"; return MinimalAction::ActOnForwardClassDeclaration(AtClassLoc, IdentList, - NumElts); + IdentLocs, NumElts); } // Pure Printing diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index 630a093a4bf6..37424057809c 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -13,13 +13,14 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/Utils.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/PreprocessorOutputOptions.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/PPCallbacks.h" -#include "clang/Lex/Preprocessor.h" #include "clang/Lex/Pragma.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Lex/TokenConcatenation.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/Diagnostic.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Config/config.h" @@ -439,7 +440,7 @@ namespace { }; } -void clang::DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) { +static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) { // -dM mode just scans and ignores all tokens in the files, then dumps out // the macro table at the end. PP.EnterMainSourceFile(); @@ -467,18 +468,23 @@ void clang::DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) { /// DoPrintPreprocessedInput - This implements -E mode. /// void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS, - bool EnableCommentOutput, - bool EnableMacroCommentOutput, - bool DisableLineMarkers, - bool DumpDefines) { + const PreprocessorOutputOptions &Opts) { + // Show macros with no output is handled specially. + if (!Opts.ShowCPP) { + assert(Opts.ShowMacros && "Not yet implemented!"); + DoPrintMacros(PP, OS); + return; + } + // Inform the preprocessor whether we want it to retain comments or not, due // to -C or -CC. - PP.SetCommentRetentionState(EnableCommentOutput, EnableMacroCommentOutput); + PP.SetCommentRetentionState(Opts.ShowComments, Opts.ShowMacroComments); OS->SetBufferSize(64*1024); PrintPPOutputPPCallbacks *Callbacks = - new PrintPPOutputPPCallbacks(PP, *OS, DisableLineMarkers, DumpDefines); + new PrintPPOutputPPCallbacks(PP, *OS, !Opts.ShowLineMarkers, + Opts.ShowMacros); PP.AddPragmaHandler(0, new UnknownPragmaHandler("#pragma", Callbacks)); PP.AddPragmaHandler("GCC", new UnknownPragmaHandler("#pragma GCC", Callbacks)); diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index 24ad69e3e0d3..06955e5c30b6 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -744,7 +744,7 @@ void RewriteObjC::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) { typedefString += "\n"; for (ObjCClassDecl::iterator I = ClassDecl->begin(), E = ClassDecl->end(); I != E; ++I) { - ObjCInterfaceDecl *ForwardDecl = *I; + ObjCInterfaceDecl *ForwardDecl = I->getInterface(); typedefString += "#ifndef _REWRITER_typedef_"; typedefString += ForwardDecl->getNameAsString(); typedefString += "\n"; diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 4f8c804844b0..6ab0e1605276 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -39,9 +39,16 @@ static const enum llvm::raw_ostream::Colors savedColor = const unsigned WordWrapIndentation = 6; TextDiagnosticPrinter::TextDiagnosticPrinter(llvm::raw_ostream &os, - const DiagnosticOptions &diags) + const DiagnosticOptions &diags, + bool _OwnsOutputStream) : OS(os), LangOpts(0), DiagOpts(&diags), - LastCaretDiagnosticWasNote(false) { + LastCaretDiagnosticWasNote(0), + OwnsOutputStream(_OwnsOutputStream) { +} + +TextDiagnosticPrinter::~TextDiagnosticPrinter() { + if (OwnsOutputStream) + delete &OS; } void TextDiagnosticPrinter:: diff --git a/lib/Frontend/VerifyDiagnosticsClient.cpp b/lib/Frontend/VerifyDiagnosticsClient.cpp new file mode 100644 index 000000000000..2891aec50444 --- /dev/null +++ b/lib/Frontend/VerifyDiagnosticsClient.cpp @@ -0,0 +1,344 @@ +//===--- VerifyDiagnosticsClient.cpp - Verifying Diagnostic Client --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a concrete diagnostic client, which buffers the diagnostic messages. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/VerifyDiagnosticsClient.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/TextDiagnosticBuffer.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +VerifyDiagnosticsClient::VerifyDiagnosticsClient(Diagnostic &_Diags, + DiagnosticClient *_Primary) + : Diags(_Diags), PrimaryClient(_Primary), + Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0), NumErrors(0) { +} + +VerifyDiagnosticsClient::~VerifyDiagnosticsClient() { + CheckDiagnostics(); +} + +// DiagnosticClient interface. + +void VerifyDiagnosticsClient::BeginSourceFile(const LangOptions &LangOpts, + const Preprocessor *PP) { + // FIXME: Const hack, we screw up the preprocessor but in practice its ok + // because it doesn't get reused. It would be better if we could make a copy + // though. + CurrentPreprocessor = const_cast<Preprocessor*>(PP); + + PrimaryClient->BeginSourceFile(LangOpts, PP); +} + +void VerifyDiagnosticsClient::EndSourceFile() { + CheckDiagnostics(); + + PrimaryClient->EndSourceFile(); + + CurrentPreprocessor = 0; +} + +void VerifyDiagnosticsClient::HandleDiagnostic(Diagnostic::Level DiagLevel, + const DiagnosticInfo &Info) { + // Send the diagnostic to the buffer, we will check it once we reach the end + // of the source file (or are destructed). + Buffer->HandleDiagnostic(DiagLevel, Info); +} + +// FIXME: It would be nice to just get this from the primary diagnostic client +// or something. +bool VerifyDiagnosticsClient::HadErrors() { + CheckDiagnostics(); + + return NumErrors != 0; +} + +//===----------------------------------------------------------------------===// +// Checking diagnostics implementation. +//===----------------------------------------------------------------------===// + +typedef TextDiagnosticBuffer::DiagList DiagList; +typedef TextDiagnosticBuffer::const_iterator const_diag_iterator; + +/// FindDiagnostics - Go through the comment and see if it indicates expected +/// diagnostics. If so, then put them in a diagnostic list. +/// +static void FindDiagnostics(const char *CommentStart, unsigned CommentLen, + DiagList &ExpectedDiags, + Preprocessor &PP, SourceLocation Pos, + const char *ExpectedStr) { + const char *CommentEnd = CommentStart+CommentLen; + unsigned ExpectedStrLen = strlen(ExpectedStr); + + // Find all expected-foo diagnostics in the string and add them to + // ExpectedDiags. + while (CommentStart != CommentEnd) { + CommentStart = std::find(CommentStart, CommentEnd, 'e'); + if (unsigned(CommentEnd-CommentStart) < ExpectedStrLen) return; + + // If this isn't expected-foo, ignore it. + if (memcmp(CommentStart, ExpectedStr, ExpectedStrLen)) { + ++CommentStart; + continue; + } + + CommentStart += ExpectedStrLen; + + // Skip whitespace. + while (CommentStart != CommentEnd && + isspace(CommentStart[0])) + ++CommentStart; + + // Default, if we find the '{' now, is 1 time. + int Times = 1; + int Temp = 0; + // In extended syntax, there could be a digit now. + while (CommentStart != CommentEnd && + CommentStart[0] >= '0' && CommentStart[0] <= '9') { + Temp *= 10; + Temp += CommentStart[0] - '0'; + ++CommentStart; + } + if (Temp > 0) + Times = Temp; + + // Skip whitespace again. + while (CommentStart != CommentEnd && + isspace(CommentStart[0])) + ++CommentStart; + + // We should have a {{ now. + if (CommentEnd-CommentStart < 2 || + CommentStart[0] != '{' || CommentStart[1] != '{') { + if (std::find(CommentStart, CommentEnd, '{') != CommentEnd) + PP.Diag(Pos, diag::err_verify_bogus_characters); + else + PP.Diag(Pos, diag::err_verify_missing_start); + return; + } + CommentStart += 2; + + // Find the }}. + const char *ExpectedEnd = CommentStart; + while (1) { + ExpectedEnd = std::find(ExpectedEnd, CommentEnd, '}'); + if (CommentEnd-ExpectedEnd < 2) { + PP.Diag(Pos, diag::err_verify_missing_end); + return; + } + + if (ExpectedEnd[1] == '}') + break; + + ++ExpectedEnd; // Skip over singular }'s + } + + std::string Msg(CommentStart, ExpectedEnd); + std::string::size_type FindPos; + while ((FindPos = Msg.find("\\n")) != std::string::npos) + Msg.replace(FindPos, 2, "\n"); + // Add is possibly multiple times. + for (int i = 0; i < Times; ++i) + ExpectedDiags.push_back(std::make_pair(Pos, Msg)); + + CommentStart = ExpectedEnd; + } +} + +/// FindExpectedDiags - Lex the main source file to find all of the +// expected errors and warnings. +static void FindExpectedDiags(Preprocessor &PP, + DiagList &ExpectedErrors, + DiagList &ExpectedWarnings, + DiagList &ExpectedNotes) { + // Create a raw lexer to pull all the comments out of the main file. We don't + // want to look in #include'd headers for expected-error strings. + FileID FID = PP.getSourceManager().getMainFileID(); + if (PP.getSourceManager().getMainFileID().isInvalid()) + return; + + // Create a lexer to lex all the tokens of the main file in raw mode. + Lexer RawLex(FID, PP.getSourceManager(), PP.getLangOptions()); + + // Return comments as tokens, this is how we find expected diagnostics. + RawLex.SetCommentRetentionState(true); + + Token Tok; + Tok.setKind(tok::comment); + while (Tok.isNot(tok::eof)) { + RawLex.Lex(Tok); + if (!Tok.is(tok::comment)) continue; + + std::string Comment = PP.getSpelling(Tok); + if (Comment.empty()) continue; + + // Find all expected errors. + FindDiagnostics(&Comment[0], Comment.size(), ExpectedErrors, PP, + Tok.getLocation(), "expected-error"); + + // Find all expected warnings. + FindDiagnostics(&Comment[0], Comment.size(), ExpectedWarnings, PP, + Tok.getLocation(), "expected-warning"); + + // Find all expected notes. + FindDiagnostics(&Comment[0], Comment.size(), ExpectedNotes, PP, + Tok.getLocation(), "expected-note"); + }; +} + +/// PrintProblem - This takes a diagnostic map of the delta between expected and +/// seen diagnostics. If there's anything in it, then something unexpected +/// happened. Print the map out in a nice format and return "true". If the map +/// is empty and we're not going to print things, then return "false". +/// +static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr, + const_diag_iterator diag_begin, + const_diag_iterator diag_end, + const char *Kind, bool Expected) { + if (diag_begin == diag_end) return 0; + + llvm::SmallString<256> Fmt; + llvm::raw_svector_ostream OS(Fmt); + for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) { + if (I->first.isInvalid() || !SourceMgr) + OS << "\n (frontend)"; + else + OS << "\n Line " << SourceMgr->getInstantiationLineNumber(I->first); + OS << ": " << I->second; + } + + Diags.Report(diag::err_verify_inconsistent_diags) + << Kind << !Expected << OS.str(); + return std::distance(diag_begin, diag_end); +} + +/// CompareDiagLists - Compare two diagnostic lists and return the difference +/// between them. +/// +static unsigned CompareDiagLists(Diagnostic &Diags, + SourceManager &SourceMgr, + const_diag_iterator d1_begin, + const_diag_iterator d1_end, + const_diag_iterator d2_begin, + const_diag_iterator d2_end, + const char *Label) { + DiagList LeftOnly; + DiagList Left(d1_begin, d1_end); + DiagList Right(d2_begin, d2_end); + + for (const_diag_iterator I = Left.begin(), E = Left.end(); I != E; ++I) { + unsigned LineNo1 = SourceMgr.getInstantiationLineNumber(I->first); + const std::string &Diag1 = I->second; + + DiagList::iterator II, IE; + for (II = Right.begin(), IE = Right.end(); II != IE; ++II) { + unsigned LineNo2 = SourceMgr.getInstantiationLineNumber(II->first); + if (LineNo1 != LineNo2) continue; + + const std::string &Diag2 = II->second; + if (Diag2.find(Diag1) != std::string::npos || + Diag1.find(Diag2) != std::string::npos) { + break; + } + } + if (II == IE) { + // Not found. + LeftOnly.push_back(*I); + } else { + // Found. The same cannot be found twice. + Right.erase(II); + } + } + // Now all that's left in Right are those that were not matched. + + return (PrintProblem(Diags, &SourceMgr, + LeftOnly.begin(), LeftOnly.end(), Label, true) + + PrintProblem(Diags, &SourceMgr, + Right.begin(), Right.end(), Label, false)); +} + +/// CheckResults - This compares the expected results to those that +/// were actually reported. It emits any discrepencies. Return "true" if there +/// were problems. Return "false" otherwise. +/// +static unsigned CheckResults(Diagnostic &Diags, SourceManager &SourceMgr, + const TextDiagnosticBuffer &Buffer, + const DiagList &ExpectedErrors, + const DiagList &ExpectedWarnings, + const DiagList &ExpectedNotes) { + // We want to capture the delta between what was expected and what was + // seen. + // + // Expected \ Seen - set expected but not seen + // Seen \ Expected - set seen but not expected + unsigned NumProblems = 0; + + // See if there are error mismatches. + NumProblems += CompareDiagLists(Diags, SourceMgr, + ExpectedErrors.begin(), ExpectedErrors.end(), + Buffer.err_begin(), Buffer.err_end(), + "error"); + + // See if there are warning mismatches. + NumProblems += CompareDiagLists(Diags, SourceMgr, + ExpectedWarnings.begin(), + ExpectedWarnings.end(), + Buffer.warn_begin(), Buffer.warn_end(), + "warning"); + + // See if there are note mismatches. + NumProblems += CompareDiagLists(Diags, SourceMgr, + ExpectedNotes.begin(), + ExpectedNotes.end(), + Buffer.note_begin(), Buffer.note_end(), + "note"); + + return NumProblems; +} + + +void VerifyDiagnosticsClient::CheckDiagnostics() { + DiagList ExpectedErrors, ExpectedWarnings, ExpectedNotes; + + // Ensure any diagnostics go to the primary client. + DiagnosticClient *CurClient = Diags.getClient(); + Diags.setClient(PrimaryClient.get()); + + // If we have a preprocessor, scan the source for expected diagnostic + // markers. If not then any diagnostics are unexpected. + if (CurrentPreprocessor) { + FindExpectedDiags(*CurrentPreprocessor, ExpectedErrors, ExpectedWarnings, + ExpectedNotes); + + // Check that the expected diagnostics occurred. + NumErrors += CheckResults(Diags, CurrentPreprocessor->getSourceManager(), + *Buffer, + ExpectedErrors, ExpectedWarnings, ExpectedNotes); + } else { + NumErrors += (PrintProblem(Diags, 0, + Buffer->err_begin(), Buffer->err_end(), + "error", false) + + PrintProblem(Diags, 0, + Buffer->warn_begin(), Buffer->warn_end(), + "warn", false) + + PrintProblem(Diags, 0, + Buffer->note_begin(), Buffer->note_end(), + "note", false)); + } + + Diags.setClient(CurClient); + + // Reset the buffer, we have processed all the diagnostics in it. + Buffer.reset(new TextDiagnosticBuffer()); +} diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp index 7b01b0fb7416..ff44c9051663 100644 --- a/lib/Frontend/Warnings.cpp +++ b/lib/Frontend/Warnings.cpp @@ -24,6 +24,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Sema/SemaDiagnostic.h" #include "clang/Lex/LexDiagnostic.h" +#include "clang/Frontend/DiagnosticOptions.h" #include "clang/Frontend/FrontendDiagnostic.h" #include <cstdio> #include <cstring> @@ -32,26 +33,24 @@ using namespace clang; bool clang::ProcessWarningOptions(Diagnostic &Diags, - std::vector<std::string> &Warnings, - bool Pedantic, bool PedanticErrors, - bool NoWarnings) { + const DiagnosticOptions &Opts) { Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers - Diags.setIgnoreAllWarnings(NoWarnings); + Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings); // If -pedantic or -pedantic-errors was specified, then we want to map all // extension diagnostics onto WARNING or ERROR unless the user has futz'd // around with them explicitly. - if (PedanticErrors) + if (Opts.PedanticErrors) Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Error); - else if (Pedantic) + else if (Opts.Pedantic) Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Warn); else Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Ignore); // FIXME: -Wfatal-errors / -Wfatal-errors=foo - for (unsigned i = 0, e = Warnings.size(); i != e; ++i) { - const std::string &Opt = Warnings[i]; + for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) { + const std::string &Opt = Opts.Warnings[i]; const char *OptStart = &Opt[0]; const char *OptEnd = OptStart+Opt.size(); assert(*OptEnd == 0 && "Expect null termination for lower-bound search"); @@ -100,8 +99,7 @@ bool clang::ProcessWarningOptions(Diagnostic &Diags, } if (Diags.setDiagnosticGroupMapping(OptStart, Mapping)) - Diags.Report(FullSourceLoc(), diag::warn_unknown_warning_option) - << ("-W" + Opt); + Diags.Report(diag::warn_unknown_warning_option) << ("-W" + Opt); } return false; diff --git a/lib/Headers/stdint.h b/lib/Headers/stdint.h index f03c1777ab01..bb81a6a3386a 100644 --- a/lib/Headers/stdint.h +++ b/lib/Headers/stdint.h @@ -33,60 +33,178 @@ # include_next <stdint.h> #else -/* We currently only support targets with power of two, 2s complement integers. - */ - /* C99 7.18.1.1 Exact-width integer types. * C99 7.18.1.2 Minimum-width integer types. * C99 7.18.1.3 Fastest minimum-width integer types. - * Since we only support pow-2 targets, these map directly to exact width types. + * + * The standard requires that exact-width type be defined for 8-, 16-, 32-, and + * 64-bit types if they are implemented. Other exact width types are optional. + * This implementation defines an exact-width types for every integer width + * that is represented in the standard integer types. + * + * The standard also requires minimum-width types be defined for 8-, 16-, 32-, + * and 64-bit widths regardless of whether there are corresponding exact-width + * types. + * + * To accomodate targets that are missing types that are exactly 8, 16, 32, or + * 64 bits wide, this implementation takes an approach of cascading + * redefintions, redefining __int_leastN_t to successively smaller exact-width + * types. It is therefore important that the types are defined in order of + * descending widths. + * + * We currently assume that the minimum-width types and the fastest + * minimum-width types are the same. This is allowed by the standard, but is + * suboptimal. + * + * In violation of the standard, some targets do not implement a type that is + * wide enough to represent all of the required widths (8-, 16-, 32-, 64-bit). + * To accomodate these targets, a required minimum-width type is only + * defined if there exists an exact-width type of equal or greater width. */ -/* 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 +# ifndef __int8_t_defined /* glibc sys/types.h also defines int64_t*/ +typedef signed __INT64_TYPE__ int64_t; +# endif /* __int8_t_defined */ 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 - -#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 +# define __int_least64_t int64_t +# define __uint_least64_t uint64_t +# define __int_least32_t int64_t +# define __uint_least32_t uint64_t +# define __int_least16_t int64_t +# define __uint_least16_t uint64_t +# define __int_least8_t int64_t +# define __uint_least8_t uint64_t +#endif /* __INT64_TYPE__ */ + +#ifdef __int_least64_t +typedef __int_least64_t int_least64_t; +typedef __uint_least64_t uint_least64_t; +typedef __int_least64_t int_fast64_t; +typedef __uint_least64_t uint_fast64_t; +#endif /* __int_least64_t */ + +#ifdef __INT56_TYPE__ +typedef signed __INT56_TYPE__ int56_t; +typedef unsigned __INT56_TYPE__ uint56_t; +typedef int56_t int_least56_t; +typedef uint56_t uint_least56_t; +typedef int56_t int_fast56_t; +typedef uint56_t uint_fast56_t; +# define __int_least32_t int56_t +# define __uint_least32_t uint56_t +# define __int_least16_t int56_t +# define __uint_least16_t uint56_t +# define __int_least8_t int56_t +# define __uint_least8_t uint56_t +#endif /* __INT56_TYPE__ */ + + +#ifdef __INT48_TYPE__ +typedef signed __INT48_TYPE__ int48_t; +typedef unsigned __INT48_TYPE__ uint48_t; +typedef int48_t int_least48_t; +typedef uint48_t uint_least48_t; +typedef int48_t int_fast48_t; +typedef uint48_t uint_fast48_t; +# define __int_least32_t int48_t +# define __uint_least32_t uint48_t +# define __int_least16_t int48_t +# define __uint_least16_t uint48_t +# define __int_least8_t int48_t +# define __uint_least8_t uint48_t +#endif /* __INT48_TYPE__ */ + + +#ifdef __INT40_TYPE__ +typedef signed __INT40_TYPE__ int40_t; +typedef unsigned __INT40_TYPE__ uint40_t; +typedef int40_t int_least40_t; +typedef uint40_t uint_least40_t; +typedef int40_t int_fast40_t; +typedef uint40_t uint_fast40_t; +# define __int_least32_t int40_t +# define __uint_least32_t uint40_t +# define __int_least16_t int40_t +# define __uint_least16_t uint40_t +# define __int_least8_t int40_t +# define __uint_least8_t uint40_t +#endif /* __INT40_TYPE__ */ + + +#ifdef __INT32_TYPE__ + +# ifndef __int8_t_defined /* glibc sys/types.h also defines int32_t*/ +typedef signed __INT32_TYPE__ int32_t; +# endif /* __int8_t_defined */ + +# ifndef __uint32_t_defined /* more glibc compatibility */ +# define __uint32_t_defined typedef unsigned __INT32_TYPE__ uint32_t; -#endif -typedef int32_t int_least32_t; -typedef uint32_t uint_least32_t; -typedef int32_t int_fast32_t; -typedef uint32_t uint_fast32_t; - - -#ifndef __int8_t_defined /* glibc does weird things with sys/types.h */ -typedef __INT16_TYPE__ int16_t; -#endif +# endif /* __uint32_t_defined */ + +# define __int_least32_t int32_t +# define __uint_least32_t uint32_t +# define __int_least16_t int32_t +# define __uint_least16_t uint32_t +# define __int_least8_t int32_t +# define __uint_least8_t uint32_t +#endif /* __INT32_TYPE__ */ + +#ifdef __int_least32_t +typedef __int_least32_t int_least32_t; +typedef __uint_least32_t uint_least32_t; +typedef __int_least32_t int_fast32_t; +typedef __uint_least32_t uint_fast32_t; +#endif /* __int_least32_t */ + +#ifdef __INT24_TYPE__ +typedef signed __INT24_TYPE__ int24_t; +typedef unsigned __INT24_TYPE__ uint24_t; +typedef int24_t int_least24_t; +typedef uint24_t uint_least24_t; +typedef int24_t int_fast24_t; +typedef uint24_t uint_fast24_t; +# define __int_least16_t int24_t +# define __uint_least16_t uint24_t +# define __int_least8_t int24_t +# define __uint_least8_t uint24_t +#endif /* __INT24_TYPE__ */ + +#ifdef __INT16_TYPE__ +#ifndef __int8_t_defined /* glibc sys/types.h also defines int16_t*/ +typedef signed __INT16_TYPE__ int16_t; +#endif /* __int8_t_defined */ 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 */ +# define __int_least16_t int16_t +# define __uint_least16_t uint16_t +# define __int_least8_t int16_t +# define __uint_least8_t uint16_t +#endif /* __INT16_TYPE__ */ + +#ifdef __int_least16_t +typedef __int_least16_t int_least16_t; +typedef __uint_least16_t uint_least16_t; +typedef __int_least16_t int_fast16_t; +typedef __uint_least16_t uint_fast16_t; +#endif /* __int_least16_t */ + + +#ifdef __INT8_TYPE__ +#ifndef __int8_t_defined /* glibc sys/types.h also defines int8_t*/ typedef signed __INT8_TYPE__ int8_t; -#endif +#endif /* __int8_t_defined */ 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; +# define __int_least8_t int8_t +# define __uint_least8_t uint8_t +#endif /* __INT8_TYPE__ */ + +#ifdef __int_least8_t +typedef __int_least8_t int_least8_t; +typedef __uint_least8_t uint_least8_t; +typedef __int_least8_t int_fast8_t; +typedef __uint_least8_t uint_fast8_t; +#endif /* __int_least8_t */ /* prevent glibc sys/types.h from defining conflicting types */ #ifndef __int8_t_defined @@ -108,75 +226,376 @@ typedef __UINTMAX_TYPE__ uintmax_t; /* C99 7.18.4 Macros for minimum-width integer constants. * + * The standard requires that integer constant macros be defined for all the + * minimum-width types defined above. As 8-, 16-, 32-, and 64-bit minimum-width + * types are required, the corresponding integer constant macros are defined + * here. This implementation also defines minimum-width types for every other + * integer width that the target implements, so corresponding macros are + * defined below, too. + * + * These macros are defined using the same successive-shrinking approach as + * the type definitions above. It is likewise important that macros are defined + * in order of decending width. + * * 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. */ +#define __int_c_join(a, b) a ## b +#define __int_c(v, suffix) __int_c_join(v, suffix) +#define __uint_c(v, suffix) __int_c_join(v##U, suffix) + + #ifdef __INT64_TYPE__ -#define INT64_C(v) (v##LL) -#define UINT64_C(v) (v##ULL) -#endif +# ifdef __INT64_C_SUFFIX__ +# define __int64_c_suffix __INT64_C_SUFFIX__ +# define __int32_c_suffix __INT64_C_SUFFIX__ +# define __int16_c_suffix __INT64_C_SUFFIX__ +# define __int8_c_suffix __INT64_C_SUFFIX__ +# else +# undef __int64_c_suffix +# undef __int32_c_suffix +# undef __int16_c_suffix +# undef __int8_c_suffix +# endif /* __INT64_C_SUFFIX__ */ +#endif /* __INT64_TYPE__ */ + +#ifdef __int_least64_t +# ifdef __int64_c_suffix +# define INT64_C(v) __int_c(v, __int64_c_suffix) +# define UINT64_C(v) __uint_c(v, __int64_c_suffix) +# else +# define INT64_C(v) v +# define UINT64_C(v) v ## U +# endif /* __int64_c_suffix */ +#endif /* __int_least64_t */ + + +#ifdef __INT56_TYPE__ +# ifdef __INT56_C_SUFFIX__ +# define INT56_C(v) __int_c(v, __INT56_C_SUFFIX__) +# define UINT56_C(v) __uint_c(v, __INT56_C_SUFFIX__) +# define __int32_c_suffix __INT56_C_SUFFIX__ +# define __int16_c_suffix __INT56_C_SUFFIX__ +# define __int8_c_suffix __INT56_C_SUFFIX__ +# else +# define INT56_C(v) v +# define UINT56_C(v) v ## U +# undef __int32_c_suffix +# undef __int16_c_suffix +# undef __int8_c_suffix +# endif /* __INT56_C_SUFFIX__ */ +#endif /* __INT56_TYPE__ */ + + +#ifdef __INT48_TYPE__ +# ifdef __INT48_C_SUFFIX__ +# define INT48_C(v) __int_c(v, __INT48_C_SUFFIX__) +# define UINT48_C(v) __uint_c(v, __INT48_C_SUFFIX__) +# define __int32_c_suffix __INT48_C_SUFFIX__ +# define __int16_c_suffix __INT48_C_SUFFIX__ +# define __int8_c_suffix __INT48_C_SUFFIX__ +# else +# define INT48_C(v) v +# define UINT48_C(v) v ## U +# undef __int32_c_suffix +# undef __int16_c_suffix +# undef __int8_c_suffix +# endif /* __INT48_C_SUFFIX__ */ +#endif /* __INT48_TYPE__ */ + + +#ifdef __INT40_TYPE__ +# ifdef __INT40_C_SUFFIX__ +# define INT40_C(v) __int_c(v, __INT40_C_SUFFIX__) +# define UINT40_C(v) __uint_c(v, __INT40_C_SUFFIX__) +# define __int32_c_suffix __INT40_C_SUFFIX__ +# define __int16_c_suffix __INT40_C_SUFFIX__ +# define __int8_c_suffix __INT40_C_SUFFIX__ +# else +# define INT40_C(v) v +# define UINT40_C(v) v ## U +# undef __int32_c_suffix +# undef __int16_c_suffix +# undef __int8_c_suffix +# endif /* __INT40_C_SUFFIX__ */ +#endif /* __INT40_TYPE__ */ + + +#ifdef __INT32_TYPE__ +# ifdef __INT32_C_SUFFIX__ +# define __int32_c_suffix __INT32_C_SUFFIX__ +# define __int16_c_suffix __INT32_C_SUFFIX__ +# define __int8_c_suffix __INT32_C_SUFFIX__ +#else +# undef __int32_c_suffix +# undef __int16_c_suffix +# undef __int8_c_suffix +# endif /* __INT32_C_SUFFIX__ */ +#endif /* __INT32_TYPE__ */ + +#ifdef __int_least32_t +# ifdef __int32_c_suffix +# define INT32_C(v) __int_c(v, __int32_c_suffix) +# define UINT32_C(v) __uint_c(v, __int32_c_suffix) +# else +# define INT32_C(v) v +# define UINT32_C(v) v ## U +# endif /* __int32_c_suffix */ +#endif /* __int_least32_t */ + + +#ifdef __INT24_TYPE__ +# ifdef __INT24_C_SUFFIX__ +# define INT24_C(v) __int_c(v, __INT24_C_SUFFIX__) +# define UINT24_C(v) __uint_c(v, __INT24_C_SUFFIX__) +# define __int16_c_suffix __INT24_C_SUFFIX__ +# define __int8_c_suffix __INT24_C_SUFFIX__ +# else +# define INT24_C(v) v +# define UINT24_C(v) v ## U +# undef __int16_c_suffix +# undef __int8_c_suffix +# endif /* __INT24_C_SUFFIX__ */ +#endif /* __INT24_TYPE__ */ + + +#ifdef __INT16_TYPE__ +# ifdef __INT16_C_SUFFIX__ +# define __int16_c_suffix __INT16_C_SUFFIX__ +# define __int8_c_suffix __INT16_C_SUFFIX__ +#else +# undef __int16_c_suffix +# undef __int8_c_suffix +# endif /* __INT16_C_SUFFIX__ */ +#endif /* __INT16_TYPE__ */ + +#ifdef __int_least16_t +# ifdef __int16_c_suffix +# define INT16_C(v) __int_c(v, __int16_c_suffix) +# define UINT16_C(v) __uint_c(v, __int16_c_suffix) +# else +# define INT16_C(v) v +# define UINT16_C(v) v ## U +# endif /* __int16_c_suffix */ +#endif /* __int_least16_t */ + + +#ifdef __INT8_TYPE__ +# ifdef __INT8_C_SUFFIX__ +# define __int8_c_suffix __INT8_C_SUFFIX__ +#else +# undef __int8_c_suffix +# endif /* __INT8_C_SUFFIX__ */ +#endif /* __INT8_TYPE__ */ + +#ifdef __int_least8_t +# ifdef __int8_c_suffix +# define INT8_C(v) __int_c(v, __int8_c_suffix) +# define UINT8_C(v) __uint_c(v, __int8_c_suffix) +# else +# define INT8_C(v) v +# define UINT8_C(v) v ## U +# endif /* __int8_c_suffix */ +#endif /* __int_least8_t */ -#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. - * Since we map these directly onto fixed-sized types, these values the same. * C99 7.18.2.3 Limits of fastest minimum-width integer types. * + * The presence of limit macros are completely optional in C99. This + * implementation defines limits for all of the types (exact- and + * minimum-width) that it defines above, using the limits of the minimum-width + * type for any types that do not have exact-width representations. + * + * As in the type definitions, this section takes an approach of + * successive-shrinking to determine which limits to use for the standard (8, + * 16, 32, 64) bit widths when they don't have exact representations. It is + * therefore important that the defintions be kept in order of decending + * widths. + * * Note that C++ should not check __STDC_LIMIT_MACROS here, contrary to the * claims of the C standard (see C++ 18.3.1p2, [cstdint.syn]). */ -/* If we do not have 64-bit support, don't define the 64-bit size macros. */ #ifdef __INT64_TYPE__ -#define INT64_MAX 9223372036854775807LL -#define INT64_MIN (-9223372036854775807LL-1) -#define UINT64_MAX 18446744073709551615ULL -#define INT_LEAST64_MIN INT64_MIN -#define INT_LEAST64_MAX INT64_MAX -#define UINT_LEAST64_MAX UINT64_MAX -#define INT_FAST64_MIN INT64_MIN -#define INT_FAST64_MAX INT64_MAX -#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 +# define INT64_MAX INT64_C( 9223372036854775807) +# define INT64_MIN (-INT64_C( 9223372036854775807)-1) +# define UINT64_MAX UINT64_C(18446744073709551615) +# define __INT_LEAST64_MIN INT64_MIN +# define __INT_LEAST64_MAX INT64_MAX +# define __UINT_LEAST64_MAX UINT64_MAX +# define __INT_LEAST32_MIN INT64_MIN +# define __INT_LEAST32_MAX INT64_MAX +# define __UINT_LEAST32_MAX UINT64_MAX +# define __INT_LEAST16_MIN INT64_MIN +# define __INT_LEAST16_MAX INT64_MAX +# define __UINT_LEAST16_MAX UINT64_MAX +# define __INT_LEAST8_MIN INT64_MIN +# define __INT_LEAST8_MAX INT64_MAX +# define __UINT_LEAST8_MAX UINT64_MAX +#endif /* __INT64_TYPE__ */ + +#ifdef __INT_LEAST64_MIN +# define INT_LEAST64_MIN __INT_LEAST64_MIN +# define INT_LEAST64_MAX __INT_LEAST64_MAX +# define UINT_LEAST64_MAX __UINT_LEAST64_MAX +# define INT_FAST64_MIN __INT_LEAST64_MIN +# define INT_FAST64_MAX __INT_LEAST64_MAX +# define UINT_FAST64_MAX __UINT_LEAST64_MAX +#endif /* __INT_LEAST64_MIN */ + + +#ifdef __INT56_TYPE__ +# define INT56_MAX INT56_C(36028797018963967) +# define INT56_MIN (-INT56_C(36028797018963967)-1) +# define UINT56_MAX UINT56_C(72057594037927935) +# define INT_LEAST56_MIN INT56_MIN +# define INT_LEAST56_MAX INT56_MAX +# define UINT_LEAST56_MAX UINT56_MAX +# define INT_FAST56_MIN INT56_MIN +# define INT_FAST56_MAX INT56_MAX +# define UINT_FAST56_MAX UINT56_MAX +# define __INT_LEAST32_MIN INT56_MIN +# define __INT_LEAST32_MAX INT56_MAX +# define __UINT_LEAST32_MAX UINT56_MAX +# define __INT_LEAST16_MIN INT56_MIN +# define __INT_LEAST16_MAX INT56_MAX +# define __UINT_LEAST16_MAX UINT56_MAX +# define __INT_LEAST8_MIN INT56_MIN +# define __INT_LEAST8_MAX INT56_MAX +# define __UINT_LEAST8_MAX UINT56_MAX +#endif /* __INT56_TYPE__ */ + + +#ifdef __INT48_TYPE__ +# define INT48_MAX INT48_C(140737488355327) +# define INT48_MIN (-INT48_C(140737488355327)-1) +# define UINT48_MAX UINT48_C(281474976710655) +# define INT_LEAST48_MIN INT48_MIN +# define INT_LEAST48_MAX INT48_MAX +# define UINT_LEAST48_MAX UINT48_MAX +# define INT_FAST48_MIN INT48_MIN +# define INT_FAST48_MAX INT48_MAX +# define UINT_FAST48_MAX UINT48_MAX +# define __INT_LEAST32_MIN INT48_MIN +# define __INT_LEAST32_MAX INT48_MAX +# define __UINT_LEAST32_MAX UINT48_MAX +# define __INT_LEAST16_MIN INT48_MIN +# define __INT_LEAST16_MAX INT48_MAX +# define __UINT_LEAST16_MAX UINT48_MAX +# define __INT_LEAST8_MIN INT48_MIN +# define __INT_LEAST8_MAX INT48_MAX +# define __UINT_LEAST8_MAX UINT48_MAX +#endif /* __INT48_TYPE__ */ + + +#ifdef __INT40_TYPE__ +# define INT40_MAX INT40_C(549755813887) +# define INT40_MIN (-INT40_C(549755813887)-1) +# define UINT40_MAX UINT40_C(1099511627775) +# define INT_LEAST40_MIN INT40_MIN +# define INT_LEAST40_MAX INT40_MAX +# define UINT_LEAST40_MAX UINT40_MAX +# define INT_FAST40_MIN INT40_MIN +# define INT_FAST40_MAX INT40_MAX +# define UINT_FAST40_MAX UINT40_MAX +# define __INT_LEAST32_MIN INT40_MIN +# define __INT_LEAST32_MAX INT40_MAX +# define __UINT_LEAST32_MAX UINT40_MAX +# define __INT_LEAST16_MIN INT40_MIN +# define __INT_LEAST16_MAX INT40_MAX +# define __UINT_LEAST16_MAX UINT40_MAX +# define __INT_LEAST8_MIN INT40_MIN +# define __INT_LEAST8_MAX INT40_MAX +# define __UINT_LEAST8_MAX UINT40_MAX +#endif /* __INT40_TYPE__ */ + + +#ifdef __INT32_TYPE__ +# define INT32_MAX INT32_C(2147483647) +# define INT32_MIN (-INT32_C(2147483647)-1) +# define UINT32_MAX UINT32_C(4294967295) +# define __INT_LEAST32_MIN INT32_MIN +# define __INT_LEAST32_MAX INT32_MAX +# define __UINT_LEAST32_MAX UINT32_MAX +# define __INT_LEAST16_MIN INT32_MIN +# define __INT_LEAST16_MAX INT32_MAX +# define __UINT_LEAST16_MAX UINT32_MAX +# define __INT_LEAST8_MIN INT32_MIN +# define __INT_LEAST8_MAX INT32_MAX +# define __UINT_LEAST8_MAX UINT32_MAX +#endif /* __INT32_TYPE__ */ + +#ifdef __INT_LEAST32_MIN +# define INT_LEAST32_MIN __INT_LEAST32_MIN +# define INT_LEAST32_MAX __INT_LEAST32_MAX +# define UINT_LEAST32_MAX __UINT_LEAST32_MAX +# define INT_FAST32_MIN __INT_LEAST32_MIN +# define INT_FAST32_MAX __INT_LEAST32_MAX +# define UINT_FAST32_MAX __UINT_LEAST32_MAX +#endif /* __INT_LEAST32_MIN */ + + +#ifdef __INT24_TYPE__ +# define INT24_MAX INT24_C(8388607) +# define INT24_MIN (-INT24_C(8388607)-1) +# define UINT24_MAX UINT24_C(16777215) +# define INT_LEAST24_MIN INT24_MIN +# define INT_LEAST24_MAX INT24_MAX +# define UINT_LEAST24_MAX UINT24_MAX +# define INT_FAST24_MIN INT24_MIN +# define INT_FAST24_MAX INT24_MAX +# define UINT_FAST24_MAX UINT24_MAX +# define __INT_LEAST16_MIN INT24_MIN +# define __INT_LEAST16_MAX INT24_MAX +# define __UINT_LEAST16_MAX UINT24_MAX +# define __INT_LEAST8_MIN INT24_MIN +# define __INT_LEAST8_MAX INT24_MAX +# define __UINT_LEAST8_MAX UINT24_MAX +#endif /* __INT24_TYPE__ */ + + +#ifdef __INT16_TYPE__ +#define INT16_MAX INT16_C(32767) +#define INT16_MIN (-INT16_C(32767)-1) +#define UINT16_MAX UINT16_C(65535) +# define __INT_LEAST16_MIN INT16_MIN +# define __INT_LEAST16_MAX INT16_MAX +# define __UINT_LEAST16_MAX UINT16_MAX +# define __INT_LEAST8_MIN INT16_MIN +# define __INT_LEAST8_MAX INT16_MAX +# define __UINT_LEAST8_MAX UINT16_MAX +#endif /* __INT16_TYPE__ */ + +#ifdef __INT_LEAST16_MIN +# define INT_LEAST16_MIN __INT_LEAST16_MIN +# define INT_LEAST16_MAX __INT_LEAST16_MAX +# define UINT_LEAST16_MAX __UINT_LEAST16_MAX +# define INT_FAST16_MIN __INT_LEAST16_MIN +# define INT_FAST16_MAX __INT_LEAST16_MAX +# define UINT_FAST16_MAX __UINT_LEAST16_MAX +#endif /* __INT_LEAST16_MIN */ + + +#ifdef __INT8_TYPE__ +# define INT8_MAX INT8_C(127) +# define INT8_MIN (-INT8_C(127)-1) +# define UINT8_MAX UINT8_C(255) +# define __INT_LEAST8_MIN INT8_MIN +# define __INT_LEAST8_MAX INT8_MAX +# define __UINT_LEAST8_MAX UINT8_MAX +#endif /* __INT8_TYPE__ */ + +#ifdef __INT_LEAST8_MIN +# define INT_LEAST8_MIN __INT_LEAST8_MIN +# define INT_LEAST8_MAX __INT_LEAST8_MAX +# define UINT_LEAST8_MAX __UINT_LEAST8_MAX +# define INT_FAST8_MIN __INT_LEAST8_MIN +# define INT_FAST8_MAX __INT_LEAST8_MAX +# define UINT_FAST8_MAX __UINT_LEAST8_MAX +#endif /* __INT_LEAST8_MIN */ /* C99 7.18.2.4 Limits of integer types capable of holding object pointers. */ /* C99 7.18.3 Limits of other integer types. */ @@ -234,8 +653,8 @@ typedef __UINTMAX_TYPE__ uintmax_t; #endif /* 7.18.4.2 Macros for greatest-width integer constants. */ -#define INTMAX_C(v) (v##LL) -#define UINTMAX_C(v) (v##ULL) +#define INTMAX_C(v) v##LL +#define UINTMAX_C(v) v##ULL #endif /* __STDC_HOSTED__ */ #endif /* __CLANG_STDINT_H */ diff --git a/lib/Index/ResolveLocation.cpp b/lib/Index/ResolveLocation.cpp index 73b584b5205d..ed905f364f0d 100644 --- a/lib/Index/ResolveLocation.cpp +++ b/lib/Index/ResolveLocation.cpp @@ -112,6 +112,7 @@ public: ASTLocation VisitDeclaratorDecl(DeclaratorDecl *D); ASTLocation VisitVarDecl(VarDecl *D); ASTLocation VisitFunctionDecl(FunctionDecl *D); + ASTLocation VisitObjCClassDecl(ObjCClassDecl *D); ASTLocation VisitObjCMethodDecl(ObjCMethodDecl *D); ASTLocation VisitTypedefDecl(TypedefDecl *D); ASTLocation VisitDecl(Decl *D); @@ -327,6 +328,17 @@ ASTLocation DeclLocResolver::VisitVarDecl(VarDecl *D) { return ASTLocation(D); } +ASTLocation DeclLocResolver::VisitObjCClassDecl(ObjCClassDecl *D) { + assert(ContainsLocation(D) && + "Should visit only after verifying that loc is in range"); + + for (ObjCClassDecl::iterator I = D->begin(), E = D->end() ; I != E; ++I) { + if (CheckRange(I->getLocation()) == ContainsLoc) + return ASTLocation(D, I->getInterface(), I->getLocation()); + } + return ASTLocation(D); +} + ASTLocation DeclLocResolver::VisitObjCMethodDecl(ObjCMethodDecl *D) { assert(ContainsLocation(D) && "Should visit only after verifying that loc is in range"); @@ -484,7 +496,7 @@ ASTLocation LocResolverBase::ResolveInDeclarator(Decl *D, Stmt *Stm, assert(ContainsLocation(DInfo) && "Should visit only after verifying that loc is in range"); - TypeLocResolver(Ctx, Loc, D); + (void)TypeLocResolver(Ctx, Loc, D); for (TypeLoc TL = DInfo->getTypeLoc(); TL; TL = TL.getNextTypeLoc()) if (ContainsLocation(TL)) return TypeLocResolver(Ctx, Loc, D).Visit(TL); diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index c8b9a5d5420a..f4a44324106a 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -384,10 +384,10 @@ static inline bool isNumberBody(unsigned char c) { /// lexer buffer was all instantiated at a single point, perform the mapping. /// This is currently only used for _Pragma implementation, so it is the slow /// path of the hot getSourceLocation method. Do not allow it to be inlined. -static SourceLocation GetMappedTokenLoc(Preprocessor &PP, - SourceLocation FileLoc, - unsigned CharNo, - unsigned TokLen) DISABLE_INLINE; +static DISABLE_INLINE SourceLocation GetMappedTokenLoc(Preprocessor &PP, + SourceLocation FileLoc, + unsigned CharNo, + unsigned TokLen); static SourceLocation GetMappedTokenLoc(Preprocessor &PP, SourceLocation FileLoc, unsigned CharNo, unsigned TokLen) { diff --git a/lib/Lex/PPCaching.cpp b/lib/Lex/PPCaching.cpp index c3f0eeab5848..7c3780ffc0ac 100644 --- a/lib/Lex/PPCaching.cpp +++ b/lib/Lex/PPCaching.cpp @@ -109,6 +109,4 @@ void Preprocessor::AnnotatePreviousCachedTokens(const Token &Tok) { return; } } - - assert(0&&"Didn't find the first token represented by the annotation token!"); } diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp index a74396c3146c..b54dfe093b2c 100644 --- a/lib/Lex/PPExpressions.cpp +++ b/lib/Lex/PPExpressions.cpp @@ -228,7 +228,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, return true; // A diagnostic was already emitted. // Character literals are always int or wchar_t, expand to intmax_t. - TargetInfo &TI = PP.getTargetInfo(); + const TargetInfo &TI = PP.getTargetInfo(); unsigned NumBits; if (Literal.isMultiChar()) NumBits = TI.getIntWidth(); diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp index f17a5d93a91a..d6a73cc74f6a 100644 --- a/lib/Lex/PTHLexer.cpp +++ b/lib/Lex/PTHLexer.cpp @@ -15,6 +15,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/OnDiskHashTable.h" +#include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/PTHLexer.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PTHManager.h" @@ -407,27 +408,17 @@ PTHManager::~PTHManager() { free(PerIDCache); } -static void InvalidPTH(Diagnostic *Diags, Diagnostic::Level level, - const char* Msg = 0) { - if (!Diags) return; - if (!Msg) Msg = "Invalid or corrupted PTH file"; - unsigned DiagID = Diags->getCustomDiagID(level, Msg); - Diags->Report(FullSourceLoc(), DiagID); +static void InvalidPTH(Diagnostic &Diags, const char *Msg) { + Diags.Report(Diags.getCustomDiagID(Diagnostic::Error, Msg)); } -PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags, - Diagnostic::Level level) { +PTHManager* PTHManager::Create(const std::string& file, Diagnostic &Diags) { // Memory map the PTH file. llvm::OwningPtr<llvm::MemoryBuffer> File(llvm::MemoryBuffer::getFile(file.c_str())); if (!File) { - if (Diags) { - unsigned DiagID = Diags->getCustomDiagID(level, - "PTH file %0 could not be read"); - Diags->Report(FullSourceLoc(), DiagID) << file; - } - + Diags.Report(diag::err_invalid_pth_file) << file; return 0; } @@ -439,7 +430,7 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags, // Check the prologue of the file. if ((BufEnd - BufBeg) < (signed) (sizeof("cfe-pth") + 3 + 4) || memcmp(BufBeg, "cfe-pth", sizeof("cfe-pth") - 1) != 0) { - InvalidPTH(Diags, level); + Diags.Report(diag::err_invalid_pth_file) << file; return 0; } @@ -447,8 +438,8 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags, const unsigned char *p = BufBeg + (sizeof("cfe-pth") - 1); unsigned Version = ReadLE32(p); - if (Version != PTHManager::Version) { - InvalidPTH(Diags, level, + if (Version < PTHManager::Version) { + InvalidPTH(Diags, Version < PTHManager::Version ? "PTH file uses an older PTH format that is no longer supported" : "PTH file uses a newer PTH format that cannot be read"); @@ -459,7 +450,7 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags, const unsigned char *PrologueOffset = p; if (PrologueOffset >= BufEnd) { - InvalidPTH(Diags, level); + Diags.Report(diag::err_invalid_pth_file) << file; return 0; } @@ -469,7 +460,7 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags, const unsigned char* FileTable = BufBeg + ReadLE32(FileTableOffset); if (!(FileTable > BufBeg && FileTable < BufEnd)) { - InvalidPTH(Diags, level); + Diags.Report(diag::err_invalid_pth_file) << file; return 0; // FIXME: Proper error diagnostic? } @@ -478,7 +469,7 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags, // Warn if the PTH file is empty. We still want to create a PTHManager // as the PTH could be used with -include-pth. if (FL->isEmpty()) - InvalidPTH(Diags, level, "PTH file contains no cached source data"); + InvalidPTH(Diags, "PTH file contains no cached source data"); // Get the location of the table mapping from persistent ids to the // data needed to reconstruct identifiers. @@ -486,7 +477,7 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags, const unsigned char* IData = BufBeg + ReadLE32(IDTableOffset); if (!(IData >= BufBeg && IData < BufEnd)) { - InvalidPTH(Diags, level); + Diags.Report(diag::err_invalid_pth_file) << file; return 0; } @@ -495,7 +486,7 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags, const unsigned char* StringIdTableOffset = PrologueOffset + sizeof(uint32_t)*1; const unsigned char* StringIdTable = BufBeg + ReadLE32(StringIdTableOffset); if (!(StringIdTable >= BufBeg && StringIdTable < BufEnd)) { - InvalidPTH(Diags, level); + Diags.Report(diag::err_invalid_pth_file) << file; return 0; } @@ -506,7 +497,7 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags, const unsigned char* spellingBaseOffset = PrologueOffset + sizeof(uint32_t)*3; const unsigned char* spellingBase = BufBeg + ReadLE32(spellingBaseOffset); if (!(spellingBase >= BufBeg && spellingBase < BufEnd)) { - InvalidPTH(Diags, level); + Diags.Report(diag::err_invalid_pth_file) << file; return 0; } @@ -521,8 +512,7 @@ PTHManager* PTHManager::Create(const std::string& file, Diagnostic* Diags, if (NumIds) { PerIDCache = (IdentifierInfo**)calloc(NumIds, sizeof(*PerIDCache)); if (!PerIDCache) { - InvalidPTH(Diags, level, - "Could not allocate memory for processing PTH file"); + InvalidPTH(Diags, "Could not allocate memory for processing PTH file"); return 0; } } diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index 487b9d63c169..066909475fe3 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -44,14 +44,16 @@ using namespace clang; //===----------------------------------------------------------------------===// Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, - TargetInfo &target, SourceManager &SM, + const TargetInfo &target, SourceManager &SM, HeaderSearch &Headers, - IdentifierInfoLookup* IILookup) + IdentifierInfoLookup* IILookup, + bool OwnsHeaders) : Diags(&diags), Features(opts), Target(target),FileMgr(Headers.getFileMgr()), SourceMgr(SM), HeaderInfo(Headers), Identifiers(opts, IILookup), BuiltinInfo(Target), CurPPLexer(0), CurDirLookup(0), Callbacks(0) { ScratchBuf = new ScratchBuffer(SourceMgr); CounterValue = 0; // __COUNTER__ starts at 0. + OwnsHeaderSearch = OwnsHeaders; // Clear stats. NumDirectives = NumDefined = NumUndefined = NumPragma = 0; @@ -115,6 +117,10 @@ Preprocessor::~Preprocessor() { // Delete the scratch buffer info. delete ScratchBuf; + // Delete the header search info, if we own it. + if (OwnsHeaderSearch) + delete &HeaderInfo; + delete Callbacks; } @@ -186,13 +192,14 @@ void Preprocessor::PrintStats() { // Token Spelling //===----------------------------------------------------------------------===// - /// getSpelling() - Return the 'spelling' of this token. The spelling of a /// token are the characters used to represent the token in the source file /// after trigraph expansion and escaped-newline folding. In particular, this /// wants to get the true, uncanonicalized, spelling of things like digraphs /// UCNs, etc. -std::string Preprocessor::getSpelling(const Token &Tok) const { +std::string Preprocessor::getSpelling(const Token &Tok, + const SourceManager &SourceMgr, + const LangOptions &Features) { assert((int)Tok.getLength() >= 0 && "Token character range is bogus!"); // If this token contains nothing interesting, return it directly. @@ -215,6 +222,15 @@ std::string Preprocessor::getSpelling(const Token &Tok) const { return Result; } +/// getSpelling() - Return the 'spelling' of this token. The spelling of a +/// token are the characters used to represent the token in the source file +/// after trigraph expansion and escaped-newline folding. In particular, this +/// wants to get the true, uncanonicalized, spelling of things like digraphs +/// UCNs, etc. +std::string Preprocessor::getSpelling(const Token &Tok) const { + return getSpelling(Tok, SourceMgr, Features); +} + /// getSpelling - This method is used to get the spelling of a token into a /// preallocated buffer, instead of as an std::string. The caller is required /// to allocate enough space for the token, which is guaranteed to be at least diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp index 344ce9e90e55..dde4bc866ac5 100644 --- a/lib/Parse/AttributeList.cpp +++ b/lib/Parse/AttributeList.cpp @@ -59,6 +59,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("mode", AT_mode) .Case("used", AT_used) .Case("alias", AT_alias) + .Case("cdecl", AT_cdecl) .Case("const", AT_const) .Case("packed", AT_packed) .Case("malloc", AT_malloc) diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index 0a4e036e4399..f00f33fcb948 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -13,6 +13,7 @@ #include "clang/Parse/DeclSpec.h" #include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Template.h" #include "clang/Lex/Preprocessor.h" #include "clang/Basic/LangOptions.h" #include "llvm/ADT/STLExtras.h" @@ -26,6 +27,15 @@ static DiagnosticBuilder Diag(Diagnostic &D, SourceLocation Loc, return D.Report(FullSourceLoc(Loc, SrcMgr), DiagID); } + +void UnqualifiedId::setTemplateId(TemplateIdAnnotation *TemplateId) { + assert(TemplateId && "NULL template-id annotation?"); + Kind = IK_TemplateId; + this->TemplateId = TemplateId; + StartLocation = TemplateId->TemplateNameLoc; + EndLocation = TemplateId->RAngleLoc; +} + /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function. /// "TheDeclarator" is the declarator that this will be added to. DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp index bf05b2baccd4..7681eac6ed8a 100644 --- a/lib/Parse/MinimalAction.cpp +++ b/lib/Parse/MinimalAction.cpp @@ -49,7 +49,8 @@ Action::DeclPtrTy Action::ActOnUsingDeclaration(Scope *CurScope, const CXXScopeSpec &SS, UnqualifiedId &Name, AttributeList *AttrList, - bool IsTypeName) { + bool IsTypeName, + SourceLocation TypenameLoc) { // FIXME: Parser seems to assume that Action::ActOn* takes ownership over // passed AttributeList, however other actions don't free it, is it @@ -213,7 +214,9 @@ MinimalAction::ActOnStartClassInterface(SourceLocation AtInterfaceLoc, /// Scope will always be top level file scope. Action::DeclPtrTy MinimalAction::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, - IdentifierInfo **IdentList, unsigned NumElts) { + IdentifierInfo **IdentList, + SourceLocation *IdentLocs, + unsigned NumElts) { for (unsigned i = 0; i != NumElts; ++i) { // Allocate and add the 'TypeNameInfo' "decl". getTable(TypeNameInfoTablePtr)->AddEntry(true, IdentList[i]); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 99752b59507f..2bfda30a951b 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -14,6 +14,7 @@ #include "clang/Parse/Parser.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Scope.h" +#include "clang/Parse/Template.h" #include "ExtensionRAIIObject.h" #include "llvm/ADT/SmallSet.h" using namespace clang; diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 154c2923486e..914bfc9db89d 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -16,6 +16,7 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" +#include "clang/Parse/Template.h" #include "ExtensionRAIIObject.h" using namespace clang; @@ -282,11 +283,13 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, SourceLocation &DeclEnd, AccessSpecifier AS) { CXXScopeSpec SS; + SourceLocation TypenameLoc; bool IsTypeName; // Ignore optional 'typename'. // FIXME: This is wrong; we should parse this as a typename-specifier. if (Tok.is(tok::kw_typename)) { + TypenameLoc = Tok.getLocation(); ConsumeToken(); IsTypeName = true; } @@ -329,7 +332,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, tok::semi); return Actions.ActOnUsingDeclaration(CurScope, AS, UsingLoc, SS, Name, - AttrList, IsTypeName); + AttrList, IsTypeName, TypenameLoc); } /// ParseStaticAssertDeclaration - Parse C++0x static_assert-declaratoion. @@ -586,13 +589,10 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Eat the template argument list and try to continue parsing this as // a class (or template thereof). TemplateArgList TemplateArgs; - TemplateArgIsTypeList TemplateArgIsType; - TemplateArgLocationList TemplateArgLocations; SourceLocation LAngleLoc, RAngleLoc; if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, &SS, true, LAngleLoc, - TemplateArgs, TemplateArgIsType, - TemplateArgLocations, RAngleLoc)) { + TemplateArgs, RAngleLoc)) { // We couldn't parse the template argument list at all, so don't // try to give any location information for the list. LAngleLoc = RAngleLoc = SourceLocation(); @@ -704,7 +704,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // or explicit instantiation. ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateId->getTemplateArgs(), - TemplateId->getTemplateArgIsType(), TemplateId->NumArgs); if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && TUK == Action::TUK_Declaration) { @@ -720,7 +719,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, - TemplateId->getTemplateArgLocations(), TemplateId->RAngleLoc, Attr); } else if (TUK == Action::TUK_Reference) { @@ -729,7 +727,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, - TemplateId->getTemplateArgLocations(), TemplateId->RAngleLoc); TypeResult = Actions.ActOnTagTemplateIdType(TypeResult, TUK, @@ -777,7 +774,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, - TemplateId->getTemplateArgLocations(), TemplateId->RAngleLoc, Attr, Action::MultiTemplateParamsArg(Actions, @@ -1304,7 +1300,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { - Diag(Tok, diag::ext_extra_struct_semi); + Diag(Tok, diag::ext_extra_struct_semi) + << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation())); ConsumeToken(); continue; } diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index a00dfb0b4c36..b2ecc9e827f1 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -14,6 +14,7 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/DeclSpec.h" +#include "clang/Parse/Template.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; @@ -108,52 +109,43 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, if (!HasScopeSpecifier && !ObjectType) break; + TentativeParsingAction TPA(*this); SourceLocation TemplateKWLoc = ConsumeToken(); UnqualifiedId TemplateName; if (Tok.is(tok::identifier)) { - TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); - - // If the next token is not '<', we may have a stray 'template' keyword. - // Complain and suggest removing the template keyword, but otherwise - // allow parsing to continue. - if (NextToken().isNot(tok::less)) { - Diag(NextToken().getLocation(), - diag::err_less_after_template_name_in_nested_name_spec) - << Tok.getIdentifierInfo()->getName() - << CodeModificationHint::CreateRemoval(SourceRange(TemplateKWLoc)); - break; - } - // Consume the identifier. + TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); ConsumeToken(); } else if (Tok.is(tok::kw_operator)) { if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, - TemplateName)) + TemplateName)) { + TPA.Commit(); break; + } if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId) { Diag(TemplateName.getSourceRange().getBegin(), diag::err_id_after_template_in_nested_name_spec) << TemplateName.getSourceRange(); - break; - } else if (Tok.isNot(tok::less)) { - std::string OperatorName = "operator "; - OperatorName += getOperatorSpelling( - TemplateName.OperatorFunctionId.Operator); - Diag(Tok.getLocation(), - diag::err_less_after_template_name_in_nested_name_spec) - << OperatorName - << TemplateName.getSourceRange(); + TPA.Commit(); break; } } else { - Diag(Tok.getLocation(), - diag::err_id_after_template_in_nested_name_spec) - << SourceRange(TemplateKWLoc); + TPA.Revert(); break; } + // If the next token is not '<', we have a qualified-id that refers + // to a template name, such as T::template apply, but is not a + // template-id. + if (Tok.isNot(tok::less)) { + TPA.Revert(); + break; + } + + // Commit to parsing the template-id. + TPA.Commit(); TemplateTy Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, TemplateName, ObjectType); @@ -381,13 +373,7 @@ Parser::OwningExprResult Parser::ParseCXXCasts() { OwningExprResult Result = ParseExpression(); // Match the ')'. - if (Result.isInvalid()) - SkipUntil(tok::r_paren); - - if (Tok.is(tok::r_paren)) - RParenLoc = ConsumeParen(); - else - MatchRHSPunctuation(tok::r_paren, LParenLoc); + RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); if (!Result.isInvalid() && !CastTy.isInvalid()) Result = Actions.ActOnCXXNamedCast(OpLoc, Kind, @@ -820,13 +806,9 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, // Parse the enclosed template argument list. SourceLocation LAngleLoc, RAngleLoc; TemplateArgList TemplateArgs; - TemplateArgIsTypeList TemplateArgIsType; - TemplateArgLocationList TemplateArgLocations; if (ParseTemplateIdAfterTemplateName(Template, Id.StartLocation, &SS, true, LAngleLoc, TemplateArgs, - TemplateArgIsType, - TemplateArgLocations, RAngleLoc)) return true; @@ -851,15 +833,10 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, TemplateId->Kind = TNK; TemplateId->LAngleLoc = LAngleLoc; TemplateId->RAngleLoc = RAngleLoc; - void **Args = TemplateId->getTemplateArgs(); - bool *ArgIsType = TemplateId->getTemplateArgIsType(); - SourceLocation *ArgLocs = TemplateId->getTemplateArgLocations(); + ParsedTemplateArgument *Args = TemplateId->getTemplateArgs(); for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); - Arg != ArgEnd; ++Arg) { + Arg != ArgEnd; ++Arg) Args[Arg] = TemplateArgs[Arg]; - ArgIsType[Arg] = TemplateArgIsType[Arg]; - ArgLocs[Arg] = TemplateArgLocations[Arg]; - } Id.setTemplateId(TemplateId); return false; @@ -867,14 +844,12 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, // Bundle the template arguments together. ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(), - TemplateArgIsType.data(), TemplateArgs.size()); // Constructor and destructor names. Action::TypeResult Type = Actions.ActOnTemplateIdType(Template, NameLoc, LAngleLoc, TemplateArgsPtr, - &TemplateArgLocations[0], RAngleLoc); if (Type.isInvalid()) return true; diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index b043dd99f304..65bd79d6b4f2 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -61,6 +61,8 @@ Parser::DeclPtrTy Parser::ParseObjCAtDirectives() { Parser::DeclPtrTy Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { ConsumeToken(); // the identifier "class" llvm::SmallVector<IdentifierInfo *, 8> ClassNames; + llvm::SmallVector<SourceLocation, 8> ClassLocs; + while (1) { if (Tok.isNot(tok::identifier)) { @@ -69,6 +71,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { return DeclPtrTy(); } ClassNames.push_back(Tok.getIdentifierInfo()); + ClassLocs.push_back(Tok.getLocation()); ConsumeToken(); if (Tok.isNot(tok::comma)) @@ -81,8 +84,9 @@ Parser::DeclPtrTy Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class")) return DeclPtrTy(); - return Actions.ActOnForwardClassDeclaration(atLoc, - &ClassNames[0], ClassNames.size()); + return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(), + ClassLocs.data(), + ClassNames.size()); } /// @@ -123,6 +127,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( Diag(Tok, diag::err_expected_ident); // missing class or category name. return DeclPtrTy(); } + // We have a class or category name - consume it. IdentifierInfo *nameId = Tok.getIdentifierInfo(); SourceLocation nameLoc = ConsumeToken(); @@ -829,6 +834,12 @@ ParseObjCProtocolReferences(llvm::SmallVectorImpl<Action::DeclPtrTy> &Protocols, llvm::SmallVector<IdentifierLocPair, 8> ProtocolIdents; while (1) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCProtocolReferences(ProtocolIdents.data(), + ProtocolIdents.size()); + ConsumeToken(); + } + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); SkipUntil(tok::greater); @@ -895,7 +906,8 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { - Diag(Tok, diag::ext_extra_struct_semi); + Diag(Tok, diag::ext_extra_struct_semi) + << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation())); ConsumeToken(); continue; } @@ -982,6 +994,11 @@ Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, "ParseObjCAtProtocolDeclaration(): Expected @protocol"); ConsumeToken(); // the "protocol" identifier + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCProtocolDecl(CurScope); + ConsumeToken(); + } + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing protocol name. return DeclPtrTy(); @@ -1092,6 +1109,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration( atLoc, nameId, nameLoc, categoryId, categoryLoc); ObjCImpDecl = ImplCatType; + PendingObjCImpDecl.push_back(ObjCImpDecl); return DeclPtrTy(); } // We have a class implementation @@ -1114,7 +1132,8 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration( if (Tok.is(tok::l_brace)) // we have ivars ParseObjCClassInstanceVariables(ImplClsType/*FIXME*/, atLoc); ObjCImpDecl = ImplClsType; - + PendingObjCImpDecl.push_back(ObjCImpDecl); + return DeclPtrTy(); } @@ -1126,12 +1145,21 @@ Parser::DeclPtrTy Parser::ParseObjCAtEndDeclaration(SourceLocation atLoc) { if (ObjCImpDecl) { Actions.ActOnAtEnd(atLoc, ObjCImpDecl); ObjCImpDecl = DeclPtrTy(); + PendingObjCImpDecl.pop_back(); } else Diag(atLoc, diag::warn_expected_implementation); // missing @implementation return Result; } +Parser::DeclGroupPtrTy Parser::RetrievePendingObjCImpDecl() { + if (PendingObjCImpDecl.empty()) + return Actions.ConvertDeclToDeclGroup(DeclPtrTy()); + DeclPtrTy ImpDecl = PendingObjCImpDecl.pop_back_val(); + Actions.ActOnAtEnd(SourceLocation(), ImpDecl); + return Actions.ConvertDeclToDeclGroup(ImpDecl); +} + /// compatibility-alias-decl: /// @compatibility_alias alias-name class-name ';' /// @@ -1201,6 +1229,8 @@ Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { } if (Tok.isNot(tok::semi)) Diag(Tok, diag::err_expected_semi_after) << "@synthesize"; + else + ConsumeToken(); // consume ';' return DeclPtrTy(); } @@ -1406,8 +1436,10 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() { // parse optional ';' if (Tok.is(tok::semi)) { - if (ObjCImpDecl) - Diag(Tok, diag::warn_semicolon_before_method_nody); + if (ObjCImpDecl) { + Diag(Tok, diag::warn_semicolon_before_method_body) + << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation())); + } ConsumeToken(); } @@ -1546,6 +1578,13 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, SourceLocation NameLoc, IdentifierInfo *ReceiverName, ExprArg ReceiverExpr) { + if (Tok.is(tok::code_completion)) { + if (ReceiverName) + Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverName, NameLoc); + else + Actions.CodeCompleteObjCInstanceMessage(CurScope, ReceiverExpr.get()); + ConsumeToken(); + } // Parse objc-selector SourceLocation Loc; IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc); diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 99578837c21c..16b1c800800f 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -15,6 +15,7 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" +#include "clang/Parse/Template.h" #include "llvm/Support/Compiler.h" using namespace clang; @@ -484,12 +485,17 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { // Get the a default value, if given. if (Tok.is(tok::equal)) { SourceLocation EqualLoc = ConsumeToken(); - OwningExprResult DefaultExpr = ParseCXXIdExpression(); - if (DefaultExpr.isInvalid()) + ParsedTemplateArgument Default = ParseTemplateTemplateArgument(); + if (Default.isInvalid()) { + Diag(Tok.getLocation(), + diag::err_default_template_template_parameter_not_template); + static tok::TokenKind EndToks[] = { + tok::comma, tok::greater, tok::greatergreater + }; + SkipUntil(EndToks, 3, true, true); return Param; - else if (Param) - Actions.ActOnTemplateTemplateParameterDefault(Param, EqualLoc, - move(DefaultExpr)); + } else if (Param) + Actions.ActOnTemplateTemplateParameterDefault(Param, EqualLoc, Default); } return Param; @@ -582,8 +588,6 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, bool ConsumeLastToken, SourceLocation &LAngleLoc, TemplateArgList &TemplateArgs, - TemplateArgIsTypeList &TemplateArgIsType, - TemplateArgLocationList &TemplateArgLocations, SourceLocation &RAngleLoc) { assert(Tok.is(tok::less) && "Must have already parsed the template-name"); @@ -595,8 +599,7 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, { GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); if (Tok.isNot(tok::greater)) - Invalid = ParseTemplateArgumentList(TemplateArgs, TemplateArgIsType, - TemplateArgLocations); + Invalid = ParseTemplateArgumentList(TemplateArgs); if (Invalid) { // Try to find the closing '>'. @@ -688,14 +691,10 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, // Parse the enclosed template argument list. SourceLocation LAngleLoc, RAngleLoc; TemplateArgList TemplateArgs; - TemplateArgIsTypeList TemplateArgIsType; - TemplateArgLocationList TemplateArgLocations; bool Invalid = ParseTemplateIdAfterTemplateName(Template, TemplateNameLoc, SS, false, LAngleLoc, TemplateArgs, - TemplateArgIsType, - TemplateArgLocations, RAngleLoc); if (Invalid) { @@ -707,7 +706,6 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, } ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(), - TemplateArgIsType.data(), TemplateArgs.size()); // Build the annotation token. @@ -715,7 +713,6 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, Action::TypeResult Type = Actions.ActOnTemplateIdType(Template, TemplateNameLoc, LAngleLoc, TemplateArgsPtr, - &TemplateArgLocations[0], RAngleLoc); if (Type.isInvalid()) { // If we failed to parse the template ID but skipped ahead to a >, we're not @@ -751,14 +748,9 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, TemplateId->Kind = TNK; TemplateId->LAngleLoc = LAngleLoc; TemplateId->RAngleLoc = RAngleLoc; - void **Args = TemplateId->getTemplateArgs(); - bool *ArgIsType = TemplateId->getTemplateArgIsType(); - SourceLocation *ArgLocs = TemplateId->getTemplateArgLocations(); - for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg) { + ParsedTemplateArgument *Args = TemplateId->getTemplateArgs(); + for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg) Args[Arg] = TemplateArgs[Arg]; - ArgIsType[Arg] = TemplateArgIsType[Arg]; - ArgLocs[Arg] = TemplateArgLocations[Arg]; - } Tok.setAnnotationValue(TemplateId); if (TemplateKWLoc.isValid()) Tok.setLocation(TemplateKWLoc); @@ -794,7 +786,6 @@ void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) { ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateId->getTemplateArgs(), - TemplateId->getTemplateArgIsType(), TemplateId->NumArgs); Action::TypeResult Type @@ -802,7 +793,6 @@ void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) { TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, - TemplateId->getTemplateArgLocations(), TemplateId->RAngleLoc); // Create the new "type" annotation token. Tok.setKind(tok::annot_typename); @@ -817,33 +807,125 @@ void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) { TemplateId->Destroy(); } +/// \brief Determine whether the given token can end a template argument. +static bool isEndOfTemplateArgument(Token Tok) { + return Tok.is(tok::comma) || Tok.is(tok::greater) || + Tok.is(tok::greatergreater); +} + +/// \brief Parse a C++ template template argument. +ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { + if (!Tok.is(tok::identifier) && !Tok.is(tok::coloncolon) && + !Tok.is(tok::annot_cxxscope)) + return ParsedTemplateArgument(); + + // C++0x [temp.arg.template]p1: + // A template-argument for a template template-parameter shall be the name + // of a class template or a template alias, expressed as id-expression. + // + // We parse an id-expression that refers to a class template or template + // alias. The grammar we parse is: + // + // nested-name-specifier[opt] template[opt] identifier + // + // followed by a token that terminates a template argument, such as ',', + // '>', or (in some cases) '>>'. + CXXScopeSpec SS; // nested-name-specifier, if present + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, + /*EnteringContext=*/false); + + if (SS.isSet() && Tok.is(tok::kw_template)) { + // Parse the optional 'template' keyword following the + // nested-name-specifier. + SourceLocation TemplateLoc = ConsumeToken(); + + if (Tok.is(tok::identifier)) { + // We appear to have a dependent template name. + UnqualifiedId Name; + Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + ConsumeToken(); // the identifier + + // If the next token signals the end of a template argument, + // then we have a dependent template name that could be a template + // template argument. + if (isEndOfTemplateArgument(Tok)) { + TemplateTy Template + = Actions.ActOnDependentTemplateName(TemplateLoc, SS, Name, + /*ObjectType=*/0); + if (Template.get()) + return ParsedTemplateArgument(SS, Template, Name.StartLocation); + } + } + } else if (Tok.is(tok::identifier)) { + // We may have a (non-dependent) template name. + TemplateTy Template; + UnqualifiedId Name; + Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + ConsumeToken(); // the identifier + + if (isEndOfTemplateArgument(Tok)) { + TemplateNameKind TNK = Actions.isTemplateName(CurScope, SS, Name, + /*ObjectType=*/0, + /*EnteringContext=*/false, + Template); + if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) { + // We have an id-expression that refers to a class template or + // (C++0x) template alias. + return ParsedTemplateArgument(SS, Template, Name.StartLocation); + } + } + } + + // We don't have a template template argument. + return ParsedTemplateArgument(); +} + /// ParseTemplateArgument - Parse a C++ template argument (C++ [temp.names]). /// /// template-argument: [C++ 14.2] /// constant-expression /// type-id /// id-expression -void *Parser::ParseTemplateArgument(bool &ArgIsType) { +ParsedTemplateArgument Parser::ParseTemplateArgument() { // C++ [temp.arg]p2: // In a template-argument, an ambiguity between a type-id and an // expression is resolved to a type-id, regardless of the form of // the corresponding template-parameter. // - // Therefore, we initially try to parse a type-id. + // Therefore, we initially try to parse a type-id. if (isCXXTypeId(TypeIdAsTemplateArgument)) { - ArgIsType = true; + SourceLocation Loc = Tok.getLocation(); TypeResult TypeArg = ParseTypeName(); if (TypeArg.isInvalid()) - return 0; - return TypeArg.get(); + return ParsedTemplateArgument(); + + return ParsedTemplateArgument(ParsedTemplateArgument::Type, TypeArg.get(), + Loc); } + + // Try to parse a template template argument. + { + TentativeParsingAction TPA(*this); + ParsedTemplateArgument TemplateTemplateArgument + = ParseTemplateTemplateArgument(); + if (!TemplateTemplateArgument.isInvalid()) { + TPA.Commit(); + return TemplateTemplateArgument; + } + + // Revert this tentative parse to parse a non-type template argument. + TPA.Revert(); + } + + // Parse a non-type template argument. + SourceLocation Loc = Tok.getLocation(); OwningExprResult ExprArg = ParseConstantExpression(); if (ExprArg.isInvalid() || !ExprArg.get()) - return 0; + return ParsedTemplateArgument(); - ArgIsType = false; - return ExprArg.release(); + return ParsedTemplateArgument(ParsedTemplateArgument::NonType, + ExprArg.release(), Loc); } /// ParseTemplateArgumentList - Parse a C++ template-argument-list @@ -853,22 +935,17 @@ void *Parser::ParseTemplateArgument(bool &ArgIsType) { /// template-argument /// template-argument-list ',' template-argument bool -Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs, - TemplateArgIsTypeList &TemplateArgIsType, - TemplateArgLocationList &TemplateArgLocations) { +Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { while (true) { - bool IsType = false; - SourceLocation Loc = Tok.getLocation(); - void *Arg = ParseTemplateArgument(IsType); - if (Arg) { - TemplateArgs.push_back(Arg); - TemplateArgIsType.push_back(IsType); - TemplateArgLocations.push_back(Loc); - } else { + ParsedTemplateArgument Arg = ParseTemplateArgument(); + if (Arg.isInvalid()) { SkipUntil(tok::comma, tok::greater, true, true); return true; } + // Save this template argument. + TemplateArgs.push_back(Arg); + // If the next token is a comma, consume it and keep reading // arguments. if (Tok.isNot(tok::comma)) break; diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 335a6cf36254..a9152745b3f7 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -15,6 +15,7 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" +#include "clang/Parse/Template.h" #include "llvm/Support/raw_ostream.h" #include "ExtensionRAIIObject.h" #include "ParsePragma.h" diff --git a/lib/Rewrite/DeltaTree.cpp b/lib/Rewrite/DeltaTree.cpp index a94444b50c77..101cf93f9db9 100644 --- a/lib/Rewrite/DeltaTree.cpp +++ b/lib/Rewrite/DeltaTree.cpp @@ -19,12 +19,6 @@ using namespace clang; using llvm::cast; using llvm::dyn_cast; -namespace { - struct SourceDelta; - class DeltaTreeNode; - class DeltaTreeInteriorNode; -} - /// The DeltaTree class is a multiway search tree (BTree) structure with some /// fancy features. B-Trees are are generally more memory and cache efficient /// than binary trees, because they store multiple keys/values in each node. @@ -55,21 +49,17 @@ namespace { return Delta; } }; -} // end anonymous namespace - - -namespace { - struct InsertResult { - DeltaTreeNode *LHS, *RHS; - SourceDelta Split; - }; -} // end anonymous namespace - - -namespace { + /// DeltaTreeNode - The common part of all nodes. /// class DeltaTreeNode { + public: + struct InsertResult { + DeltaTreeNode *LHS, *RHS; + SourceDelta Split; + }; + + private: friend class DeltaTreeInteriorNode; /// WidthFactor - This controls the number of K/V slots held in the BTree: @@ -473,7 +463,7 @@ void DeltaTree::AddDelta(unsigned FileIndex, int Delta) { assert(Delta && "Adding a noop?"); DeltaTreeNode *MyRoot = getRoot(Root); - InsertResult InsertRes; + DeltaTreeNode::InsertResult InsertRes; if (MyRoot->DoInsertion(FileIndex, Delta, &InsertRes)) { Root = MyRoot = new DeltaTreeInteriorNode(InsertRes); } diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 9b24d55f3ece..88ac4e49cf9e 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -16,28 +16,79 @@ #include "clang/Lex/Preprocessor.h" #include "Sema.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cstring> #include <functional> + using namespace clang; +using llvm::StringRef; //===----------------------------------------------------------------------===// // Code completion string implementation //===----------------------------------------------------------------------===// -CodeCompletionString::Chunk::Chunk(ChunkKind Kind, const char *Text) - : Kind(Kind), Text(0) +CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text) + : Kind(Kind), Text("") { - assert((Kind == CK_Text || Kind == CK_Placeholder || Kind == CK_Informative) - && "Invalid text chunk kind"); - char *New = new char [std::strlen(Text) + 1]; - std::strcpy(New, Text); - this->Text = New; + switch (Kind) { + case CK_TypedText: + case CK_Text: + case CK_Placeholder: + case CK_Informative: + case CK_CurrentParameter: { + char *New = new char [Text.size() + 1]; + std::memcpy(New, Text.data(), Text.size()); + New[Text.size()] = '\0'; + this->Text = New; + break; + } + + case CK_Optional: + llvm::llvm_unreachable("Optional strings cannot be created from text"); + break; + + case CK_LeftParen: + this->Text = "("; + break; + + case CK_RightParen: + this->Text = ")"; + break; + + case CK_LeftBracket: + this->Text = "["; + break; + + case CK_RightBracket: + this->Text = "]"; + break; + + case CK_LeftBrace: + this->Text = "{"; + break; + + case CK_RightBrace: + this->Text = "}"; + break; + + case CK_LeftAngle: + this->Text = "<"; + break; + + case CK_RightAngle: + this->Text = ">"; + break; + + case CK_Comma: + this->Text = ", "; + break; + } } CodeCompletionString::Chunk -CodeCompletionString::Chunk::CreateText(const char *Text) { +CodeCompletionString::Chunk::CreateText(StringRef Text) { return Chunk(CK_Text, Text); } @@ -51,15 +102,22 @@ CodeCompletionString::Chunk::CreateOptional( } CodeCompletionString::Chunk -CodeCompletionString::Chunk::CreatePlaceholder(const char *Placeholder) { +CodeCompletionString::Chunk::CreatePlaceholder(StringRef Placeholder) { return Chunk(CK_Placeholder, Placeholder); } CodeCompletionString::Chunk -CodeCompletionString::Chunk::CreateInformative(const char *Informative) { +CodeCompletionString::Chunk::CreateInformative(StringRef Informative) { return Chunk(CK_Informative, Informative); } +CodeCompletionString::Chunk +CodeCompletionString::Chunk::CreateCurrentParameter( + StringRef CurrentParameter) { + return Chunk(CK_CurrentParameter, CurrentParameter); +} + + void CodeCompletionString::Chunk::Destroy() { switch (Kind) { @@ -67,10 +125,23 @@ CodeCompletionString::Chunk::Destroy() { delete Optional; break; + case CK_TypedText: case CK_Text: case CK_Placeholder: case CK_Informative: - delete [] Text; + case CK_CurrentParameter: + delete [] Text; + break; + + case CK_LeftParen: + case CK_RightParen: + case CK_LeftBracket: + case CK_RightBracket: + case CK_LeftBrace: + case CK_RightBrace: + case CK_LeftAngle: + case CK_RightAngle: + case CK_Comma: break; } } @@ -86,16 +157,322 @@ std::string CodeCompletionString::getAsString() const { for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) { switch (C->Kind) { - case CK_Text: OS << C->Text; break; case CK_Optional: OS << "{#" << C->Optional->getAsString() << "#}"; break; case CK_Placeholder: OS << "<#" << C->Text << "#>"; break; case CK_Informative: OS << "[#" << C->Text << "#]"; break; + case CK_CurrentParameter: OS << "<#" << C->Text << "#>"; break; + default: OS << C->Text; break; } } OS.flush(); return Result; } + +namespace { + // Escape a string for XML-like formatting. + struct EscapedString { + EscapedString(llvm::StringRef Str) : Str(Str) { } + + llvm::StringRef Str; + }; + + llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, EscapedString EStr) { + llvm::StringRef Str = EStr.Str; + while (!Str.empty()) { + // Find the next escaped character. + llvm::StringRef::size_type Pos = Str.find_first_of("<>&\"'"); + + // Print everything before that escaped character. + OS << Str.substr(0, Pos); + + // If we didn't find any escaped characters, we're done. + if (Pos == llvm::StringRef::npos) + break; + + // Print the appropriate escape sequence. + switch (Str[Pos]) { + case '<': OS << "<"; break; + case '>': OS << ">"; break; + case '&': OS << "&"; break; + case '"': OS << """; break; + case '\'': OS << "'"; break; + } + + // Remove everything up to and including that escaped character. + Str = Str.substr(Pos + 1); + } + + return OS; + } + + /// \brief Remove XML-like escaping from a string. + std::string UnescapeString(llvm::StringRef Str) { + using llvm::StringRef; + + std::string Result; + llvm::raw_string_ostream OS(Result); + + while (!Str.empty()) { + StringRef::size_type Amp = Str.find('&'); + OS << Str.substr(0, Amp); + + if (Amp == StringRef::npos) + break; + + StringRef::size_type Semi = Str.substr(Amp).find(';'); + if (Semi == StringRef::npos) { + // Malformed input; do the best we can. + OS << '&'; + Str = Str.substr(Amp + 1); + continue; + } + + char Unescaped = llvm::StringSwitch<char>(Str.substr(Amp + 1, Semi - 1)) + .Case("lt", '<') + .Case("gt", '>') + .Case("amp", '&') + .Case("quot", '"') + .Case("apos", '\'') + .Default('\0'); + + if (Unescaped) + OS << Unescaped; + else + OS << Str.substr(Amp, Semi + 1); + Str = Str.substr(Amp + Semi + 1); + } + + return OS.str(); + } +} + +void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const { + for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) { + switch (C->Kind) { + case CK_TypedText: + OS << "<typed-text>" << EscapedString(C->Text) << "</>"; + break; + case CK_Text: + OS << "<text>" << EscapedString(C->Text) << "</>"; + break; + case CK_Optional: + OS << "<optional>"; + C->Optional->Serialize(OS); + OS << "</>"; + break; + case CK_Placeholder: + OS << "<placeholder>" << EscapedString(C->Text) << "</>"; + break; + case CK_Informative: + OS << "<informative>" << EscapedString(C->Text) << "</>"; + break; + case CK_CurrentParameter: + OS << "<current-parameter>" << EscapedString(C->Text) << "</>"; + break; + case CK_LeftParen: + OS << "<lparen/>"; + break; + case CK_RightParen: + OS << "<rparen/>"; + break; + case CK_LeftBracket: + OS << "<lbracket/>"; + break; + case CK_RightBracket: + OS << "<rbracket/>"; + break; + case CK_LeftBrace: + OS << "<lbrace/>"; + break; + case CK_RightBrace: + OS << "<rbrace/>"; + break; + case CK_LeftAngle: + OS << "<langle/>"; + break; + case CK_RightAngle: + OS << "<rangle/>"; + break; + case CK_Comma: + OS << "<comma/>"; + break; + } + } +} + +/// \brief Parse the next XML-ish tag of the form <blah>. +/// +/// \param Str the string in which we're looking for the next tag. +/// +/// \param TagPos if successful, will be set to the start of the tag we found. +/// +/// \param Standalone will indicate whether this is a "standalone" tag that +/// has no associated data, e.g., <comma/>. +/// +/// \param Terminator will indicate whether this is a terminating tag (that is +/// or starts with '/'). +/// +/// \returns the tag itself, without the angle brackets. +static llvm::StringRef ParseNextTag(llvm::StringRef Str, + llvm::StringRef::size_type &StartTag, + llvm::StringRef::size_type &AfterTag, + bool &Standalone, bool &Terminator) { + using llvm::StringRef; + + Standalone = false; + Terminator = false; + AfterTag = StringRef::npos; + + // Find the starting '<'. + StartTag = Str.find('<'); + if (StartTag == StringRef::npos) + return llvm::StringRef(); + + // Find the corresponding '>'. + llvm::StringRef::size_type EndTag = Str.substr(StartTag).find('>'); + if (EndTag == StringRef::npos) + return llvm::StringRef(); + AfterTag = StartTag + EndTag + 1; + + // Determine whether this is a terminating tag. + if (Str[StartTag + 1] == '/') { + Terminator = true; + Str = Str.substr(1); + --EndTag; + } + + // Determine whether this is a standalone tag. + if (!Terminator && Str[StartTag + EndTag - 1] == '/') { + Standalone = true; + if (EndTag > 1) + --EndTag; + } + + return Str.substr(StartTag + 1, EndTag - 1); +} + +CodeCompletionString *CodeCompletionString::Deserialize(llvm::StringRef &Str) { + using llvm::StringRef; + + CodeCompletionString *Result = new CodeCompletionString; + + do { + // Parse the next tag. + StringRef::size_type StartTag, AfterTag; + bool Standalone, Terminator; + StringRef Tag = ParseNextTag(Str, StartTag, AfterTag, Standalone, + Terminator); + + if (StartTag == StringRef::npos) + break; + + // Figure out what kind of chunk we have. + const unsigned UnknownKind = 10000; + unsigned Kind = llvm::StringSwitch<unsigned>(Tag) + .Case("typed-text", CK_TypedText) + .Case("text", CK_Text) + .Case("optional", CK_Optional) + .Case("placeholder", CK_Placeholder) + .Case("informative", CK_Informative) + .Case("current-parameter", CK_CurrentParameter) + .Case("lparen", CK_LeftParen) + .Case("rparen", CK_RightParen) + .Case("lbracket", CK_LeftBracket) + .Case("rbracket", CK_RightBracket) + .Case("lbrace", CK_LeftBrace) + .Case("rbrace", CK_RightBrace) + .Case("langle", CK_LeftAngle) + .Case("rangle", CK_RightAngle) + .Case("comma", CK_Comma) + .Default(UnknownKind); + + // If we've hit a terminator tag, we're done. + if (Terminator) + break; + + // Consume the tag. + Str = Str.substr(AfterTag); + + // Handle standalone tags now, since they don't need to be matched to + // anything. + if (Standalone) { + // Ignore anything we don't know about. + if (Kind == UnknownKind) + continue; + + switch ((ChunkKind)Kind) { + case CK_TypedText: + case CK_Text: + case CK_Optional: + case CK_Placeholder: + case CK_Informative: + case CK_CurrentParameter: + // There is no point in creating empty chunks of these kinds. + break; + + case CK_LeftParen: + case CK_RightParen: + case CK_LeftBracket: + case CK_RightBracket: + case CK_LeftBrace: + case CK_RightBrace: + case CK_LeftAngle: + case CK_RightAngle: + case CK_Comma: + Result->AddChunk(Chunk((ChunkKind)Kind)); + break; + } + + continue; + } + + if (Kind == CK_Optional) { + // Deserialize the optional code-completion string. + std::auto_ptr<CodeCompletionString> Optional(Deserialize(Str)); + Result->AddOptionalChunk(Optional); + } + + StringRef EndTag = ParseNextTag(Str, StartTag, AfterTag, Standalone, + Terminator); + if (StartTag == StringRef::npos || !Terminator || Standalone) + break; // Parsing failed; just give up. + + if (EndTag.empty() || Tag == EndTag) { + // Found the matching end tag. Add this chunk based on the text + // between the tags, then consume that input. + StringRef Text = Str.substr(0, StartTag); + switch ((ChunkKind)Kind) { + case CK_TypedText: + case CK_Text: + case CK_Placeholder: + case CK_Informative: + case CK_CurrentParameter: + case CK_LeftParen: + case CK_RightParen: + case CK_LeftBracket: + case CK_RightBracket: + case CK_LeftBrace: + case CK_RightBrace: + case CK_LeftAngle: + case CK_RightAngle: + case CK_Comma: + Result->AddChunk(Chunk((ChunkKind)Kind, UnescapeString(Text))); + break; + + case CK_Optional: + // We've already added the optional chunk. + break; + } + } + + // Remove this tag. + Str = Str.substr(AfterTag); + } while (!Str.empty()); + + return Result; +} + //===----------------------------------------------------------------------===// // Code completion overload candidate implementation //===----------------------------------------------------------------------===// @@ -133,7 +510,8 @@ CodeCompleteConsumer::OverloadCandidate::getFunctionType() const { CodeCompleteConsumer::~CodeCompleteConsumer() { } void -PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results, +PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, + Result *Results, unsigned NumResults) { // Print the results. for (unsigned I = 0; I != NumResults; ++I) { @@ -177,7 +555,8 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results, } void -PrintingCodeCompleteConsumer::ProcessOverloadCandidates(unsigned CurrentArg, +PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, + unsigned CurrentArg, OverloadCandidate *Candidates, unsigned NumCandidates) { for (unsigned I = 0; I != NumCandidates; ++I) { @@ -193,3 +572,87 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(unsigned CurrentArg, // FIXME: Move this somewhere else! SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); } + +void +CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, + Result *Results, + unsigned NumResults) { + // Print the results. + for (unsigned I = 0; I != NumResults; ++I) { + OS << "COMPLETION:" << Results[I].Rank << ":"; + switch (Results[I].Kind) { + case Result::RK_Declaration: + if (RecordDecl *Record = dyn_cast<RecordDecl>(Results[I].Declaration)) { + if (Record->isStruct()) + OS << "Struct:"; + else if (Record->isUnion()) + OS << "Union:"; + else + OS << "Class:"; + } else if (ObjCMethodDecl *Method + = dyn_cast<ObjCMethodDecl>(Results[I].Declaration)) { + if (Method->isInstanceMethod()) + OS << "ObjCInstanceMethod:"; + else + OS << "ObjCClassMethod:"; + } else { + OS << Results[I].Declaration->getDeclKindName() << ":"; + } + if (CodeCompletionString *CCS + = Results[I].CreateCodeCompletionString(SemaRef)) { + CCS->Serialize(OS); + delete CCS; + } else { + OS << "<typed-text>" + << Results[I].Declaration->getNameAsString() + << "</>"; + } + + OS << '\n'; + break; + + case Result::RK_Keyword: + OS << "Keyword:<typed-text>" << Results[I].Keyword << "</>\n"; + break; + + case Result::RK_Macro: { + OS << "Macro:"; + if (CodeCompletionString *CCS + = Results[I].CreateCodeCompletionString(SemaRef)) { + CCS->Serialize(OS); + delete CCS; + } else { + OS << "<typed-text>" << Results[I].Macro->getName() << "</>"; + } + OS << '\n'; + break; + } + } + } + + // Once we've printed the code-completion results, suppress remaining + // diagnostics. + // FIXME: Move this somewhere else! + SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); +} + +void +CIndexCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, + unsigned CurrentArg, + OverloadCandidate *Candidates, + unsigned NumCandidates) { + for (unsigned I = 0; I != NumCandidates; ++I) { + if (CodeCompletionString *CCS + = Candidates[I].CreateSignatureString(CurrentArg, SemaRef)) { + OS << "OVERLOAD:"; + CCS->Serialize(OS); + OS << '\n'; + delete CCS; + } + } + + // Once we've printed the code-completion results, suppress remaining + // diagnostics. + // FIXME: Move this somewhere else! + SemaRef.PP.getDiagnostics().setSuppressAllDiagnostics(); +} diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp index a8e31d2cfa2b..2b37e9df2c0e 100644 --- a/lib/Sema/JumpDiagnostics.cpp +++ b/lib/Sema/JumpDiagnostics.cpp @@ -325,5 +325,5 @@ void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, } void Sema::DiagnoseInvalidJumps(Stmt *Body) { - JumpScopeChecker(Body, *this); + (void)JumpScopeChecker(Body, *this); } diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h new file mode 100644 index 000000000000..6e72dcef161a --- /dev/null +++ b/lib/Sema/Lookup.h @@ -0,0 +1,392 @@ +//===--- Lookup.h - Classes for name lookup ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the LookupResult class, which is integral to +// Sema's name-lookup subsystem. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_LOOKUP_H +#define LLVM_CLANG_SEMA_LOOKUP_H + +#include "Sema.h" + +namespace clang { + +/// @brief Represents the results of name lookup. +/// +/// An instance of the LookupResult class captures the results of a +/// single name lookup, which can return no result (nothing found), +/// a single declaration, a set of overloaded functions, or an +/// ambiguity. Use the getKind() method to determine which of these +/// results occurred for a given lookup. +/// +/// Any non-ambiguous lookup can be converted into a single +/// (possibly NULL) @c NamedDecl* via the getAsSingleDecl() method. +/// This permits the common-case usage in C and Objective-C where +/// name lookup will always return a single declaration. Use of +/// this is largely deprecated; callers should handle the possibility +/// of multiple declarations. +class LookupResult { +public: + enum LookupResultKind { + /// @brief No entity found met the criteria. + NotFound = 0, + + /// @brief Name lookup found a single declaration that met the + /// criteria. getAsDecl will return this declaration. + Found, + + /// @brief Name lookup found a set of overloaded functions that + /// met the criteria. getAsDecl will turn this set of overloaded + /// functions into an OverloadedFunctionDecl. + FoundOverloaded, + + /// @brief Name lookup found an unresolvable value declaration + /// and cannot yet complete. This only happens in C++ dependent + /// contexts with dependent using declarations. + FoundUnresolvedValue, + + /// @brief Name lookup results in an ambiguity; use + /// getAmbiguityKind to figure out what kind of ambiguity + /// we have. + Ambiguous + }; + + enum AmbiguityKind { + /// Name lookup results in an ambiguity because multiple + /// entities that meet the lookup criteria were found in + /// subobjects of different types. For example: + /// @code + /// struct A { void f(int); } + /// struct B { void f(double); } + /// struct C : A, B { }; + /// void test(C c) { + /// c.f(0); // error: A::f and B::f come from subobjects of different + /// // types. overload resolution is not performed. + /// } + /// @endcode + AmbiguousBaseSubobjectTypes, + + /// Name lookup results in an ambiguity because multiple + /// nonstatic entities that meet the lookup criteria were found + /// in different subobjects of the same type. For example: + /// @code + /// struct A { int x; }; + /// struct B : A { }; + /// struct C : A { }; + /// struct D : B, C { }; + /// int test(D d) { + /// return d.x; // error: 'x' is found in two A subobjects (of B and C) + /// } + /// @endcode + AmbiguousBaseSubobjects, + + /// Name lookup results in an ambiguity because multiple definitions + /// of entity that meet the lookup criteria were found in different + /// declaration contexts. + /// @code + /// namespace A { + /// int i; + /// namespace B { int i; } + /// int test() { + /// using namespace B; + /// return i; // error 'i' is found in namespace A and A::B + /// } + /// } + /// @endcode + AmbiguousReference, + + /// Name lookup results in an ambiguity because an entity with a + /// tag name was hidden by an entity with an ordinary name from + /// a different context. + /// @code + /// namespace A { struct Foo {}; } + /// namespace B { void Foo(); } + /// namespace C { + /// using namespace A; + /// using namespace B; + /// } + /// void test() { + /// C::Foo(); // error: tag 'A::Foo' is hidden by an object in a + /// // different namespace + /// } + /// @endcode + AmbiguousTagHiding + }; + + /// A little identifier for flagging temporary lookup results. + enum TemporaryToken { + Temporary + }; + + typedef llvm::SmallVector<NamedDecl*, 4> DeclsTy; + typedef DeclsTy::const_iterator iterator; + + LookupResult(Sema &SemaRef, DeclarationName Name, SourceLocation NameLoc, + Sema::LookupNameKind LookupKind, + Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration) + : ResultKind(NotFound), + Paths(0), + SemaRef(SemaRef), + Name(Name), + NameLoc(NameLoc), + LookupKind(LookupKind), + IDNS(0), + Redecl(Redecl != Sema::NotForRedeclaration), + HideTags(true), + Diagnose(Redecl == Sema::NotForRedeclaration) + {} + + /// Creates a temporary lookup result, initializing its core data + /// using the information from another result. Diagnostics are always + /// disabled. + LookupResult(TemporaryToken _, const LookupResult &Other) + : ResultKind(NotFound), + Paths(0), + SemaRef(Other.SemaRef), + Name(Other.Name), + NameLoc(Other.NameLoc), + LookupKind(Other.LookupKind), + IDNS(Other.IDNS), + Redecl(Other.Redecl), + HideTags(Other.HideTags), + Diagnose(false) + {} + + ~LookupResult() { + if (Diagnose) diagnose(); + if (Paths) deletePaths(Paths); + } + + /// Gets the name to look up. + DeclarationName getLookupName() const { + return Name; + } + + /// Gets the kind of lookup to perform. + Sema::LookupNameKind getLookupKind() const { + return LookupKind; + } + + /// True if this lookup is just looking for an existing declaration. + bool isForRedeclaration() const { + return Redecl; + } + + /// Sets whether tag declarations should be hidden by non-tag + /// declarations during resolution. The default is true. + void setHideTags(bool Hide) { + HideTags = Hide; + } + + /// The identifier namespace of this lookup. This information is + /// private to the lookup routines. + unsigned getIdentifierNamespace() const { + assert(IDNS); + return IDNS; + } + + void setIdentifierNamespace(unsigned NS) { + IDNS = NS; + } + + bool isAmbiguous() const { + return getResultKind() == Ambiguous; + } + + LookupResultKind getResultKind() const { + sanity(); + return ResultKind; + } + + AmbiguityKind getAmbiguityKind() const { + assert(isAmbiguous()); + return Ambiguity; + } + + iterator begin() const { return Decls.begin(); } + iterator end() const { return Decls.end(); } + + /// \brief Return true if no decls were found + bool empty() const { return Decls.empty(); } + + /// \brief Return the base paths structure that's associated with + /// these results, or null if none is. + CXXBasePaths *getBasePaths() const { + return Paths; + } + + /// \brief Add a declaration to these results. + void addDecl(NamedDecl *D) { + Decls.push_back(D); + ResultKind = Found; + } + + /// \brief Add all the declarations from another set of lookup + /// results. + void addAllDecls(const LookupResult &Other) { + Decls.append(Other.begin(), Other.end()); + ResultKind = Found; + } + + /// \brief Hides a set of declarations. + template <class NamedDeclSet> void hideDecls(const NamedDeclSet &Set) { + unsigned I = 0, N = Decls.size(); + while (I < N) { + if (Set.count(Decls[I])) + Decls[I] = Decls[--N]; + else + I++; + } + Decls.set_size(N); + } + + /// \brief Resolves the kind of the lookup, possibly hiding decls. + /// + /// This should be called in any environment where lookup might + /// generate multiple lookup results. + void resolveKind(); + + /// \brief Fetch this as an unambiguous single declaration + /// (possibly an overloaded one). + /// + /// This is deprecated; users should be written to handle + /// ambiguous and overloaded lookups. + NamedDecl *getAsSingleDecl(ASTContext &Context) const; + + /// \brief Fetch the unique decl found by this lookup. Asserts + /// that one was found. + /// + /// This is intended for users who have examined the result kind + /// and are certain that there is only one result. + NamedDecl *getFoundDecl() const { + assert(getResultKind() == Found + && "getFoundDecl called on non-unique result"); + return Decls[0]->getUnderlyingDecl(); + } + + /// \brief Asks if the result is a single tag decl. + bool isSingleTagDecl() const { + return getResultKind() == Found && isa<TagDecl>(getFoundDecl()); + } + + /// \brief Make these results show that the name was found in + /// base classes of different types. + /// + /// The given paths object is copied and invalidated. + void setAmbiguousBaseSubobjectTypes(CXXBasePaths &P); + + /// \brief Make these results show that the name was found in + /// distinct base classes of the same type. + /// + /// The given paths object is copied and invalidated. + void setAmbiguousBaseSubobjects(CXXBasePaths &P); + + /// \brief Make these results show that the name was found in + /// different contexts and a tag decl was hidden by an ordinary + /// decl in a different context. + void setAmbiguousQualifiedTagHiding() { + setAmbiguous(AmbiguousTagHiding); + } + + /// \brief Clears out any current state. + void clear() { + ResultKind = NotFound; + Decls.clear(); + if (Paths) deletePaths(Paths); + Paths = NULL; + } + + /// \brief Clears out any current state and re-initializes for a + /// different kind of lookup. + void clear(Sema::LookupNameKind Kind) { + clear(); + LookupKind = Kind; + } + + void print(llvm::raw_ostream &); + + /// Suppress the diagnostics that would normally fire because of this + /// lookup. This happens during (e.g.) redeclaration lookups. + void suppressDiagnostics() { + Diagnose = false; + } + + /// Sets a 'context' source range. + void setContextRange(SourceRange SR) { + NameContextRange = SR; + } + + /// Gets the source range of the context of this name; for C++ + /// qualified lookups, this is the source range of the scope + /// specifier. + SourceRange getContextRange() const { + return NameContextRange; + } + + /// Gets the location of the identifier. This isn't always defined: + /// sometimes we're doing lookups on synthesized names. + SourceLocation getNameLoc() const { + return NameLoc; + } + +private: + void diagnose() { + if (isAmbiguous()) + SemaRef.DiagnoseAmbiguousLookup(*this); + } + + void setAmbiguous(AmbiguityKind AK) { + ResultKind = Ambiguous; + Ambiguity = AK; + } + + void addDeclsFromBasePaths(const CXXBasePaths &P); + + // Sanity checks. + void sanity() const { + assert(ResultKind != NotFound || Decls.size() == 0); + assert(ResultKind != Found || Decls.size() == 1); + assert(ResultKind == NotFound || ResultKind == Found || + ResultKind == FoundUnresolvedValue || + (ResultKind == Ambiguous && Ambiguity == AmbiguousBaseSubobjects) + || Decls.size() > 1); + assert((Paths != NULL) == (ResultKind == Ambiguous && + (Ambiguity == AmbiguousBaseSubobjectTypes || + Ambiguity == AmbiguousBaseSubobjects))); + } + + static void deletePaths(CXXBasePaths *); + + // Results. + LookupResultKind ResultKind; + AmbiguityKind Ambiguity; // ill-defined unless ambiguous + DeclsTy Decls; + CXXBasePaths *Paths; + + // Parameters. + Sema &SemaRef; + DeclarationName Name; + SourceLocation NameLoc; + SourceRange NameContextRange; + Sema::LookupNameKind LookupKind; + unsigned IDNS; // ill-defined until set by lookup + bool Redecl; + + /// \brief True if tag declarations should be hidden if non-tags + /// are present + bool HideTags; + + bool Diagnose; +}; + +} + +#endif diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp index d3f26d875cc4..7b223a8fa3b6 100644 --- a/lib/Sema/ParseAST.cpp +++ b/lib/Sema/ParseAST.cpp @@ -35,15 +35,14 @@ using namespace clang; void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, ASTContext &Ctx, bool PrintStats, bool CompleteTranslationUnit, - CodeCompleteConsumer *(*CreateCodeCompleter)(Sema &, void *Data), - void *CreateCodeCompleterData) { + CodeCompleteConsumer *CompletionConsumer) { // Collect global stats on Decls/Stmts (until we have a module streamer). if (PrintStats) { Decl::CollectingStats(true); Stmt::CollectingStats(true); } - Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit); + Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit, CompletionConsumer); Parser P(PP, S); PP.EnterMainSourceFile(); @@ -63,12 +62,6 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, External->StartTranslationUnit(Consumer); } - CodeCompleteConsumer *CodeCompleter = 0; - if (CreateCodeCompleter) { - CodeCompleter = CreateCodeCompleter(S, CreateCodeCompleterData); - S.setCodeCompleteConsumer(CodeCompleter); - } - Parser::DeclGroupPtrTy ADecl; while (!P.ParseTopLevelDecl(ADecl)) { // Not end of file. @@ -78,6 +71,9 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, if (ADecl) Consumer->HandleTopLevelDecl(ADecl.getAsVal<DeclGroupRef>()); }; + // Check for any pending objective-c implementation decl. + while ((ADecl = P.RetrievePendingObjCImpDecl())) + Consumer->HandleTopLevelDecl(ADecl.getAsVal<DeclGroupRef>()); // process any TopLevelDecls generated by #pragma weak for (llvm::SmallVector<Decl*,2>::iterator @@ -87,9 +83,6 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, Consumer->HandleTranslationUnit(Ctx); - if (CreateCodeCompleter) - delete CodeCompleter; - if (PrintStats) { fprintf(stderr, "\nSTATISTICS:\n"); P.getActions().PrintStats(); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 8104dd39d052..b2bbac8bc2a9 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -14,6 +14,7 @@ #include "Sema.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/APFloat.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" @@ -346,16 +347,18 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { } Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, - bool CompleteTranslationUnit) + bool CompleteTranslationUnit, + CodeCompleteConsumer *CodeCompleter) : LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), - ExternalSource(0), CodeCompleter(0), CurContext(0), + ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0), PreDeclaratorDC(0), CurBlock(0), PackContext(0), ParsingDeclDepth(0), IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0), GlobalNewDeleteDeclared(false), ExprEvalContext(PotentiallyEvaluated), CompleteTranslationUnit(CompleteTranslationUnit), - NumSFINAEErrors(0), CurrentInstantiationScope(0) { - + NumSFINAEErrors(0), NonInstantiationEntries(0), + CurrentInstantiationScope(0) +{ TUScope = 0; if (getLangOptions().CPlusPlus) FieldCollector.reset(new CXXFieldCollector()); @@ -364,6 +367,322 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, PP.getDiagnostics().SetArgToStringFn(ConvertArgToStringFn, &Context); } +/// Retrieves the width and signedness of the given integer type, +/// or returns false if it is not an integer type. +/// +/// \param T must be canonical +static bool getIntProperties(ASTContext &C, const Type *T, + unsigned &BitWidth, bool &Signed) { + assert(T->isCanonicalUnqualified()); + + if (const VectorType *VT = dyn_cast<VectorType>(T)) + T = VT->getElementType().getTypePtr(); + if (const ComplexType *CT = dyn_cast<ComplexType>(T)) + T = CT->getElementType().getTypePtr(); + + if (const BuiltinType *BT = dyn_cast<BuiltinType>(T)) { + if (!BT->isInteger()) return false; + + BitWidth = C.getIntWidth(QualType(T, 0)); + Signed = BT->isSignedInteger(); + return true; + } + + if (const FixedWidthIntType *FWIT = dyn_cast<FixedWidthIntType>(T)) { + BitWidth = FWIT->getWidth(); + Signed = FWIT->isSigned(); + return true; + } + + return false; +} + +/// Checks whether the given value will have the same value if it it +/// is truncated to the given width, then extended back to the +/// original width. +static bool IsSameIntAfterCast(const llvm::APSInt &value, + unsigned TargetWidth) { + unsigned SourceWidth = value.getBitWidth(); + llvm::APSInt truncated = value; + truncated.trunc(TargetWidth); + truncated.extend(SourceWidth); + return (truncated == value); +} + +/// Checks whether the given value will have the same value if it +/// is truncated to the given width, then extended back to the original +/// width. +/// +/// The value might be a vector or a complex. +static bool IsSameIntAfterCast(const APValue &value, unsigned TargetWidth) { + if (value.isInt()) + return IsSameIntAfterCast(value.getInt(), TargetWidth); + + if (value.isVector()) { + for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i) + if (!IsSameIntAfterCast(value.getVectorElt(i), TargetWidth)) + return false; + return true; + } + + if (value.isComplexInt()) { + return IsSameIntAfterCast(value.getComplexIntReal(), TargetWidth) && + IsSameIntAfterCast(value.getComplexIntImag(), TargetWidth); + } + + // This can happen with lossless casts to intptr_t of "based" lvalues. + // Assume it might use arbitrary bits. + assert(value.isLValue()); + return false; +} + + +/// Checks whether the given value, which currently has the given +/// source semantics, has the same value when coerced through the +/// target semantics. +static bool IsSameFloatAfterCast(const llvm::APFloat &value, + const llvm::fltSemantics &Src, + const llvm::fltSemantics &Tgt) { + llvm::APFloat truncated = value; + + bool ignored; + truncated.convert(Src, llvm::APFloat::rmNearestTiesToEven, &ignored); + truncated.convert(Tgt, llvm::APFloat::rmNearestTiesToEven, &ignored); + + return truncated.bitwiseIsEqual(value); +} + +/// Checks whether the given value, which currently has the given +/// source semantics, has the same value when coerced through the +/// target semantics. +/// +/// The value might be a vector of floats (or a complex number). +static bool IsSameFloatAfterCast(const APValue &value, + const llvm::fltSemantics &Src, + const llvm::fltSemantics &Tgt) { + if (value.isFloat()) + return IsSameFloatAfterCast(value.getFloat(), Src, Tgt); + + if (value.isVector()) { + for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i) + if (!IsSameFloatAfterCast(value.getVectorElt(i), Src, Tgt)) + return false; + return true; + } + + assert(value.isComplexFloat()); + return (IsSameFloatAfterCast(value.getComplexFloatReal(), Src, Tgt) && + IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt)); +} + +/// Determines if it's reasonable for the given expression to be truncated +/// down to the given integer width. +/// * Boolean expressions are automatically white-listed. +/// * Arithmetic operations on implicitly-promoted operands of the +/// target width or less are okay --- not because the results are +/// actually guaranteed to fit within the width, but because the +/// user is effectively pretending that the operations are closed +/// within the implicitly-promoted type. +static bool IsExprValueWithinWidth(ASTContext &C, Expr *E, unsigned Width) { + E = E->IgnoreParens(); + +#ifndef NDEBUG + { + const Type *ETy = E->getType()->getCanonicalTypeInternal().getTypePtr(); + unsigned EWidth; + bool ESigned; + + if (!getIntProperties(C, ETy, EWidth, ESigned)) + assert(0 && "expression not of integer type"); + + // The caller should never let this happen. + assert(EWidth > Width && "called on expr whose type is too small"); + } +#endif + + // Strip implicit casts off. + while (isa<ImplicitCastExpr>(E)) { + E = cast<ImplicitCastExpr>(E)->getSubExpr(); + + const Type *ETy = E->getType()->getCanonicalTypeInternal().getTypePtr(); + + unsigned EWidth; + bool ESigned; + if (!getIntProperties(C, ETy, EWidth, ESigned)) + return false; + + if (EWidth <= Width) + return true; + } + + if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { + switch (BO->getOpcode()) { + + // Boolean-valued operations are white-listed. + case BinaryOperator::LAnd: + case BinaryOperator::LOr: + case BinaryOperator::LT: + case BinaryOperator::GT: + case BinaryOperator::LE: + case BinaryOperator::GE: + case BinaryOperator::EQ: + case BinaryOperator::NE: + return true; + + // Operations with opaque sources are black-listed. + case BinaryOperator::PtrMemD: + case BinaryOperator::PtrMemI: + return false; + + // Left shift gets black-listed based on a judgement call. + case BinaryOperator::Shl: + return false; + + // Various special cases. + case BinaryOperator::Shr: + return IsExprValueWithinWidth(C, BO->getLHS(), Width); + case BinaryOperator::Comma: + return IsExprValueWithinWidth(C, BO->getRHS(), Width); + case BinaryOperator::Sub: + if (BO->getLHS()->getType()->isPointerType()) + return false; + // fallthrough + + // Any other operator is okay if the operands are + // promoted from expressions of appropriate size. + default: + return IsExprValueWithinWidth(C, BO->getLHS(), Width) && + IsExprValueWithinWidth(C, BO->getRHS(), Width); + } + } + + if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { + switch (UO->getOpcode()) { + // Boolean-valued operations are white-listed. + case UnaryOperator::LNot: + return true; + + // Operations with opaque sources are black-listed. + case UnaryOperator::Deref: + case UnaryOperator::AddrOf: // should be impossible + return false; + + case UnaryOperator::OffsetOf: + return false; + + default: + return IsExprValueWithinWidth(C, UO->getSubExpr(), Width); + } + } + + // Don't diagnose if the expression is an integer constant + // whose value in the target type is the same as it was + // in the original type. + Expr::EvalResult result; + if (E->Evaluate(result, C)) + if (IsSameIntAfterCast(result.Val, Width)) + return true; + + return false; +} + +/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. +static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) { + S.Diag(E->getExprLoc(), diag) << E->getType() << T << E->getSourceRange(); +} + +/// Implements -Wconversion. +static void CheckImplicitConversion(Sema &S, Expr *E, QualType T) { + // Don't diagnose in unevaluated contexts. + if (S.ExprEvalContext == Sema::Unevaluated) + return; + + // Don't diagnose for value-dependent expressions. + if (E->isValueDependent()) + return; + + const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr(); + const Type *Target = S.Context.getCanonicalType(T).getTypePtr(); + + // Never diagnose implicit casts to bool. + if (Target->isSpecificBuiltinType(BuiltinType::Bool)) + return; + + // Strip vector types. + if (isa<VectorType>(Source)) { + if (!isa<VectorType>(Target)) + return DiagnoseImpCast(S, E, T, diag::warn_impcast_vector_scalar); + + Source = cast<VectorType>(Source)->getElementType().getTypePtr(); + Target = cast<VectorType>(Target)->getElementType().getTypePtr(); + } + + // Strip complex types. + if (isa<ComplexType>(Source)) { + if (!isa<ComplexType>(Target)) + return DiagnoseImpCast(S, E, T, diag::warn_impcast_complex_scalar); + + Source = cast<ComplexType>(Source)->getElementType().getTypePtr(); + Target = cast<ComplexType>(Target)->getElementType().getTypePtr(); + } + + const BuiltinType *SourceBT = dyn_cast<BuiltinType>(Source); + const BuiltinType *TargetBT = dyn_cast<BuiltinType>(Target); + + // If the source is floating point... + if (SourceBT && SourceBT->isFloatingPoint()) { + // ...and the target is floating point... + if (TargetBT && TargetBT->isFloatingPoint()) { + // ...then warn if we're dropping FP rank. + + // Builtin FP kinds are ordered by increasing FP rank. + if (SourceBT->getKind() > TargetBT->getKind()) { + // Don't warn about float constants that are precisely + // representable in the target type. + Expr::EvalResult result; + if (E->Evaluate(result, S.Context)) { + // Value might be a float, a float vector, or a float complex. + if (IsSameFloatAfterCast(result.Val, + S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)), + S.Context.getFloatTypeSemantics(QualType(SourceBT, 0)))) + return; + } + + DiagnoseImpCast(S, E, T, diag::warn_impcast_float_precision); + } + return; + } + + // If the target is integral, always warn. + if ((TargetBT && TargetBT->isInteger()) || + isa<FixedWidthIntType>(Target)) + // TODO: don't warn for integer values? + return DiagnoseImpCast(S, E, T, diag::warn_impcast_float_integer); + + return; + } + + unsigned SourceWidth, TargetWidth; + bool SourceSigned, TargetSigned; + + if (!getIntProperties(S.Context, Source, SourceWidth, SourceSigned) || + !getIntProperties(S.Context, Target, TargetWidth, TargetSigned)) + return; + + if (SourceWidth > TargetWidth) { + if (IsExprValueWithinWidth(S.Context, E, TargetWidth)) + return; + + // People want to build with -Wshorten-64-to-32 and not -Wconversion + // and by god we'll let them. + if (SourceWidth == 64 && TargetWidth == 32) + return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_64_32); + return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_precision); + } + + return; +} + /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast. /// If there is already an implicit cast, merge into the existing one. /// If isLvalue, the result of the cast is an lvalue. @@ -375,18 +694,17 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, if (ExprTy == TypeTy) return; - if (Expr->getType().getTypePtr()->isPointerType() && - Ty.getTypePtr()->isPointerType()) { - QualType ExprBaseType = - cast<PointerType>(ExprTy.getUnqualifiedType())->getPointeeType(); - QualType BaseType = - cast<PointerType>(TypeTy.getUnqualifiedType())->getPointeeType(); + if (Expr->getType()->isPointerType() && Ty->isPointerType()) { + QualType ExprBaseType = cast<PointerType>(ExprTy)->getPointeeType(); + QualType BaseType = cast<PointerType>(TypeTy)->getPointeeType(); if (ExprBaseType.getAddressSpace() != BaseType.getAddressSpace()) { Diag(Expr->getExprLoc(), diag::err_implicit_pointer_address_space_cast) << Expr->getSourceRange(); } } + CheckImplicitConversion(*this, Expr, Ty); + if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) { if (ImpCast->getCastKind() == Kind) { ImpCast->setType(Ty); diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index c4de6be9eb2e..3e186b2b5be9 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -93,6 +93,7 @@ namespace clang { class FunctionProtoType; class CXXBasePaths; class CXXTemporary; + class LookupResult; /// BlockSemaInfo - When a block is being parsed, this contains information /// about the block. It is pointed to from Sema::CurBlock. @@ -373,7 +374,8 @@ public: bool isSelfExpr(Expr *RExpr); public: Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, - bool CompleteTranslationUnit = true); + bool CompleteTranslationUnit = true, + CodeCompleteConsumer *CompletionConsumer = 0); ~Sema() { if (PackContext) FreePackedContext(); } @@ -804,13 +806,15 @@ public: QualType& ConvertedType, bool &IncompatibleObjC); bool isObjCPointerConversion(QualType FromType, QualType ToType, QualType& ConvertedType, bool &IncompatibleObjC); - bool CheckPointerConversion(Expr *From, QualType ToType, - CastExpr::CastKind &Kind); + bool CheckPointerConversion(Expr *From, QualType ToType, + CastExpr::CastKind &Kind, + bool IgnoreBaseAccess); bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType, bool InOverloadResolution, QualType &ConvertedType); bool CheckMemberPointerConversion(Expr *From, QualType ToType, - CastExpr::CastKind &Kind); + CastExpr::CastKind &Kind, + bool IgnoreBaseAccess); bool IsQualificationConversion(QualType FromType, QualType ToType); OverloadingResult IsUserDefinedConversion(Expr *From, QualType ToType, UserDefinedConversionSequence& User, @@ -870,6 +874,11 @@ public: Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false); + void AddMethodCandidate(NamedDecl *Decl, + Expr *Object, Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversion = false, + bool ForceRValue = false); void AddMethodCandidate(CXXMethodDecl *Method, Expr *Object, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, @@ -1073,255 +1082,14 @@ public: LookupObjCCategoryImplName }; - /// @brief Represents the results of name lookup. - /// - /// An instance of the LookupResult class captures the results of a - /// single name lookup, which can return no result (nothing found), - /// a single declaration, a set of overloaded functions, or an - /// ambiguity. Use the getKind() method to determine which of these - /// results occurred for a given lookup. - /// - /// Any non-ambiguous lookup can be converted into a single - /// (possibly NULL) @c NamedDecl* via the getAsSingleDecl() method. - /// This permits the common-case usage in C and Objective-C where - /// name lookup will always return a single declaration. Use of - /// this is largely deprecated; callers should handle the possibility - /// of multiple declarations. - class LookupResult { - public: - enum LookupKind { - /// @brief No entity found met the criteria. - NotFound = 0, - - /// @brief Name lookup found a single declaration that met the - /// criteria. getAsDecl will return this declaration. - Found, - - /// @brief Name lookup found a set of overloaded functions that - /// met the criteria. getAsDecl will turn this set of overloaded - /// functions into an OverloadedFunctionDecl. - FoundOverloaded, - - /// @brief Name lookup results in an ambiguity; use - /// getAmbiguityKind to figure out what kind of ambiguity - /// we have. - Ambiguous - }; - - enum AmbiguityKind { - /// Name lookup results in an ambiguity because multiple - /// entities that meet the lookup criteria were found in - /// subobjects of different types. For example: - /// @code - /// struct A { void f(int); } - /// struct B { void f(double); } - /// struct C : A, B { }; - /// void test(C c) { - /// c.f(0); // error: A::f and B::f come from subobjects of different - /// // types. overload resolution is not performed. - /// } - /// @endcode - AmbiguousBaseSubobjectTypes, - - /// Name lookup results in an ambiguity because multiple - /// nonstatic entities that meet the lookup criteria were found - /// in different subobjects of the same type. For example: - /// @code - /// struct A { int x; }; - /// struct B : A { }; - /// struct C : A { }; - /// struct D : B, C { }; - /// int test(D d) { - /// return d.x; // error: 'x' is found in two A subobjects (of B and C) - /// } - /// @endcode - AmbiguousBaseSubobjects, - - /// Name lookup results in an ambiguity because multiple definitions - /// of entity that meet the lookup criteria were found in different - /// declaration contexts. - /// @code - /// namespace A { - /// int i; - /// namespace B { int i; } - /// int test() { - /// using namespace B; - /// return i; // error 'i' is found in namespace A and A::B - /// } - /// } - /// @endcode - AmbiguousReference, - - /// Name lookup results in an ambiguity because an entity with a - /// tag name was hidden by an entity with an ordinary name from - /// a different context. - /// @code - /// namespace A { struct Foo {}; } - /// namespace B { void Foo(); } - /// namespace C { - /// using namespace A; - /// using namespace B; - /// } - /// void test() { - /// C::Foo(); // error: tag 'A::Foo' is hidden by an object in a - /// // different namespace - /// } - /// @endcode - AmbiguousTagHiding - }; - - typedef llvm::SmallVector<NamedDecl*, 4> DeclsTy; - typedef DeclsTy::const_iterator iterator; - - LookupResult() - : Kind(NotFound), - Paths(0) - {} - ~LookupResult() { - if (Paths) deletePaths(Paths); - } - - bool isAmbiguous() const { - return getKind() == Ambiguous; - } - - LookupKind getKind() const { - sanity(); - return Kind; - } - - AmbiguityKind getAmbiguityKind() const { - assert(isAmbiguous()); - return Ambiguity; - } - - iterator begin() const { return Decls.begin(); } - iterator end() const { return Decls.end(); } - - /// \brief Return true if no decls were found - bool empty() const { return Decls.empty(); } - - /// \brief Return the base paths structure that's associated with - /// these results, or null if none is. - CXXBasePaths *getBasePaths() const { - return Paths; - } - - /// \brief Add a declaration to these results. - void addDecl(NamedDecl *D) { - Decls.push_back(D->getUnderlyingDecl()); - Kind = Found; - } - - /// \brief Add all the declarations from another set of lookup - /// results. - void addAllDecls(const LookupResult &Other) { - Decls.append(Other.begin(), Other.end()); - Kind = Found; - } - - /// \brief Hides a set of declarations. - template <class NamedDeclSet> void hideDecls(const NamedDeclSet &Set) { - unsigned I = 0, N = Decls.size(); - while (I < N) { - if (Set.count(Decls[I])) - Decls[I] = Decls[--N]; - else - I++; - } - Decls.set_size(N); - } - - /// \brief Resolves the kind of the lookup, possibly hiding decls. - /// - /// This should be called in any environment where lookup might - /// generate multiple lookup results. - void resolveKind(); - - /// \brief Fetch this as an unambiguous single declaration - /// (possibly an overloaded one). - /// - /// This is deprecated; users should be written to handle - /// ambiguous and overloaded lookups. - NamedDecl *getAsSingleDecl(ASTContext &Context) const; - - /// \brief Fetch the unique decl found by this lookup. Asserts - /// that one was found. - /// - /// This is intended for users who have examined the result kind - /// and are certain that there is only one result. - NamedDecl *getFoundDecl() const { - assert(getKind() == Found && "getFoundDecl called on non-unique result"); - return *Decls.begin(); - } - - /// \brief Asks if the result is a single tag decl. - bool isSingleTagDecl() const { - return getKind() == Found && isa<TagDecl>(getFoundDecl()); - } - - /// \brief Make these results show that the name was found in - /// base classes of different types. - /// - /// The given paths object is copied and invalidated. - void setAmbiguousBaseSubobjectTypes(CXXBasePaths &P); - - /// \brief Make these results show that the name was found in - /// distinct base classes of the same type. - /// - /// The given paths object is copied and invalidated. - void setAmbiguousBaseSubobjects(CXXBasePaths &P); - - /// \brief Make these results show that the name was found in - /// different contexts and a tag decl was hidden by an ordinary - /// decl in a different context. - void setAmbiguousQualifiedTagHiding() { - setAmbiguous(AmbiguousTagHiding); - } - - /// \brief Clears out any current state. - void clear() { - Kind = NotFound; - Decls.clear(); - if (Paths) deletePaths(Paths); - Paths = NULL; - } - - void print(llvm::raw_ostream &); - - private: - void setAmbiguous(AmbiguityKind AK) { - Kind = Ambiguous; - Ambiguity = AK; - } - - void addDeclsFromBasePaths(const CXXBasePaths &P); - - // Sanity checks. - void sanity() const { - assert(Kind != NotFound || Decls.size() == 0); - assert(Kind != Found || Decls.size() == 1); - assert(Kind == NotFound || Kind == Found || - (Kind == Ambiguous && Ambiguity == AmbiguousBaseSubobjects) - || Decls.size() > 1); - assert((Paths != NULL) == (Kind == Ambiguous && - (Ambiguity == AmbiguousBaseSubobjectTypes || - Ambiguity == AmbiguousBaseSubobjects))); - } - - static void deletePaths(CXXBasePaths *); - - LookupKind Kind; - AmbiguityKind Ambiguity; // ill-defined unless ambiguous - DeclsTy Decls; - CXXBasePaths *Paths; + enum RedeclarationKind { + NotForRedeclaration, + ForRedeclaration }; private: - typedef llvm::SmallVector<LookupResult, 3> LookupResultsVecTy; + bool CppLookupName(LookupResult &R, Scope *S); - bool CppLookupName(LookupResult &R, Scope *S, DeclarationName Name, - LookupNameKind NameKind, bool RedeclarationOnly); public: /// Determines whether D is a suitable lookup result according to the /// lookup criteria. @@ -1360,27 +1128,13 @@ public: /// ambiguity and overloaded. NamedDecl *LookupSingleName(Scope *S, DeclarationName Name, LookupNameKind NameKind, - bool RedeclarationOnly = false) { - LookupResult R; - LookupName(R, S, Name, NameKind, RedeclarationOnly); - return R.getAsSingleDecl(Context); - } + RedeclarationKind Redecl + = NotForRedeclaration); bool LookupName(LookupResult &R, Scope *S, - DeclarationName Name, - LookupNameKind NameKind, - bool RedeclarationOnly = false, - bool AllowBuiltinCreation = false, - SourceLocation Loc = SourceLocation()); - bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, - DeclarationName Name, - LookupNameKind NameKind, - bool RedeclarationOnly = false); + bool AllowBuiltinCreation = false); + bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx); bool LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS, - DeclarationName Name, - LookupNameKind NameKind, - bool RedeclarationOnly = false, bool AllowBuiltinCreation = false, - SourceLocation Loc = SourceLocation(), bool EnteringContext = false); ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II); @@ -1398,9 +1152,7 @@ public: AssociatedNamespaceSet &AssociatedNamespaces, AssociatedClassSet &AssociatedClasses); - bool DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name, - SourceLocation NameLoc, - SourceRange LookupRange = SourceRange()); + bool DiagnoseAmbiguousLookup(LookupResult &Result); //@} ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id); @@ -1447,6 +1199,12 @@ public: void ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, ObjCContainerDecl* IDecl, bool IncompleteImpl = false); + + /// AtomicPropertySetterGetterRules - This routine enforces the rule (via + /// warning) when atomic property has one but not the other user-declared + /// setter or getter. + void AtomicPropertySetterGetterRules(ObjCImplDecl* IMPDecl, + ObjCContainerDecl* IDecl); /// MatchTwoMethodDeclarations - Checks if two methods' type match and returns /// true, or false, accordingly. @@ -1610,7 +1368,8 @@ public: Expr **Args, unsigned NumArgs); void CheckSignCompare(Expr *LHS, Expr *RHS, SourceLocation Loc, - const PartialDiagnostic &PD); + const PartialDiagnostic &PD, + bool Equality = false); virtual ExpressionEvaluationContext PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext); @@ -1746,11 +1505,6 @@ public: const FunctionProtoType *Proto, Expr **Args, unsigned NumArgs, SourceLocation RParenLoc); - void BuildBaseOrMemberInitializers(ASTContext &C, - CXXConstructorDecl *Constructor, - CXXBaseOrMemberInitializer **Initializers, - unsigned NumInitializers - ); void DeconstructCallFunction(Expr *FnExpr, NamedDecl *&Function, @@ -1890,12 +1644,15 @@ public: SourceLocation IdentLoc, IdentifierInfo *Ident); - NamedDecl *BuildUsingDeclaration(SourceLocation UsingLoc, + NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS, + SourceLocation UsingLoc, const CXXScopeSpec &SS, SourceLocation IdentLoc, DeclarationName Name, AttributeList *AttrList, - bool IsTypeName); + bool IsInstantiation, + bool IsTypeName, + SourceLocation TypenameLoc); virtual DeclPtrTy ActOnUsingDeclaration(Scope *CurScope, AccessSpecifier AS, @@ -1903,7 +1660,8 @@ public: const CXXScopeSpec &SS, UnqualifiedId &Name, AttributeList *AttrList, - bool IsTypeName); + bool IsTypeName, + SourceLocation TypenameLoc); /// AddCXXDirectInitializerToDecl - This action is called immediately after /// ActOnDeclarator, when a C++ direct initializer is present. @@ -1997,6 +1755,12 @@ public: }; CXXConstructorDecl * + TryInitializationByConstructor(QualType ClassType, + Expr **Args, unsigned NumArgs, + SourceLocation Loc, + InitializationKind Kind); + + CXXConstructorDecl * PerformInitializationByConstructor(QualType ClassType, MultiExprArg ArgsPtr, SourceLocation Loc, SourceRange Range, @@ -2088,6 +1852,9 @@ public: void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return, QualType Argument); + bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, + DeclarationName Name, FunctionDecl* &Operator); + /// ActOnCXXDelete - Parsed a C++ 'delete' expression virtual OwningExprResult ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, bool ArrayForm, @@ -2276,17 +2043,15 @@ public: SourceLocation RParenLoc, CXXRecordDecl *ClassDecl); - void SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, + bool SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, CXXBaseOrMemberInitializer **Initializers, unsigned NumInitializers, - llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases, - llvm::SmallVectorImpl<FieldDecl *>&Members); + bool IsImplicitConstructor); - /// computeBaseOrMembersToDestroy - Compute information in current - /// destructor decl's AST of bases and non-static data members which will be - /// implicitly destroyed. We are storing the destruction in the order that - /// they should occur (which is the reverse of construction order). - void computeBaseOrMembersToDestroy(CXXDestructorDecl *Destructor); + /// MarkBaseAndMemberDestructorsReferenced - Given a destructor decl, + /// mark all its non-trivial member and base destructor declarations + /// as referenced. + void MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor); void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl); @@ -2320,6 +2085,7 @@ public: void CheckConstructor(CXXConstructorDecl *Constructor); QualType CheckDestructorDeclarator(Declarator &D, FunctionDecl::StorageClass& SC); + void CheckDestructor(CXXDestructorDecl *Destructor); void CheckConversionDeclarator(Declarator &D, QualType &R, FunctionDecl::StorageClass& SC); DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion); @@ -2353,7 +2119,8 @@ public: bool IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths); bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, - SourceLocation Loc, SourceRange Range); + SourceLocation Loc, SourceRange Range, + bool IgnoreAccess = false); bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, unsigned InaccessibleBaseID, unsigned AmbigiousBaseConvID, @@ -2451,7 +2218,7 @@ public: unsigned Position); virtual void ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParam, SourceLocation EqualLoc, - ExprArg Default); + const ParsedTemplateArgument &Default); virtual TemplateParamsTy * ActOnTemplateParameterList(unsigned Depth, @@ -2477,8 +2244,7 @@ public: AccessSpecifier AS); void translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, - SourceLocation *TemplateArgLocsIn, - llvm::SmallVector<TemplateArgumentLoc, 16> &TempArgs); + llvm::SmallVectorImpl<TemplateArgumentLoc> &TempArgs); QualType CheckTemplateIdType(TemplateName Template, SourceLocation TemplateLoc, @@ -2491,7 +2257,6 @@ public: ActOnTemplateIdType(TemplateTy Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, - SourceLocation *TemplateArgLocs, SourceLocation RAngleLoc); virtual TypeResult ActOnTagTemplateIdType(TypeResult Type, @@ -2513,7 +2278,6 @@ public: SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, - SourceLocation *TemplateArgLocs, SourceLocation RAngleLoc); virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc, @@ -2534,7 +2298,6 @@ public: SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, - SourceLocation *TemplateArgLocs, SourceLocation RAngleLoc, AttributeList *Attr, MultiTemplateParamsArg TemplateParameterLists); @@ -2575,7 +2338,6 @@ public: SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, - SourceLocation *TemplateArgLocs, SourceLocation RAngleLoc, AttributeList *Attr); @@ -2595,6 +2357,13 @@ public: SourceLocation TemplateLoc, Declarator &D); + bool CheckTemplateArgument(NamedDecl *Param, + const TemplateArgumentLoc &Arg, + TemplateDecl *Template, + SourceLocation TemplateLoc, + SourceLocation RAngleLoc, + TemplateArgumentListBuilder &Converted); + bool CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, @@ -2612,17 +2381,54 @@ public: DeclaratorInfo *Arg); bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, NamedDecl *&Entity); - bool CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member); + bool CheckTemplateArgumentPointerToMember(Expr *Arg, + TemplateArgument &Converted); bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *&Arg, TemplateArgument &Converted); - bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, DeclRefExpr *Arg); + bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, + const TemplateArgumentLoc &Arg); + + /// \brief Enumeration describing how template parameter lists are compared + /// for equality. + enum TemplateParameterListEqualKind { + /// \brief We are matching the template parameter lists of two templates + /// that might be redeclarations. + /// + /// \code + /// template<typename T> struct X; + /// template<typename T> struct X; + /// \endcode + TPL_TemplateMatch, + + /// \brief We are matching the template parameter lists of two template + /// template parameters as part of matching the template parameter lists + /// of two templates that might be redeclarations. + /// + /// \code + /// template<template<int I> class TT> struct X; + /// template<template<int Value> class Other> struct X; + /// \endcode + TPL_TemplateTemplateParmMatch, + + /// \brief We are matching the template parameter lists of a template + /// template argument against the template parameter lists of a template + /// template parameter. + /// + /// \code + /// template<template<int Value> class Metafun> struct X; + /// template<int Value> struct integer_c; + /// X<integer_c> xic; + /// \endcode + TPL_TemplateTemplateArgumentMatch + }; + bool TemplateParameterListsAreEqual(TemplateParameterList *New, TemplateParameterList *Old, bool Complain, - bool IsTemplateTemplateParm = false, + TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc - = SourceLocation()); + = SourceLocation()); bool CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams); @@ -2659,6 +2465,11 @@ public: std::string getTemplateArgumentBindingsText(const TemplateParameterList *Params, const TemplateArgumentList &Args); + + std::string + getTemplateArgumentBindingsText(const TemplateParameterList *Params, + const TemplateArgument *Args, + unsigned NumArgs); /// \brief Describes the result of template argument deduction. /// @@ -2849,7 +2660,8 @@ public: // C++ Template Instantiation // - MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D); + MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D, + const TemplateArgumentList *Innermost = 0); /// \brief A template instantiation that is currently in progress. struct ActiveTemplateInstantiation { @@ -2880,17 +2692,30 @@ public: /// partial specialization or a function template. The /// Entity is either a ClassTemplatePartialSpecializationDecl or /// a FunctionTemplateDecl. - DeducedTemplateArgumentSubstitution + DeducedTemplateArgumentSubstitution, + + /// We are substituting prior template arguments into a new + /// template parameter. The template parameter itself is either a + /// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl. + PriorTemplateArgumentSubstitution, + + /// We are checking the validity of a default template argument that + /// has been used when naming a template-id. + DefaultTemplateArgumentChecking } Kind; /// \brief The point of instantiation within the source code. SourceLocation PointOfInstantiation; + /// \brief The template in which we are performing the instantiation, + /// for substitutions of prior template arguments. + TemplateDecl *Template; + /// \brief The entity that is being instantiated. uintptr_t Entity; - // \brief If this the instantiation of a default template - // argument, the list of template arguments. + /// \brief The list of template arguments we are substituting, if they + /// are not part of the entity. const TemplateArgument *TemplateArgs; /// \brief The number of template arguments in TemplateArgs. @@ -2901,9 +2726,14 @@ public: /// template instantiation. SourceRange InstantiationRange; - ActiveTemplateInstantiation() : Kind(TemplateInstantiation), Entity(0), - TemplateArgs(0), NumTemplateArgs(0) {} + ActiveTemplateInstantiation() + : Kind(TemplateInstantiation), Template(0), Entity(0), TemplateArgs(0), + NumTemplateArgs(0) {} + /// \brief Determines whether this template is an actual instantiation + /// that should be counted toward the maximum instantiation depth. + bool isInstantiationRecord() const; + friend bool operator==(const ActiveTemplateInstantiation &X, const ActiveTemplateInstantiation &Y) { if (X.Kind != Y.Kind) @@ -2916,6 +2746,13 @@ public: case TemplateInstantiation: return true; + case PriorTemplateArgumentSubstitution: + case DefaultTemplateArgumentChecking: + if (X.Template != Y.Template) + return false; + + // Fall through + case DefaultTemplateArgumentInstantiation: case ExplicitTemplateArgumentSubstitution: case DeducedTemplateArgumentSubstitution: @@ -2942,6 +2779,11 @@ public: llvm::SmallVector<ActiveTemplateInstantiation, 16> ActiveTemplateInstantiations; + /// \brief The number of ActiveTemplateInstantiation entries in + /// \c ActiveTemplateInstantiations that are not actual instantiations and, + /// therefore, should not be counted as part of the instantiation depth. + unsigned NonInstantiationEntries; + /// \brief The last template from which a template instantiation /// error or warning was produced. /// @@ -3001,6 +2843,32 @@ public: unsigned NumTemplateArgs, SourceRange InstantiationRange = SourceRange()); + /// \brief Note that we are substituting prior template arguments into a + /// non-type or template template parameter. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + TemplateDecl *Template, + NonTypeTemplateParmDecl *Param, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceRange InstantiationRange); + + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + TemplateDecl *Template, + TemplateTemplateParmDecl *Param, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceRange InstantiationRange); + + /// \brief Note that we are checking the default template argument + /// against the template parameter for a given template-id. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + TemplateDecl *Template, + NamedDecl *Param, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceRange InstantiationRange); + + /// \brief Note that we have finished instantiating this template. void Clear(); @@ -3273,8 +3141,9 @@ public: SourceLocation CatLoc); virtual DeclPtrTy ActOnForwardClassDeclaration(SourceLocation Loc, - IdentifierInfo **IdentList, - unsigned NumElts); + IdentifierInfo **IdentList, + SourceLocation *IdentLocs, + unsigned NumElts); virtual DeclPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, const IdentifierLocPair *IdentList, @@ -3484,6 +3353,12 @@ public: /// CompatiblePointerDiscardsQualifiers - The assignment discards /// c/v/r qualifiers, which we accept as an extension. CompatiblePointerDiscardsQualifiers, + + /// IncompatibleNestedPointerQualifiers - The assignment is between two + /// nested pointer types, and the qualifiers other than the first two + /// levels differ e.g. char ** -> const char **, but we accept them as an + /// extension. + IncompatibleNestedPointerQualifiers, /// IncompatibleVectors - The assignment is between two vector types that /// have the same size, which we accept as an extension. @@ -3555,10 +3430,11 @@ public: ImplicitConversionSequence& ICS); bool PerformImplicitConversion(Expr *&From, QualType ToType, const ImplicitConversionSequence& ICS, - const char *Flavor); + const char *Flavor, + bool IgnoreBaseAccess = false); bool PerformImplicitConversion(Expr *&From, QualType ToType, const StandardConversionSequence& SCS, - const char *Flavor); + const char *Flavor, bool IgnoreBaseAccess); bool BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind, const ImplicitConversionSequence& ICS, @@ -3660,7 +3536,8 @@ public: bool SuppressUserConversions, bool AllowExplicit, bool ForceRValue, - ImplicitConversionSequence *ICS = 0); + ImplicitConversionSequence *ICS = 0, + bool IgnoreBaseAccess = false); /// CheckCastTypes - Check type constraints for casting between types under /// C semantics, or forward to CXXCheckCStyleCast in C++. @@ -3745,7 +3622,6 @@ public: /// \name Code completion //@{ - void setCodeCompleteConsumer(CodeCompleteConsumer *CCC); virtual void CodeCompleteOrdinaryName(Scope *S); virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base, SourceLocation OpLoc, @@ -3763,7 +3639,13 @@ public: virtual void CodeCompleteOperatorName(Scope *S); virtual void CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS); - //@} + virtual void CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName, + SourceLocation FNameLoc); + virtual void CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver); + virtual void CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols, + unsigned NumProtocols); + virtual void CodeCompleteObjCProtocolDecl(Scope *S); + //@} //===--------------------------------------------------------------------===// // Extra semantic analysis beyond the C type system @@ -3808,7 +3690,6 @@ private: void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex); }; - //===--------------------------------------------------------------------===// // Typed version of Parser::ExprArg (smart pointer for wrapping Expr pointers). template <typename T> diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp index 0a5335a2be05..5769716b33ea 100644 --- a/lib/Sema/SemaAttr.cpp +++ b/lib/Sema/SemaAttr.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "Lookup.h" #include "clang/AST/Expr.h" using namespace clang; @@ -179,10 +180,8 @@ void Sema::ActOnPragmaUnused(const Token *Identifiers, unsigned NumIdentifiers, for (unsigned i = 0; i < NumIdentifiers; ++i) { const Token &Tok = Identifiers[i]; IdentifierInfo *Name = Tok.getIdentifierInfo(); - LookupResult Lookup; - LookupParsedName(Lookup, curScope, NULL, Name,LookupOrdinaryName, - false, true, Tok.getLocation()); - // FIXME: Handle Lookup.isAmbiguous? + LookupResult Lookup(*this, Name, Tok.getLocation(), LookupOrdinaryName); + LookupParsedName(Lookup, curScope, NULL, true); NamedDecl *ND = Lookup.getAsSingleDecl(Context); diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 76faddaa0384..e5ad338502df 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -70,28 +70,31 @@ static TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, static TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, - unsigned &msg); + unsigned &msg, + CastExpr::CastKind &Kind); static TryCastResult TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType, bool CStyle, const SourceRange &OpRange, - unsigned &msg); -static TryCastResult TryStaticDowncast(Sema &Self, QualType SrcType, - QualType DestType, bool CStyle, + unsigned &msg, + CastExpr::CastKind &Kind); +static TryCastResult TryStaticDowncast(Sema &Self, CanQualType SrcType, + CanQualType DestType, bool CStyle, const SourceRange &OpRange, QualType OrigSrcType, - QualType OrigDestType, unsigned &msg); + QualType OrigDestType, unsigned &msg, + CastExpr::CastKind &Kind); static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType,bool CStyle, const SourceRange &OpRange, unsigned &msg, CastExpr::CastKind &Kind); -static TryCastResult TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, +static TryCastResult TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, CastExpr::CastKind &Kind, CXXMethodDecl *&ConversionDecl); -static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr, +static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, @@ -187,7 +190,8 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) { assert((DestType->isPointerType() || DestType->isMemberPointerType()) && "Destination type is not pointer or pointer to member."); - QualType UnwrappedSrcType = SrcType, UnwrappedDestType = DestType; + QualType UnwrappedSrcType = Self.Context.getCanonicalType(SrcType), + UnwrappedDestType = Self.Context.getCanonicalType(DestType); llvm::SmallVector<Qualifiers, 8> cv1, cv2; // Find the qualifications. @@ -385,14 +389,15 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, // a non-lvalue-reference target type does not lead to decay. // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". if (DestType->isVoidType()) { + Kind = CastExpr::CK_ToVoid; return; } - if (!DestType->isLValueReferenceType()) + if (!DestType->isLValueReferenceType() && !DestType->isRecordType()) Self.DefaultFunctionArrayConversion(SrcExpr); unsigned msg = diag::err_bad_cxx_cast_generic; - if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false,OpRange, msg, + if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg, Kind, ConversionDecl) != TC_Success && msg != 0) Self.Diag(OpRange.getBegin(), msg) << CT_Static @@ -402,7 +407,7 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, /// TryStaticCast - Check if a static cast can be performed, and do so if /// possible. If @p CStyle, ignore access restrictions on hierarchy casting /// and casting away constness. -static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr, +static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, CastExpr::CastKind &Kind, @@ -427,15 +432,18 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr, // C++ 5.2.9p5, reference downcast. // See the function for details. // DR 427 specifies that this is to be applied before paragraph 2. - tcr = TryStaticReferenceDowncast(Self, SrcExpr, DestType, CStyle,OpRange,msg); + tcr = TryStaticReferenceDowncast(Self, SrcExpr, DestType, CStyle, OpRange, + msg, Kind); if (tcr != TC_NotApplicable) return tcr; // N2844 5.2.9p3: An lvalue of type "cv1 T1" can be cast to type "rvalue // reference to cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1". tcr = TryLValueToRValueCast(Self, SrcExpr, DestType, msg); - if (tcr != TC_NotApplicable) + if (tcr != TC_NotApplicable) { + Kind = CastExpr::CK_NoOp; return tcr; + } // C++ 5.2.9p2: An expression e can be explicitly converted to a type T // [...] if the declaration "T t(e);" is well-formed, [...]. @@ -467,13 +475,16 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr, if (DestType->isEnumeralType()) { if (SrcType->isComplexType() || SrcType->isVectorType()) { // Fall through - these cannot be converted. - } else if (SrcType->isArithmeticType() || SrcType->isEnumeralType()) + } else if (SrcType->isArithmeticType() || SrcType->isEnumeralType()) { + Kind = CastExpr::CK_IntegralCast; return TC_Success; + } } // Reverse pointer upcast. C++ 4.10p3 specifies pointer upcast. // C++ 5.2.9p8 additionally disallows a cast path through virtual inheritance. - tcr = TryStaticPointerDowncast(Self, SrcType, DestType, CStyle, OpRange, msg); + tcr = TryStaticPointerDowncast(Self, SrcType, DestType, CStyle, OpRange, msg, + Kind); if (tcr != TC_NotApplicable) return tcr; @@ -500,6 +511,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr, msg = diag::err_bad_cxx_cast_const_away; return TC_Failed; } + Kind = CastExpr::CK_BitCast; return TC_Success; } } @@ -544,7 +556,7 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, - unsigned &msg) { + unsigned &msg, CastExpr::CastKind &Kind) { // C++ 5.2.9p5: An lvalue of type "cv1 B", where B is a class type, can be // cast to type "reference to cv2 D", where D is a class derived from B, // if a valid standard conversion from "pointer to D" to "pointer to B" @@ -567,15 +579,17 @@ TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType, QualType DestPointee = DestReference->getPointeeType(); - return TryStaticDowncast(Self, SrcExpr->getType(), DestPointee, CStyle, - OpRange, SrcExpr->getType(), DestType, msg); + return TryStaticDowncast(Self, + Self.Context.getCanonicalType(SrcExpr->getType()), + Self.Context.getCanonicalType(DestPointee), CStyle, + OpRange, SrcExpr->getType(), DestType, msg, Kind); } /// Tests whether a conversion according to C++ 5.2.9p8 is valid. TryCastResult TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType, bool CStyle, const SourceRange &OpRange, - unsigned &msg) { + unsigned &msg, CastExpr::CastKind &Kind) { // C++ 5.2.9p8: An rvalue of type "pointer to cv1 B", where B is a class // type, can be converted to an rvalue of type "pointer to cv2 D", where D // is a class derived from B, if a valid standard conversion from "pointer @@ -595,25 +609,27 @@ TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType, return TC_NotApplicable; } - return TryStaticDowncast(Self, SrcPointer->getPointeeType(), - DestPointer->getPointeeType(), CStyle, - OpRange, SrcType, DestType, msg); + return TryStaticDowncast(Self, + Self.Context.getCanonicalType(SrcPointer->getPointeeType()), + Self.Context.getCanonicalType(DestPointer->getPointeeType()), + CStyle, OpRange, SrcType, DestType, msg, Kind); } /// TryStaticDowncast - Common functionality of TryStaticReferenceDowncast and /// TryStaticPointerDowncast. Tests whether a static downcast from SrcType to -/// DestType, both of which must be canonical, is possible and allowed. +/// DestType is possible and allowed. TryCastResult -TryStaticDowncast(Sema &Self, QualType SrcType, QualType DestType, +TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, bool CStyle, const SourceRange &OpRange, QualType OrigSrcType, - QualType OrigDestType, unsigned &msg) { + QualType OrigDestType, unsigned &msg, + CastExpr::CastKind &Kind) { // We can only work with complete types. But don't complain if it doesn't work if (Self.RequireCompleteType(OpRange.getBegin(), SrcType, PDiag(0)) || Self.RequireCompleteType(OpRange.getBegin(), DestType, PDiag(0))) return TC_NotApplicable; // Downcast can only happen in class hierarchies, so we need classes. - if (!DestType->isRecordType() || !SrcType->isRecordType()) { + if (!DestType->getAs<RecordType>() || !SrcType->getAs<RecordType>()) { return TC_NotApplicable; } @@ -669,12 +685,13 @@ TryStaticDowncast(Sema &Self, QualType SrcType, QualType DestType, EE = PI->rend(); EI != EE; ++EI) PathDisplayStr += EI->Base->getType().getAsString() + " -> "; - PathDisplayStr += DestType.getAsString(); + PathDisplayStr += QualType(DestType).getAsString(); } } Self.Diag(OpRange.getBegin(), diag::err_ambiguous_base_to_derived_cast) - << SrcType.getUnqualifiedType() << DestType.getUnqualifiedType() + << QualType(SrcType).getUnqualifiedType() + << QualType(DestType).getUnqualifiedType() << PathDisplayStr << OpRange; msg = 0; return TC_Failed; @@ -695,6 +712,7 @@ TryStaticDowncast(Sema &Self, QualType SrcType, QualType DestType, return TC_Failed; } + Kind = CastExpr::CK_BaseToDerived; return TC_Success; } @@ -719,10 +737,8 @@ TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType, } // T == T, modulo cv - if (Self.Context.getCanonicalType( - SrcMemPtr->getPointeeType().getUnqualifiedType()) != - Self.Context.getCanonicalType(DestMemPtr->getPointeeType(). - getUnqualifiedType())) + if (!Self.Context.hasSameUnqualifiedType(SrcMemPtr->getPointeeType(), + DestMemPtr->getPointeeType())) return TC_NotApplicable; // B base of D @@ -772,7 +788,7 @@ TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType, /// An expression e can be explicitly converted to a type T using a /// @c static_cast if the declaration "T t(e);" is well-formed [...]. TryCastResult -TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, QualType DestType, +TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, CastExpr::CastKind &Kind, CXXMethodDecl *&ConversionDecl) { @@ -785,27 +801,49 @@ TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, QualType DestType, } if (DestType->isReferenceType()) { + // All reference bindings insert implicit casts above that do the actual + // casting. + Kind = CastExpr::CK_NoOp; + // At this point of CheckStaticCast, if the destination is a reference, // this has to work. There is no other way that works. // On the other hand, if we're checking a C-style cast, we've still got - // the reinterpret_cast way. In that case, we pass an ICS so we don't - // get error messages. - ImplicitConversionSequence ICS; - bool failed = Self.CheckReferenceInit(SrcExpr, DestType, - OpRange.getBegin(), - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, - /*ForceRValue=*/false, - CStyle ? &ICS : 0); - if (!failed) + // the reinterpret_cast way. So in C-style mode, we first try the call + // with an ICS to suppress errors. + if (CStyle) { + ImplicitConversionSequence ICS; + if(Self.CheckReferenceInit(SrcExpr, DestType, OpRange.getBegin(), + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, /*ForceRValue=*/false, + &ICS)) + return TC_NotApplicable; + } + // Now we're committed either way. + if(!Self.CheckReferenceInit(SrcExpr, DestType, OpRange.getBegin(), + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*ForceRValue=*/false, 0, + /*IgnoreBaseAccess=*/CStyle)) return TC_Success; - if (CStyle) - return TC_NotApplicable; - // If we didn't pass the ICS, we already got an error message. + + // We already got an error message. msg = 0; return TC_Failed; } + if (DestType->isRecordType()) { + if (CXXConstructorDecl *Constructor + = Self.TryInitializationByConstructor(DestType, &SrcExpr, 1, + OpRange.getBegin(), + Sema::IK_Direct)) { + ConversionDecl = Constructor; + Kind = CastExpr::CK_ConstructorConversion; + return TC_Success; + } + + return TC_NotApplicable; + } + // FIXME: To get a proper error from invalid conversions here, we need to // reimplement more of this. // FIXME: This does not actually perform the conversion, and thus does not @@ -821,18 +859,12 @@ TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, QualType DestType, if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) return TC_NotApplicable; - if (ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion) { - ConversionDecl = cast<CXXMethodDecl>(ICS.UserDefined.ConversionFunction); - if (isa<CXXConstructorDecl>(ConversionDecl)) - Kind = CastExpr::CK_ConstructorConversion; - else if (isa<CXXConversionDecl>(ConversionDecl)) - Kind = CastExpr::CK_UserDefinedConversion; - } else if (ICS.ConversionKind == - ImplicitConversionSequence::StandardConversion) { - // FIXME: Set the cast kind depending on which types of conversions we have. - } - - return TC_Success; + // The conversion is possible, so commit to it. + Kind = CastExpr::CK_NoOp; + msg = 0; + return Self.PerformImplicitConversion(SrcExpr, DestType, ICS, "casting", + /*IgnoreBaseAccess*/CStyle) ? + TC_Failed : TC_Success; } /// TryConstCast - See if a const_cast from source to destination is allowed, @@ -1104,7 +1136,7 @@ bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, if (CastTy->isDependentType() || CastExpr->isTypeDependent()) return false; - if (!CastTy->isLValueReferenceType()) + if (!CastTy->isLValueReferenceType() && !CastTy->isRecordType()) DefaultFunctionArrayConversion(CastExpr); // C++ [expr.cast]p5: The conversions performed by diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index ce3fb5f83c8f..34a5b784d49b 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "Lookup.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" @@ -307,8 +308,9 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) { if (NNS->getKind() != NestedNameSpecifier::Identifier) return 0; - LookupResult Found; - LookupName(Found, S, NNS->getAsIdentifier(), LookupNestedNameSpecifierName); + LookupResult Found(*this, NNS->getAsIdentifier(), SourceLocation(), + LookupNestedNameSpecifierName); + LookupName(Found, S); assert(!Found.isAmbiguous() && "Cannot handle ambiguities here yet"); NamedDecl *Result = Found.getAsSingleDecl(Context); @@ -336,6 +338,8 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecifier *Prefix = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + LookupResult Found(*this, &II, IdLoc, LookupNestedNameSpecifierName); + // Determine where to perform name lookup DeclContext *LookupCtx = 0; bool isDependent = false; @@ -350,9 +354,10 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, // so long into the context associated with the prior nested-name-specifier. LookupCtx = computeDeclContext(SS, EnteringContext); isDependent = isDependentScopeSpecifier(SS); + Found.setContextRange(SS.getRange()); } - LookupResult Found; + bool ObjectTypeSearchedInScope = false; if (LookupCtx) { // Perform "qualified" name lookup into the declaration context we @@ -364,10 +369,9 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS)) return 0; - LookupQualifiedName(Found, LookupCtx, &II, LookupNestedNameSpecifierName, - false); + LookupQualifiedName(Found, LookupCtx); - if (!ObjectType.isNull() && Found.getKind() == LookupResult::NotFound) { + if (!ObjectType.isNull() && Found.empty()) { // C++ [basic.lookup.classref]p4: // If the id-expression in a class member access is a qualified-id of // the form @@ -389,7 +393,7 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, // reconstruct the result from when name lookup was performed at template // definition time. if (S) - LookupName(Found, S, &II, LookupNestedNameSpecifierName); + LookupName(Found, S); else if (ScopeLookupResult) Found.addDecl(ScopeLookupResult); @@ -406,7 +410,7 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, return NestedNameSpecifier::Create(Context, Prefix, &II); } else { // Perform unqualified name lookup in the current scope. - LookupName(Found, S, &II, LookupNestedNameSpecifierName); + LookupName(Found, S); } // FIXME: Deal with ambiguities cleanly. @@ -423,9 +427,8 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, // scope, reconstruct the result from the template instantiation itself. NamedDecl *OuterDecl; if (S) { - LookupResult FoundOuter; - LookupName(FoundOuter, S, &II, LookupNestedNameSpecifierName); - // FIXME: Handle ambiguities! + LookupResult FoundOuter(*this, &II, IdLoc, LookupNestedNameSpecifierName); + LookupName(FoundOuter, S); OuterDecl = FoundOuter.getAsSingleDecl(Context); } else OuterDecl = ScopeLookupResult; @@ -467,8 +470,8 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, // ordinary name lookup, which can help us produce better error // messages. if (!SD) { - Found.clear(); - LookupName(Found, S, &II, LookupOrdinaryName); + Found.clear(LookupOrdinaryName); + LookupName(Found, S); SD = Found.getAsSingleDecl(Context); } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 38b6ebeefab9..9060fe6ab742 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -91,6 +91,12 @@ bool Sema::CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall) { if (Format->getType() == "printf0") { // printf0 allows null "format" string; if so don't check format/args unsigned format_idx = Format->getFormatIdx() - 1; + // Does the index refer to the implicit object argument? + if (isa<CXXMemberCallExpr>(TheCall)) { + if (format_idx == 0) + return false; + --format_idx; + } if (format_idx < TheCall->getNumArgs()) { Expr *Format = TheCall->getArg(format_idx)->IgnoreParenCasts(); if (!Format->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) @@ -204,7 +210,7 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { if (!HasVAListArg) { if (const FunctionProtoType *Proto = FDecl->getType()->getAs<FunctionProtoType>()) - HasVAListArg = !Proto->isVariadic(); + HasVAListArg = !Proto->isVariadic(); } CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1, HasVAListArg ? 0 : Format->getFirstArg() - 1); @@ -628,8 +634,7 @@ Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { return ExprError(); } - if (Context.getCanonicalType(FAType).getUnqualifiedType() != - Context.getCanonicalType(SAType).getUnqualifiedType()) { + if (!Context.hasSameUnqualifiedType(FAType, SAType)) { Diag(TheCall->getLocStart(), diag::err_shufflevector_incompatible_vector) << SourceRange(TheCall->getArg(0)->getLocStart(), TheCall->getArg(1)->getLocEnd()); @@ -971,6 +976,18 @@ Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg) { const Expr *Fn = TheCall->getCallee(); + // The way the format attribute works in GCC, the implicit this argument + // of member functions is counted. However, it doesn't appear in our own + // lists, so decrement format_idx in that case. + if (isa<CXXMemberCallExpr>(TheCall)) { + // Catch a format attribute mistakenly referring to the object argument. + if (format_idx == 0) + return; + --format_idx; + if(firstDataArg != 0) + --firstDataArg; + } + // CHECK: printf-like function is called with no format string. if (format_idx >= TheCall->getNumArgs()) { Diag(TheCall->getRParenLoc(), diag::warn_printf_missing_format_string) diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index e9df17d6a115..9cecdadc867e 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -13,6 +13,7 @@ #include "Sema.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/SmallPtrSet.h" @@ -23,13 +24,6 @@ using namespace clang; -/// \brief Set the code-completion consumer for semantic analysis. -void Sema::setCodeCompleteConsumer(CodeCompleteConsumer *CCC) { - assert(((CodeCompleter != 0) != (CCC != 0)) && - "Already set or cleared a code-completion consumer?"); - CodeCompleter = CCC; -} - namespace { /// \brief A container of code-completion results. class ResultBuilder { @@ -101,6 +95,9 @@ namespace { /// \brief Exit from the current scope. void ExitScope(); + /// \brief Ignore this declaration, if it is seen again. + void Ignore(Decl *D) { AllDeclsFound.insert(D->getCanonicalDecl()); } + /// \name Name lookup predicates /// /// These predicates can be passed to the name lookup functions to filter the @@ -187,8 +184,7 @@ getRequiredQualification(ASTContext &Context, Context.getTypeDeclType(TD).getTypePtr()); else assert(Parent->isTranslationUnit()); - } - + } return Result; } @@ -206,7 +202,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { return; // Look through using declarations. - if (UsingDecl *Using = dyn_cast<UsingDecl>(R.Declaration)) + if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) MaybeAddResult(Result(Using->getTargetDecl(), R.Rank, R.Qualifier), CurContext); @@ -474,17 +470,24 @@ static unsigned CollectMemberLookupResults(DeclContext *Ctx, for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx; CurCtx = CurCtx->getNextContext()) { for (DeclContext::decl_iterator D = CurCtx->decls_begin(), - DEnd = CurCtx->decls_end(); + DEnd = CurCtx->decls_end(); D != DEnd; ++D) { if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) Results.MaybeAddResult(Result(ND, Rank, 0, InBaseClass), CurContext); + + // Visit transparent contexts inside this context. + if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D)) { + if (InnerCtx->isTransparentContext()) + CollectMemberLookupResults(InnerCtx, Rank, CurContext, Visited, + Results, InBaseClass); + } } } // Traverse the contexts of inherited classes. if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) { for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(), - BEnd = Record->bases_end(); + BEnd = Record->bases_end(); B != BEnd; ++B) { QualType BaseType = B->getType(); @@ -674,6 +677,8 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank, static void AddFunctionParameterChunks(ASTContext &Context, FunctionDecl *Function, CodeCompletionString *Result) { + typedef CodeCompletionString::Chunk Chunk; + CodeCompletionString *CCStr = Result; for (unsigned P = 0, N = Function->getNumParams(); P != N; ++P) { @@ -688,7 +693,7 @@ static void AddFunctionParameterChunks(ASTContext &Context, } if (P != 0) - CCStr->AddTextChunk(", "); + CCStr->AddChunk(Chunk(CodeCompletionString::CK_Comma)); // Format the placeholder string. std::string PlaceholderStr; @@ -713,6 +718,8 @@ static void AddTemplateParameterChunks(ASTContext &Context, TemplateDecl *Template, CodeCompletionString *Result, unsigned MaxParameters = 0) { + typedef CodeCompletionString::Chunk Chunk; + CodeCompletionString *CCStr = Result; bool FirstParameter = true; @@ -768,7 +775,7 @@ static void AddTemplateParameterChunks(ASTContext &Context, if (FirstParameter) FirstParameter = false; else - CCStr->AddTextChunk(", "); + CCStr->AddChunk(Chunk(CodeCompletionString::CK_Comma)); // Add the placeholder string. CCStr->AddPlaceholderChunk(PlaceholderStr.c_str()); @@ -803,6 +810,8 @@ void AddQualifierToCompletionString(CodeCompletionString *Result, /// result is all that is needed. CodeCompletionString * CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { + typedef CodeCompletionString::Chunk Chunk; + if (Kind == RK_Keyword) return 0; @@ -813,12 +822,12 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { // Format a function-like macro with placeholders for the arguments. CodeCompletionString *Result = new CodeCompletionString; - Result->AddTextChunk(Macro->getName().str().c_str()); - Result->AddTextChunk("("); + Result->AddTypedTextChunk(Macro->getName().str().c_str()); + Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); for (MacroInfo::arg_iterator A = MI->arg_begin(), AEnd = MI->arg_end(); A != AEnd; ++A) { if (A != MI->arg_begin()) - Result->AddTextChunk(", "); + Result->AddChunk(Chunk(CodeCompletionString::CK_Comma)); if (!MI->isVariadic() || A != AEnd - 1) { // Non-variadic argument. @@ -837,21 +846,28 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { Result->AddPlaceholderChunk(Arg.c_str()); } } - Result->AddTextChunk(")"); + Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen)); return Result; } assert(Kind == RK_Declaration && "Missed a macro kind?"); NamedDecl *ND = Declaration; + if (StartsNestedNameSpecifier) { + CodeCompletionString *Result = new CodeCompletionString; + Result->AddTypedTextChunk(ND->getNameAsString().c_str()); + Result->AddTextChunk("::"); + return Result; + } + if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) { CodeCompletionString *Result = new CodeCompletionString; AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, S.Context); - Result->AddTextChunk(Function->getNameAsString().c_str()); - Result->AddTextChunk("("); + Result->AddTypedTextChunk(Function->getNameAsString().c_str()); + Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); AddFunctionParameterChunks(S.Context, Function, Result); - Result->AddTextChunk(")"); + Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen)); return Result; } @@ -860,7 +876,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, S.Context); FunctionDecl *Function = FunTmpl->getTemplatedDecl(); - Result->AddTextChunk(Function->getNameAsString().c_str()); + Result->AddTypedTextChunk(Function->getNameAsString().c_str()); // Figure out which template parameters are deduced (or have default // arguments). @@ -884,7 +900,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { else { assert(isa<TemplateTemplateParmDecl>(Param)); HasDefaultArg - = cast<TemplateTemplateParmDecl>(Param)->hasDefaultArgument(); + = cast<TemplateTemplateParmDecl>(Param)->hasDefaultArgument(); } if (!HasDefaultArg) @@ -896,16 +912,16 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { // Some of the function template arguments cannot be deduced from a // function call, so we introduce an explicit template argument list // containing all of the arguments up to the first deducible argument. - Result->AddTextChunk("<"); + Result->AddChunk(Chunk(CodeCompletionString::CK_LeftAngle)); AddTemplateParameterChunks(S.Context, FunTmpl, Result, LastDeducibleArgument); - Result->AddTextChunk(">"); + Result->AddChunk(Chunk(CodeCompletionString::CK_RightAngle)); } // Add the function parameters - Result->AddTextChunk("("); + Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); AddFunctionParameterChunks(S.Context, Function, Result); - Result->AddTextChunk(")"); + Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen)); return Result; } @@ -913,20 +929,51 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { CodeCompletionString *Result = new CodeCompletionString; AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, S.Context); - Result->AddTextChunk(Template->getNameAsString().c_str()); - Result->AddTextChunk("<"); + Result->AddTypedTextChunk(Template->getNameAsString().c_str()); + Result->AddChunk(Chunk(CodeCompletionString::CK_LeftAngle)); AddTemplateParameterChunks(S.Context, Template, Result); - Result->AddTextChunk(">"); + Result->AddChunk(Chunk(CodeCompletionString::CK_RightAngle)); return Result; } - if (Qualifier || StartsNestedNameSpecifier) { + if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) { + CodeCompletionString *Result = new CodeCompletionString; + Selector Sel = Method->getSelector(); + if (Sel.isUnarySelector()) { + Result->AddTypedTextChunk(Sel.getIdentifierInfoForSlot(0)->getName()); + return Result; + } + + Result->AddTypedTextChunk( + Sel.getIdentifierInfoForSlot(0)->getName().str() + std::string(":")); + unsigned Idx = 0; + for (ObjCMethodDecl::param_iterator P = Method->param_begin(), + PEnd = Method->param_end(); + P != PEnd; (void)++P, ++Idx) { + if (Idx > 0) { + std::string Keyword = " "; + if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Idx)) + Keyword += II->getName().str(); + Keyword += ":"; + Result->AddTextChunk(Keyword); + } + + std::string Arg; + (*P)->getType().getAsStringInternal(Arg, S.Context.PrintingPolicy); + Arg = "(" + Arg + ")"; + if (IdentifierInfo *II = (*P)->getIdentifier()) + Arg += II->getName().str(); + Result->AddPlaceholderChunk(Arg); + } + + return Result; + } + + if (Qualifier) { CodeCompletionString *Result = new CodeCompletionString; AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, S.Context); - Result->AddTextChunk(ND->getNameAsString().c_str()); - if (StartsNestedNameSpecifier) - Result->AddTextChunk("::"); + Result->AddTypedTextChunk(ND->getNameAsString().c_str()); return Result; } @@ -937,6 +984,8 @@ CodeCompletionString * CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( unsigned CurrentArg, Sema &S) const { + typedef CodeCompletionString::Chunk Chunk; + CodeCompletionString *Result = new CodeCompletionString; FunctionDecl *FDecl = getFunction(); const FunctionProtoType *Proto @@ -947,9 +996,9 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( const FunctionType *FT = getFunctionType(); Result->AddTextChunk( FT->getResultType().getAsString(S.Context.PrintingPolicy).c_str()); - Result->AddTextChunk("("); - Result->AddPlaceholderChunk("..."); - Result->AddTextChunk("("); + Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); + Result->AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, "...")); + Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen)); return Result; } @@ -959,11 +1008,11 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( Result->AddTextChunk( Proto->getResultType().getAsString(S.Context.PrintingPolicy).c_str()); - Result->AddTextChunk("("); + Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); unsigned NumParams = FDecl? FDecl->getNumParams() : Proto->getNumArgs(); for (unsigned I = 0; I != NumParams; ++I) { if (I) - Result->AddTextChunk(", "); + Result->AddChunk(Chunk(CodeCompletionString::CK_Comma)); std::string ArgString; QualType ArgType; @@ -978,19 +1027,20 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( ArgType.getAsStringInternal(ArgString, S.Context.PrintingPolicy); if (I == CurrentArg) - Result->AddPlaceholderChunk(ArgString.c_str()); + Result->AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, + ArgString.c_str())); else Result->AddTextChunk(ArgString.c_str()); } if (Proto && Proto->isVariadic()) { - Result->AddTextChunk(", "); + Result->AddChunk(Chunk(CodeCompletionString::CK_Comma)); if (CurrentArg < NumParams) Result->AddTextChunk("..."); else - Result->AddPlaceholderChunk("..."); + Result->AddChunk(Chunk(CodeCompletionString::CK_CurrentParameter, "...")); } - Result->AddTextChunk(")"); + Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen)); return Result; } @@ -1000,7 +1050,9 @@ namespace { typedef CodeCompleteConsumer::Result Result; bool isEarlierDeclarationName(DeclarationName X, DeclarationName Y) const { - if (X.getNameKind() != Y.getNameKind()) + if (!X.getObjCSelector().isNull() && !Y.getObjCSelector().isNull()) { + // Consider all selector kinds to be equivalent. + } else if (X.getNameKind() != Y.getNameKind()) return X.getNameKind() < Y.getNameKind(); return llvm::LowercaseString(X.getAsString()) @@ -1049,32 +1101,77 @@ namespace { }; } -// Add all of the known macros as code-completion results. static void AddMacroResults(Preprocessor &PP, unsigned Rank, ResultBuilder &Results) { Results.EnterNewScope(); - for (Preprocessor::macro_iterator M = PP.macro_begin(), MEnd = PP.macro_end(); + for (Preprocessor::macro_iterator M = PP.macro_begin(), + MEnd = PP.macro_end(); M != MEnd; ++M) Results.MaybeAddResult(CodeCompleteConsumer::Result(M->first, Rank)); Results.ExitScope(); } -static void HandleCodeCompleteResults(CodeCompleteConsumer *CodeCompleter, - CodeCompleteConsumer::Result *Results, - unsigned NumResults) { +static void HandleCodeCompleteResults(Sema *S, + CodeCompleteConsumer *CodeCompleter, + CodeCompleteConsumer::Result *Results, + unsigned NumResults) { // Sort the results by rank/kind/etc. std::stable_sort(Results, Results + NumResults, SortCodeCompleteResult()); if (CodeCompleter) - CodeCompleter->ProcessCodeCompleteResults(Results, NumResults); + CodeCompleter->ProcessCodeCompleteResults(*S, Results, NumResults); } void Sema::CodeCompleteOrdinaryName(Scope *S) { ResultBuilder Results(*this, &ResultBuilder::IsOrdinaryName); unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, Results); - AddMacroResults(PP, NextRank, Results); - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, NextRank, Results); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + +static void AddObjCProperties(ObjCContainerDecl *Container, + DeclContext *CurContext, + ResultBuilder &Results) { + typedef CodeCompleteConsumer::Result Result; + + // Add properties in this container. + for (ObjCContainerDecl::prop_iterator P = Container->prop_begin(), + PEnd = Container->prop_end(); + P != PEnd; + ++P) + Results.MaybeAddResult(Result(*P, 0), CurContext); + + // Add properties in referenced protocols. + if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) { + for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(), + PEnd = Protocol->protocol_end(); + P != PEnd; ++P) + AddObjCProperties(*P, CurContext, Results); + } else if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)){ + // Look through categories. + for (ObjCCategoryDecl *Category = IFace->getCategoryList(); + Category; Category = Category->getNextClassCategory()) + AddObjCProperties(Category, CurContext, Results); + + // Look through protocols. + for (ObjCInterfaceDecl::protocol_iterator I = IFace->protocol_begin(), + E = IFace->protocol_end(); + I != E; ++I) + AddObjCProperties(*I, CurContext, Results); + + // Look in the superclass. + if (IFace->getSuperClass()) + AddObjCProperties(IFace->getSuperClass(), CurContext, Results); + } else if (const ObjCCategoryDecl *Category + = dyn_cast<ObjCCategoryDecl>(Container)) { + // Look through protocols. + for (ObjCInterfaceDecl::protocol_iterator P = Category->protocol_begin(), + PEnd = Category->protocol_end(); + P != PEnd; ++P) + AddObjCProperties(*P, CurContext, Results); + } } void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, @@ -1099,11 +1196,13 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, ResultBuilder Results(*this, &ResultBuilder::IsMember); unsigned NextRank = 0; - + + Results.EnterNewScope(); if (const RecordType *Record = BaseType->getAs<RecordType>()) { - NextRank = CollectMemberLookupResults(Record->getDecl(), NextRank, + // Access to a C/C++ class, struct, or union. + NextRank = CollectMemberLookupResults(Record->getDecl(), NextRank, Record->getDecl(), Results); - + if (getLangOptions().CPlusPlus) { if (!Results.empty()) { // The "template" keyword can follow "->" or "." in the grammar. @@ -1117,27 +1216,63 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, break; } } - + if (IsDependent) Results.MaybeAddResult(Result("template", NextRank++)); } - + // We could have the start of a nested-name-specifier. Add those // results as well. Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); - CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank, + CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank, CurContext, Results); } + } else if (!IsArrow && BaseType->getAsObjCInterfacePointerType()) { + // Objective-C property reference. - // Add macros - AddMacroResults(PP, NextRank, Results); + // Add property results based on our interface. + const ObjCObjectPointerType *ObjCPtr + = BaseType->getAsObjCInterfacePointerType(); + assert(ObjCPtr && "Non-NULL pointer guaranteed above!"); + AddObjCProperties(ObjCPtr->getInterfaceDecl(), CurContext, Results); - // Hand off the results found for code completion. - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + // Add properties from the protocols in a qualified interface. + for (ObjCObjectPointerType::qual_iterator I = ObjCPtr->qual_begin(), + E = ObjCPtr->qual_end(); + I != E; ++I) + AddObjCProperties(*I, CurContext, Results); - // We're done! - return; + // FIXME: We could (should?) also look for "implicit" properties, identified + // only by the presence of nullary and unary selectors. + } else if ((IsArrow && BaseType->isObjCObjectPointerType()) || + (!IsArrow && BaseType->isObjCInterfaceType())) { + // Objective-C instance variable access. + ObjCInterfaceDecl *Class = 0; + if (const ObjCObjectPointerType *ObjCPtr + = BaseType->getAs<ObjCObjectPointerType>()) + Class = ObjCPtr->getInterfaceDecl(); + else + Class = BaseType->getAs<ObjCInterfaceType>()->getDecl(); + + // Add all ivars from this class and its superclasses. + for (; Class; Class = Class->getSuperClass()) { + for (ObjCInterfaceDecl::ivar_iterator IVar = Class->ivar_begin(), + IVarEnd = Class->ivar_end(); + IVar != IVarEnd; ++IVar) + Results.MaybeAddResult(Result(*IVar, 0), CurContext); + } } + + // FIXME: How do we cope with isa? + + Results.ExitScope(); + + // Add macros + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, NextRank, Results); + + // Hand off the results found for code completion. + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { @@ -1177,8 +1312,9 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { NextRank, CurContext, Results); } - AddMacroResults(PP, NextRank, Results); - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, NextRank, Results); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } void Sema::CodeCompleteCase(Scope *S) { @@ -1255,8 +1391,9 @@ void Sema::CodeCompleteCase(Scope *S) { } Results.ExitScope(); - AddMacroResults(PP, 1, Results); - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, 1, Results); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } namespace { @@ -1328,7 +1465,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, if (Cand->Viable) Results.push_back(ResultCandidate(Cand->Function)); } - CodeCompleter->ProcessOverloadCandidates(NumArgs, Results.data(), + CodeCompleter->ProcessOverloadCandidates(*this, NumArgs, Results.data(), Results.size()); } @@ -1350,8 +1487,9 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, if (!Results.empty() && NNS->isDependent()) Results.MaybeAddResult(CodeCompleteConsumer::Result("template", NextRank)); - AddMacroResults(PP, NextRank + 1, Results); - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, NextRank + 1, Results); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } void Sema::CodeCompleteUsing(Scope *S) { @@ -1371,8 +1509,9 @@ void Sema::CodeCompleteUsing(Scope *S) { 0, CurContext, Results); Results.ExitScope(); - AddMacroResults(PP, NextRank, Results); - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, NextRank, Results); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } void Sema::CodeCompleteUsingDirective(Scope *S) { @@ -1386,8 +1525,9 @@ void Sema::CodeCompleteUsingDirective(Scope *S) { unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, Results); Results.ExitScope(); - AddMacroResults(PP, NextRank, Results); - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, NextRank, Results); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } void Sema::CodeCompleteNamespaceDecl(Scope *S) { @@ -1421,8 +1561,9 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) { Results.ExitScope(); } - AddMacroResults(PP, 1, Results); - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, 1, Results); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) { @@ -1433,8 +1574,9 @@ void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) { ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, Results); - AddMacroResults(PP, NextRank, Results); - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, NextRank, Results); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } void Sema::CodeCompleteOperatorName(Scope *S) { @@ -1464,8 +1606,9 @@ void Sema::CodeCompleteOperatorName(Scope *S) { NextRank + 1, CurContext, Results); Results.ExitScope(); - AddMacroResults(PP, NextRank, Results); - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, NextRank, Results); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } void Sema::CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS) { @@ -1493,5 +1636,252 @@ void Sema::CodeCompleteObjCProperty(Scope *S, ObjCDeclSpec &ODS) { if (!(Attributes & ObjCDeclSpec::DQ_PR_getter)) Results.MaybeAddResult(CodeCompleteConsumer::Result("getter", 0)); Results.ExitScope(); - HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + +/// \brief Add all of the Objective-C methods in the given Objective-C +/// container to the set of results. +/// +/// The container will be a class, protocol, category, or implementation of +/// any of the above. This mether will recurse to include methods from +/// the superclasses of classes along with their categories, protocols, and +/// implementations. +/// +/// \param Container the container in which we'll look to find methods. +/// +/// \param WantInstance whether to add instance methods (only); if false, this +/// routine will add factory methods (only). +/// +/// \param CurContext the context in which we're performing the lookup that +/// finds methods. +/// +/// \param Results the structure into which we'll add results. +static void AddObjCMethods(ObjCContainerDecl *Container, + bool WantInstanceMethods, + DeclContext *CurContext, + ResultBuilder &Results) { + typedef CodeCompleteConsumer::Result Result; + for (ObjCContainerDecl::method_iterator M = Container->meth_begin(), + MEnd = Container->meth_end(); + M != MEnd; ++M) { + if ((*M)->isInstanceMethod() == WantInstanceMethods) + Results.MaybeAddResult(Result(*M, 0), CurContext); + } + + ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container); + if (!IFace) + return; + + // Add methods in protocols. + const ObjCList<ObjCProtocolDecl> &Protocols= IFace->getReferencedProtocols(); + for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), + E = Protocols.end(); + I != E; ++I) + AddObjCMethods(*I, WantInstanceMethods, CurContext, Results); + + // Add methods in categories. + for (ObjCCategoryDecl *CatDecl = IFace->getCategoryList(); CatDecl; + CatDecl = CatDecl->getNextClassCategory()) { + AddObjCMethods(CatDecl, WantInstanceMethods, CurContext, Results); + + // Add a categories protocol methods. + const ObjCList<ObjCProtocolDecl> &Protocols + = CatDecl->getReferencedProtocols(); + for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), + E = Protocols.end(); + I != E; ++I) + AddObjCMethods(*I, WantInstanceMethods, CurContext, Results); + + // Add methods in category implementations. + if (ObjCCategoryImplDecl *Impl = CatDecl->getImplementation()) + AddObjCMethods(Impl, WantInstanceMethods, CurContext, Results); + } + + // Add methods in superclass. + if (IFace->getSuperClass()) + AddObjCMethods(IFace->getSuperClass(), WantInstanceMethods, CurContext, + Results); + + // Add methods in our implementation, if any. + if (ObjCImplementationDecl *Impl = IFace->getImplementation()) + AddObjCMethods(Impl, WantInstanceMethods, CurContext, Results); +} + +void Sema::CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName, + SourceLocation FNameLoc) { + typedef CodeCompleteConsumer::Result Result; + ObjCInterfaceDecl *CDecl = 0; + + if (FName->isStr("super")) { + // We're sending a message to "super". + if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) { + // Figure out which interface we're in. + CDecl = CurMethod->getClassInterface(); + if (!CDecl) + return; + + // Find the superclass of this class. + CDecl = CDecl->getSuperClass(); + if (!CDecl) + return; + + if (CurMethod->isInstanceMethod()) { + // We are inside an instance method, which means that the message + // send [super ...] is actually calling an instance method on the + // current object. Build the super expression and handle this like + // an instance method. + QualType SuperTy = Context.getObjCInterfaceType(CDecl); + SuperTy = Context.getObjCObjectPointerType(SuperTy); + OwningExprResult Super + = Owned(new (Context) ObjCSuperExpr(FNameLoc, SuperTy)); + return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get()); + } + + // Okay, we're calling a factory method in our superclass. + } + } + + // If the given name refers to an interface type, retrieve the + // corresponding declaration. + if (!CDecl) + if (TypeTy *Ty = getTypeName(*FName, FNameLoc, S, 0, false)) { + QualType T = GetTypeFromParser(Ty, 0); + if (!T.isNull()) + if (const ObjCInterfaceType *Interface = T->getAs<ObjCInterfaceType>()) + CDecl = Interface->getDecl(); + } + + if (!CDecl && FName->isStr("super")) { + // "super" may be the name of a variable, in which case we are + // probably calling an instance method. + OwningExprResult Super = ActOnDeclarationNameExpr(S, FNameLoc, FName, + false, 0, false); + return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get()); + } + + // Add all of the factory methods in this Objective-C class, its protocols, + // superclasses, categories, implementation, etc. + ResultBuilder Results(*this); + Results.EnterNewScope(); + AddObjCMethods(CDecl, false, CurContext, Results); + Results.ExitScope(); + + // This also suppresses remaining diagnostics. + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + +void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver) { + typedef CodeCompleteConsumer::Result Result; + + Expr *RecExpr = static_cast<Expr *>(Receiver); + QualType RecType = RecExpr->getType(); + + // If necessary, apply function/array conversion to the receiver. + // C99 6.7.5.3p[7,8]. + DefaultFunctionArrayConversion(RecExpr); + QualType ReceiverType = RecExpr->getType(); + + if (ReceiverType->isObjCIdType() || ReceiverType->isBlockPointerType()) { + // FIXME: We're messaging 'id'. Do we actually want to look up every method + // in the universe? + return; + } + + // Build the set of methods we can see. + ResultBuilder Results(*this); + Results.EnterNewScope(); + + // Handle messages to Class. This really isn't a message to an instance + // method, so we treat it the same way we would treat a message send to a + // class method. + if (ReceiverType->isObjCClassType() || + ReceiverType->isObjCQualifiedClassType()) { + if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) { + if (ObjCInterfaceDecl *ClassDecl = CurMethod->getClassInterface()) + AddObjCMethods(ClassDecl, false, CurContext, Results); + } + } + // Handle messages to a qualified ID ("id<foo>"). + else if (const ObjCObjectPointerType *QualID + = ReceiverType->getAsObjCQualifiedIdType()) { + // Search protocols for instance methods. + for (ObjCObjectPointerType::qual_iterator I = QualID->qual_begin(), + E = QualID->qual_end(); + I != E; ++I) + AddObjCMethods(*I, true, CurContext, Results); + } + // Handle messages to a pointer to interface type. + else if (const ObjCObjectPointerType *IFacePtr + = ReceiverType->getAsObjCInterfacePointerType()) { + // Search the class, its superclasses, etc., for instance methods. + AddObjCMethods(IFacePtr->getInterfaceDecl(), true, CurContext, Results); + + // Search protocols for instance methods. + for (ObjCObjectPointerType::qual_iterator I = IFacePtr->qual_begin(), + E = IFacePtr->qual_end(); + I != E; ++I) + AddObjCMethods(*I, true, CurContext, Results); + } + + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + +/// \brief Add all of the protocol declarations that we find in the given +/// (translation unit) context. +static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext, + bool OnlyForwardDeclarations, + ResultBuilder &Results) { + typedef CodeCompleteConsumer::Result Result; + + for (DeclContext::decl_iterator D = Ctx->decls_begin(), + DEnd = Ctx->decls_end(); + D != DEnd; ++D) { + // Record any protocols we find. + if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(*D)) + if (!OnlyForwardDeclarations || Proto->isForwardDecl()) + Results.MaybeAddResult(Result(Proto, 0), CurContext); + + // Record any forward-declared protocols we find. + if (ObjCForwardProtocolDecl *Forward + = dyn_cast<ObjCForwardProtocolDecl>(*D)) { + for (ObjCForwardProtocolDecl::protocol_iterator + P = Forward->protocol_begin(), + PEnd = Forward->protocol_end(); + P != PEnd; ++P) + if (!OnlyForwardDeclarations || (*P)->isForwardDecl()) + Results.MaybeAddResult(Result(*P, 0), CurContext); + } + } +} + +void Sema::CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols, + unsigned NumProtocols) { + ResultBuilder Results(*this); + Results.EnterNewScope(); + + // Tell the result set to ignore all of the protocols we have + // already seen. + for (unsigned I = 0; I != NumProtocols; ++I) + if (ObjCProtocolDecl *Protocol = LookupProtocol(Protocols[I].first)) + Results.Ignore(Protocol); + + // Add all protocols. + AddProtocolResults(Context.getTranslationUnitDecl(), CurContext, false, + Results); + + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + +void Sema::CodeCompleteObjCProtocolDecl(Scope *) { + ResultBuilder Results(*this); + Results.EnterNewScope(); + + // Add all protocols. + AddProtocolResults(Context.getTranslationUnitDecl(), CurContext, true, + Results); + + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index d89cb5fc97f5..57c101bd32ce 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "Lookup.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -24,6 +25,7 @@ #include "clang/AST/StmtObjC.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Template.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -86,13 +88,14 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, II, SS->getRange()).getAsOpaquePtr(); } - LookupResult Result; - LookupParsedName(Result, S, SS, &II, LookupOrdinaryName, false, false); + LookupResult Result(*this, &II, NameLoc, LookupOrdinaryName); + LookupParsedName(Result, S, SS, false); NamedDecl *IIDecl = 0; - switch (Result.getKind()) { + switch (Result.getResultKind()) { case LookupResult::NotFound: case LookupResult::FoundOverloaded: + case LookupResult::FoundUnresolvedValue: return 0; case LookupResult::Ambiguous: @@ -101,8 +104,10 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, // diagnose the error then. If we don't do this, then the error // about hiding the type will be immediately followed by an error // that only makes sense if the identifier was treated like a type. - if (Result.getAmbiguityKind() == LookupResult::AmbiguousTagHiding) + if (Result.getAmbiguityKind() == LookupResult::AmbiguousTagHiding) { + Result.suppressDiagnostics(); return 0; + } // Look to see if we have a type anywhere in the list of results. for (LookupResult::iterator Res = Result.begin(), ResEnd = Result.end(); @@ -122,6 +127,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, // perform this lookup again (e.g., as an object name), which // will produce the ambiguity, or will complain that it expected // a type name. + Result.suppressDiagnostics(); return 0; } @@ -129,7 +135,6 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, // ambiguity and then return that type. This might be the right // answer, or it might not be, but it suppresses any attempt to // perform the name lookup again. - DiagnoseAmbiguousLookup(Result, DeclarationName(&II), NameLoc); break; case LookupResult::Found: @@ -142,7 +147,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, QualType T; if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) { DiagnoseUseOfDecl(IIDecl, NameLoc); - + // C++ [temp.local]p2: // Within the scope of a class template specialization or // partial specialization, when the injected-class-name is @@ -162,10 +167,16 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, T = getQualifiedNameType(*SS, T); } else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) { - DiagnoseUseOfDecl(IIDecl, NameLoc); T = Context.getObjCInterfaceType(IDecl); - } else + } else if (UnresolvedUsingTypenameDecl *UUDecl = + dyn_cast<UnresolvedUsingTypenameDecl>(IIDecl)) { + // FIXME: preserve source structure information. + T = Context.getTypenameType(UUDecl->getTargetNestedNameSpecifier(), &II); + } else { + // If it's not plausibly a type, suppress diagnostics. + Result.suppressDiagnostics(); return 0; + } return T.getAsOpaquePtr(); } @@ -177,9 +188,10 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, /// where the user forgot to specify the tag. DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { // Do a tag name lookup in this scope. - LookupResult R; - LookupName(R, S, &II, LookupTagName, false, false); - if (R.getKind() == LookupResult::Found) + LookupResult R(*this, &II, SourceLocation(), LookupTagName); + LookupName(R, S, false); + R.suppressDiagnostics(); + if (R.getResultKind() == LookupResult::Found) if (const TagDecl *TD = dyn_cast<TagDecl>(R.getAsSingleDecl(Context))) { switch (TD->getTagKind()) { case TagDecl::TK_struct: return DeclSpec::TST_struct; @@ -384,6 +396,26 @@ bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S) { return IdResolver.isDeclInScope(D, Ctx, Context, S); } +static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { + if (D->isUsed() || D->hasAttr<UnusedAttr>()) + return false; + + if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) { + if (const RecordType *RT = VD->getType()->getAs<RecordType>()) { + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) { + if (!RD->hasTrivialConstructor()) + return false; + if (!RD->hasTrivialDestructor()) + return false; + } + } + } + + return (isa<VarDecl>(D) && !isa<ParmVarDecl>(D) && + !isa<ImplicitParamDecl>(D) && + D->getDeclContext()->isFunctionOrMethod()); +} + void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { if (S->decl_empty()) return; assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) && @@ -400,10 +432,8 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { if (!D->getDeclName()) continue; // Diagnose unused variables in this scope. - if (!D->isUsed() && !D->hasAttr<UnusedAttr>() && isa<VarDecl>(D) && - !isa<ParmVarDecl>(D) && !isa<ImplicitParamDecl>(D) && - D->getDeclContext()->isFunctionOrMethod()) - Diag(D->getLocation(), diag::warn_unused_variable) << D->getDeclName(); + if (ShouldDiagnoseUnusedDecl(D)) + Diag(D->getLocation(), diag::warn_unused_variable) << D->getDeclName(); // Remove this name from our lexical scope. IdResolver.RemoveDecl(D); @@ -1396,9 +1426,9 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, FEnd = AnonRecord->field_end(); F != FEnd; ++F) { if ((*F)->getDeclName()) { - LookupResult R; - LookupQualifiedName(R, Owner, (*F)->getDeclName(), - LookupOrdinaryName, true); + LookupResult R(*this, (*F)->getDeclName(), SourceLocation(), + LookupOrdinaryName, ForRedeclaration); + LookupQualifiedName(R, Owner); NamedDecl *PrevDecl = R.getAsSingleDecl(Context); if (PrevDecl && !isa<TagDecl>(PrevDecl)) { // C++ [class.union]p2: @@ -1651,7 +1681,7 @@ DeclarationName Sema::GetNameFromUnqualifiedId(UnqualifiedId &Name) { case UnqualifiedId::IK_TemplateId: { TemplateName TName - = TemplateName::getFromVoidPointer(Name.TemplateId->Template); + = TemplateName::getFromVoidPointer(Name.TemplateId->Template); if (TemplateDecl *Template = TName.getAsTemplateDecl()) return Template->getDeclName(); if (OverloadedFunctionDecl *Ovl = TName.getAsOverloadedFunctionDecl()) @@ -1679,9 +1709,8 @@ static bool isNearlyMatchingFunction(ASTContext &Context, QualType DeclParamTy = Declaration->getParamDecl(Idx)->getType(); QualType DefParamTy = Definition->getParamDecl(Idx)->getType(); - DeclParamTy = Context.getCanonicalType(DeclParamTy.getNonReferenceType()); - DefParamTy = Context.getCanonicalType(DefParamTy.getNonReferenceType()); - if (DeclParamTy.getUnqualifiedType() != DefParamTy.getUnqualifiedType()) + if (!Context.hasSameUnqualifiedType(DeclParamTy.getNonReferenceType(), + DefParamTy.getNonReferenceType())) return false; } @@ -1766,10 +1795,10 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, NameKind = LookupRedeclarationWithLinkage; DC = CurContext; - LookupResult R; - LookupName(R, S, Name, NameKind, true, - NameKind == LookupRedeclarationWithLinkage, - D.getIdentifierLoc()); + LookupResult R(*this, Name, D.getIdentifierLoc(), NameKind, + ForRedeclaration); + + LookupName(R, S, NameKind == LookupRedeclarationWithLinkage); PrevDecl = R.getAsSingleDecl(Context); } else { // Something like "int foo::x;" DC = computeDeclContext(D.getCXXScopeSpec(), true); @@ -1790,8 +1819,9 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, RequireCompleteDeclContext(D.getCXXScopeSpec())) return DeclPtrTy(); - LookupResult Res; - LookupQualifiedName(Res, DC, Name, LookupOrdinaryName, true); + LookupResult Res(*this, Name, D.getIdentifierLoc(), LookupOrdinaryName, + ForRedeclaration); + LookupQualifiedName(Res, DC); PrevDecl = Res.getAsSingleDecl(Context); // C++ 7.3.1.2p2: @@ -1821,17 +1851,22 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, if (isa<TranslationUnitDecl>(DC)) { Diag(D.getIdentifierLoc(), diag::err_invalid_declarator_global_scope) << Name << D.getCXXScopeSpec().getRange(); - } else if (!CurContext->Encloses(DC)) { - // The qualifying scope doesn't enclose the original declaration. - // Emit diagnostic based on current scope. - SourceLocation L = D.getIdentifierLoc(); - SourceRange R = D.getCXXScopeSpec().getRange(); - if (isa<FunctionDecl>(CurContext)) - Diag(L, diag::err_invalid_declarator_in_function) << Name << R; - else - Diag(L, diag::err_invalid_declarator_scope) - << Name << cast<NamedDecl>(DC) << R; - D.setInvalidType(); + } else { + DeclContext *Cur = CurContext; + while (isa<LinkageSpecDecl>(Cur)) + Cur = Cur->getParent(); + if (!Cur->Encloses(DC)) { + // The qualifying scope doesn't enclose the original declaration. + // Emit diagnostic based on current scope. + SourceLocation L = D.getIdentifierLoc(); + SourceRange R = D.getCXXScopeSpec().getRange(); + if (isa<FunctionDecl>(Cur)) + Diag(L, diag::err_invalid_declarator_in_function) << Name << R; + else + Diag(L, diag::err_invalid_declarator_scope) + << Name << cast<NamedDecl>(DC) << R; + D.setInvalidType(); + } } } @@ -2417,7 +2452,9 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl, } static bool isUsingDecl(Decl *D) { - return isa<UsingDecl>(D) || isa<UnresolvedUsingDecl>(D); + return isa<UsingDecl>(D) || + isa<UnresolvedUsingTypenameDecl>(D) || + isa<UnresolvedUsingValueDecl>(D); } /// \brief Data used with FindOverriddenMethod @@ -2429,7 +2466,7 @@ struct FindOverriddenMethodData { /// \brief Member lookup function that determines whether a given C++ /// method overrides a method in a base class, to be used with /// CXXRecordDecl::lookupInBases(). -static bool FindOverriddenMethod(CXXBaseSpecifier *Specifier, +static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, void *UserData) { RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); @@ -2588,12 +2625,27 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, return 0; } + bool isStatic = SC == FunctionDecl::Static; + + // [class.free]p1: + // Any allocation function for a class T is a static member + // (even if not explicitly declared static). + if (Name.getCXXOverloadedOperator() == OO_New || + Name.getCXXOverloadedOperator() == OO_Array_New) + isStatic = true; + + // [class.free]p6 Any deallocation function for a class X is a static member + // (even if not explicitly declared static). + if (Name.getCXXOverloadedOperator() == OO_Delete || + Name.getCXXOverloadedOperator() == OO_Array_Delete) + isStatic = true; + // This is a C++ method declaration. NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC), D.getIdentifierLoc(), Name, R, DInfo, - (SC == FunctionDecl::Static), isInline); + isStatic, isInline); - isVirtualOkay = (SC != FunctionDecl::Static); + isVirtualOkay = !isStatic; } else { // Determine whether the function was written with a // prototype. This true when: @@ -2812,10 +2864,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, TemplateIdAnnotation *TemplateId = D.getName().TemplateId; ASTTemplateArgsPtr TemplateArgsPtr(*this, TemplateId->getTemplateArgs(), - TemplateId->getTemplateArgIsType(), TemplateId->NumArgs); translateTemplateArguments(TemplateArgsPtr, - TemplateId->getTemplateArgLocations(), TemplateArgs); TemplateArgsPtr.release(); @@ -2887,8 +2937,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, << Name << DC << D.getCXXScopeSpec().getRange(); NewFD->setInvalidDecl(); - LookupResult Prev; - LookupQualifiedName(Prev, DC, Name, LookupOrdinaryName, true); + LookupResult Prev(*this, Name, D.getIdentifierLoc(), LookupOrdinaryName, + ForRedeclaration); + LookupQualifiedName(Prev, DC); assert(!Prev.isAmbiguous() && "Cannot have an ambiguity in previous-declaration lookup"); for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end(); @@ -3068,9 +3119,13 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, // C++-specific checks. if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) { CheckConstructor(Constructor); - } else if (isa<CXXDestructorDecl>(NewFD)) { - CXXRecordDecl *Record = cast<CXXRecordDecl>(NewFD->getParent()); + } else if (CXXDestructorDecl *Destructor = + dyn_cast<CXXDestructorDecl>(NewFD)) { + CXXRecordDecl *Record = Destructor->getParent(); QualType ClassType = Context.getTypeDeclType(Record); + + // FIXME: Shouldn't we be able to perform thisc heck even when the class + // type is dependent? Both gcc and edg can handle that. if (!ClassType->isDependentType()) { DeclarationName Name = Context.DeclarationNames.getCXXDestructorName( @@ -3079,7 +3134,10 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, Diag(NewFD->getLocation(), diag::err_destructor_name); return NewFD->setInvalidDecl(); } + + CheckDestructor(Destructor); } + Record->setUserDeclaredDestructor(true); // C++ [class]p4: A POD-struct is an aggregate class that has [...] no // user-defined destructor. @@ -3257,8 +3315,13 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { return; } - if (!VDecl->getType()->isArrayType() && - RequireCompleteType(VDecl->getLocation(), VDecl->getType(), + // A definition must end up with a complete type, which means it must be + // complete with the restriction that an array type might be completed by the + // initializer; note that later code assumes this restriction. + QualType BaseDeclType = VDecl->getType(); + if (const ArrayType *Array = Context.getAsIncompleteArrayType(BaseDeclType)) + BaseDeclType = Array->getElementType(); + if (RequireCompleteType(VDecl->getLocation(), BaseDeclType, diag::err_typecheck_decl_incomplete_type)) { RealDecl->setInvalidDecl(); return; @@ -3433,6 +3496,16 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, return; } + // An array without size is an incomplete type, and there are no special + // rules in C++ to make such a definition acceptable. + if (getLangOptions().CPlusPlus && Type->isIncompleteArrayType() && + !Var->hasExternalStorage()) { + Diag(Var->getLocation(), + diag::err_typecheck_incomplete_array_needs_initializer); + Var->setInvalidDecl(); + return; + } + // C++ [temp.expl.spec]p15: // An explicit specialization of a static data member of a template is a // definition if the declaration includes an initializer; otherwise, it @@ -3563,7 +3636,7 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, // template <typename... Args> void f(Args... args) { // int vals[] = { args }; // } - const IncompleteArrayType *IAT = T->getAs<IncompleteArrayType>(); + const IncompleteArrayType *IAT = Context.getAsIncompleteArrayType(T); Expr *Init = IDecl->getInit(); if (IAT && Init && (Init->isTypeDependent() || Init->isValueDependent())) { @@ -3987,7 +4060,15 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body)); if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl)) - computeBaseOrMembersToDestroy(Destructor); + MarkBaseAndMemberDestructorsReferenced(Destructor); + + // If any errors have occurred, clear out any temporaries that may have + // been leftover. This ensures that these temporaries won't be picked up for + // deletion in some later function. + if (PP.getDiagnostics().hasErrorOccurred()) + ExprTemporaries.clear(); + + assert(ExprTemporaries.empty() && "Leftover temporaries in function"); return D; } @@ -4236,7 +4317,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, bool isStdBadAlloc = false; bool Invalid = false; - bool RedeclarationOnly = (TUK != TUK_Reference); + RedeclarationKind Redecl = (RedeclarationKind) (TUK != TUK_Reference); if (Name && SS.isNotEmpty()) { // We have a nested-name tag ('struct foo::bar'). @@ -4263,15 +4344,13 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, DC = computeDeclContext(SS, true); SearchDC = DC; // Look-up name inside 'foo::'. - LookupResult R; - LookupQualifiedName(R, DC, Name, LookupTagName, RedeclarationOnly); + LookupResult R(*this, Name, NameLoc, LookupTagName, Redecl); + LookupQualifiedName(R, DC); - if (R.isAmbiguous()) { - DiagnoseAmbiguousLookup(R, Name, NameLoc, SS.getRange()); + if (R.isAmbiguous()) return DeclPtrTy(); - } - if (R.getKind() == LookupResult::Found) + if (R.getResultKind() == LookupResult::Found) PrevDecl = dyn_cast<TagDecl>(R.getFoundDecl()); // A tag 'foo::bar' must already exist. @@ -4287,10 +4366,9 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // FIXME: We're looking into outer scopes here, even when we // shouldn't be. Doing so can result in ambiguities that we // shouldn't be diagnosing. - LookupResult R; - LookupName(R, S, Name, LookupTagName, RedeclarationOnly); + LookupResult R(*this, Name, NameLoc, LookupTagName, Redecl); + LookupName(R, S); if (R.isAmbiguous()) { - DiagnoseAmbiguousLookup(R, Name, NameLoc); // FIXME: This is not best way to recover from case like: // // struct S s; @@ -4552,8 +4630,9 @@ CreateNewDecl: // shall not be declared with the same name as a typedef-name // that is declared in that scope and refers to a type other // than the class or enumeration itself. - LookupResult Lookup; - LookupName(Lookup, S, Name, LookupOrdinaryName, true); + LookupResult Lookup(*this, Name, NameLoc, LookupOrdinaryName, + ForRedeclaration); + LookupName(Lookup, S); TypedefDecl *PrevTypedef = 0; if (NamedDecl *Prev = Lookup.getAsSingleDecl(Context)) PrevTypedef = dyn_cast<TypedefDecl>(Prev); @@ -4772,7 +4851,8 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); - NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName, true); + NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName, + ForRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. @@ -5157,7 +5237,8 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, DInfo, ac, (Expr *)BitfieldWidth); if (II) { - NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName, true); + NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName, + ForRedeclaration); if (PrevDecl && isDeclInScope(PrevDecl, EnclosingContext, S) && !isa<TagDecl>(PrevDecl)) { Diag(Loc, diag::err_duplicate_member) << II; @@ -5352,21 +5433,25 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, llvm::APSInt EnumVal(32); QualType EltTy; - if (Val && !Val->isTypeDependent()) { - // Make sure to promote the operand type to int. - UsualUnaryConversions(Val); - if (Val != val.get()) { - val.release(); - val = Val; - } + if (Val) { + if (Val->isTypeDependent()) + EltTy = Context.DependentTy; + else { + // Make sure to promote the operand type to int. + UsualUnaryConversions(Val); + if (Val != val.get()) { + val.release(); + val = Val; + } - // C99 6.7.2.2p2: Make sure we have an integer constant expression. - SourceLocation ExpLoc; - if (!Val->isValueDependent() && - VerifyIntegerConstantExpression(Val, &EnumVal)) { - Val = 0; - } else { - EltTy = Val->getType(); + // C99 6.7.2.2p2: Make sure we have an integer constant expression. + SourceLocation ExpLoc; + if (!Val->isValueDependent() && + VerifyIntegerConstantExpression(Val, &EnumVal)) { + Val = 0; + } else { + EltTy = Val->getType(); + } } } @@ -5388,6 +5473,8 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, } } + assert(!EltTy.isNull() && "Enum constant with NULL type"); + val.release(); return EnumConstantDecl::Create(Context, Enum, IdLoc, Id, EltTy, Val, EnumVal); diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 18f57da76912..c96ab4681cc5 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -862,7 +862,7 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { } else if (isa<ObjCPropertyDecl>(D) || isa<ObjCMethodDecl>(D)) { // We ignore weak import on properties and methods return; - } else { + } else if (!(S.LangOpts.ObjCNonFragileABI && isa<ObjCInterfaceDecl>(D))) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 2 /*variable and function*/; return; @@ -1008,6 +1008,38 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) { } +static void HandleCDeclAttr(Decl *d, const AttributeList &Attr, Sema &S) { + // Attribute has no arguments. + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return; + } + + // Attribute can be applied only to functions. + if (!isa<FunctionDecl>(d)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 0 /*function*/; + return; + } + + // cdecl and fastcall attributes are mutually incompatible. + if (d->getAttr<FastCallAttr>()) { + S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) + << "cdecl" << "fastcall"; + return; + } + + // cdecl and stdcall attributes are mutually incompatible. + if (d->getAttr<StdCallAttr>()) { + S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) + << "cdecl" << "stdcall"; + return; + } + + d->addAttr(::new (S.Context) CDeclAttr()); +} + + static void HandleStdCallAttr(Decl *d, const AttributeList &Attr, Sema &S) { // Attribute has no arguments. if (Attr.getNumArgs() != 0) { @@ -1319,7 +1351,14 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { // FIXME: Do we need to bounds check? unsigned ArgIdx = Idx.getZExtValue() - 1; - if (HasImplicitThisParam) ArgIdx--; + if (HasImplicitThisParam) { + if (ArgIdx == 0) { + S.Diag(Attr.getLoc(), diag::err_format_attribute_not) + << "a string type" << IdxExpr->getSourceRange(); + return; + } + ArgIdx--; + } // make sure the format string is really a string QualType Ty = getFunctionOrMethodArgType(d, ArgIdx); @@ -1822,6 +1861,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_analyzer_noreturn: HandleAnalyzerNoReturnAttr (D, Attr, S); break; case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break; + case AttributeList::AT_cdecl: HandleCDeclAttr (D, Attr, S); break; case AttributeList::AT_constructor: HandleConstructorAttr(D, Attr, S); break; case AttributeList::AT_deprecated: HandleDeprecatedAttr(D, Attr, S); break; case AttributeList::AT_destructor: HandleDestructorAttr(D, Attr, S); break; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index b8977cfa142d..237a869f9084 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -12,15 +12,17 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "Lookup.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/TypeOrdering.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Parse/DeclSpec.h" +#include "clang/Parse/Template.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Lex/Preprocessor.h" -#include "clang/Parse/DeclSpec.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Compiler.h" #include <algorithm> // for std::equal @@ -264,9 +266,18 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { ParmVarDecl *NewParam = New->getParamDecl(p); if (OldParam->hasDefaultArg() && NewParam->hasDefaultArg()) { + // FIXME: If the parameter doesn't have an identifier then the location + // points to the '=' which means that the fixit hint won't remove any + // extra spaces between the type and the '='. + SourceLocation Begin = NewParam->getLocation(); + if (NewParam->getIdentifier()) + Begin = PP.getLocForEndOfToken(Begin); + Diag(NewParam->getLocation(), diag::err_param_default_argument_redefinition) - << NewParam->getDefaultArgRange(); + << NewParam->getDefaultArgRange() + << CodeModificationHint::CreateRemoval(SourceRange(Begin, + NewParam->getLocEnd())); // Look for the function declaration where the default argument was // actually written, which may be a declaration prior to Old. @@ -577,7 +588,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, for (unsigned idx = 0; idx < NumBases; ++idx) { QualType NewBaseType = Context.getCanonicalType(Bases[idx]->getType()); - NewBaseType = NewBaseType.getUnqualifiedType(); + NewBaseType = NewBaseType.getLocalUnqualifiedType(); if (KnownBaseTypes[NewBaseType]) { // C++ [class.mi]p3: @@ -688,6 +699,8 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, (void)DerivationOkay; if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) { + if (InaccessibleBaseID == 0) + return false; // Check that the base class can be accessed. return CheckBaseClassAccess(Derived, Base, InaccessibleBaseID, Paths, Loc, Name); @@ -718,9 +731,11 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, bool Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, - SourceLocation Loc, SourceRange Range) { + SourceLocation Loc, SourceRange Range, + bool IgnoreAccess) { return CheckDerivedToBaseConversion(Derived, Base, - diag::err_conv_to_inaccessible_base, + IgnoreAccess ? 0 : + diag::err_conv_to_inaccessible_base, diag::err_ambiguous_derived_to_base_conv, Loc, Range, DeclarationName()); } @@ -1018,6 +1033,10 @@ Sema::MemInitResult Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs, SourceLocation IdLoc, SourceLocation RParenLoc) { + // FIXME: CXXBaseOrMemberInitializer should only contain a single + // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. + ExprTemporaries.clear(); + // Diagnose value-uses of fields to initialize themselves, e.g. // foo(foo) // where foo is not also a parameter to the constructor. @@ -1088,6 +1107,11 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, return true; Args[0] = NewExp; } + + // FIXME: CXXBaseOrMemberInitializer should only contain a single + // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. + ExprTemporaries.clear(); + // FIXME: Perform direct initialization of the member. return new (Context) CXXBaseOrMemberInitializer(Member, (Expr **)Args, NumArgs, C, IdLoc, RParenLoc); @@ -1117,8 +1141,7 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args, const CXXBaseSpecifier *DirectBaseSpec = 0; for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); Base != ClassDecl->bases_end(); ++Base) { - if (Context.getCanonicalType(BaseType).getUnqualifiedType() == - Context.getCanonicalType(Base->getType()).getUnqualifiedType()) { + if (Context.hasSameUnqualifiedType(BaseType, Base->getType())) { // We found a direct base of this type. That's what we're // initializing. DirectBaseSpec = &*Base; @@ -1166,7 +1189,7 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args, CXXConstructorDecl *C = 0; if (!BaseType->isDependentType() && !HasDependentArg) { DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(BaseType)); + Context.getCanonicalType(BaseType).getUnqualifiedType()); ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); C = PerformInitializationByConstructor(BaseType, @@ -1182,22 +1205,26 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args, } } + // FIXME: CXXBaseOrMemberInitializer should only contain a single + // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. + ExprTemporaries.clear(); + return new (Context) CXXBaseOrMemberInitializer(BaseType, (Expr **)Args, NumArgs, C, IdLoc, RParenLoc); } -void +bool Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, CXXBaseOrMemberInitializer **Initializers, unsigned NumInitializers, - llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases, - llvm::SmallVectorImpl<FieldDecl *>&Fields) { + bool IsImplicitConstructor) { // We need to build the initializer AST according to order of construction // and not what user specified in the Initializers list. CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Constructor->getDeclContext()); llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit; llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> AllBaseFields; bool HasDependentBaseInit = false; + bool HadError = false; for (unsigned i = 0; i < NumInitializers; i++) { CXXBaseOrMemberInitializer *Member = Initializers[i]; @@ -1239,13 +1266,8 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, E = ClassDecl->vbases_end(); VBase != E; ++VBase) { if (VBase->getType()->isDependentType()) continue; - if (CXXBaseOrMemberInitializer *Value = - AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) { - CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl()); - assert(BaseDecl && "SetBaseOrMemberInitializers - BaseDecl null"); - if (CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context)) - MarkDeclarationReferenced(Value->getSourceLocation(), Ctor); + if (CXXBaseOrMemberInitializer *Value + = AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) { AllToInit.push_back(Value); } else { @@ -1254,7 +1276,12 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, assert(VBaseDecl && "SetBaseOrMemberInitializers - VBaseDecl null"); CXXConstructorDecl *Ctor = VBaseDecl->getDefaultConstructor(Context); if (!Ctor) { - Bases.push_back(VBase); + Diag(Constructor->getLocation(), diag::err_missing_default_ctor) + << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl) + << 0 << VBase->getType(); + Diag(VBaseDecl->getLocation(), diag::note_previous_class_decl) + << Context.getTagDeclType(VBaseDecl); + HadError = true; continue; } @@ -1265,6 +1292,9 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, MarkDeclarationReferenced(Constructor->getLocation(), Ctor); + // FIXME: CXXBaseOrMemberInitializer should only contain a single + // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. + ExprTemporaries.clear(); CXXBaseOrMemberInitializer *Member = new (Context) CXXBaseOrMemberInitializer(VBase->getType(), CtorArgs.takeAs<Expr>(), @@ -1284,13 +1314,8 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, // Skip dependent types. if (Base->getType()->isDependentType()) continue; - if (CXXBaseOrMemberInitializer *Value = - AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) { - CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - assert(BaseDecl && "SetBaseOrMemberInitializers - BaseDecl null"); - if (CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context)) - MarkDeclarationReferenced(Value->getSourceLocation(), Ctor); + if (CXXBaseOrMemberInitializer *Value + = AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) { AllToInit.push_back(Value); } else { @@ -1299,7 +1324,12 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, assert(BaseDecl && "SetBaseOrMemberInitializers - BaseDecl null"); CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context); if (!Ctor) { - Bases.push_back(Base); + Diag(Constructor->getLocation(), diag::err_missing_default_ctor) + << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl) + << 0 << Base->getType(); + Diag(BaseDecl->getLocation(), diag::note_previous_class_decl) + << Context.getTagDeclType(BaseDecl); + HadError = true; continue; } @@ -1310,6 +1340,9 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, MarkDeclarationReferenced(Constructor->getLocation(), Ctor); + // FIXME: CXXBaseOrMemberInitializer should only contain a single + // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. + ExprTemporaries.clear(); CXXBaseOrMemberInitializer *Member = new (Context) CXXBaseOrMemberInitializer(Base->getType(), CtorArgs.takeAs<Expr>(), @@ -1328,7 +1361,7 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, if (const RecordType *FieldClassType = Field->getType()->getAs<RecordType>()) { CXXRecordDecl *FieldClassDecl - = cast<CXXRecordDecl>(FieldClassType->getDecl()); + = cast<CXXRecordDecl>(FieldClassType->getDecl()); for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(), EA = FieldClassDecl->field_end(); FA != EA; FA++) { if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*FA)) { @@ -1345,37 +1378,49 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, continue; } if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*Field)) { - QualType FT = (*Field)->getType(); - if (const RecordType* RT = FT->getAs<RecordType>()) { - CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RT->getDecl()); - assert(FieldRecDecl && "SetBaseOrMemberInitializers - BaseDecl null"); - if (CXXConstructorDecl *Ctor = - FieldRecDecl->getDefaultConstructor(Context)) - MarkDeclarationReferenced(Value->getSourceLocation(), Ctor); - } AllToInit.push_back(Value); continue; } - if ((*Field)->getType()->isDependentType()) { - Fields.push_back(*Field); + if ((*Field)->getType()->isDependentType()) continue; - } QualType FT = Context.getBaseElementType((*Field)->getType()); if (const RecordType* RT = FT->getAs<RecordType>()) { CXXConstructorDecl *Ctor = cast<CXXRecordDecl>(RT->getDecl())->getDefaultConstructor(Context); if (!Ctor) { - Fields.push_back(*Field); + Diag(Constructor->getLocation(), diag::err_missing_default_ctor) + << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl) + << 1 << (*Field)->getDeclName(); + Diag(Field->getLocation(), diag::note_field_decl); + Diag(RT->getDecl()->getLocation(), diag::note_previous_class_decl) + << Context.getTagDeclType(RT->getDecl()); + HadError = true; continue; } - + + if (FT.isConstQualified() && Ctor->isTrivial()) { + Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor) + << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl) + << 1 << (*Field)->getDeclName(); + Diag((*Field)->getLocation(), diag::note_declared_at); + HadError = true; + } + + // Don't create initializers for trivial constructors, since they don't + // actually need to be run. + if (Ctor->isTrivial()) + continue; + ASTOwningVector<&ActionBase::DeleteExpr> CtorArgs(*this); if (CompleteConstructorCall(Ctor, MultiExprArg(*this, 0, 0), Constructor->getLocation(), CtorArgs)) continue; + // FIXME: CXXBaseOrMemberInitializer should only contain a single + // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. + ExprTemporaries.clear(); CXXBaseOrMemberInitializer *Member = new (Context) CXXBaseOrMemberInitializer(*Field,CtorArgs.takeAs<Expr>(), CtorArgs.size(), Ctor, @@ -1383,23 +1428,21 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, SourceLocation()); AllToInit.push_back(Member); - if (Ctor) - MarkDeclarationReferenced(Constructor->getLocation(), Ctor); - if (FT.isConstQualified() && (!Ctor || Ctor->isTrivial())) { - Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor) - << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getDeclName(); - Diag((*Field)->getLocation(), diag::note_declared_at); - } + MarkDeclarationReferenced(Constructor->getLocation(), Ctor); } else if (FT->isReferenceType()) { Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor) - << Context.getTagDeclType(ClassDecl) << 0 << (*Field)->getDeclName(); + << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl) + << 0 << (*Field)->getDeclName(); Diag((*Field)->getLocation(), diag::note_declared_at); + HadError = true; } else if (FT.isConstQualified()) { Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor) - << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getDeclName(); + << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl) + << 1 << (*Field)->getDeclName(); Diag((*Field)->getLocation(), diag::note_declared_at); + HadError = true; } } @@ -1413,29 +1456,8 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, for (unsigned Idx = 0; Idx < NumInitializers; ++Idx) baseOrMemberInitializers[Idx] = AllToInit[Idx]; } -} - -void -Sema::BuildBaseOrMemberInitializers(ASTContext &C, - CXXConstructorDecl *Constructor, - CXXBaseOrMemberInitializer **Initializers, - unsigned NumInitializers - ) { - llvm::SmallVector<CXXBaseSpecifier *, 4> Bases; - llvm::SmallVector<FieldDecl *, 4> Members; - SetBaseOrMemberInitializers(Constructor, - Initializers, NumInitializers, Bases, Members); - 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(); - } + return HadError; } static void *GetKeyForTopLevelField(FieldDecl *Field) { @@ -1462,7 +1484,7 @@ static void *GetKeyForMember(CXXBaseOrMemberInitializer *Member, if (Member->isMemberInitializer()) { FieldDecl *Field = Member->getMember(); - // After BuildBaseOrMemberInitializers call, Field is the anonymous union + // After SetBaseOrMemberInitializers call, Field is the anonymous union // data member of the class. Data member used in the initializer list is // in AnonUnionMember field. if (MemberMaybeAnon && Field->isAnonymousStructOrUnion()) @@ -1527,9 +1549,9 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, return; } - BuildBaseOrMemberInitializers(Context, Constructor, + SetBaseOrMemberInitializers(Constructor, reinterpret_cast<CXXBaseOrMemberInitializer **>(MemInits), - NumMemInits); + NumMemInits, false); if (Constructor->isDependentContext()) return; @@ -1612,77 +1634,63 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, } void -Sema::computeBaseOrMembersToDestroy(CXXDestructorDecl *Destructor) { - CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Destructor->getDeclContext()); - llvm::SmallVector<uintptr_t, 32> AllToDestruct; +Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) { + // Ignore dependent destructors. + if (Destructor->isDependentContext()) + return; + + CXXRecordDecl *ClassDecl = Destructor->getParent(); - for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(), - E = ClassDecl->vbases_end(); VBase != E; ++VBase) { - if (VBase->getType()->isDependentType()) + // Non-static data members. + for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(), + E = ClassDecl->field_end(); I != E; ++I) { + FieldDecl *Field = *I; + + QualType FieldType = Context.getBaseElementType(Field->getType()); + + const RecordType* RT = FieldType->getAs<RecordType>(); + if (!RT) continue; - // Skip over virtual bases which have trivial destructors. - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl()); - if (BaseClassDecl->hasTrivialDestructor()) + + CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl()); + if (FieldClassDecl->hasTrivialDestructor()) continue; - if (const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context)) - MarkDeclarationReferenced(Destructor->getLocation(), - const_cast<CXXDestructorDecl*>(Dtor)); - uintptr_t Member = - reinterpret_cast<uintptr_t>(VBase->getType().getTypePtr()) - | CXXDestructorDecl::VBASE; - AllToDestruct.push_back(Member); + const CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor(Context); + MarkDeclarationReferenced(Destructor->getLocation(), + const_cast<CXXDestructorDecl*>(Dtor)); } - for (CXXRecordDecl::base_class_iterator Base = - ClassDecl->bases_begin(), + + // Bases. + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), E = ClassDecl->bases_end(); Base != E; ++Base) { + // Ignore virtual bases. if (Base->isVirtual()) continue; - if (Base->getType()->isDependentType()) - continue; - // Skip over virtual bases which have trivial destructors. + + // Ignore trivial destructors. CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); if (BaseClassDecl->hasTrivialDestructor()) continue; - if (const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context)) - MarkDeclarationReferenced(Destructor->getLocation(), - const_cast<CXXDestructorDecl*>(Dtor)); - uintptr_t Member = - reinterpret_cast<uintptr_t>(Base->getType().getTypePtr()) - | CXXDestructorDecl::DRCTNONVBASE; - AllToDestruct.push_back(Member); - } - - // non-static data members. - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - E = ClassDecl->field_end(); Field != E; ++Field) { - QualType FieldType = Context.getBaseElementType((*Field)->getType()); - - if (const RecordType* RT = FieldType->getAs<RecordType>()) { - // Skip over virtual bases which have trivial destructors. - CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl()); - if (FieldClassDecl->hasTrivialDestructor()) - continue; - if (const CXXDestructorDecl *Dtor = - FieldClassDecl->getDestructor(Context)) - MarkDeclarationReferenced(Destructor->getLocation(), - const_cast<CXXDestructorDecl*>(Dtor)); - uintptr_t Member = reinterpret_cast<uintptr_t>(*Field); - AllToDestruct.push_back(Member); - } + + const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context); + MarkDeclarationReferenced(Destructor->getLocation(), + const_cast<CXXDestructorDecl*>(Dtor)); } - - unsigned NumDestructions = AllToDestruct.size(); - if (NumDestructions > 0) { - Destructor->setNumBaseOrMemberDestructions(NumDestructions); - uintptr_t *BaseOrMemberDestructions = - new (Context) uintptr_t [NumDestructions]; - // Insert in reverse order. - for (int Idx = NumDestructions-1, i=0 ; Idx >= 0; --Idx) - BaseOrMemberDestructions[i++] = AllToDestruct[Idx]; - Destructor->setBaseOrMemberDestructions(BaseOrMemberDestructions); + + // Virtual bases. + for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(), + E = ClassDecl->vbases_end(); VBase != E; ++VBase) { + // Ignore trivial destructors. + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl()); + if (BaseClassDecl->hasTrivialDestructor()) + continue; + + const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context); + MarkDeclarationReferenced(Destructor->getLocation(), + const_cast<CXXDestructorDecl*>(Dtor)); } } @@ -1694,9 +1702,7 @@ void Sema::ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) { if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(CDtorDecl.getAs<Decl>())) - BuildBaseOrMemberInitializers(Context, - Constructor, - (CXXBaseOrMemberInitializer **)0, 0); + SetBaseOrMemberInitializers(Constructor, 0, 0, false); } namespace { @@ -1931,7 +1937,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, } if (RD->isAbstract()) - AbstractClassUsageDiagnoser(*this, RD); + (void)AbstractClassUsageDiagnoser(*this, RD); if (!RD->isDependentType() && !RD->isInvalidDecl()) AddImplicitlyDeclaredMembersToClass(RD); @@ -2334,13 +2340,18 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { if (!Constructor->isInvalidDecl() && ((Constructor->getNumParams() == 1) || (Constructor->getNumParams() > 1 && - Constructor->getParamDecl(1)->hasDefaultArg()))) { + Constructor->getParamDecl(1)->hasDefaultArg())) && + Constructor->getTemplateSpecializationKind() + != TSK_ImplicitInstantiation) { QualType ParamType = Constructor->getParamDecl(0)->getType(); QualType ClassTy = Context.getTagDeclType(ClassDecl); if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) { SourceLocation ParamLoc = Constructor->getParamDecl(0)->getLocation(); Diag(ParamLoc, diag::err_constructor_byvalue_arg) << CodeModificationHint::CreateInsertion(ParamLoc, " const &"); + + // FIXME: Rather that making the constructor invalid, we should endeavor + // to fix the type. Constructor->setInvalidDecl(); } } @@ -2349,6 +2360,28 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { ClassDecl->addedConstructor(Context, Constructor); } +/// CheckDestructor - Checks a fully-formed destructor for +/// well-formedness, issuing any diagnostics required. +void Sema::CheckDestructor(CXXDestructorDecl *Destructor) { + CXXRecordDecl *RD = Destructor->getParent(); + + if (Destructor->isVirtual()) { + SourceLocation Loc; + + if (!Destructor->isImplicit()) + Loc = Destructor->getLocation(); + else + Loc = RD->getLocation(); + + // If we have a virtual destructor, look up the deallocation function + FunctionDecl *OperatorDelete = 0; + DeclarationName Name = + Context.DeclarationNames.getCXXOperatorName(OO_Delete); + if (!FindDeallocationFunction(Loc, RD, Name, OperatorDelete)) + Destructor->setOperatorDelete(OperatorDelete); + } +} + static inline bool FTIHasSingleVoidArgument(DeclaratorChunk::FunctionTypeInfo &FTI) { return (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 && @@ -2606,7 +2639,8 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, // in that declarative region, it is treated as an original-namespace-name. NamedDecl *PrevDecl - = LookupSingleName(DeclRegionScope, II, LookupOrdinaryName, true); + = LookupSingleName(DeclRegionScope, II, LookupOrdinaryName, + ForRedeclaration); if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl)) { // This is an extended namespace definition. @@ -2714,14 +2748,14 @@ Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S, UsingDirectiveDecl *UDir = 0; // Lookup namespace name. - LookupResult R; - LookupParsedName(R, S, &SS, NamespcName, LookupNamespaceName, false); - if (R.isAmbiguous()) { - DiagnoseAmbiguousLookup(R, NamespcName, IdentLoc); + LookupResult R(*this, NamespcName, IdentLoc, LookupNamespaceName); + LookupParsedName(R, S, &SS); + if (R.isAmbiguous()) return DeclPtrTy(); - } + if (!R.empty()) { NamedDecl *NS = R.getFoundDecl(); + // FIXME: Namespace aliases! assert(isa<NamespaceDecl>(NS) && "expected namespace decl"); // C++ [namespace.udir]p1: // A using-directive specifies that the names in the nominated @@ -2776,7 +2810,8 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, const CXXScopeSpec &SS, UnqualifiedId &Name, AttributeList *AttrList, - bool IsTypeName) { + bool IsTypeName, + SourceLocation TypenameLoc) { assert(S->getFlags() & Scope::DeclScope && "Invalid Scope."); switch (Name.getKind()) { @@ -2802,9 +2837,11 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, } DeclarationName TargetName = GetNameFromUnqualifiedId(Name); - NamedDecl *UD = BuildUsingDeclaration(UsingLoc, SS, + NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS, Name.getSourceRange().getBegin(), - TargetName, AttrList, IsTypeName); + TargetName, AttrList, + /* IsInstantiation */ false, + IsTypeName, TypenameLoc); if (UD) { PushOnScopeChains(UD, S); UD->setAccess(AS); @@ -2813,12 +2850,46 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, return DeclPtrTy::make(UD); } -NamedDecl *Sema::BuildUsingDeclaration(SourceLocation UsingLoc, +/// Builds a shadow declaration corresponding to a 'using' declaration. +static UsingShadowDecl *BuildUsingShadowDecl(Sema &SemaRef, Scope *S, + AccessSpecifier AS, + UsingDecl *UD, NamedDecl *Orig) { + // FIXME: diagnose hiding, collisions + + // If we resolved to another shadow declaration, just coalesce them. + if (isa<UsingShadowDecl>(Orig)) { + Orig = cast<UsingShadowDecl>(Orig)->getTargetDecl(); + assert(!isa<UsingShadowDecl>(Orig) && "nested shadow declaration"); + } + + UsingShadowDecl *Shadow + = UsingShadowDecl::Create(SemaRef.Context, SemaRef.CurContext, + UD->getLocation(), UD, Orig); + UD->addShadowDecl(Shadow); + + if (S) + SemaRef.PushOnScopeChains(Shadow, S); + else + SemaRef.CurContext->addDecl(Shadow); + Shadow->setAccess(AS); + + return Shadow; +} + +/// Builds a using declaration. +/// +/// \param IsInstantiation - Whether this call arises from an +/// instantiation of an unresolved using declaration. We treat +/// the lookup differently for these declarations. +NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, + SourceLocation UsingLoc, const CXXScopeSpec &SS, SourceLocation IdentLoc, DeclarationName Name, AttributeList *AttrList, - bool IsTypeName) { + bool IsInstantiation, + bool IsTypeName, + SourceLocation TypenameLoc) { assert(!SS.isInvalid() && "Invalid CXXScopeSpec."); assert(IdentLoc.isValid() && "Invalid TargetName location."); @@ -2833,14 +2904,20 @@ NamedDecl *Sema::BuildUsingDeclaration(SourceLocation UsingLoc, NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); - if (isUnknownSpecialization(SS)) { - return UnresolvedUsingDecl::Create(Context, CurContext, UsingLoc, - SS.getRange(), NNS, - IdentLoc, Name, IsTypeName); + DeclContext *LookupContext = computeDeclContext(SS); + if (!LookupContext) { + if (IsTypeName) { + return UnresolvedUsingTypenameDecl::Create(Context, CurContext, + UsingLoc, TypenameLoc, + SS.getRange(), NNS, + IdentLoc, Name); + } else { + return UnresolvedUsingValueDecl::Create(Context, CurContext, + UsingLoc, SS.getRange(), NNS, + IdentLoc, Name); + } } - DeclContext *LookupContext = 0; - if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(CurContext)) { // C++0x N2914 [namespace.udecl]p3: // A using-declaration used as a member-declaration shall refer to a member @@ -2848,37 +2925,36 @@ NamedDecl *Sema::BuildUsingDeclaration(SourceLocation UsingLoc, // anonymous union that is a member of a base class of the class being // defined, or shall refer to an enumerator for an enumeration type that is // a member of a base class of the class being defined. - const Type *Ty = NNS->getAsType(); - if (!Ty || !IsDerivedFrom(Context.getTagDeclType(RD), QualType(Ty, 0))) { + + CXXRecordDecl *LookupRD = dyn_cast<CXXRecordDecl>(LookupContext); + if (!LookupRD || !RD->isDerivedFrom(LookupRD)) { Diag(SS.getRange().getBegin(), diag::err_using_decl_nested_name_specifier_is_not_a_base_class) << NNS << RD->getDeclName(); return 0; } - - QualType BaseTy = Context.getCanonicalType(QualType(Ty, 0)); - LookupContext = BaseTy->getAs<RecordType>()->getDecl(); } else { // C++0x N2914 [namespace.udecl]p8: // A using-declaration for a class member shall be a member-declaration. - if (NNS->getKind() == NestedNameSpecifier::TypeSpec) { + if (isa<CXXRecordDecl>(LookupContext)) { Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_class_member) << SS.getRange(); return 0; } - - // C++0x N2914 [namespace.udecl]p9: - // In a using-declaration, a prefix :: refers to the global namespace. - if (NNS->getKind() == NestedNameSpecifier::Global) - LookupContext = Context.getTranslationUnitDecl(); - else - LookupContext = NNS->getAsNamespace(); } + // Look up the target name. Unlike most lookups, we do not want to + // hide tag declarations: tag names are visible through the using + // declaration even if hidden by ordinary names. + LookupResult R(*this, Name, IdentLoc, LookupOrdinaryName); - // Lookup target name. - LookupResult R; - LookupQualifiedName(R, LookupContext, Name, LookupOrdinaryName); + // We don't hide tags behind ordinary decls if we're in a + // non-dependent context, but in a dependent context, this is + // important for the stability of two-phase lookup. + if (!IsInstantiation) + R.setHideTags(false); + + LookupQualifiedName(R, LookupContext); if (R.empty()) { Diag(IdentLoc, diag::err_no_member) @@ -2886,24 +2962,49 @@ NamedDecl *Sema::BuildUsingDeclaration(SourceLocation UsingLoc, return 0; } - // FIXME: handle ambiguity? - NamedDecl *ND = R.getAsSingleDecl(Context); - - if (IsTypeName && !isa<TypeDecl>(ND)) { - Diag(IdentLoc, diag::err_using_typename_non_type); + if (R.isAmbiguous()) return 0; + + if (IsTypeName) { + // If we asked for a typename and got a non-type decl, error out. + if (R.getResultKind() != LookupResult::Found + || !isa<TypeDecl>(R.getFoundDecl())) { + Diag(IdentLoc, diag::err_using_typename_non_type); + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) + Diag((*I)->getUnderlyingDecl()->getLocation(), + diag::note_using_decl_target); + return 0; + } + } else { + // If we asked for a non-typename and we got a type, error out, + // but only if this is an instantiation of an unresolved using + // decl. Otherwise just silently find the type name. + if (IsInstantiation && + R.getResultKind() == LookupResult::Found && + isa<TypeDecl>(R.getFoundDecl())) { + Diag(IdentLoc, diag::err_using_dependent_value_is_type); + Diag(R.getFoundDecl()->getLocation(), diag::note_using_decl_target); + return 0; + } } // C++0x N2914 [namespace.udecl]p6: // A using-declaration shall not name a namespace. - if (isa<NamespaceDecl>(ND)) { + if (R.getResultKind() == LookupResult::Found + && isa<NamespaceDecl>(R.getFoundDecl())) { Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_namespace) << SS.getRange(); return 0; } - return UsingDecl::Create(Context, CurContext, IdentLoc, SS.getRange(), - ND->getLocation(), UsingLoc, ND, NNS, IsTypeName); + UsingDecl *UD = UsingDecl::Create(Context, CurContext, IdentLoc, + SS.getRange(), UsingLoc, NNS, Name, + IsTypeName); + + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) + BuildUsingShadowDecl(*this, S, AS, UD, *I); + + return UD; } /// getNamespaceDecl - Returns the namespace a decl represents. If the decl @@ -2923,12 +3024,12 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, IdentifierInfo *Ident) { // Lookup the namespace name. - LookupResult R; - LookupParsedName(R, S, &SS, Ident, LookupNamespaceName, false); + LookupResult R(*this, Ident, IdentLoc, LookupNamespaceName); + LookupParsedName(R, S, &SS); // Check if we have a previous declaration with the same name. if (NamedDecl *PrevDecl - = LookupSingleName(S, Alias, LookupOrdinaryName, true)) { + = LookupSingleName(S, Alias, LookupOrdinaryName, ForRedeclaration)) { if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) { // We already have an alias with the same name that points to the same // namespace, so don't create a new one. @@ -2944,10 +3045,8 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, return DeclPtrTy(); } - if (R.isAmbiguous()) { - DiagnoseAmbiguousLookup(R, Ident, IdentLoc); + if (R.isAmbiguous()) return DeclPtrTy(); - } if (R.empty()) { Diag(NamespaceLoc, diag::err_expected_namespace_name) << SS.getRange(); @@ -2973,76 +3072,22 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Constructor->getDeclContext()); assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor"); - // Before the implicitly-declared default constructor for a class is - // implicitly defined, all the implicitly-declared default constructors - // for its base class and its non-static data members shall have been - // implicitly defined. - bool err = false; - for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), - E = ClassDecl->bases_end(); Base != E; ++Base) { - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - if (!BaseClassDecl->hasTrivialConstructor()) { - if (CXXConstructorDecl *BaseCtor = - BaseClassDecl->getDefaultConstructor(Context)) - MarkDeclarationReferenced(CurrentLocation, BaseCtor); - else { - Diag(CurrentLocation, diag::err_defining_default_ctor) - << Context.getTagDeclType(ClassDecl) << 0 - << Context.getTagDeclType(BaseClassDecl); - Diag(BaseClassDecl->getLocation(), diag::note_previous_class_decl) - << Context.getTagDeclType(BaseClassDecl); - err = true; - } - } - } - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - E = ClassDecl->field_end(); Field != E; ++Field) { - QualType FieldType = Context.getCanonicalType((*Field)->getType()); - if (const ArrayType *Array = Context.getAsArrayType(FieldType)) - FieldType = Array->getElementType(); - if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { - CXXRecordDecl *FieldClassDecl - = cast<CXXRecordDecl>(FieldClassType->getDecl()); - if (!FieldClassDecl->hasTrivialConstructor()) { - if (CXXConstructorDecl *FieldCtor = - FieldClassDecl->getDefaultConstructor(Context)) - MarkDeclarationReferenced(CurrentLocation, FieldCtor); - else { - Diag(CurrentLocation, diag::err_defining_default_ctor) - << Context.getTagDeclType(ClassDecl) << 1 << - Context.getTagDeclType(FieldClassDecl); - Diag((*Field)->getLocation(), diag::note_field_decl); - Diag(FieldClassDecl->getLocation(), diag::note_previous_class_decl) - << Context.getTagDeclType(FieldClassDecl); - err = true; - } - } - } else if (FieldType->isReferenceType()) { - Diag(CurrentLocation, diag::err_unintialized_member) - << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); - Diag((*Field)->getLocation(), diag::note_declared_at); - err = true; - } else if (FieldType.isConstQualified()) { - Diag(CurrentLocation, diag::err_unintialized_member) - << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); - Diag((*Field)->getLocation(), diag::note_declared_at); - err = true; - } - } - if (!err) - Constructor->setUsed(); - else + + if (SetBaseOrMemberInitializers(Constructor, 0, 0, true)) { + Diag(CurrentLocation, diag::note_ctor_synthesized_at) + << Context.getTagDeclType(ClassDecl); Constructor->setInvalidDecl(); + } else { + Constructor->setUsed(); + } + return; } void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, CXXDestructorDecl *Destructor) { assert((Destructor->isImplicit() && !Destructor->isUsed()) && "DefineImplicitDestructor - call it for implicit default dtor"); - - CXXRecordDecl *ClassDecl - = cast<CXXRecordDecl>(Destructor->getDeclContext()); + CXXRecordDecl *ClassDecl = Destructor->getParent(); assert(ClassDecl && "DefineImplicitDestructor - invalid destructor"); // C++ [class.dtor] p5 // Before the implicitly-declared default destructor for a class is @@ -3399,6 +3444,107 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, /*DirectInit=*/true); } +/// \brief Add the applicable constructor candidates for an initialization +/// by constructor. +static void AddConstructorInitializationCandidates(Sema &SemaRef, + QualType ClassType, + Expr **Args, + unsigned NumArgs, + Sema::InitializationKind Kind, + OverloadCandidateSet &CandidateSet) { + // C++ [dcl.init]p14: + // If the initialization is direct-initialization, or if it is + // copy-initialization where the cv-unqualified version of the + // source type is the same class as, or a derived class of, the + // class of the destination, constructors are considered. The + // applicable constructors are enumerated (13.3.1.3), and the + // best one is chosen through overload resolution (13.3). The + // constructor so selected is called to initialize the object, + // with the initializer expression(s) as its argument(s). If no + // constructor applies, or the overload resolution is ambiguous, + // the initialization is ill-formed. + const RecordType *ClassRec = ClassType->getAs<RecordType>(); + assert(ClassRec && "Can only initialize a class type here"); + + // FIXME: When we decide not to synthesize the implicitly-declared + // constructors, we'll need to make them appear here. + + const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(ClassRec->getDecl()); + DeclarationName ConstructorName + = SemaRef.Context.DeclarationNames.getCXXConstructorName( + SemaRef.Context.getCanonicalType(ClassType).getUnqualifiedType()); + DeclContext::lookup_const_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = ClassDecl->lookup(ConstructorName); + Con != ConEnd; ++Con) { + // Find the constructor (which may be a template). + CXXConstructorDecl *Constructor = 0; + FunctionTemplateDecl *ConstructorTmpl= dyn_cast<FunctionTemplateDecl>(*Con); + if (ConstructorTmpl) + Constructor + = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl()); + else + Constructor = cast<CXXConstructorDecl>(*Con); + + if ((Kind == Sema::IK_Direct) || + (Kind == Sema::IK_Copy && + Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) || + (Kind == Sema::IK_Default && Constructor->isDefaultConstructor())) { + if (ConstructorTmpl) + SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0, + Args, NumArgs, CandidateSet); + else + SemaRef.AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet); + } + } +} + +/// \brief Attempt to perform initialization by constructor +/// (C++ [dcl.init]p14), which may occur as part of direct-initialization or +/// copy-initialization. +/// +/// This routine determines whether initialization by constructor is possible, +/// but it does not emit any diagnostics in the case where the initialization +/// is ill-formed. +/// +/// \param ClassType the type of the object being initialized, which must have +/// class type. +/// +/// \param Args the arguments provided to initialize the object +/// +/// \param NumArgs the number of arguments provided to initialize the object +/// +/// \param Kind the type of initialization being performed +/// +/// \returns the constructor used to initialize the object, if successful. +/// Otherwise, emits a diagnostic and returns NULL. +CXXConstructorDecl * +Sema::TryInitializationByConstructor(QualType ClassType, + Expr **Args, unsigned NumArgs, + SourceLocation Loc, + InitializationKind Kind) { + // Build the overload candidate set + OverloadCandidateSet CandidateSet; + AddConstructorInitializationCandidates(*this, ClassType, Args, NumArgs, Kind, + CandidateSet); + + // Determine whether we found a constructor we can use. + OverloadCandidateSet::iterator Best; + switch (BestViableFunction(CandidateSet, Loc, Best)) { + case OR_Success: + case OR_Deleted: + // We found a constructor. Return it. + return cast<CXXConstructorDecl>(Best->Function); + + case OR_No_Viable_Function: + case OR_Ambiguous: + // Overload resolution failed. Return nothing. + return 0; + } + + // Silence GCC warning + return 0; +} + /// \brief Perform initialization by constructor (C++ [dcl.init]p14), which /// may occur as part of direct-initialization or copy-initialization. /// @@ -3428,55 +3574,13 @@ Sema::PerformInitializationByConstructor(QualType ClassType, DeclarationName InitEntity, InitializationKind Kind, ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs) { - const RecordType *ClassRec = ClassType->getAs<RecordType>(); - assert(ClassRec && "Can only initialize a class type here"); + + // Build the overload candidate set Expr **Args = (Expr **)ArgsPtr.get(); unsigned NumArgs = ArgsPtr.size(); - - // C++ [dcl.init]p14: - // If the initialization is direct-initialization, or if it is - // copy-initialization where the cv-unqualified version of the - // source type is the same class as, or a derived class of, the - // class of the destination, constructors are considered. The - // applicable constructors are enumerated (13.3.1.3), and the - // best one is chosen through overload resolution (13.3). The - // constructor so selected is called to initialize the object, - // with the initializer expression(s) as its argument(s). If no - // constructor applies, or the overload resolution is ambiguous, - // the initialization is ill-formed. - const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(ClassRec->getDecl()); OverloadCandidateSet CandidateSet; - - // Add constructors to the overload set. - DeclarationName ConstructorName - = Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(ClassType.getUnqualifiedType())); - DeclContext::lookup_const_iterator Con, ConEnd; - for (llvm::tie(Con, ConEnd) = ClassDecl->lookup(ConstructorName); - Con != ConEnd; ++Con) { - // Find the constructor (which may be a template). - CXXConstructorDecl *Constructor = 0; - FunctionTemplateDecl *ConstructorTmpl= dyn_cast<FunctionTemplateDecl>(*Con); - if (ConstructorTmpl) - Constructor - = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl()); - else - Constructor = cast<CXXConstructorDecl>(*Con); - - if ((Kind == IK_Direct) || - (Kind == IK_Copy && - Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) || - (Kind == IK_Default && Constructor->isDefaultConstructor())) { - if (ConstructorTmpl) - AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0, - Args, NumArgs, CandidateSet); - else - AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet); - } - } - - // FIXME: When we decide not to synthesize the implicitly-declared - // constructors, we'll need to make them appear here. + AddConstructorInitializationCandidates(*this, ClassType, Args, NumArgs, Kind, + CandidateSet); OverloadCandidateSet::iterator Best; switch (BestViableFunction(CandidateSet, Loc, Best)) { @@ -3613,8 +3717,8 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, QualType T1 = Context.getCanonicalType(OrigT1); QualType T2 = Context.getCanonicalType(OrigT2); - QualType UnqualT1 = T1.getUnqualifiedType(); - QualType UnqualT2 = T2.getUnqualifiedType(); + QualType UnqualT1 = T1.getLocalUnqualifiedType(); + QualType UnqualT2 = T2.getLocalUnqualifiedType(); // C++ [dcl.init.ref]p4: // Given types "cv1 T1" and "cv2 T2," "cv1 T1" is @@ -3663,12 +3767,15 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, /// When @p AllowExplicit, we also permit explicit user-defined /// conversion functions. /// When @p ForceRValue, we unconditionally treat the initializer as an rvalue. +/// When @p IgnoreBaseAccess, we don't do access control on to-base conversion. +/// This is used when this is called from a C-style cast. bool Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, SourceLocation DeclLoc, bool SuppressUserConversions, bool AllowExplicit, bool ForceRValue, - ImplicitConversionSequence *ICS) { + ImplicitConversionSequence *ICS, + bool IgnoreBaseAccess) { assert(DeclType->isReferenceType() && "Reference init needs a reference"); QualType T1 = DeclType->getAs<ReferenceType>()->getPointeeType(); @@ -3827,6 +3934,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, ICS->UserDefined.Before = Best->Conversions[0].Standard; ICS->UserDefined.After = Best->FinalConversion; ICS->UserDefined.ConversionFunction = Best->Function; + ICS->UserDefined.EllipsisConversion = false; assert(ICS->UserDefined.After.ReferenceBinding && ICS->UserDefined.After.DirectBinding && "Expected a direct reference binding!"); @@ -3882,7 +3990,8 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // actually happens. if (DerivedToBase) return CheckDerivedToBaseConversion(T2, T1, DeclLoc, - Init->getSourceRange()); + Init->getSourceRange(), + IgnoreBaseAccess); else return false; } @@ -4051,9 +4160,28 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { // found in the rest of this subclause do not apply to them unless // explicitly stated in 3.7.3. // FIXME: Write a separate routine for checking this. For now, just allow it. - if (Op == OO_New || Op == OO_Array_New || - Op == OO_Delete || Op == OO_Array_Delete) + if (Op == OO_Delete || Op == OO_Array_Delete) return false; + + if (Op == OO_New || Op == OO_Array_New) { + bool ret = false; + if (FunctionDecl::param_iterator Param = FnDecl->param_begin()) { + QualType SizeTy = Context.getCanonicalType(Context.getSizeType()); + QualType T = Context.getCanonicalType((*Param)->getType()); + if (!T->isDependentType() && SizeTy != T) { + Diag(FnDecl->getLocation(), + diag::err_operator_new_param_type) << FnDecl->getDeclName() + << SizeTy; + ret = true; + } + } + QualType ResultTy = Context.getCanonicalType(FnDecl->getResultType()); + if (!ResultTy->isDependentType() && ResultTy != Context.VoidPtrTy) + return Diag(FnDecl->getLocation(), + diag::err_operator_new_result_type) << FnDecl->getDeclName() + << static_cast<QualType>(Context.VoidPtrTy); + return ret; + } // C++ [over.oper]p6: // An operator function shall either be a non-static member @@ -4182,7 +4310,6 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { assert(isa<CXXMethodDecl>(FnDecl) && "Overloaded = not member, but not filtered."); CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl); - Method->setCopyAssignment(true); Method->getParent()->addedAssignmentOperator(Context, Method); } @@ -4549,8 +4676,8 @@ Sema::ActOnFriendFunctionDecl(Scope *S, // FIXME: handle dependent contexts if (!DC) return DeclPtrTy(); - LookupResult R; - LookupQualifiedName(R, DC, Name, LookupOrdinaryName, true); + LookupResult R(*this, Name, Loc, LookupOrdinaryName, ForRedeclaration); + LookupQualifiedName(R, DC); PrevDecl = R.getAsSingleDecl(Context); // If searching in that context implicitly found a declaration in @@ -4584,8 +4711,8 @@ Sema::ActOnFriendFunctionDecl(Scope *S, while (DC->isRecord()) DC = DC->getParent(); - LookupResult R; - LookupQualifiedName(R, DC, Name, LookupOrdinaryName, true); + LookupResult R(*this, Name, Loc, LookupOrdinaryName, ForRedeclaration); + LookupQualifiedName(R, DC); PrevDecl = R.getAsSingleDecl(Context); // TODO: decide what we think about using declarations. @@ -4697,7 +4824,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, QualType COldTy = Context.getCanonicalType(OldTy); if (CNewTy == COldTy && - CNewTy.getCVRQualifiers() == COldTy.getCVRQualifiers()) + CNewTy.getLocalCVRQualifiers() == COldTy.getLocalCVRQualifiers()) return false; // Check if the return types are covariant @@ -4726,7 +4853,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, return true; } - if (NewClassTy.getUnqualifiedType() != OldClassTy.getUnqualifiedType()) { + if (!Context.hasSameUnqualifiedType(NewClassTy, OldClassTy)) { // Check if the new class derives from the old class. if (!IsDerivedFrom(NewClassTy, OldClassTy)) { Diag(New->getLocation(), @@ -4748,7 +4875,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, } // The qualifiers of the return types must be the same. - if (CNewTy.getCVRQualifiers() != COldTy.getCVRQualifiers()) { + if (CNewTy.getLocalCVRQualifiers() != COldTy.getLocalCVRQualifiers()) { Diag(New->getLocation(), diag::err_covariant_return_type_different_qualifications) << New->getDeclName() << NewTy << OldTy; diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 93f8d0dc37c1..0c5569caff00 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -112,6 +112,14 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, IDecl->setLocation(AtInterfaceLoc); IDecl->setForwardDecl(false); IDecl->setClassLoc(ClassLoc); + + // Since this ObjCInterfaceDecl was created by a forward declaration, + // we now add it to the DeclContext since it wasn't added before + // (see ActOnForwardClassDeclaration). + CurContext->addDecl(IDecl); + + if (AttrList) + ProcessDeclAttributeList(TUScope, IDecl, AttrList); } } else { IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc, @@ -1113,10 +1121,46 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, assert(false && "invalid ObjCContainerDecl type."); } +void +Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, + ObjCContainerDecl* IDecl) { + // Rules apply in non-GC mode only + if (getLangOptions().getGCMode() != LangOptions::NonGC) + return; + for (ObjCContainerDecl::prop_iterator I = IDecl->prop_begin(), + E = IDecl->prop_end(); + I != E; ++I) { + ObjCPropertyDecl *Property = (*I); + unsigned Attributes = Property->getPropertyAttributes(); + // We only care about readwrite atomic property. + if ((Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) || + !(Attributes & ObjCPropertyDecl::OBJC_PR_readwrite)) + continue; + if (const ObjCPropertyImplDecl *PIDecl + = IMPDecl->FindPropertyImplDecl(Property->getIdentifier())) { + if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) + continue; + ObjCMethodDecl *GetterMethod = + IMPDecl->getInstanceMethod(Property->getGetterName()); + ObjCMethodDecl *SetterMethod = + IMPDecl->getInstanceMethod(Property->getSetterName()); + if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) { + SourceLocation MethodLoc = + (GetterMethod ? GetterMethod->getLocation() + : SetterMethod->getLocation()); + Diag(MethodLoc, diag::warn_atomic_property_rule) + << Property->getIdentifier(); + Diag(Property->getLocation(), diag::note_property_declare); + } + } + } +} + /// ActOnForwardClassDeclaration - Action::DeclPtrTy Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, IdentifierInfo **IdentList, + SourceLocation *IdentLocs, unsigned NumElts) { llvm::SmallVector<ObjCInterfaceDecl*, 32> Interfaces; @@ -1153,18 +1197,23 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); if (!IDecl) { // Not already seen? Make a forward decl. IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc, - IdentList[i], - // FIXME: need to get the 'real' - // identifier loc from the parser. - AtClassLoc, true); - PushOnScopeChains(IDecl, TUScope); + IdentList[i], IdentLocs[i], true); + + // Push the ObjCInterfaceDecl on the scope chain but do *not* add it to + // the current DeclContext. This prevents clients that walk DeclContext + // from seeing the imaginary ObjCInterfaceDecl until it is actually + // declared later (if at all). We also take care to explicitly make + // sure this declaration is visible for name lookup. + PushOnScopeChains(IDecl, TUScope, false); + CurContext->makeDeclVisibleInContext(IDecl, true); } Interfaces.push_back(IDecl); } + assert(Interfaces.size() == NumElts); ObjCClassDecl *CDecl = ObjCClassDecl::Create(Context, CurContext, AtClassLoc, - &Interfaces[0], + Interfaces.data(), IdentLocs, Interfaces.size()); CurContext->addDecl(CDecl); CheckObjCDeclScope(CDecl); @@ -1524,12 +1573,17 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl, // should be true. if (!ClassDecl) return; - + bool isInterfaceDeclKind = isa<ObjCInterfaceDecl>(ClassDecl) || isa<ObjCCategoryDecl>(ClassDecl) || isa<ObjCProtocolDecl>(ClassDecl); bool checkIdenticalMethods = isa<ObjCImplementationDecl>(ClassDecl); + if (!isInterfaceDeclKind && AtEndLoc.isInvalid()) { + AtEndLoc = ClassDecl->getLocation(); + Diag(AtEndLoc, diag::warn_missing_atend); + } + DeclContext *DC = dyn_cast<DeclContext>(ClassDecl); // FIXME: Remove these and use the ObjCContainerDecl/DeclContext. @@ -1608,8 +1662,10 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl, } if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) { IC->setAtEndLoc(AtEndLoc); - if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) + if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) { ImplMethodsVsClassMethods(IC, IDecl); + AtomicPropertySetterGetterRules(IC, IDecl); + } } else if (ObjCCategoryImplDecl* CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) { CatImplClass->setAtEndLoc(AtEndLoc); @@ -1910,13 +1966,12 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, // with continuation class's readwrite property attribute! unsigned PIkind = PIDecl->getPropertyAttributes(); if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) { - unsigned assignRetainCopyNonatomic = - (ObjCPropertyDecl::OBJC_PR_assign | - ObjCPropertyDecl::OBJC_PR_retain | + unsigned retainCopyNonatomic = + (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_copy | ObjCPropertyDecl::OBJC_PR_nonatomic); - if ((Attributes & assignRetainCopyNonatomic) != - (PIkind & assignRetainCopyNonatomic)) { + if ((Attributes & retainCopyNonatomic) != + (PIkind & retainCopyNonatomic)) { Diag(AtLoc, diag::warn_property_attr_mismatch); Diag(PIDecl->getLocation(), diag::note_property_declare); } diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index bdd00b84049d..25af0528d8b5 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -183,7 +183,7 @@ bool Sema::CheckExceptionSpecSubset( SubIsPointer = true; } bool SubIsClass = CanonicalSubT->isRecordType(); - CanonicalSubT = CanonicalSubT.getUnqualifiedType(); + CanonicalSubT = CanonicalSubT.getLocalUnqualifiedType(); CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, /*DetectVirtual=*/false); @@ -205,7 +205,7 @@ bool Sema::CheckExceptionSpecSubset( continue; } } - CanonicalSuperT = CanonicalSuperT.getUnqualifiedType(); + CanonicalSuperT = CanonicalSuperT.getLocalUnqualifiedType(); // If the types are the same, move on to the next type in the subset. if (CanonicalSubT == CanonicalSuperT) { Contained = true; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index f1d6f2bb17ce..4f08ffe9db94 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "Lookup.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" @@ -25,6 +26,7 @@ #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Designator.h" #include "clang/Parse/Scope.h" +#include "clang/Parse/Template.h" using namespace clang; @@ -622,14 +624,12 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, if (Name.getKind() == UnqualifiedId::IK_TemplateId) { ASTTemplateArgsPtr TemplateArgsPtr(*this, Name.TemplateId->getTemplateArgs(), - Name.TemplateId->getTemplateArgIsType(), Name.TemplateId->NumArgs); return ActOnTemplateIdExpr(SS, TemplateTy::make(Name.TemplateId->Template), Name.TemplateId->TemplateNameLoc, Name.TemplateId->LAngleLoc, TemplateArgsPtr, - Name.TemplateId->getTemplateArgLocations(), Name.TemplateId->RAngleLoc); } @@ -682,15 +682,11 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, isAddressOfOperand)); } - LookupResult Lookup; - LookupParsedName(Lookup, S, SS, Name, LookupOrdinaryName, false, true, Loc); + LookupResult Lookup(*this, Name, Loc, LookupOrdinaryName); + LookupParsedName(Lookup, S, SS, true); - if (Lookup.isAmbiguous()) { - DiagnoseAmbiguousLookup(Lookup, Name, Loc, - SS && SS->isSet() ? SS->getRange() - : SourceRange()); + if (Lookup.isAmbiguous()) return ExprError(); - } NamedDecl *D = Lookup.getAsSingleDecl(Context); @@ -814,22 +810,18 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, // information to check this property. if (Var->isDeclaredInCondition() && Var->getType()->isScalarType()) { Scope *CheckS = S; - while (CheckS) { + while (CheckS && CheckS->getControlParent()) { if (CheckS->isWithinElse() && CheckS->getControlParent()->isDeclScope(DeclPtrTy::make(Var))) { - if (Var->getType()->isBooleanType()) - ExprError(Diag(Loc, diag::warn_value_always_false) - << Var->getDeclName()); - else - ExprError(Diag(Loc, diag::warn_value_always_zero) - << Var->getDeclName()); + ExprError(Diag(Loc, diag::warn_value_always_zero) + << Var->getDeclName() + << (Var->getType()->isPointerType()? 2 : + Var->getType()->isBooleanType()? 1 : 0)); break; } - // Move up one more control parent to check again. - CheckS = CheckS->getControlParent(); - if (CheckS) - CheckS = CheckS->getParent(); + // Move to the parent of this scope. + CheckS = CheckS->getParent(); } } } else if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D)) { @@ -986,7 +978,7 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D, else if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) return BuildDeclRefExpr(Template, Context.OverloadTy, Loc, false, false, SS); - else if (UnresolvedUsingDecl *UD = dyn_cast<UnresolvedUsingDecl>(D)) + else if (UnresolvedUsingValueDecl *UD = dyn_cast<UnresolvedUsingValueDecl>(D)) return BuildDeclRefExpr(UD, Context.DependentTy, Loc, /*TypeDependent=*/true, /*ValueDependent=*/true, SS); @@ -1441,10 +1433,6 @@ QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc, bool isReal) { Action::OwningExprResult Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Kind, ExprArg Input) { - // Since this might be a postfix expression, get rid of ParenListExprs. - Input = MaybeConvertParenListExprToParenExpr(S, move(Input)); - Expr *Arg = (Expr *)Input.get(); - UnaryOperator::Opcode Opc; switch (Kind) { default: assert(0 && "Unknown unary op!"); @@ -1452,124 +1440,7 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, case tok::minusminus: Opc = UnaryOperator::PostDec; break; } - if (getLangOptions().CPlusPlus && - (Arg->getType()->isRecordType() || Arg->getType()->isEnumeralType())) { - // Which overloaded operator? - OverloadedOperatorKind OverOp = - (Opc == UnaryOperator::PostInc)? OO_PlusPlus : OO_MinusMinus; - - // C++ [over.inc]p1: - // - // [...] If the function is a member function with one - // parameter (which shall be of type int) or a non-member - // function with two parameters (the second of which shall be - // of type int), it defines the postfix increment operator ++ - // for objects of that type. When the postfix increment is - // called as a result of using the ++ operator, the int - // argument will have value zero. - Expr *Args[2] = { - Arg, - new (Context) IntegerLiteral(llvm::APInt(Context.Target.getIntWidth(), 0, - /*isSigned=*/true), Context.IntTy, SourceLocation()) - }; - - // Build the candidate set for overloading - OverloadCandidateSet CandidateSet; - AddOperatorCandidates(OverOp, S, OpLoc, Args, 2, CandidateSet); - - // Perform overload resolution. - OverloadCandidateSet::iterator Best; - switch (BestViableFunction(CandidateSet, OpLoc, Best)) { - case OR_Success: { - // We found a built-in operator or an overloaded operator. - FunctionDecl *FnDecl = Best->Function; - - if (FnDecl) { - // We matched an overloaded operator. Build a call to that - // operator. - - // Convert the arguments. - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { - if (PerformObjectArgumentInitialization(Arg, Method)) - return ExprError(); - } else { - // Convert the arguments. - if (PerformCopyInitialization(Arg, - FnDecl->getParamDecl(0)->getType(), - "passing")) - return ExprError(); - } - - // Determine the result type - QualType ResultTy = FnDecl->getResultType().getNonReferenceType(); - - // Build the actual expression node. - Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(), - SourceLocation()); - UsualUnaryConversions(FnExpr); - - Input.release(); - Args[0] = Arg; - - ExprOwningPtr<CXXOperatorCallExpr> - TheCall(this, new (Context) CXXOperatorCallExpr(Context, OverOp, - FnExpr, Args, 2, - ResultTy, OpLoc)); - - if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall.get(), - FnDecl)) - return ExprError(); - return Owned(TheCall.release()); - - } else { - // We matched a built-in operator. Convert the arguments, then - // break out so that we will build the appropriate built-in - // operator node. - if (PerformCopyInitialization(Arg, Best->BuiltinTypes.ParamTypes[0], - "passing")) - return ExprError(); - - break; - } - } - - case OR_No_Viable_Function: { - // No viable function; try checking this as a built-in operator, which - // will fail and provide a diagnostic. Then, print the overload - // candidates. - OwningExprResult Result = CreateBuiltinUnaryOp(OpLoc, Opc, move(Input)); - assert(Result.isInvalid() && - "C++ postfix-unary operator overloading is missing candidates!"); - if (Result.isInvalid()) - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); - - return move(Result); - } - - case OR_Ambiguous: - Diag(OpLoc, diag::err_ovl_ambiguous_oper) - << UnaryOperator::getOpcodeStr(Opc) - << Arg->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); - return ExprError(); - - case OR_Deleted: - Diag(OpLoc, diag::err_ovl_deleted_oper) - << Best->Function->isDeleted() - << UnaryOperator::getOpcodeStr(Opc) - << Arg->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); - return ExprError(); - } - - // Either we found no viable overloaded operator or we matched a - // built-in operator. In either case, fall through to trying to - // build a built-in operation. - } - - Input.release(); - Input = Arg; - return CreateBuiltinUnaryOp(OpLoc, Opc, move(Input)); + return BuildUnaryOp(S, OpLoc, Opc, move(Input)); } Action::OwningExprResult @@ -1886,6 +1757,38 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, DefaultFunctionArrayConversion(BaseExpr); QualType BaseType = BaseExpr->getType(); + + // If the user is trying to apply -> or . to a function pointer + // type, it's probably because the forgot parentheses to call that + // function. Suggest the addition of those parentheses, build the + // call, and continue on. + if (const PointerType *Ptr = BaseType->getAs<PointerType>()) { + if (const FunctionProtoType *Fun + = Ptr->getPointeeType()->getAs<FunctionProtoType>()) { + QualType ResultTy = Fun->getResultType(); + if (Fun->getNumArgs() == 0 && + ((OpKind == tok::period && ResultTy->isRecordType()) || + (OpKind == tok::arrow && ResultTy->isPointerType() && + ResultTy->getAs<PointerType>()->getPointeeType() + ->isRecordType()))) { + SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd()); + Diag(Loc, diag::err_member_reference_needs_call) + << QualType(Fun, 0) + << CodeModificationHint::CreateInsertion(Loc, "()"); + + OwningExprResult NewBase + = ActOnCallExpr(S, ExprArg(*this, BaseExpr), Loc, + MultiExprArg(*this, 0, 0), 0, Loc); + if (NewBase.isInvalid()) + return move(NewBase); + + BaseExpr = NewBase.takeAs<Expr>(); + DefaultFunctionArrayConversion(BaseExpr); + BaseType = BaseExpr->getType(); + } + } + } + // If this is an Objective-C pseudo-builtin and a definition is provided then // use that. if (BaseType->isObjCIdType()) { @@ -2048,17 +1951,14 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, } // The record definition is complete, now make sure the member is valid. - LookupResult Result; - LookupQualifiedName(Result, DC, MemberName, LookupMemberName, false); + LookupResult Result(*this, MemberName, MemberLoc, LookupMemberName); + LookupQualifiedName(Result, DC); if (Result.empty()) return ExprError(Diag(MemberLoc, diag::err_no_member) << MemberName << DC << BaseExpr->getSourceRange()); - if (Result.isAmbiguous()) { - DiagnoseAmbiguousLookup(Result, MemberName, MemberLoc, - BaseExpr->getSourceRange()); + if (Result.isAmbiguous()) return ExprError(); - } NamedDecl *MemberDecl = Result.getAsSingleDecl(Context); @@ -2356,16 +2256,6 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), MemberLoc, BaseExpr)); } - for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), - E = OPT->qual_end(); I != E; ++I) - if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) { - // Check whether we can reference this property. - if (DiagnoseUseOfDecl(PD, MemberLoc)) - return ExprError(); - - return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), - MemberLoc, BaseExpr)); - } // If that failed, look for an "implicit" property by seeing if the nullary // selector is implemented. @@ -2441,18 +2331,6 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union) << BaseType << BaseExpr->getSourceRange(); - // If the user is trying to apply -> or . to a function or function - // pointer, it's probably because they forgot parentheses to call - // the function. Suggest the addition of those parentheses. - if (BaseType == Context.OverloadTy || - BaseType->isFunctionType() || - (BaseType->isPointerType() && - BaseType->getAs<PointerType>()->isFunctionType())) { - SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd()); - Diag(Loc, diag::note_member_reference_needs_call) - << CodeModificationHint::CreateInsertion(Loc, "()"); - } - return ExprError(); } @@ -2485,12 +2363,10 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg Base, // Translate the parser's template argument list in our AST format. ASTTemplateArgsPtr TemplateArgsPtr(*this, Member.TemplateId->getTemplateArgs(), - Member.TemplateId->getTemplateArgIsType(), Member.TemplateId->NumArgs); llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs; translateTemplateArguments(TemplateArgsPtr, - Member.TemplateId->getTemplateArgLocations(), TemplateArgs); TemplateArgsPtr.release(); @@ -2639,6 +2515,9 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, // Pass the argument. if (PerformCopyInitialization(Arg, ProtoArgType, "passing")) return true; + + if (!ProtoArgType->isReferenceType()) + Arg = MaybeBindToTemporary(Arg).takeAs<Expr>(); } else { ParmVarDecl *Param = FDecl->getParamDecl(i); @@ -2663,7 +2542,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, CallType = VariadicMethod; // Promote the arguments (C99 6.5.2.2p7). - for (unsigned i = NumArgsInProto; i != NumArgs; i++) { + for (unsigned i = NumArgsInProto; i < NumArgs; i++) { Expr *Arg = Args[i]; Invalid |= DefaultVariadicArgumentPromotion(Arg, CallType); Call->setArg(i, Arg); @@ -3054,8 +2933,7 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist, static CastExpr::CastKind getScalarCastKind(ASTContext &Context, QualType SrcTy, QualType DestTy) { - if (Context.getCanonicalType(SrcTy).getUnqualifiedType() == - Context.getCanonicalType(DestTy).getUnqualifiedType()) + if (Context.hasSameUnqualifiedType(SrcTy, DestTy)) return CastExpr::CK_NoOp; if (SrcTy->hasPointerRepresentation()) { @@ -3106,8 +2984,7 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, } if (!castType->isScalarType() && !castType->isVectorType()) { - if (Context.getCanonicalType(castType).getUnqualifiedType() == - Context.getCanonicalType(castExpr->getType().getUnqualifiedType()) && + if (Context.hasSameUnqualifiedType(castType, castExpr->getType()) && (castType->isStructureType() || castType->isUnionType())) { // GCC struct/union extension: allow cast to self. // FIXME: Check that the cast destination type is complete. @@ -3123,8 +3000,8 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, RecordDecl::field_iterator Field, FieldEnd; for (Field = RD->field_begin(), FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) { - if (Context.getCanonicalType(Field->getType()).getUnqualifiedType() == - Context.getCanonicalType(castExpr->getType()).getUnqualifiedType()) { + if (Context.hasSameUnqualifiedType(Field->getType(), + castExpr->getType())) { Diag(TyR.getBegin(), diag::ext_typecheck_cast_to_union) << castExpr->getSourceRange(); break; @@ -3570,9 +3447,9 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, = Context.getQualifiedType(rhptee, lhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); // Add qualifiers if necessary. - ImpCastExprToType(LHS, destType, CastExpr::CK_NoOp); + ImpCastExprToType(RHS, destType, CastExpr::CK_NoOp); // Promote to void*. - ImpCastExprToType(RHS, destType, CastExpr::CK_BitCast); + ImpCastExprToType(LHS, destType, CastExpr::CK_BitCast); return destType; } @@ -3731,6 +3608,24 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { return ConvTy; return IncompatiblePointerSign; } + + // If we are a multi-level pointer, it's possible that our issue is simply + // one of qualification - e.g. char ** -> const char ** is not allowed. If + // the eventual target type is the same and the pointers have the same + // level of indirection, this must be the issue. + if (lhptee->isPointerType() && rhptee->isPointerType()) { + do { + lhptee = lhptee->getAs<PointerType>()->getPointeeType(); + rhptee = rhptee->getAs<PointerType>()->getPointeeType(); + + lhptee = Context.getCanonicalType(lhptee); + rhptee = Context.getCanonicalType(rhptee); + } while (lhptee->isPointerType() && rhptee->isPointerType()); + + if (Context.hasSameUnqualifiedType(lhptee, rhptee)) + return IncompatibleNestedPointerQualifiers; + } + // General pointer incompatibility takes priority over qualifiers. return IncompatiblePointer; } @@ -3757,7 +3652,7 @@ Sema::CheckBlockPointerTypesForAssignment(QualType lhsType, AssignConvertType ConvTy = Compatible; // For blocks we enforce that qualifiers are identical. - if (lhptee.getCVRQualifiers() != rhptee.getCVRQualifiers()) + if (lhptee.getLocalCVRQualifiers() != rhptee.getLocalCVRQualifiers()) ConvTy = CompatiblePointerDiscardsQualifiers; if (!Context.typesAreCompatible(lhptee, rhptee)) @@ -4429,26 +4324,51 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, return LHSTy; } -/// Implements -Wsign-compare. +/// \brief Implements -Wsign-compare. +/// +/// \param lex the left-hand expression +/// \param rex the right-hand expression +/// \param OpLoc the location of the joining operator +/// \param Equality whether this is an "equality-like" join, which +/// suppresses the warning in some cases void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc, - const PartialDiagnostic &PD) { + const PartialDiagnostic &PD, bool Equality) { + // Don't warn if we're in an unevaluated context. + if (ExprEvalContext == Unevaluated) + return; + QualType lt = lex->getType(), rt = rex->getType(); // Only warn if both operands are integral. if (!lt->isIntegerType() || !rt->isIntegerType()) return; + // If either expression is value-dependent, don't warn. We'll get another + // chance at instantiation time. + if (lex->isValueDependent() || rex->isValueDependent()) + return; + // The rule is that the signed operand becomes unsigned, so isolate the // signed operand. - Expr *signedOperand; + Expr *signedOperand, *unsignedOperand; if (lt->isSignedIntegerType()) { if (rt->isSignedIntegerType()) return; signedOperand = lex; + unsignedOperand = rex; } else { if (!rt->isSignedIntegerType()) return; signedOperand = rex; + unsignedOperand = lex; } + // If the unsigned type is strictly smaller than the signed type, + // then (1) the result type will be signed and (2) the unsigned + // value will fit fully within the signed type, and thus the result + // of the comparison will be exact. + if (Context.getIntWidth(signedOperand->getType()) > + Context.getIntWidth(unsignedOperand->getType())) + return; + // If the value is a non-negative integer constant, then the // signed->unsigned conversion won't change it. llvm::APSInt value; @@ -4459,6 +4379,20 @@ void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc, return; } + if (Equality) { + // For (in)equality comparisons, if the unsigned operand is a + // constant which cannot collide with a overflowed signed operand, + // then reinterpreting the signed operand as unsigned will not + // change the result of the comparison. + if (unsignedOperand->isIntegerConstantExpr(value, Context)) { + assert(!value.isSigned() && "result of unsigned expression is signed"); + + // 2's complement: test the top bit. + if (value.isNonNegative()) + return; + } + } + Diag(OpLoc, PD) << lex->getType() << rex->getType() << lex->getSourceRange() << rex->getSourceRange(); @@ -4472,7 +4406,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); + CheckSignCompare(lex, rex, Loc, diag::warn_mixed_sign_comparison, + (Opc == BinaryOperator::EQ || Opc == BinaryOperator::NE)); // C99 6.5.8p3 / C99 6.5.9p4 if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) @@ -5637,7 +5572,8 @@ Action::OwningExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, UnaryOperator::Opcode Opc, ExprArg input) { Expr *Input = (Expr*)input.get(); - if (getLangOptions().CPlusPlus && Input->getType()->isOverloadableType()) { + if (getLangOptions().CPlusPlus && Input->getType()->isOverloadableType() && + Opc != UnaryOperator::Extension) { // Find all of the overloaded operators visible from this // point. We perform both an operator-name lookup from the local // scope and an argument-dependent lookup based on the types of @@ -5814,8 +5750,8 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, } } - LookupResult R; - LookupQualifiedName(R, RD, OC.U.IdentInfo, LookupMemberName); + LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName); + LookupQualifiedName(R, RD); FieldDecl *MemberDecl = dyn_cast_or_null<FieldDecl>(R.getAsSingleDecl(Context)); @@ -5828,7 +5764,7 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, // FIXME: Verify that MemberDecl isn't a bitfield. if (cast<RecordDecl>(MemberDecl->getDeclContext())->isAnonymousStructOrUnion()) { Res = BuildAnonymousStructUnionMemberReference( - SourceLocation(), MemberDecl, Res, SourceLocation()).takeAs<Expr>(); + OC.LocEnd, MemberDecl, Res, OC.LocEnd).takeAs<Expr>(); } else { // MemberDecl->getType() doesn't get the right qualifiers, but it // doesn't matter here. @@ -6127,6 +6063,34 @@ Sema::OwningExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) { return Owned(new (Context) GNUNullExpr(Ty, TokenLoc)); } +static void +MakeObjCStringLiteralCodeModificationHint(Sema& SemaRef, + QualType DstType, + Expr *SrcExpr, + CodeModificationHint &Hint) { + if (!SemaRef.getLangOptions().ObjC1) + return; + + const ObjCObjectPointerType *PT = DstType->getAs<ObjCObjectPointerType>(); + if (!PT) + return; + + // Check if the destination is of type 'id'. + if (!PT->isObjCIdType()) { + // Check if the destination is the 'NSString' interface. + const ObjCInterfaceDecl *ID = PT->getInterfaceDecl(); + if (!ID || !ID->getIdentifier()->isStr("NSString")) + return; + } + + // Strip off any parens and casts. + StringLiteral *SL = dyn_cast<StringLiteral>(SrcExpr->IgnoreParenCasts()); + if (!SL || SL->isWide()) + return; + + Hint = CodeModificationHint::CreateInsertion(SL->getLocStart(), "@"); +} + bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, SourceLocation Loc, QualType DstType, QualType SrcType, @@ -6134,6 +6098,8 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, // Decode the result (notice that AST's are still created for extensions). bool isInvalid = false; unsigned DiagKind; + CodeModificationHint Hint; + switch (ConvTy) { default: assert(0 && "Unknown conversion type"); case Compatible: return false; @@ -6144,6 +6110,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, DiagKind = diag::ext_typecheck_convert_int_pointer; break; case IncompatiblePointer: + MakeObjCStringLiteralCodeModificationHint(*this, DstType, SrcExpr, Hint); DiagKind = diag::ext_typecheck_convert_incompatible_pointer; break; case IncompatiblePointerSign: @@ -6167,6 +6134,9 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, return false; DiagKind = diag::ext_typecheck_convert_discards_qualifiers; break; + case IncompatibleNestedPointerQualifiers: + DiagKind = diag::ext_nested_pointer_qualifier_mismatch; + break; case IntToBlockPointer: DiagKind = diag::err_int_to_block_pointer; break; @@ -6188,7 +6158,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, } Diag(Loc, DiagKind) << DstType << SrcType << Flavor - << SrcExpr->getSourceRange(); + << SrcExpr->getSourceRange() << Hint; return isInvalid; } @@ -6405,11 +6375,29 @@ bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc, void Sema::DiagnoseAssignmentAsCondition(Expr *E) { SourceLocation Loc; + unsigned diagnostic = diag::warn_condition_is_assignment; + if (isa<BinaryOperator>(E)) { BinaryOperator *Op = cast<BinaryOperator>(E); if (Op->getOpcode() != BinaryOperator::Assign) return; + // Greylist some idioms by putting them into a warning subcategory. + if (ObjCMessageExpr *ME + = dyn_cast<ObjCMessageExpr>(Op->getRHS()->IgnoreParenCasts())) { + Selector Sel = ME->getSelector(); + + // self = [<foo> init...] + if (isSelfExpr(Op->getLHS()) + && Sel.getIdentifierInfoForSlot(0)->getName().startswith("init")) + diagnostic = diag::warn_condition_is_idiomatic_assignment; + + // <foo> = [<bar> nextObject] + else if (Sel.isUnarySelector() && + Sel.getIdentifierInfoForSlot(0)->getName() == "nextObject") + diagnostic = diag::warn_condition_is_idiomatic_assignment; + } + Loc = Op->getOperatorLoc(); } else if (isa<CXXOperatorCallExpr>(E)) { CXXOperatorCallExpr *Op = cast<CXXOperatorCallExpr>(E); @@ -6425,7 +6413,7 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) { SourceLocation Open = E->getSourceRange().getBegin(); SourceLocation Close = PP.getLocForEndOfToken(E->getSourceRange().getEnd()); - Diag(Loc, diag::warn_condition_is_assignment) + Diag(Loc, diagnostic) << E->getSourceRange() << CodeModificationHint::CreateInsertion(Open, "(") << CodeModificationHint::CreateInsertion(Close, ")"); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index dc5768157356..0eea169b0727 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "Lookup.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/ExprCXX.h" @@ -34,8 +35,8 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, TyOrExpr = GetTypeFromParser(TyOrExpr).getAsOpaquePtr(); IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info"); - LookupResult R; - LookupQualifiedName(R, StdNamespace, TypeInfoII, LookupTagName); + LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName); + LookupQualifiedName(R, StdNamespace); Decl *TypeInfoDecl = R.getAsSingleDecl(Context); RecordDecl *TypeInfoRecordDecl = dyn_cast_or_null<RecordDecl>(TypeInfoDecl); if (!TypeInfoRecordDecl) @@ -424,14 +425,13 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, Expr **ConsArgs = (Expr**)ConstructorArgs.get(); const RecordType *RT; unsigned NumConsArgs = ConstructorArgs.size(); - + ASTOwningVector<&ActionBase::DeleteExpr> ConvertedConstructorArgs(*this); + if (AllocType->isDependentType() || Expr::hasAnyTypeDependentArguments(ConsArgs, NumConsArgs)) { // Skip all the checks. } else if ((RT = AllocType->getAs<RecordType>()) && !AllocType->isAggregateType()) { - ASTOwningVector<&ActionBase::DeleteExpr> ConvertedConstructorArgs(*this); - Constructor = PerformInitializationByConstructor( AllocType, move(ConstructorArgs), TypeLoc, @@ -568,8 +568,8 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, DeclarationName Name, Expr** Args, unsigned NumArgs, DeclContext *Ctx, bool AllowMissing, FunctionDecl *&Operator) { - LookupResult R; - LookupQualifiedName(R, Ctx, Name, LookupOrdinaryName); + LookupResult R(*this, Name, StartLoc, LookupOrdinaryName); + LookupQualifiedName(R, Ctx); if (R.empty()) { if (AllowMissing) return false; @@ -754,6 +754,57 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, ((DeclContext *)TUScope->getEntity())->addDecl(Alloc); } +bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, + DeclarationName Name, + FunctionDecl* &Operator) { + LookupResult Found(*this, Name, StartLoc, LookupOrdinaryName); + // Try to find operator delete/operator delete[] in class scope. + LookupQualifiedName(Found, RD); + + if (Found.isAmbiguous()) + return true; + + for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); + F != FEnd; ++F) { + if (CXXMethodDecl *Delete = dyn_cast<CXXMethodDecl>(*F)) + if (Delete->isUsualDeallocationFunction()) { + Operator = Delete; + return false; + } + } + + // We did find operator delete/operator delete[] declarations, but + // none of them were suitable. + if (!Found.empty()) { + Diag(StartLoc, diag::err_no_suitable_delete_member_function_found) + << Name << RD; + + for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); + F != FEnd; ++F) { + Diag((*F)->getLocation(), + diag::note_delete_member_function_declared_here) + << Name; + } + + return true; + } + + // Look for a global declaration. + DeclareGlobalNewDelete(); + DeclContext *TUDecl = Context.getTranslationUnitDecl(); + + CXXNullPtrLiteralExpr Null(Context.VoidPtrTy, SourceLocation()); + Expr* DeallocArgs[1]; + DeallocArgs[0] = &Null; + if (FindAllocationOverload(StartLoc, SourceRange(), Name, + DeallocArgs, 1, TUDecl, /*AllowMissing=*/false, + Operator)) + return true; + + assert(Operator && "Did not find a deallocation function!"); + return false; +} + /// ActOnCXXDelete - Parsed a C++ 'delete' expression (C++ 5.3.5), as in: /// @code ::delete ptr; @endcode /// or @@ -845,32 +896,21 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( ArrayForm ? OO_Array_Delete : OO_Delete); - if (Pointee->isRecordType() && !UseGlobal) { - CXXRecordDecl *Record - = cast<CXXRecordDecl>(Pointee->getAs<RecordType>()->getDecl()); - - // Try to find operator delete/operator delete[] in class scope. - LookupResult Found; - LookupQualifiedName(Found, Record, DeleteName, LookupOrdinaryName); - // FIXME: Diagnose ambiguity properly - assert(!Found.isAmbiguous() && "Ambiguous delete/delete[] not handled"); - for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); - F != FEnd; ++F) { - if (CXXMethodDecl *Delete = dyn_cast<CXXMethodDecl>(*F)) - if (Delete->isUsualDeallocationFunction()) { - OperatorDelete = Delete; - break; - } - } + if (const RecordType *RT = Pointee->getAs<RecordType>()) { + CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + + if (!UseGlobal && + FindDeallocationFunction(StartLoc, RD, DeleteName, OperatorDelete)) + return ExprError(); - if (!Record->hasTrivialDestructor()) - if (const CXXDestructorDecl *Dtor = Record->getDestructor(Context)) + if (!RD->hasTrivialDestructor()) + if (const CXXDestructorDecl *Dtor = RD->getDestructor(Context)) MarkDeclarationReferenced(StartLoc, const_cast<CXXDestructorDecl*>(Dtor)); } - + if (!OperatorDelete) { - // Didn't find a member overload. Look for a global one. + // Look for a global declaration. DeclareGlobalNewDelete(); DeclContext *TUDecl = Context.getTranslationUnitDecl(); if (FindAllocationOverload(StartLoc, SourceRange(), DeleteName, @@ -1064,10 +1104,11 @@ Sema::BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind, bool Sema::PerformImplicitConversion(Expr *&From, QualType ToType, const ImplicitConversionSequence &ICS, - const char* Flavor) { + const char* Flavor, bool IgnoreBaseAccess) { switch (ICS.ConversionKind) { case ImplicitConversionSequence::StandardConversion: - if (PerformImplicitConversion(From, ToType, ICS.Standard, Flavor)) + if (PerformImplicitConversion(From, ToType, ICS.Standard, Flavor, + IgnoreBaseAccess)) return true; break; @@ -1086,18 +1127,22 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, } else if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(FD)) { CastKind = CastExpr::CK_ConstructorConversion; - - // If the user-defined conversion is specified by a constructor, the - // initial standard conversion sequence converts the source type to the - // type required by the argument of the constructor - BeforeToType = Ctor->getParamDecl(0)->getType(); + // Do no conversion if dealing with ... for the first conversion. + if (!ICS.UserDefined.EllipsisConversion) + // If the user-defined conversion is specified by a constructor, the + // initial standard conversion sequence converts the source type to the + // type required by the argument of the constructor + BeforeToType = Ctor->getParamDecl(0)->getType(); } else assert(0 && "Unknown conversion function kind!"); - - if (PerformImplicitConversion(From, BeforeToType, - ICS.UserDefined.Before, "converting")) - return true; + // Whatch out for elipsis conversion. + if (!ICS.UserDefined.EllipsisConversion) { + if (PerformImplicitConversion(From, BeforeToType, + ICS.UserDefined.Before, "converting", + IgnoreBaseAccess)) + return true; + } OwningExprResult CastArg = BuildCXXCastArgument(From->getLocStart(), @@ -1145,7 +1190,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, bool Sema::PerformImplicitConversion(Expr *&From, QualType ToType, const StandardConversionSequence& SCS, - const char *Flavor) { + const char *Flavor, bool IgnoreBaseAccess) { // Overall FIXME: we are recomputing too many types here and doing far too // much extra work. What this means is that we need to keep track of more // information that is computed when we try the implicit conversion initially, @@ -1273,7 +1318,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, CastExpr::CastKind Kind = CastExpr::CK_Unknown; - if (CheckPointerConversion(From, ToType, Kind)) + if (CheckPointerConversion(From, ToType, Kind, IgnoreBaseAccess)) return true; ImpCastExprToType(From, ToType, Kind); break; @@ -1281,7 +1326,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, case ICK_Pointer_Member: { CastExpr::CastKind Kind = CastExpr::CK_Unknown; - if (CheckMemberPointerConversion(From, ToType, Kind)) + if (CheckMemberPointerConversion(From, ToType, Kind, IgnoreBaseAccess)) return true; if (CheckExceptionSpecCompatibility(From, ToType)) return true; @@ -1292,6 +1337,17 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, ImpCastExprToType(From, Context.BoolTy, CastExpr::CK_Unknown); break; + case ICK_Derived_To_Base: + if (CheckDerivedToBaseConversion(From->getType(), + ToType.getNonReferenceType(), + From->getLocStart(), + From->getSourceRange(), + IgnoreBaseAccess)) + return true; + ImpCastExprToType(From, ToType.getNonReferenceType(), + CastExpr::CK_DerivedToBase); + break; + default: assert(false && "Improper second standard conversion"); break; @@ -1309,7 +1365,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, CastExpr::CK_NoOp, ToType->isLValueReferenceType()); break; - + default: assert(false && "Improper second standard conversion"); break; @@ -1374,8 +1430,7 @@ QualType Sema::CheckPointerToMemberOperands( } } - if (Context.getCanonicalType(Class).getUnqualifiedType() != - Context.getCanonicalType(LType).getUnqualifiedType()) { + if (!Context.hasSameUnqualifiedType(Class, LType)) { CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, /*DetectVirtual=*/false); // FIXME: Would it be useful to print full ambiguity paths, or is that @@ -1827,8 +1882,6 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { !T2->isPointerType() && !T2->isMemberPointerType()) return QualType(); - // FIXME: Do we need to work on the canonical types? - // C++0x 5.9p2 // Pointer conversions and qualification conversions are performed on // pointer operands to bring them to their composite pointer type. If @@ -1850,8 +1903,8 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { } // Now both have to be pointers or member pointers. - if (!T1->isPointerType() && !T1->isMemberPointerType() && - !T2->isPointerType() && !T2->isMemberPointerType()) + if ((!T1->isPointerType() && !T1->isMemberPointerType()) || + (!T2->isPointerType() && !T2->isMemberPointerType())) return QualType(); // Otherwise, of one of the operands has type "pointer to cv1 void," then @@ -1865,9 +1918,13 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { // conversions in both directions. If only one works, or if the two composite // types are the same, we have succeeded. // FIXME: extended qualifiers? - llvm::SmallVector<unsigned, 4> QualifierUnion; - llvm::SmallVector<std::pair<const Type *, const Type *>, 4> MemberOfClass; - QualType Composite1 = T1, Composite2 = T2; + typedef llvm::SmallVector<unsigned, 4> QualifierVector; + QualifierVector QualifierUnion; + typedef llvm::SmallVector<std::pair<const Type *, const Type *>, 4> + ContainingClassVector; + ContainingClassVector MemberOfClass; + QualType Composite1 = Context.getCanonicalType(T1), + Composite2 = Context.getCanonicalType(T2); do { const PointerType *Ptr1, *Ptr2; if ((Ptr1 = Composite1->getAs<PointerType>()) && @@ -1899,11 +1956,11 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { } while (true); // Rewrap the composites as pointers or member pointers with the union CVRs. - llvm::SmallVector<std::pair<const Type *, const Type *>, 4>::iterator MOC - = MemberOfClass.begin(); - for (llvm::SmallVector<unsigned, 4>::iterator - I = QualifierUnion.begin(), - E = QualifierUnion.end(); + ContainingClassVector::reverse_iterator MOC + = MemberOfClass.rbegin(); + for (QualifierVector::reverse_iterator + I = QualifierUnion.rbegin(), + E = QualifierUnion.rend(); I != E; (void)++I, ++MOC) { Qualifiers Quals = Qualifiers::fromCVRMask(*I); if (MOC->first && MOC->second) { @@ -2085,12 +2142,19 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, return move(Base); } + // The object type must be complete (or dependent). + if (!BaseType->isDependentType() && + RequireCompleteType(OpLoc, BaseType, + PDiag(diag::err_incomplete_member_access))) + return ExprError(); + // C++ [basic.lookup.classref]p2: // If the id-expression in a class member access (5.2.5) is an - // unqualified-id, and the type of the object expres- sion is of a class + // unqualified-id, and the type of the object expression is of a class // type C (or of pointer to a class type C), the unqualified-id is looked // up in the scope of class C. [...] ObjectType = BaseType.getAsOpaquePtr(); + return move(Base); } @@ -2108,7 +2172,7 @@ CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, CXXMemberCallExpr *CE = new (Context) CXXMemberCallExpr(Context, ME, 0, 0, ResultType, - SourceLocation()); + Exp->getLocEnd()); return CE; } diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 4746a2597e55..0f973d6d9ba3 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -174,7 +174,8 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType, // copy-initialization where the cv-unqualified version of the // source type is the same class as, or a derived class of, the // class of the destination, constructors are considered. - if ((DeclTypeC.getUnqualifiedType() == InitTypeC.getUnqualifiedType()) || + if ((DeclTypeC.getLocalUnqualifiedType() + == InitTypeC.getLocalUnqualifiedType()) || IsDerivedFrom(InitTypeC, DeclTypeC)) { const CXXRecordDecl *RD = cast<CXXRecordDecl>(DeclType->getAs<RecordType>()->getDecl()); diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 93752e130c94..1f49b789d3f0 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// #include "Sema.h" +#include "Lookup.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/Decl.h" @@ -34,77 +35,161 @@ using namespace clang; -typedef llvm::SmallVector<UsingDirectiveDecl*, 4> UsingDirectivesTy; -typedef llvm::DenseSet<NamespaceDecl*> NamespaceSet; +namespace { + class UnqualUsingEntry { + const DeclContext *Nominated; + const DeclContext *CommonAncestor; -/// UsingDirAncestorCompare - Implements strict weak ordering of -/// UsingDirectives. It orders them by address of its common ancestor. -struct UsingDirAncestorCompare { + public: + UnqualUsingEntry(const DeclContext *Nominated, + const DeclContext *CommonAncestor) + : Nominated(Nominated), CommonAncestor(CommonAncestor) { + } - /// @brief Compares UsingDirectiveDecl common ancestor with DeclContext. - bool operator () (UsingDirectiveDecl *U, const DeclContext *Ctx) const { - return U->getCommonAncestor() < Ctx; - } + const DeclContext *getCommonAncestor() const { + return CommonAncestor; + } - /// @brief Compares UsingDirectiveDecl common ancestor with DeclContext. - bool operator () (const DeclContext *Ctx, UsingDirectiveDecl *U) const { - return Ctx < U->getCommonAncestor(); - } + const DeclContext *getNominatedNamespace() const { + return Nominated; + } - /// @brief Compares UsingDirectiveDecl common ancestors. - bool operator () (UsingDirectiveDecl *U1, UsingDirectiveDecl *U2) const { - return U1->getCommonAncestor() < U2->getCommonAncestor(); - } -}; - -/// AddNamespaceUsingDirectives - Adds all UsingDirectiveDecl's to heap UDirs -/// (ordered by common ancestors), found in namespace NS, -/// including all found (recursively) in their nominated namespaces. -void AddNamespaceUsingDirectives(ASTContext &Context, - DeclContext *NS, - UsingDirectivesTy &UDirs, - NamespaceSet &Visited) { - DeclContext::udir_iterator I, End; - - for (llvm::tie(I, End) = NS->getUsingDirectives(); I !=End; ++I) { - UDirs.push_back(*I); - std::push_heap(UDirs.begin(), UDirs.end(), UsingDirAncestorCompare()); - NamespaceDecl *Nominated = (*I)->getNominatedNamespace(); - if (Visited.insert(Nominated).second) - AddNamespaceUsingDirectives(Context, Nominated, UDirs, /*ref*/ Visited); - } -} + // Sort by the pointer value of the common ancestor. + struct Comparator { + bool operator()(const UnqualUsingEntry &L, const UnqualUsingEntry &R) { + return L.getCommonAncestor() < R.getCommonAncestor(); + } -/// AddScopeUsingDirectives - Adds all UsingDirectiveDecl's found in Scope S, -/// including all found in the namespaces they nominate. -static void AddScopeUsingDirectives(ASTContext &Context, Scope *S, - UsingDirectivesTy &UDirs) { - NamespaceSet VisitedNS; + bool operator()(const UnqualUsingEntry &E, const DeclContext *DC) { + return E.getCommonAncestor() < DC; + } - if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) { + bool operator()(const DeclContext *DC, const UnqualUsingEntry &E) { + return DC < E.getCommonAncestor(); + } + }; + }; + + /// A collection of using directives, as used by C++ unqualified + /// lookup. + class UnqualUsingDirectiveSet { + typedef llvm::SmallVector<UnqualUsingEntry, 8> ListTy; + + ListTy list; + llvm::SmallPtrSet<DeclContext*, 8> visited; + + public: + UnqualUsingDirectiveSet() {} + + void visitScopeChain(Scope *S, Scope *InnermostFileScope) { + // C++ [namespace.udir]p1: + // During unqualified name lookup, the names appear as if they + // were declared in the nearest enclosing namespace which contains + // both the using-directive and the nominated namespace. + DeclContext *InnermostFileDC + = static_cast<DeclContext*>(InnermostFileScope->getEntity()); + assert(InnermostFileDC && InnermostFileDC->isFileContext()); + + for (; S; S = S->getParent()) { + if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) { + DeclContext *EffectiveDC = (Ctx->isFileContext() ? Ctx : InnermostFileDC); + visit(Ctx, EffectiveDC); + } else { + Scope::udir_iterator I = S->using_directives_begin(), + End = S->using_directives_end(); + + for (; I != End; ++I) + visit(I->getAs<UsingDirectiveDecl>(), InnermostFileDC); + } + } + } - if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(Ctx)) - VisitedNS.insert(NS); + // Visits a context and collect all of its using directives + // recursively. Treats all using directives as if they were + // declared in the context. + // + // A given context is only every visited once, so it is important + // that contexts be visited from the inside out in order to get + // the effective DCs right. + void visit(DeclContext *DC, DeclContext *EffectiveDC) { + if (!visited.insert(DC)) + return; + + addUsingDirectives(DC, EffectiveDC); + } - AddNamespaceUsingDirectives(Context, Ctx, UDirs, /*ref*/ VisitedNS); + // Visits a using directive and collects all of its using + // directives recursively. Treats all using directives as if they + // were declared in the effective DC. + void visit(UsingDirectiveDecl *UD, DeclContext *EffectiveDC) { + DeclContext *NS = UD->getNominatedNamespace(); + if (!visited.insert(NS)) + return; - } else { - Scope::udir_iterator I = S->using_directives_begin(), - End = S->using_directives_end(); - - for (; I != End; ++I) { - UsingDirectiveDecl *UD = I->getAs<UsingDirectiveDecl>(); - UDirs.push_back(UD); - std::push_heap(UDirs.begin(), UDirs.end(), UsingDirAncestorCompare()); - - NamespaceDecl *Nominated = UD->getNominatedNamespace(); - if (!VisitedNS.count(Nominated)) { - VisitedNS.insert(Nominated); - AddNamespaceUsingDirectives(Context, Nominated, UDirs, - /*ref*/ VisitedNS); + addUsingDirective(UD, EffectiveDC); + addUsingDirectives(NS, EffectiveDC); + } + + // Adds all the using directives in a context (and those nominated + // by its using directives, transitively) as if they appeared in + // the given effective context. + void addUsingDirectives(DeclContext *DC, DeclContext *EffectiveDC) { + llvm::SmallVector<DeclContext*,4> queue; + while (true) { + DeclContext::udir_iterator I, End; + for (llvm::tie(I, End) = DC->getUsingDirectives(); I != End; ++I) { + UsingDirectiveDecl *UD = *I; + DeclContext *NS = UD->getNominatedNamespace(); + if (visited.insert(NS)) { + addUsingDirective(UD, EffectiveDC); + queue.push_back(NS); + } + } + + if (queue.empty()) + return; + + DC = queue.back(); + queue.pop_back(); } } - } + + // Add a using directive as if it had been declared in the given + // context. This helps implement C++ [namespace.udir]p3: + // The using-directive is transitive: if a scope contains a + // using-directive that nominates a second namespace that itself + // contains using-directives, the effect is as if the + // using-directives from the second namespace also appeared in + // the first. + void addUsingDirective(UsingDirectiveDecl *UD, DeclContext *EffectiveDC) { + // Find the common ancestor between the effective context and + // the nominated namespace. + DeclContext *Common = UD->getNominatedNamespace(); + while (!Common->Encloses(EffectiveDC)) + Common = Common->getParent(); + Common = Common->getPrimaryContext(); + + list.push_back(UnqualUsingEntry(UD->getNominatedNamespace(), Common)); + } + + void done() { + std::sort(list.begin(), list.end(), UnqualUsingEntry::Comparator()); + } + + typedef ListTy::iterator iterator; + typedef ListTy::const_iterator const_iterator; + + iterator begin() { return list.begin(); } + iterator end() { return list.end(); } + const_iterator begin() const { return list.begin(); } + const_iterator end() const { return list.end(); } + + std::pair<const_iterator,const_iterator> + getNamespacesFor(DeclContext *DC) const { + return std::equal_range(begin(), end(), DC->getPrimaryContext(), + UnqualUsingEntry::Comparator()); + } + }; } // Retrieve the set of identifier namespaces that correspond to a @@ -153,42 +238,50 @@ getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind, } // Necessary because CXXBasePaths is not complete in Sema.h -void Sema::LookupResult::deletePaths(CXXBasePaths *Paths) { +void LookupResult::deletePaths(CXXBasePaths *Paths) { delete Paths; } -void Sema::LookupResult::resolveKind() { +void LookupResult::resolveKind() { unsigned N = Decls.size(); // Fast case: no possible ambiguity. - if (N <= 1) return; + if (N == 0) return; + if (N == 1) { + if (isa<UnresolvedUsingValueDecl>(Decls[0])) + ResultKind = FoundUnresolvedValue; + return; + } // Don't do any extra resolution if we've already resolved as ambiguous. - if (Kind == Ambiguous) return; + if (ResultKind == Ambiguous) return; llvm::SmallPtrSet<NamedDecl*, 16> Unique; bool Ambiguous = false; bool HasTag = false, HasFunction = false, HasNonFunction = false; + bool HasUnresolved = false; unsigned UniqueTagIndex = 0; unsigned I = 0; while (I < N) { - NamedDecl *D = Decls[I]; - assert(D == D->getUnderlyingDecl()); + NamedDecl *D = Decls[I]->getUnderlyingDecl(); + D = cast<NamedDecl>(D->getCanonicalDecl()); - NamedDecl *CanonD = cast<NamedDecl>(D->getCanonicalDecl()); - if (!Unique.insert(CanonD)) { + if (!Unique.insert(D)) { // If it's not unique, pull something off the back (and // continue at this index). Decls[I] = Decls[--N]; - } else if (isa<UnresolvedUsingDecl>(D)) { - // FIXME: proper support for UnresolvedUsingDecls. + } else if (isa<UnresolvedUsingValueDecl>(D)) { + // FIXME: support unresolved using value declarations Decls[I] = Decls[--N]; } else { // Otherwise, do some decl type analysis and then continue. - if (isa<TagDecl>(D)) { + + if (isa<UnresolvedUsingValueDecl>(D)) { + HasUnresolved = true; + } else if (isa<TagDecl>(D)) { if (HasTag) Ambiguous = true; UniqueTagIndex = I; @@ -213,7 +306,8 @@ void Sema::LookupResult::resolveKind() { // wherever the object, function, or enumerator name is visible. // But it's still an error if there are distinct tag types found, // even if they're not visible. (ref?) - if (HasTag && !Ambiguous && (HasFunction || HasNonFunction)) + if (HideTags && HasTag && !Ambiguous && !HasUnresolved && + (HasFunction || HasNonFunction)) Decls[UniqueTagIndex] = Decls[--N]; Decls.set_size(N); @@ -223,10 +317,12 @@ void Sema::LookupResult::resolveKind() { if (Ambiguous) setAmbiguous(LookupResult::AmbiguousReference); + else if (HasUnresolved) + ResultKind = LookupResult::FoundUnresolvedValue; else if (N > 1) - Kind = LookupResult::FoundOverloaded; + ResultKind = LookupResult::FoundOverloaded; else - Kind = LookupResult::Found; + ResultKind = LookupResult::Found; } /// @brief Converts the result of name lookup into a single (possible @@ -242,10 +338,10 @@ void Sema::LookupResult::resolveKind() { /// solution, since it causes the OverloadedFunctionDecl to be /// leaked. FIXME: Eventually, there will be a better way to iterate /// over the set of overloaded functions returned by name lookup. -NamedDecl *Sema::LookupResult::getAsSingleDecl(ASTContext &C) const { +NamedDecl *LookupResult::getAsSingleDecl(ASTContext &C) const { size_t size = Decls.size(); if (size == 0) return 0; - if (size == 1) return *begin(); + if (size == 1) return (*begin())->getUnderlyingDecl(); if (isAmbiguous()) return 0; @@ -255,9 +351,7 @@ NamedDecl *Sema::LookupResult::getAsSingleDecl(ASTContext &C) const { = OverloadedFunctionDecl::Create(C, (*I)->getDeclContext(), (*I)->getDeclName()); for (; I != E; ++I) { - NamedDecl *ND = *I; - assert(ND->getUnderlyingDecl() == ND - && "decls in lookup result should have redirections stripped"); + NamedDecl *ND = (*I)->getUnderlyingDecl(); assert(ND->isFunctionOrFunctionTemplate()); if (isa<FunctionDecl>(ND)) Ovl->addOverload(cast<FunctionDecl>(ND)); @@ -269,7 +363,7 @@ NamedDecl *Sema::LookupResult::getAsSingleDecl(ASTContext &C) const { return Ovl; } -void Sema::LookupResult::addDeclsFromBasePaths(const CXXBasePaths &P) { +void LookupResult::addDeclsFromBasePaths(const CXXBasePaths &P) { CXXBasePaths::paths_iterator I, E; DeclContext::lookup_iterator DI, DE; for (I = P.begin(), E = P.end(); I != E; ++I) @@ -277,7 +371,7 @@ void Sema::LookupResult::addDeclsFromBasePaths(const CXXBasePaths &P) { addDecl(*DI); } -void Sema::LookupResult::setAmbiguousBaseSubobjects(CXXBasePaths &P) { +void LookupResult::setAmbiguousBaseSubobjects(CXXBasePaths &P) { Paths = new CXXBasePaths; Paths->swap(P); addDeclsFromBasePaths(*Paths); @@ -285,7 +379,7 @@ void Sema::LookupResult::setAmbiguousBaseSubobjects(CXXBasePaths &P) { setAmbiguous(AmbiguousBaseSubobjects); } -void Sema::LookupResult::setAmbiguousBaseSubobjectTypes(CXXBasePaths &P) { +void LookupResult::setAmbiguousBaseSubobjectTypes(CXXBasePaths &P) { Paths = new CXXBasePaths; Paths->swap(P); addDeclsFromBasePaths(*Paths); @@ -293,7 +387,7 @@ void Sema::LookupResult::setAmbiguousBaseSubobjectTypes(CXXBasePaths &P) { setAmbiguous(AmbiguousBaseSubobjectTypes); } -void Sema::LookupResult::print(llvm::raw_ostream &Out) { +void LookupResult::print(llvm::raw_ostream &Out) { Out << Decls.size() << " result(s)"; if (isAmbiguous()) Out << ", ambiguous"; if (Paths) Out << ", base paths present"; @@ -306,42 +400,36 @@ void Sema::LookupResult::print(llvm::raw_ostream &Out) { // Adds all qualifying matches for a name within a decl context to the // given lookup result. Returns true if any matches were found. -static bool LookupDirect(Sema::LookupResult &R, DeclContext *DC, - DeclarationName Name, - Sema::LookupNameKind NameKind, - unsigned IDNS) { +static bool LookupDirect(LookupResult &R, const DeclContext *DC) { bool Found = false; - DeclContext::lookup_iterator I, E; - for (llvm::tie(I, E) = DC->lookup(Name); I != E; ++I) - if (Sema::isAcceptableLookupResult(*I, NameKind, IDNS)) + DeclContext::lookup_const_iterator I, E; + for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) + if (Sema::isAcceptableLookupResult(*I, R.getLookupKind(), + R.getIdentifierNamespace())) R.addDecl(*I), Found = true; return Found; } +// Performs C++ unqualified lookup into the given file context. static bool -CppNamespaceLookup(Sema::LookupResult &R, ASTContext &Context, DeclContext *NS, - DeclarationName Name, Sema::LookupNameKind NameKind, - unsigned IDNS, UsingDirectivesTy *UDirs = 0) { +CppNamespaceLookup(LookupResult &R, ASTContext &Context, DeclContext *NS, + UnqualUsingDirectiveSet &UDirs) { assert(NS && NS->isFileContext() && "CppNamespaceLookup() requires namespace!"); - // Perform qualified name lookup into the LookupCtx. - bool Found = LookupDirect(R, NS, Name, NameKind, IDNS); - - if (UDirs) { - // For each UsingDirectiveDecl, which common ancestor is equal - // to NS, we preform qualified name lookup into namespace nominated by it. - UsingDirectivesTy::const_iterator UI, UEnd; - llvm::tie(UI, UEnd) = - std::equal_range(UDirs->begin(), UDirs->end(), NS, - UsingDirAncestorCompare()); - - for (; UI != UEnd; ++UI) - if (LookupDirect(R, (*UI)->getNominatedNamespace(), Name, NameKind, IDNS)) - Found = true; - } + // Perform direct name lookup into the LookupCtx. + bool Found = LookupDirect(R, NS); + + // Perform direct name lookup into the namespaces nominated by the + // using directives whose common ancestor is this namespace. + UnqualUsingDirectiveSet::const_iterator UI, UEnd; + llvm::tie(UI, UEnd) = UDirs.getNamespacesFor(NS); + + for (; UI != UEnd; ++UI) + if (LookupDirect(R, UI->getNominatedNamespace())) + Found = true; R.resolveKind(); @@ -363,20 +451,23 @@ static DeclContext *findOuterContext(Scope *S) { return 0; } -bool -Sema::CppLookupName(LookupResult &R, Scope *S, DeclarationName Name, - LookupNameKind NameKind, bool RedeclarationOnly) { +bool Sema::CppLookupName(LookupResult &R, Scope *S) { assert(getLangOptions().CPlusPlus && "Can perform only C++ lookup"); + LookupNameKind NameKind = R.getLookupKind(); unsigned IDNS = getIdentifierNamespacesFromLookupNameKind(NameKind, /*CPlusPlus*/ true); // If we're testing for redeclarations, also look in the friend namespaces. - if (RedeclarationOnly) { + if (R.isForRedeclaration()) { if (IDNS & Decl::IDNS_Tag) IDNS |= Decl::IDNS_TagFriend; if (IDNS & Decl::IDNS_Ordinary) IDNS |= Decl::IDNS_OrdinaryFriend; } + R.setIdentifierNamespace(IDNS); + + DeclarationName Name = R.getLookupName(); + Scope *Initial = S; IdentifierResolver::iterator I = IdResolver.begin(Name), @@ -427,24 +518,25 @@ Sema::CppLookupName(LookupResult &R, Scope *S, DeclarationName Name, // example, inside a class without any base classes, we never need to // perform qualified lookup because all of the members are on top of the // identifier chain. - if (LookupQualifiedName(R, Ctx, Name, NameKind, RedeclarationOnly)) + if (LookupQualifiedName(R, Ctx)) return true; } } } + // Stop if we ran out of scopes. + // FIXME: This really, really shouldn't be happening. + if (!S) return false; + // Collect UsingDirectiveDecls in all scopes, and recursively all // nominated namespaces by those using-directives. - // UsingDirectives are pushed to heap, in common ancestor pointer value order. + // // FIXME: Cache this sorted list in Scope structure, and DeclContext, so we // don't build it for each lookup! - UsingDirectivesTy UDirs; - for (Scope *SC = Initial; SC; SC = SC->getParent()) - if (SC->getFlags() & Scope::DeclScope) - AddScopeUsingDirectives(Context, SC, UDirs); - // Sort heapified UsingDirectiveDecls. - std::sort_heap(UDirs.begin(), UDirs.end(), UsingDirAncestorCompare()); + UnqualUsingDirectiveSet UDirs; + UDirs.visitScopeChain(Initial, S); + UDirs.done(); // Lookup namespace scope, and global scope. // Unqualified name lookup in C++ requires looking into scopes @@ -473,7 +565,7 @@ Sema::CppLookupName(LookupResult &R, Scope *S, DeclarationName Name, } // Look into context considering using-directives. - if (CppNamespaceLookup(R, Context, Ctx, Name, NameKind, IDNS, &UDirs)) + if (CppNamespaceLookup(R, Context, Ctx, UDirs)) Found = true; if (Found) { @@ -481,7 +573,7 @@ Sema::CppLookupName(LookupResult &R, Scope *S, DeclarationName Name, return true; } - if (RedeclarationOnly && !Ctx->isTransparentContext()) + if (R.isForRedeclaration() && !Ctx->isTransparentContext()) return false; } @@ -519,11 +611,12 @@ Sema::CppLookupName(LookupResult &R, Scope *S, DeclarationName Name, /// @returns The result of name lookup, which includes zero or more /// declarations and possibly additional information used to diagnose /// ambiguities. -bool Sema::LookupName(LookupResult &R, Scope *S, DeclarationName Name, - LookupNameKind NameKind, bool RedeclarationOnly, - bool AllowBuiltinCreation, SourceLocation Loc) { +bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { + DeclarationName Name = R.getLookupName(); if (!Name) return false; + LookupNameKind NameKind = R.getLookupKind(); + if (!getLangOptions().CPlusPlus) { // Unqualified name lookup in C/Objective-C is purely lexical, so // search in the declarations attached to the name. @@ -619,7 +712,7 @@ bool Sema::LookupName(LookupResult &R, Scope *S, DeclarationName Name, } } else { // Perform C++ unqualified name lookup. - if (CppLookupName(R, S, Name, NameKind, RedeclarationOnly)) + if (CppLookupName(R, S)) return true; } @@ -639,7 +732,8 @@ bool Sema::LookupName(LookupResult &R, Scope *S, DeclarationName Name, return false; NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID, - S, RedeclarationOnly, Loc); + S, R.isForRedeclaration(), + R.getNameLoc()); if (D) R.addDecl(D); return (D != NULL); } @@ -674,11 +768,8 @@ bool Sema::LookupName(LookupResult &R, Scope *S, DeclarationName Name, /// class or enumeration name if and only if the declarations are /// from the same namespace; otherwise (the declarations are from /// different namespaces), the program is ill-formed. -static bool LookupQualifiedNameInUsingDirectives(Sema::LookupResult &R, - DeclContext *StartDC, - DeclarationName Name, - Sema::LookupNameKind NameKind, - unsigned IDNS) { +static bool LookupQualifiedNameInUsingDirectives(LookupResult &R, + DeclContext *StartDC) { assert(StartDC->isFileContext() && "start context is not a file context"); DeclContext::udir_iterator I = StartDC->using_directives_begin(); @@ -697,7 +788,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema::LookupResult &R, // We have already looked into the initial namespace; seed the queue // with its using-children. for (; I != E; ++I) { - NamespaceDecl *ND = (*I)->getNominatedNamespace(); + NamespaceDecl *ND = (*I)->getNominatedNamespace()->getOriginalNamespace(); if (Visited.insert(ND).second) Queue.push_back(ND); } @@ -709,7 +800,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema::LookupResult &R, bool FoundTag = false; bool FoundNonTag = false; - Sema::LookupResult LocalR; + LookupResult LocalR(LookupResult::Temporary, R); bool Found = false; while (!Queue.empty()) { @@ -719,8 +810,8 @@ static bool LookupQualifiedNameInUsingDirectives(Sema::LookupResult &R, // We go through some convolutions here to avoid copying results // between LookupResults. bool UseLocal = !R.empty(); - Sema::LookupResult &DirectR = UseLocal ? LocalR : R; - bool FoundDirect = LookupDirect(DirectR, ND, Name, NameKind, IDNS); + LookupResult &DirectR = UseLocal ? LocalR : R; + bool FoundDirect = LookupDirect(DirectR, ND); if (FoundDirect) { // First do any local hiding. @@ -792,22 +883,23 @@ static bool LookupQualifiedNameInUsingDirectives(Sema::LookupResult &R, /// @returns The result of name lookup, which includes zero or more /// declarations and possibly additional information used to diagnose /// ambiguities. -bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, - DeclarationName Name, LookupNameKind NameKind, - bool RedeclarationOnly) { +bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx) { assert(LookupCtx && "Sema::LookupQualifiedName requires a lookup context"); - if (!Name) + if (!R.getLookupName()) return false; // If we're performing qualified name lookup (e.g., lookup into a // struct), find fields as part of ordinary name lookup. + LookupNameKind NameKind = R.getLookupKind(); unsigned IDNS = getIdentifierNamespacesFromLookupNameKind(NameKind, getLangOptions().CPlusPlus); if (NameKind == LookupOrdinaryName) IDNS |= Decl::IDNS_Member; + R.setIdentifierNamespace(IDNS); + // Make sure that the declaration context is complete. assert((!isa<TagDecl>(LookupCtx) || LookupCtx->isDependentContext() || @@ -817,7 +909,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, "Declaration context must already be complete!"); // Perform qualified name lookup into the LookupCtx. - if (LookupDirect(R, LookupCtx, Name, NameKind, IDNS)) { + if (LookupDirect(R, LookupCtx)) { R.resolveKind(); return true; } @@ -831,13 +923,12 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // the unqualified-id shall name a member of the namespace // designated by the nested-name-specifier. // See also [class.mfct]p5 and [class.static.data]p2. - if (RedeclarationOnly) + if (R.isForRedeclaration()) return false; - // If this is a namespace, look it up in + // If this is a namespace, look it up in the implied namespaces. if (LookupCtx->isFileContext()) - return LookupQualifiedNameInUsingDirectives(R, LookupCtx, Name, NameKind, - IDNS); + return LookupQualifiedNameInUsingDirectives(R, LookupCtx); // If this isn't a C++ class, we aren't allowed to look into base // classes, we're done. @@ -851,7 +942,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // Look for this member in our base classes CXXRecordDecl::BaseMatchesCallback *BaseCallback = 0; - switch (NameKind) { + switch (R.getLookupKind()) { case LookupOrdinaryName: case LookupMemberName: case LookupRedeclarationWithLinkage: @@ -875,7 +966,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, break; } - if (!LookupRec->lookupInBases(BaseCallback, Name.getAsOpaquePtr(), Paths)) + if (!LookupRec->lookupInBases(BaseCallback, + R.getLookupName().getAsOpaquePtr(), Paths)) return false; // C++ [class.member.lookup]p2: @@ -977,10 +1069,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, /// /// @returns True if any decls were found (but possibly ambiguous) bool Sema::LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS, - DeclarationName Name, LookupNameKind NameKind, - bool RedeclarationOnly, bool AllowBuiltinCreation, - SourceLocation Loc, - bool EnteringContext) { + bool AllowBuiltinCreation, bool EnteringContext) { if (SS && SS->isInvalid()) { // When the scope specifier is invalid, don't even look for // anything. @@ -994,7 +1083,9 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS, if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS)) return false; - return LookupQualifiedName(R, DC, Name, NameKind, RedeclarationOnly); + R.setContextRange(SS->getRange()); + + return LookupQualifiedName(R, DC); } // We could not resolve the scope specified to a specific declaration @@ -1004,8 +1095,7 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS, } // Perform unqualified name lookup starting in the given scope. - return LookupName(R, S, Name, NameKind, RedeclarationOnly, - AllowBuiltinCreation, Loc); + return LookupName(R, S, AllowBuiltinCreation); } @@ -1025,11 +1115,13 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS, /// precedes the name. /// /// @returns true -bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name, - SourceLocation NameLoc, - SourceRange LookupRange) { +bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) { assert(Result.isAmbiguous() && "Lookup result must be ambiguous"); + DeclarationName Name = Result.getLookupName(); + SourceLocation NameLoc = Result.getNameLoc(); + SourceRange LookupRange = Result.getContextRange(); + switch (Result.getAmbiguityKind()) { case LookupResult::AmbiguousBaseSubobjects: { CXXBasePaths *Paths = Result.getBasePaths(); @@ -1136,12 +1228,13 @@ addAssociatedClassesAndNamespaces(const TemplateArgument &Arg, AssociatedClasses); break; - case TemplateArgument::Declaration: + case TemplateArgument::Template: { // [...] the namespaces in which any template template arguments are // defined; and the classes in which any member templates used as // template template arguments are defined. + TemplateName Template = Arg.getAsTemplate(); if (ClassTemplateDecl *ClassTemplate - = dyn_cast<ClassTemplateDecl>(Arg.getAsDecl())) { + = dyn_cast<ClassTemplateDecl>(Template.getAsTemplateDecl())) { DeclContext *Ctx = ClassTemplate->getDeclContext(); if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx)) AssociatedClasses.insert(EnclosingClass); @@ -1151,7 +1244,9 @@ addAssociatedClassesAndNamespaces(const TemplateArgument &Arg, CollectNamespace(AssociatedNamespaces, Ctx); } break; - + } + + case TemplateArgument::Declaration: case TemplateArgument::Integral: case TemplateArgument::Expression: // [Note: non-type template arguments do not contribute to the set of @@ -1490,8 +1585,7 @@ IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn, if (T1->isEnumeralType()) { QualType ArgType = Proto->getArgType(0).getNonReferenceType(); - if (Context.getCanonicalType(T1).getUnqualifiedType() - == Context.getCanonicalType(ArgType).getUnqualifiedType()) + if (Context.hasSameUnqualifiedType(T1, ArgType)) return true; } @@ -1500,14 +1594,21 @@ IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn, if (!T2.isNull() && T2->isEnumeralType()) { QualType ArgType = Proto->getArgType(1).getNonReferenceType(); - if (Context.getCanonicalType(T2).getUnqualifiedType() - == Context.getCanonicalType(ArgType).getUnqualifiedType()) + if (Context.hasSameUnqualifiedType(T2, ArgType)) return true; } return false; } +NamedDecl *Sema::LookupSingleName(Scope *S, DeclarationName Name, + LookupNameKind NameKind, + RedeclarationKind Redecl) { + LookupResult R(*this, Name, SourceLocation(), NameKind, Redecl); + LookupName(R, S); + return R.getAsSingleDecl(Context); +} + /// \brief Find the protocol with the given name, if any. ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II) { Decl *D = LookupSingleName(TUScope, II, LookupObjCProtocolName); @@ -1537,8 +1638,8 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, // of type T2 or "reference to (possibly cv-qualified) T2", // when T2 is an enumeration type, are candidate functions. DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); - LookupResult Operators; - LookupName(Operators, S, OpName, LookupOperatorName); + LookupResult Operators(*this, OpName, SourceLocation(), LookupOperatorName); + LookupName(Operators, S); assert(!Operators.isAmbiguous() && "Operator lookup cannot be ambiguous"); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 3e6778bc4770..adcd977e626d 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "Lookup.h" #include "clang/Basic/Diagnostic.h" #include "clang/Lex/Preprocessor.h" #include "clang/AST/ASTContext.h" @@ -350,7 +351,7 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD, if (NewTemplate && (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(), OldTemplate->getTemplateParameters(), - false, false, SourceLocation()) || + false, TPL_TemplateMatch) || OldType->getResultType() != NewType->getResultType())) return true; @@ -519,8 +520,6 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // cv-unqualified version of T. Otherwise, the type of the rvalue // is T (C++ 4.1p1). C++ can't get here with class types; in C, we // just strip the qualifiers because they don't matter. - - // FIXME: Doesn't see through to qualifiers behind a typedef! FromType = FromType.getUnqualifiedType(); } else if (FromType->isArrayType()) { // Array-to-pointer conversion (C++ 4.2) @@ -678,8 +677,9 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // a conversion. [...] CanonFrom = Context.getCanonicalType(FromType); CanonTo = Context.getCanonicalType(ToType); - if (CanonFrom.getUnqualifiedType() == CanonTo.getUnqualifiedType() && - CanonFrom.getCVRQualifiers() != CanonTo.getCVRQualifiers()) { + if (CanonFrom.getLocalUnqualifiedType() + == CanonTo.getLocalUnqualifiedType() && + CanonFrom.getLocalCVRQualifiers() != CanonTo.getLocalCVRQualifiers()) { FromType = ToType; CanonFrom = CanonTo; } @@ -756,8 +756,7 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { // We found the type that we can promote to. If this is the // type we wanted, we have a promotion. Otherwise, no // promotion. - return Context.getCanonicalType(ToType).getUnqualifiedType() - == Context.getCanonicalType(PromoteTypes[Idx]).getUnqualifiedType(); + return Context.hasSameUnqualifiedType(ToType, PromoteTypes[Idx]); } } } @@ -864,7 +863,7 @@ BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr, Qualifiers Quals = CanonFromPointee.getQualifiers(); // Exact qualifier match -> return the pointer type we're converting to. - if (CanonToPointee.getQualifiers() == Quals) { + if (CanonToPointee.getLocalQualifiers() == Quals) { // ToType is exactly what we need. Return it. if (!ToType.isNull()) return ToType; @@ -876,7 +875,8 @@ BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr, // Just build a canonical type that has the right qualifiers. return Context.getPointerType( - Context.getQualifiedType(CanonToPointee.getUnqualifiedType(), Quals)); + Context.getQualifiedType(CanonToPointee.getLocalUnqualifiedType(), + Quals)); } static bool isNullPointerConstantForConversion(Expr *Expr, @@ -1155,7 +1155,8 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, /// true. It returns true and produces a diagnostic if there was an /// error, or returns false otherwise. bool Sema::CheckPointerConversion(Expr *From, QualType ToType, - CastExpr::CastKind &Kind) { + CastExpr::CastKind &Kind, + bool IgnoreBaseAccess) { QualType FromType = From->getType(); if (const PointerType *FromPtrType = FromType->getAs<PointerType>()) @@ -1169,7 +1170,8 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType, // ambiguous or inaccessible conversion. if (CheckDerivedToBaseConversion(FromPointeeType, ToPointeeType, From->getExprLoc(), - From->getSourceRange())) + From->getSourceRange(), + IgnoreBaseAccess)) return true; // The conversion was successful. @@ -1238,7 +1240,9 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType, /// true and produces a diagnostic if there was an error, or returns false /// otherwise. bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType, - CastExpr::CastKind &Kind) { + CastExpr::CastKind &Kind, + bool IgnoreBaseAccess) { + (void)IgnoreBaseAccess; QualType FromType = From->getType(); const MemberPointerType *FromPtrType = FromType->getAs<MemberPointerType>(); if (!FromPtrType) { @@ -1344,8 +1348,7 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) { // of types. If we unwrapped any pointers, and if FromType and // ToType have the same unqualified type (since we checked // qualifiers above), then this is a qualification conversion. - return UnwrappedAnyPointer && - FromType.getUnqualifiedType() == ToType.getUnqualifiedType(); + return UnwrappedAnyPointer && Context.hasSameUnqualifiedType(FromType,ToType); } /// \brief Given a function template or function, extract the function template @@ -1399,6 +1402,13 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion( // functions are all the converting constructors (12.3.1) of // that class. The argument list is the expression-list within // the parentheses of the initializer. + bool SuppressUserConversions = !UserCast; + if (Context.hasSameUnqualifiedType(ToType, From->getType()) || + IsDerivedFrom(From->getType(), ToType)) { + SuppressUserConversions = false; + AllowConversionFunctions = false; + } + DeclarationName ConstructorName = Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(ToType).getUnqualifiedType()); @@ -1415,20 +1425,18 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion( = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl()); else Constructor = cast<CXXConstructorDecl>(*Con); - + if (!Constructor->isInvalidDecl() && Constructor->isConvertingConstructor(AllowExplicit)) { if (ConstructorTmpl) AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0, &From, - 1, CandidateSet, - /*SuppressUserConversions=*/!UserCast, - ForceRValue); + 1, CandidateSet, + SuppressUserConversions, ForceRValue); else // Allow one user-defined conversion when user specifies a // From->ToType conversion via an static cast (c-style, etc). AddOverloadCandidate(Constructor, &From, 1, CandidateSet, - /*SuppressUserConversions=*/!UserCast, - ForceRValue); + SuppressUserConversions, ForceRValue); } } } @@ -1481,9 +1489,14 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion( // sequence converts the source type to the type required by // the argument of the constructor. // - // FIXME: What about ellipsis conversions? QualType ThisType = Constructor->getThisType(Context); - User.Before = Best->Conversions[0].Standard; + if (Best->Conversions[0].ConversionKind == + ImplicitConversionSequence::EllipsisConversion) + User.EllipsisConversion = true; + else { + User.Before = Best->Conversions[0].Standard; + User.EllipsisConversion = false; + } User.ConversionFunction = Constructor; User.After.setAsIdentityConversion(); User.After.FromTypePtr @@ -1500,6 +1513,7 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion( // implicit object parameter of the conversion function. User.Before = Best->Conversions[0].Standard; User.ConversionFunction = Conversion; + User.EllipsisConversion = false; // C++ [over.ics.user]p2: // The second standard conversion sequence converts the @@ -1727,7 +1741,7 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr); T1 = Context.getCanonicalType(T1); T2 = Context.getCanonicalType(T2); - if (T1.getUnqualifiedType() == T2.getUnqualifiedType()) { + if (Context.hasSameUnqualifiedType(T1, T2)) { if (T2.isMoreQualifiedThan(T1)) return ImplicitConversionSequence::Better; else if (T1.isMoreQualifiedThan(T2)) @@ -1763,7 +1777,7 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1, // If the types are the same, we won't learn anything by unwrapped // them. - if (T1.getUnqualifiedType() == T2.getUnqualifiedType()) + if (Context.hasSameUnqualifiedType(T1, T2)) return ImplicitConversionSequence::Indistinguishable; ImplicitConversionSequence::CompareKind Result @@ -1803,7 +1817,7 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1, } // If the types after this point are equivalent, we're done. - if (T1.getUnqualifiedType() == T2.getUnqualifiedType()) + if (Context.hasSameUnqualifiedType(T1, T2)) break; } @@ -1918,8 +1932,8 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, // -- binding of an expression of type C to a reference of type // B& is better than binding an expression of type C to a // reference of type A&, - if (FromType1.getUnqualifiedType() == FromType2.getUnqualifiedType() && - ToType1.getUnqualifiedType() != ToType2.getUnqualifiedType()) { + if (Context.hasSameUnqualifiedType(FromType1, FromType2) && + !Context.hasSameUnqualifiedType(ToType1, ToType2)) { if (IsDerivedFrom(ToType1, ToType2)) return ImplicitConversionSequence::Better; else if (IsDerivedFrom(ToType2, ToType1)) @@ -1929,8 +1943,8 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, // -- binding of an expression of type B to a reference of type // A& is better than binding an expression of type C to a // reference of type A&, - if (FromType1.getUnqualifiedType() != FromType2.getUnqualifiedType() && - ToType1.getUnqualifiedType() == ToType2.getUnqualifiedType()) { + if (!Context.hasSameUnqualifiedType(FromType1, FromType2) && + Context.hasSameUnqualifiedType(ToType1, ToType2)) { if (IsDerivedFrom(FromType2, FromType1)) return ImplicitConversionSequence::Better; else if (IsDerivedFrom(FromType1, FromType2)) @@ -1977,8 +1991,8 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, if (SCS1.CopyConstructor && SCS2.CopyConstructor && SCS1.Second == ICK_Derived_To_Base) { // -- conversion of C to B is better than conversion of C to A, - if (FromType1.getUnqualifiedType() == FromType2.getUnqualifiedType() && - ToType1.getUnqualifiedType() != ToType2.getUnqualifiedType()) { + if (Context.hasSameUnqualifiedType(FromType1, FromType2) && + !Context.hasSameUnqualifiedType(ToType1, ToType2)) { if (IsDerivedFrom(ToType1, ToType2)) return ImplicitConversionSequence::Better; else if (IsDerivedFrom(ToType2, ToType1)) @@ -1986,8 +2000,8 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, } // -- conversion of B to A is better than conversion of C to A. - if (FromType1.getUnqualifiedType() != FromType2.getUnqualifiedType() && - ToType1.getUnqualifiedType() == ToType2.getUnqualifiedType()) { + if (!Context.hasSameUnqualifiedType(FromType1, FromType2) && + Context.hasSameUnqualifiedType(ToType1, ToType2)) { if (IsDerivedFrom(FromType2, FromType1)) return ImplicitConversionSequence::Better; else if (IsDerivedFrom(FromType1, FromType2)) @@ -2099,14 +2113,15 @@ 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() != FromTypeCanon.getCVRQualifiers() && + if (ImplicitParamType.getCVRQualifiers() + != FromTypeCanon.getLocalCVRQualifiers() && !ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) return ICS; // Check that we have either the same type or a derived type. It // affects the conversion rank. QualType ClassTypeCanon = Context.getCanonicalType(ClassType); - if (ClassTypeCanon == FromTypeCanon.getUnqualifiedType()) + if (ClassTypeCanon == FromTypeCanon.getLocalUnqualifiedType()) ICS.Standard.Second = ICK_Identity; else if (IsDerivedFrom(FromType, ClassType)) ICS.Standard.Second = ICK_Derived_To_Base; @@ -2228,7 +2243,18 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, if (!CandidateSet.isNewCandidate(Function)) return; - + + if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Function)){ + // C++ [class.copy]p3: + // A member function template is never instantiated to perform the copy + // of a class object to an object of its class type. + QualType ClassType = Context.getTypeDeclType(Constructor->getParent()); + if (NumArgs == 1 && + Constructor->isCopyConstructorLikeSpecialization() && + Context.hasSameUnqualifiedType(ClassType, Args[0]->getType())) + return; + } + // Add this candidate CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); @@ -2342,6 +2368,33 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions, } } +/// AddMethodCandidate - Adds a named decl (which is some kind of +/// method) as a method candidate to the given overload set. +void Sema::AddMethodCandidate(NamedDecl *Decl, Expr *Object, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversions, bool ForceRValue) { + + // FIXME: use this + //DeclContext *ActingContext = Decl->getDeclContext(); + + if (isa<UsingShadowDecl>(Decl)) + Decl = cast<UsingShadowDecl>(Decl)->getTargetDecl(); + + if (FunctionTemplateDecl *TD = dyn_cast<FunctionTemplateDecl>(Decl)) { + assert(isa<CXXMethodDecl>(TD->getTemplatedDecl()) && + "Expected a member function template"); + AddMethodTemplateCandidate(TD, false, 0, 0, + Object, Args, NumArgs, + CandidateSet, + SuppressUserConversions, + ForceRValue); + } else { + AddMethodCandidate(cast<CXXMethodDecl>(Decl), Object, Args, NumArgs, + CandidateSet, SuppressUserConversions, ForceRValue); + } +} + /// AddMethodCandidate - Adds the given C++ member function to the set /// of candidate functions, using the given function call arguments /// and the object argument (@c Object). For example, in a call @@ -2593,7 +2646,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, // call on the stack and we don't need its arguments to be // well-formed. DeclRefExpr ConversionRef(Conversion, Conversion->getType(), - SourceLocation()); + From->getLocStart()); ImplicitCastExpr ConversionFn(Context.getPointerType(Conversion->getType()), CastExpr::CK_FunctionToPointerDecay, &ConversionRef, false); @@ -2603,7 +2656,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, // allocator). CallExpr Call(Context, &ConversionFn, 0, 0, Conversion->getConversionType().getNonReferenceType(), - SourceLocation()); + From->getLocStart()); ImplicitConversionSequence ICS = TryCopyInitialization(&Call, ToType, /*SuppressUserConversions=*/true, @@ -2693,6 +2746,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, Candidate.Conversions[0].ConversionKind = ImplicitConversionSequence::UserDefinedConversion; Candidate.Conversions[0].UserDefined.Before = ObjectInit.Standard; + Candidate.Conversions[0].UserDefined.EllipsisConversion = false; Candidate.Conversions[0].UserDefined.ConversionFunction = Conversion; Candidate.Conversions[0].UserDefined.After = Candidate.Conversions[0].UserDefined.Before; @@ -2807,27 +2861,16 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, if (RequireCompleteType(OpLoc, T1, PDiag())) return; - LookupResult Operators; - LookupQualifiedName(Operators, T1Rec->getDecl(), OpName, - LookupOrdinaryName, false); + LookupResult Operators(*this, OpName, OpLoc, LookupOrdinaryName); + LookupQualifiedName(Operators, T1Rec->getDecl()); + Operators.suppressDiagnostics(); + for (LookupResult::iterator Oper = Operators.begin(), OperEnd = Operators.end(); Oper != OperEnd; - ++Oper) { - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Oper)) { - AddMethodCandidate(Method, Args[0], Args+1, NumArgs - 1, CandidateSet, - /*SuppressUserConversions=*/false); - continue; - } - - assert(isa<FunctionTemplateDecl>(*Oper) && - isa<CXXMethodDecl>(cast<FunctionTemplateDecl>(*Oper) - ->getTemplatedDecl()) && - "Expected a member function template"); - AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(*Oper), false, 0, 0, - Args[0], Args+1, NumArgs - 1, CandidateSet, - /*SuppressUserConversions=*/false); - } + ++Oper) + AddMethodCandidate(*Oper, Args[0], Args + 1, NumArgs - 1, CandidateSet, + /* SuppressUserConversions = */ false); } } @@ -2975,6 +3018,8 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty, QualType PointeeTy = PointerTy->getPointeeType(); unsigned BaseCVR = PointeeTy.getCVRQualifiers(); + if (const ConstantArrayType *Array =Context.getAsConstantArrayType(PointeeTy)) + BaseCVR = Array->getElementType().getCVRQualifiers(); bool hasVolatile = VisibleQuals.hasVolatile(); bool hasRestrict = VisibleQuals.hasRestrict(); @@ -3050,7 +3095,7 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, Ty = RefTy->getPointeeType(); // We don't care about qualifiers on the type. - Ty = Ty.getUnqualifiedType(); + Ty = Ty.getLocalUnqualifiedType(); // If we're dealing with an array type, decay to the pointer. if (Ty->isArrayType()) @@ -4710,10 +4755,10 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UsualUnaryConversions(FnExpr); input.release(); - + Args[0] = Input; ExprOwningPtr<CallExpr> TheCall(this, new (Context) CXXOperatorCallExpr(Context, Op, FnExpr, - &Input, 1, ResultTy, OpLoc)); + Args, NumArgs, ResultTy, OpLoc)); if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall.get(), FnDecl)) @@ -5226,17 +5271,22 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // (E).operator(). OverloadCandidateSet CandidateSet; DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call); - DeclContext::lookup_const_iterator Oper, OperEnd; - for (llvm::tie(Oper, OperEnd) = Record->getDecl()->lookup(OpName); - Oper != OperEnd; ++Oper) - AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Object, Args, NumArgs, - CandidateSet, /*SuppressUserConversions=*/false); if (RequireCompleteType(LParenLoc, Object->getType(), PartialDiagnostic(diag::err_incomplete_object_call) - << Object->getSourceRange())) + << Object->getSourceRange())) return true; + LookupResult R(*this, OpName, LParenLoc, LookupOrdinaryName); + LookupQualifiedName(R, Record->getDecl()); + R.suppressDiagnostics(); + + for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); + Oper != OperEnd; ++Oper) { + AddMethodCandidate(*Oper, Object, Args, NumArgs, CandidateSet, + /*SuppressUserConversions=*/ false); + } + // C++ [over.call.object]p2: // In addition, for each conversion function declared in T of the // form @@ -5405,7 +5455,14 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, QualType ProtoArgType = Proto->getArgType(i); IsError |= PerformCopyInitialization(Arg, ProtoArgType, "passing"); } else { - Arg = CXXDefaultArgExpr::Create(Context, Method->getParamDecl(i)); + OwningExprResult DefArg + = BuildCXXDefaultArgExpr(LParenLoc, Method, Method->getParamDecl(i)); + if (DefArg.isInvalid()) { + IsError = true; + break; + } + + Arg = DefArg.takeAs<Expr>(); } TheCall->setArg(i + 1, Arg); @@ -5447,8 +5504,14 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { OverloadCandidateSet CandidateSet; const RecordType *BaseRecord = Base->getType()->getAs<RecordType>(); - LookupResult R; - LookupQualifiedName(R, BaseRecord->getDecl(), OpName, LookupOrdinaryName); + if (RequireCompleteType(Base->getLocStart(), Base->getType(), + PDiag(diag::err_typecheck_incomplete_tag) + << Base->getSourceRange())) + return ExprError(); + + LookupResult R(*this, OpName, OpLoc, LookupOrdinaryName); + LookupQualifiedName(R, BaseRecord->getDecl()); + R.suppressDiagnostics(); for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index 898393a9e4d9..0d1f37aa4beb 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -156,6 +156,14 @@ namespace clang { /// object parameter of the conversion function. StandardConversionSequence Before; + /// EllipsisConversion - When this is true, it means user-defined + /// conversion sequence starts with a ... (elipsis) conversion, instead of + /// a standard conversion. In this case, 'Before' field must be ignored. + // FIXME. I much rather put this as the first field. But there seems to be + // a gcc code gen. bug which causes a crash in a test. Putting it here seems + // to work around the crash. + bool EllipsisConversion : 1; + /// After - Represents the standard conversion that occurs after /// the actual user-defined conversion. StandardConversionSequence After; diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 6a65bd1dd1ec..d0f214fbd83d 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -873,8 +873,7 @@ static bool IsReturnCopyElidable(ASTContext &Ctx, QualType RetType, if (!RetType->isRecordType()) return false; // ... the same cv-unqualified type as the function return type ... - if (Ctx.getCanonicalType(RetType).getUnqualifiedType() != - Ctx.getCanonicalType(ExprType).getUnqualifiedType()) + if (!Ctx.hasSameUnqualifiedType(RetType, ExprType)) return false; // ... the expression is the name of a non-volatile automatic object ... // We ignore parentheses here. @@ -965,9 +964,12 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { // In C++ the return statement is handled via a copy initialization. // the C version of which boils down to CheckSingleAssignmentConstraints. // FIXME: Leaks RetValExp on error. - if (PerformCopyInitialization(RetValExp, FnRetType, "returning", Elidable)) + if (PerformCopyInitialization(RetValExp, FnRetType, "returning", Elidable)){ + // We should still clean up our temporaries, even when we're failing! + RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp, true); return StmtError(); - + } + if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 5ef370104dd9..466a0e37d49c 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -10,12 +10,14 @@ //===----------------------------------------------------------------------===/ #include "Sema.h" +#include "Lookup.h" #include "TreeTransform.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/DeclTemplate.h" #include "clang/Parse/DeclSpec.h" +#include "clang/Parse/Template.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/PartialDiagnostic.h" #include "llvm/Support/Compiler.h" @@ -129,29 +131,29 @@ TemplateNameKind Sema::isTemplateName(Scope *S, QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr); LookupCtx = computeDeclContext(ObjectType); isDependent = ObjectType->isDependentType(); + assert((isDependent || !ObjectType->isIncompleteType()) && + "Caller should have completed object type"); } else if (SS.isSet()) { // This nested-name-specifier occurs after another nested-name-specifier, // so long into the context associated with the prior nested-name-specifier. - LookupCtx = computeDeclContext(SS, EnteringContext); isDependent = isDependentScopeSpecifier(SS); + + // The declaration context must be complete. + if (LookupCtx && RequireCompleteDeclContext(SS)) + return TNK_Non_template; } - LookupResult Found; + LookupResult Found(*this, TName, SourceLocation(), LookupOrdinaryName); bool ObjectTypeSearchedInScope = false; if (LookupCtx) { // Perform "qualified" name lookup into the declaration context we // computed, which is either the type of the base of a member access // expression or the declaration context associated with a prior // nested-name-specifier. + LookupQualifiedName(Found, LookupCtx); - // The declaration context must be complete. - if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS)) - return TNK_Non_template; - - LookupQualifiedName(Found, LookupCtx, TName, LookupOrdinaryName); - - if (ObjectTypePtr && Found.getKind() == LookupResult::NotFound) { + if (ObjectTypePtr && Found.empty()) { // C++ [basic.lookup.classref]p1: // In a class member access expression (5.2.5), if the . or -> token is // immediately followed by an identifier followed by a <, the @@ -164,7 +166,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S, // // FIXME: When we're instantiating a template, do we actually have to // look in the scope of the template? Seems fishy... - LookupName(Found, S, TName, LookupOrdinaryName); + LookupName(Found, S); ObjectTypeSearchedInScope = true; } } else if (isDependent) { @@ -172,7 +174,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S, return TNK_Non_template; } else { // Perform unqualified name lookup in the current scope. - LookupName(Found, S, TName, LookupOrdinaryName); + LookupName(Found, S); } // FIXME: Cope with ambiguous name-lookup results. @@ -190,8 +192,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S, // template, the name is also looked up in the context of the entire // postfix-expression and [...] // - LookupResult FoundOuter; - LookupName(FoundOuter, S, TName, LookupOrdinaryName); + LookupResult FoundOuter(*this, TName, SourceLocation(), LookupOrdinaryName); + LookupName(FoundOuter, S); // FIXME: Handle ambiguities in this lookup better NamedDecl *OuterTemplate = isAcceptableTemplateName(Context, FoundOuter.getAsSingleDecl(Context)); @@ -283,6 +285,46 @@ TemplateDecl *Sema::AdjustDeclIfTemplate(DeclPtrTy &D) { return 0; } +static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef, + const ParsedTemplateArgument &Arg) { + + switch (Arg.getKind()) { + case ParsedTemplateArgument::Type: { + DeclaratorInfo *DI; + QualType T = SemaRef.GetTypeFromParser(Arg.getAsType(), &DI); + if (!DI) + DI = SemaRef.Context.getTrivialDeclaratorInfo(T, Arg.getLocation()); + return TemplateArgumentLoc(TemplateArgument(T), DI); + } + + case ParsedTemplateArgument::NonType: { + Expr *E = static_cast<Expr *>(Arg.getAsExpr()); + return TemplateArgumentLoc(TemplateArgument(E), E); + } + + case ParsedTemplateArgument::Template: { + TemplateName Template + = TemplateName::getFromVoidPointer(Arg.getAsTemplate().get()); + return TemplateArgumentLoc(TemplateArgument(Template), + Arg.getScopeSpec().getRange(), + Arg.getLocation()); + } + } + + llvm::llvm_unreachable("Unhandled parsed template argument"); + return TemplateArgumentLoc(); +} + +/// \brief Translates template arguments as provided by the parser +/// into template arguments used by semantic analysis. +void Sema::translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, + llvm::SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) { + TemplateArgs.reserve(TemplateArgsIn.size()); + + for (unsigned I = 0, Last = TemplateArgsIn.size(); I != Last; ++I) + TemplateArgs.push_back(translateTemplateArgument(*this, TemplateArgsIn[I])); +} + /// ActOnTypeParameter - Called when a C++ template type parameter /// (e.g., "typename T") has been parsed. Typename specifies whether /// the keyword "typename" was used to declare the type parameter @@ -517,34 +559,30 @@ Sema::DeclPtrTy Sema::ActOnTemplateTemplateParameter(Scope* S, /// parameter. void Sema::ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParamD, SourceLocation EqualLoc, - ExprArg DefaultE) { + const ParsedTemplateArgument &Default) { TemplateTemplateParmDecl *TemplateParm = cast<TemplateTemplateParmDecl>(TemplateParamD.getAs<Decl>()); - - // Since a template-template parameter's default argument is an - // id-expression, it must be a DeclRefExpr. - DeclRefExpr *Default - = cast<DeclRefExpr>(static_cast<Expr *>(DefaultE.get())); - + // C++ [temp.param]p14: // A template-parameter shall not be used in its own default argument. // FIXME: Implement this check! Needs a recursive walk over the types. - // Check the well-formedness of the template argument. - if (!isa<TemplateDecl>(Default->getDecl())) { - Diag(Default->getSourceRange().getBegin(), - diag::err_template_arg_must_be_template) - << Default->getSourceRange(); - TemplateParm->setInvalidDecl(); - return; - } - if (CheckTemplateArgument(TemplateParm, Default)) { - TemplateParm->setInvalidDecl(); + // Check only that we have a template template argument. We don't want to + // try to check well-formedness now, because our template template parameter + // might have dependent types in its template parameters, which we wouldn't + // be able to match now. + // + // If none of the template template parameter's template arguments mention + // other template parameters, we could actually perform more checking here. + // However, it isn't worth doing. + TemplateArgumentLoc DefaultArg = translateTemplateArgument(*this, Default); + if (DefaultArg.getArgument().getAsTemplate().isNull()) { + Diag(DefaultArg.getLocation(), diag::err_template_arg_not_class_template) + << DefaultArg.getSourceRange(); return; } - - DefaultE.release(); - TemplateParm->setDefaultArgument(Default); + + TemplateParm->setDefaultArgument(DefaultArg); } /// ActOnTemplateParameterList - Builds a TemplateParameterList that @@ -591,7 +629,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // Find any previous declaration with this name. DeclContext *SemanticContext; - LookupResult Previous; + LookupResult Previous(*this, Name, NameLoc, LookupOrdinaryName, + ForRedeclaration); if (SS.isNotEmpty() && !SS.isInvalid()) { if (RequireCompleteDeclContext(SS)) return true; @@ -602,11 +641,10 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, return true; } - LookupQualifiedName(Previous, SemanticContext, Name, LookupOrdinaryName, - true); + LookupQualifiedName(Previous, SemanticContext); } else { SemanticContext = CurContext; - LookupName(Previous, S, Name, LookupOrdinaryName, true); + LookupName(Previous, S); } assert(!Previous.isAmbiguous() && "Ambiguity in class template redecl?"); @@ -669,7 +707,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // Ensure that the template parameter lists are compatible. if (!TemplateParameterListsAreEqual(TemplateParams, PrevClassTemplate->getTemplateParameters(), - /*Complain=*/true)) + /*Complain=*/true, + TPL_TemplateMatch)) return true; // C++ [temp.class]p4: @@ -923,8 +962,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, = OldParams? cast<TemplateTemplateParmDecl>(*OldParam) : 0; if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() && NewTemplateParm->hasDefaultArgument()) { - OldDefaultLoc = OldTemplateParm->getDefaultArgumentLoc(); - NewDefaultLoc = NewTemplateParm->getDefaultArgumentLoc(); + OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation(); + NewDefaultLoc = NewTemplateParm->getDefaultArgument().getLocation(); SawDefaultArgument = true; RedundantDefaultArg = true; PreviousDefaultArgLoc = NewDefaultLoc; @@ -936,10 +975,12 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, // that points to a previous template template parameter. NewTemplateParm->setDefaultArgument( OldTemplateParm->getDefaultArgument()); - PreviousDefaultArgLoc = OldTemplateParm->getDefaultArgumentLoc(); + PreviousDefaultArgLoc + = OldTemplateParm->getDefaultArgument().getLocation(); } else if (NewTemplateParm->hasDefaultArgument()) { SawDefaultArgument = true; - PreviousDefaultArgLoc = NewTemplateParm->getDefaultArgumentLoc(); + PreviousDefaultArgLoc + = NewTemplateParm->getDefaultArgument().getLocation(); } else if (SawDefaultArgument) MissingDefaultArg = true; } @@ -1085,7 +1126,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, if (ExpectedTemplateParams) TemplateParameterListsAreEqual(ParamLists[Idx], ExpectedTemplateParams, - true); + true, TPL_TemplateMatch); } } else if (ParamLists[Idx]->size() > 0) Diag(ParamLists[Idx]->getTemplateLoc(), @@ -1118,28 +1159,6 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, return ParamLists[NumParamLists - 1]; } -/// \brief Translates template arguments as provided by the parser -/// into template arguments used by semantic analysis. -void Sema::translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, - SourceLocation *TemplateArgLocs, - llvm::SmallVector<TemplateArgumentLoc, 16> &TemplateArgs) { - TemplateArgs.reserve(TemplateArgsIn.size()); - - void **Args = TemplateArgsIn.getArgs(); - bool *ArgIsType = TemplateArgsIn.getArgIsType(); - for (unsigned Arg = 0, Last = TemplateArgsIn.size(); Arg != Last; ++Arg) { - if (ArgIsType[Arg]) { - DeclaratorInfo *DI; - QualType T = Sema::GetTypeFromParser(Args[Arg], &DI); - if (!DI) DI = Context.getTrivialDeclaratorInfo(T, TemplateArgLocs[Arg]); - TemplateArgs.push_back(TemplateArgumentLoc(TemplateArgument(T), DI)); - } else { - Expr *E = reinterpret_cast<Expr *>(Args[Arg]); - TemplateArgs.push_back(TemplateArgumentLoc(TemplateArgument(E), E)); - } - } -} - QualType Sema::CheckTemplateIdType(TemplateName Name, SourceLocation TemplateLoc, SourceLocation LAngleLoc, @@ -1169,7 +1188,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, QualType CanonType; - if (TemplateSpecializationType::anyDependentTemplateArguments( + if (Name.isDependent() || + TemplateSpecializationType::anyDependentTemplateArguments( TemplateArgs, NumTemplateArgs)) { // This class template specialization is a dependent @@ -1228,13 +1248,12 @@ Action::TypeResult Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, - SourceLocation *TemplateArgLocsIn, SourceLocation RAngleLoc) { TemplateName Template = TemplateD.getAsVal<TemplateName>(); // Translate the parser's template argument list in our AST format. llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs; - translateTemplateArguments(TemplateArgsIn, TemplateArgLocsIn, TemplateArgs); + translateTemplateArguments(TemplateArgsIn, TemplateArgs); QualType Result = CheckTemplateIdType(Template, TemplateLoc, LAngleLoc, TemplateArgs.data(), @@ -1336,13 +1355,12 @@ Sema::OwningExprResult Sema::ActOnTemplateIdExpr(const CXXScopeSpec &SS, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, - SourceLocation *TemplateArgSLs, SourceLocation RAngleLoc) { TemplateName Template = TemplateD.getAsVal<TemplateName>(); // Translate the parser's template argument list in our AST format. llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs; - translateTemplateArguments(TemplateArgsIn, TemplateArgSLs, TemplateArgs); + translateTemplateArguments(TemplateArgsIn, TemplateArgs); TemplateArgsIn.release(); return BuildTemplateIdExpr((NestedNameSpecifier *)SS.getScopeRep(), @@ -1449,6 +1467,333 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, return false; } +/// \brief Substitute template arguments into the default template argument for +/// the given template type parameter. +/// +/// \param SemaRef the semantic analysis object for which we are performing +/// the substitution. +/// +/// \param Template the template that we are synthesizing template arguments +/// for. +/// +/// \param TemplateLoc the location of the template name that started the +/// template-id we are checking. +/// +/// \param RAngleLoc the location of the right angle bracket ('>') that +/// terminates the template-id. +/// +/// \param Param the template template parameter whose default we are +/// substituting into. +/// +/// \param Converted the list of template arguments provided for template +/// parameters that precede \p Param in the template parameter list. +/// +/// \returns the substituted template argument, or NULL if an error occurred. +static DeclaratorInfo * +SubstDefaultTemplateArgument(Sema &SemaRef, + TemplateDecl *Template, + SourceLocation TemplateLoc, + SourceLocation RAngleLoc, + TemplateTypeParmDecl *Param, + TemplateArgumentListBuilder &Converted) { + DeclaratorInfo *ArgType = Param->getDefaultArgumentInfo(); + + // If the argument type is dependent, instantiate it now based + // on the previously-computed template arguments. + if (ArgType->getType()->isDependentType()) { + TemplateArgumentList TemplateArgs(SemaRef.Context, Converted, + /*TakeArgs=*/false); + + MultiLevelTemplateArgumentList AllTemplateArgs + = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs); + + Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, + Template, Converted.getFlatArguments(), + Converted.flatSize(), + SourceRange(TemplateLoc, RAngleLoc)); + + ArgType = SemaRef.SubstType(ArgType, AllTemplateArgs, + Param->getDefaultArgumentLoc(), + Param->getDeclName()); + } + + return ArgType; +} + +/// \brief Substitute template arguments into the default template argument for +/// the given non-type template parameter. +/// +/// \param SemaRef the semantic analysis object for which we are performing +/// the substitution. +/// +/// \param Template the template that we are synthesizing template arguments +/// for. +/// +/// \param TemplateLoc the location of the template name that started the +/// template-id we are checking. +/// +/// \param RAngleLoc the location of the right angle bracket ('>') that +/// terminates the template-id. +/// +/// \param Param the non-type template parameter whose default we are +/// substituting into. +/// +/// \param Converted the list of template arguments provided for template +/// parameters that precede \p Param in the template parameter list. +/// +/// \returns the substituted template argument, or NULL if an error occurred. +static Sema::OwningExprResult +SubstDefaultTemplateArgument(Sema &SemaRef, + TemplateDecl *Template, + SourceLocation TemplateLoc, + SourceLocation RAngleLoc, + NonTypeTemplateParmDecl *Param, + TemplateArgumentListBuilder &Converted) { + TemplateArgumentList TemplateArgs(SemaRef.Context, Converted, + /*TakeArgs=*/false); + + MultiLevelTemplateArgumentList AllTemplateArgs + = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs); + + Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, + Template, Converted.getFlatArguments(), + Converted.flatSize(), + SourceRange(TemplateLoc, RAngleLoc)); + + return SemaRef.SubstExpr(Param->getDefaultArgument(), AllTemplateArgs); +} + +/// \brief Substitute template arguments into the default template argument for +/// the given template template parameter. +/// +/// \param SemaRef the semantic analysis object for which we are performing +/// the substitution. +/// +/// \param Template the template that we are synthesizing template arguments +/// for. +/// +/// \param TemplateLoc the location of the template name that started the +/// template-id we are checking. +/// +/// \param RAngleLoc the location of the right angle bracket ('>') that +/// terminates the template-id. +/// +/// \param Param the template template parameter whose default we are +/// substituting into. +/// +/// \param Converted the list of template arguments provided for template +/// parameters that precede \p Param in the template parameter list. +/// +/// \returns the substituted template argument, or NULL if an error occurred. +static TemplateName +SubstDefaultTemplateArgument(Sema &SemaRef, + TemplateDecl *Template, + SourceLocation TemplateLoc, + SourceLocation RAngleLoc, + TemplateTemplateParmDecl *Param, + TemplateArgumentListBuilder &Converted) { + TemplateArgumentList TemplateArgs(SemaRef.Context, Converted, + /*TakeArgs=*/false); + + MultiLevelTemplateArgumentList AllTemplateArgs + = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs); + + Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, + Template, Converted.getFlatArguments(), + Converted.flatSize(), + SourceRange(TemplateLoc, RAngleLoc)); + + return SemaRef.SubstTemplateName( + Param->getDefaultArgument().getArgument().getAsTemplate(), + Param->getDefaultArgument().getTemplateNameLoc(), + AllTemplateArgs); +} + +/// \brief Check that the given template argument corresponds to the given +/// template parameter. +bool Sema::CheckTemplateArgument(NamedDecl *Param, + const TemplateArgumentLoc &Arg, + TemplateDecl *Template, + SourceLocation TemplateLoc, + SourceLocation RAngleLoc, + TemplateArgumentListBuilder &Converted) { + // Check template type parameters. + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) + return CheckTemplateTypeArgument(TTP, Arg, Converted); + + // Check non-type template parameters. + if (NonTypeTemplateParmDecl *NTTP =dyn_cast<NonTypeTemplateParmDecl>(Param)) { + // Do substitution on the type of the non-type template parameter + // with the template arguments we've seen thus far. + QualType NTTPType = NTTP->getType(); + if (NTTPType->isDependentType()) { + // Do substitution on the type of the non-type template parameter. + InstantiatingTemplate Inst(*this, TemplateLoc, Template, + NTTP, Converted.getFlatArguments(), + Converted.flatSize(), + SourceRange(TemplateLoc, RAngleLoc)); + + TemplateArgumentList TemplateArgs(Context, Converted, + /*TakeArgs=*/false); + NTTPType = SubstType(NTTPType, + MultiLevelTemplateArgumentList(TemplateArgs), + NTTP->getLocation(), + NTTP->getDeclName()); + // If that worked, check the non-type template parameter type + // for validity. + if (!NTTPType.isNull()) + NTTPType = CheckNonTypeTemplateParameterType(NTTPType, + NTTP->getLocation()); + if (NTTPType.isNull()) + return true; + } + + switch (Arg.getArgument().getKind()) { + case TemplateArgument::Null: + assert(false && "Should never see a NULL template argument here"); + return true; + + case TemplateArgument::Expression: { + Expr *E = Arg.getArgument().getAsExpr(); + TemplateArgument Result; + if (CheckTemplateArgument(NTTP, NTTPType, E, Result)) + return true; + + Converted.Append(Result); + break; + } + + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + // We've already checked this template argument, so just copy + // it to the list of converted arguments. + Converted.Append(Arg.getArgument()); + break; + + case TemplateArgument::Template: + // We were given a template template argument. It may not be ill-formed; + // see below. + if (DependentTemplateName *DTN + = Arg.getArgument().getAsTemplate().getAsDependentTemplateName()) { + // We have a template argument such as \c T::template X, which we + // parsed as a template template argument. However, since we now + // know that we need a non-type template argument, convert this + // template name into an expression. + Expr *E = new (Context) UnresolvedDeclRefExpr(DTN->getIdentifier(), + Context.DependentTy, + Arg.getTemplateNameLoc(), + Arg.getTemplateQualifierRange(), + DTN->getQualifier(), + /*isAddressOfOperand=*/false); + + TemplateArgument Result; + if (CheckTemplateArgument(NTTP, NTTPType, E, Result)) + return true; + + Converted.Append(Result); + break; + } + + // We have a template argument that actually does refer to a class + // template, template alias, or template template parameter, and + // therefore cannot be a non-type template argument. + Diag(Arg.getLocation(), diag::err_template_arg_must_be_expr) + << Arg.getSourceRange(); + + Diag(Param->getLocation(), diag::note_template_param_here); + return true; + + case TemplateArgument::Type: { + // We have a non-type template parameter but the template + // argument is a type. + + // C++ [temp.arg]p2: + // In a template-argument, an ambiguity between a type-id and + // an expression is resolved to a type-id, regardless of the + // form of the corresponding template-parameter. + // + // We warn specifically about this case, since it can be rather + // confusing for users. + QualType T = Arg.getArgument().getAsType(); + SourceRange SR = Arg.getSourceRange(); + if (T->isFunctionType()) + Diag(SR.getBegin(), diag::err_template_arg_nontype_ambig) << SR << T; + else + Diag(SR.getBegin(), diag::err_template_arg_must_be_expr) << SR; + Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + + case TemplateArgument::Pack: + llvm::llvm_unreachable("Caller must expand template argument packs"); + break; + } + + return false; + } + + + // Check template template parameters. + TemplateTemplateParmDecl *TempParm = cast<TemplateTemplateParmDecl>(Param); + + // Substitute into the template parameter list of the template + // template parameter, since previously-supplied template arguments + // may appear within the template template parameter. + { + // Set up a template instantiation context. + LocalInstantiationScope Scope(*this); + InstantiatingTemplate Inst(*this, TemplateLoc, Template, + TempParm, Converted.getFlatArguments(), + Converted.flatSize(), + SourceRange(TemplateLoc, RAngleLoc)); + + TemplateArgumentList TemplateArgs(Context, Converted, + /*TakeArgs=*/false); + TempParm = cast_or_null<TemplateTemplateParmDecl>( + SubstDecl(TempParm, CurContext, + MultiLevelTemplateArgumentList(TemplateArgs))); + if (!TempParm) + return true; + + // FIXME: TempParam is leaked. + } + + switch (Arg.getArgument().getKind()) { + case TemplateArgument::Null: + assert(false && "Should never see a NULL template argument here"); + return true; + + case TemplateArgument::Template: + if (CheckTemplateArgument(TempParm, Arg)) + return true; + + Converted.Append(Arg.getArgument()); + break; + + case TemplateArgument::Expression: + case TemplateArgument::Type: + // We have a template template parameter but the template + // argument does not refer to a template. + Diag(Arg.getLocation(), diag::err_template_arg_must_be_template); + return true; + + case TemplateArgument::Declaration: + llvm::llvm_unreachable( + "Declaration argument with template template parameter"); + break; + case TemplateArgument::Integral: + llvm::llvm_unreachable( + "Integral argument with template template parameter"); + break; + + case TemplateArgument::Pack: + llvm::llvm_unreachable("Caller must expand template argument packs"); + break; + } + + return false; +} + /// \brief Check that the given template argument list is well-formed /// for specializing the given template. bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, @@ -1499,226 +1844,105 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, if (ArgIdx > NumArgs && PartialTemplateArgs) break; - // Decode the template argument - TemplateArgumentLoc Arg; - - if (ArgIdx >= NumArgs) { - // Retrieve the default template argument from the template - // parameter. - if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) { - if (TTP->isParameterPack()) { - // We have an empty argument pack. - Converted.BeginPack(); - Converted.EndPack(); - break; - } - - if (!TTP->hasDefaultArgument()) + // If we have a template parameter pack, check every remaining template + // argument against that template parameter pack. + if ((*Param)->isTemplateParameterPack()) { + Converted.BeginPack(); + for (; ArgIdx < NumArgs; ++ArgIdx) { + if (CheckTemplateArgument(*Param, TemplateArgs[ArgIdx], Template, + TemplateLoc, RAngleLoc, Converted)) { + Invalid = true; break; - - DeclaratorInfo *ArgType = TTP->getDefaultArgumentInfo(); - - // If the argument type is dependent, instantiate it now based - // on the previously-computed template arguments. - if (ArgType->getType()->isDependentType()) { - InstantiatingTemplate Inst(*this, TemplateLoc, - Template, Converted.getFlatArguments(), - Converted.flatSize(), - SourceRange(TemplateLoc, RAngleLoc)); - - TemplateArgumentList TemplateArgs(Context, Converted, - /*TakeArgs=*/false); - ArgType = SubstType(ArgType, - MultiLevelTemplateArgumentList(TemplateArgs), - TTP->getDefaultArgumentLoc(), - TTP->getDeclName()); } - - if (!ArgType) - return true; - - Arg = TemplateArgumentLoc(TemplateArgument(ArgType->getType()), ArgType); - } else if (NonTypeTemplateParmDecl *NTTP - = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { - if (!NTTP->hasDefaultArgument()) - break; - - InstantiatingTemplate Inst(*this, TemplateLoc, - Template, Converted.getFlatArguments(), - Converted.flatSize(), - SourceRange(TemplateLoc, RAngleLoc)); - - TemplateArgumentList TemplateArgs(Context, Converted, - /*TakeArgs=*/false); - - Sema::OwningExprResult E - = SubstExpr(NTTP->getDefaultArgument(), - MultiLevelTemplateArgumentList(TemplateArgs)); - if (E.isInvalid()) - return true; - - Expr *Ex = E.takeAs<Expr>(); - Arg = TemplateArgumentLoc(TemplateArgument(Ex), Ex); - } else { - TemplateTemplateParmDecl *TempParm - = cast<TemplateTemplateParmDecl>(*Param); - - if (!TempParm->hasDefaultArgument()) - break; - - // FIXME: Subst default argument - Arg = TemplateArgumentLoc(TemplateArgument(TempParm->getDefaultArgument()), - TempParm->getDefaultArgument()); } - } else { - // Retrieve the template argument produced by the user. - Arg = TemplateArgs[ArgIdx]; + Converted.EndPack(); + continue; } - - + + if (ArgIdx < NumArgs) { + // Check the template argument we were given. + if (CheckTemplateArgument(*Param, TemplateArgs[ArgIdx], Template, + TemplateLoc, RAngleLoc, Converted)) + return true; + + continue; + } + + // We have a default template argument that we will use. + TemplateArgumentLoc Arg; + + // Retrieve the default template argument from the template + // parameter. For each kind of template parameter, we substitute the + // template arguments provided thus far and any "outer" template arguments + // (when the template parameter was part of a nested template) into + // the default argument. if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) { - if (TTP->isParameterPack()) { - Converted.BeginPack(); - // Check all the remaining arguments (if any). - for (; ArgIdx < NumArgs; ++ArgIdx) { - if (CheckTemplateTypeArgument(TTP, TemplateArgs[ArgIdx], Converted)) - Invalid = true; - } - - Converted.EndPack(); - } else { - if (CheckTemplateTypeArgument(TTP, Arg, Converted)) - Invalid = true; + if (!TTP->hasDefaultArgument()) { + assert((Invalid || PartialTemplateArgs) && "Missing default argument"); + break; } + + DeclaratorInfo *ArgType = SubstDefaultTemplateArgument(*this, + Template, + TemplateLoc, + RAngleLoc, + TTP, + Converted); + if (!ArgType) + return true; + + Arg = TemplateArgumentLoc(TemplateArgument(ArgType->getType()), + ArgType); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { - // Check non-type template parameters. - - // Do substitution on the type of the non-type template parameter - // with the template arguments we've seen thus far. - QualType NTTPType = NTTP->getType(); - if (NTTPType->isDependentType()) { - // Do substitution on the type of the non-type template parameter. - InstantiatingTemplate Inst(*this, TemplateLoc, - Template, Converted.getFlatArguments(), - Converted.flatSize(), - SourceRange(TemplateLoc, RAngleLoc)); - - TemplateArgumentList TemplateArgs(Context, Converted, - /*TakeArgs=*/false); - NTTPType = SubstType(NTTPType, - MultiLevelTemplateArgumentList(TemplateArgs), - NTTP->getLocation(), - NTTP->getDeclName()); - // If that worked, check the non-type template parameter type - // for validity. - if (!NTTPType.isNull()) - NTTPType = CheckNonTypeTemplateParameterType(NTTPType, - NTTP->getLocation()); - if (NTTPType.isNull()) { - Invalid = true; - break; - } - } - - switch (Arg.getArgument().getKind()) { - case TemplateArgument::Null: - assert(false && "Should never see a NULL template argument here"); - break; - - case TemplateArgument::Expression: { - Expr *E = Arg.getArgument().getAsExpr(); - TemplateArgument Result; - if (CheckTemplateArgument(NTTP, NTTPType, E, Result)) - Invalid = true; - else - Converted.Append(Result); + if (!NTTP->hasDefaultArgument()) { + assert((Invalid || PartialTemplateArgs) && "Missing default argument"); break; } - case TemplateArgument::Declaration: - case TemplateArgument::Integral: - // We've already checked this template argument, so just copy - // it to the list of converted arguments. - Converted.Append(Arg.getArgument()); - break; - - case TemplateArgument::Type: { - // We have a non-type template parameter but the template - // argument is a type. - - // C++ [temp.arg]p2: - // In a template-argument, an ambiguity between a type-id and - // an expression is resolved to a type-id, regardless of the - // form of the corresponding template-parameter. - // - // We warn specifically about this case, since it can be rather - // confusing for users. - QualType T = Arg.getArgument().getAsType(); - SourceRange SR = Arg.getSourceRange(); - if (T->isFunctionType()) - Diag(SR.getBegin(), diag::err_template_arg_nontype_ambig) - << SR << T; - else - Diag(SR.getBegin(), diag::err_template_arg_must_be_expr) << SR; - Diag((*Param)->getLocation(), diag::note_template_param_here); - Invalid = true; - break; - } + Sema::OwningExprResult E = SubstDefaultTemplateArgument(*this, Template, + TemplateLoc, + RAngleLoc, + NTTP, + Converted); + if (E.isInvalid()) + return true; - case TemplateArgument::Pack: - assert(0 && "FIXME: Implement!"); - break; - } + Expr *Ex = E.takeAs<Expr>(); + Arg = TemplateArgumentLoc(TemplateArgument(Ex), Ex); } else { - // Check template template parameters. TemplateTemplateParmDecl *TempParm = cast<TemplateTemplateParmDecl>(*Param); - switch (Arg.getArgument().getKind()) { - case TemplateArgument::Null: - assert(false && "Should never see a NULL template argument here"); + if (!TempParm->hasDefaultArgument()) { + assert((Invalid || PartialTemplateArgs) && "Missing default argument"); break; - - case TemplateArgument::Expression: { - Expr *ArgExpr = Arg.getArgument().getAsExpr(); - if (ArgExpr && isa<DeclRefExpr>(ArgExpr) && - isa<TemplateDecl>(cast<DeclRefExpr>(ArgExpr)->getDecl())) { - if (CheckTemplateArgument(TempParm, cast<DeclRefExpr>(ArgExpr))) - Invalid = true; - - // Add the converted template argument. - Decl *D - = cast<DeclRefExpr>(ArgExpr)->getDecl()->getCanonicalDecl(); - Converted.Append(TemplateArgument(D)); - continue; - } } - // fall through - case TemplateArgument::Type: { - // We have a template template parameter but the template - // argument does not refer to a template. - Diag(Arg.getLocation(), diag::err_template_arg_must_be_template); - Invalid = true; - break; - } - - case TemplateArgument::Declaration: - // We've already checked this template argument, so just copy - // it to the list of converted arguments. - Converted.Append(Arg.getArgument()); - break; - - case TemplateArgument::Integral: - assert(false && "Integral argument with template template parameter"); - break; - - case TemplateArgument::Pack: - assert(0 && "FIXME: Implement!"); - break; - } + TemplateName Name = SubstDefaultTemplateArgument(*this, Template, + TemplateLoc, + RAngleLoc, + TempParm, + Converted); + if (Name.isNull()) + return true; + + Arg = TemplateArgumentLoc(TemplateArgument(Name), + TempParm->getDefaultArgument().getTemplateQualifierRange(), + TempParm->getDefaultArgument().getTemplateNameLoc()); } + + // Introduce an instantiation record that describes where we are using + // the default template argument. + InstantiatingTemplate Instantiating(*this, RAngleLoc, Template, *Param, + Converted.getFlatArguments(), + Converted.flatSize(), + SourceRange(TemplateLoc, RAngleLoc)); + + // Check the default template argument. + if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, + RAngleLoc, Converted)) + return true; } return Invalid; @@ -1864,8 +2088,8 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, /// \brief Checks whether the given template argument is a pointer to /// member constant according to C++ [temp.arg.nontype]p1. -bool -Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { +bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, + TemplateArgument &Converted) { bool Invalid = false; // See through any implicit casts we added to fix the type. @@ -1896,13 +2120,33 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { Arg = Parens->getSubExpr(); } - if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) + // A pointer-to-member constant written &Class::member. + if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) { if (UnOp->getOpcode() == UnaryOperator::AddrOf) { DRE = dyn_cast<DeclRefExpr>(UnOp->getSubExpr()); if (DRE && !DRE->getQualifier()) DRE = 0; } - + } + // A constant of pointer-to-member type. + else if ((DRE = dyn_cast<DeclRefExpr>(Arg))) { + if (ValueDecl *VD = dyn_cast<ValueDecl>(DRE->getDecl())) { + if (VD->getType()->isMemberPointerType()) { + if (isa<NonTypeTemplateParmDecl>(VD) || + (isa<VarDecl>(VD) && + Context.getCanonicalType(VD->getType()).isConstQualified())) { + if (Arg->isTypeDependent() || Arg->isValueDependent()) + Converted = TemplateArgument(Arg->Retain()); + else + Converted = TemplateArgument(VD->getCanonicalDecl()); + return Invalid; + } + } + } + + DRE = 0; + } + if (!DRE) return Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_not_pointer_to_member_form) @@ -1915,7 +2159,10 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { // Okay: this is the address of a non-static member, and therefore // a member pointer constant. - Member = DRE->getDecl(); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + Converted = TemplateArgument(Arg->Retain()); + else + Converted = TemplateArgument(DRE->getDecl()->getCanonicalDecl()); return Invalid; } @@ -2119,16 +2366,8 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return true; } - if (ParamType->isMemberPointerType()) { - NamedDecl *Member = 0; - if (CheckTemplateArgumentPointerToMember(Arg, Member)) - return true; - - if (Member) - Member = cast<NamedDecl>(Member->getCanonicalDecl()); - Converted = TemplateArgument(Member); - return false; - } + if (ParamType->isMemberPointerType()) + return CheckTemplateArgumentPointerToMember(Arg, Converted); NamedDecl *Entity = 0; if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) @@ -2241,14 +2480,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return true; } - NamedDecl *Member = 0; - if (CheckTemplateArgumentPointerToMember(Arg, Member)) - return true; - - if (Member) - Member = cast<NamedDecl>(Member->getCanonicalDecl()); - Converted = TemplateArgument(Member); - return false; + return CheckTemplateArgumentPointerToMember(Arg, Converted); } /// \brief Check a template argument against its corresponding @@ -2257,9 +2489,14 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, /// This routine implements the semantics of C++ [temp.arg.template]. /// It returns true if an error occurred, and false otherwise. bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, - DeclRefExpr *Arg) { - assert(isa<TemplateDecl>(Arg->getDecl()) && "Only template decls allowed"); - TemplateDecl *Template = cast<TemplateDecl>(Arg->getDecl()); + const TemplateArgumentLoc &Arg) { + TemplateName Name = Arg.getArgument().getAsTemplate(); + TemplateDecl *Template = Name.getAsTemplateDecl(); + if (!Template) { + // Any dependent template name is fine. + assert(Name.isDependent() && "Non-dependent template isn't a declaration?"); + return false; + } // C++ [temp.arg.template]p1: // A template-argument for a template template-parameter shall be @@ -2276,15 +2513,16 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, !isa<TemplateTemplateParmDecl>(Template)) { assert(isa<FunctionTemplateDecl>(Template) && "Only function templates are possible here"); - Diag(Arg->getLocStart(), diag::err_template_arg_not_class_template); + Diag(Arg.getLocation(), diag::err_template_arg_not_class_template); Diag(Template->getLocation(), diag::note_template_arg_refers_here_func) << Template; } return !TemplateParameterListsAreEqual(Template->getTemplateParameters(), Param->getTemplateParameters(), - true, true, - Arg->getSourceRange().getBegin()); + true, + TPL_TemplateTemplateArgumentMatch, + Arg.getLocation()); } /// \brief Determine whether the given template parameter lists are @@ -2300,9 +2538,7 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, /// \param Complain If true, this routine will produce a diagnostic if /// the template parameter lists are not equivalent. /// -/// \param IsTemplateTemplateParm If true, this routine is being -/// called to compare the template parameter lists of a template -/// template parameter. +/// \param Kind describes how we are to match the template parameter lists. /// /// \param TemplateArgLoc If this source location is valid, then we /// are actually checking the template parameter list of a template @@ -2316,7 +2552,7 @@ bool Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, TemplateParameterList *Old, bool Complain, - bool IsTemplateTemplateParm, + TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc) { if (Old->size() != New->size()) { if (Complain) { @@ -2327,10 +2563,10 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, } Diag(New->getTemplateLoc(), NextDiag) << (New->size() > Old->size()) - << IsTemplateTemplateParm + << (Kind != TPL_TemplateMatch) << SourceRange(New->getTemplateLoc(), New->getRAngleLoc()); Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration) - << IsTemplateTemplateParm + << (Kind != TPL_TemplateMatch) << SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc()); } @@ -2348,9 +2584,9 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, NextDiag = diag::note_template_param_different_kind; } Diag((*NewParm)->getLocation(), NextDiag) - << IsTemplateTemplateParm; + << (Kind != TPL_TemplateMatch); Diag((*OldParm)->getLocation(), diag::note_template_prev_declaration) - << IsTemplateTemplateParm; + << (Kind != TPL_TemplateMatch); } return false; } @@ -2358,26 +2594,21 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, if (isa<TemplateTypeParmDecl>(*OldParm)) { // Okay; all template type parameters are equivalent (since we // know we're at the same index). -#if 0 - // FIXME: Enable this code in debug mode *after* we properly go through - // and "instantiate" the template parameter lists of template template - // parameters. It's only after this instantiation that (1) any dependent - // types within the template parameter list of the template template - // parameter can be checked, and (2) the template type parameter depths - // will match up. - QualType OldParmType - = Context.getTypeDeclType(cast<TemplateTypeParmDecl>(*OldParm)); - QualType NewParmType - = Context.getTypeDeclType(cast<TemplateTypeParmDecl>(*NewParm)); - assert(Context.getCanonicalType(OldParmType) == - Context.getCanonicalType(NewParmType) && - "type parameter mismatch?"); -#endif } else if (NonTypeTemplateParmDecl *OldNTTP = dyn_cast<NonTypeTemplateParmDecl>(*OldParm)) { // The types of non-type template parameters must agree. NonTypeTemplateParmDecl *NewNTTP = cast<NonTypeTemplateParmDecl>(*NewParm); + + // If we are matching a template template argument to a template + // template parameter and one of the non-type template parameter types + // is dependent, then we must wait until template instantiation time + // to actually compare the arguments. + if (Kind == TPL_TemplateTemplateArgumentMatch && + (OldNTTP->getType()->isDependentType() || + NewNTTP->getType()->isDependentType())) + continue; + if (Context.getCanonicalType(OldNTTP->getType()) != Context.getCanonicalType(NewNTTP->getType())) { if (Complain) { @@ -2389,7 +2620,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, } Diag(NewNTTP->getLocation(), NextDiag) << NewNTTP->getType() - << IsTemplateTemplateParm; + << (Kind != TPL_TemplateMatch); Diag(OldNTTP->getLocation(), diag::note_template_nontype_parm_prev_declaration) << OldNTTP->getType(); @@ -2399,7 +2630,6 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, } else { // The template parameter lists of template template // parameters must agree. - // FIXME: Could we perform a faster "type" comparison here? assert(isa<TemplateTemplateParmDecl>(*OldParm) && "Only template template parameters handled here"); TemplateTemplateParmDecl *OldTTP @@ -2409,7 +2639,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, if (!TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(), OldTTP->getTemplateParameters(), Complain, - /*IsTemplateTemplateParm=*/true, + (Kind == TPL_TemplateMatch? TPL_TemplateTemplateParmMatch : Kind), TemplateArgLoc)) return false; } @@ -2635,16 +2865,9 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs( } else if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>( TemplateParams->getParam(I))) { - // FIXME: We should settle on either Declaration storage or - // Expression storage for template template parameters. + TemplateName Name = ArgList[I].getAsTemplate(); TemplateTemplateParmDecl *ArgDecl - = dyn_cast_or_null<TemplateTemplateParmDecl>( - ArgList[I].getAsDecl()); - if (!ArgDecl) - if (DeclRefExpr *DRE - = dyn_cast_or_null<DeclRefExpr>(ArgList[I].getAsExpr())) - ArgDecl = dyn_cast<TemplateTemplateParmDecl>(DRE->getDecl()); - + = dyn_cast_or_null<TemplateTemplateParmDecl>(Name.getAsTemplateDecl()); if (!ArgDecl || ArgDecl->getIndex() != TTP->getIndex() || ArgDecl->getDepth() != TTP->getDepth()) @@ -2724,7 +2947,6 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, - SourceLocation *TemplateArgLocs, SourceLocation RAngleLoc, AttributeList *Attr, MultiTemplateParamsArg TemplateParameterLists) { @@ -2733,7 +2955,14 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // Find the class template we're specializing TemplateName Name = TemplateD.getAsVal<TemplateName>(); ClassTemplateDecl *ClassTemplate - = cast<ClassTemplateDecl>(Name.getAsTemplateDecl()); + = dyn_cast_or_null<ClassTemplateDecl>(Name.getAsTemplateDecl()); + + if (!ClassTemplate) { + Diag(TemplateNameLoc, diag::err_not_class_template_specialization) + << (Name.getAsTemplateDecl() && + isa<TemplateTemplateParmDecl>(Name.getAsTemplateDecl())); + return true; + } bool isExplicitSpecialization = false; bool isPartialSpecialization = false; @@ -2772,12 +3001,11 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, } } else { TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(Param); - if (Expr *DefArg = TTP->getDefaultArgument()) { - Diag(TTP->getDefaultArgumentLoc(), + if (TTP->hasDefaultArgument()) { + Diag(TTP->getDefaultArgument().getLocation(), diag::err_default_arg_in_partial_spec) - << DefArg->getSourceRange(); - TTP->setDefaultArgument(0); - DefArg->Destroy(Context); + << TTP->getDefaultArgument().getSourceRange(); + TTP->setDefaultArgument(TemplateArgumentLoc()); } } } @@ -2819,7 +3047,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // Translate the parser's template argument list in our AST format. llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs; - translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); + translateTemplateArguments(TemplateArgsIn, TemplateArgs); // Check that the template argument list is well-formed for this // template. @@ -3625,7 +3853,6 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, - SourceLocation *TemplateArgLocs, SourceLocation RAngleLoc, AttributeList *Attr) { // Find the class template we're specializing @@ -3664,7 +3891,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, // Translate the parser's template argument list in our AST format. llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs; - translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); + translateTemplateArguments(TemplateArgsIn, TemplateArgs); // Check that the template argument list is well-formed for this // template. @@ -3966,19 +4193,16 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition : TSK_ExplicitInstantiationDeclaration; - LookupResult Previous; - LookupParsedName(Previous, S, &D.getCXXScopeSpec(), - Name, LookupOrdinaryName); + LookupResult Previous(*this, Name, D.getIdentifierLoc(), LookupOrdinaryName); + LookupParsedName(Previous, S, &D.getCXXScopeSpec()); if (!R->isFunctionType()) { // C++ [temp.explicit]p1: // A [...] static data member of a class template can be explicitly // instantiated from the member definition associated with its class // template. - if (Previous.isAmbiguous()) { - return DiagnoseAmbiguousLookup(Previous, Name, D.getIdentifierLoc(), - D.getSourceRange()); - } + if (Previous.isAmbiguous()) + return true; VarDecl *Prev = dyn_cast_or_null<VarDecl>( Previous.getAsSingleDecl(Context)); @@ -4047,10 +4271,8 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, TemplateIdAnnotation *TemplateId = D.getName().TemplateId; ASTTemplateArgsPtr TemplateArgsPtr(*this, TemplateId->getTemplateArgs(), - TemplateId->getTemplateArgIsType(), TemplateId->NumArgs); translateTemplateArguments(TemplateArgsPtr, - TemplateId->getTemplateArgLocations(), TemplateArgs); HasExplicitTemplateArgs = true; TemplateArgsPtr.release(); @@ -4259,11 +4481,11 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, assert(Ctx && "No declaration context?"); DeclarationName Name(&II); - LookupResult Result; - LookupQualifiedName(Result, Ctx, Name, LookupOrdinaryName, false); + LookupResult Result(*this, Name, Range.getEnd(), LookupOrdinaryName); + LookupQualifiedName(Result, Ctx); unsigned DiagID = 0; Decl *Referenced = 0; - switch (Result.getKind()) { + switch (Result.getResultKind()) { case LookupResult::NotFound: DiagID = diag::err_typename_nested_not_found; break; @@ -4280,13 +4502,16 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, Referenced = Result.getFoundDecl(); break; + case LookupResult::FoundUnresolvedValue: + llvm::llvm_unreachable("unresolved using decl in non-dependent context"); + return QualType(); + case LookupResult::FoundOverloaded: DiagID = diag::err_typename_nested_not_type; Referenced = *Result.begin(); break; case LookupResult::Ambiguous: - DiagnoseAmbiguousLookup(Result, Name, Range.getEnd(), Range); return QualType(); } @@ -4436,12 +4661,24 @@ QualType Sema::RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc, std::string Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params, const TemplateArgumentList &Args) { + // FIXME: For variadic templates, we'll need to get the structured list. + return getTemplateArgumentBindingsText(Params, Args.getFlatArgumentList(), + Args.flat_size()); +} + +std::string +Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params, + const TemplateArgument *Args, + unsigned NumArgs) { std::string Result; - if (!Params || Params->size() == 0) + if (!Params || Params->size() == 0 || NumArgs == 0) return Result; for (unsigned I = 0, N = Params->size(); I != N; ++I) { + if (I >= NumArgs) + break; + if (I == 0) Result += "[with "; else @@ -4484,6 +4721,14 @@ Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params, break; } + case TemplateArgument::Template: { + std::string Str; + llvm::raw_string_ostream OS(Str); + Args[I].getAsTemplate().print(OS, Context.PrintingPolicy); + Result += OS.str(); + break; + } + case TemplateArgument::Integral: { Result += Args[I].getAsIntegral()->toString(10); break; diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 7b5ad7fc640e..10594c728fbe 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -126,7 +126,6 @@ DeduceNonTypeTemplateArgument(ASTContext &Context, /// from the given type- or value-dependent expression. /// /// \returns true if deduction succeeded, false otherwise. - static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument(ASTContext &Context, NonTypeTemplateParmDecl *NTTP, @@ -166,34 +165,87 @@ DeduceNonTypeTemplateArgument(ASTContext &Context, return Sema::TDK_Success; } +/// \brief Deduce the value of the given non-type template parameter +/// from the given declaration. +/// +/// \returns true if deduction succeeded, false otherwise. +static Sema::TemplateDeductionResult +DeduceNonTypeTemplateArgument(ASTContext &Context, + NonTypeTemplateParmDecl *NTTP, + Decl *D, + Sema::TemplateDeductionInfo &Info, + llvm::SmallVectorImpl<TemplateArgument> &Deduced) { + assert(NTTP->getDepth() == 0 && + "Cannot deduce non-type template argument with depth > 0"); + + if (Deduced[NTTP->getIndex()].isNull()) { + Deduced[NTTP->getIndex()] = TemplateArgument(D->getCanonicalDecl()); + return Sema::TDK_Success; + } + + if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Expression) { + // Okay, we deduced a declaration in one case and a dependent expression + // in another case. + return Sema::TDK_Success; + } + + if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Declaration) { + // Compare the declarations for equality + if (Deduced[NTTP->getIndex()].getAsDecl()->getCanonicalDecl() == + D->getCanonicalDecl()) + return Sema::TDK_Success; + + // FIXME: Fill in argument mismatch information + return Sema::TDK_NonDeducedMismatch; + } + + return Sema::TDK_Success; +} + static Sema::TemplateDeductionResult DeduceTemplateArguments(ASTContext &Context, + TemplateParameterList *TemplateParams, TemplateName Param, TemplateName Arg, Sema::TemplateDeductionInfo &Info, llvm::SmallVectorImpl<TemplateArgument> &Deduced) { - // FIXME: Implement template argument deduction for template - // template parameters. - - // FIXME: this routine does not have enough information to produce - // good diagnostics. - TemplateDecl *ParamDecl = Param.getAsTemplateDecl(); - TemplateDecl *ArgDecl = Arg.getAsTemplateDecl(); - - if (!ParamDecl || !ArgDecl) { - // FIXME: fill in Info.Param/Info.FirstArg - return Sema::TDK_Inconsistent; + if (!ParamDecl) { + // The parameter type is dependent and is not a template template parameter, + // so there is nothing that we can deduce. + return Sema::TDK_Success; } - - ParamDecl = cast<TemplateDecl>(ParamDecl->getCanonicalDecl()); - ArgDecl = cast<TemplateDecl>(ArgDecl->getCanonicalDecl()); - if (ParamDecl != ArgDecl) { - // FIXME: fill in Info.Param/Info.FirstArg + + if (TemplateTemplateParmDecl *TempParam + = dyn_cast<TemplateTemplateParmDecl>(ParamDecl)) { + // Bind the template template parameter to the given template name. + TemplateArgument &ExistingArg = Deduced[TempParam->getIndex()]; + if (ExistingArg.isNull()) { + // This is the first deduction for this template template parameter. + ExistingArg = TemplateArgument(Context.getCanonicalTemplateName(Arg)); + return Sema::TDK_Success; + } + + // Verify that the previous binding matches this deduction. + assert(ExistingArg.getKind() == TemplateArgument::Template); + if (Context.hasSameTemplateName(ExistingArg.getAsTemplate(), Arg)) + return Sema::TDK_Success; + + // Inconsistent deduction. + Info.Param = TempParam; + Info.FirstArg = ExistingArg; + Info.SecondArg = TemplateArgument(Arg); return Sema::TDK_Inconsistent; } - - return Sema::TDK_Success; + + // Verify that the two template names are equivalent. + if (Context.hasSameTemplateName(Param, Arg)) + return Sema::TDK_Success; + + // Mismatch of non-dependent template parameter to argument. + Info.FirstArg = TemplateArgument(Param); + Info.SecondArg = TemplateArgument(Arg); + return Sema::TDK_NonDeducedMismatch; } /// \brief Deduce the template arguments by comparing the template parameter @@ -224,32 +276,20 @@ DeduceTemplateArguments(ASTContext &Context, assert(Arg.isCanonical() && "Argument type must be canonical"); // Check whether the template argument is a dependent template-id. - // FIXME: This is untested code; it can be tested when we implement - // partial ordering of class template partial specializations. if (const TemplateSpecializationType *SpecArg = dyn_cast<TemplateSpecializationType>(Arg)) { // Perform template argument deduction for the template name. if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(Context, + = DeduceTemplateArguments(Context, TemplateParams, Param->getTemplateName(), SpecArg->getTemplateName(), Info, Deduced)) return Result; - unsigned NumArgs = Param->getNumArgs(); - - // FIXME: When one of the template-names refers to a - // declaration with default template arguments, do we need to - // fill in those default template arguments here? Most likely, - // the answer is "yes", but I don't see any references. This - // issue may be resolved elsewhere, because we may want to - // instantiate default template arguments when we actually write - // the template-id. - if (SpecArg->getNumArgs() != NumArgs) - return Sema::TDK_NonDeducedMismatch; // Perform template argument deduction on each template // argument. + unsigned NumArgs = std::min(SpecArg->getNumArgs(), Param->getNumArgs()); for (unsigned I = 0; I != NumArgs; ++I) if (Sema::TemplateDeductionResult Result = DeduceTemplateArguments(Context, TemplateParams, @@ -276,13 +316,12 @@ DeduceTemplateArguments(ASTContext &Context, // Perform template argument deduction for the template name. if (Sema::TemplateDeductionResult Result = DeduceTemplateArguments(Context, + TemplateParams, Param->getTemplateName(), TemplateName(SpecArg->getSpecializedTemplate()), Info, Deduced)) return Result; - // FIXME: Can the # of arguments in the parameter and the argument - // differ due to default arguments? unsigned NumArgs = Param->getNumArgs(); const TemplateArgumentList &ArgArgs = SpecArg->getTemplateArgs(); if (NumArgs != ArgArgs.size()) @@ -315,8 +354,8 @@ static QualType getUnqualifiedArrayType(ASTContext &Context, QualType T, Qualifiers &Quals) { assert(T.isCanonical() && "Only operates on canonical types"); if (!isa<ArrayType>(T)) { - Quals = T.getQualifiers(); - return T.getUnqualifiedType(); + Quals = T.getLocalQualifiers(); + return T.getLocalUnqualifiedType(); } assert(!T.hasQualifiers() && "canonical array type has qualifiers!"); @@ -639,9 +678,9 @@ DeduceTemplateArguments(ASTContext &Context, // template-name<T> (where template-name refers to a class template) // template-name<i> - // TT<T> (TODO) - // TT<i> (TODO) - // TT<> (TODO) + // TT<T> + // TT<i> + // TT<> case Type::TemplateSpecialization: { const TemplateSpecializationType *SpecParam = cast<TemplateSpecializationType>(Param); @@ -785,13 +824,28 @@ DeduceTemplateArguments(ASTContext &Context, break; case TemplateArgument::Type: - assert(Arg.getKind() == TemplateArgument::Type && "Type/value mismatch"); - return DeduceTemplateArguments(Context, TemplateParams, Param.getAsType(), - Arg.getAsType(), Info, Deduced, 0); - + if (Arg.getKind() == TemplateArgument::Type) + return DeduceTemplateArguments(Context, TemplateParams, Param.getAsType(), + Arg.getAsType(), Info, Deduced, 0); + Info.FirstArg = Param; + Info.SecondArg = Arg; + return Sema::TDK_NonDeducedMismatch; + + case TemplateArgument::Template: + if (Arg.getKind() == TemplateArgument::Template) + return DeduceTemplateArguments(Context, TemplateParams, + Param.getAsTemplate(), + Arg.getAsTemplate(), Info, Deduced); + Info.FirstArg = Param; + Info.SecondArg = Arg; + return Sema::TDK_NonDeducedMismatch; + case TemplateArgument::Declaration: - // FIXME: Implement this check - assert(false && "Unimplemented template argument deduction case"); + if (Arg.getKind() == TemplateArgument::Declaration && + Param.getAsDecl()->getCanonicalDecl() == + Arg.getAsDecl()->getCanonicalDecl()) + return Sema::TDK_Success; + Info.FirstArg = Param; Info.SecondArg = Arg; return Sema::TDK_NonDeducedMismatch; @@ -829,7 +883,10 @@ DeduceTemplateArguments(ASTContext &Context, if (Arg.getKind() == TemplateArgument::Expression) return DeduceNonTypeTemplateArgument(Context, NTTP, Arg.getAsExpr(), Info, Deduced); - + if (Arg.getKind() == TemplateArgument::Declaration) + return DeduceNonTypeTemplateArgument(Context, NTTP, Arg.getAsDecl(), + Info, Deduced); + assert(false && "Type/value mismatch"); Info.FirstArg = Param; Info.SecondArg = Arg; @@ -885,13 +942,21 @@ static bool isSameTemplateArg(ASTContext &Context, return X.getAsDecl()->getCanonicalDecl() == Y.getAsDecl()->getCanonicalDecl(); + case TemplateArgument::Template: + return Context.getCanonicalTemplateName(X.getAsTemplate()) + .getAsVoidPointer() == + Context.getCanonicalTemplateName(Y.getAsTemplate()) + .getAsVoidPointer(); + case TemplateArgument::Integral: return *X.getAsIntegral() == *Y.getAsIntegral(); - case TemplateArgument::Expression: - // FIXME: We assume that all expressions are distinct, but we should - // really check their canonical forms. - return false; + case TemplateArgument::Expression: { + llvm::FoldingSetNodeID XID, YID; + X.getAsExpr()->Profile(XID, Context, true); + Y.getAsExpr()->Profile(YID, Context, true); + return XID == YID; + } case TemplateArgument::Pack: if (X.pack_size() != Y.pack_size()) @@ -1030,15 +1095,6 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, Info.FirstArg = Partial->getTemplateArgs()[I]; return TDK_SubstitutionFailure; } - } else if (TemplateTemplateParmDecl *TTP - = dyn_cast<TemplateTemplateParmDecl>(Param)) { - // FIXME: template template arguments should really resolve to decls - DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InstExpr); - if (!DRE || CheckTemplateArgument(TTP, DRE)) { - Info.Param = makeTemplateParameter(Param); - Info.FirstArg = Partial->getTemplateArgs()[I]; - return TDK_SubstitutionFailure; - } } } @@ -1384,16 +1440,16 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // - If A is a cv-qualified type, the top level cv-qualifiers of A’s // type are ignored for type deduction. QualType CanonArgType = Context.getCanonicalType(ArgType); - if (CanonArgType.getCVRQualifiers()) - ArgType = CanonArgType.getUnqualifiedType(); + if (CanonArgType.getLocalCVRQualifiers()) + ArgType = CanonArgType.getLocalUnqualifiedType(); } } // C++0x [temp.deduct.call]p3: // If P is a cv-qualified type, the top level cv-qualifiers of P’s type // are ignored for type deduction. - if (CanonParamType.getCVRQualifiers()) - ParamType = CanonParamType.getUnqualifiedType(); + if (CanonParamType.getLocalCVRQualifiers()) + ParamType = CanonParamType.getLocalUnqualifiedType(); if (const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>()) { // [...] If P is a reference type, the type referred to by P is used // for type deduction. @@ -2074,6 +2130,7 @@ Sema::getMoreSpecializedPartialSpecialization( 0); // Determine whether PS2 is at least as specialized as PS1 + Deduced.clear(); Deduced.resize(PS1->getTemplateParameters()->size()); bool Better2 = !DeduceTemplateArgumentsDuringPartialOrdering(Context, PS1->getTemplateParameters(), @@ -2153,6 +2210,9 @@ MarkUsedTemplateParameters(Sema &SemaRef, return; } + if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) + MarkUsedTemplateParameters(SemaRef, QTN->getQualifier(), OnlyDeduced, + Depth, Used); if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) MarkUsedTemplateParameters(SemaRef, DTN->getQualifier(), OnlyDeduced, Depth, Used); @@ -2309,6 +2369,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, switch (TemplateArg.getKind()) { case TemplateArgument::Null: case TemplateArgument::Integral: + case TemplateArgument::Declaration: break; case TemplateArgument::Type: @@ -2316,12 +2377,9 @@ MarkUsedTemplateParameters(Sema &SemaRef, Depth, Used); break; - case TemplateArgument::Declaration: - if (TemplateTemplateParmDecl *TTP - = dyn_cast<TemplateTemplateParmDecl>(TemplateArg.getAsDecl())) { - if (TTP->getDepth() == Depth) - Used[TTP->getIndex()] = true; - } + case TemplateArgument::Template: + MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsTemplate(), + OnlyDeduced, Depth, Used); break; case TemplateArgument::Expression: diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index dfe37d8caf17..58fe59e321cf 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -28,11 +28,20 @@ using namespace clang; /// \brief Retrieve the template argument list(s) that should be used to /// instantiate the definition of the given declaration. +/// +/// \param D the declaration for which we are computing template instantiation +/// arguments. +/// +/// \param Innermost if non-NULL, the innermost template argument list. MultiLevelTemplateArgumentList -Sema::getTemplateInstantiationArgs(NamedDecl *D) { +Sema::getTemplateInstantiationArgs(NamedDecl *D, + const TemplateArgumentList *Innermost) { // Accumulate the set of template argument lists in this structure. MultiLevelTemplateArgumentList Result; + if (Innermost) + Result.addOuterTemplateArguments(Innermost); + DeclContext *Ctx = dyn_cast<DeclContext>(D); if (!Ctx) Ctx = D->getDeclContext(); @@ -87,6 +96,23 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D) { return Result; } +bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const { + switch (Kind) { + case TemplateInstantiation: + case DefaultTemplateArgumentInstantiation: + case DefaultFunctionArgumentInstantiation: + return true; + + case ExplicitTemplateArgumentSubstitution: + case DeducedTemplateArgumentSubstitution: + case PriorTemplateArgumentSubstitution: + case DefaultTemplateArgumentChecking: + return false; + } + + return true; +} + Sema::InstantiatingTemplate:: InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, Decl *Entity, @@ -104,7 +130,6 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, Inst.NumTemplateArgs = 0; Inst.InstantiationRange = InstantiationRange; SemaRef.ActiveTemplateInstantiations.push_back(Inst); - Invalid = false; } } @@ -128,7 +153,6 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, Inst.NumTemplateArgs = NumTemplateArgs; Inst.InstantiationRange = InstantiationRange; SemaRef.ActiveTemplateInstantiations.push_back(Inst); - Invalid = false; } } @@ -152,7 +176,9 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, Inst.NumTemplateArgs = NumTemplateArgs; Inst.InstantiationRange = InstantiationRange; SemaRef.ActiveTemplateInstantiations.push_back(Inst); - Invalid = false; + + if (!Inst.isInstantiationRecord()) + ++SemaRef.NonInstantiationEntries; } } @@ -164,48 +190,119 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, SourceRange InstantiationRange) : SemaRef(SemaRef) { - Invalid = CheckInstantiationDepth(PointOfInstantiation, - InstantiationRange); - if (!Invalid) { - ActiveTemplateInstantiation Inst; - Inst.Kind - = ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution; - Inst.PointOfInstantiation = PointOfInstantiation; - Inst.Entity = reinterpret_cast<uintptr_t>(PartialSpec); - Inst.TemplateArgs = TemplateArgs; - Inst.NumTemplateArgs = NumTemplateArgs; - Inst.InstantiationRange = InstantiationRange; - SemaRef.ActiveTemplateInstantiations.push_back(Inst); - Invalid = false; - } + Invalid = false; + + ActiveTemplateInstantiation Inst; + Inst.Kind = ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution; + Inst.PointOfInstantiation = PointOfInstantiation; + Inst.Entity = reinterpret_cast<uintptr_t>(PartialSpec); + Inst.TemplateArgs = TemplateArgs; + Inst.NumTemplateArgs = NumTemplateArgs; + Inst.InstantiationRange = InstantiationRange; + SemaRef.ActiveTemplateInstantiations.push_back(Inst); + + assert(!Inst.isInstantiationRecord()); + ++SemaRef.NonInstantiationEntries; } Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, - SourceLocation PointOfInstantation, + SourceLocation PointOfInstantiation, ParmVarDecl *Param, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceRange InstantiationRange) : SemaRef(SemaRef) { - Invalid = CheckInstantiationDepth(PointOfInstantation, InstantiationRange); + Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); if (!Invalid) { ActiveTemplateInstantiation Inst; Inst.Kind = ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation; - Inst.PointOfInstantiation = PointOfInstantation; + Inst.PointOfInstantiation = PointOfInstantiation; Inst.Entity = reinterpret_cast<uintptr_t>(Param); Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; Inst.InstantiationRange = InstantiationRange; SemaRef.ActiveTemplateInstantiations.push_back(Inst); - Invalid = false; } } +Sema::InstantiatingTemplate:: +InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + TemplateDecl *Template, + NonTypeTemplateParmDecl *Param, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceRange InstantiationRange) : SemaRef(SemaRef) { + Invalid = false; + + ActiveTemplateInstantiation Inst; + Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution; + Inst.PointOfInstantiation = PointOfInstantiation; + Inst.Template = Template; + Inst.Entity = reinterpret_cast<uintptr_t>(Param); + Inst.TemplateArgs = TemplateArgs; + Inst.NumTemplateArgs = NumTemplateArgs; + Inst.InstantiationRange = InstantiationRange; + SemaRef.ActiveTemplateInstantiations.push_back(Inst); + + assert(!Inst.isInstantiationRecord()); + ++SemaRef.NonInstantiationEntries; +} + +Sema::InstantiatingTemplate:: +InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + TemplateDecl *Template, + TemplateTemplateParmDecl *Param, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceRange InstantiationRange) : SemaRef(SemaRef) { + Invalid = false; + ActiveTemplateInstantiation Inst; + Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution; + Inst.PointOfInstantiation = PointOfInstantiation; + Inst.Template = Template; + Inst.Entity = reinterpret_cast<uintptr_t>(Param); + Inst.TemplateArgs = TemplateArgs; + Inst.NumTemplateArgs = NumTemplateArgs; + Inst.InstantiationRange = InstantiationRange; + SemaRef.ActiveTemplateInstantiations.push_back(Inst); + + assert(!Inst.isInstantiationRecord()); + ++SemaRef.NonInstantiationEntries; +} + +Sema::InstantiatingTemplate:: +InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + TemplateDecl *Template, + NamedDecl *Param, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceRange InstantiationRange) : SemaRef(SemaRef) { + Invalid = false; + + ActiveTemplateInstantiation Inst; + Inst.Kind = ActiveTemplateInstantiation::DefaultTemplateArgumentChecking; + Inst.PointOfInstantiation = PointOfInstantiation; + Inst.Template = Template; + Inst.Entity = reinterpret_cast<uintptr_t>(Param); + Inst.TemplateArgs = TemplateArgs; + Inst.NumTemplateArgs = NumTemplateArgs; + Inst.InstantiationRange = InstantiationRange; + SemaRef.ActiveTemplateInstantiations.push_back(Inst); + + assert(!Inst.isInstantiationRecord()); + ++SemaRef.NonInstantiationEntries; +} + void Sema::InstantiatingTemplate::Clear() { if (!Invalid) { + if (!SemaRef.ActiveTemplateInstantiations.back().isInstantiationRecord()) { + assert(SemaRef.NonInstantiationEntries > 0); + --SemaRef.NonInstantiationEntries; + } + SemaRef.ActiveTemplateInstantiations.pop_back(); Invalid = true; } @@ -214,8 +311,11 @@ void Sema::InstantiatingTemplate::Clear() { bool Sema::InstantiatingTemplate::CheckInstantiationDepth( SourceLocation PointOfInstantiation, SourceRange InstantiationRange) { - if (SemaRef.ActiveTemplateInstantiations.size() - <= SemaRef.getLangOptions().InstantiationDepth) + assert(SemaRef.NonInstantiationEntries <= + SemaRef.ActiveTemplateInstantiations.size()); + if ((SemaRef.ActiveTemplateInstantiations.size() - + SemaRef.NonInstantiationEntries) + <= SemaRef.getLangOptions().InstantiationDepth) return false; SemaRef.Diag(PointOfInstantiation, @@ -322,6 +422,34 @@ void Sema::PrintInstantiationStack() { break; } + case ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution: { + NamedDecl *Parm = cast<NamedDecl>((Decl *)Active->Entity); + std::string Name; + if (!Parm->getName().empty()) + Name = std::string(" '") + Parm->getName().str() + "'"; + + Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + diag::note_prior_template_arg_substitution) + << isa<TemplateTemplateParmDecl>(Parm) + << Name + << getTemplateArgumentBindingsText( + Active->Template->getTemplateParameters(), + Active->TemplateArgs, + Active->NumTemplateArgs) + << Active->InstantiationRange; + break; + } + + case ActiveTemplateInstantiation::DefaultTemplateArgumentChecking: { + Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + diag::note_template_default_arg_checking) + << getTemplateArgumentBindingsText( + Active->Template->getTemplateParameters(), + Active->TemplateArgs, + Active->NumTemplateArgs) + << Active->InstantiationRange; + break; + } } } } @@ -332,18 +460,20 @@ bool Sema::isSFINAEContext() const { Active = ActiveTemplateInstantiations.rbegin(), ActiveEnd = ActiveTemplateInstantiations.rend(); Active != ActiveEnd; - ++Active) { - + ++Active) + { switch(Active->Kind) { case ActiveTemplateInstantiation::TemplateInstantiation: case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation: - // This is a template instantiation, so there is no SFINAE. return false; case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation: - // A default template argument instantiation may or may not be a - // SFINAE context; look further up the stack. + case ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution: + case ActiveTemplateInstantiation::DefaultTemplateArgumentChecking: + // A default template argument instantiation and substitution into + // template parameters with arguments for prior parameters may or may + // not be a SFINAE context; look further up the stack. break; case ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution: @@ -427,6 +557,9 @@ namespace { Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E, bool isAddressOfOperand); + Sema::OwningExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E, + bool isAddressOfOperand); + /// \brief Transforms a template type parameter type by performing /// substitution of the corresponding template type argument. QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, @@ -440,10 +573,11 @@ Decl *TemplateInstantiator::TransformDecl(Decl *D) { if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) { if (TTP->getDepth() < TemplateArgs.getNumLevels()) { - assert(TemplateArgs(TTP->getDepth(), TTP->getPosition()).getAsDecl() && + TemplateName Template + = TemplateArgs(TTP->getDepth(), TTP->getPosition()).getAsTemplate(); + assert(!Template.isNull() && Template.getAsTemplateDecl() && "Wrong kind of template template argument"); - return cast<TemplateDecl>(TemplateArgs(TTP->getDepth(), - TTP->getPosition()).getAsDecl()); + return Template.getAsTemplateDecl(); } // If the corresponding template argument is NULL or non-existent, it's @@ -454,9 +588,8 @@ Decl *TemplateInstantiator::TransformDecl(Decl *D) { TTP->getPosition())) return D; - // FIXME: Implement depth reduction of template template parameters - assert(false && - "Reducing depth of template template parameters is not yet implemented"); + // Fall through to find the instantiated declaration for this template + // template parameter. } return SemaRef.FindInstantiatedDecl(cast<NamedDecl>(D), TemplateArgs); @@ -567,7 +700,6 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E, NamedDecl *D = E->getDecl(); if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) { if (NTTP->getDepth() < TemplateArgs.getNumLevels()) { - // If the corresponding template argument is NULL or non-existent, it's // because we are performing instantiation from explicitly-specified // template arguments in a function template, but there were some @@ -592,7 +724,38 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E, if (!VD) return SemaRef.ExprError(); - return SemaRef.BuildDeclRefExpr(VD, VD->getType(), E->getLocation(), + if (VD->getDeclContext()->isRecord()) { + // If the value is a class member, we might have a pointer-to-member. + // Determine whether the non-type template template parameter is of + // pointer-to-member type. If so, we need to build an appropriate + // expression for a pointer-to-member, since a "normal" DeclRefExpr + // would refer to the member itself. + if (NTTP->getType()->isMemberPointerType()) { + QualType ClassType + = SemaRef.Context.getTypeDeclType( + cast<RecordDecl>(VD->getDeclContext())); + NestedNameSpecifier *Qualifier + = NestedNameSpecifier::Create(SemaRef.Context, 0, false, + ClassType.getTypePtr()); + CXXScopeSpec SS; + SS.setScopeRep(Qualifier); + OwningExprResult RefExpr + = SemaRef.BuildDeclRefExpr(VD, + VD->getType().getNonReferenceType(), + E->getLocation(), + /*FIXME:*/false, /*FIXME:*/false, + &SS); + if (RefExpr.isInvalid()) + return SemaRef.ExprError(); + + return SemaRef.CreateBuiltinUnaryOp(E->getLocation(), + UnaryOperator::AddrOf, + move(RefExpr)); + } + } + + return SemaRef.BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), + E->getLocation(), /*FIXME:*/false, /*FIXME:*/false); } @@ -625,10 +788,46 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E, if (!InstD) return SemaRef.ExprError(); - // If we instantiated an UnresolvedUsingDecl and got back an UsingDecl, - // we need to get the underlying decl. - // FIXME: Is this correct? Maybe FindInstantiatedDecl should do this? - InstD = InstD->getUnderlyingDecl(); + // Flatten using declarations into their shadow declarations. + if (isa<UsingDecl>(InstD)) { + UsingDecl *UD = cast<UsingDecl>(InstD); + + bool HasNonFunction = false; + + llvm::SmallVector<NamedDecl*, 8> Decls; + for (UsingDecl::shadow_iterator I = UD->shadow_begin(), + E = UD->shadow_end(); I != E; ++I) { + NamedDecl *TD = (*I)->getTargetDecl(); + if (!TD->isFunctionOrFunctionTemplate()) + HasNonFunction = true; + + Decls.push_back(TD); + } + + if (Decls.empty()) + return SemaRef.ExprError(); + + if (Decls.size() == 1) + InstD = Decls[0]; + else if (!HasNonFunction) { + OverloadedFunctionDecl *OFD + = OverloadedFunctionDecl::Create(SemaRef.Context, + UD->getDeclContext(), + UD->getDeclName()); + for (llvm::SmallVectorImpl<NamedDecl*>::iterator I = Decls.begin(), + E = Decls.end(); I != E; ++I) + if (isa<FunctionDecl>(*I)) + OFD->addOverload(cast<FunctionDecl>(*I)); + else + OFD->addOverload(cast<FunctionTemplateDecl>(*I)); + + InstD = OFD; + } else { + // FIXME + assert(false && "using declaration resolved to mixed set"); + return SemaRef.ExprError(); + } + } CXXScopeSpec SS; NestedNameSpecifier *Qualifier = 0; @@ -648,6 +847,15 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E, isAddressOfOperand); } +Sema::OwningExprResult TemplateInstantiator::TransformCXXDefaultArgExpr( + CXXDefaultArgExpr *E, bool isAddressOfOperand) { + assert(!cast<FunctionDecl>(E->getParam()->getDeclContext())-> + getDescribedFunctionTemplate() && + "Default arg expressions are never formed in dependent cases."); + return SemaRef.Owned(E->Retain()); +} + + QualType TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, TemplateTypeParmTypeLoc TL) { @@ -889,9 +1097,9 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Member != MemberEnd; ++Member) { Decl *NewMember = SubstDecl(*Member, Instantiation, TemplateArgs); if (NewMember) { - if (NewMember->isInvalidDecl()) + if (NewMember->isInvalidDecl()) { Invalid = true; - else if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) + } else if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) Fields.push_back(DeclPtrTy::make(Field)); else if (UsingDecl *UD = dyn_cast<UsingDecl>(NewMember)) Instantiation->addDecl(UD); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 7288ae29a0e3..7e618cd4faea 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===/ #include "Sema.h" +#include "Lookup.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" @@ -28,6 +29,8 @@ namespace { DeclContext *Owner; const MultiLevelTemplateArgumentList &TemplateArgs; + void InstantiateAttrs(Decl *Tmpl, Decl *New); + public: typedef Sema::OwningExprResult OwningExprResult; @@ -62,11 +65,19 @@ namespace { Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *D); Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); - Decl *VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D); + Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); + Decl *VisitUsingDirectiveDecl(UsingDirectiveDecl *D); + Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); + Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); // Base case. FIXME: Remove once we can instantiate everything. - Decl *VisitDecl(Decl *) { - assert(false && "Template instantiation of unknown declaration kind!"); + Decl *VisitDecl(Decl *D) { + unsigned DiagID = SemaRef.getDiagnostics().getCustomDiagID( + Diagnostic::Error, + "cannot instantiate %0 yet"); + SemaRef.Diag(D->getLocation(), DiagID) + << D->getDeclKindName(); + return 0; } @@ -89,6 +100,18 @@ namespace { }; } +// FIXME: Is this too simple? +void TemplateDeclInstantiator::InstantiateAttrs(Decl *Tmpl, Decl *New) { + for (const Attr *TmplAttr = Tmpl->getAttrs(); TmplAttr; + TmplAttr = TmplAttr->getNext()) { + + // FIXME: Is cloning correct for all attributes? + Attr *NewAttr = TmplAttr->clone(SemaRef.Context); + + New->addAttr(NewAttr); + } +} + Decl * TemplateDeclInstantiator::VisitTranslationUnitDecl(TranslationUnitDecl *D) { assert(false && "Translation units cannot be instantiated"); @@ -172,6 +195,15 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { = SemaRef.SubstExpr(D->getInit(), TemplateArgs); if (Init.isInvalid()) Var->setInvalidDecl(); + else if (!D->getType()->isDependentType() && + !D->getInit()->isTypeDependent() && + !D->getInit()->isValueDependent()) { + // If neither the declaration's type nor its initializer are dependent, + // we don't want to redo all the checking, especially since the + // initializer might have been wrapped by a CXXConstructExpr since we did + // it the first time. + Var->setInit(SemaRef.Context, Init.takeAs<Expr>()); + } else if (ParenListExpr *PLE = dyn_cast<ParenListExpr>((Expr *)Init.get())) { // FIXME: We're faking all of the comma locations, which is suboptimal. // Do we even need these comma locations? @@ -258,6 +290,8 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { return 0; } + InstantiateAttrs(D, Field); + if (Invalid) Field->setInvalidDecl(); @@ -632,6 +666,12 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { TemplateParams, Function); Function->setDescribedFunctionTemplate(FunctionTemplate); FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext()); + } else if (FunctionTemplate) { + // Record this function template specialization. + Function->setFunctionTemplateSpecialization(SemaRef.Context, + FunctionTemplate, + &TemplateArgs.getInnermost(), + InsertPos); } if (InitFunctionInstantiation(Function, D)) @@ -645,9 +685,10 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { // Look only into the namespace where the friend would be declared to // find a previous declaration. This is the innermost enclosing namespace, // as described in ActOnFriendFunctionDecl. - Sema::LookupResult R; - SemaRef.LookupQualifiedName(R, DC, Function->getDeclName(), - Sema::LookupOrdinaryName, true); + LookupResult R(SemaRef, Function->getDeclName(), SourceLocation(), + Sema::LookupOrdinaryName, + Sema::ForRedeclaration); + SemaRef.LookupQualifiedName(R, DC); PrevDecl = R.getAsSingleDecl(SemaRef.Context); @@ -683,14 +724,6 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); } - if (FunctionTemplate && !TemplateParams) { - // Record this function template specialization. - Function->setFunctionTemplateSpecialization(SemaRef.Context, - FunctionTemplate, - &TemplateArgs.getInnermost(), - InsertPos); - } - return Function; } @@ -785,9 +818,17 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, if (D->isOutOfLine()) FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext()); Method->setDescribedFunctionTemplate(FunctionTemplate); - } else if (!FunctionTemplate) + } else if (FunctionTemplate) { + // Record this function template specialization. + Method->setFunctionTemplateSpecialization(SemaRef.Context, + FunctionTemplate, + &TemplateArgs.getInnermost(), + InsertPos); + } else { + // Record that this is an instantiation of a member function. Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); - + } + // If we are instantiating a member function defined // out-of-line, the instantiation will have the same lexical // context (which will be a namespace scope) as the template. @@ -805,8 +846,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, NamedDecl *PrevDecl = 0; if (!FunctionTemplate || TemplateParams) { - Sema::LookupResult R; - SemaRef.LookupQualifiedName(R, Owner, Name, Sema::LookupOrdinaryName, true); + LookupResult R(SemaRef, Name, SourceLocation(), + Sema::LookupOrdinaryName, + Sema::ForRedeclaration); + SemaRef.LookupQualifiedName(R, Owner); PrevDecl = R.getAsSingleDecl(SemaRef.Context); // In C++, the previous declaration we find might be a tag type @@ -817,13 +860,6 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, PrevDecl = 0; } - if (FunctionTemplate && !TemplateParams) - // Record this function template specialization. - Method->setFunctionTemplateSpecialization(SemaRef.Context, - FunctionTemplate, - &TemplateArgs.getInnermost(), - InsertPos); - bool Redeclaration = false; bool OverloadableAttrRequired = false; SemaRef.CheckFunctionDeclaration(Method, PrevDecl, false, Redeclaration, @@ -898,18 +934,8 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( D->wasDeclaredWithTypename(), D->isParameterPack()); - // FIXME: Do we actually want to perform substitution here? I don't think - // we do. - if (D->hasDefaultArgument()) { - DeclaratorInfo *DefaultPattern = D->getDefaultArgumentInfo(); - DeclaratorInfo *DefaultInst - = SemaRef.SubstType(DefaultPattern, TemplateArgs, - D->getDefaultArgumentLoc(), - D->getDeclName()); - - Inst->setDefaultArgument(DefaultInst, - D->defaultArgumentWasInherited() /* preserve? */); - } + if (D->hasDefaultArgument()) + Inst->setDefaultArgument(D->getDefaultArgumentInfo(), false); // Introduce this template parameter's instantiation into the instantiation // scope. @@ -959,7 +985,75 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( } Decl * -TemplateDeclInstantiator::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) { +TemplateDeclInstantiator::VisitTemplateTemplateParmDecl( + TemplateTemplateParmDecl *D) { + // Instantiate the template parameter list of the template template parameter. + TemplateParameterList *TempParams = D->getTemplateParameters(); + TemplateParameterList *InstParams; + { + // Perform the actual substitution of template parameters within a new, + // local instantiation scope. + Sema::LocalInstantiationScope Scope(SemaRef); + InstParams = SubstTemplateParams(TempParams); + if (!InstParams) + return NULL; + } + + // Build the template template parameter. + TemplateTemplateParmDecl *Param + = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner, D->getLocation(), + D->getDepth() - 1, D->getPosition(), + D->getIdentifier(), InstParams); + Param->setDefaultArgument(D->getDefaultArgument()); + + // Introduce this template parameter's instantiation into the instantiation + // scope. + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param); + + return Param; +} + +Decl *TemplateDeclInstantiator::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { + // Using directives are never dependent, so they require no explicit + + UsingDirectiveDecl *Inst + = UsingDirectiveDecl::Create(SemaRef.Context, Owner, D->getLocation(), + D->getNamespaceKeyLocation(), + D->getQualifierRange(), D->getQualifier(), + D->getIdentLocation(), + D->getNominatedNamespace(), + D->getCommonAncestor()); + Owner->addDecl(Inst); + return Inst; +} + +Decl * TemplateDeclInstantiator + ::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { + NestedNameSpecifier *NNS = + SemaRef.SubstNestedNameSpecifier(D->getTargetNestedNameSpecifier(), + D->getTargetNestedNameRange(), + TemplateArgs); + if (!NNS) + return 0; + + CXXScopeSpec SS; + SS.setRange(D->getTargetNestedNameRange()); + SS.setScopeRep(NNS); + + NamedDecl *UD = + SemaRef.BuildUsingDeclaration(/*Scope*/ 0, D->getAccess(), + D->getUsingLoc(), SS, D->getLocation(), + D->getDeclName(), 0, + /*instantiation*/ true, + /*typename*/ true, D->getTypenameLoc()); + if (UD) + SemaRef.Context.setInstantiatedFromUnresolvedUsingDecl(cast<UsingDecl>(UD), + D); + return UD; +} + +Decl * TemplateDeclInstantiator + ::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { NestedNameSpecifier *NNS = SemaRef.SubstNestedNameSpecifier(D->getTargetNestedNameSpecifier(), D->getTargetNestedNameRange(), @@ -972,9 +1066,11 @@ TemplateDeclInstantiator::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) { SS.setScopeRep(NNS); NamedDecl *UD = - SemaRef.BuildUsingDeclaration(D->getLocation(), SS, - D->getTargetNameLocation(), - D->getTargetName(), 0, D->isTypeName()); + SemaRef.BuildUsingDeclaration(/*Scope*/ 0, D->getAccess(), + D->getUsingLoc(), SS, D->getLocation(), + D->getDeclName(), 0, + /*instantiation*/ true, + /*typename*/ false, SourceLocation()); if (UD) SemaRef.Context.setInstantiatedFromUnresolvedUsingDecl(cast<UsingDecl>(UD), D); @@ -1006,7 +1102,7 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) { PI != PE; ++PI) { NamedDecl *D = cast_or_null<NamedDecl>(Visit(*PI)); Params.push_back(D); - Invalid = Invalid || !D; + Invalid = Invalid || !D || D->isInvalidDecl(); } // Clean up if we had an error. @@ -1240,6 +1336,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, (void) FunTmpl; ActiveInst.Kind = ActiveInstType::TemplateInstantiation; ActiveInst.Entity = reinterpret_cast<uintptr_t>(New); + --SemaRef.NonInstantiationEntries; } } @@ -1656,7 +1753,13 @@ static bool isInstantiationOf(EnumDecl *Pattern, return false; } -static bool isInstantiationOf(UnresolvedUsingDecl *Pattern, +static bool isInstantiationOf(UnresolvedUsingValueDecl *Pattern, + UsingDecl *Instance, + ASTContext &C) { + return C.getInstantiatedFromUnresolvedUsingDecl(Instance) == Pattern; +} + +static bool isInstantiationOf(UnresolvedUsingTypenameDecl *Pattern, UsingDecl *Instance, ASTContext &C) { return C.getInstantiatedFromUnresolvedUsingDecl(Instance) == Pattern; @@ -1679,7 +1782,15 @@ static bool isInstantiationOfStaticDataMember(VarDecl *Pattern, static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { if (D->getKind() != Other->getKind()) { - if (UnresolvedUsingDecl *UUD = dyn_cast<UnresolvedUsingDecl>(D)) { + if (UnresolvedUsingTypenameDecl *UUD + = dyn_cast<UnresolvedUsingTypenameDecl>(D)) { + if (UsingDecl *UD = dyn_cast<UsingDecl>(Other)) { + return isInstantiationOf(UUD, UD, Ctx); + } + } + + if (UnresolvedUsingValueDecl *UUD + = dyn_cast<UnresolvedUsingValueDecl>(D)) { if (UsingDecl *UD = dyn_cast<UsingDecl>(Other)) { return isInstantiationOf(UUD, UD, Ctx); } diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index f003127f149f..00dc809f51a8 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -229,7 +229,8 @@ static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){ case DeclSpec::TST_enum: case DeclSpec::TST_union: case DeclSpec::TST_struct: { - TypeDecl *D = cast_or_null<TypeDecl>(static_cast<Decl *>(DS.getTypeRep())); + TypeDecl *D + = dyn_cast_or_null<TypeDecl>(static_cast<Decl *>(DS.getTypeRep())); if (!D) { // This can happen in C++ with ambiguous lookups. Result = Context.IntTy; @@ -1703,7 +1704,7 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, // 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>()) + if (const ConstantArrayType *Array = Context.getAsConstantArrayType(T)) MaybeTemplate = Array->getElementType(); if (const RecordType *Record = MaybeTemplate->getAs<RecordType>()) { if (ClassTemplateSpecializationDecl *ClassTemplateSpec diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 767725a1f318..2bee32aa0fc8 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1063,8 +1063,18 @@ public: /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildInitList(SourceLocation LBraceLoc, MultiExprArg Inits, - SourceLocation RBraceLoc) { - return SemaRef.ActOnInitList(LBraceLoc, move(Inits), RBraceLoc); + SourceLocation RBraceLoc, + QualType ResultTy) { + OwningExprResult Result + = SemaRef.ActOnInitList(LBraceLoc, move(Inits), RBraceLoc); + if (Result.isInvalid() || ResultTy->isDependentType()) + return move(Result); + + // Patch in the result type we were given, which may have been computed + // when the initial InitListExpr was built. + InitListExpr *ILE = cast<InitListExpr>((Expr *)Result.get()); + ILE->setType(ResultTy); + return move(Result); } /// \brief Build a new designated initializer expression. @@ -1699,7 +1709,7 @@ Sema::OwningStmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) { if (E.isInvalid()) return getSema().StmtError(); - return getSema().Owned(E.takeAs<Stmt>()); + return getSema().ActOnExprStmt(getSema().FullExpr(E)); } } @@ -1947,6 +1957,10 @@ void TreeTransform<Derived>::InventTemplateArgumentLoc( break; + case TemplateArgument::Template: + Output = TemplateArgumentLoc(Arg, SourceRange(), Loc); + break; + case TemplateArgument::Expression: Output = TemplateArgumentLoc(Arg, Arg.getAsExpr()); break; @@ -1987,7 +2001,7 @@ bool TreeTransform<Derived>::TransformTemplateArgument( DeclarationName Name; if (NamedDecl *ND = dyn_cast<NamedDecl>(Arg.getAsDecl())) Name = ND->getDeclName(); - TemporaryBase Rebase(*this, SourceLocation(), Name); + TemporaryBase Rebase(*this, Input.getLocation(), Name); Decl *D = getDerived().TransformDecl(Arg.getAsDecl()); if (!D) return true; @@ -2008,6 +2022,19 @@ bool TreeTransform<Derived>::TransformTemplateArgument( return false; } + case TemplateArgument::Template: { + TemporaryBase Rebase(*this, Input.getLocation(), DeclarationName()); + TemplateName Template + = getDerived().TransformTemplateName(Arg.getAsTemplate()); + if (Template.isNull()) + return true; + + Output = TemplateArgumentLoc(TemplateArgument(Template), + Input.getTemplateQualifierRange(), + Input.getTemplateNameLoc()); + return false; + } + case TemplateArgument::Expression: { // Template argument expressions are not potentially evaluated. EnterExpressionEvaluationContext Unevaluated(getSema(), @@ -2119,7 +2146,7 @@ template<typename Derived> QualType TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB, QualifiedTypeLoc T) { - Qualifiers Quals = T.getType().getQualifiers(); + Qualifiers Quals = T.getType().getLocalQualifiers(); QualType Result = getDerived().TransformType(TLB, T.getUnqualifiedLoc()); if (Result.isNull()) @@ -3893,7 +3920,7 @@ TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E, return SemaRef.Owned(E->Retain()); return getDerived().RebuildInitList(E->getLBraceLoc(), move_arg(Inits), - E->getRBraceLoc()); + E->getRBraceLoc(), E->getType()); } template<typename Derived> @@ -5279,7 +5306,7 @@ TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, QualType T) { if (T->isDependentType() || T->isRecordType() || (SemaRef.getLangOptions().CPlusPlus0x && T->isEnumeralType())) { - assert(!T.hasQualifiers() && "Can't get cv-qualifiers here"); + assert(!T.hasLocalQualifiers() && "Can't get cv-qualifiers here"); return NestedNameSpecifier::Create(SemaRef.Context, Prefix, TemplateKW, T.getTypePtr()); } @@ -5363,6 +5390,9 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, return getSema().CreateBuiltinArraySubscriptExpr(move(First), DRE->getLocStart(), move(Second), OpLoc); + } else if (Op == OO_Arrow) { + // -> is never a builtin operation. + return SemaRef.BuildOverloadedArrowExpr(0, move(First), OpLoc); } else if (SecondExpr == 0 || isPostIncDec) { if (!FirstExpr->getType()->isOverloadableType()) { // The argument is not of overloadable type, so try to create a |