diff options
Diffstat (limited to 'lib')
164 files changed, 12940 insertions, 5509 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 6c9ecf0..cc7055d 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -260,24 +260,40 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl, } NamedDecl * -ASTContext::getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD) { +ASTContext::getInstantiatedFromUsingDecl(UsingDecl *UUD) { llvm::DenseMap<UsingDecl *, NamedDecl *>::const_iterator Pos - = InstantiatedFromUnresolvedUsingDecl.find(UUD); - if (Pos == InstantiatedFromUnresolvedUsingDecl.end()) + = InstantiatedFromUsingDecl.find(UUD); + if (Pos == InstantiatedFromUsingDecl.end()) return 0; return Pos->second; } void -ASTContext::setInstantiatedFromUnresolvedUsingDecl(UsingDecl *UD, - 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; +ASTContext::setInstantiatedFromUsingDecl(UsingDecl *Inst, NamedDecl *Pattern) { + assert((isa<UsingDecl>(Pattern) || + isa<UnresolvedUsingValueDecl>(Pattern) || + isa<UnresolvedUsingTypenameDecl>(Pattern)) && + "pattern decl is not a using decl"); + assert(!InstantiatedFromUsingDecl[Inst] && "pattern already exists"); + InstantiatedFromUsingDecl[Inst] = Pattern; +} + +UsingShadowDecl * +ASTContext::getInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst) { + llvm::DenseMap<UsingShadowDecl*, UsingShadowDecl*>::const_iterator Pos + = InstantiatedFromUsingShadowDecl.find(Inst); + if (Pos == InstantiatedFromUsingShadowDecl.end()) + return 0; + + return Pos->second; +} + +void +ASTContext::setInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst, + UsingShadowDecl *Pattern) { + assert(!InstantiatedFromUsingShadowDecl[Inst] && "pattern already exists"); + InstantiatedFromUsingShadowDecl[Inst] = Pattern; } FieldDecl *ASTContext::getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field) { @@ -711,10 +727,6 @@ ASTContext::getTypeInfo(const Type *T) { break; } case Type::MemberPointer: { - // FIXME: This is ABI dependent. We use the Itanium C++ ABI. - // http://www.codesourcery.com/public/cxx-abi/abi.html#member-pointers - // If we ever want to support other ABIs this needs to be abstracted. - QualType Pointee = cast<MemberPointerType>(T)->getPointeeType(); std::pair<uint64_t, unsigned> PtrDiffInfo = getTypeInfo(getPointerDiffType()); @@ -997,31 +1009,31 @@ void ASTContext::setObjCImplementation(ObjCCategoryDecl *CatD, ObjCImpls[CatD] = ImplD; } -/// \brief Allocate an uninitialized DeclaratorInfo. +/// \brief Allocate an uninitialized TypeSourceInfo. /// -/// The caller should initialize the memory held by DeclaratorInfo using +/// The caller should initialize the memory held by TypeSourceInfo using /// the TypeLoc wrappers. /// /// \param T the type that will be the basis for type source info. This type /// should refer to how the declarator was written in source code, not to /// what type semantic analysis resolved the declarator to. -DeclaratorInfo *ASTContext::CreateDeclaratorInfo(QualType T, +TypeSourceInfo *ASTContext::CreateTypeSourceInfo(QualType T, unsigned DataSize) { if (!DataSize) DataSize = TypeLoc::getFullDataSizeForType(T); else assert(DataSize == TypeLoc::getFullDataSizeForType(T) && - "incorrect data size provided to CreateDeclaratorInfo!"); + "incorrect data size provided to CreateTypeSourceInfo!"); - DeclaratorInfo *DInfo = - (DeclaratorInfo*)BumpAlloc.Allocate(sizeof(DeclaratorInfo) + DataSize, 8); - new (DInfo) DeclaratorInfo(T); - return DInfo; + TypeSourceInfo *TInfo = + (TypeSourceInfo*)BumpAlloc.Allocate(sizeof(TypeSourceInfo) + DataSize, 8); + new (TInfo) TypeSourceInfo(T); + return TInfo; } -DeclaratorInfo *ASTContext::getTrivialDeclaratorInfo(QualType T, +TypeSourceInfo *ASTContext::getTrivialTypeSourceInfo(QualType T, SourceLocation L) { - DeclaratorInfo *DI = CreateDeclaratorInfo(T); + TypeSourceInfo *DI = CreateTypeSourceInfo(T); DI->getTypeLoc().initialize(L); return DI; } @@ -1092,6 +1104,20 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { return *NewEntry; } +const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) { + RD = cast<CXXRecordDecl>(RD->getDefinition(*this)); + assert(RD && "Cannot get key function for forward declarations!"); + + const CXXMethodDecl *&Entry = KeyFunctions[RD]; + if (!Entry) + Entry = ASTRecordLayoutBuilder::ComputeKeyFunction(RD); + else + assert(Entry == ASTRecordLayoutBuilder::ComputeKeyFunction(RD) && + "Key function changed!"); + + return Entry; +} + //===----------------------------------------------------------------------===// // Type creation/memoization methods //===----------------------------------------------------------------------===// @@ -1174,32 +1200,42 @@ QualType ASTContext::getObjCGCQualType(QualType T, return getExtQualType(TypeNode, Quals); } -QualType ASTContext::getNoReturnType(QualType T) { +QualType ASTContext::getNoReturnType(QualType T, bool AddNoReturn) { QualType ResultType; - if (T->isPointerType()) { - QualType Pointee = T->getAs<PointerType>()->getPointeeType(); - ResultType = getNoReturnType(Pointee); + if (const PointerType *Pointer = T->getAs<PointerType>()) { + QualType Pointee = Pointer->getPointeeType(); + ResultType = getNoReturnType(Pointee, AddNoReturn); + if (ResultType == Pointee) + return T; + ResultType = getPointerType(ResultType); - } else if (T->isBlockPointerType()) { - QualType Pointee = T->getAs<BlockPointerType>()->getPointeeType(); - ResultType = getNoReturnType(Pointee); + } else if (const BlockPointerType *BlockPointer + = T->getAs<BlockPointerType>()) { + QualType Pointee = BlockPointer->getPointeeType(); + ResultType = getNoReturnType(Pointee, AddNoReturn); + if (ResultType == Pointee) + return T; + ResultType = getBlockPointerType(ResultType); - } else { - assert (T->isFunctionType() - && "can't noreturn qualify non-pointer to function or block type"); - - if (const FunctionNoProtoType *FNPT = T->getAs<FunctionNoProtoType>()) { - ResultType = getFunctionNoProtoType(FNPT->getResultType(), true); + } else if (const FunctionType *F = T->getAs<FunctionType>()) { + if (F->getNoReturnAttr() == AddNoReturn) + return T; + + if (const FunctionNoProtoType *FNPT = dyn_cast<FunctionNoProtoType>(F)) { + ResultType = getFunctionNoProtoType(FNPT->getResultType(), AddNoReturn); } else { - const FunctionProtoType *F = T->getAs<FunctionProtoType>(); + const FunctionProtoType *FPT = cast<FunctionProtoType>(F); ResultType - = getFunctionType(F->getResultType(), F->arg_type_begin(), - F->getNumArgs(), F->isVariadic(), F->getTypeQuals(), - F->hasExceptionSpec(), F->hasAnyExceptionSpec(), - F->getNumExceptions(), F->exception_begin(), true); + = getFunctionType(FPT->getResultType(), FPT->arg_type_begin(), + FPT->getNumArgs(), FPT->isVariadic(), + FPT->getTypeQuals(), + FPT->hasExceptionSpec(), FPT->hasAnyExceptionSpec(), + FPT->getNumExceptions(), FPT->exception_begin(), + AddNoReturn); } - } - + } else + return T; + return getQualifiedType(ResultType, T.getLocalQualifiers()); } @@ -1766,6 +1802,9 @@ QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) { Decl->TypeForDecl = PrevDecl->TypeForDecl; else Decl->TypeForDecl = new (*this, TypeAlignment) EnumType(Enum); + } else if (UnresolvedUsingTypenameDecl *Using = + dyn_cast<UnresolvedUsingTypenameDecl>(Decl)) { + Decl->TypeForDecl = new (*this, TypeAlignment) UnresolvedUsingType(Using); } else assert(false && "TypeDecl without a type?"); @@ -2238,7 +2277,7 @@ QualType ASTContext::getTagDeclType(const TagDecl *Decl) { /// getSizeType - Return the unique type for "size_t" (C99 7.17), the result /// of the sizeof operator (C99 6.5.3.4p4). The value is target dependent and /// needs to agree with the definition in <stddef.h>. -QualType ASTContext::getSizeType() const { +CanQualType ASTContext::getSizeType() const { return getFromTargetType(Target.getSizeType()); } @@ -2354,8 +2393,9 @@ DeclarationName ASTContext::getNameForTemplate(TemplateName Name) { } } - assert(Name.getAsOverloadedFunctionDecl()); - return Name.getAsOverloadedFunctionDecl()->getDeclName(); + OverloadedTemplateStorage *Storage = Name.getAsOverloadedTemplate(); + assert(Storage); + return (*Storage->begin())->getDeclName(); } TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) { @@ -2364,27 +2404,7 @@ TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) { if (TemplateDecl *Template = Name.getAsTemplateDecl()) return TemplateName(cast<TemplateDecl>(Template->getCanonicalDecl())); - // If this template name refers to a set of overloaded function templates, - /// the canonical template name merely stores the set of function templates. - if (OverloadedFunctionDecl *Ovl = Name.getAsOverloadedFunctionDecl()) { - OverloadedFunctionDecl *CanonOvl = 0; - for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(), - FEnd = Ovl->function_end(); - F != FEnd; ++F) { - Decl *Canon = F->get()->getCanonicalDecl(); - if (CanonOvl || Canon != F->get()) { - if (!CanonOvl) - CanonOvl = OverloadedFunctionDecl::Create(*this, - Ovl->getDeclContext(), - Ovl->getDeclName()); - - CanonOvl->addOverload( - AnyFunctionDecl::getFromNamedDecl(cast<NamedDecl>(Canon))); - } - } - - return TemplateName(CanonOvl? CanonOvl : Ovl); - } + assert(!Name.getAsOverloadedTemplate()); DependentTemplateName *DTN = Name.getAsDependentTemplateName(); assert(DTN && "Non-dependent template names must refer to template decls."); @@ -2651,7 +2671,7 @@ int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) { unsigned ASTContext::getIntegerRank(Type *T) { assert(T->isCanonicalUnqualified() && "T should be canonicalized"); if (EnumType* ET = dyn_cast<EnumType>(T)) - T = ET->getDecl()->getIntegerType().getTypePtr(); + T = ET->getDecl()->getPromotionType().getTypePtr(); if (T->isSpecificBuiltinType(BuiltinType::WChar)) T = getFromTargetType(Target.getWCharType()).getTypePtr(); @@ -2732,6 +2752,8 @@ QualType ASTContext::isPromotableBitField(Expr *E) { QualType ASTContext::getPromotedIntegerType(QualType Promotable) { assert(!Promotable.isNull()); assert(Promotable->isPromotableIntegerType()); + if (const EnumType *ET = Promotable->getAs<EnumType>()) + return ET->getDecl()->getPromotionType(); if (Promotable->isSignedIntegerType()) return IntTy; uint64_t PromotableSize = getTypeSize(Promotable); @@ -2812,7 +2834,7 @@ QualType ASTContext::getCFConstantStringType() { for (unsigned i = 0; i < 4; ++i) { FieldDecl *Field = FieldDecl::Create(*this, CFConstantStringTypeDecl, SourceLocation(), 0, - FieldTypes[i], /*DInfo=*/0, + FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); CFConstantStringTypeDecl->addDecl(Field); @@ -2848,7 +2870,7 @@ QualType ASTContext::getObjCFastEnumerationStateType() { FieldDecl *Field = FieldDecl::Create(*this, ObjCFastEnumerationStateTypeDecl, SourceLocation(), 0, - FieldTypes[i], /*DInfo=*/0, + FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); ObjCFastEnumerationStateTypeDecl->addDecl(Field); @@ -2884,7 +2906,7 @@ QualType ASTContext::getBlockDescriptorType() { T, SourceLocation(), &Idents.get(FieldNames[i]), - FieldTypes[i], /*DInfo=*/0, + FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); T->addDecl(Field); @@ -2931,7 +2953,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() { T, SourceLocation(), &Idents.get(FieldNames[i]), - FieldTypes[i], /*DInfo=*/0, + FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); T->addDecl(Field); @@ -3009,7 +3031,7 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) { continue; FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), &Idents.get(FieldNames[i]), - FieldTypes[i], /*DInfo=*/0, + FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); T->addDecl(Field); } @@ -3052,7 +3074,7 @@ QualType ASTContext::getBlockParmType( for (size_t i = 0; i < 5; ++i) { FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), &Idents.get(FieldNames[i]), - FieldTypes[i], /*DInfo=*/0, + FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); T->addDecl(Field); } @@ -3072,7 +3094,7 @@ QualType ASTContext::getBlockParmType( FieldType); FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), - Name, FieldType, /*DInfo=*/0, + Name, FieldType, /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); T->addDecl(Field); } @@ -3690,36 +3712,40 @@ void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) { ObjCConstantStringType = getObjCInterfaceType(Decl); } -/// \brief Retrieve the template name that represents a qualified -/// template name such as \c std::vector. -TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, - bool TemplateKeyword, - TemplateDecl *Template) { - llvm::FoldingSetNodeID ID; - QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template); +/// \brief Retrieve the template name that corresponds to a non-empty +/// lookup. +TemplateName ASTContext::getOverloadedTemplateName(NamedDecl * const *Begin, + NamedDecl * const *End) { + unsigned size = End - Begin; + assert(size > 1 && "set is not overloaded!"); - void *InsertPos = 0; - QualifiedTemplateName *QTN = - QualifiedTemplateNames.FindNodeOrInsertPos(ID, InsertPos); - if (!QTN) { - QTN = new (*this,4) QualifiedTemplateName(NNS, TemplateKeyword, Template); - QualifiedTemplateNames.InsertNode(QTN, InsertPos); + void *memory = Allocate(sizeof(OverloadedTemplateStorage) + + size * sizeof(FunctionTemplateDecl*)); + OverloadedTemplateStorage *OT = new(memory) OverloadedTemplateStorage(size); + + NamedDecl **Storage = OT->getStorage(); + for (NamedDecl * const *I = Begin; I != End; ++I) { + NamedDecl *D = *I; + assert(isa<FunctionTemplateDecl>(D) || + (isa<UsingShadowDecl>(D) && + isa<FunctionTemplateDecl>(D->getUnderlyingDecl()))); + *Storage++ = D; } - return TemplateName(QTN); + return TemplateName(OT); } /// \brief Retrieve the template name that represents a qualified /// template name such as \c std::vector. TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, - OverloadedFunctionDecl *Template) { + TemplateDecl *Template) { llvm::FoldingSetNodeID ID; QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template); void *InsertPos = 0; QualifiedTemplateName *QTN = - QualifiedTemplateNames.FindNodeOrInsertPos(ID, InsertPos); + QualifiedTemplateNames.FindNodeOrInsertPos(ID, InsertPos); if (!QTN) { QTN = new (*this,4) QualifiedTemplateName(NNS, TemplateKeyword, Template); QualifiedTemplateNames.InsertNode(QTN, InsertPos); @@ -4334,6 +4360,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { if (LHSClass != RHSClass) { // C99 6.7.2.2p4: Each enumerated type shall be compatible with char, // a signed integer type, or an unsigned integer type. + // Compatibility is based on the underlying type, not the promotion + // type. if (const EnumType* ETy = LHS->getAs<EnumType>()) { if (ETy->getDecl()->getIntegerType() == RHSCan.getUnqualifiedType()) return RHS; @@ -4493,6 +4521,8 @@ unsigned ASTContext::getIntWidth(QualType T) { if (FixedWidthIntType *FWIT = dyn_cast<FixedWidthIntType>(T)) { return FWIT->getWidth(); } + if (EnumType *ET = dyn_cast<EnumType>(T)) + T = ET->getDecl()->getIntegerType(); // For builtin types, just use the standard type sizing method return (unsigned)getTypeSize(T); } diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index 023bca4..92a58b7 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -90,6 +90,57 @@ bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) cons return lookupInBases(&FindBaseClass, Base->getCanonicalDecl(), Paths); } +static bool BaseIsNot(const CXXRecordDecl *Base, void *OpaqueTarget) { + // OpaqueTarget is a CXXRecordDecl*. + return Base->getCanonicalDecl() != (const CXXRecordDecl*) OpaqueTarget; +} + +bool CXXRecordDecl::isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const { + return forallBases(BaseIsNot, (void*) Base->getCanonicalDecl()); +} + +bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches, + void *OpaqueData, + bool AllowShortCircuit) const { + ASTContext &Context = getASTContext(); + llvm::SmallVector<const CXXRecordDecl*, 8> Queue; + + const CXXRecordDecl *Record = this; + bool AllMatches = true; + while (true) { + for (CXXRecordDecl::base_class_const_iterator + I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) { + const RecordType *Ty = I->getType()->getAs<RecordType>(); + if (!Ty) { + if (AllowShortCircuit) return false; + AllMatches = false; + continue; + } + + CXXRecordDecl *Base = + cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition(Context)); + if (!Base) { + if (AllowShortCircuit) return false; + AllMatches = false; + continue; + } + + Queue.push_back(Base); + if (!BaseMatches(Base, OpaqueData)) { + if (AllowShortCircuit) return false; + AllMatches = false; + continue; + } + } + + if (Queue.empty()) break; + Record = Queue.back(); // not actually a queue. + Queue.pop_back(); + } + + return AllMatches; +} + bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, void *UserData, CXXBasePaths &Paths) const { diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 572d76f..4d0d422 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -38,7 +38,7 @@ void Attr::Destroy(ASTContext &C) { } /// \brief Return the TypeLoc wrapper for the type source info. -TypeLoc DeclaratorInfo::getTypeLoc() const { +TypeLoc TypeSourceInfo::getTypeLoc() const { return TypeLoc(Ty, (void*)(this + 1)); } @@ -86,17 +86,17 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - QualType T, DeclaratorInfo *DInfo, + QualType T, TypeSourceInfo *TInfo, StorageClass S, Expr *DefArg) { - return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, DInfo, S, DefArg); + return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo, S, DefArg); } SourceRange ParmVarDecl::getDefaultArgRange() const { if (const Expr *E = getInit()) return E->getSourceRange(); - if (const Expr *E = getUninstantiatedDefaultArg()) - return E->getSourceRange(); + if (hasUninstantiatedDefaultArg()) + return getUninstantiatedDefaultArg()->getSourceRange(); return SourceRange(); } @@ -136,11 +136,11 @@ bool VarDecl::isExternC() const { FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName N, QualType T, - DeclaratorInfo *DInfo, + TypeSourceInfo *TInfo, StorageClass S, bool isInline, bool hasWrittenPrototype) { FunctionDecl *New - = new (C) FunctionDecl(Function, DC, L, N, T, DInfo, S, isInline); + = new (C) FunctionDecl(Function, DC, L, N, T, TInfo, S, isInline); New->HasWrittenPrototype = hasWrittenPrototype; return New; } @@ -151,8 +151,8 @@ BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { FieldDecl *FieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, - DeclaratorInfo *DInfo, Expr *BW, bool Mutable) { - return new (C) FieldDecl(Decl::Field, DC, L, Id, T, DInfo, BW, Mutable); + TypeSourceInfo *TInfo, Expr *BW, bool Mutable) { + return new (C) FieldDecl(Decl::Field, DC, L, Id, T, TInfo, BW, Mutable); } bool FieldDecl::isAnonymousStructOrUnion() const { @@ -179,8 +179,8 @@ void EnumConstantDecl::Destroy(ASTContext& C) { TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - DeclaratorInfo *DInfo) { - return new (C) TypedefDecl(DC, L, Id, DInfo); + TypeSourceInfo *TInfo) { + return new (C) TypedefDecl(DC, L, Id, TInfo); } EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, @@ -195,9 +195,12 @@ void EnumDecl::Destroy(ASTContext& C) { Decl::Destroy(C); } -void EnumDecl::completeDefinition(ASTContext &C, QualType NewType) { +void EnumDecl::completeDefinition(ASTContext &C, + QualType NewType, + QualType NewPromotionType) { assert(!isDefinition() && "Cannot redefine enums!"); IntegerType = NewType; + PromotionType = NewPromotionType; TagDecl::completeDefinition(); } @@ -535,9 +538,9 @@ SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const { //===----------------------------------------------------------------------===// VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType T, DeclaratorInfo *DInfo, + IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S) { - return new (C) VarDecl(Var, DC, L, Id, T, DInfo, S); + return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S); } void VarDecl::Destroy(ASTContext& C) { @@ -838,8 +841,20 @@ unsigned FunctionDecl::getMinRequiredArguments() const { } bool FunctionDecl::isInlined() const { - if (isInlineSpecified() || (isa<CXXMethodDecl>(this) && !isOutOfLine())) + // FIXME: This is not enough. Consider: + // + // inline void f(); + // void f() { } + // + // f is inlined, but does not have inline specified. + // To fix this we should add an 'inline' flag to FunctionDecl. + if (isInlineSpecified()) return true; + + if (isa<CXXMethodDecl>(this)) { + if (!isOutOfLine() || getCanonicalDecl()->isInlineSpecified()) + return true; + } switch (getTemplateSpecializationKind()) { case TSK_Undeclared: @@ -1199,7 +1214,7 @@ TagDecl* TagDecl::getDefinition(ASTContext& C) const { TagDecl::TagKind TagDecl::getTagKindForTypeSpec(unsigned TypeSpec) { switch (TypeSpec) { - default: llvm::llvm_unreachable("unexpected type specifier"); + default: llvm_unreachable("unexpected type specifier"); case DeclSpec::TST_struct: return TK_struct; case DeclSpec::TST_class: return TK_class; case DeclSpec::TST_union: return TK_union; diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 2dcd80b..3afb4e4 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -190,7 +190,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case CXXConstructor: case CXXDestructor: case CXXConversion: - case OverloadedFunction: case Typedef: case EnumConstant: case Var: @@ -199,7 +198,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case NonTypeTemplateParm: case ObjCMethod: case ObjCContainer: - case ObjCCategory: case ObjCInterface: case ObjCProperty: case ObjCCompatibleAlias: @@ -221,8 +219,9 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ObjCImplementation: return IDNS_ObjCImplementation; + case ObjCCategory: case ObjCCategoryImpl: - return IDNS_ObjCCategoryImpl; + return IDNS_ObjCCategoryName; case Field: case ObjCAtDefsField: @@ -637,6 +636,46 @@ bool DeclContext::decls_empty() const { return !FirstDecl; } +void DeclContext::removeDecl(Decl *D) { + assert(D->getLexicalDeclContext() == this && + "decl being removed from non-lexical context"); + assert((D->NextDeclInContext || D == LastDecl) && + "decl is not in decls list"); + + // Remove D from the decl chain. This is O(n) but hopefully rare. + if (D == FirstDecl) { + if (D == LastDecl) + FirstDecl = LastDecl = 0; + else + FirstDecl = D->NextDeclInContext; + } else { + for (Decl *I = FirstDecl; true; I = I->NextDeclInContext) { + assert(I && "decl not found in linked list"); + if (I->NextDeclInContext == D) { + I->NextDeclInContext = D->NextDeclInContext; + if (D == LastDecl) LastDecl = I; + break; + } + } + } + + // Mark that D is no longer in the decl chain. + D->NextDeclInContext = 0; + + // Remove D from the lookup table if necessary. + if (isa<NamedDecl>(D)) { + NamedDecl *ND = cast<NamedDecl>(D); + + void *OpaqueMap = getPrimaryContext()->LookupPtr; + if (!OpaqueMap) return; + + StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(OpaqueMap); + StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName()); + assert(Pos != Map->end() && "no lookup entry for decl"); + Pos->second.remove(ND); + } +} + void DeclContext::addHiddenDecl(Decl *D) { assert(D->getLexicalDeclContext() == this && "Decl inserted into wrong lexical context"); @@ -742,6 +781,9 @@ void DeclContext::makeDeclVisibleInContext(NamedDecl *D, bool Recoverable) { // from being visible? if (isa<ClassTemplateSpecializationDecl>(D)) return; + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + if (FD->isFunctionTemplateSpecialization()) + return; DeclContext *PrimaryContext = getPrimaryContext(); if (PrimaryContext != this) { diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 4001988..292a3ed 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -15,6 +15,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" +#include "clang/AST/TypeLoc.h" #include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" @@ -438,6 +439,18 @@ void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) { Conversions.addDecl(ConvDecl); } + +void CXXRecordDecl::setMethodAsVirtual(FunctionDecl *Method) { + Method->setVirtualAsWritten(true); + setAggregate(false); + setPOD(false); + setEmpty(false); + setPolymorphic(true); + setHasTrivialConstructor(false); + setHasTrivialCopyConstructor(false); + setHasTrivialCopyAssignment(false); +} + CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const { if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) return cast<CXXRecordDecl>(MSInfo->getInstantiatedFrom()); @@ -459,8 +472,8 @@ CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD, = new (getASTContext()) MemberSpecializationInfo(RD, TSK); } -TemplateSpecializationKind CXXRecordDecl::getTemplateSpecializationKind() { - if (ClassTemplateSpecializationDecl *Spec +TemplateSpecializationKind CXXRecordDecl::getTemplateSpecializationKind() const{ + if (const ClassTemplateSpecializationDecl *Spec = dyn_cast<ClassTemplateSpecializationDecl>(this)) return Spec->getSpecializationKind(); @@ -507,8 +520,7 @@ CXXRecordDecl::getDefaultConstructor(ASTContext &Context) { return 0; } -const CXXDestructorDecl * -CXXRecordDecl::getDestructor(ASTContext &Context) { +CXXDestructorDecl *CXXRecordDecl::getDestructor(ASTContext &Context) { QualType ClassType = Context.getTypeDeclType(this); DeclarationName Name @@ -519,7 +531,7 @@ CXXRecordDecl::getDestructor(ASTContext &Context) { llvm::tie(I, E) = lookup(Name); assert(I != E && "Did not find a destructor!"); - const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I); + CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I); assert(++I == E && "Found more than one destructor!"); return Dtor; @@ -528,9 +540,9 @@ CXXRecordDecl::getDestructor(ASTContext &Context) { CXXMethodDecl * CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, - QualType T, DeclaratorInfo *DInfo, + QualType T, TypeSourceInfo *TInfo, bool isStatic, bool isInline) { - return new (C) CXXMethodDecl(CXXMethod, RD, L, N, T, DInfo, + return new (C) CXXMethodDecl(CXXMethod, RD, L, N, T, TInfo, isStatic, isInline); } @@ -577,6 +589,8 @@ typedef llvm::DenseMap<const CXXMethodDecl*, static OverriddenMethodsMapTy *OverriddenMethods = 0; void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) { + assert(MD->isCanonicalDecl() && "Method is not canonical!"); + // FIXME: The CXXMethodDecl dtor needs to remove and free the entry. if (!OverriddenMethods) @@ -630,55 +644,107 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const { return C.getPointerType(ClassTy); } -CXXBaseOrMemberInitializer:: -CXXBaseOrMemberInitializer(QualType BaseType, Expr **Args, unsigned NumArgs, - CXXConstructorDecl *C, - SourceLocation L, SourceLocation R) - : Args(0), NumArgs(0), CtorOrAnonUnion(), IdLoc(L), RParenLoc(R) { - BaseOrMember = reinterpret_cast<uintptr_t>(BaseType.getTypePtr()); - assert((BaseOrMember & 0x01) == 0 && "Invalid base class type pointer"); - BaseOrMember |= 0x01; +static bool MethodHasBody(const CXXMethodDecl *MD, const FunctionDecl *&fn) { + // Simple case: function has a body + if (MD->getBody(fn)) + return true; + // Complex case: function is an instantiation of a function which has a + // body, but the definition hasn't been instantiated. + const FunctionDecl *PatternDecl = MD->getTemplateInstantiationPattern(); + if (PatternDecl && PatternDecl->getBody(fn)) + return true; + + return false; +} + +bool CXXMethodDecl::hasInlineBody() const { + const FunctionDecl *fn; + return MethodHasBody(this, fn) && !fn->isOutOfLine(); +} + +CXXBaseOrMemberInitializer:: +CXXBaseOrMemberInitializer(ASTContext &Context, + TypeSourceInfo *TInfo, CXXConstructorDecl *C, + SourceLocation L, + Expr **Args, unsigned NumArgs, + SourceLocation R) + : BaseOrMember(TInfo), Args(0), NumArgs(0), CtorOrAnonUnion(C), + LParenLoc(L), RParenLoc(R) +{ if (NumArgs > 0) { this->NumArgs = NumArgs; - // FIXME. Allocation via Context - this->Args = new Stmt*[NumArgs]; + this->Args = new (Context) Stmt*[NumArgs]; for (unsigned Idx = 0; Idx < NumArgs; ++Idx) this->Args[Idx] = Args[Idx]; } - CtorOrAnonUnion = C; } CXXBaseOrMemberInitializer:: -CXXBaseOrMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs, - CXXConstructorDecl *C, - SourceLocation L, SourceLocation R) - : Args(0), NumArgs(0), CtorOrAnonUnion(), IdLoc(L), RParenLoc(R) { - BaseOrMember = reinterpret_cast<uintptr_t>(Member); - assert((BaseOrMember & 0x01) == 0 && "Invalid member pointer"); - +CXXBaseOrMemberInitializer(ASTContext &Context, + FieldDecl *Member, SourceLocation MemberLoc, + CXXConstructorDecl *C, SourceLocation L, + Expr **Args, unsigned NumArgs, + SourceLocation R) + : BaseOrMember(Member), MemberLocation(MemberLoc), Args(0), NumArgs(0), + CtorOrAnonUnion(C), LParenLoc(L), RParenLoc(R) +{ if (NumArgs > 0) { this->NumArgs = NumArgs; - this->Args = new Stmt*[NumArgs]; + this->Args = new (Context) Stmt*[NumArgs]; for (unsigned Idx = 0; Idx < NumArgs; ++Idx) this->Args[Idx] = Args[Idx]; } - CtorOrAnonUnion = C; } -CXXBaseOrMemberInitializer::~CXXBaseOrMemberInitializer() { - delete [] Args; +void CXXBaseOrMemberInitializer::Destroy(ASTContext &Context) { + for (unsigned I = 0; I != NumArgs; ++I) + Args[I]->Destroy(Context); + Context.Deallocate(Args); + this->~CXXBaseOrMemberInitializer(); +} + +TypeLoc CXXBaseOrMemberInitializer::getBaseClassLoc() const { + if (isBaseInitializer()) + return BaseOrMember.get<TypeSourceInfo*>()->getTypeLoc(); + else + return TypeLoc(); +} + +Type *CXXBaseOrMemberInitializer::getBaseClass() { + if (isBaseInitializer()) + return BaseOrMember.get<TypeSourceInfo*>()->getType().getTypePtr(); + else + return 0; +} + +const Type *CXXBaseOrMemberInitializer::getBaseClass() const { + if (isBaseInitializer()) + return BaseOrMember.get<TypeSourceInfo*>()->getType().getTypePtr(); + else + return 0; +} + +SourceLocation CXXBaseOrMemberInitializer::getSourceLocation() const { + if (isMemberInitializer()) + return getMemberLocation(); + + return getBaseClassLoc().getSourceRange().getBegin(); +} + +SourceRange CXXBaseOrMemberInitializer::getSourceRange() const { + return SourceRange(getSourceLocation(), getRParenLoc()); } CXXConstructorDecl * CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, - QualType T, DeclaratorInfo *DInfo, + QualType T, TypeSourceInfo *TInfo, bool isExplicit, bool isInline, bool isImplicitlyDeclared) { assert(N.getNameKind() == DeclarationName::CXXConstructorName && "Name must refer to a constructor"); - return new (C) CXXConstructorDecl(RD, L, N, T, DInfo, isExplicit, isInline, + return new (C) CXXConstructorDecl(RD, L, N, T, TInfo, isExplicit, isInline, isImplicitlyDeclared); } @@ -790,69 +856,11 @@ CXXConstructorDecl::Destroy(ASTContext& C) { CXXConversionDecl * CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, - QualType T, DeclaratorInfo *DInfo, + QualType T, TypeSourceInfo *TInfo, bool isInline, bool isExplicit) { assert(N.getNameKind() == DeclarationName::CXXConversionFunctionName && "Name must refer to a conversion function"); - return new (C) CXXConversionDecl(RD, L, N, T, DInfo, isInline, isExplicit); -} - -OverloadedFunctionDecl * -OverloadedFunctionDecl::Create(ASTContext &C, DeclContext *DC, - DeclarationName N) { - return new (C) OverloadedFunctionDecl(DC, N); -} - -OverloadIterator::OverloadIterator(NamedDecl *ND) : D(0) { - if (!ND) - return; - - if (isa<FunctionDecl>(ND) || isa<FunctionTemplateDecl>(ND)) - D = ND; - else if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(ND)) { - if (Ovl->size() != 0) { - D = ND; - Iter = Ovl->function_begin(); - } - } -} - -void OverloadedFunctionDecl::addOverload(AnyFunctionDecl F) { - Functions.push_back(F); - this->setLocation(F.get()->getLocation()); -} - -OverloadIterator::reference OverloadIterator::operator*() const { - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - return FD; - - if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D)) - return FTD; - - assert(isa<OverloadedFunctionDecl>(D)); - return *Iter; -} - -OverloadIterator &OverloadIterator::operator++() { - if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) { - D = 0; - return *this; - } - - if (++Iter == cast<OverloadedFunctionDecl>(D)->function_end()) - D = 0; - - return *this; -} - -bool OverloadIterator::Equals(const OverloadIterator &Other) const { - if (!D || !Other.D) - return D == Other.D; - - if (D != Other.D) - return false; - - return !isa<OverloadedFunctionDecl>(D) || Iter == Other.Iter; + return new (C) CXXConversionDecl(RD, L, N, T, TInfo, isInline, isExplicit); } FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC, diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index c33720f..2506f27 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -501,9 +501,9 @@ bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto, ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - QualType T, DeclaratorInfo *DInfo, + QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW) { - return new (C) ObjCIvarDecl(DC, L, Id, T, DInfo, ac, BW); + return new (C) ObjCIvarDecl(DC, L, Id, T, TInfo, ac, BW); } diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index a5982cf..32ac53d 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -52,7 +52,6 @@ namespace { void VisitVarDecl(VarDecl *D); void VisitParmVarDecl(ParmVarDecl *D); void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); - void VisitOverloadedFunctionDecl(OverloadedFunctionDecl *D); void VisitNamespaceDecl(NamespaceDecl *D); void VisitUsingDirectiveDecl(UsingDirectiveDecl *D); void VisitNamespaceAliasDecl(NamespaceAliasDecl *D); @@ -149,6 +148,17 @@ void Decl::printGroup(Decl** Begin, unsigned NumDecls, } } +void DeclContext::dumpDeclContext() const { + // Get the translation unit + const DeclContext *DC = this; + while (!DC->isTranslationUnit()) + DC = DC->getParent(); + + ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext(); + DeclPrinter Printer(llvm::errs(), Ctx, Ctx.PrintingPolicy, 0); + Printer.VisitDeclContext(const_cast<DeclContext *>(this), /*Indent=*/false); +} + void Decl::dump() const { print(llvm::errs()); } @@ -362,6 +372,24 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { } Proto += ")"; + + if (FT && FT->hasExceptionSpec()) { + Proto += " throw("; + if (FT->hasAnyExceptionSpec()) + Proto += "..."; + else + for (unsigned I = 0, N = FT->getNumExceptions(); I != N; ++I) { + if (I) + Proto += ", "; + + + std::string ExceptionType; + FT->getExceptionType(I).getAsStringInternal(ExceptionType, SubPolicy); + Proto += ExceptionType; + } + Proto += ")"; + } + if (D->hasAttr<NoReturnAttr>()) Proto += " __attribute((noreturn))"; if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D)) { @@ -488,11 +516,6 @@ void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { //---------------------------------------------------------------------------- // C++ declarations //---------------------------------------------------------------------------- -void DeclPrinter::VisitOverloadedFunctionDecl(OverloadedFunctionDecl *D) { - assert(false && - "OverloadedFunctionDecls aren't really decls and are never printed"); -} - void DeclPrinter::VisitNamespaceDecl(NamespaceDecl *D) { Out << "namespace " << D->getNameAsString() << " {\n"; VisitDeclContext(D); diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 902339e..75b3975 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -262,8 +262,8 @@ NonTypeTemplateParmDecl * NonTypeTemplateParmDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, IdentifierInfo *Id, QualType T, - DeclaratorInfo *DInfo) { - return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, DInfo); + TypeSourceInfo *TInfo) { + return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, TInfo); } SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const { diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 3471657..0ce03c2 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -338,7 +338,7 @@ void DeclarationName::setFETokenInfo(void *T) { DeclarationName DeclarationName::getUsingDirectiveName() { // Single instance of DeclarationNameExtra for using-directive - static DeclarationNameExtra UDirExtra = + static const DeclarationNameExtra UDirExtra = { DeclarationNameExtra::CXXUsingDirective }; uintptr_t Ptr = reinterpret_cast<uintptr_t>(&UDirExtra); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 624a620..139e04b 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -110,7 +110,7 @@ void DeclRefExpr::computeDependence() { DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier, SourceRange QualifierRange, - NamedDecl *D, SourceLocation NameLoc, + ValueDecl *D, SourceLocation NameLoc, const TemplateArgumentListInfo *TemplateArgs, QualType T) : Expr(DeclRefExprClass, T, false, false), @@ -118,7 +118,6 @@ DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier, (Qualifier? HasQualifierFlag : 0) | (TemplateArgs ? HasExplicitTemplateArgumentListFlag : 0)), Loc(NameLoc) { - assert(!isa<OverloadedFunctionDecl>(D)); if (Qualifier) { NameQualifier *NQ = getNameQualifier(); NQ->NNS = Qualifier; @@ -134,7 +133,7 @@ DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier, DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, - NamedDecl *D, + ValueDecl *D, SourceLocation NameLoc, QualType T, const TemplateArgumentListInfo *TemplateArgs) { @@ -204,7 +203,8 @@ std::string PredefinedExpr::ComputeName(ASTContext &Context, IdentType IT, } Proto += ")"; - AFT->getResultType().getAsStringInternal(Proto, Policy); + if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD)) + AFT->getResultType().getAsStringInternal(Proto, Policy); Out << Proto; @@ -471,7 +471,7 @@ QualType CallExpr::getCallReturnType() const { } MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, - SourceRange qualrange, NamedDecl *memberdecl, + SourceRange qualrange, ValueDecl *memberdecl, SourceLocation l, const TemplateArgumentListInfo *targs, QualType ty) : Expr(MemberExprClass, ty, @@ -494,7 +494,7 @@ MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, NestedNameSpecifier *qual, SourceRange qualrange, - NamedDecl *memberdecl, + ValueDecl *memberdecl, SourceLocation l, const TemplateArgumentListInfo *targs, QualType ty) { @@ -558,12 +558,40 @@ const char *CastExpr::getCastKindName() const { return "FloatingCast"; case CastExpr::CK_MemberPointerToBoolean: return "MemberPointerToBoolean"; + case CastExpr::CK_AnyPointerToObjCPointerCast: + return "AnyPointerToObjCPointerCast"; + case CastExpr::CK_AnyPointerToBlockPointerCast: + return "AnyPointerToBlockPointerCast"; } assert(0 && "Unhandled cast kind!"); return 0; } +Expr *CastExpr::getSubExprAsWritten() { + Expr *SubExpr = 0; + CastExpr *E = this; + do { + SubExpr = E->getSubExpr(); + + // Skip any temporary bindings; they're implicit. + if (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(SubExpr)) + SubExpr = Binder->getSubExpr(); + + // Conversions by constructor and conversion functions have a + // subexpression describing the call; strip it off. + if (E->getCastKind() == CastExpr::CK_ConstructorConversion) + SubExpr = cast<CXXConstructExpr>(SubExpr)->getArg(0); + else if (E->getCastKind() == CastExpr::CK_UserDefinedConversion) + SubExpr = cast<CXXMemberCallExpr>(SubExpr)->getImplicitObjectArgument(); + + // If the subexpression we're left with is an implicit cast, look + // through that, too. + } while ((E = dyn_cast<ImplicitCastExpr>(SubExpr))); + + return SubExpr; +} + /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it /// corresponds to, e.g. "<<=". const char *BinaryOperator::getOpcodeStr(Opcode Op) { @@ -944,8 +972,7 @@ static bool DeclCanBeLvalue(const NamedDecl *Decl, ASTContext &Ctx) { return isa<VarDecl>(Decl) || isa<FieldDecl>(Decl) || // C++ 3.10p2: An lvalue refers to an object or function. (Ctx.getLangOptions().CPlusPlus && - (isa<FunctionDecl>(Decl) || isa<OverloadedFunctionDecl>(Decl) || - isa<FunctionTemplateDecl>(Decl))); + (isa<FunctionDecl>(Decl) || isa<FunctionTemplateDecl>(Decl))); } /// isLvalue - C99 6.3.2.1: an lvalue is an expression with an object type or an @@ -982,6 +1009,7 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const { // Check whether the expression can be sanely treated like an l-value Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { switch (getStmtClass()) { + case ObjCIsaExprClass: case StringLiteralClass: // C99 6.5.1p4 case ObjCEncodeExprClass: // @encode behaves like its string in every way. return LV_Valid; @@ -1343,6 +1371,13 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) { } } +bool Expr::isDefaultArgument() const { + const Expr *E = this; + while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) + E = ICE->getSubExprAsWritten(); + + return isa<CXXDefaultArgExpr>(E); +} /// hasAnyTypeDependentArguments - Determines if any of the expressions /// in Exprs is type-dependent. @@ -1598,13 +1633,18 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { // constant expression (5.19). In that case, the member can appear // in integral constant expressions. if (Def->isOutOfLine()) { - Dcl->setInitKnownICE(Ctx, false); + Dcl->setInitKnownICE(false); + return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); + } + + if (Dcl->isCheckingICE()) { return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); } - + + Dcl->setCheckingICE(); ICEDiag Result = CheckICE(Init, Ctx); // Cache the result of the ICE test. - Dcl->setInitKnownICE(Ctx, Result.Val == 0); + Dcl->setInitKnownICE(Result.Val == 0); return Result; } } @@ -1804,7 +1844,7 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, } EvalResult EvalResult; if (!Evaluate(EvalResult, Ctx)) - llvm::llvm_unreachable("ICE cannot be evaluated!"); + llvm_unreachable("ICE cannot be evaluated!"); assert(!EvalResult.HasSideEffects && "ICE with side effects!"); assert(EvalResult.Val.isInt() && "ICE that isn't integer!"); Result = EvalResult.Val.getInt(); diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index d1a0390..a9f96ad 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -199,6 +199,7 @@ bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const { switch(UTT) { default: assert(false && "Unknown type trait or not implemented"); case UTT_IsPOD: return QueriedType->isPODType(); + case UTT_IsLiteral: return QueriedType->isLiteralType(); case UTT_IsClass: // Fallthrough case UTT_IsUnion: if (const RecordType *Record = QueriedType->getAs<RecordType>()) { @@ -518,7 +519,8 @@ Stmt::child_iterator CXXUnresolvedConstructExpr::child_end() { } CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, - Expr *Base, bool IsArrow, + Expr *Base, QualType BaseType, + bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -527,8 +529,8 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, SourceLocation MemberLoc, const TemplateArgumentListInfo *TemplateArgs) : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, true, true), - Base(Base), IsArrow(IsArrow), - HasExplicitTemplateArgumentList(TemplateArgs), + Base(Base), BaseType(BaseType), IsArrow(IsArrow), + HasExplicitTemplateArgs(TemplateArgs != 0), OperatorLoc(OperatorLoc), Qualifier(Qualifier), QualifierRange(QualifierRange), FirstQualifierFoundInScope(FirstQualifierFoundInScope), @@ -539,7 +541,7 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, CXXDependentScopeMemberExpr * CXXDependentScopeMemberExpr::Create(ASTContext &C, - Expr *Base, bool IsArrow, + Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -548,22 +550,22 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C, SourceLocation MemberLoc, const TemplateArgumentListInfo *TemplateArgs) { if (!TemplateArgs) - return new (C) CXXDependentScopeMemberExpr(C, Base, IsArrow, OperatorLoc, - Qualifier, QualifierRange, - FirstQualifierFoundInScope, - Member, MemberLoc); + return new (C) CXXDependentScopeMemberExpr(C, Base, BaseType, + IsArrow, OperatorLoc, + Qualifier, QualifierRange, + FirstQualifierFoundInScope, + Member, MemberLoc); std::size_t size = sizeof(CXXDependentScopeMemberExpr); if (TemplateArgs) size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs); void *Mem = C.Allocate(size, llvm::alignof<CXXDependentScopeMemberExpr>()); - return new (Mem) CXXDependentScopeMemberExpr(C, Base, IsArrow, OperatorLoc, - Qualifier, QualifierRange, - FirstQualifierFoundInScope, - Member, - MemberLoc, - TemplateArgs); + return new (Mem) CXXDependentScopeMemberExpr(C, Base, BaseType, + IsArrow, OperatorLoc, + Qualifier, QualifierRange, + FirstQualifierFoundInScope, + Member, MemberLoc, TemplateArgs); } Stmt::child_iterator CXXDependentScopeMemberExpr::child_begin() { @@ -571,12 +573,15 @@ Stmt::child_iterator CXXDependentScopeMemberExpr::child_begin() { } Stmt::child_iterator CXXDependentScopeMemberExpr::child_end() { + if (isImplicitAccess()) + return child_iterator(&Base); return child_iterator(&Base + 1); } UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent, bool HasUnresolvedUsing, - Expr *Base, bool IsArrow, + Expr *Base, QualType BaseType, + bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -584,7 +589,8 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent, SourceLocation MemberLoc, const TemplateArgumentListInfo *TemplateArgs) : Expr(UnresolvedMemberExprClass, T, Dependent, Dependent), - Base(Base), IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing), + Base(Base), BaseType(BaseType), IsArrow(IsArrow), + HasUnresolvedUsing(HasUnresolvedUsing), HasExplicitTemplateArgs(TemplateArgs != 0), OperatorLoc(OperatorLoc), Qualifier(Qualifier), QualifierRange(QualifierRange), @@ -596,7 +602,7 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent, UnresolvedMemberExpr * UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent, bool HasUnresolvedUsing, - Expr *Base, bool IsArrow, + Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, @@ -610,8 +616,8 @@ UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent, void *Mem = C.Allocate(size, llvm::alignof<UnresolvedMemberExpr>()); return new (Mem) UnresolvedMemberExpr( Dependent ? C.DependentTy : C.OverloadTy, - Dependent, HasUnresolvedUsing, Base, IsArrow, - OperatorLoc, Qualifier, QualifierRange, + Dependent, HasUnresolvedUsing, Base, BaseType, + IsArrow, OperatorLoc, Qualifier, QualifierRange, Member, MemberLoc, TemplateArgs); } @@ -620,5 +626,7 @@ Stmt::child_iterator UnresolvedMemberExpr::child_begin() { } Stmt::child_iterator UnresolvedMemberExpr::child_end() { + if (isImplicitAccess()) + return child_iterator(&Base); return child_iterator(&Base + 1); } diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index a20e1cc..13831dc 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -848,16 +848,8 @@ static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) { bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) { // Enums are integer constant exprs. - if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) { - // FIXME: This is an ugly hack around the fact that enums don't set their - // signedness consistently; see PR3173. - APSInt SI = ECD->getInitVal(); - SI.setIsUnsigned(!E->getType()->isSignedIntegerType()); - // FIXME: This is an ugly hack around the fact that enums don't - // set their width (!?!) consistently; see PR3173. - SI.extOrTrunc(Info.Ctx.getIntWidth(E->getType())); - return Success(SI, E); - } + if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) + return Success(ECD->getInitVal(), E); // In C++, const, non-volatile integers initialized with ICEs are ICEs. // In C, they can also be folded, although they are not ICEs. @@ -866,15 +858,24 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) { if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { const VarDecl *Def = 0; if (const Expr *Init = VD->getDefinition(Def)) { - if (APValue *V = VD->getEvaluatedValue()) - return Success(V->getInt(), E); - + if (APValue *V = VD->getEvaluatedValue()) { + if (V->isInt()) + return Success(V->getInt(), E); + return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + } + + if (VD->isEvaluatingValue()) + return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + + VD->setEvaluatingValue(); + if (Visit(const_cast<Expr*>(Init))) { // Cache the evaluated value in the variable declaration. - VD->setEvaluatedValue(Info.Ctx, Result); + VD->setEvaluatedValue(Result); return true; } + VD->setEvaluatedValue(APValue()); return false; } } @@ -1506,6 +1507,7 @@ public: bool VisitFloatingLiteral(const FloatingLiteral *E); bool VisitCastExpr(CastExpr *E); bool VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E); + bool VisitConditionalOperator(ConditionalOperator *E); bool VisitChooseExpr(const ChooseExpr *E) { return Visit(E->getChosenSubExpr(Info.Ctx)); } @@ -1513,8 +1515,7 @@ public: { return Visit(E->getSubExpr()); } // FIXME: Missing: __real__/__imag__, array subscript of vector, - // member of vector, ImplicitValueInitExpr, - // conditional ?: + // member of vector, ImplicitValueInitExpr }; } // end anonymous namespace @@ -1547,16 +1548,10 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { if (!S->isWide()) { const llvm::fltSemantics &Sem = Info.Ctx.getFloatTypeSemantics(E->getType()); - llvm::SmallString<16> s; - s.append(S->getStrData(), S->getStrData() + S->getByteLength()); - s += '\0'; - long l; - char *endp; - l = strtol(&s[0], &endp, 0); - if (endp != s.end()-1) + unsigned Type = 0; + if (!S->getString().empty() && S->getString().getAsInteger(0, Type)) return false; - unsigned type = (unsigned int)l;; - Result = llvm::APFloat::getNaN(Sem, false, type); + Result = llvm::APFloat::getNaN(Sem, false, Type); return true; } } @@ -1673,6 +1668,14 @@ bool FloatExprEvaluator::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) { return true; } +bool FloatExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) { + bool Cond; + if (!HandleConversionToBool(E->getCond(), Cond, Info)) + return false; + + return Visit(Cond ? E->getTrueExpr() : E->getFalseExpr()); +} + //===----------------------------------------------------------------------===// // Complex Evaluation (for float and integer) //===----------------------------------------------------------------------===// diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 326a1dc..c914f3f 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -663,31 +663,6 @@ void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) { Alignment = NewAlignment; } -static const CXXMethodDecl *GetKeyFunction(const CXXRecordDecl *RD) { - if (!RD->isDynamicClass()) - return 0; - - for (CXXRecordDecl::method_iterator I = RD->method_begin(), - E = RD->method_end(); I != E; ++I) { - const CXXMethodDecl *MD = *I; - - if (!MD->isVirtual()) - continue; - - if (MD->isPure()) - continue; - - const FunctionDecl *fn; - if (MD->getBody(fn) && !fn->isOutOfLine()) - continue; - - // We found it. - return MD; - } - - return 0; -} - const ASTRecordLayout * ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, const RecordDecl *D) { @@ -711,8 +686,6 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, uint64_t NonVirtualSize = IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize; - const CXXMethodDecl *KeyFunction = GetKeyFunction(cast<CXXRecordDecl>(D)); - return new ASTRecordLayout(Builder.Size, Builder.Alignment, DataSize, Builder.FieldOffsets.data(), Builder.FieldOffsets.size(), @@ -722,8 +695,7 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, Builder.Bases.data(), Builder.Bases.size(), Builder.VBases.data(), - Builder.VBases.size(), - KeyFunction); + Builder.VBases.size()); } const ASTRecordLayout * @@ -739,3 +711,51 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, Builder.FieldOffsets.data(), Builder.FieldOffsets.size()); } + +const CXXMethodDecl * +ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { + assert(RD->isDynamicClass() && "Class does not have any virtual methods!"); + + // If a class isnt' polymorphic it doesn't have a key function. + if (!RD->isPolymorphic()) + return 0; + + // A class template specialization or instantation does not have a key + // function. + if (RD->getTemplateSpecializationKind() != TSK_Undeclared) + return 0; + + // A class inside an anonymous namespace doesn't have a key function. (Or + // at least, there's no point to assigning a key function to such a class; + // this doesn't affect the ABI.) + if (RD->isInAnonymousNamespace()) + return 0; + + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + if (!MD->isVirtual()) + continue; + + if (MD->isPure()) + continue; + + if (MD->isInlineSpecified()) + continue; + + // Ignore implicit member functions, they are always marked as inline, but + // they don't have a body until they're defined. + if (MD->isImplicit()) + continue; + + if (MD->hasInlineBody()) + continue; + + // We found it. + return MD; + } + + return 0; +} + diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h index 69e0498..d4171d3 100644 --- a/lib/AST/RecordLayoutBuilder.h +++ b/lib/AST/RecordLayoutBuilder.h @@ -151,6 +151,7 @@ public: static const ASTRecordLayout *ComputeLayout(ASTContext &Ctx, const ObjCInterfaceDecl *D, const ObjCImplementationDecl *Impl); + static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD); }; } // end namespace clang diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index bbe6a71..ae76526 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -17,7 +17,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/PrettyPrinter.h" #include "clang/Basic/SourceManager.h" -#include <cstdio> +#include "llvm/Support/raw_ostream.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -27,7 +27,7 @@ using namespace clang; namespace { class StmtDumper : public StmtVisitor<StmtDumper> { SourceManager *SM; - FILE *F; + llvm::raw_ostream &OS; unsigned IndentLevel; /// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump @@ -41,8 +41,8 @@ namespace { unsigned LastLocLine; public: - StmtDumper(SourceManager *sm, FILE *f, unsigned maxDepth) - : SM(sm), F(f), IndentLevel(0-1), MaxDepth(maxDepth) { + StmtDumper(SourceManager *sm, llvm::raw_ostream &os, unsigned maxDepth) + : SM(sm), OS(os), IndentLevel(0-1), MaxDepth(maxDepth) { LastLocFilename = ""; LastLocLine = ~0U; } @@ -62,15 +62,15 @@ namespace { Stmt::child_iterator CI = S->child_begin(), CE = S->child_end(); if (CI != CE) { while (CI != CE) { - fprintf(F, "\n"); + OS << '\n'; DumpSubTree(*CI++); } } - fprintf(F, ")"); + OS << ')'; } } else { Indent(); - fprintf(F, "<<<NULL>>>"); + OS << "<<<NULL>>>"; } --IndentLevel; } @@ -79,27 +79,28 @@ namespace { void Indent() const { for (int i = 0, e = IndentLevel; i < e; ++i) - fprintf(F, " "); + OS << " "; } void DumpType(QualType T) { - fprintf(F, "'%s'", T.getAsString().c_str()); + OS << "'" << T.getAsString() << "'"; if (!T.isNull()) { // If the type is sugared, also dump a (shallow) desugared type. QualType Simplified = T.getDesugaredType(); if (Simplified != T) - fprintf(F, ":'%s'", Simplified.getAsString().c_str()); + OS << ":'" << Simplified.getAsString() << "'"; } } void DumpStmt(const Stmt *Node) { Indent(); - fprintf(F, "(%s %p", Node->getStmtClassName(), (void*)Node); + OS << "(" << Node->getStmtClassName() + << " " << (void*)Node; DumpSourceRange(Node); } void DumpExpr(const Expr *Node) { DumpStmt(Node); - fprintf(F, " "); + OS << ' '; DumpType(Node->getType()); } void DumpSourceRange(const Stmt *Node); @@ -138,6 +139,7 @@ namespace { void VisitCXXConstructExpr(CXXConstructExpr *Node); void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node); void VisitCXXExprWithTemporaries(CXXExprWithTemporaries *Node); + void VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node); void DumpCXXTemporary(CXXTemporary *Temporary); // ObjC @@ -161,7 +163,7 @@ void StmtDumper::DumpLocation(SourceLocation Loc) { SourceLocation SpellingLoc = SM->getSpellingLoc(Loc); if (SpellingLoc.isInvalid()) { - fprintf(stderr, "<invalid sloc>"); + OS << "<invalid sloc>"; return; } @@ -170,15 +172,16 @@ void StmtDumper::DumpLocation(SourceLocation Loc) { PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc); if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) { - fprintf(stderr, "%s:%u:%u", PLoc.getFilename(), PLoc.getLine(), - PLoc.getColumn()); + OS << PLoc.getFilename() << ':' << PLoc.getLine() + << ':' << PLoc.getColumn(); LastLocFilename = PLoc.getFilename(); LastLocLine = PLoc.getLine(); } else if (PLoc.getLine() != LastLocLine) { - fprintf(stderr, "line:%u:%u", PLoc.getLine(), PLoc.getColumn()); + OS << "line" << ':' << PLoc.getLine() + << ':' << PLoc.getColumn(); LastLocLine = PLoc.getLine(); } else { - fprintf(stderr, "col:%u", PLoc.getColumn()); + OS << "col" << ':' << PLoc.getColumn(); } } @@ -190,13 +193,13 @@ void StmtDumper::DumpSourceRange(const Stmt *Node) { // location. SourceRange R = Node->getSourceRange(); - fprintf(stderr, " <"); + OS << " <"; DumpLocation(R.getBegin()); if (R.getBegin() != R.getEnd()) { - fprintf(stderr, ", "); + OS << ", "; DumpLocation(R.getEnd()); } - fprintf(stderr, ">"); + OS << ">"; // <t2.c:123:421[blah], t2.c:412:321> @@ -215,31 +218,30 @@ void StmtDumper::DumpDeclarator(Decl *D) { // FIXME: Need to complete/beautify this... this code simply shows the // nodes are where they need to be. if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) { - fprintf(F, "\"typedef %s %s\"", - localType->getUnderlyingType().getAsString().c_str(), - localType->getNameAsString().c_str()); + OS << "\"typedef " << localType->getUnderlyingType().getAsString() + << " " << localType->getNameAsString() << "\""; } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) { - fprintf(F, "\""); + OS << "\""; // Emit storage class for vardecls. if (VarDecl *V = dyn_cast<VarDecl>(VD)) { if (V->getStorageClass() != VarDecl::None) - fprintf(F, "%s ", - VarDecl::getStorageClassSpecifierString(V->getStorageClass())); + OS << VarDecl::getStorageClassSpecifierString(V->getStorageClass()) + << " "; } std::string Name = VD->getNameAsString(); VD->getType().getAsStringInternal(Name, PrintingPolicy(VD->getASTContext().getLangOptions())); - fprintf(F, "%s", Name.c_str()); + OS << Name; // If this is a vardecl with an initializer, emit it. if (VarDecl *V = dyn_cast<VarDecl>(VD)) { if (V->getInit()) { - fprintf(F, " =\n"); + OS << " =\n"; DumpSubTree(V->getInit()); } } - fprintf(F, "\""); + OS << '"'; } else if (TagDecl *TD = dyn_cast<TagDecl>(D)) { // print a free standing tag decl (e.g. "struct x;"). const char *tagname; @@ -247,7 +249,7 @@ void StmtDumper::DumpDeclarator(Decl *D) { tagname = II->getNameStart(); else tagname = "<anonymous>"; - fprintf(F, "\"%s %s;\"", TD->getKindName(), tagname); + OS << '"' << TD->getKindName() << ' ' << tagname << ";\""; // FIXME: print tag bodies. } else if (UsingDirectiveDecl *UD = dyn_cast<UsingDirectiveDecl>(D)) { // print using-directive decl (e.g. "using namespace x;") @@ -256,7 +258,7 @@ void StmtDumper::DumpDeclarator(Decl *D) { ns = II->getNameStart(); else ns = "<anonymous>"; - fprintf(F, "\"%s %s;\"",UD->getDeclKindName(), ns); + OS << '"' << UD->getDeclKindName() << ns << ";\""; } else { assert(0 && "Unexpected decl"); } @@ -264,28 +266,29 @@ void StmtDumper::DumpDeclarator(Decl *D) { void StmtDumper::VisitDeclStmt(DeclStmt *Node) { DumpStmt(Node); - fprintf(F,"\n"); + OS << "\n"; for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end(); DI != DE; ++DI) { Decl* D = *DI; ++IndentLevel; Indent(); - fprintf(F, "%p ", (void*) D); + OS << (void*) D << " "; DumpDeclarator(D); if (DI+1 != DE) - fprintf(F,"\n"); + OS << "\n"; --IndentLevel; } } void StmtDumper::VisitLabelStmt(LabelStmt *Node) { DumpStmt(Node); - fprintf(F, " '%s'", Node->getName()); + OS << " '" << Node->getName() << "'"; } void StmtDumper::VisitGotoStmt(GotoStmt *Node) { DumpStmt(Node); - fprintf(F, " '%s':%p", Node->getLabel()->getName(), (void*)Node->getLabel()); + OS << " '" << Node->getLabel()->getName() + << "':" << (void*)Node->getLabel(); } //===----------------------------------------------------------------------===// @@ -298,129 +301,130 @@ void StmtDumper::VisitExpr(Expr *Node) { void StmtDumper::VisitCastExpr(CastExpr *Node) { DumpExpr(Node); - fprintf(F, " <%s>", Node->getCastKindName()); + OS << " <" << Node->getCastKindName() << ">"; } void StmtDumper::VisitImplicitCastExpr(ImplicitCastExpr *Node) { VisitCastExpr(Node); if (Node->isLvalueCast()) - fprintf(F, " lvalue"); + OS << " lvalue"; } void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) { DumpExpr(Node); - fprintf(F, " "); + OS << " "; switch (Node->getDecl()->getKind()) { - default: fprintf(F,"Decl"); break; - case Decl::Function: fprintf(F,"FunctionDecl"); break; - case Decl::Var: fprintf(F,"Var"); break; - case Decl::ParmVar: fprintf(F,"ParmVar"); break; - case Decl::EnumConstant: fprintf(F,"EnumConstant"); break; - case Decl::Typedef: fprintf(F,"Typedef"); break; - case Decl::Record: fprintf(F,"Record"); break; - case Decl::Enum: fprintf(F,"Enum"); break; - case Decl::CXXRecord: fprintf(F,"CXXRecord"); break; - case Decl::ObjCInterface: fprintf(F,"ObjCInterface"); break; - case Decl::ObjCClass: fprintf(F,"ObjCClass"); break; + default: OS << "Decl"; break; + case Decl::Function: OS << "FunctionDecl"; break; + case Decl::Var: OS << "Var"; break; + case Decl::ParmVar: OS << "ParmVar"; break; + case Decl::EnumConstant: OS << "EnumConstant"; break; + case Decl::Typedef: OS << "Typedef"; break; + case Decl::Record: OS << "Record"; break; + case Decl::Enum: OS << "Enum"; break; + case Decl::CXXRecord: OS << "CXXRecord"; break; + case Decl::ObjCInterface: OS << "ObjCInterface"; break; + case Decl::ObjCClass: OS << "ObjCClass"; break; } - fprintf(F, "='%s' %p", Node->getDecl()->getNameAsString().c_str(), - (void*)Node->getDecl()); + OS << "='" << Node->getDecl()->getNameAsString() + << "' " << (void*)Node->getDecl(); +} + +void StmtDumper::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) { + DumpExpr(Node); + OS << " ("; + if (!Node->requiresADL()) OS << "no "; + OS << "ADL) = '" << Node->getName().getAsString() << "'"; + + UnresolvedLookupExpr::decls_iterator + I = Node->decls_begin(), E = Node->decls_end(); + if (I == E) OS << " empty"; + for (; I != E; ++I) + OS << " " << (void*) *I; } void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { DumpExpr(Node); - fprintf(F, " %sDecl='%s' %p", Node->getDecl()->getDeclKindName(), - Node->getDecl()->getNameAsString().c_str(), (void*)Node->getDecl()); + OS << " " << Node->getDecl()->getDeclKindName() + << "Decl='" << Node->getDecl()->getNameAsString() + << "' " << (void*)Node->getDecl(); if (Node->isFreeIvar()) - fprintf(F, " isFreeIvar"); + OS << " isFreeIvar"; } void StmtDumper::VisitPredefinedExpr(PredefinedExpr *Node) { DumpExpr(Node); switch (Node->getIdentType()) { default: assert(0 && "unknown case"); - case PredefinedExpr::Func: fprintf(F, " __func__"); break; - case PredefinedExpr::Function: fprintf(F, " __FUNCTION__"); break; - case PredefinedExpr::PrettyFunction: fprintf(F, " __PRETTY_FUNCTION__");break; + case PredefinedExpr::Func: OS << " __func__"; break; + case PredefinedExpr::Function: OS << " __FUNCTION__"; break; + case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break; } } void StmtDumper::VisitCharacterLiteral(CharacterLiteral *Node) { DumpExpr(Node); - fprintf(F, " %d", Node->getValue()); + OS << Node->getValue(); } void StmtDumper::VisitIntegerLiteral(IntegerLiteral *Node) { DumpExpr(Node); bool isSigned = Node->getType()->isSignedIntegerType(); - fprintf(F, " %s", Node->getValue().toString(10, isSigned).c_str()); + OS << " " << Node->getValue().toString(10, isSigned); } void StmtDumper::VisitFloatingLiteral(FloatingLiteral *Node) { DumpExpr(Node); - fprintf(F, " %f", Node->getValueAsApproximateDouble()); + OS << " " << Node->getValueAsApproximateDouble(); } void StmtDumper::VisitStringLiteral(StringLiteral *Str) { DumpExpr(Str); // FIXME: this doesn't print wstrings right. - fprintf(F, " %s\"", Str->isWide() ? "L" : ""); - - for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) { - switch (char C = Str->getStrData()[i]) { - default: - if (isprint(C)) - fputc(C, F); - else - fprintf(F, "\\%03o", C); - break; - // Handle some common ones to make dumps prettier. - case '\\': fprintf(F, "\\\\"); break; - case '"': fprintf(F, "\\\""); break; - case '\n': fprintf(F, "\\n"); break; - case '\t': fprintf(F, "\\t"); break; - case '\a': fprintf(F, "\\a"); break; - case '\b': fprintf(F, "\\b"); break; - } - } - fprintf(F, "\""); + OS << " "; + if (Str->isWide()) + OS << "L"; + OS << '"'; + OS.write_escaped(llvm::StringRef(Str->getStrData(), + Str->getByteLength())); + OS << '"'; } void StmtDumper::VisitUnaryOperator(UnaryOperator *Node) { DumpExpr(Node); - fprintf(F, " %s '%s'", Node->isPostfix() ? "postfix" : "prefix", - UnaryOperator::getOpcodeStr(Node->getOpcode())); + OS << " " << (Node->isPostfix() ? "postfix" : "prefix") + << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'"; } void StmtDumper::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { DumpExpr(Node); - fprintf(F, " %s ", Node->isSizeOf() ? "sizeof" : "alignof"); + OS << " " << (Node->isSizeOf() ? "sizeof" : "alignof") << " "; if (Node->isArgumentType()) DumpType(Node->getArgumentType()); } void StmtDumper::VisitMemberExpr(MemberExpr *Node) { DumpExpr(Node); - fprintf(F, " %s%s %p", Node->isArrow() ? "->" : ".", - Node->getMemberDecl()->getNameAsString().c_str(), - (void*)Node->getMemberDecl()); + OS << " " << (Node->isArrow() ? "->" : ".") + << Node->getMemberDecl()->getNameAsString() << " " + << (void*)Node->getMemberDecl(); } void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { DumpExpr(Node); - fprintf(F, " %s", Node->getAccessor().getNameStart()); + OS << " " << Node->getAccessor().getNameStart(); } void StmtDumper::VisitBinaryOperator(BinaryOperator *Node) { DumpExpr(Node); - fprintf(F, " '%s'", BinaryOperator::getOpcodeStr(Node->getOpcode())); + OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) << "'"; } void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) { DumpExpr(Node); - fprintf(F, " '%s' ComputeLHSTy=", - BinaryOperator::getOpcodeStr(Node->getOpcode())); + OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) + << "' ComputeLHSTy="; DumpType(Node->getComputationLHSType()); - fprintf(F, " ComputeResultTy="); + OS << " ComputeResultTy="; DumpType(Node->getComputationResultType()); } @@ -428,14 +432,15 @@ void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) { void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) { DumpExpr(Node); - fprintf(F, " %s %p", Node->getLabel()->getName(), (void*)Node->getLabel()); + OS << " " << Node->getLabel()->getName() + << " " << (void*)Node->getLabel(); } void StmtDumper::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) { DumpExpr(Node); - fprintf(F, " "); + OS << " "; DumpType(Node->getArgType1()); - fprintf(F, " "); + OS << " "; DumpType(Node->getArgType2()); } @@ -445,36 +450,35 @@ void StmtDumper::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) { void StmtDumper::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) { DumpExpr(Node); - fprintf(F, " %s<%s> <%s>", Node->getCastName(), - Node->getTypeAsWritten().getAsString().c_str(), - Node->getCastKindName()); + OS << " " << Node->getCastName() + << "<" << Node->getTypeAsWritten().getAsString() << ">" + << " <" << Node->getCastKindName() << ">"; } void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { DumpExpr(Node); - fprintf(F, " %s", Node->getValue() ? "true" : "false"); + OS << " " << (Node->getValue() ? "true" : "false"); } void StmtDumper::VisitCXXThisExpr(CXXThisExpr *Node) { DumpExpr(Node); - fprintf(F, " this"); + OS << " this"; } void StmtDumper::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) { DumpExpr(Node); - fprintf(F, " functional cast to %s", - Node->getTypeAsWritten().getAsString().c_str()); + OS << " functional cast to " << Node->getTypeAsWritten().getAsString(); } void StmtDumper::VisitCXXConstructExpr(CXXConstructExpr *Node) { DumpExpr(Node); if (Node->isElidable()) - fprintf(F, " elidable"); + OS << " elidable"; } void StmtDumper::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) { DumpExpr(Node); - fprintf(F, " "); + OS << " "; DumpCXXTemporary(Node->getTemporary()); } @@ -482,7 +486,7 @@ void StmtDumper::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *Node) { DumpExpr(Node); ++IndentLevel; for (unsigned i = 0, e = Node->getNumTemporaries(); i != e; ++i) { - fprintf(F, "\n"); + OS << "\n"; Indent(); DumpCXXTemporary(Node->getTemporary(i)); } @@ -490,7 +494,7 @@ void StmtDumper::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *Node) { } void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) { - fprintf(F, "(CXXTemporary %p)", (void *)Temporary); + OS << "(CXXTemporary " << (void *)Temporary << ")"; } //===----------------------------------------------------------------------===// @@ -499,37 +503,34 @@ void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) { void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) { DumpExpr(Node); - fprintf(F, " selector=%s", Node->getSelector().getAsString().c_str()); - IdentifierInfo* clsName = Node->getClassName(); - if (clsName) fprintf(F, " class=%s", clsName->getNameStart()); + OS << " selector=" << Node->getSelector().getAsString(); + if (IdentifierInfo *clsName = Node->getClassName()) + OS << " class=" << clsName->getNameStart(); } void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { DumpExpr(Node); - - fprintf(F, " "); + OS << " "; DumpType(Node->getEncodedType()); } void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { DumpExpr(Node); - fprintf(F, " "); - fprintf(F, "%s", Node->getSelector().getAsString().c_str()); + OS << " " << Node->getSelector().getAsString(); } void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { DumpExpr(Node); - fprintf(F, " "); - fprintf(F, "%s", Node->getProtocol()->getNameAsString().c_str()); + OS << " " << Node->getProtocol()->getNameAsString(); } void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { DumpExpr(Node); - fprintf(F, " Kind=PropertyRef Property=\"%s\"", - Node->getProperty()->getNameAsString().c_str()); + OS << " Kind=PropertyRef Property=\"" + << Node->getProperty()->getNameAsString() << "\""; } void StmtDumper::VisitObjCImplicitSetterGetterRefExpr( @@ -538,14 +539,19 @@ void StmtDumper::VisitObjCImplicitSetterGetterRefExpr( ObjCMethodDecl *Getter = Node->getGetterMethod(); ObjCMethodDecl *Setter = Node->getSetterMethod(); - fprintf(F, " Kind=MethodRef Getter=\"%s\" Setter=\"%s\"", - Getter->getSelector().getAsString().c_str(), - Setter ? Setter->getSelector().getAsString().c_str() : "(null)"); + OS << " Kind=MethodRef Getter=\"" + << Getter->getSelector().getAsString() + << "\" Setter=\""; + if (Setter) + OS << Setter->getSelector().getAsString(); + else + OS << "(null)"; + OS << "\""; } void StmtDumper::VisitObjCSuperExpr(ObjCSuperExpr *Node) { DumpExpr(Node); - fprintf(F, " super"); + OS << " super"; } //===----------------------------------------------------------------------===// @@ -556,30 +562,30 @@ void StmtDumper::VisitObjCSuperExpr(ObjCSuperExpr *Node) { /// specified node and a few nodes underneath it, but not the whole subtree. /// This is useful in a debugger. void Stmt::dump(SourceManager &SM) const { - StmtDumper P(&SM, stderr, 4); + StmtDumper P(&SM, llvm::errs(), 4); P.DumpSubTree(const_cast<Stmt*>(this)); - fprintf(stderr, "\n"); + llvm::errs() << "\n"; } /// dump - This does a local dump of the specified AST fragment. It dumps the /// specified node and a few nodes underneath it, but not the whole subtree. /// This is useful in a debugger. void Stmt::dump() const { - StmtDumper P(0, stderr, 4); + StmtDumper P(0, llvm::errs(), 4); P.DumpSubTree(const_cast<Stmt*>(this)); - fprintf(stderr, "\n"); + llvm::errs() << "\n"; } /// dumpAll - This does a dump of the specified AST fragment and all subtrees. void Stmt::dumpAll(SourceManager &SM) const { - StmtDumper P(&SM, stderr, ~0U); + StmtDumper P(&SM, llvm::errs(), ~0U); P.DumpSubTree(const_cast<Stmt*>(this)); - fprintf(stderr, "\n"); + llvm::errs() << "\n"; } /// dumpAll - This does a dump of the specified AST fragment and all subtrees. void Stmt::dumpAll() const { - StmtDumper P(0, stderr, ~0U); + StmtDumper P(0, llvm::errs(), ~0U); P.DumpSubTree(const_cast<Stmt*>(this)); - fprintf(stderr, "\n"); + llvm::errs() << "\n"; } diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 205ea0d..a7e42af 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1145,17 +1145,19 @@ StmtPrinter::VisitCXXUnresolvedConstructExpr( void StmtPrinter::VisitCXXDependentScopeMemberExpr( CXXDependentScopeMemberExpr *Node) { - PrintExpr(Node->getBase()); - OS << (Node->isArrow() ? "->" : "."); + if (!Node->isImplicitAccess()) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + } if (NestedNameSpecifier *Qualifier = Node->getQualifier()) Qualifier->print(OS, Policy); - else if (Node->hasExplicitTemplateArgumentList()) + else if (Node->hasExplicitTemplateArgs()) // FIXME: Track use of "template" keyword explicitly? OS << "template "; OS << Node->getMember().getAsString(); - if (Node->hasExplicitTemplateArgumentList()) { + if (Node->hasExplicitTemplateArgs()) { OS << TemplateSpecializationType::PrintTemplateArgumentList( Node->getTemplateArgs(), Node->getNumTemplateArgs(), @@ -1164,8 +1166,10 @@ void StmtPrinter::VisitCXXDependentScopeMemberExpr( } void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) { - PrintExpr(Node->getBase()); - OS << (Node->isArrow() ? "->" : "."); + if (!Node->isImplicitAccess()) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + } if (NestedNameSpecifier *Qualifier = Node->getQualifier()) Qualifier->print(OS, Policy); diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index d832a46..e2d772b 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -554,18 +554,24 @@ StmtProfiler::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *S) { void StmtProfiler::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *S) { - VisitExpr(S); - ID.AddBoolean(S->isArrow()); + ID.AddBoolean(S->isImplicitAccess()); + if (!S->isImplicitAccess()) { + VisitExpr(S); + ID.AddBoolean(S->isArrow()); + } VisitNestedNameSpecifier(S->getQualifier()); VisitName(S->getMember()); - ID.AddBoolean(S->hasExplicitTemplateArgumentList()); - if (S->hasExplicitTemplateArgumentList()) + ID.AddBoolean(S->hasExplicitTemplateArgs()); + if (S->hasExplicitTemplateArgs()) VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); } void StmtProfiler::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *S) { - VisitExpr(S); - ID.AddBoolean(S->isArrow()); + ID.AddBoolean(S->isImplicitAccess()); + if (!S->isImplicitAccess()) { + VisitExpr(S); + ID.AddBoolean(S->isArrow()); + } VisitNestedNameSpecifier(S->getQualifier()); VisitName(S->getMemberName()); ID.AddBoolean(S->hasExplicitTemplateArgs()); @@ -653,13 +659,6 @@ void StmtProfiler::VisitDecl(Decl *D) { ID.AddInteger(TTP->getIndex()); return; } - - if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D)) { - // The Itanium C++ ABI mangles references to a set of overloaded - // functions using just the function name, so we do the same here. - VisitName(Ovl->getDeclName()); - return; - } } ID.AddPointer(D? D->getCanonicalDecl() : 0); diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp index f341b45..e9b1725 100644 --- a/lib/AST/TemplateBase.cpp +++ b/lib/AST/TemplateBase.cpp @@ -102,7 +102,7 @@ SourceRange TemplateArgumentLoc::getSourceRange() const { return getSourceDeclExpression()->getSourceRange(); case TemplateArgument::Type: - return getSourceDeclaratorInfo()->getTypeLoc().getFullSourceRange(); + return getTypeSourceInfo()->getTypeLoc().getFullSourceRange(); case TemplateArgument::Template: if (getTemplateQualifierRange().isValid()) diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp index 5b4cf0a..b56c0ceb 100644 --- a/lib/AST/TemplateName.cpp +++ b/lib/AST/TemplateName.cpp @@ -29,25 +29,14 @@ TemplateDecl *TemplateName::getAsTemplateDecl() const { return 0; } -OverloadedFunctionDecl *TemplateName::getAsOverloadedFunctionDecl() const { - if (OverloadedFunctionDecl *Ovl - = Storage.dyn_cast<OverloadedFunctionDecl *>()) - return Ovl; - - if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) - return QTN->getOverloadedFunctionDecl(); - - return 0; -} - bool TemplateName::isDependent() const { if (TemplateDecl *Template = getAsTemplateDecl()) { return isa<TemplateTemplateParmDecl>(Template) || Template->getDeclContext()->isDependentContext(); } - if (OverloadedFunctionDecl *Ovl = getAsOverloadedFunctionDecl()) - return Ovl->getDeclContext()->isDependentContext(); + assert(!getAsOverloadedTemplate() && + "overloaded templates shouldn't survive to here"); return true; } @@ -57,9 +46,6 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, bool SuppressNNS) const { if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>()) OS << Template->getNameAsString(); - else if (OverloadedFunctionDecl *Ovl - = Storage.dyn_cast<OverloadedFunctionDecl *>()) - OS << Ovl->getNameAsString(); else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) { if (!SuppressNNS) QTN->getQualifier()->print(OS, Policy); @@ -84,13 +70,3 @@ void TemplateName::dump() const { LO.Bool = true; print(llvm::errs(), PrintingPolicy(LO)); } - -TemplateDecl *QualifiedTemplateName::getTemplateDecl() const { - return dyn_cast<TemplateDecl>(Template); -} - -OverloadedFunctionDecl * -QualifiedTemplateName::getOverloadedFunctionDecl() const { - return dyn_cast<OverloadedFunctionDecl>(Template); -} - diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 5a2434d..687beae 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -434,6 +434,18 @@ bool Type::isWideCharType() const { return false; } +/// \brief Determine whether this type is any of the built-in character +/// types. +bool Type::isAnyCharacterType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return (BT->getKind() >= BuiltinType::Char_U && + BT->getKind() <= BuiltinType::Char32) || + (BT->getKind() >= BuiltinType::Char_S && + BT->getKind() <= BuiltinType::WChar); + + return false; +} + /// isSignedIntegerType - Return true if this is an integer type that is /// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..], /// an enum decl which has a signed representation, or a vector of signed @@ -639,6 +651,40 @@ bool Type::isPODType() const { } } +bool Type::isLiteralType() const { + if (isIncompleteType()) + return false; + + // C++0x [basic.types]p10: + // A type is a literal type if it is: + switch (CanonicalType->getTypeClass()) { + // We're whitelisting + default: return false; + + // -- a scalar type + case Builtin: + case Complex: + case Pointer: + case MemberPointer: + case Vector: + case ExtVector: + case ObjCObjectPointer: + case Enum: + return true; + + // -- a class type with ... + case Record: + // FIXME: Do the tests + return false; + + // -- an array of literal type + // Extension: variable arrays cannot be literal types, since they're + // runtime-sized. + case ConstantArray: + return cast<ArrayType>(CanonicalType)->getElementType()->isLiteralType(); + } +} + bool Type::isPromotableIntegerType() const { if (const BuiltinType *BT = getAs<BuiltinType>()) switch (BT->getKind()) { diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index 50a5120..3ccb7a9 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -94,3 +94,32 @@ void TypeLoc::initializeImpl(TypeLoc TL, SourceLocation Loc) { TypeLocInitializer(Loc).Visit(TL); } while ((TL = TL.getNextTypeLoc())); } + +namespace { + struct TSTChecker : public TypeLocVisitor<TSTChecker, bool> { + // Overload resolution does the real work for us. + static bool isTypeSpec(TypeSpecTypeLoc _) { return true; } + static bool isTypeSpec(TypeLoc _) { return false; } + +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return isTypeSpec(TyLoc); \ + } +#include "clang/AST/TypeLocNodes.def" + }; +} + + +/// \brief Determines if the given type loc corresponds to a +/// TypeSpecTypeLoc. Since there is not actually a TypeSpecType in +/// the type hierarchy, this is made somewhat complicated. +/// +/// There are a lot of types that currently use TypeSpecTypeLoc +/// because it's a convenient base class. Ideally we would not accept +/// those here, but ideally we would have better implementations for +/// them. +bool TypeSpecTypeLoc::classof(const TypeLoc *TL) { + if (TL->getType().hasLocalQualifiers()) return false; + return TSTChecker().Visit(*TL); +} diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 562e830..4a2b956 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -242,12 +242,13 @@ void TypePrinter::PrintDependentSizedExtVector( 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. + Print(T->getElementType(), S); + std::string V = "__attribute__((__vector_size__("; + V += llvm::utostr_32(T->getNumElements()); // convert back to bytes. std::string ET; Print(T->getElementType(), ET); - S += " * sizeof(" + ET + "))))"; - Print(T->getElementType(), S); + V += " * sizeof(" + ET + ")))) "; + S = V + S; } void TypePrinter::PrintExtVector(const ExtVectorType *T, std::string &S) { @@ -284,6 +285,23 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T, } S += ")"; + + if (T->hasExceptionSpec()) { + S += " throw("; + if (T->hasAnyExceptionSpec()) + S += "..."; + else + for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I) { + if (I) + S += ", "; + + std::string ExceptionType; + Print(T->getExceptionType(I), ExceptionType); + S += ExceptionType; + } + S += ")"; + } + if (T->getNoReturnAttr()) S += " __attribute__((noreturn))"; Print(T->getResultType(), S); @@ -302,6 +320,15 @@ void TypePrinter::PrintFunctionNoProto(const FunctionNoProtoType *T, Print(T->getResultType(), S); } +void TypePrinter::PrintUnresolvedUsing(const UnresolvedUsingType *T, + std::string &S) { + IdentifierInfo *II = T->getDecl()->getIdentifier(); + if (S.empty()) + S = II->getName().str(); + else + S = II->getName().str() + ' ' + S; +} + void TypePrinter::PrintTypedef(const TypedefType *T, std::string &S) { if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'. S = ' ' + S; @@ -683,9 +710,8 @@ void QualType::dump(const char *msg) const { 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()); + llvm::errs() << msg << ": "; + llvm::errs() << R << "\n"; } void QualType::dump() const { dump(""); diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp index 339e2c9..05e5196 100644 --- a/lib/Analysis/AnalysisContext.cpp +++ b/lib/Analysis/AnalysisContext.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/PathSensitive/AnalysisContext.h" +#include "clang/Analysis/PathSensitive/MemRegion.h" #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/CFG.h" #include "clang/AST/Decl.h" @@ -35,8 +36,10 @@ Stmt *AnalysisContext::getBody() { return FD->getBody(); else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) return MD->getBody(); + else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) + return BD->getBody(); - llvm::llvm_unreachable("unknown code decl"); + llvm_unreachable("unknown code decl"); } const ImplicitParamDecl *AnalysisContext::getSelfDecl() const { @@ -80,73 +83,113 @@ AnalysisContext *AnalysisContextManager::getContext(const Decl *D) { return AC; } -void LocationContext::Profile(llvm::FoldingSetNodeID &ID, ContextKind k, - AnalysisContext *ctx, - const LocationContext *parent) { - ID.AddInteger(k); +const BlockDecl *BlockInvocationContext::getBlockDecl() const { + return Data.is<const BlockDataRegion*>() ? + Data.get<const BlockDataRegion*>()->getDecl() + : Data.get<const BlockDecl*>(); +} + +//===----------------------------------------------------------------------===// +// FoldingSet profiling. +//===----------------------------------------------------------------------===// + +void LocationContext::ProfileCommon(llvm::FoldingSetNodeID &ID, + ContextKind ck, + AnalysisContext *ctx, + const LocationContext *parent, + const void* data) { + ID.AddInteger(ck); ID.AddPointer(ctx); ID.AddPointer(parent); + ID.AddPointer(data); } -void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID,AnalysisContext *ctx, - const LocationContext *parent, const Stmt *s) { - LocationContext::Profile(ID, StackFrame, ctx, parent); - ID.AddPointer(s); +void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getAnalysisContext(), getParent(), CallSite); } -void ScopeContext::Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx, - const LocationContext *parent, const Stmt *s) { - LocationContext::Profile(ID, Scope, ctx, parent); - ID.AddPointer(s); +void ScopeContext::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getAnalysisContext(), getParent(), Enter); } -LocationContextManager::~LocationContextManager() { - clear(); +void BlockInvocationContext::Profile(llvm::FoldingSetNodeID &ID) { + if (const BlockDataRegion *BR = getBlockRegion()) + Profile(ID, getAnalysisContext(), getParent(), BR); + else + Profile(ID, getAnalysisContext(), getParent(), + Data.get<const BlockDecl*>()); } -void LocationContextManager::clear() { - for (llvm::FoldingSet<LocationContext>::iterator I = Contexts.begin(), - E = Contexts.end(); I != E; ) { - LocationContext *LC = &*I; - ++I; - delete LC; - } +//===----------------------------------------------------------------------===// +// LocationContext creation. +//===----------------------------------------------------------------------===// + +template <typename LOC, typename DATA> +const LOC* +LocationContextManager::getLocationContext(AnalysisContext *ctx, + const LocationContext *parent, + const DATA *d) { + llvm::FoldingSetNodeID ID; + LOC::Profile(ID, ctx, parent, d); + void *InsertPos; - Contexts.clear(); + LOC *L = cast_or_null<LOC>(Contexts.FindNodeOrInsertPos(ID, InsertPos)); + + if (!L) { + L = new LOC(ctx, parent, d); + Contexts.InsertNode(L, InsertPos); + } + return L; } -StackFrameContext* +const StackFrameContext* LocationContextManager::getStackFrame(AnalysisContext *ctx, const LocationContext *parent, const Stmt *s) { - llvm::FoldingSetNodeID ID; - StackFrameContext::Profile(ID, ctx, parent, s); - void *InsertPos; + return getLocationContext<StackFrameContext, Stmt>(ctx, parent, s); +} - StackFrameContext *f = - cast_or_null<StackFrameContext>(Contexts.FindNodeOrInsertPos(ID, InsertPos)); - if (!f) { - f = new StackFrameContext(ctx, parent, s); - Contexts.InsertNode(f, InsertPos); - } - return f; +const ScopeContext * +LocationContextManager::getScope(AnalysisContext *ctx, + const LocationContext *parent, + const Stmt *s) { + return getLocationContext<ScopeContext, Stmt>(ctx, parent, s); } -ScopeContext *LocationContextManager::getScope(AnalysisContext *ctx, - const LocationContext *parent, - const Stmt *s) { - llvm::FoldingSetNodeID ID; - ScopeContext::Profile(ID, ctx, parent, s); - void *InsertPos; +const BlockInvocationContext * +LocationContextManager::getBlockInvocation(AnalysisContext *ctx, + const LocationContext *parent, + const BlockDataRegion *BR) { + return getLocationContext<BlockInvocationContext, BlockDataRegion>(ctx, + parent, + BR); +} - ScopeContext *scope = - cast_or_null<ScopeContext>(Contexts.FindNodeOrInsertPos(ID, InsertPos)); +//===----------------------------------------------------------------------===// +// LocationContext methods. +//===----------------------------------------------------------------------===// - if (!scope) { - scope = new ScopeContext(ctx, parent, s); - Contexts.InsertNode(scope, InsertPos); +const StackFrameContext *LocationContext::getCurrentStackFrame() const { + const LocationContext *LC = this; + while (LC) { + if (const StackFrameContext *SFC = dyn_cast<StackFrameContext>(LC)) + return SFC; + LC = LC->getParent(); } - return scope; + return NULL; +} + +const StackFrameContext * +LocationContext::getStackFrameForDeclContext(const DeclContext *DC) const { + const LocationContext *LC = this; + while (LC) { + if (const StackFrameContext *SFC = dyn_cast<StackFrameContext>(LC)) { + if (cast<DeclContext>(SFC->getDecl()) == DC) + return SFC; + } + LC = LC->getParent(); + } + return NULL; } //===----------------------------------------------------------------------===// @@ -220,3 +263,21 @@ AnalysisContextManager::~AnalysisContextManager() { for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I) delete I->second; } + +LocationContext::~LocationContext() {} + +LocationContextManager::~LocationContextManager() { + clear(); +} + +void LocationContextManager::clear() { + for (llvm::FoldingSet<LocationContext>::iterator I = Contexts.begin(), + E = Contexts.end(); I != E; ) { + LocationContext *LC = &*I; + ++I; + delete LC; + } + + Contexts.clear(); +} + diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp index 45fc11a..a38aaa7 100644 --- a/lib/Analysis/BasicStore.cpp +++ b/lib/Analysis/BasicStore.cpp @@ -68,14 +68,14 @@ public: } const GRState *BindCompoundLiteral(const GRState *state, - const CompoundLiteralExpr* cl, + const CompoundLiteralExpr*, + const LocationContext*, SVal val) { return state; } SVal getLValueVar(const VarDecl *VD, const LocationContext *LC); SVal getLValueString(const StringLiteral *S); - SVal getLValueCompoundLiteral(const CompoundLiteralExpr *CL); SVal getLValueIvar(const ObjCIvarDecl* D, SVal Base); SVal getLValueField(const FieldDecl *D, SVal Base); SVal getLValueElement(QualType elementType, SVal Offset, SVal Base); @@ -130,10 +130,6 @@ SVal BasicStoreManager::getLValueString(const StringLiteral* S) { return ValMgr.makeLoc(MRMgr.getStringRegion(S)); } -SVal BasicStoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL){ - return ValMgr.makeLoc(MRMgr.getCompoundLiteralRegion(CL)); -} - SVal BasicStoreManager::getLValueIvar(const ObjCIvarDecl* D, SVal Base) { if (Base.isUnknownOrUndef()) @@ -368,7 +364,7 @@ BasicStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, // Iterate over the variable bindings. for (BindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I) { if (const VarRegion *VR = dyn_cast<VarRegion>(I.getKey())) { - if (SymReaper.isLive(Loc, VR->getDecl())) + if (SymReaper.isLive(Loc, VR)) RegionRoots.push_back(VR); else continue; diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp index c26a60a..e648269 100644 --- a/lib/Analysis/BugReporter.cpp +++ b/lib/Analysis/BugReporter.cpp @@ -204,10 +204,19 @@ PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream& os, os << "Execution continues on line " << getSourceManager().getInstantiationLineNumber(Loc.asLocation()) << '.'; - else - os << "Execution jumps to the end of the " - << (isa<ObjCMethodDecl>(N->getLocationContext()->getDecl()) ? - "method" : "function") << '.'; + else { + os << "Execution jumps to the end of the "; + const Decl *D = N->getLocationContext()->getDecl(); + if (isa<ObjCMethodDecl>(D)) + os << "method"; + else if (isa<FunctionDecl>(D)) + os << "function"; + else { + assert(isa<BlockDecl>(D)); + os << "anonymous block"; + } + os << '.'; + } return Loc; } diff --git a/lib/Analysis/BuiltinFunctionChecker.cpp b/lib/Analysis/BuiltinFunctionChecker.cpp new file mode 100644 index 0000000..a89ad21 --- /dev/null +++ b/lib/Analysis/BuiltinFunctionChecker.cpp @@ -0,0 +1,76 @@ +//=== BuiltinFunctionChecker.cpp --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This checker evaluates clang builtin functions. +// +//===----------------------------------------------------------------------===// + +#include "GRExprEngineInternalChecks.h" +#include "clang/Analysis/PathSensitive/Checker.h" +#include "clang/Basic/Builtins.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; + +namespace { + +class BuiltinFunctionChecker : public Checker { +public: + static void *getTag() { static int tag = 0; return &tag; } + virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE); +}; + +} + +void clang::RegisterBuiltinFunctionChecker(GRExprEngine &Eng) { + Eng.registerCheck(new BuiltinFunctionChecker()); +} + +bool BuiltinFunctionChecker::EvalCallExpr(CheckerContext &C,const CallExpr *CE){ + const GRState *state = C.getState(); + const Expr *Callee = CE->getCallee(); + SVal L = state->getSVal(Callee); + const FunctionDecl *FD = L.getAsFunctionDecl(); + + if (!FD) + return false; + + unsigned id = FD->getBuiltinID(); + + if (!id) + return false; + + switch (id) { + case Builtin::BI__builtin_expect: { + // For __builtin_expect, just return the value of the subexpression. + assert (CE->arg_begin() != CE->arg_end()); + SVal X = state->getSVal(*(CE->arg_begin())); + C.GenerateNode(state->BindExpr(CE, X)); + return true; + } + + case Builtin::BI__builtin_alloca: { + // FIXME: Refactor into StoreManager itself? + MemRegionManager& RM = C.getStoreManager().getRegionManager(); + const MemRegion* R = + RM.getAllocaRegion(CE, C.getNodeBuilder().getCurrentBlockCount(), + C.getPredecessor()->getLocationContext()); + + // Set the extent of the region in bytes. This enables us to use the + // SVal of the argument directly. If we save the extent in bits, we + // cannot represent values like symbol*8. + SVal Extent = state->getSVal(*(CE->arg_begin())); + state = C.getStoreManager().setExtent(state, R, Extent); + C.GenerateNode(state->BindExpr(CE, loc::MemRegionVal(R))); + return true; + } + } + + return false; +} diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index c97692f..e1a1e72 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -87,7 +87,6 @@ private: CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, bool alwaysAdd); CFGBlock *VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd); CFGBlock *VisitBlockExpr(BlockExpr* E, bool alwaysAdd); - CFGBlock *VisitBlockDeclRefExpr(BlockDeclRefExpr* E, bool alwaysAdd); CFGBlock *VisitBreakStmt(BreakStmt *B); CFGBlock *VisitCallExpr(CallExpr *C, bool alwaysAdd); CFGBlock *VisitCaseStmt(CaseStmt *C); @@ -95,7 +94,9 @@ private: CFGBlock *VisitCompoundStmt(CompoundStmt *C); CFGBlock *VisitConditionalOperator(ConditionalOperator *C); CFGBlock *VisitContinueStmt(ContinueStmt *C); + CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S) { return NYS(); } CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T); + CFGBlock *VisitCXXTryStmt(CXXTryStmt *S) { return NYS(); } CFGBlock *VisitDeclStmt(DeclStmt *DS); CFGBlock *VisitDeclSubExpr(Decl* D); CFGBlock *VisitDefaultStmt(DefaultStmt *D); @@ -292,9 +293,6 @@ tryAgain: case Stmt::BlockExprClass: return VisitBlockExpr(cast<BlockExpr>(S), alwaysAdd); - case Stmt::BlockDeclRefExprClass: - return VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(S), alwaysAdd); - case Stmt::BreakStmtClass: return VisitBreakStmt(cast<BreakStmt>(S)); @@ -468,12 +466,6 @@ CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, bool alwaysAdd) { return Block; } -CFGBlock *CFGBuilder::VisitBlockDeclRefExpr(BlockDeclRefExpr* E, - bool alwaysAdd) { - // FIXME - return NYS(); -} - CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) { // "break" is a control-flow statement. Thus we stop processing the current // block. diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index b95f981..9639ad9 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -675,11 +675,9 @@ template <> struct DenseMapInfo<ObjCSummaryKey> { RHS.getSelector()); } - static bool isPod() { - return DenseMapInfo<ObjCInterfaceDecl*>::isPod() && - DenseMapInfo<Selector>::isPod(); - } }; +template <> +struct isPodLike<ObjCSummaryKey> { static const bool value = true; }; } // end llvm namespace namespace { @@ -1984,8 +1982,9 @@ public: Expr* Ex, Expr* Receiver, const RetainSummary& Summ, + const MemRegion *Callee, ExprIterator arg_beg, ExprIterator arg_end, - ExplodedNode* Pred); + ExplodedNode* Pred, const GRState *state); virtual void EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Eng, @@ -1998,7 +1997,8 @@ public: GRExprEngine& Engine, GRStmtNodeBuilder& Builder, ObjCMessageExpr* ME, - ExplodedNode* Pred); + ExplodedNode* Pred, + const GRState *state); bool EvalObjCMessageExprAux(ExplodedNodeSet& Dst, GRExprEngine& Engine, @@ -2776,11 +2776,9 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, Expr* Ex, Expr* Receiver, const RetainSummary& Summ, + const MemRegion *Callee, ExprIterator arg_beg, ExprIterator arg_end, - ExplodedNode* Pred) { - - // Get the state. - const GRState *state = Builder.GetState(Pred); + ExplodedNode* Pred, const GRState *state) { // Evaluate the effect of the arguments. RefVal::Kind hasErr = (RefVal::Kind) 0; @@ -2788,6 +2786,8 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, Expr* ErrorExpr = NULL; SymbolRef ErrorSym = 0; + llvm::SmallVector<const MemRegion*, 10> RegionsToInvalidate; + for (ExprIterator I = arg_beg; I != arg_end; ++I, ++idx) { SVal V = state->getSValAsScalarOrLoc(*I); SymbolRef Sym = V.getAsLocSymbol(); @@ -2810,16 +2810,8 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, continue; // Invalidate the value of the variable passed by reference. - - // FIXME: We can have collisions on the conjured symbol if the - // expression *I also creates conjured symbols. We probably want - // to identify conjured symbols by an expression pair: the enclosing - // expression (the context) and the expression itself. This should - // disambiguate conjured symbols. - unsigned Count = Builder.getCurrentBlockCount(); - StoreManager& StoreMgr = Eng.getStateManager().getStoreManager(); - const MemRegion *R = MR->getRegion(); + // Are we dealing with an ElementRegion? If the element type is // a basic integer type (e.g., char, int) and the underying region // is a variable region then strip off the ElementRegion. @@ -2843,14 +2835,11 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, } // FIXME: What about layers of ElementRegions? } - - StoreManager::InvalidatedSymbols IS; - state = StoreMgr.InvalidateRegion(state, R, *I, Count, &IS); - for (StoreManager::InvalidatedSymbols::iterator I = IS.begin(), - E = IS.end(); I!=E; ++I) { - // Remove any existing reference-count binding. - state = state->remove<RefBindings>(*I); - } + + // Mark this region for invalidation. We batch invalidate regions + // below for efficiency. + RegionsToInvalidate.push_back(R); + continue; } else { // Nuke all other arguments passed by reference. @@ -2866,6 +2855,36 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, goto tryAgain; } } + + // Block calls result in all captured values passed-via-reference to be + // invalidated. + if (const BlockDataRegion *BR = dyn_cast_or_null<BlockDataRegion>(Callee)) { + RegionsToInvalidate.push_back(BR); + } + + // Invalidate regions we designed for invalidation use the batch invalidation + // API. + if (!RegionsToInvalidate.empty()) { + // FIXME: We can have collisions on the conjured symbol if the + // expression *I also creates conjured symbols. We probably want + // to identify conjured symbols by an expression pair: the enclosing + // expression (the context) and the expression itself. This should + // disambiguate conjured symbols. + unsigned Count = Builder.getCurrentBlockCount(); + StoreManager& StoreMgr = Eng.getStateManager().getStoreManager(); + + + StoreManager::InvalidatedSymbols IS; + state = StoreMgr.InvalidateRegions(state, RegionsToInvalidate.data(), + RegionsToInvalidate.data() + + RegionsToInvalidate.size(), + Ex, Count, &IS); + for (StoreManager::InvalidatedSymbols::iterator I = IS.begin(), + E = IS.end(); I!=E; ++I) { + // Remove any existing reference-count binding. + state = state->remove<RefBindings>(*I); + } + } // Evaluate the effect on the message receiver. if (!ErrorExpr && Receiver) { @@ -3012,35 +3031,24 @@ void CFRefCount::EvalCall(ExplodedNodeSet& Dst, } assert(Summ); - EvalSummary(Dst, Eng, Builder, CE, 0, *Summ, - CE->arg_begin(), CE->arg_end(), Pred); + EvalSummary(Dst, Eng, Builder, CE, 0, *Summ, L.getAsRegion(), + CE->arg_begin(), CE->arg_end(), Pred, Builder.GetState(Pred)); } void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, GRExprEngine& Eng, GRStmtNodeBuilder& Builder, ObjCMessageExpr* ME, - ExplodedNode* Pred) { - // FIXME: Since we moved the nil check into a checker, we could get nil - // receiver here. Need a better way to check such case. - if (Expr* Receiver = ME->getReceiver()) { - const GRState *state = Pred->getState(); - DefinedOrUnknownSVal L=cast<DefinedOrUnknownSVal>(state->getSVal(Receiver)); - if (!state->Assume(L, true)) { - Dst.Add(Pred); - return; - } - } - + ExplodedNode* Pred, + const GRState *state) { RetainSummary *Summ = ME->getReceiver() - ? Summaries.getInstanceMethodSummary(ME, Builder.GetState(Pred), - Pred->getLocationContext()) + ? Summaries.getInstanceMethodSummary(ME, state,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); + EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ, NULL, + ME->arg_begin(), ME->arg_end(), Pred, state); } namespace { @@ -3671,7 +3679,24 @@ void RetainReleaseChecker::PostVisitBlockExpr(CheckerContext &C, if (I == E) return; - state = state->scanReachableSymbols<StopTrackingCallback>(I, E).getState(); + // FIXME: For now we invalidate the tracking of all symbols passed to blocks + // via captured variables, even though captured variables result in a copy + // and in implicit increment/decrement of a retain count. + llvm::SmallVector<const MemRegion*, 10> Regions; + const LocationContext *LC = C.getPredecessor()->getLocationContext(); + MemRegionManager &MemMgr = C.getValueManager().getRegionManager(); + + for ( ; I != E; ++I) { + const VarRegion *VR = *I; + if (VR->getSuperRegion() == R) { + VR = MemMgr.getVarRegion(VR->getDecl(), LC); + } + Regions.push_back(VR); + } + + state = + state->scanReachableSymbols<StopTrackingCallback>(Regions.data(), + Regions.data() + Regions.size()).getState(); C.addTransition(state); } diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index 409292d..521f1be 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -10,10 +10,10 @@ add_clang_library(clangAnalysis BasicValueFactory.cpp BugReporter.cpp BugReporterVisitors.cpp + BuiltinFunctionChecker.cpp CFG.cpp CFRefCount.cpp CallAndMessageChecker.cpp - CallGraph.cpp CallInliner.cpp CastToStructChecker.cpp CheckDeadStores.cpp @@ -37,8 +37,10 @@ add_clang_library(clangAnalysis MallocChecker.cpp ManagerRegistry.cpp MemRegion.cpp + NoReturnFunctionChecker.cpp NSAutoreleasePoolChecker.cpp NSErrorChecker.cpp + OSAtomicChecker.cpp PathDiagnostic.cpp PointerArithChecker.cpp PointerSubChecker.cpp diff --git a/lib/Analysis/CallAndMessageChecker.cpp b/lib/Analysis/CallAndMessageChecker.cpp index d8dd16c..c287354 100644 --- a/lib/Analysis/CallAndMessageChecker.cpp +++ b/lib/Analysis/CallAndMessageChecker.cpp @@ -41,6 +41,7 @@ public: void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME); + bool EvalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME); private: void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE); @@ -148,28 +149,12 @@ void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C, } } } +} - // Check if the receiver was nil and then returns a value that may - // be garbage. - if (const Expr *Receiver = ME->getReceiver()) { - DefinedOrUnknownSVal receiverVal = - cast<DefinedOrUnknownSVal>(state->getSVal(Receiver)); - - const GRState *notNullState, *nullState; - llvm::tie(notNullState, nullState) = state->Assume(receiverVal); - - if (nullState && !notNullState) { - HandleNilReceiver(C, nullState, ME); - C.setDoneEvaluating(); // FIXME: eventually remove. - return; - } - - assert(notNullState); - state = notNullState; - } - - // Add a state transition if the state has changed. - C.addTransition(state); +bool CallAndMessageChecker::EvalNilReceiver(CheckerContext &C, + const ObjCMessageExpr *ME) { + HandleNilReceiver(C, C.getState(), ME); + return true; // Nil receiver is not handled elsewhere. } void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C, diff --git a/lib/Analysis/CheckDeadStores.cpp b/lib/Analysis/CheckDeadStores.cpp index ad63eb4..db9016f 100644 --- a/lib/Analysis/CheckDeadStores.cpp +++ b/lib/Analysis/CheckDeadStores.cpp @@ -84,7 +84,8 @@ public: const LiveVariables::AnalysisDataTy& AD, const LiveVariables::ValTy& Live) { - if (VD->hasLocalStorage() && !Live(VD, AD) && !VD->getAttr<UnusedAttr>()) + if (VD->hasLocalStorage() && !Live(VD, AD) && + !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>())) Report(VD, dsk, Ex->getSourceRange().getBegin(), Val->getSourceRange()); } @@ -185,6 +186,10 @@ public: if (V->hasLocalStorage()) if (Expr* E = V->getInit()) { + // Don't warn on C++ objects (yet) until we can show that their + // constructors/destructors don't have side effects. + if (isa<CXXConstructExpr>(E)) + return; // A dead initialization is a variable that is dead after it // is initialized. We don't flag warnings for those variables // marked 'unused'. diff --git a/lib/Analysis/CheckSecuritySyntaxOnly.cpp b/lib/Analysis/CheckSecuritySyntaxOnly.cpp index e6ab17a..3214101 100644 --- a/lib/Analysis/CheckSecuritySyntaxOnly.cpp +++ b/lib/Analysis/CheckSecuritySyntaxOnly.cpp @@ -23,6 +23,7 @@ class WalkAST : public StmtVisitor<WalkAST> { BugReporter &BR; IdentifierInfo *II_gets; IdentifierInfo *II_getpw; + IdentifierInfo *II_mktemp; enum { num_rands = 9 }; IdentifierInfo *II_rand[num_rands]; IdentifierInfo *II_random; @@ -31,7 +32,8 @@ class WalkAST : public StmtVisitor<WalkAST> { public: WalkAST(BugReporter &br) : BR(br), - II_gets(0), II_getpw(0), II_rand(), II_random(0), II_setid() {} + II_gets(0), II_getpw(0), II_mktemp(0), + II_rand(), II_random(0), II_setid() {} // Statement visitor methods. void VisitCallExpr(CallExpr *CE); @@ -48,6 +50,7 @@ public: 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_mktemp(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); @@ -79,6 +82,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) { if (const FunctionDecl *FD = CE->getDirectCallee()) { CheckCall_gets(CE, FD); CheckCall_getpw(CE, FD); + CheckCall_mktemp(CE, FD); CheckCall_rand(CE, FD); CheckCall_random(CE, FD); } @@ -288,6 +292,42 @@ void WalkAST::CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD) { } //===----------------------------------------------------------------------===// +// Check: Any use of 'mktemp' is insecure.It is obsoleted by mkstemp(). +// CWE-377: Insecure Temporary File +//===----------------------------------------------------------------------===// + +void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) { + if (FD->getIdentifier() != GetIdentifier(II_mktemp, "mktemp")) + return; + + const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FD->getType()); + if(!FPT) + return; + + // Verify that the funcion takes a single argument. + if (FPT->getNumArgs() != 1) + return; + + // Verify that the argument is Pointer Type. + const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(0)); + if (!PT) + return; + + // Verify that the argument is a 'char*'. + if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy) + return; + + // Issue a waring. + SourceRange R = CE->getCallee()->getSourceRange(); + BR.EmitBasicReport("Potential insecure temporary file in call 'mktemp'", + "Security", + "Call to function 'mktemp' is insecure as it always " + "creates or uses insecure temporary file", + 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/Checker.cpp b/lib/Analysis/Checker.cpp index 0d907e5..fb9d04d 100644 --- a/lib/Analysis/Checker.cpp +++ b/lib/Analysis/Checker.cpp @@ -24,10 +24,10 @@ CheckerContext::~CheckerContext() { // if we are building sinks or we generated a node and decided to not // add it as a transition. if (Dst.size() == size && !B.BuildSinks && !B.HasGeneratedNode) { - if (state && state != B.GetState(Pred)) { + if (ST && ST != B.GetState(Pred)) { static int autoTransitionTag = 0; B.Tag = &autoTransitionTag; - addTransition(state); + addTransition(ST); } else Dst.Add(Pred); diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 20820d4..51e6a54 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -116,53 +116,91 @@ public: // Checker worklist routines. //===----------------------------------------------------------------------===// -bool GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, +void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, bool isPrevisit) { if (Checkers.empty()) { Dst.insert(Src); - return false; + return; } ExplodedNodeSet Tmp; ExplodedNodeSet *PrevSet = &Src; - bool stopProcessingAfterCurrentChecker = false; - - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) - { - ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst - : (PrevSet == &Tmp) ? &Src : &Tmp; - CurrSet->clear(); + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E;++I){ + ExplodedNodeSet *CurrSet = 0; + if (I+1 == E) + CurrSet = &Dst; + else { + CurrSet = (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) { - // FIXME: Halting evaluation of the checkers is something we may - // not support later. The design is still evolving. - if (checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, - tag, isPrevisit)) { - if (CurrSet != &Dst) - Dst.insert(*CurrSet); - - stopProcessingAfterCurrentChecker = true; - continue; - } - assert(stopProcessingAfterCurrentChecker == false && - "Inconsistent setting of 'stopProcessingAfterCurrentChecker'"); - } - - if (stopProcessingAfterCurrentChecker) - return true; - - // Continue on to the next checker. Update the current NodeSet. + NI != NE; ++NI) + checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit); PrevSet = CurrSet; } // Don't autotransition. The CheckerContext objects should do this // automatically. - return false; +} + +void GRExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME, + ExplodedNodeSet &Dst, + const GRState *state, + ExplodedNode *Pred) { + bool Evaluated = false; + ExplodedNodeSet DstTmp; + + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) { + void *tag = I->first; + Checker *checker = I->second; + + if (checker->GR_EvalNilReceiver(DstTmp, *Builder, *this, ME, Pred, state, + tag)) { + Evaluated = true; + break; + } else + // The checker didn't evaluate the expr. Restore the Dst. + DstTmp.clear(); + } + + if (Evaluated) + Dst.insert(DstTmp); + else + Dst.insert(Pred); +} + +// CheckerEvalCall returns true if one of the checkers processed the node. +// This may return void when all call evaluation logic goes to some checker +// in the future. +bool GRExprEngine::CheckerEvalCall(const CallExpr *CE, + ExplodedNodeSet &Dst, + ExplodedNode *Pred) { + bool Evaluated = false; + ExplodedNodeSet DstTmp; + + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) { + void *tag = I->first; + Checker *checker = I->second; + + if (checker->GR_EvalCallExpr(DstTmp, *Builder, *this, CE, Pred, tag)) { + Evaluated = true; + break; + } else + // The checker didn't evaluate the expr. Restore the DstTmp set. + DstTmp.clear(); + } + + if (Evaluated) + Dst.insert(DstTmp); + else + Dst.insert(Pred); + + return Evaluated; } // FIXME: This is largely copy-paste from CheckerVisit(). Need to @@ -173,7 +211,7 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, SVal location, SVal val, bool isPrevisit) { if (Checkers.empty()) { - Dst = Src; + Dst.insert(Src); return; } @@ -182,10 +220,14 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) { - ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst - : (PrevSet == &Tmp) ? &Src : &Tmp; + ExplodedNodeSet *CurrSet = 0; + if (I+1 == E) + CurrSet = &Dst; + else { + CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; + CurrSet->clear(); + } - CurrSet->clear(); void *tag = I->first; Checker *checker = I->second; @@ -227,6 +269,11 @@ static void RegisterInternalChecks(GRExprEngine &Eng) { RegisterUndefinedAssignmentChecker(Eng); RegisterUndefBranchChecker(Eng); RegisterUndefResultChecker(Eng); + + // This is not a checker yet. + RegisterNoReturnFunctionChecker(Eng); + RegisterBuiltinFunctionChecker(Eng); + RegisterOSAtomicChecker(Eng); } GRExprEngine::GRExprEngine(AnalysisManager &mgr) @@ -347,8 +394,9 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) { Builder->setAuditor(BatchAuditor.get()); // Create the cleaned state. - SymbolReaper SymReaper(Builder->getBasePredecessor()->getLiveVariables(), - SymMgr); + const ExplodedNode *BasePred = Builder->getBasePredecessor(); + SymbolReaper SymReaper(BasePred->getLiveVariables(), SymMgr, + BasePred->getLocationContext()->getCurrentStackFrame()); CleanedState = AMgr.shouldPurgeDead() ? StateMgr.RemoveDeadBindings(EntryNode->getState(), CurrentStmt, SymReaper) : EntryNode->getState(); @@ -371,16 +419,20 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) { CleanedState, SymReaper); if (Checkers.empty()) - Tmp = Tmp2; + Tmp.insert(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(); + ExplodedNodeSet *DstSet = 0; + if (I+1 == E) + DstSet = &Tmp; + else { + DstSet = (SrcSet == &Tmp2) ? &Tmp3 : &Tmp2; + DstSet->clear(); + } + void *tag = I->first; Checker *checker = I->second; for (ExplodedNodeSet::iterator NI = SrcSet->begin(), NE = SrcSet->end(); @@ -441,6 +493,41 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { } switch (S->getStmtClass()) { + // C++ stuff we don't support yet. + case Stmt::CXXMemberCallExprClass: + case Stmt::CXXNamedCastExprClass: + case Stmt::CXXStaticCastExprClass: + case Stmt::CXXDynamicCastExprClass: + case Stmt::CXXReinterpretCastExprClass: + case Stmt::CXXConstCastExprClass: + case Stmt::CXXFunctionalCastExprClass: + case Stmt::CXXTypeidExprClass: + case Stmt::CXXBoolLiteralExprClass: + case Stmt::CXXNullPtrLiteralExprClass: + case Stmt::CXXThisExprClass: + case Stmt::CXXThrowExprClass: + case Stmt::CXXDefaultArgExprClass: + case Stmt::CXXZeroInitValueExprClass: + case Stmt::CXXNewExprClass: + case Stmt::CXXDeleteExprClass: + case Stmt::CXXPseudoDestructorExprClass: + case Stmt::UnresolvedLookupExprClass: + case Stmt::UnaryTypeTraitExprClass: + case Stmt::DependentScopeDeclRefExprClass: + case Stmt::CXXConstructExprClass: + case Stmt::CXXBindTemporaryExprClass: + case Stmt::CXXExprWithTemporariesClass: + case Stmt::CXXTemporaryObjectExprClass: + case Stmt::CXXUnresolvedConstructExprClass: + case Stmt::CXXDependentScopeMemberExprClass: + case Stmt::UnresolvedMemberExprClass: + case Stmt::CXXCatchStmtClass: + case Stmt::CXXTryStmtClass: { + SaveAndRestore<bool> OldSink(Builder->BuildSinks); + Builder->BuildSinks = true; + MakeNode(Dst, S, Pred, GetState(Pred)); + break; + } default: // Cases we intentionally have "default" handle: @@ -456,6 +543,10 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { case Stmt::AsmStmtClass: VisitAsmStmt(cast<AsmStmt>(S), Pred, Dst); break; + + case Stmt::BlockDeclRefExprClass: + VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(S), Pred, Dst, false); + break; case Stmt::BlockExprClass: VisitBlockExpr(cast<BlockExpr>(S), Pred, Dst); @@ -627,6 +718,10 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(Ex), Pred, Dst, true); return; + case Stmt::BlockDeclRefExprClass: + VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(Ex), Pred, Dst, true); + return; + case Stmt::DeclRefExprClass: VisitDeclRefExpr(cast<DeclRefExpr>(Ex), Pred, Dst, true); return; @@ -1118,9 +1213,20 @@ void GRExprEngine::VisitBlockExpr(BlockExpr *BE, ExplodedNode *Pred, void GRExprEngine::VisitDeclRefExpr(DeclRefExpr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst, bool asLValue) { + VisitCommonDeclRefExpr(Ex, Ex->getDecl(), Pred, Dst, asLValue); +} + +void GRExprEngine::VisitBlockDeclRefExpr(BlockDeclRefExpr *Ex, + ExplodedNode *Pred, + ExplodedNodeSet &Dst, bool asLValue) { + VisitCommonDeclRefExpr(Ex, Ex->getDecl(), Pred, Dst, asLValue); +} + +void GRExprEngine::VisitCommonDeclRefExpr(Expr *Ex, const NamedDecl *D, + ExplodedNode *Pred, + ExplodedNodeSet &Dst, bool asLValue) { const GRState *state = GetState(Pred); - const NamedDecl *D = Ex->getDecl(); if (const VarDecl* VD = dyn_cast<VarDecl>(D)) { @@ -1354,10 +1460,14 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S, for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) { - ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst - : (PrevSet == &Tmp) ? &Src : &Tmp; + ExplodedNodeSet *CurrSet = 0; + if (I+1 == E) + CurrSet = &Dst; + else { + CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; + CurrSet->clear(); + } - CurrSet->clear(); void *tag = I->first; Checker *checker = I->second; @@ -1376,232 +1486,8 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S, } //===----------------------------------------------------------------------===// -// Transfer function: OSAtomics. -// -// FIXME: Eventually refactor into a more "plugin" infrastructure. -//===----------------------------------------------------------------------===// - -// Mac OS X: -// http://developer.apple.com/documentation/Darwin/Reference/Manpages/man3 -// atomic.3.html -// -static bool EvalOSAtomicCompareAndSwap(ExplodedNodeSet& Dst, - GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, - CallExpr* CE, ExplodedNode* Pred) { - - // Not enough arguments to match OSAtomicCompareAndSwap? - if (CE->getNumArgs() != 3) - return false; - - ASTContext &C = Engine.getContext(); - Expr *oldValueExpr = CE->getArg(0); - QualType oldValueType = C.getCanonicalType(oldValueExpr->getType()); - - Expr *newValueExpr = CE->getArg(1); - QualType newValueType = C.getCanonicalType(newValueExpr->getType()); - - // Do the types of 'oldValue' and 'newValue' match? - if (oldValueType != newValueType) - return false; - - Expr *theValueExpr = CE->getArg(2); - const PointerType *theValueType = - theValueExpr->getType()->getAs<PointerType>(); - - // theValueType not a pointer? - if (!theValueType) - return false; - - QualType theValueTypePointee = - C.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType(); - - // The pointee must match newValueType and oldValueType. - if (theValueTypePointee != newValueType) - return false; - - static unsigned magic_load = 0; - static unsigned magic_store = 0; - - const void *OSAtomicLoadTag = &magic_load; - const void *OSAtomicStoreTag = &magic_store; - - // Load 'theValue'. - const GRState *state = Pred->getState(); - ExplodedNodeSet Tmp; - SVal location = state->getSVal(theValueExpr); - // 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) { - - ExplodedNode *N = *I; - const GRState *stateLoad = N->getState(); - SVal theValueVal_untested = stateLoad->getSVal(theValueExpr); - SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr); - - // FIXME: Issue an error. - if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) { - return false; - } - - DefinedOrUnknownSVal theValueVal = - cast<DefinedOrUnknownSVal>(theValueVal_untested); - DefinedOrUnknownSVal oldValueVal = - cast<DefinedOrUnknownSVal>(oldValueVal_untested); - - SValuator &SVator = Engine.getSValuator(); - - // Perform the comparison. - DefinedOrUnknownSVal Cmp = SVator.EvalEQ(stateLoad, theValueVal, - oldValueVal); - - const GRState *stateEqual = stateLoad->Assume(Cmp, true); - - // Were they equal? - if (stateEqual) { - // Perform the store. - ExplodedNodeSet TmpStore; - SVal val = stateEqual->getSVal(newValueExpr); - - // Handle implicit value casts. - if (const TypedRegion *R = - dyn_cast_or_null<TypedRegion>(location.getAsRegion())) { - llvm::tie(state, val) = SVator.EvalCast(val, state, R->getValueType(C), - newValueExpr->getType()); - } - - Engine.EvalStore(TmpStore, NULL, theValueExpr, N, stateEqual, location, - val, OSAtomicStoreTag); - - // Now bind the result of the comparison. - for (ExplodedNodeSet::iterator I2 = TmpStore.begin(), - E2 = TmpStore.end(); I2 != E2; ++I2) { - ExplodedNode *predNew = *I2; - const GRState *stateNew = predNew->getState(); - SVal Res = Engine.getValueManager().makeTruthVal(true, CE->getType()); - Engine.MakeNode(Dst, CE, predNew, stateNew->BindExpr(CE, Res)); - } - } - - // Were they not equal? - if (const GRState *stateNotEqual = stateLoad->Assume(Cmp, false)) { - SVal Res = Engine.getValueManager().makeTruthVal(false, CE->getType()); - Engine.MakeNode(Dst, CE, N, stateNotEqual->BindExpr(CE, Res)); - } - } - - return true; -} - -static bool EvalOSAtomic(ExplodedNodeSet& Dst, - GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, - CallExpr* CE, SVal L, - ExplodedNode* Pred) { - const FunctionDecl* FD = L.getAsFunctionDecl(); - if (!FD) - return false; - - const char *FName = FD->getNameAsCString(); - - // Check for compare and swap. - if (strncmp(FName, "OSAtomicCompareAndSwap", 22) == 0 || - strncmp(FName, "objc_atomicCompareAndSwap", 25) == 0) - return EvalOSAtomicCompareAndSwap(Dst, Engine, Builder, CE, Pred); - - // FIXME: Other atomics. - return false; -} - -//===----------------------------------------------------------------------===// // Transfer function: Function calls. //===----------------------------------------------------------------------===// -static void MarkNoReturnFunction(const FunctionDecl *FD, CallExpr *CE, - const GRState *state, - GRStmtNodeBuilder *Builder) { - if (!FD) - return; - - if (FD->getAttr<NoReturnAttr>() || - FD->getAttr<AnalyzerNoReturnAttr>()) - Builder->BuildSinks = true; - else { - // HACK: Some functions are not marked noreturn, and don't return. - // Here are a few hardwired ones. If this takes too long, we can - // potentially cache these results. - using llvm::StringRef; - bool BuildSinks - = llvm::StringSwitch<bool>(StringRef(FD->getIdentifier()->getName())) - .Case("exit", true) - .Case("panic", true) - .Case("error", true) - .Case("Assert", true) - // FIXME: This is just a wrapper around throwing an exception. - // Eventually inter-procedural analysis should handle this easily. - .Case("ziperr", true) - .Case("assfail", true) - .Case("db_error", true) - .Case("__assert", true) - .Case("__assert_rtn", true) - .Case("__assert_fail", true) - .Case("dtrace_assfail", true) - .Case("yy_fatal_error", true) - .Case("_XCAssertionFailureHandler", true) - .Case("_DTAssertionFailureHandler", true) - .Case("_TSAssertionFailureHandler", true) - .Default(false); - - if (BuildSinks) - Builder->BuildSinks = true; - } -} - -bool GRExprEngine::EvalBuiltinFunction(const FunctionDecl *FD, CallExpr *CE, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - if (!FD) - return false; - - unsigned id = FD->getBuiltinID(); - if (!id) - return false; - - const GRState *state = Pred->getState(); - - switch (id) { - case Builtin::BI__builtin_expect: { - // For __builtin_expect, just return the value of the subexpression. - assert (CE->arg_begin() != CE->arg_end()); - SVal X = state->getSVal(*(CE->arg_begin())); - MakeNode(Dst, CE, Pred, state->BindExpr(CE, X)); - return true; - } - - case Builtin::BI__builtin_alloca: { - // FIXME: Refactor into StoreManager itself? - MemRegionManager& RM = getStateManager().getRegionManager(); - const MemRegion* R = - RM.getAllocaRegion(CE, Builder->getCurrentBlockCount()); - - // Set the extent of the region in bytes. This enables us to use the - // SVal of the argument directly. If we save the extent in bits, we - // cannot represent values like symbol*8. - SVal Extent = state->getSVal(*(CE->arg_begin())); - state = getStoreManager().setExtent(state, R, Extent); - MakeNode(Dst, CE, Pred, state->BindExpr(CE, loc::MemRegionVal(R))); - return true; - } - } - - return false; -} void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, CallExpr::arg_iterator AI, @@ -1659,6 +1545,8 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, ExplodedNode* Pred, } // Finally, evaluate the function call. + ExplodedNodeSet DstTmp3; + for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); DI != DE; ++DI) { @@ -1667,39 +1555,39 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, ExplodedNode* Pred, // FIXME: Add support for symbolic function calls (calls involving // function pointer values that are symbolic). - - // Check for the "noreturn" attribute. - SaveAndRestore<bool> OldSink(Builder->BuildSinks); - const FunctionDecl* FD = L.getAsFunctionDecl(); - - MarkNoReturnFunction(FD, CE, state, Builder); - - // Evaluate the call. - if (EvalBuiltinFunction(FD, CE, *DI, Dst)) - continue; - - // Dispatch to the plug-in transfer function. - SaveOr OldHasGen(Builder->HasGeneratedNode); - Pred = *DI; + ExplodedNodeSet DstChecker; - // 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 the callee is processed by a checker, skip the rest logic. + if (CheckerEvalCall(CE, DstChecker, *DI)) + DstTmp3.insert(DstChecker); + else { + for (ExplodedNodeSet::iterator DI_Checker = DstChecker.begin(), + DE_Checker = DstChecker.end(); + DI_Checker != DE_Checker; ++DI_Checker) { + + // Dispatch to the plug-in transfer function. + unsigned OldSize = DstTmp3.size(); + SaveOr OldHasGen(Builder->HasGeneratedNode); + Pred = *DI_Checker; + + // Dispatch to transfer function logic to handle the call itself. + // FIXME: Allow us to chain together transfer functions. + assert(Builder && "GRStmtNodeBuilder must be defined."); - if (!EvalOSAtomic(DstTmp, *this, *Builder, CE, L, Pred)) - getTF().EvalCall(DstTmp, *this, *Builder, CE, L, Pred); + getTF().EvalCall(DstTmp3, *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 && DstTmp.empty() && - !Builder->HasGeneratedNode) - MakeNode(DstTmp, CE, Pred, state); - - // Perform the post-condition check of the CallExpr. - CheckerVisit(CE, Dst, DstTmp, false); + // Handle the case where no nodes where generated. Auto-generate that + // contains the updated state if we aren't generating sinks. + if (!Builder->BuildSinks && DstTmp3.size() == OldSize && + !Builder->HasGeneratedNode) + MakeNode(DstTmp3, CE, Pred, state); + } + } } + + // Perform the post-condition check of the CallExpr. + CheckerVisit(CE, Dst, DstTmp3, false); } //===----------------------------------------------------------------------===// @@ -1922,10 +1810,7 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, ExplodedNodeSet Src, DstTmp; Src.Add(Pred); - if (CheckerVisit(ME, DstTmp, Src, true)) { - Dst.insert(DstTmp); - return; - } + CheckerVisit(ME, DstTmp, Src, true); unsigned size = Dst.size(); @@ -1934,10 +1819,38 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, Pred = *DI; bool RaisesException = false; - if (ME->getReceiver()) { + if (const Expr *Receiver = ME->getReceiver()) { + const GRState *state = Pred->getState(); + + // Bifurcate the state into nil and non-nil ones. + DefinedOrUnknownSVal receiverVal = + cast<DefinedOrUnknownSVal>(state->getSVal(Receiver)); + + const GRState *notNilState, *nilState; + llvm::tie(notNilState, nilState) = state->Assume(receiverVal); + + // There are three cases: can be nil or non-nil, must be nil, must be + // non-nil. We handle must be nil, and merge the rest two into non-nil. + if (nilState && !notNilState) { + CheckerEvalNilReceiver(ME, Dst, nilState, Pred); + return; + } + + assert(notNilState); + // Check if the "raise" message was sent. if (ME->getSelector() == RaiseSel) RaisesException = true; + + // Check if we raise an exception. For now treat these as sinks. + // Eventually we will want to handle exceptions properly. + SaveAndRestore<bool> OldSink(Builder->BuildSinks); + if (RaisesException) + Builder->BuildSinks = true; + + // Dispatch to plug-in transfer function. + SaveOr OldHasGen(Builder->HasGeneratedNode); + EvalObjCMessageExpr(Dst, ME, Pred, notNilState); } else { @@ -1984,17 +1897,17 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, RaisesException = true; break; } } - } - // Check if we raise an exception. For now treat these as sinks. Eventually - // we will want to handle exceptions properly. - SaveAndRestore<bool> OldSink(Builder->BuildSinks); - if (RaisesException) - Builder->BuildSinks = true; + // Check if we raise an exception. For now treat these as sinks. + // Eventually we will want to handle exceptions properly. + SaveAndRestore<bool> OldSink(Builder->BuildSinks); + if (RaisesException) + Builder->BuildSinks = true; - // Dispatch to plug-in transfer function. - SaveOr OldHasGen(Builder->HasGeneratedNode); - EvalObjCMessageExpr(Dst, ME, Pred); + // Dispatch to plug-in transfer function. + SaveOr OldHasGen(Builder->HasGeneratedNode); + EvalObjCMessageExpr(Dst, ME, Pred, Builder->GetState(Pred)); + } } // Handle the case where no nodes where generated. Auto-generate that @@ -2052,10 +1965,12 @@ void GRExprEngine::VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, for (ExplodedNodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I!=EI; ++I) { const GRState* state = GetState(*I); SVal ILV = state->getSVal(ILE); - state = state->bindCompoundLiteral(CL, ILV); + const LocationContext *LC = (*I)->getLocationContext(); + state = state->bindCompoundLiteral(CL, LC, ILV); - if (asLValue) - MakeNode(Dst, CL, *I, state->BindExpr(CL, state->getLValue(CL))); + if (asLValue) { + MakeNode(Dst, CL, *I, state->BindExpr(CL, state->getLValue(CL, LC))); + } else MakeNode(Dst, CL, *I, state->BindExpr(CL, ILV)); } diff --git a/lib/Analysis/GRExprEngineInternalChecks.h b/lib/Analysis/GRExprEngineInternalChecks.h index 5b7a757..e2354ed 100644 --- a/lib/Analysis/GRExprEngineInternalChecks.h +++ b/lib/Analysis/GRExprEngineInternalChecks.h @@ -37,5 +37,8 @@ void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng); void RegisterUndefBranchChecker(GRExprEngine &Eng); void RegisterUndefResultChecker(GRExprEngine &Eng); +void RegisterNoReturnFunctionChecker(GRExprEngine &Eng); +void RegisterBuiltinFunctionChecker(GRExprEngine &Eng); +void RegisterOSAtomicChecker(GRExprEngine &Eng); } // end clang namespace #endif diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp index a56859d..7415fa5 100644 --- a/lib/Analysis/GRState.cpp +++ b/lib/Analysis/GRState.cpp @@ -312,10 +312,10 @@ bool GRState::scanReachableSymbols(const SVal *I, const SVal *E, SymbolVisitor &visitor) const { ScanReachableSymbols S(this, visitor); for ( ; I != E; ++I) { - if (S.scan(*I)) - return true; + if (!S.scan(*I)) + return false; } - return false; + return true; } bool GRState::scanReachableSymbols(const MemRegion * const *I, @@ -323,10 +323,10 @@ bool GRState::scanReachableSymbols(const MemRegion * const *I, SymbolVisitor &visitor) const { ScanReachableSymbols S(this, visitor); for ( ; I != E; ++I) { - if (S.scan(*I)) - return true; + if (!S.scan(*I)) + return false; } - return false; + return true; } //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Analysis/MallocChecker.cpp index 204c7b3..2ed070a 100644 --- a/lib/Analysis/MallocChecker.cpp +++ b/lib/Analysis/MallocChecker.cpp @@ -22,10 +22,11 @@ using namespace clang; namespace { -struct RefState { +class RefState { enum Kind { Allocated, Released, Escaped } K; const Stmt *S; +public: RefState(Kind k, const Stmt *s) : K(k), S(s) {} bool isAllocated() const { return K == Allocated; } @@ -51,19 +52,25 @@ class RegionState {}; class MallocChecker : public CheckerVisitor<MallocChecker> { BuiltinBug *BT_DoubleFree; BuiltinBug *BT_Leak; - IdentifierInfo *II_malloc; - IdentifierInfo *II_free; + IdentifierInfo *II_malloc, *II_free, *II_realloc; public: - MallocChecker() : BT_DoubleFree(0), BT_Leak(0), II_malloc(0), II_free(0) {} + MallocChecker() + : BT_DoubleFree(0), BT_Leak(0), II_malloc(0), II_free(0), II_realloc(0) {} static void *getTag(); - void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE); + bool EvalCallExpr(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); + const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE, + const GRState *state); void FreeMem(CheckerContext &C, const CallExpr *CE); + const GRState *FreeMemAux(CheckerContext &C, const CallExpr *CE, + const GRState *state); + + void ReallocMem(CheckerContext &C, const CallExpr *CE); }; } // end anonymous namespace @@ -84,39 +91,71 @@ void *MallocChecker::getTag() { return &x; } -void MallocChecker::PostVisitCallExpr(CheckerContext &C, const CallExpr *CE) { - const FunctionDecl *FD = CE->getDirectCallee(); +bool MallocChecker::EvalCallExpr(CheckerContext &C, const CallExpr *CE) { + const GRState *state = C.getState(); + const Expr *Callee = CE->getCallee(); + SVal L = state->getSVal(Callee); + + const FunctionDecl *FD = L.getAsFunctionDecl(); if (!FD) - return; + return false; ASTContext &Ctx = C.getASTContext(); if (!II_malloc) II_malloc = &Ctx.Idents.get("malloc"); if (!II_free) II_free = &Ctx.Idents.get("free"); + if (!II_realloc) + II_realloc = &Ctx.Idents.get("realloc"); if (FD->getIdentifier() == II_malloc) { MallocMem(C, CE); - return; + return true; } if (FD->getIdentifier() == II_free) { FreeMem(C, CE); - return; + return true; + } + + if (FD->getIdentifier() == II_realloc) { + ReallocMem(C, CE); + return true; } + + return false; } void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) { - const GRState *state = C.getState(); - SVal CallVal = state->getSVal(CE); - SymbolRef Sym = CallVal.getAsLocSymbol(); + const GRState *state = MallocMemAux(C, CE, C.getState()); + C.addTransition(state); +} + +const GRState *MallocChecker::MallocMemAux(CheckerContext &C, + const CallExpr *CE, + const GRState *state) { + unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); + ValueManager &ValMgr = C.getValueManager(); + + SVal RetVal = ValMgr.getConjuredSymbolVal(NULL, CE, CE->getType(), Count); + + state = state->BindExpr(CE, RetVal); + + SymbolRef Sym = RetVal.getAsLocSymbol(); assert(Sym); // Set the symbol's state to Allocated. - C.addTransition(state->set<RegionState>(Sym, RefState::getAllocated(CE))); + return state->set<RegionState>(Sym, RefState::getAllocated(CE)); } void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) { - const GRState *state = C.getState(); + const GRState *state = FreeMemAux(C, CE, C.getState()); + + if (state) + C.addTransition(state); +} + +const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE, + const GRState *state) { SVal ArgVal = state->getSVal(CE->getArg(0)); SymbolRef Sym = ArgVal.getAsLocSymbol(); assert(Sym); @@ -136,13 +175,59 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) { BT_DoubleFree->getDescription(), N); C.EmitReport(R); } - return; + return NULL; } // Normal free. - const GRState *FreedState - = state->set<RegionState>(Sym, RefState::getReleased(CE)); - C.addTransition(FreedState); + return state->set<RegionState>(Sym, RefState::getReleased(CE)); +} + +void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) { + const GRState *state = C.getState(); + const Expr *Arg0 = CE->getArg(0); + DefinedOrUnknownSVal Arg0Val=cast<DefinedOrUnknownSVal>(state->getSVal(Arg0)); + + ValueManager &ValMgr = C.getValueManager(); + SValuator &SVator = C.getSValuator(); + + DefinedOrUnknownSVal PtrEQ = SVator.EvalEQ(state, Arg0Val, ValMgr.makeNull()); + + // If the ptr is NULL, the call is equivalent to malloc(size). + if (const GRState *stateEqual = state->Assume(PtrEQ, true)) { + // Hack: set the NULL symbolic region to released to suppress false warning. + // In the future we should add more states for allocated regions, e.g., + // CheckedNull, CheckedNonNull. + + SymbolRef Sym = Arg0Val.getAsLocSymbol(); + if (Sym) + stateEqual = stateEqual->set<RegionState>(Sym, RefState::getReleased(CE)); + + const GRState *stateMalloc = MallocMemAux(C, CE, stateEqual); + C.addTransition(stateMalloc); + } + + if (const GRState *stateNotEqual = state->Assume(PtrEQ, false)) { + const Expr *Arg1 = CE->getArg(1); + DefinedOrUnknownSVal Arg1Val = + cast<DefinedOrUnknownSVal>(stateNotEqual->getSVal(Arg1)); + DefinedOrUnknownSVal SizeZero = SVator.EvalEQ(stateNotEqual, Arg1Val, + ValMgr.makeIntValWithPtrWidth(0, false)); + + if (const GRState *stateSizeZero = stateNotEqual->Assume(SizeZero, true)) { + const GRState *stateFree = FreeMemAux(C, CE, stateSizeZero); + if (stateFree) + C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true)); + } + + if (const GRState *stateSizeNotZero=stateNotEqual->Assume(SizeZero,false)) { + const GRState *stateFree = FreeMemAux(C, CE, stateSizeNotZero); + if (stateFree) { + // FIXME: We should copy the content of the original buffer. + const GRState *stateRealloc = MallocMemAux(C, CE, stateFree); + C.addTransition(stateRealloc); + } + } + } } void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S, diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp index af8bd16..bc3a5b7 100644 --- a/lib/Analysis/MemRegion.cpp +++ b/lib/Analysis/MemRegion.cpp @@ -22,6 +22,110 @@ using namespace clang; //===----------------------------------------------------------------------===// +// MemRegion Construction. +//===----------------------------------------------------------------------===// + +template<typename RegionTy> struct MemRegionManagerTrait; + +template <typename RegionTy, typename A1> +RegionTy* MemRegionManager::getRegion(const A1 a1) { + + const typename MemRegionManagerTrait<RegionTy>::SuperRegionTy *superRegion = + MemRegionManagerTrait<RegionTy>::getSuperRegion(*this, a1); + + llvm::FoldingSetNodeID ID; + RegionTy::ProfileRegion(ID, a1, superRegion); + void* InsertPos; + RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, + InsertPos)); + + if (!R) { + R = (RegionTy*) A.Allocate<RegionTy>(); + new (R) RegionTy(a1, superRegion); + Regions.InsertNode(R, InsertPos); + } + + return R; +} + +template <typename RegionTy, typename A1> +RegionTy* MemRegionManager::getSubRegion(const A1 a1, + const MemRegion *superRegion) { + llvm::FoldingSetNodeID ID; + RegionTy::ProfileRegion(ID, a1, superRegion); + void* InsertPos; + RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, + InsertPos)); + + if (!R) { + R = (RegionTy*) A.Allocate<RegionTy>(); + new (R) RegionTy(a1, superRegion); + Regions.InsertNode(R, InsertPos); + } + + return R; +} + +template <typename RegionTy, typename A1, typename A2> +RegionTy* MemRegionManager::getRegion(const A1 a1, const A2 a2) { + + const typename MemRegionManagerTrait<RegionTy>::SuperRegionTy *superRegion = + MemRegionManagerTrait<RegionTy>::getSuperRegion(*this, a1, a2); + + llvm::FoldingSetNodeID ID; + RegionTy::ProfileRegion(ID, a1, a2, superRegion); + void* InsertPos; + RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, + InsertPos)); + + if (!R) { + R = (RegionTy*) A.Allocate<RegionTy>(); + new (R) RegionTy(a1, a2, superRegion); + Regions.InsertNode(R, InsertPos); + } + + return R; +} + +template <typename RegionTy, typename A1, typename A2> +RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2, + const MemRegion *superRegion) { + + llvm::FoldingSetNodeID ID; + RegionTy::ProfileRegion(ID, a1, a2, superRegion); + void* InsertPos; + RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, + InsertPos)); + + if (!R) { + R = (RegionTy*) A.Allocate<RegionTy>(); + new (R) RegionTy(a1, a2, superRegion); + Regions.InsertNode(R, InsertPos); + } + + return R; +} + +template <typename RegionTy, typename A1, typename A2, typename A3> +RegionTy* MemRegionManager::getSubRegion(const A1 a1, const A2 a2, const A3 a3, + const MemRegion *superRegion) { + + llvm::FoldingSetNodeID ID; + RegionTy::ProfileRegion(ID, a1, a2, a3, superRegion); + void* InsertPos; + RegionTy* R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, + InsertPos)); + + if (!R) { + R = (RegionTy*) A.Allocate<RegionTy>(); + new (R) RegionTy(a1, a2, a3, superRegion); + Regions.InsertNode(R, InsertPos); + } + + return R; +} + +//===----------------------------------------------------------------------===// // Object destruction. //===----------------------------------------------------------------------===// @@ -61,10 +165,24 @@ MemRegionManager* SubRegion::getMemRegionManager() const { } while (1); } +const StackFrameContext *VarRegion::getStackFrame() const { + const StackSpaceRegion *SSR = dyn_cast<StackSpaceRegion>(getMemorySpace()); + return SSR ? SSR->getStackFrame() : NULL; +} + +//===----------------------------------------------------------------------===// +// FoldingSet profiling. +//===----------------------------------------------------------------------===// + void MemSpaceRegion::Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger((unsigned)getKind()); } +void StackSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger((unsigned)getKind()); + ID.AddPointer(getStackFrame()); +} + void StringRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const StringLiteral* Str, const MemRegion* superRegion) { @@ -109,7 +227,7 @@ void DeclRegion::Profile(llvm::FoldingSetNodeID& ID) const { } void VarRegion::Profile(llvm::FoldingSetNodeID &ID) const { - VarRegion::ProfileRegion(ID, getDecl(), LC, superRegion); + VarRegion::ProfileRegion(ID, getDecl(), superRegion); } void SymbolicRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, SymbolRef sym, @@ -148,27 +266,29 @@ void FunctionTextRegion::Profile(llvm::FoldingSetNodeID& ID) const { } void BlockTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, - const BlockDecl *BD, CanQualType, - const MemRegion*) { + const BlockDecl *BD, CanQualType, + const AnalysisContext *AC, + const MemRegion*) { ID.AddInteger(MemRegion::BlockTextRegionKind); ID.AddPointer(BD); } void BlockTextRegion::Profile(llvm::FoldingSetNodeID& ID) const { - BlockTextRegion::ProfileRegion(ID, BD, locTy, superRegion); + BlockTextRegion::ProfileRegion(ID, BD, locTy, AC, superRegion); } void BlockDataRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockTextRegion *BC, const LocationContext *LC, - const MemRegion *) { + const MemRegion *sReg) { ID.AddInteger(MemRegion::BlockDataRegionKind); ID.AddPointer(BC); ID.AddPointer(LC); + ID.AddPointer(sReg); } void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const { - BlockDataRegion::ProfileRegion(ID, BC, LC, NULL); + BlockDataRegion::ProfileRegion(ID, BC, LC, getSuperRegion()); } //===----------------------------------------------------------------------===// @@ -249,36 +369,58 @@ void RegionRawOffset::dumpToStream(llvm::raw_ostream& os) const { // MemRegionManager methods. //===----------------------------------------------------------------------===// -MemSpaceRegion* MemRegionManager::LazyAllocate(MemSpaceRegion*& region) { +template <typename REG> +const REG *MemRegionManager::LazyAllocate(REG*& region) { if (!region) { - region = (MemSpaceRegion*) A.Allocate<MemSpaceRegion>(); - new (region) MemSpaceRegion(this); + region = (REG*) A.Allocate<REG>(); + new (region) REG(this); } return region; } -MemSpaceRegion* MemRegionManager::getStackRegion() { - return LazyAllocate(stack); +template <typename REG, typename ARG> +const REG *MemRegionManager::LazyAllocate(REG*& region, ARG a) { + if (!region) { + region = (REG*) A.Allocate<REG>(); + new (region) REG(this, a); + } + + return region; } -MemSpaceRegion* MemRegionManager::getStackArgumentsRegion() { - return LazyAllocate(stackArguments); +const StackLocalsSpaceRegion* +MemRegionManager::getStackLocalsRegion(const StackFrameContext *STC) { + assert(STC); + if (STC == cachedStackLocalsFrame) + return cachedStackLocalsRegion; + cachedStackLocalsFrame = STC; + return LazyAllocate(cachedStackLocalsRegion, STC); } -MemSpaceRegion* MemRegionManager::getGlobalsRegion() { +const StackArgumentsSpaceRegion * +MemRegionManager::getStackArgumentsRegion(const StackFrameContext *STC) { + assert(STC); + if (STC == cachedStackArgumentsFrame) + return cachedStackArgumentsRegion; + + cachedStackArgumentsFrame = STC; + return LazyAllocate(cachedStackArgumentsRegion, STC); +} + +const GlobalsSpaceRegion *MemRegionManager::getGlobalsRegion() { return LazyAllocate(globals); } -MemSpaceRegion* MemRegionManager::getHeapRegion() { +const HeapSpaceRegion *MemRegionManager::getHeapRegion() { return LazyAllocate(heap); } -MemSpaceRegion* MemRegionManager::getUnknownRegion() { +const MemSpaceRegion *MemRegionManager::getUnknownRegion() { return LazyAllocate(unknown); } -MemSpaceRegion* MemRegionManager::getCodeRegion() { +const MemSpaceRegion *MemRegionManager::getCodeRegion() { return LazyAllocate(code); } @@ -286,40 +428,79 @@ MemSpaceRegion* MemRegionManager::getCodeRegion() { // Constructing regions. //===----------------------------------------------------------------------===// -StringRegion* MemRegionManager::getStringRegion(const StringLiteral* Str) { - return getRegion<StringRegion>(Str); +const StringRegion* MemRegionManager::getStringRegion(const StringLiteral* Str) { + return getSubRegion<StringRegion>(Str, getGlobalsRegion()); } -VarRegion* MemRegionManager::getVarRegion(const VarDecl *D, - const LocationContext *LC) { +const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D, + const LocationContext *LC) { + const MemRegion *sReg = 0; - // FIXME: Once we implement scope handling, we will need to properly lookup - // 'D' to the proper LocationContext. For now, just strip down to the - // StackFrame. - while (!isa<StackFrameContext>(LC)) - LC = LC->getParent(); + if (D->hasLocalStorage()) { + // FIXME: Once we implement scope handling, we will need to properly lookup + // 'D' to the proper LocationContext. + const DeclContext *DC = D->getDeclContext(); + const StackFrameContext *STC = LC->getStackFrameForDeclContext(DC); - return getRegion<VarRegion>(D, LC); + if (!STC) + sReg = getUnknownRegion(); + else { + sReg = isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D) + ? static_cast<const MemRegion*>(getStackArgumentsRegion(STC)) + : static_cast<const MemRegion*>(getStackLocalsRegion(STC)); + } + } + else { + sReg = getGlobalsRegion(); + } + + return getSubRegion<VarRegion>(D, sReg); } -BlockDataRegion *MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC, - const LocationContext *LC) -{ - // FIXME: Once we implement scope handling, we will need to properly lookup - // 'D' to the proper LocationContext. For now, just strip down to the - // StackFrame. - while (!isa<StackFrameContext>(LC)) - LC = LC->getParent(); +const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D, + const MemRegion *superR) { + return getSubRegion<VarRegion>(D, superR); +} + +const BlockDataRegion * +MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC, + const LocationContext *LC) { + const MemRegion *sReg = 0; - return getSubRegion<BlockDataRegion>(BC, LC, getStackRegion()); + if (LC) { + // FIXME: Once we implement scope handling, we want the parent region + // to be the scope. + const StackFrameContext *STC = LC->getCurrentStackFrame(); + assert(STC); + sReg = getStackLocalsRegion(STC); + } + else { + // We allow 'LC' to be NULL for cases where want BlockDataRegions + // without context-sensitivity. + sReg = getUnknownRegion(); + } + + return getSubRegion<BlockDataRegion>(BC, LC, sReg); } -CompoundLiteralRegion* -MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL) { - return getRegion<CompoundLiteralRegion>(CL); +const CompoundLiteralRegion* +MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL, + const LocationContext *LC) { + + const MemRegion *sReg = 0; + + if (CL->isFileScope()) + sReg = getGlobalsRegion(); + else { + const StackFrameContext *STC = LC->getCurrentStackFrame(); + assert(STC); + sReg = getStackLocalsRegion(STC); + } + + return getSubRegion<CompoundLiteralRegion>(CL, sReg); } -ElementRegion* +const ElementRegion* MemRegionManager::getElementRegion(QualType elementType, SVal Idx, const MemRegion* superRegion, ASTContext& Ctx){ @@ -342,41 +523,47 @@ MemRegionManager::getElementRegion(QualType elementType, SVal Idx, return R; } -FunctionTextRegion * +const FunctionTextRegion * MemRegionManager::getFunctionTextRegion(const FunctionDecl *FD) { - return getRegion<FunctionTextRegion>(FD); + return getSubRegion<FunctionTextRegion>(FD, getCodeRegion()); } -BlockTextRegion *MemRegionManager::getBlockTextRegion(const BlockDecl *BD, - CanQualType locTy) { - return getRegion<BlockTextRegion>(BD, locTy); +const BlockTextRegion * +MemRegionManager::getBlockTextRegion(const BlockDecl *BD, CanQualType locTy, + AnalysisContext *AC) { + return getSubRegion<BlockTextRegion>(BD, locTy, AC, getCodeRegion()); } /// getSymbolicRegion - Retrieve or create a "symbolic" memory region. -SymbolicRegion* MemRegionManager::getSymbolicRegion(SymbolRef sym) { - return getRegion<SymbolicRegion>(sym); +const SymbolicRegion *MemRegionManager::getSymbolicRegion(SymbolRef sym) { + return getSubRegion<SymbolicRegion>(sym, getUnknownRegion()); } -FieldRegion* MemRegionManager::getFieldRegion(const FieldDecl* d, - const MemRegion* superRegion) { +const FieldRegion * +MemRegionManager::getFieldRegion(const FieldDecl* d, + const MemRegion* superRegion){ return getSubRegion<FieldRegion>(d, superRegion); } -ObjCIvarRegion* +const ObjCIvarRegion* MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d, const MemRegion* superRegion) { return getSubRegion<ObjCIvarRegion>(d, superRegion); } -ObjCObjectRegion* +const ObjCObjectRegion* MemRegionManager::getObjCObjectRegion(const ObjCInterfaceDecl* d, const MemRegion* superRegion) { return getSubRegion<ObjCObjectRegion>(d, superRegion); } -AllocaRegion* MemRegionManager::getAllocaRegion(const Expr* E, unsigned cnt) { - return getRegion<AllocaRegion>(E, cnt); +const AllocaRegion* +MemRegionManager::getAllocaRegion(const Expr* E, unsigned cnt, + const LocationContext *LC) { + const StackFrameContext *STC = LC->getCurrentStackFrame(); + assert(STC); + return getSubRegion<AllocaRegion>(E, cnt, getStackLocalsRegion(STC)); } const MemSpaceRegion *MemRegion::getMemorySpace() const { @@ -392,52 +579,30 @@ const MemSpaceRegion *MemRegion::getMemorySpace() const { } bool MemRegion::hasStackStorage() const { - if (const MemSpaceRegion *MS = getMemorySpace()) { - MemRegionManager *Mgr = getMemRegionManager(); - return MS == Mgr->getStackRegion() || MS == Mgr->getStackArgumentsRegion(); - } - - return false; + return isa<StackSpaceRegion>(getMemorySpace()); } bool MemRegion::hasHeapStorage() const { - if (const MemSpaceRegion *MS = getMemorySpace()) - return MS == getMemRegionManager()->getHeapRegion(); - - return false; + return isa<HeapSpaceRegion>(getMemorySpace()); } bool MemRegion::hasHeapOrStackStorage() const { - if (const MemSpaceRegion *MS = getMemorySpace()) { - MemRegionManager *Mgr = getMemRegionManager(); - return MS == Mgr->getHeapRegion() - || MS == Mgr->getStackRegion() - || MS == Mgr->getStackArgumentsRegion(); - } - return false; + const MemSpaceRegion *MS = getMemorySpace(); + return isa<StackSpaceRegion>(MS) || isa<HeapSpaceRegion>(MS); } bool MemRegion::hasGlobalsStorage() const { - if (const MemSpaceRegion *MS = getMemorySpace()) - return MS == getMemRegionManager()->getGlobalsRegion(); - - return false; + return isa<GlobalsSpaceRegion>(getMemorySpace()); } bool MemRegion::hasParametersStorage() const { - if (const MemSpaceRegion *MS = getMemorySpace()) - return MS == getMemRegionManager()->getStackArgumentsRegion(); - - return false; + return isa<StackArgumentsSpaceRegion>(getMemorySpace()); } bool MemRegion::hasGlobalsOrParametersStorage() const { - if (const MemSpaceRegion *MS = getMemorySpace()) { - MemRegionManager *Mgr = getMemRegionManager(); - return MS == Mgr->getGlobalsRegion() - || MS == Mgr->getStackArgumentsRegion(); - } - return false; + const MemSpaceRegion *MS = getMemorySpace(); + return isa<StackArgumentsSpaceRegion>(MS) || + isa<GlobalsSpaceRegion>(MS); } // getBaseRegion strips away all elements and fields, and get the base region @@ -543,7 +708,7 @@ void BlockDataRegion::LazyInitializeReferencedVars() { if (ReferencedVars) return; - AnalysisContext *AC = LC->getAnalysisContext(); + AnalysisContext *AC = getCodeRegion()->getAnalysisContext(); AnalysisContext::referenced_decls_iterator I, E; llvm::tie(I, E) = AC->getReferencedBlockVars(BC->getDecl()); @@ -558,10 +723,25 @@ void BlockDataRegion::LazyInitializeReferencedVars() { typedef BumpVector<const MemRegion*> VarVec; VarVec *BV = (VarVec*) A.Allocate<VarVec>(); - new (BV) VarVec(BC, (E - I) / sizeof(*I)); + new (BV) VarVec(BC, E - I); - for ( ; I != E; ++I) - BV->push_back(MemMgr.getVarRegion(*I, LC), BC); + for ( ; I != E; ++I) { + const VarDecl *VD = *I; + const VarRegion *VR = 0; + + if (!VD->getAttr<BlocksAttr>()) + VR = MemMgr.getVarRegion(VD, this); + else { + if (LC) + VR = MemMgr.getVarRegion(VD, LC); + else { + VR = MemMgr.getVarRegion(VD, MemMgr.getUnknownRegion()); + } + } + + assert(VR); + BV->push_back(VR, BC); + } ReferencedVars = BV; } @@ -573,7 +753,8 @@ BlockDataRegion::referenced_vars_begin() const { BumpVector<const MemRegion*> *Vec = static_cast<BumpVector<const MemRegion*>*>(ReferencedVars); - return Vec == (void*) 0x1 ? NULL : Vec->begin(); + return BlockDataRegion::referenced_vars_iterator(Vec == (void*) 0x1 ? + NULL : Vec->begin()); } BlockDataRegion::referenced_vars_iterator @@ -583,5 +764,6 @@ BlockDataRegion::referenced_vars_end() const { BumpVector<const MemRegion*> *Vec = static_cast<BumpVector<const MemRegion*>*>(ReferencedVars); - return Vec == (void*) 0x1 ? NULL : Vec->end(); + return BlockDataRegion::referenced_vars_iterator(Vec == (void*) 0x1 ? + NULL : Vec->end()); } diff --git a/lib/Analysis/NoReturnFunctionChecker.cpp b/lib/Analysis/NoReturnFunctionChecker.cpp new file mode 100644 index 0000000..6806273 --- /dev/null +++ b/lib/Analysis/NoReturnFunctionChecker.cpp @@ -0,0 +1,80 @@ +//=== NoReturnFunctionChecker.cpp -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines NoReturnFunctionChecker, which evaluates functions that do not +// return to the caller. +// +//===----------------------------------------------------------------------===// + +#include "GRExprEngineInternalChecks.h" +#include "clang/Analysis/PathSensitive/Checker.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; + +namespace { + +class NoReturnFunctionChecker : public Checker { +public: + static void *getTag() { static int tag = 0; return &tag; } + virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE); +}; + +} + +void clang::RegisterNoReturnFunctionChecker(GRExprEngine &Eng) { + Eng.registerCheck(new NoReturnFunctionChecker()); +} + +bool NoReturnFunctionChecker::EvalCallExpr(CheckerContext &C, + const CallExpr *CE) { + const GRState *state = C.getState(); + const Expr *Callee = CE->getCallee(); + SVal L = state->getSVal(Callee); + const FunctionDecl *FD = L.getAsFunctionDecl(); + if (!FD) + return false; + + bool BuildSinks = false; + + if (FD->getAttr<NoReturnAttr>() || FD->getAttr<AnalyzerNoReturnAttr>()) + BuildSinks = true; + else { + // HACK: Some functions are not marked noreturn, and don't return. + // Here are a few hardwired ones. If this takes too long, we can + // potentially cache these results. + using llvm::StringRef; + BuildSinks + = llvm::StringSwitch<bool>(StringRef(FD->getIdentifier()->getName())) + .Case("exit", true) + .Case("panic", true) + .Case("error", true) + .Case("Assert", true) + // FIXME: This is just a wrapper around throwing an exception. + // Eventually inter-procedural analysis should handle this easily. + .Case("ziperr", true) + .Case("assfail", true) + .Case("db_error", true) + .Case("__assert", true) + .Case("__assert_rtn", true) + .Case("__assert_fail", true) + .Case("dtrace_assfail", true) + .Case("yy_fatal_error", true) + .Case("_XCAssertionFailureHandler", true) + .Case("_DTAssertionFailureHandler", true) + .Case("_TSAssertionFailureHandler", true) + .Default(false); + } + + if (!BuildSinks) + return false; + + C.GenerateSink(CE); + return true; +} diff --git a/lib/Analysis/OSAtomicChecker.cpp b/lib/Analysis/OSAtomicChecker.cpp new file mode 100644 index 0000000..5a89345 --- /dev/null +++ b/lib/Analysis/OSAtomicChecker.cpp @@ -0,0 +1,196 @@ +//=== OSAtomicChecker.cpp - OSAtomic functions evaluator --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This checker evaluates OSAtomic functions. +// +//===----------------------------------------------------------------------===// + +#include "GRExprEngineInternalChecks.h" +#include "clang/Analysis/PathSensitive/Checker.h" +#include "clang/Basic/Builtins.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; + +namespace { + +class OSAtomicChecker : public Checker { +public: + static void *getTag() { static int tag = 0; return &tag; } + virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE); + +private: + bool EvalOSAtomicCompareAndSwap(CheckerContext &C, const CallExpr *CE); +}; + +} + +void clang::RegisterOSAtomicChecker(GRExprEngine &Eng) { + Eng.registerCheck(new OSAtomicChecker()); +} + +bool OSAtomicChecker::EvalCallExpr(CheckerContext &C,const CallExpr *CE) { + const GRState *state = C.getState(); + const Expr *Callee = CE->getCallee(); + SVal L = state->getSVal(Callee); + + const FunctionDecl* FD = L.getAsFunctionDecl(); + if (!FD) + return false; + + const char *FName = FD->getNameAsCString(); + + // Check for compare and swap. + if (strncmp(FName, "OSAtomicCompareAndSwap", 22) == 0 || + strncmp(FName, "objc_atomicCompareAndSwap", 25) == 0) + return EvalOSAtomicCompareAndSwap(C, CE); + + // FIXME: Other atomics. + return false; +} + +bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C, + const CallExpr *CE) { + // Not enough arguments to match OSAtomicCompareAndSwap? + if (CE->getNumArgs() != 3) + return false; + + ASTContext &Ctx = C.getASTContext(); + const Expr *oldValueExpr = CE->getArg(0); + QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType()); + + const Expr *newValueExpr = CE->getArg(1); + QualType newValueType = Ctx.getCanonicalType(newValueExpr->getType()); + + // Do the types of 'oldValue' and 'newValue' match? + if (oldValueType != newValueType) + return false; + + const Expr *theValueExpr = CE->getArg(2); + const PointerType *theValueType=theValueExpr->getType()->getAs<PointerType>(); + + // theValueType not a pointer? + if (!theValueType) + return false; + + QualType theValueTypePointee = + Ctx.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType(); + + // The pointee must match newValueType and oldValueType. + if (theValueTypePointee != newValueType) + return false; + + static unsigned magic_load = 0; + static unsigned magic_store = 0; + + const void *OSAtomicLoadTag = &magic_load; + const void *OSAtomicStoreTag = &magic_store; + + // Load 'theValue'. + GRExprEngine &Engine = C.getEngine(); + const GRState *state = C.getState(); + ExplodedNodeSet Tmp; + SVal location = state->getSVal(theValueExpr); + // Here we should use the value type of the region as the load type. + QualType LoadTy; + if (const MemRegion *R = location.getAsRegion()) { + // We must be careful, as SymbolicRegions aren't typed. + const MemRegion *strippedR = R->StripCasts(); + // FIXME: This isn't quite the right solution. One test case in 'test/Analysis/NSString.m' + // is giving the wrong result. + const TypedRegion *typedR = + isa<SymbolicRegion>(strippedR) ? cast<TypedRegion>(R) : + dyn_cast<TypedRegion>(strippedR); + + if (typedR) { + LoadTy = typedR->getValueType(Ctx); + location = loc::MemRegionVal(typedR); + } + } + Engine.EvalLoad(Tmp, const_cast<Expr *>(theValueExpr), C.getPredecessor(), + state, location, OSAtomicLoadTag, LoadTy); + + if (Tmp.empty()) { + // If no nodes were generated, other checkers must generated sinks. But + // since the builder state was restored, we set it manually to prevent + // auto transition. + // FIXME: there should be a better approach. + C.getNodeBuilder().BuildSinks = true; + return true; + } + + for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); + I != E; ++I) { + + ExplodedNode *N = *I; + const GRState *stateLoad = N->getState(); + SVal theValueVal_untested = stateLoad->getSVal(theValueExpr); + SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr); + + // FIXME: Issue an error. + if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) { + return false; + } + + DefinedOrUnknownSVal theValueVal = + cast<DefinedOrUnknownSVal>(theValueVal_untested); + DefinedOrUnknownSVal oldValueVal = + cast<DefinedOrUnknownSVal>(oldValueVal_untested); + + SValuator &SVator = Engine.getSValuator(); + + // Perform the comparison. + DefinedOrUnknownSVal Cmp = SVator.EvalEQ(stateLoad,theValueVal,oldValueVal); + + const GRState *stateEqual = stateLoad->Assume(Cmp, true); + + // Were they equal? + if (stateEqual) { + // Perform the store. + ExplodedNodeSet TmpStore; + SVal val = stateEqual->getSVal(newValueExpr); + + // Handle implicit value casts. + if (const TypedRegion *R = + dyn_cast_or_null<TypedRegion>(location.getAsRegion())) { + llvm::tie(state, val) = SVator.EvalCast(val, state,R->getValueType(Ctx), + newValueExpr->getType()); + } + + Engine.EvalStore(TmpStore, NULL, const_cast<Expr *>(theValueExpr), N, + stateEqual, location, val, OSAtomicStoreTag); + + if (TmpStore.empty()) { + // If no nodes were generated, other checkers must generated sinks. But + // since the builder state was restored, we set it manually to prevent + // auto transition. + // FIXME: there should be a better approach. + C.getNodeBuilder().BuildSinks = true; + return true; + } + + // Now bind the result of the comparison. + for (ExplodedNodeSet::iterator I2 = TmpStore.begin(), + E2 = TmpStore.end(); I2 != E2; ++I2) { + ExplodedNode *predNew = *I2; + const GRState *stateNew = predNew->getState(); + SVal Res = Engine.getValueManager().makeTruthVal(true, CE->getType()); + C.GenerateNode(stateNew->BindExpr(CE, Res), predNew); + } + } + + // Were they not equal? + if (const GRState *stateNotEqual = stateLoad->Assume(Cmp, false)) { + SVal Res = Engine.getValueManager().makeTruthVal(false, CE->getType()); + C.GenerateNode(stateNotEqual->BindExpr(CE, Res), N); + } + } + + return true; +} diff --git a/lib/Analysis/PathDiagnostic.cpp b/lib/Analysis/PathDiagnostic.cpp index 800496a..734570a 100644 --- a/lib/Analysis/PathDiagnostic.cpp +++ b/lib/Analysis/PathDiagnostic.cpp @@ -36,30 +36,16 @@ bool PathDiagnosticMacroPiece::containsEvent() const { return false; } -static size_t GetNumCharsToLastNonPeriod(const char *s) { - const char *start = s; - const char *lastNonPeriod = 0; - - for ( ; *s != '\0' ; ++s) - if (*s != '.') lastNonPeriod = s; - - if (!lastNonPeriod) - return 0; - - return (lastNonPeriod - start) + 1; -} - -static inline size_t GetNumCharsToLastNonPeriod(const std::string &s) { - return s.empty () ? 0 : GetNumCharsToLastNonPeriod(&s[0]); +static llvm::StringRef StripTrailingDots(llvm::StringRef s) { + for (llvm::StringRef::size_type i = s.size(); i != 0; --i) + if (s[i - 1] != '.') + return s.substr(0, i); + return ""; } -PathDiagnosticPiece::PathDiagnosticPiece(const std::string& s, +PathDiagnosticPiece::PathDiagnosticPiece(llvm::StringRef s, Kind k, DisplayHint hint) - : str(s, 0, GetNumCharsToLastNonPeriod(s)), kind(k), Hint(hint) {} - -PathDiagnosticPiece::PathDiagnosticPiece(const char* s, Kind k, - DisplayHint hint) - : str(s, GetNumCharsToLastNonPeriod(s)), kind(k), Hint(hint) {} + : str(StripTrailingDots(s)), kind(k), Hint(hint) {} PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint) : kind(k), Hint(hint) {} @@ -89,20 +75,12 @@ void PathDiagnostic::resetPath(bool deletePieces) { } -PathDiagnostic::PathDiagnostic(const char* bugtype, const char* desc, - const char* category) - : Size(0), - BugType(bugtype, GetNumCharsToLastNonPeriod(bugtype)), - Desc(desc, GetNumCharsToLastNonPeriod(desc)), - Category(category, GetNumCharsToLastNonPeriod(category)) {} - -PathDiagnostic::PathDiagnostic(const std::string& bugtype, - const std::string& desc, - const std::string& category) +PathDiagnostic::PathDiagnostic(llvm::StringRef bugtype, llvm::StringRef desc, + llvm::StringRef category) : Size(0), - BugType(bugtype, 0, GetNumCharsToLastNonPeriod(bugtype)), - Desc(desc, 0, GetNumCharsToLastNonPeriod(desc)), - Category(category, 0, GetNumCharsToLastNonPeriod(category)) {} + BugType(StripTrailingDots(bugtype)), + Desc(StripTrailingDots(desc)), + Category(StripTrailingDots(category)) {} void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel, const DiagnosticInfo &Info) { @@ -126,8 +104,7 @@ void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel, Info.FormatDiagnostic(StrC); PathDiagnosticPiece *P = - new PathDiagnosticEventPiece(Info.getLocation(), - std::string(StrC.begin(), StrC.end())); + new PathDiagnosticEventPiece(Info.getLocation(), StrC.str()); for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) P->addRange(Info.getRange(i)); diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index e645172..b5eeb1e 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -269,7 +269,15 @@ public: const GRState *InvalidateRegion(const GRState *state, const MemRegion *R, const Expr *E, unsigned Count, - InvalidatedSymbols *IS); + InvalidatedSymbols *IS) { + return RegionStoreManager::InvalidateRegions(state, &R, &R+1, E, Count, IS); + } + + const GRState *InvalidateRegions(const GRState *state, + const MemRegion * const *Begin, + const MemRegion * const *End, + const Expr *E, unsigned Count, + InvalidatedSymbols *IS); private: void RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R, @@ -279,7 +287,9 @@ public: const GRState *Bind(const GRState *state, Loc LV, SVal V); const GRState *BindCompoundLiteral(const GRState *state, - const CompoundLiteralExpr* CL, SVal V); + const CompoundLiteralExpr* CL, + const LocationContext *LC, + SVal V); const GRState *BindDecl(const GRState *ST, const VarRegion *VR, SVal InitVal); @@ -460,16 +470,14 @@ void RegionStoreManager::RemoveSubRegionBindings(RegionBindings &B, B = RBFactory.Remove(B, R); } -const GRState *RegionStoreManager::InvalidateRegion(const GRState *state, - const MemRegion *R, - const Expr *Ex, - unsigned Count, - InvalidatedSymbols *IS) { +const GRState *RegionStoreManager::InvalidateRegions(const GRState *state, + const MemRegion * const *I, + const MemRegion * const *E, + const Expr *Ex, + unsigned Count, + InvalidatedSymbols *IS) { ASTContext& Ctx = StateMgr.getContext(); - // Strip away casts. - R = R->StripCasts(); - // Get the mapping of regions -> subregions. llvm::OwningPtr<RegionStoreSubRegionMap> SubRegions(getRegionStoreSubRegionMap(state->getStore())); @@ -478,10 +486,14 @@ const GRState *RegionStoreManager::InvalidateRegion(const GRState *state, llvm::DenseMap<const MemRegion *, unsigned> Visited; llvm::SmallVector<const MemRegion *, 10> WorkList; - WorkList.push_back(R); + + for ( ; I != E; ++I) { + // Strip away casts. + WorkList.push_back((*I)->StripCasts()); + } while (!WorkList.empty()) { - R = WorkList.back(); + const MemRegion *R = WorkList.back(); WorkList.pop_back(); // Have we visited this region before? @@ -512,6 +524,19 @@ const GRState *RegionStoreManager::InvalidateRegion(const GRState *state, if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) IS->insert(SR->getSymbol()); } + + // BlockDataRegion? If so, invalidate captured variables that are passed + // by reference. + if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) { + for (BlockDataRegion::referenced_vars_iterator + I = BR->referenced_vars_begin(), E = BR->referenced_vars_end() ; + I != E; ++I) { + const VarRegion *VR = *I; + if (VR->getDecl()->getAttr<BlocksAttr>()) + WorkList.push_back(VR); + } + continue; + } // Handle the region itself. if (isa<AllocaRegion>(R) || isa<SymbolicRegion>(R) || @@ -592,15 +617,6 @@ SVal RegionStoreManager::getLValueVar(const VarDecl *VD, return loc::MemRegionVal(MRMgr.getVarRegion(VD, LC)); } -/// getLValueCompoundLiteral - Returns an SVal representing the lvalue -/// of a compound literal. Within RegionStore a compound literal -/// has an associated region, and the lvalue of the compound literal -/// is the lvalue of that region. -SVal -RegionStoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL) { - return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL)); -} - SVal RegionStoreManager::getLValueIvar(const ObjCIvarDecl* D, SVal Base) { return getLValueFieldOrIvar(D, Base); } @@ -707,7 +723,12 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, const MemRegion *R) { switch (R->getKind()) { - case MemRegion::MemSpaceRegionKind: + case MemRegion::GenericMemSpaceRegionKind: + case MemRegion::StackLocalsSpaceRegionKind: + case MemRegion::StackArgumentsSpaceRegionKind: + case MemRegion::HeapSpaceRegionKind: + case MemRegion::GlobalsSpaceRegionKind: + case MemRegion::UnknownSpaceRegionKind: assert(0 && "Cannot index into a MemSpace"); return UnknownVal(); @@ -752,13 +773,6 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, // essentially are arrays of size 1. return ValMgr.makeIntVal(1, false); } - - case MemRegion::BEG_DECL_REGIONS: - case MemRegion::END_DECL_REGIONS: - case MemRegion::BEG_TYPED_REGIONS: - case MemRegion::END_TYPED_REGIONS: - assert(0 && "Infeasible region"); - return UnknownVal(); } assert(0 && "Unreachable"); @@ -797,9 +811,8 @@ SVal RegionStoreManager::ArrayToPointer(Loc Array) { T = AT->getElementType(); SVal ZeroIdx = ValMgr.makeZeroArrayIndex(); - ElementRegion* ER = MRMgr.getElementRegion(T, ZeroIdx, ArrayR, getContext()); - - return loc::MemRegionVal(ER); + return loc::MemRegionVal(MRMgr.getElementRegion(T, ZeroIdx, ArrayR, + getContext())); } //===----------------------------------------------------------------------===// @@ -864,16 +877,14 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state, // Technically this can happen if people do funny things with casts. return UnknownVal(); - case MemRegion::MemSpaceRegionKind: + case MemRegion::GenericMemSpaceRegionKind: + case MemRegion::StackLocalsSpaceRegionKind: + case MemRegion::StackArgumentsSpaceRegionKind: + case MemRegion::HeapSpaceRegionKind: + case MemRegion::GlobalsSpaceRegionKind: + case MemRegion::UnknownSpaceRegionKind: assert(0 && "Cannot perform pointer arithmetic on a MemSpace"); return UnknownVal(); - - case MemRegion::BEG_DECL_REGIONS: - case MemRegion::END_DECL_REGIONS: - case MemRegion::BEG_TYPED_REGIONS: - case MemRegion::END_TYPED_REGIONS: - assert(0 && "Infeasible region"); - return UnknownVal(); } SVal Idx = ER->getIndex(); @@ -1283,7 +1294,8 @@ SVal RegionStoreManager::RetrieveVar(const GRState *state, // Lazily derive a value for the VarRegion. const VarDecl *VD = R->getDecl(); - if (R->hasGlobalsOrParametersStorage()) + if (R->hasGlobalsOrParametersStorage() || + isa<UnknownSpaceRegion>(R->getMemorySpace())) return ValMgr.getRegionValueSymbolValOrUnknown(R, VD->getType()); return UndefinedVal(); @@ -1440,11 +1452,11 @@ const GRState *RegionStoreManager::BindDecl(const GRState *ST, // FIXME: this method should be merged into Bind(). const GRState * RegionStoreManager::BindCompoundLiteral(const GRState *state, - const CompoundLiteralExpr* CL, + const CompoundLiteralExpr *CL, + const LocationContext *LC, SVal V) { - - CompoundLiteralRegion* R = MRMgr.getCompoundLiteralRegion(CL); - return Bind(state, loc::MemRegionVal(R), V); + return Bind(state, loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)), + V); } const GRState *RegionStoreManager::setImplicitDefaultValue(const GRState *state, @@ -1497,8 +1509,8 @@ const GRState *RegionStoreManager::BindArray(const GRState *state, break; SVal Idx = ValMgr.makeArrayIndex(i); - ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx, R, - getContext()); + const ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx, R, + getContext()); SVal V = ValMgr.makeIntVal(str[j], sizeof(char)*8, true); state = Bind(state, loc::MemRegionVal(ER), V); @@ -1526,7 +1538,7 @@ const GRState *RegionStoreManager::BindArray(const GRState *state, break; SVal Idx = ValMgr.makeArrayIndex(i); - ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext()); + const ElementRegion *ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext()); if (CAT->getElementType()->isStructureType()) state = BindStruct(state, ER, *VI); @@ -1677,7 +1689,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, IntermediateVisited.insert(R); if (const VarRegion* VR = dyn_cast<VarRegion>(R)) { - if (SymReaper.isLive(Loc, VR->getDecl())) + if (SymReaper.isLive(Loc, VR)) WorkList.push_back(std::make_pair(&state, VR)); continue; } @@ -1753,14 +1765,16 @@ tryAgain: if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R)) SymReaper.markLive(SymR->getSymbol()); - // For BlockDataRegions, enqueue all VarRegions for that are referenced + // For BlockDataRegions, enqueue the VarRegions for variables marked + // with __block (passed-by-reference). // via BlockDeclRefExprs. if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(R)) { for (BlockDataRegion::referenced_vars_iterator RI = BD->referenced_vars_begin(), RE = BD->referenced_vars_end(); - RI != RE; ++RI) - WorkList.push_back(std::make_pair(state_N, *RI)); - + RI != RE; ++RI) { + if ((*RI)->getDecl()->getAttr<BlocksAttr>()) + WorkList.push_back(std::make_pair(state_N, *RI)); + } // No possible data bindings on a BlockDataRegion. Continue to the // next region in the worklist. continue; @@ -1846,8 +1860,7 @@ GRState const *RegionStoreManager::EnterStackFrame(GRState const *state, // Copy the arg expression value to the arg variables. for (; AI != AE; ++AI, ++PI) { SVal ArgVal = state->getSVal(*AI); - MemRegion *R = MRMgr.getVarRegion(*PI, frame); - state = Bind(state, ValMgr.makeLoc(R), ArgVal); + state = Bind(state, ValMgr.makeLoc(MRMgr.getVarRegion(*PI, frame)), ArgVal); } return state; diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp index 2fd573c..e6ff6e5 100644 --- a/lib/Analysis/Store.cpp +++ b/lib/Analysis/Store.cpp @@ -77,11 +77,12 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) // Process region cast according to the kind of the region being cast. switch (R->getKind()) { - case MemRegion::BEG_TYPED_REGIONS: - case MemRegion::MemSpaceRegionKind: - case MemRegion::BEG_DECL_REGIONS: - case MemRegion::END_DECL_REGIONS: - case MemRegion::END_TYPED_REGIONS: { + case MemRegion::GenericMemSpaceRegionKind: + case MemRegion::StackLocalsSpaceRegionKind: + case MemRegion::StackArgumentsSpaceRegionKind: + case MemRegion::HeapSpaceRegionKind: + case MemRegion::UnknownSpaceRegionKind: + case MemRegion::GlobalsSpaceRegionKind: { assert(0 && "Invalid region cast"); break; } @@ -199,9 +200,33 @@ SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R, QualType castTy) { if (castTy.isNull()) return V; - + assert(ValMgr.getContext().hasSameUnqualifiedType(castTy, R->getValueType(ValMgr.getContext()))); return V; } +const GRState *StoreManager::InvalidateRegions(const GRState *state, + const MemRegion * const *I, + const MemRegion * const *End, + const Expr *E, + unsigned Count, + InvalidatedSymbols *IS) { + for ( ; I != End ; ++I) + state = InvalidateRegion(state, *I, E, Count, IS); + + return state; +} + +//===----------------------------------------------------------------------===// +// Common getLValueXXX methods. +//===----------------------------------------------------------------------===// + +/// getLValueCompoundLiteral - Returns an SVal representing the lvalue +/// of a compound literal. Within RegionStore a compound literal +/// has an associated region, and the lvalue of the compound literal +/// is the lvalue of that region. +SVal StoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL, + const LocationContext *LC) { + return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)); +} diff --git a/lib/Analysis/SymbolManager.cpp b/lib/Analysis/SymbolManager.cpp index 22e1101..3fe36b0 100644 --- a/lib/Analysis/SymbolManager.cpp +++ b/lib/Analysis/SymbolManager.cpp @@ -220,4 +220,9 @@ bool SymbolReaper::isLive(SymbolRef sym) { return isa<SymbolRegionValue>(sym); } +bool SymbolReaper::isLive(const Stmt *Loc, const VarRegion *VR) const { + const StackFrameContext *SFC = VR->getStackFrame(); + return SFC == CurrentStackFrame ? Liveness.isLive(Loc, VR->getDecl()) : true; +} + SymbolVisitor::~SymbolVisitor() {} diff --git a/lib/Analysis/ValueManager.cpp b/lib/Analysis/ValueManager.cpp index 22a8211..d091373 100644 --- a/lib/Analysis/ValueManager.cpp +++ b/lib/Analysis/ValueManager.cpp @@ -14,6 +14,7 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/PathSensitive/ValueManager.h" +#include "clang/Analysis/PathSensitive/AnalysisContext.h" using namespace clang; using namespace llvm; @@ -138,15 +139,15 @@ ValueManager::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol, } DefinedSVal ValueManager::getFunctionPointer(const FunctionDecl* FD) { - CodeTextRegion *R = MemMgr.getFunctionTextRegion(FD); - return loc::MemRegionVal(R); + return loc::MemRegionVal(MemMgr.getFunctionTextRegion(FD)); } DefinedSVal ValueManager::getBlockPointer(const BlockDecl *D, CanQualType locTy, const LocationContext *LC) { - BlockTextRegion *BC = MemMgr.getBlockTextRegion(D, locTy); - BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, LC); + const BlockTextRegion *BC = + MemMgr.getBlockTextRegion(D, locTy, LC->getAnalysisContext()); + const BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, LC); return loc::MemRegionVal(BD); } diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index fbc7313..8d0d813 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -163,7 +163,7 @@ namespace clang { return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first; } - unsigned getOrCreateDiagID(Diagnostic::Level L, const char *Message, + unsigned getOrCreateDiagID(Diagnostic::Level L, llvm::StringRef Message, Diagnostic &Diags) { DiagDesc D(L, Message); // Check to see if it already exists. @@ -210,7 +210,7 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) { ErrorOccurred = false; FatalErrorOccurred = false; NumDiagnostics = 0; - + NumErrors = 0; CustomDiagInfo = 0; CurDiagID = ~0U; @@ -246,7 +246,7 @@ bool Diagnostic::popMappings() { /// getCustomDiagID - Return an ID for a diagnostic with the specified message /// and level. If this is the first request for this diagnosic, it is /// registered and created, otherwise the existing ID is returned. -unsigned Diagnostic::getCustomDiagID(Level L, const char *Message) { +unsigned Diagnostic::getCustomDiagID(Level L, llvm::StringRef Message) { if (CustomDiagInfo == 0) CustomDiagInfo = new diag::CustomDiagInfo(); return CustomDiagInfo->getOrCreateDiagID(L, Message, *this); diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp index ee4309d..434ff39 100644 --- a/lib/Basic/FileManager.cpp +++ b/lib/Basic/FileManager.cpp @@ -147,6 +147,12 @@ FileManager::FileManager() FileManager::~FileManager() { delete &UniqueDirs; delete &UniqueFiles; + for (llvm::SmallVectorImpl<FileEntry *>::iterator + V = VirtualFileEntries.begin(), + VEnd = VirtualFileEntries.end(); + V != VEnd; + ++V) + delete *V; } void FileManager::addStatCache(StatSysCallCache *statCache, bool AtBeginning) { @@ -184,6 +190,30 @@ void FileManager::removeStatCache(StatSysCallCache *statCache) { assert(false && "Stat cache not found for removal"); } +/// \brief Retrieve the directory that the given file name resides in. +static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr, + const char *NameStart, + const char *NameEnd) { + // Figure out what directory it is in. If the string contains a / in it, + // strip off everything after it. + // FIXME: this logic should be in sys::Path. + const char *SlashPos = NameEnd-1; + while (SlashPos >= NameStart && !IS_DIR_SEPARATOR_CHAR(SlashPos[0])) + --SlashPos; + // Ignore duplicate //'s. + while (SlashPos > NameStart && IS_DIR_SEPARATOR_CHAR(SlashPos[-1])) + --SlashPos; + + if (SlashPos < NameStart) { + // Use the current directory if file has no path component. + const char *Name = "."; + return FileMgr.getDirectory(Name, Name+1); + } else if (SlashPos == NameEnd-1) + return 0; // If filename ends with a /, it's a directory. + else + return FileMgr.getDirectory(NameStart, SlashPos); +} + /// getDirectory - Lookup, cache, and verify the specified directory. This /// returns null if the directory doesn't exist. /// @@ -252,33 +282,16 @@ const FileEntry *FileManager::getFile(const char *NameStart, // By default, initialize it to invalid. NamedFileEnt.setValue(NON_EXISTENT_FILE); - // Figure out what directory it is in. If the string contains a / in it, - // strip off everything after it. - // FIXME: this logic should be in sys::Path. - const char *SlashPos = NameEnd-1; - while (SlashPos >= NameStart && !IS_DIR_SEPARATOR_CHAR(SlashPos[0])) - --SlashPos; - // Ignore duplicate //'s. - while (SlashPos > NameStart && IS_DIR_SEPARATOR_CHAR(SlashPos[-1])) - --SlashPos; - - const DirectoryEntry *DirInfo; - if (SlashPos < NameStart) { - // Use the current directory if file has no path component. - const char *Name = "."; - DirInfo = getDirectory(Name, Name+1); - } else if (SlashPos == NameEnd-1) - return 0; // If filename ends with a /, it's a directory. - else - DirInfo = getDirectory(NameStart, SlashPos); - - if (DirInfo == 0) // Directory doesn't exist, file can't exist. - return 0; // Get the null-terminated file name as stored as the key of the // FileEntries map. const char *InterndFileName = NamedFileEnt.getKeyData(); + const DirectoryEntry *DirInfo + = getDirectoryFromFile(*this, NameStart, NameEnd); + if (DirInfo == 0) // Directory doesn't exist, file can't exist. + return 0; + // FIXME: Use the directory info to prune this, before doing the stat syscall. // FIXME: This will reduce the # syscalls. @@ -312,6 +325,44 @@ const FileEntry *FileManager::getFile(const char *NameStart, return &UFE; } +const FileEntry * +FileManager::getVirtualFile(const llvm::StringRef &Filename, + off_t Size, time_t ModificationTime) { + const char *NameStart = Filename.begin(), *NameEnd = Filename.end(); + + ++NumFileLookups; + + // See if there is already an entry in the map. + llvm::StringMapEntry<FileEntry *> &NamedFileEnt = + FileEntries.GetOrCreateValue(NameStart, NameEnd); + + // See if there is already an entry in the map. + if (NamedFileEnt.getValue()) + return NamedFileEnt.getValue() == NON_EXISTENT_FILE + ? 0 : NamedFileEnt.getValue(); + + ++NumFileCacheMisses; + + // By default, initialize it to invalid. + NamedFileEnt.setValue(NON_EXISTENT_FILE); + + const DirectoryEntry *DirInfo + = getDirectoryFromFile(*this, NameStart, NameEnd); + if (DirInfo == 0) // Directory doesn't exist, file can't exist. + return 0; + + FileEntry *UFE = new FileEntry(); + VirtualFileEntries.push_back(UFE); + NamedFileEnt.setValue(UFE); + + UFE->Name = NamedFileEnt.getKeyData(); + UFE->Size = Size; + UFE->ModTime = ModificationTime; + UFE->Dir = DirInfo; + UFE->UID = NextFileUID++; + return UFE; +} + void FileManager::PrintStats() const { llvm::errs() << "\n*** File Manager Stats:\n"; llvm::errs() << UniqueFiles.size() << " files found, " @@ -327,17 +378,16 @@ void FileManager::PrintStats() const { int MemorizeStatCalls::stat(const char *path, struct stat *buf) { int result = StatSysCallCache::stat(path, buf); - if (result != 0) { - // Cache failed 'stat' results. - struct stat empty; - memset(&empty, 0, sizeof(empty)); - StatCalls[path] = StatResult(result, empty); - } - else if (!S_ISDIR(buf->st_mode) || llvm::sys::Path(path).isAbsolute()) { - // Cache file 'stat' results and directories with absolutely - // paths. + // Do not cache failed stats, it is easy to construct common inconsistent + // situations if we do, and they are not important for PCH performance (which + // currently only needs the stats to construct the initial FileManager + // entries). + if (result != 0) + return result; + + // Cache file 'stat' results and directories with absolutely paths. + if (!S_ISDIR(buf->st_mode) || llvm::sys::Path(path).isAbsolute()) StatCalls[path] = StatResult(result, *buf); - } return result; } diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index a85bef0..354bf7b 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -41,64 +41,42 @@ unsigned ContentCache::getSizeBytesMapped() const { /// getSize - Returns the size of the content encapsulated by this ContentCache. /// This can be the size of the source file or the size of an arbitrary /// scratch buffer. If the ContentCache encapsulates a source file, that -/// file is not lazily brought in from disk to satisfy this query unless it -/// needs to be truncated due to a truncateAt() call. +/// file is not lazily brought in from disk to satisfy this query. unsigned ContentCache::getSize() const { return Buffer ? Buffer->getBufferSize() : Entry->getSize(); } -const llvm::MemoryBuffer *ContentCache::getBuffer() const { - // Lazily create the Buffer for ContentCaches that wrap files. - if (!Buffer && Entry) { - // FIXME: Should we support a way to not have to do this check over - // and over if we cannot open the file? - Buffer = MemoryBuffer::getFile(Entry->getName(), 0, Entry->getSize()); - if (isTruncated()) - const_cast<ContentCache *>(this)->truncateAt(TruncateAtLine, - TruncateAtColumn); - } - return Buffer; +void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) { + assert(B != Buffer); + + delete Buffer; + Buffer = B; } -void ContentCache::truncateAt(unsigned Line, unsigned Column) { - TruncateAtLine = Line; - TruncateAtColumn = Column; - - if (!isTruncated() || !Buffer) - return; - - // Find the byte position of the truncation point. - const char *Position = Buffer->getBufferStart(); - for (unsigned Line = 1; Line < TruncateAtLine; ++Line) { - for (; *Position; ++Position) { - if (*Position != '\r' && *Position != '\n') - continue; - - // Eat \r\n or \n\r as a single line. - if ((Position[1] == '\r' || Position[1] == '\n') && - Position[0] != Position[1]) - ++Position; - ++Position; - break; +const llvm::MemoryBuffer *ContentCache::getBuffer(std::string *ErrorStr) const { + // Lazily create the Buffer for ContentCaches that wrap files. + if (!Buffer && Entry) { + Buffer = MemoryBuffer::getFile(Entry->getName(), ErrorStr,Entry->getSize()); + + // If we were unable to open the file, then we are in an inconsistent + // situation where the content cache referenced a file which no longer + // exists. Most likely, we were using a stat cache with an invalid entry but + // the file could also have been removed during processing. Since we can't + // really deal with this situation, just create an empty buffer. + // + // FIXME: This is definitely not ideal, but our immediate clients can't + // currently handle returning a null entry here. Ideally we should detect + // that we are in an inconsistent situation and error out as quickly as + // possible. + if (!Buffer) { + const llvm::StringRef FillStr("<<<MISSING SOURCE FILE>>>\n"); + Buffer = MemoryBuffer::getNewMemBuffer(Entry->getSize(), "<invalid>"); + char *Ptr = const_cast<char*>(Buffer->getBufferStart()); + for (unsigned i = 0, e = Entry->getSize(); i != e; ++i) + Ptr[i] = FillStr[i % FillStr.size()]; } } - - for (unsigned Column = 1; Column < TruncateAtColumn; ++Column, ++Position) { - if (!*Position) - break; - - if (*Position == '\t') - Column += 7; - } - - // Truncate the buffer. - if (Position != Buffer->getBufferEnd()) { - MemoryBuffer *TruncatedBuffer - = MemoryBuffer::getMemBufferCopy(Buffer->getBufferStart(), Position, - Buffer->getBufferIdentifier()); - delete Buffer; - Buffer = TruncatedBuffer; - } + return Buffer; } unsigned LineTableInfo::getLineTableFilenameID(const char *Ptr, unsigned Len) { @@ -332,16 +310,6 @@ SourceManager::getOrCreateContentCache(const FileEntry *FileEnt) { EntryAlign = std::max(8U, EntryAlign); Entry = ContentCacheAlloc.Allocate<ContentCache>(1, EntryAlign); new (Entry) ContentCache(FileEnt); - - if (FileEnt == TruncateFile) { - // If we had queued up a file truncation request, perform the truncation - // now. - Entry->truncateAt(TruncateAtLine, TruncateAtColumn); - TruncateFile = 0; - TruncateAtLine = 0; - TruncateAtColumn = 0; - } - return Entry; } @@ -413,8 +381,6 @@ FileID SourceManager::createFileID(const ContentCache *File, = SLocEntry::get(Offset, FileInfo::get(IncludePos, File, FileCharacter)); SLocEntryLoaded[PreallocatedID] = true; FileID FID = FileID::get(PreallocatedID); - if (File->FirstFID.isInvalid()) - File->FirstFID = FID; return LastFileIDLookup = FID; } @@ -428,8 +394,6 @@ FileID SourceManager::createFileID(const ContentCache *File, // Set LastFileIDLookup to the newly created file. The next getFileID call is // almost guaranteed to be from that file. FileID FID = FileID::get(SLocEntryTable.size()-1); - if (File->FirstFID.isInvalid()) - File->FirstFID = FID; return LastFileIDLookup = FID; } @@ -461,6 +425,25 @@ SourceLocation SourceManager::createInstantiationLoc(SourceLocation SpellingLoc, return SourceLocation::getMacroLoc(NextOffset-(TokLength+1)); } +const llvm::MemoryBuffer * +SourceManager::getMemoryBufferForFile(const FileEntry *File) { + const SrcMgr::ContentCache *IR = getOrCreateContentCache(File); + if (IR == 0) + return 0; + + return IR->getBuffer(); +} + +bool SourceManager::overrideFileContents(const FileEntry *SourceFile, + const llvm::MemoryBuffer *Buffer) { + const SrcMgr::ContentCache *IR = getOrCreateContentCache(SourceFile); + if (IR == 0) + return true; + + const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(Buffer); + return false; +} + /// getBufferData - Return a pointer to the start and end of the source buffer /// data for the specified FileID. std::pair<const char*, const char*> @@ -1007,8 +990,33 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, if (i < Col-1) return SourceLocation(); - return getLocForStartOfFile(Content->FirstFID). - getFileLocWithOffset(FilePos + Col - 1); + // Find the first file ID that corresponds to the given file. + FileID FirstFID; + + // First, check the main file ID, since it is common to look for a + // location in the main file. + if (!MainFileID.isInvalid()) { + const SLocEntry &MainSLoc = getSLocEntry(MainFileID); + if (MainSLoc.isFile() && MainSLoc.getFile().getContentCache() == Content) + FirstFID = MainFileID; + } + + if (FirstFID.isInvalid()) { + // The location we're looking for isn't in the main file; look + // through all of the source locations. + for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) { + const SLocEntry &SLoc = getSLocEntry(I); + if (SLoc.isFile() && SLoc.getFile().getContentCache() == Content) { + FirstFID = FileID::get(I); + break; + } + } + } + + if (FirstFID.isInvalid()) + return SourceLocation(); + + return getLocForStartOfFile(FirstFID).getFileLocWithOffset(FilePos + Col - 1); } /// \brief Determines the order of 2 source locations in the translation unit. @@ -1087,52 +1095,20 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, return LastResForBeforeTUCheck = LOffs.second < I->second; } - // No common ancestor. - // Now we are getting into murky waters. Most probably this is because one - // location is in the predefines buffer. - - const FileEntry *LEntry = - getSLocEntry(LOffs.first).getFile().getContentCache()->Entry; - const FileEntry *REntry = - getSLocEntry(ROffs.first).getFile().getContentCache()->Entry; - - // If the locations are in two memory buffers we give up, we can't answer - // which one should be considered first. - // FIXME: Should there be a way to "include" memory buffers in the translation - // unit ? - assert((LEntry != 0 || REntry != 0) && "Locations in memory buffers."); - (void) REntry; - - // Consider the memory buffer as coming before the file in the translation - // unit. - if (LEntry == 0) - return LastResForBeforeTUCheck = true; - else { - assert(REntry == 0 && "Locations in not #included files ?"); - return LastResForBeforeTUCheck = false; - } -} + // There is no common ancestor, most probably because one location is in the + // predefines buffer. + // + // FIXME: We should rearrange the external interface so this simply never + // happens; it can't conceptually happen. Also see PR5662. -void SourceManager::truncateFileAt(const FileEntry *Entry, unsigned Line, - unsigned Column) { - llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*>::iterator FI - = FileInfos.find(Entry); - if (FI != FileInfos.end()) { - FI->second->truncateAt(Line, Column); - return; - } - - // We cannot perform the truncation until we actually see the file, so - // save the truncation information. - assert(TruncateFile == 0 && "Can't queue up multiple file truncations!"); - TruncateFile = Entry; - TruncateAtLine = Line; - TruncateAtColumn = Column; -} + // If exactly one location is a memory buffer, assume it preceeds the other. + bool LIsMB = !getSLocEntry(LOffs.first).getFile().getContentCache()->Entry; + bool RIsMB = !getSLocEntry(ROffs.first).getFile().getContentCache()->Entry; + if (LIsMB != RIsMB) + return LastResForBeforeTUCheck = LIsMB; -/// \brief Determine whether this file was truncated. -bool SourceManager::isTruncatedFile(FileID FID) const { - return getSLocEntry(FID).getFile().getContentCache()->isTruncated(); + // Otherwise, just assume FileIDs were created in order. + return LastResForBeforeTUCheck = (LOffs.first < ROffs.first); } /// PrintStats - Print statistics to stderr. diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 2df779c..9e44db0 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -296,7 +296,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { ++helpersize; continue; } else - E = new (getContext()) DeclRefExpr (cast<NamedDecl>(VD), + E = new (getContext()) DeclRefExpr (VD, VD->getType(), SourceLocation()); } @@ -1136,36 +1136,38 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T, } llvm::Constant *BlockFunction::BuildbyrefCopyHelper(const llvm::Type *T, - int flag, unsigned Align) { - // All alignments below that of pointer alignment collpase down to just + int Flag, unsigned Align) { + // All alignments below that of pointer alignment collapse down to just // pointer alignment, as we always have at least that much alignment to begin // with. Align /= unsigned(CGF.Target.getPointerAlign(0)/8); + // As an optimization, we only generate a single function of each kind we // might need. We need a different one for each alignment and for each // setting of flags. We mix Align and flag to get the kind. - uint64_t kind = (uint64_t)Align*BLOCK_BYREF_CURRENT_MAX + flag; - llvm::Constant *& Entry = CGM.AssignCache[kind]; + uint64_t Kind = (uint64_t)Align*BLOCK_BYREF_CURRENT_MAX + Flag; + llvm::Constant *&Entry = CGM.AssignCache[Kind]; if (Entry) return Entry; - return Entry=CodeGenFunction(CGM).GeneratebyrefCopyHelperFunction(T, flag); + return Entry = CodeGenFunction(CGM).GeneratebyrefCopyHelperFunction(T, Flag); } llvm::Constant *BlockFunction::BuildbyrefDestroyHelper(const llvm::Type *T, - int flag, + int Flag, unsigned Align) { // All alignments below that of pointer alignment collpase down to just // pointer alignment, as we always have at least that much alignment to begin // with. Align /= unsigned(CGF.Target.getPointerAlign(0)/8); + // As an optimization, we only generate a single function of each kind we // might need. We need a different one for each alignment and for each // setting of flags. We mix Align and flag to get the kind. - uint64_t kind = (uint64_t)Align*BLOCK_BYREF_CURRENT_MAX + flag; - llvm::Constant *& Entry = CGM.DestroyCache[kind]; + uint64_t Kind = (uint64_t)Align*BLOCK_BYREF_CURRENT_MAX + Flag; + llvm::Constant *&Entry = CGM.DestroyCache[Kind]; if (Entry) return Entry; - return Entry=CodeGenFunction(CGM).GeneratebyrefDestroyHelperFunction(T, flag); + return Entry=CodeGenFunction(CGM).GeneratebyrefDestroyHelperFunction(T, Flag); } llvm::Value *BlockFunction::getBlockObjectDispose() { diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index be4c27c..c704432 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -204,7 +204,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Builder.CreateCall(F, ArgValue, "tmp")); } case Builtin::BI__builtin_object_size: { -#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[] = { @@ -214,15 +213,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Builder.CreateCall2(F, EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1)))); -#else - // 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; - bool UseMinimum = TypeArg.getZExtValue() & 2; - return RValue::get( - llvm::ConstantInt::get(ResType, UseMinimum ? 0 : -1LL)); -#endif } case Builtin::BI__builtin_prefetch: { Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0)); @@ -815,13 +805,44 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, Ops[0] = Builder.CreateBitCast(Ops[0], PtrTy); return Builder.CreateStore(Ops[1], Ops[0]); } - case X86::BI__builtin_ia32_palignr128: case X86::BI__builtin_ia32_palignr: { - Function *F = CGM.getIntrinsic(BuiltinID == X86::BI__builtin_ia32_palignr128 ? - Intrinsic::x86_ssse3_palign_r_128 : - Intrinsic::x86_ssse3_palign_r); + Function *F = CGM.getIntrinsic(Intrinsic::x86_ssse3_palign_r); return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size()); } + case X86::BI__builtin_ia32_palignr128: { + unsigned shiftVal = cast<llvm::ConstantInt>(Ops[2])->getZExtValue(); + + // If palignr is shifting the pair of input vectors less than 17 bytes, + // emit a shuffle instruction. + if (shiftVal <= 16) { + const llvm::Type *IntTy = llvm::Type::getInt32Ty(VMContext); + + llvm::SmallVector<llvm::Constant*, 16> Indices; + for (unsigned i = 0; i != 16; ++i) + Indices.push_back(llvm::ConstantInt::get(IntTy, shiftVal + i)); + + Value* SV = llvm::ConstantVector::get(Indices.begin(), Indices.size()); + return Builder.CreateShuffleVector(Ops[1], Ops[0], SV, "palignr"); + } + + // If palignr is shifting the pair of input vectors more than 16 but less + // than 32 bytes, emit a logical right shift of the destination. + if (shiftVal < 32) { + const llvm::Type *EltTy = llvm::Type::getInt64Ty(VMContext); + const llvm::Type *VecTy = llvm::VectorType::get(EltTy, 2); + const llvm::Type *IntTy = llvm::Type::getInt32Ty(VMContext); + + Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast"); + Ops[1] = llvm::ConstantInt::get(IntTy, (shiftVal-16) * 8); + + // create i32 constant + llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse2_psrl_dq); + return Builder.CreateCall(F, &Ops[0], &Ops[0] + 2, "palignr"); + } + + // If palignr is shifting the pair of vectors more than 32 bytes, emit zero. + return llvm::Constant::getNullValue(ConvertType(E->getType())); + } } } diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 34d1c8d..0d11be2 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -26,168 +26,6 @@ using namespace clang; using namespace CodeGen; -void -CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, - llvm::Constant *DeclPtr) { - const llvm::Type *Int8PtrTy = - llvm::Type::getInt8Ty(VMContext)->getPointerTo(); - - std::vector<const llvm::Type *> Params; - Params.push_back(Int8PtrTy); - - // Get the destructor function type - const llvm::Type *DtorFnTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false); - DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy); - - Params.clear(); - Params.push_back(DtorFnTy); - Params.push_back(Int8PtrTy); - Params.push_back(Int8PtrTy); - - // Get the __cxa_atexit function type - // extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d ); - const llvm::FunctionType *AtExitFnTy = - llvm::FunctionType::get(ConvertType(getContext().IntTy), Params, false); - - llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy, - "__cxa_atexit"); - - llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy, - "__dso_handle"); - llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy), - llvm::ConstantExpr::getBitCast(DeclPtr, Int8PtrTy), - llvm::ConstantExpr::getBitCast(Handle, Int8PtrTy) }; - Builder.CreateCall(AtExitFn, &Args[0], llvm::array_endof(Args)); -} - -void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, - llvm::Constant *DeclPtr) { - assert(D.hasGlobalStorage() && - "VarDecl must have global storage!"); - - const Expr *Init = D.getInit(); - QualType T = D.getType(); - bool isVolatile = getContext().getCanonicalType(T).isVolatileQualified(); - - if (T->isReferenceType()) { - ErrorUnsupported(Init, "global variable that binds to a reference"); - } else if (!hasAggregateLLVMType(T)) { - llvm::Value *V = EmitScalarExpr(Init); - EmitStoreOfScalar(V, DeclPtr, isVolatile, T); - } else if (T->isAnyComplexType()) { - 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()) { - 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); - } - } - } -} - -void -CodeGenModule::EmitCXXGlobalInitFunc() { - if (CXXGlobalInits.empty()) - return; - - const llvm::FunctionType *FTy - = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), - false); - - // Create our global initialization function. - // FIXME: Should this be tweakable by targets? - llvm::Function *Fn = - llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, - "__cxx_global_initialization", &TheModule); - - CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, - &CXXGlobalInits[0], - CXXGlobalInits.size()); - AddGlobalCtor(Fn); -} - -void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, - const VarDecl **Decls, - unsigned NumDecls) { - StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(), - SourceLocation()); - - for (unsigned i = 0; i != NumDecls; ++i) { - const VarDecl *D = Decls[i]; - - llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D); - EmitCXXGlobalVarDeclInit(*D, DeclPtr); - } - FinishFunction(); -} - -void -CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, - llvm::GlobalVariable *GV) { - // FIXME: This should use __cxa_guard_{acquire,release}? - - assert(!getContext().getLangOptions().ThreadsafeStatics && - "thread safe statics are currently not supported!"); - - llvm::SmallString<256> GuardVName; - CGM.getMangleContext().mangleGuardVariable(&D, GuardVName); - - // Create the guard variable. - llvm::GlobalValue *GuardV = - new llvm::GlobalVariable(CGM.getModule(), llvm::Type::getInt64Ty(VMContext), - false, GV->getLinkage(), - llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)), - GuardVName.str()); - - // Load the first byte of the guard variable. - const llvm::Type *PtrTy - = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); - llvm::Value *V = Builder.CreateLoad(Builder.CreateBitCast(GuardV, PtrTy), - "tmp"); - - // Compare it against 0. - llvm::Value *nullValue - = llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext)); - llvm::Value *ICmp = Builder.CreateICmpEQ(V, nullValue , "tobool"); - - llvm::BasicBlock *InitBlock = createBasicBlock("init"); - llvm::BasicBlock *EndBlock = createBasicBlock("init.end"); - - // If the guard variable is 0, jump to the initializer code. - Builder.CreateCondBr(ICmp, InitBlock, EndBlock); - - EmitBlock(InitBlock); - - EmitCXXGlobalVarDeclInit(D, GV); - - Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), - 1), - Builder.CreateBitCast(GuardV, PtrTy)); - - EmitBlock(EndBlock); -} - RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD, llvm::Value *Callee, llvm::Value *This, @@ -241,10 +79,10 @@ static bool canDevirtualizeMemberFunctionCalls(const Expr *Base) { } RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) { - if (isa<BinaryOperator>(CE->getCallee())) + if (isa<BinaryOperator>(CE->getCallee()->IgnoreParens())) return EmitCXXMemberPointerCallExpr(CE); - const MemberExpr *ME = cast<MemberExpr>(CE->getCallee()); + const MemberExpr *ME = cast<MemberExpr>(CE->getCallee()->IgnoreParens()); const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl()); if (MD->isStatic()) { @@ -307,7 +145,8 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) { RValue CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E) { - const BinaryOperator *BO = cast<BinaryOperator>(E->getCallee()); + const BinaryOperator *BO = + cast<BinaryOperator>(E->getCallee()->IgnoreParens()); const Expr *BaseExpr = BO->getLHS(); const Expr *MemFnExpr = BO->getRHS(); @@ -519,7 +358,7 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, // C++ [class.temporary]p4: // There are two contexts in which temporaries are destroyed at a different - // point than the end of the full- expression. The first context is when a + // point than the end of the full-expression. The first context is when a // default constructor is called to initialize an element of an array. // If the constructor has one or more default arguments, the destruction of // every temporary created in a default argument expression is sequenced @@ -558,8 +397,9 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, 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); + + const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType()); + llvm::Value* ElementCountPtr = llvm::ConstantInt::get(SizeLTy, ElementCount); EmitCXXAggrDestructorCall(D, ElementCountPtr, This); } @@ -569,13 +409,14 @@ void CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, llvm::Value *UpperCount, llvm::Value *This) { - llvm::Value *One = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - 1); + const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType()); + llvm::Value *One = llvm::ConstantInt::get(SizeLTy, 1); + // 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 *IndexPtr = CreateTempAlloca(SizeLTy, "loop.index"); + + // Store the number of elements in the index pointer. Builder.CreateStore(UpperCount, IndexPtr); // Start the loop with a block that tests the condition. @@ -589,7 +430,7 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, // Generate: if (loop-index != 0 fall to the loop body, // otherwise, go to the block after the for-loop. llvm::Value* zeroConstant = - llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)); + llvm::Constant::getNullValue(SizeLTy); llvm::Value *Counter = Builder.CreateLoad(IndexPtr); llvm::Value *IsNE = Builder.CreateICmpNE(Counter, zeroConstant, "isne"); @@ -626,7 +467,6 @@ llvm::Constant * CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, const ArrayType *Array, llvm::Value *This) { - static int UniqueCount; FunctionArgList Args; ImplicitParamDecl *Dst = ImplicitParamDecl::Create(getContext(), 0, @@ -635,16 +475,15 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, Args.push_back(std::make_pair(Dst, Dst->getType())); llvm::SmallString<16> Name; - llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueCount); + llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueAggrDestructorCount); 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(), + Name.str(), &CGM.getModule()); - IdentifierInfo *II - = &CGM.getContext().Idents.get(Name.c_str()); + IdentifierInfo *II = &CGM.getContext().Idents.get(Name.str()); FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), SourceLocation(), II, R, 0, @@ -691,21 +530,29 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, EmitCXXMemberCall(D, Callee, This, ArgBeg, ArgEnd); } -void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *D, +void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, CXXDtorType Type, llvm::Value *This) { - if (D->isVirtual()) { - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(D), - /*isVariadic=*/false); + llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(DD, Type); + + CallArgList Args; + + // Push the this ptr. + Args.push_back(std::make_pair(RValue::get(This), + DD->getThisType(getContext()))); + + // Add a VTT parameter if necessary. + // FIXME: This should not be a dummy null parameter! + if (Type == Dtor_Base && DD->getParent()->getNumVBases() != 0) { + QualType T = getContext().getPointerType(getContext().VoidPtrTy); - llvm::Value *Callee = BuildVirtualCall(D, Dtor_Deleting, This, Ty); - EmitCXXMemberCall(D, Callee, This, 0, 0); - return; + Args.push_back(std::make_pair(RValue::get(CGM.EmitNullConstant(T)), T)); } - llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(D, Type); - EmitCXXMemberCall(D, Callee, This, 0, 0); + // FIXME: We should try to share this code with EmitCXXMemberCall. + + QualType ResultType = DD->getType()->getAs<FunctionType>()->getResultType(); + EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee, Args, DD); } void @@ -793,9 +640,9 @@ const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D, void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) { if (D->isVirtual()) - EmitGlobalDefinition(GlobalDecl(D, Dtor_Deleting)); - EmitGlobalDefinition(GlobalDecl(D, Dtor_Complete)); - EmitGlobalDefinition(GlobalDecl(D, Dtor_Base)); + EmitGlobal(GlobalDecl(D, Dtor_Deleting)); + EmitGlobal(GlobalDecl(D, Dtor_Complete)); + EmitGlobal(GlobalDecl(D, Dtor_Base)); } void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D, @@ -829,10 +676,10 @@ const char *CodeGenModule::getMangledCXXDtorName(const CXXDestructorDecl *D, } llvm::Constant * -CodeGenFunction::GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD, +CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, bool Extern, const ThunkAdjustment &ThisAdjustment) { - return GenerateCovariantThunk(Fn, MD, Extern, + return GenerateCovariantThunk(Fn, GD, Extern, CovariantThunkAdjustment(ThisAdjustment, ThunkAdjustment())); } @@ -875,8 +722,9 @@ CodeGenFunction::DynamicTypeAdjust(llvm::Value *V, llvm::Constant * CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, - const CXXMethodDecl *MD, bool Extern, + GlobalDecl GD, bool Extern, const CovariantThunkAdjustment &Adjustment) { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType(); FunctionArgList Args; @@ -906,7 +754,8 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, const llvm::Type *Ty = CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), FPT->isVariadic()); - llvm::Value *Callee = CGM.GetAddrOfFunction(MD, Ty); + llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty); + CallArgList CallArgs; bool ShouldAdjustReturnPointer = true; @@ -922,7 +771,7 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, CovariantThunkAdjustment(ThunkAdjustment(), Adjustment.ReturnAdjustment); - Callee = CGM.BuildCovariantThunk(MD, Extern, ReturnAdjustment); + Callee = CGM.BuildCovariantThunk(GD, Extern, ReturnAdjustment); Callee = Builder.CreateBitCast(Callee, OrigTy); ShouldAdjustReturnPointer = false; @@ -938,7 +787,8 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, QualType ArgType = D->getType(); // llvm::Value *Arg = CGF.GetAddrOfLocalVar(Dst); - Expr *Arg = new (getContext()) DeclRefExpr(D, ArgType, SourceLocation()); + Expr *Arg = new (getContext()) DeclRefExpr(D, ArgType.getNonReferenceType(), + SourceLocation()); CallArgs.push_back(std::make_pair(EmitCallArg(Arg, ArgType), ArgType)); } @@ -983,11 +833,117 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, } llvm::Constant * -CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern, +CodeGenModule::GetAddrOfThunk(GlobalDecl GD, + const ThunkAdjustment &ThisAdjustment) { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + + // Compute mangled name + llvm::SmallString<256> OutName; + if (const CXXDestructorDecl* DD = dyn_cast<CXXDestructorDecl>(MD)) + getMangleContext().mangleCXXDtorThunk(DD, GD.getDtorType(), ThisAdjustment, + OutName); + else + getMangleContext().mangleThunk(MD, ThisAdjustment, OutName); + OutName += '\0'; + const char* Name = UniqueMangledName(OutName.begin(), OutName.end()); + + // Get function for mangled name + const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD); + return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl()); +} + +llvm::Constant * +CodeGenModule::GetAddrOfCovariantThunk(GlobalDecl GD, + const CovariantThunkAdjustment &Adjustment) { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + + // Compute mangled name + llvm::SmallString<256> OutName; + getMangleContext().mangleCovariantThunk(MD, Adjustment, OutName); + OutName += '\0'; + const char* Name = UniqueMangledName(OutName.begin(), OutName.end()); + + // Get function for mangled name + const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD); + return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl()); +} + +void CodeGenModule::BuildThunksForVirtual(GlobalDecl GD) { + CGVtableInfo::AdjustmentVectorTy *AdjPtr = getVtableInfo().getAdjustments(GD); + if (!AdjPtr) + return; + CGVtableInfo::AdjustmentVectorTy &Adj = *AdjPtr; + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + for (unsigned i = 0; i < Adj.size(); i++) { + GlobalDecl OGD = Adj[i].first; + const CXXMethodDecl *OMD = cast<CXXMethodDecl>(OGD.getDecl()); + QualType nc_oret = OMD->getType()->getAs<FunctionType>()->getResultType(); + CanQualType oret = getContext().getCanonicalType(nc_oret); + QualType nc_ret = MD->getType()->getAs<FunctionType>()->getResultType(); + CanQualType ret = getContext().getCanonicalType(nc_ret); + ThunkAdjustment ReturnAdjustment; + if (oret != ret) { + QualType qD = nc_ret->getPointeeType(); + QualType qB = nc_oret->getPointeeType(); + CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl()); + CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl()); + ReturnAdjustment = ComputeThunkAdjustment(D, B); + } + ThunkAdjustment ThisAdjustment = Adj[i].second; + bool Extern = !cast<CXXRecordDecl>(OMD->getDeclContext())->isInAnonymousNamespace(); + if (!ReturnAdjustment.isEmpty() || !ThisAdjustment.isEmpty()) { + CovariantThunkAdjustment CoAdj(ThisAdjustment, ReturnAdjustment); + llvm::Constant *FnConst; + if (!ReturnAdjustment.isEmpty()) + FnConst = GetAddrOfCovariantThunk(GD, CoAdj); + else + FnConst = GetAddrOfThunk(GD, ThisAdjustment); + if (!isa<llvm::Function>(FnConst)) { + llvm::Constant *SubExpr = + cast<llvm::ConstantExpr>(FnConst)->getOperand(0); + llvm::Function *OldFn = cast<llvm::Function>(SubExpr); + std::string Name = OldFn->getNameStr(); + GlobalDeclMap.erase(UniqueMangledName(Name.data(), + Name.data() + Name.size() + 1)); + llvm::Constant *NewFnConst; + if (!ReturnAdjustment.isEmpty()) + NewFnConst = GetAddrOfCovariantThunk(GD, CoAdj); + else + NewFnConst = GetAddrOfThunk(GD, ThisAdjustment); + llvm::Function *NewFn = cast<llvm::Function>(NewFnConst); + NewFn->takeName(OldFn); + llvm::Constant *NewPtrForOldDecl = + llvm::ConstantExpr::getBitCast(NewFn, OldFn->getType()); + OldFn->replaceAllUsesWith(NewPtrForOldDecl); + OldFn->eraseFromParent(); + FnConst = NewFn; + } + llvm::Function *Fn = cast<llvm::Function>(FnConst); + if (Fn->isDeclaration()) { + llvm::GlobalVariable::LinkageTypes linktype; + linktype = llvm::GlobalValue::WeakAnyLinkage; + if (!Extern) + linktype = llvm::GlobalValue::InternalLinkage; + Fn->setLinkage(linktype); + if (!Features.Exceptions && !Features.ObjCNonFragileABI) + Fn->addFnAttr(llvm::Attribute::NoUnwind); + Fn->setAlignment(2); + CodeGenFunction(*this).GenerateCovariantThunk(Fn, GD, Extern, CoAdj); + } + } + } +} + +llvm::Constant * +CodeGenModule::BuildThunk(GlobalDecl GD, bool Extern, const ThunkAdjustment &ThisAdjustment) { - + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); llvm::SmallString<256> OutName; - getMangleContext().mangleThunk(MD, ThisAdjustment, OutName); + if (const CXXDestructorDecl *D = dyn_cast<CXXDestructorDecl>(MD)) { + getMangleContext().mangleCXXDtorThunk(D, GD.getDtorType(), ThisAdjustment, + OutName); + } else + getMangleContext().mangleThunk(MD, ThisAdjustment, OutName); llvm::GlobalVariable::LinkageTypes linktype; linktype = llvm::GlobalValue::WeakAnyLinkage; @@ -1001,14 +957,15 @@ CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern, llvm::Function *Fn = llvm::Function::Create(FTy, linktype, OutName.str(), &getModule()); - CodeGenFunction(*this).GenerateThunk(Fn, MD, Extern, ThisAdjustment); + CodeGenFunction(*this).GenerateThunk(Fn, GD, Extern, ThisAdjustment); llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty); return m; } llvm::Constant * -CodeGenModule::BuildCovariantThunk(const CXXMethodDecl *MD, bool Extern, +CodeGenModule::BuildCovariantThunk(const GlobalDecl &GD, bool Extern, const CovariantThunkAdjustment &Adjustment) { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); llvm::SmallString<256> OutName; getMangleContext().mangleCovariantThunk(MD, Adjustment, OutName); llvm::GlobalVariable::LinkageTypes linktype; @@ -1453,6 +1410,8 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType()); } } + + InitializeVtablePtrs(ClassDecl); FinishFunction(); } @@ -1537,8 +1496,16 @@ void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD, // 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()); + } } // return *this; @@ -1666,8 +1633,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, const CXXRecordDecl *ClassDecl = CD->getParent(); // FIXME: Add vbase initialization - llvm::Value *LoadOfThis = 0; - + for (CXXConstructorDecl::init_const_iterator B = CD->init_begin(), E = CD->init_end(); B != E; ++B) { @@ -1686,18 +1652,28 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, PopCXXTemporary(); } - // Initialize the vtable pointer - if (ClassDecl->isDynamicClass()) { - if (!LoadOfThis) - LoadOfThis = LoadCXXThis(); - llvm::Value *VtableField; - llvm::Type *Ptr8Ty, *PtrPtr8Ty; - Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); - PtrPtr8Ty = llvm::PointerType::get(Ptr8Ty, 0); - VtableField = Builder.CreateBitCast(LoadOfThis, PtrPtr8Ty); - llvm::Value *vtable = CGM.getVtableInfo().getVtable(ClassDecl); - Builder.CreateStore(vtable, VtableField); - } + InitializeVtablePtrs(ClassDecl); +} + +void CodeGenFunction::InitializeVtablePtrs(const CXXRecordDecl *ClassDecl) { + if (!ClassDecl->isDynamicClass()) + return; + + // Initialize the vtable pointer. + // FIXME: This needs to initialize secondary vtable pointers too. + llvm::Value *ThisPtr = LoadCXXThis(); + + llvm::Constant *Vtable = CGM.getVtableInfo().getVtable(ClassDecl); + uint64_t AddressPoint = CGM.getVtableInfo().getVtableAddressPoint(ClassDecl); + + llvm::Value *VtableAddressPoint = + Builder.CreateConstInBoundsGEP2_64(Vtable, 0, AddressPoint); + + llvm::Value *VtableField = + Builder.CreateBitCast(ThisPtr, + VtableAddressPoint->getType()->getPointerTo()); + + Builder.CreateStore(VtableAddressPoint, VtableField); } /// EmitDtorEpilogue - Emit all code that comes at the end of class's @@ -1808,9 +1784,12 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, } // If we have a deleting destructor, emit a call to the delete operator. - if (DtorType == Dtor_Deleting) + if (DtorType == Dtor_Deleting) { + assert(DD->getOperatorDelete() && + "operator delete missing - EmitDtorEpilogue"); EmitDeleteCall(DD->getOperatorDelete(), LoadCXXThis(), getContext().getTagDeclType(ClassDecl)); + } } void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor, diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index decc73c..4856f54 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -561,6 +561,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, const ABIArgInfo &AI = it->info; unsigned Attributes = 0; + if (ParamType.isRestrictQualified()) + Attributes |= llvm::Attribute::NoAlias; + switch (AI.getKind()) { case ABIArgInfo::Coerce: break; @@ -764,7 +767,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI, ComplexPairTy RT = LoadComplexFromAddr(ReturnValue, false); StoreComplexToAddr(RT, CurFn->arg_begin(), false); } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { - EmitAggregateCopy(CurFn->arg_begin(), ReturnValue, RetTy); + // Do nothing; aggregrates get evaluated directly into the destination. } else { EmitStoreOfScalar(Builder.CreateLoad(ReturnValue), CurFn->arg_begin(), false, RetTy); diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index b3c2b98..fd2afe7 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -112,6 +112,42 @@ static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF, return NonVirtualOffset; } +// FIXME: This probably belongs in CGVtable, but it relies on +// the static function ComputeNonVirtualBaseClassOffset, so we should make that +// a CodeGenModule member function as well. +ThunkAdjustment +CodeGenModule::ComputeThunkAdjustment(const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl) { + CXXBasePaths Paths(/*FindAmbiguities=*/false, + /*RecordPaths=*/true, /*DetectVirtual=*/false); + if (!const_cast<CXXRecordDecl *>(ClassDecl)-> + isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClassDecl), Paths)) { + assert(false && "Class must be derived from the passed in base class!"); + return ThunkAdjustment(); + } + + unsigned Start = 0; + uint64_t VirtualOffset = 0; + + const CXXBasePath &Path = Paths.front(); + const CXXRecordDecl *VBase = 0; + for (unsigned i = 0, e = Path.size(); i != e; ++i) { + const CXXBasePathElement& Element = Path[i]; + if (Element.Base->isVirtual()) { + Start = i+1; + QualType VBaseType = Element.Base->getType(); + VBase = cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl()); + } + } + if (VBase) + VirtualOffset = + getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl); + + uint64_t Offset = + ComputeNonVirtualBaseClassOffset(getContext(), Paths, Start); + return ThunkAdjustment(Offset, VirtualOffset); +} + llvm::Value * CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, const CXXRecordDecl *ClassDecl, diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 317da7e..2238c89 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -35,8 +35,8 @@ using namespace clang; using namespace clang::CodeGen; -CGDebugInfo::CGDebugInfo(CodeGenModule *m) - : M(m), isMainCompileUnitCreated(false), DebugFactory(M->getModule()), +CGDebugInfo::CGDebugInfo(CodeGenModule &CGM) + : CGM(CGM), isMainCompileUnitCreated(false), DebugFactory(CGM.getModule()), BlockLiteralGenericSet(false) { } @@ -46,7 +46,7 @@ CGDebugInfo::~CGDebugInfo() { void CGDebugInfo::setLocation(SourceLocation Loc) { if (Loc.isValid()) - CurLoc = M->getContext().getSourceManager().getInstantiationLoc(Loc); + CurLoc = CGM.getContext().getSourceManager().getInstantiationLoc(Loc); } /// getContext - Get context info for the decl. @@ -70,7 +70,7 @@ llvm::DIDescriptor CGDebugInfo::getContext(const VarDecl *Decl, llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { // Get source file information. const char *FileName = "<unknown>"; - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); unsigned FID = 0; if (Loc.isValid()) { PresumedLoc PLoc = SM.getPresumedLoc(Loc); @@ -84,18 +84,14 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { // Get absolute path name. llvm::sys::Path AbsFileName(FileName); - if (!AbsFileName.isAbsolute()) { - llvm::sys::Path tmp = llvm::sys::Path::GetCurrentDirectory(); - tmp.appendComponent(FileName); - AbsFileName = tmp; - } + AbsFileName.makeAbsolute(); // See if thie compile unit is representing main source file. Each source // file has corresponding compile unit. There is only one main source // file at a time. bool isMain = false; - const LangOptions &LO = M->getLangOptions(); - const CodeGenOptions &CGO = M->getCodeGenOpts(); + const LangOptions &LO = CGM.getLangOptions(); + const CodeGenOptions &CGO = CGM.getCodeGenOpts(); if (isMainCompileUnitCreated == false) { if (!CGO.MainFileName.empty()) { if (AbsFileName.getLast() == CGO.MainFileName) @@ -122,7 +118,7 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { LangTag = llvm::dwarf::DW_LANG_C89; } - std::string Producer = + const char *Producer = #ifdef CLANG_VENDOR CLANG_VENDOR #endif @@ -137,9 +133,9 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { // Create new compile unit. return Unit = DebugFactory.CreateCompileUnit(LangTag, - AbsFileName.getLast().c_str(), - AbsFileName.getDirname().c_str(), - Producer.c_str(), isMain, + AbsFileName.getLast(), + AbsFileName.getDirname(), + Producer, isMain, isOptimized, Flags, RuntimeVers); } @@ -170,13 +166,13 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT, case BuiltinType::Double: Encoding = llvm::dwarf::DW_ATE_float; break; } // Bit size, align and offset of the type. - uint64_t Size = M->getContext().getTypeSize(BT); - uint64_t Align = M->getContext().getTypeAlign(BT); + uint64_t Size = CGM.getContext().getTypeSize(BT); + uint64_t Align = CGM.getContext().getTypeAlign(BT); uint64_t Offset = 0; llvm::DIType DbgTy = DebugFactory.CreateBasicType(Unit, - BT->getName(M->getContext().getLangOptions()), + BT->getName(CGM.getContext().getLangOptions()), Unit, 0, Size, Align, Offset, /*flags*/ 0, Encoding); return DbgTy; @@ -189,8 +185,8 @@ llvm::DIType CGDebugInfo::CreateType(const ComplexType *Ty, if (Ty->isComplexIntegerType()) Encoding = llvm::dwarf::DW_ATE_lo_user; - uint64_t Size = M->getContext().getTypeSize(Ty); - uint64_t Align = M->getContext().getTypeAlign(Ty); + uint64_t Size = CGM.getContext().getTypeSize(Ty); + uint64_t Align = CGM.getContext().getTypeAlign(Ty); uint64_t Offset = 0; llvm::DIType DbgTy = @@ -262,8 +258,8 @@ llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag, // 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); + CGM.getContext().Target.getPointerWidth(PointeeTy.getAddressSpace()); + uint64_t Align = CGM.getContext().getTypeAlign(Ty); return DebugFactory.CreateDerivedType(Tag, Unit, "", llvm::DICompileUnit(), @@ -291,10 +287,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, llvm::DIType EltTy, DescTy; FieldOffset = 0; - FType = M->getContext().UnsignedLongTy; + FType = CGM.getContext().UnsignedLongTy; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "reserved", DefUnit, 0, FieldSize, FieldAlign, @@ -302,10 +298,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().UnsignedLongTy; + FType = CGM.getContext().UnsignedLongTy; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "Size", DefUnit, 0, FieldSize, FieldAlign, @@ -323,18 +319,18 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, llvm::DIType(), Elements); // Bit size, align and offset of the type. - uint64_t Size = M->getContext().getTypeSize(Ty); - uint64_t Align = M->getContext().getTypeAlign(Ty); + uint64_t Size = CGM.getContext().getTypeSize(Ty); + uint64_t Align = CGM.getContext().getTypeAlign(Ty); DescTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit, "", llvm::DICompileUnit(), 0, Size, Align, 0, 0, EltTy); FieldOffset = 0; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__isa", DefUnit, 0, FieldSize, FieldAlign, @@ -342,10 +338,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().IntTy; + FType = CGM.getContext().IntTy; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__flags", DefUnit, 0, FieldSize, FieldAlign, @@ -353,10 +349,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().IntTy; + FType = CGM.getContext().IntTy; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__reserved", DefUnit, 0, FieldSize, FieldAlign, @@ -364,10 +360,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__FuncPtr", DefUnit, 0, FieldSize, FieldAlign, @@ -375,10 +371,10 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = DescTy; - FieldSize = M->getContext().getTypeSize(Ty); - FieldAlign = M->getContext().getTypeAlign(Ty); + FieldSize = CGM.getContext().getTypeSize(Ty); + FieldAlign = CGM.getContext().getTypeAlign(Ty); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__descriptor", DefUnit, 0, FieldSize, FieldAlign, @@ -411,7 +407,7 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, SourceLocation DefLoc = Ty->getDecl()->getLocation(); llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(DefLoc); - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(DefLoc); unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine(); @@ -464,7 +460,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, Tag = llvm::dwarf::DW_TAG_class_type; } - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); // Get overall information about the record type for the debug info. PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); @@ -487,7 +483,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, llvm::DIType(), llvm::DIArray()); // If this is just a forward declaration, return it. - if (!Decl->getDefinition(M->getContext())) + if (!Decl->getDefinition(CGM.getContext())) return FwdDecl; llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode(); @@ -498,7 +494,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, // Convert all the elements. llvm::SmallVector<llvm::DIDescriptor, 16> EltTys; - const ASTRecordLayout &RL = M->getContext().getASTRecordLayout(Decl); + const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(Decl); unsigned FieldNo = 0; for (RecordDecl::field_iterator I = Decl->field_begin(), @@ -530,12 +526,12 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, if (!FType->isIncompleteArrayType()) { // Bit size, align and offset of the type. - FieldSize = M->getContext().getTypeSize(FType); + FieldSize = CGM.getContext().getTypeSize(FType); Expr *BitWidth = Field->getBitWidth(); if (BitWidth) - FieldSize = BitWidth->EvaluateAsInt(M->getContext()).getZExtValue(); + FieldSize = BitWidth->EvaluateAsInt(CGM.getContext()).getZExtValue(); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); } uint64_t FieldOffset = RL.getFieldOffset(FieldNo); @@ -554,8 +550,8 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); // Bit size, align and offset of the type. - uint64_t Size = M->getContext().getTypeSize(Ty); - uint64_t Align = M->getContext().getTypeAlign(Ty); + uint64_t Size = CGM.getContext().getTypeSize(Ty); + uint64_t Align = CGM.getContext().getTypeAlign(Ty); llvm::DICompositeType RealDecl = DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(), @@ -575,7 +571,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, ObjCInterfaceDecl *Decl = Ty->getDecl(); unsigned Tag = llvm::dwarf::DW_TAG_structure_type; - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); // Get overall information about the record type for the debug info. llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(Decl->getLocation()); @@ -612,7 +608,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, ObjCInterfaceDecl *SClass = Decl->getSuperClass(); if (SClass) { llvm::DIType SClassTy = - getOrCreateType(M->getContext().getObjCInterfaceType(SClass), Unit); + getOrCreateType(CGM.getContext().getObjCInterfaceType(SClass), Unit); llvm::DIType InhTag = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_inheritance, Unit, "", llvm::DICompileUnit(), 0, 0, 0, @@ -620,7 +616,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, EltTys.push_back(InhTag); } - const ASTRecordLayout &RL = M->getContext().getASTObjCInterfaceLayout(Decl); + const ASTRecordLayout &RL = CGM.getContext().getASTObjCInterfaceLayout(Decl); unsigned FieldNo = 0; for (ObjCInterfaceDecl::ivar_iterator I = Decl->ivar_begin(), @@ -648,12 +644,12 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, if (!FType->isIncompleteArrayType()) { // Bit size, align and offset of the type. - FieldSize = M->getContext().getTypeSize(FType); + FieldSize = CGM.getContext().getTypeSize(FType); Expr *BitWidth = Field->getBitWidth(); if (BitWidth) - FieldSize = BitWidth->EvaluateAsInt(M->getContext()).getZExtValue(); + FieldSize = BitWidth->EvaluateAsInt(CGM.getContext()).getZExtValue(); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); } uint64_t FieldOffset = RL.getFieldOffset(FieldNo); @@ -678,8 +674,8 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); // Bit size, align and offset of the type. - uint64_t Size = M->getContext().getTypeSize(Ty); - uint64_t Align = M->getContext().getTypeAlign(Ty); + uint64_t Size = CGM.getContext().getTypeSize(Ty); + uint64_t Align = CGM.getContext().getTypeAlign(Ty); llvm::DICompositeType RealDecl = DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(), DefUnit, @@ -713,7 +709,7 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty, SourceLocation DefLoc = Decl->getLocation(); llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(DefLoc); - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(DefLoc); unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine(); @@ -722,8 +718,8 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty, uint64_t Size = 0; unsigned Align = 0; if (!Ty->isIncompleteType()) { - Size = M->getContext().getTypeSize(Ty); - Align = M->getContext().getTypeAlign(Ty); + Size = CGM.getContext().getTypeSize(Ty); + Align = CGM.getContext().getTypeAlign(Ty); } llvm::DIType DbgTy = @@ -754,14 +750,14 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty, if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(Ty)) { Size = 0; Align = - M->getContext().getTypeAlign(M->getContext().getBaseElementType(VAT)); + CGM.getContext().getTypeAlign(CGM.getContext().getBaseElementType(VAT)); } else if (Ty->isIncompleteArrayType()) { Size = 0; - Align = M->getContext().getTypeAlign(Ty->getElementType()); + Align = CGM.getContext().getTypeAlign(Ty->getElementType()); } else { // Size and align of the whole array, not the element type. - Size = M->getContext().getTypeSize(Ty); - Align = M->getContext().getTypeAlign(Ty); + Size = CGM.getContext().getTypeSize(Ty); + Align = CGM.getContext().getTypeAlign(Ty); } // Add the dimensions of the array. FIXME: This loses CV qualifiers from @@ -797,6 +793,47 @@ llvm::DIType CGDebugInfo::CreateType(const LValueReferenceType *Ty, Ty, Ty->getPointeeType(), Unit); } +llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty, + llvm::DICompileUnit U) { + QualType PointerDiffTy = CGM.getContext().getPointerDiffType(); + llvm::DIType PointerDiffDITy = getOrCreateType(PointerDiffTy, U); + + if (!Ty->getPointeeType()->isFunctionType()) { + // We have a data member pointer type. + return PointerDiffDITy; + } + + // We have a member function pointer type. Treat it as a struct with two + // ptrdiff_t members. + std::pair<uint64_t, unsigned> Info = CGM.getContext().getTypeInfo(Ty); + + uint64_t FieldOffset = 0; + llvm::DIDescriptor ElementTypes[2]; + + // FIXME: This should probably be a function type instead. + ElementTypes[0] = + DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, U, + "ptr", llvm::DICompileUnit(), 0, + Info.first, Info.second, FieldOffset, 0, + PointerDiffDITy); + FieldOffset += Info.first; + + ElementTypes[1] = + DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, U, + "ptr", llvm::DICompileUnit(), 0, + Info.first, Info.second, FieldOffset, 0, + PointerDiffDITy); + + llvm::DIArray Elements = + DebugFactory.GetOrCreateArray(&ElementTypes[0], + llvm::array_lengthof(ElementTypes)); + + return DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_structure_type, + U, llvm::StringRef("test"), + llvm::DICompileUnit(), 0, FieldOffset, + 0, 0, 0, llvm::DIType(), Elements); +} + static QualType CanonicalizeTypeForDebugInfo(QualType T) { switch (T->getTypeClass()) { default: @@ -895,25 +932,27 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, case Type::LValueReference: return CreateType(cast<LValueReferenceType>(Ty), Unit); + case Type::MemberPointer: + return CreateType(cast<MemberPointerType>(Ty), Unit); } } /// EmitFunctionStart - Constructs the debug code for entering a function - /// "llvm.dbg.func.start.". -void CGDebugInfo::EmitFunctionStart(const char *Name, QualType FnType, +void CGDebugInfo::EmitFunctionStart(llvm::StringRef Name, QualType FnType, llvm::Function *Fn, CGBuilderTy &Builder) { - const char *LinkageName = Name; + llvm::StringRef LinkageName(Name); // Skip the asm prefix if it exists. // // FIXME: This should probably be the unmangled name? if (Name[0] == '\01') - ++Name; + Name = Name.substr(1); // FIXME: Why is this using CurLoc??? llvm::DICompileUnit Unit = getOrCreateCompileUnit(CurLoc); - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); unsigned LineNo = SM.getPresumedLoc(CurLoc).getLine(); llvm::DISubprogram SP = @@ -930,7 +969,7 @@ void CGDebugInfo::EmitStopPoint(llvm::Function *Fn, CGBuilderTy &Builder) { if (CurLoc.isInvalid() || CurLoc.isMacroID()) return; // Don't bother if things are the same as last time. - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); if (CurLoc == PrevLoc || (SM.getInstantiationLineNumber(CurLoc) == SM.getInstantiationLineNumber(PrevLoc) @@ -982,7 +1021,7 @@ 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 CodeGenOptions &CGO = M->getCodeGenOpts(); + const CodeGenOptions &CGO = CGM.getCodeGenOpts(); if (CGO.OptimizationLevel) return; @@ -1006,10 +1045,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, // Build up structure for the byref. See BuildByRefType. FieldOffset = 0; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__isa", DefUnit, 0, FieldSize, FieldAlign, @@ -1017,10 +1056,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__forwarding", DefUnit, 0, FieldSize, FieldAlign, @@ -1028,10 +1067,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getFixedWidthIntType(32, true); // Int32Ty; + FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__flags", DefUnit, 0, FieldSize, FieldAlign, @@ -1039,10 +1078,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getFixedWidthIntType(32, true); // Int32Ty; + FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__size", DefUnit, 0, FieldSize, FieldAlign, @@ -1050,12 +1089,12 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - bool HasCopyAndDispose = M->BlockRequiresCopying(Type); + bool HasCopyAndDispose = CGM.BlockRequiresCopying(Type); if (HasCopyAndDispose) { - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__copy_helper", DefUnit, 0, FieldSize, FieldAlign, @@ -1063,10 +1102,10 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__destroy_helper", DefUnit, 0, FieldSize, FieldAlign, @@ -1075,8 +1114,8 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, FieldOffset += FieldSize; } - unsigned Align = M->getContext().getDeclAlignInBytes(Decl); - if (Align > M->getContext().Target.getPointerAlign(0) / 8) { + unsigned Align = CGM.getContext().getDeclAlignInBytes(Decl); + if (Align > CGM.getContext().Target.getPointerAlign(0) / 8) { unsigned AlignedOffsetInBytes = llvm::RoundUpToAlignment(FieldOffset/8, Align); unsigned NumPaddingBytes @@ -1084,11 +1123,11 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, if (NumPaddingBytes > 0) { llvm::APInt pad(32, NumPaddingBytes); - FType = M->getContext().getConstantArrayType(M->getContext().CharTy, + FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy, pad, ArrayType::Normal, 0); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "", DefUnit, 0, FieldSize, FieldAlign, @@ -1100,7 +1139,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, FType = Type; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); + FieldSize = CGM.getContext().getTypeSize(FType); FieldAlign = Align*8; FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, @@ -1121,7 +1160,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag, } // Get location information. - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); unsigned Line = 0; unsigned Column = 0; @@ -1158,7 +1197,7 @@ 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 CodeGenOptions &CGO = M->getCodeGenOpts(); + const CodeGenOptions &CGO = CGM.getCodeGenOpts(); if (CGO.OptimizationLevel || Builder.GetInsertBlock() == 0) return; @@ -1183,10 +1222,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, // Build up structure for the byref. See BuildByRefType. FieldOffset = 0; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__isa", DefUnit, 0, FieldSize, FieldAlign, @@ -1194,10 +1233,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__forwarding", DefUnit, 0, FieldSize, FieldAlign, @@ -1205,10 +1244,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getFixedWidthIntType(32, true); // Int32Ty; + FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__flags", DefUnit, 0, FieldSize, FieldAlign, @@ -1216,10 +1255,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getFixedWidthIntType(32, true); // Int32Ty; + FType = CGM.getContext().getFixedWidthIntType(32, true); // Int32Ty; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__size", DefUnit, 0, FieldSize, FieldAlign, @@ -1227,12 +1266,12 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - bool HasCopyAndDispose = M->BlockRequiresCopying(Type); + bool HasCopyAndDispose = CGM.BlockRequiresCopying(Type); if (HasCopyAndDispose) { - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__copy_helper", DefUnit, 0, FieldSize, FieldAlign, @@ -1240,10 +1279,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - FType = M->getContext().getPointerType(M->getContext().VoidTy); + FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "__destroy_helper", DefUnit, 0, FieldSize, FieldAlign, @@ -1252,8 +1291,8 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, FieldOffset += FieldSize; } - unsigned Align = M->getContext().getDeclAlignInBytes(Decl); - if (Align > M->getContext().Target.getPointerAlign(0) / 8) { + unsigned Align = CGM.getContext().getDeclAlignInBytes(Decl); + if (Align > CGM.getContext().Target.getPointerAlign(0) / 8) { unsigned AlignedOffsetInBytes = llvm::RoundUpToAlignment(FieldOffset/8, Align); unsigned NumPaddingBytes @@ -1261,11 +1300,11 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, if (NumPaddingBytes > 0) { llvm::APInt pad(32, NumPaddingBytes); - FType = M->getContext().getConstantArrayType(M->getContext().CharTy, + FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy, pad, ArrayType::Normal, 0); FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); - FieldAlign = M->getContext().getTypeAlign(FType); + FieldSize = CGM.getContext().getTypeSize(FType); + FieldAlign = CGM.getContext().getTypeAlign(FType); FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, "", DefUnit, 0, FieldSize, FieldAlign, @@ -1277,7 +1316,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, FType = Type; FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = M->getContext().getTypeSize(FType); + FieldSize = CGM.getContext().getTypeSize(FType); FieldAlign = Align*8; XOffset = FieldOffset; @@ -1299,7 +1338,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, } // Get location information. - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); unsigned Line = 0; if (!PLoc.isInvalid()) @@ -1309,7 +1348,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, uint64_t offset = CGF->BlockDecls[Decl]; llvm::SmallVector<llvm::Value *, 9> addr; - llvm::LLVMContext &VMContext = M->getLLVMContext(); + llvm::LLVMContext &VMContext = CGM.getLLVMContext(); addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), llvm::DIFactory::OpDeref)); addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), @@ -1376,7 +1415,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, // Create global variable debug descriptor. llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation()); - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine(); @@ -1387,9 +1426,9 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, llvm::APSInt ConstVal(32); ConstVal = 1; - QualType ET = M->getContext().getAsArrayType(T)->getElementType(); + QualType ET = CGM.getContext().getAsArrayType(T)->getElementType(); - T = M->getContext().getConstantArrayType(ET, ConstVal, + T = CGM.getContext().getConstantArrayType(ET, ConstVal, ArrayType::Normal, 0); } llvm::StringRef DeclName = Decl->getName(); @@ -1405,22 +1444,22 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, ObjCInterfaceDecl *Decl) { // Create global variable debug descriptor. llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation()); - SourceManager &SM = M->getContext().getSourceManager(); + SourceManager &SM = CGM.getContext().getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine(); llvm::StringRef Name = Decl->getName(); - QualType T = M->getContext().getObjCInterfaceType(Decl); + QualType T = CGM.getContext().getObjCInterfaceType(Decl); if (T->isIncompleteArrayType()) { // CodeGen turns int[] into int[1] so we'll do the same here. llvm::APSInt ConstVal(32); ConstVal = 1; - QualType ET = M->getContext().getAsArrayType(T)->getElementType(); + QualType ET = CGM.getContext().getAsArrayType(T)->getElementType(); - T = M->getContext().getConstantArrayType(ET, ConstVal, + T = CGM.getContext().getConstantArrayType(ET, ConstVal, ArrayType::Normal, 0); } diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index af86e2b..7df2a62 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -40,7 +40,7 @@ namespace CodeGen { /// and is responsible for emitting to llvm globals or pass directly to /// the backend. class CGDebugInfo { - CodeGenModule *M; + CodeGenModule &CGM; bool isMainCompileUnitCreated; llvm::DIFactory DebugFactory; @@ -74,12 +74,13 @@ class CGDebugInfo { 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 CreateType(const MemberPointerType *Ty, llvm::DICompileUnit U); + llvm::DIType CreatePointerLikeType(unsigned Tag, const Type *Ty, QualType PointeeTy, llvm::DICompileUnit U); public: - CGDebugInfo(CodeGenModule *m); + CGDebugInfo(CodeGenModule &CGM); ~CGDebugInfo(); /// setLocation - Update the current source location. If \arg loc is @@ -92,7 +93,7 @@ public: /// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate /// start of a new function. - void EmitFunctionStart(const char *Name, QualType FnType, + void EmitFunctionStart(llvm::StringRef Name, QualType FnType, llvm::Function *Fn, CGBuilderTy &Builder); /// EmitRegionStart - Emit a call to llvm.dbg.region.start to indicate start diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index c047283..14ee90d 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -43,6 +43,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::Using: // using X; [C++] case Decl::UsingShadow: case Decl::UsingDirective: // using namespace X; [C++] + case Decl::StaticAssert: // static_assert(X, ""); [C++0x] // None of these decls require codegen support. return; @@ -85,28 +86,32 @@ void CodeGenFunction::EmitBlockVarDecl(const VarDecl &D) { assert(0 && "Unknown storage class"); } +static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D, + const char *Separator) { + CodeGenModule &CGM = CGF.CGM; + if (CGF.getContext().getLangOptions().CPlusPlus) + return CGM.getMangledName(&D); + + std::string ContextName; + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CGF.CurFuncDecl)) + ContextName = CGM.getMangledName(FD); + else if (isa<ObjCMethodDecl>(CGF.CurFuncDecl)) + ContextName = CGF.CurFn->getName(); + else + // FIXME: What about in a block?? + assert(0 && "Unknown context for block var decl"); + + return ContextName + Separator + D.getNameAsString(); +} + llvm::GlobalVariable * CodeGenFunction::CreateStaticBlockVarDecl(const VarDecl &D, const char *Separator, - llvm::GlobalValue::LinkageTypes - Linkage) { + llvm::GlobalValue::LinkageTypes Linkage) { QualType Ty = D.getType(); assert(Ty->isConstantSizeType() && "VLAs can't be static"); - std::string Name; - if (getContext().getLangOptions().CPlusPlus) { - Name = CGM.getMangledName(&D); - } else { - std::string ContextName; - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurFuncDecl)) - ContextName = CGM.getMangledName(FD); - else if (isa<ObjCMethodDecl>(CurFuncDecl)) - ContextName = CurFn->getName(); - else - assert(0 && "Unknown context for block var decl"); - - Name = ContextName + Separator + D.getNameAsString(); - } + std::string Name = GetStaticDeclName(*this, D, Separator); const llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty); llvm::GlobalVariable *GV = @@ -118,6 +123,54 @@ CodeGenFunction::CreateStaticBlockVarDecl(const VarDecl &D, return GV; } +/// AddInitializerToGlobalBlockVarDecl - Add the initializer for 'D' to the +/// global variable that has already been created for it. If the initializer +/// has a different type than GV does, this may free GV and return a different +/// one. Otherwise it just returns GV. +llvm::GlobalVariable * +CodeGenFunction::AddInitializerToGlobalBlockVarDecl(const VarDecl &D, + llvm::GlobalVariable *GV) { + llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(), D.getType(), this); + + // If constant emission failed, then this should be a C++ static + // initializer. + if (!Init) { + if (!getContext().getLangOptions().CPlusPlus) + CGM.ErrorUnsupported(D.getInit(), "constant l-value expression"); + else + EmitStaticCXXBlockVarDeclInit(D, GV); + return GV; + } + + // The initializer may differ in type from the global. Rewrite + // the global to match the initializer. (We have to do this + // because some types, like unions, can't be completely represented + // in the LLVM type system.) + if (GV->getType() != Init->getType()) { + llvm::GlobalVariable *OldGV = GV; + + GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), + OldGV->isConstant(), + OldGV->getLinkage(), Init, "", + 0, D.isThreadSpecified(), + D.getType().getAddressSpace()); + + // Steal the name of the old global + GV->takeName(OldGV); + + // Replace all uses of the old global with the new global + llvm::Constant *NewPtrForOldDecl = + llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); + OldGV->replaceAllUsesWith(NewPtrForOldDecl); + + // Erase the old global, since it is no longer used. + OldGV->eraseFromParent(); + } + + GV->setInitializer(Init); + return GV; +} + void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) { llvm::Value *&DMEntry = LocalDeclMap[&D]; assert(DMEntry == 0 && "Decl already exists in localdeclmap!"); @@ -135,45 +188,9 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) { if (D.getType()->isVariablyModifiedType()) EmitVLASize(D.getType()); - if (D.getInit()) { - llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(), D.getType(), this); - - // If constant emission failed, then this should be a C++ static - // initializer. - if (!Init) { - if (!getContext().getLangOptions().CPlusPlus) - CGM.ErrorUnsupported(D.getInit(), "constant l-value expression"); - else - EmitStaticCXXBlockVarDeclInit(D, GV); - } else { - // The initializer may differ in type from the global. Rewrite - // the global to match the initializer. (We have to do this - // because some types, like unions, can't be completely represented - // in the LLVM type system.) - if (GV->getType() != Init->getType()) { - llvm::GlobalVariable *OldGV = GV; - - GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), - OldGV->isConstant(), - OldGV->getLinkage(), Init, "", - 0, D.isThreadSpecified(), - D.getType().getAddressSpace()); - - // Steal the name of the old global - GV->takeName(OldGV); - - // Replace all uses of the old global with the new global - llvm::Constant *NewPtrForOldDecl = - llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); - OldGV->replaceAllUsesWith(NewPtrForOldDecl); - - // Erase the old global, since it is no longer used. - OldGV->eraseFromParent(); - } - - GV->setInitializer(Init); - } - } + // If this value has an initializer, emit it. + if (D.getInit()) + GV = AddInitializerToGlobalBlockVarDecl(D, GV); // FIXME: Merge attribute handling. if (const AnnotateAttr *AA = D.getAttr<AnnotateAttr>()) { @@ -317,32 +334,36 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { bool isByRef = D.hasAttr<BlocksAttr>(); bool needsDispose = false; unsigned Align = 0; + bool IsSimpleConstantInitializer = false; llvm::Value *DeclPtr; if (Ty->isConstantSizeType()) { if (!Target.useGlobalsForAutomaticVariables()) { - // All constant structs and arrays should be global if - // their initializer is constant and if the element type is POD. - if (CGM.getCodeGenOpts().MergeAllConstants) { - if (Ty.isConstant(getContext()) - && (Ty->isArrayType() || Ty->isRecordType()) - && (D.getInit() - && D.getInit()->isConstantInitializer(getContext())) - && Ty->isPODType()) { + // If this value is an array or struct, is POD, and if the initializer is + // a staticly determinable constant, try to optimize it. + if (D.getInit() && !isByRef && + (Ty->isArrayType() || Ty->isRecordType()) && + Ty->isPODType() && + D.getInit()->isConstantInitializer(getContext())) { + // If this variable is marked 'const', emit the value as a global. + if (CGM.getCodeGenOpts().MergeAllConstants && + Ty.isConstant(getContext())) { EmitStaticBlockVarDecl(D); return; } + + IsSimpleConstantInitializer = true; } // A normal fixed sized variable becomes an alloca in the entry block. const llvm::Type *LTy = ConvertTypeForMem(Ty); - Align = getContext().getDeclAlignInBytes(&D); if (isByRef) LTy = BuildByRefType(&D); llvm::AllocaInst *Alloc = CreateTempAlloca(LTy); - Alloc->setName(D.getNameAsString().c_str()); + Alloc->setName(D.getNameAsString()); + Align = getContext().getDeclAlignInBytes(&D); if (isByRef) Align = std::max(Align, unsigned(Target.getPointerAlign(0) / 8)); Alloc->setAlignment(Align); @@ -436,9 +457,48 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D), D.getNameAsString()); - bool isVolatile = (getContext().getCanonicalType(D.getType()) - .isVolatileQualified()); - if (Ty->isReferenceType()) { + bool isVolatile = + getContext().getCanonicalType(D.getType()).isVolatileQualified(); + + // If the initializer was a simple constant initializer, we can optimize it + // in various ways. + if (IsSimpleConstantInitializer) { + llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(),D.getType(),this); + assert(Init != 0 && "Wasn't a simple constant init?"); + + llvm::Value *AlignVal = + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Align); + const llvm::Type *IntPtr = + llvm::IntegerType::get(VMContext, LLVMPointerWidth); + llvm::Value *SizeVal = + llvm::ConstantInt::get(IntPtr, getContext().getTypeSizeInBytes(Ty)); + + const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext); + if (Loc->getType() != BP) + Loc = Builder.CreateBitCast(Loc, BP, "tmp"); + + // If the initializer is all zeros, codegen with memset. + if (isa<llvm::ConstantAggregateZero>(Init)) { + llvm::Value *Zero = + llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 0); + Builder.CreateCall4(CGM.getMemSetFn(), Loc, Zero, SizeVal, AlignVal); + } else { + // Otherwise, create a temporary global with the initializer then + // memcpy from the global to the alloca. + std::string Name = GetStaticDeclName(*this, D, "."); + llvm::GlobalVariable *GV = + new llvm::GlobalVariable(CGM.getModule(), Init->getType(), true, + llvm::GlobalValue::InternalLinkage, + Init, Name, 0, false, 0); + GV->setAlignment(Align); + + llvm::Value *SrcPtr = GV; + if (SrcPtr->getType() != BP) + SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp"); + + Builder.CreateCall4(CGM.getMemCpyFn(), Loc, SrcPtr, SizeVal, AlignVal); + } + } else if (Ty->isReferenceType()) { RValue RV = EmitReferenceBindingToExpr(Init, Ty, /*IsInitializer=*/true); EmitStoreOfScalar(RV.getScalarVal(), Loc, false, Ty); } else if (!hasAggregateLLVMType(Init->getType())) { @@ -521,19 +581,39 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { if (const ConstantArrayType *Array = getContext().getAsConstantArrayType(Ty)) { - DelayedCleanupBlock Scope(*this); - QualType BaseElementTy = getContext().getBaseElementType(Array); - const llvm::Type *BasePtr = ConvertType(BaseElementTy); - BasePtr = llvm::PointerType::getUnqual(BasePtr); - llvm::Value *BaseAddrPtr = - Builder.CreateBitCast(DeclPtr, BasePtr); - EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); + { + DelayedCleanupBlock Scope(*this); + QualType BaseElementTy = getContext().getBaseElementType(Array); + const llvm::Type *BasePtr = ConvertType(BaseElementTy); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + Builder.CreateBitCast(DeclPtr, BasePtr); + EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); - // Make sure to jump to the exit block. - EmitBranch(Scope.getCleanupExitBlock()); + // Make sure to jump to the exit block. + EmitBranch(Scope.getCleanupExitBlock()); + } + if (Exceptions) { + EHCleanupBlock Cleanup(*this); + QualType BaseElementTy = getContext().getBaseElementType(Array); + const llvm::Type *BasePtr = ConvertType(BaseElementTy); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + Builder.CreateBitCast(DeclPtr, BasePtr); + EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); + } } else { - DelayedCleanupBlock Scope(*this); - EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); + { + DelayedCleanupBlock Scope(*this); + EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); + + // Make sure to jump to the exit block. + EmitBranch(Scope.getCleanupExitBlock()); + } + if (Exceptions) { + EHCleanupBlock Cleanup(*this); + EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); + } } } } @@ -545,8 +625,6 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { llvm::Constant* F = CGM.GetAddrOfFunction(FD); assert(F && "Could not find function!"); - DelayedCleanupBlock scope(*this); - const CGFunctionInfo &Info = CGM.getTypes().getFunctionInfo(FD); // In some cases, the type of the function argument will be different from @@ -556,20 +634,40 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { // // To fix this we insert a bitcast here. QualType ArgTy = Info.arg_begin()->type; - DeclPtr = Builder.CreateBitCast(DeclPtr, ConvertType(ArgTy)); - - CallArgList Args; - Args.push_back(std::make_pair(RValue::get(DeclPtr), - getContext().getPointerType(D.getType()))); - - EmitCall(Info, F, Args); + { + DelayedCleanupBlock scope(*this); + + CallArgList Args; + Args.push_back(std::make_pair(RValue::get(Builder.CreateBitCast(DeclPtr, + ConvertType(ArgTy))), + getContext().getPointerType(D.getType()))); + EmitCall(Info, F, Args); + } + if (Exceptions) { + EHCleanupBlock Cleanup(*this); + + CallArgList Args; + Args.push_back(std::make_pair(RValue::get(Builder.CreateBitCast(DeclPtr, + ConvertType(ArgTy))), + getContext().getPointerType(D.getType()))); + EmitCall(Info, F, Args); + } } if (needsDispose && CGM.getLangOptions().getGCMode() != LangOptions::GCOnly) { - DelayedCleanupBlock scope(*this); - llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding"); - V = Builder.CreateLoad(V); - BuildBlockRelease(V); + { + DelayedCleanupBlock scope(*this); + llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding"); + V = Builder.CreateLoad(V); + BuildBlockRelease(V); + } + // FIXME: Turn this on and audit the codegen + if (0 && Exceptions) { + EHCleanupBlock Cleanup(*this); + llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding"); + V = Builder.CreateLoad(V); + BuildBlockRelease(V); + } } } @@ -591,10 +689,8 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) { const llvm::Type *LTy = ConvertTypeForMem(Ty); if (LTy->isSingleValueType()) { // TODO: Alignment - std::string Name = D.getNameAsString(); - Name += ".addr"; DeclPtr = CreateTempAlloca(LTy); - DeclPtr->setName(Name.c_str()); + DeclPtr->setName(D.getNameAsString() + llvm::StringRef(".addr")); // Store the initial value into the alloca. EmitStoreOfScalar(Arg, DeclPtr, CTy.isVolatileQualified(), Ty); diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp new file mode 100644 index 0000000..0b6ea5a --- /dev/null +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -0,0 +1,211 @@ +//===--- CGDeclCXX.cpp - Emit LLVM Code for C++ declarations --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with code generation of C++ declarations +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +using namespace clang; +using namespace CodeGen; + +static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D, + llvm::Constant *DeclPtr) { + assert(D.hasGlobalStorage() && "VarDecl must have global storage!"); + assert(!D.getType()->isReferenceType() && + "Should not call EmitDeclInit on a reference!"); + + CodeGenModule &CGM = CGF.CGM; + ASTContext &Context = CGF.getContext(); + + const Expr *Init = D.getInit(); + QualType T = D.getType(); + bool isVolatile = Context.getCanonicalType(T).isVolatileQualified(); + + if (!CGF.hasAggregateLLVMType(T)) { + llvm::Value *V = CGF.EmitScalarExpr(Init); + CGF.EmitStoreOfScalar(V, DeclPtr, isVolatile, T); + } else if (T->isAnyComplexType()) { + CGF.EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile); + } else { + CGF.EmitAggExpr(Init, DeclPtr, isVolatile); + + // Avoid generating destructor(s) for initialized objects. + if (!isa<CXXConstructExpr>(Init)) + return; + + const ConstantArrayType *Array = Context.getAsConstantArrayType(T); + if (Array) + T = Context.getBaseElementType(Array); + + const RecordType *RT = T->getAs<RecordType>(); + if (!RT) + return; + + CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + if (RD->hasTrivialDestructor()) + return; + + CXXDestructorDecl *Dtor = RD->getDestructor(Context); + + llvm::Constant *DtorFn; + if (Array) { + DtorFn = + CodeGenFunction(CGM).GenerateCXXAggrDestructorHelper(Dtor, + Array, + DeclPtr); + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + DeclPtr = llvm::Constant::getNullValue(Int8PtrTy); + } else + DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete); + + CGF.EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr); + } +} + +void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, + llvm::Constant *DeclPtr) { + + const Expr *Init = D.getInit(); + QualType T = D.getType(); + + if (!T->isReferenceType()) { + EmitDeclInit(*this, D, DeclPtr); + return; + } + + ErrorUnsupported(Init, "global variable that binds to a reference"); +} + +void +CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, + llvm::Constant *DeclPtr) { + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8Ty(VMContext)->getPointerTo(); + + std::vector<const llvm::Type *> Params; + Params.push_back(Int8PtrTy); + + // Get the destructor function type + const llvm::Type *DtorFnTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false); + DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy); + + Params.clear(); + Params.push_back(DtorFnTy); + Params.push_back(Int8PtrTy); + Params.push_back(Int8PtrTy); + + // Get the __cxa_atexit function type + // extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d ); + const llvm::FunctionType *AtExitFnTy = + llvm::FunctionType::get(ConvertType(getContext().IntTy), Params, false); + + llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy, + "__cxa_atexit"); + + llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy, + "__dso_handle"); + llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy), + llvm::ConstantExpr::getBitCast(DeclPtr, Int8PtrTy), + llvm::ConstantExpr::getBitCast(Handle, Int8PtrTy) }; + Builder.CreateCall(AtExitFn, &Args[0], llvm::array_endof(Args)); +} + +void +CodeGenModule::EmitCXXGlobalInitFunc() { + if (CXXGlobalInits.empty()) + return; + + const llvm::FunctionType *FTy + = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), + false); + + // Create our global initialization function. + // FIXME: Should this be tweakable by targets? + llvm::Function *Fn = + llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, + "__cxx_global_initialization", &TheModule); + + CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, + &CXXGlobalInits[0], + CXXGlobalInits.size()); + AddGlobalCtor(Fn); +} + +void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, + const VarDecl **Decls, + unsigned NumDecls) { + StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(), + SourceLocation()); + + for (unsigned i = 0; i != NumDecls; ++i) { + const VarDecl *D = Decls[i]; + + llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D); + EmitCXXGlobalVarDeclInit(*D, DeclPtr); + } + FinishFunction(); +} + +void +CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, + llvm::GlobalVariable *GV) { + // FIXME: This should use __cxa_guard_{acquire,release}? + + assert(!getContext().getLangOptions().ThreadsafeStatics && + "thread safe statics are currently not supported!"); + + llvm::SmallString<256> GuardVName; + CGM.getMangleContext().mangleGuardVariable(&D, GuardVName); + + // Create the guard variable. + llvm::GlobalValue *GuardV = + new llvm::GlobalVariable(CGM.getModule(), llvm::Type::getInt64Ty(VMContext), + false, GV->getLinkage(), + llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)), + GuardVName.str()); + + // Load the first byte of the guard variable. + const llvm::Type *PtrTy + = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); + llvm::Value *V = Builder.CreateLoad(Builder.CreateBitCast(GuardV, PtrTy), + "tmp"); + + // Compare it against 0. + llvm::Value *nullValue + = llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext)); + llvm::Value *ICmp = Builder.CreateICmpEQ(V, nullValue , "tobool"); + + llvm::BasicBlock *InitBlock = createBasicBlock("init"); + llvm::BasicBlock *EndBlock = createBasicBlock("init.end"); + + // If the guard variable is 0, jump to the initializer code. + Builder.CreateCondBr(ICmp, InitBlock, EndBlock); + + EmitBlock(InitBlock); + + if (D.getType()->isReferenceType()) { + QualType T = D.getType(); + // We don't want to pass true for IsInitializer here, because a static + // reference to a temporary does not extend its lifetime. + RValue RV = EmitReferenceBindingToExpr(D.getInit(), T, + /*IsInitializer=*/false); + EmitStoreOfScalar(RV.getScalarVal(), GV, /*Volatile=*/false, T); + + } else + EmitDeclInit(*this, D, GV); + + Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), + 1), + Builder.CreateBitCast(GuardV, PtrTy)); + + EmitBlock(EndBlock); +} diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 420e275..b15b2e9 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -23,58 +23,83 @@ static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) { // void *__cxa_allocate_exception(size_t thrown_size); const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); std::vector<const llvm::Type*> Args(1, SizeTy); - - const llvm::FunctionType *FTy = + + const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getInt8PtrTy(CGF.getLLVMContext()), Args, false); - + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception"); } +static llvm::Constant *getFreeExceptionFn(CodeGenFunction &CGF) { + // void __cxa_free_exception(void *thrown_exception); + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + std::vector<const llvm::Type*> Args(1, Int8PtrTy); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), + Args, false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception"); +} + static llvm::Constant *getThrowFn(CodeGenFunction &CGF) { - // void __cxa_throw (void *thrown_exception, std::type_info *tinfo, - // void (*dest) (void *) ); + // void __cxa_throw(void *thrown_exception, std::type_info *tinfo, + // void (*dest) (void *)); const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); std::vector<const llvm::Type*> Args(3, Int8PtrTy); - - const llvm::FunctionType *FTy = + + const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args, false); - + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw"); } static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) { - // void __cxa_rethrow (); + // void __cxa_rethrow(); - const llvm::FunctionType *FTy = + const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); - + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow"); } static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) { - // void* __cxa_begin_catch (); + // void* __cxa_begin_catch(); const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); std::vector<const llvm::Type*> Args(1, Int8PtrTy); - - const llvm::FunctionType *FTy = + + const llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args, false); - + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch"); } static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) { - // void __cxa_end_catch (); + // void __cxa_end_catch(); - const llvm::FunctionType *FTy = + const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); - + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch"); } +static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) { + // void __cxa_call_unexepcted(void *thrown_exception); + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + std::vector<const llvm::Type*> Args(1, Int8PtrTy); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), + Args, false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected"); +} + // FIXME: Eventually this will all go into the backend. Set from the target for // now. static int using_sjlj_exceptions = 0; @@ -82,38 +107,64 @@ static int using_sjlj_exceptions = 0; static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) { const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); std::vector<const llvm::Type*> Args(1, Int8PtrTy); - - const llvm::FunctionType *FTy = + + const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args, false); - + if (using_sjlj_exceptions) return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume"); return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow"); } +static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) { + // void __terminate(); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "_ZSt9terminatev"); +} + // CopyObject - Utility to copy an object. Calls copy constructor as necessary. -// N is casted to the right type. -static void CopyObject(CodeGenFunction &CGF, const Expr *E, llvm::Value *N) { +// DestPtr is casted to the right type. +static void CopyObject(CodeGenFunction &CGF, const Expr *E, + llvm::Value *DestPtr, llvm::Value *ExceptionPtrPtr) { QualType ObjectType = E->getType(); // Store the throw exception in the exception object. if (!CGF.hasAggregateLLVMType(ObjectType)) { llvm::Value *Value = CGF.EmitScalarExpr(E); - const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); - - CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy)); + const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(); + + CGF.Builder.CreateStore(Value, + CGF.Builder.CreateBitCast(DestPtr, ValuePtrTy)); } else { - const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0); - const CXXRecordDecl *RD; - RD = cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl()); - llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty); + const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(); + const CXXRecordDecl *RD = + cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl()); + + llvm::Value *This = CGF.Builder.CreateBitCast(DestPtr, Ty); if (RD->hasTrivialCopyConstructor()) { CGF.EmitAggExpr(E, This, false); } else if (CXXConstructorDecl *CopyCtor = RD->getCopyConstructor(CGF.getContext(), 0)) { - // FIXME: region management + llvm::BasicBlock *PrevLandingPad = CGF.getInvokeDest(); + if (CGF.Exceptions) { + CodeGenFunction::EHCleanupBlock Cleanup(CGF); + llvm::Constant *FreeExceptionFn = getFreeExceptionFn(CGF); + + // Load the exception pointer. + llvm::Value *ExceptionPtr = CGF.Builder.CreateLoad(ExceptionPtrPtr); + CGF.Builder.CreateCall(FreeExceptionFn, ExceptionPtr); + } + llvm::Value *Src = CGF.EmitLValue(E).getAddress(); + CGF.setInvokeDest(PrevLandingPad); + + llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler(); + PrevLandingPad = CGF.getInvokeDest(); + CGF.setInvokeDest(TerminateHandler); // Stolen from EmitClassAggrMemberwiseCopy llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, @@ -129,21 +180,22 @@ static void CopyObject(CodeGenFunction &CGF, const Expr *E, llvm::Value *N) { CopyCtor->getType()->getAs<FunctionType>()->getResultType(); CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), Callee, CallArgs, CopyCtor); - // FIXME: region management + CGF.setInvokeDest(PrevLandingPad); } else - CGF.ErrorUnsupported(E, "uncopyable object"); + llvm_unreachable("uncopyable object"); } } // CopyObject - Utility to copy an object. Calls copy constructor as necessary. // N is casted to the right type. static void CopyObject(CodeGenFunction &CGF, QualType ObjectType, - llvm::Value *E, llvm::Value *N) { + bool WasPointer, llvm::Value *E, llvm::Value *N) { // Store the throw exception in the exception object. - if (!CGF.hasAggregateLLVMType(ObjectType)) { + if (WasPointer || !CGF.hasAggregateLLVMType(ObjectType)) { llvm::Value *Value = E; + if (!WasPointer) + Value = CGF.Builder.CreateLoad(Value); const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); - CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy)); } else { const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0); @@ -154,7 +206,6 @@ static void CopyObject(CodeGenFunction &CGF, QualType ObjectType, CGF.EmitAggregateCopy(This, E, ObjectType); } else if (CXXConstructorDecl *CopyCtor = RD->getCopyConstructor(CGF.getContext(), 0)) { - // FIXME: region management llvm::Value *Src = E; // Stolen from EmitClassAggrMemberwiseCopy @@ -171,66 +222,181 @@ static void CopyObject(CodeGenFunction &CGF, QualType ObjectType, CopyCtor->getType()->getAs<FunctionType>()->getResultType(); CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), Callee, CallArgs, CopyCtor); - // FIXME: region management } else - llvm::llvm_unreachable("uncopyable object"); + llvm_unreachable("uncopyable object"); } } void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { if (!E->getSubExpr()) { - Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn(); + if (getInvokeDest()) { + llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); + Builder.CreateInvoke(getReThrowFn(*this), Cont, getInvokeDest()) + ->setDoesNotReturn(); + EmitBlock(Cont); + } else + Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn(); Builder.CreateUnreachable(); // Clear the insertion point to indicate we are in unreachable code. Builder.ClearInsertionPoint(); return; } - + QualType ThrowType = E->getSubExpr()->getType(); - // FIXME: Handle cleanup. - if (!CleanupEntries.empty()){ - ErrorUnsupported(E, "throw expression with cleanup entries"); - return; - } - + // Now allocate the exception object. const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); uint64_t TypeSize = getContext().getTypeSize(ThrowType) / 8; - + llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this); - llvm::Value *ExceptionPtr = - Builder.CreateCall(AllocExceptionFn, + llvm::Value *ExceptionPtr = + Builder.CreateCall(AllocExceptionFn, llvm::ConstantInt::get(SizeTy, TypeSize), "exception"); - - CopyObject(*this, E->getSubExpr(), ExceptionPtr); + llvm::Value *ExceptionPtrPtr = + CreateTempAlloca(ExceptionPtr->getType(), "exception.ptr"); + Builder.CreateStore(ExceptionPtr, ExceptionPtrPtr); + + + CopyObject(*this, E->getSubExpr(), ExceptionPtr, ExceptionPtrPtr); + // Now throw the exception. const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); - llvm::Constant *TypeInfo = CGM.GenerateRtti(ThrowType); + llvm::Constant *TypeInfo = CGM.GenerateRTTI(ThrowType); llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy); - - llvm::CallInst *ThrowCall = - Builder.CreateCall3(getThrowFn(*this), ExceptionPtr, TypeInfo, Dtor); - ThrowCall->setDoesNotReturn(); + + if (getInvokeDest()) { + llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); + llvm::InvokeInst *ThrowCall = + Builder.CreateInvoke3(getThrowFn(*this), Cont, getInvokeDest(), + ExceptionPtr, TypeInfo, Dtor); + ThrowCall->setDoesNotReturn(); + EmitBlock(Cont); + } else { + llvm::CallInst *ThrowCall = + Builder.CreateCall3(getThrowFn(*this), ExceptionPtr, TypeInfo, Dtor); + ThrowCall->setDoesNotReturn(); + } Builder.CreateUnreachable(); - + // Clear the insertion point to indicate we are in unreachable code. Builder.ClearInsertionPoint(); + + // FIXME: For now, emit a dummy basic block because expr emitters in generally + // are not ready to handle emitting expressions at unreachable points. + EnsureInsertPoint(); } -void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { -#if 1 - EmitStmt(S.getTryBlock()); - if (0) { - getBeginCatchFn(*this); - getEndCatchFn(*this); - getUnwindResumeOrRethrowFn(*this); - CopyObject(*this, QualType(), 0, 0); +void CodeGenFunction::EmitStartEHSpec(const Decl *D) { + const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D); + if (FD == 0) + return; + const FunctionProtoType *Proto = FD->getType()->getAs<FunctionProtoType>(); + if (Proto == 0) + return; + + assert(!Proto->hasAnyExceptionSpec() && "function with parameter pack"); + + if (!Proto->hasExceptionSpec()) + return; + + llvm::Constant *Personality = + CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty + (VMContext), + true), + "__gxx_personality_v0"); + Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); + llvm::Value *llvm_eh_exception = + CGM.getIntrinsic(llvm::Intrinsic::eh_exception); + llvm::Value *llvm_eh_selector = + CGM.getIntrinsic(llvm::Intrinsic::eh_selector); + const llvm::IntegerType *Int8Ty; + const llvm::PointerType *PtrToInt8Ty; + Int8Ty = llvm::Type::getInt8Ty(VMContext); + // C string type. Used in lots of places. + PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); + llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); + llvm::SmallVector<llvm::Value*, 8> SelectorArgs; + + llvm::BasicBlock *PrevLandingPad = getInvokeDest(); + llvm::BasicBlock *EHSpecHandler = createBasicBlock("ehspec.handler"); + llvm::BasicBlock *Match = createBasicBlock("match"); + llvm::BasicBlock *Unwind = 0; + + assert(PrevLandingPad == 0 && "EHSpec has invoke context"); + (void)PrevLandingPad; + + llvm::BasicBlock *Cont = createBasicBlock("cont"); + + EmitBranchThroughCleanup(Cont); + + // Emit the statements in the try {} block + setInvokeDest(EHSpecHandler); + + EmitBlock(EHSpecHandler); + // Exception object + llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); + llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow"); + + SelectorArgs.push_back(Exc); + SelectorArgs.push_back(Personality); + SelectorArgs.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + Proto->getNumExceptions()+1)); + + for (unsigned i = 0; i < Proto->getNumExceptions(); ++i) { + QualType Ty = Proto->getExceptionType(i); + llvm::Value *EHType + = CGM.GenerateRTTI(Ty.getNonReferenceType()); + SelectorArgs.push_back(EHType); } -#else - // FIXME: The below is still just a sketch of the code we need. + if (Proto->getNumExceptions()) + SelectorArgs.push_back(Null); + + // Find which handler was matched. + llvm::Value *Selector + = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(), + SelectorArgs.end(), "selector"); + if (Proto->getNumExceptions()) { + Unwind = createBasicBlock("Unwind"); + + Builder.CreateStore(Exc, RethrowPtr); + Builder.CreateCondBr(Builder.CreateICmpSLT(Selector, + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + 0)), + Match, Unwind); + + EmitBlock(Match); + } + Builder.CreateCall(getUnexpectedFn(*this), Exc)->setDoesNotReturn(); + Builder.CreateUnreachable(); + + if (Proto->getNumExceptions()) { + EmitBlock(Unwind); + Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), + Builder.CreateLoad(RethrowPtr)); + Builder.CreateUnreachable(); + } + + EmitBlock(Cont); +} + +void CodeGenFunction::EmitEndEHSpec(const Decl *D) { + const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D); + if (FD == 0) + return; + const FunctionProtoType *Proto = FD->getType()->getAs<FunctionProtoType>(); + if (Proto == 0) + return; + + if (!Proto->hasExceptionSpec()) + return; + + setInvokeDest(0); +} + +void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { // Pointer to the personality function llvm::Constant *Personality = CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty @@ -238,31 +404,66 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { true), "__gxx_personality_v0"); Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); + llvm::Value *llvm_eh_exception = + CGM.getIntrinsic(llvm::Intrinsic::eh_exception); + llvm::Value *llvm_eh_selector = + CGM.getIntrinsic(llvm::Intrinsic::eh_selector); llvm::BasicBlock *PrevLandingPad = getInvokeDest(); llvm::BasicBlock *TryHandler = createBasicBlock("try.handler"); -#if 0 llvm::BasicBlock *FinallyBlock = createBasicBlock("finally"); -#endif llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw"); llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end"); -#if 0 // Push an EH context entry, used for handling rethrows. PushCleanupBlock(FinallyBlock); -#endif // Emit the statements in the try {} block setInvokeDest(TryHandler); - EmitStmt(S.getTryBlock()); + // FIXME: We should not have to do this here. The AST should have the member + // initializers under the CXXTryStmt's TryBlock. + if (OuterTryBlock == &S) { + GlobalDecl GD = CurGD; + const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); + + if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) { + size_t OldCleanupStackSize = CleanupEntries.size(); + EmitCtorPrologue(CD, CurGD.getCtorType()); + EmitStmt(S.getTryBlock()); + + // If any of the member initializers are temporaries bound to references + // make sure to emit their destructors. + EmitCleanupBlocks(OldCleanupStackSize); + } else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) { + llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue"); + PushCleanupBlock(DtorEpilogue); + + EmitStmt(S.getTryBlock()); + + CleanupBlockInfo Info = PopCleanupBlock(); + + assert(Info.CleanupBlock == DtorEpilogue && "Block mismatch!"); + EmitBlock(DtorEpilogue); + EmitDtorEpilogue(DD, GD.getDtorType()); + + if (Info.SwitchBlock) + EmitBlock(Info.SwitchBlock); + if (Info.EndBlock) + EmitBlock(Info.EndBlock); + } else + EmitStmt(S.getTryBlock()); + } else + EmitStmt(S.getTryBlock()); // Jump to end if there is no exception EmitBranchThroughCleanup(FinallyEnd); + llvm::BasicBlock *TerminateHandler = getTerminateHandler(); + // Emit the handlers EmitBlock(TryHandler); - + const llvm::IntegerType *Int8Ty; const llvm::PointerType *PtrToInt8Ty; Int8Ty = llvm::Type::getInt8Ty(VMContext); @@ -270,16 +471,14 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); llvm::SmallVector<llvm::Value*, 8> SelectorArgs; - llvm::Value *llvm_eh_exception = - CGM.getIntrinsic(llvm::Intrinsic::eh_exception); - llvm::Value *llvm_eh_selector = - CGM.getIntrinsic(llvm::Intrinsic::eh_selector); llvm::Value *llvm_eh_typeid_for = CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for); // Exception object llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow"); + llvm::SmallVector<llvm::Value*, 8> Args; + Args.clear(); SelectorArgs.push_back(Exc); SelectorArgs.push_back(Personality); @@ -288,7 +487,8 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { const CXXCatchStmt *C = S.getHandler(i); VarDecl *CatchParam = C->getExceptionDecl(); if (CatchParam) { - llvm::Value *EHType = CGM.GenerateRtti(C->getCaughtType().getNonReferenceType()); + llvm::Value *EHType + = CGM.GenerateRTTI(C->getCaughtType().getNonReferenceType()); SelectorArgs.push_back(EHType); } else { // null indicates catch all @@ -334,27 +534,31 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { llvm::Value *ExcObject = Builder.CreateCall(getBeginCatchFn(*this), Exc); - // Bind the catch parameter if it exists. - if (CatchParam) { - QualType CatchType = CatchParam->getType().getNonReferenceType(); - if (!CatchType.getTypePtr()->isPointerType()) - CatchType = getContext().getPointerType(CatchType); - ExcObject = - Builder.CreateBitCast(ExcObject, ConvertType(CatchType)); - // CatchParam is a ParmVarDecl because of the grammar - // construction used to handle this, but for codegen purposes - // we treat this as a local decl. - EmitLocalBlockVarDecl(*CatchParam); -#if 0 - // FIXME: objects with ctors, references - Builder.CreateStore(ExcObject, GetAddrOfLocalVar(CatchParam)); -#else - CopyObject(*this, CatchParam->getType().getNonReferenceType(), - ExcObject, GetAddrOfLocalVar(CatchParam)); -#endif + { + CleanupScope CatchScope(*this); + // Bind the catch parameter if it exists. + if (CatchParam) { + QualType CatchType = CatchParam->getType().getNonReferenceType(); + setInvokeDest(TerminateHandler); + bool WasPointer = true; + if (!CatchType.getTypePtr()->isPointerType()) { + if (!isa<ReferenceType>(CatchParam->getType())) + WasPointer = false; + CatchType = getContext().getPointerType(CatchType); + } + ExcObject = Builder.CreateBitCast(ExcObject, ConvertType(CatchType)); + EmitLocalBlockVarDecl(*CatchParam); + // FIXME: we need to do this sooner so that the EH region for the + // cleanup doesn't start until after the ctor completes, use a decl + // init? + CopyObject(*this, CatchParam->getType().getNonReferenceType(), + WasPointer, ExcObject, GetAddrOfLocalVar(CatchParam)); + setInvokeDest(MatchHandler); + } + + EmitStmt(CatchBody); } - EmitStmt(CatchBody); EmitBranchThroughCleanup(FinallyEnd); EmitBlock(MatchHandler); @@ -362,7 +566,7 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); // We are required to emit this call to satisfy LLVM, even // though we don't use the result. - llvm::SmallVector<llvm::Value*, 8> Args; + Args.clear(); Args.push_back(Exc); Args.push_back(Personality); Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), @@ -375,45 +579,32 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { EmitBlock(MatchEnd); - // Unfortunately, we also have to generate another EH frame here - // in case this throws. - llvm::BasicBlock *MatchEndHandler = - createBasicBlock("match.end.handler"); - llvm::BasicBlock *Cont = createBasicBlock("myinvoke.cont"); + llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); Builder.CreateInvoke(getEndCatchFn(*this), - Cont, MatchEndHandler, + Cont, TerminateHandler, Args.begin(), Args.begin()); - EmitBlock(Cont); if (Info.SwitchBlock) EmitBlock(Info.SwitchBlock); if (Info.EndBlock) EmitBlock(Info.EndBlock); - EmitBlock(MatchEndHandler); Exc = Builder.CreateCall(llvm_eh_exception, "exc"); - // We are required to emit this call to satisfy LLVM, even - // though we don't use the result. - Args.clear(); - Args.push_back(Exc); - Args.push_back(Personality); - Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), - 0)); - Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); Builder.CreateStore(Exc, RethrowPtr); EmitBranchThroughCleanup(FinallyRethrow); if (Next) EmitBlock(Next); } - if (!HasCatchAll) + if (!HasCatchAll) { + Builder.CreateStore(Exc, RethrowPtr); EmitBranchThroughCleanup(FinallyRethrow); + } CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); setInvokeDest(PrevLandingPad); -#if 0 EmitBlock(FinallyBlock); if (Info.SwitchBlock) @@ -423,13 +614,122 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { // Branch around the rethrow code. EmitBranch(FinallyEnd); -#endif EmitBlock(FinallyRethrow); - Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), - Builder.CreateLoad(RethrowPtr)); + // FIXME: Eventually we can chain the handlers together and just do a call + // here. + if (getInvokeDest()) { + llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); + Builder.CreateInvoke(getUnwindResumeOrRethrowFn(*this), Cont, + getInvokeDest(), + Builder.CreateLoad(RethrowPtr)); + EmitBlock(Cont); + } else + Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), + Builder.CreateLoad(RethrowPtr)); + Builder.CreateUnreachable(); EmitBlock(FinallyEnd); -#endif +} + +CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() { + llvm::BasicBlock *Cont1 = CGF.createBasicBlock("cont"); + CGF.EmitBranch(Cont1); + CGF.setInvokeDest(PreviousInvokeDest); + + + CGF.EmitBlock(CleanupHandler); + + llvm::Constant *Personality = + CGF.CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty + (CGF.VMContext), + true), + "__gxx_personality_v0"); + Personality = llvm::ConstantExpr::getBitCast(Personality, CGF.PtrToInt8Ty); + llvm::Value *llvm_eh_exception = + CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception); + llvm::Value *llvm_eh_selector = + CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector); + + llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc"); + const llvm::IntegerType *Int8Ty; + const llvm::PointerType *PtrToInt8Ty; + Int8Ty = llvm::Type::getInt8Ty(CGF.VMContext); + // C string type. Used in lots of places. + PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); + llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); + llvm::SmallVector<llvm::Value*, 8> Args; + Args.clear(); + Args.push_back(Exc); + Args.push_back(Personality); + Args.push_back(Null); + CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); + + CGF.EmitBlock(CleanupEntryBB); + + CGF.EmitBlock(Cont1); + + if (CGF.getInvokeDest()) { + llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont"); + CGF.Builder.CreateInvoke(getUnwindResumeOrRethrowFn(CGF), Cont, + CGF.getInvokeDest(), Exc); + CGF.EmitBlock(Cont); + } else + CGF.Builder.CreateCall(getUnwindResumeOrRethrowFn(CGF), Exc); + + CGF.Builder.CreateUnreachable(); + + CGF.EmitBlock(Cont); + if (CGF.Exceptions) + CGF.setInvokeDest(CleanupHandler); +} + +llvm::BasicBlock *CodeGenFunction::getTerminateHandler() { + if (TerminateHandler) + return TerminateHandler; + + llvm::BasicBlock *Cont = 0; + + if (HaveInsertPoint()) { + Cont = createBasicBlock("cont"); + EmitBranch(Cont); + } + + llvm::Constant *Personality = + CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty + (VMContext), + true), + "__gxx_personality_v0"); + Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); + llvm::Value *llvm_eh_exception = + CGM.getIntrinsic(llvm::Intrinsic::eh_exception); + llvm::Value *llvm_eh_selector = + CGM.getIntrinsic(llvm::Intrinsic::eh_selector); + + // Set up terminate handler + TerminateHandler = createBasicBlock("terminate.handler"); + EmitBlock(TerminateHandler); + llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); + // We are required to emit this call to satisfy LLVM, even + // though we don't use the result. + llvm::SmallVector<llvm::Value*, 8> Args; + Args.push_back(Exc); + Args.push_back(Personality); + Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + 1)); + Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); + llvm::CallInst *TerminateCall = + Builder.CreateCall(getTerminateFn(*this)); + TerminateCall->setDoesNotReturn(); + TerminateCall->setDoesNotThrow(); + Builder.CreateUnreachable(); + + // Clear the insertion point to indicate we are in unreachable code. + Builder.ClearInsertionPoint(); + + if (Cont) + EmitBlock(Cont); + + return TerminateHandler; } diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 63fca2d..e6bbfa8 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -17,6 +17,8 @@ #include "CGObjCRuntime.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" +#include "llvm/Intrinsics.h" +#include "clang/CodeGen/CodeGenOptions.h" #include "llvm/Target/TargetData.h" using namespace clang; using namespace CodeGen; @@ -38,6 +40,21 @@ llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(const llvm::Type *Ty, /// expression and compare the result against zero, returning an Int1Ty value. llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) { QualType BoolTy = getContext().BoolTy; + if (E->getType()->isMemberFunctionPointerType()) { + llvm::Value *Ptr = CreateTempAlloca(ConvertType(E->getType())); + EmitAggExpr(E, Ptr, /*VolatileDest=*/false); + + // Get the pointer. + llvm::Value *FuncPtr = Builder.CreateStructGEP(Ptr, 0, "src.ptr"); + FuncPtr = Builder.CreateLoad(FuncPtr); + + llvm::Value *IsNotNull = + Builder.CreateICmpNE(FuncPtr, + llvm::Constant::getNullValue(FuncPtr->getType()), + "tobool"); + + return IsNotNull; + } if (!E->getType()->isAnyComplexType()) return EmitScalarConversion(EmitScalarExpr(E), E->getType(), BoolTy); @@ -137,8 +154,19 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, const CXXDestructorDecl *Dtor = ClassDecl->getDestructor(getContext()); - DelayedCleanupBlock scope(*this); - EmitCXXDestructorCall(Dtor, Dtor_Complete, Val.getAggregateAddr()); + { + DelayedCleanupBlock Scope(*this); + EmitCXXDestructorCall(Dtor, Dtor_Complete, + Val.getAggregateAddr()); + + // Make sure to jump to the exit block. + EmitBranch(Scope.getCleanupExitBlock()); + } + if (Exceptions) { + EHCleanupBlock Cleanup(*this); + EmitCXXDestructorCall(Dtor, Dtor_Complete, + Val.getAggregateAddr()); + } } } } @@ -237,6 +265,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { switch (E->getStmtClass()) { default: return EmitUnsupportedLValue(E, "l-value expression"); + case Expr::ObjCIsaExprClass: + return EmitObjCIsaExpr(cast<ObjCIsaExpr>(E)); case Expr::BinaryOperatorClass: return EmitBinaryOperatorLValue(cast<BinaryOperator>(E)); case Expr::CallExprClass: @@ -330,13 +360,8 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr, if (Ty->isBooleanType()) { // Bool can have different representation in memory than in registers. - const llvm::Type *SrcTy = Value->getType(); const llvm::PointerType *DstPtr = cast<llvm::PointerType>(Addr->getType()); - if (DstPtr->getElementType() != SrcTy) { - const llvm::Type *MemTy = - llvm::PointerType::get(SrcTy, DstPtr->getAddressSpace()); - Addr = Builder.CreateBitCast(Addr, MemTy, "storetmp"); - } + Value = Builder.CreateIntCast(Value, DstPtr->getElementType(), false); } Builder.CreateStore(Value, Addr, Volatile); } @@ -408,8 +433,7 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV, // Shift to proper location. if (StartBit) - Val = Builder.CreateLShr(Val, llvm::ConstantInt::get(EltTy, StartBit), - "bf.lo"); + Val = Builder.CreateLShr(Val, StartBit, "bf.lo"); // Mask off unused bits. llvm::Constant *LowMask = llvm::ConstantInt::get(VMContext, @@ -431,8 +455,7 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV, HighVal = Builder.CreateAnd(HighVal, HighMask, "bf.lo.cleared"); // Shift to proper location and or in to bitfield value. - HighVal = Builder.CreateShl(HighVal, - llvm::ConstantInt::get(EltTy, LowBits)); + HighVal = Builder.CreateShl(HighVal, LowBits); Val = Builder.CreateOr(Val, HighVal, "bf.val"); } @@ -618,8 +641,7 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, // LowVal = (LowVal & InvMask) | (NewVal << StartBit), // with the shift of NewVal implicitly stripping the high bits. llvm::Value *NewLowVal = - Builder.CreateShl(NewVal, llvm::ConstantInt::get(EltTy, StartBit), - "bf.value.lo"); + Builder.CreateShl(NewVal, StartBit, "bf.value.lo"); LowVal = Builder.CreateAnd(LowVal, InvMask, "bf.prev.lo.cleared"); LowVal = Builder.CreateOr(LowVal, NewLowVal, "bf.new.lo"); @@ -645,8 +667,7 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, // where the high bits of NewVal have already been cleared and the // shift stripping the low bits. llvm::Value *NewHighVal = - Builder.CreateLShr(NewVal, llvm::ConstantInt::get(EltTy, LowBits), - "bf.value.high"); + Builder.CreateLShr(NewVal, LowBits, "bf.value.high"); HighVal = Builder.CreateAnd(HighVal, InvMask, "bf.prev.hi.cleared"); HighVal = Builder.CreateOr(HighVal, NewHighVal, "bf.new.hi"); @@ -993,6 +1014,36 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) { } } +llvm::BasicBlock *CodeGenFunction::getTrapBB() { + const CodeGenOptions &GCO = CGM.getCodeGenOpts(); + + // If we are not optimzing, don't collapse all calls to trap in the function + // to the same call, that way, in the debugger they can see which operation + // did in fact fail. If we are optimizing, we collpase all call to trap down + // to just one per function to save on codesize. + if (GCO.OptimizationLevel + && TrapBB) + return TrapBB; + + llvm::BasicBlock *Cont = 0; + if (HaveInsertPoint()) { + Cont = createBasicBlock("cont"); + EmitBranch(Cont); + } + TrapBB = createBasicBlock("trap"); + EmitBlock(TrapBB); + + llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::trap, 0, 0); + llvm::CallInst *TrapCall = Builder.CreateCall(F); + TrapCall->setDoesNotReturn(); + TrapCall->setDoesNotThrow(); + Builder.CreateUnreachable(); + + if (Cont) + EmitBlock(Cont); + return TrapBB; +} + LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { // The index must always be an integer, which is not an aggregate. Emit it. llvm::Value *Idx = EmitScalarExpr(E->getIdx()); @@ -1021,6 +1072,24 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { llvm::IntegerType::get(VMContext, LLVMPointerWidth), IdxSigned, "idxprom"); + if (CatchUndefined) { + if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E->getBase())) { + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr())) { + if (ICE->getCastKind() == CastExpr::CK_ArrayToPointerDecay) { + if (const ConstantArrayType *CAT + = getContext().getAsConstantArrayType(DRE->getType())) { + llvm::APInt Size = CAT->getSize(); + llvm::BasicBlock *Cont = createBasicBlock("cont"); + Builder.CreateCondBr(Builder.CreateICmpULE(Idx, + llvm::ConstantInt::get(Idx->getType(), Size)), + Cont, getTrapBB()); + EmitBlock(Cont); + } + } + } + } + } + // We know that the pointer points to a type of the correct size, unless the // size is a VLA or Objective-C interface. llvm::Value *Address = 0; @@ -1417,7 +1486,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E) { if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(TargetDecl)) return EmitCXXOperatorMemberCallExpr(CE, MD); - if (isa<CXXPseudoDestructorExpr>(E->getCallee())) { + if (isa<CXXPseudoDestructorExpr>(E->getCallee()->IgnoreParens())) { // C++ [expr.pseudo]p1: // The result shall only be used as the operand for the function call // operator (), and the result of such a call has type void. The only @@ -1436,6 +1505,7 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { // Comma expressions just emit their LHS then their RHS as an l-value. if (E->getOpcode() == BinaryOperator::Comma) { EmitAnyExpr(E->getLHS()); + EnsureInsertPoint(); return EmitLValue(E->getRHS()); } diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index d225d90..2c122eb 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -120,7 +120,7 @@ public: void EmitInitializationToLValue(Expr *E, LValue Address); void EmitNullInitializationToLValue(LValue Address, QualType T); // case Expr::ChooseExprClass: - + void VisitCXXThrowExpr(const CXXThrowExpr *E) { CGF.EmitCXXThrowExpr(E); } }; } // end anonymous namespace. @@ -502,21 +502,16 @@ void AggExprEmitter::EmitNullInitializationToLValue(LValue LV, QualType T) { void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { #if 0 - // FIXME: Disabled while we figure out what to do about - // test/CodeGen/bitfield.c + // FIXME: Assess perf here? Figure out what cases are worth optimizing here + // (Length of globals? Chunks of zeroed-out space?). // // If we can, prefer a copy from a global; this is a lot less code for long // globals, and it's easier for the current optimizers to analyze. - // FIXME: Should we really be doing this? Should we try to avoid cases where - // we emit a global with a lot of zeros? Should we try to avoid short - // globals? - if (E->isConstantInitializer(CGF.getContext(), 0)) { - llvm::Constant* C = CGF.CGM.EmitConstantExpr(E, &CGF); + if (llvm::Constant* C = CGF.CGM.EmitConstantExpr(E, E->getType(), &CGF)) { llvm::GlobalVariable* GV = - new llvm::GlobalVariable(C->getType(), true, - llvm::GlobalValue::InternalLinkage, - C, "", &CGF.CGM.getModule(), 0); - EmitFinalDestCopy(E, LValue::MakeAddr(GV, 0)); + new llvm::GlobalVariable(CGF.CGM.getModule(), C->getType(), true, + llvm::GlobalValue::InternalLinkage, C, ""); + EmitFinalDestCopy(E, LValue::MakeAddr(GV, Qualifiers())); return; } #endif diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index b982c15..150f11e 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -15,13 +15,8 @@ using namespace clang; using namespace CodeGen; -static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) { - if (!E->isArray()) - return 0; - - QualType T = E->getAllocatedType(); - - const RecordType *RT = T->getAs<RecordType>(); +static uint64_t CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) { + const RecordType *RT = ElementType->getAs<RecordType>(); if (!RT) return 0; @@ -31,13 +26,59 @@ static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) { // Check if the class has a trivial destructor. if (RD->hasTrivialDestructor()) { - // FIXME: Check for a two-argument delete. - return 0; - } + // Check if the usual deallocation function takes two arguments. + const CXXMethodDecl *UsualDeallocationFunction = 0; + + DeclarationName OpName = + Ctx.DeclarationNames.getCXXOperatorName(OO_Array_Delete); + DeclContext::lookup_const_iterator Op, OpEnd; + for (llvm::tie(Op, OpEnd) = RD->lookup(OpName); + Op != OpEnd; ++Op) { + const CXXMethodDecl *Delete = cast<CXXMethodDecl>(*Op); + + if (Delete->isUsualDeallocationFunction()) { + UsualDeallocationFunction = Delete; + break; + } + } + + // No usual deallocation function, we don't need a cookie. + if (!UsualDeallocationFunction) + return 0; + + // The usual deallocation function doesn't take a size_t argument, so we + // don't need a cookie. + if (UsualDeallocationFunction->getNumParams() == 1) + return 0; + + assert(UsualDeallocationFunction->getNumParams() == 2 && + "Unexpected deallocation function type!"); + } - // Padding is the maximum of sizeof(size_t) and alignof(T) + // Padding is the maximum of sizeof(size_t) and alignof(ElementType) return std::max(Ctx.getTypeSize(Ctx.getSizeType()), - static_cast<uint64_t>(Ctx.getTypeAlign(T))) / 8; + static_cast<uint64_t>(Ctx.getTypeAlign(ElementType))) / 8; +} + +static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) { + if (!E->isArray()) + return 0; + + // No cookie is required if the new operator being used is + // ::operator new[](size_t, void*). + const FunctionDecl *OperatorNew = E->getOperatorNew(); + if (OperatorNew->getDeclContext()->getLookupContext()->isFileContext()) { + if (OperatorNew->getNumParams() == 2) { + CanQualType ParamType = + Ctx.getCanonicalType(OperatorNew->getParamDecl(1)->getType()); + + if (ParamType == Ctx.VoidPtrTy) + return 0; + } + } + + return CalculateCookiePadding(Ctx, E->getAllocatedType()); + QualType T = E->getAllocatedType(); } static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF, @@ -237,6 +278,39 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { return NewPtr; } +static std::pair<llvm::Value *, llvm::Value *> +GetAllocatedObjectPtrAndNumElements(CodeGenFunction &CGF, + llvm::Value *Ptr, QualType DeleteTy) { + QualType SizeTy = CGF.getContext().getSizeType(); + const llvm::Type *SizeLTy = CGF.ConvertType(SizeTy); + + uint64_t DeleteTypeAlign = CGF.getContext().getTypeAlign(DeleteTy); + uint64_t CookiePadding = std::max(CGF.getContext().getTypeSize(SizeTy), + DeleteTypeAlign) / 8; + assert(CookiePadding && "CookiePadding should not be 0."); + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + uint64_t CookieOffset = + CookiePadding - CGF.getContext().getTypeSize(SizeTy) / 8; + + llvm::Value *AllocatedObjectPtr = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy); + AllocatedObjectPtr = + CGF.Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr, + -CookiePadding); + + llvm::Value *NumElementsPtr = + CGF.Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr, + CookieOffset); + NumElementsPtr = + CGF.Builder.CreateBitCast(NumElementsPtr, SizeLTy->getPointerTo()); + + llvm::Value *NumElements = CGF.Builder.CreateLoad(NumElementsPtr); + NumElements = + CGF.Builder.CreateIntCast(NumElements, SizeLTy, /*isSigned=*/false); + + return std::make_pair(AllocatedObjectPtr, NumElements); +} + void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, llvm::Value *Ptr, QualType DeleteTy) { @@ -245,17 +319,37 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, CallArgList DeleteArgs; + // Check if we need to pass the size to the delete operator. + llvm::Value *Size = 0; + QualType SizeTy; + if (DeleteFTy->getNumArgs() == 2) { + SizeTy = DeleteFTy->getArgType(1); + uint64_t DeleteTypeSize = getContext().getTypeSize(DeleteTy) / 8; + Size = llvm::ConstantInt::get(ConvertType(SizeTy), DeleteTypeSize); + } + + if (DeleteFD->getOverloadedOperator() == OO_Array_Delete && + + CalculateCookiePadding(getContext(), DeleteTy)) { + // We need to get the number of elements in the array from the cookie. + llvm::Value *AllocatedObjectPtr; + llvm::Value *NumElements; + llvm::tie(AllocatedObjectPtr, NumElements) = + GetAllocatedObjectPtrAndNumElements(*this, Ptr, DeleteTy); + + // Multiply the size with the number of elements. + if (Size) + Size = Builder.CreateMul(NumElements, Size); + + Ptr = AllocatedObjectPtr; + } + 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); + if (Size) DeleteArgs.push_back(std::make_pair(RValue::get(Size), SizeTy)); - } // Emit the call to delete. EmitCall(CGM.getTypes().getFunctionInfo(DeleteFTy->getResultType(), @@ -300,34 +394,13 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { if (!RD->hasTrivialDestructor()) { const CXXDestructorDecl *Dtor = RD->getDestructor(getContext()); 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()) { + llvm::Value *AllocatedObjectPtr; + llvm::Value *NumElements; + llvm::tie(AllocatedObjectPtr, NumElements) = + GetAllocatedObjectPtrAndNumElements(*this, Ptr, DeleteTy); + + EmitCXXAggrDestructorCall(Dtor, NumElements, Ptr); + } else if (Dtor->isVirtual()) { const llvm::Type *Ty = CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(Dtor), /*isVariadic=*/false); @@ -352,18 +425,10 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { 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.GenerateRtti(Ty), LTy); - } + + if (E->isTypeOperand()) + return Builder.CreateBitCast(CGM.GetAddrOfRTTI(E->getTypeOperand()), LTy); + Expr *subE = E->getExprOperand(); Ty = subE->getType(); CanQualType CanTy = CGM.getContext().getCanonicalType(Ty); @@ -404,9 +469,9 @@ llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) { V = Builder.CreateLoad(V); return V; } - return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy); + return Builder.CreateBitCast(CGM.GenerateRTTI(RD), LTy); } - return Builder.CreateBitCast(CGM.GenerateRtti(Ty), LTy); + return Builder.CreateBitCast(CGM.GenerateRTTI(Ty), LTy); } llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V, @@ -485,8 +550,8 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V, // FIXME: Calculate better hint. llvm::Value *hint = llvm::ConstantInt::get(PtrDiffTy, -1ULL); - llvm::Value *SrcArg = CGM.GenerateRttiRef(SrcTy); - llvm::Value *DstArg = CGM.GenerateRttiRef(DstTy); + 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); diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 9289f78..d428983 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -167,7 +167,11 @@ class ConstStructBuilder { } // Or in the bits that go into the previous byte. - Tmp |= cast<llvm::ConstantInt>(Elements.back())->getValue(); + if (llvm::ConstantInt *Val = dyn_cast<llvm::ConstantInt>(Elements.back())) + Tmp |= Val->getValue(); + else + assert(isa<llvm::UndefValue>(Elements.back())); + Elements.back() = llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp); if (FitsCompletelyInPreviousByte) diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index c1cbecc..2f31c05 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -167,6 +167,12 @@ public: return CGF.EmitObjCMessageExpr(E).getScalarVal(); } + Value *VisitObjCIsaExpr(ObjCIsaExpr *E) { + LValue LV = CGF.EmitObjCIsaExpr(E); + Value *V = CGF.EmitLoadOfLValue(LV, E->getType()).getScalarVal(); + return V; + } + Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E); Value *VisitShuffleVectorExpr(ShuffleVectorExpr *E); Value *VisitMemberExpr(MemberExpr *E); @@ -257,6 +263,10 @@ public: CGF.EmitCXXDeleteExpr(E); return 0; } + Value *VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) { + return llvm::ConstantInt::get(Builder.getInt1Ty(), + E->EvaluateTrait(CGF.getContext())); + } Value *VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *E) { // C++ [expr.pseudo]p1: @@ -798,6 +808,8 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { //assert(0 && "Unknown cast kind!"); break; + case CastExpr::CK_AnyPointerToObjCPointerCast: + case CastExpr::CK_AnyPointerToBlockPointerCast: case CastExpr::CK_BitCast: { Value *Src = Visit(const_cast<Expr*>(E)); return Builder.CreateBitCast(Src, ConvertType(DestTy)); @@ -943,34 +955,8 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { case CastExpr::CK_FloatingCast: return EmitScalarConversion(Visit(E), E->getType(), DestTy); - case CastExpr::CK_MemberPointerToBoolean: { - const MemberPointerType* T = E->getType()->getAs<MemberPointerType>(); - - if (T->getPointeeType()->isFunctionType()) { - // We have a member function pointer. - llvm::Value *Ptr = CGF.CreateTempAlloca(ConvertType(E->getType())); - - CGF.EmitAggExpr(E, Ptr, /*VolatileDest=*/false); - - // Get the pointer. - llvm::Value *FuncPtr = Builder.CreateStructGEP(Ptr, 0, "src.ptr"); - FuncPtr = Builder.CreateLoad(FuncPtr); - - llvm::Value *IsNotNull = - Builder.CreateICmpNE(FuncPtr, - llvm::Constant::getNullValue(FuncPtr->getType()), - "tobool"); - - return IsNotNull; - } - - // We have a regular member pointer. - Value *Ptr = Visit(const_cast<Expr*>(E)); - llvm::Value *IsNotNull = - Builder.CreateICmpNE(Ptr, CGF.CGM.EmitNullConstant(E->getType()), - "tobool"); - return IsNotNull; - } + case CastExpr::CK_MemberPointerToBoolean: + return CGF.EvaluateExprAsBool(E); } // Handle cases where the source is an non-complex type. @@ -1540,6 +1526,16 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) { if (Ops.LHS->getType() != RHS->getType()) RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom"); + if (CGF.CatchUndefined + && isa<llvm::IntegerType>(Ops.LHS->getType())) { + unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth(); + llvm::BasicBlock *Cont = CGF.createBasicBlock("cont"); + CGF.Builder.CreateCondBr(Builder.CreateICmpULT(RHS, + llvm::ConstantInt::get(RHS->getType(), Width)), + Cont, CGF.getTrapBB()); + CGF.EmitBlock(Cont); + } + return Builder.CreateShl(Ops.LHS, RHS, "shl"); } @@ -1550,6 +1546,16 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) { if (Ops.LHS->getType() != RHS->getType()) RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom"); + if (CGF.CatchUndefined + && isa<llvm::IntegerType>(Ops.LHS->getType())) { + unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth(); + llvm::BasicBlock *Cont = CGF.createBasicBlock("cont"); + CGF.Builder.CreateCondBr(Builder.CreateICmpULT(RHS, + llvm::ConstantInt::get(RHS->getType(), Width)), + Cont, CGF.getTrapBB()); + CGF.EmitBlock(Cont); + } + if (Ops.Ty->isUnsignedIntegerType()) return Builder.CreateLShr(Ops.LHS, RHS, "shr"); return Builder.CreateAShr(Ops.LHS, RHS, "shr"); @@ -1560,7 +1566,34 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc, TestAndClearIgnoreResultAssign(); Value *Result; QualType LHSTy = E->getLHS()->getType(); - if (!LHSTy->isAnyComplexType()) { + if (LHSTy->isMemberFunctionPointerType()) { + Value *LHSPtr = CGF.EmitAnyExprToTemp(E->getLHS()).getAggregateAddr(); + Value *RHSPtr = CGF.EmitAnyExprToTemp(E->getRHS()).getAggregateAddr(); + llvm::Value *LHSFunc = Builder.CreateStructGEP(LHSPtr, 0); + LHSFunc = Builder.CreateLoad(LHSFunc); + llvm::Value *RHSFunc = Builder.CreateStructGEP(RHSPtr, 0); + RHSFunc = Builder.CreateLoad(RHSFunc); + Value *ResultF = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, + LHSFunc, RHSFunc, "cmp.func"); + Value *NullPtr = llvm::Constant::getNullValue(LHSFunc->getType()); + Value *ResultNull = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, + LHSFunc, NullPtr, "cmp.null"); + llvm::Value *LHSAdj = Builder.CreateStructGEP(LHSPtr, 1); + LHSAdj = Builder.CreateLoad(LHSAdj); + llvm::Value *RHSAdj = Builder.CreateStructGEP(RHSPtr, 1); + RHSAdj = Builder.CreateLoad(RHSAdj); + Value *ResultA = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, + LHSAdj, RHSAdj, "cmp.adj"); + if (E->getOpcode() == BinaryOperator::EQ) { + Result = Builder.CreateOr(ResultNull, ResultA, "or.na"); + Result = Builder.CreateAnd(Result, ResultF, "and.f"); + } else { + assert(E->getOpcode() == BinaryOperator::NE && + "Member pointer comparison other than == or != ?"); + Result = Builder.CreateAnd(ResultNull, ResultA, "and.na"); + Result = Builder.CreateOr(Result, ResultF, "or.f"); + } + } else if (!LHSTy->isAnyComplexType()) { Value *LHS = Visit(E->getLHS()); Value *RHS = Visit(E->getRHS()); @@ -1868,10 +1901,11 @@ VisitConditionalOperator(const ConditionalOperator *E) { CGF.EmitBlock(ContBlock); - if (!LHS || !RHS) { - assert(E->getType()->isVoidType() && "Non-void value should have a value"); - return 0; - } + // If the LHS or RHS is a throw expression, it will be legitimately null. + if (!LHS) + return RHS; + if (!RHS) + return LHS; // Create a PHI node for the real part. llvm::PHINode *PN = Builder.CreatePHI(LHS->getType(), "cond"); @@ -1976,3 +2010,22 @@ llvm::Value *CodeGenFunction::EmitVector(llvm::Value * const *Vals, return Vec; } + +LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) { + llvm::Value *V; + // object->isa or (*object).isa + // Generate code as for: *(Class*)object + Expr *BaseExpr = E->getBase(); + if (E->isArrow()) + V = ScalarExprEmitter(*this).EmitLoadOfLValue(BaseExpr); + else + V = EmitLValue(BaseExpr).getAddress(); + + // build Class* type + const llvm::Type *ClassPtrTy = ConvertType(E->getType()); + ClassPtrTy = ClassPtrTy->getPointerTo(); + V = Builder.CreateBitCast(V, ClassPtrTy); + LValue LV = LValue::MakeAddr(V, MakeQualifiers(E->getType())); + return LV; +} + diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 2e8ab29..fb920f0 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -28,6 +28,7 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetData.h" #include <cstdio> @@ -905,6 +906,13 @@ protected: const ObjCContainerDecl *OCD, const ObjCCommonTypesHelper &ObjCTypes); + /// PushProtocolProperties - Push protocol's property on the input stack. + void PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*, 16> &PropertySet, + std::vector<llvm::Constant*> &Properties, + const Decl *Container, + const ObjCProtocolDecl *PROTO, + const ObjCCommonTypesHelper &ObjCTypes); + /// GetProtocolRef - Return a reference to the internal protocol /// description, creating an empty one if it has not been /// defined. The return value has type ProtocolPtrTy. @@ -1793,6 +1801,26 @@ CGObjCMac::EmitProtocolList(llvm::Twine Name, return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListPtrTy); } +void CGObjCCommonMac::PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*, 16> &PropertySet, + std::vector<llvm::Constant*> &Properties, + const Decl *Container, + const ObjCProtocolDecl *PROTO, + const ObjCCommonTypesHelper &ObjCTypes) { + std::vector<llvm::Constant*> Prop(2); + for (ObjCProtocolDecl::protocol_iterator P = PROTO->protocol_begin(), + E = PROTO->protocol_end(); P != E; ++P) + PushProtocolProperties(PropertySet, Properties, Container, (*P), ObjCTypes); + for (ObjCContainerDecl::prop_iterator I = PROTO->prop_begin(), + E = PROTO->prop_end(); I != E; ++I) { + const ObjCPropertyDecl *PD = *I; + if (!PropertySet.insert(PD->getIdentifier())) + continue; + Prop[0] = GetPropertyName(PD->getIdentifier()); + Prop[1] = GetPropertyTypeString(PD, Container); + Properties.push_back(llvm::ConstantStruct::get(ObjCTypes.PropertyTy, Prop)); + } +} + /* struct _objc_property { const char * const name; @@ -1810,14 +1838,20 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(llvm::Twine Name, const ObjCContainerDecl *OCD, const ObjCCommonTypesHelper &ObjCTypes) { std::vector<llvm::Constant*> Properties, Prop(2); + llvm::SmallPtrSet<const IdentifierInfo*, 16> PropertySet; for (ObjCContainerDecl::prop_iterator I = OCD->prop_begin(), E = OCD->prop_end(); I != E; ++I) { const ObjCPropertyDecl *PD = *I; + PropertySet.insert(PD->getIdentifier()); Prop[0] = GetPropertyName(PD->getIdentifier()); Prop[1] = GetPropertyTypeString(PD, Container); Properties.push_back(llvm::ConstantStruct::get(ObjCTypes.PropertyTy, Prop)); } + if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD)) + for (ObjCInterfaceDecl::protocol_iterator P = OID->protocol_begin(), + E = OID->protocol_end(); P != E; ++P) + PushProtocolProperties(PropertySet, Properties, Container, (*P), ObjCTypes); // Return null for empty list. if (Properties.empty()) @@ -2507,8 +2541,11 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // through finally. CGF.PushCleanupBlock(FinallyBlock); - CGF.ObjCEHValueStack.push_back(0); - + if (CGF.ObjCEHValueStack.empty()) + CGF.ObjCEHValueStack.push_back(0); + // If This is a nested @try, caught exception is that of enclosing @try. + else + CGF.ObjCEHValueStack.push_back(CGF.ObjCEHValueStack.back()); // Allocate memory for the exception data and rethrow pointer. llvm::Value *ExceptionData = CGF.CreateTempAlloca(ObjCTypes.ExceptionDataTy, "exceptiondata.ptr"); @@ -4134,23 +4171,19 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() { "\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); - } - } + 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_$", @@ -4437,9 +4470,12 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { while (const ObjCInterfaceDecl *Super = Root->getSuperClass()) Root = Super; IsAGV = GetClassGlobal(ObjCMetaClassName + Root->getNameAsString()); + if (Root->hasAttr<WeakImportAttr>()) + IsAGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); // work on super class metadata symbol. std::string SuperClassName = - ObjCMetaClassName + ID->getClassInterface()->getSuperClass()->getNameAsString(); + ObjCMetaClassName + + ID->getClassInterface()->getSuperClass()->getNameAsString(); SuperClassGV = GetClassGlobal(SuperClassName); if (ID->getClassInterface()->getSuperClass()->hasAttr<WeakImportAttr>()) SuperClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); diff --git a/lib/CodeGen/CGRtti.cpp b/lib/CodeGen/CGRTTI.cpp index 43fcb31..02de00e 100644 --- a/lib/CodeGen/CGRtti.cpp +++ b/lib/CodeGen/CGRTTI.cpp @@ -1,4 +1,4 @@ -//===--- CGCXXRtti.cpp - Emit LLVM Code for C++ RTTI descriptors ----------===// +//===--- CGCXXRTTI.cpp - Emit LLVM Code for C++ RTTI descriptors ----------===// // // The LLVM Compiler Infrastructure // @@ -17,14 +17,35 @@ using namespace clang; using namespace CodeGen; -class RttiBuilder { +namespace { +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; + + // Type info flags. + enum { + /// TI_Const - Type has const qualifier. + TI_Const = 0x1, + + /// TI_Volatile - Type has volatile qualifier. + TI_Volatile = 0x2, + + /// TI_Restrict - Type has restrict qualifier. + TI_Restrict = 0x4, + + /// TI_Incomplete - Type is incomplete. + TI_Incomplete = 0x8, + + /// TI_ContainingClassIncomplete - Containing class is incomplete. + /// (in pointer to member). + TI_ContainingClassIncomplete = 0x10 + }; + public: - RttiBuilder(CodeGenModule &cgm) + RTTIBuilder(CodeGenModule &cgm) : CGM(cgm), VMContext(cgm.getModule().getContext()), Int8PtrTy(llvm::Type::getInt8PtrTy(VMContext)) { } @@ -47,27 +68,37 @@ public: return llvm::ConstantExpr::getBitCast(C, Int8PtrTy); } + // FIXME: This should be removed, and clients should pass in the linkage + // directly instead. + static inline llvm::GlobalVariable::LinkageTypes + GetLinkageFromExternFlag(bool Extern) { + if (Extern) + return llvm::GlobalValue::WeakODRLinkage; + + return llvm::GlobalValue::InternalLinkage; + } + + // FIXME: This should be removed, and clients should pass in the linkage + // directly instead. llvm::Constant *BuildName(QualType Ty, bool Hidden, bool Extern) { + return BuildName(Ty, Hidden, GetLinkageFromExternFlag(Extern)); + } + + llvm::Constant *BuildName(QualType Ty, bool Hidden, + llvm::GlobalVariable::LinkageTypes Linkage) { llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRttiName(Ty, OutName); + CGM.getMangleContext().mangleCXXRTTIName(Ty, OutName); llvm::StringRef Name = OutName.str(); - llvm::GlobalVariable::LinkageTypes linktype; - linktype = llvm::GlobalValue::LinkOnceODRLinkage; - if (!Extern) - linktype = llvm::GlobalValue::InternalLinkage; - - llvm::GlobalVariable *GV; - GV = CGM.getModule().getGlobalVariable(Name); - if (GV && !GV->isDeclaration()) - return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); + llvm::GlobalVariable *OGV = CGM.getModule().getGlobalVariable(Name); + if (OGV && !OGV->isDeclaration()) + return llvm::ConstantExpr::getBitCast(OGV, Int8PtrTy); - llvm::Constant *C; - C = llvm::ConstantArray::get(VMContext, Name.substr(4)); + llvm::Constant *C = llvm::ConstantArray::get(VMContext, Name.substr(4)); - llvm::GlobalVariable *OGV = GV; - GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, linktype, - C, Name); + llvm::GlobalVariable *GV = + new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, Linkage, + C, Name); if (OGV) { GV->takeName(OGV); llvm::Constant *NewPtr = llvm::ConstantExpr::getBitCast(GV, @@ -94,11 +125,8 @@ public: llvm::Constant *BuildTypeRef(QualType Ty) { llvm::Constant *C; - if (!CGM.getContext().getLangOptions().Rtti) - return llvm::Constant::getNullValue(Int8PtrTy); - llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRtti(Ty, OutName); + CGM.getMangleContext().mangleCXXRTTI(Ty, OutName); llvm::StringRef Name = OutName.str(); C = CGM.getModule().getGlobalVariable(Name); @@ -158,19 +186,15 @@ public: return true; } - llvm::Constant *finish(std::vector<llvm::Constant *> &info, + llvm::Constant *finish(llvm::Constant *const *Values, unsigned NumValues, llvm::GlobalVariable *GV, - llvm::StringRef Name, bool Hidden, bool Extern) { - llvm::GlobalVariable::LinkageTypes linktype; - linktype = llvm::GlobalValue::LinkOnceODRLinkage; - if (!Extern) - linktype = llvm::GlobalValue::InternalLinkage; - - llvm::Constant *C; - C = llvm::ConstantStruct::get(VMContext, &info[0], info.size(), false); + llvm::StringRef Name, bool Hidden, + llvm::GlobalVariable::LinkageTypes Linkage) { + llvm::Constant *C = + llvm::ConstantStruct::get(VMContext, Values, NumValues, /*Packed=*/false); llvm::GlobalVariable *OGV = GV; - GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, linktype, + GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, Linkage, C, Name); if (OGV) { GV->takeName(OGV); @@ -185,14 +209,16 @@ public: } - llvm::Constant *Buildclass_type_info(const CXXRecordDecl *RD) { - if (!CGM.getContext().getLangOptions().Rtti) - return llvm::Constant::getNullValue(Int8PtrTy); - + llvm::Constant * + Buildclass_type_info(const CXXRecordDecl *RD, + llvm::GlobalVariable::LinkageTypes Linkage) { + std::vector<llvm::Constant *> info; + assert(info.empty() && "Info vector must be empty!"); + llvm::Constant *C; llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRtti(CGM.getContext().getTagDeclType(RD), + CGM.getMangleContext().mangleCXXRTTI(CGM.getContext().getTagDeclType(RD), OutName); llvm::StringRef Name = OutName.str(); @@ -201,10 +227,11 @@ public: if (GV && !GV->isDeclaration()) return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); - std::vector<llvm::Constant *> info; - + // If we're in an anonymous namespace, then we always want internal linkage. + if (RD->isInAnonymousNamespace() || !RD->hasLinkage()) + Linkage = llvm::GlobalVariable::InternalLinkage; + bool Hidden = CGM.getDeclVisibilityMode(RD) == LangOptions::Hidden; - bool Extern = !RD->isInAnonymousNamespace(); bool simple = false; if (RD->getNumBases() == 0) @@ -216,7 +243,7 @@ public: C = BuildVtableRef("_ZTVN10__cxxabiv121__vmi_class_type_infoE"); info.push_back(C); info.push_back(BuildName(CGM.getContext().getTagDeclType(RD), Hidden, - Extern)); + Linkage)); // If we have no bases, there are no more fields. if (RD->getNumBases()) { @@ -230,7 +257,7 @@ public: e = RD->bases_end(); i != e; ++i) { const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - info.push_back(CGM.GenerateRttiRef(Base)); + info.push_back(CGM.GetAddrOfRTTI(Base)); if (simple) break; int64_t offset; @@ -249,12 +276,12 @@ public: } } - return finish(info, GV, Name, Hidden, Extern); + return finish(&info[0], info.size(), GV, Name, Hidden, Linkage); } /// - 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 *BuildInt(unsigned n) { + return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), n); } bool DecideExtern(QualType Ty) { @@ -266,7 +293,7 @@ public: return DecideExtern(PT->getPointeeType()); if (const RecordType *RT = Ty->getAs<RecordType>()) if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) - return !RD->isInAnonymousNamespace(); + return !RD->isInAnonymousNamespace() && RD->hasLinkage(); return true; } @@ -284,10 +311,13 @@ public: } llvm::Constant *BuildPointerType(QualType Ty) { + std::vector<llvm::Constant *> info; + assert(info.empty() && "Info vector must be empty!"); + llvm::Constant *C; llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRtti(Ty, OutName); + CGM.getMangleContext().mangleCXXRTTI(Ty, OutName); llvm::StringRef Name = OutName.str(); llvm::GlobalVariable *GV; @@ -295,52 +325,58 @@ public: if (GV && !GV->isDeclaration()) return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); - std::vector<llvm::Constant *> info; - bool Extern = DecideExtern(Ty); bool Hidden = DecideHidden(Ty); - 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(); - } + const MemberPointerType *PtrMemTy = dyn_cast<MemberPointerType>(Ty); + QualType PointeeTy; + + if (PtrMemTy) + PointeeTy = PtrMemTy->getPointeeType(); + else + PointeeTy = Ty->getPointeeType(); - if (PtrMem) + if (PtrMemTy) 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, Extern)); - 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)); + Qualifiers Q = PointeeTy.getQualifiers(); + + PointeeTy = + CGM.getContext().getCanonicalType(PointeeTy).getUnqualifiedType(); + + unsigned Flags = 0; + if (Q.hasConst()) + Flags |= TI_Const; + if (Q.hasVolatile()) + Flags |= TI_Volatile; + if (Q.hasRestrict()) + Flags |= TI_Restrict; + + if (Ty->isIncompleteType()) + Flags |= TI_Incomplete; + + if (PtrMemTy && PtrMemTy->getClass()->isIncompleteType()) + Flags |= TI_ContainingClassIncomplete; + + info.push_back(BuildInt(Flags)); info.push_back(BuildInt(0)); - info.push_back(BuildType(PTy)); + info.push_back(BuildType(PointeeTy)); - if (PtrMem) - info.push_back(BuildType(BTy)); + if (PtrMemTy) + info.push_back(BuildType(QualType(PtrMemTy->getClass(), 0))); // We always generate these as hidden, only the name isn't hidden. - return finish(info, GV, Name, true, Extern); + return finish(&info[0], info.size(), GV, Name, /*Hidden=*/true, + GetLinkageFromExternFlag(Extern)); } llvm::Constant *BuildSimpleType(QualType Ty, const char *vtbl) { - llvm::Constant *C; - llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRtti(Ty, OutName); + CGM.getMangleContext().mangleCXXRTTI(Ty, OutName); llvm::StringRef Name = OutName.str(); llvm::GlobalVariable *GV; @@ -348,26 +384,26 @@ public: if (GV && !GV->isDeclaration()) return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); - std::vector<llvm::Constant *> info; - bool Extern = DecideExtern(Ty); bool Hidden = DecideHidden(Ty); - C = BuildVtableRef(vtbl); - info.push_back(C); - info.push_back(BuildName(Ty, Hidden, Extern)); - + llvm::Constant *Info[] = { + BuildVtableRef(vtbl), BuildName(Ty, Hidden, Extern) + }; + // We always generate these as hidden, only the name isn't hidden. - return finish(info, GV, Name, true, Extern); + return finish(&Info[0], llvm::array_lengthof(Info), GV, Name, + /*Hidden=*/true, GetLinkageFromExternFlag(Extern)); } + /// BuildType - Builds the type info for the given type. llvm::Constant *BuildType(QualType Ty) { const clang::Type &Type = *CGM.getContext().getCanonicalType(Ty).getTypePtr(); if (const RecordType *RT = Ty.getTypePtr()->getAs<RecordType>()) if (const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl())) - return Buildclass_type_info(RD); + return BuildClassTypeInfo(RD); switch (Type.getTypeClass()) { default: { @@ -405,22 +441,65 @@ public: return BuildSimpleType(Ty, "_ZTVN10__cxxabiv116__enum_type_infoE"); } } + + /// BuildClassTypeInfo - Builds the class type info (or a reference to it) + /// for the given record decl. + llvm::Constant *BuildClassTypeInfo(const CXXRecordDecl *RD) { + const CXXMethodDecl *KeyFunction = 0; + + if (RD->isDynamicClass()) + KeyFunction = CGM.getContext().getKeyFunction(RD); + + if (KeyFunction) { + // If the key function is defined in this translation unit, then the RTTI + // related constants should also be emitted here, with external linkage. + if (KeyFunction->getBody()) + return Buildclass_type_info(RD, llvm::GlobalValue::ExternalLinkage); + + // Otherwise, we just want a reference to the type info. + return Buildclass_type_infoRef(RD); + } + + // If there is no key function (or if the record doesn't have any virtual + // member functions or virtual bases), emit the type info with weak_odr + // linkage. + return Buildclass_type_info(RD, llvm::GlobalValue::WeakODRLinkage); + } }; +} + +llvm::Constant *CodeGenModule::GetAddrOfRTTI(const CXXRecordDecl *RD) { + if (!getContext().getLangOptions().RTTI) { + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); + return llvm::Constant::getNullValue(Int8PtrTy); + } + + return RTTIBuilder(*this).BuildClassTypeInfo(RD); +} + +llvm::Constant *CodeGenModule::GetAddrOfRTTI(QualType Ty) { + if (!getContext().getLangOptions().RTTI) { + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); + return llvm::Constant::getNullValue(Int8PtrTy); + } + + return RTTIBuilder(*this).BuildType(Ty); +} -llvm::Constant *CodeGenModule::GenerateRttiRef(const CXXRecordDecl *RD) { - RttiBuilder b(*this); +llvm::Constant *CodeGenModule::GenerateRTTIRef(const CXXRecordDecl *RD) { + RTTIBuilder b(*this); return b.Buildclass_type_infoRef(RD); } -llvm::Constant *CodeGenModule::GenerateRtti(const CXXRecordDecl *RD) { - RttiBuilder b(*this); +llvm::Constant *CodeGenModule::GenerateRTTI(const CXXRecordDecl *RD) { + RTTIBuilder b(*this); - return b.Buildclass_type_info(RD); + return b.Buildclass_type_info(RD, llvm::GlobalValue::ExternalLinkage); } -llvm::Constant *CodeGenModule::GenerateRtti(QualType Ty) { - RttiBuilder b(*this); +llvm::Constant *CodeGenModule::GenerateRTTI(QualType Ty) { + RTTIBuilder b(*this); return b.BuildType(Ty); } diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index 1a9bc39..31784ed 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -88,8 +88,6 @@ void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D, AppendBytes(NumBytesToAppend); - AlignmentAsLLVMStruct = std::max(AlignmentAsLLVMStruct, getTypeAlignment(Ty)); - BitsAvailableInLastField = NextFieldOffsetInBytes * 8 - (FieldOffset + FieldSize); } @@ -247,6 +245,14 @@ void CGRecordLayoutBuilder::AppendTailPadding(uint64_t RecordSize) { uint64_t RecordSizeInBytes = RecordSize / 8; assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!"); + uint64_t AlignedNextFieldOffset = + llvm::RoundUpToAlignment(NextFieldOffsetInBytes, AlignmentAsLLVMStruct); + + if (AlignedNextFieldOffset == RecordSizeInBytes) { + // We don't need any padding. + return; + } + unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes; AppendBytes(NumPadBytes); } diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index 715aa4c..5283ed9 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -26,12 +26,23 @@ class VtableBuilder { public: /// Index_t - Vtable index type. typedef uint64_t Index_t; + typedef std::vector<std::pair<GlobalDecl, + std::pair<GlobalDecl, ThunkAdjustment> > > + SavedAdjustmentsVectorTy; private: - std::vector<llvm::Constant *> &methods; - std::vector<llvm::Constant *> submethods; + + // VtableComponents - The components of the vtable being built. + typedef llvm::SmallVector<llvm::Constant *, 64> VtableComponentsVectorTy; + VtableComponentsVectorTy VtableComponents; + + const bool BuildVtable; + llvm::Type *Ptr8Ty; - /// Class - The most derived class that this vtable is being built for. - const CXXRecordDecl *Class; + + /// MostDerivedClass - The most derived class that this vtable is being + /// built for. + const CXXRecordDecl *MostDerivedClass; + /// LayoutClass - The most derived class used for virtual base layout /// information. const CXXRecordDecl *LayoutClass; @@ -45,9 +56,7 @@ private: llvm::Constant *rtti; llvm::LLVMContext &VMContext; CodeGenModule &CGM; // Per-module state. - /// Index - Maps a method decl into a vtable index. Useful for virtual - /// dispatch codegen. - 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 @@ -57,54 +66,93 @@ private: /// PureVirtualFunction - Points to __cxa_pure_virtual. llvm::Constant *PureVirtualFn; - /// Thunk - Represents a single thunk. - struct Thunk { - Thunk() - : Index(0) { } - - Thunk(uint64_t Index, const ThunkAdjustment &Adjustment) - : Index(Index), Adjustment(Adjustment) { } - - /// Index - The index in the vtable. - uint64_t Index; + /// VtableMethods - A data structure for keeping track of methods in a vtable. + /// Can add methods, override methods and iterate in vtable order. + class VtableMethods { + // MethodToIndexMap - Maps from a global decl to the index it has in the + // Methods vector. + llvm::DenseMap<GlobalDecl, uint64_t> MethodToIndexMap; + + /// Methods - The methods, in vtable order. + typedef llvm::SmallVector<GlobalDecl, 16> MethodsVectorTy; + MethodsVectorTy Methods; + MethodsVectorTy OrigMethods; + + public: + /// AddMethod - Add a method to the vtable methods. + void AddMethod(GlobalDecl GD) { + assert(!MethodToIndexMap.count(GD) && + "Method has already been added!"); + + MethodToIndexMap[GD] = Methods.size(); + Methods.push_back(GD); + OrigMethods.push_back(GD); + } - /// Adjustment - The thunk adjustment. - ThunkAdjustment Adjustment; - }; + /// OverrideMethod - Replace a method with another. + void OverrideMethod(GlobalDecl OverriddenGD, GlobalDecl GD) { + llvm::DenseMap<GlobalDecl, uint64_t>::iterator i + = MethodToIndexMap.find(OverriddenGD); + assert(i != MethodToIndexMap.end() && "Did not find entry!"); + + // Get the index of the old decl. + uint64_t Index = i->second; + + // Replace the old decl with the new decl. + Methods[Index] = GD; - /// Thunks - The thunks in a vtable. - typedef llvm::DenseMap<GlobalDecl, Thunk> ThunksMapTy; - ThunksMapTy Thunks; + // And add the new. + MethodToIndexMap[GD] = Index; + } - /// CovariantThunk - Represents a single covariant thunk. - struct CovariantThunk { - CovariantThunk() - : Index(0) { } - - CovariantThunk(uint64_t Index, const ThunkAdjustment &ThisAdjustment, - const ThunkAdjustment &ReturnAdjustment, - CanQualType ReturnType) - : Index(Index), Adjustment(ThisAdjustment, ReturnAdjustment), - ReturnType(ReturnType) { } - - // Index - The index in the vtable. - uint64_t Index; - - /// Adjustment - The covariant thunk adjustment. - CovariantThunkAdjustment Adjustment; + /// getIndex - Gives the index of a passed in GlobalDecl. Returns false if + /// the index couldn't be found. + bool getIndex(GlobalDecl GD, uint64_t &Index) const { + llvm::DenseMap<GlobalDecl, uint64_t>::const_iterator i + = MethodToIndexMap.find(GD); + + if (i == MethodToIndexMap.end()) + return false; + + Index = i->second; + return true; + } + + GlobalDecl getOrigMethod(uint64_t Index) const { + return OrigMethods[Index]; + } + + MethodsVectorTy::size_type size() const { + return Methods.size(); + } + + void clear() { + MethodToIndexMap.clear(); + Methods.clear(); + OrigMethods.clear(); + } - /// ReturnType - The return type of the function. - CanQualType ReturnType; + GlobalDecl operator[](uint64_t Index) const { + return Methods[Index]; + } }; - /// CovariantThunks - The covariant thunks in a vtable. - typedef llvm::DenseMap<GlobalDecl, CovariantThunk> CovariantThunksMapTy; - CovariantThunksMapTy CovariantThunks; + /// Methods - The vtable methods we're currently building. + VtableMethods Methods; + + /// ThisAdjustments - For a given index in the vtable, contains the 'this' + /// pointer adjustment needed for a method. + typedef llvm::DenseMap<uint64_t, ThunkAdjustment> ThisAdjustmentsMapTy; + ThisAdjustmentsMapTy ThisAdjustments; + + SavedAdjustmentsVectorTy SavedAdjustments; + + /// BaseReturnTypes - Contains the base return types of methods who have been + /// overridden with methods whose return types require adjustment. Used for + /// generating covariant thunk information. + typedef llvm::DenseMap<uint64_t, CanQualType> BaseReturnTypesMapTy; + BaseReturnTypesMapTy BaseReturnTypes; - /// PureVirtualMethods - Pure virtual methods. - typedef llvm::DenseSet<GlobalDecl> PureVirtualMethodsSetTy; - PureVirtualMethodsSetTy PureVirtualMethods; - std::vector<Index_t> VCalls; typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t; @@ -143,21 +191,32 @@ private: } public: - 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), PureVirtualFn(0),subAddressPoints(AllocAddressPoint(cgm, l, c)), + VtableBuilder(const CXXRecordDecl *MostDerivedClass, + const CXXRecordDecl *l, uint64_t lo, CodeGenModule &cgm, + bool build) + : BuildVtable(build), MostDerivedClass(MostDerivedClass), LayoutClass(l), + LayoutOffset(lo), BLayout(cgm.getContext().getASTRecordLayout(l)), + rtti(0), VMContext(cgm.getModule().getContext()),CGM(cgm), + PureVirtualFn(0), + subAddressPoints(AllocAddressPoint(cgm, l, MostDerivedClass)), Extern(!l->isInAnonymousNamespace()), - LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) { + LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) { Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); + if (BuildVtable) + rtti = CGM.GetAddrOfRTTI(MostDerivedClass); } - llvm::DenseMap<GlobalDecl, Index_t> &getIndex() { return Index; } + // getVtableComponents - Returns a reference to the vtable components. + const VtableComponentsVectorTy &getVtableComponents() const { + return VtableComponents; + } + llvm::DenseMap<const CXXRecordDecl *, Index_t> &getVBIndex() { return VBIndex; } + SavedAdjustmentsVectorTy &getSavedAdjustments() + { return SavedAdjustments; } + llvm::Constant *wrap(Index_t i) { llvm::Constant *m; m = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), i); @@ -168,8 +227,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) { @@ -249,7 +308,7 @@ public: qB = qB->getPointeeType(); CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl()); CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl()); - if (D != Class) + if (D != MostDerivedClass) return CGM.getVtableInfo().getVirtualBaseOffsetIndex(D, B); llvm::DenseMap<const CXXRecordDecl *, Index_t>::iterator i; i = VBIndex.find(B); @@ -260,166 +319,19 @@ public: return 0; } - bool OverrideMethod(GlobalDecl GD, llvm::Constant *m, - bool MorallyVirtual, Index_t OverrideOffset, - 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? - - // FIXME: Don't like the nested loops. For very large inheritance - // heirarchies we could have a table on the side with the final overridder - // and just replace each instance of an overridden method once. Would be - // nice to measure the cost/benefit on real code. - - 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 = WrapAddrOf(OGD); - om = llvm::ConstantExpr::getBitCast(om, Ptr8Ty); - - for (Index_t i = 0, e = submethods.size(); - i != e; ++i) { - // FIXME: begin_overridden_methods might be too lax, covariance */ - if (submethods[i] != om) - continue; - QualType nc_oret = OMD->getType()->getAs<FunctionType>()->getResultType(); - CanQualType oret = CGM.getContext().getCanonicalType(nc_oret); - QualType nc_ret = MD->getType()->getAs<FunctionType>()->getResultType(); - CanQualType ret = CGM.getContext().getCanonicalType(nc_ret); - ThunkAdjustment ReturnAdjustment; - if (oret != ret) { - // FIXME: calculate offsets for covariance - CovariantThunksMapTy::iterator i = CovariantThunks.find(OMD); - if (i != CovariantThunks.end()) { - oret = i->second.ReturnType; - CovariantThunks.erase(i); - } - // FIXME: Double check oret - Index_t nv = getNVOffset(oret, ret)/8; - ReturnAdjustment = ThunkAdjustment(nv, getVbaseOffset(oret, ret)); - } - Index[GD] = i; - submethods[i] = m; - if (isPure) - PureVirtualMethods.insert(GD); - PureVirtualMethods.erase(OGD); - Thunks.erase(OGD); - if (MorallyVirtual || VCall.count(OGD)) { - Index_t &idx = VCall[OGD]; - if (idx == 0) { - 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->getNameAsString().c_str(), (int)-idx-3, - (int)VCalls[idx-1], Class->getNameAsCString())); - } else { - 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->getNameAsString().c_str(), (int)-idx-3, - (int)VCalls[idx-1], Class->getNameAsCString())); - } - VCall[GD] = idx; - int64_t NonVirtualAdjustment = NonVirtualOffset[GD]; - int64_t VirtualAdjustment = - -((idx + extra + 2) * LLVMPointerWidth / 8); - - // Optimize out virtual adjustments of 0. - if (VCalls[idx-1] == 0) - VirtualAdjustment = 0; - - ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, - VirtualAdjustment); - - // FIXME: Do we always have to build a covariant thunk to save oret, - // which is the containing virtual base class? - if (!ReturnAdjustment.isEmpty()) { - CovariantThunks[GD] = - CovariantThunk(i, ThisAdjustment, ReturnAdjustment, oret); - } else if (!isPure && !ThisAdjustment.isEmpty()) - Thunks[GD] = Thunk(i, ThisAdjustment); - return true; - } - - // FIXME: finish off - int64_t NonVirtualAdjustment = VCallOffset[OGD] - OverrideOffset/8; - - if (NonVirtualAdjustment || !ReturnAdjustment.isEmpty()) { - ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, 0); - - if (!ReturnAdjustment.isEmpty()) { - CovariantThunks[GD] = - CovariantThunk(i, ThisAdjustment, ReturnAdjustment, oret); - } else if (!isPure) - Thunks[GD] = Thunk(i, ThisAdjustment); - } - return true; - } - } - - return false; - } - - void InstallThunks() { - for (ThunksMapTy::const_iterator i = Thunks.begin(), e = Thunks.end(); - i != e; ++i) { - GlobalDecl GD = i->first; - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - assert(!MD->isPure() && "Can't thunk pure virtual methods!"); - - const Thunk& Thunk = i->second; - assert(Thunk.Index == Index[GD] && "Thunk index mismatch!"); - - submethods[Thunk.Index] = CGM.BuildThunk(MD, Extern, Thunk.Adjustment); - } - Thunks.clear(); - - for (CovariantThunksMapTy::const_iterator i = CovariantThunks.begin(), - e = CovariantThunks.end(); i != e; ++i) { - GlobalDecl GD = i->first; - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - if (MD->isPure()) - continue; - - const CovariantThunk &Thunk = i->second; - assert(Thunk.Index == Index[GD] && "Thunk index mismatch!"); - submethods[Thunk.Index] = - CGM.BuildCovariantThunk(MD, Extern, Thunk.Adjustment); - } - CovariantThunks.clear(); - - for (PureVirtualMethodsSetTy::iterator i = PureVirtualMethods.begin(), - e = PureVirtualMethods.end(); i != e; ++i) { - GlobalDecl GD = *i; - submethods[Index[GD]] = getPureVirtualFn(); - } - PureVirtualMethods.clear(); - } + bool OverrideMethod(GlobalDecl GD, bool MorallyVirtual, + Index_t OverrideOffset, Index_t Offset, + int64_t CurrentVBaseOffset); + /// AppendMethods - Append the current methods to the vtable. + void AppendMethodsToVtable(); + 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, GD.getDtorType())); - const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVtable(MD); - return wrap(CGM.GetAddrOfFunction(MD, Ty)); + return wrap(CGM.GetAddrOfFunction(GD, Ty)); } void OverrideMethods(Path_t *Path, bool MorallyVirtual, int64_t Offset, @@ -438,15 +350,15 @@ public: 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); - + OverrideMethod(CompDtor, MorallyVirtual, OverrideOffset, Offset, + CurrentVBaseOffset); + GlobalDecl DeletingDtor(DD, Dtor_Deleting); - OverrideMethod(DeletingDtor, WrapAddrOf(DeletingDtor), MorallyVirtual, - OverrideOffset, Offset, CurrentVBaseOffset); + OverrideMethod(DeletingDtor, MorallyVirtual, OverrideOffset, Offset, + CurrentVBaseOffset); } else { - OverrideMethod(MD, WrapAddrOf(MD), MorallyVirtual, OverrideOffset, - Offset, CurrentVBaseOffset); + OverrideMethod(MD, MorallyVirtual, OverrideOffset, Offset, + CurrentVBaseOffset); } } } @@ -454,24 +366,20 @@ public: void AddMethod(const GlobalDecl GD, bool MorallyVirtual, Index_t Offset, int64_t CurrentVBaseOffset) { - llvm::Constant *m = WrapAddrOf(GD); - // If we can find a previously allocated slot for this, reuse it. - if (OverrideMethod(GD, m, MorallyVirtual, Offset, Offset, + if (OverrideMethod(GD, MorallyVirtual, Offset, Offset, CurrentVBaseOffset)) return; - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - - // else allocate a new slot. - Index[GD] = submethods.size(); - submethods.push_back(m); + // We didn't find an entry in the vtable that we could use, add a new + // entry. + Methods.AddMethod(GD); + D1(printf(" vfn for %s at %d\n", MD->getNameAsString().c_str(), (int)Index[GD])); - if (MD->isPure()) - PureVirtualMethods.insert(GD); + + VCallOffset[GD] = Offset/8; if (MorallyVirtual) { - VCallOffset[GD] = Offset/8; Index_t &idx = VCall[GD]; // Allocate the first one, after that, we reuse the previous one. if (idx == 0) { @@ -530,16 +438,19 @@ public: #define D(X) void insertVCalls(int InsertionPoint) { - llvm::Constant *e = 0; D1(printf("============= combining vbase/vcall\n")); D(VCalls.insert(VCalls.begin(), 673)); D(VCalls.push_back(672)); - methods.insert(methods.begin() + InsertionPoint, VCalls.size(), e); - // The vcalls come first... - for (std::vector<Index_t>::reverse_iterator i = VCalls.rbegin(), - e = VCalls.rend(); - i != e; ++i) - methods[InsertionPoint++] = wrap((0?600:0) + *i); + + VtableComponents.insert(VtableComponents.begin() + InsertionPoint, + VCalls.size(), 0); + if (BuildVtable) { + // The vcalls come first... + for (std::vector<Index_t>::reverse_iterator i = VCalls.rbegin(), + e = VCalls.rend(); + i != e; ++i) + VtableComponents[InsertionPoint++] = wrap((0?600:0) + *i); + } VCalls.clear(); VCall.clear(); } @@ -570,11 +481,13 @@ public: } - 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) { + Index_t FinishGenerateVtable(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) { alloc = true; @@ -584,21 +497,22 @@ public: StartNewTable(); extra = 0; bool DeferVCalls = MorallyVirtual || ForVirtualBase; - int VCallInsertionPoint = methods.size(); + int VCallInsertionPoint = VtableComponents.size(); if (!DeferVCalls) { insertVCalls(VCallInsertionPoint); } else // FIXME: just for extra, or for all uses of VCalls.size post this? extra = -VCalls.size(); - methods.push_back(wrap(-((Offset-LayoutOffset)/8))); - methods.push_back(rtti); - Index_t AddressPoint = methods.size(); + // Add the offset to top. + VtableComponents.push_back(BuildVtable ? wrap(-((Offset-LayoutOffset)/8)) : 0); + + // Add the RTTI information. + VtableComponents.push_back(rtti); + + Index_t AddressPoint = VtableComponents.size(); - InstallThunks(); - D1(printf("============= combining methods\n")); - methods.insert(methods.end(), submethods.begin(), submethods.end()); - submethods.clear(); + AppendMethodsToVtable(); // and then the non-virtual bases. NonVirtualBases(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, @@ -635,17 +549,11 @@ public: const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); // vtables are composed from the chain of primaries. - if (PrimaryBase) { + if (PrimaryBase && !PrimaryBaseWasVirtual) { 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, BaseCurrentVBaseOffset); + Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset, + updateVBIndex, current_vbindex, CurrentVBaseOffset); } D1(printf(" doing vcall entries for %s most derived %s\n", @@ -702,7 +610,8 @@ public: // Construction vtable don't need parts that have no virtual bases and // aren't morally virtual. - if ((LayoutClass != Class) && RD->getNumVBases() == 0 && !MorallyVirtual) + if ((LayoutClass != MostDerivedClass) && + RD->getNumVBases() == 0 && !MorallyVirtual) return 0; const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); @@ -722,8 +631,9 @@ public: if (Path) OverrideMethods(Path, MorallyVirtual, Offset, CurrentVBaseOffset); - return end(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, MorallyVirtual, - Offset, ForVirtualBase, CurrentVBaseOffset, Path); + return FinishGenerateVtable(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, + MorallyVirtual, Offset, ForVirtualBase, + CurrentVBaseOffset, Path); } void GenerateVtableForVBases(const CXXRecordDecl *RD, @@ -770,8 +680,7 @@ public: delete Path; } }; - -} +} // end anonymous namespace /// TypeConversionRequiresAdjustment - Returns whether conversion from a /// derived type to a base type requires adjustment. @@ -790,18 +699,18 @@ TypeConversionRequiresAdjustment(ASTContext &Ctx, // If we found a virtual base we always want to require adjustment. if (Paths.getDetectedVirtual()) return true; - + const CXXBasePath &Path = Paths.front(); for (size_t Start = 0, End = Path.size(); Start != End; ++Start) { const CXXBasePathElement &Element = Path[Start]; - + // Check the base class offset. const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Element.Class); const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>(); const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl()); - + if (Layout.getBaseClassOffset(Base) != 0) { // This requires an adjustment. return true; @@ -825,7 +734,7 @@ TypeConversionRequiresAdjustment(ASTContext &Ctx, // No adjustment needed. return false; } - + if (const ReferenceType *RT = dyn_cast<ReferenceType>(CanDerivedType)) { CanDerivedType = RT->getPointeeType(); CanBaseType = cast<ReferenceType>(CanBaseType)->getPointeeType(); @@ -835,21 +744,190 @@ TypeConversionRequiresAdjustment(ASTContext &Ctx, } else { assert(false && "Unexpected return type!"); } - + if (CanDerivedType == CanBaseType) { // No adjustment needed. return false; } const CXXRecordDecl *DerivedDecl = - cast<CXXRecordDecl>(cast<RecordType>(CanDerivedType)->getDecl()); - + cast<CXXRecordDecl>(cast<RecordType>(CanDerivedType)->getDecl()); + const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(cast<RecordType>(CanBaseType)->getDecl()); - + cast<CXXRecordDecl>(cast<RecordType>(CanBaseType)->getDecl()); + return TypeConversionRequiresAdjustment(Ctx, DerivedDecl, BaseDecl); } +bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual, + Index_t OverrideOffset, Index_t Offset, + int64_t CurrentVBaseOffset) { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + + const bool isPure = MD->isPure(); + + // FIXME: Should OverrideOffset's be Offset? + + for (CXXMethodDecl::method_iterator 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; + + // Check whether this is the method being overridden in this section of + // the vtable. + uint64_t Index; + if (!Methods.getIndex(OGD, Index)) + continue; + + // Get the original method, which we should be computing thunks, etc, + // against. + OGD = Methods.getOrigMethod(Index); + OMD = cast<CXXMethodDecl>(OGD.getDecl()); + + QualType ReturnType = + MD->getType()->getAs<FunctionType>()->getResultType(); + QualType OverriddenReturnType = + OMD->getType()->getAs<FunctionType>()->getResultType(); + + // Check if we need a return type adjustment. + if (TypeConversionRequiresAdjustment(CGM.getContext(), ReturnType, + OverriddenReturnType)) { + CanQualType &BaseReturnType = BaseReturnTypes[Index]; + + // Insert the base return type. + if (BaseReturnType.isNull()) + BaseReturnType = + CGM.getContext().getCanonicalType(OverriddenReturnType); + } + + Methods.OverrideMethod(OGD, GD); + + ThisAdjustments.erase(Index); + if (MorallyVirtual || VCall.count(OGD)) { + Index_t &idx = VCall[OGD]; + if (idx == 0) { + 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->getNameAsString().c_str(), (int)-idx-3, + (int)VCalls[idx-1], Class->getNameAsCString())); + } else { + 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->getNameAsString().c_str(), (int)-idx-3, + (int)VCalls[idx-1], Class->getNameAsCString())); + } + VCall[GD] = idx; + int64_t NonVirtualAdjustment = NonVirtualOffset[GD]; + int64_t VirtualAdjustment = + -((idx + extra + 2) * LLVMPointerWidth / 8); + + // Optimize out virtual adjustments of 0. + if (VCalls[idx-1] == 0) + VirtualAdjustment = 0; + + ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, + VirtualAdjustment); + + if (!isPure && !ThisAdjustment.isEmpty()) { + ThisAdjustments[Index] = ThisAdjustment; + SavedAdjustments.push_back( + std::make_pair(GD, std::make_pair(OGD, ThisAdjustment))); + } + return true; + } + + int64_t NonVirtualAdjustment = -VCallOffset[OGD] + OverrideOffset/8; + + if (NonVirtualAdjustment) { + ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, 0); + + if (!isPure) { + ThisAdjustments[Index] = ThisAdjustment; + SavedAdjustments.push_back( + std::make_pair(GD, std::make_pair(OGD, ThisAdjustment))); + } + } + return true; + } + + return false; +} + +void VtableBuilder::AppendMethodsToVtable() { + if (!BuildVtable) { + VtableComponents.insert(VtableComponents.end(), Methods.size(), + (llvm::Constant *)0); + ThisAdjustments.clear(); + BaseReturnTypes.clear(); + Methods.clear(); + return; + } + + // Reserve room in the vtable for our new methods. + VtableComponents.reserve(VtableComponents.size() + Methods.size()); + + for (unsigned i = 0, e = Methods.size(); i != e; ++i) { + GlobalDecl GD = Methods[i]; + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + + // Get the 'this' pointer adjustment. + ThunkAdjustment ThisAdjustment = ThisAdjustments.lookup(i); + + // Construct the return type adjustment. + ThunkAdjustment ReturnAdjustment; + + QualType BaseReturnType = BaseReturnTypes.lookup(i); + if (!BaseReturnType.isNull() && !MD->isPure()) { + QualType DerivedType = + MD->getType()->getAs<FunctionType>()->getResultType(); + + int64_t NonVirtualAdjustment = + getNVOffset(BaseReturnType, DerivedType) / 8; + + int64_t VirtualAdjustment = + getVbaseOffset(BaseReturnType, DerivedType); + + ReturnAdjustment = ThunkAdjustment(NonVirtualAdjustment, + VirtualAdjustment); + } + + llvm::Constant *Method = 0; + if (!ReturnAdjustment.isEmpty()) { + // Build a covariant thunk. + CovariantThunkAdjustment Adjustment(ThisAdjustment, ReturnAdjustment); + Method = wrap(CGM.GetAddrOfCovariantThunk(GD, Adjustment)); + } else if (!ThisAdjustment.isEmpty()) { + // Build a "regular" thunk. + Method = wrap(CGM.GetAddrOfThunk(GD, ThisAdjustment)); + } else if (MD->isPure()) { + // We have a pure virtual method. + Method = getPureVirtualFn(); + } else { + // We have a good old regular method. + Method = WrapAddrOf(GD); + } + + // Add the method to the vtable. + VtableComponents.push_back(Method); + } + + + ThisAdjustments.clear(); + BaseReturnTypes.clear(); + + Methods.clear(); +} + void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { // Itanium C++ ABI 2.5.2: @@ -874,7 +952,15 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { // we need to start counting at the end of the primary base's vtable. CurrentIndex = getNumVirtualFunctionPointers(PrimaryBase); } - + + // Collect all the primary bases, so we can check whether methods override + // a method from the base. + llvm::SmallPtrSet<const CXXRecordDecl *, 5> PrimaryBases; + for (ASTRecordLayout::primary_base_info_iterator + I = Layout.primary_base_begin(), E = Layout.primary_base_end(); + I != E; ++I) + PrimaryBases.insert((*I).getBase()); + const CXXDestructorDecl *ImplicitVirtualDtor = 0; for (CXXRecordDecl::method_iterator i = RD->method_begin(), @@ -895,7 +981,7 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { assert(OverriddenMD->isCanonicalDecl() && "Should have the canonical decl of the overridden RD!"); - if (OverriddenRD == PrimaryBase) { + if (PrimaryBases.count(OverriddenRD)) { // Check if converting from the return type of the method to the // return type of the overridden method requires conversion. QualType ReturnType = @@ -993,6 +1079,33 @@ uint64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) { return I->second; } +CGVtableInfo::AdjustmentVectorTy* +CGVtableInfo::getAdjustments(GlobalDecl GD) { + SavedAdjustmentsTy::iterator I = SavedAdjustments.find(GD); + if (I != SavedAdjustments.end()) + return &I->second; + + const CXXRecordDecl *RD = cast<CXXRecordDecl>(GD.getDecl()->getDeclContext()); + if (!SavedAdjustmentRecords.insert(RD).second) + return 0; + + VtableBuilder b(RD, RD, 0, CGM, false); + D1(printf("vtable %s\n", RD->getNameAsCString())); + b.GenerateVtableForBase(RD); + b.GenerateVtableForVBases(RD); + + for (VtableBuilder::SavedAdjustmentsVectorTy::iterator + i = b.getSavedAdjustments().begin(), + e = b.getSavedAdjustments().end(); i != e; i++) + SavedAdjustments[i->first].push_back(i->second); + + I = SavedAdjustments.find(GD); + if (I != SavedAdjustments.end()) + return &I->second; + + return 0; +} + int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, const CXXRecordDecl *VBase) { ClassPairTy ClassPair(RD, VBase); @@ -1002,10 +1115,9 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, if (I != VirtualBaseClassIndicies.end()) return I->second; - std::vector<llvm::Constant *> methods; // FIXME: This seems expensive. Can we do a partial job to get // just this data. - VtableBuilder b(methods, RD, RD, 0, CGM); + VtableBuilder b(RD, RD, 0, CGM, false); D1(printf("vtable %s\n", RD->getNameAsCString())); b.GenerateVtableForBase(RD); b.GenerateVtableForVBases(RD); @@ -1024,30 +1136,38 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, return I->second; } -llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass, - const CXXRecordDecl *RD, - uint64_t Offset) { +uint64_t CGVtableInfo::getVtableAddressPoint(const CXXRecordDecl *RD) { + uint64_t AddressPoint = + (*(*(CGM.AddressPoints[RD]))[RD])[std::make_pair(RD, 0)]; + + return AddressPoint; +} + +llvm::GlobalVariable * +CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage, + bool GenerateDefinition, + const CXXRecordDecl *LayoutClass, + const CXXRecordDecl *RD, uint64_t Offset) { llvm::SmallString<256> OutName; if (LayoutClass != RD) - getMangleContext().mangleCXXCtorVtable(LayoutClass, Offset/8, RD, OutName); + CGM.getMangleContext().mangleCXXCtorVtable(LayoutClass, Offset / 8, + RD, OutName); else - getMangleContext().mangleCXXVtable(RD, OutName); + CGM.getMangleContext().mangleCXXVtable(RD, OutName); llvm::StringRef Name = OutName.str(); - std::vector<llvm::Constant *> methods; - llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0); int64_t AddressPoint; - llvm::GlobalVariable *GV = getModule().getGlobalVariable(Name); - if (GV && AddressPoints[LayoutClass] && !GV->isDeclaration()) { - AddressPoint=(*(*(AddressPoints[LayoutClass]))[RD])[std::make_pair(RD, + llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name); + if (GV && CGM.AddressPoints[LayoutClass] && !GV->isDeclaration()) { + AddressPoint=(*(*(CGM.AddressPoints[LayoutClass]))[RD])[std::make_pair(RD, Offset)]; // FIXME: We can never have 0 address point. Do this for now so gepping // retains the same structure. Later, we'll just assert. if (AddressPoint == 0) AddressPoint = 1; } else { - VtableBuilder b(methods, RD, LayoutClass, Offset, *this); + VtableBuilder b(RD, LayoutClass, Offset, CGM, GenerateDefinition); D1(printf("vtable %s\n", RD->getNameAsCString())); // First comes the vtables for all the non-virtual bases... @@ -1056,59 +1176,34 @@ llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass, // then the vtables for all the virtual bases. b.GenerateVtableForVBases(RD, Offset); - bool CreateDefinition = true; - if (LayoutClass != RD) - CreateDefinition = true; - else { - const ASTRecordLayout &Layout = - getContext().getASTRecordLayout(LayoutClass); - - if (const CXXMethodDecl *KeyFunction = Layout.getKeyFunction()) { - if (!KeyFunction->getBody()) { - // If there is a KeyFunction, and it isn't defined, just build a - // reference to the vtable. - CreateDefinition = false; - } - } - } + llvm::Constant *Init = 0; + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + llvm::ArrayType *ArrayType = + llvm::ArrayType::get(Int8PtrTy, b.getVtableComponents().size()); + + if (GenerateDefinition) + Init = llvm::ConstantArray::get(ArrayType, &b.getVtableComponents()[0], + b.getVtableComponents().size()); - llvm::Constant *C = 0; - llvm::Type *type = Ptr8Ty; - llvm::GlobalVariable::LinkageTypes linktype - = llvm::GlobalValue::ExternalLinkage; - if (CreateDefinition) { - llvm::ArrayType *ntype = llvm::ArrayType::get(Ptr8Ty, methods.size()); - C = llvm::ConstantArray::get(ntype, methods); - linktype = llvm::GlobalValue::LinkOnceODRLinkage; - if (LayoutClass->isInAnonymousNamespace()) - linktype = llvm::GlobalValue::InternalLinkage; - type = ntype; - } llvm::GlobalVariable *OGV = GV; - GV = new llvm::GlobalVariable(getModule(), type, true, linktype, C, Name); + + GV = new llvm::GlobalVariable(CGM.getModule(), ArrayType, + /*isConstant=*/true, Linkage, Init, Name); + CGM.setGlobalVisibility(GV, RD); + if (OGV) { GV->takeName(OGV); - llvm::Constant *NewPtr = llvm::ConstantExpr::getBitCast(GV, - OGV->getType()); + llvm::Constant *NewPtr = + llvm::ConstantExpr::getBitCast(GV, OGV->getType()); OGV->replaceAllUsesWith(NewPtr); OGV->eraseFromParent(); } - bool Hidden = getDeclVisibilityMode(RD) == LangOptions::Hidden; - if (Hidden) - GV->setVisibility(llvm::GlobalVariable::HiddenVisibility); } - llvm::Constant *vtable = llvm::ConstantExpr::getBitCast(GV, Ptr8Ty); - llvm::Constant *AddressPointC; - uint32_t LLVMPointerWidth = getContext().Target.getPointerWidth(0); - AddressPointC = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - AddressPoint*LLVMPointerWidth/8); - vtable = llvm::ConstantExpr::getInBoundsGetElementPtr(vtable, &AddressPointC, - 1); - - assert(vtable->getType() == Ptr8Ty); - return vtable; + + return GV; } +namespace { class VTTBuilder { /// Inits - The list of values built for the VTT. std::vector<llvm::Constant *> &Inits; @@ -1125,12 +1220,13 @@ class VTTBuilder { llvm::LLVMContext &VMContext; /// BuildVtablePtr - Build up a referene to the given secondary vtable - llvm::Constant *BuildVtablePtr(llvm::Constant *vtbl, - const CXXRecordDecl *VtblClass, + llvm::Constant *BuildVtablePtr(llvm::Constant *Vtable, + const CXXRecordDecl *VtableClass, const CXXRecordDecl *RD, uint64_t Offset) { - int64_t AddressPoint; - AddressPoint = (*AddressPoints[VtblClass])[std::make_pair(RD, Offset)]; + int64_t AddressPoint = + (*AddressPoints[VtableClass])[std::make_pair(RD, Offset)]; + // FIXME: We can never have 0 address point. Do this for now so gepping // retains the same structure. Later we'll just assert. if (AddressPoint == 0) @@ -1138,12 +1234,17 @@ class VTTBuilder { 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; + + llvm::Value *Idxs[] = { + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), 0), + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), AddressPoint) + }; + + llvm::Constant *Init = + llvm::ConstantExpr::getInBoundsGetElementPtr(Vtable, Idxs, 2); + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); + return llvm::ConstantExpr::getBitCast(Init, Int8PtrTy); } /// Secondary - Add the secondary vtable pointers to Inits. Offset is the @@ -1180,8 +1281,11 @@ class VTTBuilder { init = BuildVtablePtr(vtbl, VtblClass, RD, Offset); else { init = CGM.getVtableInfo().getCtorVtable(Class, Base, BaseOffset); - subvtbl = dyn_cast<llvm::Constant>(init->getOperand(0)); + + subvtbl = init; subVtblClass = Base; + + init = BuildVtablePtr(init, Class, Base, BaseOffset); } Inits.push_back(init); } @@ -1195,25 +1299,26 @@ class VTTBuilder { if (RD->getNumVBases() == 0 && !MorallyVirtual) return; - llvm::Constant *init; - const CXXRecordDecl *VtblClass; + llvm::Constant *Vtable; + const CXXRecordDecl *VtableClass; // First comes the primary virtual table pointer... if (MorallyVirtual) { - init = BuildVtablePtr(ClassVtbl, Class, RD, Offset); - VtblClass = Class; + Vtable = ClassVtbl; + VtableClass = Class; } else { - init = CGM.getVtableInfo().getCtorVtable(Class, RD, Offset); - VtblClass = RD; + Vtable = CGM.getVtableInfo().getCtorVtable(Class, RD, Offset); + VtableClass = RD; } - llvm::Constant *vtbl = dyn_cast<llvm::Constant>(init->getOperand(0)); - Inits.push_back(init); + + llvm::Constant *Init = BuildVtablePtr(Vtable, VtableClass, RD, Offset); + Inits.push_back(Init); // then the secondary VTTs.... SecondaryVTTs(RD, Offset, MorallyVirtual); // and last the secondary vtable pointers. - Secondary(RD, vtbl, VtblClass, Offset, MorallyVirtual); + Secondary(RD, Vtable, VtableClass, Offset, MorallyVirtual); } /// SecondaryVTTs - Add the secondary VTTs to Inits. The secondary VTTs are @@ -1248,6 +1353,7 @@ class VTTBuilder { VirtualVTTs(Base); } } + public: VTTBuilder(std::vector<llvm::Constant *> &inits, const CXXRecordDecl *c, CodeGenModule &cgm) @@ -1258,8 +1364,7 @@ public: // 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)); + Inits.push_back(BuildVtablePtr(ClassVtbl, Class, Class, 0)); // then the secondary VTTs... SecondaryVTTs(Class); @@ -1271,98 +1376,116 @@ public: VirtualVTTs(Class); } }; +} -llvm::Constant *CodeGenModule::GenerateVTT(const CXXRecordDecl *RD) { +llvm::GlobalVariable * +CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD) { // Only classes that have virtual bases need a VTT. if (RD->getNumVBases() == 0) return 0; llvm::SmallString<256> OutName; - getMangleContext().mangleCXXVTT(RD, OutName); + CGM.getMangleContext().mangleCXXVTT(RD, OutName); llvm::StringRef Name = OutName.str(); - llvm::GlobalVariable::LinkageTypes linktype; - linktype = llvm::GlobalValue::LinkOnceODRLinkage; - if (RD->isInAnonymousNamespace()) - linktype = llvm::GlobalValue::InternalLinkage; - 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, Name); - bool Hidden = getDeclVisibilityMode(RD) == LangOptions::Hidden; - if (Hidden) - vtt->setVisibility(llvm::GlobalVariable::HiddenVisibility); - return llvm::ConstantExpr::getBitCast(vtt, Ptr8Ty); -} + std::vector<llvm::Constant *> inits; + VTTBuilder b(inits, RD, CGM); -void CGVtableInfo::GenerateClassData(const CXXRecordDecl *RD) { - Vtables[RD] = CGM.GenerateVtable(RD, RD); - CGM.GenerateRtti(RD); - CGM.GenerateVTT(RD); + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + const llvm::ArrayType *Type = llvm::ArrayType::get(Int8PtrTy, inits.size()); + + llvm::Constant *Init = llvm::ConstantArray::get(Type, inits); + + llvm::GlobalVariable *VTT = + new llvm::GlobalVariable(CGM.getModule(), Type, /*isConstant=*/true, + Linkage, Init, Name); + CGM.setGlobalVisibility(VTT, RD); + + return VTT; } -llvm::Constant *CGVtableInfo::getVtable(const CXXRecordDecl *RD) { - llvm::Constant *&vtbl = Vtables[RD]; - if (vtbl) - return vtbl; - vtbl = CGM.GenerateVtable(RD, RD); - - bool CreateDefinition = true; - - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - if (const CXXMethodDecl *KeyFunction = Layout.getKeyFunction()) { - if (!KeyFunction->getBody()) { - // If there is a KeyFunction, and it isn't defined, just build a - // reference to the vtable. - CreateDefinition = false; - } +void CGVtableInfo::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD) { + llvm::GlobalVariable *&Vtable = Vtables[RD]; + if (Vtable) { + assert(Vtable->getInitializer() && "Vtable doesn't have a definition!"); + return; } + + Vtable = GenerateVtable(Linkage, /*GenerateDefinition=*/true, RD, RD, 0); + GenerateVTT(Linkage, RD); +} - if (CreateDefinition) { - CGM.GenerateRtti(RD); - CGM.GenerateVTT(RD); - } - return vtbl; +llvm::GlobalVariable *CGVtableInfo::getVtable(const CXXRecordDecl *RD) { + llvm::GlobalVariable *Vtable = Vtables.lookup(RD); + + if (!Vtable) + Vtable = GenerateVtable(llvm::GlobalValue::ExternalLinkage, + /*GenerateDefinition=*/false, RD, RD, 0); + + return Vtable; } -llvm::Constant *CGVtableInfo::getCtorVtable(const CXXRecordDecl *LayoutClass, - const CXXRecordDecl *RD, - uint64_t Offset) { - return CGM.GenerateVtable(LayoutClass, RD, Offset); +llvm::GlobalVariable * +CGVtableInfo::getCtorVtable(const CXXRecordDecl *LayoutClass, + const CXXRecordDecl *RD, uint64_t Offset) { + return GenerateVtable(llvm::GlobalValue::InternalLinkage, + /*GenerateDefinition=*/true, + LayoutClass, RD, Offset); } void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) { const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); const CXXRecordDecl *RD = MD->getParent(); - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + // If the class doesn't have a vtable we don't need to emit one. + if (!RD->isDynamicClass()) + return; // Get the key function. - const CXXMethodDecl *KeyFunction = Layout.getKeyFunction(); + const CXXMethodDecl *KeyFunction = CGM.getContext().getKeyFunction(RD); - if (!KeyFunction) { - // If there's no key function, we don't want to emit the vtable here. - return; + if (KeyFunction) { + // We don't have the right key function. + if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) + return; + + // If the key function is a destructor, we only want to emit the vtable + // once, so do it for the complete destructor. + if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() != Dtor_Complete) + return; + } else { + // If there is no key function, we only want to emit the vtable if we are + // emitting a constructor. + if (!isa<CXXConstructorDecl>(MD) || GD.getCtorType() != Ctor_Complete) + return; } - // Check if we have the key function. - if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) - return; + llvm::GlobalVariable::LinkageTypes Linkage; + if (RD->isInAnonymousNamespace() || !RD->hasLinkage()) + Linkage = llvm::GlobalVariable::InternalLinkage; + else if (KeyFunction && !MD->isInlined()) + Linkage = llvm::GlobalVariable::ExternalLinkage; + else + Linkage = llvm::GlobalVariable::WeakODRLinkage; - // If the key function is a destructor, we only want to emit the vtable once, - // so do it for the complete destructor. - if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() != Dtor_Complete) - return; - // Emit the data. - GenerateClassData(RD); + GenerateClassData(Linkage, RD); + + for (CXXRecordDecl::method_iterator i = RD->method_begin(), + e = RD->method_end(); i != e; ++i) { + if ((*i)->isVirtual() && ((*i)->hasInlineBody() || (*i)->isImplicit())) { + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(*i)) { + CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Complete)); + CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Deleting)); + } else { + CGM.BuildThunksForVirtual(GlobalDecl(*i)); + } + } + } } diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h index 5c2b74c..eed5b64 100644 --- a/lib/CodeGen/CGVtable.h +++ b/lib/CodeGen/CGVtable.h @@ -15,12 +15,10 @@ #define CLANG_CODEGEN_CGVTABLE_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/GlobalVariable.h" #include "GlobalDecl.h" -namespace llvm { - class Constant; -} - namespace clang { class CXXRecordDecl; @@ -64,6 +62,11 @@ public: }; class CGVtableInfo { +public: + typedef std::vector<std::pair<GlobalDecl, ThunkAdjustment> > + AdjustmentVectorTy; + +private: CodeGenModule &CGM; /// MethodVtableIndices - Contains the index (relative to the vtable address @@ -79,12 +82,17 @@ class CGVtableInfo { typedef llvm::DenseMap<ClassPairTy, int64_t> VirtualBaseClassIndiciesTy; VirtualBaseClassIndiciesTy VirtualBaseClassIndicies; - llvm::DenseMap<const CXXRecordDecl *, llvm::Constant *> Vtables; + /// Vtables - All the vtables which have been defined. + llvm::DenseMap<const CXXRecordDecl *, llvm::GlobalVariable *> Vtables; /// NumVirtualFunctionPointers - Contains the number of virtual function /// pointers in the vtable for a given record decl. llvm::DenseMap<const CXXRecordDecl *, uint64_t> NumVirtualFunctionPointers; + typedef llvm::DenseMap<GlobalDecl, AdjustmentVectorTy> SavedAdjustmentsTy; + SavedAdjustmentsTy SavedAdjustments; + llvm::DenseSet<const CXXRecordDecl*> SavedAdjustmentRecords; + /// getNumVirtualFunctionPointers - Return the number of virtual function /// pointers in the vtable for a given record decl. uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD); @@ -94,8 +102,19 @@ class CGVtableInfo { /// GenerateClassData - Generate all the class data requires to be generated /// upon definition of a KeyFunction. This includes the vtable, the /// rtti data structure and the VTT. - void GenerateClassData(const CXXRecordDecl *RD); - + /// + /// \param Linkage - The desired linkage of the vtable, the RTTI and the VTT. + void GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD); + + llvm::GlobalVariable * + GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage, + bool GenerateDefinition, const CXXRecordDecl *LayoutClass, + const CXXRecordDecl *RD, uint64_t Offset); + + llvm::GlobalVariable *GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, + const CXXRecordDecl *RD); + public: CGVtableInfo(CodeGenModule &CGM) : CGM(CGM) { } @@ -113,9 +132,17 @@ public: 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); + AdjustmentVectorTy *getAdjustments(GlobalDecl GD); + + /// getVtableAddressPoint - returns the address point of the vtable for the + /// given record decl. + /// FIXME: This should return a list of address points. + uint64_t getVtableAddressPoint(const CXXRecordDecl *RD); + + llvm::GlobalVariable *getVtable(const CXXRecordDecl *RD); + llvm::GlobalVariable *getCtorVtable(const CXXRecordDecl *RD, + const CXXRecordDecl *Class, + uint64_t Offset); void MaybeEmitVtable(GlobalDecl GD); diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index 9281416..3c26484 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -8,6 +8,7 @@ add_clang_library(clangCodeGen CGCXX.cpp CGDebugInfo.cpp CGDecl.cpp + CGDeclCXX.cpp CGException.cpp CGExpr.cpp CGExprAgg.cpp @@ -19,7 +20,7 @@ add_clang_library(clangCodeGen CGObjCGNU.cpp CGObjCMac.cpp CGRecordLayoutBuilder.cpp - CGRtti.cpp + CGRTTI.cpp CGStmt.cpp CGTemporaries.cpp CGVtable.cpp diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 6e0a77c..28df9e4 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -19,6 +19,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/StmtCXX.h" #include "llvm/Target/TargetData.h" using namespace clang; using namespace CodeGen; @@ -30,9 +31,12 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) DebugInfo(0), IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0), CXXThisDecl(0), CXXVTTDecl(0), - ConditionalBranchLevel(0) { + ConditionalBranchLevel(0), TerminateHandler(0), TrapBB(0), + UniqueAggrDestructorCount(0) { LLVMIntTy = ConvertType(getContext().IntTy); LLVMPointerWidth = Target.getPointerWidth(0); + Exceptions = getContext().getLangOptions().Exceptions; + CatchUndefined = getContext().getLangOptions().CatchUndefined; } ASTContext &CodeGenFunction::getContext() const { @@ -130,6 +134,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { } EmitFunctionEpilog(*CurFnInfo, ReturnValue); + EmitEndEHSpec(CurCodeDecl); // If someone did an indirect goto, emit the indirect goto block at the end of // the function. @@ -179,9 +184,6 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, AllocaInsertPt->setName("allocapt"); ReturnBlock = createBasicBlock("return"); - ReturnValue = 0; - if (!RetTy->isVoidType()) - ReturnValue = CreateTempAlloca(ConvertType(RetTy), "retval"); Builder.SetInsertPoint(EntryBB); @@ -195,15 +197,26 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, DI->EmitFunctionStart(CGM.getMangledName(GD), FnType, CurFn, Builder); } else { // Just use LLVM function name. - - // FIXME: Remove unnecessary conversion to std::string when API settles. - DI->EmitFunctionStart(std::string(Fn->getName()).c_str(), - FnType, CurFn, Builder); + DI->EmitFunctionStart(Fn->getName(), FnType, CurFn, Builder); } } // FIXME: Leaked. CurFnInfo = &CGM.getTypes().getFunctionInfo(FnRetTy, Args); + + if (RetTy->isVoidType()) { + // Void type; nothing to return. + ReturnValue = 0; + } else if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect && + hasAggregateLLVMType(CurFnInfo->getReturnType())) { + // Indirect aggregate return; emit returned value directly into sret slot. + // This reduces code size, and is also affects correctness in C++. + ReturnValue = CurFn->arg_begin(); + } else { + ReturnValue = CreateTempAlloca(ConvertType(RetTy), "retval"); + } + + EmitStartEHSpec(CurCodeDecl); EmitFunctionProlog(*CurFnInfo, CurFn, Args); // If any of the arguments have a variably modified type, make sure to @@ -245,6 +258,8 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, FunctionArgList Args; + CurGD = GD; + OuterTryBlock = 0; if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { if (MD->isInstance()) { // Create the implicit 'this' decl. @@ -276,7 +291,6 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, FProto->getArgType(i))); } - // FIXME: Support CXXTryStmt here, too. if (const CompoundStmt *S = FD->getCompoundBody()) { StartFunction(GD, FD->getResultType(), Fn, Args, S->getLBracLoc()); @@ -341,6 +355,13 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, } else { assert(false && "Cannot synthesize unknown implicit function"); } + } else if (const Stmt *S = FD->getBody()) { + if (const CXXTryStmt *TS = dyn_cast<CXXTryStmt>(S)) { + OuterTryBlock = TS; + StartFunction(GD, FD->getResultType(), Fn, Args, TS->getTryLoc()); + EmitStmt(TS); + FinishFunction(TS->getEndLoc()); + } } // Destroy the 'this' declaration. @@ -606,8 +627,11 @@ llvm::Value* CodeGenFunction::EmitVAListRef(const Expr* E) { } void CodeGenFunction::PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock, - llvm::BasicBlock *CleanupExitBlock) { - CleanupEntries.push_back(CleanupEntry(CleanupEntryBlock, CleanupExitBlock)); + llvm::BasicBlock *CleanupExitBlock, + llvm::BasicBlock *PreviousInvokeDest, + bool EHOnly) { + CleanupEntries.push_back(CleanupEntry(CleanupEntryBlock, CleanupExitBlock, + PreviousInvokeDest, EHOnly)); } void CodeGenFunction::EmitCleanupBlocks(size_t OldCleanupStackSize) { @@ -629,6 +653,10 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() { std::vector<llvm::BranchInst *> BranchFixups; std::swap(BranchFixups, CE.BranchFixups); + bool EHOnly = CE.EHOnly; + + setInvokeDest(CE.PreviousInvokeDest); + CleanupEntries.pop_back(); // Check if any branch fixups pointed to the scope we just popped. If so, @@ -663,8 +691,9 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() { Builder.SetInsertPoint(SwitchBlock); - llvm::Value *DestCodePtr = CreateTempAlloca(llvm::Type::getInt32Ty(VMContext), - "cleanup.dst"); + llvm::Value *DestCodePtr + = CreateTempAlloca(llvm::Type::getInt32Ty(VMContext), + "cleanup.dst"); llvm::Value *DestCode = Builder.CreateLoad(DestCodePtr, "tmp"); // Create a switch instruction to determine where to jump next. @@ -710,15 +739,16 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() { new llvm::StoreInst(ID, DestCodePtr, BI); } else { // We need to jump through another cleanup block. Create a pad block - // with a branch instruction that jumps to the final destination and - // add it as a branch fixup to the current cleanup scope. + // with a branch instruction that jumps to the final destination and add + // it as a branch fixup to the current cleanup scope. // Create the pad block. llvm::BasicBlock *CleanupPad = createBasicBlock("cleanup.pad", CurFn); // Create a unique case ID. - llvm::ConstantInt *ID = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), - SI->getNumSuccessors()); + llvm::ConstantInt *ID + = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + SI->getNumSuccessors()); // Store the jump destination before the branch instruction. new llvm::StoreInst(ID, DestCodePtr, BI); @@ -744,12 +774,19 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() { BlockScopes.erase(Blocks[i]); } - return CleanupBlockInfo(CleanupEntryBlock, SwitchBlock, EndBlock); + return CleanupBlockInfo(CleanupEntryBlock, SwitchBlock, EndBlock, EHOnly); } void CodeGenFunction::EmitCleanupBlock() { CleanupBlockInfo Info = PopCleanupBlock(); + if (Info.EHOnly) { + // FIXME: Add this to the exceptional edge + if (Info.CleanupBlock->getNumUses() == 0) + delete Info.CleanupBlock; + return; + } + llvm::BasicBlock *CurBB = Builder.GetInsertBlock(); if (CurBB && !CurBB->getTerminator() && Info.CleanupBlock->getNumUses() == 0) { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 7f32045..12e636c 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -88,11 +88,17 @@ public: QualType FnRetTy; llvm::Function *CurFn; + /// CurGD - The GlobalDecl for the current function being compiled. + GlobalDecl CurGD; + /// OuterTryBlock - This is the address of the outter most try block, 0 + /// otherwise. + const Stmt *OuterTryBlock; + /// ReturnBlock - Unified return block. llvm::BasicBlock *ReturnBlock; /// ReturnValue - The temporary alloca to hold the return value. This is null /// iff the function has no return value. - llvm::Instruction *ReturnValue; + llvm::Value *ReturnValue; /// AllocaInsertPoint - This is an instruction in the entry block before which /// we prefer to insert allocas. @@ -101,6 +107,8 @@ public: const llvm::Type *LLVMIntTy; uint32_t LLVMPointerWidth; + bool Exceptions; + bool CatchUndefined; public: /// ObjCEHValueStack - Stack of Objective-C exception values, used for /// rethrows. @@ -109,7 +117,12 @@ public: /// PushCleanupBlock - Push a new cleanup entry on the stack and set the /// passed in block as the cleanup block. void PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock, - llvm::BasicBlock *CleanupExitBlock = 0); + llvm::BasicBlock *CleanupExitBlock, + llvm::BasicBlock *PreviousInvokeDest, + bool EHOnly = false); + void PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock) { + PushCleanupBlock(CleanupEntryBlock, 0, getInvokeDest(), false); + } /// CleanupBlockInfo - A struct representing a popped cleanup block. struct CleanupBlockInfo { @@ -123,14 +136,43 @@ public: /// EndBlock - the default destination for the switch instruction. llvm::BasicBlock *EndBlock; + /// EHOnly - True iff this cleanup should only be performed on the + /// exceptional edge. + bool EHOnly; + CleanupBlockInfo(llvm::BasicBlock *cb, llvm::BasicBlock *sb, - llvm::BasicBlock *eb) - : CleanupBlock(cb), SwitchBlock(sb), EndBlock(eb) {} + llvm::BasicBlock *eb, bool ehonly = false) + : CleanupBlock(cb), SwitchBlock(sb), EndBlock(eb), EHOnly(ehonly) {} + }; + + /// EHCleanupBlock - RAII object that will create a cleanup block for the + /// exceptional edge and set the insert point to that block. When destroyed, + /// it creates the cleanup edge and sets the insert point to the previous + /// block. + class EHCleanupBlock { + CodeGenFunction& CGF; + llvm::BasicBlock *Cont; + llvm::BasicBlock *CleanupHandler; + llvm::BasicBlock *CleanupEntryBB; + llvm::BasicBlock *PreviousInvokeDest; + public: + EHCleanupBlock(CodeGenFunction &cgf) + : CGF(cgf), Cont(CGF.createBasicBlock("cont")), + CleanupHandler(CGF.createBasicBlock("ehcleanup")), + CleanupEntryBB(CGF.createBasicBlock("ehcleanup.rest")), + PreviousInvokeDest(CGF.getInvokeDest()) { + CGF.EmitBranch(Cont); + llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler(); + CGF.Builder.SetInsertPoint(CleanupEntryBB); + CGF.setInvokeDest(TerminateHandler); + } + ~EHCleanupBlock(); }; /// PopCleanupBlock - Will pop the cleanup entry on the stack, process all /// branch fixups and return a block info struct with the switch block and end - /// block. + /// block. This will also reset the invoke handler to the previous value + /// from when the cleanup block was created. CleanupBlockInfo PopCleanupBlock(); /// DelayedCleanupBlock - RAII object that will create a cleanup block and set @@ -141,11 +183,15 @@ public: llvm::BasicBlock *CurBB; llvm::BasicBlock *CleanupEntryBB; llvm::BasicBlock *CleanupExitBB; + llvm::BasicBlock *CurInvokeDest; + bool EHOnly; public: - DelayedCleanupBlock(CodeGenFunction &cgf) + DelayedCleanupBlock(CodeGenFunction &cgf, bool ehonly = false) : CGF(cgf), CurBB(CGF.Builder.GetInsertBlock()), - CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0) { + CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0), + CurInvokeDest(CGF.getInvokeDest()), + EHOnly(ehonly) { CGF.Builder.SetInsertPoint(CleanupEntryBB); } @@ -156,7 +202,8 @@ public: } ~DelayedCleanupBlock() { - CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB); + CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB, CurInvokeDest, + EHOnly); // FIXME: This is silly, move this into the builder. if (CurBB) CGF.Builder.SetInsertPoint(CurBB); @@ -303,10 +350,21 @@ private: /// inserted into the current function yet. std::vector<llvm::BranchInst *> BranchFixups; + /// PreviousInvokeDest - The invoke handler from the start of the cleanup + /// region. + llvm::BasicBlock *PreviousInvokeDest; + + /// EHOnly - Perform this only on the exceptional edge, not the main edge. + bool EHOnly; + explicit CleanupEntry(llvm::BasicBlock *CleanupEntryBlock, - llvm::BasicBlock *CleanupExitBlock) - : CleanupEntryBlock(CleanupEntryBlock), - CleanupExitBlock(CleanupExitBlock) {} + llvm::BasicBlock *CleanupExitBlock, + llvm::BasicBlock *PreviousInvokeDest, + bool ehonly) + : CleanupEntryBlock(CleanupEntryBlock), + CleanupExitBlock(CleanupExitBlock), + PreviousInvokeDest(PreviousInvokeDest), + EHOnly(ehonly) {} }; /// CleanupEntries - Stack of cleanup entries. @@ -365,7 +423,11 @@ private: /// getByrefValueFieldNumber - Given a declaration, returns the LLVM field /// number that holds the value. unsigned getByRefValueLLVMField(const ValueDecl *VD) const; - + + llvm::BasicBlock *TerminateHandler; + llvm::BasicBlock *TrapBB; + + int UniqueAggrDestructorCount; public: CodeGenFunction(CodeGenModule &cgm); @@ -441,16 +503,18 @@ public: const ThunkAdjustment &Adjustment); /// GenerateThunk - Generate a thunk for the given method - llvm::Constant *GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD, + llvm::Constant *GenerateThunk(llvm::Function *Fn, GlobalDecl GD, bool Extern, const ThunkAdjustment &ThisAdjustment); llvm::Constant * - GenerateCovariantThunk(llvm::Function *Fn, const CXXMethodDecl *MD, + GenerateCovariantThunk(llvm::Function *Fn, GlobalDecl GD, bool Extern, const CovariantThunkAdjustment &Adjustment); void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type); + void InitializeVtablePtrs(const CXXRecordDecl *ClassDecl); + void SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, CXXCtorType Type, llvm::Function *Fn, @@ -487,6 +551,15 @@ public: /// given temporary. void EmitFunctionEpilog(const CGFunctionInfo &FI, llvm::Value *ReturnValue); + /// EmitStartEHSpec - Emit the start of the exception spec. + void EmitStartEHSpec(const Decl *D); + + /// EmitEndEHSpec - Emit the end of the exception spec. + void EmitEndEHSpec(const Decl *D); + + /// getTerminateHandler - Return a handler that just calls terminate. + llvm::BasicBlock *getTerminateHandler(); + const llvm::Type *ConvertTypeForMem(QualType T); const llvm::Type *ConvertType(QualType T); @@ -903,6 +976,7 @@ public: LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E); LValue EmitExtVectorElementExpr(const ExtVectorElementExpr *E); LValue EmitMemberExpr(const MemberExpr *E); + LValue EmitObjCIsaExpr(const ObjCIsaExpr *E); LValue EmitCompoundLiteralLValue(const CompoundLiteralExpr *E); LValue EmitConditionalOperatorLValue(const ConditionalOperator *E); LValue EmitCastLValue(const CastExpr *E); @@ -1059,9 +1133,18 @@ public: /// CreateStaticBlockVarDecl - Create a zero-initialized LLVM global for a /// static block var decl. - llvm::GlobalVariable * CreateStaticBlockVarDecl(const VarDecl &D, - const char *Separator, + llvm::GlobalVariable *CreateStaticBlockVarDecl(const VarDecl &D, + const char *Separator, llvm::GlobalValue::LinkageTypes Linkage); + + /// AddInitializerToGlobalBlockVarDecl - Add the initializer for 'D' to the + /// global variable that has already been created for it. If the initializer + /// has a different type than GV does, this may free GV and return a different + /// one. Otherwise it just returns GV. + llvm::GlobalVariable * + AddInitializerToGlobalBlockVarDecl(const VarDecl &D, + llvm::GlobalVariable *GV); + /// EmitStaticCXXBlockVarDeclInit - Create the initializer for a C++ runtime /// initialized static block var decl. @@ -1112,6 +1195,10 @@ public: /// try to simplify the codegen of the conditional based on the branch. void EmitBranchOnBoolExpr(const Expr *Cond, llvm::BasicBlock *TrueBlock, llvm::BasicBlock *FalseBlock); + + /// getTrapBB - Create a basic block that will call the trap intrinsic. We'll + /// generate a branch around the created basic block as necessary. + llvm::BasicBlock* getTrapBB(); private: void EmitReturnOfRValue(RValue RV, QualType Ty); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 4b3b122..761f343 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -56,7 +56,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, Runtime = CreateMacObjCRuntime(*this); // If debug info generation is enabled, create the CGDebugInfo object. - DebugInfo = CodeGenOpts.DebugInfo ? new CGDebugInfo(this) : 0; + DebugInfo = CodeGenOpts.DebugInfo ? new CGDebugInfo(*this) : 0; } CodeGenModule::~CodeGenModule() { @@ -256,9 +256,18 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, // The kind of external linkage this function will have, if it is not // inline or static. CodeGenModule::GVALinkage External = CodeGenModule::GVA_StrongExternal; - if (Context.getLangOptions().CPlusPlus && - FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) - External = CodeGenModule::GVA_TemplateInstantiation; + if (Context.getLangOptions().CPlusPlus) { + TemplateSpecializationKind TSK = FD->getTemplateSpecializationKind(); + + if (TSK == TSK_ExplicitInstantiationDefinition) { + // If a function has been explicitly instantiated, then it should + // always have strong external linkage. + return CodeGenModule::GVA_StrongExternal; + } + + if (TSK == TSK_ImplicitInstantiation) + External = CodeGenModule::GVA_TemplateInstantiation; + } if (!FD->isInlined()) return External; @@ -522,6 +531,16 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) { FD->hasAttr<DestructorAttr>()) return false; + // The key function for a class must never be deferred. + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Global)) { + const CXXRecordDecl *RD = MD->getParent(); + if (MD->isOutOfLine() && RD->isDynamicClass()) { + const CXXMethodDecl *KeyFunction = getContext().getKeyFunction(RD); + if (KeyFunction == MD->getCanonicalDecl()) + return false; + } + } + GVALinkage Linkage = GetLinkageForFunction(getContext(), FD, Features); // static, static inline, always_inline, and extern inline functions can @@ -576,11 +595,17 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { const VarDecl *VD = cast<VarDecl>(Global); assert(VD->isFileVarDecl() && "Cannot emit local var decl as global."); - // In C++, if this is marked "extern", defer code generation. - if (getLangOptions().CPlusPlus && !VD->getInit() && - (VD->getStorageClass() == VarDecl::Extern || - VD->isExternC())) - return; + if (getLangOptions().CPlusPlus && !VD->getInit()) { + // In C++, if this is marked "extern", defer code generation. + if (VD->getStorageClass() == VarDecl::Extern || VD->isExternC()) + return; + + // If this is a declaration of an explicit specialization of a static + // data member in a class template, don't emit it. + if (VD->isStaticDataMember() && + VD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + return; + } // In C, if this isn't a definition, defer code generation. if (!getLangOptions().CPlusPlus && !VD->getInit()) @@ -615,8 +640,19 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { Context.getSourceManager(), "Generating code for declaration"); - if (isa<CXXMethodDecl>(D)) + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { getVtableInfo().MaybeEmitVtable(GD); + if (MD->isVirtual() && MD->isOutOfLine() && + (!isa<CXXDestructorDecl>(D) || GD.getDtorType() != Dtor_Base)) { + if (isa<CXXDestructorDecl>(D)) { + GlobalDecl CanonGD(cast<CXXDestructorDecl>(D->getCanonicalDecl()), + GD.getDtorType()); + BuildThunksForVirtual(CanonGD); + } else { + BuildThunksForVirtual(MD->getCanonicalDecl()); + } + } + } if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D)) EmitCXXConstructor(CD, GD.getCtorType()); @@ -724,6 +760,17 @@ CodeGenModule::CreateRuntimeFunction(const llvm::FunctionType *FTy, return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl()); } +static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D) { + if (!D->getType().isConstant(Context)) + return false; + if (Context.getLangOptions().CPlusPlus && + Context.getBaseElementType(D->getType())->getAs<RecordType>()) { + // FIXME: We should do something fancier here! + return false; + } + return true; +} + /// GetOrCreateLLVMGlobal - If the specified mangled name is not in the module, /// create and return an llvm GlobalVariable with the specified type. If there /// is something in the module with the specified name, return it potentially @@ -767,7 +814,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *MangledName, if (D) { // FIXME: This code is overly simple and should be merged with other global // handling. - GV->setConstant(D->getType().isConstant(Context)); + GV->setConstant(DeclIsConstantGlobal(Context, D)); // FIXME: Merge with other attribute handling code. if (D->getStorageClass() == VarDecl::PrivateExtern) @@ -844,7 +891,7 @@ GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) { return CodeGenModule::GVA_StrongExternal; case TSK_ExplicitInstantiationDeclaration: - llvm::llvm_unreachable("Variable should not be instantiated"); + llvm_unreachable("Variable should not be instantiated"); // Fall through to treat this like any other instantiation. case TSK_ImplicitInstantiation: @@ -942,11 +989,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { // If it is safe to mark the global 'constant', do so now. GV->setConstant(false); - if (D->getType().isConstant(Context)) { - // FIXME: In C++, if the variable has a non-trivial ctor/dtor or any mutable - // members, it cannot be declared "LLVM const". + if (DeclIsConstantGlobal(Context, D)) GV->setConstant(true); - } GV->setAlignment(getContext().getDeclAlignInBytes(D)); @@ -1226,13 +1270,8 @@ llvm::Value *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD, if (Context.BuiltinInfo.isLibFunction(BuiltinID)) Name += 10; - // Get the type for the builtin. - ASTContext::GetBuiltinTypeError Error; - QualType Type = Context.GetBuiltinType(BuiltinID, Error); - assert(Error == ASTContext::GE_None && "Can't get builtin type"); - const llvm::FunctionType *Ty = - cast<llvm::FunctionType>(getTypes().ConvertType(Type)); + cast<llvm::FunctionType>(getTypes().ConvertType(FD->getType())); // Unique the name through the identifier table. Name = getContext().Idents.get(Name).getNameStart(); @@ -1658,14 +1697,13 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case Decl::FileScopeAsm: { FileScopeAsmDecl *AD = cast<FileScopeAsmDecl>(D); - std::string AsmString(AD->getAsmString()->getStrData(), - AD->getAsmString()->getByteLength()); + llvm::StringRef AsmString = AD->getAsmString()->getString(); const std::string &S = getModule().getModuleInlineAsm(); if (S.empty()) getModule().setModuleInlineAsm(AsmString); else - getModule().setModuleInlineAsm(S + '\n' + AsmString); + getModule().setModuleInlineAsm(S + '\n' + AsmString.str()); break; } diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 78bc4ed..cc7ec9c 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -212,34 +212,38 @@ 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 + /// GetAddrOfRTTI - Get the address of the RTTI structure for the given type. + llvm::Constant *GetAddrOfRTTI(QualType Ty); + + /// GetAddrOfRTTI - Get the address of the RTTI structure for the given record + /// decl. + llvm::Constant *GetAddrOfRTTI(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 + llvm::Constant *GenerateRTTIRef(const CXXRecordDecl *RD); + + /// GenerateRTTI - Generate the rtti information for the given /// non-class type. - llvm::Constant *GenerateRtti(QualType Ty); + llvm::Constant *GenerateRTTI(QualType Ty); + + llvm::Constant *GetAddrOfThunk(GlobalDecl GD, + const ThunkAdjustment &ThisAdjustment); + llvm::Constant *GetAddrOfCovariantThunk(GlobalDecl GD, + const CovariantThunkAdjustment &ThisAdjustment); + void BuildThunksForVirtual(GlobalDecl GD); + void BuildThunksForVirtualRecursive(GlobalDecl GD, GlobalDecl BaseOGD); /// BuildThunk - Build a thunk for the given method. - llvm::Constant *BuildThunk(const CXXMethodDecl *MD, bool Extern, + llvm::Constant *BuildThunk(GlobalDecl GD, bool Extern, const ThunkAdjustment &ThisAdjustment); /// BuildCoVariantThunk - Build a thunk for the given method llvm::Constant * - BuildCovariantThunk(const CXXMethodDecl *MD, bool Extern, + BuildCovariantThunk(const GlobalDecl &GD, bool Extern, const CovariantThunkAdjustment &Adjustment); typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t; @@ -252,6 +256,11 @@ public: llvm::Constant *GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl, const CXXRecordDecl *BaseClassDecl); + /// ComputeThunkAdjustment - Returns the two parts required to compute the + /// offset for an object. + ThunkAdjustment ComputeThunkAdjustment(const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl); + /// GetStringForStringLiteral - Return the appropriate bytes for a string /// literal, properly padded to match the literal type. If only the address of /// a constant is needed consider using GetAddrOfConstantStringLiteral. diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index c89879f..cd3575c 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -379,13 +379,13 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { // If we ever want to support other ABIs this needs to be abstracted. QualType ETy = cast<MemberPointerType>(Ty).getPointeeType(); + const llvm::Type *PtrDiffTy = + ConvertTypeRecursive(Context.getPointerDiffType()); if (ETy->isFunctionType()) { - return llvm::StructType::get(TheModule.getContext(), - ConvertType(Context.getPointerDiffType()), - ConvertType(Context.getPointerDiffType()), + return llvm::StructType::get(TheModule.getContext(), PtrDiffTy, PtrDiffTy, NULL); } else - return ConvertType(Context.getPointerDiffType()); + return PtrDiffTy; } case Type::TemplateSpecialization: diff --git a/lib/CodeGen/GlobalDecl.h b/lib/CodeGen/GlobalDecl.h index b812020..b054312 100644 --- a/lib/CodeGen/GlobalDecl.h +++ b/lib/CodeGen/GlobalDecl.h @@ -96,15 +96,14 @@ namespace llvm { 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; - } - }; -} + // GlobalDecl isn't *technically* a POD type. However, its copy constructor, + // copy assignment operator, and destructor are all trivial. + template <> + struct isPodLike<clang::CodeGen::GlobalDecl> { + static const bool value = true; + }; +} // end namespace llvm #endif diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index d6f7808..90cc894 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -89,8 +89,6 @@ private: void addSubstitution(QualType T); void addSubstitution(uintptr_t Ptr); - bool mangleFunctionDecl(const FunctionDecl *FD); - void mangleName(const TemplateDecl *TD, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); @@ -99,7 +97,7 @@ private: void mangleUnscopedTemplateName(const TemplateDecl *ND); void mangleSourceName(const IdentifierInfo *II); void mangleLocalName(const NamedDecl *ND); - void mangleNestedName(const NamedDecl *ND); + void mangleNestedName(const NamedDecl *ND, const DeclContext *DC); void mangleNestedName(const TemplateDecl *TD, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); @@ -108,6 +106,8 @@ private: void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); void mangleQualifiers(Qualifiers Quals); + void mangleObjCMethodName(const ObjCMethodDecl *MD); + // Declare manglers for every type class. #define ABSTRACT_TYPE(CLASS, PARENT) #define NON_CANONICAL_TYPE(CLASS, PARENT) @@ -117,6 +117,8 @@ private: void mangleType(const TagType*); void mangleBareFunctionType(const FunctionType *T, bool MangleReturnType); + + void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value); void mangleExpression(const Expr *E); void mangleCXXCtorType(CXXCtorType T); void mangleCXXDtorType(CXXDtorType T); @@ -169,11 +171,19 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) { isInExternCSystemHeader(D->getLocation())) return false; - // C functions, "main", and variables at global scope are not - // mangled. - if ((FD && FD->isMain()) || - (!FD && D->getDeclContext()->isTranslationUnit()) || - isInCLinkageSpecification(D)) + // Variables at global scope are not mangled. + if (!FD) { + const DeclContext *DC = D->getDeclContext(); + // Check for extern variable declared locally. + if (isa<FunctionDecl>(DC) && D->hasLinkage()) + while (!DC->isNamespace() && !DC->isTranslationUnit()) + DC = DC->getParent(); + if (DC->isTranslationUnit()) + return false; + } + + // C functions and "main" are not mangled. + if ((FD && FD->isMain()) || isInCLinkageSpecification(D)) return false; return true; @@ -241,14 +251,32 @@ void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { mangleBareFunctionType(FT, MangleReturnType); } -static bool isStdNamespace(const NamespaceDecl *NS) { +/// isStd - Return whether a given namespace is the 'std' namespace. +static bool isStd(const NamespaceDecl *NS) { const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier(); return II && II->isStr("std"); } +static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) { + while (isa<LinkageSpecDecl>(DC)) { + assert(cast<LinkageSpecDecl>(DC)->getLanguage() == + LinkageSpecDecl::lang_cxx && "Unexpected linkage decl!"); + DC = DC->getParent(); + } + + return DC; +} + +// isStdNamespace - Return whether a given decl context is a toplevel 'std' +// namespace. static bool isStdNamespace(const DeclContext *DC) { - return DC->isNamespace() && DC->getParent()->isTranslationUnit() && - isStdNamespace(cast<NamespaceDecl>(DC)); + if (!DC->isNamespace()) + return false; + + if (!IgnoreLinkageSpecDecls(DC->getParent())->isTranslationUnit()) + return false; + + return isStd(cast<NamespaceDecl>(DC)); } static const TemplateDecl * @@ -278,6 +306,13 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) { // ::= <local-name> // const DeclContext *DC = ND->getDeclContext(); + + // If this is an extern variable declared locally, the relevant DeclContext + // is that of the containing namespace, or the translation unit. + if (isa<FunctionDecl>(DC) && ND->hasLinkage()) + while (!DC->isNamespace() && !DC->isTranslationUnit()) + DC = DC->getParent(); + while (isa<LinkageSpecDecl>(DC)) DC = DC->getParent(); @@ -294,22 +329,17 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) { return; } - if (isa<FunctionDecl>(DC)) { + if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)) { mangleLocalName(ND); return; } - mangleNestedName(ND); + mangleNestedName(ND, DC); } void CXXNameMangler::mangleName(const TemplateDecl *TD, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs) { - const DeclContext *DC = TD->getDeclContext(); - while (isa<LinkageSpecDecl>(DC)) { - assert(cast<LinkageSpecDecl>(DC)->getLanguage() == - LinkageSpecDecl::lang_cxx && "Unexpected linkage decl!"); - DC = DC->getParent(); - } + const DeclContext *DC = IgnoreLinkageSpecDecls(TD->getDeclContext()); if (DC->isTranslationUnit() || isStdNamespace(DC)) { mangleUnscopedTemplateName(TD); @@ -456,8 +486,8 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) { break; case DeclarationName::CXXLiteralOperatorName: - // Guessing based on existing ABI. - Out << "ul"; + // FIXME: This mangling is not yet official. + Out << "li"; mangleSourceName(Name.getCXXLiteralIdentifier()); break; @@ -474,7 +504,8 @@ void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) { Out << II->getLength() << II->getName(); } -void CXXNameMangler::mangleNestedName(const NamedDecl *ND) { +void CXXNameMangler::mangleNestedName(const NamedDecl *ND, + const DeclContext *DC) { // <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E // ::= N [<CV-qualifiers>] <template-prefix> <template-args> E @@ -488,7 +519,7 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND) { mangleTemplatePrefix(TD); mangleTemplateArgumentList(*TemplateArgs); } else { - manglePrefix(ND->getDeclContext()); + manglePrefix(DC); mangleUnqualifiedName(ND); } @@ -512,9 +543,14 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) { // := Z <function encoding> E s [<discriminator>] // <discriminator> := _ <non-negative number> Out << 'Z'; - mangleFunctionEncoding(cast<FunctionDecl>(ND->getDeclContext())); + + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ND->getDeclContext())) + mangleObjCMethodName(MD); + else + mangleFunctionEncoding(cast<FunctionDecl>(ND->getDeclContext())); + Out << 'E'; - mangleSourceName(ND->getIdentifier()); + mangleUnqualifiedName(ND); } void CXXNameMangler::manglePrefix(const DeclContext *DC) { @@ -523,7 +559,6 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC) { // ::= <template-param> // ::= # empty // ::= <substitution> - // FIXME: We only handle mangling of namespaces and classes at the moment. while (isa<LinkageSpecDecl>(DC)) DC = DC->getParent(); @@ -654,10 +689,13 @@ CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) { case OO_Call: Out << "cl"; break; // ::= ix # [] case OO_Subscript: Out << "ix"; break; - // UNSUPPORTED: ::= qu # ? + + // ::= qu # ? + // The conditional operator can't be overloaded, but we still handle it when + // mangling expressions. + case OO_Conditional: Out << "qu"; break; case OO_None: - case OO_Conditional: case NUM_OVERLOADED_OPERATORS: assert(false && "Not an overloaded operator"); break; @@ -676,6 +714,21 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { // FIXME: For now, just drop all extension qualifiers on the floor. } +void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { + llvm::SmallString<64> Name; + llvm::raw_svector_ostream OS(Name); + + const ObjCContainerDecl *CD = + dyn_cast<ObjCContainerDecl>(MD->getDeclContext()); + assert (CD && "Missing container decl in GetNameForMethod"); + OS << (MD->isInstanceMethod() ? '-' : '+') << '[' << CD->getName(); + if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(CD)) + OS << '(' << CID->getNameAsString() << ')'; + OS << ' ' << MD->getSelector().getAsString() << ']'; + + Out << OS.str().size() << OS.str(); +} + void CXXNameMangler::mangleType(QualType T) { // Only operate on the canonical type! T = Context.getASTContext().getCanonicalType(T); @@ -694,7 +747,7 @@ void CXXNameMangler::mangleType(QualType T) { #define ABSTRACT_TYPE(CLASS, PARENT) #define NON_CANONICAL_TYPE(CLASS, PARENT) \ case Type::CLASS: \ - llvm::llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \ + llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \ return; #define TYPE(CLASS, PARENT) \ case Type::CLASS: \ @@ -788,7 +841,7 @@ void CXXNameMangler::mangleType(const FunctionProtoType *T) { Out << 'E'; } void CXXNameMangler::mangleType(const FunctionNoProtoType *T) { - llvm::llvm_unreachable("Can't mangle K&R function prototypes"); + llvm_unreachable("Can't mangle K&R function prototypes"); } void CXXNameMangler::mangleBareFunctionType(const FunctionType *T, bool MangleReturnType) { @@ -816,6 +869,12 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T, // <type> ::= <class-enum-type> // <class-enum-type> ::= <name> +void CXXNameMangler::mangleType(const UnresolvedUsingType *T) { + mangleName(T->getDecl()); +} + +// <type> ::= <class-enum-type> +// <class-enum-type> ::= <name> void CXXNameMangler::mangleType(const EnumType *T) { mangleType(static_cast<const TagType*>(T)); } @@ -823,10 +882,7 @@ void CXXNameMangler::mangleType(const RecordType *T) { mangleType(static_cast<const TagType*>(T)); } void CXXNameMangler::mangleType(const TagType *T) { - if (!T->getDecl()->getIdentifier()) - mangleName(T->getDecl()->getTypedefForAnonDecl()); - else - mangleName(T->getDecl()); + mangleName(T->getDecl()); } // <type> ::= <array-type> @@ -960,6 +1016,24 @@ void CXXNameMangler::mangleType(const TypenameType *T) { Out << 'E'; } +void CXXNameMangler::mangleIntegerLiteral(QualType T, + const llvm::APSInt &Value) { + // <expr-primary> ::= L <type> <value number> E # integer literal + Out << 'L'; + + mangleType(T); + if (T->isBooleanType()) { + // Boolean values are encoded as 0/1. + Out << (Value.getBoolValue() ? '1' : '0'); + } else { + if (Value.isNegative()) + Out << 'n'; + Value.abs().print(Out, false); + } + Out << 'E'; + +} + void CXXNameMangler::mangleExpression(const Expr *E) { // <expression> ::= <unary operator-name> <expression> // ::= <binary operator-name> <expression> <expression> @@ -978,6 +1052,32 @@ void CXXNameMangler::mangleExpression(const Expr *E) { switch (E->getStmtClass()) { default: assert(false && "Unhandled expression kind!"); + case Expr::UnaryOperatorClass: { + const UnaryOperator *UO = cast<UnaryOperator>(E); + mangleOperatorName(UnaryOperator::getOverloadedOperator(UO->getOpcode()), + /*Arity=*/1); + mangleExpression(UO->getSubExpr()); + break; + } + + case Expr::BinaryOperatorClass: { + const BinaryOperator *BO = cast<BinaryOperator>(E); + mangleOperatorName(BinaryOperator::getOverloadedOperator(BO->getOpcode()), + /*Arity=*/2); + mangleExpression(BO->getLHS()); + mangleExpression(BO->getRHS()); + break; + } + + case Expr::ConditionalOperatorClass: { + const ConditionalOperator *CO = cast<ConditionalOperator>(E); + mangleOperatorName(OO_Conditional, /*Arity=*/3); + mangleExpression(CO->getCond()); + mangleExpression(CO->getLHS()); + mangleExpression(CO->getRHS()); + break; + } + case Expr::ParenExprClass: mangleExpression(cast<ParenExpr>(E)->getSubExpr()); break; @@ -1014,6 +1114,11 @@ void CXXNameMangler::mangleExpression(const Expr *E) { break; } + case Expr::IntegerLiteralClass: + mangleIntegerLiteral(E->getType(), + llvm::APSInt(cast<IntegerLiteral>(E)->getValue())); + break; + } } @@ -1090,23 +1195,9 @@ void CXXNameMangler::mangleTemplateArgument(const TemplateArgument &A) { mangleExpression(A.getAsExpr()); Out << 'E'; break; - case TemplateArgument::Integral: { - // <expr-primary> ::= L <type> <value number> E # integer literal - - const llvm::APSInt *Integral = A.getAsIntegral(); - Out << 'L'; - mangleType(A.getIntegralType()); - if (A.getIntegralType()->isBooleanType()) { - // Boolean values are encoded as 0/1. - Out << (Integral->getBoolValue() ? '1' : '0'); - } else { - if (Integral->isNegative()) - Out << 'n'; - Integral->abs().print(Out, false); - } - Out << 'E'; + case TemplateArgument::Integral: + mangleIntegerLiteral(A.getIntegralType(), *A.getAsIntegral()); break; - } case TemplateArgument::Declaration: { // <expr-primary> ::= L <mangled-name> E # external name @@ -1228,12 +1319,29 @@ static bool isCharSpecialization(QualType T, const char *Name) { return SD->getIdentifier()->getName() == Name; } +template <std::size_t StrLen> +bool isStreamCharSpecialization(const ClassTemplateSpecializationDecl *SD, + const char (&Str)[StrLen]) { + if (!SD->getIdentifier()->isStr(Str)) + return false; + + const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); + if (TemplateArgs.size() != 2) + return false; + + if (!isCharType(TemplateArgs[0].getAsType())) + return false; + + if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits")) + return false; + + return true; +} + 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)) { + if (isStd(NS)) { Out << "St"; return true; } @@ -1280,23 +1388,26 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { return true; } - // <substitution> ::= So # ::std::basic_ostream<char, + // <substitution> ::= Si # ::std::basic_istream<char, // ::std::char_traits<char> > - if (SD->getIdentifier()->isStr("basic_ostream")) { - const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); - - if (TemplateArgs.size() != 2) - return false; - - if (!isCharType(TemplateArgs[0].getAsType())) - return false; - - if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits")) - return false; + if (isStreamCharSpecialization(SD, "basic_istream")) { + Out << "Si"; + return true; + } + // <substitution> ::= So # ::std::basic_ostream<char, + // ::std::char_traits<char> > + if (isStreamCharSpecialization(SD, "basic_ostream")) { Out << "So"; return true; } + + // <substitution> ::= Sd # ::std::basic_iostream<char, + // ::std::char_traits<char> > + if (isStreamCharSpecialization(SD, "basic_iostream")) { + Out << "Sd"; + return true; + } } return false; } @@ -1362,7 +1473,6 @@ void MangleContext::mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, void MangleContext::mangleThunk(const FunctionDecl *FD, const ThunkAdjustment &ThisAdjustment, llvm::SmallVectorImpl<char> &Res) { - // FIXME: Hum, we might have to thunk these, fix. assert(!isa<CXXDestructorDecl>(FD) && "Use mangleCXXDtor for destructor decls!"); @@ -1374,15 +1484,26 @@ void MangleContext::mangleThunk(const FunctionDecl *FD, Mangler.mangleFunctionEncoding(FD); } +void MangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *D, + CXXDtorType Type, + const ThunkAdjustment &ThisAdjustment, + llvm::SmallVectorImpl<char> &Res) { + // <special-name> ::= T <call-offset> <base encoding> + // # base is the nominal target function of thunk + CXXNameMangler Mangler(*this, Res, D, Type); + Mangler.getStream() << "_ZT"; + Mangler.mangleCallOffset(ThisAdjustment); + Mangler.mangleFunctionEncoding(D); +} + /// \brief Mangles the a covariant thunk for the declaration D and emits that /// name to the given output stream. void MangleContext::mangleCovariantThunk(const FunctionDecl *FD, const CovariantThunkAdjustment& Adjustment, llvm::SmallVectorImpl<char> &Res) { - // FIXME: Hum, we might have to thunk these, fix. assert(!isa<CXXDestructorDecl>(FD) && - "Use mangleCXXDtor for destructor decls!"); + "No such thing as a covariant thunk for a destructor!"); // <special-name> ::= Tc <call-offset> <call-offset> <base encoding> // # base is the nominal target function of thunk @@ -1434,7 +1555,7 @@ void MangleContext::mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset, Mangler.mangleName(Type); } -void MangleContext::mangleCXXRtti(QualType Ty, +void MangleContext::mangleCXXRTTI(QualType Ty, llvm::SmallVectorImpl<char> &Res) { // <special-name> ::= TI <type> # typeinfo structure CXXNameMangler Mangler(*this, Res); @@ -1442,7 +1563,7 @@ void MangleContext::mangleCXXRtti(QualType Ty, Mangler.mangleType(Ty); } -void MangleContext::mangleCXXRttiName(QualType Ty, +void MangleContext::mangleCXXRTTIName(QualType Ty, llvm::SmallVectorImpl<char> &Res) { // <special-name> ::= TS <type> # typeinfo name (null terminated byte string) CXXNameMangler Mangler(*this, Res); diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h index 65b1d9f..8d96295 100644 --- a/lib/CodeGen/Mangle.h +++ b/lib/CodeGen/Mangle.h @@ -67,6 +67,9 @@ public: void mangleThunk(const FunctionDecl *FD, const ThunkAdjustment &ThisAdjustment, llvm::SmallVectorImpl<char> &); + void mangleCXXDtorThunk(const CXXDestructorDecl *D, CXXDtorType Type, + const ThunkAdjustment &ThisAdjustment, + llvm::SmallVectorImpl<char> &); void mangleCovariantThunk(const FunctionDecl *FD, const CovariantThunkAdjustment& Adjustment, llvm::SmallVectorImpl<char> &); @@ -76,8 +79,8 @@ public: void mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset, const CXXRecordDecl *Type, llvm::SmallVectorImpl<char> &); - void mangleCXXRtti(QualType T, llvm::SmallVectorImpl<char> &); - void mangleCXXRttiName(QualType T, llvm::SmallVectorImpl<char> &); + void mangleCXXRTTI(QualType T, llvm::SmallVectorImpl<char> &); + void mangleCXXRTTIName(QualType T, llvm::SmallVectorImpl<char> &); void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, llvm::SmallVectorImpl<char> &); void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, diff --git a/lib/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp index 2bc6175..7be1ead 100644 --- a/lib/CodeGen/TargetABIInfo.cpp +++ b/lib/CodeGen/TargetABIInfo.cpp @@ -17,37 +17,37 @@ #include "clang/AST/RecordLayout.h" #include "llvm/Type.h" #include "llvm/ADT/Triple.h" -#include <cstdio> - +#include "llvm/Support/raw_ostream.h" using namespace clang; using namespace CodeGen; ABIInfo::~ABIInfo() {} void ABIArgInfo::dump() const { - fprintf(stderr, "(ABIArgInfo Kind="); + llvm::raw_ostream &OS = llvm::errs(); + OS << "(ABIArgInfo Kind="; switch (TheKind) { case Direct: - fprintf(stderr, "Direct"); + OS << "Direct"; break; case Extend: - fprintf(stderr, "Extend"); + OS << "Extend"; break; case Ignore: - fprintf(stderr, "Ignore"); + OS << "Ignore"; break; case Coerce: - fprintf(stderr, "Coerce Type="); - getCoerceToType()->print(llvm::errs()); + OS << "Coerce Type="; + getCoerceToType()->print(OS); break; case Indirect: - fprintf(stderr, "Indirect Align=%d", getIndirectAlign()); + OS << "Indirect Align=" << getIndirectAlign(); break; case Expand: - fprintf(stderr, "Expand"); + OS << "Expand"; break; } - fprintf(stderr, ")\n"); + OS << ")\n"; } static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays); diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 87357cf..dbe7bd9 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -41,9 +41,9 @@ using namespace clang; // Used to set values for "production" clang, for releases. // #define USE_PRODUCTION_CLANG -Driver::Driver(const char *_Name, const char *_Dir, - const char *_DefaultHostTriple, - const char *_DefaultImageName, +Driver::Driver(llvm::StringRef _Name, llvm::StringRef _Dir, + llvm::StringRef _DefaultHostTriple, + llvm::StringRef _DefaultImageName, bool IsProduction, Diagnostic &_Diags) : Opts(createDriverOptTable()), Diags(_Diags), Name(_Name), Dir(_Dir), DefaultHostTriple(_DefaultHostTriple), @@ -113,81 +113,57 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) { const char **Start = argv + 1, **End = argv + argc; const char *HostTriple = DefaultHostTriple.c_str(); - // Read -ccc args. + InputArgList *Args = ParseArgStrings(Start, End); + + // -no-canonical-prefixes is used very early in main. + Args->ClaimAllArgs(options::OPT_no_canonical_prefixes); + + // Extract -ccc args. // // FIXME: We need to figure out where this behavior should live. Most of it // should be outside in the client; the parts that aren't should have proper // options, either by introducing new ones or by overloading gcc ones like -V // or -b. - for (; Start != End && memcmp(*Start, "-ccc-", 5) == 0; ++Start) { - const char *Opt = *Start + 5; - - if (!strcmp(Opt, "print-options")) { - CCCPrintOptions = true; - } else if (!strcmp(Opt, "print-phases")) { - CCCPrintActions = true; - } else if (!strcmp(Opt, "print-bindings")) { - CCCPrintBindings = true; - } else if (!strcmp(Opt, "cxx")) { - CCCIsCXX = true; - } else if (!strcmp(Opt, "echo")) { - CCCEcho = true; - - } else if (!strcmp(Opt, "gcc-name")) { - assert(Start+1 < End && "FIXME: -ccc- argument handling."); - CCCGenericGCCName = *++Start; - - } else if (!strcmp(Opt, "clang-cxx")) { - CCCUseClangCXX = true; - } else if (!strcmp(Opt, "no-clang-cxx")) { - CCCUseClangCXX = false; - } else if (!strcmp(Opt, "pch-is-pch")) { - CCCUsePCH = true; - } else if (!strcmp(Opt, "pch-is-pth")) { - CCCUsePCH = false; - } else if (!strcmp(Opt, "no-clang")) { - CCCUseClang = false; - } else if (!strcmp(Opt, "no-clang-cpp")) { - CCCUseClangCPP = false; - } else if (!strcmp(Opt, "clang-archs")) { - assert(Start+1 < End && "FIXME: -ccc- argument handling."); - llvm::StringRef Cur = *++Start; - - CCCClangArchs.clear(); - while (!Cur.empty()) { - std::pair<llvm::StringRef, llvm::StringRef> Split = Cur.split(','); - - if (!Split.first.empty()) { - llvm::Triple::ArchType Arch = - llvm::Triple(Split.first, "", "").getArch(); - - if (Arch == llvm::Triple::UnknownArch) { - // FIXME: Error handling. - llvm::errs() << "invalid arch name: " << Split.first << "\n"; - exit(1); - } - - CCCClangArchs.insert(Arch); + CCCPrintOptions = Args->hasArg(options::OPT_ccc_print_options); + CCCPrintActions = Args->hasArg(options::OPT_ccc_print_phases); + CCCPrintBindings = Args->hasArg(options::OPT_ccc_print_bindings); + CCCIsCXX = Args->hasArg(options::OPT_ccc_cxx) || CCCIsCXX; + CCCEcho = Args->hasArg(options::OPT_ccc_echo); + if (const Arg *A = Args->getLastArg(options::OPT_ccc_gcc_name)) + CCCGenericGCCName = A->getValue(*Args); + CCCUseClangCXX = Args->hasFlag(options::OPT_ccc_clang_cxx, + options::OPT_ccc_no_clang_cxx, + CCCUseClangCXX); + CCCUsePCH = Args->hasFlag(options::OPT_ccc_pch_is_pch, + options::OPT_ccc_pch_is_pth); + CCCUseClang = !Args->hasArg(options::OPT_ccc_no_clang); + CCCUseClangCPP = !Args->hasArg(options::OPT_ccc_no_clang_cpp); + if (const Arg *A = Args->getLastArg(options::OPT_ccc_clang_archs)) { + llvm::StringRef Cur = A->getValue(*Args); + + CCCClangArchs.clear(); + while (!Cur.empty()) { + std::pair<llvm::StringRef, llvm::StringRef> Split = Cur.split(','); + + if (!Split.first.empty()) { + llvm::Triple::ArchType Arch = + llvm::Triple(Split.first, "", "").getArch(); + + if (Arch == llvm::Triple::UnknownArch) { + Diag(clang::diag::err_drv_invalid_arch_name) << Arch; + continue; } - Cur = Split.second; + CCCClangArchs.insert(Arch); } - } else if (!strcmp(Opt, "host-triple")) { - assert(Start+1 < End && "FIXME: -ccc- argument handling."); - HostTriple = *++Start; - } else if (!strcmp(Opt, "install-dir")) { - assert(Start+1 < End && "FIXME: -ccc- argument handling."); - Dir = *++Start; - - } else { - // FIXME: Error handling. - llvm::errs() << "invalid option: " << *Start << "\n"; - exit(1); + Cur = Split.second; } } - - InputArgList *Args = ParseArgStrings(Start, End); + if (const Arg *A = Args->getLastArg(options::OPT_ccc_host_triple)) + HostTriple = A->getValue(*Args); + if (const Arg *A = Args->getLastArg(options::OPT_ccc_install_dir)) + Dir = A->getValue(*Args); Host = GetHostInfo(HostTriple); @@ -287,110 +263,11 @@ void Driver::PrintOptions(const ArgList &Args) const { } } -static std::string getOptionHelpName(const OptTable &Opts, options::ID Id) { - std::string Name = Opts.getOptionName(Id); - - // Add metavar, if used. - switch (Opts.getOptionKind(Id)) { - case Option::GroupClass: case Option::InputClass: case Option::UnknownClass: - assert(0 && "Invalid option with help text."); - - case Option::MultiArgClass: case Option::JoinedAndSeparateClass: - assert(0 && "Cannot print metavar for this kind of option."); - - case Option::FlagClass: - break; - - case Option::SeparateClass: case Option::JoinedOrSeparateClass: - Name += ' '; - // FALLTHROUGH - case Option::JoinedClass: case Option::CommaJoinedClass: - Name += Opts.getOptionMetaVar(Id); - break; - } - - return Name; -} - +// FIXME: Move -ccc options to real options in the .td file (or eliminate), and +// then move to using OptTable::PrintHelp. void Driver::PrintHelp(bool ShowHidden) const { - llvm::raw_ostream &OS = llvm::outs(); - - OS << "OVERVIEW: clang \"gcc-compatible\" driver\n"; - OS << '\n'; - OS << "USAGE: " << Name << " [options] <input files>\n"; - OS << '\n'; - OS << "OPTIONS:\n"; - - // Render help text into (option, help) pairs. - std::vector< std::pair<std::string, const char*> > OptionHelp; - - for (unsigned i = 0, e = getOpts().getNumOptions(); i != e; ++i) { - options::ID Id = (options::ID) (i + 1); - if (const char *Text = getOpts().getOptionHelpText(Id)) - OptionHelp.push_back(std::make_pair(getOptionHelpName(getOpts(), Id), - Text)); - } - - if (ShowHidden) { - OptionHelp.push_back(std::make_pair("\nDRIVER OPTIONS:","")); - OptionHelp.push_back(std::make_pair("-ccc-cxx", - "Act as a C++ driver")); - OptionHelp.push_back(std::make_pair("-ccc-gcc-name", - "Name for native GCC compiler")); - OptionHelp.push_back(std::make_pair("-ccc-clang-cxx", - "Enable the clang compiler for C++")); - OptionHelp.push_back(std::make_pair("-ccc-no-clang-cxx", - "Disable the clang compiler for C++")); - OptionHelp.push_back(std::make_pair("-ccc-no-clang", - "Disable the clang compiler")); - OptionHelp.push_back(std::make_pair("-ccc-no-clang-cpp", - "Disable the clang preprocessor")); - OptionHelp.push_back(std::make_pair("-ccc-clang-archs", - "Comma separate list of architectures " - "to use the clang compiler for")); - OptionHelp.push_back(std::make_pair("-ccc-pch-is-pch", - "Use lazy PCH for precompiled headers")); - OptionHelp.push_back(std::make_pair("-ccc-pch-is-pth", - "Use pretokenized headers for precompiled headers")); - - OptionHelp.push_back(std::make_pair("\nDEBUG/DEVELOPMENT OPTIONS:","")); - OptionHelp.push_back(std::make_pair("-ccc-host-triple", - "Simulate running on the given target")); - OptionHelp.push_back(std::make_pair("-ccc-install-dir", - "Simulate installation in the given directory")); - OptionHelp.push_back(std::make_pair("-ccc-print-options", - "Dump parsed command line arguments")); - OptionHelp.push_back(std::make_pair("-ccc-print-phases", - "Dump list of actions to perform")); - OptionHelp.push_back(std::make_pair("-ccc-print-bindings", - "Show bindings of tools to actions")); - OptionHelp.push_back(std::make_pair("CCC_ADD_ARGS", - "(ENVIRONMENT VARIABLE) Comma separated list of " - "arguments to prepend to the command line")); - } - - // Find the maximum option length. - unsigned OptionFieldWidth = 0; - for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) { - // Skip titles. - if (!OptionHelp[i].second) - continue; - - // Limit the amount of padding we are willing to give up for alignment. - unsigned Length = OptionHelp[i].first.size(); - if (Length <= 23) - OptionFieldWidth = std::max(OptionFieldWidth, Length); - } - - for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) { - const std::string &Option = OptionHelp[i].first; - OS << " " << Option; - for (int j = Option.length(), e = OptionFieldWidth; j < e; ++j) - OS << ' '; - OS << ' ' << OptionHelp[i].second << '\n'; - } - - OS.flush(); + getOpts().PrintHelp(llvm::outs(), Name.c_str(), + "clang \"gcc-compatible\" driver", ShowHidden); } void Driver::PrintVersion(const Compilation &C, llvm::raw_ostream &OS) const { diff --git a/lib/Driver/DriverOptions.cpp b/lib/Driver/DriverOptions.cpp index d1af95c..72aaf56 100644 --- a/lib/Driver/DriverOptions.cpp +++ b/lib/Driver/DriverOptions.cpp @@ -14,7 +14,7 @@ using namespace clang::driver; using namespace clang::driver::options; -static OptTable::Info InfoTable[] = { +static const OptTable::Info InfoTable[] = { #define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ HELPTEXT, METAVAR) \ { NAME, HELPTEXT, METAVAR, Option::KIND##Class, FLAGS, PARAM, \ diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp index 280e7c4..1bd123e 100644 --- a/lib/Driver/Job.cpp +++ b/lib/Driver/Job.cpp @@ -14,10 +14,11 @@ using namespace clang::driver; Job::~Job() {} -Command::Command(const Action &_Source, const char *_Executable, - const ArgStringList &_Arguments) - : Job(CommandClass), Source(_Source), Executable(_Executable), - Arguments(_Arguments) { +Command::Command(const Action &_Source, const Tool &_Creator, + const char *_Executable, const ArgStringList &_Arguments) + : Job(CommandClass), Source(_Source), Creator(_Creator), + Executable(_Executable), Arguments(_Arguments) +{ } PipedJob::PipedJob() : Job(PipedJobClass) {} diff --git a/lib/Driver/OptTable.cpp b/lib/Driver/OptTable.cpp index f68a1d8..f69d5d8 100644 --- a/lib/Driver/OptTable.cpp +++ b/lib/Driver/OptTable.cpp @@ -11,9 +11,10 @@ #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" #include "clang/Driver/Option.h" +#include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cassert> - +#include <map> using namespace clang::driver; using namespace clang::driver::options; @@ -255,3 +256,122 @@ InputArgList *OptTable::ParseArgs(const char **ArgBegin, const char **ArgEnd, return Args; } + +static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) { + std::string Name = Opts.getOptionName(Id); + + // Add metavar, if used. + switch (Opts.getOptionKind(Id)) { + case Option::GroupClass: case Option::InputClass: case Option::UnknownClass: + assert(0 && "Invalid option with help text."); + + case Option::MultiArgClass: case Option::JoinedAndSeparateClass: + assert(0 && "Cannot print metavar for this kind of option."); + + case Option::FlagClass: + break; + + case Option::SeparateClass: case Option::JoinedOrSeparateClass: + Name += ' '; + // FALLTHROUGH + case Option::JoinedClass: case Option::CommaJoinedClass: + if (const char *MetaVarName = Opts.getOptionMetaVar(Id)) + Name += MetaVarName; + else + Name += "<value>"; + break; + } + + return Name; +} + +static void PrintHelpOptionList(llvm::raw_ostream &OS, llvm::StringRef Title, + std::vector<std::pair<std::string, + const char*> > &OptionHelp) { + OS << Title << ":\n"; + + // Find the maximum option length. + unsigned OptionFieldWidth = 0; + for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) { + // Skip titles. + if (!OptionHelp[i].second) + continue; + + // Limit the amount of padding we are willing to give up for alignment. + unsigned Length = OptionHelp[i].first.size(); + if (Length <= 23) + OptionFieldWidth = std::max(OptionFieldWidth, Length); + } + + const unsigned InitialPad = 2; + for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) { + const std::string &Option = OptionHelp[i].first; + int Pad = OptionFieldWidth - int(Option.size()); + OS.indent(InitialPad) << Option; + + // Break on long option names. + if (Pad < 0) { + OS << "\n"; + Pad = OptionFieldWidth + InitialPad; + } + OS.indent(Pad + 1) << OptionHelp[i].second << '\n'; + } +} + +static const char *getOptionHelpGroup(const OptTable &Opts, OptSpecifier Id) { + unsigned GroupID = Opts.getOptionGroupID(Id); + + // If not in a group, return the default help group. + if (!GroupID) + return "OPTIONS"; + + // Abuse the help text of the option groups to store the "help group" + // name. + // + // FIXME: Split out option groups. + if (const char *GroupHelp = Opts.getOptionHelpText(GroupID)) + return GroupHelp; + + // Otherwise keep looking. + return getOptionHelpGroup(Opts, GroupID); +} + +void OptTable::PrintHelp(llvm::raw_ostream &OS, const char *Name, + const char *Title, bool ShowHidden) const { + OS << "OVERVIEW: " << Title << "\n"; + OS << '\n'; + OS << "USAGE: " << Name << " [options] <inputs>\n"; + OS << '\n'; + + // Render help text into a map of group-name to a list of (option, help) + // pairs. + typedef std::map<std::string, + std::vector<std::pair<std::string, const char*> > > helpmap_ty; + helpmap_ty GroupedOptionHelp; + + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { + unsigned Id = i + 1; + + // FIXME: Split out option groups. + if (getOptionKind(Id) == Option::GroupClass) + continue; + + if (!ShowHidden && isOptionHelpHidden(Id)) + continue; + + if (const char *Text = getOptionHelpText(Id)) { + const char *HelpGroup = getOptionHelpGroup(*this, Id); + const std::string &OptName = getOptionHelpName(*this, Id); + GroupedOptionHelp[HelpGroup].push_back(std::make_pair(OptName, Text)); + } + } + + for (helpmap_ty::iterator it = GroupedOptionHelp .begin(), + ie = GroupedOptionHelp.end(); it != ie; ++it) { + if (it != GroupedOptionHelp .begin()) + OS << "\n"; + PrintHelpOptionList(OS, it->first, it->second); + } + + OS.flush(); +} diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index af63952..420573d 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -510,7 +510,7 @@ DerivedArgList *Darwin::TranslateArgs(InputArgList &Args, DAL->append(DAL->MakeJoinedArg(0, MArch, "armv7a")); else - llvm::llvm_unreachable("invalid Darwin arch"); + llvm_unreachable("invalid Darwin arch"); } return DAL; diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index eb165cf..70597ab 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -9,6 +9,7 @@ #include "Tools.h" +#include "clang/Basic/Version.h" #include "clang/Driver/Action.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" @@ -419,14 +420,17 @@ void Clang::AddARMTargetArgs(const ArgList &Args, // // FIXME: This changes CPP defines, we need -target-soft-float. CmdArgs.push_back("-msoft-float"); - CmdArgs.push_back("-mfloat-abi=soft"); + CmdArgs.push_back("-mfloat-abi"); + CmdArgs.push_back("soft"); } else if (FloatABI == "softfp") { // Floating point operations are hard, but argument passing is soft. - CmdArgs.push_back("-mfloat-abi=soft"); + CmdArgs.push_back("-mfloat-abi"); + CmdArgs.push_back("soft"); } else { // Floating point operations and argument passing are hard. assert(FloatABI == "hard" && "Invalid float abi!"); - CmdArgs.push_back("-mfloat-abi=hard"); + CmdArgs.push_back("-mfloat-abi"); + CmdArgs.push_back("hard"); } } @@ -590,6 +594,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); + // Invoke ourselves in -cc1 mode. + // + // FIXME: Implement custom jobs for internal actions. + CmdArgs.push_back("-cc1"); + // Add the "effective" target triple. CmdArgs.push_back("-triple"); std::string TripleStr = getEffectiveClangTriple(D, getToolChain(), Args); @@ -647,6 +656,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Enable region store model by default. CmdArgs.push_back("-analyzer-store=region"); + // Treat blocks as analysis entry points. + CmdArgs.push_back("-analyzer-opt-analyze-nested-blocks"); + // Add default argument set. if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) { CmdArgs.push_back("-warn-dead-stores"); @@ -787,7 +799,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Arg *Unsupported; if ((Unsupported = Args.getLastArg(options::OPT_MG)) || (Unsupported = Args.getLastArg(options::OPT_MQ)) || - (Unsupported = Args.getLastArg(options::OPT_iframework))) + (Unsupported = Args.getLastArg(options::OPT_iframework)) || + (Unsupported = Args.getLastArg(options::OPT_fshort_enums))) D.Diag(clang::diag::err_drv_clang_unsupported) << Unsupported->getOption().getName(); @@ -803,7 +816,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_nostdinc); Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc); - Args.AddLastArg(CmdArgs, options::OPT_isysroot); + // Pass the path to compiler resource files. + // + // FIXME: Get this from a configuration object. + llvm::sys::Path P(D.Dir); + P.eraseComponent(); // Remove /bin from foo/bin + P.appendComponent("lib"); + P.appendComponent("clang"); + P.appendComponent(CLANG_VERSION_STRING); + CmdArgs.push_back("-resource-dir"); + CmdArgs.push_back(Args.MakeArgString(P.str())); // Add preprocessing options like -I, -D, etc. if we are using the // preprocessor. @@ -877,7 +899,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(llvm::Twine(N))); } - // Forward -f options which we can pass directly. + if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ)) { + CmdArgs.push_back("-fvisibility"); + CmdArgs.push_back(A->getValue(Args)); + } + + // Forward -f (flag) options which we can pass directly. + Args.AddLastArg(CmdArgs, options::OPT_fcatch_undefined_behavior); Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); Args.AddLastArg(CmdArgs, options::OPT_ffreestanding); Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); @@ -890,7 +918,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info); Args.AddLastArg(CmdArgs, options::OPT_ftime_report); Args.AddLastArg(CmdArgs, options::OPT_ftrapv); - Args.AddLastArg(CmdArgs, options::OPT_fvisibility_EQ); Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings); Args.AddLastArg(CmdArgs, options::OPT_pthread); @@ -1027,7 +1054,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Default to -fno-builtin-str{cat,cpy} on Darwin for ARM. // - // FIXME: This is disabled until clang-cc supports -fno-builtin-foo. PR4941. + // FIXME: This is disabled until clang -cc1 supports -fno-builtin-foo. PR4941. #if 0 if (getToolChain().getTriple().getOS() == llvm::Triple::Darwin && (getToolChain().getTriple().getArch() == llvm::Triple::arm || @@ -1077,8 +1104,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_undef); const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath(C, "clang-cc")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Args.MakeArgString(getToolChain().GetProgramPath(C, "clang")); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); // Explicitly warn that these options are unsupported, even though // we are allowing compilation to continue. @@ -1200,7 +1227,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, getToolChain().getHost().getDriver().CCCGenericGCCName.c_str(); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, GCCName)); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void gcc::Preprocess::RenderExtraToolArgs(ArgStringList &CmdArgs) const { @@ -1589,7 +1616,7 @@ void darwin::Preprocess::ConstructJob(Compilation &C, const JobAction &JA, const char *CC1Name = getCC1Name(Inputs[0].getType()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, CC1Name)); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA, @@ -1683,7 +1710,7 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA, const char *CC1Name = getCC1Name(Inputs[0].getType()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, CC1Name)); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA, @@ -1738,7 +1765,7 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "as")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } /// Helper routine for seeing if we should use dsymutil; this is a @@ -2152,7 +2179,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "ld")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); // Find the first non-empty base input (we want to ignore linker // inputs). @@ -2182,7 +2209,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, Args.MakeArgString(getToolChain().GetProgramPath(C, "dsymutil")); ArgStringList CmdArgs; CmdArgs.push_back(Output.getFilename()); - C.getJobs().addCommand(new Command(JA, Exec, CmdArgs)); + C.getJobs().addCommand(new Command(JA, *this, Exec, CmdArgs)); } } } @@ -2208,7 +2235,7 @@ void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA, } const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "lipo")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA, @@ -2238,7 +2265,7 @@ void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "gas")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA, @@ -2339,7 +2366,7 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "ld")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, @@ -2369,7 +2396,7 @@ void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "as")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, @@ -2469,7 +2496,7 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "ld")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, @@ -2504,7 +2531,7 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "as")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, @@ -2617,7 +2644,7 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "ld")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } /// DragonFly Tools @@ -2656,7 +2683,7 @@ void dragonfly::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "as")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, @@ -2780,5 +2807,5 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "ld")); - Dest.addCommand(new Command(JA, Exec, CmdArgs)); + Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); } diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp index 3397677..433af03 100644 --- a/lib/Driver/Types.cpp +++ b/lib/Driver/Types.cpp @@ -23,7 +23,7 @@ struct TypeInfo { ID PreprocessedType; }; -static TypeInfo TypeInfos[] = { +static const TypeInfo TypeInfos[] = { #define TYPE(NAME, ID, PP_TYPE, TEMP_SUFFIX, FLAGS) \ { NAME, FLAGS, TEMP_SUFFIX, TY_##PP_TYPE, }, #include "clang/Driver/Types.def" @@ -31,7 +31,7 @@ static TypeInfo TypeInfos[] = { }; static const unsigned numTypes = sizeof(TypeInfos) / sizeof(TypeInfos[0]); -static TypeInfo &getInfo(unsigned id) { +static const TypeInfo &getInfo(unsigned id) { assert(id > 0 && id - 1 < numTypes && "Invalid Type ID."); return TypeInfos[id - 1]; } diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp index 9a30f59..f1a6666 100644 --- a/lib/Frontend/ASTConsumers.cpp +++ b/lib/Frontend/ASTConsumers.cpp @@ -28,8 +28,6 @@ #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" -#include <cstdio> - using namespace clang; //===----------------------------------------------------------------------===// @@ -405,8 +403,13 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "<objc property> " << OPD->getNameAsString() << "\n"; break; } + case Decl::FunctionTemplate: { + FunctionTemplateDecl* FTD = cast<FunctionTemplateDecl>(*I); + Out << "<function template> " << FTD->getNameAsString() << "\n"; + break; + } default: - fprintf(stderr, "DeclKind: %d \"%s\"\n", DK, I->getDeclKindName()); + Out << "DeclKind: " << DK << '"' << I->getDeclKindName() << "\"\n"; assert(0 && "decl unhandled"); } } diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index f647c8a..48296c7 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -17,27 +17,29 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Job.h" +#include "clang/Driver/Tool.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/FrontendOptions.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/LLVMContext.h" +#include "llvm/System/Host.h" #include "llvm/System/Path.h" using namespace clang; -ASTUnit::ASTUnit(DiagnosticClient *diagClient) : tempFile(false) { - Diags.setClient(diagClient ? diagClient : new TextDiagnosticBuffer()); +ASTUnit::ASTUnit(bool _MainFileIsAST) + : tempFile(false), MainFileIsAST(_MainFileIsAST) { } ASTUnit::~ASTUnit() { if (tempFile) llvm::sys::Path(getPCHFileName()).eraseFromDisk(); - - // The ASTUnit object owns the DiagnosticClient. - delete Diags.getClient(); } namespace { @@ -90,19 +92,19 @@ public: } // anonymous namespace const std::string &ASTUnit::getOriginalSourceFileName() { - return dyn_cast<PCHReader>(Ctx->getExternalSource())->getOriginalSourceFile(); + return OriginalSourceFile; } const std::string &ASTUnit::getPCHFileName() { + assert(isMainFileAST() && "Not an ASTUnit from a PCH file!"); return dyn_cast<PCHReader>(Ctx->getExternalSource())->getFileName(); } ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, - std::string *ErrMsg, - DiagnosticClient *diagClient, + Diagnostic &Diags, bool OnlyLocalDecls, bool UseBumpAllocator) { - llvm::OwningPtr<ASTUnit> AST(new ASTUnit(diagClient)); + llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true)); AST->OnlyLocalDecls = OnlyLocalDecls; AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager())); @@ -118,7 +120,7 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, llvm::OwningPtr<ExternalASTSource> Source; Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(), - AST->Diags)); + Diags)); Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple, Predefines, Counter)); @@ -128,11 +130,12 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, case PCHReader::Failure: case PCHReader::IgnorePCH: - if (ErrMsg) - *ErrMsg = "Could not load PCH file"; + Diags.Report(diag::err_fe_unable_to_load_pch); return NULL; } + AST->OriginalSourceFile = Reader->getOriginalSourceFile(); + // PCH loaded successfully. Now create the preprocessor. // Get information about the target being compiled for. @@ -143,8 +146,8 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, 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->Target.reset(TargetInfo::CreateTargetInfo(Diags, TargetOpts)); + AST->PP.reset(new Preprocessor(Diags, LangInfo, *AST->Target.get(), AST->getSourceManager(), HeaderInfo)); Preprocessor &PP = *AST->PP.get(); @@ -177,13 +180,30 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, namespace { -class NullAction : public ASTFrontendAction { +class TopLevelDeclTrackerConsumer : public ASTConsumer { + ASTUnit &Unit; + +public: + TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {} + + void HandleTopLevelDecl(DeclGroupRef D) { + for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) + Unit.getTopLevelDecls().push_back(*it); + } +}; + +class TopLevelDeclTrackerAction : public ASTFrontendAction { +public: + ASTUnit &Unit; + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { - return new ASTConsumer(); + return new TopLevelDeclTrackerConsumer(Unit); } public: + TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {} + virtual bool hasCodeCompletionSupport() const { return false; } }; @@ -191,12 +211,11 @@ public: ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI, Diagnostic &Diags, - bool OnlyLocalDecls, - bool UseBumpAllocator) { + bool OnlyLocalDecls) { // Create the compiler instance to use for building the AST. - CompilerInstance Clang(&llvm::getGlobalContext(), false); + CompilerInstance Clang; llvm::OwningPtr<ASTUnit> AST; - NullAction Act; + llvm::OwningPtr<TopLevelDeclTrackerAction> Act; Clang.getInvocation() = CI; @@ -221,9 +240,10 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI, "FIXME: AST inputs not yet supported here!"); // Create the AST unit. - // - // FIXME: Use the provided diagnostic client. - AST.reset(new ASTUnit()); + AST.reset(new ASTUnit(false)); + + AST->OnlyLocalDecls = OnlyLocalDecls; + AST->OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second; // Create a file manager object to provide access to and cache the filesystem. Clang.setFileManager(&AST->getFileManager()); @@ -234,20 +254,22 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI, // Create the preprocessor. Clang.createPreprocessor(); - if (!Act.BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second, + Act.reset(new TopLevelDeclTrackerAction(*AST)); + if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second, /*IsAST=*/false)) goto error; - Act.Execute(); + Act->Execute(); - // Steal the created context and preprocessor, and take back the source and - // file managers. + // Steal the created target, context, and preprocessor, and take back the + // source and file managers. AST->Ctx.reset(Clang.takeASTContext()); AST->PP.reset(Clang.takePreprocessor()); Clang.takeSourceManager(); Clang.takeFileManager(); + AST->Target.reset(Clang.takeTarget()); - Act.EndSourceFile(); + Act->EndSourceFile(); Clang.takeDiagnosticClient(); Clang.takeDiagnostics(); @@ -261,3 +283,53 @@ error: Clang.takeDiagnostics(); return 0; } + +ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, + const char **ArgEnd, + Diagnostic &Diags, + llvm::StringRef ResourceFilesPath, + bool OnlyLocalDecls, + bool UseBumpAllocator) { + llvm::SmallVector<const char *, 16> Args; + Args.push_back("<clang>"); // FIXME: Remove dummy argument. + Args.insert(Args.end(), ArgBegin, ArgEnd); + + // FIXME: Find a cleaner way to force the driver into restricted modes. We + // also want to force it to use clang. + Args.push_back("-fsyntax-only"); + + // FIXME: We shouldn't have to pass in the path info. + driver::Driver TheDriver("clang", "/", llvm::sys::getHostTriple(), + "a.out", false, Diags); + llvm::OwningPtr<driver::Compilation> C( + TheDriver.BuildCompilation(Args.size(), Args.data())); + + // We expect to get back exactly one command job, if we didn't something + // failed. + const driver::JobList &Jobs = C->getJobs(); + if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) { + llvm::SmallString<256> Msg; + llvm::raw_svector_ostream OS(Msg); + C->PrintJob(OS, C->getJobs(), "; ", true); + Diags.Report(diag::err_fe_expected_compiler_job) << OS.str(); + return 0; + } + + const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin()); + if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") { + Diags.Report(diag::err_fe_expected_clang_command); + return 0; + } + + const driver::ArgStringList &CCArgs = Cmd->getArguments(); + CompilerInvocation CI; + CompilerInvocation::CreateFromArgs(CI, (const char**) CCArgs.data(), + (const char**) CCArgs.data()+CCArgs.size(), + Diags); + + // Override the resources path. + CI.getHeaderSearchOpts().ResourceDir = ResourceFilesPath; + + CI.getFrontendOpts().DisableFree = UseBumpAllocator; + return LoadFromCompilerInvocation(CI, Diags, OnlyLocalDecls); +} diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp index 5df1ece..a74bbc2 100644 --- a/lib/Frontend/AnalysisConsumer.cpp +++ b/lib/Frontend/AnalysisConsumer.cpp @@ -139,13 +139,17 @@ public: return; declDisplayed = true; - // FIXME: Is getCodeDecl() always a named decl? + SourceManager &SM = Mgr->getASTContext().getSourceManager(); + PresumedLoc Loc = SM.getPresumedLoc(D->getLocation()); + llvm::errs() << "ANALYZE: " << Loc.getFilename(); + 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'; + llvm::errs() << ' ' << ND->getNameAsString() << '\n'; + } + else if (isa<BlockDecl>(D)) { + llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:" + << Loc.getColumn() << '\n'; } } @@ -167,7 +171,6 @@ public: Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(), PP.getLangOptions(), PD, CreateStoreMgr, CreateConstraintMgr, - Opts.AnalyzerDisplayProgress, Opts.VisualizeEGDot, Opts.VisualizeEGUbi, Opts.PurgeDead, Opts.EagerlyAssume, Opts.TrimGraph)); @@ -265,10 +268,21 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { // Explicitly destroy the PathDiagnosticClient. This will flush its output. // FIXME: This should be replaced with something that doesn't rely on - // side-effects in PathDiagnosticClient's destructor. + // side-effects in PathDiagnosticClient's destructor. This is required when + // used with option -disable-free. Mgr.reset(NULL); } +static void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) { + if (BlockDecl *BD = dyn_cast<BlockDecl>(D)) + WL.push_back(BD); + + for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end(); + I!=E; ++I) + if (DeclContext *DC = dyn_cast<DeclContext>(*I)) + FindBlocks(DC, WL); +} + void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) { // Don't run the actions if an error has occured with parsing the file. @@ -285,8 +299,16 @@ void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) { Mgr->ClearContexts(); // Dispatch on the actions. + llvm::SmallVector<Decl*, 10> WL; + WL.push_back(D); + + if (Body && Opts.AnalyzeNestedBlocks) + FindBlocks(cast<DeclContext>(D), WL); + for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I) - (*I)(*this, *Mgr, D); + for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end(); + WI != WE; ++WI) + (*I)(*this, *Mgr, *WI); } //===----------------------------------------------------------------------===// diff --git a/lib/Frontend/Backend.cpp b/lib/Frontend/Backend.cpp index 9dc109d..9be6786 100644 --- a/lib/Frontend/Backend.cpp +++ b/lib/Frontend/Backend.cpp @@ -15,6 +15,7 @@ #include "clang/Basic/TargetOptions.h" #include "clang/CodeGen/CodeGenOptions.h" #include "clang/CodeGen/ModuleBuilder.h" +#include "clang/Frontend/FrontendDiagnostic.h" #include "llvm/Module.h" #include "llvm/ModuleProvider.h" #include "llvm/PassManager.h" @@ -31,12 +32,14 @@ #include "llvm/Target/SubtargetFeature.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetRegistry.h" using namespace clang; using namespace llvm; namespace { class BackendConsumer : public ASTConsumer { + Diagnostic &Diags; BackendAction Action; const CodeGenOptions &CodeGenOpts; const LangOptions &LangOpts; @@ -64,21 +67,20 @@ namespace { void CreatePasses(); - /// AddEmitPasses - Add passes necessary to emit assembly or LLVM - /// IR. + /// AddEmitPasses - Add passes necessary to emit assembly or LLVM IR. /// - /// \return True on success. On failure \arg Error will be set to - /// a user readable error message. - bool AddEmitPasses(std::string &Error); + /// \return True on success. + bool AddEmitPasses(); void EmitAssembly(); public: - BackendConsumer(BackendAction action, Diagnostic &Diags, + BackendConsumer(BackendAction action, Diagnostic &_Diags, const LangOptions &langopts, const CodeGenOptions &compopts, const TargetOptions &targetopts, bool TimePasses, const std::string &infile, llvm::raw_ostream *OS, LLVMContext& C) : + Diags(_Diags), Action(action), CodeGenOpts(compopts), LangOpts(langopts), @@ -195,7 +197,7 @@ FunctionPassManager *BackendConsumer::getPerFunctionPasses() const { return PerFunctionPasses; } -bool BackendConsumer::AddEmitPasses(std::string &Error) { +bool BackendConsumer::AddEmitPasses() { if (Action == Backend_EmitNothing) return true; @@ -207,48 +209,68 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) { bool Fast = CodeGenOpts.OptimizationLevel == 0; // Create the TargetMachine for generating code. + std::string Error; std::string Triple = TheModule->getTargetTriple(); const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error); if (!TheTarget) { - Error = std::string("Unable to get target machine: ") + Error; + Diags.Report(diag::err_fe_unable_to_create_target) << Error; return false; } // FIXME: Expose these capabilities via actual APIs!!!! Aside from just // being gross, this is also totally broken if we ever care about // concurrency. + llvm::NoFramePointerElim = CodeGenOpts.DisableFPElim; + if (CodeGenOpts.FloatABI == "soft") + llvm::FloatABIType = llvm::FloatABI::Soft; + else if (CodeGenOpts.FloatABI == "hard") + llvm::FloatABIType = llvm::FloatABI::Hard; + else { + assert(CodeGenOpts.FloatABI.empty() && "Invalid float abi!"); + llvm::FloatABIType = llvm::FloatABI::Default; + } + NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS; + llvm::UseSoftFloat = CodeGenOpts.SoftFloat; + UnwindTablesMandatory = CodeGenOpts.UnwindTables; + + TargetMachine::setAsmVerbosityDefault(CodeGenOpts.AsmVerbose); + + // FIXME: Parse this earlier. + if (CodeGenOpts.RelocationModel == "static") { + TargetMachine::setRelocationModel(llvm::Reloc::Static); + } else if (CodeGenOpts.RelocationModel == "pic") { + TargetMachine::setRelocationModel(llvm::Reloc::PIC_); + } else { + assert(CodeGenOpts.RelocationModel == "dynamic-no-pic" && + "Invalid PIC model!"); + TargetMachine::setRelocationModel(llvm::Reloc::DynamicNoPIC); + } + // FIXME: Parse this earlier. + if (CodeGenOpts.CodeModel == "small") { + TargetMachine::setCodeModel(llvm::CodeModel::Small); + } else if (CodeGenOpts.CodeModel == "kernel") { + TargetMachine::setCodeModel(llvm::CodeModel::Kernel); + } else if (CodeGenOpts.CodeModel == "medium") { + TargetMachine::setCodeModel(llvm::CodeModel::Medium); + } else if (CodeGenOpts.CodeModel == "large") { + TargetMachine::setCodeModel(llvm::CodeModel::Large); + } else { + assert(CodeGenOpts.CodeModel.empty() && "Invalid code model!"); + TargetMachine::setCodeModel(llvm::CodeModel::Default); + } + std::vector<const char *> BackendArgs; BackendArgs.push_back("clang"); // Fake program name. - if (CodeGenOpts.AsmVerbose) - BackendArgs.push_back("-asm-verbose"); - if (!CodeGenOpts.CodeModel.empty()) { - BackendArgs.push_back("-code-model"); - BackendArgs.push_back(CodeGenOpts.CodeModel.c_str()); - } if (!CodeGenOpts.DebugPass.empty()) { BackendArgs.push_back("-debug-pass"); BackendArgs.push_back(CodeGenOpts.DebugPass.c_str()); } - if (CodeGenOpts.DisableFPElim) - BackendArgs.push_back("-disable-fp-elim"); - if (!CodeGenOpts.FloatABI.empty()) { - BackendArgs.push_back("-float-abi"); - BackendArgs.push_back(CodeGenOpts.FloatABI.c_str()); - } if (!CodeGenOpts.LimitFloatPrecision.empty()) { BackendArgs.push_back("-limit-float-precision"); BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str()); } - if (CodeGenOpts.NoZeroInitializedInBSS) - BackendArgs.push_back("-nozero-initialized-in-bss"); - if (CodeGenOpts.SoftFloat) - BackendArgs.push_back("-soft-float"); - BackendArgs.push_back("-relocation-model"); - BackendArgs.push_back(CodeGenOpts.RelocationModel.c_str()); if (llvm::TimePassesIsEnabled) BackendArgs.push_back("-time-passes"); - if (CodeGenOpts.UnwindTables) - BackendArgs.push_back("-unwind-tables"); BackendArgs.push_back(0); llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1, (char**) &BackendArgs[0]); @@ -290,7 +312,7 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) { TargetMachine::AssemblyFile, OptLevel)) { default: case FileModel::Error: - Error = "Unable to interface with target machine!\n"; + Diags.Report(diag::err_fe_unable_to_interface_with_target); return false; case FileModel::AsmFile: break; @@ -298,7 +320,7 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) { if (TM->addPassesToEmitFileFinish(*CodeGenPasses, (MachineCodeEmitter *)0, OptLevel)) { - Error = "Unable to interface with target machine!\n"; + Diags.Report(diag::err_fe_unable_to_interface_with_target); return false; } } @@ -329,8 +351,14 @@ void BackendConsumer::CreatePasses() { switch (Inlining) { case CodeGenOptions::NoInlining: break; case CodeGenOptions::NormalInlining: { - // Inline small functions - unsigned Threshold = (CodeGenOpts.OptimizeSize || OptLevel < 3) ? 50 : 200; + // Set the inline threshold following llvm-gcc. + // + // FIXME: Derive these constants in a principled fashion. + unsigned Threshold = 200; + if (CodeGenOpts.OptimizeSize) + Threshold = 50; + else if (OptLevel > 2) + Threshold = 250; InliningPass = createFunctionInliningPass(Threshold); break; } @@ -372,13 +400,8 @@ void BackendConsumer::EmitAssembly() { assert(TheModule == M && "Unexpected module change during IR generation"); CreatePasses(); - - std::string Error; - if (!AddEmitPasses(Error)) { - // FIXME: Don't fail this way. - llvm::errs() << "ERROR: " << Error << "\n"; - ::exit(1); - } + if (!AddEmitPasses()) + return; // Run passes. For now we do all passes at once, but eventually we // would like to have the option of streaming code generation. diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 1083d5e..2a6a8a8 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -95,7 +95,7 @@ static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, return; } - (*OS) << "clang-cc command line arguments: "; + (*OS) << "clang -cc1 command line arguments: "; for (unsigned i = 0; i != argc; ++i) (*OS) << argv[i] << ' '; (*OS) << '\n'; @@ -172,10 +172,6 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags, 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, @@ -287,7 +283,7 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, } // Truncate the named file at the given line/column. - PP.getSourceManager().truncateFileAt(Entry, Line, Column); + PP.SetCodeCompletionPoint(Entry, Line, Column); // Set up the creation routine for code-completion. if (UseDebugPrinter) @@ -332,9 +328,9 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath, InFile, Extension, &OutputPathName); if (!OS) { - // FIXME: Don't fail this way. - llvm::errs() << "error: " << Error << "\n"; - ::exit(1); + getDiagnostics().Report(diag::err_fe_unable_to_open_output) + << OutputPath << Error; + return 0; } // Add the output file -- but don't try to remove "-", since this means we are diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index c537507..7a3388f 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -31,7 +31,7 @@ using namespace clang; static const char *getAnalysisName(Analyses Kind) { switch (Kind) { default: - llvm::llvm_unreachable("Unknown analysis store!"); + llvm_unreachable("Unknown analysis kind!"); #define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)\ case NAME: return "-" CMDFLAG; #include "clang/Frontend/Analyses.def" @@ -41,7 +41,7 @@ static const char *getAnalysisName(Analyses Kind) { static const char *getAnalysisStoreName(AnalysisStores Kind) { switch (Kind) { default: - llvm::llvm_unreachable("Unknown analysis store!"); + llvm_unreachable("Unknown analysis store!"); #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \ case NAME##Model: return CMDFLAG; #include "clang/Frontend/Analyses.def" @@ -51,7 +51,7 @@ static const char *getAnalysisStoreName(AnalysisStores Kind) { static const char *getAnalysisConstraintName(AnalysisConstraints Kind) { switch (Kind) { default: - llvm::llvm_unreachable("Unknown analysis constraints!"); + llvm_unreachable("Unknown analysis constraints!"); #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \ case NAME##Model: return CMDFLAG; #include "clang/Frontend/Analyses.def" @@ -61,7 +61,7 @@ static const char *getAnalysisConstraintName(AnalysisConstraints Kind) { static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) { switch (Kind) { default: - llvm::llvm_unreachable("Unknown analysis client!"); + llvm_unreachable("Unknown analysis client!"); #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREATE) \ case PD_##NAME: return CMDFLAG; #include "clang/Frontend/Analyses.def" @@ -96,6 +96,8 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, Res.push_back("-analyzer-opt-analyze-headers"); if (Opts.AnalyzerDisplayProgress) Res.push_back("-analyzer-display-progress"); + if (Opts.AnalyzeNestedBlocks) + Res.push_back("-analyzer-opt-analyze-nested-blocks"); if (Opts.EagerlyAssume) Res.push_back("-analyzer-eagerly-assume"); if (!Opts.PurgeDead) @@ -244,7 +246,7 @@ static const char *getInputKindName(FrontendOptions::InputKind Kind) { case FrontendOptions::IK_PreprocessedObjCXX:return "objective-c++-cpp-output"; } - llvm::llvm_unreachable("Unexpected language kind!"); + llvm_unreachable("Unexpected language kind!"); return 0; } @@ -252,7 +254,7 @@ static const char *getActionName(frontend::ActionKind Kind) { switch (Kind) { case frontend::PluginAction: case frontend::InheritanceView: - llvm::llvm_unreachable("Invalid kind!"); + llvm_unreachable("Invalid kind!"); case frontend::ASTDump: return "-ast-dump"; case frontend::ASTPrint: return "-ast-print"; @@ -282,7 +284,7 @@ static const char *getActionName(frontend::ActionKind Kind) { case frontend::RunPreprocessorOnly: return "-Eonly"; } - llvm::llvm_unreachable("Unexpected language kind!"); + llvm_unreachable("Unexpected language kind!"); return 0; } @@ -296,12 +298,16 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-empty-input-only"); if (Opts.RelocatablePCH) Res.push_back("-relocatable-pch"); + if (Opts.ShowHelp) + Res.push_back("-help"); if (Opts.ShowMacrosInCodeCompletion) Res.push_back("-code-completion-macros"); if (Opts.ShowStats) Res.push_back("-print-stats"); if (Opts.ShowTimers) Res.push_back("-ftime-report"); + if (Opts.ShowVersion) + Res.push_back("-version"); bool NeedLang = false; for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) @@ -345,6 +351,10 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-plugin"); Res.push_back(Opts.ActionName); } + for (unsigned i = 0, e = Opts.Plugins.size(); i != e; ++i) { + Res.push_back("-load"); + Res.push_back(Opts.Plugins[i]); + } } static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, @@ -399,8 +409,9 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, // 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.ResourceDir.empty()) { + Res.push_back("-resource-dir"); + Res.push_back(Opts.ResourceDir); } if (!Opts.UseStandardIncludes) Res.push_back("-nostdinc"); @@ -437,6 +448,8 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-fno-operator-names"); if (Opts.PascalStrings) Res.push_back("-fpascal-strings"); + if (Opts.CatchUndefined) + Res.push_back("-fcatch-undefined-behavior"); if (Opts.WritableStrings) Res.push_back("-fwritable-strings"); if (!Opts.LaxVectorConversions) @@ -445,7 +458,7 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-faltivec"); if (Opts.Exceptions) Res.push_back("-fexceptions"); - if (!Opts.Rtti) + if (!Opts.RTTI) Res.push_back("-fno-rtti"); if (!Opts.NeXTRuntime) Res.push_back("-fgnu-runtime"); @@ -550,6 +563,11 @@ static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts, assert(Opts.ImplicitPTHInclude == Opts.TokenCache && "Unsupported option combination!"); } + for (unsigned i = 0, e = Opts.RemappedFiles.size(); i != e; ++i) { + Res.push_back("-remap-file"); + Res.push_back(Opts.RemappedFiles[i].first + ";" + + Opts.RemappedFiles[i].second); + } } static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts, @@ -696,6 +714,8 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, Opts.VisualizeEGUbi = Args.hasArg(OPT_analyzer_viz_egraph_ubigraph); Opts.AnalyzeAll = Args.hasArg(OPT_analyzer_opt_analyze_headers); Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress); + Opts.AnalyzeNestedBlocks = + Args.hasArg(OPT_analyzer_opt_analyze_nested_blocks); Opts.PurgeDead = !Args.hasArg(OPT_analyzer_no_purge_dead); Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume); Opts.AnalyzeSpecificFunction = getLastArgValue(Args, OPT_analyze_function); @@ -877,10 +897,13 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { } Opts.OutputFile = getLastArgValue(Args, OPT_o); + Opts.Plugins = getAllArgValues(Args, OPT_load); Opts.RelocatablePCH = Args.hasArg(OPT_relocatable_pch); + Opts.ShowHelp = Args.hasArg(OPT_help); Opts.ShowMacrosInCodeCompletion = Args.hasArg(OPT_code_completion_macros); Opts.ShowStats = Args.hasArg(OPT_print_stats); Opts.ShowTimers = Args.hasArg(OPT_ftime_report); + Opts.ShowVersion = Args.hasArg(OPT_version); Opts.ViewClassInheritance = getLastArgValue(Args, OPT_cxx_inheritance_view); FrontendOptions::InputKind DashX = FrontendOptions::IK_None; @@ -929,8 +952,8 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { return DashX; } -static std::string GetBuiltinIncludePath(const char *Argv0, - void *MainAddr) { +std::string CompilerInvocation::GetResourcesPath(const char *Argv0, + void *MainAddr) { llvm::sys::Path P = llvm::sys::Path::GetMainExecutable(Argv0, MainAddr); if (!P.isEmpty()) { @@ -941,22 +964,18 @@ static std::string GetBuiltinIncludePath(const char *Argv0, P.appendComponent("lib"); P.appendComponent("clang"); P.appendComponent(CLANG_VERSION_STRING); - P.appendComponent("include"); } return P.str(); } -static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, - const char *Argv0, void *MainAddr) { +static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { using namespace cc1options; Opts.Sysroot = getLastArgValue(Args, OPT_isysroot, "/"); Opts.Verbose = Args.hasArg(OPT_v); + Opts.UseBuiltinIncludes = !Args.hasArg(OPT_nobuiltininc); Opts.UseStandardIncludes = !Args.hasArg(OPT_nostdinc); - Opts.BuiltinIncludePath = ""; - // FIXME: Add an option for this, its a slow call. - if (!Args.hasArg(OPT_nobuiltininc)) - Opts.BuiltinIncludePath = GetBuiltinIncludePath(Argv0, MainAddr); + Opts.ResourceDir = getLastArgValue(Args, OPT_resource_dir); // Add -I... and -F... options in order. for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F), @@ -1115,7 +1134,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, if (Args.hasArg(OPT_fno_lax_vector_conversions)) Opts.LaxVectorConversions = 0; Opts.Exceptions = Args.hasArg(OPT_fexceptions); - Opts.Rtti = !Args.hasArg(OPT_fno_rtti); + Opts.RTTI = !Args.hasArg(OPT_fno_rtti); Opts.Blocks = Args.hasArg(OPT_fblocks); Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char); Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar); @@ -1131,6 +1150,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.ObjCConstantStringClass = getLastArgValue(Args, OPT_fconstant_string_class); Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi); + Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior); Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls); Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags); Opts.Static = Args.hasArg(OPT_static_define); @@ -1160,7 +1180,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, } } -static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args) { +static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, + Diagnostic &Diags) { using namespace cc1options; Opts.ImplicitPCHInclude = getLastArgValue(Args, OPT_include_pch); Opts.ImplicitPTHInclude = getLastArgValue(Args, OPT_include_pth); @@ -1188,16 +1209,27 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args) { // PCH is handled specially, we need to extra the original include path. if (it->getOption().matches(OPT_include_pch)) { std::string OriginalFile = - PCHReader::getOriginalSourceFile(it->getValue(Args)); - - // FIXME: Don't fail like this. + PCHReader::getOriginalSourceFile(it->getValue(Args), Diags); if (OriginalFile.empty()) - exit(1); + continue; Opts.Includes.push_back(OriginalFile); } else Opts.Includes.push_back(it->getValue(Args)); } + + for (arg_iterator it = Args.filtered_begin(OPT_remap_file), + ie = Args.filtered_end(); it != ie; ++it) { + std::pair<llvm::StringRef,llvm::StringRef> Split = + llvm::StringRef(it->getValue(Args)).split(';'); + + if (Split.second.empty()) { + Diags.Report(diag::err_drv_invalid_remap_file) << it->getAsString(Args); + continue; + } + + Opts.addRemappedFile(Split.first, Split.second); + } } static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, @@ -1227,8 +1259,6 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) { void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, const char **ArgBegin, const char **ArgEnd, - const char *Argv0, - void *MainAddr, Diagnostic &Diags) { // Parse the arguments. llvm::OwningPtr<OptTable> Opts(createCC1OptTable()); @@ -1252,11 +1282,10 @@ void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, Diags); FrontendOptions::InputKind DashX = ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags); - ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args, - Argv0, MainAddr); + ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args); if (DashX != FrontendOptions::IK_AST) ParseLangArgs(Res.getLangOpts(), *Args, DashX, Diags); - ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args); + ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, Diags); ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args); ParseTargetArgs(Res.getTargetOpts(), *Args); } diff --git a/lib/Frontend/DiagChecker.cpp b/lib/Frontend/DiagChecker.cpp index e7a66b1..a50cc99 100644 --- a/lib/Frontend/DiagChecker.cpp +++ b/lib/Frontend/DiagChecker.cpp @@ -17,7 +17,7 @@ #include "clang/AST/ASTConsumer.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Preprocessor.h" -#include <cstdio> +#include "llvm/Support/raw_ostream.h" using namespace clang; typedef TextDiagnosticBuffer::DiagList DiagList; @@ -190,12 +190,10 @@ static bool PrintProblem(SourceManager &SourceMgr, const char *Msg) { if (diag_begin == diag_end) return false; - fprintf(stderr, "%s\n", Msg); - + llvm::errs() << Msg << "\n"; for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) - fprintf(stderr, " Line %d: %s\n", - SourceMgr.getInstantiationLineNumber(I->first), - I->second.c_str()); + llvm::errs() << " Line " << SourceMgr.getInstantiationLineNumber(I->first) + << " " << I->second << "\n"; return true; } diff --git a/lib/Frontend/FixItRewriter.cpp b/lib/Frontend/FixItRewriter.cpp index dddcaa9..4fa2b3c 100644 --- a/lib/Frontend/FixItRewriter.cpp +++ b/lib/Frontend/FixItRewriter.cpp @@ -66,7 +66,7 @@ bool FixItRewriter::WriteFixedFile(const std::string &InFileName, Rewrite.getRewriteBufferFor(MainFileID)) { *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end()); } else { - std::fprintf(stderr, "Main file is unchanged\n"); + Diag(FullSourceLoc(), diag::note_fixit_main_file_unchanged); } OutFile->flush(); diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index 91c946c..96a68c9 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -46,11 +46,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, 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; + ASTUnit *AST = ASTUnit::LoadFromPCHFile(Filename, CI.getDiagnostics()); + if (!AST) goto failure; - } setCurrentFile(Filename, AST); @@ -224,5 +222,5 @@ void ASTFrontendAction::ExecuteAction() { ASTConsumer * PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { - llvm::llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!"); + llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!"); } diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 27e194e..e3c313a 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -35,13 +35,16 @@ ASTConsumer *AnalysisAction::CreateASTConsumer(CompilerInstance &CI, ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { - return CreateASTPrinter(CI.createDefaultOutputFile(false, InFile)); + if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) + return CreateASTPrinter(OS); + return 0; } ASTConsumer *ASTPrintXMLAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { - return CreateASTPrinterXML(CI.createDefaultOutputFile(false, InFile, - "xml")); + if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "xml")) + return CreateASTPrinterXML(OS); + return 0; } ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, @@ -74,6 +77,9 @@ ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, } llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, InFile); + if (!OS) + return 0; + if (CI.getFrontendOpts().RelocatablePCH) return CreatePCHGenerator(CI.getPreprocessor(), OS, Sysroot.c_str()); @@ -82,8 +88,9 @@ ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, ASTConsumer *HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { - return CreateHTMLPrinter(CI.createDefaultOutputFile(false, InFile), - CI.getPreprocessor()); + if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) + return CreateHTMLPrinter(OS, CI.getPreprocessor()); + return 0; } ASTConsumer *InheritanceViewAction::CreateASTConsumer(CompilerInstance &CI, @@ -140,10 +147,11 @@ void FixItAction::EndSourceFileAction() { ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { - return CreateObjCRewriter(InFile, - CI.createDefaultOutputFile(true, InFile, "cpp"), - CI.getDiagnostics(), CI.getLangOpts(), - CI.getDiagnosticOpts().NoRewriteMacros); + if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp")) + return CreateObjCRewriter(InFile, OS, + CI.getDiagnostics(), CI.getLangOpts(), + CI.getDiagnosticOpts().NoRewriteMacros); + return 0; } ASTConsumer *RewriteBlocksAction::CreateASTConsumer(CompilerInstance &CI, @@ -162,12 +170,21 @@ ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { BackendAction BA = static_cast<BackendAction>(Act); llvm::OwningPtr<llvm::raw_ostream> OS; - if (BA == Backend_EmitAssembly) + switch (BA) { + case Backend_EmitAssembly: OS.reset(CI.createDefaultOutputFile(false, InFile, "s")); - else if (BA == Backend_EmitLL) + break; + case Backend_EmitLL: OS.reset(CI.createDefaultOutputFile(false, InFile, "ll")); - else if (BA == Backend_EmitBC) + break; + case Backend_EmitBC: OS.reset(CI.createDefaultOutputFile(true, InFile, "bc")); + break; + case Backend_EmitNothing: + break; + } + if (BA != Backend_EmitNothing && !OS) + return 0; return CreateBackendConsumer(BA, CI.getDiagnostics(), CI.getLangOpts(), CI.getCodeGenOpts(), CI.getTargetOpts(), @@ -228,6 +245,8 @@ void GeneratePTHAction::ExecuteAction() { } llvm::raw_fd_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); + if (!OS) return; + CacheTokens(CI.getPreprocessor(), OS); } @@ -255,6 +274,8 @@ void PrintParseAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); Preprocessor &PP = getCompilerInstance().getPreprocessor(); llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); + if (!OS) return; + llvm::OwningPtr<Action> PA(CreatePrintParserActionsAction(PP, OS)); Parser P(PP, *PA); @@ -265,6 +286,8 @@ void PrintParseAction::ExecuteAction() { void PrintPreprocessedAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); + if (!OS) return; + DoPrintPreprocessedInput(CI.getPreprocessor(), OS, CI.getPreprocessorOutputOpts()); } @@ -272,11 +295,15 @@ void PrintPreprocessedAction::ExecuteAction() { void RewriteMacrosAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); + if (!OS) return; + RewriteMacrosInInput(CI.getPreprocessor(), OS); } void RewriteTestAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); + if (!OS) return; + DoRewriteTest(CI.getPreprocessor(), OS); } diff --git a/lib/Frontend/HTMLPrint.cpp b/lib/Frontend/HTMLPrint.cpp index 75e6184..9ea8cb3 100644 --- a/lib/Frontend/HTMLPrint.cpp +++ b/lib/Frontend/HTMLPrint.cpp @@ -41,9 +41,9 @@ namespace { bool _SyntaxHighlight, bool _HighlightMacros) : Out(OS), PP(pp), SyntaxHighlight(_SyntaxHighlight), HighlightMacros(_HighlightMacros) {} - virtual ~HTMLPrinter(); void Initialize(ASTContext &context); + void HandleTranslationUnit(ASTContext &Ctx); }; } @@ -58,7 +58,7 @@ void HTMLPrinter::Initialize(ASTContext &context) { R.setSourceMgr(context.getSourceManager(), context.getLangOptions()); } -HTMLPrinter::~HTMLPrinter() { +void HTMLPrinter::HandleTranslationUnit(ASTContext &Ctx) { if (PP.getDiagnostics().hasErrorOccurred()) return; diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index a40a569..b4ea257 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -21,10 +21,10 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" +#include "llvm/ADT/Twine.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" #include "llvm/Config/config.h" -#include <cstdio> #ifdef _MSC_VER #define WIN32_LEAN_AND_MEAN 1 #include <windows.h> @@ -50,27 +50,27 @@ public: : Headers(HS), Verbose(verbose), isysroot(iSysroot) {} /// AddPath - Add the specified path to the specified group list. - void AddPath(const llvm::StringRef &Path, IncludeDirGroup Group, + void AddPath(const llvm::Twine &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, + void AddGnuCPlusPlusIncludePaths(llvm::StringRef Base, + llvm::StringRef ArchDir, + llvm::StringRef Dir32, + llvm::StringRef 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); + void AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base, + llvm::StringRef Arch, + llvm::StringRef 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); + void AddDelimitedPaths(llvm::StringRef String); // AddDefaultCIncludePaths - Add paths that should always be searched. void AddDefaultCIncludePaths(const llvm::Triple &triple); @@ -91,25 +91,26 @@ public: } -void InitHeaderSearch::AddPath(const llvm::StringRef &Path, +void InitHeaderSearch::AddPath(const llvm::Twine &Path, IncludeDirGroup Group, bool isCXXAware, bool isUserSupplied, bool isFramework, bool IgnoreSysRoot) { - assert(!Path.empty() && "can't handle empty path here"); + assert(!Path.isTriviallyEmpty() && "can't handle empty path here"); FileManager &FM = Headers.getFileMgr(); // Compute the actual path, taking into consideration -isysroot. - llvm::SmallString<256> MappedPath; + llvm::SmallString<256> MappedPathStr; + llvm::raw_svector_ostream MappedPath(MappedPathStr); // Handle isysroot. if (Group == System && !IgnoreSysRoot) { // FIXME: Portability. This should be a sys::Path interface, this doesn't // handle things like C:\ right, nor win32 \\network\device\blah. if (isysroot.size() != 1 || isysroot[0] != '/') // Add isysroot if present. - MappedPath.append(isysroot.begin(), isysroot.end()); + MappedPath << isysroot; } - MappedPath.append(Path.begin(), Path.end()); + Path.print(MappedPath); // Compute the DirectoryLookup type. SrcMgr::CharacteristicKind Type; @@ -146,29 +147,29 @@ void InitHeaderSearch::AddPath(const llvm::StringRef &Path, } -void InitHeaderSearch::AddDelimitedPaths(const char *at) { - if (*at == 0) // Empty string should not add '.' path. +void InitHeaderSearch::AddDelimitedPaths(llvm::StringRef at) { + if (at.empty()) // Empty string should not add '.' path. return; - const char* delim = strchr(at, llvm::sys::PathSeparator); - while (delim != 0) { - if (delim-at == 0) + llvm::StringRef::size_type delim; + while ((delim = at.find(llvm::sys::PathSeparator)) != llvm::StringRef::npos) { + if (delim == 0) AddPath(".", Angled, false, true, false); else - AddPath(llvm::StringRef(at, delim-at), Angled, false, true, false); - at = delim + 1; - delim = strchr(at, llvm::sys::PathSeparator); + AddPath(at.substr(0, delim), Angled, false, true, false); + at = at.substr(delim + 1); } - if (*at == 0) + + if (at.empty()) AddPath(".", Angled, false, true, false); else AddPath(at, Angled, false, true, false); } -void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(const std::string &Base, - const char *ArchDir, - const char *Dir32, - const char *Dir64, +void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(llvm::StringRef Base, + llvm::StringRef ArchDir, + llvm::StringRef Dir32, + llvm::StringRef Dir64, const llvm::Triple &triple) { // Add the base dir AddPath(Base, System, true, false, false); @@ -185,10 +186,10 @@ void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(const std::string &Base, AddPath(Base + "/backward", System, true, false, false); } -void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(const std::string &Base, - const char *Arch, - const char *Version) { - std::string localBase = Base + "/" + Arch + "/" + Version + "/include"; +void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base, + llvm::StringRef Arch, + llvm::StringRef Version) { + llvm::Twine 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); @@ -258,25 +259,25 @@ bool getSystemRegistryString(const char *keyPath, const char *valueName, int bestIndex = -1; double bestValue = 0.0; DWORD index, size = sizeof(keyName) - 1; - for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL,
- NULL, NULL, NULL) == ERROR_SUCCESS; index++) {
- const char *sp = keyName;
- while (*sp && !isdigit(*sp))
- sp++;
- if (!*sp)
- continue;
- const char *ep = sp + 1;
- while (*ep && (isdigit(*ep) || (*ep == '.')))
- ep++;
- char numBuf[32];
- strncpy(numBuf, sp, sizeof(numBuf) - 1);
- numBuf[sizeof(numBuf) - 1] = '\0';
- double value = strtod(numBuf, NULL);
- if (value > bestValue) {
- bestIndex = (int)index;
- bestValue = value;
- strcpy(bestName, keyName);
- }
+ for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL, + NULL, NULL, NULL) == ERROR_SUCCESS; index++) { + const char *sp = keyName; + while (*sp && !isdigit(*sp)) + sp++; + if (!*sp) + continue; + const char *ep = sp + 1; + while (*ep && (isdigit(*ep) || (*ep == '.'))) + ep++; + char numBuf[32]; + strncpy(numBuf, sp, sizeof(numBuf) - 1); + numBuf[sizeof(numBuf) - 1] = '\0'; + double value = strtod(numBuf, NULL); + if (value > bestValue) { + bestIndex = (int)index; + bestValue = value; + strcpy(bestName, keyName); + } size = sizeof(keyName) - 1; } // If we found the highest versioned key, open the key and get the value. @@ -500,6 +501,10 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1", "i586-redhat-linux","", "", triple); + // Fedora 12 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", + "i686-redhat-linux","", "", triple); + // openSUSE 11.1 32 bit AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", "i586-suse-linux", "", "", triple); @@ -643,11 +648,11 @@ static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList, } if (Verbose) { - fprintf(stderr, "ignoring duplicate directory \"%s\"\n", - CurEntry.getName()); + llvm::errs() << "ignoring duplicate directory \"" + << CurEntry.getName() << "\"\n"; if (DirToRemove != i) - fprintf(stderr, " as it is a non-system directory that duplicates" - " a system directory\n"); + llvm::errs() << " as it is a non-system directory that duplicates " + << "a system directory\n"; } // This is reached if the current entry is a duplicate. Remove the @@ -680,11 +685,11 @@ void InitHeaderSearch::Realize() { // If verbose, print the list of directories that will be searched. if (Verbose) { - fprintf(stderr, "#include \"...\" search starts here:\n"); + llvm::errs() << "#include \"...\" search starts here:\n"; unsigned QuotedIdx = IncludeGroup[Quoted].size(); for (unsigned i = 0, e = SearchList.size(); i != e; ++i) { if (i == QuotedIdx) - fprintf(stderr, "#include <...> search starts here:\n"); + llvm::errs() << "#include <...> search starts here:\n"; const char *Name = SearchList[i].getName(); const char *Suffix; if (SearchList[i].isNormalDir()) @@ -695,9 +700,9 @@ void InitHeaderSearch::Realize() { assert(SearchList[i].isHeaderMap() && "Unknown DirectoryLookup"); Suffix = " (headermap)"; } - fprintf(stderr, " %s%s\n", Name, Suffix); + llvm::errs() << " " << Name << Suffix << "\n"; } - fprintf(stderr, "End of search list.\n"); + llvm::errs() << "End of search list.\n"; } } @@ -715,21 +720,22 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS, } // Add entries from CPATH and friends. - Init.AddDelimitedPaths(HSOpts.EnvIncPath.c_str()); + Init.AddDelimitedPaths(HSOpts.EnvIncPath); if (Lang.CPlusPlus && Lang.ObjC1) - Init.AddDelimitedPaths(HSOpts.ObjCXXEnvIncPath.c_str()); + Init.AddDelimitedPaths(HSOpts.ObjCXXEnvIncPath); else if (Lang.CPlusPlus) - Init.AddDelimitedPaths(HSOpts.CXXEnvIncPath.c_str()); + Init.AddDelimitedPaths(HSOpts.CXXEnvIncPath); else if (Lang.ObjC1) - Init.AddDelimitedPaths(HSOpts.ObjCEnvIncPath.c_str()); + Init.AddDelimitedPaths(HSOpts.ObjCEnvIncPath); else - Init.AddDelimitedPaths(HSOpts.CEnvIncPath.c_str()); + Init.AddDelimitedPaths(HSOpts.CEnvIncPath); - if (!HSOpts.BuiltinIncludePath.empty()) { + if (HSOpts.UseBuiltinIncludes) { // Ignore the sys root, we *always* look for clang headers relative to // supplied path. - Init.AddPath(HSOpts.BuiltinIncludePath, System, - false, false, false, /*IgnoreSysRoot=*/ true); + llvm::sys::Path P(HSOpts.ResourceDir); + P.appendComponent("include"); + Init.AddPath(P.str(), System, false, false, false, /*IgnoreSysRoot=*/ true); } if (HSOpts.UseStandardIncludes) diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 972c21f..c1fc92d 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -13,17 +13,23 @@ #include "clang/Frontend/Utils.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/PreprocessorOptions.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/System/Path.h" using namespace clang; // Append a #define line to Buf for Macro. Macro should be of the form XXX, // in which case we emit "#define XXX 1" or "XXX=Y z W" in which case we emit // "#define XXX Y z W". To get a #define with no value, use "XXX=". -static void DefineBuiltinMacro(std::vector<char> &Buf, const char *Macro) { +static void DefineBuiltinMacro(std::vector<char> &Buf, const char *Macro, + Diagnostic *Diags = 0) { const char *Command = "#define "; Buf.insert(Buf.end(), Command, Command+strlen(Command)); if (const char *Equal = strchr(Macro, '=')) { @@ -34,9 +40,9 @@ static void DefineBuiltinMacro(std::vector<char> &Buf, const char *Macro) { // Per GCC -D semantics, the macro ends at \n if it exists. const char *End = strpbrk(Equal, "\n\r"); if (End) { - fprintf(stderr, "warning: macro '%s' contains embedded newline, text " - "after the newline is ignored.\n", - std::string(Macro, Equal).c_str()); + assert(Diags && "Unexpected macro with embedded newline!"); + Diags->Report(diag::warn_fe_macro_contains_embedded_newline) + << std::string(Macro, Equal); } else { End = Equal+strlen(Equal); } @@ -118,11 +124,9 @@ static void AddImplicitIncludePTH(std::vector<char> &Buf, Preprocessor &PP, const char *OriginalFile = P->getOriginalSourceFile(); if (!OriginalFile) { - assert(!ImplicitIncludePTH.empty()); - fprintf(stderr, "error: PTH file '%s' does not designate an original " - "source header file for -include-pth\n", - ImplicitIncludePTH.c_str()); - exit (1); + PP.getDiagnostics().Report(diag::err_fe_pth_file_has_no_source_header) + << ImplicitIncludePTH; + return; } AddImplicitInclude(Buf, OriginalFile); @@ -358,6 +362,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI, DefineBuiltinMacro(Buf, "__int16=__INT16_TYPE__"); DefineBuiltinMacro(Buf, "__int32=__INT32_TYPE__"); DefineBuiltinMacro(Buf, "__int64=__INT64_TYPE__"); + // Both __PRETTY_FUNCTION__ and __FUNCTION__ are GCC extensions, however + // VC++ appears to only like __FUNCTION__. + DefineBuiltinMacro(Buf, "__PRETTY_FUNCTION__=__FUNCTION__"); // Work around some issues with Visual C++ headerws. if (LangOpts.CPlusPlus) { // Since we define wchar_t in C++ mode. @@ -478,6 +485,52 @@ static void InitializePredefinedMacros(const TargetInfo &TI, TI.getTargetDefines(LangOpts, Buf); } +// Initialize the remapping of files to alternative contents, e.g., +// those specified through other files. +static void InitializeFileRemapping(Diagnostic &Diags, + SourceManager &SourceMgr, + FileManager &FileMgr, + const PreprocessorOptions &InitOpts) { + // Remap files in the source manager. + for (PreprocessorOptions::remapped_file_iterator + Remap = InitOpts.remapped_file_begin(), + RemapEnd = InitOpts.remapped_file_end(); + Remap != RemapEnd; + ++Remap) { + // Find the file that we're mapping to. + const FileEntry *ToFile = FileMgr.getFile(Remap->second); + if (!ToFile) { + Diags.Report(diag::err_fe_remap_missing_to_file) + << Remap->first << Remap->second; + continue; + } + + // Create the file entry for the file that we're mapping from. + const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first, + ToFile->getSize(), + 0); + if (!FromFile) { + Diags.Report(diag::err_fe_remap_missing_from_file) + << Remap->first; + continue; + } + + // Load the contents of the file we're mapping to. + std::string ErrorStr; + const llvm::MemoryBuffer *Buffer + = llvm::MemoryBuffer::getFile(ToFile->getName(), &ErrorStr); + if (!Buffer) { + Diags.Report(diag::err_fe_error_opening) + << Remap->second << ErrorStr; + continue; + } + + // Override the contents of the "from" file with the contents of + // the "to" file. + SourceMgr.overrideFileContents(FromFile, Buffer); + } +} + /// InitializePreprocessor - Initialize the preprocessor getting it and the /// environment ready to process a single file. This returns true on error. /// @@ -486,6 +539,9 @@ void clang::InitializePreprocessor(Preprocessor &PP, const HeaderSearchOptions &HSOpts) { std::vector<char> PredefineBuffer; + InitializeFileRemapping(PP.getDiagnostics(), PP.getSourceManager(), + PP.getFileManager(), InitOpts); + const char *LineDirective = "# 1 \"<built-in>\" 3\n"; PredefineBuffer.insert(PredefineBuffer.end(), LineDirective, LineDirective+strlen(LineDirective)); @@ -506,7 +562,8 @@ void clang::InitializePreprocessor(Preprocessor &PP, if (InitOpts.Macros[i].second) // isUndef UndefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str()); else - DefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str()); + DefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str(), + &PP.getDiagnostics()); } // If -imacros are specified, include them now. These are processed before @@ -523,6 +580,11 @@ void clang::InitializePreprocessor(Preprocessor &PP, AddImplicitInclude(PredefineBuffer, Path); } + // Exit the command line and go back to <built-in> (2 is LC_LEAVE). + LineDirective = "# 1 \"<built-in>\" 2\n"; + PredefineBuffer.insert(PredefineBuffer.end(), + LineDirective, LineDirective+strlen(LineDirective)); + // Null terminate PredefinedBuffer and add it. PredefineBuffer.push_back(0); PP.setPredefines(&PredefineBuffer[0]); diff --git a/lib/Frontend/LangStandards.cpp b/lib/Frontend/LangStandards.cpp index 771a58c..ed0ea1f 100644 --- a/lib/Frontend/LangStandards.cpp +++ b/lib/Frontend/LangStandards.cpp @@ -14,13 +14,13 @@ using namespace clang; using namespace clang::frontend; #define LANGSTANDARD(id, name, desc, features) \ - static LangStandard Lang_##id = { name, desc, features }; + static const LangStandard Lang_##id = { name, desc, features }; #include "clang/Frontend/LangStandards.def" const LangStandard &LangStandard::getLangStandardForKind(Kind K) { switch (K) { default: - llvm::llvm_unreachable("Invalid language kind!"); + llvm_unreachable("Invalid language kind!"); case lang_unspecified: llvm::llvm_report_error("getLangStandardForKind() on unspecified kind"); #define LANGSTANDARD(id, name, desc, features) \ diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index cb96bcb..48ef2ac 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -116,6 +116,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) { diag::warn_pch_stack_protector); PARSE_LANGOPT_BENIGN(InstantiationDepth); PARSE_LANGOPT_IMPORTANT(OpenCL, diag::warn_pch_opencl); + PARSE_LANGOPT_BENIGN(CatchUndefined); PARSE_LANGOPT_IMPORTANT(ElideConstructors, diag::warn_pch_elide_constructors); #undef PARSE_LANGOPT_IRRELEVANT #undef PARSE_LANGOPT_BENIGN @@ -1569,13 +1570,14 @@ void PCHReader::InitializeContext(ASTContext &Ctx) { /// \brief Retrieve the name of the original source file name /// directly from the PCH file, without actually loading the PCH /// file. -std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) { +std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName, + Diagnostic &Diags) { // Open the PCH file. std::string ErrStr; llvm::OwningPtr<llvm::MemoryBuffer> Buffer; Buffer.reset(llvm::MemoryBuffer::getFile(PCHFileName.c_str(), &ErrStr)); if (!Buffer) { - fprintf(stderr, "error: %s\n", ErrStr.c_str()); + Diags.Report(diag::err_fe_unable_to_read_pch_file) << ErrStr; return std::string(); } @@ -1591,9 +1593,7 @@ std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) { Stream.Read(8) != 'P' || Stream.Read(8) != 'C' || Stream.Read(8) != 'H') { - fprintf(stderr, - "error: '%s' does not appear to be a precompiled header file\n", - PCHFileName.c_str()); + Diags.Report(diag::err_fe_not_a_pch_file) << PCHFileName; return std::string(); } @@ -1608,14 +1608,14 @@ std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) { switch (BlockID) { case pch::PCH_BLOCK_ID: if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) { - fprintf(stderr, "error: malformed block record in PCH file\n"); + Diags.Report(diag::err_fe_pch_malformed_block) << PCHFileName; return std::string(); } break; default: if (Stream.SkipBlock()) { - fprintf(stderr, "error: malformed block record in PCH file\n"); + Diags.Report(diag::err_fe_pch_malformed_block) << PCHFileName; return std::string(); } break; @@ -1625,7 +1625,7 @@ std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName) { if (Code == llvm::bitc::END_BLOCK) { if (Stream.ReadBlockEnd()) { - fprintf(stderr, "error: error at end of module block in PCH file\n"); + Diags.Report(diag::err_fe_pch_error_at_end_block) << PCHFileName; return std::string(); } continue; @@ -1720,6 +1720,8 @@ bool PCHReader::ParseLanguageOptions( ++Idx; PARSE_LANGOPT(InstantiationDepth); PARSE_LANGOPT(OpenCL); + PARSE_LANGOPT(CatchUndefined); + // FIXME: Missing ElideConstructors?! #undef PARSE_LANGOPT return Listener->ReadLanguageOptions(LangOpts); @@ -1881,6 +1883,10 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { Exceptions.data()); } + case pch::TYPE_UNRESOLVED_USING: + return Context->getTypeDeclType( + cast<UnresolvedUsingTypenameDecl>(GetDecl(Record[0]))); + case pch::TYPE_TYPEDEF: assert(Record.size() == 1 && "incorrect encoding of typedef type"); return Context->getTypeDeclType(cast<TypedefDecl>(GetDecl(Record[0]))); @@ -2045,6 +2051,9 @@ void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { VisitFunctionTypeLoc(TL); } +void TypeLocReader::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } @@ -2107,17 +2116,17 @@ void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { TL.setProtocolLoc(i, SourceLocation::getFromRawEncoding(Record[Idx++])); } -DeclaratorInfo *PCHReader::GetDeclaratorInfo(const RecordData &Record, +TypeSourceInfo *PCHReader::GetTypeSourceInfo(const RecordData &Record, unsigned &Idx) { QualType InfoTy = GetType(Record[Idx++]); if (InfoTy.isNull()) return 0; - DeclaratorInfo *DInfo = getContext()->CreateDeclaratorInfo(InfoTy); + TypeSourceInfo *TInfo = getContext()->CreateTypeSourceInfo(InfoTy); TypeLocReader TLR(*this, Record, Idx); - for (TypeLoc TL = DInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) + for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) TLR.Visit(TL); - return DInfo; + return TInfo; } QualType PCHReader::GetType(pch::TypeID ID) { @@ -2183,7 +2192,7 @@ PCHReader::GetTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, case TemplateArgument::Expression: return ReadDeclExpr(); case TemplateArgument::Type: - return GetDeclaratorInfo(Record, Index); + return GetTypeSourceInfo(Record, Index); case TemplateArgument::Template: { SourceLocation QualStart = SourceLocation::getFromRawEncoding(Record[Index++]), @@ -2198,7 +2207,7 @@ PCHReader::GetTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, case TemplateArgument::Pack: return TemplateArgumentLocInfo(); } - llvm::llvm_unreachable("unexpected template argument loc"); + llvm_unreachable("unexpected template argument loc"); return TemplateArgumentLocInfo(); } diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index 03f3b4767..01e1a41 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -107,7 +107,7 @@ void PCHDeclReader::VisitTypedefDecl(TypedefDecl *TD) { // the type associated with the TypedefDecl. VisitNamedDecl(TD); uint64_t TypeData = Record[Idx++]; - TD->setTypeDeclaratorInfo(Reader.GetDeclaratorInfo(Record, Idx)); + TD->setTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx)); TD->setTypeForDecl(Reader.GetType(TypeData).getTypePtr()); } @@ -126,6 +126,7 @@ void PCHDeclReader::VisitTagDecl(TagDecl *TD) { void PCHDeclReader::VisitEnumDecl(EnumDecl *ED) { VisitTagDecl(ED); ED->setIntegerType(Reader.GetType(Record[Idx++])); + ED->setPromotionType(Reader.GetType(Record[Idx++])); // FIXME: C++ InstantiatedFrom } @@ -150,9 +151,9 @@ void PCHDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) { void PCHDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) { VisitValueDecl(DD); - DeclaratorInfo *DInfo = Reader.GetDeclaratorInfo(Record, Idx); - if (DInfo) - DD->setDeclaratorInfo(DInfo); + TypeSourceInfo *TInfo = Reader.GetTypeSourceInfo(Record, Idx); + if (TInfo) + DD->setTypeSourceInfo(TInfo); } void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) { diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp index 00734a0..f28e61e 100644 --- a/lib/Frontend/PCHReaderStmt.cpp +++ b/lib/Frontend/PCHReaderStmt.cpp @@ -349,7 +349,7 @@ unsigned PCHStmtReader::VisitPredefinedExpr(PredefinedExpr *E) { unsigned PCHStmtReader::VisitDeclRefExpr(DeclRefExpr *E) { VisitExpr(E); - E->setDecl(cast<NamedDecl>(Reader.GetDecl(Record[Idx++]))); + E->setDecl(cast<ValueDecl>(Reader.GetDecl(Record[Idx++]))); E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); // FIXME: read qualifier // FIXME: read explicit template arguments @@ -428,7 +428,7 @@ unsigned PCHStmtReader::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { E->setArgument(cast<Expr>(StmtStack.back())); ++Idx; } else { - E->setArgument(Reader.GetDeclaratorInfo(Record, Idx)); + E->setArgument(Reader.GetTypeSourceInfo(Record, Idx)); } E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); @@ -456,7 +456,7 @@ unsigned PCHStmtReader::VisitCallExpr(CallExpr *E) { unsigned PCHStmtReader::VisitMemberExpr(MemberExpr *E) { VisitExpr(E); E->setBase(cast<Expr>(StmtStack.back())); - E->setMemberDecl(cast<NamedDecl>(Reader.GetDecl(Record[Idx++]))); + E->setMemberDecl(cast<ValueDecl>(Reader.GetDecl(Record[Idx++]))); E->setMemberLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); E->setArrow(Record[Idx++]); return 1; diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index e79f9c9..681c1ff 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -166,6 +166,14 @@ void PCHTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) { Code = pch::TYPE_FUNCTION_PROTO; } +#if 0 +// For when we want it.... +void PCHTypeWriter::VisitUnresolvedUsingType(const UnresolvedUsingType *T) { + Writer.AddDeclRef(T->getDecl(), Record); + Code = pch::TYPE_UNRESOLVED_USING; +} +#endif + void PCHTypeWriter::VisitTypedefType(const TypedefType *T) { Writer.AddDeclRef(T->getDecl(), Record); Code = pch::TYPE_TYPEDEF; @@ -337,6 +345,9 @@ void TypeLocWriter::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { void TypeLocWriter::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { VisitFunctionTypeLoc(TL); } +void TypeLocWriter::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } @@ -770,6 +781,7 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) { Record.push_back(LangOpts.getStackProtectorMode()); Record.push_back(LangOpts.InstantiationDepth); Record.push_back(LangOpts.OpenCL); + Record.push_back(LangOpts.CatchUndefined); Record.push_back(LangOpts.ElideConstructors); Stream.EmitRecord(pch::LANGUAGE_OPTIONS, Record); } @@ -2129,7 +2141,7 @@ void PCHWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg, AddStmt(Arg.getLocInfo().getAsExpr()); break; case TemplateArgument::Type: - AddDeclaratorInfo(Arg.getLocInfo().getAsDeclaratorInfo(), Record); + AddTypeSourceInfo(Arg.getLocInfo().getAsTypeSourceInfo(), Record); break; case TemplateArgument::Template: Record.push_back( @@ -2145,15 +2157,15 @@ void PCHWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg, } } -void PCHWriter::AddDeclaratorInfo(DeclaratorInfo *DInfo, RecordData &Record) { - if (DInfo == 0) { +void PCHWriter::AddTypeSourceInfo(TypeSourceInfo *TInfo, RecordData &Record) { + if (TInfo == 0) { AddTypeRef(QualType(), Record); return; } - AddTypeRef(DInfo->getType(), Record); + AddTypeRef(TInfo->getType(), Record); TypeLocWriter TLW(*this, Record); - for (TypeLoc TL = DInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) + for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) TLW.Visit(TL); } diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index c7bfee2..049cdb0 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -14,9 +14,9 @@ #include "clang/Frontend/PCHWriter.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/Expr.h" +#include "llvm/ADT/Twine.h" #include "llvm/Bitcode/BitstreamWriter.h" -#include <cstdio> - +#include "llvm/Support/ErrorHandling.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -106,7 +106,7 @@ void PCHDeclWriter::VisitTypeDecl(TypeDecl *D) { void PCHDeclWriter::VisitTypedefDecl(TypedefDecl *D) { VisitTypeDecl(D); - Writer.AddDeclaratorInfo(D->getTypeDeclaratorInfo(), Record); + Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); Code = pch::DECL_TYPEDEF; } @@ -123,6 +123,7 @@ void PCHDeclWriter::VisitTagDecl(TagDecl *D) { void PCHDeclWriter::VisitEnumDecl(EnumDecl *D) { VisitTagDecl(D); Writer.AddTypeRef(D->getIntegerType(), Record); + Writer.AddTypeRef(D->getPromotionType(), Record); // FIXME: C++ InstantiatedFrom Code = pch::DECL_ENUM; } @@ -151,7 +152,7 @@ void PCHDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) { void PCHDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) { VisitValueDecl(D); - Writer.AddDeclaratorInfo(D->getDeclaratorInfo(), Record); + Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); } void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) { @@ -370,7 +371,7 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { // If the assumptions about the DECL_PARM_VAR abbrev are true, use it. Here // we dynamically check for the properties that we optimize for, but don't // know are true of all PARM_VAR_DECLs. - if (!D->getDeclaratorInfo() && + if (!D->getTypeSourceInfo() && !D->hasAttrs() && !D->isImplicit() && !D->isUsed() && @@ -568,12 +569,9 @@ void PCHWriter::WriteDecl(ASTContext &Context, Decl *D) { W.Visit(D); if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset); - if (!W.Code) { - fprintf(stderr, "Cannot serialize declaration of kind %s\n", - D->getDeclKindName()); - assert(false && "Unhandled declaration kind while generating PCH"); - exit(-1); - } + if (!W.Code) + llvm::llvm_report_error(llvm::StringRef("unexpected declaration kind '") + + D->getDeclKindName() + "'"); Stream.EmitRecord(W.Code, Record, W.AbbrevToUse); // If the declaration had any attributes, write them now. diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp index 27b83ed..22f7ad6 100644 --- a/lib/Frontend/PCHWriterStmt.cpp +++ b/lib/Frontend/PCHWriterStmt.cpp @@ -388,7 +388,7 @@ void PCHStmtWriter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { VisitExpr(E); Record.push_back(E->isSizeOf()); if (E->isArgumentType()) - Writer.AddDeclaratorInfo(E->getArgumentTypeInfo(), Record); + Writer.AddTypeSourceInfo(E->getArgumentTypeInfo(), Record); else { Record.push_back(0); Writer.WriteSubStmt(E->getArgumentExpr()); diff --git a/lib/Frontend/PlistDiagnostics.cpp b/lib/Frontend/PlistDiagnostics.cpp index 80ee2c2..92cafe6 100644 --- a/lib/Frontend/PlistDiagnostics.cpp +++ b/lib/Frontend/PlistDiagnostics.cpp @@ -30,6 +30,40 @@ namespace clang { } namespace { +struct CompareDiagnostics { + // Compare if 'X' is "<" than 'Y'. + bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const { + // First compare by location + const FullSourceLoc &XLoc = X->getLocation().asLocation(); + const FullSourceLoc &YLoc = Y->getLocation().asLocation(); + if (XLoc < YLoc) + return true; + if (XLoc != YLoc) + return false; + + // Next, compare by bug type. + llvm::StringRef XBugType = X->getBugType(); + llvm::StringRef YBugType = Y->getBugType(); + if (XBugType < YBugType) + return true; + if (XBugType != YBugType) + return false; + + // Next, compare by bug description. + llvm::StringRef XDesc = X->getDescription(); + llvm::StringRef YDesc = Y->getDescription(); + if (XDesc < YDesc) + return true; + if (XDesc != YDesc) + return false; + + // FIXME: Further refine by comparing PathDiagnosticPieces? + return false; + } +}; +} + +namespace { class PlistDiagnostics : public PathDiagnosticClient { std::vector<const PathDiagnostic*> BatchedDiags; const std::string OutputFile; @@ -314,6 +348,11 @@ void PlistDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> return; flushed = true; + + // Sort the diagnostics so that they are always emitted in a deterministic + // order. + if (!BatchedDiags.empty()) + std::sort(BatchedDiags.begin(), BatchedDiags.end(), CompareDiagnostics()); // Build up a set of FIDs that we use by scanning the locations and // ranges of the diagnostics. diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index 3742405..d9708d8 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -36,22 +36,23 @@ static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI, if (MI.isFunctionLike()) { OS << '('; - if (MI.arg_empty()) - ; - else if (MI.getNumArgs() == 1) - OS << (*MI.arg_begin())->getName(); - else { + if (!MI.arg_empty()) { MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_end(); - OS << (*AI++)->getName(); - while (AI != E) - OS << ',' << (*AI++)->getName(); - } - - if (MI.isVariadic()) { - if (!MI.arg_empty()) + for (; AI+1 != E; ++AI) { + OS << (*AI)->getName(); OS << ','; - OS << "..."; + } + + // Last argument. + if ((*AI)->getName() == "__VA_ARGS__") + OS << "..."; + else + OS << (*AI)->getName(); } + + if (MI.isGNUVarargs()) + OS << "..."; // #define foo(x...) + OS << ')'; } @@ -94,6 +95,7 @@ private: bool Initialized; bool DisableLineMarkers; bool DumpDefines; + bool UseLineDirective; public: PrintPPOutputPPCallbacks(Preprocessor &pp, llvm::raw_ostream &os, bool lineMarkers, bool defines) @@ -105,6 +107,9 @@ public: EmittedMacroOnThisLine = false; FileType = SrcMgr::C_User; Initialized = false; + + // If we're in microsoft mode, use normal #line instead of line markers. + UseLineDirective = PP.getLangOptions().Microsoft; } void SetEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; } @@ -141,17 +146,24 @@ void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo, EmittedMacroOnThisLine = false; } - OS << '#' << ' ' << LineNo << ' ' << '"'; - OS.write(&CurFilename[0], CurFilename.size()); - OS << '"'; - - if (ExtraLen) - OS.write(Extra, ExtraLen); - - if (FileType == SrcMgr::C_System) - OS.write(" 3", 2); - else if (FileType == SrcMgr::C_ExternCSystem) - OS.write(" 3 4", 4); + // Emit #line directives or GNU line markers depending on what mode we're in. + if (UseLineDirective) { + OS << "#line" << ' ' << LineNo << ' ' << '"'; + OS.write(&CurFilename[0], CurFilename.size()); + OS << '"'; + } else { + OS << '#' << ' ' << LineNo << ' ' << '"'; + OS.write(&CurFilename[0], CurFilename.size()); + OS << '"'; + + if (ExtraLen) + OS.write(Extra, ExtraLen); + + if (FileType == SrcMgr::C_System) + OS.write(" 3", 2); + else if (FileType == SrcMgr::C_ExternCSystem) + OS.write(" 3 4", 4); + } OS << '\n'; } diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index 710fa55..df85c13 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -255,7 +255,10 @@ namespace { Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp); Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp); Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp); - void WarnAboutReturnGotoContinueOrBreakStmts(Stmt *S); + void WarnAboutReturnGotoStmts(Stmt *S); + void HasReturnStmts(Stmt *S, bool &hasReturns); + void RewriteTryReturnStmts(Stmt *S); + void RewriteSyncReturnStmts(Stmt *S, std::string buf); Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S); Stmt *RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S); Stmt *RewriteObjCCatchStmt(ObjCAtCatchStmt *S); @@ -328,11 +331,16 @@ namespace { const char *funcName, std::string Tag); std::string SynthesizeBlockFunc(BlockExpr *CE, int i, const char *funcName, std::string Tag); - std::string SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, - bool hasCopyDisposeHelpers); + std::string SynthesizeBlockImpl(BlockExpr *CE, + std::string Tag, std::string Desc); + std::string SynthesizeBlockDescriptor(std::string DescTag, + std::string ImplTag, + int i, const char *funcName, + unsigned hasCopy); Stmt *SynthesizeBlockCall(CallExpr *Exp); void SynthesizeBlockLiterals(SourceLocation FunLocStart, const char *FunName); + void RewriteRecordBody(RecordDecl *RD); void CollectBlockDeclRefInfo(BlockExpr *Exp); void GetBlockCallExprs(Stmt *S); @@ -547,14 +555,21 @@ void RewriteObjC::Initialize(ASTContext &context) { Preamble += "struct __block_impl {\n"; Preamble += " void *isa;\n"; Preamble += " int Flags;\n"; - Preamble += " int Size;\n"; + Preamble += " int Reserved;\n"; Preamble += " void *FuncPtr;\n"; Preamble += "};\n"; Preamble += "// Runtime copy/destroy helper functions (from Block_private.h)\n"; - Preamble += "__OBJC_RW_STATICIMPORT void _Block_object_assign(void *, const void *, const int);\n"; - Preamble += "__OBJC_RW_STATICIMPORT void _Block_object_dispose(const void *, const int);\n"; - Preamble += "__OBJC_RW_STATICIMPORT void *_NSConcreteGlobalBlock[32];\n"; - Preamble += "__OBJC_RW_STATICIMPORT void *_NSConcreteStackBlock[32];\n"; + Preamble += "#ifdef __OBJC_EXPORT_BLOCKS\n"; + Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_assign(void *, const void *, const int);\n"; + Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_dispose(const void *, const int);\n"; + Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];\n"; + Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteStackBlock[32];\n"; + Preamble += "#else\n"; + Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];\n"; + Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n"; + Preamble += "#endif\n"; Preamble += "#endif\n"; if (LangOpts.Microsoft) { Preamble += "#undef __OBJC_RW_DLLIMPORT\n"; @@ -1325,7 +1340,12 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, // type elem; NamedDecl* D = cast<NamedDecl>(DS->getSingleDecl()); QualType ElementType = cast<ValueDecl>(D)->getType(); - elementTypeAsString = ElementType.getAsString(); + if (ElementType->isObjCQualifiedIdType() || + ElementType->isObjCQualifiedInterfaceType()) + // Simply use 'id' for all qualified types. + elementTypeAsString = "id"; + else + elementTypeAsString = ElementType.getAsString(); buf += elementTypeAsString; buf += " "; elementName = D->getNameAsCString(); @@ -1335,8 +1355,13 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, else { DeclRefExpr *DR = cast<DeclRefExpr>(S->getElement()); elementName = DR->getDecl()->getNameAsCString(); - elementTypeAsString - = cast<ValueDecl>(DR->getDecl())->getType().getAsString(); + ValueDecl *VD = cast<ValueDecl>(DR->getDecl()); + if (VD->getType()->isObjCQualifiedIdType() || + VD->getType()->isObjCQualifiedInterfaceType()) + // Simply use 'id' for all qualified types. + elementTypeAsString = "id"; + else + elementTypeAsString = VD->getType().getAsString(); } // struct __objcFastEnumerationState enumState = { 0 }; @@ -1502,7 +1527,9 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { buf += "}\n"; buf += "{ /* implicit finally clause */\n"; buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n"; - buf += " objc_sync_exit("; + + std::string syncBuf; + syncBuf += " objc_sync_exit("; Expr *syncExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(), CastExpr::CK_Unknown, S->getSynchExpr(), @@ -1513,31 +1540,102 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { llvm::raw_string_ostream syncExprBuf(syncExprBufS); syncExpr->printPretty(syncExprBuf, *Context, 0, PrintingPolicy(LangOpts)); - buf += syncExprBuf.str(); - buf += ");\n"; - buf += " if (_rethrow) objc_exception_throw(_rethrow);\n"; + syncBuf += syncExprBuf.str(); + syncBuf += ");"; + + buf += syncBuf; + buf += "\n if (_rethrow) objc_exception_throw(_rethrow);\n"; buf += "}\n"; buf += "}"; ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size()); + + bool hasReturns = false; + HasReturnStmts(S->getSynchBody(), hasReturns); + if (hasReturns) + RewriteSyncReturnStmts(S->getSynchBody(), syncBuf); + return 0; } -void RewriteObjC::WarnAboutReturnGotoContinueOrBreakStmts(Stmt *S) { +void RewriteObjC::WarnAboutReturnGotoStmts(Stmt *S) +{ // Perform a bottom up traversal of all children. for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E; ++CI) if (*CI) - WarnAboutReturnGotoContinueOrBreakStmts(*CI); + WarnAboutReturnGotoStmts(*CI); - if (isa<ReturnStmt>(S) || isa<ContinueStmt>(S) || - isa<BreakStmt>(S) || isa<GotoStmt>(S)) { + if (isa<ReturnStmt>(S) || isa<GotoStmt>(S)) { Diags.Report(Context->getFullLoc(S->getLocStart()), TryFinallyContainsReturnDiag); } return; } +void RewriteObjC::HasReturnStmts(Stmt *S, bool &hasReturns) +{ + // Perform a bottom up traversal of all children. + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); + CI != E; ++CI) + if (*CI) + HasReturnStmts(*CI, hasReturns); + + if (isa<ReturnStmt>(S)) + hasReturns = true; + return; +} + +void RewriteObjC::RewriteTryReturnStmts(Stmt *S) { + // Perform a bottom up traversal of all children. + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); + CI != E; ++CI) + if (*CI) { + RewriteTryReturnStmts(*CI); + } + if (isa<ReturnStmt>(S)) { + SourceLocation startLoc = S->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + + const char *semiBuf = strchr(startBuf, ';'); + assert((*semiBuf == ';') && "RewriteTryReturnStmts: can't find ';'"); + SourceLocation onePastSemiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf+1); + + std::string buf; + buf = "{ objc_exception_try_exit(&_stack); return"; + + ReplaceText(startLoc, 6, buf.c_str(), buf.size()); + InsertText(onePastSemiLoc, "}", 1); + } + return; +} + +void RewriteObjC::RewriteSyncReturnStmts(Stmt *S, std::string syncExitBuf) { + // Perform a bottom up traversal of all children. + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); + CI != E; ++CI) + if (*CI) { + RewriteSyncReturnStmts(*CI, syncExitBuf); + } + if (isa<ReturnStmt>(S)) { + SourceLocation startLoc = S->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + + const char *semiBuf = strchr(startBuf, ';'); + assert((*semiBuf == ';') && "RewriteSyncReturnStmts: can't find ';'"); + SourceLocation onePastSemiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf+1); + + std::string buf; + buf = "{ objc_exception_try_exit(&_stack);"; + buf += syncExitBuf; + buf += " return"; + + ReplaceText(startLoc, 6, buf.c_str(), buf.size()); + InsertText(onePastSemiLoc, "}", 1); + } + return; +} + Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { // Get the start location and compute the semi location. SourceLocation startLoc = S->getLocStart(); @@ -1689,13 +1787,21 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { lastCurlyLoc = body->getLocEnd(); // Now check for any return/continue/go statements within the @try. - WarnAboutReturnGotoContinueOrBreakStmts(S->getTryBody()); + WarnAboutReturnGotoStmts(S->getTryBody()); } else { /* no finally clause - make sure we synthesize an implicit one */ buf = "{ /* implicit finally clause */\n"; buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n"; buf += " if (_rethrow) objc_exception_throw(_rethrow);\n"; buf += "}"; ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size()); + + // Now check for any return/continue/go statements within the @try. + // The implicit finally clause won't called if the @try contains any + // jump statements. + bool hasReturns = false; + HasReturnStmts(S->getTryBody(), hasReturns); + if (hasReturns) + RewriteTryReturnStmts(S->getTryBody()); } // Now emit the final closing curly brace... lastCurlyLoc = lastCurlyLoc.getFileLocWithOffset(1); @@ -1878,6 +1984,10 @@ void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) { return; Type = proto->getResultType(); } + else if (FieldDecl *FD = dyn_cast<FieldDecl>(Dcl)) { + Loc = FD->getLocation(); + Type = FD->getType(); + } else return; @@ -2134,8 +2244,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { PrintingPolicy(LangOpts)); Preamble += prettyBuf.str(); Preamble += ","; - // The minus 2 removes the begin/end double quotes. - Preamble += utostr(prettyBuf.str().size()-2) + "};\n"; + Preamble += utostr(Exp->getString()->getByteLength()) + "};\n"; VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), &Context->Idents.get(S.c_str()), strType, 0, @@ -2569,7 +2678,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { // Build sizeof(returnType) SizeOfAlignOfExpr *sizeofExpr = new (Context) SizeOfAlignOfExpr(true, - Context->getTrivialDeclaratorInfo(returnType), + Context->getTrivialTypeSourceInfo(returnType), Context->getSizeType(), SourceLocation(), SourceLocation()); // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) @@ -2609,12 +2718,12 @@ Stmt *RewriteObjC::RewriteMessageExpr(ObjCMessageExpr *Exp) { // typedef struct objc_object Protocol; QualType RewriteObjC::getProtocolType() { if (!ProtocolTypeDecl) { - DeclaratorInfo *DInfo - = Context->getTrivialDeclaratorInfo(Context->getObjCIdType()); + TypeSourceInfo *TInfo + = Context->getTrivialTypeSourceInfo(Context->getObjCIdType()); ProtocolTypeDecl = TypedefDecl::Create(*Context, TUDecl, SourceLocation(), &Context->Idents.get("Protocol"), - DInfo); + TInfo); } return Context->getTypeDeclType(ProtocolTypeDecl); } @@ -2737,7 +2846,7 @@ void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, ReplaceText(LocStart, endHeader-startBuf, Result.c_str(), Result.size()); } else { // rewrite the original header *without* disturbing the '{' - ReplaceText(LocStart, cursor-startBuf-1, Result.c_str(), Result.size()); + ReplaceText(LocStart, cursor-startBuf, Result.c_str(), Result.size()); } if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) { Result = "\n struct "; @@ -3689,20 +3798,18 @@ std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, return S; } -std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, - bool hasCopyDisposeHelpers) { +std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, + std::string Desc) { std::string S = "\nstruct " + Tag; std::string Constructor = " " + Tag; S += " {\n struct __block_impl impl;\n"; + S += " struct " + Desc; + S += "* Desc;\n"; - if (hasCopyDisposeHelpers) - S += " void *copy;\n void *dispose;\n"; - - Constructor += "(void *fp"; - - if (hasCopyDisposeHelpers) - Constructor += ", void *copyHelp, void *disposeHelp"; + Constructor += "(void *fp, "; // Invoke function pointer. + Constructor += "struct " + Desc; // Descriptor pointer. + Constructor += " *desc"; if (BlockDeclRefs.size()) { // Output all "by copy" declarations. @@ -3765,11 +3872,9 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n"; else Constructor += " impl.isa = &_NSConcreteStackBlock;\n"; - Constructor += " impl.Size = sizeof("; - Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n"; + Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n"; - if (hasCopyDisposeHelpers) - Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n"; + Constructor += " Desc = desc;\n"; // Initialize all "by copy" arguments. for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), @@ -3800,10 +3905,8 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n"; else Constructor += " impl.isa = &_NSConcreteStackBlock;\n"; - Constructor += " impl.Size = sizeof("; - Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n"; - if (hasCopyDisposeHelpers) - Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n"; + Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n"; + Constructor += " Desc = desc;\n"; } Constructor += " "; Constructor += "}\n"; @@ -3812,6 +3915,29 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, return S; } +std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag, + std::string ImplTag, int i, + const char *FunName, + unsigned hasCopy) { + std::string S = "\nstatic struct " + DescTag; + + S += " {\n unsigned long reserved;\n"; + S += " unsigned long Block_size;\n"; + if (hasCopy) { + S += " void *copy;\n void *dispose;\n"; + } + S += "} "; + + S += DescTag + "_DATA = { 0, sizeof(struct "; + S += ImplTag + ")"; + if (hasCopy) { + S += ", __" + std::string(FunName) + "_block_copy_" + utostr(i); + S += ", __" + std::string(FunName) + "_block_dispose_" + utostr(i); + } + S += "};\n"; + return S; +} + void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, const char *FunName) { // Insert closures that were part of the function. @@ -3819,21 +3945,24 @@ void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, CollectBlockDeclRefInfo(Blocks[i]); - std::string Tag = "__" + std::string(FunName) + "_block_impl_" + utostr(i); + std::string ImplTag = "__" + std::string(FunName) + "_block_impl_" + utostr(i); + std::string DescTag = "__" + std::string(FunName) + "_block_desc_" + utostr(i); - std::string CI = SynthesizeBlockImpl(Blocks[i], Tag, - ImportedBlockDecls.size() > 0); + std::string CI = SynthesizeBlockImpl(Blocks[i], ImplTag, DescTag); InsertText(FunLocStart, CI.c_str(), CI.size()); - std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, Tag); + std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, ImplTag); InsertText(FunLocStart, CF.c_str(), CF.size()); if (ImportedBlockDecls.size()) { - std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, Tag); + std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, ImplTag); InsertText(FunLocStart, HF.c_str(), HF.size()); } + std::string BD = SynthesizeBlockDescriptor(DescTag, ImplTag, i, FunName, + ImportedBlockDecls.size() > 0); + InsertText(FunLocStart, BD.c_str(), BD.size()); BlockDeclRefs.clear(); BlockByRefDecls.clear(); @@ -4243,25 +4372,21 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) { SourceLocation()); InitExprs.push_back(castExpr); - if (ImportedBlockDecls.size()) { - std::string Buf = "__" + FuncName + "_block_copy_" + BlockNumber; - FD = SynthBlockInitFunctionDecl(Buf.c_str()); - Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); - castExpr = new (Context) CStyleCastExpr(Context->VoidPtrTy, - CastExpr::CK_Unknown, Arg, - Context->VoidPtrTy, SourceLocation(), - SourceLocation()); - InitExprs.push_back(castExpr); - - Buf = "__" + FuncName + "_block_dispose_" + BlockNumber; - FD = SynthBlockInitFunctionDecl(Buf.c_str()); - Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); - castExpr = new (Context) CStyleCastExpr(Context->VoidPtrTy, - CastExpr::CK_Unknown, Arg, - Context->VoidPtrTy, SourceLocation(), - SourceLocation()); - InitExprs.push_back(castExpr); - } + // Initialize the block descriptor. + std::string DescData = "__" + FuncName + "_block_desc_" + BlockNumber + "_DATA"; + + VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), + &Context->Idents.get(DescData.c_str()), + Context->VoidPtrTy, 0, + VarDecl::Static); + UnaryOperator *DescRefExpr = new (Context) UnaryOperator( + new (Context) DeclRefExpr(NewVD, + Context->VoidPtrTy, SourceLocation()), + UnaryOperator::AddrOf, + Context->getPointerType(Context->VoidPtrTy), + SourceLocation()); + InitExprs.push_back(DescRefExpr); + // Add initializers for any closure decl refs. if (BlockDeclRefs.size()) { Expr *Exp; @@ -4297,6 +4422,17 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) { InitExprs.push_back(Exp); } } + if (ImportedBlockDecls.size()) { // generate "1<<25" to indicate we have helper functions. + unsigned IntSize = + static_cast<unsigned>(Context->getTypeSize(Context->IntTy)); + BinaryOperator *Exp = new (Context) BinaryOperator( + new (Context) IntegerLiteral(llvm::APInt(IntSize, 1), + Context->IntTy,SourceLocation()), + new (Context) IntegerLiteral(llvm::APInt(IntSize, 25), + Context->IntTy, SourceLocation()), + BinaryOperator::Shl, Context->IntTy, SourceLocation()); + InitExprs.push_back(Exp); + } NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(), FType, SourceLocation()); NewRep = new (Context) UnaryOperator(NewRep, UnaryOperator::AddrOf, @@ -4486,7 +4622,14 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { // FIXME: What we're doing here is modifying the type-specifier that // precedes the first Decl. In the future the DeclGroup should have // a separate type-specifier that we can rewrite. - RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin()); + // NOTE: We need to avoid rewriting the DeclStmt if it is within + // the context of an ObjCForCollectionStmt. For example: + // NSArray *someArray; + // for (id <FooProtocol> index in someArray) ; + // This is because RewriteObjCForCollectionStmt() does textual rewriting + // and it depends on the original text locations/positions. + if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back())) + RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin()); // Blocks rewrite rules. for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end(); @@ -4552,6 +4695,18 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { return S; } +void RewriteObjC::RewriteRecordBody(RecordDecl *RD) { + for (RecordDecl::field_iterator i = RD->field_begin(), + e = RD->field_end(); i != e; ++i) { + FieldDecl *FD = *i; + if (isTopLevelBlockPointerType(FD->getType())) + RewriteBlockPointerDecl(FD); + if (FD->getType()->isObjCQualifiedIdType() || + FD->getType()->isObjCQualifiedInterfaceType()) + RewriteObjCQualifiedInterfaceTypes(FD); + } +} + /// HandleDeclInMainFile - This is called for each top-level decl defined in the /// main file of the input. void RewriteObjC::HandleDeclInMainFile(Decl *D) { @@ -4618,6 +4773,10 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) { RewriteCastExpr(CE); } } + } else if (VD->getType()->isRecordType()) { + RecordDecl *RD = VD->getType()->getAs<RecordType>()->getDecl(); + if (RD->isDefinition()) + RewriteRecordBody(RD); } if (VD->getInit()) { GlobalVarDecl = VD; @@ -4645,17 +4804,16 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) { RewriteBlockPointerDecl(TD); else if (TD->getUnderlyingType()->isFunctionPointerType()) CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); + else if (TD->getUnderlyingType()->isRecordType()) { + RecordDecl *RD = TD->getUnderlyingType()->getAs<RecordType>()->getDecl(); + if (RD->isDefinition()) + RewriteRecordBody(RD); + } return; } if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) { - if (RD->isDefinition()) { - for (RecordDecl::field_iterator i = RD->field_begin(), - e = RD->field_end(); i != e; ++i) { - FieldDecl *FD = *i; - if (isTopLevelBlockPointerType(FD->getType())) - RewriteBlockPointerDecl(FD); - } - } + if (RD->isDefinition()) + RewriteRecordBody(RD); return; } // Nothing yet. diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 6ab0e16..61f8a70 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -279,13 +279,14 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, assert(!Loc.isInvalid() && "must have a valid source location here"); // If this is a macro ID, first emit information about where this was - // instantiated (recursively) then emit information about where. the token was + // instantiated (recursively) then emit information about where the token was // spelled from. if (!Loc.isFileID()) { SourceLocation OneLevelUp = SM.getImmediateInstantiationRange(Loc).first; // FIXME: Map ranges? EmitCaretDiagnostic(OneLevelUp, Ranges, NumRanges, SM, 0, 0, Columns); + // Map the location. Loc = SM.getImmediateSpellingLoc(Loc); // Map the ranges. @@ -295,15 +296,22 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, if (E.isMacroID()) E = SM.getImmediateSpellingLoc(E); Ranges[i] = SourceRange(S, E); } + + // Get the pretty name, according to #line directives etc. + PresumedLoc PLoc = SM.getPresumedLoc(Loc); + + // If this diagnostic is not in the main file, print out the "included from" + // lines. + if (LastWarningLoc != PLoc.getIncludeLoc()) { + LastWarningLoc = PLoc.getIncludeLoc(); + PrintIncludeStack(LastWarningLoc, SM); + } if (DiagOpts->ShowLocation) { - std::pair<FileID, unsigned> IInfo = SM.getDecomposedInstantiationLoc(Loc); - // Emit the file/line/column that this expansion came from. - OS << SM.getBuffer(IInfo.first)->getBufferIdentifier() << ':' - << SM.getLineNumber(IInfo.first, IInfo.second) << ':'; + OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':'; if (DiagOpts->ShowColumn) - OS << SM.getColumnNumber(IInfo.first, IInfo.second) << ':'; + OS << PLoc.getColumn() << ':'; OS << ' '; } OS << "note: instantiated from:\n"; @@ -489,12 +497,17 @@ static inline char findMatchingPunctuation(char c) { /// /// \returns the index pointing one character past the end of the /// word. -unsigned findEndOfWord(unsigned Start, - const llvm::SmallVectorImpl<char> &Str, - unsigned Length, unsigned Column, - unsigned Columns) { +static unsigned findEndOfWord(unsigned Start, + const llvm::SmallVectorImpl<char> &Str, + unsigned Length, unsigned Column, + unsigned Columns) { + assert(Start < Str.size() && "Invalid start position!"); unsigned End = Start + 1; + // If we are already at the end of the string, take that as the word. + if (End == Str.size()) + return End; + // Determine if the start of the string is actually opening // punctuation, e.g., a quote or parentheses. char EndPunct = findMatchingPunctuation(Str[Start]); @@ -645,11 +658,17 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, if (DiagOpts->ShowLocation) { if (DiagOpts->ShowColors) OS.changeColor(savedColor, true); - OS << PLoc.getFilename() << ':' << LineNo << ':'; - if (DiagOpts->ShowColumn) - if (unsigned ColNo = PLoc.getColumn()) - OS << ColNo << ':'; - + + // Emit a Visual Studio compatible line number syntax. + if (LangOpts && LangOpts->Microsoft) { + OS << PLoc.getFilename() << '(' << LineNo << ')'; + OS << " : "; + } else { + OS << PLoc.getFilename() << ':' << LineNo << ':'; + if (DiagOpts->ShowColumn) + if (unsigned ColNo = PLoc.getColumn()) + OS << ColNo << ':'; + } if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) { FileID CaretFileID = SM.getFileID(SM.getInstantiationLoc(Info.getLocation())); diff --git a/lib/Headers/limits.h b/lib/Headers/limits.h index e4909ab..2627533 100644 --- a/lib/Headers/limits.h +++ b/lib/Headers/limits.h @@ -49,7 +49,6 @@ #undef LONG_MAX #undef ULONG_MAX -#undef MB_LEN_MAX #undef CHAR_BIT #undef CHAR_MIN #undef CHAR_MAX diff --git a/lib/Headers/tmmintrin.h b/lib/Headers/tmmintrin.h index 374a27e..7adb776 100644 --- a/lib/Headers/tmmintrin.h +++ b/lib/Headers/tmmintrin.h @@ -67,7 +67,7 @@ _mm_abs_epi32(__m128i a) } #define _mm_alignr_epi8(a, b, n) (__builtin_ia32_palignr128((a), (b), (n))) -#define _mm_alignr_pi8(a, b, n) (__builtin_ia32_palignr((a), (b), (n))) +#define _mm_alignr_pi8(a, b, n) (__builtin_ia32_palignr((a), (b), (n*8))) static inline __m128i __attribute__((__always_inline__, __nodebug__)) _mm_hadd_epi16(__m128i a, __m128i b) diff --git a/lib/Index/ASTVisitor.h b/lib/Index/ASTVisitor.h index 0ae78fb..943c720 100644 --- a/lib/Index/ASTVisitor.h +++ b/lib/Index/ASTVisitor.h @@ -52,8 +52,8 @@ public: void VisitDeclaratorDecl(DeclaratorDecl *D) { BaseDeclVisitor::VisitDeclaratorDecl(D); - if (DeclaratorInfo *DInfo = D->getDeclaratorInfo()) - Visit(DInfo->getTypeLoc()); + if (TypeSourceInfo *TInfo = D->getTypeSourceInfo()) + Visit(TInfo->getTypeLoc()); } void VisitFunctionDecl(FunctionDecl *D) { @@ -104,7 +104,7 @@ public: } void VisitBlockExpr(BlockExpr *Node) { - Visit(Node->getBlockDecl()); + // The BlockDecl is also visited by 'VisitDeclContext()'. No need to visit it twice. } void VisitStmt(Stmt *Node) { diff --git a/lib/Index/CMakeLists.txt b/lib/Index/CMakeLists.txt index 5f81817..4d67035 100644 --- a/lib/Index/CMakeLists.txt +++ b/lib/Index/CMakeLists.txt @@ -3,6 +3,7 @@ set(LLVM_NO_RTTI 1) add_clang_library(clangIndex ASTLocation.cpp Analyzer.cpp + CallGraph.cpp DeclReferenceMap.cpp Entity.cpp GlobalSelector.cpp diff --git a/lib/Analysis/CallGraph.cpp b/lib/Index/CallGraph.cpp index c1040f0..6403319 100644 --- a/lib/Analysis/CallGraph.cpp +++ b/lib/Index/CallGraph.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/CallGraph.h" +#include "clang/Index/CallGraph.h" #include "clang/AST/ASTContext.h" #include "clang/AST/StmtVisitor.h" diff --git a/lib/Index/ResolveLocation.cpp b/lib/Index/ResolveLocation.cpp index c7379f7..81a5de4 100644 --- a/lib/Index/ResolveLocation.cpp +++ b/lib/Index/ResolveLocation.cpp @@ -30,7 +30,7 @@ protected: ASTContext &Ctx; SourceLocation Loc; - ASTLocation ResolveInDeclarator(Decl *D, Stmt *Stm, DeclaratorInfo *DInfo); + ASTLocation ResolveInDeclarator(Decl *D, Stmt *Stm, TypeSourceInfo *TInfo); enum RangePos { BeforeLoc, @@ -39,13 +39,13 @@ protected: }; RangePos CheckRange(SourceRange Range); - RangePos CheckRange(DeclaratorInfo *DInfo); + RangePos CheckRange(TypeSourceInfo *TInfo); RangePos CheckRange(Decl *D) { if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) - if (ContainsLocation(DD->getDeclaratorInfo())) + if (ContainsLocation(DD->getTypeSourceInfo())) return ContainsLoc; if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) - if (ContainsLocation(TD->getTypeDeclaratorInfo())) + if (ContainsLocation(TD->getTypeSourceInfo())) return ContainsLoc; return CheckRange(D->getSourceRange()); @@ -142,9 +142,9 @@ StmtLocResolver::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { "Should visit only after verifying that loc is in range"); if (Node->isArgumentType()) { - DeclaratorInfo *DInfo = Node->getArgumentTypeInfo(); - if (ContainsLocation(DInfo)) - return ResolveInDeclarator(Parent, Node, DInfo); + TypeSourceInfo *TInfo = Node->getArgumentTypeInfo(); + if (ContainsLocation(TInfo)) + return ResolveInDeclarator(Parent, Node, TInfo); } else { Expr *SubNode = Node->getArgumentExpr(); if (ContainsLocation(SubNode)) @@ -245,8 +245,8 @@ ASTLocation DeclLocResolver::VisitFunctionDecl(FunctionDecl *D) { assert(ContainsLocation(D) && "Should visit only after verifying that loc is in range"); - if (ContainsLocation(D->getDeclaratorInfo())) - return ResolveInDeclarator(D, 0, D->getDeclaratorInfo()); + if (ContainsLocation(D->getTypeSourceInfo())) + return ResolveInDeclarator(D, 0, D->getTypeSourceInfo()); // First, search through the parameters of the function. for (FunctionDecl::param_iterator @@ -296,8 +296,8 @@ ASTLocation DeclLocResolver::VisitFunctionDecl(FunctionDecl *D) { ASTLocation DeclLocResolver::VisitDeclaratorDecl(DeclaratorDecl *D) { assert(ContainsLocation(D) && "Should visit only after verifying that loc is in range"); - if (ContainsLocation(D->getDeclaratorInfo())) - return ResolveInDeclarator(D, /*Stmt=*/0, D->getDeclaratorInfo()); + if (ContainsLocation(D->getTypeSourceInfo())) + return ResolveInDeclarator(D, /*Stmt=*/0, D->getTypeSourceInfo()); return ASTLocation(D); } @@ -306,8 +306,8 @@ ASTLocation DeclLocResolver::VisitTypedefDecl(TypedefDecl *D) { assert(ContainsLocation(D) && "Should visit only after verifying that loc is in range"); - if (ContainsLocation(D->getTypeDeclaratorInfo())) - return ResolveInDeclarator(D, /*Stmt=*/0, D->getTypeDeclaratorInfo()); + if (ContainsLocation(D->getTypeSourceInfo())) + return ResolveInDeclarator(D, /*Stmt=*/0, D->getTypeSourceInfo()); return ASTLocation(D); } @@ -321,8 +321,8 @@ ASTLocation DeclLocResolver::VisitVarDecl(VarDecl *D) { if (Init && ContainsLocation(Init)) return StmtLocResolver(Ctx, Loc, D).Visit(Init); - if (ContainsLocation(D->getDeclaratorInfo())) - return ResolveInDeclarator(D, 0, D->getDeclaratorInfo()); + if (ContainsLocation(D->getTypeSourceInfo())) + return ResolveInDeclarator(D, 0, D->getTypeSourceInfo()); return ASTLocation(D); } @@ -491,12 +491,12 @@ ASTLocation TypeLocResolver::VisitTypeLoc(TypeLoc TL) { } ASTLocation LocResolverBase::ResolveInDeclarator(Decl *D, Stmt *Stm, - DeclaratorInfo *DInfo) { - assert(ContainsLocation(DInfo) && + TypeSourceInfo *TInfo) { + assert(ContainsLocation(TInfo) && "Should visit only after verifying that loc is in range"); (void)TypeLocResolver(Ctx, Loc, D); - for (TypeLoc TL = DInfo->getTypeLoc(); TL; TL = TL.getNextTypeLoc()) + for (TypeLoc TL = TInfo->getTypeLoc(); TL; TL = TL.getNextTypeLoc()) if (ContainsLocation(TL)) return TypeLocResolver(Ctx, Loc, D).Visit(TL); @@ -504,11 +504,11 @@ ASTLocation LocResolverBase::ResolveInDeclarator(Decl *D, Stmt *Stm, return ASTLocation(D, Stm); } -LocResolverBase::RangePos LocResolverBase::CheckRange(DeclaratorInfo *DInfo) { - if (!DInfo) +LocResolverBase::RangePos LocResolverBase::CheckRange(TypeSourceInfo *TInfo) { + if (!TInfo) return BeforeLoc; // Keep looking. - for (TypeLoc TL = DInfo->getTypeLoc(); TL; TL = TL.getNextTypeLoc()) + for (TypeLoc TL = TInfo->getTypeLoc(); TL; TL = TL.getNextTypeLoc()) if (ContainsLocation(TL)) return ContainsLoc; diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 52a7a04..a91e404 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -33,7 +33,7 @@ #include <cctype> using namespace clang; -static void InitCharacterInfo(); +static void InitCharacterInfo(LangOptions); //===----------------------------------------------------------------------===// // Token Class Implementation @@ -59,7 +59,7 @@ tok::ObjCKeywordKind Token::getObjCKeywordID() const { void Lexer::InitLexer(const char *BufStart, const char *BufPtr, const char *BufEnd) { - InitCharacterInfo(); + InitCharacterInfo(Features); BufferStart = BufStart; BufferPtr = BufPtr; @@ -70,7 +70,7 @@ void Lexer::InitLexer(const char *BufStart, const char *BufPtr, " to simplify lexing!"); Is_PragmaLexer = false; - IsEofCodeCompletion = false; + IsInConflictMarker = false; // Start of the file is a start of line. IsAtStartOfLine = true; @@ -105,10 +105,6 @@ Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *InputFile, Preprocessor &PP) // Default to keeping comments if the preprocessor wants them. SetCommentRetentionState(PP.getCommentRetentionState()); - - // If the input file is truncated, the EOF is a code-completion token. - if (PP.getSourceManager().isTruncatedFile(FID)) - IsEofCodeCompletion = true; } /// Lexer constructor - Create a new raw lexer object. This object is only @@ -258,7 +254,7 @@ enum { // Statically initialize CharInfo table based on ASCII character set // Reference: FreeBSD 7.2 /usr/share/misc/ascii -static const unsigned char CharInfo[256] = +static unsigned char CharInfo[256] = { // 0 NUL 1 SOH 2 STX 3 ETX // 4 EOT 5 ENQ 6 ACK 7 BEL @@ -326,7 +322,7 @@ static const unsigned char CharInfo[256] = 0 , 0 , 0 , 0 }; -static void InitCharacterInfo() { +static void InitCharacterInfo(LangOptions Features) { static bool isInited = false; if (isInited) return; // check the statically-initialized CharInfo table @@ -344,6 +340,11 @@ static void InitCharacterInfo() { } for (unsigned i = '0'; i <= '9'; ++i) assert(CHAR_NUMBER == CharInfo[i]); + + if (Features.Microsoft) + // Hack to treat DOS & CP/M EOF (^Z) as horizontal whitespace. + CharInfo[26/*sub*/] = CHAR_HORZ_WS; + isInited = true; } @@ -1326,24 +1327,16 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { // Otherwise, check if we are code-completing, then issue diagnostics for // unterminated #if and missing newline. - if (IsEofCodeCompletion) { - bool isIntendedFile = true; - if (PP && FileLoc.isFileID()) { - SourceManager &SM = PP->getSourceManager(); - isIntendedFile = SM.isTruncatedFile(SM.getFileID(FileLoc)); - } + if (PP && PP->isCodeCompletionFile(FileLoc)) { + // We're at the end of the file, but we've been asked to consider the + // end of the file to be a code-completion token. Return the + // code-completion token. + Result.startToken(); + FormTokenWithChars(Result, CurPtr, tok::code_completion); - if (isIntendedFile) { - // We're at the end of the file, but we've been asked to consider the - // end of the file to be a code-completion token. Return the - // code-completion token. - Result.startToken(); - FormTokenWithChars(Result, CurPtr, tok::code_completion); - - // Only do the eof -> code_completion translation once. - IsEofCodeCompletion = false; - return true; - } + // Only do the eof -> code_completion translation once. + PP->SetCodeCompletionPoint(0, 0, 0); + return true; } // If we are in a #if directive, emit an error. @@ -1398,6 +1391,105 @@ unsigned Lexer::isNextPPTokenLParen() { return Tok.is(tok::l_paren); } +/// FindConflictEnd - Find the end of a version control conflict marker. +static const char *FindConflictEnd(const char *CurPtr, const char *BufferEnd) { + llvm::StringRef RestOfBuffer(CurPtr+7, BufferEnd-CurPtr-7); + size_t Pos = RestOfBuffer.find(">>>>>>>"); + while (Pos != llvm::StringRef::npos) { + // Must occur at start of line. + if (RestOfBuffer[Pos-1] != '\r' && + RestOfBuffer[Pos-1] != '\n') { + RestOfBuffer = RestOfBuffer.substr(Pos+7); + continue; + } + return RestOfBuffer.data()+Pos; + } + return 0; +} + +/// IsStartOfConflictMarker - If the specified pointer is the start of a version +/// control conflict marker like '<<<<<<<', recognize it as such, emit an error +/// and recover nicely. This returns true if it is a conflict marker and false +/// if not. +bool Lexer::IsStartOfConflictMarker(const char *CurPtr) { + // Only a conflict marker if it starts at the beginning of a line. + if (CurPtr != BufferStart && + CurPtr[-1] != '\n' && CurPtr[-1] != '\r') + return false; + + // Check to see if we have <<<<<<<. + if (BufferEnd-CurPtr < 8 || + llvm::StringRef(CurPtr, 7) != "<<<<<<<") + return false; + + // If we have a situation where we don't care about conflict markers, ignore + // it. + if (IsInConflictMarker || isLexingRawMode()) + return false; + + // Check to see if there is a >>>>>>> somewhere in the buffer at the start of + // a line to terminate this conflict marker. + if (FindConflictEnd(CurPtr+7, BufferEnd)) { + // We found a match. We are really in a conflict marker. + // Diagnose this, and ignore to the end of line. + Diag(CurPtr, diag::err_conflict_marker); + IsInConflictMarker = true; + + // Skip ahead to the end of line. We know this exists because the + // end-of-conflict marker starts with \r or \n. + while (*CurPtr != '\r' && *CurPtr != '\n') { + assert(CurPtr != BufferEnd && "Didn't find end of line"); + ++CurPtr; + } + BufferPtr = CurPtr; + return true; + } + + // No end of conflict marker found. + return false; +} + + +/// HandleEndOfConflictMarker - If this is a '=======' or '|||||||' or '>>>>>>>' +/// marker, then it is the end of a conflict marker. Handle it by ignoring up +/// until the end of the line. This returns true if it is a conflict marker and +/// false if not. +bool Lexer::HandleEndOfConflictMarker(const char *CurPtr) { + // Only a conflict marker if it starts at the beginning of a line. + if (CurPtr != BufferStart && + CurPtr[-1] != '\n' && CurPtr[-1] != '\r') + return false; + + // If we have a situation where we don't care about conflict markers, ignore + // it. + if (!IsInConflictMarker || isLexingRawMode()) + return false; + + // Check to see if we have the marker (7 characters in a row). + for (unsigned i = 1; i != 7; ++i) + if (CurPtr[i] != CurPtr[0]) + return false; + + // If we do have it, search for the end of the conflict marker. This could + // fail if it got skipped with a '#if 0' or something. Note that CurPtr might + // be the end of conflict marker. + if (const char *End = FindConflictEnd(CurPtr, BufferEnd)) { + CurPtr = End; + + // Skip ahead to the end of line. + while (CurPtr != BufferEnd && *CurPtr != '\r' && *CurPtr != '\n') + ++CurPtr; + + BufferPtr = CurPtr; + + // No longer in the conflict marker. + IsInConflictMarker = false; + return true; + } + + return false; +} + /// LexTokenInternal - This implements a simple C family lexer. It is an /// extremely performance critical piece of code. This assumes that the buffer @@ -1764,14 +1856,20 @@ LexNextToken: Char = getCharAndSize(CurPtr, SizeTmp); if (ParsingFilename) { return LexAngledStringLiteral(Result, CurPtr); - } else if (Char == '<' && - getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '=') { - Kind = tok::lesslessequal; - CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), - SizeTmp2, Result); } else if (Char == '<') { - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - Kind = tok::lessless; + char After = getCharAndSize(CurPtr+SizeTmp, SizeTmp2); + if (After == '=') { + Kind = tok::lesslessequal; + CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), + SizeTmp2, Result); + } else if (After == '<' && IsStartOfConflictMarker(CurPtr-1)) { + // If this is actually a '<<<<<<<' version control conflict marker, + // recognize it as such and recover nicely. + goto LexNextToken; + } else { + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + Kind = tok::lessless; + } } else if (Char == '=') { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::lessequal; @@ -1790,14 +1888,20 @@ LexNextToken: if (Char == '=') { CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::greaterequal; - } else if (Char == '>' && - getCharAndSize(CurPtr+SizeTmp, SizeTmp2) == '=') { - CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), - SizeTmp2, Result); - Kind = tok::greatergreaterequal; } else if (Char == '>') { - CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); - Kind = tok::greatergreater; + char After = getCharAndSize(CurPtr+SizeTmp, SizeTmp2); + if (After == '=') { + CurPtr = ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result), + SizeTmp2, Result); + Kind = tok::greatergreaterequal; + } else if (After == '>' && HandleEndOfConflictMarker(CurPtr-1)) { + // If this is '>>>>>>>' and we're in a conflict marker, ignore it. + goto LexNextToken; + } else { + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); + Kind = tok::greatergreater; + } + } else { Kind = tok::greater; } @@ -1817,6 +1921,9 @@ LexNextToken: Kind = tok::pipeequal; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); } else if (Char == '|') { + // If this is '|||||||' and we're in a conflict marker, ignore it. + if (CurPtr[1] == '|' && HandleEndOfConflictMarker(CurPtr-1)) + goto LexNextToken; Kind = tok::pipepipe; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); } else { @@ -1841,6 +1948,10 @@ LexNextToken: case '=': Char = getCharAndSize(CurPtr, SizeTmp); if (Char == '=') { + // If this is '=======' and we're in a conflict marker, ignore it. + if (CurPtr[1] == '=' && HandleEndOfConflictMarker(CurPtr-1)) + goto LexNextToken; + Kind = tok::equalequal; CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); } else { diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp index c14d7c4..376cce8 100644 --- a/lib/Lex/MacroArgs.cpp +++ b/lib/Lex/MacroArgs.cpp @@ -20,7 +20,8 @@ using namespace clang; /// MacroArgs ctor function - This destroys the vector passed in. MacroArgs *MacroArgs::create(const MacroInfo *MI, const Token *UnexpArgTokens, - unsigned NumToks, bool VarargsElided) { + unsigned NumToks, bool VarargsElided, + Preprocessor &PP) { assert(MI->isFunctionLike() && "Can't have args for an object-like macro!"); @@ -40,13 +41,26 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI, /// destroy - Destroy and deallocate the memory for this object. /// -void MacroArgs::destroy() { +void MacroArgs::destroy(Preprocessor &PP) { // Run the dtor to deallocate the vectors. this->~MacroArgs(); // Release the memory for the object. free(this); } +/// deallocate - This should only be called by the Preprocessor when managing +/// its freelist. +MacroArgs *MacroArgs::deallocate() { + MacroArgs *Next = ArgCache; + + // Run the dtor to deallocate the vectors. + this->~MacroArgs(); + // Release the memory for the object. + free(this); + + return Next; +} + /// getArgLength - Given a pointer to an expanded or unexpanded argument, /// return the number of tokens, not counting the EOF, that make up the diff --git a/lib/Lex/MacroArgs.h b/lib/Lex/MacroArgs.h index 8dee5b3..fa040c7 100644 --- a/lib/Lex/MacroArgs.h +++ b/lib/Lex/MacroArgs.h @@ -30,6 +30,13 @@ class MacroArgs { /// concatenated together, with 'EOF' markers at the end of each argument. unsigned NumUnexpArgTokens; + /// VarargsElided - True if this is a C99 style varargs macro invocation and + /// there was no argument specified for the "..." argument. If the argument + /// was specified (even empty) or this isn't a C99 style varargs function, or + /// if in strict mode and the C99 varargs macro had only a ... argument, this + /// is false. + bool VarargsElided; + /// PreExpArgTokens - Pre-expanded tokens for arguments that need them. Empty /// if not yet computed. This includes the EOF marker at the end of the /// stream. @@ -39,26 +46,24 @@ class MacroArgs { /// stringified form of an argument has not yet been computed, this is empty. std::vector<Token> StringifiedArgs; - /// VarargsElided - True if this is a C99 style varargs macro invocation and - /// there was no argument specified for the "..." argument. If the argument - /// was specified (even empty) or this isn't a C99 style varargs function, or - /// if in strict mode and the C99 varargs macro had only a ... argument, this - /// is false. - bool VarargsElided; - + /// ArgCache - This is a linked list of MacroArgs objects that the + /// Preprocessor owns which we use to avoid thrashing malloc/free. + MacroArgs *ArgCache; + MacroArgs(unsigned NumToks, bool varargsElided) - : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided) {} + : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided), ArgCache(0) {} ~MacroArgs() {} public: /// MacroArgs ctor function - Create a new MacroArgs object with the specified /// macro and argument info. static MacroArgs *create(const MacroInfo *MI, const Token *UnexpArgTokens, - unsigned NumArgTokens, bool VarargsElided); + unsigned NumArgTokens, bool VarargsElided, + Preprocessor &PP); /// destroy - Destroy and deallocate the memory for this object. /// - void destroy(); + void destroy(Preprocessor &PP); /// ArgNeedsPreexpansion - If we can prove that the argument won't be affected /// by pre-expansion, return false. Otherwise, conservatively return true. @@ -102,6 +107,11 @@ public: /// static Token StringifyArgument(const Token *ArgToks, Preprocessor &PP, bool Charify = false); + + + /// deallocate - This should only be called by the Preprocessor when managing + /// its freelist. + MacroArgs *deallocate(); }; } // end namespace clang diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 9caca33..f5c60eb 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -481,11 +481,11 @@ void Preprocessor::HandleDirective(Token &Result) { CurPPLexer->ParsingPreprocessorDirective = true; ++NumDirectives; - + // We are about to read a token. For the multiple-include optimization FA to // work, we have to remember if we had read any tokens *before* this // pp-directive. - bool ReadAnyTokensBeforeDirective = CurPPLexer->MIOpt.getHasReadAnyTokensVal(); + bool ReadAnyTokensBeforeDirective =CurPPLexer->MIOpt.getHasReadAnyTokensVal(); // Save the '#' token in case we need to return it later. Token SavedHash = Result; @@ -1112,9 +1112,10 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok, } // Finally, if all is good, enter the new file! - if (EnterSourceFile(FID, CurDir)) + std::string ErrorStr; + if (EnterSourceFile(FID, CurDir, ErrorStr)) Diag(FilenameTok, diag::err_pp_error_opening_file) - << std::string(SourceMgr.getFileEntryForID(FID)->getName()); + << std::string(SourceMgr.getFileEntryForID(FID)->getName()) << ErrorStr; } /// HandleIncludeNextDirective - Implements #include_next. @@ -1548,8 +1549,9 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef, // Should we include the stuff contained by this directive? if (!MI == isIfndef) { // Yes, remember that we are inside a conditional, then lex the next token. - CurPPLexer->pushConditionalLevel(DirectiveTok.getLocation(), /*wasskip*/false, - /*foundnonskip*/true, /*foundelse*/false); + CurPPLexer->pushConditionalLevel(DirectiveTok.getLocation(), + /*wasskip*/false, /*foundnonskip*/true, + /*foundelse*/false); } else { // No, skip the contents of this block and return the first token after it. SkipExcludedConditionalBlock(DirectiveTok.getLocation(), diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp index b54dfe0..2a6b2a7 100644 --- a/lib/Lex/PPExpressions.cpp +++ b/lib/Lex/PPExpressions.cpp @@ -72,8 +72,8 @@ struct DefinedTracker { }; /// EvaluateDefined - Process a 'defined(sym)' expression. -static bool EvaluateDefined(PPValue &Result, Token &PeekTok, - DefinedTracker &DT, bool ValueLive, Preprocessor &PP) { +static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT, + bool ValueLive, Preprocessor &PP) { IdentifierInfo *II; Result.setBegin(PeekTok.getLocation()); @@ -142,22 +142,21 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, // 'defined' or if it is a macro. Note that we check here because many // keywords are pp-identifiers, so we can't check the kind. if (IdentifierInfo *II = PeekTok.getIdentifierInfo()) { - if (II->isStr("defined")) { - // Handle "defined X" and "defined(X)". + // Handle "defined X" and "defined(X)". + if (II->isStr("defined")) return(EvaluateDefined(Result, PeekTok, DT, ValueLive, PP)); - } else { - // If this identifier isn't 'defined' or one of the special - // preprocessor keywords and it wasn't macro expanded, it turns - // into a simple 0, unless it is the C++ keyword "true", in which case it - // turns into "1". - if (ValueLive) - PP.Diag(PeekTok, diag::warn_pp_undef_identifier) << II; - Result.Val = II->getTokenID() == tok::kw_true; - Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0. - Result.setRange(PeekTok.getLocation()); - PP.LexNonComment(PeekTok); - return false; - } + + // If this identifier isn't 'defined' or one of the special + // preprocessor keywords and it wasn't macro expanded, it turns + // into a simple 0, unless it is the C++ keyword "true", in which case it + // turns into "1". + if (ValueLive) + PP.Diag(PeekTok, diag::warn_pp_undef_identifier) << II; + Result.Val = II->getTokenID() == tok::kw_true; + Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0. + Result.setRange(PeekTok.getLocation()); + PP.LexNonComment(PeekTok); + return false; } switch (PeekTok.getKind()) { @@ -677,6 +676,15 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec, /// to "!defined(X)" return X in IfNDefMacro. bool Preprocessor:: EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { + // Save the current state of 'DisableMacroExpansion' and reset it to false. If + // 'DisableMacroExpansion' is true, then we must be in a macro argument list + // in which case a directive is undefined behavior. We want macros to be able + // to recursively expand in order to get more gcc-list behavior, so we force + // DisableMacroExpansion to false and restore it when we're done parsing the + // expression. + bool DisableMacroExpansionAtStartOfDirective = DisableMacroExpansion; + DisableMacroExpansion = false; + // Peek ahead one token. Token Tok; Lex(Tok); @@ -690,6 +698,9 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { // Parse error, skip the rest of the macro line. if (Tok.isNot(tok::eom)) DiscardUntilEndOfDirective(); + + // Restore 'DisableMacroExpansion'. + DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective; return false; } @@ -702,6 +713,8 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { if (DT.State == DefinedTracker::NotDefinedMacro) IfNDefMacro = DT.TheMacro; + // Restore 'DisableMacroExpansion'. + DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective; return ResVal.Val != 0; } @@ -712,6 +725,9 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { // Parse error, skip the rest of the macro line. if (Tok.isNot(tok::eom)) DiscardUntilEndOfDirective(); + + // Restore 'DisableMacroExpansion'. + DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective; return false; } @@ -722,6 +738,8 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { DiscardUntilEndOfDirective(); } + // Restore 'DisableMacroExpansion'. + DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective; return ResVal.Val != 0; } diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp index 8a61d7b..ce1b19c 100644 --- a/lib/Lex/PPLexerChange.cpp +++ b/lib/Lex/PPLexerChange.cpp @@ -64,7 +64,8 @@ PreprocessorLexer *Preprocessor::getCurrentFileLexer() const { /// EnterSourceFile - Add a source file to the top of the include stack and /// start lexing tokens from it instead of the current buffer. -bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir) { +bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir, + std::string &ErrorStr) { assert(CurTokenLexer == 0 && "Cannot #include a file inside a macro!"); ++NumEnteredSourceFiles; @@ -79,8 +80,9 @@ bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir) { } // Get the MemoryBuffer for this FID, if it fails, we fail. - const llvm::MemoryBuffer *InputFile = getSourceManager().getBuffer(FID); - if (InputFile == 0) + const llvm::MemoryBuffer *InputFile = + getSourceManager().getBuffer(FID, &ErrorStr); + if (!ErrorStr.empty()) return true; EnterSourceFileWithLexer(new Lexer(FID, InputFile, *this), CurDir); diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 699b701..dfb14ff 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -204,7 +204,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, // expansion stack, only to take it right back off. if (MI->getNumTokens() == 0) { // No need for arg info. - if (Args) Args->destroy(); + if (Args) Args->destroy(*this); // Ignore this macro use, just return the next token in the current // buffer. @@ -232,7 +232,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, // "#define VAL 42". // No need for arg info. - if (Args) Args->destroy(); + if (Args) Args->destroy(*this); // Propagate the isAtStartOfLine/hasLeadingSpace markers of the macro // identifier to the expanded token. @@ -446,7 +446,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName, } return MacroArgs::create(MI, ArgTokens.data(), ArgTokens.size(), - isVarargsElided); + isVarargsElided, *this); } /// ComputeDATE_TIME - Compute the current time, enter it into the specified @@ -486,6 +486,12 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { case 6: if (II->isStr("blocks")) return LangOpts.Blocks; return false; + case 8: + if (II->isStr("cxx_rtti")) return LangOpts.RTTI; + return false; + case 14: + if (II->isStr("cxx_exceptions")) return LangOpts.Exceptions; + return false; case 19: if (II->isStr("objc_nonfragile_abi")) return LangOpts.ObjCNonFragileABI; return false; @@ -667,7 +673,6 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { // __BASE_FILE__ is a GNU extension that returns the top of the presumed // #include stack instead of the current file. if (II == Ident__BASE_FILE__) { - Diag(Tok, diag::ext_pp_base_file); SourceLocation NextLoc = PLoc.getIncludeLoc(); while (NextLoc.isValid()) { PLoc = SourceMgr.getPresumedLoc(NextLoc); @@ -697,8 +702,6 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { Tok.getLocation(), Tok.getLength())); } else if (II == Ident__INCLUDE_LEVEL__) { - Diag(Tok, diag::ext_pp_include_level); - // Compute the presumed include depth of this token. This can be affected // by GNU line markers. unsigned Depth = 0; @@ -715,7 +718,6 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { } else if (II == Ident__TIMESTAMP__) { // MSVC, ICC, GCC, VisualAge C++ extension. The generated string should be // of the form "Ddd Mmm dd hh::mm::ss yyyy", which is returned by asctime. - Diag(Tok, diag::ext_pp_timestamp); // Get the file that we are lexing out of. If we're currently lexing from // a macro, dig into the include stack. @@ -725,7 +727,6 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { if (TheLexer) CurFile = SourceMgr.getFileEntryForID(TheLexer->getFileID()); - // If this file is older than the file it depends on, emit a diagnostic. const char *Result; if (CurFile) { time_t TT = CurFile->getModificationTime(); @@ -741,8 +742,6 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { Tok.setKind(tok::string_literal); CreateString(TmpBuffer, Len+1, Tok, Tok.getLocation()); } else if (II == Ident__COUNTER__) { - Diag(Tok, diag::ext_pp_counter); - // __COUNTER__ expands to a simple numeric value. sprintf(TmpBuffer, "%u", CounterValue++); Tok.setKind(tok::numeric_constant); diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index 0669094..d4e441b 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -26,6 +26,7 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/Preprocessor.h" +#include "MacroArgs.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Pragma.h" @@ -50,7 +51,8 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, 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) { + BuiltinInfo(Target), CodeCompletionFile(0), CurPPLexer(0), CurDirLookup(0), + Callbacks(0), MacroArgCache(0) { ScratchBuf = new ScratchBuffer(SourceMgr); CounterValue = 0; // __COUNTER__ starts at 0. OwnsHeaderSearch = OwnsHeaders; @@ -101,7 +103,7 @@ Preprocessor::~Preprocessor() { Macros.begin(), E = Macros.end(); I != E; ++I) { // We don't need to free the MacroInfo objects directly. These // will be released when the BumpPtrAllocator 'BP' object gets - // destroyed. We still need to run the dstor, however, to free + // destroyed. We still need to run the dtor, however, to free // memory alocated by MacroInfo. I->second->Destroy(BP); I->first->setHasMacroDefinition(false); @@ -110,6 +112,10 @@ Preprocessor::~Preprocessor() { // Free any cached macro expanders. for (unsigned i = 0, e = NumCachedTokenLexers; i != e; ++i) delete TokenLexerCache[i]; + + // Free any cached MacroArgs. + for (MacroArgs *ArgList = MacroArgCache; ArgList; ) + ArgList = ArgList->deallocate(); // Release pragma information. delete PragmaHandlers; @@ -188,6 +194,57 @@ void Preprocessor::PrintStats() { << NumFastTokenPaste << " on the fast path.\n"; } +bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File, + unsigned TruncateAtLine, + unsigned TruncateAtColumn) { + using llvm::MemoryBuffer; + + CodeCompletionFile = File; + + // Okay to clear out the code-completion point by passing NULL. + if (!CodeCompletionFile) + return false; + + // Load the actual file's contents. + const MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File); + if (!Buffer) + return true; + + // Find the byte position of the truncation point. + const char *Position = Buffer->getBufferStart(); + for (unsigned Line = 1; Line < TruncateAtLine; ++Line) { + for (; *Position; ++Position) { + if (*Position != '\r' && *Position != '\n') + continue; + + // Eat \r\n or \n\r as a single line. + if ((Position[1] == '\r' || Position[1] == '\n') && + Position[0] != Position[1]) + ++Position; + ++Position; + break; + } + } + + Position += TruncateAtColumn - 1; + + // Truncate the buffer. + if (Position < Buffer->getBufferEnd()) { + MemoryBuffer *TruncatedBuffer + = MemoryBuffer::getMemBufferCopy(Buffer->getBufferStart(), Position, + Buffer->getBufferIdentifier()); + SourceMgr.overrideFileContents(File, TruncatedBuffer); + } + + return false; +} + +bool Preprocessor::isCodeCompletionFile(SourceLocation FileLoc) const { + return CodeCompletionFile && FileLoc.isFileID() && + SourceMgr.getFileEntryForID(SourceMgr.getFileID(FileLoc)) + == CodeCompletionFile; +} + //===----------------------------------------------------------------------===// // Token Spelling //===----------------------------------------------------------------------===// @@ -380,7 +437,9 @@ void Preprocessor::EnterMainSourceFile() { FileID MainFileID = SourceMgr.getMainFileID(); // Enter the main file source buffer. - EnterSourceFile(MainFileID, 0); + std::string ErrorStr; + bool Res = EnterSourceFile(MainFileID, 0, ErrorStr); + assert(!Res && "Entering main file should not fail!"); // Tell the header info that the main file was entered. If the file is later // #imported, it won't be re-entered. @@ -406,7 +465,8 @@ void Preprocessor::EnterMainSourceFile() { assert(!FID.isInvalid() && "Could not create FileID for predefines?"); // Start parsing the predefines. - EnterSourceFile(FID, 0); + Res = EnterSourceFile(FID, 0, ErrorStr); + assert(!Res && "Entering predefines should not fail!"); } diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp index f006f5a..a40bb62 100644 --- a/lib/Lex/TokenLexer.cpp +++ b/lib/Lex/TokenLexer.cpp @@ -92,7 +92,7 @@ void TokenLexer::destroy() { } // TokenLexer owns its formal arguments. - if (ActualArgs) ActualArgs->destroy(); + if (ActualArgs) ActualArgs->destroy(PP); } /// Expand the arguments of a function-like macro so that we can quickly @@ -321,13 +321,12 @@ void TokenLexer::Lex(Token &Tok) { // If this token is followed by a token paste (##) operator, paste the tokens! if (!isAtEnd() && Tokens[CurToken].is(tok::hashhash)) { - if (PasteTokens(Tok)) { - // When handling the microsoft /##/ extension, the final token is - // returned by PasteTokens, not the pasted token. + // When handling the microsoft /##/ extension, the final token is + // returned by PasteTokens, not the pasted token. + if (PasteTokens(Tok)) return; - } else { - TokenIsFromPaste = true; - } + + TokenIsFromPaste = true; } // The token's current location indicate where the token was lexed from. We diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index f00f33f..4cd8fe8 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -137,7 +137,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::SCS S) { case DeclSpec::SCS_private_extern: return "__private_extern__"; case DeclSpec::SCS_mutable: return "mutable"; } - llvm::llvm_unreachable("Unknown typespec!"); + llvm_unreachable("Unknown typespec!"); } const char *DeclSpec::getSpecifierName(TSW W) { @@ -147,7 +147,7 @@ const char *DeclSpec::getSpecifierName(TSW W) { case TSW_long: return "long"; case TSW_longlong: return "long long"; } - llvm::llvm_unreachable("Unknown typespec!"); + llvm_unreachable("Unknown typespec!"); } const char *DeclSpec::getSpecifierName(TSC C) { @@ -156,7 +156,7 @@ const char *DeclSpec::getSpecifierName(TSC C) { case TSC_imaginary: return "imaginary"; case TSC_complex: return "complex"; } - llvm::llvm_unreachable("Unknown typespec!"); + llvm_unreachable("Unknown typespec!"); } @@ -166,7 +166,7 @@ const char *DeclSpec::getSpecifierName(TSS S) { case TSS_signed: return "signed"; case TSS_unsigned: return "unsigned"; } - llvm::llvm_unreachable("Unknown typespec!"); + llvm_unreachable("Unknown typespec!"); } const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { @@ -195,7 +195,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { case DeclSpec::TST_decltype: return "(decltype)"; case DeclSpec::TST_error: return "(error)"; } - llvm::llvm_unreachable("Unknown typespec!"); + llvm_unreachable("Unknown typespec!"); } const char *DeclSpec::getSpecifierName(TQ T) { @@ -205,7 +205,7 @@ const char *DeclSpec::getSpecifierName(TQ T) { case DeclSpec::TQ_restrict: return "restrict"; case DeclSpec::TQ_volatile: return "volatile"; } - llvm::llvm_unreachable("Unknown typespec!"); + llvm_unreachable("Unknown typespec!"); } bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc, diff --git a/lib/Parse/ExtensionRAIIObject.h b/lib/Parse/ExtensionRAIIObject.h deleted file mode 100644 index cc7c8e2..0000000 --- a/lib/Parse/ExtensionRAIIObject.h +++ /dev/null @@ -1,40 +0,0 @@ -//===--- ExtensionRAIIObject.h - Use RAII for __extension__ -----*- 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 and implements the ExtensionRAIIObject class. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_PARSE_EXTENSION_RAII_OBJECT_H -#define LLVM_CLANG_PARSE_EXTENSION_RAII_OBJECT_H - -#include "clang/Parse/ParseDiagnostic.h" - -namespace clang { - - /// ExtensionRAIIObject - This saves the state of extension warnings when - /// constructed and disables them. When destructed, it restores them back to - /// the way they used to be. This is used to handle __extension__ in the - /// parser. - class ExtensionRAIIObject { - void operator=(const ExtensionRAIIObject &); // DO NOT IMPLEMENT - ExtensionRAIIObject(const ExtensionRAIIObject&); // DO NOT IMPLEMENT - Diagnostic &Diags; - public: - ExtensionRAIIObject(Diagnostic &diags) : Diags(diags) { - Diags.IncrementAllExtensionsSilenced(); - } - - ~ExtensionRAIIObject() { - Diags.DecrementAllExtensionsSilenced(); - } - }; -} - -#endif diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp index aa0b89b..8b207fa 100644 --- a/lib/Parse/MinimalAction.cpp +++ b/lib/Parse/MinimalAction.cpp @@ -45,6 +45,7 @@ Action::DeclPtrTy Action::ActOnUsingDirective(Scope *CurScope, // Defined out-of-line here because of dependency on AttributeList Action::DeclPtrTy Action::ActOnUsingDeclaration(Scope *CurScope, AccessSpecifier AS, + bool HasUsingKeyword, SourceLocation UsingLoc, const CXXScopeSpec &SS, UnqualifiedId &Name, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index b13dc73..5dd78f7 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1,4 +1,3 @@ - //===--- ParseDecl.cpp - Declaration Parsing ------------------------------===// // // The LLVM Compiler Infrastructure @@ -16,7 +15,7 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Scope.h" #include "clang/Parse/Template.h" -#include "ExtensionRAIIObject.h" +#include "RAIIObjectsForParser.h" #include "llvm/ADT/SmallSet.h" using namespace clang; @@ -825,14 +824,18 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (DS.hasTypeSpecifier()) goto DoneWithDeclSpec; + CXXScopeSpec SS; + SS.setScopeRep(Tok.getAnnotationValue()); + SS.setRange(Tok.getAnnotationRange()); + // We are looking for a qualified typename. Token Next = NextToken(); if (Next.is(tok::annot_template_id) && static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue()) ->Kind == TNK_Type_template) { // We have a qualified template-id, e.g., N::A<int> - CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true); + DS.getTypeSpecScope() = SS; + ConsumeToken(); // The C++ scope. assert(Tok.is(tok::annot_template_id) && "ParseOptionalCXXScopeSpecifier not working"); AnnotateTemplateIdTokenAsType(&SS); @@ -840,8 +843,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, } if (Next.is(tok::annot_typename)) { - // FIXME: is this scope-specifier getting dropped? - ConsumeToken(); // the scope-specifier + DS.getTypeSpecScope() = SS; + ConsumeToken(); // The C++ scope. if (Tok.getAnnotationValue()) isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, @@ -855,10 +858,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (Next.isNot(tok::identifier)) goto DoneWithDeclSpec; - CXXScopeSpec SS; - SS.setScopeRep(Tok.getAnnotationValue()); - SS.setRange(Tok.getAnnotationRange()); - // If the next token is the name of the class type that the C++ scope // denotes, followed by a '(', then this is a constructor declaration. // We're done with the decl-specifiers. @@ -880,6 +879,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, goto DoneWithDeclSpec; } + DS.getTypeSpecScope() = SS; ConsumeToken(); // The C++ scope. isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, @@ -1545,8 +1545,11 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { /// struct-declarator: declarator /// struct-declarator: declarator[opt] ':' constant-expression - if (Tok.isNot(tok::colon)) + if (Tok.isNot(tok::colon)) { + // Don't parse FOO:BAR as if it were a typo for FOO::BAR. + ColonProtectionRAIIObject X(*this); ParseDeclarator(DeclaratorInfo.D); + } if (Tok.is(tok::colon)) { ConsumeToken(); @@ -1616,7 +1619,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { Diag(Tok, diag::ext_extra_struct_semi) - << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation())); + << CodeModificationHint::CreateRemoval(Tok.getLocation()); ConsumeToken(); continue; } @@ -1841,7 +1844,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) { !(getLang().C99 || getLang().CPlusPlus0x)) Diag(CommaLoc, diag::ext_enumerator_list_comma) << getLang().CPlusPlus - << CodeModificationHint::CreateRemoval((SourceRange(CommaLoc))); + << CodeModificationHint::CreateRemoval(CommaLoc); } // Eat the }. @@ -2333,9 +2336,10 @@ void Parser::ParseDirectDeclarator(Declarator &D) { ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0, true); if (afterCXXScope) { - // Change the declaration context for name lookup, until this function - // is exited (and the declarator has been parsed). - DeclScopeObj.EnterDeclaratorScope(); + if (Actions.ShouldEnterDeclaratorScope(CurScope, D.getCXXScopeSpec())) + // Change the declaration context for name lookup, until this function + // is exited (and the declarator has been parsed). + DeclScopeObj.EnterDeclaratorScope(); } if (Tok.is(tok::identifier) || Tok.is(tok::kw_operator) || diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 505a4d8..d4d19a0 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -17,7 +17,7 @@ #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" #include "clang/Parse/Template.h" -#include "ExtensionRAIIObject.h" +#include "RAIIObjectsForParser.h" using namespace clang; /// ParseNamespace - We know that the current token is a namespace keyword. This @@ -161,7 +161,8 @@ Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, /// 'extern' string-literal '{' declaration-seq[opt] '}' /// 'extern' string-literal declaration /// -Parser::DeclPtrTy Parser::ParseLinkage(unsigned Context) { +Parser::DeclPtrTy Parser::ParseLinkage(ParsingDeclSpec &DS, + unsigned Context) { assert(Tok.is(tok::string_literal) && "Not a string literal!"); llvm::SmallVector<char, 8> LangBuffer; // LangBuffer is guaranteed to be big enough. @@ -185,7 +186,7 @@ Parser::DeclPtrTy Parser::ParseLinkage(unsigned Context) { } if (Tok.isNot(tok::l_brace)) { - ParseDeclarationOrFunctionDefinition(Attr.AttrList); + ParseDeclarationOrFunctionDefinition(DS, Attr.AttrList); return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec, SourceLocation()); } @@ -356,7 +357,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, AttrList ? "attributes list" : "using declaration", tok::semi); - return Actions.ActOnUsingDeclaration(CurScope, AS, UsingLoc, SS, Name, + return Actions.ActOnUsingDeclaration(CurScope, AS, true, UsingLoc, SS, Name, AttrList, IsTypeName, TypenameLoc); } @@ -599,11 +600,15 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } // Parse the (optional) nested-name-specifier. - CXXScopeSpec SS; - if (getLang().CPlusPlus && - ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true)) - if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) - Diag(Tok, diag::err_expected_ident); + CXXScopeSpec &SS = DS.getTypeSpecScope(); + if (getLang().CPlusPlus) { + // "FOO : BAR" is not a potential typo for "FOO::BAR". + ColonProtectionRAIIObject X(*this); + + if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true)) + if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) + Diag(Tok, diag::err_expected_ident); + } TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; @@ -954,7 +959,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) { if (IsVirtual) { // Complain about duplicate 'virtual' Diag(VirtualLoc, diag::err_dup_virtual) - << CodeModificationHint::CreateRemoval(SourceRange(VirtualLoc)); + << CodeModificationHint::CreateRemoval(VirtualLoc); } IsVirtual = true; @@ -1060,6 +1065,46 @@ void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, /// void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, const ParsedTemplateInfo &TemplateInfo) { + // Access declarations. + if (!TemplateInfo.Kind && + (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) && + TryAnnotateCXXScopeToken() && + Tok.is(tok::annot_cxxscope)) { + bool isAccessDecl = false; + if (NextToken().is(tok::identifier)) + isAccessDecl = GetLookAheadToken(2).is(tok::semi); + else + isAccessDecl = NextToken().is(tok::kw_operator); + + if (isAccessDecl) { + // Collect the scope specifier token we annotated earlier. + CXXScopeSpec SS; + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType*/ 0, false); + + // Try to parse an unqualified-id. + UnqualifiedId Name; + if (ParseUnqualifiedId(SS, false, true, true, /*ObjectType*/ 0, Name)) { + SkipUntil(tok::semi); + return; + } + + // TODO: recover from mistakenly-qualified operator declarations. + if (ExpectAndConsume(tok::semi, + diag::err_expected_semi_after, + "access declaration", + tok::semi)) + return; + + Actions.ActOnUsingDeclaration(CurScope, AS, + false, SourceLocation(), + SS, Name, + /* AttrList */ 0, + /* IsTypeName */ false, + SourceLocation()); + return; + } + } + // static_assert-declaration if (Tok.is(tok::kw_static_assert)) { // FIXME: Check for templates @@ -1085,11 +1130,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return ParseCXXClassMemberDeclaration(AS, TemplateInfo); } + // Don't parse FOO:BAR as if it were a typo for FOO::BAR. + ColonProtectionRAIIObject X(*this); + CXX0XAttributeList AttrList; // Optional C++0x attribute-specifier - if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { + if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) AttrList = ParseCXX0XAttributes(); - } if (Tok.is(tok::kw_using)) { // FIXME: Check for template aliases @@ -1133,6 +1180,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext); if (Tok.isNot(tok::colon)) { + // Don't parse FOO:BAR as if it were a typo for FOO::BAR. + ColonProtectionRAIIObject X(*this); + // Parse the first declarator. ParseDeclarator(DeclaratorInfo); // Error parsing the declarator? @@ -1349,7 +1399,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { Diag(Tok, diag::ext_extra_struct_semi) - << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation())); + << CodeModificationHint::CreateRemoval(Tok.getLocation()); ConsumeToken(); continue; } diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index f780cf1..bdbc67f 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -23,7 +23,7 @@ #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" #include "clang/Basic/PrettyStackTrace.h" -#include "ExtensionRAIIObject.h" +#include "RAIIObjectsForParser.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallString.h" using namespace clang; @@ -317,6 +317,9 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { OwningExprResult TernaryMiddle(Actions, true); if (NextTokPrec == prec::Conditional) { if (Tok.isNot(tok::colon)) { + // Don't parse FOO:BAR as if it were a typo for FOO::BAR. + ColonProtectionRAIIObject X(*this); + // Handle this production specially: // logical-OR-expression '?' expression ':' conditional-expression // In particular, the RHS of the '?' is 'expression', not @@ -562,9 +565,15 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, TypeTy *CastTy; SourceLocation LParenLoc = Tok.getLocation(); SourceLocation RParenLoc; - Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/, - TypeOfCast, CastTy, RParenLoc); - if (Res.isInvalid()) return move(Res); + + { + // The inside of the parens don't need to be a colon protected scope. + ColonProtectionRAIIObject X(*this, false); + + Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/, + TypeOfCast, CastTy, RParenLoc); + if (Res.isInvalid()) return move(Res); + } switch (ParenExprType) { case SimpleExpr: break; // Nothing else to do. @@ -826,6 +835,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___is_empty: case tok::kw___is_polymorphic: case tok::kw___is_abstract: + case tok::kw___is_literal: case tok::kw___has_trivial_constructor: case tok::kw___has_trivial_copy: case tok::kw___has_trivial_assign: diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 52003e6..abd26d7 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -214,11 +214,29 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // namespace-name '::' // nested-name-specifier identifier '::' Token Next = NextToken(); + + // If we get foo:bar, this is almost certainly a typo for foo::bar. Recover + // and emit a fixit hint for it. + if (Next.is(tok::colon) && !ColonIsSacred && + Actions.IsInvalidUnlessNestedName(CurScope, SS, II, ObjectType, + EnteringContext) && + // If the token after the colon isn't an identifier, it's still an + // error, but they probably meant something else strange so don't + // recover like this. + PP.LookAhead(1).is(tok::identifier)) { + Diag(Next, diag::err_unexected_colon_in_nested_name_spec) + << CodeModificationHint::CreateReplacement(Next.getLocation(), "::"); + + // Recover as if the user wrote '::'. + Next.setKind(tok::coloncolon); + } + if (Next.is(tok::coloncolon)) { // We have an identifier followed by a '::'. Lookup this name // as the name in a nested-name-specifier. SourceLocation IdLoc = ConsumeToken(); - assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!"); + assert((Tok.is(tok::coloncolon) || Tok.is(tok::colon)) && + "NextToken() not working properly!"); SourceLocation CCLoc = ConsumeToken(); if (!HasScopeSpecifier) { @@ -1459,6 +1477,7 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) { case tok::kw___is_pod: return UTT_IsPOD; case tok::kw___is_polymorphic: return UTT_IsPolymorphic; case tok::kw___is_union: return UTT_IsUnion; + case tok::kw___is_literal: return UTT_IsLiteral; } } diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 295625a..2c53847 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -30,6 +30,11 @@ using namespace clang; Parser::DeclPtrTy Parser::ParseObjCAtDirectives() { SourceLocation AtLoc = ConsumeToken(); // the "@" + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, false); + ConsumeToken(); + } + switch (Tok.getObjCKeywordID()) { case tok::objc_class: return ParseObjCAtClassDeclaration(AtLoc); @@ -228,6 +233,63 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( return ClsType; } +/// The Objective-C property callback. This should be defined where +/// it's used, but instead it's been lifted to here to support VS2005. +struct Parser::ObjCPropertyCallback : FieldCallback { + Parser &P; + DeclPtrTy IDecl; + llvm::SmallVectorImpl<DeclPtrTy> &Props; + ObjCDeclSpec &OCDS; + SourceLocation AtLoc; + tok::ObjCKeywordKind MethodImplKind; + + ObjCPropertyCallback(Parser &P, DeclPtrTy IDecl, + llvm::SmallVectorImpl<DeclPtrTy> &Props, + ObjCDeclSpec &OCDS, SourceLocation AtLoc, + tok::ObjCKeywordKind MethodImplKind) : + P(P), IDecl(IDecl), Props(Props), OCDS(OCDS), AtLoc(AtLoc), + MethodImplKind(MethodImplKind) { + } + + DeclPtrTy invoke(FieldDeclarator &FD) { + if (FD.D.getIdentifier() == 0) { + P.Diag(AtLoc, diag::err_objc_property_requires_field_name) + << FD.D.getSourceRange(); + return DeclPtrTy(); + } + if (FD.BitfieldSize) { + P.Diag(AtLoc, diag::err_objc_property_bitfield) + << FD.D.getSourceRange(); + return DeclPtrTy(); + } + + // Install the property declarator into interfaceDecl. + IdentifierInfo *SelName = + OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier(); + + Selector GetterSel = + P.PP.getSelectorTable().getNullarySelector(SelName); + IdentifierInfo *SetterName = OCDS.getSetterName(); + Selector SetterSel; + if (SetterName) + SetterSel = P.PP.getSelectorTable().getSelector(1, &SetterName); + else + SetterSel = SelectorTable::constructSetterName(P.PP.getIdentifierTable(), + P.PP.getSelectorTable(), + FD.D.getIdentifier()); + bool isOverridingProperty = false; + DeclPtrTy Property = + P.Actions.ActOnProperty(P.CurScope, AtLoc, FD, OCDS, + GetterSel, SetterSel, IDecl, + &isOverridingProperty, + MethodImplKind); + if (!isOverridingProperty) + Props.push_back(Property); + + return Property; + } +}; + /// objc-interface-decl-list: /// empty /// objc-interface-decl-list objc-property-decl [OBJC2] @@ -288,6 +350,12 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, // Otherwise, we have an @ directive, eat the @. SourceLocation AtLoc = ConsumeToken(); // the "@" + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, true); + ConsumeToken(); + break; + } + tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID(); if (DirectiveKind == tok::objc_end) { // @end -> terminate list @@ -329,61 +397,8 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, ParseObjCPropertyAttribute(OCDS, interfaceDecl, allMethods.data(), allMethods.size()); - struct ObjCPropertyCallback : FieldCallback { - Parser &P; - DeclPtrTy IDecl; - llvm::SmallVectorImpl<DeclPtrTy> &Props; - ObjCDeclSpec &OCDS; - SourceLocation AtLoc; - tok::ObjCKeywordKind MethodImplKind; - - ObjCPropertyCallback(Parser &P, DeclPtrTy IDecl, - llvm::SmallVectorImpl<DeclPtrTy> &Props, - ObjCDeclSpec &OCDS, SourceLocation AtLoc, - tok::ObjCKeywordKind MethodImplKind) : - P(P), IDecl(IDecl), Props(Props), OCDS(OCDS), AtLoc(AtLoc), - MethodImplKind(MethodImplKind) { - } - - DeclPtrTy invoke(FieldDeclarator &FD) { - if (FD.D.getIdentifier() == 0) { - P.Diag(AtLoc, diag::err_objc_property_requires_field_name) - << FD.D.getSourceRange(); - return DeclPtrTy(); - } - if (FD.BitfieldSize) { - P.Diag(AtLoc, diag::err_objc_property_bitfield) - << FD.D.getSourceRange(); - return DeclPtrTy(); - } - - // Install the property declarator into interfaceDecl. - IdentifierInfo *SelName = - OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier(); - - Selector GetterSel = - P.PP.getSelectorTable().getNullarySelector(SelName); - IdentifierInfo *SetterName = OCDS.getSetterName(); - Selector SetterSel; - if (SetterName) - SetterSel = P.PP.getSelectorTable().getSelector(1, &SetterName); - else - SetterSel = SelectorTable::constructSetterName(P.PP.getIdentifierTable(), - P.PP.getSelectorTable(), - FD.D.getIdentifier()); - bool isOverridingProperty = false; - DeclPtrTy Property = - P.Actions.ActOnProperty(P.CurScope, AtLoc, FD, OCDS, - GetterSel, SetterSel, IDecl, - &isOverridingProperty, - MethodImplKind); - if (!isOverridingProperty) - Props.push_back(Property); - - return Property; - } - } Callback(*this, interfaceDecl, allProperties, - OCDS, AtLoc, MethodImplKind); + ObjCPropertyCallback Callback(*this, interfaceDecl, allProperties, + OCDS, AtLoc, MethodImplKind); // Parse all the comma separated declarators. DeclSpec DS; @@ -397,7 +412,10 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, // We break out of the big loop in two cases: when we see @end or when we see // EOF. In the former case, eat the @end. In the later case, emit an error. - if (Tok.isObjCAtKeyword(tok::objc_end)) + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCAtDirective(CurScope, ObjCImpDecl, true); + ConsumeToken(); + } else if (Tok.isObjCAtKeyword(tok::objc_end)) ConsumeToken(); // the "end" identifier else Diag(Tok, diag::err_objc_missing_end); @@ -938,7 +956,7 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, // Check for extraneous top-level semicolon. if (Tok.is(tok::semi)) { Diag(Tok, diag::ext_extra_struct_semi) - << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation())); + << CodeModificationHint::CreateRemoval(Tok.getLocation()); ConsumeToken(); continue; } @@ -1503,7 +1521,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() { if (Tok.is(tok::semi)) { if (ObjCImpDecl) { Diag(Tok, diag::warn_semicolon_before_method_body) - << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation())); + << CodeModificationHint::CreateRemoval(Tok.getLocation()); } ConsumeToken(); } @@ -1545,12 +1563,21 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() { } Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { - if (Tok.isObjCAtKeyword(tok::objc_try)) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCAtStatement(CurScope); + ConsumeToken(); + return StmtError(); + } + + if (Tok.isObjCAtKeyword(tok::objc_try)) return ParseObjCTryStmt(AtLoc); - } else if (Tok.isObjCAtKeyword(tok::objc_throw)) + + if (Tok.isObjCAtKeyword(tok::objc_throw)) return ParseObjCThrowStmt(AtLoc); - else if (Tok.isObjCAtKeyword(tok::objc_synchronized)) + + if (Tok.isObjCAtKeyword(tok::objc_synchronized)) return ParseObjCSynchronizedStmt(AtLoc); + OwningExprResult Res(ParseExpressionWithLeadingAt(AtLoc)); if (Res.isInvalid()) { // If the expression is invalid, skip ahead to the next semicolon. Not @@ -1559,6 +1586,7 @@ Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { SkipUntil(tok::semi); return StmtError(); } + // Otherwise, eat the semicolon. ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr); return Actions.ActOnExprStmt(Actions.FullExpr(Res)); @@ -1566,6 +1594,11 @@ Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { switch (Tok.getKind()) { + case tok::code_completion: + Actions.CodeCompleteObjCAtExpression(CurScope); + ConsumeToken(); + return ExprError(); + case tok::string_literal: // primary-expression: string-literal case tok::wide_string_literal: return ParsePostfixExpressionSuffix(ParseObjCStringLiteral(AtLoc)); diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index c87010e..a2ac646 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Parse/Parser.h" -#include "ExtensionRAIIObject.h" +#include "RAIIObjectsForParser.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" #include "clang/Basic/Diagnostic.h" @@ -279,6 +279,11 @@ Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) { ConsumeToken(); } + /// We don't want to treat 'case x : y' as a potential typo for 'case x::y'. + /// Disable this form of error recovery while we're parsing the case + /// expression. + ColonProtectionRAIIObject ColonProtection(*this); + OwningExprResult LHS(ParseConstantExpression()); if (LHS.isInvalid()) { SkipUntil(tok::colon); @@ -298,6 +303,8 @@ Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) { return StmtError(); } } + + ColonProtection.restore(); if (Tok.isNot(tok::colon)) { Diag(Tok, diag::err_expected_colon_after) << "'case'"; @@ -1162,7 +1169,20 @@ Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() { Tok.isNot(tok::r_brace) && Tok.isNot(tok::semi) && Tok.isNot(tok::eof)); } - return Actions.ActOnNullStmt(Tok.getLocation()); + llvm::SmallVector<std::string, 4> Names; + Token t; + t.setKind(tok::string_literal); + t.setLiteralData("\"FIXME: not done\""); + t.clearFlag(Token::NeedsCleaning); + t.setLength(17); + OwningExprResult AsmString(Actions.ActOnStringLiteral(&t, 1)); + ExprVector Constraints(Actions); + ExprVector Exprs(Actions); + ExprVector Clobbers(Actions); + return Actions.ActOnAsmStmt(Tok.getLocation(), true, true, 0, 0, Names.data(), + move_arg(Constraints), move_arg(Exprs), + move(AsmString), move_arg(Clobbers), + Tok.getLocation()); } /// ParseAsmStatement - Parse a GNU extended asm statement. diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 0dbf37c..cc28541 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -16,6 +16,7 @@ #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" #include "clang/Parse/Template.h" +#include "RAIIObjectsForParser.h" using namespace clang; /// \brief Parse a template declaration, explicit instantiation, or @@ -522,7 +523,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { if (Default.isInvalid()) { Diag(Tok.getLocation(), diag::err_default_template_template_parameter_not_template); - static tok::TokenKind EndToks[] = { + static const tok::TokenKind EndToks[] = { tok::comma, tok::greater, tok::greatergreater }; SkipUntil(EndToks, 3, true, true); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index e321564..a864e7c 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -17,7 +17,7 @@ #include "clang/Parse/Scope.h" #include "clang/Parse/Template.h" #include "llvm/Support/raw_ostream.h" -#include "ExtensionRAIIObject.h" +#include "RAIIObjectsForParser.h" #include "ParsePragma.h" using namespace clang; @@ -36,7 +36,8 @@ public: Parser::Parser(Preprocessor &pp, Action &actions) : CrashInfo(*this), PP(pp), Actions(actions), Diags(PP.getDiagnostics()), - GreaterThanIsOperator(true), TemplateParameterDepth(0) { + GreaterThanIsOperator(true), ColonIsSacred(false), + TemplateParameterDepth(0) { Tok.setKind(tok::eof); CurScope = 0; NumCachedScopes = 0; @@ -405,7 +406,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr) case tok::semi: if (!getLang().CPlusPlus0x) Diag(Tok, diag::ext_top_level_semi) - << CodeModificationHint::CreateRemoval(SourceRange(Tok.getLocation())); + << CodeModificationHint::CreateRemoval(Tok.getLocation()); ConsumeToken(); // TODO: Invoke action for top-level semicolon. @@ -507,12 +508,13 @@ bool Parser::isDeclarationAfterDeclarator() { /// \brief Determine whether the current token, if it occurs after a /// declarator, indicates the start of a function definition. bool Parser::isStartOfFunctionDefinition() { - return Tok.is(tok::l_brace) || // int X() {} - (!getLang().CPlusPlus && - isDeclarationSpecifier()) || // int X(f) int f; {} - (getLang().CPlusPlus && - (Tok.is(tok::colon) || // X() : Base() {} (used for ctors) - Tok.is(tok::kw_try))); // X() try { ... } + if (Tok.is(tok::l_brace)) // int X() {} + return true; + + if (!getLang().CPlusPlus) + return isDeclarationSpecifier(); // int X(f) int f; {} + return Tok.is(tok::colon) || // X() : Base() {} (used for ctors) + Tok.is(tok::kw_try); // X() try { ... } } /// ParseDeclarationOrFunctionDefinition - Parse either a function-definition or @@ -532,10 +534,10 @@ bool Parser::isStartOfFunctionDefinition() { /// [OMP] threadprivate-directive [TODO] /// Parser::DeclGroupPtrTy -Parser::ParseDeclarationOrFunctionDefinition(AttributeList *Attr, +Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS, + AttributeList *Attr, AccessSpecifier AS) { // Parse the common declaration-specifiers piece. - ParsingDeclSpec DS(*this); if (Attr) DS.AddAttributes(Attr); @@ -584,13 +586,20 @@ Parser::ParseDeclarationOrFunctionDefinition(AttributeList *Attr, DS.getStorageClassSpec() == DeclSpec::SCS_extern && DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) { DS.abort(); - DeclPtrTy TheDecl = ParseLinkage(Declarator::FileContext); + DeclPtrTy TheDecl = ParseLinkage(DS, Declarator::FileContext); return Actions.ConvertDeclToDeclGroup(TheDecl); } return ParseDeclGroup(DS, Declarator::FileContext, true); } +Parser::DeclGroupPtrTy +Parser::ParseDeclarationOrFunctionDefinition(AttributeList *Attr, + AccessSpecifier AS) { + ParsingDeclSpec DS(*this); + return ParseDeclarationOrFunctionDefinition(DS, Attr, AS); +} + /// ParseFunctionDefinition - We parsed and verified that the specified /// Declarator is well formed. If this is a K&R-style function, read the /// parameters declaration-list, then start the compound-statement. @@ -1029,7 +1038,9 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { CXXScopeSpec SS; if (!ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext)) - return Tok.is(tok::annot_template_id); + // If the token left behind is not an identifier, we either had an error or + // successfully turned it into an annotation token. + return Tok.isNot(tok::identifier); // Push the current token back into the token stream (or revert it if it is // cached) and use an annotation scope token for current token. diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h new file mode 100644 index 0000000..06bbbc2 --- /dev/null +++ b/lib/Parse/RAIIObjectsForParser.h @@ -0,0 +1,85 @@ +//===--- RAIIObjectsForParser.h - RAII helpers for the parser ---*- 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 and implements the some simple RAII objects that are used +// by the parser to manage bits in recursion. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PARSE_RAII_OBJECTS_FOR_PARSER_H +#define LLVM_CLANG_PARSE_RAII_OBJECTS_FOR_PARSER_H + +#include "clang/Parse/ParseDiagnostic.h" + +namespace clang { + // TODO: move ParsingDeclRAIIObject here. + // TODO: move ParsingClassDefinition here. + // TODO: move TentativeParsingAction here. + + + /// ExtensionRAIIObject - This saves the state of extension warnings when + /// constructed and disables them. When destructed, it restores them back to + /// the way they used to be. This is used to handle __extension__ in the + /// parser. + class ExtensionRAIIObject { + void operator=(const ExtensionRAIIObject &); // DO NOT IMPLEMENT + ExtensionRAIIObject(const ExtensionRAIIObject&); // DO NOT IMPLEMENT + Diagnostic &Diags; + public: + ExtensionRAIIObject(Diagnostic &diags) : Diags(diags) { + Diags.IncrementAllExtensionsSilenced(); + } + + ~ExtensionRAIIObject() { + Diags.DecrementAllExtensionsSilenced(); + } + }; + + /// ColonProtectionRAIIObject - This sets the Parser::ColonIsSacred bool and + /// restores it when destroyed. This says that "foo:" should not be + /// considered a possible typo for "foo::" for error recovery purposes. + class ColonProtectionRAIIObject { + Parser &P; + bool OldVal; + public: + ColonProtectionRAIIObject(Parser &p, bool Value = true) + : P(p), OldVal(P.ColonIsSacred) { + P.ColonIsSacred = Value; + } + + /// restore - This can be used to restore the state early, before the dtor + /// is run. + void restore() { + P.ColonIsSacred = OldVal; + } + + ~ColonProtectionRAIIObject() { + restore(); + } + }; + + /// \brief RAII object that makes '>' behave either as an operator + /// or as the closing angle bracket for a template argument list. + class GreaterThanIsOperatorScope { + bool &GreaterThanIsOperator; + bool OldGreaterThanIsOperator; + public: + GreaterThanIsOperatorScope(bool >IO, bool Val) + : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) { + GreaterThanIsOperator = Val; + } + + ~GreaterThanIsOperatorScope() { + GreaterThanIsOperator = OldGreaterThanIsOperator; + } + }; + +} // end namespace clang + +#endif diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 91b16d3..d8ed894 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -46,7 +46,7 @@ CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text) } case CK_Optional: - llvm::llvm_unreachable("Optional strings cannot be created from text"); + llvm_unreachable("Optional strings cannot be created from text"); break; case CK_LeftParen: diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h index e2134a2..78f79ea 100644 --- a/lib/Sema/Lookup.h +++ b/lib/Sema/Lookup.h @@ -26,13 +26,6 @@ namespace clang { /// 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 { @@ -40,12 +33,11 @@ public: NotFound = 0, /// @brief Name lookup found a single declaration that met the - /// criteria. getAsDecl will return this declaration. + /// criteria. getFoundDecl() 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. + /// met the criteria. FoundOverloaded, /// @brief Name lookup found an unresolvable value declaration @@ -282,13 +274,6 @@ public: } } - /// \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; - template <class DeclClass> DeclClass *getAsSingle() const { if (getResultKind() != Found) return 0; diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp index 7c7df4b..898b3c2 100644 --- a/lib/Sema/ParseAST.cpp +++ b/lib/Sema/ParseAST.cpp @@ -75,7 +75,7 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, while ((ADecl = P.RetrievePendingObjCImpDecl())) Consumer->HandleTopLevelDecl(ADecl.getAsVal<DeclGroupRef>()); - // process any TopLevelDecls generated by #pragma weak + // Process any TopLevelDecls generated by #pragma weak. for (llvm::SmallVector<Decl*,2>::iterator I = S.WeakTopLevelDecls().begin(), E = S.WeakTopLevelDecls().end(); I != E; ++I) @@ -83,6 +83,13 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, Consumer->HandleTranslationUnit(Ctx); + if (ExternalSemaSource *ESS = + dyn_cast_or_null<ExternalSemaSource>(Ctx.getExternalSource())) + ESS->ForgetSema(); + + if (SemaConsumer *SC = dyn_cast<SemaConsumer>(Consumer)) + SC->ForgetSema(); + if (PrintStats) { fprintf(stderr, "\nSTATISTICS:\n"); P.getActions().PrintStats(); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index f0812bf..ef61474 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -278,20 +278,20 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { PushDeclContext(S, Context.getTranslationUnitDecl()); if (PP.getTargetInfo().getPointerWidth(0) >= 64) { - DeclaratorInfo *DInfo; + TypeSourceInfo *TInfo; // Install [u]int128_t for 64-bit targets. - DInfo = Context.getTrivialDeclaratorInfo(Context.Int128Ty); + TInfo = Context.getTrivialTypeSourceInfo(Context.Int128Ty); PushOnScopeChains(TypedefDecl::Create(Context, CurContext, SourceLocation(), &Context.Idents.get("__int128_t"), - DInfo), TUScope); + TInfo), TUScope); - DInfo = Context.getTrivialDeclaratorInfo(Context.UnsignedInt128Ty); + TInfo = Context.getTrivialTypeSourceInfo(Context.UnsignedInt128Ty); PushOnScopeChains(TypedefDecl::Create(Context, CurContext, SourceLocation(), &Context.Idents.get("__uint128_t"), - DInfo), TUScope); + TInfo), TUScope); } @@ -301,7 +301,7 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { if (Context.getObjCSelType().isNull()) { // Create the built-in typedef for 'SEL'. QualType SelT = Context.getPointerType(Context.ObjCBuiltinSelTy); - DeclaratorInfo *SelInfo = Context.getTrivialDeclaratorInfo(SelT); + TypeSourceInfo *SelInfo = Context.getTrivialTypeSourceInfo(SelT); TypedefDecl *SelTypedef = TypedefDecl::Create(Context, CurContext, SourceLocation(), &Context.Idents.get("SEL"), SelInfo); @@ -322,7 +322,7 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { // Create the built-in typedef for 'id'. if (Context.getObjCIdType().isNull()) { QualType IdT = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy); - DeclaratorInfo *IdInfo = Context.getTrivialDeclaratorInfo(IdT); + TypeSourceInfo *IdInfo = Context.getTrivialTypeSourceInfo(IdT); TypedefDecl *IdTypedef = TypedefDecl::Create(Context, CurContext, SourceLocation(), &Context.Idents.get("id"), IdInfo); @@ -334,7 +334,7 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { if (Context.getObjCClassType().isNull()) { QualType ClassType = Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy); - DeclaratorInfo *ClassInfo = Context.getTrivialDeclaratorInfo(ClassType); + TypeSourceInfo *ClassInfo = Context.getTrivialTypeSourceInfo(ClassType); TypedefDecl *ClassTypedef = TypedefDecl::Create(Context, CurContext, SourceLocation(), &Context.Idents.get("Class"), ClassInfo); @@ -728,18 +728,27 @@ void Sema::DeleteStmt(StmtTy *S) { /// translation unit when EOF is reached and all but the top-level scope is /// popped. void Sema::ActOnEndOfTranslationUnit() { - // C++: Perform implicit template instantiations. - // - // FIXME: When we perform these implicit instantiations, we do not carefully - // keep track of the point of instantiation (C++ [temp.point]). This means - // that name lookup that occurs within the template instantiation will - // always happen at the end of the translation unit, so it will find - // some names that should not be found. Although this is common behavior - // for C++ compilers, it is technically wrong. In the future, we either need - // to be able to filter the results of name lookup or we need to perform - // template instantiations earlier. - PerformPendingImplicitInstantiations(); - + + while (1) { + // C++: Perform implicit template instantiations. + // + // FIXME: When we perform these implicit instantiations, we do not carefully + // keep track of the point of instantiation (C++ [temp.point]). This means + // that name lookup that occurs within the template instantiation will + // always happen at the end of the translation unit, so it will find + // some names that should not be found. Although this is common behavior + // for C++ compilers, it is technically wrong. In the future, we either need + // to be able to filter the results of name lookup or we need to perform + // template instantiations earlier. + PerformPendingImplicitInstantiations(); + + /// If ProcessPendingClassesWithUnmarkedVirtualMembers ends up marking + /// any virtual member functions it might lead to more pending template + /// instantiations, which is why we need to loop here. + if (!ProcessPendingClassesWithUnmarkedVirtualMembers()) + break; + } + // Check for #pragma weak identifiers that were never declared // FIXME: This will cause diagnostics to be emitted in a non-determinstic // order! Iterating over a densemap like this is bad. diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index b594ece..ada8aa1 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -32,6 +32,7 @@ #include "llvm/ADT/OwningPtr.h" #include <deque> #include <list> +#include <map> #include <string> #include <vector> @@ -94,7 +95,10 @@ namespace clang { class CXXBasePaths; class CXXTemporary; class LookupResult; - + class InitializedEntity; + class InitializationKind; + class InitializationSequence; + /// BlockSemaInfo - When a block is being parsed, this contains information /// about the block. It is pointed to from Sema::CurBlock. struct BlockSemaInfo { @@ -131,7 +135,7 @@ struct BlockSemaInfo { BlockSemaInfo *PrevBlockInfo; }; -/// \brief Holds a QualType and a DeclaratorInfo* that came out of a declarator +/// \brief Holds a QualType and a TypeSourceInfo* that came out of a declarator /// parsing. /// /// LocInfoType is a "transient" type, only needed for passing to/from Parser @@ -144,17 +148,17 @@ class LocInfoType : public Type { LocInfo = (1 << TypeClassBitSize) - 1 }; - DeclaratorInfo *DeclInfo; + TypeSourceInfo *DeclInfo; - LocInfoType(QualType ty, DeclaratorInfo *DInfo) - : Type((TypeClass)LocInfo, ty, ty->isDependentType()), DeclInfo(DInfo) { + LocInfoType(QualType ty, TypeSourceInfo *TInfo) + : Type((TypeClass)LocInfo, ty, ty->isDependentType()), DeclInfo(TInfo) { assert(getTypeClass() == (TypeClass)LocInfo && "LocInfo didn't fit in TC?"); } friend class Sema; public: QualType getType() const { return getCanonicalTypeInternal(); } - DeclaratorInfo *getDeclaratorInfo() const { return DeclInfo; } + TypeSourceInfo *getTypeSourceInfo() const { return DeclInfo; } virtual void getAsStringInternal(std::string &Str, const PrintingPolicy &Policy) const; @@ -335,6 +339,10 @@ public: typedef std::vector<std::pair<SourceLocation, Decl *> > PotentiallyReferencedDecls; + /// \brief A set of diagnostics that may be emitted. + typedef std::vector<std::pair<SourceLocation, PartialDiagnostic> > + PotentiallyEmittedDiagnostics; + /// \brief Data structure used to record current or nested /// expression evaluation contexts. struct ExpressionEvaluationContextRecord { @@ -354,10 +362,14 @@ public: /// evaluated. PotentiallyReferencedDecls *PotentiallyReferenced; + /// \brief The set of diagnostics to emit should this potentially + /// potentially-evaluated context become evaluated. + PotentiallyEmittedDiagnostics *PotentiallyDiagnosed; + ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, unsigned NumTemporaries) : Context(Context), NumTemporaries(NumTemporaries), - PotentiallyReferenced(0) { } + PotentiallyReferenced(0), PotentiallyDiagnosed(0) { } void addReferencedDecl(SourceLocation Loc, Decl *Decl) { if (!PotentiallyReferenced) @@ -365,9 +377,17 @@ public: PotentiallyReferenced->push_back(std::make_pair(Loc, Decl)); } + void addDiagnostic(SourceLocation Loc, const PartialDiagnostic &PD) { + if (!PotentiallyDiagnosed) + PotentiallyDiagnosed = new PotentiallyEmittedDiagnostics; + PotentiallyDiagnosed->push_back(std::make_pair(Loc, PD)); + } + void Destroy() { delete PotentiallyReferenced; + delete PotentiallyDiagnosed; PotentiallyReferenced = 0; + PotentiallyDiagnosed = 0; } }; @@ -517,14 +537,14 @@ public: QualType BuildBlockPointerType(QualType T, unsigned Quals, SourceLocation Loc, DeclarationName Entity); QualType GetTypeForDeclarator(Declarator &D, Scope *S, - DeclaratorInfo **DInfo = 0, + TypeSourceInfo **TInfo = 0, TagDecl **OwnedDecl = 0); - DeclaratorInfo *GetDeclaratorInfoForDeclarator(Declarator &D, QualType T); - /// \brief Create a LocInfoType to hold the given QualType and DeclaratorInfo. - QualType CreateLocInfoType(QualType T, DeclaratorInfo *DInfo); + TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T); + /// \brief Create a LocInfoType to hold the given QualType and TypeSourceInfo. + QualType CreateLocInfoType(QualType T, TypeSourceInfo *TInfo); DeclarationName GetNameForDeclarator(Declarator &D); DeclarationName GetNameFromUnqualifiedId(const UnqualifiedId &Name); - static QualType GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo = 0); + static QualType GetTypeFromParser(TypeTy *Ty, TypeSourceInfo **TInfo = 0); bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range); bool CheckDistantExceptionSpec(QualType T); bool CheckEquivalentExceptionSpec( @@ -596,23 +616,24 @@ public: SourceLocation NameLoc, unsigned Diagnostic); NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, DeclaratorInfo *DInfo, + QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, bool &Redeclaration); NamedDecl* ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, DeclaratorInfo *DInfo, + QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool &Redeclaration); void CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous, bool &Redeclaration); NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, DeclaratorInfo *DInfo, + QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool IsFunctionDefinition, bool &Redeclaration); void AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); - void CheckFunctionDeclaration(FunctionDecl *NewFD, LookupResult &Previous, + void CheckFunctionDeclaration(Scope *S, + FunctionDecl *NewFD, LookupResult &Previous, bool IsExplicitSpecialization, bool &Redeclaration, bool &OverloadableAttrRequired); @@ -710,7 +731,7 @@ public: AccessSpecifier AS); FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T, - DeclaratorInfo *DInfo, + TypeSourceInfo *TInfo, RecordDecl *Record, SourceLocation Loc, bool Mutable, Expr *BitfieldWidth, SourceLocation TSSL, @@ -811,19 +832,9 @@ public: return NULL; } - /// OverloadingResult - Capture the result of performing overload - /// resolution. - enum OverloadingResult { - OR_Success, ///< Overload resolution succeeded. - OR_No_Viable_Function, ///< No viable function found. - OR_Ambiguous, ///< Ambiguous candidates found. - OR_Deleted ///< Overload resoltuion refers to a deleted function. - }; - - /// Subroutines of ActOnDeclarator(). TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T, - DeclaratorInfo *DInfo); + TypeSourceInfo *TInfo); void MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls); bool MergeFunctionDecl(FunctionDecl *New, Decl *Old); bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old); @@ -831,8 +842,22 @@ public: bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old); /// C++ Overloading. - bool IsOverload(FunctionDecl *New, LookupResult &OldDecls, - NamedDecl *&OldDecl); + enum OverloadKind { + /// This is a legitimate overload: the existing declarations are + /// functions or function templates with different signatures. + Ovl_Overload, + + /// This is not an overload because the signature exactly matches + /// an existing declaration. + Ovl_Match, + + /// This is not an overload because the lookup results contain a + /// non-function. + Ovl_NonFunction + }; + OverloadKind CheckOverload(FunctionDecl *New, + const LookupResult &OldDecls, + NamedDecl *&OldDecl); bool IsOverload(FunctionDecl *New, FunctionDecl *Old); ImplicitConversionSequence @@ -896,7 +921,8 @@ public: const char *Flavor, bool Elidable = false); ImplicitConversionSequence - TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method); + TryObjectArgumentInitialization(QualType FromType, CXXMethodDecl *Method, + CXXRecordDecl *ActingContext); bool PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method); ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From); @@ -922,18 +948,20 @@ public: OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false); void AddMethodCandidate(NamedDecl *Decl, - Expr *Object, Expr **Args, unsigned NumArgs, + QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversion = false, bool ForceRValue = false); - void AddMethodCandidate(CXXMethodDecl *Method, - Expr *Object, Expr **Args, unsigned NumArgs, + void AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, + QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool ForceRValue = false); void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, + CXXRecordDecl *ActingContext, const TemplateArgumentListInfo *ExplicitTemplateArgs, - Expr *Object, Expr **Args, unsigned NumArgs, + QualType ObjectType, + Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool ForceRValue = false); @@ -944,14 +972,17 @@ public: bool SuppressUserConversions = false, bool ForceRValue = false); void AddConversionCandidate(CXXConversionDecl *Conversion, + CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet& CandidateSet); void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, + CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet); void AddSurrogateCandidate(CXXConversionDecl *Conversion, + CXXRecordDecl *ActingContext, const FunctionProtoType *Proto, - Expr *Object, Expr **Args, unsigned NumArgs, + QualType ObjectTy, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet); void AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, SourceLocation OpLoc, @@ -990,6 +1021,8 @@ public: FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, bool Complain); Expr *FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn); + OwningExprResult FixOverloadedFunctionReference(OwningExprResult, + FunctionDecl *Fn); void AddOverloadedCallCandidates(llvm::SmallVectorImpl<NamedDecl*>& Callees, DeclarationName &UnqualifiedName, @@ -1023,7 +1056,7 @@ public: SourceLocation RLoc, ExprArg Base,ExprArg Idx); - ExprResult + OwningExprResult BuildCallToMemberFunction(Scope *S, Expr *MemExpr, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation *CommaLocs, @@ -1107,6 +1140,10 @@ public: /// namespace alias definition, ignoring non-namespace names (C++ /// [basic.lookup.udir]p1). LookupNamespaceName, + /// Look up all declarations in a scope with the given name, + /// including resolved using declarations. This is appropriate + /// for checking redeclarations for a using declaration. + LookupUsingDeclName, /// Look up an ordinary name that is going to be redeclared as a /// name with linkage. This lookup ignores any declarations that /// are outside of the current scope unless they have linkage. See @@ -1115,9 +1152,7 @@ public: /// Look up the name of an Objective-C protocol. LookupObjCProtocolName, /// Look up the name of an Objective-C implementation - LookupObjCImplementationName, - /// Look up the name of an Objective-C category implementation - LookupObjCCategoryImplName + LookupObjCImplementationName }; enum RedeclarationKind { @@ -1138,9 +1173,9 @@ public: case Sema::LookupTagName: case Sema::LookupMemberName: case Sema::LookupRedeclarationWithLinkage: // FIXME: check linkage, scoping + case Sema::LookupUsingDeclName: case Sema::LookupObjCProtocolName: case Sema::LookupObjCImplementationName: - case Sema::LookupObjCCategoryImplName: return D->isInIdentifierNamespace(IDNS); case Sema::LookupOperatorName: @@ -1160,7 +1195,7 @@ public: } /// \brief Look up a name, looking for a single declaration. Return - /// null if no unambiguous results were found. + /// null if the results were absent, ambiguous, or overloaded. /// /// It is preferable to use the elaborated form and explicitly handle /// ambiguity and overloaded. @@ -1176,7 +1211,6 @@ public: bool EnteringContext = false); ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II); - ObjCCategoryImplDecl *LookupObjCCategoryImpl(IdentifierInfo *II); void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, QualType T1, QualType T2, @@ -1379,7 +1413,7 @@ public: StmtArg SynchBody); VarDecl *BuildExceptionDeclaration(Scope *S, QualType ExDeclType, - DeclaratorInfo *DInfo, + TypeSourceInfo *TInfo, IdentifierInfo *Name, SourceLocation Loc, SourceRange Range); @@ -1438,10 +1472,10 @@ public: OwningExprResult ActOnDependentIdExpression(const CXXScopeSpec &SS, DeclarationName Name, SourceLocation NameLoc, - bool CheckForImplicitMember, + bool isAddressOfOperand, const TemplateArgumentListInfo *TemplateArgs); - OwningExprResult BuildDeclRefExpr(NamedDecl *D, QualType Ty, + OwningExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc, const CXXScopeSpec *SS = 0); VarDecl *BuildAnonymousStructUnionMemberPath(FieldDecl *Field, @@ -1451,9 +1485,10 @@ public: FieldDecl *Field, Expr *BaseObjectExpr = 0, SourceLocation OpLoc = SourceLocation()); - OwningExprResult BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS, - LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs); + OwningExprResult BuildImplicitMemberExpr(const CXXScopeSpec &SS, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs, + bool IsDefiniteInstance); bool UseArgumentDependentLookup(const CXXScopeSpec &SS, const LookupResult &R, bool HasTrailingLParen); @@ -1498,7 +1533,7 @@ public: virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Op, ExprArg Input); - OwningExprResult CreateSizeOfAlignOfExpr(DeclaratorInfo *T, + OwningExprResult CreateSizeOfAlignOfExpr(TypeSourceInfo *T, SourceLocation OpLoc, bool isSizeOf, SourceRange R); OwningExprResult CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc, @@ -1525,6 +1560,7 @@ public: SourceLocation RLoc); OwningExprResult BuildMemberReferenceExpr(ExprArg Base, + QualType BaseType, SourceLocation OpLoc, bool IsArrow, const CXXScopeSpec &SS, @@ -1534,23 +1570,24 @@ public: const TemplateArgumentListInfo *TemplateArgs); OwningExprResult BuildMemberReferenceExpr(ExprArg Base, + QualType BaseType, SourceLocation OpLoc, bool IsArrow, const CXXScopeSpec &SS, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs); OwningExprResult LookupMemberExpr(LookupResult &R, Expr *&Base, - bool IsArrow, SourceLocation OpLoc, + bool &IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, NamedDecl *FirstQualifierInScope, DeclPtrTy ObjCImpDecl); bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, + const CXXScopeSpec &SS, const LookupResult &R); OwningExprResult ActOnDependentMemberExpr(ExprArg Base, + QualType BaseType, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, @@ -1592,6 +1629,11 @@ public: MultiExprArg Args, SourceLocation *CommaLocs, SourceLocation RParenLoc); + OwningExprResult BuildResolvedCallExpr(Expr *Fn, + NamedDecl *NDecl, + SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation RParenLoc); virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty, SourceLocation RParenLoc, @@ -1715,6 +1757,21 @@ public: SourceLocation IdentLoc, IdentifierInfo *Ident); + void HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow); + bool CheckUsingShadowDecl(UsingDecl *UD, NamedDecl *Target, + const LookupResult &PreviousDecls); + UsingShadowDecl *BuildUsingShadowDecl(Scope *S, UsingDecl *UD, + NamedDecl *Target); + + bool CheckUsingDeclRedeclaration(SourceLocation UsingLoc, + bool isTypeName, + const CXXScopeSpec &SS, + SourceLocation NameLoc, + const LookupResult &Previous); + bool CheckUsingDeclQualifier(SourceLocation UsingLoc, + const CXXScopeSpec &SS, + SourceLocation NameLoc); + NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, const CXXScopeSpec &SS, @@ -1727,6 +1784,7 @@ public: virtual DeclPtrTy ActOnUsingDeclaration(Scope *CurScope, AccessSpecifier AS, + bool HasUsingKeyword, SourceLocation UsingLoc, const CXXScopeSpec &SS, UnqualifiedId &Name, @@ -1809,7 +1867,8 @@ public: /// getAssignOperatorMethod - Returns the default copy assignmment operator /// for the class. - CXXMethodDecl *getAssignOperatorMethod(ParmVarDecl *Decl, + CXXMethodDecl *getAssignOperatorMethod(SourceLocation CurrentLocation, + ParmVarDecl *Decl, CXXRecordDecl *ClassDecl); /// MaybeBindToTemporary - If the passed in expression has a record type with @@ -1817,14 +1876,6 @@ public: /// it simply returns the passed in expression. OwningExprResult MaybeBindToTemporary(Expr *E); - /// InitializationKind - Represents which kind of C++ initialization - /// [dcl.init] a routine is to perform. - enum InitializationKind { - IK_Direct, ///< Direct initialization - IK_Copy, ///< Copy initialization - IK_Default ///< Default initialization - }; - CXXConstructorDecl * TryInitializationByConstructor(QualType ClassType, Expr **Args, unsigned NumArgs, @@ -1982,7 +2033,8 @@ public: IdentifierInfo &II, QualType ObjectType, NamedDecl *ScopeLookupResult, - bool EnteringContext); + bool EnteringContext, + bool ErrorRecoveryLookup); virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, @@ -1992,6 +2044,12 @@ public: TypeTy *ObjectType, bool EnteringContext); + virtual bool IsInvalidUnlessNestedName(Scope *S, + const CXXScopeSpec &SS, + IdentifierInfo &II, + TypeTy *ObjectType, + bool EnteringContext); + /// ActOnCXXNestedNameSpecifier - Called during parsing of a /// nested-name-specifier that involves a template-id, e.g., /// "foo::bar<int, float>::", and now we need to build a scope @@ -2006,6 +2064,8 @@ public: SourceRange TypeRange, SourceLocation CCLoc); + virtual bool ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS); + /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global /// scope or nested-name-specifier) is parsed, part of a declarator-id. /// After this method is called, according to [C++ 3.4.3p3], names should be @@ -2102,10 +2162,13 @@ public: MemInitResult BuildMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs, SourceLocation IdLoc, + SourceLocation LParenLoc, SourceLocation RParenLoc); - MemInitResult BuildBaseInitializer(QualType BaseType, Expr **Args, - unsigned NumArgs, SourceLocation IdLoc, + MemInitResult BuildBaseInitializer(QualType BaseType, + TypeSourceInfo *BaseTInfo, + Expr **Args, unsigned NumArgs, + SourceLocation LParenLoc, SourceLocation RParenLoc, CXXRecordDecl *ClassDecl); @@ -2119,12 +2182,34 @@ public: /// as referenced. void MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor); + /// ClassesWithUnmarkedVirtualMembers - Contains record decls whose virtual + /// members might need to be marked as referenced. This is either done when + /// the key function definition is emitted (this is handled by by + /// MaybeMarkVirtualMembersReferenced), or at the end of the translation unit + /// (done by ProcessPendingClassesWithUnmarkedVirtualMembers). + std::map<CXXRecordDecl *, SourceLocation> ClassesWithUnmarkedVirtualMembers; + + /// MaybeMarkVirtualMembersReferenced - If the passed in method is the + /// key function of the record decl, will mark virtual member functions as + /// referenced. + void MaybeMarkVirtualMembersReferenced(SourceLocation Loc, CXXMethodDecl *MD); + + /// MarkVirtualMembersReferenced - Will mark all virtual members of the given + /// CXXRecordDecl referenced. + void MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD); + + /// ProcessPendingClassesWithUnmarkedVirtualMembers - Will process classes + /// that might need to have their virtual members marked as referenced. + /// Returns false if no work was done. + bool ProcessPendingClassesWithUnmarkedVirtualMembers(); + void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl); virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl, SourceLocation ColonLoc, MemInitTy **MemInits, unsigned NumMemInits); + void CheckCompletedCXXClass(CXXRecordDecl *Record); virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, DeclPtrTy TagDecl, SourceLocation LBrac, @@ -2168,6 +2253,14 @@ public: bool Virtual, AccessSpecifier Access, QualType BaseType, SourceLocation BaseLoc); + + /// SetClassDeclAttributesFromBase - Copies class decl traits + /// (such as whether the class has a trivial constructor, + /// trivial destructor etc) from the given base class. + void SetClassDeclAttributesFromBase(CXXRecordDecl *Class, + const CXXRecordDecl *BaseClass, + bool BaseIsVirtual); + virtual BaseResult ActOnBaseSpecifier(DeclPtrTy classdecl, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, @@ -2208,6 +2301,7 @@ public: bool CheckOverridingFunctionAttributes(const CXXMethodDecl *New, const CXXMethodDecl *Old); + bool CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange); //===--------------------------------------------------------------------===// // C++ Access Control // @@ -2452,7 +2546,7 @@ public: TemplateArgumentListBuilder &Converted); bool CheckTemplateArgument(TemplateTypeParmDecl *Param, - DeclaratorInfo *Arg); + TypeSourceInfo *Arg); bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, NamedDecl *&Entity); bool CheckTemplateArgumentPointerToMember(Expr *Arg, @@ -3084,7 +3178,7 @@ public: void PerformPendingImplicitInstantiations(); - DeclaratorInfo *SubstType(DeclaratorInfo *T, + TypeSourceInfo *SubstType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity); @@ -3490,6 +3584,9 @@ public: AssignConvertType CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType); + AssignConvertType CheckObjCPointerTypesForAssignment(QualType lhsType, + QualType rhsType); + // Helper function for CheckAssignmentConstraints involving two // block pointer types. AssignConvertType CheckBlockPointerTypesForAssignment(QualType lhsType, @@ -3556,6 +3653,9 @@ public: Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc); QualType FindCompositePointerType(Expr *&E1, Expr *&E2); // C++ 5.9 + QualType FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, + SourceLocation questionLoc); + /// type checking for vector binary operators. inline QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex); inline QualType CheckVectorCompareOperands(Expr *&lex, Expr *&rx, @@ -3718,6 +3818,10 @@ public: virtual void CodeCompleteNamespaceAliasDecl(Scope *S); virtual void CodeCompleteOperatorName(Scope *S); + virtual void CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl, + bool InInterface); + virtual void CodeCompleteObjCAtStatement(Scope *S); + virtual void CodeCompleteObjCAtExpression(Scope *S); virtual void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS); virtual void CodeCompleteObjCPropertyGetter(Scope *S, DeclPtrTy ClassDecl, DeclPtrTy *Methods, diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp index 5769716..095f537 100644 --- a/lib/Sema/SemaAttr.cpp +++ b/lib/Sema/SemaAttr.cpp @@ -183,20 +183,19 @@ void Sema::ActOnPragmaUnused(const Token *Identifiers, unsigned NumIdentifiers, LookupResult Lookup(*this, Name, Tok.getLocation(), LookupOrdinaryName); LookupParsedName(Lookup, curScope, NULL, true); - NamedDecl *ND = Lookup.getAsSingleDecl(Context); - - if (!ND) { + if (Lookup.empty()) { Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var) << Name << SourceRange(Tok.getLocation()); continue; } - if (!isa<VarDecl>(ND) || !cast<VarDecl>(ND)->hasLocalStorage()) { + VarDecl *VD = Lookup.getAsSingle<VarDecl>(); + if (!VD || !VD->hasLocalStorage()) { Diag(PragmaLoc, diag::warn_pragma_unused_expected_localvar) << Name << SourceRange(Tok.getLocation()); continue; } - ND->addAttr(::new (Context) UnusedAttr()); + VD->addAttr(::new (Context) UnusedAttr()); } } diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 6b4f87e..814af90 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" @@ -539,6 +540,16 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, return TC_Success; } } + else if (CStyle && DestType->isObjCObjectPointerType()) { + // allow c-style cast of objective-c pointers as they are pervasive. + Kind = CastExpr::CK_AnyPointerToObjCPointerCast; + return TC_Success; + } + else if (CStyle && DestType->isBlockPointerType()) { + // allow c-style cast of void * to block pointers. + Kind = CastExpr::CK_AnyPointerToBlockPointerCast; + return TC_Success; + } } } @@ -859,7 +870,9 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, if (CXXConstructorDecl *Constructor = Self.TryInitializationByConstructor(DestType, &SrcExpr, 1, OpRange.getBegin(), - Sema::IK_Direct)) { + InitializationKind::CreateDirect(OpRange.getBegin(), + OpRange.getBegin(), + OpRange.getEnd()))) { ConversionDecl = Constructor; Kind = CastExpr::CK_ConstructorConversion; return TC_Success; @@ -1053,8 +1066,10 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, return TC_Failed; } - bool destIsPtr = DestType->isPointerType(); - bool srcIsPtr = SrcType->isPointerType(); + bool destIsPtr = + CStyle? DestType->isAnyPointerType() : DestType->isPointerType(); + bool srcIsPtr = + CStyle ? SrcType->isAnyPointerType() : SrcType->isPointerType(); if (!destIsPtr && !srcIsPtr) { // Except for std::nullptr_t->integer and lvalue->reference, which are // handled above, at least one of the two arguments must be a pointer. @@ -1106,7 +1121,11 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, msg = diag::err_bad_cxx_cast_const_away; return TC_Failed; } - + if (CStyle && DestType->isObjCObjectPointerType()) { + Kind = CastExpr::CK_AnyPointerToObjCPointerCast; + return TC_Success; + } + // Not casting away constness, so the only remaining check is for compatible // pointer categories. Kind = CastExpr::CK_BitCast; @@ -1141,7 +1160,6 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, // Void pointers are not specified, but supported by every compiler out there. // So we finish by allowing everything that remains - it's got to be two // object pointers. - Kind = CastExpr::CK_BitCast; return TC_Success; } diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 34a5b78..039691f 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -313,7 +313,10 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) { LookupName(Found, S); assert(!Found.isAmbiguous() && "Cannot handle ambiguities here yet"); - NamedDecl *Result = Found.getAsSingleDecl(Context); + if (!Found.isSingleResult()) + return 0; + + NamedDecl *Result = Found.getFoundDecl(); if (isAcceptableNestedNameSpecifier(Result)) return Result; @@ -327,6 +330,12 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) { /// that it contains an extra parameter \p ScopeLookupResult, which provides /// the result of name lookup within the scope of the nested-name-specifier /// that was computed at template definitino time. +/// +/// If ErrorRecoveryLookup is true, then this call is used to improve error +/// recovery. This means that it should not emit diagnostics, it should +/// just return null on failure. It also means it should only return a valid +/// scope if it *knows* that the result is correct. It should not return in a +/// dependent context, for example. Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, SourceLocation IdLoc, @@ -334,7 +343,8 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, IdentifierInfo &II, QualType ObjectType, NamedDecl *ScopeLookupResult, - bool EnteringContext) { + bool EnteringContext, + bool ErrorRecoveryLookup) { NestedNameSpecifier *Prefix = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); @@ -400,6 +410,10 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, ObjectTypeSearchedInScope = true; } } else if (isDependent) { + // Don't speculate if we're just trying to improve error recovery. + if (ErrorRecoveryLookup) + return 0; + // We were not able to compute the declaration context for a dependent // base object type or prior nested-name-specifier, so this // nested-name-specifier refers to an unknown specialization. Just build @@ -414,7 +428,7 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, } // FIXME: Deal with ambiguities cleanly. - NamedDecl *SD = Found.getAsSingleDecl(Context); + NamedDecl *SD = Found.getAsSingle<NamedDecl>(); if (isAcceptableNestedNameSpecifier(SD)) { if (!ObjectType.isNull() && !ObjectTypeSearchedInScope) { // C++ [basic.lookup.classref]p4: @@ -429,7 +443,7 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, if (S) { LookupResult FoundOuter(*this, &II, IdLoc, LookupNestedNameSpecifierName); LookupName(FoundOuter, S); - OuterDecl = FoundOuter.getAsSingleDecl(Context); + OuterDecl = FoundOuter.getAsSingle<NamedDecl>(); } else OuterDecl = ScopeLookupResult; @@ -439,14 +453,17 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, !Context.hasSameType( Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)), Context.getTypeDeclType(cast<TypeDecl>(SD))))) { + if (ErrorRecoveryLookup) + return 0; + Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous) << &II; Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type) << ObjectType; Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope); - // Fall through so that we'll pick the name we found in the object type, - // since that's probably what the user wanted anyway. + // Fall through so that we'll pick the name we found in the object + // type, since that's probably what the user wanted anyway. } } @@ -466,17 +483,21 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, T.getTypePtr()); } + // Otherwise, we have an error case. If we don't want diagnostics, just + // return an error now. + if (ErrorRecoveryLookup) + return 0; + // If we didn't find anything during our lookup, try again with // ordinary name lookup, which can help us produce better error // messages. - if (!SD) { + if (Found.empty()) { Found.clear(LookupOrdinaryName); LookupName(Found, S); - SD = Found.getAsSingleDecl(Context); } unsigned DiagID; - if (SD) + if (!Found.empty()) DiagID = diag::err_expected_class_or_namespace; else if (SS.isSet()) { Diag(IdLoc, diag::err_no_member) << &II << LookupCtx << SS.getRange(); @@ -507,7 +528,23 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, bool EnteringContext) { return BuildCXXNestedNameSpecifier(S, SS, IdLoc, CCLoc, II, QualType::getFromOpaquePtr(ObjectTypePtr), - /*ScopeLookupResult=*/0, EnteringContext); + /*ScopeLookupResult=*/0, EnteringContext, + false); +} + +/// IsInvalidUnlessNestedName - This method is used for error recovery +/// purposes to determine whether the specified identifier is only valid as +/// a nested name specifier, for example a namespace name. It is +/// conservatively correct to always return false from this method. +/// +/// The arguments are the same as those passed to ActOnCXXNestedNameSpecifier. +bool Sema::IsInvalidUnlessNestedName(Scope *S, const CXXScopeSpec &SS, + IdentifierInfo &II, TypeTy *ObjectType, + bool EnteringContext) { + return BuildCXXNestedNameSpecifier(S, SS, SourceLocation(), SourceLocation(), + II, QualType::getFromOpaquePtr(ObjectType), + /*ScopeLookupResult=*/0, EnteringContext, + true); } Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, @@ -522,6 +559,44 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, T.getTypePtr()); } +bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { + assert(SS.isSet() && "Parser passed invalid CXXScopeSpec."); + + NestedNameSpecifier *Qualifier = + static_cast<NestedNameSpecifier*>(SS.getScopeRep()); + + // There are only two places a well-formed program may qualify a + // declarator: first, when defining a namespace or class member + // out-of-line, and second, when naming an explicitly-qualified + // friend function. The latter case is governed by + // C++03 [basic.lookup.unqual]p10: + // In a friend declaration naming a member function, a name used + // in the function declarator and not part of a template-argument + // in a template-id is first looked up in the scope of the member + // function's class. If it is not found, or if the name is part of + // a template-argument in a template-id, the look up is as + // described for unqualified names in the definition of the class + // granting friendship. + // i.e. we don't push a scope unless it's a class member. + + switch (Qualifier->getKind()) { + case NestedNameSpecifier::Global: + case NestedNameSpecifier::Namespace: + // These are always namespace scopes. We never want to enter a + // namespace scope from anything but a file context. + return CurContext->getLookupContext()->isFileContext(); + + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + // These are never namespace scopes. + return true; + } + + // Silence bogus warning. + return false; +} + /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global /// scope or nested-name-specifier) is parsed, part of a declarator-id. /// After this method is called, according to [C++ 3.4.3p3], names should be diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 9060fe6..28de500 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -700,30 +700,30 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) { if (Arg->isTypeDependent()) continue; - QualType RWType = Arg->getType(); - - const BuiltinType *BT = RWType->getAs<BuiltinType>(); - llvm::APSInt Result; - if (!BT || BT->getKind() != BuiltinType::Int) - return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_argument) + if (!Arg->getType()->isIntegralType()) + return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_arg_type) << Arg->getSourceRange(); + ImpCastExprToType(Arg, Context.IntTy, CastExpr::CK_IntegralCast); + TheCall->setArg(i, Arg); + if (Arg->isValueDependent()) continue; + llvm::APSInt Result; if (!Arg->isIntegerConstantExpr(Result, Context)) - return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_argument) + return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_arg_ice) << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); // FIXME: gcc issues a warning and rewrites these to 0. These // seems especially odd for the third argument since the default // is 3. if (i == 1) { - if (Result.getSExtValue() < 0 || Result.getSExtValue() > 1) + if (Result.getLimitedValue() > 1) return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range) << "0" << "1" << Arg->getSourceRange(); } else { - if (Result.getSExtValue() < 0 || Result.getSExtValue() > 3) + if (Result.getLimitedValue() > 3) return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range) << "0" << "3" << Arg->getSourceRange(); } diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index b386adb..4ce9330 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -45,11 +45,64 @@ namespace { /// the result set twice. llvm::SmallPtrSet<Decl*, 16> AllDeclsFound; + typedef std::pair<NamedDecl *, unsigned> DeclIndexPair; + + /// \brief An entry in the shadow map, which is optimized to store + /// a single (declaration, index) mapping (the common case) but + /// can also store a list of (declaration, index) mappings. + class ShadowMapEntry { + typedef llvm::SmallVector<DeclIndexPair, 4> DeclIndexPairVector; + + /// \brief Contains either the solitary NamedDecl * or a vector + /// of (declaration, index) pairs. + llvm::PointerUnion<NamedDecl *, DeclIndexPairVector*> DeclOrVector; + + /// \brief When the entry contains a single declaration, this is + /// the index associated with that entry. + unsigned SingleDeclIndex; + + public: + ShadowMapEntry() : DeclOrVector(), SingleDeclIndex(0) { } + + void Add(NamedDecl *ND, unsigned Index) { + if (DeclOrVector.isNull()) { + // 0 - > 1 elements: just set the single element information. + DeclOrVector = ND; + SingleDeclIndex = Index; + return; + } + + if (NamedDecl *PrevND = DeclOrVector.dyn_cast<NamedDecl *>()) { + // 1 -> 2 elements: create the vector of results and push in the + // existing declaration. + DeclIndexPairVector *Vec = new DeclIndexPairVector; + Vec->push_back(DeclIndexPair(PrevND, SingleDeclIndex)); + DeclOrVector = Vec; + } + + // Add the new element to the end of the vector. + DeclOrVector.get<DeclIndexPairVector*>()->push_back( + DeclIndexPair(ND, Index)); + } + + void Destroy() { + if (DeclIndexPairVector *Vec + = DeclOrVector.dyn_cast<DeclIndexPairVector *>()) { + delete Vec; + DeclOrVector = ((NamedDecl *)0); + } + } + + // Iteration. + class iterator; + iterator begin() const; + iterator end() const; + }; + /// \brief A mapping from declaration names to the declarations that have /// this name within a particular scope and their index within the list of /// results. - typedef std::multimap<DeclarationName, - std::pair<NamedDecl *, unsigned> > ShadowMap; + typedef llvm::DenseMap<DeclarationName, ShadowMapEntry> ShadowMap; /// \brief The semantic analysis object for which results are being /// produced. @@ -117,6 +170,95 @@ namespace { }; } +class ResultBuilder::ShadowMapEntry::iterator { + llvm::PointerUnion<NamedDecl*, const DeclIndexPair*> DeclOrIterator; + unsigned SingleDeclIndex; + +public: + typedef DeclIndexPair value_type; + typedef value_type reference; + typedef std::ptrdiff_t difference_type; + typedef std::input_iterator_tag iterator_category; + + class pointer { + DeclIndexPair Value; + + public: + pointer(const DeclIndexPair &Value) : Value(Value) { } + + const DeclIndexPair *operator->() const { + return &Value; + } + }; + + iterator() : DeclOrIterator((NamedDecl *)0), SingleDeclIndex(0) { } + + iterator(NamedDecl *SingleDecl, unsigned Index) + : DeclOrIterator(SingleDecl), SingleDeclIndex(Index) { } + + iterator(const DeclIndexPair *Iterator) + : DeclOrIterator(Iterator), SingleDeclIndex(0) { } + + iterator &operator++() { + if (DeclOrIterator.is<NamedDecl *>()) { + DeclOrIterator = (NamedDecl *)0; + SingleDeclIndex = 0; + return *this; + } + + const DeclIndexPair *I = DeclOrIterator.get<const DeclIndexPair*>(); + ++I; + DeclOrIterator = I; + return *this; + } + + iterator operator++(int) { + iterator tmp(*this); + ++(*this); + return tmp; + } + + reference operator*() const { + if (NamedDecl *ND = DeclOrIterator.dyn_cast<NamedDecl *>()) + return reference(ND, SingleDeclIndex); + + return *DeclOrIterator.get<const DeclIndexPair*>(); + } + + pointer operator->() const { + return pointer(**this); + } + + friend bool operator==(const iterator &X, const iterator &Y) { + return X.DeclOrIterator.getOpaqueValue() + == Y.DeclOrIterator.getOpaqueValue() && + X.SingleDeclIndex == Y.SingleDeclIndex; + } + + friend bool operator!=(const iterator &X, const iterator &Y) { + return !(X == Y); + } +}; + +ResultBuilder::ShadowMapEntry::iterator +ResultBuilder::ShadowMapEntry::begin() const { + if (DeclOrVector.isNull()) + return iterator(); + + if (NamedDecl *ND = DeclOrVector.dyn_cast<NamedDecl *>()) + return iterator(ND, SingleDeclIndex); + + return iterator(DeclOrVector.get<DeclIndexPairVector *>()->begin()); +} + +ResultBuilder::ShadowMapEntry::iterator +ResultBuilder::ShadowMapEntry::end() const { + if (DeclOrVector.is<NamedDecl *>() || DeclOrVector.isNull()) + return iterator(); + + return iterator(DeclOrVector.get<DeclIndexPairVector *>()->end()); +} + /// \brief Determines whether the given hidden result could be found with /// some extra work, e.g., by qualifying the name. /// @@ -214,7 +356,16 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { if (isa<FriendDecl>(CanonDecl) || (IDNS & (Decl::IDNS_OrdinaryFriend | Decl::IDNS_TagFriend))) return; + + // Class template (partial) specializations are never added as results. + if (isa<ClassTemplateSpecializationDecl>(CanonDecl) || + isa<ClassTemplatePartialSpecializationDecl>(CanonDecl)) + return; + // Using declarations themselves are never added as results. + if (isa<UsingDecl>(CanonDecl)) + return; + if (const IdentifierInfo *Id = R.Declaration->getIdentifier()) { // __va_list_tag is a freak of nature. Find it and skip it. if (Id->isStr("__va_list_tag") || Id->isStr("__builtin_va_list")) @@ -241,14 +392,18 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { return; ShadowMap &SMap = ShadowMaps.back(); - ShadowMap::iterator I, IEnd; - for (llvm::tie(I, IEnd) = SMap.equal_range(R.Declaration->getDeclName()); - I != IEnd; ++I) { - NamedDecl *ND = I->second.first; - unsigned Index = I->second.second; + ShadowMapEntry::iterator I, IEnd; + ShadowMap::iterator NamePos = SMap.find(R.Declaration->getDeclName()); + if (NamePos != SMap.end()) { + I = NamePos->second.begin(); + IEnd = NamePos->second.end(); + } + + for (; I != IEnd; ++I) { + NamedDecl *ND = I->first; + unsigned Index = I->second; if (ND->getCanonicalDecl() == CanonDecl) { // This is a redeclaration. Always pick the newer declaration. - I->second.first = R.Declaration; Results[Index].Declaration = R.Declaration; // Pick the best rank of the two. @@ -265,23 +420,28 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { std::list<ShadowMap>::iterator SM, SMEnd = ShadowMaps.end(); --SMEnd; for (SM = ShadowMaps.begin(); SM != SMEnd; ++SM) { - for (llvm::tie(I, IEnd) = SM->equal_range(R.Declaration->getDeclName()); - I != IEnd; ++I) { + ShadowMapEntry::iterator I, IEnd; + ShadowMap::iterator NamePos = SM->find(R.Declaration->getDeclName()); + if (NamePos != SM->end()) { + I = NamePos->second.begin(); + IEnd = NamePos->second.end(); + } + for (; I != IEnd; ++I) { // A tag declaration does not hide a non-tag declaration. - if (I->second.first->getIdentifierNamespace() == Decl::IDNS_Tag && + if (I->first->getIdentifierNamespace() == Decl::IDNS_Tag && (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | Decl::IDNS_ObjCProtocol))) continue; // Protocols are in distinct namespaces from everything else. - if (((I->second.first->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol) + if (((I->first->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol) || (IDNS & Decl::IDNS_ObjCProtocol)) && - I->second.first->getIdentifierNamespace() != IDNS) + I->first->getIdentifierNamespace() != IDNS) continue; // The newly-added result is hidden by an entry in the shadow map. if (canHiddenResultBeFound(SemaRef.getLangOptions(), R.Declaration, - I->second.first)) { + I->first)) { // Note that this result was hidden. R.Hidden = true; R.QualifierIsInformative = false; @@ -327,8 +487,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { // Insert this result into the set of results and into the current shadow // map. - SMap.insert(std::make_pair(R.Declaration->getDeclName(), - std::make_pair(R.Declaration, Results.size()))); + SMap[R.Declaration->getDeclName()].Add(R.Declaration, Results.size()); Results.push_back(R); } @@ -339,6 +498,12 @@ void ResultBuilder::EnterNewScope() { /// \brief Exit from the current scope. void ResultBuilder::ExitScope() { + for (ShadowMap::iterator E = ShadowMaps.back().begin(), + EEnd = ShadowMaps.back().end(); + E != EEnd; + ++E) + E->second.Destroy(); + ShadowMaps.pop_back(); } @@ -403,18 +568,20 @@ bool ResultBuilder::IsNamespaceOrAlias(NamedDecl *ND) const { return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND); } -/// \brief Brief determines whether the given declaration is a namespace or -/// namespace alias. +/// \brief Determines whether the given declaration is a type. bool ResultBuilder::IsType(NamedDecl *ND) const { return isa<TypeDecl>(ND); } -/// \brief Since every declaration found within a class is a member that we -/// care about, always returns true. This predicate exists mostly to -/// communicate to the result builder that we are performing a lookup for -/// member access. +/// \brief Determines which members of a class should be visible via +/// "." or "->". Only value declarations, nested name specifiers, and +/// using declarations thereof should show up. bool ResultBuilder::IsMember(NamedDecl *ND) const { - return true; + if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(ND)) + ND = Using->getTargetDecl(); + + return isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND) || + isa<ObjCPropertyDecl>(ND); } // Find the next outer declaration context corresponding to this scope. @@ -615,7 +782,7 @@ static unsigned CollectLookupResults(Scope *S, } /// \brief Add type specifiers for the current language as keyword results. -static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank, +static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank, ResultBuilder &Results) { typedef CodeCompleteConsumer::Result Result; Results.MaybeAddResult(Result("short", Rank)); @@ -773,10 +940,11 @@ static void AddTemplateParameterChunks(ASTContext &Context, /// \brief Add a qualifier to the given code-completion string, if the /// provided nested-name-specifier is non-NULL. -void AddQualifierToCompletionString(CodeCompletionString *Result, - NestedNameSpecifier *Qualifier, - bool QualifierIsInformative, - ASTContext &Context) { +static void +AddQualifierToCompletionString(CodeCompletionString *Result, + NestedNameSpecifier *Qualifier, + bool QualifierIsInformative, + ASTContext &Context) { if (!Qualifier) return; @@ -791,6 +959,23 @@ void AddQualifierToCompletionString(CodeCompletionString *Result, Result->AddTextChunk(PrintedNNS); } +static void AddFunctionTypeQualsToCompletionString(CodeCompletionString *Result, + FunctionDecl *Function) { + const FunctionProtoType *Proto + = Function->getType()->getAs<FunctionProtoType>(); + if (!Proto || !Proto->getTypeQuals()) + return; + + std::string QualsStr; + if (Proto->getTypeQuals() & Qualifiers::Const) + QualsStr += " const"; + if (Proto->getTypeQuals() & Qualifiers::Volatile) + QualsStr += " volatile"; + if (Proto->getTypeQuals() & Qualifiers::Restrict) + QualsStr += " restrict"; + Result->AddInformativeChunk(QualsStr); +} + /// \brief If possible, create a new code completion string for the given /// result. /// @@ -864,6 +1049,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); AddFunctionParameterChunks(S.Context, Function, Result); Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen)); + AddFunctionTypeQualsToCompletionString(Result, Function); return Result; } @@ -917,6 +1103,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { Result->AddChunk(Chunk(CodeCompletionString::CK_LeftParen)); AddFunctionParameterChunks(S.Context, Function, Result); Result->AddChunk(Chunk(CodeCompletionString::CK_RightParen)); + AddFunctionTypeQualsToCompletionString(Result, Function); return Result; } @@ -1064,13 +1251,54 @@ namespace { typedef CodeCompleteConsumer::Result Result; bool isEarlierDeclarationName(DeclarationName X, DeclarationName Y) const { - if (!X.getObjCSelector().isNull() && !Y.getObjCSelector().isNull()) { - // Consider all selector kinds to be equivalent. - } else if (X.getNameKind() != Y.getNameKind()) + Selector XSel = X.getObjCSelector(); + Selector YSel = Y.getObjCSelector(); + if (!XSel.isNull() && !YSel.isNull()) { + // We are comparing two selectors. + unsigned N = std::min(XSel.getNumArgs(), YSel.getNumArgs()); + if (N == 0) + ++N; + for (unsigned I = 0; I != N; ++I) { + IdentifierInfo *XId = XSel.getIdentifierInfoForSlot(I); + IdentifierInfo *YId = YSel.getIdentifierInfoForSlot(I); + if (!XId || !YId) + return XId && !YId; + + switch (XId->getName().compare_lower(YId->getName())) { + case -1: return true; + case 1: return false; + default: break; + } + } + + return XSel.getNumArgs() < YSel.getNumArgs(); + } + + // For non-selectors, order by kind. + if (X.getNameKind() != Y.getNameKind()) return X.getNameKind() < Y.getNameKind(); - return llvm::LowercaseString(X.getAsString()) - < llvm::LowercaseString(Y.getAsString()); + // Order identifiers by comparison of their lowercased names. + if (IdentifierInfo *XId = X.getAsIdentifierInfo()) + return XId->getName().compare_lower( + Y.getAsIdentifierInfo()->getName()) < 0; + + // Order overloaded operators by the order in which they appear + // in our list of operators. + if (OverloadedOperatorKind XOp = X.getCXXOverloadedOperator()) + return XOp < Y.getCXXOverloadedOperator(); + + // Order C++0x user-defined literal operators lexically by their + // lowercased suffixes. + if (IdentifierInfo *XLit = X.getCXXLiteralIdentifier()) + return XLit->getName().compare_lower( + Y.getCXXLiteralIdentifier()->getName()) < 0; + + // The only stable ordering we have is to turn the name into a + // string and then compare the lower-case strings. This is + // inefficient, but thankfully does not happen too often. + return llvm::StringRef(X.getAsString()).compare_lower( + Y.getAsString()) < 0; } bool operator()(const Result &X, const Result &Y) const { @@ -1088,7 +1316,7 @@ namespace { : X.Pattern->getTypedText(); const char *YStr = (Y.Kind == Result::RK_Keyword)? Y.Keyword : Y.Pattern->getTypedText(); - return strcmp(XStr, YStr) < 0; + return llvm::StringRef(XStr).compare_lower(YStr) < 0; } // Result kinds are ordered by decreasing importance. @@ -1113,12 +1341,11 @@ namespace { Y.Declaration->getDeclName()); case Result::RK_Macro: - return llvm::LowercaseString(X.Macro->getName()) < - llvm::LowercaseString(Y.Macro->getName()); + return X.Macro->getName().compare_lower(Y.Macro->getName()) < 0; case Result::RK_Keyword: case Result::RK_Pattern: - llvm::llvm_unreachable("Result kinds handled above"); + llvm_unreachable("Result kinds handled above"); break; } @@ -1153,9 +1380,23 @@ static void HandleCodeCompleteResults(Sema *S, } void Sema::CodeCompleteOrdinaryName(Scope *S) { + typedef CodeCompleteConsumer::Result Result; ResultBuilder Results(*this, &ResultBuilder::IsOrdinaryName); unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, Results); + + Results.EnterNewScope(); + AddTypeSpecifierResults(getLangOptions(), NextRank, Results); + + if (getLangOptions().ObjC1) { + // Add the "super" keyword, if appropriate. + if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(CurContext)) + if (Method->getClassInterface()->getSuperClass()) + Results.MaybeAddResult(Result("super", NextRank)); + } + + Results.ExitScope(); + if (CodeCompleter->includeMacros()) AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); @@ -1257,6 +1498,8 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, // We could have the start of a nested-name-specifier. Add those // results as well. + // FIXME: We should really walk base classes to produce + // nested-name-specifiers so that we produce more-precise results. Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank, CurContext, Results); @@ -1448,14 +1691,21 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, ExprTy **ArgsIn, unsigned NumArgs) { if (!CodeCompleter) return; - + + // When we're code-completing for a call, we fall back to ordinary + // name code-completion whenever we can't produce specific + // results. We may want to revisit this strategy in the future, + // e.g., by merging the two kinds of results. + Expr *Fn = (Expr *)FnIn; Expr **Args = (Expr **)ArgsIn; - + // Ignore type-dependent call expressions entirely. if (Fn->isTypeDependent() || - Expr::hasAnyTypeDependentArguments(Args, NumArgs)) + Expr::hasAnyTypeDependentArguments(Args, NumArgs)) { + CodeCompleteOrdinaryName(S); return; + } llvm::SmallVector<NamedDecl*,8> Fns; DeclarationName UnqualifiedName; @@ -1498,8 +1748,12 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, if (Cand->Viable) Results.push_back(ResultCandidate(Cand->Function)); } - CodeCompleter->ProcessOverloadCandidates(*this, NumArgs, Results.data(), - Results.size()); + + if (Results.empty()) + CodeCompleteOrdinaryName(S); + else + CodeCompleter->ProcessOverloadCandidates(*this, NumArgs, Results.data(), + Results.size()); } void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, @@ -1510,7 +1764,12 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, DeclContext *Ctx = computeDeclContext(SS, EnteringContext); if (!Ctx) return; - + + // Try to instantiate any non-dependent declaration contexts before + // we look in them. + if (!isDependentScopeSpecifier(SS) && RequireCompleteDeclContext(SS)) + return; + ResultBuilder Results(*this); unsigned NextRank = CollectMemberLookupResults(Ctx, 0, Ctx, Results); @@ -1644,6 +1903,183 @@ void Sema::CodeCompleteOperatorName(Scope *S) { HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } +void Sema::CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl, + bool InInterface) { + typedef CodeCompleteConsumer::Result Result; + ResultBuilder Results(*this); + Results.EnterNewScope(); + if (ObjCImpDecl) { + // Since we have an implementation, we can end it. + Results.MaybeAddResult(Result("end", 0)); + + CodeCompletionString *Pattern = 0; + Decl *ImpDecl = ObjCImpDecl.getAs<Decl>(); + if (isa<ObjCImplementationDecl>(ImpDecl) || + isa<ObjCCategoryImplDecl>(ImpDecl)) { + // @dynamic + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("dynamic"); + Pattern->AddTextChunk(" "); + Pattern->AddPlaceholderChunk("property"); + Results.MaybeAddResult(Result(Pattern, 0)); + + // @synthesize + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("synthesize"); + Pattern->AddTextChunk(" "); + Pattern->AddPlaceholderChunk("property"); + Results.MaybeAddResult(Result(Pattern, 0)); + } + } else if (InInterface) { + // Since we have an interface or protocol, we can end it. + Results.MaybeAddResult(Result("end", 0)); + + if (LangOpts.ObjC2) { + // @property + Results.MaybeAddResult(Result("property", 0)); + } + + // @required + Results.MaybeAddResult(Result("required", 0)); + + // @optional + Results.MaybeAddResult(Result("optional", 0)); + } else { + CodeCompletionString *Pattern = 0; + + // @class name ; + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("class"); + Pattern->AddTextChunk(" "); + Pattern->AddPlaceholderChunk("identifier"); + Pattern->AddTextChunk(";"); // add ';' chunk + Results.MaybeAddResult(Result(Pattern, 0)); + + // @interface name + // FIXME: Could introduce the whole pattern, including superclasses and + // such. + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("interface"); + Pattern->AddTextChunk(" "); + Pattern->AddPlaceholderChunk("class"); + Results.MaybeAddResult(Result(Pattern, 0)); + + // @protocol name + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("protocol"); + Pattern->AddTextChunk(" "); + Pattern->AddPlaceholderChunk("protocol"); + Results.MaybeAddResult(Result(Pattern, 0)); + + // @implementation name + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("implementation"); + Pattern->AddTextChunk(" "); + Pattern->AddPlaceholderChunk("class"); + Results.MaybeAddResult(Result(Pattern, 0)); + + // @compatibility_alias name + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("compatibility_alias"); + Pattern->AddTextChunk(" "); + Pattern->AddPlaceholderChunk("alias"); + Pattern->AddTextChunk(" "); + Pattern->AddPlaceholderChunk("class"); + Results.MaybeAddResult(Result(Pattern, 0)); + } + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + +static void AddObjCExpressionResults(unsigned Rank, ResultBuilder &Results) { + typedef CodeCompleteConsumer::Result Result; + CodeCompletionString *Pattern = 0; + + // @encode ( type-name ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("encode"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("type-name"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // @protocol ( protocol-name ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("protocol"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("protocol-name"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // @selector ( selector ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("selector"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("selector"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.MaybeAddResult(Result(Pattern, Rank)); +} + +void Sema::CodeCompleteObjCAtStatement(Scope *S) { + typedef CodeCompleteConsumer::Result Result; + ResultBuilder Results(*this); + Results.EnterNewScope(); + + CodeCompletionString *Pattern = 0; + + // @try { statements } @catch ( declaration ) { statements } @finally + // { statements } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("try"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Pattern->AddTextChunk("@catch"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("parameter"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Pattern->AddTextChunk("@finally"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.MaybeAddResult(Result(Pattern, 0)); + + // @throw + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("throw"); + Pattern->AddTextChunk(" "); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddTextChunk(";"); + Results.MaybeAddResult(Result(Pattern, 0)); // FIXME: add ';' chunk + + // @synchronized ( expression ) { statements } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("synchronized"); + Pattern->AddTextChunk(" "); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.MaybeAddResult(Result(Pattern, 0)); // FIXME: add ';' chunk + + AddObjCExpressionResults(0, Results); + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + +void Sema::CodeCompleteObjCAtExpression(Scope *S) { + ResultBuilder Results(*this); + Results.EnterNewScope(); + AddObjCExpressionResults(0, Results); + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + /// \brief Determine whether the addition of the given flag to an Objective-C /// property's attributes will cause a conflict. static bool ObjCPropertyFlagConflicts(unsigned Attributes, unsigned NewFlag) { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 520d7de..14d2377 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" #include "Lookup.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTConsumer.h" @@ -229,7 +230,7 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { LookupName(R, S, false); R.suppressDiagnostics(); if (R.getResultKind() == LookupResult::Found) - if (const TagDecl *TD = dyn_cast<TagDecl>(R.getAsSingleDecl(Context))) { + if (const TagDecl *TD = R.getAsSingle<TagDecl>()) { switch (TD->getTagKind()) { case TagDecl::TK_struct: return DeclSpec::TST_struct; case TagDecl::TK_union: return DeclSpec::TST_union; @@ -379,7 +380,9 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { // scope. if ((isa<FunctionTemplateDecl>(D) && cast<FunctionTemplateDecl>(D)->getTemplatedDecl()->isOutOfLine()) || - (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isOutOfLine()) || + (isa<FunctionDecl>(D) && + (cast<FunctionDecl>(D)->isFunctionTemplateSpecialization() || + cast<FunctionDecl>(D)->isOutOfLine())) || (isa<VarDecl>(D) && cast<VarDecl>(D)->isOutOfLine())) return; @@ -588,7 +591,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, FunctionDecl *New = FunctionDecl::Create(Context, Context.getTranslationUnitDecl(), - Loc, II, R, /*DInfo=*/0, + Loc, II, R, /*TInfo=*/0, FunctionDecl::Extern, false, /*hasPrototype=*/true); New->setImplicit(); @@ -599,7 +602,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, llvm::SmallVector<ParmVarDecl*, 16> Params; for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) Params.push_back(ParmVarDecl::Create(Context, New, SourceLocation(), 0, - FT->getArgType(i), /*DInfo=*/0, + FT->getArgType(i), /*TInfo=*/0, VarDecl::None, 0)); New->setParams(Context, Params.data(), Params.size()); } @@ -762,6 +765,24 @@ struct GNUCompatibleParamWarning { QualType PromotedType; }; + +/// getSpecialMember - get the special member enum for a method. +static Sema::CXXSpecialMember getSpecialMember(ASTContext &Ctx, + const CXXMethodDecl *MD) { + if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) { + if (Ctor->isDefaultConstructor()) + return Sema::CXXDefaultConstructor; + if (Ctor->isCopyConstructor(Ctx)) + return Sema::CXXCopyConstructor; + } + + if (isa<CXXDestructorDecl>(MD)) + return Sema::CXXDestructor; + + assert(MD->isCopyAssignment() && "Must have copy assignment operator"); + return Sema::CXXCopyAssignment; +} + /// MergeFunctionDecl - We just parsed a function 'New' from /// declarator D which has the same name and scope as a previous /// declaration 'Old'. Figure out how to resolve this situation, @@ -782,6 +803,15 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { else Old = dyn_cast<FunctionDecl>(OldD); if (!Old) { + if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(OldD)) { + Diag(New->getLocation(), diag::err_using_decl_conflict_reverse); + Diag(Shadow->getTargetDecl()->getLocation(), + diag::note_using_decl_target); + Diag(Shadow->getUsingDecl()->getLocation(), + diag::note_using_decl) << 0; + return true; + } + Diag(New->getLocation(), diag::err_redefinition_different_kind) << New->getDeclName(); Diag(OldD->getLocation(), diag::note_previous_definition); @@ -827,33 +857,45 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old); const CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New); - if (OldMethod && NewMethod && !NewMethod->getFriendObjectKind() && - NewMethod->getLexicalDeclContext()->isRecord()) { - // -- Member function declarations with the same name and the - // same parameter types cannot be overloaded if any of them - // is a static member function declaration. - if (OldMethod->isStatic() || NewMethod->isStatic()) { - Diag(New->getLocation(), diag::err_ovl_static_nonstatic_member); + if (OldMethod && NewMethod) { + if (!NewMethod->getFriendObjectKind() && + NewMethod->getLexicalDeclContext()->isRecord()) { + // -- Member function declarations with the same name and the + // same parameter types cannot be overloaded if any of them + // is a static member function declaration. + if (OldMethod->isStatic() || NewMethod->isStatic()) { + Diag(New->getLocation(), diag::err_ovl_static_nonstatic_member); + Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); + return true; + } + + // C++ [class.mem]p1: + // [...] A member shall not be declared twice in the + // member-specification, except that a nested class or member + // class template can be declared and then later defined. + unsigned NewDiag; + if (isa<CXXConstructorDecl>(OldMethod)) + NewDiag = diag::err_constructor_redeclared; + else if (isa<CXXDestructorDecl>(NewMethod)) + NewDiag = diag::err_destructor_redeclared; + else if (isa<CXXConversionDecl>(NewMethod)) + NewDiag = diag::err_conv_function_redeclared; + else + NewDiag = diag::err_member_redeclared; + + Diag(New->getLocation(), NewDiag); Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); - return true; + } else { + if (OldMethod->isImplicit()) { + Diag(NewMethod->getLocation(), + diag::err_definition_of_implicitly_declared_member) + << New << getSpecialMember(Context, OldMethod); + + Diag(OldMethod->getLocation(), + diag::note_previous_implicit_declaration); + return true; + } } - - // C++ [class.mem]p1: - // [...] A member shall not be declared twice in the - // member-specification, except that a nested class or member - // class template can be declared and then later defined. - unsigned NewDiag; - if (isa<CXXConstructorDecl>(OldMethod)) - NewDiag = diag::err_constructor_redeclared; - else if (isa<CXXDestructorDecl>(NewMethod)) - NewDiag = diag::err_destructor_redeclared; - else if (isa<CXXConversionDecl>(NewMethod)) - NewDiag = diag::err_conv_function_redeclared; - else - NewDiag = diag::err_member_redeclared; - - Diag(New->getLocation(), NewDiag); - Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); } // (C++98 8.3.5p3): @@ -894,7 +936,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { ParamType != ParamEnd; ++ParamType) { ParmVarDecl *Param = ParmVarDecl::Create(Context, New, SourceLocation(), 0, - *ParamType, /*DInfo=*/0, + *ParamType, /*TInfo=*/0, VarDecl::None, 0); Param->setImplicit(); Params.push_back(Param); @@ -1057,10 +1099,11 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { if (getLangOptions().CPlusPlus) { if (Context.hasSameType(New->getType(), Old->getType())) MergedT = New->getType(); - // C++ [basic.types]p7: - // [...] The declared type of an array object might be an array of - // unknown size and therefore be incomplete at one point in a - // translation unit and complete later on; [...] + // C++ [basic.link]p10: + // [...] the types specified by all declarations referring to a given + // object or function shall be identical, except that declarations for an + // array object can specify array types that differ by the presence or + // absence of a major array bound (8.3.4). else if (Old->getType()->isIncompleteArrayType() && New->getType()->isArrayType()) { CanQual<ArrayType> OldArray @@ -1069,6 +1112,14 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { = Context.getCanonicalType(New->getType())->getAs<ArrayType>(); if (OldArray->getElementType() == NewArray->getElementType()) MergedT = New->getType(); + } else if (Old->getType()->isArrayType() && + New->getType()->isIncompleteArrayType()) { + CanQual<ArrayType> OldArray + = Context.getCanonicalType(Old->getType())->getAs<ArrayType>(); + CanQual<ArrayType> NewArray + = Context.getCanonicalType(New->getType())->getAs<ArrayType>(); + if (OldArray->getElementType() == NewArray->getElementType()) + MergedT = Old->getType(); } } else { MergedT = Context.mergeTypes(New->getType(), Old->getType()); @@ -1202,6 +1253,11 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { HasFakeEdge = true; continue; } + if (isa<AsmStmt>(S)) { + HasFakeEdge = true; + HasLiveReturn = true; + continue; + } bool NoReturnEdge = false; if (CallExpr *C = dyn_cast<CallExpr>(S)) { Expr *CEE = C->getCallee()->IgnoreParenCasts(); @@ -1209,11 +1265,10 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { NoReturnEdge = true; HasFakeEdge = true; } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) { - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) { - if (FD->hasAttr<NoReturnAttr>()) { - NoReturnEdge = true; - HasFakeEdge = true; - } + ValueDecl *VD = DRE->getDecl(); + if (VD->hasAttr<NoReturnAttr>()) { + NoReturnEdge = true; + HasFakeEdge = true; } } } @@ -1648,9 +1703,9 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // Mock up a declarator. Declarator Dc(DS, Declarator::TypeNameContext); - DeclaratorInfo *DInfo = 0; - GetTypeForDeclarator(Dc, S, &DInfo); - assert(DInfo && "couldn't build declarator info for anonymous struct/union"); + TypeSourceInfo *TInfo = 0; + GetTypeForDeclarator(Dc, S, &TInfo); + assert(TInfo && "couldn't build declarator info for anonymous struct/union"); // Create a declaration for this anonymous struct/union. NamedDecl *Anon = 0; @@ -1658,7 +1713,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Anon = FieldDecl::Create(Context, OwningClass, Record->getLocation(), /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), - DInfo, + TInfo, /*BitWidth=*/0, /*Mutable=*/false); Anon->setAccess(AS_public); if (getLangOptions().CPlusPlus) @@ -1685,7 +1740,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Anon = VarDecl::Create(Context, Owner, Record->getLocation(), /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), - DInfo, + TInfo, SC); } Anon->setImplicit(); @@ -1765,13 +1820,8 @@ DeclarationName Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) { case UnqualifiedId::IK_TemplateId: { TemplateName TName - = TemplateName::getFromVoidPointer(Name.TemplateId->Template); - if (TemplateDecl *Template = TName.getAsTemplateDecl()) - return Template->getDeclName(); - if (OverloadedFunctionDecl *Ovl = TName.getAsOverloadedFunctionDecl()) - return Ovl->getDeclName(); - - return DeclarationName(); + = TemplateName::getFromVoidPointer(Name.TemplateId->Template); + return Context.getNameForTemplate(TName); } } @@ -1851,8 +1901,8 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, DeclContext *DC; NamedDecl *New; - DeclaratorInfo *DInfo = 0; - QualType R = GetTypeForDeclarator(D, S, &DInfo); + TypeSourceInfo *TInfo = 0; + QualType R = GetTypeForDeclarator(D, S, &TInfo); LookupResult Previous(*this, Name, D.getIdentifierLoc(), LookupOrdinaryName, ForRedeclaration); @@ -1982,13 +2032,13 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, return DeclPtrTy(); } - New = ActOnTypedefDeclarator(S, D, DC, R, DInfo, Previous, Redeclaration); + New = ActOnTypedefDeclarator(S, D, DC, R, TInfo, Previous, Redeclaration); } else if (R->isFunctionType()) { - New = ActOnFunctionDeclarator(S, D, DC, R, DInfo, Previous, + New = ActOnFunctionDeclarator(S, D, DC, R, TInfo, Previous, move(TemplateParamLists), IsFunctionDefinition, Redeclaration); } else { - New = ActOnVariableDeclarator(S, D, DC, R, DInfo, Previous, + New = ActOnVariableDeclarator(S, D, DC, R, TInfo, Previous, move(TemplateParamLists), Redeclaration); } @@ -1998,9 +2048,7 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, // If this has an identifier and is not an invalid redeclaration or // function template specialization, add it to the scope stack. - if (Name && !(Redeclaration && New->isInvalidDecl()) && - !(isa<FunctionDecl>(New) && - cast<FunctionDecl>(New)->isFunctionTemplateSpecialization())) + if (Name && !(Redeclaration && New->isInvalidDecl())) PushOnScopeChains(New, S); return DeclPtrTy::make(New); @@ -2104,7 +2152,7 @@ void Sema::DiagnoseFunctionSpecifiers(Declarator& D) { NamedDecl* Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, DeclaratorInfo *DInfo, + QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, bool &Redeclaration) { // Typedef declarators cannot be qualified (C++ [dcl.meaning]p1). if (D.getCXXScopeSpec().isSet()) { @@ -2125,7 +2173,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); - TypedefDecl *NewTD = ParseTypedefDecl(S, D, R, DInfo); + TypedefDecl *NewTD = ParseTypedefDecl(S, D, R, TInfo); if (!NewTD) return 0; // Handle attributes prior to checking for duplicates in MergeVarDecl @@ -2151,7 +2199,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative); if (!FixedTy.isNull()) { Diag(D.getIdentifierLoc(), diag::warn_illegal_constant_array_size); - NewTD->setTypeDeclaratorInfo(Context.getTrivialDeclaratorInfo(FixedTy)); + NewTD->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(FixedTy)); } else { if (SizeIsNegative) Diag(D.getIdentifierLoc(), diag::err_typecheck_negative_array_size); @@ -2244,7 +2292,7 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC, NamedDecl* Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, DeclaratorInfo *DInfo, + QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool &Redeclaration) { @@ -2302,7 +2350,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_static_out_of_line) << CodeModificationHint::CreateRemoval( - SourceRange(D.getDeclSpec().getStorageClassSpecLoc())); + D.getDeclSpec().getStorageClassSpecLoc()); } else if (SC == VarDecl::None) SC = VarDecl::Static; } @@ -2346,7 +2394,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, } NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), - II, R, DInfo, SC); + II, R, TInfo, SC); if (D.isInvalidType()) NewVD->setInvalidDecl(); @@ -2449,12 +2497,6 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, return NewVD->setInvalidDecl(); } - // The variable can not have an abstract class type. - if (RequireNonAbstractType(NewVD->getLocation(), T, - diag::err_abstract_type_in_decl, - AbstractVariableType)) - return NewVD->setInvalidDecl(); - // Emit an error if an address space was applied to decl with local storage. // This includes arrays of objects with address space qualifiers, but not // automatic variables that point to other address spaces. @@ -2596,7 +2638,7 @@ void Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { if (!CheckOverridingFunctionReturnType(MD, OldMD) && !CheckOverridingFunctionExceptionSpec(MD, OldMD) && !CheckOverridingFunctionAttributes(MD, OldMD)) - MD->addOverriddenMethod(OldMD); + MD->addOverriddenMethod(OldMD->getCanonicalDecl()); } } } @@ -2604,7 +2646,7 @@ void Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { NamedDecl* Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, DeclaratorInfo *DInfo, + QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool IsFunctionDefinition, bool &Redeclaration) { @@ -2686,7 +2728,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Create the new declaration NewFD = CXXConstructorDecl::Create(Context, cast<CXXRecordDecl>(DC), - D.getIdentifierLoc(), Name, R, DInfo, + D.getIdentifierLoc(), Name, R, TInfo, isExplicit, isInline, /*isImplicitlyDeclared=*/false); } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { @@ -2707,7 +2749,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Create a FunctionDecl to satisfy the function definition parsing // code path. NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(), - Name, R, DInfo, SC, isInline, + Name, R, TInfo, SC, isInline, /*hasPrototype=*/true); D.setInvalidType(); } @@ -2720,7 +2762,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, CheckConversionDeclarator(D, R, SC); NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC), - D.getIdentifierLoc(), Name, R, DInfo, + D.getIdentifierLoc(), Name, R, TInfo, isInline, isExplicit); isVirtualOkay = true; @@ -2754,7 +2796,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // This is a C++ method declaration. NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC), - D.getIdentifierLoc(), Name, R, DInfo, + D.getIdentifierLoc(), Name, R, TInfo, isStatic, isInline); isVirtualOkay = !isStatic; @@ -2772,7 +2814,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(), - Name, R, DInfo, SC, isInline, HasPrototype); + Name, R, TInfo, SC, isInline, HasPrototype); } if (D.isInvalidType()) @@ -2830,18 +2872,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // 'virtual' was specified outside of the class. Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_out_of_class) << CodeModificationHint::CreateRemoval( - SourceRange(D.getDeclSpec().getVirtualSpecLoc())); + D.getDeclSpec().getVirtualSpecLoc()); } else { // Okay: Add virtual to the method. - cast<CXXMethodDecl>(NewFD)->setVirtualAsWritten(true); CXXRecordDecl *CurClass = cast<CXXRecordDecl>(DC); - CurClass->setAggregate(false); - CurClass->setPOD(false); - CurClass->setEmpty(false); - CurClass->setPolymorphic(true); - CurClass->setHasTrivialConstructor(false); - CurClass->setHasTrivialCopyConstructor(false); - CurClass->setHasTrivialCopyAssignment(false); + CurClass->setMethodAsVirtual(NewFD); } } @@ -2865,9 +2900,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, NewFD->setAccess(AS_public); } - if (CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD)) - AddOverriddenMethods(cast<CXXRecordDecl>(DC), NewMD); - if (SC == FunctionDecl::Static && isa<CXXMethodDecl>(NewFD) && !CurContext->isRecord()) { // C++ [class.static]p1: @@ -2880,7 +2912,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_static_out_of_line) << CodeModificationHint::CreateRemoval( - SourceRange(D.getDeclSpec().getStorageClassSpecLoc())); + D.getDeclSpec().getStorageClassSpecLoc()); } // Handle GNU asm-label extension (encoded as an attribute). @@ -2937,7 +2969,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, AE = FT->arg_type_end(); AI != AE; ++AI) { ParmVarDecl *Param = ParmVarDecl::Create(Context, DC, SourceLocation(), 0, - *AI, /*DInfo=*/0, + *AI, /*TInfo=*/0, VarDecl::None, 0); Param->setImplicit(); Params.push_back(Param); @@ -2996,7 +3028,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Perform semantic checking on the function declaration. bool OverloadableAttrRequired = false; // FIXME: HACK! - CheckFunctionDeclaration(NewFD, Previous, isExplicitSpecialization, + CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization, Redeclaration, /*FIXME:*/OverloadableAttrRequired); assert((NewFD->isInvalidDecl() || !Redeclaration || @@ -3118,7 +3150,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, /// an explicit specialization of the previous declaration. /// /// This sets NewFD->isInvalidDecl() to true if there was an error. -void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, +void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, LookupResult &Previous, bool IsExplicitSpecialization, bool &Redeclaration, @@ -3156,34 +3188,47 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, // there's no more work to do here; we'll just add the new // function to the scope. - if (!getLangOptions().CPlusPlus && - AllowOverloadingOfFunction(Previous, Context)) { - OverloadableAttrRequired = true; - - // Functions marked "overloadable" must have a prototype (that - // we can't get through declaration merging). - if (!NewFD->getType()->getAs<FunctionProtoType>()) { - Diag(NewFD->getLocation(), diag::err_attribute_overloadable_no_prototype) - << NewFD; - Redeclaration = true; + NamedDecl *OldDecl = 0; + if (!AllowOverloadingOfFunction(Previous, Context)) { + Redeclaration = true; + OldDecl = Previous.getFoundDecl(); + } else { + if (!getLangOptions().CPlusPlus) { + OverloadableAttrRequired = true; + + // Functions marked "overloadable" must have a prototype (that + // we can't get through declaration merging). + if (!NewFD->getType()->getAs<FunctionProtoType>()) { + Diag(NewFD->getLocation(), + diag::err_attribute_overloadable_no_prototype) + << NewFD; + Redeclaration = true; - // Turn this into a variadic function with no parameters. - QualType R = Context.getFunctionType( - NewFD->getType()->getAs<FunctionType>()->getResultType(), - 0, 0, true, 0); - NewFD->setType(R); - return NewFD->setInvalidDecl(); + // Turn this into a variadic function with no parameters. + QualType R = Context.getFunctionType( + NewFD->getType()->getAs<FunctionType>()->getResultType(), + 0, 0, true, 0); + NewFD->setType(R); + return NewFD->setInvalidDecl(); + } } - } - NamedDecl *OldDecl = 0; - if (!Previous.empty()) { - if (!AllowOverloadingOfFunction(Previous, Context)) { + switch (CheckOverload(NewFD, Previous, OldDecl)) { + case Ovl_Match: Redeclaration = true; - OldDecl = Previous.getFoundDecl(); - } else if (!IsOverload(NewFD, Previous, OldDecl)) { - if (!isUsingDecl(OldDecl)) - Redeclaration = true; + if (isa<UsingShadowDecl>(OldDecl) && CurContext->isRecord()) { + HideUsingShadowDecl(S, cast<UsingShadowDecl>(OldDecl)); + Redeclaration = false; + } + break; + + case Ovl_NonFunction: + Redeclaration = true; + break; + + case Ovl_Overload: + Redeclaration = false; + break; } } @@ -3243,8 +3288,6 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, Diag(NewFD->getLocation(), diag::err_destructor_name); return NewFD->setInvalidDecl(); } - - CheckDestructor(Destructor); } Record->setUserDeclaredDestructor(true); @@ -3257,8 +3300,22 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, // FIXME: C++0x: don't do this for "= default" destructors Record->setHasTrivialDestructor(false); } else if (CXXConversionDecl *Conversion - = dyn_cast<CXXConversionDecl>(NewFD)) + = dyn_cast<CXXConversionDecl>(NewFD)) { ActOnConversionDeclarator(Conversion); + } + + // Find any virtual functions that this function overrides. + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD)) { + if (!Method->isFunctionTemplateSpecialization() && + !Method->getDescribedFunctionTemplate()) + AddOverriddenMethods(Method->getParent(), Method); + } + + // Additional checks for the destructor; make sure we do this after we + // figure out whether the destructor is virtual. + if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(NewFD)) + if (!Destructor->getParent()->isDependentType()) + CheckDestructor(Destructor); // Extra checking for C++ overloaded operators (C++ [over.oper]). if (NewFD->isOverloadedOperator() && @@ -3392,18 +3449,9 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { IntegerLiteral *IL; Expr *Init = static_cast<Expr *>(init.get()); if ((IL = dyn_cast<IntegerLiteral>(Init)) && IL->getValue() == 0 && - Context.getCanonicalType(IL->getType()) == Context.IntTy) { - if (Method->isVirtualAsWritten()) { - Method->setPure(); - - // A class is abstract if at least one function is pure virtual. - cast<CXXRecordDecl>(CurContext)->setAbstract(true); - } else if (!Method->isInvalidDecl()) { - Diag(Method->getLocation(), diag::err_non_virtual_pure) - << Method->getDeclName() << Init->getSourceRange(); - Method->setInvalidDecl(); - } - } else { + Context.getCanonicalType(IL->getType()) == Context.IntTy) + CheckPureMethod(Method, Init->getSourceRange()); + else { Diag(Method->getLocation(), diag::err_member_function_initialization) << Method->getDeclName() << Init->getSourceRange(); Method->setInvalidDecl(); @@ -3436,6 +3484,12 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { return; } + // The variable can not have an abstract class type. + if (RequireNonAbstractType(VDecl->getLocation(), VDecl->getType(), + diag::err_abstract_type_in_decl, + AbstractVariableType)) + VDecl->setInvalidDecl(); + const VarDecl *Def = 0; if (VDecl->getDefinition(Def)) { Diag(VDecl->getLocation(), diag::err_redefinition) @@ -3458,8 +3512,36 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { Diag(VDecl->getLocation(), diag::err_block_extern_cant_init); VDecl->setInvalidDecl(); } else if (!VDecl->isInvalidDecl()) { - if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(), - VDecl->getDeclName(), DirectInit)) + if (VDecl->getType()->isReferenceType() + || isa<InitListExpr>(Init)) { + InitializedEntity Entity + = InitializedEntity::InitializeVariable(VDecl); + + // FIXME: Poor source location information. + InitializationKind Kind + = DirectInit? InitializationKind::CreateDirect(VDecl->getLocation(), + SourceLocation(), + SourceLocation()) + : InitializationKind::CreateCopy(VDecl->getLocation(), + SourceLocation()); + InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1); + if (InitSeq) { + OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, (void**)&Init, 1), + &DclT); + if (Result.isInvalid()) { + VDecl->setInvalidDecl(); + return; + } + + Init = Result.takeAs<Expr>(); + } else { + InitSeq.Diagnose(*this, Entity, Kind, &Init, 1); + VDecl->setInvalidDecl(); + return; + } + } else if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(), + VDecl->getDeclName(), DirectInit)) VDecl->setInvalidDecl(); // C++ 3.6.2p2, allow dynamic initialization of static initializers. @@ -3649,7 +3731,7 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, SourceRange(Var->getLocation(), Var->getLocation()), Var->getDeclName(), - IK_Default, + InitializationKind::CreateDefault(Var->getLocation()), ConstructorArgs); // FIXME: Location info for the variable initialization? @@ -3668,6 +3750,12 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, Var->setInvalidDecl(); } } + + // The variable can not have an abstract class type. + if (RequireNonAbstractType(Var->getLocation(), Type, + diag::err_abstract_type_in_decl, + AbstractVariableType)) + Var->setInvalidDecl(); } #if 0 @@ -3817,9 +3905,9 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { if (getLangOptions().CPlusPlus) CheckExtraCXXDefaultArguments(D); - DeclaratorInfo *DInfo = 0; + TypeSourceInfo *TInfo = 0; TagDecl *OwnedDecl = 0; - QualType parmDeclType = GetTypeForDeclarator(D, S, &DInfo, &OwnedDecl); + QualType parmDeclType = GetTypeForDeclarator(D, S, &TInfo, &OwnedDecl); if (getLangOptions().CPlusPlus && OwnedDecl && OwnedDecl->isDefinition()) { // C++ [dcl.fct]p6: @@ -3862,7 +3950,7 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { ParmVarDecl *New = ParmVarDecl::Create(Context, CurContext, D.getIdentifierLoc(), II, - T, DInfo, StorageClass, 0); + T, TInfo, StorageClass, 0); if (D.isInvalidType()) New->setInvalidDecl(); @@ -3960,6 +4048,50 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, return ActOnStartOfFunctionDef(FnBodyScope, DP); } +static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD) { + // Don't warn about invalid declarations. + if (FD->isInvalidDecl()) + return false; + + // Or declarations that aren't global. + if (!FD->isGlobal()) + return false; + + // Don't warn about C++ member functions. + if (isa<CXXMethodDecl>(FD)) + return false; + + // Don't warn about 'main'. + if (FD->isMain()) + return false; + + // Don't warn about inline functions. + if (FD->isInlineSpecified()) + return false; + + // Don't warn about function templates. + if (FD->getDescribedFunctionTemplate()) + return false; + + // Don't warn about function template specializations. + if (FD->isFunctionTemplateSpecialization()) + return false; + + bool MissingPrototype = true; + for (const FunctionDecl *Prev = FD->getPreviousDeclaration(); + Prev; Prev = Prev->getPreviousDeclaration()) { + // Ignore any declarations that occur in function or method + // scope, because they aren't visible from the header. + if (Prev->getDeclContext()->isFunctionOrMethod()) + continue; + + MissingPrototype = !Prev->getType()->isFunctionProtoType(); + break; + } + + return MissingPrototype; +} + Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { // Clear the last template instantiation error context. LastTemplateInstantiationErrorContext = ActiveTemplateInstantiation(); @@ -4005,23 +4137,8 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { // prototype declaration. This warning is issued even if the // definition itself provides a prototype. The aim is to detect // global functions that fail to be declared in header files. - if (!FD->isInvalidDecl() && FD->isGlobal() && !isa<CXXMethodDecl>(FD) && - !FD->isMain()) { - bool MissingPrototype = true; - for (const FunctionDecl *Prev = FD->getPreviousDeclaration(); - Prev; Prev = Prev->getPreviousDeclaration()) { - // Ignore any declarations that occur in function or method - // scope, because they aren't visible from the header. - if (Prev->getDeclContext()->isFunctionOrMethod()) - continue; - - MissingPrototype = !Prev->getType()->isFunctionProtoType(); - break; - } - - if (MissingPrototype) - Diag(FD->getLocation(), diag::warn_missing_prototype) << FD; - } + if (ShouldWarnAboutMissingPrototype(FD)) + Diag(FD->getLocation(), diag::warn_missing_prototype) << FD; if (FnBodyScope) PushDeclContext(FnBodyScope, FD); @@ -4090,11 +4207,8 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, if (!FD->isInvalidDecl()) DiagnoseUnusedParameters(FD->param_begin(), FD->param_end()); - // C++ [basic.def.odr]p2: - // [...] A virtual member function is used if it is not pure. [...] if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD)) - if (Method->isVirtual() && !Method->isPure()) - MarkDeclarationReferenced(Method->getLocation(), Method); + MaybeMarkVirtualMembersReferenced(Method->getLocation(), Method); assert(FD == getCurFunctionDecl() && "Function parsing confused"); } else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) { @@ -4301,20 +4415,20 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { } TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, - DeclaratorInfo *DInfo) { + TypeSourceInfo *TInfo) { assert(D.getIdentifier() && "Wrong callback for declspec without declarator"); assert(!T.isNull() && "GetTypeForDeclarator() returned null type"); - if (!DInfo) { + if (!TInfo) { assert(D.isInvalidType() && "no declarator info for valid type"); - DInfo = Context.getTrivialDeclaratorInfo(T); + TInfo = Context.getTrivialTypeSourceInfo(T); } // Scope manipulation handled by caller. TypedefDecl *NewTD = TypedefDecl::Create(Context, CurContext, D.getIdentifierLoc(), D.getIdentifier(), - DInfo); + TInfo); if (const TagType *TT = T->getAs<TagType>()) { TagDecl *TD = TT->getDecl(); @@ -4621,8 +4735,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, Previous.clear(); } } - } else if (TUK == TUK_Reference && SS.isEmpty() && Name && - (Kind != TagDecl::TK_enum || !getLangOptions().CPlusPlus)) { + } else if (TUK == TUK_Reference && SS.isEmpty() && Name) { // C++ [basic.scope.pdecl]p5: // -- for an elaborated-type-specifier of the form // @@ -4640,6 +4753,11 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // C99 6.7.2.3p8 has a similar (but not identical!) provision for // C structs and unions. // + // It is an error in C++ to declare (rather than define) an enum + // type, including via an elaborated type specifier. We'll + // diagnose that later; for now, declare the enum in the same + // scope as we would have picked for any other tag type. + // // GNU C also supports this behavior as part of its incomplete // enum types extension, while GNU C++ does not. // @@ -4739,10 +4857,7 @@ CreateNewDecl: LookupResult Lookup(*this, Name, NameLoc, LookupOrdinaryName, ForRedeclaration); LookupName(Lookup, S); - TypedefDecl *PrevTypedef = 0; - if (NamedDecl *Prev = Lookup.getAsSingleDecl(Context)) - PrevTypedef = dyn_cast<TypedefDecl>(Prev); - + TypedefDecl *PrevTypedef = Lookup.getAsSingle<TypedefDecl>(); NamedDecl *PrevTypedefNamed = PrevTypedef; if (PrevTypedef && isDeclInScope(PrevTypedefNamed, SearchDC, S) && Context.getCanonicalType(Context.getTypeDeclType(PrevTypedef)) != @@ -4947,8 +5062,8 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, SourceLocation Loc = DeclStart; if (II) Loc = D.getIdentifierLoc(); - DeclaratorInfo *DInfo = 0; - QualType T = GetTypeForDeclarator(D, S, &DInfo); + TypeSourceInfo *TInfo = 0; + QualType T = GetTypeForDeclarator(D, S, &TInfo); if (getLangOptions().CPlusPlus) CheckExtraCXXDefaultArguments(D); @@ -4974,7 +5089,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, = (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable); SourceLocation TSSL = D.getSourceRange().getBegin(); FieldDecl *NewFD - = CheckFieldDecl(II, T, DInfo, Record, Loc, Mutable, BitWidth, TSSL, + = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, TSSL, AS, PrevDecl, &D); if (NewFD->isInvalidDecl() && PrevDecl) { // Don't introduce NewFD into scope; there's already something @@ -4998,7 +5113,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, /// /// \todo The Declarator argument is a hack. It will be removed once FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, - DeclaratorInfo *DInfo, + TypeSourceInfo *TInfo, RecordDecl *Record, SourceLocation Loc, bool Mutable, Expr *BitWidth, SourceLocation TSSL, @@ -5015,9 +5130,14 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, T = Context.IntTy; } + QualType EltTy = Context.getBaseElementType(T); + if (!EltTy->isDependentType() && + RequireCompleteType(Loc, EltTy, diag::err_field_incomplete)) + InvalidDecl = true; + // C99 6.7.2.1p8: A member of a structure or union may have any type other // than a variably modified type. - if (T->isVariablyModifiedType()) { + if (!InvalidDecl && T->isVariablyModifiedType()) { bool SizeIsNegative; QualType FixedTy = TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative); @@ -5034,20 +5154,22 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, } // Fields can not have abstract class types - if (RequireNonAbstractType(Loc, T, diag::err_abstract_type_in_decl, - AbstractFieldType)) + if (!InvalidDecl && RequireNonAbstractType(Loc, T, + diag::err_abstract_type_in_decl, + AbstractFieldType)) InvalidDecl = true; bool ZeroWidth = false; // If this is declared as a bit-field, check the bit-field. - if (BitWidth && VerifyBitField(Loc, II, T, BitWidth, &ZeroWidth)) { + if (!InvalidDecl && BitWidth && + VerifyBitField(Loc, II, T, BitWidth, &ZeroWidth)) { InvalidDecl = true; DeleteExpr(BitWidth); BitWidth = 0; ZeroWidth = false; } - FieldDecl *NewFD = FieldDecl::Create(Context, Record, Loc, II, T, DInfo, + FieldDecl *NewFD = FieldDecl::Create(Context, Record, Loc, II, T, TInfo, BitWidth, Mutable); if (InvalidDecl) NewFD->setInvalidDecl(); @@ -5059,8 +5181,6 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, } if (getLangOptions().CPlusPlus) { - QualType EltTy = Context.getBaseElementType(T); - CXXRecordDecl* CXXRecord = cast<CXXRecordDecl>(Record); if (!T->isPODType()) @@ -5296,8 +5416,8 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, // FIXME: Unnamed fields can be handled in various different ways, for // example, unnamed unions inject all members into the struct namespace! - DeclaratorInfo *DInfo = 0; - QualType T = GetTypeForDeclarator(D, S, &DInfo); + TypeSourceInfo *TInfo = 0; + QualType T = GetTypeForDeclarator(D, S, &TInfo); if (BitWidth) { // 6.7.2.1p3, 6.7.2.1p4 @@ -5340,7 +5460,7 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, // Construct the decl. ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context, EnclosingContext, Loc, II, T, - DInfo, ac, (Expr *)BitfieldWidth); + TInfo, ac, (Expr *)BitfieldWidth); if (II) { NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName, @@ -5403,8 +5523,10 @@ void Sema::ActOnFields(Scope* S, // If the field is already invalid for some reason, don't emit more // diagnostics about it. - if (FD->isInvalidDecl()) + if (FD->isInvalidDecl()) { + EnclosingDecl->setInvalidDecl(); continue; + } // C99 6.7.2.1p2: // A structure or union shall not contain a member with @@ -5540,7 +5662,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, llvm::APSInt EnumVal(32); QualType EltTy; if (Val) { - if (Val->isTypeDependent()) + if (Enum->isDependentType()) EltTy = Context.DependentTy; else { // Make sure to promote the operand type to int. @@ -5552,8 +5674,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // C99 6.7.2.2p2: Make sure we have an integer constant expression. SourceLocation ExpLoc; - if (!Val->isValueDependent() && - VerifyIntegerConstantExpression(Val, &EnumVal)) { + if (VerifyIntegerConstantExpression(Val, &EnumVal)) { Val = 0; } else { EltTy = Val->getType(); @@ -5562,7 +5683,9 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, } if (!Val) { - if (LastEnumConst) { + if (Enum->isDependentType()) + EltTy = Context.DependentTy; + else if (LastEnumConst) { // Assign the last value + 1. EnumVal = LastEnumConst->getInitVal(); ++EnumVal; @@ -5576,6 +5699,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // First value, set to zero. EltTy = Context.IntTy; EnumVal.zextOrTrunc(static_cast<uint32_t>(Context.getTypeSize(EltTy))); + EnumVal.setIsSigned(true); } } @@ -5647,6 +5771,19 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, if (Attr) ProcessDeclAttributeList(S, Enum, Attr); + if (Enum->isDependentType()) { + for (unsigned i = 0; i != NumElements; ++i) { + EnumConstantDecl *ECD = + cast_or_null<EnumConstantDecl>(Elements[i].getAs<Decl>()); + if (!ECD) continue; + + ECD->setType(EnumType); + } + + Enum->completeDefinition(Context, Context.DependentTy, Context.DependentTy); + return; + } + // TODO: If the result value doesn't fit in an int, it must be a long or long // long value. ISO C does not support this, but GCC does as an extension, // emit a warning. @@ -5698,6 +5835,17 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, QualType BestType; unsigned BestWidth; + // C++0x N3000 [conv.prom]p3: + // An rvalue of an unscoped enumeration type whose underlying + // type is not fixed can be converted to an rvalue of the first + // of the following types that can represent all the values of + // the enumeration: int, unsigned int, long int, unsigned long + // int, long long int, or unsigned long long int. + // C99 6.4.4.3p2: + // An identifier declared as an enumeration constant has type int. + // The C99 rule is modified by a gcc extension + QualType BestPromotionType; + bool Packed = Enum->getAttr<PackedAttr>() ? true : false; if (NumNegativeBits) { @@ -5705,22 +5853,21 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, // int/long/longlong) that fits. // If it's packed, check also if it fits a char or a short. if (Packed && NumNegativeBits <= CharWidth && NumPositiveBits < CharWidth) { - BestType = Context.SignedCharTy; - BestWidth = CharWidth; + BestType = Context.SignedCharTy; + BestWidth = CharWidth; } else if (Packed && NumNegativeBits <= ShortWidth && NumPositiveBits < ShortWidth) { - BestType = Context.ShortTy; - BestWidth = ShortWidth; - } - else if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) { + BestType = Context.ShortTy; + BestWidth = ShortWidth; + } else if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) { BestType = Context.IntTy; BestWidth = IntWidth; } else { BestWidth = Context.Target.getLongWidth(); - if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth) + if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth) { BestType = Context.LongTy; - else { + } else { BestWidth = Context.Target.getLongLongWidth(); if (NumNegativeBits > BestWidth || NumPositiveBits >= BestWidth) @@ -5728,31 +5875,46 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, BestType = Context.LongLongTy; } } + BestPromotionType = (BestWidth <= IntWidth ? Context.IntTy : BestType); } else { // If there is no negative value, figure out which of uint, ulong, ulonglong // fits. // If it's packed, check also if it fits a char or a short. if (Packed && NumPositiveBits <= CharWidth) { - BestType = Context.UnsignedCharTy; - BestWidth = CharWidth; + BestType = Context.UnsignedCharTy; + BestPromotionType = Context.IntTy; + BestWidth = CharWidth; } else if (Packed && NumPositiveBits <= ShortWidth) { - BestType = Context.UnsignedShortTy; - BestWidth = ShortWidth; - } - else if (NumPositiveBits <= IntWidth) { + BestType = Context.UnsignedShortTy; + BestPromotionType = Context.IntTy; + BestWidth = ShortWidth; + } else if (NumPositiveBits <= IntWidth) { BestType = Context.UnsignedIntTy; BestWidth = IntWidth; + BestPromotionType = (NumPositiveBits == BestWidth + ? Context.UnsignedIntTy : Context.IntTy); } else if (NumPositiveBits <= (BestWidth = Context.Target.getLongWidth())) { BestType = Context.UnsignedLongTy; + BestPromotionType = (NumPositiveBits == BestWidth + ? Context.UnsignedLongTy : Context.LongTy); } else { BestWidth = Context.Target.getLongLongWidth(); assert(NumPositiveBits <= BestWidth && "How could an initializer get larger than ULL?"); BestType = Context.UnsignedLongLongTy; + BestPromotionType = (NumPositiveBits == BestWidth + ? Context.UnsignedLongLongTy : Context.LongLongTy); } } + // If we're in C and the promotion type is larger than an int, just + // use the underlying type, which is generally the unsigned integer + // type of the same rank as the promotion type. This is how the gcc + // extension works. + if (!getLangOptions().CPlusPlus && BestPromotionType != Context.IntTy) + BestPromotionType = BestType; + // Loop over all of the enumerator constants, changing their types to match // the type of the enum if needed. for (unsigned i = 0; i != NumElements; ++i) { @@ -5765,19 +5927,8 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, // enumerator value fits in an int, type it as an int, otherwise type it the // same as the enumerator decl itself. This means that in "enum { X = 1U }" // that X has type 'int', not 'unsigned'. - if (ECD->getType() == Context.IntTy) { - // Make sure the init value is signed. - llvm::APSInt IV = ECD->getInitVal(); - IV.setIsSigned(true); - ECD->setInitVal(IV); - - if (getLangOptions().CPlusPlus) - // C++ [dcl.enum]p4: Following the closing brace of an - // enum-specifier, each enumerator has the type of its - // enumeration. - ECD->setType(EnumType); - continue; // Already int type. - } + if (!getLangOptions().CPlusPlus && ECD->getType() == Context.IntTy) + continue; // Determine whether the value fits into an int. llvm::APSInt InitVal = ECD->getInitVal(); @@ -5792,7 +5943,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, QualType NewTy; unsigned NewWidth; bool NewSign; - if (FitsInInt) { + if (FitsInInt && !getLangOptions().CPlusPlus) { NewTy = Context.IntTy; NewWidth = IntWidth; NewSign = true; @@ -5830,7 +5981,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, ECD->setType(NewTy); } - Enum->completeDefinition(Context, BestType); + Enum->completeDefinition(Context, BestType, BestPromotionType); } Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc, diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index b2124fe..84ee207 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -195,98 +195,13 @@ static void HandleExtVectorTypeAttr(Scope *scope, Decl *d, QualType T = S.BuildExtVectorType(curType, S.Owned(sizeExpr), Attr.getLoc()); if (!T.isNull()) { // FIXME: preserve the old source info. - tDecl->setTypeDeclaratorInfo(S.Context.getTrivialDeclaratorInfo(T)); + tDecl->setTypeSourceInfo(S.Context.getTrivialTypeSourceInfo(T)); // Remember this typedef decl, we will need it later for diagnostics. S.ExtVectorDecls.push_back(tDecl); } } - -/// HandleVectorSizeAttribute - this attribute is only applicable to integral -/// and float scalars, although arrays, pointers, and function return values are -/// allowed in conjunction with this construct. Aggregates with this attribute -/// are invalid, even if they are of the same size as a corresponding scalar. -/// The raw attribute should contain precisely 1 argument, the vector size for -/// the variable, measured in bytes. If curType and rawAttr are well formed, -/// this routine will return a new vector type. -static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) { - QualType CurType; - if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) - CurType = VD->getType(); - else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) - CurType = TD->getUnderlyingType(); - else { - S.Diag(D->getLocation(), diag::err_attr_wrong_decl) - << "vector_size" << SourceRange(Attr.getLoc(), Attr.getLoc()); - return; - } - - // Check the attribute arugments. - if (Attr.getNumArgs() != 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; - return; - } - Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0)); - llvm::APSInt vecSize(32); - if (!sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) - << "vector_size" << sizeExpr->getSourceRange(); - return; - } - // navigate to the base type - we need to provide for vector pointers, vector - // arrays, and functions returning vectors. - if (CurType->isPointerType() || CurType->isArrayType() || - CurType->isFunctionType()) { - S.Diag(Attr.getLoc(), diag::err_unsupported_vector_size) << CurType; - return; - /* FIXME: rebuild the type from the inside out, vectorizing the inner type. - do { - if (PointerType *PT = dyn_cast<PointerType>(canonType)) - canonType = PT->getPointeeType().getTypePtr(); - else if (ArrayType *AT = dyn_cast<ArrayType>(canonType)) - canonType = AT->getElementType().getTypePtr(); - else if (FunctionType *FT = dyn_cast<FunctionType>(canonType)) - canonType = FT->getResultType().getTypePtr(); - } while (canonType->isPointerType() || canonType->isArrayType() || - canonType->isFunctionType()); - */ - } - // the base type must be integer or float, and can't already be a vector. - if (CurType->isVectorType() || - (!CurType->isIntegerType() && !CurType->isRealFloatingType())) { - S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << CurType; - return; - } - unsigned typeSize = static_cast<unsigned>(S.Context.getTypeSize(CurType)); - // vecSize is specified in bytes - convert to bits. - unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue() * 8); - - // the vector size needs to be an integral multiple of the type size. - if (vectorSize % typeSize) { - S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size) - << sizeExpr->getSourceRange(); - return; - } - if (vectorSize == 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_zero_size) - << sizeExpr->getSourceRange(); - return; - } - - // Success! Instantiate the vector type, the number of elements is > 0, and - // not required to be a power of 2, unlike GCC. - CurType = S.Context.getVectorType(CurType, vectorSize/typeSize); - - if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) - VD->setType(CurType); - else { - // FIXME: preserve existing source info. - DeclaratorInfo *DInfo = S.Context.getTrivialDeclaratorInfo(CurType); - cast<TypedefDecl>(D)->setTypeDeclaratorInfo(DInfo); - } -} - static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() > 0) { @@ -461,7 +376,8 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr, if (!isFunctionOrMethod(d) && !isa<BlockDecl>(d)) { ValueDecl *VD = dyn_cast<ValueDecl>(d); - if (VD == 0 || !VD->getType()->isBlockPointerType()) { + if (VD == 0 || (!VD->getType()->isBlockPointerType() + && !VD->getType()->isFunctionPointerType())) { S.Diag(Attr.getLoc(), Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type : diag::warn_attribute_wrong_decl_type) @@ -1143,10 +1059,6 @@ static void HandlePureAttr(Decl *d, const AttributeList &Attr, Sema &S) { } static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) { - // Match gcc which ignores cleanup attrs when compiling C++. - if (S.getLangOptions().CPlusPlus) - return; - if (!Attr.getParameterName()) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; @@ -1709,7 +1621,7 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) { // Install the new type. if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { // FIXME: preserve existing source info. - TD->setTypeDeclaratorInfo(S.Context.getTrivialDeclaratorInfo(NewTy)); + TD->setTypeSourceInfo(S.Context.getTrivialTypeSourceInfo(NewTy)); } else cast<ValueDecl>(D)->setType(NewTy); } @@ -1964,6 +1876,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_IBOutlet: HandleIBOutletAttr (D, Attr, S); break; case AttributeList::AT_address_space: case AttributeList::AT_objc_gc: + case AttributeList::AT_vector_size: // Ignore these, these are type attributes, handled by // ProcessTypeAttributes. break; @@ -2013,7 +1926,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_unavailable: HandleUnavailableAttr (D, Attr, S); break; case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break; case AttributeList::AT_used: HandleUsedAttr (D, Attr, S); break; - case AttributeList::AT_vector_size: HandleVectorSizeAttr (D, Attr, S); break; case AttributeList::AT_visibility: HandleVisibilityAttr (D, Attr, S); break; case AttributeList::AT_warn_unused_result: HandleWarnUnusedResult(D,Attr,S); break; @@ -2062,11 +1974,11 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) { if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { NewD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(), FD->getLocation(), DeclarationName(II), - FD->getType(), FD->getDeclaratorInfo()); + FD->getType(), FD->getTypeSourceInfo()); } else if (VarDecl *VD = dyn_cast<VarDecl>(ND)) { NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(), VD->getLocation(), II, - VD->getType(), VD->getDeclaratorInfo(), + VD->getType(), VD->getTypeSourceInfo(), VD->getStorageClass()); } return NewD; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index f161cb5..228a716 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -12,11 +12,14 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" #include "Lookup.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/RecordLayout.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclVisitor.h" +#include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" #include "clang/AST/StmtVisitor.h" #include "clang/Parse/DeclSpec.h" @@ -482,24 +485,47 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, assert(BaseDecl && "Base type is not incomplete, but has no definition"); CXXRecordDecl * CXXBaseDecl = cast<CXXRecordDecl>(BaseDecl); assert(CXXBaseDecl && "Base type is not a C++ type"); - if (!CXXBaseDecl->isEmpty()) - Class->setEmpty(false); - if (CXXBaseDecl->isPolymorphic()) - Class->setPolymorphic(true); + // C++0x CWG Issue #817 indicates that [[final]] classes shouldn't be bases. if (CXXBaseDecl->hasAttr<FinalAttr>()) { Diag(BaseLoc, diag::err_final_base) << BaseType.getAsString(); - Diag(CXXBaseDecl->getLocation(), diag::note_previous_class_decl) - << BaseType.getAsString(); + Diag(CXXBaseDecl->getLocation(), diag::note_previous_decl) + << BaseType; return 0; } + SetClassDeclAttributesFromBase(Class, CXXBaseDecl, Virtual); + + // Create the base specifier. + // FIXME: Allocate via ASTContext? + return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual, + Class->getTagKind() == RecordDecl::TK_class, + Access, BaseType); +} + +void Sema::SetClassDeclAttributesFromBase(CXXRecordDecl *Class, + const CXXRecordDecl *BaseClass, + bool BaseIsVirtual) { + // A class with a non-empty base class is not empty. + // FIXME: Standard ref? + if (!BaseClass->isEmpty()) + Class->setEmpty(false); + + // C++ [class.virtual]p1: + // A class that [...] inherits a virtual function is called a polymorphic + // class. + if (BaseClass->isPolymorphic()) + Class->setPolymorphic(true); + // C++ [dcl.init.aggr]p1: // An aggregate is [...] a class with [...] no base classes [...]. Class->setAggregate(false); + + // C++ [class]p4: + // A POD-struct is an aggregate class... Class->setPOD(false); - if (Virtual) { + if (BaseIsVirtual) { // C++ [class.ctor]p5: // A constructor is trivial if its class has no virtual base classes. Class->setHasTrivialConstructor(false); @@ -521,33 +547,27 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, // C++ [class.ctor]p5: // A constructor is trivial if all the direct base classes of its // class have trivial constructors. - if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialConstructor()) + if (!BaseClass->hasTrivialConstructor()) Class->setHasTrivialConstructor(false); // C++ [class.copy]p6: // A copy constructor is trivial if all the direct base classes of its // class have trivial copy constructors. - if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialCopyConstructor()) + if (!BaseClass->hasTrivialCopyConstructor()) Class->setHasTrivialCopyConstructor(false); // C++ [class.copy]p11: // A copy assignment operator is trivial if all the direct base classes // of its class have trivial copy assignment operators. - if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialCopyAssignment()) + if (!BaseClass->hasTrivialCopyAssignment()) Class->setHasTrivialCopyAssignment(false); } // C++ [class.ctor]p3: // A destructor is trivial if all the direct base classes of its class // have trivial destructors. - if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialDestructor()) + if (!BaseClass->hasTrivialDestructor()) Class->setHasTrivialDestructor(false); - - // Create the base specifier. - // FIXME: Allocate via ASTContext? - return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual, - Class->getTagKind() == RecordDecl::TK_class, - Access, BaseType); } /// ActOnBaseSpecifier - Parsed a base specifier. A base specifier is @@ -976,19 +996,26 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, if (Member) return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc, - RParenLoc); + LParenLoc, RParenLoc); } // It didn't name a member, so see if it names a class. - TypeTy *BaseTy = TemplateTypeTy ? TemplateTypeTy - : getTypeName(*MemberOrBase, IdLoc, S, &SS); - if (!BaseTy) + QualType BaseType; + + TypeSourceInfo *TInfo = 0; + if (TemplateTypeTy) + BaseType = GetTypeFromParser(TemplateTypeTy, &TInfo); + else + BaseType = QualType::getFromOpaquePtr(getTypeName(*MemberOrBase, IdLoc, + S, &SS)); + if (BaseType.isNull()) return Diag(IdLoc, diag::err_mem_init_not_member_or_class) << MemberOrBase << SourceRange(IdLoc, RParenLoc); - QualType BaseType = GetTypeFromParser(BaseTy); + if (!TInfo) + TInfo = Context.getTrivialTypeSourceInfo(BaseType, IdLoc); - return BuildBaseInitializer(BaseType, (Expr **)Args, NumArgs, IdLoc, - RParenLoc, ClassDecl); + return BuildBaseInitializer(BaseType, TInfo, (Expr **)Args, NumArgs, + LParenLoc, RParenLoc, ClassDecl); } /// Checks an initializer expression for use of uninitialized fields, such as @@ -1037,6 +1064,7 @@ static bool InitExprContainsUninitializedFields(const Stmt* S, Sema::MemInitResult Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs, SourceLocation IdLoc, + SourceLocation LParenLoc, SourceLocation RParenLoc) { // FIXME: CXXBaseOrMemberInitializer should only contain a single // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. @@ -1081,7 +1109,8 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, NumArgs), IdLoc, SourceRange(IdLoc, RParenLoc), - Member->getDeclName(), IK_Direct, + Member->getDeclName(), + InitializationKind::CreateDirect(IdLoc, LParenLoc, RParenLoc), ConstructorArgs); if (C) { @@ -1118,22 +1147,25 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, ExprTemporaries.clear(); // FIXME: Perform direct initialization of the member. - return new (Context) CXXBaseOrMemberInitializer(Member, (Expr **)Args, - NumArgs, C, IdLoc, RParenLoc); + return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc, + C, LParenLoc, (Expr **)Args, + NumArgs, RParenLoc); } Sema::MemInitResult -Sema::BuildBaseInitializer(QualType BaseType, Expr **Args, - unsigned NumArgs, SourceLocation IdLoc, - SourceLocation RParenLoc, CXXRecordDecl *ClassDecl) { +Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, + Expr **Args, unsigned NumArgs, + SourceLocation LParenLoc, SourceLocation RParenLoc, + CXXRecordDecl *ClassDecl) { bool HasDependentArg = false; for (unsigned i = 0; i < NumArgs; i++) HasDependentArg |= Args[i]->isTypeDependent(); + SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getSourceRange().getBegin(); if (!BaseType->isDependentType()) { if (!BaseType->isRecordType()) - return Diag(IdLoc, diag::err_base_init_does_not_name_class) - << BaseType << SourceRange(IdLoc, RParenLoc); + return Diag(BaseLoc, diag::err_base_init_does_not_name_class) + << BaseType << BaseTInfo->getTypeLoc().getSourceRange(); // C++ [class.base.init]p2: // [...] Unless the mem-initializer-id names a nonstatic data @@ -1179,16 +1211,16 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args, // a direct non-virtual base class and an inherited virtual base // class, the mem-initializer is ill-formed. if (DirectBaseSpec && VirtualBaseSpec) - return Diag(IdLoc, diag::err_base_init_direct_and_virtual) - << BaseType << SourceRange(IdLoc, RParenLoc); + return Diag(BaseLoc, diag::err_base_init_direct_and_virtual) + << BaseType << BaseTInfo->getTypeLoc().getSourceRange(); // C++ [base.class.init]p2: // Unless the mem-initializer-id names a nonstatic data membeer of the // constructor's class ot a direst or virtual base of that class, the // mem-initializer is ill-formed. if (!DirectBaseSpec && !VirtualBaseSpec) - return Diag(IdLoc, diag::err_not_direct_base_or_virtual) - << BaseType << ClassDecl->getNameAsCString() - << SourceRange(IdLoc, RParenLoc); + return Diag(BaseLoc, diag::err_not_direct_base_or_virtual) + << BaseType << ClassDecl->getNameAsCString() + << BaseTInfo->getTypeLoc().getSourceRange(); } CXXConstructorDecl *C = 0; @@ -1200,8 +1232,10 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args, C = PerformInitializationByConstructor(BaseType, MultiExprArg(*this, (void**)Args, NumArgs), - IdLoc, SourceRange(IdLoc, RParenLoc), - Name, IK_Direct, + BaseLoc, + SourceRange(BaseLoc, RParenLoc), + Name, + InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc), ConstructorArgs); if (C) { // Take over the constructor arguments as our own. @@ -1214,8 +1248,9 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args, // subexpression so we can wrap it in a CXXExprWithTemporaries if necessary. ExprTemporaries.clear(); - return new (Context) CXXBaseOrMemberInitializer(BaseType, (Expr **)Args, - NumArgs, C, IdLoc, RParenLoc); + return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, C, + LParenLoc, (Expr **)Args, + NumArgs, RParenLoc); } bool @@ -1277,14 +1312,14 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, } else { CXXRecordDecl *VBaseDecl = - cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl()); + cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl()); assert(VBaseDecl && "SetBaseOrMemberInitializers - VBaseDecl null"); CXXConstructorDecl *Ctor = VBaseDecl->getDefaultConstructor(Context); if (!Ctor) { Diag(Constructor->getLocation(), diag::err_missing_default_ctor) << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl) << 0 << VBase->getType(); - Diag(VBaseDecl->getLocation(), diag::note_previous_class_decl) + Diag(VBaseDecl->getLocation(), diag::note_previous_decl) << Context.getTagDeclType(VBaseDecl); HadError = true; continue; @@ -1298,13 +1333,18 @@ 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. + // subexpression so we can wrap it in a CXXExprWithTemporaries if + // necessary. + // FIXME: Is there any better source-location information we can give? ExprTemporaries.clear(); CXXBaseOrMemberInitializer *Member = - new (Context) CXXBaseOrMemberInitializer(VBase->getType(), - CtorArgs.takeAs<Expr>(), - CtorArgs.size(), Ctor, + new (Context) CXXBaseOrMemberInitializer(Context, + Context.getTrivialTypeSourceInfo(VBase->getType(), + SourceLocation()), + Ctor, SourceLocation(), + CtorArgs.takeAs<Expr>(), + CtorArgs.size(), SourceLocation()); AllToInit.push_back(Member); } @@ -1332,7 +1372,7 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, Diag(Constructor->getLocation(), diag::err_missing_default_ctor) << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl) << 0 << Base->getType(); - Diag(BaseDecl->getLocation(), diag::note_previous_class_decl) + Diag(BaseDecl->getLocation(), diag::note_previous_decl) << Context.getTagDeclType(BaseDecl); HadError = true; continue; @@ -1346,13 +1386,18 @@ 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. + // subexpression so we can wrap it in a CXXExprWithTemporaries if + // necessary. + // FIXME: Is there any better source-location information we can give? ExprTemporaries.clear(); CXXBaseOrMemberInitializer *Member = - new (Context) CXXBaseOrMemberInitializer(Base->getType(), - CtorArgs.takeAs<Expr>(), - CtorArgs.size(), Ctor, + new (Context) CXXBaseOrMemberInitializer(Context, + Context.getTrivialTypeSourceInfo(Base->getType(), + SourceLocation()), + Ctor, SourceLocation(), + CtorArgs.takeAs<Expr>(), + CtorArgs.size(), SourceLocation()); AllToInit.push_back(Member); } @@ -1399,7 +1444,7 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getDeclName(); Diag(Field->getLocation(), diag::note_field_decl); - Diag(RT->getDecl()->getLocation(), diag::note_previous_class_decl) + Diag(RT->getDecl()->getLocation(), diag::note_previous_decl) << Context.getTagDeclType(RT->getDecl()); HadError = true; continue; @@ -1427,9 +1472,12 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, // 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, + new (Context) CXXBaseOrMemberInitializer(Context, + *Field, SourceLocation(), + Ctor, SourceLocation(), + CtorArgs.takeAs<Expr>(), + CtorArgs.size(), SourceLocation()); AllToInit.push_back(Member); @@ -1537,13 +1585,15 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, if (FieldDecl *Field = Member->getMember()) Diag(Member->getSourceLocation(), diag::error_multiple_mem_initialization) - << Field->getNameAsString(); + << Field->getNameAsString() + << Member->getSourceRange(); else { Type *BaseClass = Member->getBaseClass(); assert(BaseClass && "ActOnMemInitializers - neither field or base"); Diag(Member->getSourceLocation(), diag::error_multiple_base_initialization) - << QualType(BaseClass, 0); + << QualType(BaseClass, 0) + << Member->getSourceRange(); } Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer) << 0; @@ -1920,6 +1970,28 @@ namespace { }; } +/// \brief Perform semantic checks on a class definition that has been +/// completing, introducing implicitly-declared members, checking for +/// abstract types, etc. +void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { + if (!Record || Record->isInvalidDecl()) + return; + + if (!Record->isAbstract()) { + // Collect all the pure virtual methods and see if this is an abstract + // class after all. + PureVirtualMethodCollector Collector(Context, Record); + if (!Collector.empty()) + Record->setAbstract(true); + } + + if (Record->isAbstract()) + (void)AbstractClassUsageDiagnoser(*this, Record); + + if (!Record->isDependentType() && !Record->isInvalidDecl()) + AddImplicitlyDeclaredMembersToClass(Record); +} + void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, DeclPtrTy TagDecl, SourceLocation LBrac, @@ -1928,24 +2000,13 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, return; AdjustDeclIfTemplate(TagDecl); + ActOnFields(S, RLoc, TagDecl, (DeclPtrTy*)FieldCollector->getCurFields(), FieldCollector->getCurNumFields(), LBrac, RBrac, 0); - CXXRecordDecl *RD = cast<CXXRecordDecl>(TagDecl.getAs<Decl>()); - if (!RD->isAbstract()) { - // Collect all the pure virtual methods and see if this is an abstract - // class after all. - PureVirtualMethodCollector Collector(Context, RD); - if (!Collector.empty()) - RD->setAbstract(true); - } - - if (RD->isAbstract()) - (void)AbstractClassUsageDiagnoser(*this, RD); - - if (!RD->isDependentType() && !RD->isInvalidDecl()) - AddImplicitlyDeclaredMembersToClass(RD); + CheckCompletedCXXClass( + dyn_cast_or_null<CXXRecordDecl>(TagDecl.getAs<Decl>())); } /// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared @@ -1974,7 +2035,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { ClassDecl->getLocation(), Name, Context.getFunctionType(Context.VoidTy, 0, 0, false, 0), - /*DInfo=*/0, + /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true); @@ -2046,7 +2107,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { Context.getFunctionType(Context.VoidTy, &ArgType, 1, false, 0), - /*DInfo=*/0, + /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true); @@ -2058,7 +2119,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor, ClassDecl->getLocation(), /*IdentifierInfo=*/0, - ArgType, /*DInfo=*/0, + ArgType, /*TInfo=*/0, VarDecl::None, 0); CopyConstructor->setParams(Context, &FromParam, 1); ClassDecl->addDecl(CopyConstructor); @@ -2132,7 +2193,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { CXXMethodDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name, Context.getFunctionType(RetType, &ArgType, 1, false, 0), - /*DInfo=*/0, /*isStatic=*/false, /*isInline=*/true); + /*TInfo=*/0, /*isStatic=*/false, /*isInline=*/true); CopyAssignment->setAccess(AS_public); CopyAssignment->setImplicit(); CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment()); @@ -2142,13 +2203,14 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment, ClassDecl->getLocation(), /*IdentifierInfo=*/0, - ArgType, /*DInfo=*/0, + ArgType, /*TInfo=*/0, VarDecl::None, 0); CopyAssignment->setParams(Context, &FromParam, 1); // Don't call addedAssignmentOperator. There is no way to distinguish an // implicit from an explicit assignment operator. ClassDecl->addDecl(CopyAssignment); + AddOverriddenMethods(ClassDecl, CopyAssignment); } if (!ClassDecl->hasUserDeclaredDestructor()) { @@ -2814,6 +2876,7 @@ void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) { Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS, + bool HasUsingKeyword, SourceLocation UsingLoc, const CXXScopeSpec &SS, UnqualifiedId &Name, @@ -2830,6 +2893,9 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, break; case UnqualifiedId::IK_ConstructorName: + // C++0x inherited constructors. + if (getLangOptions().CPlusPlus0x) break; + Diag(Name.getSourceRange().getBegin(), diag::err_using_decl_constructor) << SS.getRange(); return DeclPtrTy(); @@ -2846,45 +2912,237 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, } DeclarationName TargetName = GetNameFromUnqualifiedId(Name); + if (!TargetName) + return DeclPtrTy(); + + // Warn about using declarations. + // TODO: store that the declaration was written without 'using' and + // talk about access decls instead of using decls in the + // diagnostics. + if (!HasUsingKeyword) { + UsingLoc = Name.getSourceRange().getBegin(); + + Diag(UsingLoc, diag::warn_access_decl_deprecated) + << CodeModificationHint::CreateInsertion(SS.getRange().getBegin(), + "using "); + } + NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS, Name.getSourceRange().getBegin(), TargetName, AttrList, /* IsInstantiation */ false, IsTypeName, TypenameLoc); - if (UD) { - PushOnScopeChains(UD, S); - UD->setAccess(AS); - } + if (UD) + PushOnScopeChains(UD, S, /*AddToContext*/ false); return DeclPtrTy::make(UD); } +/// Determines whether to create a using shadow decl for a particular +/// decl, given the set of decls existing prior to this using lookup. +bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, + const LookupResult &Previous) { + // Diagnose finding a decl which is not from a base class of the + // current class. We do this now because there are cases where this + // function will silently decide not to build a shadow decl, which + // will pre-empt further diagnostics. + // + // We don't need to do this in C++0x because we do the check once on + // the qualifier. + // + // FIXME: diagnose the following if we care enough: + // struct A { int foo; }; + // struct B : A { using A::foo; }; + // template <class T> struct C : A {}; + // template <class T> struct D : C<T> { using B::foo; } // <--- + // This is invalid (during instantiation) in C++03 because B::foo + // resolves to the using decl in B, which is not a base class of D<T>. + // We can't diagnose it immediately because C<T> is an unknown + // specialization. The UsingShadowDecl in D<T> then points directly + // to A::foo, which will look well-formed when we instantiate. + // The right solution is to not collapse the shadow-decl chain. + if (!getLangOptions().CPlusPlus0x && CurContext->isRecord()) { + DeclContext *OrigDC = Orig->getDeclContext(); + + // Handle enums and anonymous structs. + if (isa<EnumDecl>(OrigDC)) OrigDC = OrigDC->getParent(); + CXXRecordDecl *OrigRec = cast<CXXRecordDecl>(OrigDC); + while (OrigRec->isAnonymousStructOrUnion()) + OrigRec = cast<CXXRecordDecl>(OrigRec->getDeclContext()); + + if (cast<CXXRecordDecl>(CurContext)->isProvablyNotDerivedFrom(OrigRec)) { + if (OrigDC == CurContext) { + Diag(Using->getLocation(), + diag::err_using_decl_nested_name_specifier_is_current_class) + << Using->getNestedNameRange(); + Diag(Orig->getLocation(), diag::note_using_decl_target); + return true; + } + + Diag(Using->getNestedNameRange().getBegin(), + diag::err_using_decl_nested_name_specifier_is_not_base_class) + << Using->getTargetNestedNameDecl() + << cast<CXXRecordDecl>(CurContext) + << Using->getNestedNameRange(); + Diag(Orig->getLocation(), diag::note_using_decl_target); + return true; + } + } + + if (Previous.empty()) return false; + + NamedDecl *Target = Orig; + if (isa<UsingShadowDecl>(Target)) + Target = cast<UsingShadowDecl>(Target)->getTargetDecl(); + + // If the target happens to be one of the previous declarations, we + // don't have a conflict. + // + // FIXME: but we might be increasing its access, in which case we + // should redeclare it. + NamedDecl *NonTag = 0, *Tag = 0; + for (LookupResult::iterator I = Previous.begin(), E = Previous.end(); + I != E; ++I) { + NamedDecl *D = (*I)->getUnderlyingDecl(); + if (D->getCanonicalDecl() == Target->getCanonicalDecl()) + return false; + + (isa<TagDecl>(D) ? Tag : NonTag) = D; + } + + if (Target->isFunctionOrFunctionTemplate()) { + FunctionDecl *FD; + if (isa<FunctionTemplateDecl>(Target)) + FD = cast<FunctionTemplateDecl>(Target)->getTemplatedDecl(); + else + FD = cast<FunctionDecl>(Target); + + NamedDecl *OldDecl = 0; + switch (CheckOverload(FD, Previous, OldDecl)) { + case Ovl_Overload: + return false; + + case Ovl_NonFunction: + Diag(Using->getLocation(), diag::err_using_decl_conflict); + break; + + // We found a decl with the exact signature. + case Ovl_Match: + if (isa<UsingShadowDecl>(OldDecl)) { + // Silently ignore the possible conflict. + return false; + } + + // If we're in a record, we want to hide the target, so we + // return true (without a diagnostic) to tell the caller not to + // build a shadow decl. + if (CurContext->isRecord()) + return true; + + // If we're not in a record, this is an error. + Diag(Using->getLocation(), diag::err_using_decl_conflict); + break; + } + + Diag(Target->getLocation(), diag::note_using_decl_target); + Diag(OldDecl->getLocation(), diag::note_using_decl_conflict); + return true; + } + + // Target is not a function. + + if (isa<TagDecl>(Target)) { + // No conflict between a tag and a non-tag. + if (!Tag) return false; + + Diag(Using->getLocation(), diag::err_using_decl_conflict); + Diag(Target->getLocation(), diag::note_using_decl_target); + Diag(Tag->getLocation(), diag::note_using_decl_conflict); + return true; + } + + // No conflict between a tag and a non-tag. + if (!NonTag) return false; + + Diag(Using->getLocation(), diag::err_using_decl_conflict); + Diag(Target->getLocation(), diag::note_using_decl_target); + Diag(NonTag->getLocation(), diag::note_using_decl_conflict); + return true; +} + /// 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 +UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S, + UsingDecl *UD, + NamedDecl *Orig) { // 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"); + NamedDecl *Target = Orig; + if (isa<UsingShadowDecl>(Target)) { + Target = cast<UsingShadowDecl>(Target)->getTargetDecl(); + assert(!isa<UsingShadowDecl>(Target) && "nested shadow declaration"); } UsingShadowDecl *Shadow - = UsingShadowDecl::Create(SemaRef.Context, SemaRef.CurContext, - UD->getLocation(), UD, Orig); + = UsingShadowDecl::Create(Context, CurContext, + UD->getLocation(), UD, Target); UD->addShadowDecl(Shadow); if (S) - SemaRef.PushOnScopeChains(Shadow, S); + PushOnScopeChains(Shadow, S); else - SemaRef.CurContext->addDecl(Shadow); - Shadow->setAccess(AS); + CurContext->addDecl(Shadow); + Shadow->setAccess(UD->getAccess()); + + if (Orig->isInvalidDecl() || UD->isInvalidDecl()) + Shadow->setInvalidDecl(); return Shadow; } +/// Hides a using shadow declaration. This is required by the current +/// using-decl implementation when a resolvable using declaration in a +/// class is followed by a declaration which would hide or override +/// one or more of the using decl's targets; for example: +/// +/// struct Base { void foo(int); }; +/// struct Derived : Base { +/// using Base::foo; +/// void foo(int); +/// }; +/// +/// The governing language is C++03 [namespace.udecl]p12: +/// +/// When a using-declaration brings names from a base class into a +/// derived class scope, member functions in the derived class +/// override and/or hide member functions with the same name and +/// parameter types in a base class (rather than conflicting). +/// +/// There are two ways to implement this: +/// (1) optimistically create shadow decls when they're not hidden +/// by existing declarations, or +/// (2) don't create any shadow decls (or at least don't make them +/// visible) until we've fully parsed/instantiated the class. +/// The problem with (1) is that we might have to retroactively remove +/// a shadow decl, which requires several O(n) operations because the +/// decl structures are (very reasonably) not designed for removal. +/// (2) avoids this but is very fiddly and phase-dependent. +void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) { + // Remove it from the DeclContext... + Shadow->getDeclContext()->removeDecl(Shadow); + + // ...and the scope, if applicable... + if (S) { + S->RemoveDecl(DeclPtrTy::make(static_cast<Decl*>(Shadow))); + IdResolver.RemoveDecl(Shadow); + } + + // ...and the using decl. + Shadow->getUsingDecl()->removeShadowDecl(Shadow); + + // TODO: complain somehow if Shadow was used. It shouldn't + // be possible for this to happen, because +} + /// Builds a using declaration. /// /// \param IsInstantiation - Whether this call arises from an @@ -2910,56 +3168,76 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, return 0; } + // Do the redeclaration lookup in the current scope. + LookupResult Previous(*this, Name, IdentLoc, LookupUsingDeclName, + ForRedeclaration); + Previous.setHideTags(false); + if (S) { + LookupName(Previous, S); + + // It is really dumb that we have to do this. + LookupResult::Filter F = Previous.makeFilter(); + while (F.hasNext()) { + NamedDecl *D = F.next(); + if (!isDeclInScope(D, CurContext, S)) + F.erase(); + } + F.done(); + } else { + assert(IsInstantiation && "no scope in non-instantiation"); + assert(CurContext->isRecord() && "scope not record in instantiation"); + LookupQualifiedName(Previous, CurContext); + } + NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + // Check for invalid redeclarations. + if (CheckUsingDeclRedeclaration(UsingLoc, IsTypeName, SS, IdentLoc, Previous)) + return 0; + + // Check for bad qualifiers. + if (CheckUsingDeclQualifier(UsingLoc, SS, IdentLoc)) + return 0; + DeclContext *LookupContext = computeDeclContext(SS); + NamedDecl *D; 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, + // FIXME: not all declaration name kinds are legal here + D = UnresolvedUsingTypenameDecl::Create(Context, CurContext, + UsingLoc, TypenameLoc, + SS.getRange(), NNS, IdentLoc, Name); + } else { + D = UnresolvedUsingValueDecl::Create(Context, CurContext, + UsingLoc, SS.getRange(), NNS, + IdentLoc, Name); } + } else { + D = UsingDecl::Create(Context, CurContext, IdentLoc, + SS.getRange(), UsingLoc, NNS, Name, + IsTypeName); } + D->setAccess(AS); + CurContext->addDecl(D); - 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 - // of a base class of the class being defined, shall refer to a member of an - // 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. - - 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; - } - } else { - // C++0x N2914 [namespace.udecl]p8: - // A using-declaration for a class member shall be a member-declaration. - if (isa<CXXRecordDecl>(LookupContext)) { - Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_class_member) - << SS.getRange(); - return 0; - } + if (!LookupContext) return D; + UsingDecl *UD = cast<UsingDecl>(D); + + if (RequireCompleteDeclContext(SS)) { + UD->setInvalidDecl(); + return UD; } - // 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. + // Look up the target name. + LookupResult R(*this, Name, IdentLoc, 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. + // Unlike most lookups, we don't always want to hide tag + // declarations: tag names are visible through the using declaration + // even if hidden by ordinary names, *except* in a dependent context + // where it's important for the sanity of two-phase lookup. if (!IsInstantiation) R.setHideTags(false); @@ -2968,54 +3246,243 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, if (R.empty()) { Diag(IdentLoc, diag::err_no_member) << Name << LookupContext << SS.getRange(); - return 0; + UD->setInvalidDecl(); + return UD; } - if (R.isAmbiguous()) - return 0; + if (R.isAmbiguous()) { + UD->setInvalidDecl(); + return UD; + } 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())) { + if (!R.getAsSingle<TypeDecl>()) { 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; + UD->setInvalidDecl(); + return UD; } } 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())) { + if (IsInstantiation && R.getAsSingle<TypeDecl>()) { Diag(IdentLoc, diag::err_using_dependent_value_is_type); Diag(R.getFoundDecl()->getLocation(), diag::note_using_decl_target); - return 0; + UD->setInvalidDecl(); + return UD; } } // C++0x N2914 [namespace.udecl]p6: // A using-declaration shall not name a namespace. - if (R.getResultKind() == LookupResult::Found - && isa<NamespaceDecl>(R.getFoundDecl())) { + if (R.getAsSingle<NamespaceDecl>()) { Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_namespace) << SS.getRange(); - return 0; + UD->setInvalidDecl(); + return UD; } - 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); + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { + if (!CheckUsingShadowDecl(UD, *I, Previous)) + BuildUsingShadowDecl(S, UD, *I); + } return UD; } +/// Checks that the given using declaration is not an invalid +/// redeclaration. Note that this is checking only for the using decl +/// itself, not for any ill-formedness among the UsingShadowDecls. +bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, + bool isTypeName, + const CXXScopeSpec &SS, + SourceLocation NameLoc, + const LookupResult &Prev) { + // C++03 [namespace.udecl]p8: + // C++0x [namespace.udecl]p10: + // A using-declaration is a declaration and can therefore be used + // repeatedly where (and only where) multiple declarations are + // allowed. + // That's only in file contexts. + if (CurContext->getLookupContext()->isFileContext()) + return false; + + NestedNameSpecifier *Qual + = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); + + for (LookupResult::iterator I = Prev.begin(), E = Prev.end(); I != E; ++I) { + NamedDecl *D = *I; + + bool DTypename; + NestedNameSpecifier *DQual; + if (UsingDecl *UD = dyn_cast<UsingDecl>(D)) { + DTypename = UD->isTypeName(); + DQual = UD->getTargetNestedNameDecl(); + } else if (UnresolvedUsingValueDecl *UD + = dyn_cast<UnresolvedUsingValueDecl>(D)) { + DTypename = false; + DQual = UD->getTargetNestedNameSpecifier(); + } else if (UnresolvedUsingTypenameDecl *UD + = dyn_cast<UnresolvedUsingTypenameDecl>(D)) { + DTypename = true; + DQual = UD->getTargetNestedNameSpecifier(); + } else continue; + + // using decls differ if one says 'typename' and the other doesn't. + // FIXME: non-dependent using decls? + if (isTypeName != DTypename) continue; + + // using decls differ if they name different scopes (but note that + // template instantiation can cause this check to trigger when it + // didn't before instantiation). + if (Context.getCanonicalNestedNameSpecifier(Qual) != + Context.getCanonicalNestedNameSpecifier(DQual)) + continue; + + Diag(NameLoc, diag::err_using_decl_redeclaration) << SS.getRange(); + Diag(D->getLocation(), diag::note_using_decl) << 1; + return true; + } + + return false; +} + + +/// Checks that the given nested-name qualifier used in a using decl +/// in the current context is appropriately related to the current +/// scope. If an error is found, diagnoses it and returns true. +bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, + const CXXScopeSpec &SS, + SourceLocation NameLoc) { + DeclContext *NamedContext = computeDeclContext(SS); + + if (!CurContext->isRecord()) { + // C++03 [namespace.udecl]p3: + // C++0x [namespace.udecl]p8: + // A using-declaration for a class member shall be a member-declaration. + + // If we weren't able to compute a valid scope, it must be a + // dependent class scope. + if (!NamedContext || NamedContext->isRecord()) { + Diag(NameLoc, diag::err_using_decl_can_not_refer_to_class_member) + << SS.getRange(); + return true; + } + + // Otherwise, everything is known to be fine. + return false; + } + + // The current scope is a record. + + // If the named context is dependent, we can't decide much. + if (!NamedContext) { + // FIXME: in C++0x, we can diagnose if we can prove that the + // nested-name-specifier does not refer to a base class, which is + // still possible in some cases. + + // Otherwise we have to conservatively report that things might be + // okay. + return false; + } + + if (!NamedContext->isRecord()) { + // Ideally this would point at the last name in the specifier, + // but we don't have that level of source info. + Diag(SS.getRange().getBegin(), + diag::err_using_decl_nested_name_specifier_is_not_class) + << (NestedNameSpecifier*) SS.getScopeRep() << SS.getRange(); + return true; + } + + if (getLangOptions().CPlusPlus0x) { + // C++0x [namespace.udecl]p3: + // In a using-declaration used as a member-declaration, the + // nested-name-specifier shall name a base class of the class + // being defined. + + if (cast<CXXRecordDecl>(CurContext)->isProvablyNotDerivedFrom( + cast<CXXRecordDecl>(NamedContext))) { + if (CurContext == NamedContext) { + Diag(NameLoc, + diag::err_using_decl_nested_name_specifier_is_current_class) + << SS.getRange(); + return true; + } + + Diag(SS.getRange().getBegin(), + diag::err_using_decl_nested_name_specifier_is_not_base_class) + << (NestedNameSpecifier*) SS.getScopeRep() + << cast<CXXRecordDecl>(CurContext) + << SS.getRange(); + return true; + } + + return false; + } + + // C++03 [namespace.udecl]p4: + // A using-declaration used as a member-declaration shall refer + // to a member of a base class of the class being defined [etc.]. + + // Salient point: SS doesn't have to name a base class as long as + // lookup only finds members from base classes. Therefore we can + // diagnose here only if we can prove that that can't happen, + // i.e. if the class hierarchies provably don't intersect. + + // TODO: it would be nice if "definitely valid" results were cached + // in the UsingDecl and UsingShadowDecl so that these checks didn't + // need to be repeated. + + struct UserData { + llvm::DenseSet<const CXXRecordDecl*> Bases; + + static bool collect(const CXXRecordDecl *Base, void *OpaqueData) { + UserData *Data = reinterpret_cast<UserData*>(OpaqueData); + Data->Bases.insert(Base); + return true; + } + + bool hasDependentBases(const CXXRecordDecl *Class) { + return !Class->forallBases(collect, this); + } + + /// Returns true if the base is dependent or is one of the + /// accumulated base classes. + static bool doesNotContain(const CXXRecordDecl *Base, void *OpaqueData) { + UserData *Data = reinterpret_cast<UserData*>(OpaqueData); + return !Data->Bases.count(Base); + } + + bool mightShareBases(const CXXRecordDecl *Class) { + return Bases.count(Class) || !Class->forallBases(doesNotContain, this); + } + }; + + UserData Data; + + // Returns false if we find a dependent base. + if (Data.hasDependentBases(cast<CXXRecordDecl>(CurContext))) + return false; + + // Returns false if the class has a dependent base or if it or one + // of its bases is present in the base set of the current context. + if (Data.mightShareBases(cast<CXXRecordDecl>(NamedContext))) + return false; + + Diag(SS.getRange().getBegin(), + diag::err_using_decl_nested_name_specifier_is_not_base_class) + << (NestedNameSpecifier*) SS.getScopeRep() + << cast<CXXRecordDecl>(CurContext) + << SS.getRange(); + + return true; +} + Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc, SourceLocation AliasLoc, @@ -3081,7 +3548,6 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, } else { Constructor->setUsed(); } - return; } void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, @@ -3163,7 +3629,8 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); if (CXXMethodDecl *BaseAssignOpMethod = - getAssignOperatorMethod(MethodDecl->getParamDecl(0), BaseClassDecl)) + getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0), + BaseClassDecl)) MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod); } for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), @@ -3175,7 +3642,8 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(FieldClassType->getDecl()); if (CXXMethodDecl *FieldAssignOpMethod = - getAssignOperatorMethod(MethodDecl->getParamDecl(0), FieldClassDecl)) + getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0), + FieldClassDecl)) MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod); } else if (FieldType->isReferenceType()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) @@ -3196,7 +3664,8 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, } CXXMethodDecl * -Sema::getAssignOperatorMethod(ParmVarDecl *ParmDecl, +Sema::getAssignOperatorMethod(SourceLocation CurrentLocation, + ParmVarDecl *ParmDecl, CXXRecordDecl *ClassDecl) { QualType LHSType = Context.getTypeDeclType(ClassDecl); QualType RHSType(LHSType); @@ -3206,18 +3675,17 @@ Sema::getAssignOperatorMethod(ParmVarDecl *ParmDecl, RHSType = Context.getCVRQualifiedType(RHSType, ParmDecl->getType().getCVRQualifiers()); ExprOwningPtr<Expr> LHS(this, new (Context) DeclRefExpr(ParmDecl, - LHSType, - SourceLocation())); + LHSType, + SourceLocation())); ExprOwningPtr<Expr> RHS(this, new (Context) DeclRefExpr(ParmDecl, - RHSType, - SourceLocation())); + RHSType, + CurrentLocation)); Expr *Args[2] = { &*LHS, &*RHS }; OverloadCandidateSet CandidateSet; AddMemberOperatorCandidates(clang::OO_Equal, SourceLocation(), Args, 2, CandidateSet); OverloadCandidateSet::iterator Best; - if (BestViableFunction(CandidateSet, - ClassDecl->getLocation(), Best) == OR_Success) + if (BestViableFunction(CandidateSet, CurrentLocation, Best) == OR_Success) return cast<CXXMethodDecl>(Best->Function); assert(false && "getAssignOperatorMethod - copy assignment operator method not found"); @@ -3286,8 +3754,10 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) if (ICE->getCastKind() == CastExpr::CK_NoOp) E = ICE->getSubExpr(); - - if (isa<CallExpr>(E) || isa<CXXTemporaryObjectExpr>(E)) + + if (CallExpr *CE = dyn_cast<CallExpr>(E)) + Elidable = !CE->getCallReturnType()->isReferenceType(); + else if (isa<CXXTemporaryObjectExpr>(E)) Elidable = true; } @@ -3428,7 +3898,9 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, SourceRange(VDecl->getLocation(), RParenLoc), VDecl->getDeclName(), - IK_Direct, + InitializationKind::CreateDirect(VDecl->getLocation(), + LParenLoc, + RParenLoc), ConstructorArgs); if (!Constructor) RealDecl->setInvalidDecl(); @@ -3464,7 +3936,7 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef, QualType ClassType, Expr **Args, unsigned NumArgs, - Sema::InitializationKind Kind, + InitializationKind Kind, OverloadCandidateSet &CandidateSet) { // C++ [dcl.init]p14: // If the initialization is direct-initialization, or if it is @@ -3499,10 +3971,12 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef, else Constructor = cast<CXXConstructorDecl>(*Con); - if ((Kind == Sema::IK_Direct) || - (Kind == Sema::IK_Copy && + if ((Kind.getKind() == InitializationKind::IK_Direct) || + (Kind.getKind() == InitializationKind::IK_Value) || + (Kind.getKind() == InitializationKind::IK_Copy && Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) || - (Kind == Sema::IK_Default && Constructor->isDefaultConstructor())) { + ((Kind.getKind() == InitializationKind::IK_Default) && + Constructor->isDefaultConstructor())) { if (ConstructorTmpl) SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0, @@ -3774,7 +4248,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // real, update the initializer with the resulting function. if (!ICS) { if (DiagnoseUseOfDecl(Fn, DeclLoc)) - return true; + return true; Init = FixOverloadedFunctionReference(Init, Fn); } @@ -3874,23 +4348,28 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, = T2RecordDecl->getVisibleConversionFunctions(); for (UnresolvedSet::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { + NamedDecl *D = *I; + CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext()); + if (isa<UsingShadowDecl>(D)) + D = cast<UsingShadowDecl>(D)->getTargetDecl(); + FunctionTemplateDecl *ConvTemplate - = dyn_cast<FunctionTemplateDecl>(*I); + = dyn_cast<FunctionTemplateDecl>(D); CXXConversionDecl *Conv; if (ConvTemplate) Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl()); else - Conv = cast<CXXConversionDecl>(*I); + Conv = cast<CXXConversionDecl>(D); // If the conversion function doesn't return a reference type, // it can't be considered for this conversion. if (Conv->getConversionType()->isLValueReferenceType() && (AllowExplicit || !Conv->isExplicit())) { if (ConvTemplate) - AddTemplateConversionCandidate(ConvTemplate, Init, DeclType, - CandidateSet); + AddTemplateConversionCandidate(ConvTemplate, ActingDC, + Init, DeclType, CandidateSet); else - AddConversionCandidate(Conv, Init, DeclType, CandidateSet); + AddConversionCandidate(Conv, ActingDC, Init, DeclType, CandidateSet); } } @@ -4125,6 +4604,138 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, } } +static inline bool +CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef, + const FunctionDecl *FnDecl) { + const DeclContext *DC = FnDecl->getDeclContext()->getLookupContext(); + if (isa<NamespaceDecl>(DC)) { + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_new_delete_declared_in_namespace) + << FnDecl->getDeclName(); + } + + if (isa<TranslationUnitDecl>(DC) && + FnDecl->getStorageClass() == FunctionDecl::Static) { + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_new_delete_declared_static) + << FnDecl->getDeclName(); + } + + return false; +} + +static inline bool +CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl, + CanQualType ExpectedResultType, + CanQualType ExpectedFirstParamType, + unsigned DependentParamTypeDiag, + unsigned InvalidParamTypeDiag) { + QualType ResultType = + FnDecl->getType()->getAs<FunctionType>()->getResultType(); + + // Check that the result type is not dependent. + if (ResultType->isDependentType()) + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_new_delete_dependent_result_type) + << FnDecl->getDeclName() << ExpectedResultType; + + // Check that the result type is what we expect. + if (SemaRef.Context.getCanonicalType(ResultType) != ExpectedResultType) + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_new_delete_invalid_result_type) + << FnDecl->getDeclName() << ExpectedResultType; + + // A function template must have at least 2 parameters. + if (FnDecl->getDescribedFunctionTemplate() && FnDecl->getNumParams() < 2) + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_new_delete_template_too_few_parameters) + << FnDecl->getDeclName(); + + // The function decl must have at least 1 parameter. + if (FnDecl->getNumParams() == 0) + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_new_delete_too_few_parameters) + << FnDecl->getDeclName(); + + // Check the the first parameter type is not dependent. + QualType FirstParamType = FnDecl->getParamDecl(0)->getType(); + if (FirstParamType->isDependentType()) + return SemaRef.Diag(FnDecl->getLocation(), DependentParamTypeDiag) + << FnDecl->getDeclName() << ExpectedFirstParamType; + + // Check that the first parameter type is what we expect. + if (SemaRef.Context.getCanonicalType(FirstParamType) != + ExpectedFirstParamType) + return SemaRef.Diag(FnDecl->getLocation(), InvalidParamTypeDiag) + << FnDecl->getDeclName() << ExpectedFirstParamType; + + return false; +} + +static bool +CheckOperatorNewDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) { + // C++ [basic.stc.dynamic.allocation]p1: + // A program is ill-formed if an allocation function is declared in a + // namespace scope other than global scope or declared static in global + // scope. + if (CheckOperatorNewDeleteDeclarationScope(SemaRef, FnDecl)) + return true; + + CanQualType SizeTy = + SemaRef.Context.getCanonicalType(SemaRef.Context.getSizeType()); + + // C++ [basic.stc.dynamic.allocation]p1: + // The return type shall be void*. The first parameter shall have type + // std::size_t. + if (CheckOperatorNewDeleteTypes(SemaRef, FnDecl, SemaRef.Context.VoidPtrTy, + SizeTy, + diag::err_operator_new_dependent_param_type, + diag::err_operator_new_param_type)) + return true; + + // C++ [basic.stc.dynamic.allocation]p1: + // The first parameter shall not have an associated default argument. + if (FnDecl->getParamDecl(0)->hasDefaultArg()) + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_new_default_arg) + << FnDecl->getDeclName() << FnDecl->getParamDecl(0)->getDefaultArgRange(); + + return false; +} + +static bool +CheckOperatorDeleteDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) { + // C++ [basic.stc.dynamic.deallocation]p1: + // A program is ill-formed if deallocation functions are declared in a + // namespace scope other than global scope or declared static in global + // scope. + if (CheckOperatorNewDeleteDeclarationScope(SemaRef, FnDecl)) + return true; + + // C++ [basic.stc.dynamic.deallocation]p2: + // Each deallocation function shall return void and its first parameter + // shall be void*. + if (CheckOperatorNewDeleteTypes(SemaRef, FnDecl, SemaRef.Context.VoidTy, + SemaRef.Context.VoidPtrTy, + diag::err_operator_delete_dependent_param_type, + diag::err_operator_delete_param_type)) + return true; + + QualType FirstParamType = FnDecl->getParamDecl(0)->getType(); + if (FirstParamType->isDependentType()) + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_delete_dependent_param_type) + << FnDecl->getDeclName() << SemaRef.Context.VoidPtrTy; + + if (SemaRef.Context.getCanonicalType(FirstParamType) != + SemaRef.Context.VoidPtrTy) + return SemaRef.Diag(FnDecl->getLocation(), + diag::err_operator_delete_param_type) + << FnDecl->getDeclName() << SemaRef.Context.VoidPtrTy; + + return false; +} + /// CheckOverloadedOperatorDeclaration - Check whether the declaration /// of this overloaded operator is well-formed. If so, returns false; /// otherwise, emits appropriate diagnostics and returns true. @@ -4140,29 +4751,11 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { // described completely in 3.7.3. The attributes and restrictions // 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_Delete || Op == OO_Array_Delete) - return false; + return CheckOperatorDeleteDeclaration(*this, FnDecl); - 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; - } + if (Op == OO_New || Op == OO_Array_New) + return CheckOperatorNewDeclaration(*this, FnDecl); // C++ [over.oper]p6: // An operator function shall either be a non-static member @@ -4201,14 +4794,10 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { if (Op != OO_Call) { for (FunctionDecl::param_iterator Param = FnDecl->param_begin(); Param != FnDecl->param_end(); ++Param) { - if ((*Param)->hasUnparsedDefaultArg()) + if ((*Param)->hasDefaultArg()) return Diag((*Param)->getLocation(), diag::err_operator_overload_default_arg) - << FnDecl->getDeclName(); - else if (Expr *DefArg = (*Param)->getDefaultArg()) - return Diag((*Param)->getLocation(), - diag::err_operator_overload_default_arg) - << FnDecl->getDeclName() << DefArg->getSourceRange(); + << FnDecl->getDeclName() << (*Param)->getDefaultArgRange(); } } @@ -4346,7 +4935,7 @@ Sema::DeclPtrTy Sema::ActOnFinishLinkageSpecification(Scope *S, /// occurs within a C++ catch clause, returning the newly-created /// variable. VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, - DeclaratorInfo *DInfo, + TypeSourceInfo *TInfo, IdentifierInfo *Name, SourceLocation Loc, SourceRange Range) { @@ -4396,7 +4985,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, // FIXME: Need to check for abstract classes. VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc, - Name, ExDeclType, DInfo, VarDecl::None); + Name, ExDeclType, TInfo, VarDecl::None); if (Invalid) ExDecl->setInvalidDecl(); @@ -4407,8 +4996,8 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, /// ActOnExceptionDeclarator - Parsed the exception-declarator in a C++ catch /// handler. Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { - DeclaratorInfo *DInfo = 0; - QualType ExDeclType = GetTypeForDeclarator(D, S, &DInfo); + TypeSourceInfo *TInfo = 0; + QualType ExDeclType = GetTypeForDeclarator(D, S, &TInfo); bool Invalid = D.isInvalidType(); IdentifierInfo *II = D.getIdentifier(); @@ -4428,7 +5017,7 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { Invalid = true; } - VarDecl *ExDecl = BuildExceptionDeclaration(S, ExDeclType, DInfo, + VarDecl *ExDecl = BuildExceptionDeclaration(S, ExDeclType, TInfo, D.getIdentifier(), D.getIdentifierLoc(), D.getDeclSpec().getSourceRange()); @@ -4462,10 +5051,8 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc, } if (Value == 0) { - std::string str(AssertMessage->getStrData(), - AssertMessage->getByteLength()); Diag(AssertLoc, diag::err_static_assert_failed) - << str << AssertExpr->getSourceRange(); + << AssertMessage->getString() << AssertExpr->getSourceRange(); } } @@ -4602,8 +5189,8 @@ Sema::ActOnFriendFunctionDecl(Scope *S, assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified); SourceLocation Loc = D.getIdentifierLoc(); - DeclaratorInfo *DInfo = 0; - QualType T = GetTypeForDeclarator(D, S, &DInfo); + TypeSourceInfo *TInfo = 0; + QualType T = GetTypeForDeclarator(D, S, &TInfo); // C++ [class.friend]p1 // A friend of a class is a function or class.... @@ -4726,7 +5313,7 @@ Sema::ActOnFriendFunctionDecl(Scope *S, } bool Redeclaration = false; - NamedDecl *ND = ActOnFunctionDeclarator(S, D, DC, T, DInfo, Previous, + NamedDecl *ND = ActOnFunctionDeclarator(S, D, DC, T, TInfo, Previous, move(TemplateParams), IsDefinition, Redeclaration); @@ -4890,6 +5477,26 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New, return false; } +/// \brief Mark the given method pure. +/// +/// \param Method the method to be marked pure. +/// +/// \param InitRange the source range that covers the "0" initializer. +bool Sema::CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange) { + if (Method->isVirtual() || Method->getParent()->isDependentContext()) { + Method->setPure(); + + // A class is abstract if at least one function is pure virtual. + Method->getParent()->setAbstract(true); + return false; + } + + if (!Method->isInvalidDecl()) + Diag(Method->getLocation(), diag::err_non_virtual_pure) + << Method->getDeclName() << InitRange; + return true; +} + /// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an /// initializer for the declaration 'Dcl'. /// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a @@ -4949,9 +5556,9 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { assert(D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && "Parser allowed 'typedef' as storage class of condition decl."); - DeclaratorInfo *DInfo = 0; + TypeSourceInfo *TInfo = 0; TagDecl *OwnedTag = 0; - QualType Ty = GetTypeForDeclarator(D, S, &DInfo, &OwnedTag); + QualType Ty = GetTypeForDeclarator(D, S, &TInfo, &OwnedTag); if (Ty->isFunctionType()) { // The declarator shall not specify a function... // We exit without creating a CXXConditionDeclExpr because a FunctionDecl @@ -4972,3 +5579,80 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { VD->setDeclaredInCondition(true); return Dcl; } + +void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc, + CXXMethodDecl *MD) { + // Ignore dependent types. + if (MD->isDependentContext()) + return; + + CXXRecordDecl *RD = MD->getParent(); + + // Ignore classes without a vtable. + if (!RD->isDynamicClass()) + return; + + if (!MD->isOutOfLine()) { + // The only inline functions we care about are constructors. We also defer + // marking the virtual members as referenced until we've reached the end + // of the translation unit. We do this because we need to know the key + // function of the class in order to determine the key function. + if (isa<CXXConstructorDecl>(MD)) + ClassesWithUnmarkedVirtualMembers.insert(std::make_pair(RD, Loc)); + return; + } + + const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD); + + if (!KeyFunction) { + // This record does not have a key function, so we assume that the vtable + // will be emitted when it's used by the constructor. + if (!isa<CXXConstructorDecl>(MD)) + return; + } else if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) { + // We don't have the right key function. + return; + } + + // Mark the members as referenced. + MarkVirtualMembersReferenced(Loc, RD); + ClassesWithUnmarkedVirtualMembers.erase(RD); +} + +bool Sema::ProcessPendingClassesWithUnmarkedVirtualMembers() { + if (ClassesWithUnmarkedVirtualMembers.empty()) + return false; + + for (std::map<CXXRecordDecl *, SourceLocation>::iterator i = + ClassesWithUnmarkedVirtualMembers.begin(), + e = ClassesWithUnmarkedVirtualMembers.end(); i != e; ++i) { + CXXRecordDecl *RD = i->first; + + const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD); + if (KeyFunction) { + // We know that the class has a key function. If the key function was + // declared in this translation unit, then it the class decl would not + // have been in the ClassesWithUnmarkedVirtualMembers map. + continue; + } + + SourceLocation Loc = i->second; + MarkVirtualMembersReferenced(Loc, RD); + } + + ClassesWithUnmarkedVirtualMembers.clear(); + return true; +} + +void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD) { + for (CXXRecordDecl::method_iterator i = RD->method_begin(), + e = RD->method_end(); i != e; ++i) { + CXXMethodDecl *MD = *i; + + // C++ [basic.def.odr]p2: + // [...] A virtual member function is used if it is not pure. [...] + if (MD->isVirtual() && !MD->isPure()) + MarkDeclarationReferenced(Loc, MD); + } +} + diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 7da37af..a768e1b 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -1349,10 +1349,10 @@ ObjCMethodDecl *Sema::LookupInstanceMethodInGlobalPool(Selector Sel, } if (issueWarning && (MethList.Method && MethList.Next)) { Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R; - Diag(MethList.Method->getLocStart(), diag::note_using_decl) + Diag(MethList.Method->getLocStart(), diag::note_using) << MethList.Method->getSourceRange(); for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) - Diag(Next->Method->getLocStart(), diag::note_also_found_decl) + Diag(Next->Method->getLocStart(), diag::note_also_found) << Next->Method->getSourceRange(); } return MethList.Method; @@ -1413,10 +1413,10 @@ ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel, } if (issueWarning && (MethList.Method && MethList.Next)) { Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R; - Diag(MethList.Method->getLocStart(), diag::note_using_decl) + Diag(MethList.Method->getLocStart(), diag::note_using) << MethList.Method->getSourceRange(); for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) - Diag(Next->Method->getLocStart(), diag::note_also_found_decl) + Diag(Next->Method->getLocStart(), diag::note_also_found) << Next->Method->getSourceRange(); } return MethList.Method; @@ -1495,7 +1495,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, property->getLocation(), property->getIdentifier(), property->getType(), - /*DInfo=*/0, + /*TInfo=*/0, VarDecl::None, 0); SetterMethod->setMethodParams(Context, &Argument, 1); @@ -1765,7 +1765,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( for (unsigned i = 0, e = Sel.getNumArgs(); i != e; ++i) { QualType ArgType; - DeclaratorInfo *DI; + TypeSourceInfo *DI; if (ArgInfo[i].Type == 0) { ArgType = Context.getObjCIdType(); diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 25af052..7e2a98d 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -35,10 +35,15 @@ static const FunctionProtoType *GetUnderlyingFunction(QualType T) /// exception specification. Incomplete types, or pointers to incomplete types /// other than void are not allowed. bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) { - // FIXME: This may not correctly work with the fix for core issue 437, - // where a class's own type is considered complete within its body. But - // perhaps RequireCompleteType itself should contain this logic? + // This check (and the similar one below) deals with issue 437, that changes + // C++ 9.2p2 this way: + // Within the class member-specification, the class is regarded as complete + // within function bodies, default arguments, exception-specifications, and + // constructor ctor-initializers (including such things in nested classes). + if (T->isRecordType() && T->getAs<RecordType>()->isBeingDefined()) + return false; + // C++ 15.4p2: A type denoted in an exception-specification shall not denote // an incomplete type. if (RequireCompleteType(Range.getBegin(), T, @@ -58,8 +63,12 @@ bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) { } else return false; + // Again as before + if (T->isRecordType() && T->getAs<RecordType>()->isBeingDefined()) + return false; + if (!T->isVoidType() && RequireCompleteType(Range.getBegin(), T, - PDiag(diag::err_incomplete_in_exception_spec) << /*direct*/kind << Range)) + PDiag(diag::err_incomplete_in_exception_spec) << kind << Range)) return true; return false; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index f653cf6..358f445 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -259,15 +259,43 @@ bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) { DefaultArgumentPromotion(Expr); if (Expr->getType()->isObjCInterfaceType()) { - Diag(Expr->getLocStart(), - diag::err_cannot_pass_objc_interface_to_vararg) - << Expr->getType() << CT; - return true; + switch (ExprEvalContexts.back().Context ) { + case Unevaluated: + // The argument will never be evaluated, so don't complain. + break; + + case PotentiallyEvaluated: + Diag(Expr->getLocStart(), + diag::err_cannot_pass_objc_interface_to_vararg) + << Expr->getType() << CT; + return true; + + case PotentiallyPotentiallyEvaluated: + ExprEvalContexts.back().addDiagnostic(Expr->getLocStart(), + PDiag(diag::err_cannot_pass_objc_interface_to_vararg) + << Expr->getType() << CT); + break; + } } - if (!Expr->getType()->isPODType()) - Diag(Expr->getLocStart(), diag::warn_cannot_pass_non_pod_arg_to_vararg) - << Expr->getType() << CT; + if (!Expr->getType()->isPODType()) { + switch (ExprEvalContexts.back().Context ) { + case Unevaluated: + // The argument will never be evaluated, so don't complain. + break; + + case PotentiallyEvaluated: + Diag(Expr->getLocStart(), diag::warn_cannot_pass_non_pod_arg_to_vararg) + << Expr->getType() << CT; + break; + + case PotentiallyPotentiallyEvaluated: + ExprEvalContexts.back().addDiagnostic(Expr->getLocStart(), + PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg) + << Expr->getType() << CT); + break; + } + } return false; } @@ -415,7 +443,7 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock, /// BuildDeclRefExpr - Build a DeclRefExpr. Sema::OwningExprResult -Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc, +Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc, const CXXScopeSpec *SS) { if (Context.getCanonicalType(Ty) == Context.UndeducedAutoTy) { Diag(Loc, @@ -605,6 +633,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, MemberType = Context.getQualifiedType(MemberType, NewQuals); MarkDeclarationReferenced(Loc, *FI); + PerformObjectMemberConversion(Result, *FI); // FIXME: Might this end up being a qualified name? Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, *FI, OpLoc, MemberType); @@ -665,9 +694,9 @@ static void DecomposeTemplateName(LookupResult &R, const UnqualifiedId &Id) { if (TemplateDecl *TD = TName.getAsTemplateDecl()) R.addDecl(TD); - else if (OverloadedFunctionDecl *OD - = TName.getAsOverloadedFunctionDecl()) - for (OverloadIterator I(OD), E; I != E; ++I) + else if (OverloadedTemplateStorage *OT = TName.getAsOverloadedTemplate()) + for (OverloadedTemplateStorage::iterator I = OT->begin(), E = OT->end(); + I != E; ++I) R.addDecl(*I); R.resolveKind(); @@ -703,18 +732,188 @@ static bool IsDependentIdExpression(Sema &SemaRef, const CXXScopeSpec &SS) { // We can't look into record types unless they're fully-formed. if (!IsFullyFormedScope(SemaRef, cast<CXXRecordDecl>(DC))) return true; - // We can always look into fully-formed record types, but if we're - // in a dependent but not fully-formed context, we can't decide - // whether the qualifier names a base class. We shouldn't be trying - // to decide that yet anyway, but we are, so we need to delay that - // decision. - CXXRecordDecl *CurRecord; - if (CXXMethodDecl *CurMethod = dyn_cast<CXXMethodDecl>(SemaRef.CurContext)) - CurRecord = cast<CXXRecordDecl>(CurMethod->getParent()); - else - CurRecord = dyn_cast<CXXRecordDecl>(SemaRef.CurContext); + return false; +} + +/// Determines if the given class is provably not derived from all of +/// the prospective base classes. +static bool IsProvablyNotDerivedFrom(Sema &SemaRef, + CXXRecordDecl *Record, + const llvm::SmallPtrSet<CXXRecordDecl*, 4> &Bases) { + if (Bases.count(Record->getCanonicalDecl())) + return false; + + RecordDecl *RD = Record->getDefinition(SemaRef.Context); + if (!RD) return false; + Record = cast<CXXRecordDecl>(RD); + + for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(), + E = Record->bases_end(); I != E; ++I) { + CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType()); + CanQual<RecordType> BaseRT = BaseT->getAs<RecordType>(); + if (!BaseRT) return false; + + CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl()); + if (!IsProvablyNotDerivedFrom(SemaRef, BaseRecord, Bases)) + return false; + } + + return true; +} + +/// Determines if this a C++ class member. +static bool IsClassMember(NamedDecl *D) { + DeclContext *DC = D->getDeclContext(); + + // C++0x [class.mem]p1: + // The enumerators of an unscoped enumeration defined in + // the class are members of the class. + // FIXME: support C++0x scoped enumerations. + if (isa<EnumDecl>(DC)) + DC = DC->getParent(); + + return DC->isRecord(); +} + +/// Determines if this is an instance member of a class. +static bool IsInstanceMember(NamedDecl *D) { + assert(IsClassMember(D) && + "checking whether non-member is instance member"); + + if (isa<FieldDecl>(D)) return true; + + if (isa<CXXMethodDecl>(D)) + return !cast<CXXMethodDecl>(D)->isStatic(); + + if (isa<FunctionTemplateDecl>(D)) { + D = cast<FunctionTemplateDecl>(D)->getTemplatedDecl(); + return !cast<CXXMethodDecl>(D)->isStatic(); + } + + return false; +} + +enum IMAKind { + /// The reference is definitely not an instance member access. + IMA_Static, + + /// The reference may be an implicit instance member access. + IMA_Mixed, + + /// The reference may be to an instance member, but it is invalid if + /// so, because the context is not an instance method. + IMA_Mixed_StaticContext, + + /// The reference may be to an instance member, but it is invalid if + /// so, because the context is from an unrelated class. + IMA_Mixed_Unrelated, + + /// The reference is definitely an implicit instance member access. + IMA_Instance, + + /// The reference may be to an unresolved using declaration. + IMA_Unresolved, + + /// The reference may be to an unresolved using declaration and the + /// context is not an instance method. + IMA_Unresolved_StaticContext, + + /// The reference is to a member of an anonymous structure in a + /// non-class context. + IMA_AnonymousMember, - return CurRecord && !IsFullyFormedScope(SemaRef, CurRecord); + /// All possible referrents are instance members and the current + /// context is not an instance method. + IMA_Error_StaticContext, + + /// All possible referrents are instance members of an unrelated + /// class. + IMA_Error_Unrelated +}; + +/// The given lookup names class member(s) and is not being used for +/// an address-of-member expression. Classify the type of access +/// according to whether it's possible that this reference names an +/// instance member. This is best-effort; it is okay to +/// conservatively answer "yes", in which case some errors will simply +/// not be caught until template-instantiation. +static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, + const LookupResult &R) { + assert(!R.empty() && IsClassMember(*R.begin())); + + bool isStaticContext = + (!isa<CXXMethodDecl>(SemaRef.CurContext) || + cast<CXXMethodDecl>(SemaRef.CurContext)->isStatic()); + + if (R.isUnresolvableResult()) + return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved; + + // Collect all the declaring classes of instance members we find. + bool hasNonInstance = false; + llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes; + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { + NamedDecl *D = (*I)->getUnderlyingDecl(); + if (IsInstanceMember(D)) { + CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext()); + + // If this is a member of an anonymous record, move out to the + // innermost non-anonymous struct or union. If there isn't one, + // that's a special case. + while (R->isAnonymousStructOrUnion()) { + R = dyn_cast<CXXRecordDecl>(R->getParent()); + if (!R) return IMA_AnonymousMember; + } + Classes.insert(R->getCanonicalDecl()); + } + else + hasNonInstance = true; + } + + // If we didn't find any instance members, it can't be an implicit + // member reference. + if (Classes.empty()) + return IMA_Static; + + // If the current context is not an instance method, it can't be + // an implicit member reference. + if (isStaticContext) + return (hasNonInstance ? IMA_Mixed_StaticContext : IMA_Error_StaticContext); + + // If we can prove that the current context is unrelated to all the + // declaring classes, it can't be an implicit member reference (in + // which case it's an error if any of those members are selected). + if (IsProvablyNotDerivedFrom(SemaRef, + cast<CXXMethodDecl>(SemaRef.CurContext)->getParent(), + Classes)) + return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated); + + return (hasNonInstance ? IMA_Mixed : IMA_Instance); +} + +/// Diagnose a reference to a field with no object available. +static void DiagnoseInstanceReference(Sema &SemaRef, + const CXXScopeSpec &SS, + const LookupResult &R) { + SourceLocation Loc = R.getNameLoc(); + SourceRange Range(Loc); + if (SS.isSet()) Range.setBegin(SS.getRange().getBegin()); + + if (R.getAsSingle<FieldDecl>()) { + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(SemaRef.CurContext)) { + if (MD->isStatic()) { + // "invalid use of member 'x' in static member function" + SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method) + << Range << R.getLookupName(); + return; + } + } + + SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use) + << R.getLookupName() << Range; + return; + } + + SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range; } Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, @@ -746,10 +945,8 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // Determine whether this is a member of an unknown specialization; // we need to handle these differently. if (SS.isSet() && IsDependentIdExpression(*this, SS)) { - bool CheckForImplicitMember = !isAddressOfOperand; - return ActOnDependentIdExpression(SS, Name, NameLoc, - CheckForImplicitMember, + isAddressOfOperand, TemplateArgs); } @@ -847,23 +1044,41 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, } } - // &SomeClass::foo is an abstract member reference, regardless of - // the nature of foo, but &SomeClass::foo(...) is not. If this is - // *not* an abstract member reference, and any of the results is a - // class member (which necessarily means they're all class members), - // then we make an implicit member reference instead. - // - // This check considers all the same information as the "needs ADL" - // check, but there's no simple logical relationship other than the - // fact that they can never be simultaneously true. We could - // calculate them both in one pass if that proves important for - // performance. - if (!ADL) { + // Check whether this might be a C++ implicit instance member access. + // C++ [expr.prim.general]p6: + // Within the definition of a non-static member function, an + // identifier that names a non-static member is transformed to a + // class member access expression. + // But note that &SomeClass::foo is grammatically distinct, even + // though we don't parse it that way. + if (!R.empty() && IsClassMember(*R.begin())) { bool isAbstractMemberPointer = (isAddressOfOperand && !SS.isEmpty()); - if (!isAbstractMemberPointer && !R.empty() && - isa<CXXRecordDecl>((*R.begin())->getDeclContext())) { - return BuildImplicitMemberReferenceExpr(SS, R, TemplateArgs); + if (!isAbstractMemberPointer) { + switch (ClassifyImplicitMemberAccess(*this, R)) { + case IMA_Instance: + return BuildImplicitMemberExpr(SS, R, TemplateArgs, true); + + case IMA_AnonymousMember: + assert(R.isSingleResult()); + return BuildAnonymousStructUnionMemberReference(R.getNameLoc(), + R.getAsSingle<FieldDecl>()); + + case IMA_Mixed: + case IMA_Mixed_Unrelated: + case IMA_Unresolved: + return BuildImplicitMemberExpr(SS, R, TemplateArgs, false); + + case IMA_Static: + case IMA_Mixed_StaticContext: + case IMA_Unresolved_StaticContext: + break; + + case IMA_Error_StaticContext: + case IMA_Error_Unrelated: + DiagnoseInstanceReference(*this, SS, R); + return ExprError(); + } } } @@ -1027,7 +1242,7 @@ Sema::PerformObjectMemberConversion(Expr *&From, NamedDecl *Member) { /// \brief Build a MemberExpr AST node. static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, - const CXXScopeSpec &SS, NamedDecl *Member, + const CXXScopeSpec &SS, ValueDecl *Member, SourceLocation Loc, QualType Ty, const TemplateArgumentListInfo *TemplateArgs = 0) { NestedNameSpecifier *Qualifier = 0; @@ -1041,35 +1256,15 @@ static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, Member, Loc, TemplateArgs, Ty); } -/// Return true if all the decls in the given result are instance -/// methods. -static bool IsOnlyInstanceMethods(const LookupResult &R) { - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { - NamedDecl *D = (*I)->getUnderlyingDecl(); - - CXXMethodDecl *Method; - if (isa<FunctionTemplateDecl>(D)) - Method = cast<CXXMethodDecl>(cast<FunctionTemplateDecl>(D) - ->getTemplatedDecl()); - else if (isa<CXXMethodDecl>(D)) - Method = cast<CXXMethodDecl>(D); - else - return false; - - if (Method->isStatic()) - return false; - } - - return true; -} - -/// Builds an implicit member access expression from the given -/// unqualified lookup set, which is known to contain only class -/// members. +/// Builds an implicit member access expression. The current context +/// is known to be an instance method, and the given unqualified lookup +/// set is known to contain only instance members, at least one of which +/// is from an appropriate type. Sema::OwningExprResult -Sema::BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS, - LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs) { +Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs, + bool IsKnownInstance) { assert(!R.empty() && !R.isAmbiguous()); SourceLocation Loc = R.getNameLoc(); @@ -1082,44 +1277,18 @@ Sema::BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS, if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion()) return BuildAnonymousStructUnionMemberReference(Loc, FD); - QualType ThisType; - if (isImplicitMemberReference(R, ThisType)) { - Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType); - return BuildMemberReferenceExpr(ExprArg(*this, This), - /*OpLoc*/ SourceLocation(), - /*IsArrow*/ true, - SS, R, TemplateArgs); - } - - // Diagnose now if none of the available methods are static. - if (IsOnlyInstanceMethods(R)) - return ExprError(Diag(Loc, diag::err_member_call_without_object)); - - if (R.getAsSingle<FieldDecl>()) { - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) { - if (MD->isStatic()) { - // "invalid use of member 'x' in static member function" - Diag(Loc, diag::err_invalid_member_use_in_static_method) - << R.getLookupName(); - return ExprError(); - } - } - - // Any other ways we could have found the field in a well-formed - // program would have been turned into implicit member expressions - // above. - Diag(Loc, diag::err_invalid_non_static_member_use) - << R.getLookupName(); - return ExprError(); + // If this is known to be an instance access, go ahead and build a + // 'this' expression now. + QualType ThisType = cast<CXXMethodDecl>(CurContext)->getThisType(Context); + Expr *This = 0; // null signifies implicit access + if (IsKnownInstance) { + This = new (Context) CXXThisExpr(SourceLocation(), ThisType); } - // We're not in an implicit member-reference context, but the lookup - // results might not require an instance. Try to build a non-member - // decl reference. - if (TemplateArgs) - return BuildTemplateIdExpr(SS, R, /* ADL */ false, *TemplateArgs); - - return BuildDeclarationNameExpr(SS, R, /*ADL*/ false); + return BuildMemberReferenceExpr(ExprArg(*this, This), ThisType, + /*OpLoc*/ SourceLocation(), + /*IsArrow*/ true, + SS, R, TemplateArgs); } bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS, @@ -1146,7 +1315,7 @@ bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS, // -- a declaration of a class member // Since using decls preserve this property, we check this on the // original decl. - if (D->getDeclContext()->isRecord()) + if (IsClassMember(D)) return false; // C++0x [basic.lookup.argdep]p3: @@ -1205,11 +1374,9 @@ Sema::OwningExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, LookupResult &R, bool NeedsADL) { - assert(R.getResultKind() != LookupResult::FoundUnresolvedValue); - - // If this isn't an overloaded result and we don't need ADL, just - // build an ordinary singleton decl ref. - if (!NeedsADL && !R.isOverloadedResult()) + // If this is a single, fully-resolved result and we don't need ADL, + // just build an ordinary singleton decl ref. + if (!NeedsADL && R.isSingleResult()) return BuildDeclarationNameExpr(SS, R.getNameLoc(), R.getFoundDecl()); // We only need to check the declaration if there's exactly one @@ -1246,7 +1413,23 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, if (CheckDeclInExpr(*this, Loc, D)) return ExprError(); - ValueDecl *VD = cast<ValueDecl>(D); + if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) { + // Specifically diagnose references to class templates that are missing + // a template argument list. + Diag(Loc, diag::err_template_decl_ref) + << Template << SS.getRange(); + Diag(Template->getLocation(), diag::note_template_decl_here); + return ExprError(); + } + + // Make sure that we're referring to a value. + ValueDecl *VD = dyn_cast<ValueDecl>(D); + if (!VD) { + Diag(Loc, diag::err_ref_non_value) + << D << SS.getRange(); + Diag(D->getLocation(), diag::note_previous_declaration); + return ExprError(); + } // Check whether this declaration can be used. Note that we suppress // this check when we're going to perform argument-dependent lookup @@ -1558,20 +1741,20 @@ bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, /// \brief Build a sizeof or alignof expression given a type operand. Action::OwningExprResult -Sema::CreateSizeOfAlignOfExpr(DeclaratorInfo *DInfo, +Sema::CreateSizeOfAlignOfExpr(TypeSourceInfo *TInfo, SourceLocation OpLoc, bool isSizeOf, SourceRange R) { - if (!DInfo) + if (!TInfo) return ExprError(); - QualType T = DInfo->getType(); + QualType T = TInfo->getType(); if (!T->isDependentType() && CheckSizeOfAlignOfOperand(T, OpLoc, R, isSizeOf)) return ExprError(); // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t. - return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, DInfo, + return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, TInfo, Context.getSizeType(), OpLoc, R.getEnd())); } @@ -1613,9 +1796,9 @@ Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, if (TyOrEx == 0) return ExprError(); if (isType) { - DeclaratorInfo *DInfo; - (void) GetTypeFromParser(TyOrEx, &DInfo); - return CreateSizeOfAlignOfExpr(DInfo, OpLoc, isSizeof, ArgRange); + TypeSourceInfo *TInfo; + (void) GetTypeFromParser(TyOrEx, &TInfo); + return CreateSizeOfAlignOfExpr(TInfo, OpLoc, isSizeof, ArgRange); } Expr *ArgEx = (Expr *)TyOrEx; @@ -1952,7 +2135,8 @@ static Decl *FindGetterNameDecl(const ObjCObjectPointerType *QIdTy, } Sema::OwningExprResult -Sema::ActOnDependentMemberExpr(ExprArg Base, bool IsArrow, SourceLocation OpLoc, +Sema::ActOnDependentMemberExpr(ExprArg Base, QualType BaseType, + bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, NamedDecl *FirstQualifierInScope, DeclarationName Name, SourceLocation NameLoc, @@ -1969,20 +2153,21 @@ Sema::ActOnDependentMemberExpr(ExprArg Base, bool IsArrow, SourceLocation OpLoc, // accessing the 'f' property if T is an Obj-C interface. The extra check // allows this, while still reporting an error if T is a struct pointer. if (!IsArrow) { - const PointerType *PT = BaseExpr->getType()->getAs<PointerType>(); + const PointerType *PT = BaseType->getAs<PointerType>(); if (PT && (!getLangOptions().ObjC1 || PT->getPointeeType()->isRecordType())) { + assert(BaseExpr && "cannot happen with implicit member accesses"); Diag(NameLoc, diag::err_typecheck_member_reference_struct_union) - << BaseExpr->getType() << BaseExpr->getSourceRange(); + << BaseType << BaseExpr->getSourceRange(); return ExprError(); } } - assert(BaseExpr->getType()->isDependentType()); + assert(BaseType->isDependentType()); // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr // must have pointer type, and the accessed type is the pointee. - return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, + return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, BaseType, IsArrow, OpLoc, static_cast<NestedNameSpecifier*>(SS.getScopeRep()), SS.getRange(), @@ -1997,15 +2182,18 @@ Sema::ActOnDependentMemberExpr(ExprArg Base, bool IsArrow, SourceLocation OpLoc, static void DiagnoseQualifiedMemberReference(Sema &SemaRef, Expr *BaseExpr, QualType BaseType, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, + const CXXScopeSpec &SS, const LookupResult &R) { - DeclContext *DC = R.getRepresentativeDecl()->getDeclContext(); + // If this is an implicit member access, use a different set of + // diagnostics. + if (!BaseExpr) + return DiagnoseInstanceReference(SemaRef, SS, R); // FIXME: this is an exceedingly lame diagnostic for some of the more // complicated cases here. + DeclContext *DC = R.getRepresentativeDecl()->getDeclContext(); SemaRef.Diag(R.getNameLoc(), diag::err_not_direct_base_or_virtual) - << QualifierRange << DC << BaseType; + << SS.getRange() << DC << BaseType; } // Check whether the declarations we found through a nested-name @@ -2022,37 +2210,78 @@ static void DiagnoseQualifiedMemberReference(Sema &SemaRef, // we actually pick through overload resolution is from a superclass. bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, + const CXXScopeSpec &SS, const LookupResult &R) { - QualType BaseTypeCanon - = Context.getCanonicalType(BaseType).getUnqualifiedType(); - - bool FoundValid = false; + const RecordType *BaseRT = BaseType->getAs<RecordType>(); + if (!BaseRT) { + // We can't check this yet because the base type is still + // dependent. + assert(BaseType->isDependentType()); + return false; + } + CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl()); for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { - TypeDecl* TyD = cast<TypeDecl>((*I)->getUnderlyingDecl()->getDeclContext()); - CanQualType MemberTypeCanon - = Context.getCanonicalType(Context.getTypeDeclType(TyD)); + // If this is an implicit member reference and we find a + // non-instance member, it's not an error. + if (!BaseExpr && !IsInstanceMember((*I)->getUnderlyingDecl())) + return false; - if (BaseTypeCanon == MemberTypeCanon || - IsDerivedFrom(BaseTypeCanon, MemberTypeCanon)) { - FoundValid = true; - break; - } + // Note that we use the DC of the decl, not the underlying decl. + CXXRecordDecl *RecordD = cast<CXXRecordDecl>((*I)->getDeclContext()); + while (RecordD->isAnonymousStructOrUnion()) + RecordD = cast<CXXRecordDecl>(RecordD->getParent()); + + llvm::SmallPtrSet<CXXRecordDecl*,4> MemberRecord; + MemberRecord.insert(RecordD->getCanonicalDecl()); + + if (!IsProvablyNotDerivedFrom(*this, BaseRecord, MemberRecord)) + return false; } - if (!FoundValid) { - DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, - Qualifier, QualifierRange, R); + DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType, SS, R); + return true; +} + +static bool +LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, + SourceRange BaseRange, const RecordType *RTy, + SourceLocation OpLoc, const CXXScopeSpec &SS) { + RecordDecl *RDecl = RTy->getDecl(); + if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0), + PDiag(diag::err_typecheck_incomplete_tag) + << BaseRange)) return true; + + DeclContext *DC = RDecl; + if (SS.isSet()) { + // If the member name was a qualified-id, look into the + // nested-name-specifier. + DC = SemaRef.computeDeclContext(SS, false); + + if (SemaRef.RequireCompleteDeclContext(SS)) { + SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag) + << SS.getRange() << DC; + return true; + } + + assert(DC && "Cannot handle non-computable dependent contexts in lookup"); + + if (!isa<TypeDecl>(DC)) { + SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass) + << DC << SS.getRange(); + return true; + } } + // The record definition is complete, now look up the member. + SemaRef.LookupQualifiedName(R, DC); + return false; } Sema::OwningExprResult -Sema::BuildMemberReferenceExpr(ExprArg BaseArg, +Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType, SourceLocation OpLoc, bool IsArrow, const CXXScopeSpec &SS, NamedDecl *FirstQualifierInScope, @@ -2060,38 +2289,53 @@ Sema::BuildMemberReferenceExpr(ExprArg BaseArg, const TemplateArgumentListInfo *TemplateArgs) { Expr *Base = BaseArg.takeAs<Expr>(); - if (Base->getType()->isDependentType()) - return ActOnDependentMemberExpr(ExprArg(*this, Base), + if (BaseType->isDependentType() || + (SS.isSet() && isDependentScopeSpecifier(SS))) + return ActOnDependentMemberExpr(ExprArg(*this, Base), BaseType, IsArrow, OpLoc, SS, FirstQualifierInScope, Name, NameLoc, TemplateArgs); LookupResult R(*this, Name, NameLoc, LookupMemberName); - OwningExprResult Result = - LookupMemberExpr(R, Base, IsArrow, OpLoc, - SS, FirstQualifierInScope, - /*ObjCImpDecl*/ DeclPtrTy()); - if (Result.isInvalid()) { - Owned(Base); - return ExprError(); - } + // Implicit member accesses. + if (!Base) { + QualType RecordTy = BaseType; + if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType(); + if (LookupMemberExprInRecord(*this, R, SourceRange(), + RecordTy->getAs<RecordType>(), + OpLoc, SS)) + return ExprError(); + + // Explicit member accesses. + } else { + OwningExprResult Result = + LookupMemberExpr(R, Base, IsArrow, OpLoc, + SS, FirstQualifierInScope, + /*ObjCImpDecl*/ DeclPtrTy()); - if (Result.get()) - return move(Result); + if (Result.isInvalid()) { + Owned(Base); + return ExprError(); + } + + if (Result.get()) + return move(Result); + } - return BuildMemberReferenceExpr(ExprArg(*this, Base), OpLoc, - IsArrow, SS, R, TemplateArgs); + return BuildMemberReferenceExpr(ExprArg(*this, Base), BaseType, + OpLoc, IsArrow, SS, R, TemplateArgs); } Sema::OwningExprResult -Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc, - bool IsArrow, const CXXScopeSpec &SS, +Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, + SourceLocation OpLoc, bool IsArrow, + const CXXScopeSpec &SS, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs) { Expr *BaseExpr = Base.takeAs<Expr>(); - QualType BaseType = BaseExpr->getType(); + QualType BaseType = BaseExprType; if (IsArrow) { assert(BaseType->isPointerType()); BaseType = BaseType->getAs<PointerType>()->getPointeeType(); @@ -2112,29 +2356,30 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc, : BaseType->getAs<RecordType>()->getDecl()); Diag(R.getNameLoc(), diag::err_no_member) - << MemberName << DC << BaseExpr->getSourceRange(); + << MemberName << DC + << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange()); return ExprError(); } - // We can't always diagnose the problem yet: it's permitted for - // lookup to find things from an invalid context as long as they - // don't get picked by overload resolution. - if (SS.isSet() && CheckQualifiedMemberReference(BaseExpr, BaseType, - Qualifier, SS.getRange(), R)) + // Diagnose qualified lookups that find only declarations from a + // non-base type. Note that it's okay for lookup to find + // declarations from a non-base type as long as those aren't the + // ones picked by overload resolution. + if (SS.isSet() && CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R)) return ExprError(); // Construct an unresolved result if we in fact got an unresolved // result. if (R.isOverloadedResult() || R.isUnresolvableResult()) { - bool Dependent = R.isUnresolvableResult(); - Dependent = Dependent || - UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), - TemplateArgs); + bool Dependent = + R.isUnresolvableResult() || + UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), TemplateArgs); UnresolvedMemberExpr *MemExpr = UnresolvedMemberExpr::Create(Context, Dependent, R.isUnresolvableResult(), - BaseExpr, IsArrow, OpLoc, + BaseExpr, BaseExprType, + IsArrow, OpLoc, Qualifier, SS.getRange(), MemberName, MemberLoc, TemplateArgs); @@ -2155,6 +2400,15 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc, if (MemberDecl->isInvalidDecl()) return ExprError(); + // Handle the implicit-member-access case. + if (!BaseExpr) { + // If this is not an instance member, convert to a non-member access. + if (!IsInstanceMember(MemberDecl)) + return BuildDeclarationNameExpr(SS, R.getNameLoc(), MemberDecl); + + BaseExpr = new (Context) CXXThisExpr(SourceLocation(), BaseExprType); + } + bool ShouldCheckUse = true; if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MemberDecl)) { // Don't diagnose the use of a virtual member function unless it's @@ -2172,7 +2426,8 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc, if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) { // We may have found a field within an anonymous union or struct // (C++ [class.union]). - if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion()) + if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion() && + !BaseType->getAs<RecordType>()->getDecl()->isAnonymousStructOrUnion()) return BuildAnonymousStructUnionMemberReference(MemberLoc, FD, BaseExpr, OpLoc); @@ -2246,7 +2501,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc, /// fixed for ObjC++. Sema::OwningExprResult Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, - bool IsArrow, SourceLocation OpLoc, + bool &IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, NamedDecl *FirstQualifierInScope, DeclPtrTy ObjCImpDecl) { @@ -2295,6 +2550,16 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // If this is an Objective-C pseudo-builtin and a definition is provided then // use that. if (BaseType->isObjCIdType()) { + if (IsArrow) { + // Handle the following exceptional case PObj->isa. + if (const ObjCObjectPointerType *OPT = + BaseType->getAs<ObjCObjectPointerType>()) { + if (OPT->getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCId) && + MemberName.getAsIdentifierInfo()->isStr("isa")) + return Owned(new (Context) ObjCIsaExpr(BaseExpr, true, MemberLoc, + Context.getObjCClassType())); + } + } // We have an 'id' type. Rather than fall through, we check if this // is a reference to 'isa'. if (BaseType != Context.ObjCIdRedefinitionType) { @@ -2377,41 +2642,48 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, BaseType = PT->getPointeeType(); else if (BaseType->isObjCObjectPointerType()) ; - else { + else if (BaseType->isRecordType()) { + // Recover from arrow accesses to records, e.g.: + // struct MyRecord foo; + // foo->bar + // This is actually well-formed in C++ if MyRecord has an + // overloaded operator->, but that should have been dealt with + // by now. + Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) + << BaseType << int(IsArrow) << BaseExpr->getSourceRange() + << CodeModificationHint::CreateReplacement(OpLoc, "."); + IsArrow = false; + } else { Diag(MemberLoc, diag::err_typecheck_member_reference_arrow) << BaseType << BaseExpr->getSourceRange(); return ExprError(); } + } else { + // Recover from dot accesses to pointers, e.g.: + // type *foo; + // foo.bar + // This is actually well-formed in two cases: + // - 'type' is an Objective C type + // - 'bar' is a pseudo-destructor name which happens to refer to + // the appropriate pointer type + if (MemberName.getNameKind() != DeclarationName::CXXDestructorName) { + const PointerType *PT = BaseType->getAs<PointerType>(); + if (PT && PT->getPointeeType()->isRecordType()) { + Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) + << BaseType << int(IsArrow) << BaseExpr->getSourceRange() + << CodeModificationHint::CreateReplacement(OpLoc, "->"); + BaseType = PT->getPointeeType(); + IsArrow = true; + } + } } - + // Handle field access to simple records. This also handles access // to fields of the ObjC 'id' struct. if (const RecordType *RTy = BaseType->getAs<RecordType>()) { - RecordDecl *RDecl = RTy->getDecl(); - if (RequireCompleteType(OpLoc, BaseType, - PDiag(diag::err_typecheck_incomplete_tag) - << BaseExpr->getSourceRange())) + if (LookupMemberExprInRecord(*this, R, BaseExpr->getSourceRange(), + RTy, OpLoc, SS)) return ExprError(); - - DeclContext *DC = RDecl; - if (SS.isSet()) { - // If the member name was a qualified-id, look into the - // nested-name-specifier. - DC = computeDeclContext(SS, false); - - if (!isa<TypeDecl>(DC)) { - Diag(MemberLoc, diag::err_qualified_member_nonclass) - << DC << SS.getRange(); - return ExprError(); - } - - // FIXME: If DC is not computable, we should build a - // CXXDependentScopeMemberExpr. - assert(DC && "Cannot handle non-computable dependent contexts in lookup"); - } - - // The record definition is complete, now make sure the member is valid. - LookupQualifiedName(R, DC); return Owned((Expr*) 0); } @@ -2644,7 +2916,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, BaseType->isSpecificBuiltinType(BuiltinType::ObjCId) && MemberName.getAsIdentifierInfo()->isStr("isa")) return Owned(new (Context) ObjCIsaExpr(BaseExpr, false, MemberLoc, - Context.getObjCIdType())); + Context.getObjCClassType())); // Handle 'field access' to vectors, such as 'V.xx'. if (BaseType->isExtVectorType()) { @@ -2723,7 +2995,7 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, Expr *Base = BaseArg.takeAs<Expr>(); OwningExprResult Result(*this); if (Base->getType()->isDependentType()) { - Result = ActOnDependentMemberExpr(ExprArg(*this, Base), + Result = ActOnDependentMemberExpr(ExprArg(*this, Base), Base->getType(), IsArrow, OpLoc, SS, FirstQualifierInScope, Name, NameLoc, @@ -2756,8 +3028,8 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, } } - Result = BuildMemberReferenceExpr(ExprArg(*this, Base), OpLoc, - IsArrow, SS, R, TemplateArgs); + Result = BuildMemberReferenceExpr(ExprArg(*this, Base), Base->getType(), + OpLoc, IsArrow, SS, R, TemplateArgs); } return move(Result); @@ -3054,16 +3326,16 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, isa<FunctionTemplateDecl>(*MemE->decls_begin())); (void)MemE; - return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, - CommaLocs, RParenLoc)); + return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, + CommaLocs, RParenLoc); } // Determine whether this is a call to a member function. if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(NakedFn)) { NamedDecl *MemDecl = MemExpr->getMemberDecl(); if (isa<CXXMethodDecl>(MemDecl)) - return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, - CommaLocs, RParenLoc)); + return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, + CommaLocs, RParenLoc); } // Determine whether this is a call to a pointer-to-member function. @@ -3155,13 +3427,28 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, } else { assert(Fns.size() <= 1 && "overloaded without Overloaded flag"); if (Fns.empty()) - NDecl = FDecl = 0; + NDecl = 0; else { NDecl = Fns[0]; - FDecl = dyn_cast<FunctionDecl>(NDecl); } } + return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, Args, NumArgs, RParenLoc); +} + +/// BuildCallExpr - Build a call to a resolved expression, i.e. an +/// expression not of \p OverloadTy. The expression should +/// unary-convert to an expression of function-pointer or +/// block-pointer type. +/// +/// \param NDecl the declaration being called, if available +Sema::OwningExprResult +Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, + SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation RParenLoc) { + FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl); + // Promote the function operand. UsualUnaryConversions(Fn); @@ -3661,41 +3948,14 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, ImpCastExprToType(LHS, RHSTy, CastExpr::CK_Unknown); return RHSTy; } - // Handle things like Class and struct objc_class*. Here we case the result - // to the pseudo-builtin, because that will be implicitly cast back to the - // redefinition type if an attempt is made to access its fields. - if (LHSTy->isObjCClassType() && - (RHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) { - ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); - return LHSTy; - } - if (RHSTy->isObjCClassType() && - (LHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) { - ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast); - return RHSTy; - } - // And the same for struct objc_object* / id - if (LHSTy->isObjCIdType() && - (RHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) { - ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); - return LHSTy; - } - if (RHSTy->isObjCIdType() && - (LHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) { - ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast); - return RHSTy; - } - // And the same for struct objc_selector* / SEL - if (Context.isObjCSelType(LHSTy) && - (RHSTy.getDesugaredType() == Context.ObjCSelRedefinitionType)) { - ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); - return LHSTy; - } - if (Context.isObjCSelType(RHSTy) && - (LHSTy.getDesugaredType() == Context.ObjCSelRedefinitionType)) { - ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast); - return RHSTy; - } + + // All objective-c pointer type analysis is done here. + QualType compositeType = FindCompositeObjCPointerType(LHS, RHS, + QuestionLoc); + if (!compositeType.isNull()) + return compositeType; + + // Handle block pointer types. if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) { if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) { @@ -3706,7 +3966,7 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, return destType; } Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) - << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); + << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); return QualType(); } // We have 2 block pointer types. @@ -3717,11 +3977,11 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // The block pointer types aren't identical, continue checking. QualType lhptee = LHSTy->getAs<BlockPointerType>()->getPointeeType(); QualType rhptee = RHSTy->getAs<BlockPointerType>()->getPointeeType(); - + if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(), rhptee.getUnqualifiedType())) { Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers) - << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); + << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); // In this situation, we assume void* type. No especially good // reason, but this is what gcc does, and we do have to pick // to get a consistent AST. @@ -3735,86 +3995,7 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); return LHSTy; } - // Check constraints for Objective-C object pointers types. - if (LHSTy->isObjCObjectPointerType() && RHSTy->isObjCObjectPointerType()) { - - if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) { - // Two identical object pointer types are always compatible. - return LHSTy; - } - const ObjCObjectPointerType *LHSOPT = LHSTy->getAs<ObjCObjectPointerType>(); - const ObjCObjectPointerType *RHSOPT = RHSTy->getAs<ObjCObjectPointerType>(); - QualType compositeType = LHSTy; - - // If both operands are interfaces and either operand can be - // assigned to the other, use that type as the composite - // type. This allows - // xxx ? (A*) a : (B*) b - // where B is a subclass of A. - // - // Additionally, as for assignment, if either type is 'id' - // allow silent coercion. Finally, if the types are - // incompatible then make sure to use 'id' as the composite - // type so the result is acceptable for sending messages to. - - // FIXME: Consider unifying with 'areComparableObjCPointerTypes'. - // It could return the composite type. - if (Context.canAssignObjCInterfaces(LHSOPT, RHSOPT)) { - compositeType = RHSOPT->isObjCBuiltinType() ? RHSTy : LHSTy; - } else if (Context.canAssignObjCInterfaces(RHSOPT, LHSOPT)) { - compositeType = LHSOPT->isObjCBuiltinType() ? LHSTy : RHSTy; - } else if ((LHSTy->isObjCQualifiedIdType() || - RHSTy->isObjCQualifiedIdType()) && - Context.ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true)) { - // Need to handle "id<xx>" explicitly. - // GCC allows qualified id and any Objective-C type to devolve to - // id. Currently localizing to here until clear this should be - // part of ObjCQualifiedIdTypesAreCompatible. - compositeType = Context.getObjCIdType(); - } else if (LHSTy->isObjCIdType() || RHSTy->isObjCIdType()) { - compositeType = Context.getObjCIdType(); - } else if (!(compositeType = - Context.areCommonBaseCompatible(LHSOPT, RHSOPT)).isNull()) - ; - else { - Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands) - << LHSTy << RHSTy - << LHS->getSourceRange() << RHS->getSourceRange(); - QualType incompatTy = Context.getObjCIdType(); - ImpCastExprToType(LHS, incompatTy, CastExpr::CK_BitCast); - ImpCastExprToType(RHS, incompatTy, CastExpr::CK_BitCast); - return incompatTy; - } - // The object pointer types are compatible. - ImpCastExprToType(LHS, compositeType, CastExpr::CK_BitCast); - ImpCastExprToType(RHS, compositeType, CastExpr::CK_BitCast); - return compositeType; - } - // Check Objective-C object pointer types and 'void *' - if (LHSTy->isVoidPointerType() && RHSTy->isObjCObjectPointerType()) { - QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType(); - QualType rhptee = RHSTy->getAs<ObjCObjectPointerType>()->getPointeeType(); - QualType destPointee - = Context.getQualifiedType(lhptee, rhptee.getQualifiers()); - QualType destType = Context.getPointerType(destPointee); - // Add qualifiers if necessary. - ImpCastExprToType(LHS, destType, CastExpr::CK_NoOp); - // Promote to void*. - ImpCastExprToType(RHS, destType, CastExpr::CK_BitCast); - return destType; - } - if (LHSTy->isObjCObjectPointerType() && RHSTy->isVoidPointerType()) { - QualType lhptee = LHSTy->getAs<ObjCObjectPointerType>()->getPointeeType(); - QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType(); - QualType destPointee - = Context.getQualifiedType(rhptee, lhptee.getQualifiers()); - QualType destType = Context.getPointerType(destPointee); - // Add qualifiers if necessary. - ImpCastExprToType(RHS, destType, CastExpr::CK_NoOp); - // Promote to void*. - ImpCastExprToType(LHS, destType, CastExpr::CK_BitCast); - return destType; - } + // Check constraints for C object pointers types (C99 6.5.15p3,6). if (LHSTy->isPointerType() && RHSTy->isPointerType()) { // get the "pointed to" types @@ -3892,6 +4073,131 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, return QualType(); } +/// FindCompositeObjCPointerType - Helper method to find composite type of +/// two objective-c pointer types of the two input expressions. +QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, + SourceLocation QuestionLoc) { + QualType LHSTy = LHS->getType(); + QualType RHSTy = RHS->getType(); + + // Handle things like Class and struct objc_class*. Here we case the result + // to the pseudo-builtin, because that will be implicitly cast back to the + // redefinition type if an attempt is made to access its fields. + if (LHSTy->isObjCClassType() && + (RHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) { + ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); + return LHSTy; + } + if (RHSTy->isObjCClassType() && + (LHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) { + ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast); + return RHSTy; + } + // And the same for struct objc_object* / id + if (LHSTy->isObjCIdType() && + (RHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) { + ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); + return LHSTy; + } + if (RHSTy->isObjCIdType() && + (LHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) { + ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast); + return RHSTy; + } + // And the same for struct objc_selector* / SEL + if (Context.isObjCSelType(LHSTy) && + (RHSTy.getDesugaredType() == Context.ObjCSelRedefinitionType)) { + ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); + return LHSTy; + } + if (Context.isObjCSelType(RHSTy) && + (LHSTy.getDesugaredType() == Context.ObjCSelRedefinitionType)) { + ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast); + return RHSTy; + } + // Check constraints for Objective-C object pointers types. + if (LHSTy->isObjCObjectPointerType() && RHSTy->isObjCObjectPointerType()) { + + if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) { + // Two identical object pointer types are always compatible. + return LHSTy; + } + const ObjCObjectPointerType *LHSOPT = LHSTy->getAs<ObjCObjectPointerType>(); + const ObjCObjectPointerType *RHSOPT = RHSTy->getAs<ObjCObjectPointerType>(); + QualType compositeType = LHSTy; + + // If both operands are interfaces and either operand can be + // assigned to the other, use that type as the composite + // type. This allows + // xxx ? (A*) a : (B*) b + // where B is a subclass of A. + // + // Additionally, as for assignment, if either type is 'id' + // allow silent coercion. Finally, if the types are + // incompatible then make sure to use 'id' as the composite + // type so the result is acceptable for sending messages to. + + // FIXME: Consider unifying with 'areComparableObjCPointerTypes'. + // It could return the composite type. + if (Context.canAssignObjCInterfaces(LHSOPT, RHSOPT)) { + compositeType = RHSOPT->isObjCBuiltinType() ? RHSTy : LHSTy; + } else if (Context.canAssignObjCInterfaces(RHSOPT, LHSOPT)) { + compositeType = LHSOPT->isObjCBuiltinType() ? LHSTy : RHSTy; + } else if ((LHSTy->isObjCQualifiedIdType() || + RHSTy->isObjCQualifiedIdType()) && + Context.ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true)) { + // Need to handle "id<xx>" explicitly. + // GCC allows qualified id and any Objective-C type to devolve to + // id. Currently localizing to here until clear this should be + // part of ObjCQualifiedIdTypesAreCompatible. + compositeType = Context.getObjCIdType(); + } else if (LHSTy->isObjCIdType() || RHSTy->isObjCIdType()) { + compositeType = Context.getObjCIdType(); + } else if (!(compositeType = + Context.areCommonBaseCompatible(LHSOPT, RHSOPT)).isNull()) + ; + else { + Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands) + << LHSTy << RHSTy + << LHS->getSourceRange() << RHS->getSourceRange(); + QualType incompatTy = Context.getObjCIdType(); + ImpCastExprToType(LHS, incompatTy, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, incompatTy, CastExpr::CK_BitCast); + return incompatTy; + } + // The object pointer types are compatible. + ImpCastExprToType(LHS, compositeType, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, compositeType, CastExpr::CK_BitCast); + return compositeType; + } + // Check Objective-C object pointer types and 'void *' + if (LHSTy->isVoidPointerType() && RHSTy->isObjCObjectPointerType()) { + QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType(); + QualType rhptee = RHSTy->getAs<ObjCObjectPointerType>()->getPointeeType(); + QualType destPointee + = Context.getQualifiedType(lhptee, rhptee.getQualifiers()); + QualType destType = Context.getPointerType(destPointee); + // Add qualifiers if necessary. + ImpCastExprToType(LHS, destType, CastExpr::CK_NoOp); + // Promote to void*. + ImpCastExprToType(RHS, destType, CastExpr::CK_BitCast); + return destType; + } + if (LHSTy->isObjCObjectPointerType() && RHSTy->isVoidPointerType()) { + QualType lhptee = LHSTy->getAs<ObjCObjectPointerType>()->getPointeeType(); + QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType(); + QualType destPointee + = Context.getQualifiedType(rhptee, lhptee.getQualifiers()); + QualType destType = Context.getPointerType(destPointee); + // Add qualifiers if necessary. + ImpCastExprToType(RHS, destType, CastExpr::CK_NoOp); + // Promote to void*. + ImpCastExprToType(LHS, destType, CastExpr::CK_BitCast); + return destType; + } + return QualType(); +} + /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null /// in the case of a the GNU conditional expr extension. Action::OwningExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, @@ -4051,6 +4357,29 @@ Sema::CheckBlockPointerTypesForAssignment(QualType lhsType, return ConvTy; } +/// CheckObjCPointerTypesForAssignment - Compares two objective-c pointer types +/// for assignment compatibility. +Sema::AssignConvertType +Sema::CheckObjCPointerTypesForAssignment(QualType lhsType, QualType rhsType) { + if (lhsType->isObjCBuiltinType() || rhsType->isObjCBuiltinType()) + return Compatible; + QualType lhptee = + lhsType->getAs<ObjCObjectPointerType>()->getPointeeType(); + QualType rhptee = + rhsType->getAs<ObjCObjectPointerType>()->getPointeeType(); + // make sure we operate on the canonical type + lhptee = Context.getCanonicalType(lhptee); + rhptee = Context.getCanonicalType(rhptee); + if (!lhptee.isAtLeastAsQualifiedAs(rhptee)) + return CompatiblePointerDiscardsQualifiers; + + if (Context.typesAreCompatible(lhsType, rhsType)) + return Compatible; + if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType()) + return IncompatibleObjCQualifiedId; + return IncompatiblePointer; +} + /// CheckAssignmentConstraints (C99 6.5.16) - This routine currently /// has code to accommodate several GCC extensions when type checking /// pointers. Here are some objectionable examples that GCC considers warnings: @@ -4173,13 +4502,7 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { return IncompatiblePointer; } if (rhsType->isObjCObjectPointerType()) { - if (lhsType->isObjCBuiltinType() || rhsType->isObjCBuiltinType()) - return Compatible; - if (Context.typesAreCompatible(lhsType, rhsType)) - return Compatible; - if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType()) - return IncompatibleObjCQualifiedId; - return IncompatiblePointer; + return CheckObjCPointerTypesForAssignment(lhsType, rhsType); } if (const PointerType *RHSPT = rhsType->getAs<PointerType>()) { if (RHSPT->getPointeeType()->isVoidType()) @@ -4794,6 +5117,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, unsigned OpaqueOpc, bool isRelational) { BinaryOperator::Opcode Opc = (BinaryOperator::Opcode)OpaqueOpc; + // Handle vector comparisons separately. if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) return CheckVectorCompareOperands(lex, rex, Loc, isRelational); @@ -4871,17 +5195,15 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, } // The result of comparisons is 'bool' in C++, 'int' in C. - QualType ResultTy = getLangOptions().CPlusPlus? Context.BoolTy :Context.IntTy; + QualType ResultTy = getLangOptions().CPlusPlus ? Context.BoolTy:Context.IntTy; if (isRelational) { if (lType->isRealType() && rType->isRealType()) return ResultTy; } else { // Check for comparisons of floating point operands using != and ==. - if (lType->isFloatingType()) { - assert(rType->isFloatingType()); + if (lType->isFloatingType() && rType->isFloatingType()) CheckFloatComparison(Loc,lex,rex); - } if (lType->isArithmeticType() && rType->isArithmeticType()) return ResultTy; @@ -6157,18 +6479,33 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, RecordDecl *RD = RC->getDecl(); if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) { if (!CRD->isPOD() && !DidWarnAboutNonPOD) { - ExprError(Diag(BuiltinLoc, diag::warn_offsetof_non_pod_type) - << SourceRange(CompPtr[0].LocStart, OC.LocEnd) - << Res->getType()); - DidWarnAboutNonPOD = true; + switch (ExprEvalContexts.back().Context ) { + case Unevaluated: + // The argument will never be evaluated, so don't complain. + break; + + case PotentiallyEvaluated: + ExprError(Diag(BuiltinLoc, diag::warn_offsetof_non_pod_type) + << SourceRange(CompPtr[0].LocStart, OC.LocEnd) + << Res->getType()); + DidWarnAboutNonPOD = true; + break; + + case PotentiallyPotentiallyEvaluated: + ExprEvalContexts.back().addDiagnostic(BuiltinLoc, + PDiag(diag::warn_offsetof_non_pod_type) + << SourceRange(CompPtr[0].LocStart, OC.LocEnd) + << Res->getType()); + DidWarnAboutNonPOD = true; + break; + } } } LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName); LookupQualifiedName(R, RD); - FieldDecl *MemberDecl - = dyn_cast_or_null<FieldDecl>(R.getAsSingleDecl(Context)); + FieldDecl *MemberDecl = R.getAsSingle<FieldDecl>(); // FIXME: Leaks Res if (!MemberDecl) return ExprError(Diag(BuiltinLoc, diag::err_no_member) @@ -6180,6 +6517,7 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, Res = BuildAnonymousStructUnionMemberReference( OC.LocEnd, MemberDecl, Res, OC.LocEnd).takeAs<Expr>(); } else { + PerformObjectMemberConversion(Res, MemberDecl); // MemberDecl->getType() doesn't get the right qualifiers, but it // doesn't matter here. Res = new (Context) MemberExpr(Res, false, MemberDecl, OC.LocEnd, @@ -6270,6 +6608,7 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) { CurFunctionNeedsScopeChecking = false; BSI->TheDecl = BlockDecl::Create(Context, CurContext, CaretLoc); + CurContext->addDecl(BSI->TheDecl); PushDeclContext(BlockScope, BSI->TheDecl); } @@ -6625,16 +6964,26 @@ Sema::PopExpressionEvaluationContext() { ExpressionEvaluationContextRecord Rec = ExprEvalContexts.back(); ExprEvalContexts.pop_back(); - if (Rec.Context == PotentiallyPotentiallyEvaluated && - Rec.PotentiallyReferenced) { - // Mark any remaining declarations in the current position of the stack - // as "referenced". If they were not meant to be referenced, semantic - // analysis would have eliminated them (e.g., in ActOnCXXTypeId). - for (PotentiallyReferencedDecls::iterator - I = Rec.PotentiallyReferenced->begin(), - IEnd = Rec.PotentiallyReferenced->end(); - I != IEnd; ++I) - MarkDeclarationReferenced(I->first, I->second); + if (Rec.Context == PotentiallyPotentiallyEvaluated) { + if (Rec.PotentiallyReferenced) { + // Mark any remaining declarations in the current position of the stack + // as "referenced". If they were not meant to be referenced, semantic + // analysis would have eliminated them (e.g., in ActOnCXXTypeId). + for (PotentiallyReferencedDecls::iterator + I = Rec.PotentiallyReferenced->begin(), + IEnd = Rec.PotentiallyReferenced->end(); + I != IEnd; ++I) + MarkDeclarationReferenced(I->first, I->second); + } + + if (Rec.PotentiallyDiagnosed) { + // Emit any pending diagnostics. + for (PotentiallyEmittedDiagnostics::iterator + I = Rec.PotentiallyDiagnosed->begin(), + IEnd = Rec.PotentiallyDiagnosed->end(); + I != IEnd; ++I) + Diag(I->first, I->second); + } } // When are coming out of an unevaluated context, clear out any @@ -6708,6 +7057,8 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { if (!Constructor->isUsed()) DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals); } + + MaybeMarkVirtualMembersReferenced(Loc, Constructor); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { if (Destructor->isImplicit() && !Destructor->isUsed()) DefineImplicitDestructor(Loc, Destructor); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 00fb65d..6d991b6 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" #include "Lookup.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" @@ -37,8 +38,7 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info"); LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName); LookupQualifiedName(R, StdNamespace); - Decl *TypeInfoDecl = R.getAsSingleDecl(Context); - RecordDecl *TypeInfoRecordDecl = dyn_cast_or_null<RecordDecl>(TypeInfoDecl); + RecordDecl *TypeInfoRecordDecl = R.getAsSingle<RecordDecl>(); if (!TypeInfoRecordDecl) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); @@ -226,7 +226,9 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, SourceRange(TypeRange.getBegin(), RParenLoc), DeclarationName(), - IK_Direct, + InitializationKind::CreateDirect(TypeRange.getBegin(), + LParenLoc, + RParenLoc), ConstructorArgs); if (!Constructor) @@ -322,9 +324,9 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, } } - //FIXME: Store DeclaratorInfo in CXXNew expression. - DeclaratorInfo *DInfo = 0; - QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, &DInfo); + //FIXME: Store TypeSourceInfo in CXXNew expression. + TypeSourceInfo *TInfo = 0; + QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, &TInfo); if (D.isInvalidType()) return ExprError(); @@ -450,12 +452,17 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, // Skip all the checks. } else if ((RT = AllocType->getAs<RecordType>()) && !AllocType->isAggregateType()) { + InitializationKind InitKind = InitializationKind::CreateDefault(TypeLoc); + if (NumConsArgs > 0) + InitKind = InitializationKind::CreateDirect(TypeLoc, + PlacementLParen, + PlacementRParen); Constructor = PerformInitializationByConstructor( AllocType, move(ConstructorArgs), TypeLoc, SourceRange(TypeLoc, ConstructorRParen), RT->getDecl()->getDeclName(), - NumConsArgs != 0 ? IK_Direct : IK_Default, + InitKind, ConvertedConstructorArgs); if (!Constructor) return ExprError(); @@ -602,7 +609,8 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, Alloc != AllocEnd; ++Alloc) { // Even member operator new/delete are implicitly treated as // static, so don't use AddMemberCandidate. - if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(*Alloc)) { + if (FunctionDecl *Fn = + dyn_cast<FunctionDecl>((*Alloc)->getUnderlyingDecl())) { AddOverloadCandidate(Fn, Args, NumArgs, Candidates, /*SuppressUserConversions=*/false); continue; @@ -761,10 +769,10 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, &BadAllocType); FunctionDecl *Alloc = FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name, - FnType, /*DInfo=*/0, FunctionDecl::None, false, true); + FnType, /*TInfo=*/0, FunctionDecl::None, false, true); Alloc->setImplicit(); ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(), - 0, Argument, /*DInfo=*/0, + 0, Argument, /*TInfo=*/0, VarDecl::None, 0); Alloc->setParams(Context, &Param, 1); @@ -1270,6 +1278,16 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // Nothing else to do. break; + case ICK_NoReturn_Adjustment: + // If both sides are functions (or pointers/references to them), there could + // be incompatible exception declarations. + if (CheckExceptionSpecCompatibility(From, ToType)) + return true; + + ImpCastExprToType(From, Context.getNoReturnType(From->getType(), false), + CastExpr::CK_NoOp); + break; + case ICK_Integral_Promotion: case ICK_Integral_Conversion: ImpCastExprToType(From, ToType, CastExpr::CK_IntegralCast); @@ -1574,7 +1592,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, OverloadCandidateSet::iterator Best; switch (Self.BestViableFunction(CandidateSet, Loc, Best)) { - case Sema::OR_Success: + case OR_Success: // We found a match. Perform the conversions on the arguments and move on. if (Self.PerformImplicitConversion(LHS, Best->BuiltinTypes.ParamTypes[0], Best->Conversions[0], "converting") || @@ -1583,13 +1601,13 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, break; return false; - case Sema::OR_No_Viable_Function: + case OR_No_Viable_Function: Self.Diag(Loc, diag::err_typecheck_cond_incompatible_operands) << LHS->getType() << RHS->getType() << LHS->getSourceRange() << RHS->getSourceRange(); return true; - case Sema::OR_Ambiguous: + case OR_Ambiguous: Self.Diag(Loc, diag::err_conditional_ambiguous_ovl) << LHS->getType() << RHS->getType() << LHS->getSourceRange() << RHS->getSourceRange(); @@ -1597,7 +1615,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, // the viable candidates. break; - case Sema::OR_Deleted: + case OR_Deleted: assert(false && "Conditional operator has only built-in overloads"); break; } @@ -1788,6 +1806,11 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, QualType Composite = FindCompositePointerType(LHS, RHS); if (!Composite.isNull()) return Composite; + + // Similarly, attempt to find composite type of twp objective-c pointers. + Composite = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc); + if (!Composite.isNull()) + return Composite; // Fourth bullet is same for pointers-to-member. However, the possible // conversions are far more limited: we have null-to-pointer, upcast of @@ -1882,8 +1905,8 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { assert(getLangOptions().CPlusPlus && "This function assumes C++"); QualType T1 = E1->getType(), T2 = E2->getType(); - if (!T1->isPointerType() && !T1->isMemberPointerType() && - !T2->isPointerType() && !T2->isMemberPointerType()) + if (!T1->isAnyPointerType() && !T1->isMemberPointerType() && + !T2->isAnyPointerType() && !T2->isMemberPointerType()) return QualType(); // C++0x 5.9p2 @@ -2070,14 +2093,17 @@ Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr, bool ShouldDestroyTemps) { assert(SubExpr && "sub expression can't be null!"); - if (ExprTemporaries.empty()) + unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries; + assert(ExprTemporaries.size() >= FirstTemporary); + if (ExprTemporaries.size() == FirstTemporary) return SubExpr; Expr *E = CXXExprWithTemporaries::Create(Context, SubExpr, - &ExprTemporaries[0], - ExprTemporaries.size(), + &ExprTemporaries[FirstTemporary], + ExprTemporaries.size() - FirstTemporary, ShouldDestroyTemps); - ExprTemporaries.clear(); + ExprTemporaries.erase(ExprTemporaries.begin() + FirstTemporary, + ExprTemporaries.end()); return E; } @@ -2164,15 +2190,13 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, CXXMethodDecl *Method) { + if (PerformObjectArgumentInitialization(Exp, Method)) + assert(0 && "Calling BuildCXXMemberCallExpr with invalid call?"); + MemberExpr *ME = new (Context) MemberExpr(Exp, /*IsArrow=*/false, Method, SourceLocation(), Method->getType()); - QualType ResultType; - if (const CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(Method)) - ResultType = Conv->getConversionType().getNonReferenceType(); - else - ResultType = Method->getResultType().getNonReferenceType(); - + QualType ResultType = Method->getResultType().getNonReferenceType(); MarkDeclarationReferenced(Exp->getLocStart(), Method); CXXMemberCallExpr *CE = new (Context) CXXMemberCallExpr(Context, ME, 0, 0, ResultType, @@ -2208,11 +2232,7 @@ Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc, case CastExpr::CK_UserDefinedConversion: { assert(!From->getType()->isPointerType() && "Arg can't have pointer type!"); - - // Cast to base if needed. - if (PerformObjectArgumentInitialization(From, Method)) - return ExprError(); - + // Create an implicit call expr that calls it. CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method); return MaybeBindToTemporary(CE); diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 2eba704..4518465 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -15,11 +15,13 @@ // //===----------------------------------------------------------------------===// +#include "SemaInit.h" #include "Sema.h" #include "clang/Parse/Designator.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "llvm/Support/ErrorHandling.h" #include <map> using namespace clang; @@ -76,7 +78,7 @@ static bool CheckSingleInitializer(Expr *&Init, QualType DeclType, OverloadCandidateSet CandidateSet; if (S.IsUserDefinedConversion(Init, DeclType, ICS.UserDefined, CandidateSet, - true, false, false) != S.OR_Ambiguous) + true, false, false) != OR_Ambiguous) return S.Diag(Init->getSourceRange().getBegin(), diag::err_typecheck_convert_incompatible) << DeclType << Init->getType() << "initializing" @@ -230,13 +232,20 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType, ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + // FIXME: Poor location information + InitializationKind InitKind + = InitializationKind::CreateCopy(Init->getLocStart(), + SourceLocation()); + if (DirectInit) + InitKind = InitializationKind::CreateDirect(Init->getLocStart(), + SourceLocation(), + SourceLocation()); CXXConstructorDecl *Constructor = PerformInitializationByConstructor(DeclType, MultiExprArg(*this, (void **)&Init, 1), InitLoc, Init->getSourceRange(), - InitEntity, - DirectInit? IK_Direct : IK_Copy, + InitEntity, InitKind, ConstructorArgs); if (!Constructor) return true; @@ -637,8 +646,8 @@ void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T, if (T->isScalarType() && !TopLevelObject) SemaRef.Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init) << IList->getSourceRange() - << CodeModificationHint::CreateRemoval(SourceRange(IList->getLocStart())) - << CodeModificationHint::CreateRemoval(SourceRange(IList->getLocEnd())); + << CodeModificationHint::CreateRemoval(IList->getLocStart()) + << CodeModificationHint::CreateRemoval(IList->getLocEnd()); } void InitListChecker::CheckListElementTypes(InitListExpr *IList, @@ -1875,12 +1884,13 @@ bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) { if (ClassDecl->hasUserDeclaredConstructor()) { ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + // FIXME: Poor location information CXXConstructorDecl *Constructor = PerformInitializationByConstructor(Type, MultiExprArg(*this, 0, 0), Loc, SourceRange(Loc), DeclarationName(), - IK_Direct, + InitializationKind::CreateValue(Loc, Loc, Loc), ConstructorArgs); if (!Constructor) return true; @@ -1908,3 +1918,1379 @@ bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) { return false; } + +//===----------------------------------------------------------------------===// +// Initialization entity +//===----------------------------------------------------------------------===// + +void InitializedEntity::InitDeclLoc() { + assert((Kind == EK_Variable || Kind == EK_Parameter || Kind == EK_Member) && + "InitDeclLoc cannot be used with non-declaration entities."); + + if (TypeSourceInfo *DI = VariableOrMember->getTypeSourceInfo()) { + TL = DI->getTypeLoc(); + return; + } + + // FIXME: Once we've gone through the effort to create the fake + // TypeSourceInfo, should we cache it in the declaration? + // (If not, we "leak" it). + TypeSourceInfo *DI = VariableOrMember->getASTContext() + .CreateTypeSourceInfo(VariableOrMember->getType()); + DI->getTypeLoc().initialize(VariableOrMember->getLocation()); + TL = DI->getTypeLoc(); +} + +InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context, + CXXBaseSpecifier *Base) +{ + InitializedEntity Result; + Result.Kind = EK_Base; + Result.Base = Base; + // FIXME: CXXBaseSpecifier should store a TypeLoc. + TypeSourceInfo *DI = Context.CreateTypeSourceInfo(Base->getType()); + DI->getTypeLoc().initialize(Base->getSourceRange().getBegin()); + Result.TL = DI->getTypeLoc(); + return Result; +} + +//===----------------------------------------------------------------------===// +// Initialization sequence +//===----------------------------------------------------------------------===// + +void InitializationSequence::Step::Destroy() { + switch (Kind) { + case SK_ResolveAddressOfOverloadedFunction: + case SK_CastDerivedToBaseRValue: + case SK_CastDerivedToBaseLValue: + case SK_BindReference: + case SK_BindReferenceToTemporary: + case SK_UserConversion: + case SK_QualificationConversionRValue: + case SK_QualificationConversionLValue: + case SK_ListInitialization: + case SK_ConstructorInitialization: + case SK_ZeroInitialization: + break; + + case SK_ConversionSequence: + delete ICS; + } +} + +void InitializationSequence::AddAddressOverloadResolutionStep( + FunctionDecl *Function) { + Step S; + S.Kind = SK_ResolveAddressOfOverloadedFunction; + S.Type = Function->getType(); + S.Function = Function; + Steps.push_back(S); +} + +void InitializationSequence::AddDerivedToBaseCastStep(QualType BaseType, + bool IsLValue) { + Step S; + S.Kind = IsLValue? SK_CastDerivedToBaseLValue : SK_CastDerivedToBaseRValue; + S.Type = BaseType; + Steps.push_back(S); +} + +void InitializationSequence::AddReferenceBindingStep(QualType T, + bool BindingTemporary) { + Step S; + S.Kind = BindingTemporary? SK_BindReferenceToTemporary : SK_BindReference; + S.Type = T; + Steps.push_back(S); +} + +void InitializationSequence::AddUserConversionStep(FunctionDecl *Function, + QualType T) { + Step S; + S.Kind = SK_UserConversion; + S.Type = T; + S.Function = Function; + Steps.push_back(S); +} + +void InitializationSequence::AddQualificationConversionStep(QualType Ty, + bool IsLValue) { + Step S; + S.Kind = IsLValue? SK_QualificationConversionLValue + : SK_QualificationConversionRValue; + S.Type = Ty; + Steps.push_back(S); +} + +void InitializationSequence::AddConversionSequenceStep( + const ImplicitConversionSequence &ICS, + QualType T) { + Step S; + S.Kind = SK_ConversionSequence; + S.Type = T; + S.ICS = new ImplicitConversionSequence(ICS); + Steps.push_back(S); +} + +void InitializationSequence::AddListInitializationStep(QualType T) { + Step S; + S.Kind = SK_ListInitialization; + S.Type = T; + Steps.push_back(S); +} + +void +InitializationSequence::AddConstructorInitializationStep( + CXXConstructorDecl *Constructor, + QualType T) { + Step S; + S.Kind = SK_ConstructorInitialization; + S.Type = T; + S.Function = Constructor; + Steps.push_back(S); +} + +void InitializationSequence::AddZeroInitializationStep(QualType T) { + Step S; + S.Kind = SK_ZeroInitialization; + S.Type = T; + Steps.push_back(S); +} + +void InitializationSequence::SetOverloadFailure(FailureKind Failure, + OverloadingResult Result) { + SequenceKind = FailedSequence; + this->Failure = Failure; + this->FailedOverloadResult = Result; +} + +//===----------------------------------------------------------------------===// +// Attempt initialization +//===----------------------------------------------------------------------===// + +/// \brief Attempt list initialization (C++0x [dcl.init.list]) +static void TryListInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + InitListExpr *InitList, + InitializationSequence &Sequence) { + // FIXME: We only perform rudimentary checking of list + // initializations at this point, then assume that any list + // initialization of an array, aggregate, or scalar will be + // well-formed. We we actually "perform" list initialization, we'll + // do all of the necessary checking. C++0x initializer lists will + // force us to perform more checking here. + Sequence.setSequenceKind(InitializationSequence::ListInitialization); + + QualType DestType = Entity.getType().getType(); + + // C++ [dcl.init]p13: + // If T is a scalar type, then a declaration of the form + // + // T x = { a }; + // + // is equivalent to + // + // T x = a; + if (DestType->isScalarType()) { + if (InitList->getNumInits() > 1 && S.getLangOptions().CPlusPlus) { + Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForScalar); + return; + } + + // Assume scalar initialization from a single value works. + } else if (DestType->isAggregateType()) { + // Assume aggregate initialization works. + } else if (DestType->isVectorType()) { + // Assume vector initialization works. + } else if (DestType->isReferenceType()) { + // FIXME: C++0x defines behavior for this. + Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList); + return; + } else if (DestType->isRecordType()) { + // FIXME: C++0x defines behavior for this + Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType); + } + + // Add a general "list initialization" step. + Sequence.AddListInitializationStep(DestType); +} + +/// \brief Try a reference initialization that involves calling a conversion +/// function. +/// +/// FIXME: look intos DRs 656, 896 +static OverloadingResult TryRefInitWithConversionFunction(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr *Initializer, + bool AllowRValues, + InitializationSequence &Sequence) { + QualType DestType = Entity.getType().getType(); + QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType(); + QualType T1 = cv1T1.getUnqualifiedType(); + QualType cv2T2 = Initializer->getType(); + QualType T2 = cv2T2.getUnqualifiedType(); + + bool DerivedToBase; + assert(!S.CompareReferenceRelationship(Initializer->getLocStart(), + T1, T2, DerivedToBase) && + "Must have incompatible references when binding via conversion"); + (void)DerivedToBase; + + // Build the candidate set directly in the initialization sequence + // structure, so that it will persist if we fail. + OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); + CandidateSet.clear(); + + // Determine whether we are allowed to call explicit constructors or + // explicit conversion operators. + bool AllowExplicit = Kind.getKind() == InitializationKind::IK_Direct; + + const RecordType *T1RecordType = 0; + if (AllowRValues && (T1RecordType = T1->getAs<RecordType>())) { + // The type we're converting to is a class type. Enumerate its constructors + // to see if there is a suitable conversion. + CXXRecordDecl *T1RecordDecl = cast<CXXRecordDecl>(T1RecordType->getDecl()); + + DeclarationName ConstructorName + = S.Context.DeclarationNames.getCXXConstructorName( + S.Context.getCanonicalType(T1).getUnqualifiedType()); + DeclContext::lookup_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = T1RecordDecl->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 (!Constructor->isInvalidDecl() && + Constructor->isConvertingConstructor(AllowExplicit)) { + if (ConstructorTmpl) + S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0, + &Initializer, 1, CandidateSet); + else + S.AddOverloadCandidate(Constructor, &Initializer, 1, CandidateSet); + } + } + } + + if (const RecordType *T2RecordType = T2->getAs<RecordType>()) { + // The type we're converting from is a class type, enumerate its conversion + // functions. + CXXRecordDecl *T2RecordDecl = cast<CXXRecordDecl>(T2RecordType->getDecl()); + + // Determine the type we are converting to. If we are allowed to + // convert to an rvalue, take the type that the destination type + // refers to. + QualType ToType = AllowRValues? cv1T1 : DestType; + + const UnresolvedSet *Conversions + = T2RecordDecl->getVisibleConversionFunctions(); + for (UnresolvedSet::iterator I = Conversions->begin(), + E = Conversions->end(); + I != E; ++I) { + NamedDecl *D = *I; + CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext()); + if (isa<UsingShadowDecl>(D)) + D = cast<UsingShadowDecl>(D)->getTargetDecl(); + + FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D); + CXXConversionDecl *Conv; + if (ConvTemplate) + Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl()); + else + Conv = cast<CXXConversionDecl>(*I); + + // If the conversion function doesn't return a reference type, + // it can't be considered for this conversion unless we're allowed to + // consider rvalues. + // FIXME: Do we need to make sure that we only consider conversion + // candidates with reference-compatible results? That might be needed to + // break recursion. + if ((AllowExplicit || !Conv->isExplicit()) && + (AllowRValues || Conv->getConversionType()->isLValueReferenceType())){ + if (ConvTemplate) + S.AddTemplateConversionCandidate(ConvTemplate, ActingDC, Initializer, + ToType, CandidateSet); + else + S.AddConversionCandidate(Conv, ActingDC, Initializer, cv1T1, + CandidateSet); + } + } + } + + SourceLocation DeclLoc = Initializer->getLocStart(); + + // Perform overload resolution. If it fails, return the failed result. + OverloadCandidateSet::iterator Best; + if (OverloadingResult Result + = S.BestViableFunction(CandidateSet, DeclLoc, Best)) + return Result; + + FunctionDecl *Function = Best->Function; + + // Compute the returned type of the conversion. + if (isa<CXXConversionDecl>(Function)) + T2 = Function->getResultType(); + else + T2 = cv1T1; + + // Add the user-defined conversion step. + Sequence.AddUserConversionStep(Function, T2.getNonReferenceType()); + + // Determine whether we need to perform derived-to-base or + // cv-qualification adjustments. + bool NewDerivedToBase = false; + Sema::ReferenceCompareResult NewRefRelationship + = S.CompareReferenceRelationship(DeclLoc, T1, T2.getNonReferenceType(), + NewDerivedToBase); + assert(NewRefRelationship != Sema::Ref_Incompatible && + "Overload resolution picked a bad conversion function"); + (void)NewRefRelationship; + if (NewDerivedToBase) + Sequence.AddDerivedToBaseCastStep( + S.Context.getQualifiedType(T1, + T2.getNonReferenceType().getQualifiers()), + /*isLValue=*/true); + + if (cv1T1.getQualifiers() != T2.getNonReferenceType().getQualifiers()) + Sequence.AddQualificationConversionStep(cv1T1, T2->isReferenceType()); + + Sequence.AddReferenceBindingStep(cv1T1, !T2->isReferenceType()); + return OR_Success; +} + +/// \brief Attempt reference initialization (C++0x [dcl.init.list]) +static void TryReferenceInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr *Initializer, + InitializationSequence &Sequence) { + Sequence.setSequenceKind(InitializationSequence::ReferenceBinding); + + QualType DestType = Entity.getType().getType(); + QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType(); + QualType T1 = cv1T1.getUnqualifiedType(); + QualType cv2T2 = Initializer->getType(); + QualType T2 = cv2T2.getUnqualifiedType(); + SourceLocation DeclLoc = Initializer->getLocStart(); + + // If the initializer is the address of an overloaded function, try + // to resolve the overloaded function. If all goes well, T2 is the + // type of the resulting function. + if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) { + FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(Initializer, + T1, + false); + if (!Fn) { + Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); + return; + } + + Sequence.AddAddressOverloadResolutionStep(Fn); + cv2T2 = Fn->getType(); + T2 = cv2T2.getUnqualifiedType(); + } + + // FIXME: Rvalue references + bool ForceRValue = false; + + // Compute some basic properties of the types and the initializer. + bool isLValueRef = DestType->isLValueReferenceType(); + bool isRValueRef = !isLValueRef; + bool DerivedToBase = false; + Expr::isLvalueResult InitLvalue = ForceRValue ? Expr::LV_InvalidExpression : + Initializer->isLvalue(S.Context); + Sema::ReferenceCompareResult RefRelationship + = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase); + + // C++0x [dcl.init.ref]p5: + // A reference to type "cv1 T1" is initialized by an expression of type + // "cv2 T2" as follows: + // + // - If the reference is an lvalue reference and the initializer + // expression + OverloadingResult ConvOvlResult = OR_Success; + if (isLValueRef) { + if (InitLvalue == Expr::LV_Valid && + RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { + // - is an lvalue (but is not a bit-field), and "cv1 T1" is + // reference-compatible with "cv2 T2," or + // + // Per C++ [over.best.ics]p2, we ignore whether the lvalue is a + // bit-field when we're determining whether the reference initialization + // can occur. This property will be checked by PerformInitialization. + if (DerivedToBase) + Sequence.AddDerivedToBaseCastStep( + S.Context.getQualifiedType(T1, cv2T2.getQualifiers()), + /*isLValue=*/true); + if (cv1T1.getQualifiers() != cv2T2.getQualifiers()) + Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/true); + Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/false); + return; + } + + // - has a class type (i.e., T2 is a class type), where T1 is not + // reference-related to T2, and can be implicitly converted to an + // lvalue of type "cv3 T3," where "cv1 T1" is reference-compatible + // with "cv3 T3" (this conversion is selected by enumerating the + // applicable conversion functions (13.3.1.6) and choosing the best + // one through overload resolution (13.3)), + if (RefRelationship == Sema::Ref_Incompatible && T2->isRecordType()) { + ConvOvlResult = TryRefInitWithConversionFunction(S, Entity, Kind, + Initializer, + /*AllowRValues=*/false, + Sequence); + if (ConvOvlResult == OR_Success) + return; + } + } + + // - Otherwise, the reference shall be an lvalue reference to a + // non-volatile const type (i.e., cv1 shall be const), or the reference + // shall be an rvalue reference and the initializer expression shall + // be an rvalue. + if (!((isLValueRef && cv1T1.getCVRQualifiers() == Qualifiers::Const) || + (isRValueRef && InitLvalue != Expr::LV_Valid))) { + if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty()) + Sequence.SetOverloadFailure( + InitializationSequence::FK_ReferenceInitOverloadFailed, + ConvOvlResult); + else if (isLValueRef) + Sequence.SetFailed(InitLvalue == Expr::LV_Valid + ? (RefRelationship == Sema::Ref_Related + ? InitializationSequence::FK_ReferenceInitDropsQualifiers + : InitializationSequence::FK_NonConstLValueReferenceBindingToUnrelated) + : InitializationSequence::FK_NonConstLValueReferenceBindingToTemporary); + else + Sequence.SetFailed( + InitializationSequence::FK_RValueReferenceBindingToLValue); + + return; + } + + // - If T1 and T2 are class types and + if (T1->isRecordType() && T2->isRecordType()) { + // - the initializer expression is an rvalue and "cv1 T1" is + // reference-compatible with "cv2 T2", or + if (InitLvalue != Expr::LV_Valid && + RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { + if (DerivedToBase) + Sequence.AddDerivedToBaseCastStep( + S.Context.getQualifiedType(T1, cv2T2.getQualifiers()), + /*isLValue=*/false); + if (cv1T1.getQualifiers() != cv2T2.getQualifiers()) + Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/false); + Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true); + return; + } + + // - T1 is not reference-related to T2 and the initializer expression + // can be implicitly converted to an rvalue of type "cv3 T3" (this + // conversion is selected by enumerating the applicable conversion + // functions (13.3.1.6) and choosing the best one through overload + // resolution (13.3)), + if (RefRelationship == Sema::Ref_Incompatible) { + ConvOvlResult = TryRefInitWithConversionFunction(S, Entity, + Kind, Initializer, + /*AllowRValues=*/true, + Sequence); + if (ConvOvlResult) + Sequence.SetOverloadFailure( + InitializationSequence::FK_ReferenceInitOverloadFailed, + ConvOvlResult); + + return; + } + + Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers); + return; + } + + // - If the initializer expression is an rvalue, with T2 an array type, + // and "cv1 T1" is reference-compatible with "cv2 T2," the reference + // is bound to the object represented by the rvalue (see 3.10). + // FIXME: How can an array type be reference-compatible with anything? + // Don't we mean the element types of T1 and T2? + + // - Otherwise, a temporary of type “cv1 T1” is created and initialized + // from the initializer expression using the rules for a non-reference + // copy initialization (8.5). The reference is then bound to the + // temporary. [...] + // Determine whether we are allowed to call explicit constructors or + // explicit conversion operators. + bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct); + ImplicitConversionSequence ICS + = S.TryImplicitConversion(Initializer, cv1T1, + /*SuppressUserConversions=*/false, AllowExplicit, + /*ForceRValue=*/false, + /*FIXME:InOverloadResolution=*/false, + /*UserCast=*/Kind.isExplicitCast()); + + if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) { + // FIXME: Use the conversion function set stored in ICS to turn + // this into an overloading ambiguity diagnostic. However, we need + // to keep that set as an OverloadCandidateSet rather than as some + // other kind of set. + Sequence.SetFailed(InitializationSequence::FK_ReferenceInitFailed); + return; + } + + // [...] If T1 is reference-related to T2, cv1 must be the + // same cv-qualification as, or greater cv-qualification + // than, cv2; otherwise, the program is ill-formed. + if (RefRelationship == Sema::Ref_Related && + !cv1T1.isAtLeastAsQualifiedAs(cv2T2)) { + Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers); + return; + } + + // Perform the actual conversion. + Sequence.AddConversionSequenceStep(ICS, cv1T1); + Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true); + return; +} + +/// \brief Attempt character array initialization from a string literal +/// (C++ [dcl.init.string], C99 6.7.8). +static void TryStringLiteralInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr *Initializer, + InitializationSequence &Sequence) { + // FIXME: Implement! +} + +/// \brief Attempt initialization by constructor (C++ [dcl.init]), which +/// enumerates the constructors of the initialized entity and performs overload +/// resolution to select the best. +static void TryConstructorInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr **Args, unsigned NumArgs, + QualType DestType, + InitializationSequence &Sequence) { + Sequence.setSequenceKind(InitializationSequence::ConstructorInitialization); + + // Build the candidate set directly in the initialization sequence + // structure, so that it will persist if we fail. + OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); + CandidateSet.clear(); + + // Determine whether we are allowed to call explicit constructors or + // explicit conversion operators. + bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct || + Kind.getKind() == InitializationKind::IK_Value || + Kind.getKind() == InitializationKind::IK_Default); + + // The type we're converting to is a class type. Enumerate its constructors + // to see if one is suitable. + const RecordType *DestRecordType = DestType->getAs<RecordType>(); + assert(DestRecordType && "Constructor initialization requires record type"); + CXXRecordDecl *DestRecordDecl + = cast<CXXRecordDecl>(DestRecordType->getDecl()); + + DeclarationName ConstructorName + = S.Context.DeclarationNames.getCXXConstructorName( + S.Context.getCanonicalType(DestType).getUnqualifiedType()); + DeclContext::lookup_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = DestRecordDecl->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 (!Constructor->isInvalidDecl() && + Constructor->isConvertingConstructor(AllowExplicit)) { + if (ConstructorTmpl) + S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0, + Args, NumArgs, CandidateSet); + else + S.AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet); + } + } + + SourceLocation DeclLoc = Kind.getLocation(); + + // Perform overload resolution. If it fails, return the failed result. + OverloadCandidateSet::iterator Best; + if (OverloadingResult Result + = S.BestViableFunction(CandidateSet, DeclLoc, Best)) { + Sequence.SetOverloadFailure( + InitializationSequence::FK_ConstructorOverloadFailed, + Result); + return; + } + + // Add the constructor initialization step. Any cv-qualification conversion is + // subsumed by the initialization. + Sequence.AddConstructorInitializationStep( + cast<CXXConstructorDecl>(Best->Function), + DestType); +} + +/// \brief Attempt value initialization (C++ [dcl.init]p7). +static void TryValueInitialization(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + InitializationSequence &Sequence) { + // C++ [dcl.init]p5: + // + // To value-initialize an object of type T means: + QualType T = Entity.getType().getType(); + + // -- if T is an array type, then each element is value-initialized; + while (const ArrayType *AT = S.Context.getAsArrayType(T)) + T = AT->getElementType(); + + if (const RecordType *RT = T->getAs<RecordType>()) { + if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { + // -- if T is a class type (clause 9) with a user-declared + // constructor (12.1), then the default constructor for T is + // called (and the initialization is ill-formed if T has no + // accessible default constructor); + // + // FIXME: we really want to refer to a single subobject of the array, + // but Entity doesn't have a way to capture that (yet). + if (ClassDecl->hasUserDeclaredConstructor()) + return TryConstructorInitialization(S, Entity, Kind, 0, 0, T, Sequence); + + // FIXME: non-union class type w/ non-trivial default constructor gets + // zero-initialized, then constructor gets called. + } + } + + Sequence.AddZeroInitializationStep(Entity.getType().getType()); + Sequence.setSequenceKind(InitializationSequence::ZeroInitialization); +} + +/// \brief Attempt a user-defined conversion between two types (C++ [dcl.init]), +/// which enumerates all conversion functions and performs overload resolution +/// to select the best. +static void TryUserDefinedConversion(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr *Initializer, + InitializationSequence &Sequence) { + Sequence.setSequenceKind(InitializationSequence::UserDefinedConversion); + + QualType DestType = Entity.getType().getType(); + assert(!DestType->isReferenceType() && "References are handled elsewhere"); + QualType SourceType = Initializer->getType(); + assert((DestType->isRecordType() || SourceType->isRecordType()) && + "Must have a class type to perform a user-defined conversion"); + + // Build the candidate set directly in the initialization sequence + // structure, so that it will persist if we fail. + OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); + CandidateSet.clear(); + + // Determine whether we are allowed to call explicit constructors or + // explicit conversion operators. + bool AllowExplicit = Kind.getKind() == InitializationKind::IK_Direct; + + if (const RecordType *DestRecordType = DestType->getAs<RecordType>()) { + // The type we're converting to is a class type. Enumerate its constructors + // to see if there is a suitable conversion. + CXXRecordDecl *DestRecordDecl + = cast<CXXRecordDecl>(DestRecordType->getDecl()); + + DeclarationName ConstructorName + = S.Context.DeclarationNames.getCXXConstructorName( + S.Context.getCanonicalType(DestType).getUnqualifiedType()); + DeclContext::lookup_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = DestRecordDecl->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 (!Constructor->isInvalidDecl() && + Constructor->isConvertingConstructor(AllowExplicit)) { + if (ConstructorTmpl) + S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0, + &Initializer, 1, CandidateSet); + else + S.AddOverloadCandidate(Constructor, &Initializer, 1, CandidateSet); + } + } + } + + if (const RecordType *SourceRecordType = SourceType->getAs<RecordType>()) { + // The type we're converting from is a class type, enumerate its conversion + // functions. + CXXRecordDecl *SourceRecordDecl + = cast<CXXRecordDecl>(SourceRecordType->getDecl()); + + const UnresolvedSet *Conversions + = SourceRecordDecl->getVisibleConversionFunctions(); + for (UnresolvedSet::iterator I = Conversions->begin(), + E = Conversions->end(); + I != E; ++I) { + NamedDecl *D = *I; + CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext()); + if (isa<UsingShadowDecl>(D)) + D = cast<UsingShadowDecl>(D)->getTargetDecl(); + + FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D); + CXXConversionDecl *Conv; + if (ConvTemplate) + Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl()); + else + Conv = cast<CXXConversionDecl>(*I); + + if (AllowExplicit || !Conv->isExplicit()) { + if (ConvTemplate) + S.AddTemplateConversionCandidate(ConvTemplate, ActingDC, Initializer, + DestType, CandidateSet); + else + S.AddConversionCandidate(Conv, ActingDC, Initializer, DestType, + CandidateSet); + } + } + } + + SourceLocation DeclLoc = Initializer->getLocStart(); + + // Perform overload resolution. If it fails, return the failed result. + OverloadCandidateSet::iterator Best; + if (OverloadingResult Result + = S.BestViableFunction(CandidateSet, DeclLoc, Best)) { + Sequence.SetOverloadFailure( + InitializationSequence::FK_UserConversionOverloadFailed, + Result); + return; + } + + FunctionDecl *Function = Best->Function; + + if (isa<CXXConstructorDecl>(Function)) { + // Add the user-defined conversion step. Any cv-qualification conversion is + // subsumed by the initialization. + Sequence.AddUserConversionStep(Function, DestType); + return; + } + + // Add the user-defined conversion step that calls the conversion function. + QualType ConvType = Function->getResultType().getNonReferenceType(); + Sequence.AddUserConversionStep(Function, ConvType); + + // If the conversion following the call to the conversion function is + // interesting, add it as a separate step. + if (Best->FinalConversion.First || Best->FinalConversion.Second || + Best->FinalConversion.Third) { + ImplicitConversionSequence ICS; + ICS.ConversionKind = ImplicitConversionSequence::StandardConversion; + ICS.Standard = Best->FinalConversion; + Sequence.AddConversionSequenceStep(ICS, DestType); + } +} + +/// \brief Attempt an implicit conversion (C++ [conv]) converting from one +/// non-class type to another. +static void TryImplicitConversion(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr *Initializer, + InitializationSequence &Sequence) { + ImplicitConversionSequence ICS + = S.TryImplicitConversion(Initializer, Entity.getType().getType(), + /*SuppressUserConversions=*/true, + /*AllowExplicit=*/false, + /*ForceRValue=*/false, + /*FIXME:InOverloadResolution=*/false, + /*UserCast=*/Kind.isExplicitCast()); + + if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) { + Sequence.SetFailed(InitializationSequence::FK_ConversionFailed); + return; + } + + Sequence.AddConversionSequenceStep(ICS, Entity.getType().getType()); +} + +InitializationSequence::InitializationSequence(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr **Args, + unsigned NumArgs) { + ASTContext &Context = S.Context; + + // C++0x [dcl.init]p16: + // The semantics of initializers are as follows. The destination type is + // the type of the object or reference being initialized and the source + // type is the type of the initializer expression. The source type is not + // defined when the initializer is a braced-init-list or when it is a + // parenthesized list of expressions. + QualType DestType = Entity.getType().getType(); + + if (DestType->isDependentType() || + Expr::hasAnyTypeDependentArguments(Args, NumArgs)) { + SequenceKind = DependentSequence; + return; + } + + QualType SourceType; + Expr *Initializer = 0; + if (Kind.getKind() == InitializationKind::IK_Copy) { + Initializer = Args[0]; + if (!isa<InitListExpr>(Initializer)) + SourceType = Initializer->getType(); + } + + // - If the initializer is a braced-init-list, the object is + // list-initialized (8.5.4). + if (InitListExpr *InitList = dyn_cast_or_null<InitListExpr>(Initializer)) { + TryListInitialization(S, Entity, Kind, InitList, *this); + return; + } + + // - If the destination type is a reference type, see 8.5.3. + if (DestType->isReferenceType()) { + // C++0x [dcl.init.ref]p1: + // A variable declared to be a T& or T&&, that is, "reference to type T" + // (8.3.2), shall be initialized by an object, or function, of type T or + // by an object that can be converted into a T. + // (Therefore, multiple arguments are not permitted.) + if (NumArgs != 1) + SetFailed(FK_TooManyInitsForReference); + else + TryReferenceInitialization(S, Entity, Kind, Args[0], *this); + return; + } + + // - If the destination type is an array of characters, an array of + // char16_t, an array of char32_t, or an array of wchar_t, and the + // initializer is a string literal, see 8.5.2. + if (Initializer && IsStringInit(Initializer, DestType, Context)) { + TryStringLiteralInitialization(S, Entity, Kind, Initializer, *this); + return; + } + + // - If the initializer is (), the object is value-initialized. + if (Kind.getKind() == InitializationKind::IK_Value) { + TryValueInitialization(S, Entity, Kind, *this); + return; + } + + // - Otherwise, if the destination type is an array, the program is + // ill-formed. + if (const ArrayType *AT = Context.getAsArrayType(DestType)) { + if (AT->getElementType()->isAnyCharacterType()) + SetFailed(FK_ArrayNeedsInitListOrStringLiteral); + else + SetFailed(FK_ArrayNeedsInitList); + + return; + } + + // - If the destination type is a (possibly cv-qualified) class type: + if (DestType->isRecordType()) { + // - 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. [...] + if (Kind.getKind() == InitializationKind::IK_Direct || + (Kind.getKind() == InitializationKind::IK_Copy && + (Context.hasSameUnqualifiedType(SourceType, DestType) || + S.IsDerivedFrom(SourceType, DestType)))) + TryConstructorInitialization(S, Entity, Kind, Args, NumArgs, + Entity.getType().getType(), *this); + // - Otherwise (i.e., for the remaining copy-initialization cases), + // user-defined conversion sequences that can convert from the source + // type to the destination type or (when a conversion function is + // used) to a derived class thereof are enumerated as described in + // 13.3.1.4, and the best one is chosen through overload resolution + // (13.3). + else + TryUserDefinedConversion(S, Entity, Kind, Initializer, *this); + return; + } + + // - Otherwise, if the source type is a (possibly cv-qualified) class + // type, conversion functions are considered. + if (SourceType->isRecordType()) { + TryUserDefinedConversion(S, Entity, Kind, Initializer, *this); + return; + } + + // - Otherwise, the initial value of the object being initialized is the + // (possibly converted) value of the initializer expression. Standard + // conversions (Clause 4) will be used, if necessary, to convert the + // initializer expression to the cv-unqualified version of the + // destination type; no user-defined conversions are considered. + TryImplicitConversion(S, Entity, Kind, Initializer, *this); +} + +InitializationSequence::~InitializationSequence() { + for (llvm::SmallVectorImpl<Step>::iterator Step = Steps.begin(), + StepEnd = Steps.end(); + Step != StepEnd; ++Step) + Step->Destroy(); +} + +//===----------------------------------------------------------------------===// +// Perform initialization +//===----------------------------------------------------------------------===// + +Action::OwningExprResult +InitializationSequence::Perform(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Action::MultiExprArg Args, + QualType *ResultType) { + if (SequenceKind == FailedSequence) { + unsigned NumArgs = Args.size(); + Diagnose(S, Entity, Kind, (Expr **)Args.release(), NumArgs); + return S.ExprError(); + } + + if (SequenceKind == DependentSequence) { + // If the declaration is a non-dependent, incomplete array type + // that has an initializer, then its type will be completed once + // the initializer is instantiated. + if (ResultType && !Entity.getType().getType()->isDependentType() && + Args.size() == 1) { + QualType DeclType = Entity.getType().getType(); + if (const IncompleteArrayType *ArrayT + = S.Context.getAsIncompleteArrayType(DeclType)) { + // FIXME: We don't currently have the ability to accurately + // compute the length of an initializer list without + // performing full type-checking of the initializer list + // (since we have to determine where braces are implicitly + // introduced and such). So, we fall back to making the array + // type a dependently-sized array type with no specified + // bound. + if (isa<InitListExpr>((Expr *)Args.get()[0])) { + SourceRange Brackets; + // Scavange the location of the brackets from the entity, if we can. + if (isa<IncompleteArrayTypeLoc>(Entity.getType())) { + IncompleteArrayTypeLoc ArrayLoc + = cast<IncompleteArrayTypeLoc>(Entity.getType()); + Brackets = ArrayLoc.getBracketsRange(); + } + + *ResultType + = S.Context.getDependentSizedArrayType(ArrayT->getElementType(), + /*NumElts=*/0, + ArrayT->getSizeModifier(), + ArrayT->getIndexTypeCVRQualifiers(), + Brackets); + } + + } + } + + if (Kind.getKind() == InitializationKind::IK_Copy) + return Sema::OwningExprResult(S, Args.release()[0]); + + unsigned NumArgs = Args.size(); + return S.Owned(new (S.Context) ParenListExpr(S.Context, + SourceLocation(), + (Expr **)Args.release(), + NumArgs, + SourceLocation())); + } + + QualType DestType = Entity.getType().getType().getNonReferenceType(); + if (ResultType) + *ResultType = Entity.getType().getType(); + + Sema::OwningExprResult CurInit(S); + // For copy initialization and any other initialization forms that + // only have a single initializer, we start with the (only) + // initializer we have. + // FIXME: DPG is not happy about this. There's confusion regarding whether + // we're supposed to start the conversion from the solitary initializer or + // from the set of arguments. + if (Kind.getKind() == InitializationKind::IK_Copy || + SequenceKind != ConstructorInitialization) { + assert(Args.size() == 1); + CurInit = Sema::OwningExprResult(S, Args.release()[0]); + if (CurInit.isInvalid()) + return S.ExprError(); + } + + // Walk through the computed steps for the initialization sequence, + // performing the specified conversions along the way. + for (step_iterator Step = step_begin(), StepEnd = step_end(); + Step != StepEnd; ++Step) { + if (CurInit.isInvalid()) + return S.ExprError(); + + Expr *CurInitExpr = (Expr *)CurInit.get(); + QualType SourceType = CurInitExpr->getType(); + + switch (Step->Kind) { + case SK_ResolveAddressOfOverloadedFunction: + // Overload resolution determined which function invoke; update the + // initializer to reflect that choice. + CurInit = S.FixOverloadedFunctionReference(move(CurInit), Step->Function); + break; + + case SK_CastDerivedToBaseRValue: + case SK_CastDerivedToBaseLValue: { + // We have a derived-to-base cast that produces either an rvalue or an + // lvalue. Perform that cast. + + // Casts to inaccessible base classes are allowed with C-style casts. + bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast(); + if (S.CheckDerivedToBaseConversion(SourceType, Step->Type, + CurInitExpr->getLocStart(), + CurInitExpr->getSourceRange(), + IgnoreBaseAccess)) + return S.ExprError(); + + CurInit = S.Owned(new (S.Context) ImplicitCastExpr(Step->Type, + CastExpr::CK_DerivedToBase, + (Expr*)CurInit.release(), + Step->Kind == SK_CastDerivedToBaseLValue)); + break; + } + + case SK_BindReference: + if (FieldDecl *BitField = CurInitExpr->getBitField()) { + // References cannot bind to bit fields (C++ [dcl.init.ref]p5). + S.Diag(Kind.getLocation(), diag::err_reference_bind_to_bitfield) + << Entity.getType().getType().isVolatileQualified() + << BitField->getDeclName() + << CurInitExpr->getSourceRange(); + S.Diag(BitField->getLocation(), diag::note_bitfield_decl); + return S.ExprError(); + } + + // Reference binding does not have any corresponding ASTs. + + // Check exception specifications + if (S.CheckExceptionSpecCompatibility(CurInitExpr, DestType)) + return S.ExprError(); + break; + + case SK_BindReferenceToTemporary: + // Check exception specifications + if (S.CheckExceptionSpecCompatibility(CurInitExpr, DestType)) + return S.ExprError(); + + // FIXME: At present, we have no AST to describe when we need to make a + // temporary to bind a reference to. We should. + break; + + case SK_UserConversion: { + // We have a user-defined conversion that invokes either a constructor + // or a conversion function. + CastExpr::CastKind CastKind = CastExpr::CK_Unknown; + if (CXXConstructorDecl *Constructor + = dyn_cast<CXXConstructorDecl>(Step->Function)) { + // Build a call to the selected constructor. + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); + SourceLocation Loc = CurInitExpr->getLocStart(); + CurInit.release(); // Ownership transferred into MultiExprArg, below. + + // Determine the arguments required to actually perform the constructor + // call. + if (S.CompleteConstructorCall(Constructor, + Sema::MultiExprArg(S, + (void **)&CurInitExpr, + 1), + Loc, ConstructorArgs)) + return S.ExprError(); + + // Build the an expression that constructs a temporary. + CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor, + move_arg(ConstructorArgs)); + if (CurInit.isInvalid()) + return S.ExprError(); + + CastKind = CastExpr::CK_ConstructorConversion; + } else { + // Build a call to the conversion function. + CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Step->Function); + + // FIXME: Should we move this initialization into a separate + // derived-to-base conversion? I believe the answer is "no", because + // we don't want to turn off access control here for c-style casts. + if (S.PerformObjectArgumentInitialization(CurInitExpr, Conversion)) + return S.ExprError(); + + // Do a little dance to make sure that CurInit has the proper + // pointer. + CurInit.release(); + + // Build the actual call to the conversion function. + CurInit = S.Owned(S.BuildCXXMemberCallExpr(CurInitExpr, Conversion)); + if (CurInit.isInvalid() || !CurInit.get()) + return S.ExprError(); + + CastKind = CastExpr::CK_UserDefinedConversion; + } + + CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); + CurInitExpr = CurInit.takeAs<Expr>(); + CurInit = S.Owned(new (S.Context) ImplicitCastExpr(CurInitExpr->getType(), + CastKind, + CurInitExpr, + false)); + break; + } + + case SK_QualificationConversionLValue: + case SK_QualificationConversionRValue: + // Perform a qualification conversion; these can never go wrong. + S.ImpCastExprToType(CurInitExpr, Step->Type, + CastExpr::CK_NoOp, + Step->Kind == SK_QualificationConversionLValue); + CurInit.release(); + CurInit = S.Owned(CurInitExpr); + break; + + case SK_ConversionSequence: + if (S.PerformImplicitConversion(CurInitExpr, Step->Type, "converting", + false, false, *Step->ICS)) + return S.ExprError(); + + CurInit.release(); + CurInit = S.Owned(CurInitExpr); + break; + + case SK_ListInitialization: { + InitListExpr *InitList = cast<InitListExpr>(CurInitExpr); + QualType Ty = Step->Type; + if (S.CheckInitList(InitList, ResultType? *ResultType : Ty)) + return S.ExprError(); + + CurInit.release(); + CurInit = S.Owned(InitList); + break; + } + + case SK_ConstructorInitialization: { + CXXConstructorDecl *Constructor + = cast<CXXConstructorDecl>(Step->Function); + + // Build a call to the selected constructor. + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); + SourceLocation Loc = Kind.getLocation(); + + // Determine the arguments required to actually perform the constructor + // call. + if (S.CompleteConstructorCall(Constructor, move(Args), + Loc, ConstructorArgs)) + return S.ExprError(); + + // Build the an expression that constructs a temporary. + CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor, + move_arg(ConstructorArgs)); + if (CurInit.isInvalid()) + return S.ExprError(); + + CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); + break; + } + + case SK_ZeroInitialization: { + if (Kind.getKind() == InitializationKind::IK_Value) + CurInit = S.Owned(new (S.Context) CXXZeroInitValueExpr(Step->Type, + Kind.getRange().getBegin(), + Kind.getRange().getEnd())); + else + CurInit = S.Owned(new (S.Context) ImplicitValueInitExpr(Step->Type)); + break; + } + } + } + + return move(CurInit); +} + +//===----------------------------------------------------------------------===// +// Diagnose initialization failures +//===----------------------------------------------------------------------===// +bool InitializationSequence::Diagnose(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr **Args, unsigned NumArgs) { + if (SequenceKind != FailedSequence) + return false; + + QualType DestType = Entity.getType().getType(); + switch (Failure) { + case FK_TooManyInitsForReference: + S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits) + << SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd()); + break; + + case FK_ArrayNeedsInitList: + case FK_ArrayNeedsInitListOrStringLiteral: + S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) + << (Failure == FK_ArrayNeedsInitListOrStringLiteral); + break; + + case FK_AddressOfOverloadFailed: + S.ResolveAddressOfOverloadedFunction(Args[0], + DestType.getNonReferenceType(), + true); + break; + + case FK_ReferenceInitOverloadFailed: + case FK_UserConversionOverloadFailed: + switch (FailedOverloadResult) { + case OR_Ambiguous: + S.Diag(Kind.getLocation(), diag::err_typecheck_ambiguous_condition) + << Args[0]->getType() << DestType.getNonReferenceType() + << Args[0]->getSourceRange(); + S.PrintOverloadCandidates(FailedCandidateSet, true); + break; + + case OR_No_Viable_Function: + S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition) + << Args[0]->getType() << DestType.getNonReferenceType() + << Args[0]->getSourceRange(); + S.PrintOverloadCandidates(FailedCandidateSet, false); + break; + + case OR_Deleted: { + S.Diag(Kind.getLocation(), diag::err_typecheck_deleted_function) + << Args[0]->getType() << DestType.getNonReferenceType() + << Args[0]->getSourceRange(); + OverloadCandidateSet::iterator Best; + OverloadingResult Ovl = S.BestViableFunction(FailedCandidateSet, + Kind.getLocation(), + Best); + if (Ovl == OR_Deleted) { + S.Diag(Best->Function->getLocation(), diag::note_unavailable_here) + << Best->Function->isDeleted(); + } else { + llvm_unreachable("Inconsistent overload resolution?"); + } + break; + } + + case OR_Success: + llvm_unreachable("Conversion did not fail!"); + break; + } + break; + + case FK_NonConstLValueReferenceBindingToTemporary: + case FK_NonConstLValueReferenceBindingToUnrelated: + S.Diag(Kind.getLocation(), + Failure == FK_NonConstLValueReferenceBindingToTemporary + ? diag::err_lvalue_reference_bind_to_temporary + : diag::err_lvalue_reference_bind_to_unrelated) + << DestType.getNonReferenceType() + << Args[0]->getType() + << Args[0]->getSourceRange(); + break; + + case FK_RValueReferenceBindingToLValue: + S.Diag(Kind.getLocation(), diag::err_lvalue_to_rvalue_ref) + << Args[0]->getSourceRange(); + break; + + case FK_ReferenceInitDropsQualifiers: + S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals) + << DestType.getNonReferenceType() + << Args[0]->getType() + << Args[0]->getSourceRange(); + break; + + case FK_ReferenceInitFailed: + S.Diag(Kind.getLocation(), diag::err_reference_bind_failed) + << DestType.getNonReferenceType() + << (Args[0]->isLvalue(S.Context) == Expr::LV_Valid) + << Args[0]->getType() + << Args[0]->getSourceRange(); + break; + + case FK_ConversionFailed: + S.Diag(Kind.getLocation(), diag::err_cannot_initialize_decl_noname) + << DestType + << (Args[0]->isLvalue(S.Context) == Expr::LV_Valid) + << Args[0]->getType() + << Args[0]->getSourceRange(); + break; + + case FK_TooManyInitsForScalar: { + InitListExpr *InitList = cast<InitListExpr>(Args[0]); + + S.Diag(Kind.getLocation(), diag::err_excess_initializers) + << /*scalar=*/2 + << SourceRange(InitList->getInit(1)->getLocStart(), + InitList->getLocEnd()); + break; + } + + case FK_ReferenceBindingToInitList: + S.Diag(Kind.getLocation(), diag::err_reference_bind_init_list) + << DestType.getNonReferenceType() << Args[0]->getSourceRange(); + break; + + case FK_InitListBadDestinationType: + S.Diag(Kind.getLocation(), diag::err_init_list_bad_dest_type) + << (DestType->isRecordType()) << DestType << Args[0]->getSourceRange(); + break; + + case FK_ConstructorOverloadFailed: { + SourceRange ArgsRange; + if (NumArgs) + ArgsRange = SourceRange(Args[0]->getLocStart(), + Args[NumArgs - 1]->getLocEnd()); + + // FIXME: Using "DestType" for the entity we're printing is probably + // bad. + switch (FailedOverloadResult) { + case OR_Ambiguous: + S.Diag(Kind.getLocation(), diag::err_ovl_ambiguous_init) + << DestType << ArgsRange; + S.PrintOverloadCandidates(FailedCandidateSet, true); + break; + + case OR_No_Viable_Function: + S.Diag(Kind.getLocation(), diag::err_ovl_no_viable_function_in_init) + << DestType << ArgsRange; + S.PrintOverloadCandidates(FailedCandidateSet, false); + break; + + case OR_Deleted: { + S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init) + << true << DestType << ArgsRange; + OverloadCandidateSet::iterator Best; + OverloadingResult Ovl = S.BestViableFunction(FailedCandidateSet, + Kind.getLocation(), + Best); + if (Ovl == OR_Deleted) { + S.Diag(Best->Function->getLocation(), diag::note_unavailable_here) + << Best->Function->isDeleted(); + } else { + llvm_unreachable("Inconsistent overload resolution?"); + } + break; + } + + case OR_Success: + llvm_unreachable("Conversion did not fail!"); + break; + } + break; + } + } + + return true; +} diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h new file mode 100644 index 0000000..2d4b01f --- /dev/null +++ b/lib/Sema/SemaInit.h @@ -0,0 +1,579 @@ +//===--- SemaInit.h - Semantic Analysis for Initializers --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides supporting data types for initialization of objects. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_INIT_H +#define LLVM_CLANG_SEMA_INIT_H + +#include "SemaOverload.h" +#include "clang/AST/TypeLoc.h" +#include "clang/Parse/Action.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/SmallVector.h" +#include <cassert> + +namespace clang { + +class CXXBaseSpecifier; +class DeclaratorDecl; +class DeclaratorInfo; +class FieldDecl; +class FunctionDecl; +class ParmVarDecl; +class Sema; +class TypeLoc; +class VarDecl; + +/// \brief Describes an entity that is being initialized. +class InitializedEntity { +public: + /// \brief Specifies the kind of entity being initialized. + enum EntityKind { + /// \brief The entity being initialized is a variable. + EK_Variable, + /// \brief The entity being initialized is a function parameter. + EK_Parameter, + /// \brief The entity being initialized is the result of a function call. + EK_Result, + /// \brief The entity being initialized is an exception object that + /// is being thrown. + EK_Exception, + /// \brief The entity being initialized is a temporary object. + EK_Temporary, + /// \brief The entity being initialized is a base member subobject. + EK_Base, + /// \brief The entity being initialized is a non-static data member + /// subobject. + EK_Member + }; + +private: + /// \brief The kind of entity being initialized. + EntityKind Kind; + + /// \brief The type of the object or reference being initialized along with + /// its location information. + TypeLoc TL; + + union { + /// \brief When Kind == EK_Variable, EK_Parameter, or EK_Member, + /// the VarDecl, ParmVarDecl, or FieldDecl, respectively. + DeclaratorDecl *VariableOrMember; + + /// \brief When Kind == EK_Result or EK_Exception, the location of the + /// 'return' or 'throw' keyword, respectively. When Kind == EK_Temporary, + /// the location where the temporary is being created. + unsigned Location; + + /// \brief When Kind == EK_Base, the base specifier that provides the + /// base class. + CXXBaseSpecifier *Base; + }; + + InitializedEntity() { } + + /// \brief Create the initialization entity for a variable. + InitializedEntity(VarDecl *Var) + : Kind(EK_Variable), + VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Var)) + { + InitDeclLoc(); + } + + /// \brief Create the initialization entity for a parameter. + InitializedEntity(ParmVarDecl *Parm) + : Kind(EK_Parameter), + VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Parm)) + { + InitDeclLoc(); + } + + /// \brief Create the initialization entity for the result of a function, + /// throwing an object, or performing an explicit cast. + InitializedEntity(EntityKind Kind, SourceLocation Loc, TypeLoc TL) + : Kind(Kind), TL(TL), Location(Loc.getRawEncoding()) { } + + /// \brief Create the initialization entity for a member subobject. + InitializedEntity(FieldDecl *Member) + : Kind(EK_Member), + VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Member)) + { + InitDeclLoc(); + } + + /// \brief Initialize type-location information from a declaration. + void InitDeclLoc(); + +public: + /// \brief Create the initialization entity for a variable. + static InitializedEntity InitializeVariable(VarDecl *Var) { + return InitializedEntity(Var); + } + + /// \brief Create the initialization entity for a parameter. + static InitializedEntity InitializeParameter(ParmVarDecl *Parm) { + return InitializedEntity(Parm); + } + + /// \brief Create the initialization entity for the result of a function. + static InitializedEntity InitializeResult(SourceLocation ReturnLoc, + TypeLoc TL) { + return InitializedEntity(EK_Result, ReturnLoc, TL); + } + + /// \brief Create the initialization entity for an exception object. + static InitializedEntity InitializeException(SourceLocation ThrowLoc, + TypeLoc TL) { + return InitializedEntity(EK_Exception, ThrowLoc, TL); + } + + /// \brief Create the initialization entity for a temporary. + static InitializedEntity InitializeTemporary(EntityKind Kind, TypeLoc TL) { + return InitializedEntity(Kind, SourceLocation(), TL); + } + + /// \brief Create the initialization entity for a base class subobject. + static InitializedEntity InitializeBase(ASTContext &Context, + CXXBaseSpecifier *Base); + + /// \brief Create the initialize entity for a member subobject. + static InitializedEntity InitializeMember(FieldDecl *Member) { + return InitializedEntity(Member); + } + + /// \brief Determine the kind of initialization. + EntityKind getKind() const { return Kind; } + + /// \brief Retrieve type being initialized. + TypeLoc getType() const { return TL; } + + /// \brief Determine the location of the 'return' keyword when initializing + /// the result of a function call. + SourceLocation getReturnLoc() const { + assert(getKind() == EK_Result && "No 'return' location!"); + return SourceLocation::getFromRawEncoding(Location); + } + + /// \brief Determine the location of the 'throw' keyword when initializing + /// an exception object. + SourceLocation getThrowLoc() const { + assert(getKind() == EK_Exception && "No 'throw' location!"); + return SourceLocation::getFromRawEncoding(Location); + } +}; + +/// \brief Describes the kind of initialization being performed, along with +/// location information for tokens related to the initialization (equal sign, +/// parentheses). +class InitializationKind { +public: + /// \brief The kind of initialization being performed. + enum InitKind { + IK_Direct, ///< Direct initialization + IK_Copy, ///< Copy initialization + IK_Default, ///< Default initialization + IK_Value ///< Value initialization + }; + +private: + /// \brief The kind of initialization that we're storing. + enum StoredInitKind { + SIK_Direct = IK_Direct, ///< Direct initialization + SIK_Copy = IK_Copy, ///< Copy initialization + SIK_Default = IK_Default, ///< Default initialization + SIK_Value = IK_Value, ///< Value initialization + SIK_DirectCast, ///< Direct initialization due to a cast + /// \brief Direct initialization due to a C-style or functional cast. + SIK_DirectCStyleOrFunctionalCast + }; + + /// \brief The kind of initialization being performed. + StoredInitKind Kind; + + /// \brief The source locations involved in the initialization. + SourceLocation Locations[3]; + + InitializationKind(StoredInitKind Kind, SourceLocation Loc1, + SourceLocation Loc2, SourceLocation Loc3) + : Kind(Kind) + { + Locations[0] = Loc1; + Locations[1] = Loc2; + Locations[2] = Loc3; + } + +public: + /// \brief Create a direct initialization. + static InitializationKind CreateDirect(SourceLocation InitLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + return InitializationKind(SIK_Direct, InitLoc, LParenLoc, RParenLoc); + } + + /// \brief Create a direct initialization due to a cast. + static InitializationKind CreateCast(SourceRange TypeRange, + bool IsCStyleCast) { + return InitializationKind(IsCStyleCast? SIK_DirectCStyleOrFunctionalCast + : SIK_DirectCast, + TypeRange.getBegin(), TypeRange.getBegin(), + TypeRange.getEnd()); + } + + /// \brief Create a copy initialization. + static InitializationKind CreateCopy(SourceLocation InitLoc, + SourceLocation EqualLoc) { + return InitializationKind(SIK_Copy, InitLoc, EqualLoc, EqualLoc); + } + + /// \brief Create a default initialization. + static InitializationKind CreateDefault(SourceLocation InitLoc) { + return InitializationKind(SIK_Default, InitLoc, InitLoc, InitLoc); + } + + /// \brief Create a value initialization. + static InitializationKind CreateValue(SourceLocation InitLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + return InitializationKind(SIK_Value, InitLoc, LParenLoc, RParenLoc); + } + + /// \brief Determine the initialization kind. + InitKind getKind() const { + if (Kind > SIK_Value) + return IK_Direct; + + return (InitKind)Kind; + } + + /// \brief Determine whether this initialization is an explicit cast. + bool isExplicitCast() const { + return Kind == SIK_DirectCast || Kind == SIK_DirectCStyleOrFunctionalCast; + } + + /// \brief Determine whether this initialization is a C-style cast. + bool isCStyleOrFunctionalCast() const { + return Kind == SIK_DirectCStyleOrFunctionalCast; + } + + /// \brief Retrieve the location at which initialization is occurring. + SourceLocation getLocation() const { return Locations[0]; } + + /// \brief Retrieve the source range that covers the initialization. + SourceRange getRange() const { + return SourceRange(Locations[0], Locations[2]); + } + + /// \brief Retrieve the location of the equal sign for copy initialization + /// (if present). + SourceLocation getEqualLoc() const { + assert(Kind == SIK_Copy && "Only copy initialization has an '='"); + return Locations[1]; + } + + /// \brief Retrieve the source range containing the locations of the open + /// and closing parentheses for value and direct initializations. + SourceRange getParenRange() const { + assert((getKind() == IK_Direct || Kind == SIK_Value) && + "Only direct- and value-initialization have parentheses"); + return SourceRange(Locations[1], Locations[2]); + } +}; + +/// \brief Describes the sequence of initializations required to initialize +/// a given object or reference with a set of arguments. +class InitializationSequence { +public: + /// \brief Describes the kind of initialization sequence computed. + /// + /// FIXME: Much of this information is in the initialization steps... why is + /// it duplicated here? + enum SequenceKind { + /// \brief A failed initialization sequence. The failure kind tells what + /// happened. + FailedSequence = 0, + + /// \brief A dependent initialization, which could not be + /// type-checked due to the presence of dependent types or + /// dependently-type expressions. + DependentSequence, + + /// \brief A user-defined conversion sequence. + UserDefinedConversion, + + /// \brief A constructor call. + ConstructorInitialization, + + /// \brief A reference binding. + ReferenceBinding, + + /// \brief List initialization + ListInitialization, + + /// \brief Zero-initialization. + ZeroInitialization + }; + + /// \brief Describes the kind of a particular step in an initialization + /// sequence. + enum StepKind { + /// \brief Resolve the address of an overloaded function to a specific + /// function declaration. + SK_ResolveAddressOfOverloadedFunction, + /// \brief Perform a derived-to-base cast, producing an rvalue. + SK_CastDerivedToBaseRValue, + /// \brief Perform a derived-to-base cast, producing an lvalue. + SK_CastDerivedToBaseLValue, + /// \brief Reference binding to an lvalue. + SK_BindReference, + /// \brief Reference binding to a temporary. + SK_BindReferenceToTemporary, + /// \brief Perform a user-defined conversion, either via a conversion + /// function or via a constructor. + SK_UserConversion, + /// \brief Perform a qualification conversion, producing an rvalue. + SK_QualificationConversionRValue, + /// \brief Perform a qualification conversion, producing an lvalue. + SK_QualificationConversionLValue, + /// \brief Perform an implicit conversion sequence. + SK_ConversionSequence, + /// \brief Perform list-initialization + SK_ListInitialization, + /// \brief Perform initialization via a constructor. + SK_ConstructorInitialization, + /// \brief Zero-initialize the object + SK_ZeroInitialization + }; + + /// \brief A single step in the initialization sequence. + class Step { + public: + /// \brief The kind of conversion or initialization step we are taking. + StepKind Kind; + + // \brief The type that results from this initialization. + QualType Type; + + union { + /// \brief When Kind == SK_ResolvedOverloadedFunction or Kind == + /// SK_UserConversion, the function that the expression should be + /// resolved to or the conversion function to call, respectively. + FunctionDecl *Function; + + /// \brief When Kind = SK_ConversionSequence, the implicit conversion + /// sequence + ImplicitConversionSequence *ICS; + }; + + void Destroy(); + }; + +private: + /// \brief The kind of initialization sequence computed. + enum SequenceKind SequenceKind; + + /// \brief Steps taken by this initialization. + llvm::SmallVector<Step, 4> Steps; + +public: + /// \brief Describes why initialization failed. + enum FailureKind { + /// \brief Too many initializers provided for a reference. + FK_TooManyInitsForReference, + /// \brief Array must be initialized with an initializer list. + FK_ArrayNeedsInitList, + /// \brief Array must be initialized with an initializer list or a + /// string literal. + FK_ArrayNeedsInitListOrStringLiteral, + /// \brief Cannot resolve the address of an overloaded function. + FK_AddressOfOverloadFailed, + /// \brief Overloading due to reference initialization failed. + FK_ReferenceInitOverloadFailed, + /// \brief Non-const lvalue reference binding to a temporary. + FK_NonConstLValueReferenceBindingToTemporary, + /// \brief Non-const lvalue reference binding to an lvalue of unrelated + /// type. + FK_NonConstLValueReferenceBindingToUnrelated, + /// \brief Rvalue reference binding to an lvalue. + FK_RValueReferenceBindingToLValue, + /// \brief Reference binding drops qualifiers. + FK_ReferenceInitDropsQualifiers, + /// \brief Reference binding failed. + FK_ReferenceInitFailed, + /// \brief Implicit conversion failed. + FK_ConversionFailed, + /// \brief Too many initializers for scalar + FK_TooManyInitsForScalar, + /// \brief Reference initialization from an initializer list + FK_ReferenceBindingToInitList, + /// \brief Initialization of some unused destination type with an + /// initializer list. + FK_InitListBadDestinationType, + /// \brief Overloading for a user-defined conversion failed. + FK_UserConversionOverloadFailed, + /// \brief Overloaded for initialization by constructor failed. + FK_ConstructorOverloadFailed + }; + +private: + /// \brief The reason why initialization failued. + FailureKind Failure; + + /// \brief The failed result of overload resolution. + OverloadingResult FailedOverloadResult; + + /// \brief The candidate set created when initialization failed. + OverloadCandidateSet FailedCandidateSet; + +public: + /// \brief Try to perform initialization of the given entity, creating a + /// record of the steps required to perform the initialization. + /// + /// The generated initialization sequence will either contain enough + /// information to diagnose + /// + /// \param S the semantic analysis object. + /// + /// \param Entity the entity being initialized. + /// + /// \param Kind the kind of initialization being performed. + /// + /// \param Args the argument(s) provided for initialization. + /// + /// \param NumArgs the number of arguments provided for initialization. + InitializationSequence(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr **Args, + unsigned NumArgs); + + ~InitializationSequence(); + + /// \brief Perform the actual initialization of the given entity based on + /// the computed initialization sequence. + /// + /// \param S the semantic analysis object. + /// + /// \param Entity the entity being initialized. + /// + /// \param Kind the kind of initialization being performed. + /// + /// \param Args the argument(s) provided for initialization, ownership of + /// which is transfered into the routine. + /// + /// \param ResultType if non-NULL, will be set to the type of the + /// initialized object, which is the type of the declaration in most + /// cases. However, when the initialized object is a variable of + /// incomplete array type and the initializer is an initializer + /// list, this type will be set to the completed array type. + /// + /// \returns an expression that performs the actual object initialization, if + /// the initialization is well-formed. Otherwise, emits diagnostics + /// and returns an invalid expression. + Action::OwningExprResult Perform(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Action::MultiExprArg Args, + QualType *ResultType = 0); + + /// \brief Diagnose an potentially-invalid initialization sequence. + /// + /// \returns true if the initialization sequence was ill-formed, + /// false otherwise. + bool Diagnose(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr **Args, unsigned NumArgs); + + /// \brief Determine the kind of initialization sequence computed. + enum SequenceKind getKind() const { return SequenceKind; } + + /// \brief Set the kind of sequence computed. + void setSequenceKind(enum SequenceKind SK) { SequenceKind = SK; } + + /// \brief Determine whether the initialization sequence is valid. + operator bool() const { return SequenceKind != FailedSequence; } + + typedef llvm::SmallVector<Step, 4>::const_iterator step_iterator; + step_iterator step_begin() const { return Steps.begin(); } + step_iterator step_end() const { return Steps.end(); } + + /// \brief Add a new step in the initialization that resolves the address + /// of an overloaded function to a specific function declaration. + /// + /// \param Function the function to which the overloaded function reference + /// resolves. + void AddAddressOverloadResolutionStep(FunctionDecl *Function); + + /// \brief Add a new step in the initialization that performs a derived-to- + /// base cast. + /// + /// \param BaseType the base type to which we will be casting. + /// + /// \param IsLValue true if the result of this cast will be treated as + /// an lvalue. + void AddDerivedToBaseCastStep(QualType BaseType, bool IsLValue); + + /// \brief Add a new step binding a reference to an object. + /// + /// \param BindingTemporary true if we are binding a reference to a temporary + /// object (thereby extending its lifetime); false if we are binding to an + /// lvalue or an lvalue treated as an rvalue. + void AddReferenceBindingStep(QualType T, bool BindingTemporary); + + /// \brief Add a new step invoking a conversion function, which is either + /// a constructor or a conversion function. + void AddUserConversionStep(FunctionDecl *Function, QualType T); + + /// \brief Add a new step that performs a qualification conversion to the + /// given type. + void AddQualificationConversionStep(QualType Ty, bool IsLValue); + + /// \brief Add a new step that applies an implicit conversion sequence. + void AddConversionSequenceStep(const ImplicitConversionSequence &ICS, + QualType T); + + /// \brief Add a list-initialiation step + void AddListInitializationStep(QualType T); + + /// \brief Add a constructor-initialization step. + void AddConstructorInitializationStep(CXXConstructorDecl *Constructor, + QualType T); + + /// \brief Add a zero-initialization step. + void AddZeroInitializationStep(QualType T); + + /// \brief Note that this initialization sequence failed. + void SetFailed(FailureKind Failure) { + SequenceKind = FailedSequence; + this->Failure = Failure; + } + + /// \brief Note that this initialization sequence failed due to failed + /// overload resolution. + void SetOverloadFailure(FailureKind Failure, OverloadingResult Result); + + /// \brief Retrieve a reference to the candidate set when overload + /// resolution fails. + OverloadCandidateSet &getFailedCandidateSet() { + return FailedCandidateSet; + } + + /// \brief Determine why initialization failed. + FailureKind getFailureKind() const { + assert(getKind() == FailedSequence && "Not an initialization failure!"); + return Failure; + } +}; + +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_INIT_H diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 8f09827..724e2fc 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -222,6 +222,11 @@ getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind, IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member; break; + case Sema::LookupUsingDeclName: + IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag + | Decl::IDNS_Member | Decl::IDNS_Using; + break; + case Sema::LookupObjCProtocolName: IDNS = Decl::IDNS_ObjCProtocol; break; @@ -229,10 +234,6 @@ getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind, case Sema::LookupObjCImplementationName: IDNS = Decl::IDNS_ObjCImplementation; break; - - case Sema::LookupObjCCategoryImplName: - IDNS = Decl::IDNS_ObjCCategoryImpl; - break; } return IDNS; } @@ -245,7 +246,7 @@ void LookupResult::deletePaths(CXXBasePaths *Paths) { /// Resolves the result kind of this lookup. void LookupResult::resolveKind() { unsigned N = Decls.size(); - + // Fast case: no possible ambiguity. if (N == 0) { assert(ResultKind == NotFound); @@ -282,9 +283,6 @@ void LookupResult::resolveKind() { // If it's not unique, pull something off the back (and // continue at this index). Decls[I] = Decls[--N]; - } 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. @@ -318,13 +316,13 @@ void 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 (HideTags && HasTag && !Ambiguous && !HasUnresolved && - (HasFunction || HasNonFunction)) + if (HideTags && HasTag && !Ambiguous && + (HasFunction || HasNonFunction || HasUnresolved)) Decls[UniqueTagIndex] = Decls[--N]; Decls.set_size(N); - if (HasFunction && HasNonFunction) + if (HasNonFunction && (HasFunction || HasUnresolved)) Ambiguous = true; if (Ambiguous) @@ -337,44 +335,6 @@ void LookupResult::resolveKind() { ResultKind = LookupResult::Found; } -/// @brief Converts the result of name lookup into a single (possible -/// NULL) pointer to a declaration. -/// -/// The resulting declaration will either be the declaration we found -/// (if only a single declaration was found), an -/// OverloadedFunctionDecl (if an overloaded function was found), or -/// NULL (if no declaration was found). This conversion must not be -/// used anywhere where name lookup could result in an ambiguity. -/// -/// The OverloadedFunctionDecl conversion is meant as a stop-gap -/// 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 *LookupResult::getAsSingleDecl(ASTContext &C) const { - size_t size = Decls.size(); - if (size == 0) return 0; - if (size == 1) return (*begin())->getUnderlyingDecl(); - - if (isAmbiguous()) return 0; - - iterator I = begin(), E = end(); - - OverloadedFunctionDecl *Ovl - = OverloadedFunctionDecl::Create(C, (*I)->getDeclContext(), - (*I)->getDeclName()); - for (; I != E; ++I) { - NamedDecl *ND = (*I)->getUnderlyingDecl(); - assert(ND->isFunctionOrFunctionTemplate()); - if (isa<FunctionDecl>(ND)) - Ovl->addOverload(cast<FunctionDecl>(ND)); - else - Ovl->addOverload(cast<FunctionTemplateDecl>(ND)); - // FIXME: UnresolvedUsingDecls. - } - - return Ovl; -} - void LookupResult::addDeclsFromBasePaths(const CXXBasePaths &P) { CXXBasePaths::paths_iterator I, E; DeclContext::lookup_iterator DI, DE; @@ -521,7 +481,12 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { DeclContext *OuterCtx = findOuterContext(S); for (; Ctx && Ctx->getPrimaryContext() != OuterCtx; Ctx = Ctx->getLookupParent()) { - if (Ctx->isFunctionOrMethod()) + // We do not directly look into function or method contexts + // (since all local variables are found via the identifier + // changes) or in transparent contexts (since those entities + // will be found in the nearest enclosing non-transparent + // context). + if (Ctx->isFunctionOrMethod() || Ctx->isTransparentContext()) continue; // Perform qualified name lookup into this context. @@ -649,6 +614,7 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { case Sema::LookupOperatorName: case Sema::LookupNestedNameSpecifierName: case Sema::LookupNamespaceName: + case Sema::LookupUsingDeclName: assert(false && "C does not perform these kinds of name lookup"); break; @@ -670,9 +636,6 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { IDNS = Decl::IDNS_ObjCImplementation; break; - case Sema::LookupObjCCategoryImplName: - IDNS = Decl::IDNS_ObjCCategoryImpl; - break; } // Scan up the scope chain looking for a decl that matches this @@ -964,12 +927,14 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx) { case LookupTagName: BaseCallback = &CXXRecordDecl::FindTagMember; break; + + case LookupUsingDeclName: + // This lookup is for redeclarations only. case LookupOperatorName: case LookupNamespaceName: case LookupObjCProtocolName: case LookupObjCImplementationName: - case LookupObjCCategoryImplName: // These lookups will never find a member in a C++ class (or base class). return false; @@ -1202,7 +1167,7 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) { } } - llvm::llvm_unreachable("unknown ambiguity kind"); + llvm_unreachable("unknown ambiguity kind"); return true; } @@ -1610,7 +1575,7 @@ NamedDecl *Sema::LookupSingleName(Scope *S, DeclarationName Name, RedeclarationKind Redecl) { LookupResult R(*this, Name, SourceLocation(), NameKind, Redecl); LookupName(R, S); - return R.getAsSingleDecl(Context); + return R.getAsSingle<NamedDecl>(); } /// \brief Find the protocol with the given name, if any. @@ -1619,13 +1584,6 @@ ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II) { return cast_or_null<ObjCProtocolDecl>(D); } -/// \brief Find the Objective-C category implementation with the given -/// name, if any. -ObjCCategoryImplDecl *Sema::LookupObjCCategoryImpl(IdentifierInfo *II) { - Decl *D = LookupSingleName(TUScope, II, LookupObjCCategoryImplName); - return cast_or_null<ObjCCategoryImplDecl>(D); -} - void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, QualType T1, QualType T2, FunctionSet &Functions) { diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 6ea6a14..561cfdb 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -38,6 +38,7 @@ GetConversionCategory(ImplicitConversionKind Kind) { ICC_Lvalue_Transformation, ICC_Lvalue_Transformation, ICC_Lvalue_Transformation, + ICC_Identity, ICC_Qualification_Adjustment, ICC_Promotion, ICC_Promotion, @@ -66,6 +67,7 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) { ICR_Exact_Match, ICR_Exact_Match, ICR_Exact_Match, + ICR_Exact_Match, ICR_Promotion, ICR_Promotion, ICR_Promotion, @@ -91,6 +93,7 @@ const char* GetImplicitConversionName(ImplicitConversionKind Kind) { "Lvalue-to-rvalue", "Array-to-pointer", "Function-to-pointer", + "Noreturn adjustment", "Qualification", "Integral promotion", "Floating point promotion", @@ -172,7 +175,7 @@ isPointerConversionToVoidPointer(ASTContext& Context) const { if (First == ICK_Array_To_Pointer) FromType = Context.getArrayDecayedType(FromType); - if (Second == ICK_Pointer_Conversion) + if (Second == ICK_Pointer_Conversion && FromType->isPointerType()) if (const PointerType* ToPtrType = ToType->getAs<PointerType>()) return ToPtrType->getPointeeType()->isVoidType(); @@ -255,12 +258,13 @@ void ImplicitConversionSequence::DebugPrint() const { } // IsOverload - Determine whether the given New declaration is an -// overload of the Old declaration. This routine returns false if New -// and Old cannot be overloaded, e.g., if they are functions with the -// same signature (C++ 1.3.10) or if the Old declaration isn't a -// function (or overload set). When it does return false and Old is an -// OverloadedFunctionDecl, MatchedDecl will be set to point to the -// FunctionDecl that New cannot be overloaded with. +// overload of the declarations in Old. This routine returns false if +// New and Old cannot be overloaded, e.g., if New has the same +// signature as some function in Old (C++ 1.3.10) or if the Old +// declarations aren't functions (or function templates) at all. When +// it does return false, MatchedDecl will point to the decl that New +// cannot be overloaded with. This decl may be a UsingShadowDecl on +// top of the underlying declaration. // // Example: Given the following input: // @@ -271,42 +275,51 @@ void ImplicitConversionSequence::DebugPrint() const { // When we process #1, there is no previous declaration of "f", // so IsOverload will not be used. // -// When we process #2, Old is a FunctionDecl for #1. By comparing the -// parameter types, we see that #1 and #2 are overloaded (since they -// have different signatures), so this routine returns false; -// MatchedDecl is unchanged. +// When we process #2, Old contains only the FunctionDecl for #1. By +// comparing the parameter types, we see that #1 and #2 are overloaded +// (since they have different signatures), so this routine returns +// false; MatchedDecl is unchanged. // -// When we process #3, Old is an OverloadedFunctionDecl containing #1 -// and #2. We compare the signatures of #3 to #1 (they're overloaded, -// so we do nothing) and then #3 to #2. Since the signatures of #3 and -// #2 are identical (return types of functions are not part of the +// When we process #3, Old is an overload set containing #1 and #2. We +// compare the signatures of #3 to #1 (they're overloaded, so we do +// nothing) and then #3 to #2. Since the signatures of #3 and #2 are +// identical (return types of functions are not part of the // signature), IsOverload returns false and MatchedDecl will be set to // point to the FunctionDecl for #2. -bool -Sema::IsOverload(FunctionDecl *New, LookupResult &Previous, NamedDecl *&Match) { - for (LookupResult::iterator I = Previous.begin(), E = Previous.end(); +Sema::OverloadKind +Sema::CheckOverload(FunctionDecl *New, const LookupResult &Old, + NamedDecl *&Match) { + for (LookupResult::iterator I = Old.begin(), E = Old.end(); I != E; ++I) { - NamedDecl *Old = (*I)->getUnderlyingDecl(); - if (FunctionTemplateDecl *OldT = dyn_cast<FunctionTemplateDecl>(Old)) { + NamedDecl *OldD = (*I)->getUnderlyingDecl(); + if (FunctionTemplateDecl *OldT = dyn_cast<FunctionTemplateDecl>(OldD)) { if (!IsOverload(New, OldT->getTemplatedDecl())) { - Match = Old; - return false; + Match = *I; + return Ovl_Match; } - } else if (FunctionDecl *OldF = dyn_cast<FunctionDecl>(Old)) { + } else if (FunctionDecl *OldF = dyn_cast<FunctionDecl>(OldD)) { if (!IsOverload(New, OldF)) { - Match = Old; - return false; + Match = *I; + return Ovl_Match; } + } else if (isa<UsingDecl>(OldD) || isa<TagDecl>(OldD)) { + // We can overload with these, which can show up when doing + // redeclaration checks for UsingDecls. + assert(Old.getLookupKind() == LookupUsingDeclName); + } else if (isa<UnresolvedUsingValueDecl>(OldD)) { + // Optimistically assume that an unresolved using decl will + // overload; if it doesn't, we'll have to diagnose during + // template instantiation. } else { // (C++ 13p1): // Only function declarations can be overloaded; object and type // declarations cannot be overloaded. - Match = Old; - return false; + Match = *I; + return Ovl_NonFunction; } } - return true; + return Ovl_Overload; } bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old) { @@ -474,6 +487,23 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, return ICS; } +/// \brief Determine whether the conversion from FromType to ToType is a valid +/// conversion that strips "noreturn" off the nested function type. +static bool IsNoReturnConversion(ASTContext &Context, QualType FromType, + QualType ToType, QualType &ResultTy) { + if (Context.hasSameUnqualifiedType(FromType, ToType)) + return false; + + // Strip the noreturn off the type we're converting from; noreturn can + // safely be removed. + FromType = Context.getNoReturnType(FromType, false); + if (!Context.hasSameUnqualifiedType(FromType, ToType)) + return false; + + ResultTy = FromType; + return true; +} + /// IsStandardConversion - Determines whether there is a standard /// conversion sequence (C++ [conv], C++ [over.ics.scs]) from the /// expression From to the type ToType. Standard conversion sequences @@ -553,7 +583,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // function. (C++ 4.3p1). FromType = Context.getPointerType(FromType); } else if (FunctionDecl *Fn - = ResolveAddressOfOverloadedFunction(From, ToType, false)) { + = ResolveAddressOfOverloadedFunction(From, ToType, false)) { // Address of overloaded function (C++ [over.over]). SCS.First = ICK_Function_To_Pointer; @@ -644,7 +674,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, } else if (ToType->isBooleanType() && (FromType->isArithmeticType() || FromType->isEnumeralType() || - FromType->isPointerType() || + FromType->isAnyPointerType() || FromType->isBlockPointerType() || FromType->isMemberPointerType() || FromType->isNullPtrType())) { @@ -655,6 +685,9 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, Context.typesAreCompatible(ToType, FromType)) { // Compatible conversions (Clang extension for C function overloading) SCS.Second = ICK_Compatible_Conversion; + } else if (IsNoReturnConversion(Context, FromType, ToType, FromType)) { + // Treat a conversion that strips "noreturn" as an identity conversion. + SCS.Second = ICK_NoReturn_Adjustment; } else { // No second conversion required. SCS.Second = ICK_Identity; @@ -728,19 +761,21 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { // can be converted to an rvalue of the first of the following types // that can represent all the values of its underlying type: int, // unsigned int, long, or unsigned long (C++ 4.5p2). - if ((FromType->isEnumeralType() || FromType->isWideCharType()) - && ToType->isIntegerType()) { + + // We pre-calculate the promotion type for enum types. + if (const EnumType *FromEnumType = FromType->getAs<EnumType>()) + if (ToType->isIntegerType()) + return Context.hasSameUnqualifiedType(ToType, + FromEnumType->getDecl()->getPromotionType()); + + if (FromType->isWideCharType() && ToType->isIntegerType()) { // Determine whether the type we're converting from is signed or // unsigned. bool FromIsSigned; uint64_t FromSize = Context.getTypeSize(FromType); - if (const EnumType *FromEnumType = FromType->getAs<EnumType>()) { - QualType UnderlyingType = FromEnumType->getDecl()->getIntegerType(); - FromIsSigned = UnderlyingType->isSignedIntegerType(); - } else { - // FIXME: Is wchar_t signed or unsigned? We assume it's signed for now. - FromIsSigned = true; - } + + // FIXME: Is wchar_t signed or unsigned? We assume it's signed for now. + FromIsSigned = true; // The types we'll try to promote to, in the appropriate // order. Try each of these types. @@ -1233,7 +1268,7 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType, return false; } - + /// CheckMemberPointerConversion - Check the member pointer conversion from the /// expression From to the type ToType. This routine checks for ambiguous or /// virtual (FIXME: or inaccessible) base-to-derived member pointer conversions @@ -1371,13 +1406,13 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) { /// for overload resolution. /// \param UserCast true if looking for user defined conversion for a static /// cast. -Sema::OverloadingResult Sema::IsUserDefinedConversion( - Expr *From, QualType ToType, - UserDefinedConversionSequence& User, - OverloadCandidateSet& CandidateSet, - bool AllowConversionFunctions, - bool AllowExplicit, bool ForceRValue, - bool UserCast) { +OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, + UserDefinedConversionSequence& User, + OverloadCandidateSet& CandidateSet, + bool AllowConversionFunctions, + bool AllowExplicit, + bool ForceRValue, + bool UserCast) { if (const RecordType *ToRecordType = ToType->getAs<RecordType>()) { if (RequireCompleteType(From->getLocStart(), ToType, PDiag())) { // We're not going to find any constructors. @@ -1446,6 +1481,11 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion( = FromRecordDecl->getVisibleConversionFunctions(); for (UnresolvedSet::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { + NamedDecl *D = *I; + CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext()); + if (isa<UsingShadowDecl>(D)) + D = cast<UsingShadowDecl>(D)->getTargetDecl(); + CXXConversionDecl *Conv; FunctionTemplateDecl *ConvTemplate; if ((ConvTemplate = dyn_cast<FunctionTemplateDecl>(*I))) @@ -1455,10 +1495,11 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion( if (AllowExplicit || !Conv->isExplicit()) { if (ConvTemplate) - AddTemplateConversionCandidate(ConvTemplate, From, ToType, - CandidateSet); + AddTemplateConversionCandidate(ConvTemplate, ActingContext, + From, ToType, CandidateSet); else - AddConversionCandidate(Conv, From, ToType, CandidateSet); + AddConversionCandidate(Conv, ActingContext, From, ToType, + CandidateSet); } } } @@ -2075,8 +2116,10 @@ bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType, /// parameter of the given member function (@c Method) from the /// expression @p From. ImplicitConversionSequence -Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) { - QualType ClassType = Context.getTypeDeclType(Method->getParent()); +Sema::TryObjectArgumentInitialization(QualType FromType, + CXXMethodDecl *Method, + CXXRecordDecl *ActingContext) { + QualType ClassType = Context.getTypeDeclType(ActingContext); // [class.dtor]p2: A destructor can be invoked for a const, volatile or // const volatile object. unsigned Quals = isa<CXXDestructorDecl>(Method) ? @@ -2090,7 +2133,6 @@ Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) { ICS.ConversionKind = ImplicitConversionSequence::BadConversion; // We need to have an object of class type. - QualType FromType = From->getType(); if (const PointerType *PT = FromType->getAs<PointerType>()) FromType = PT->getPointeeType(); @@ -2150,8 +2192,11 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method) { DestType = ImplicitParamRecordType; } + // Note that we always use the true parent context when performing + // the actual argument initialization. ImplicitConversionSequence ICS - = TryObjectArgumentInitialization(From, Method); + = TryObjectArgumentInitialization(From->getType(), Method, + Method->getParent()); if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) return Diag(From->getSourceRange().getBegin(), diag::err_implicit_object_parameter_init) @@ -2226,9 +2271,11 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // that is named without a member access expression (e.g., // "this->f") that was either written explicitly or created // implicitly. This can happen with a qualified call to a member - // function, e.g., X::f(). We use a NULL object as the implied - // object argument (C++ [over.call.func]p3). - AddMethodCandidate(Method, 0, Args, NumArgs, CandidateSet, + // function, e.g., X::f(). We use an empty type for the implied + // object argument (C++ [over.call.func]p3), and the acting context + // is irrelevant. + AddMethodCandidate(Method, Method->getParent(), + QualType(), Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); return; } @@ -2340,10 +2387,12 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions, for (FunctionSet::const_iterator F = Functions.begin(), FEnd = Functions.end(); F != FEnd; ++F) { + // FIXME: using declarations if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*F)) { if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic()) AddMethodCandidate(cast<CXXMethodDecl>(FD), - Args[0], Args + 1, NumArgs - 1, + cast<CXXMethodDecl>(FD)->getParent(), + Args[0]->getType(), Args + 1, NumArgs - 1, CandidateSet, SuppressUserConversions); else AddOverloadCandidate(FD, Args, NumArgs, CandidateSet, @@ -2353,8 +2402,9 @@ void Sema::AddFunctionCandidates(const FunctionSet &Functions, if (isa<CXXMethodDecl>(FunTmpl->getTemplatedDecl()) && !cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())->isStatic()) AddMethodTemplateCandidate(FunTmpl, + cast<CXXRecordDecl>(FunTmpl->getDeclContext()), /*FIXME: explicit args */ 0, - Args[0], Args + 1, NumArgs - 1, + Args[0]->getType(), Args + 1, NumArgs - 1, CandidateSet, SuppressUserConversions); else @@ -2368,13 +2418,14 @@ 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, +void Sema::AddMethodCandidate(NamedDecl *Decl, + QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions, bool ForceRValue) { // FIXME: use this - //DeclContext *ActingContext = Decl->getDeclContext(); + CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(Decl->getDeclContext()); if (isa<UsingShadowDecl>(Decl)) Decl = cast<UsingShadowDecl>(Decl)->getTargetDecl(); @@ -2382,13 +2433,14 @@ void Sema::AddMethodCandidate(NamedDecl *Decl, Expr *Object, if (FunctionTemplateDecl *TD = dyn_cast<FunctionTemplateDecl>(Decl)) { assert(isa<CXXMethodDecl>(TD->getTemplatedDecl()) && "Expected a member function template"); - AddMethodTemplateCandidate(TD, /*ExplicitArgs*/ 0, - Object, Args, NumArgs, + AddMethodTemplateCandidate(TD, ActingContext, /*ExplicitArgs*/ 0, + ObjectType, Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); } else { - AddMethodCandidate(cast<CXXMethodDecl>(Decl), Object, Args, NumArgs, + AddMethodCandidate(cast<CXXMethodDecl>(Decl), ActingContext, + ObjectType, Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); } } @@ -2403,8 +2455,8 @@ void Sema::AddMethodCandidate(NamedDecl *Decl, Expr *Object, /// a slightly hacky way to implement the overloading rules for elidable copy /// initialization in C++0x (C++0x 12.8p15). void -Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object, - Expr **Args, unsigned NumArgs, +Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, + QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions, bool ForceRValue) { const FunctionProtoType* Proto @@ -2453,13 +2505,14 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object, Candidate.Viable = true; Candidate.Conversions.resize(NumArgs + 1); - if (Method->isStatic() || !Object) + if (Method->isStatic() || ObjectType.isNull()) // The implicit object argument is ignored. Candidate.IgnoreObjectArgument = true; else { // Determine the implicit conversion sequence for the object // parameter. - Candidate.Conversions[0] = TryObjectArgumentInitialization(Object, Method); + Candidate.Conversions[0] + = TryObjectArgumentInitialization(ObjectType, Method, ActingContext); if (Candidate.Conversions[0].ConversionKind == ImplicitConversionSequence::BadConversion) { Candidate.Viable = false; @@ -2500,8 +2553,10 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object, /// function template specialization. void Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, + CXXRecordDecl *ActingContext, const TemplateArgumentListInfo *ExplicitTemplateArgs, - Expr *Object, Expr **Args, unsigned NumArgs, + QualType ObjectType, + Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions, bool ForceRValue) { @@ -2533,7 +2588,8 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, assert(Specialization && "Missing member function template specialization?"); assert(isa<CXXMethodDecl>(Specialization) && "Specialization is not a member function?"); - AddMethodCandidate(cast<CXXMethodDecl>(Specialization), Object, Args, NumArgs, + AddMethodCandidate(cast<CXXMethodDecl>(Specialization), ActingContext, + ObjectType, Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); } @@ -2585,6 +2641,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, /// conversion function produces). void Sema::AddConversionCandidate(CXXConversionDecl *Conversion, + CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet& CandidateSet) { assert(!Conversion->getDescribedFunctionTemplate() && @@ -2611,7 +2668,9 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, // object parameter. Candidate.Viable = true; Candidate.Conversions.resize(1); - Candidate.Conversions[0] = TryObjectArgumentInitialization(From, Conversion); + Candidate.Conversions[0] + = TryObjectArgumentInitialization(From->getType(), Conversion, + ActingContext); // Conversion functions to a different type in the base class is visible in // the derived class. So, a derived to base conversion should not participate // in overload resolution. @@ -2683,6 +2742,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, /// [temp.deduct.conv]). void Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, + CXXRecordDecl *ActingDC, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet) { assert(isa<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()) && @@ -2705,7 +2765,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, // Add the conversion function template specialization produced by // template argument deduction as a candidate. assert(Specialization && "Missing function template specialization?"); - AddConversionCandidate(Specialization, From, ToType, CandidateSet); + AddConversionCandidate(Specialization, ActingDC, From, ToType, CandidateSet); } /// AddSurrogateCandidate - Adds a "surrogate" candidate function that @@ -2714,8 +2774,10 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, /// with the given arguments (C++ [over.call.object]p2-4). Proto is /// the type of function that we'll eventually be calling. void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, + CXXRecordDecl *ActingContext, const FunctionProtoType *Proto, - Expr *Object, Expr **Args, unsigned NumArgs, + QualType ObjectType, + Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet) { if (!CandidateSet.isNewCandidate(Conversion)) return; @@ -2735,7 +2797,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, // Determine the implicit conversion sequence for the implicit // object parameter. ImplicitConversionSequence ObjectInit - = TryObjectArgumentInitialization(Object, Conversion); + = TryObjectArgumentInitialization(ObjectType, Conversion, ActingContext); if (ObjectInit.ConversionKind == ImplicitConversionSequence::BadConversion) { Candidate.Viable = false; return; @@ -2870,7 +2932,8 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, OperEnd = Operators.end(); Oper != OperEnd; ++Oper) - AddMethodCandidate(*Oper, Args[0], Args + 1, NumArgs - 1, CandidateSet, + AddMethodCandidate(*Oper, Args[0]->getType(), + Args + 1, NumArgs - 1, CandidateSet, /* SuppressUserConversions = */ false); } } @@ -4111,10 +4174,9 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1, /// function, Best points to the candidate function found. /// /// \returns The result of overload resolution. -Sema::OverloadingResult -Sema::BestViableFunction(OverloadCandidateSet& CandidateSet, - SourceLocation Loc, - OverloadCandidateSet::iterator& Best) { +OverloadingResult Sema::BestViableFunction(OverloadCandidateSet& CandidateSet, + SourceLocation Loc, + OverloadCandidateSet::iterator& Best) { // Find the best viable function. Best = CandidateSet.end(); for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); @@ -4426,7 +4488,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, continue; if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*I)) { - if (FunctionType == Context.getCanonicalType(FunDecl->getType())) { + QualType ResultTy; + if (Context.hasSameUnqualifiedType(FunctionType, FunDecl->getType()) || + IsNoReturnConversion(Context, FunDecl->getType(), FunctionType, + ResultTy)) { Matches.insert(cast<FunctionDecl>(FunDecl->getCanonicalDecl())); FoundNonTemplateFunction = true; } @@ -5122,7 +5187,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, /// parameter). The caller needs to validate that the member /// expression refers to a member function or an overloaded member /// function. -Sema::ExprResult +Sema::OwningExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation *CommaLocs, @@ -5131,46 +5196,46 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, // argument and the member function we're referring to. Expr *NakedMemExpr = MemExprE->IgnoreParens(); - // Extract the object argument. - Expr *ObjectArg; - MemberExpr *MemExpr; CXXMethodDecl *Method = 0; if (isa<MemberExpr>(NakedMemExpr)) { MemExpr = cast<MemberExpr>(NakedMemExpr); - ObjectArg = MemExpr->getBase(); Method = cast<CXXMethodDecl>(MemExpr->getMemberDecl()); } else { UnresolvedMemberExpr *UnresExpr = cast<UnresolvedMemberExpr>(NakedMemExpr); - ObjectArg = UnresExpr->getBase(); + + QualType ObjectType = UnresExpr->getBaseType(); // Add overload candidates OverloadCandidateSet CandidateSet; + // FIXME: avoid copy. + TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0; + if (UnresExpr->hasExplicitTemplateArgs()) { + UnresExpr->copyTemplateArgumentsInto(TemplateArgsBuffer); + TemplateArgs = &TemplateArgsBuffer; + } + for (UnresolvedMemberExpr::decls_iterator I = UnresExpr->decls_begin(), E = UnresExpr->decls_end(); I != E; ++I) { - // TODO: note if we found something through a using declaration - NamedDecl *Func = (*I)->getUnderlyingDecl(); - + NamedDecl *Func = *I; + CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(Func->getDeclContext()); + if (isa<UsingShadowDecl>(Func)) + Func = cast<UsingShadowDecl>(Func)->getTargetDecl(); + if ((Method = dyn_cast<CXXMethodDecl>(Func))) { // If explicit template arguments were provided, we can't call a // non-template member function. - if (UnresExpr->hasExplicitTemplateArgs()) + if (TemplateArgs) continue; - AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet, - /*SuppressUserConversions=*/false); + AddMethodCandidate(Method, ActingDC, ObjectType, Args, NumArgs, + CandidateSet, /*SuppressUserConversions=*/false); } else { - // FIXME: avoid copy. - TemplateArgumentListInfo TemplateArgs; - if (UnresExpr->hasExplicitTemplateArgs()) - UnresExpr->copyTemplateArgumentsInto(TemplateArgs); - AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(Func), - (UnresExpr->hasExplicitTemplateArgs() - ? &TemplateArgs : 0), - ObjectArg, Args, NumArgs, + ActingDC, TemplateArgs, + ObjectType, Args, NumArgs, CandidateSet, /*SuppressUsedConversions=*/false); } @@ -5190,14 +5255,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, << DeclName << MemExprE->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); // FIXME: Leaking incoming expressions! - return true; + return ExprError(); case OR_Ambiguous: Diag(UnresExpr->getMemberLoc(), diag::err_ovl_ambiguous_member_call) << DeclName << MemExprE->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); // FIXME: Leaking incoming expressions! - return true; + return ExprError(); case OR_Deleted: Diag(UnresExpr->getMemberLoc(), diag::err_ovl_deleted_member_call) @@ -5205,16 +5270,24 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, << DeclName << MemExprE->getSourceRange(); PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); // FIXME: Leaking incoming expressions! - return true; + return ExprError(); } MemExprE = FixOverloadedFunctionReference(MemExprE, Method); + + // If overload resolution picked a static member, build a + // non-member call based on that function. + if (Method->isStatic()) { + return BuildResolvedCallExpr(MemExprE, Method, LParenLoc, + Args, NumArgs, RParenLoc); + } + MemExpr = cast<MemberExpr>(MemExprE->IgnoreParens()); } assert(Method && "Member call to something that isn't a method?"); ExprOwningPtr<CXXMemberCallExpr> - TheCall(this, new (Context) CXXMemberCallExpr(Context, MemExpr, Args, + TheCall(this, new (Context) CXXMemberCallExpr(Context, MemExprE, Args, NumArgs, Method->getResultType().getNonReferenceType(), RParenLoc)); @@ -5222,24 +5295,25 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, // Check for a valid return type. if (CheckCallReturnType(Method->getResultType(), MemExpr->getMemberLoc(), TheCall.get(), Method)) - return true; + return ExprError(); // Convert the object argument (for a non-static member function call). + Expr *ObjectArg = MemExpr->getBase(); if (!Method->isStatic() && PerformObjectArgumentInitialization(ObjectArg, Method)) - return true; + return ExprError(); MemExpr->setBase(ObjectArg); // Convert the rest of the arguments const FunctionProtoType *Proto = cast<FunctionProtoType>(Method->getType()); if (ConvertArgumentsForCall(&*TheCall, MemExpr, Method, Proto, Args, NumArgs, RParenLoc)) - return true; + return ExprError(); if (CheckFunctionCall(Method, TheCall.get())) - return true; + return ExprError(); - return MaybeBindToTemporary(TheCall.release()).release(); + return MaybeBindToTemporary(TheCall.release()); } /// BuildCallToObjectOfClassType - Build a call to an object of class @@ -5276,7 +5350,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) { - AddMethodCandidate(*Oper, Object, Args, NumArgs, CandidateSet, + AddMethodCandidate(*Oper, Object->getType(), Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/ false); } @@ -5302,12 +5376,17 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions(); for (UnresolvedSet::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { + NamedDecl *D = *I; + CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext()); + if (isa<UsingShadowDecl>(D)) + D = cast<UsingShadowDecl>(D)->getTargetDecl(); + // Skip over templated conversion functions; they aren't // surrogates. - if (isa<FunctionTemplateDecl>(*I)) + if (isa<FunctionTemplateDecl>(D)) continue; - CXXConversionDecl *Conv = cast<CXXConversionDecl>(*I); + CXXConversionDecl *Conv = cast<CXXConversionDecl>(D); // Strip the reference type (if any) and then the pointer type (if // any) to get down to what might be a function type. @@ -5316,7 +5395,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, ConvType = ConvPtrType->getPointeeType(); if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>()) - AddSurrogateCandidate(Conv, Proto, Object, Args, NumArgs, CandidateSet); + AddSurrogateCandidate(Conv, ActingContext, Proto, + Object->getType(), Args, NumArgs, + CandidateSet); } // Perform overload resolution. @@ -5372,8 +5453,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // Create an implicit member expr to refer to the conversion operator. // and then call it. - CXXMemberCallExpr *CE = - BuildCXXMemberCallExpr(Object, Conv); + CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(Object, Conv); return ActOnCallExpr(S, ExprArg(*this, CE), LParenLoc, MultiExprArg(*this, (ExprTy**)Args, NumArgs), @@ -5503,9 +5583,16 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { R.suppressDiagnostics(); for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); - Oper != OperEnd; ++Oper) - AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Base, 0, 0, CandidateSet, + Oper != OperEnd; ++Oper) { + NamedDecl *D = *Oper; + CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext()); + if (isa<UsingShadowDecl>(D)) + D = cast<UsingShadowDecl>(D)->getTargetDecl(); + + AddMethodCandidate(cast<CXXMethodDecl>(D), ActingContext, + Base->getType(), 0, 0, CandidateSet, /*SuppressUserConversions=*/false); + } // Perform overload resolution. OverloadCandidateSet::iterator Best; @@ -5632,19 +5719,11 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { } if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) { + // FIXME: avoid copy. + TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0; if (ULE->hasExplicitTemplateArgs()) { - // FIXME: avoid copy. - TemplateArgumentListInfo TemplateArgs; - if (ULE->hasExplicitTemplateArgs()) - ULE->copyTemplateArgumentsInto(TemplateArgs); - - return DeclRefExpr::Create(Context, - ULE->getQualifier(), - ULE->getQualifierRange(), - Fn, - ULE->getNameLoc(), - Fn->getType(), - &TemplateArgs); + ULE->copyTemplateArgumentsInto(TemplateArgsBuffer); + TemplateArgs = &TemplateArgsBuffer; } return DeclRefExpr::Create(Context, @@ -5652,23 +5731,43 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { ULE->getQualifierRange(), Fn, ULE->getNameLoc(), - Fn->getType()); + Fn->getType(), + TemplateArgs); } if (UnresolvedMemberExpr *MemExpr = dyn_cast<UnresolvedMemberExpr>(E)) { // FIXME: avoid copy. - TemplateArgumentListInfo TemplateArgs; - if (MemExpr->hasExplicitTemplateArgs()) - MemExpr->copyTemplateArgumentsInto(TemplateArgs); + TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0; + if (MemExpr->hasExplicitTemplateArgs()) { + MemExpr->copyTemplateArgumentsInto(TemplateArgsBuffer); + TemplateArgs = &TemplateArgsBuffer; + } - return MemberExpr::Create(Context, MemExpr->getBase()->Retain(), + Expr *Base; + + // If we're filling in + if (MemExpr->isImplicitAccess()) { + if (cast<CXXMethodDecl>(Fn)->isStatic()) { + return DeclRefExpr::Create(Context, + MemExpr->getQualifier(), + MemExpr->getQualifierRange(), + Fn, + MemExpr->getMemberLoc(), + Fn->getType(), + TemplateArgs); + } else + Base = new (Context) CXXThisExpr(SourceLocation(), + MemExpr->getBaseType()); + } else + Base = MemExpr->getBase()->Retain(); + + return MemberExpr::Create(Context, Base, MemExpr->isArrow(), MemExpr->getQualifier(), MemExpr->getQualifierRange(), Fn, MemExpr->getMemberLoc(), - (MemExpr->hasExplicitTemplateArgs() - ? &TemplateArgs : 0), + TemplateArgs, Fn->getType()); } @@ -5676,4 +5775,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { return E->Retain(); } +Sema::OwningExprResult Sema::FixOverloadedFunctionReference(OwningExprResult E, + FunctionDecl *Fn) { + return Owned(FixOverloadedFunctionReference((Expr *)E.get(), Fn)); +} + } // end namespace clang diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index 0d1f37a..3613d60 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -15,12 +15,26 @@ #ifndef LLVM_CLANG_SEMA_OVERLOAD_H #define LLVM_CLANG_SEMA_OVERLOAD_H +#include "clang/AST/Decl.h" +#include "clang/AST/Type.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" namespace clang { + class ASTContext; class CXXConstructorDecl; + class CXXConversionDecl; class FunctionDecl; + /// OverloadingResult - Capture the result of performing overload + /// resolution. + enum OverloadingResult { + OR_Success, ///< Overload resolution succeeded. + OR_No_Viable_Function, ///< No viable function found. + OR_Ambiguous, ///< Ambiguous candidates found. + OR_Deleted ///< Overload resoltuion refers to a deleted function. + }; + /// ImplicitConversionKind - The kind of implicit conversion used to /// convert an argument to a parameter's type. The enumerator values /// match with Table 9 of (C++ 13.3.3.1.1) and are listed such that @@ -30,6 +44,7 @@ namespace clang { ICK_Lvalue_To_Rvalue, ///< Lvalue-to-rvalue conversion (C++ 4.1) ICK_Array_To_Pointer, ///< Array-to-pointer conversion (C++ 4.2) ICK_Function_To_Pointer, ///< Function-to-pointer (C++ 4.3) + ICK_NoReturn_Adjustment, ///< Removal of noreturn from a type (Clang) ICK_Qualification, ///< Qualification conversions (C++ 4.4) ICK_Integral_Promotion, ///< Integral promotions (C++ 4.5) ICK_Floating_Promotion, ///< Floating point promotions (C++ 4.6) @@ -270,6 +285,7 @@ namespace clang { /// OverloadCandidateSet - A set of overload candidates, used in C++ /// overload resolution (C++ 13.3). class OverloadCandidateSet : public llvm::SmallVector<OverloadCandidate, 16> { + typedef llvm::SmallVector<OverloadCandidate, 16> inherited; llvm::SmallPtrSet<Decl *, 16> Functions; public: @@ -278,6 +294,12 @@ namespace clang { bool isNewCandidate(Decl *F) { return Functions.insert(F->getCanonicalDecl()); } + + /// \brief Clear out all of the candidates. + void clear() { + inherited::clear(); + Functions.clear(); + } }; } // end namespace clang diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index f47577e..ac1b1ec 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -108,36 +108,36 @@ TemplateNameKind Sema::isTemplateName(Scope *S, if (R.empty()) return TNK_Non_template; - NamedDecl *Template = R.getAsSingleDecl(Context); - - if (SS.isSet() && !SS.isInvalid()) { - NestedNameSpecifier *Qualifier - = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); - if (OverloadedFunctionDecl *Ovl - = dyn_cast<OverloadedFunctionDecl>(Template)) - TemplateResult - = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false, - Ovl)); - else - TemplateResult - = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false, - cast<TemplateDecl>(Template))); - } else if (OverloadedFunctionDecl *Ovl - = dyn_cast<OverloadedFunctionDecl>(Template)) { - TemplateResult = TemplateTy::make(TemplateName(Ovl)); + TemplateName Template; + TemplateNameKind TemplateKind; + + unsigned ResultCount = R.end() - R.begin(); + if (ResultCount > 1) { + // We assume that we'll preserve the qualifier from a function + // template name in other ways. + Template = Context.getOverloadedTemplateName(R.begin(), R.end()); + TemplateKind = TNK_Function_template; } else { - TemplateResult = TemplateTy::make( - TemplateName(cast<TemplateDecl>(Template))); - } + TemplateDecl *TD = cast<TemplateDecl>((*R.begin())->getUnderlyingDecl()); + + if (SS.isSet() && !SS.isInvalid()) { + NestedNameSpecifier *Qualifier + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + Template = Context.getQualifiedTemplateName(Qualifier, false, TD); + } else { + Template = TemplateName(TD); + } - if (isa<ClassTemplateDecl>(Template) || - isa<TemplateTemplateParmDecl>(Template)) - return TNK_Type_template; + if (isa<FunctionTemplateDecl>(TD)) + TemplateKind = TNK_Function_template; + else { + assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD)); + TemplateKind = TNK_Type_template; + } + } - assert((isa<FunctionTemplateDecl>(Template) || - isa<OverloadedFunctionDecl>(Template)) && - "Unhandled template kind in Sema::isTemplateName"); - return TNK_Function_template; + TemplateResult = TemplateTy::make(Template); + return TemplateKind; } void Sema::LookupTemplateName(LookupResult &Found, @@ -248,126 +248,30 @@ void Sema::LookupTemplateName(LookupResult &Found, } } -/// Constructs a full type for the given nested-name-specifier. -static QualType GetTypeForQualifier(ASTContext &Context, - NestedNameSpecifier *Qualifier) { - // Three possibilities: - - // 1. A namespace (global or not). - assert(!Qualifier->getAsNamespace() && "can't construct type for namespace"); - - // 2. A type (templated or not). - Type *Ty = Qualifier->getAsType(); - if (Ty) return QualType(Ty, 0); - - // 3. A dependent identifier. - assert(Qualifier->getAsIdentifier()); - return Context.getTypenameType(Qualifier->getPrefix(), - Qualifier->getAsIdentifier()); -} - -static bool HasDependentTypeAsBase(ASTContext &Context, - CXXRecordDecl *Record, - CanQualType T) { - for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(), - E = Record->bases_end(); I != E; ++I) { - CanQualType BaseT = Context.getCanonicalType((*I).getType()); - if (BaseT == T) - return true; - - // We have to recurse here to cover some really bizarre cases. - // Obviously, we can only have the dependent type as an indirect - // base class through a dependent base class, and usually it's - // impossible to know which instantiation a dependent base class - // will have. But! If we're actually *inside* the dependent base - // class, then we know its instantiation and can therefore be - // reasonably expected to look into it. - - // template <class T> class A : Base<T> { - // class Inner : A<T> { - // void foo() { - // Base<T>::foo(); // statically known to be an implicit member - // reference - // } - // }; - // }; - - CanQual<RecordType> RT = BaseT->getAs<RecordType>(); - - // Base might be a dependent member type, in which case we - // obviously can't look into it. - if (!RT) continue; - - CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(RT->getDecl()); - if (BaseRecord->isDefinition() && - HasDependentTypeAsBase(Context, BaseRecord, T)) - return true; - } - - return false; -} - -/// Checks whether the given dependent nested-name specifier -/// introduces an implicit member reference. This is only true if the -/// nested-name specifier names a type identical to one of the current -/// instance method's context's (possibly indirect) base classes. -static bool IsImplicitDependentMemberReference(Sema &SemaRef, - NestedNameSpecifier *Qualifier, - QualType &ThisType) { - // If the context isn't a C++ method, then it isn't an implicit - // member reference. - CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(SemaRef.CurContext); - if (!MD || MD->isStatic()) - return false; - - ASTContext &Context = SemaRef.Context; - - // We want to check whether the method's context is known to inherit - // from the type named by the nested name specifier. The trivial - // case here is: - // template <class T> class Base { ... }; - // template <class T> class Derived : Base<T> { - // void foo() { - // Base<T>::foo(); - // } - // }; - - QualType QT = GetTypeForQualifier(Context, Qualifier); - CanQualType T = Context.getCanonicalType(QT); - - // And now, just walk the non-dependent type hierarchy, trying to - // find the given type as a literal base class. - CXXRecordDecl *Record = cast<CXXRecordDecl>(MD->getParent()); - if (Context.getCanonicalType(Context.getTypeDeclType(Record)) == T || - HasDependentTypeAsBase(Context, Record, T)) { - ThisType = MD->getThisType(Context); - return true; - } - - return false; -} - -/// ActOnDependentIdExpression - Handle a dependent declaration name -/// that was just parsed. +/// ActOnDependentIdExpression - Handle a dependent id-expression that +/// was just parsed. This is only possible with an explicit scope +/// specifier naming a dependent type. Sema::OwningExprResult Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS, DeclarationName Name, SourceLocation NameLoc, - bool CheckForImplicitMember, + bool isAddressOfOperand, const TemplateArgumentListInfo *TemplateArgs) { NestedNameSpecifier *Qualifier = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); - QualType ThisType; - if (CheckForImplicitMember && - IsImplicitDependentMemberReference(*this, Qualifier, ThisType)) { - Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType); - + if (!isAddressOfOperand && + isa<CXXMethodDecl>(CurContext) && + cast<CXXMethodDecl>(CurContext)->isInstance()) { + QualType ThisType = cast<CXXMethodDecl>(CurContext)->getThisType(Context); + // Since the 'this' expression is synthesized, we don't need to // perform the double-lookup check. NamedDecl *FirstQualifierInScope = 0; - return Owned(CXXDependentScopeMemberExpr::Create(Context, This, true, + return Owned(CXXDependentScopeMemberExpr::Create(Context, + /*This*/ 0, ThisType, + /*IsArrow*/ true, /*Op*/ SourceLocation(), Qualifier, SS.getRange(), FirstQualifierInScope, @@ -426,10 +330,10 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef, switch (Arg.getKind()) { case ParsedTemplateArgument::Type: { - DeclaratorInfo *DI; + TypeSourceInfo *DI; QualType T = SemaRef.GetTypeFromParser(Arg.getAsType(), &DI); if (!DI) - DI = SemaRef.Context.getTrivialDeclaratorInfo(T, Arg.getLocation()); + DI = SemaRef.Context.getTrivialTypeSourceInfo(T, Arg.getLocation()); return TemplateArgumentLoc(TemplateArgument(T), DI); } @@ -447,7 +351,7 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef, } } - llvm::llvm_unreachable("Unhandled parsed template argument"); + llvm_unreachable("Unhandled parsed template argument"); return TemplateArgumentLoc(); } @@ -515,10 +419,10 @@ void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam, TemplateTypeParmDecl *Parm = cast<TemplateTypeParmDecl>(TypeParam.getAs<Decl>()); - DeclaratorInfo *DefaultDInfo; - GetTypeFromParser(DefaultT, &DefaultDInfo); + TypeSourceInfo *DefaultTInfo; + GetTypeFromParser(DefaultT, &DefaultTInfo); - assert(DefaultDInfo && "expected source information for type"); + assert(DefaultTInfo && "expected source information for type"); // C++0x [temp.param]p9: // A default template-argument may be specified for any kind of @@ -533,12 +437,12 @@ void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam, // FIXME: Implement this check! Needs a recursive walk over the types. // Check the template argument itself. - if (CheckTemplateArgument(Parm, DefaultDInfo)) { + if (CheckTemplateArgument(Parm, DefaultTInfo)) { Parm->setInvalidDecl(); return; } - Parm->setDefaultArgument(DefaultDInfo, false); + Parm->setDefaultArgument(DefaultTInfo, false); } /// \brief Check that the type of a non-type template parameter is @@ -592,8 +496,8 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) { Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, unsigned Depth, unsigned Position) { - DeclaratorInfo *DInfo = 0; - QualType T = GetTypeForDeclarator(D, S, &DInfo); + TypeSourceInfo *TInfo = 0; + QualType T = GetTypeForDeclarator(D, S, &TInfo); assert(S->isTemplateParamScope() && "Non-type template parameter not in template parameter scope!"); @@ -615,7 +519,7 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, NonTypeTemplateParmDecl *Param = NonTypeTemplateParmDecl::Create(Context, CurContext, D.getIdentifierLoc(), - Depth, Position, ParamName, T, DInfo); + Depth, Position, ParamName, T, TInfo); if (Invalid) Param->setInvalidDecl(); @@ -1266,8 +1170,27 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, ExplicitSpecializationsInSpecifier; for (NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep(); NNS; NNS = NNS->getPrefix()) { + const Type *T = NNS->getAsType(); + if (!T) break; + + // C++0x [temp.expl.spec]p17: + // A member or a member template may be nested within many + // enclosing class templates. In an explicit specialization for + // such a member, the member declaration shall be preceded by a + // template<> for each enclosing class template that is + // explicitly specialized. + // We interpret this as forbidding typedefs of template + // specializations in the scope specifiers of out-of-line decls. + if (const TypedefType *TT = dyn_cast<TypedefType>(T)) { + const Type *UnderlyingT = TT->LookThroughTypedefs().getTypePtr(); + if (isa<TemplateSpecializationType>(UnderlyingT)) + // FIXME: better source location information. + Diag(DeclStartLoc, diag::err_typedef_in_def_scope) << QualType(T,0); + T = UnderlyingT; + } + if (const TemplateSpecializationType *SpecType - = dyn_cast_or_null<TemplateSpecializationType>(NNS->getAsType())) { + = dyn_cast<TemplateSpecializationType>(T)) { TemplateDecl *Template = SpecType->getTemplateName().getAsTemplateDecl(); if (!Template) continue; // FIXME: should this be an error? probably... @@ -1481,7 +1404,7 @@ Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc, if (Result.isNull()) return true; - DeclaratorInfo *DI = Context.CreateDeclaratorInfo(Result); + TypeSourceInfo *DI = Context.CreateTypeSourceInfo(Result); TemplateSpecializationTypeLoc TL = cast<TemplateSpecializationTypeLoc>(DI->getTypeLoc()); TL.setTemplateNameLoc(TemplateLoc); @@ -1501,7 +1424,7 @@ Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult, return Sema::TypeResult(); // FIXME: preserve source info, ideally without copying the DI. - DeclaratorInfo *DI; + TypeSourceInfo *DI; QualType Type = GetTypeFromParser(TypeResult.get(), &DI); // Verify the tag specifier. @@ -1687,7 +1610,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, return true; } - if (CheckTemplateArgument(Param, AL.getSourceDeclaratorInfo())) + if (CheckTemplateArgument(Param, AL.getTypeSourceInfo())) return true; // Add the converted template type argument. @@ -1718,14 +1641,14 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, /// parameters that precede \p Param in the template parameter list. /// /// \returns the substituted template argument, or NULL if an error occurred. -static DeclaratorInfo * +static TypeSourceInfo * SubstDefaultTemplateArgument(Sema &SemaRef, TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, TemplateTypeParmDecl *Param, TemplateArgumentListBuilder &Converted) { - DeclaratorInfo *ArgType = Param->getDefaultArgumentInfo(); + TypeSourceInfo *ArgType = Param->getDefaultArgumentInfo(); // If the argument type is dependent, instantiate it now based // on the previously-computed template arguments. @@ -1851,7 +1774,7 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, if (!TypeParm->hasDefaultArgument()) return TemplateArgumentLoc(); - DeclaratorInfo *DI = SubstDefaultTemplateArgument(*this, Template, + TypeSourceInfo *DI = SubstDefaultTemplateArgument(*this, Template, TemplateLoc, RAngleLoc, TypeParm, @@ -2012,7 +1935,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, } case TemplateArgument::Pack: - llvm::llvm_unreachable("Caller must expand template argument packs"); + llvm_unreachable("Caller must expand template argument packs"); break; } @@ -2065,16 +1988,16 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, return true; case TemplateArgument::Declaration: - llvm::llvm_unreachable( + llvm_unreachable( "Declaration argument with template template parameter"); break; case TemplateArgument::Integral: - llvm::llvm_unreachable( + llvm_unreachable( "Integral argument with template template parameter"); break; case TemplateArgument::Pack: - llvm::llvm_unreachable("Caller must expand template argument packs"); + llvm_unreachable("Caller must expand template argument packs"); break; } @@ -2168,7 +2091,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, break; } - DeclaratorInfo *ArgType = SubstDefaultTemplateArgument(*this, + TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(*this, Template, TemplateLoc, RAngleLoc, @@ -2240,8 +2163,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, /// This routine implements the semantics of C++ [temp.arg.type]. It /// returns true if an error occurred, and false otherwise. bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, - DeclaratorInfo *ArgInfo) { - assert(ArgInfo && "invalid DeclaratorInfo"); + TypeSourceInfo *ArgInfo) { + assert(ArgInfo && "invalid TypeSourceInfo"); QualType Arg = ArgInfo->getType(); // C++ [temp.arg.type]p2: @@ -4469,8 +4392,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (D.getDeclSpec().isInlineSpecified() && getLangOptions().CPlusPlus0x) Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_explicit_instantiation_inline) - << CodeModificationHint::CreateRemoval( - SourceRange(D.getDeclSpec().getInlineSpecLoc())); + <<CodeModificationHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); // FIXME: check for constexpr specifier. @@ -4493,8 +4415,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (Previous.isAmbiguous()) return true; - VarDecl *Prev = dyn_cast_or_null<VarDecl>( - Previous.getAsSingleDecl(Context)); + VarDecl *Prev = Previous.getAsSingle<VarDecl>(); if (!Prev || !Prev->isStaticDataMember()) { // We expect to see a data data member here. Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_not_known) @@ -4793,7 +4714,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, break; case LookupResult::FoundUnresolvedValue: - llvm::llvm_unreachable("unresolved using decl in non-dependent context"); + llvm_unreachable("unresolved using decl in non-dependent context"); return QualType(); case LookupResult::FoundOverloaded: diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 613ffde..b4754db 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -2361,6 +2361,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, case Type::Enum: case Type::ObjCInterface: case Type::ObjCObjectPointer: + case Type::UnresolvedUsing: #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 623cde8..dddb93c8 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -544,7 +544,7 @@ namespace { /// \brief Rebuild the exception declaration and register the declaration /// as an instantiated local. VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T, - DeclaratorInfo *Declarator, + TypeSourceInfo *Declarator, IdentifierInfo *Name, SourceLocation Loc, SourceRange TypeRange); @@ -552,13 +552,10 @@ namespace { /// elaborated type. QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag); - Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E, - bool isAddressOfOperand); - Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E, - bool isAddressOfOperand); + Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E); + Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E); - Sema::OwningExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E, - bool isAddressOfOperand); + Sema::OwningExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E); /// \brief Transforms a template type parameter type by performing /// substitution of the corresponding template type argument. @@ -632,7 +629,7 @@ TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D, VarDecl * TemplateInstantiator::RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T, - DeclaratorInfo *Declarator, + TypeSourceInfo *Declarator, IdentifierInfo *Name, SourceLocation Loc, SourceRange TypeRange) { @@ -670,8 +667,7 @@ TemplateInstantiator::RebuildElaboratedType(QualType T, } Sema::OwningExprResult -TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E, - bool isAddressOfOperand) { +TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) { if (!E->isTypeDependent()) return SemaRef.Owned(E->Retain()); @@ -694,8 +690,7 @@ TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E, } Sema::OwningExprResult -TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E, - bool isAddressOfOperand) { +TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) { // FIXME: Clean this up a bit NamedDecl *D = E->getDecl(); if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) { @@ -782,29 +777,11 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E, // FindInstantiatedDecl will find it in the local instantiation scope. } - NamedDecl *InstD = SemaRef.FindInstantiatedDecl(D, TemplateArgs); - if (!InstD) - return SemaRef.ExprError(); - - assert(!isa<UsingDecl>(InstD) && "decl ref instantiated to UsingDecl"); - - CXXScopeSpec SS; - NestedNameSpecifier *Qualifier = 0; - if (E->getQualifier()) { - Qualifier = TransformNestedNameSpecifier(E->getQualifier(), - E->getQualifierRange()); - if (!Qualifier) - return SemaRef.ExprError(); - - SS.setScopeRep(Qualifier); - SS.setRange(E->getQualifierRange()); - } - - return SemaRef.BuildDeclarationNameExpr(SS, E->getLocation(), InstD); + return TreeTransform<TemplateInstantiator>::TransformDeclRefExpr(E); } Sema::OwningExprResult TemplateInstantiator::TransformCXXDefaultArgExpr( - CXXDefaultArgExpr *E, bool isAddressOfOperand) { + CXXDefaultArgExpr *E) { assert(!cast<FunctionDecl>(E->getParam()->getDeclContext())-> getDescribedFunctionTemplate() && "Default arg expressions are never formed in dependent cases."); @@ -889,7 +866,7 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, /// /// \returns If the instantiation succeeds, the instantiated /// type. Otherwise, produces diagnostics and returns a NULL type. -DeclaratorInfo *Sema::SubstType(DeclaratorInfo *T, +TypeSourceInfo *Sema::SubstType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &Args, SourceLocation Loc, DeclarationName Entity) { @@ -936,6 +913,13 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation, Base = Pattern->bases_begin(), BaseEnd = Pattern->bases_end(); Base != BaseEnd; ++Base) { if (!Base->getType()->isDependentType()) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + + // Make sure to set the attributes from the base. + SetClassDeclAttributesFromBase(Instantiation, BaseDecl, + Base->isVirtual()); + InstantiatedBases.push_back(new (Context) CXXBaseSpecifier(*Base)); continue; } @@ -1053,12 +1037,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Member != MemberEnd; ++Member) { Decl *NewMember = SubstDecl(*Member, Instantiation, TemplateArgs); if (NewMember) { - if (NewMember->isInvalidDecl()) { - Invalid = true; - } else if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) + if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) Fields.push_back(DeclPtrTy::make(Field)); - else if (UsingDecl *UD = dyn_cast<UsingDecl>(NewMember)) - Instantiation->addDecl(UD); + else if (NewMember->isInvalidDecl()) + Invalid = true; } else { // FIXME: Eventually, a NULL return will mean that one of the // instantiations was a semantic disaster, and we'll want to set Invalid = @@ -1070,13 +1052,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, ActOnFields(0, Instantiation->getLocation(), DeclPtrTy::make(Instantiation), Fields.data(), Fields.size(), SourceLocation(), SourceLocation(), 0); + CheckCompletedCXXClass(Instantiation); if (Instantiation->isInvalidDecl()) Invalid = true; - // Add any implicitly-declared members that we might need. - if (!Invalid) - AddImplicitlyDeclaredMembersToClass(Instantiation); - // Exit the scope of this instantiation. CurContext = PreviousContext; diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index a125857..8d74bd7 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -16,6 +16,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/Lex/Preprocessor.h" @@ -66,6 +67,8 @@ namespace { Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); Decl *VisitUsingDirectiveDecl(UsingDirectiveDecl *D); + Decl *VisitUsingDecl(UsingDecl *D); + Decl *VisitUsingShadowDecl(UsingShadowDecl *D); Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); @@ -125,13 +128,13 @@ TemplateDeclInstantiator::VisitNamespaceDecl(NamespaceDecl *D) { Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { bool Invalid = false; - DeclaratorInfo *DI = D->getTypeDeclaratorInfo(); + TypeSourceInfo *DI = D->getTypeSourceInfo(); if (DI->getType()->isDependentType()) { DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(), D->getDeclName()); if (!DI) { Invalid = true; - DI = SemaRef.Context.getTrivialDeclaratorInfo(SemaRef.Context.IntTy); + DI = SemaRef.Context.getTrivialTypeSourceInfo(SemaRef.Context.IntTy); } } @@ -147,9 +150,38 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { return Typedef; } +/// \brief Instantiate the arguments provided as part of initialization. +/// +/// \returns true if an error occurred, false otherwise. +static bool InstantiateInitializationArguments(Sema &SemaRef, + Expr **Args, unsigned NumArgs, + const MultiLevelTemplateArgumentList &TemplateArgs, + llvm::SmallVectorImpl<SourceLocation> &FakeCommaLocs, + ASTOwningVector<&ActionBase::DeleteExpr> &InitArgs) { + for (unsigned I = 0; I != NumArgs; ++I) { + // When we hit the first defaulted argument, break out of the loop: + // we don't pass those default arguments on. + if (Args[I]->isDefaultArgument()) + break; + + Sema::OwningExprResult Arg = SemaRef.SubstExpr(Args[I], TemplateArgs); + if (Arg.isInvalid()) + return true; + + Expr *ArgExpr = (Expr *)Arg.get(); + InitArgs.push_back(Arg.release()); + + // FIXME: We're faking all of the comma locations. Do we need them? + FakeCommaLocs.push_back( + SemaRef.PP.getLocForEndOfToken(ArgExpr->getLocEnd())); + } + + return false; +} + Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // Do substitution on the type of the declaration - DeclaratorInfo *DI = SemaRef.SubstType(D->getDeclaratorInfo(), + TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs, D->getTypeSpecStartLoc(), D->getDeclName()); @@ -193,48 +225,82 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { TSK_ImplicitInstantiation); if (D->getInit()) { - OwningExprResult Init - = 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->setType(D->getType()); - 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? - llvm::SmallVector<SourceLocation, 4> FakeCommaLocs; - if (PLE->getNumExprs() > 0) { - FakeCommaLocs.reserve(PLE->getNumExprs() - 1); - for (unsigned I = 0, N = PLE->getNumExprs() - 1; I != N; ++I) { - Expr *E = PLE->getExpr(I)->Retain(); - FakeCommaLocs.push_back( - SemaRef.PP.getLocForEndOfToken(E->getLocEnd())); - } - PLE->getExpr(PLE->getNumExprs() - 1)->Retain(); + if (Var->isStaticDataMember() && !D->isOutOfLine()) + SemaRef.PushExpressionEvaluationContext(Sema::Unevaluated); + else + SemaRef.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated); + + // Extract the initializer, skipping through any temporary-binding + // expressions and look at the subexpression as it was written. + Expr *DInit = D->getInit(); + while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(DInit)) + DInit = Binder->getSubExpr(); + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(DInit)) + DInit = ICE->getSubExprAsWritten(); + + if (ParenListExpr *PLE = dyn_cast<ParenListExpr>(DInit)) { + // The initializer is a parenthesized list of expressions that is + // type-dependent. Instantiate each of the expressions; we'll be + // performing direct initialization with them. + llvm::SmallVector<SourceLocation, 4> CommaLocs; + ASTOwningVector<&ActionBase::DeleteExpr> InitArgs(SemaRef); + if (!InstantiateInitializationArguments(SemaRef, + PLE->getExprs(), + PLE->getNumExprs(), + TemplateArgs, + CommaLocs, InitArgs)) { + // Add the direct initializer to the declaration. + SemaRef.AddCXXDirectInitializerToDecl(Sema::DeclPtrTy::make(Var), + PLE->getLParenLoc(), + move_arg(InitArgs), + CommaLocs.data(), + PLE->getRParenLoc()); } + } else if (CXXConstructExpr *Construct =dyn_cast<CXXConstructExpr>(DInit)) { + // The initializer resolved to a constructor. Instantiate the constructor + // arguments. + llvm::SmallVector<SourceLocation, 4> CommaLocs; + ASTOwningVector<&ActionBase::DeleteExpr> InitArgs(SemaRef); + + if (!InstantiateInitializationArguments(SemaRef, + Construct->getArgs(), + Construct->getNumArgs(), + TemplateArgs, + CommaLocs, InitArgs)) { + if (D->hasCXXDirectInitializer()) { + SourceLocation FakeLParenLoc = + SemaRef.PP.getLocForEndOfToken(D->getLocation()); + SourceLocation FakeRParenLoc = CommaLocs.empty()? FakeLParenLoc + : CommaLocs.back(); + SemaRef.AddCXXDirectInitializerToDecl(Sema::DeclPtrTy::make(Var), + FakeLParenLoc, + move_arg(InitArgs), + CommaLocs.data(), + FakeRParenLoc); + } else if (InitArgs.size() == 1) { + Expr *Init = (Expr*)(InitArgs.take()[0]); + SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), + SemaRef.Owned(Init), + false); + } else { + assert(InitArgs.size() == 0); + SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false); + } + } + } else { + OwningExprResult Init + = SemaRef.SubstExpr(D->getInit(), TemplateArgs); - // Add the direct initializer to the declaration. - SemaRef.AddCXXDirectInitializerToDecl(Sema::DeclPtrTy::make(Var), - PLE->getLParenLoc(), - Sema::MultiExprArg(SemaRef, - (void**)PLE->getExprs(), - PLE->getNumExprs()), - FakeCommaLocs.data(), - PLE->getRParenLoc()); - - // When Init is destroyed, it will destroy the instantiated ParenListExpr; - // we've explicitly retained all of its subexpressions already. - } else - SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), move(Init), - D->hasCXXDirectInitializer()); + // FIXME: Not happy about invalidating decls just because of a bad + // initializer, unless it affects the type. + if (Init.isInvalid()) + Var->setInvalidDecl(); + else + SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), move(Init), + D->hasCXXDirectInitializer()); + } + + SemaRef.PopExpressionEvaluationContext(); } else if (!Var->isStaticDataMember() || Var->isOutOfLine()) SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false); @@ -243,12 +309,12 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { bool Invalid = false; - DeclaratorInfo *DI = D->getDeclaratorInfo(); + TypeSourceInfo *DI = D->getTypeSourceInfo(); if (DI->getType()->isDependentType()) { DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(), D->getDeclName()); if (!DI) { - DI = D->getDeclaratorInfo(); + DI = D->getTypeSourceInfo(); Invalid = true; } else if (DI->getType()->isFunctionType()) { // C++ [temp.arg.type]p3: @@ -561,7 +627,12 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { InstTemplate->setAccess(D->getAccess()); assert(InstTemplate && "VisitFunctionDecl/CXXMethodDecl didn't create a template!"); - if (!InstTemplate->getInstantiatedFromMemberTemplate()) + + // Link the instantiation back to the pattern *unless* this is a + // non-definition friend declaration. + if (!InstTemplate->getInstantiatedFromMemberTemplate() && + !(InstTemplate->getFriendObjectKind() && + !D->getTemplatedDecl()->isThisDeclarationADefinition())) InstTemplate->setInstantiatedFromMemberTemplate(D); // Add non-friends into the owner. @@ -638,7 +709,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { TemplateArgs); FunctionDecl *Function = FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(), - D->getDeclName(), T, D->getDeclaratorInfo(), + D->getDeclName(), T, D->getTypeSourceInfo(), D->getStorageClass(), D->isInlineSpecified(), D->hasWrittenPrototype()); Function->setLexicalDeclContext(Owner); @@ -700,7 +771,8 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { Previous.clear(); } - SemaRef.CheckFunctionDeclaration(Function, Previous, false, Redeclaration, + SemaRef.CheckFunctionDeclaration(/*Scope*/ 0, Function, Previous, + false, Redeclaration, /*FIXME:*/OverloadableAttrRequired); // If the original function was part of a friend declaration, @@ -771,7 +843,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method = CXXConstructorDecl::Create(SemaRef.Context, Record, Constructor->getLocation(), Name, T, - Constructor->getDeclaratorInfo(), + Constructor->getTypeSourceInfo(), Constructor->isExplicit(), Constructor->isInlineSpecified(), false); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { @@ -789,12 +861,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, ConvTy); Method = CXXConversionDecl::Create(SemaRef.Context, Record, Conversion->getLocation(), Name, - T, Conversion->getDeclaratorInfo(), + T, Conversion->getTypeSourceInfo(), Conversion->isInlineSpecified(), Conversion->isExplicit()); } else { Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(), - D->getDeclName(), T, D->getDeclaratorInfo(), + D->getDeclName(), T, D->getTypeSourceInfo(), D->isStatic(), D->isInlineSpecified()); } @@ -860,15 +932,16 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, bool Redeclaration = false; bool OverloadableAttrRequired = false; - SemaRef.CheckFunctionDeclaration(Method, Previous, false, Redeclaration, + SemaRef.CheckFunctionDeclaration(0, Method, Previous, false, Redeclaration, /*FIXME:*/OverloadableAttrRequired); + if (D->isPure()) + SemaRef.CheckPureMethod(Method, SourceRange()); + if (!FunctionTemplate && (!Method->isInvalidDecl() || Previous.empty()) && !Method->getFriendObjectKind()) Owner->addDecl(Method); - SemaRef.AddOverriddenMethods(Record, Method); - return Method; } @@ -886,7 +959,7 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) { ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) { QualType T; - DeclaratorInfo *DI = D->getDeclaratorInfo(); + TypeSourceInfo *DI = D->getTypeSourceInfo(); if (DI) { DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(), D->getDeclName()); @@ -948,7 +1021,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( NonTypeTemplateParmDecl *D) { // Substitute into the type of the non-type template parameter. QualType T; - DeclaratorInfo *DI = D->getDeclaratorInfo(); + TypeSourceInfo *DI = D->getTypeSourceInfo(); if (DI) { DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(), D->getDeclName()); @@ -1027,6 +1100,80 @@ Decl *TemplateDeclInstantiator::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { return Inst; } +Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { + // The nested name specifier is non-dependent, so no transformation + // is required. + + // We only need to do redeclaration lookups if we're in a class + // scope (in fact, it's not really even possible in non-class + // scopes). + bool CheckRedeclaration = Owner->isRecord(); + + LookupResult Prev(SemaRef, D->getDeclName(), D->getLocation(), + Sema::LookupUsingDeclName, Sema::ForRedeclaration); + + UsingDecl *NewUD = UsingDecl::Create(SemaRef.Context, Owner, + D->getLocation(), + D->getNestedNameRange(), + D->getUsingLocation(), + D->getTargetNestedNameDecl(), + D->getDeclName(), + D->isTypeName()); + + CXXScopeSpec SS; + SS.setScopeRep(D->getTargetNestedNameDecl()); + SS.setRange(D->getNestedNameRange()); + + if (CheckRedeclaration) { + Prev.setHideTags(false); + SemaRef.LookupQualifiedName(Prev, Owner); + + // Check for invalid redeclarations. + if (SemaRef.CheckUsingDeclRedeclaration(D->getUsingLocation(), + D->isTypeName(), SS, + D->getLocation(), Prev)) + NewUD->setInvalidDecl(); + + } + + if (!NewUD->isInvalidDecl() && + SemaRef.CheckUsingDeclQualifier(D->getUsingLocation(), SS, + D->getLocation())) + NewUD->setInvalidDecl(); + + SemaRef.Context.setInstantiatedFromUsingDecl(NewUD, D); + NewUD->setAccess(D->getAccess()); + Owner->addDecl(NewUD); + + // Don't process the shadow decls for an invalid decl. + if (NewUD->isInvalidDecl()) + return NewUD; + + // Process the shadow decls. + for (UsingDecl::shadow_iterator I = D->shadow_begin(), E = D->shadow_end(); + I != E; ++I) { + UsingShadowDecl *Shadow = *I; + NamedDecl *InstTarget = + cast<NamedDecl>(SemaRef.FindInstantiatedDecl(Shadow->getTargetDecl(), + TemplateArgs)); + + if (CheckRedeclaration && + SemaRef.CheckUsingShadowDecl(NewUD, InstTarget, Prev)) + continue; + + UsingShadowDecl *InstShadow + = SemaRef.BuildUsingShadowDecl(/*Scope*/ 0, NewUD, InstTarget); + SemaRef.Context.setInstantiatedFromUsingShadowDecl(InstShadow, Shadow); + } + + return NewUD; +} + +Decl *TemplateDeclInstantiator::VisitUsingShadowDecl(UsingShadowDecl *D) { + // Ignore these; we handle them in bulk when processing the UsingDecl. + return 0; +} + Decl * TemplateDeclInstantiator ::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { NestedNameSpecifier *NNS = @@ -1047,8 +1194,8 @@ Decl * TemplateDeclInstantiator /*instantiation*/ true, /*typename*/ true, D->getTypenameLoc()); if (UD) - SemaRef.Context.setInstantiatedFromUnresolvedUsingDecl(cast<UsingDecl>(UD), - D); + SemaRef.Context.setInstantiatedFromUsingDecl(cast<UsingDecl>(UD), D); + return UD; } @@ -1072,8 +1219,8 @@ Decl * TemplateDeclInstantiator /*instantiation*/ true, /*typename*/ false, SourceLocation()); if (UD) - SemaRef.Context.setInstantiatedFromUnresolvedUsingDecl(cast<UsingDecl>(UD), - D); + SemaRef.Context.setInstantiatedFromUsingDecl(cast<UsingDecl>(UD), D); + return UD; } @@ -1336,6 +1483,43 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, } } + const FunctionProtoType *Proto = Tmpl->getType()->getAs<FunctionProtoType>(); + assert(Proto && "Function template without prototype?"); + + if (Proto->hasExceptionSpec() || Proto->hasAnyExceptionSpec() || + Proto->getNoReturnAttr()) { + // The function has an exception specification or a "noreturn" + // attribute. Substitute into each of the exception types. + llvm::SmallVector<QualType, 4> Exceptions; + for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) { + // FIXME: Poor location information! + QualType T + = SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs, + New->getLocation(), New->getDeclName()); + if (T.isNull() || + SemaRef.CheckSpecifiedExceptionType(T, New->getLocation())) + continue; + + Exceptions.push_back(T); + } + + // Rebuild the function type + + const FunctionProtoType *NewProto + = New->getType()->getAs<FunctionProtoType>(); + assert(NewProto && "Template instantiation without function prototype?"); + New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(), + NewProto->arg_type_begin(), + NewProto->getNumArgs(), + NewProto->isVariadic(), + NewProto->getTypeQuals(), + Proto->hasExceptionSpec(), + Proto->hasAnyExceptionSpec(), + Exceptions.size(), + Exceptions.data(), + Proto->getNoReturnAttr())); + } + return false; } @@ -1352,17 +1536,8 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner); New->setAccess(Tmpl->getAccess()); - if (Tmpl->isVirtualAsWritten()) { - New->setVirtualAsWritten(true); - Record->setAggregate(false); - Record->setPOD(false); - Record->setEmpty(false); - Record->setPolymorphic(true); - } - if (Tmpl->isPure()) { - New->setPure(); - Record->setAbstract(true); - } + if (Tmpl->isVirtualAsWritten()) + Record->setMethodAsVirtual(New); // FIXME: attributes // FIXME: New needs a pointer to Tmpl @@ -1623,14 +1798,19 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, MemInitResult NewInit; if (Init->isBaseInitializer()) { - QualType BaseType(Init->getBaseClass(), 0); - BaseType = SubstType(BaseType, TemplateArgs, Init->getSourceLocation(), - New->getDeclName()); - - NewInit = BuildBaseInitializer(BaseType, + TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(), + TemplateArgs, + Init->getSourceLocation(), + New->getDeclName()); + if (!BaseTInfo) { + New->setInvalidDecl(); + continue; + } + + NewInit = BuildBaseInitializer(BaseTInfo->getType(), BaseTInfo, (Expr **)NewArgs.data(), NewArgs.size(), - Init->getSourceLocation(), + Init->getLParenLoc(), Init->getRParenLoc(), New->getParent()); } else if (Init->isMemberInitializer()) { @@ -1646,6 +1826,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, NewInit = BuildMemberInitializer(Member, (Expr **)NewArgs.data(), NewArgs.size(), Init->getSourceLocation(), + Init->getLParenLoc(), Init->getRParenLoc()); } @@ -1749,16 +1930,28 @@ static bool isInstantiationOf(EnumDecl *Pattern, return false; } +static bool isInstantiationOf(UsingShadowDecl *Pattern, + UsingShadowDecl *Instance, + ASTContext &C) { + return C.getInstantiatedFromUsingShadowDecl(Instance) == Pattern; +} + +static bool isInstantiationOf(UsingDecl *Pattern, + UsingDecl *Instance, + ASTContext &C) { + return C.getInstantiatedFromUsingDecl(Instance) == Pattern; +} + static bool isInstantiationOf(UnresolvedUsingValueDecl *Pattern, UsingDecl *Instance, ASTContext &C) { - return C.getInstantiatedFromUnresolvedUsingDecl(Instance) == Pattern; + return C.getInstantiatedFromUsingDecl(Instance) == Pattern; } static bool isInstantiationOf(UnresolvedUsingTypenameDecl *Pattern, UsingDecl *Instance, ASTContext &C) { - return C.getInstantiatedFromUnresolvedUsingDecl(Instance) == Pattern; + return C.getInstantiatedFromUsingDecl(Instance) == Pattern; } static bool isInstantiationOfStaticDataMember(VarDecl *Pattern, @@ -1776,6 +1969,8 @@ static bool isInstantiationOfStaticDataMember(VarDecl *Pattern, return false; } +// Other is the prospective instantiation +// D is the prospective pattern static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { if (D->getKind() != Other->getKind()) { if (UnresolvedUsingTypenameDecl *UUD @@ -1827,6 +2022,12 @@ static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { } } + if (UsingDecl *Using = dyn_cast<UsingDecl>(Other)) + return isInstantiationOf(cast<UsingDecl>(D), Using, Ctx); + + if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(Other)) + return isInstantiationOf(cast<UsingShadowDecl>(D), Shadow, Ctx); + return D->getDeclName() && isa<NamedDecl>(Other) && D->getDeclName() == cast<NamedDecl>(Other)->getDeclName(); } @@ -1979,7 +2180,10 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D, ParentDC->decls_end()); } - assert(Result && "Unable to find instantiation of declaration!"); + // UsingShadowDecls can instantiate to nothing because of using hiding. + assert((Result || isa<UsingShadowDecl>(D)) + && "Unable to find instantiation of declaration!"); + D = Result; } diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index afce5e3..37f19f2 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -356,10 +356,14 @@ static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){ // or incomplete types shall not be restrict-qualified." C++ also allows // restrict-qualified references. if (TypeQuals & DeclSpec::TQ_restrict) { - if (Result->isPointerType() || Result->isReferenceType()) { - QualType EltTy = Result->isPointerType() ? - Result->getAs<PointerType>()->getPointeeType() : - Result->getAs<ReferenceType>()->getPointeeType(); + if (Result->isAnyPointerType() || Result->isReferenceType()) { + QualType EltTy; + if (Result->isObjCObjectPointerType()) + EltTy = Result; + else + EltTy = Result->isPointerType() ? + Result->getAs<PointerType>()->getPointeeType() : + Result->getAs<ReferenceType>()->getPointeeType(); // If we have a pointer or reference, the pointee must have an object // incomplete type. @@ -846,20 +850,20 @@ QualType Sema::BuildBlockPointerType(QualType T, unsigned CVR, return Context.getQualifiedType(Context.getBlockPointerType(T), Quals); } -QualType Sema::GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo) { +QualType Sema::GetTypeFromParser(TypeTy *Ty, TypeSourceInfo **TInfo) { QualType QT = QualType::getFromOpaquePtr(Ty); if (QT.isNull()) { - if (DInfo) *DInfo = 0; + if (TInfo) *TInfo = 0; return QualType(); } - DeclaratorInfo *DI = 0; + TypeSourceInfo *DI = 0; if (LocInfoType *LIT = dyn_cast<LocInfoType>(QT)) { QT = LIT->getType(); - DI = LIT->getDeclaratorInfo(); + DI = LIT->getTypeSourceInfo(); } - if (DInfo) *DInfo = DI; + if (TInfo) *TInfo = DI; return QT; } @@ -870,7 +874,7 @@ QualType Sema::GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo) { /// owns the declaration of a type (e.g., the definition of a struct /// type), then *OwnedDecl will receive the owned declaration. QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, - DeclaratorInfo **DInfo, + TypeSourceInfo **TInfo, TagDecl **OwnedDecl) { // Determine the type of the declarator. Not all forms of declarator // have a type. @@ -897,6 +901,9 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, break; } + if (T.isNull()) + return T; + if (T == Context.UndeducedAutoTy) { int Error = -1; @@ -1186,7 +1193,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, case NestedNameSpecifier::Namespace: case NestedNameSpecifier::Global: - llvm::llvm_unreachable("Nested-name-specifier must name a type"); + llvm_unreachable("Nested-name-specifier must name a type"); break; case NestedNameSpecifier::TypeSpec: @@ -1256,11 +1263,11 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (const AttributeList *Attrs = D.getAttributes()) ProcessTypeAttributeList(T, Attrs); - if (DInfo) { + if (TInfo) { if (D.isInvalidType()) - *DInfo = 0; + *TInfo = 0; else - *DInfo = GetDeclaratorInfoForDeclarator(D, T); + *TInfo = GetTypeSourceInfoForDeclarator(D, T); } return T; @@ -1326,18 +1333,18 @@ namespace { } } void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) { - DeclaratorInfo *DInfo = 0; - Sema::GetTypeFromParser(DS.getTypeRep(), &DInfo); + TypeSourceInfo *TInfo = 0; + Sema::GetTypeFromParser(DS.getTypeRep(), &TInfo); // If we got no declarator info from previous Sema routines, // just fill with the typespec loc. - if (!DInfo) { + if (!TInfo) { TL.initialize(DS.getTypeSpecTypeLoc()); return; } TemplateSpecializationTypeLoc OldTL = - cast<TemplateSpecializationTypeLoc>(DInfo->getTypeLoc()); + cast<TemplateSpecializationTypeLoc>(TInfo->getTypeLoc()); TL.copy(OldTL); } void VisitTypeLoc(TypeLoc TL) { @@ -1353,7 +1360,7 @@ namespace { DeclaratorLocFiller(const DeclaratorChunk &Chunk) : Chunk(Chunk) {} void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { - llvm::llvm_unreachable("qualified type locs not expected here!"); + llvm_unreachable("qualified type locs not expected here!"); } void VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { @@ -1408,18 +1415,18 @@ namespace { } void VisitTypeLoc(TypeLoc TL) { - llvm::llvm_unreachable("unsupported TypeLoc kind in declarator!"); + llvm_unreachable("unsupported TypeLoc kind in declarator!"); } }; } -/// \brief Create and instantiate a DeclaratorInfo with type source information. +/// \brief Create and instantiate a TypeSourceInfo with type source information. /// /// \param T QualType referring to the type as written in source code. -DeclaratorInfo * -Sema::GetDeclaratorInfoForDeclarator(Declarator &D, QualType T) { - DeclaratorInfo *DInfo = Context.CreateDeclaratorInfo(T); - UnqualTypeLoc CurrTL = DInfo->getTypeLoc().getUnqualifiedLoc(); +TypeSourceInfo * +Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T) { + TypeSourceInfo *TInfo = Context.CreateTypeSourceInfo(T); + UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc(); for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { DeclaratorLocFiller(D.getTypeObject(i)).Visit(CurrTL); @@ -1428,16 +1435,16 @@ Sema::GetDeclaratorInfoForDeclarator(Declarator &D, QualType T) { TypeSpecLocFiller(D.getDeclSpec()).Visit(CurrTL); - return DInfo; + return TInfo; } -/// \brief Create a LocInfoType to hold the given QualType and DeclaratorInfo. -QualType Sema::CreateLocInfoType(QualType T, DeclaratorInfo *DInfo) { +/// \brief Create a LocInfoType to hold the given QualType and TypeSourceInfo. +QualType Sema::CreateLocInfoType(QualType T, TypeSourceInfo *TInfo) { // FIXME: LocInfoTypes are "transient", only needed for passing to/from Parser // and Sema during declaration parsing. Try deallocating/caching them when // it's appropriate, instead of allocating them and keeping them around. LocInfoType *LocT = (LocInfoType*)BumpAlloc.Allocate(sizeof(LocInfoType), 8); - new (LocT) LocInfoType(T, DInfo); + new (LocT) LocInfoType(T, TInfo); assert(LocT->getTypeClass() != T->getTypeClass() && "LocInfoType's TypeClass conflicts with an existing Type class"); return QualType(LocT, 0); @@ -1512,9 +1519,9 @@ Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { // the parser. assert(D.getIdentifier() == 0 && "Type name should have no identifier!"); - DeclaratorInfo *DInfo = 0; + TypeSourceInfo *TInfo = 0; TagDecl *OwnedTag = 0; - QualType T = GetTypeForDeclarator(D, S, &DInfo, &OwnedTag); + QualType T = GetTypeForDeclarator(D, S, &TInfo, &OwnedTag); if (D.isInvalidType()) return true; @@ -1531,8 +1538,8 @@ Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { << Context.getTypeDeclType(OwnedTag); } - if (DInfo) - T = CreateLocInfoType(T, DInfo); + if (TInfo) + T = CreateLocInfoType(T, TInfo); return T.getAsOpaquePtr(); } @@ -1640,6 +1647,53 @@ static void HandleNoReturnTypeAttribute(QualType &Type, Type = S.Context.getNoReturnType(Type); } +/// HandleVectorSizeAttribute - this attribute is only applicable to integral +/// and float scalars, although arrays, pointers, and function return values are +/// allowed in conjunction with this construct. Aggregates with this attribute +/// are invalid, even if they are of the same size as a corresponding scalar. +/// The raw attribute should contain precisely 1 argument, the vector size for +/// the variable, measured in bytes. If curType and rawAttr are well formed, +/// this routine will return a new vector type. +static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, Sema &S) { + // Check the attribute arugments. + if (Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0)); + llvm::APSInt vecSize(32); + if (!sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) + << "vector_size" << sizeExpr->getSourceRange(); + return; + } + // the base type must be integer or float, and can't already be a vector. + if (CurType->isVectorType() || + (!CurType->isIntegerType() && !CurType->isRealFloatingType())) { + S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << CurType; + return; + } + unsigned typeSize = static_cast<unsigned>(S.Context.getTypeSize(CurType)); + // vecSize is specified in bytes - convert to bits. + unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue() * 8); + + // the vector size needs to be an integral multiple of the type size. + if (vectorSize % typeSize) { + S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size) + << sizeExpr->getSourceRange(); + return; + } + if (vectorSize == 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_zero_size) + << sizeExpr->getSourceRange(); + return; + } + + // Success! Instantiate the vector type, the number of elements is > 0, and + // not required to be a power of 2, unlike GCC. + CurType = S.Context.getVectorType(CurType, vectorSize/typeSize); +} + void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) { // Scan through and apply attributes to this type where it makes sense. Some // attributes (such as __address_space__, __vector_size__, etc) apply to the @@ -1659,6 +1713,9 @@ void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) { case AttributeList::AT_noreturn: HandleNoReturnTypeAttribute(Result, *AL, *this); break; + case AttributeList::AT_vector_size: + HandleVectorSizeAttr(Result, *AL, *this); + break; } } } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 28b2174..fd19987 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -172,13 +172,23 @@ public: return T.isNull(); } + /// \brief Determine whether the given call argument should be dropped, e.g., + /// because it is a default argument. + /// + /// Subclasses can provide an alternative implementation of this routine to + /// determine which kinds of call arguments get dropped. By default, + /// CXXDefaultArgument nodes are dropped (prior to transformation). + bool DropCallArgument(Expr *E) { + return E->isDefaultArgument(); + } + /// \brief Transforms the given type into another type. /// /// By default, this routine transforms a type by creating a - /// DeclaratorInfo for it and delegating to the appropriate + /// TypeSourceInfo for it and delegating to the appropriate /// function. This is expensive, but we don't mind, because /// this method is deprecated anyway; all users should be - /// switched to storing DeclaratorInfos. + /// switched to storing TypeSourceInfos. /// /// \returns the transformed type. QualType TransformType(QualType T); @@ -191,7 +201,7 @@ public: /// may override this function (to take over all type /// transformations) or some set of the TransformXXXType functions /// to alter the transformation. - DeclaratorInfo *TransformType(DeclaratorInfo *DI); + TypeSourceInfo *TransformType(TypeSourceInfo *DI); /// \brief Transform the given type-with-location into a new /// type, collecting location information in the given builder @@ -218,19 +228,7 @@ public: /// other mechanism. /// /// \returns the transformed expression. - OwningExprResult TransformExpr(Expr *E) { - return getDerived().TransformExpr(E, /*isAddressOfOperand=*/false); - } - - /// \brief Transform the given expression. - /// - /// By default, this routine transforms an expression by delegating to the - /// appropriate TransformXXXExpr function to build a new expression. - /// Subclasses may override this function to transform expressions using some - /// other mechanism. - /// - /// \returns the transformed expression. - OwningExprResult TransformExpr(Expr *E, bool isAddressOfOperand); + OwningExprResult TransformExpr(Expr *E); /// \brief Transform the given declaration, which is referenced from a type /// or expression. @@ -301,9 +299,9 @@ public: void InventTemplateArgumentLoc(const TemplateArgument &Arg, TemplateArgumentLoc &ArgLoc); - /// \brief Fakes up a DeclaratorInfo for a type. - DeclaratorInfo *InventDeclaratorInfo(QualType T) { - return SemaRef.Context.getTrivialDeclaratorInfo(T, + /// \brief Fakes up a TypeSourceInfo for a type. + TypeSourceInfo *InventTypeSourceInfo(QualType T) { + return SemaRef.Context.getTrivialTypeSourceInfo(T, getDerived().getBaseLocation()); } @@ -328,7 +326,7 @@ public: #define STMT(Node, Parent) \ OwningStmtResult Transform##Node(Node *S); #define EXPR(Node, Parent) \ - OwningExprResult Transform##Node(Node *E, bool isAddressOfOperand); + OwningExprResult Transform##Node(Node *E); #define ABSTRACT_EXPR(Node, Parent) #include "clang/AST/StmtNodes.def" @@ -461,6 +459,10 @@ public: /// \brief Build a new unprototyped function type. QualType RebuildFunctionNoProtoType(QualType ResultType); + /// \brief Rebuild an unresolved typename type, given the decl that + /// the UnresolvedUsingTypenameDecl was transformed to. + QualType RebuildUnresolvedUsingType(Decl *D); + /// \brief Build a new typedef type. QualType RebuildTypedefType(TypedefDecl *Typedef) { return SemaRef.Context.getTypeDeclType(Typedef); @@ -779,7 +781,7 @@ public: /// By default, performs semantic analysis to build the new decaration. /// Subclasses may override this routine to provide different behavior. VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T, - DeclaratorInfo *Declarator, + TypeSourceInfo *Declarator, IdentifierInfo *Name, SourceLocation Loc, SourceRange TypeRange) { @@ -826,15 +828,15 @@ public: /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildDeclRefExpr(NestedNameSpecifier *Qualifier, SourceRange QualifierRange, - NamedDecl *ND, SourceLocation Loc, - bool isAddressOfOperand) { + ValueDecl *VD, SourceLocation Loc, + TemplateArgumentListInfo *TemplateArgs) { CXXScopeSpec SS; SS.setScopeRep(Qualifier); SS.setRange(QualifierRange); - return getSema().BuildDeclarationNameExpr(Loc, ND, - /*FIXME:*/false, - &SS, - isAddressOfOperand); + + // FIXME: loses template args. + + return getSema().BuildDeclarationNameExpr(SS, Loc, VD); } /// \brief Build a new expression in parentheses. @@ -863,11 +865,14 @@ public: SS.setScopeRep(Qualifier); } + QualType BaseType = ((Expr*) Base.get())->getType(); + DeclarationName Name = SemaRef.Context.DeclarationNames.getCXXDestructorName( SemaRef.Context.getCanonicalType(DestroyedType)); - return getSema().BuildMemberReferenceExpr(move(Base), OperatorLoc, isArrow, + return getSema().BuildMemberReferenceExpr(move(Base), BaseType, + OperatorLoc, isArrow, SS, /*FIXME: FirstQualifier*/ 0, Name, DestroyedTypeLoc, /*TemplateArgs*/ 0); @@ -887,10 +892,10 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildSizeOfAlignOf(DeclaratorInfo *DInfo, + OwningExprResult RebuildSizeOfAlignOf(TypeSourceInfo *TInfo, SourceLocation OpLoc, bool isSizeOf, SourceRange R) { - return getSema().CreateSizeOfAlignOfExpr(DInfo, OpLoc, isSizeOf, R); + return getSema().CreateSizeOfAlignOfExpr(TInfo, OpLoc, isSizeOf, R); } /// \brief Build a new sizeof or alignof expression with an expression @@ -944,7 +949,7 @@ public: NestedNameSpecifier *Qualifier, SourceRange QualifierRange, SourceLocation MemberLoc, - NamedDecl *Member, + ValueDecl *Member, const TemplateArgumentListInfo *ExplicitTemplateArgs, NamedDecl *FirstQualifierInScope) { if (!Member->getDeclName()) { @@ -964,7 +969,11 @@ public: SS.setScopeRep(Qualifier); } - return getSema().BuildMemberReferenceExpr(move(Base), OpLoc, isArrow, + QualType BaseType = ((Expr*) Base.get())->getType(); + + // FIXME: wait, this is re-performing lookup? + return getSema().BuildMemberReferenceExpr(move(Base), BaseType, + OpLoc, isArrow, SS, FirstQualifierInScope, Member->getDeclName(), MemberLoc, ExplicitTemplateArgs); @@ -994,19 +1003,6 @@ public: move(LHS), move(RHS)); } - /// \brief Build a new implicit cast expression. - /// - /// By default, builds a new implicit cast without any semantic analysis. - /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildImplicitCastExpr(QualType T, CastExpr::CastKind Kind, - ExprArg SubExpr, bool isLvalue) { - ImplicitCastExpr *ICE - = new (getSema().Context) ImplicitCastExpr(T, Kind, - (Expr *)SubExpr.release(), - isLvalue); - return getSema().Owned(ICE); - } - /// \brief Build a new C-style cast expression. /// /// By default, performs semantic analysis to build the new expression. @@ -1042,8 +1038,10 @@ public: SourceLocation OpLoc, SourceLocation AccessorLoc, IdentifierInfo &Accessor) { + CXXScopeSpec SS; - return getSema().BuildMemberReferenceExpr(move(Base), + QualType BaseType = ((Expr*) Base.get())->getType(); + return getSema().BuildMemberReferenceExpr(move(Base), BaseType, OpLoc, /*IsArrow*/ false, SS, /*FirstQualifierInScope*/ 0, DeclarationName(&Accessor), @@ -1471,13 +1469,17 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCXXConstructExpr(QualType T, + SourceLocation Loc, CXXConstructorDecl *Constructor, bool IsElidable, MultiExprArg Args) { - return getSema().BuildCXXConstructExpr(/*FIXME:ConstructLoc*/ - SourceLocation(), - T, Constructor, IsElidable, - move(Args)); + ASTOwningVector<&ActionBase::DeleteExpr> ConvertedArgs(SemaRef); + if (getSema().CompleteConstructorCall(Constructor, move(Args), Loc, + ConvertedArgs)) + return getSema().ExprError(); + + return getSema().BuildCXXConstructExpr(Loc, T, Constructor, IsElidable, + move_arg(ConvertedArgs)); } /// \brief Build a new object-construction expression. @@ -1522,6 +1524,7 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCXXDependentScopeMemberExpr(ExprArg BaseE, + QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, @@ -1534,7 +1537,8 @@ public: SS.setRange(QualifierRange); SS.setScopeRep(Qualifier); - return SemaRef.BuildMemberReferenceExpr(move(BaseE), OperatorLoc, IsArrow, + return SemaRef.BuildMemberReferenceExpr(move(BaseE), BaseType, + OperatorLoc, IsArrow, SS, FirstQualifierInScope, Name, MemberLoc, TemplateArgs); } @@ -1544,19 +1548,19 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildUnresolvedMemberExpr(ExprArg BaseE, + QualType BaseType, SourceLocation OperatorLoc, bool IsArrow, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs) { - OwningExprResult Base = move(BaseE); - CXXScopeSpec SS; SS.setRange(QualifierRange); SS.setScopeRep(Qualifier); - return SemaRef.BuildMemberReferenceExpr(move(Base), OperatorLoc, IsArrow, + return SemaRef.BuildMemberReferenceExpr(move(BaseE), BaseType, + OperatorLoc, IsArrow, SS, R, TemplateArgs); } @@ -1660,8 +1664,7 @@ Sema::OwningStmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) { template<typename Derived> -Sema::OwningExprResult TreeTransform<Derived>::TransformExpr(Expr *E, - bool isAddressOfOperand) { +Sema::OwningExprResult TreeTransform<Derived>::TransformExpr(Expr *E) { if (!E) return SemaRef.Owned(E); @@ -1669,8 +1672,7 @@ Sema::OwningExprResult TreeTransform<Derived>::TransformExpr(Expr *E, case Stmt::NoStmtClass: break; #define STMT(Node, Parent) case Stmt::Node##Class: break; #define EXPR(Node, Parent) \ - case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(E), \ - isAddressOfOperand); + case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(E)); #include "clang/AST/StmtNodes.def" } @@ -1870,12 +1872,12 @@ void TreeTransform<Derived>::InventTemplateArgumentLoc( SourceLocation Loc = getDerived().getBaseLocation(); switch (Arg.getKind()) { case TemplateArgument::Null: - llvm::llvm_unreachable("null template argument in TreeTransform"); + llvm_unreachable("null template argument in TreeTransform"); break; case TemplateArgument::Type: Output = TemplateArgumentLoc(Arg, - SemaRef.Context.getTrivialDeclaratorInfo(Arg.getAsType(), Loc)); + SemaRef.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc)); break; @@ -1907,9 +1909,9 @@ bool TreeTransform<Derived>::TransformTemplateArgument( return false; case TemplateArgument::Type: { - DeclaratorInfo *DI = Input.getSourceDeclaratorInfo(); + TypeSourceInfo *DI = Input.getTypeSourceInfo(); if (DI == NULL) - DI = InventDeclaratorInfo(Input.getArgument().getAsType()); + DI = InventTypeSourceInfo(Input.getArgument().getAsType()); DI = getDerived().TransformType(DI); if (!DI) return true; @@ -2016,10 +2018,10 @@ QualType TreeTransform<Derived>::TransformType(QualType T) { // Temporary workaround. All of these transformations should // eventually turn into transformations on TypeLocs. - DeclaratorInfo *DI = getSema().Context.CreateDeclaratorInfo(T); + TypeSourceInfo *DI = getSema().Context.CreateTypeSourceInfo(T); DI->getTypeLoc().initialize(getDerived().getBaseLocation()); - DeclaratorInfo *NewDI = getDerived().TransformType(DI); + TypeSourceInfo *NewDI = getDerived().TransformType(DI); if (!NewDI) return QualType(); @@ -2028,7 +2030,7 @@ QualType TreeTransform<Derived>::TransformType(QualType T) { } template<typename Derived> -DeclaratorInfo *TreeTransform<Derived>::TransformType(DeclaratorInfo *DI) { +TypeSourceInfo *TreeTransform<Derived>::TransformType(TypeSourceInfo *DI) { if (getDerived().AlreadyTransformed(DI->getType())) return DI; @@ -2041,7 +2043,7 @@ DeclaratorInfo *TreeTransform<Derived>::TransformType(DeclaratorInfo *DI) { if (Result.isNull()) return 0; - return TLB.getDeclaratorInfo(SemaRef.Context, Result); + return TLB.getTypeSourceInfo(SemaRef.Context, Result); } template<typename Derived> @@ -2055,7 +2057,7 @@ TreeTransform<Derived>::TransformType(TypeLocBuilder &TLB, TypeLoc T) { #include "clang/AST/TypeLocNodes.def" } - llvm::llvm_unreachable("unhandled type loc!"); + llvm_unreachable("unhandled type loc!"); return QualType(); } @@ -2489,10 +2491,10 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, ParmVarDecl *NewParm; if (OldParm) { - DeclaratorInfo *OldDI = OldParm->getDeclaratorInfo(); + TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); assert(OldDI->getType() == T->getArgType(i)); - DeclaratorInfo *NewDI = getDerived().TransformType(OldDI); + TypeSourceInfo *NewDI = getDerived().TransformType(OldDI); if (!NewDI) return QualType(); @@ -2567,6 +2569,29 @@ QualType TreeTransform<Derived>::TransformFunctionNoProtoType( return Result; } +template<typename Derived> QualType +TreeTransform<Derived>::TransformUnresolvedUsingType(TypeLocBuilder &TLB, + UnresolvedUsingTypeLoc TL) { + UnresolvedUsingType *T = TL.getTypePtr(); + Decl *D = getDerived().TransformDecl(T->getDecl()); + if (!D) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || D != T->getDecl()) { + Result = getDerived().RebuildUnresolvedUsingType(D); + if (Result.isNull()) + return QualType(); + } + + // We might get an arbitrary type spec type back. We should at + // least always get a type spec type, though. + TypeSpecTypeLoc NewTL = TLB.pushTypeSpec(Result); + NewTL.setNameLoc(TL.getNameLoc()); + + return Result; +} + template<typename Derived> QualType TreeTransform<Derived>::TransformTypedefType(TypeLocBuilder &TLB, TypedefTypeLoc TL) { @@ -2622,7 +2647,7 @@ QualType TreeTransform<Derived>::TransformTypeOfType(TypeLocBuilder &TLB, TypeOfTypeLoc TL) { TypeOfType *T = TL.getTypePtr(); - // FIXME: should be an inner type, or at least have a DeclaratorInfo. + // FIXME: should be an inner type, or at least have a TypeSourceInfo. QualType Underlying = getDerived().TransformType(T->getUnderlyingType()); if (Underlying.isNull()) return QualType(); @@ -3364,7 +3389,7 @@ TreeTransform<Derived>::TransformCXXCatchStmt(CXXCatchStmt *S) { Var = getDerived().RebuildExceptionDecl(ExceptionDecl, T, - ExceptionDecl->getDeclaratorInfo(), + ExceptionDecl->getTypeSourceInfo(), ExceptionDecl->getIdentifier(), ExceptionDecl->getLocation(), /*FIXME: Inaccurate*/ @@ -3430,15 +3455,13 @@ TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) { //===----------------------------------------------------------------------===// template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformPredefinedExpr(PredefinedExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformPredefinedExpr(PredefinedExpr *E) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) { NestedNameSpecifier *Qualifier = 0; if (E->getQualifier()) { Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), @@ -3446,72 +3469,74 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E, if (!Qualifier) return SemaRef.ExprError(); } - - NamedDecl *ND - = dyn_cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getDecl())); + + ValueDecl *ND + = cast_or_null<ValueDecl>(getDerived().TransformDecl(E->getDecl())); if (!ND) return SemaRef.ExprError(); if (!getDerived().AlwaysRebuild() && Qualifier == E->getQualifier() && ND == E->getDecl() && - !E->hasExplicitTemplateArgumentList()) - return SemaRef.Owned(E->Retain()); + !E->hasExplicitTemplateArgumentList()) { - // FIXME: We're losing the explicit template arguments in this transformation. + // Mark it referenced in the new context regardless. + // FIXME: this is a bit instantiation-specific. + SemaRef.MarkDeclarationReferenced(E->getLocation(), ND); - llvm::SmallVector<TemplateArgumentLoc, 4> TransArgs(E->getNumTemplateArgs()); - for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { - if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], - TransArgs[I])) - return SemaRef.ExprError(); + return SemaRef.Owned(E->Retain()); } - - // FIXME: Pass the qualifier/qualifier range along. + + TemplateArgumentListInfo TransArgs, *TemplateArgs = 0; + if (E->hasExplicitTemplateArgumentList()) { + TemplateArgs = &TransArgs; + TransArgs.setLAngleLoc(E->getLAngleLoc()); + TransArgs.setRAngleLoc(E->getRAngleLoc()); + for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { + TemplateArgumentLoc Loc; + if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], Loc)) + return SemaRef.ExprError(); + TransArgs.addArgument(Loc); + } + } + return getDerived().RebuildDeclRefExpr(Qualifier, E->getQualifierRange(), - ND, E->getLocation(), - isAddressOfOperand); + ND, E->getLocation(), TemplateArgs); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformIntegerLiteral(IntegerLiteral *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformIntegerLiteral(IntegerLiteral *E) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformFloatingLiteral(FloatingLiteral *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformFloatingLiteral(FloatingLiteral *E) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformImaginaryLiteral(ImaginaryLiteral *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformImaginaryLiteral(ImaginaryLiteral *E) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformStringLiteral(StringLiteral *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformStringLiteral(StringLiteral *E) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformParenExpr(ParenExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformParenExpr(ParenExpr *E) { OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -3525,10 +3550,8 @@ TreeTransform<Derived>::TransformParenExpr(ParenExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E, - bool isAddressOfOperand) { - OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr(), - E->getOpcode() == UnaryOperator::AddrOf); +TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E) { + OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -3542,12 +3565,11 @@ TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { if (E->isArgumentType()) { - DeclaratorInfo *OldT = E->getArgumentTypeInfo(); + TypeSourceInfo *OldT = E->getArgumentTypeInfo(); - DeclaratorInfo *NewT = getDerived().TransformType(OldT); + TypeSourceInfo *NewT = getDerived().TransformType(OldT); if (!NewT) return SemaRef.ExprError(); @@ -3581,8 +3603,7 @@ TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformArraySubscriptExpr(ArraySubscriptExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformArraySubscriptExpr(ArraySubscriptExpr *E) { OwningExprResult LHS = getDerived().TransformExpr(E->getLHS()); if (LHS.isInvalid()) return SemaRef.ExprError(); @@ -3605,8 +3626,7 @@ TreeTransform<Derived>::TransformArraySubscriptExpr(ArraySubscriptExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCallExpr(CallExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformCallExpr(CallExpr *E) { // Transform the callee. OwningExprResult Callee = getDerived().TransformExpr(E->getCallee()); if (Callee.isInvalid()) @@ -3645,8 +3665,7 @@ TreeTransform<Derived>::TransformCallExpr(CallExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) { OwningExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) return SemaRef.ExprError(); @@ -3660,8 +3679,8 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E, return SemaRef.ExprError(); } - NamedDecl *Member - = cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getMemberDecl())); + ValueDecl *Member + = cast_or_null<ValueDecl>(getDerived().TransformDecl(E->getMemberDecl())); if (!Member) return SemaRef.ExprError(); @@ -3701,16 +3720,14 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCastExpr(CastExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformCastExpr(CastExpr *E) { assert(false && "Cannot transform abstract class"); return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) { OwningExprResult LHS = getDerived().TransformExpr(E->getLHS()); if (LHS.isInvalid()) return SemaRef.ExprError(); @@ -3731,15 +3748,13 @@ TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E, template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCompoundAssignOperator( - CompoundAssignOperator *E, - bool isAddressOfOperand) { - return getDerived().TransformBinaryOperator(E, isAddressOfOperand); + CompoundAssignOperator *E) { + return getDerived().TransformBinaryOperator(E); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformConditionalOperator(ConditionalOperator *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformConditionalOperator(ConditionalOperator *E) { OwningExprResult Cond = getDerived().TransformExpr(E->getCond()); if (Cond.isInvalid()) return SemaRef.ExprError(); @@ -3767,42 +3782,22 @@ TreeTransform<Derived>::TransformConditionalOperator(ConditionalOperator *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformImplicitCastExpr(ImplicitCastExpr *E, - bool isAddressOfOperand) { - TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName()); - - // FIXME: Will we ever have type information here? It seems like we won't, - // so do we even need to transform the type? - QualType T = getDerived().TransformType(E->getType()); - if (T.isNull()) - return SemaRef.ExprError(); - - OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); - if (SubExpr.isInvalid()) - return SemaRef.ExprError(); - - if (!getDerived().AlwaysRebuild() && - T == E->getType() && - SubExpr.get() == E->getSubExpr()) - return SemaRef.Owned(E->Retain()); - - return getDerived().RebuildImplicitCastExpr(T, E->getCastKind(), - move(SubExpr), - E->isLvalueCast()); +TreeTransform<Derived>::TransformImplicitCastExpr(ImplicitCastExpr *E) { + // Implicit casts are eliminated during transformation, since they + // will be recomputed by semantic analysis after transformation. + return getDerived().TransformExpr(E->getSubExprAsWritten()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformExplicitCastExpr(ExplicitCastExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformExplicitCastExpr(ExplicitCastExpr *E) { assert(false && "Cannot transform abstract class"); return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) { QualType T; { // FIXME: Source location isn't quite accurate. @@ -3815,7 +3810,8 @@ TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E, return SemaRef.ExprError(); } - OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); + OwningExprResult SubExpr + = getDerived().TransformExpr(E->getSubExprAsWritten()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -3831,8 +3827,7 @@ TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCompoundLiteralExpr(CompoundLiteralExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformCompoundLiteralExpr(CompoundLiteralExpr *E) { QualType T; { // FIXME: Source location isn't quite accurate. @@ -3861,8 +3856,7 @@ TreeTransform<Derived>::TransformCompoundLiteralExpr(CompoundLiteralExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformExtVectorElementExpr(ExtVectorElementExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformExtVectorElementExpr(ExtVectorElementExpr *E) { OwningExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) return SemaRef.ExprError(); @@ -3881,8 +3875,7 @@ TreeTransform<Derived>::TransformExtVectorElementExpr(ExtVectorElementExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E) { bool InitChanged = false; ASTOwningVector<&ActionBase::DeleteExpr, 4> Inits(SemaRef); @@ -3904,8 +3897,7 @@ TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) { Designation Desig; // transform the initializer value @@ -3974,8 +3966,7 @@ TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E, template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformImplicitValueInitExpr( - ImplicitValueInitExpr *E, - bool isAddressOfOperand) { + ImplicitValueInitExpr *E) { TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName()); // FIXME: Will we ever have proper type location here? Will we actually @@ -3993,8 +3984,7 @@ TreeTransform<Derived>::TransformImplicitValueInitExpr( template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformVAArgExpr(VAArgExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformVAArgExpr(VAArgExpr *E) { // FIXME: Do we want the type as written? QualType T; @@ -4021,8 +4011,7 @@ TreeTransform<Derived>::TransformVAArgExpr(VAArgExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformParenListExpr(ParenListExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformParenListExpr(ParenListExpr *E) { bool ArgumentChanged = false; ASTOwningVector<&ActionBase::DeleteExpr, 4> Inits(SemaRef); for (unsigned I = 0, N = E->getNumExprs(); I != N; ++I) { @@ -4046,16 +4035,14 @@ TreeTransform<Derived>::TransformParenListExpr(ParenListExpr *E, /// the corresponding label statement by semantic analysis. template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformAddrLabelExpr(AddrLabelExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformAddrLabelExpr(AddrLabelExpr *E) { return getDerived().RebuildAddrLabelExpr(E->getAmpAmpLoc(), E->getLabelLoc(), E->getLabel()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformStmtExpr(StmtExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformStmtExpr(StmtExpr *E) { OwningStmtResult SubStmt = getDerived().TransformCompoundStmt(E->getSubStmt(), true); if (SubStmt.isInvalid()) @@ -4072,8 +4059,7 @@ TreeTransform<Derived>::TransformStmtExpr(StmtExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformTypesCompatibleExpr(TypesCompatibleExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformTypesCompatibleExpr(TypesCompatibleExpr *E) { QualType T1, T2; { // FIXME: Source location isn't quite accurate. @@ -4099,8 +4085,7 @@ TreeTransform<Derived>::TransformTypesCompatibleExpr(TypesCompatibleExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformChooseExpr(ChooseExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformChooseExpr(ChooseExpr *E) { OwningExprResult Cond = getDerived().TransformExpr(E->getCond()); if (Cond.isInvalid()) return SemaRef.ExprError(); @@ -4126,22 +4111,83 @@ TreeTransform<Derived>::TransformChooseExpr(ChooseExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformGNUNullExpr(GNUNullExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformGNUNullExpr(GNUNullExpr *E) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + switch (E->getOperator()) { + case OO_New: + case OO_Delete: + case OO_Array_New: + case OO_Array_Delete: + llvm_unreachable("new and delete operators cannot use CXXOperatorCallExpr"); + return SemaRef.ExprError(); + + case OO_Call: { + // This is a call to an object's operator(). + assert(E->getNumArgs() >= 1 && "Object call is missing arguments"); + + // Transform the object itself. + OwningExprResult Object = getDerived().TransformExpr(E->getArg(0)); + if (Object.isInvalid()) + return SemaRef.ExprError(); + + // FIXME: Poor location information + SourceLocation FakeLParenLoc + = SemaRef.PP.getLocForEndOfToken( + static_cast<Expr *>(Object.get())->getLocEnd()); + + // Transform the call arguments. + ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef); + llvm::SmallVector<SourceLocation, 4> FakeCommaLocs; + for (unsigned I = 1, N = E->getNumArgs(); I != N; ++I) { + if (getDerived().DropCallArgument(E->getArg(I))) + break; + + OwningExprResult Arg = getDerived().TransformExpr(E->getArg(I)); + if (Arg.isInvalid()) + return SemaRef.ExprError(); + + // FIXME: Poor source location information. + SourceLocation FakeCommaLoc + = SemaRef.PP.getLocForEndOfToken( + static_cast<Expr *>(Arg.get())->getLocEnd()); + FakeCommaLocs.push_back(FakeCommaLoc); + Args.push_back(Arg.release()); + } + + return getDerived().RebuildCallExpr(move(Object), FakeLParenLoc, + move_arg(Args), + FakeCommaLocs.data(), + E->getLocEnd()); + } + +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + case OO_##Name: +#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly) +#include "clang/Basic/OperatorKinds.def" + case OO_Subscript: + // Handled below. + break; + + case OO_Conditional: + llvm_unreachable("conditional operator is not actually overloadable"); + return SemaRef.ExprError(); + + case OO_None: + case NUM_OVERLOADED_OPERATORS: + llvm_unreachable("not an overloaded operator?"); + return SemaRef.ExprError(); + } + OwningExprResult Callee = getDerived().TransformExpr(E->getCallee()); if (Callee.isInvalid()) return SemaRef.ExprError(); - OwningExprResult First - = getDerived().TransformExpr(E->getArg(0), - E->getNumArgs() == 1 && E->getOperator() == OO_Amp); + OwningExprResult First = getDerived().TransformExpr(E->getArg(0)); if (First.isInvalid()) return SemaRef.ExprError(); @@ -4167,15 +4213,13 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXMemberCallExpr(CXXMemberCallExpr *E, - bool isAddressOfOperand) { - return getDerived().TransformCallExpr(E, isAddressOfOperand); +TreeTransform<Derived>::TransformCXXMemberCallExpr(CXXMemberCallExpr *E) { + return getDerived().TransformCallExpr(E); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { QualType ExplicitTy; { // FIXME: Source location isn't quite accurate. @@ -4188,7 +4232,8 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E, return SemaRef.ExprError(); } - OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); + OwningExprResult SubExpr + = getDerived().TransformExpr(E->getSubExprAsWritten()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -4216,38 +4261,33 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXStaticCastExpr(CXXStaticCastExpr *E, - bool isAddressOfOperand) { - return getDerived().TransformCXXNamedCastExpr(E, isAddressOfOperand); +TreeTransform<Derived>::TransformCXXStaticCastExpr(CXXStaticCastExpr *E) { + return getDerived().TransformCXXNamedCastExpr(E); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXDynamicCastExpr(CXXDynamicCastExpr *E, - bool isAddressOfOperand) { - return getDerived().TransformCXXNamedCastExpr(E, isAddressOfOperand); +TreeTransform<Derived>::TransformCXXDynamicCastExpr(CXXDynamicCastExpr *E) { + return getDerived().TransformCXXNamedCastExpr(E); } template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXReinterpretCastExpr( - CXXReinterpretCastExpr *E, - bool isAddressOfOperand) { - return getDerived().TransformCXXNamedCastExpr(E, isAddressOfOperand); + CXXReinterpretCastExpr *E) { + return getDerived().TransformCXXNamedCastExpr(E); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXConstCastExpr(CXXConstCastExpr *E, - bool isAddressOfOperand) { - return getDerived().TransformCXXNamedCastExpr(E, isAddressOfOperand); +TreeTransform<Derived>::TransformCXXConstCastExpr(CXXConstCastExpr *E) { + return getDerived().TransformCXXNamedCastExpr(E); } template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXFunctionalCastExpr( - CXXFunctionalCastExpr *E, - bool isAddressOfOperand) { + CXXFunctionalCastExpr *E) { QualType ExplicitTy; { TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); @@ -4257,7 +4297,8 @@ TreeTransform<Derived>::TransformCXXFunctionalCastExpr( return SemaRef.ExprError(); } - OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); + OwningExprResult SubExpr + = getDerived().TransformExpr(E->getSubExprAsWritten()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -4277,8 +4318,7 @@ TreeTransform<Derived>::TransformCXXFunctionalCastExpr( template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) { if (E->isTypeOperand()) { TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName()); @@ -4318,23 +4358,20 @@ TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXBoolLiteralExpr(CXXBoolLiteralExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXNullPtrLiteralExpr( - CXXNullPtrLiteralExpr *E, - bool isAddressOfOperand) { + CXXNullPtrLiteralExpr *E) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) { TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName()); QualType T = getDerived().TransformType(E->getType()); @@ -4350,8 +4387,7 @@ TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXThrowExpr(CXXThrowExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformCXXThrowExpr(CXXThrowExpr *E) { OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -4365,8 +4401,7 @@ TreeTransform<Derived>::TransformCXXThrowExpr(CXXThrowExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) { ParmVarDecl *Param = cast_or_null<ParmVarDecl>(getDerived().TransformDecl(E->getParam())); if (!Param) @@ -4381,8 +4416,7 @@ TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXZeroInitValueExpr(CXXZeroInitValueExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) { TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); QualType T = getDerived().TransformType(E->getType()); @@ -4401,8 +4435,7 @@ TreeTransform<Derived>::TransformCXXZeroInitValueExpr(CXXZeroInitValueExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { // Transform the type that we're allocating TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName()); QualType AllocType = getDerived().TransformType(E->getAllocatedType()); @@ -4460,8 +4493,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E) { OwningExprResult Operand = getDerived().TransformExpr(E->getArgument()); if (Operand.isInvalid()) return SemaRef.ExprError(); @@ -4479,8 +4511,7 @@ TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E, template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXPseudoDestructorExpr( - CXXPseudoDestructorExpr *E, - bool isAddressOfOperand) { + CXXPseudoDestructorExpr *E) { OwningExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) return SemaRef.ExprError(); @@ -4517,8 +4548,7 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr( template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformUnresolvedLookupExpr( - UnresolvedLookupExpr *Old, - bool isAddressOfOperand) { + UnresolvedLookupExpr *Old) { TemporaryBase Rebase(*this, Old->getNameLoc(), DeclarationName()); LookupResult R(SemaRef, Old->getName(), Old->getNameLoc(), @@ -4528,8 +4558,14 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr( for (UnresolvedLookupExpr::decls_iterator I = Old->decls_begin(), E = Old->decls_end(); I != E; ++I) { NamedDecl *InstD = static_cast<NamedDecl*>(getDerived().TransformDecl(*I)); - if (!InstD) - return SemaRef.ExprError(); + if (!InstD) { + // Silently ignore these if a UsingShadowDecl instantiated to nothing. + // This can happen because of dependent hiding. + if (isa<UsingShadowDecl>(*I)) + continue; + else + return SemaRef.ExprError(); + } // Expand using declarations. if (isa<UsingDecl>(InstD)) { @@ -4580,8 +4616,7 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr( template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName()); QualType T = getDerived().TransformType(E->getQueriedType()); @@ -4606,8 +4641,7 @@ TreeTransform<Derived>::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E, template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformDependentScopeDeclRefExpr( - DependentScopeDeclRefExpr *E, - bool isAddressOfOperand) { + DependentScopeDeclRefExpr *E) { NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(E->getQualifier(), E->getQualifierRange()); @@ -4647,8 +4681,7 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr( template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) { TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName()); QualType T = getDerived().TransformType(E->getType()); @@ -4666,6 +4699,11 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E, for (CXXConstructExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end(); Arg != ArgEnd; ++Arg) { + if (getDerived().DropCallArgument(*Arg)) { + ArgumentChanged = true; + break; + } + OwningExprResult TransArg = getDerived().TransformExpr(*Arg); if (TransArg.isInvalid()) return SemaRef.ExprError(); @@ -4680,7 +4718,8 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E, !ArgumentChanged) return SemaRef.Owned(E->Retain()); - return getDerived().RebuildCXXConstructExpr(T, Constructor, E->isElidable(), + return getDerived().RebuildCXXConstructExpr(T, /*FIXME:*/E->getLocStart(), + Constructor, E->isElidable(), move_arg(Args)); } @@ -4692,8 +4731,7 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E, /// must be unique. template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -4711,8 +4749,7 @@ TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E, template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXExprWithTemporaries( - CXXExprWithTemporaries *E, - bool isAddressOfOperand) { + CXXExprWithTemporaries *E) { OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -4725,8 +4762,7 @@ TreeTransform<Derived>::TransformCXXExprWithTemporaries( template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXTemporaryObjectExpr( - CXXTemporaryObjectExpr *E, - bool isAddressOfOperand) { + CXXTemporaryObjectExpr *E) { TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); QualType T = getDerived().TransformType(E->getType()); if (T.isNull()) @@ -4776,8 +4812,7 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr( template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr( - CXXUnresolvedConstructExpr *E, - bool isAddressOfOperand) { + CXXUnresolvedConstructExpr *E) { TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); QualType T = getDerived().TransformType(E->getTypeAsWritten()); if (T.isNull()) @@ -4816,21 +4851,34 @@ TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr( template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr( - CXXDependentScopeMemberExpr *E, - bool isAddressOfOperand) { + CXXDependentScopeMemberExpr *E) { // Transform the base of the expression. - OwningExprResult Base = getDerived().TransformExpr(E->getBase()); - if (Base.isInvalid()) - return SemaRef.ExprError(); + OwningExprResult Base(SemaRef, (Expr*) 0); + Expr *OldBase; + QualType BaseType; + QualType ObjectType; + if (!E->isImplicitAccess()) { + OldBase = E->getBase(); + Base = getDerived().TransformExpr(OldBase); + if (Base.isInvalid()) + return SemaRef.ExprError(); - // Start the member reference and compute the object's type. - Sema::TypeTy *ObjectType = 0; - Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), - E->getOperatorLoc(), + // Start the member reference and compute the object's type. + Sema::TypeTy *ObjectTy = 0; + Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), + E->getOperatorLoc(), E->isArrow()? tok::arrow : tok::period, - ObjectType); - if (Base.isInvalid()) - return SemaRef.ExprError(); + ObjectTy); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + ObjectType = QualType::getFromOpaquePtr(ObjectTy); + BaseType = ((Expr*) Base.get())->getType(); + } else { + OldBase = 0; + BaseType = getDerived().TransformType(E->getBaseType()); + ObjectType = BaseType->getAs<PointerType>()->getPointeeType(); + } // Transform the first part of the nested-name-specifier that qualifies // the member name. @@ -4843,29 +4891,31 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr( if (E->getQualifier()) { Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), E->getQualifierRange(), - QualType::getFromOpaquePtr(ObjectType), - FirstQualifierInScope); + ObjectType, + FirstQualifierInScope); if (!Qualifier) return SemaRef.ExprError(); } DeclarationName Name = getDerived().TransformDeclarationName(E->getMember(), E->getMemberLoc(), - QualType::getFromOpaquePtr(ObjectType)); + ObjectType); if (!Name) return SemaRef.ExprError(); - if (!E->hasExplicitTemplateArgumentList()) { + if (!E->hasExplicitTemplateArgs()) { // This is a reference to a member without an explicitly-specified // template argument list. Optimize for this common case. if (!getDerived().AlwaysRebuild() && - Base.get() == E->getBase() && + Base.get() == OldBase && + BaseType == E->getBaseType() && Qualifier == E->getQualifier() && Name == E->getMember() && FirstQualifierInScope == E->getFirstQualifierFoundInScope()) return SemaRef.Owned(E->Retain()); return getDerived().RebuildCXXDependentScopeMemberExpr(move(Base), + BaseType, E->isArrow(), E->getOperatorLoc(), Qualifier, @@ -4885,6 +4935,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr( } return getDerived().RebuildCXXDependentScopeMemberExpr(move(Base), + BaseType, E->isArrow(), E->getOperatorLoc(), Qualifier, @@ -4897,12 +4948,18 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr( template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) { // Transform the base of the expression. - OwningExprResult Base = getDerived().TransformExpr(Old->getBase()); - if (Base.isInvalid()) - return SemaRef.ExprError(); + OwningExprResult Base(SemaRef, (Expr*) 0); + QualType BaseType; + if (!Old->isImplicitAccess()) { + Base = getDerived().TransformExpr(Old->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + BaseType = ((Expr*) Base.get())->getType(); + } else { + BaseType = getDerived().TransformType(Old->getBaseType()); + } NestedNameSpecifier *Qualifier = 0; if (Old->getQualifier()) { @@ -4920,8 +4977,14 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old, for (UnresolvedMemberExpr::decls_iterator I = Old->decls_begin(), E = Old->decls_end(); I != E; ++I) { NamedDecl *InstD = static_cast<NamedDecl*>(getDerived().TransformDecl(*I)); - if (!InstD) - return SemaRef.ExprError(); + if (!InstD) { + // Silently ignore these if a UsingShadowDecl instantiated to nothing. + // This can happen because of dependent hiding. + if (isa<UsingShadowDecl>(*I)) + continue; + else + return SemaRef.ExprError(); + } // Expand using declarations. if (isa<UsingDecl>(InstD)) { @@ -4951,6 +5014,7 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old, } return getDerived().RebuildUnresolvedMemberExpr(move(Base), + BaseType, Old->getOperatorLoc(), Old->isArrow(), Qualifier, @@ -4962,15 +5026,13 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E) { // FIXME: poor source location TemporaryBase Rebase(*this, E->getAtLoc(), DeclarationName()); QualType EncodedType = getDerived().TransformType(E->getEncodedType()); @@ -4988,8 +5050,7 @@ TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -4997,15 +5058,13 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCSelectorExpr(ObjCSelectorExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformObjCSelectorExpr(ObjCSelectorExpr *E) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E) { ObjCProtocolDecl *Protocol = cast_or_null<ObjCProtocolDecl>( getDerived().TransformDecl(E->getProtocol())); @@ -5026,8 +5085,7 @@ TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -5035,8 +5093,7 @@ TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -5045,8 +5102,7 @@ TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E, template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformObjCImplicitSetterGetterRefExpr( - ObjCImplicitSetterGetterRefExpr *E, - bool isAddressOfOperand) { + ObjCImplicitSetterGetterRefExpr *E) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -5054,8 +5110,7 @@ TreeTransform<Derived>::TransformObjCImplicitSetterGetterRefExpr( template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCSuperExpr(ObjCSuperExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformObjCSuperExpr(ObjCSuperExpr *E) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -5063,8 +5118,7 @@ TreeTransform<Derived>::TransformObjCSuperExpr(ObjCSuperExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -5072,8 +5126,7 @@ TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) { bool ArgumentChanged = false; ASTOwningVector<&ActionBase::DeleteExpr> SubExprs(SemaRef); for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I) { @@ -5096,8 +5149,7 @@ TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) { // FIXME: Implement this! assert(false && "Cannot transform block expressions yet"); return SemaRef.Owned(E->Retain()); @@ -5105,8 +5157,7 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E, template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E, - bool isAddressOfOperand) { +TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) { // FIXME: Implement this! assert(false && "Cannot transform block-related expressions yet"); return SemaRef.Owned(E->Retain()); @@ -5282,6 +5333,30 @@ QualType TreeTransform<Derived>::RebuildFunctionNoProtoType(QualType T) { } template<typename Derived> +QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(Decl *D) { + assert(D && "no decl found"); + if (D->isInvalidDecl()) return QualType(); + + TypeDecl *Ty; + if (isa<UsingDecl>(D)) { + UsingDecl *Using = cast<UsingDecl>(D); + assert(Using->isTypeName() && + "UnresolvedUsingTypenameDecl transformed to non-typename using"); + + // A valid resolved using typename decl points to exactly one type decl. + assert(++Using->shadow_begin() == Using->shadow_end()); + Ty = cast<TypeDecl>((*Using->shadow_begin())->getTargetDecl()); + + } else { + assert(isa<UnresolvedUsingTypenameDecl>(D) && + "UnresolvedUsingTypenameDecl transformed to non-using decl"); + Ty = cast<UnresolvedUsingTypenameDecl>(D); + } + + return SemaRef.Context.getTypeDeclType(Ty); +} + +template<typename Derived> QualType TreeTransform<Derived>::RebuildTypeOfExprType(ExprArg E) { return SemaRef.BuildTypeofExprType(E.takeAs<Expr>()); } @@ -5320,7 +5395,7 @@ TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, Range.getEnd(), II, ObjectType, FirstQualifierInScope, - false)); + false, false)); } template<typename Derived> |