diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2010-01-15 15:39:40 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2010-01-15 15:39:40 +0000 |
commit | a3fa5c7f1b5e2ba4d6ec033dc0e2376326b05824 (patch) | |
tree | a6082d4d1d1e9ddaea09a6a04bb4a47da95d642d /lib | |
parent | bb1e3bc1e0be2b8f891db46457a8943451bf4d8b (diff) | |
download | FreeBSD-src-a3fa5c7f1b5e2ba4d6ec033dc0e2376326b05824.zip FreeBSD-src-a3fa5c7f1b5e2ba4d6ec033dc0e2376326b05824.tar.gz |
Update clang to r93512.
Diffstat (limited to 'lib')
134 files changed, 9544 insertions, 4175 deletions
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index 772a884..50a6e0a 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -12,9 +12,20 @@ //===----------------------------------------------------------------------===// #include "clang/AST/APValue.h" +#include "clang/AST/CharUnits.h" #include "llvm/Support/raw_ostream.h" using namespace clang; +namespace { + struct LV { + Expr* Base; + CharUnits Offset; + }; +} + +APValue::APValue(Expr* B) : Kind(Uninitialized) { + MakeLValue(); setLValue(B, CharUnits::Zero()); +} const APValue &APValue::operator=(const APValue &RHS) { if (Kind != RHS.Kind) { @@ -106,3 +117,25 @@ void APValue::print(llvm::raw_ostream &OS) const { } } +Expr* APValue::getLValueBase() const { + assert(isLValue() && "Invalid accessor"); + return ((const LV*)(const void*)Data)->Base; +} + +CharUnits APValue::getLValueOffset() const { + assert(isLValue() && "Invalid accessor"); + return ((const LV*)(const void*)Data)->Offset; +} + +void APValue::setLValue(Expr *B, const CharUnits &O) { + assert(isLValue() && "Invalid accessor"); + ((LV*)(char*)Data)->Base = B; + ((LV*)(char*)Data)->Offset = O; +} + +void APValue::MakeLValue() { + assert(isUninit() && "Bad state change"); + new ((void*)(char*)Data) LV(); + Kind = LValue; +} + diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 74e74e7..76ec852 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -814,10 +814,10 @@ ASTContext::getTypeInfo(const Type *T) { /// getTypeSizeInChars - Return the size of the specified type, in characters. /// This method does not work on incomplete types. CharUnits ASTContext::getTypeSizeInChars(QualType T) { - return CharUnits::fromRaw(getTypeSize(T) / getCharWidth()); + return CharUnits::fromQuantity(getTypeSize(T) / getCharWidth()); } CharUnits ASTContext::getTypeSizeInChars(const Type *T) { - return CharUnits::fromRaw(getTypeSize(T) / getCharWidth()); + return CharUnits::fromQuantity(getTypeSize(T) / getCharWidth()); } /// getPreferredTypeAlign - Return the "preferred" alignment of the specified @@ -2374,16 +2374,14 @@ CanQualType ASTContext::getCanonicalType(QualType T) { QualType ASTContext::getUnqualifiedArrayType(QualType T, Qualifiers &Quals) { - assert(T.isCanonical() && "Only operates on canonical types"); + Quals = T.getQualifiers(); if (!isa<ArrayType>(T)) { - Quals = T.getLocalQualifiers(); - return T.getLocalUnqualifiedType(); + return T.getUnqualifiedType(); } - assert(!T.hasQualifiers() && "canonical array type has qualifiers!"); const ArrayType *AT = cast<ArrayType>(T); QualType Elt = AT->getElementType(); - QualType UnqualElt = getUnqualifiedArrayType(getCanonicalType(Elt), Quals); + QualType UnqualElt = getUnqualifiedArrayType(Elt, Quals); if (Elt == UnqualElt) return T; @@ -2396,12 +2394,6 @@ QualType ASTContext::getUnqualifiedArrayType(QualType T, return getIncompleteArrayType(UnqualElt, IAT->getSizeModifier(), 0); } - if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(T)) { - return getVariableArrayType(UnqualElt, VAT->getSizeExpr()->Retain(), - VAT->getSizeModifier(), 0, - SourceRange()); - } - const DependentSizedArrayType *DSAT = cast<DependentSizedArrayType>(T); return getDependentSizedArrayType(UnqualElt, DSAT->getSizeExpr()->Retain(), DSAT->getSizeModifier(), 0, @@ -3143,16 +3135,21 @@ static bool isTypeTypedefedAsBOOL(QualType T) { /// getObjCEncodingTypeSize returns size of type for objective-c encoding /// purpose. -int ASTContext::getObjCEncodingTypeSize(QualType type) { - uint64_t sz = getTypeSize(type); +CharUnits ASTContext::getObjCEncodingTypeSize(QualType type) { + CharUnits sz = getTypeSizeInChars(type); // Make all integer and enum types at least as large as an int - if (sz > 0 && type->isIntegralType()) - sz = std::max(sz, getTypeSize(IntTy)); + if (sz.isPositive() && type->isIntegralType()) + sz = std::max(sz, getTypeSizeInChars(IntTy)); // Treat arrays as pointers, since that's how they're passed in. else if (type->isArrayType()) - sz = getTypeSize(VoidPtrTy); - return sz / getTypeSize(CharTy); + sz = getTypeSizeInChars(VoidPtrTy); + return sz; +} + +static inline +std::string charUnitsToString(const CharUnits &CU) { + return llvm::itostr(CU.getQuantity()); } /// getObjCEncodingForBlockDecl - Return the encoded type for this method @@ -3168,17 +3165,17 @@ void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr, // Start with computing size of a pointer in number of bytes. // FIXME: There might(should) be a better way of doing this computation! SourceLocation Loc; - int PtrSize = getTypeSize(VoidPtrTy) / getTypeSize(CharTy); - int ParmOffset = PtrSize; + CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy); + CharUnits ParmOffset = PtrSize; for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(), E = Decl->param_end(); PI != E; ++PI) { QualType PType = (*PI)->getType(); - int sz = getObjCEncodingTypeSize(PType); - assert (sz > 0 && "BlockExpr - Incomplete param type"); + CharUnits sz = getObjCEncodingTypeSize(PType); + assert (sz.isPositive() && "BlockExpr - Incomplete param type"); ParmOffset += sz; } // Size of the argument frame - S += llvm::utostr(ParmOffset); + S += charUnitsToString(ParmOffset); // Block pointer and offset. S += "@?0"; ParmOffset = PtrSize; @@ -3198,7 +3195,7 @@ void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr, } else if (PType->isFunctionType()) PType = PVDecl->getType(); getObjCEncodingForType(PType, S); - S += llvm::utostr(ParmOffset); + S += charUnitsToString(ParmOffset); ParmOffset += getObjCEncodingTypeSize(PType); } } @@ -3216,20 +3213,21 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, // Start with computing size of a pointer in number of bytes. // FIXME: There might(should) be a better way of doing this computation! SourceLocation Loc; - int PtrSize = getTypeSize(VoidPtrTy) / getTypeSize(CharTy); + CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy); // The first two arguments (self and _cmd) are pointers; account for // their size. - int ParmOffset = 2 * PtrSize; + CharUnits ParmOffset = 2 * PtrSize; for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(), E = Decl->param_end(); PI != E; ++PI) { QualType PType = (*PI)->getType(); - int sz = getObjCEncodingTypeSize(PType); - assert (sz > 0 && "getObjCEncodingForMethodDecl - Incomplete param type"); + CharUnits sz = getObjCEncodingTypeSize(PType); + assert (sz.isPositive() && + "getObjCEncodingForMethodDecl - Incomplete param type"); ParmOffset += sz; } - S += llvm::utostr(ParmOffset); + S += charUnitsToString(ParmOffset); S += "@0:"; - S += llvm::utostr(PtrSize); + S += charUnitsToString(PtrSize); // Argument types. ParmOffset = 2 * PtrSize; @@ -3249,7 +3247,7 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, // 'in', 'inout', etc. getObjCEncodingForTypeQualifier(PVDecl->getObjCDeclQualifier(), S); getObjCEncodingForType(PType, S); - S += llvm::utostr(ParmOffset); + S += charUnitsToString(ParmOffset); ParmOffset += getObjCEncodingTypeSize(PType); } } diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp new file mode 100644 index 0000000..02c70b6 --- /dev/null +++ b/lib/AST/AttrImpl.cpp @@ -0,0 +1,143 @@ +//===--- AttrImpl.cpp - Classes for representing attributes -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains out-of-line virtual methods for Attr classes. +// +//===----------------------------------------------------------------------===// + + +#include "clang/AST/Attr.h" +#include "clang/AST/ASTContext.h" +using namespace clang; + +#define DEF_SIMPLE_ATTR_CLONE(ATTR) \ + Attr *ATTR##Attr::clone(ASTContext &C) const { \ + return ::new (C) ATTR##Attr; \ + } + +// FIXME: Can we use variadic macro to define DEF_SIMPLE_ATTR_CLONE for +// "non-simple" classes? + +DEF_SIMPLE_ATTR_CLONE(Packed) +DEF_SIMPLE_ATTR_CLONE(AlwaysInline) +DEF_SIMPLE_ATTR_CLONE(Malloc) +DEF_SIMPLE_ATTR_CLONE(NoReturn) +DEF_SIMPLE_ATTR_CLONE(AnalyzerNoReturn) +DEF_SIMPLE_ATTR_CLONE(Deprecated) +DEF_SIMPLE_ATTR_CLONE(Final) +DEF_SIMPLE_ATTR_CLONE(Unavailable) +DEF_SIMPLE_ATTR_CLONE(Unused) +DEF_SIMPLE_ATTR_CLONE(Used) +DEF_SIMPLE_ATTR_CLONE(Weak) +DEF_SIMPLE_ATTR_CLONE(WeakImport) +DEF_SIMPLE_ATTR_CLONE(NoThrow) +DEF_SIMPLE_ATTR_CLONE(Const) +DEF_SIMPLE_ATTR_CLONE(Pure) +DEF_SIMPLE_ATTR_CLONE(FastCall) +DEF_SIMPLE_ATTR_CLONE(StdCall) +DEF_SIMPLE_ATTR_CLONE(CDecl) +DEF_SIMPLE_ATTR_CLONE(TransparentUnion) +DEF_SIMPLE_ATTR_CLONE(ObjCNSObject) +DEF_SIMPLE_ATTR_CLONE(ObjCException) +DEF_SIMPLE_ATTR_CLONE(NoDebug) +DEF_SIMPLE_ATTR_CLONE(WarnUnusedResult) +DEF_SIMPLE_ATTR_CLONE(NoInline) +DEF_SIMPLE_ATTR_CLONE(CFReturnsRetained) +DEF_SIMPLE_ATTR_CLONE(NSReturnsRetained) +DEF_SIMPLE_ATTR_CLONE(BaseCheck) +DEF_SIMPLE_ATTR_CLONE(Hiding) +DEF_SIMPLE_ATTR_CLONE(Override) +DEF_SIMPLE_ATTR_CLONE(DLLImport) +DEF_SIMPLE_ATTR_CLONE(DLLExport) + +Attr* PragmaPackAttr::clone(ASTContext &C) const { + return ::new (C) PragmaPackAttr(Alignment); +} + +Attr* AlignedAttr::clone(ASTContext &C) const { + return ::new (C) AlignedAttr(Alignment); +} + +Attr* AnnotateAttr::clone(ASTContext &C) const { + return ::new (C) AnnotateAttr(Annotation); +} + +Attr *AsmLabelAttr::clone(ASTContext &C) const { + return ::new (C) AsmLabelAttr(Label); +} + +Attr *AliasAttr::clone(ASTContext &C) const { + return ::new (C) AliasAttr(Aliasee); +} + +Attr *ConstructorAttr::clone(ASTContext &C) const { + return ::new (C) ConstructorAttr(priority); +} + +Attr *DestructorAttr::clone(ASTContext &C) const { + return ::new (C) DestructorAttr(priority); +} + +Attr *IBOutletAttr::clone(ASTContext &C) const { + return ::new (C) IBOutletAttr; +} + +Attr *GNUInlineAttr::clone(ASTContext &C) const { + return ::new (C) GNUInlineAttr; +} + +Attr *SectionAttr::clone(ASTContext &C) const { + return ::new (C) SectionAttr(Name); +} + +Attr *NonNullAttr::clone(ASTContext &C) const { + return ::new (C) NonNullAttr(ArgNums, Size); +} + +Attr *FormatAttr::clone(ASTContext &C) const { + return ::new (C) FormatAttr(Type, formatIdx, firstArg); +} + +Attr *FormatArgAttr::clone(ASTContext &C) const { + return ::new (C) FormatArgAttr(formatIdx); +} + +Attr *SentinelAttr::clone(ASTContext &C) const { + return ::new (C) SentinelAttr(sentinel, NullPos); +} + +Attr *VisibilityAttr::clone(ASTContext &C) const { + return ::new (C) VisibilityAttr(VisibilityType); +} + +Attr *OverloadableAttr::clone(ASTContext &C) const { + return ::new (C) OverloadableAttr; +} + +Attr *BlocksAttr::clone(ASTContext &C) const { + return ::new (C) BlocksAttr(BlocksAttrType); +} + +Attr *CleanupAttr::clone(ASTContext &C) const { + return ::new (C) CleanupAttr(FD); +} + +Attr *RegparmAttr::clone(ASTContext &C) const { + return ::new (C) RegparmAttr(NumParams); +} + +Attr *ReqdWorkGroupSizeAttr::clone(ASTContext &C) const { + return ::new (C) ReqdWorkGroupSizeAttr(X, Y, Z); +} + +Attr *MSP430InterruptAttr::clone(ASTContext &C) const { + return ::new (C) MSP430InterruptAttr(Number); +} + + diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 5aecf87..dea96e7 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -4,6 +4,7 @@ add_clang_library(clangAST APValue.cpp ASTConsumer.cpp ASTContext.cpp + AttrImpl.cpp CXXInheritance.cpp Decl.cpp DeclBase.cpp diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index e112fa3..e77661a 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -957,7 +957,7 @@ bool FunctionDecl::isInlined() const { /// "externally" visible to other translation units in the program. /// /// In C99, inline definitions are not externally visible by default. However, -/// if even one of the globa-scope declarations is marked "extern inline", the +/// if even one of the global-scope declarations is marked "extern inline", the /// inline definition becomes externally visible (C99 6.7.4p6). /// /// In GNU89 mode, or if the gnu_inline attribute is attached to the function @@ -1039,6 +1039,15 @@ OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const { return OO_None; } +/// getLiteralIdentifier - The literal suffix identifier this function +/// represents, if any. +const IdentifierInfo *FunctionDecl::getLiteralIdentifier() const { + if (getDeclName().getNameKind() == DeclarationName::CXXLiteralOperatorName) + return getDeclName().getCXXLiteralIdentifier(); + else + return 0; +} + FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const { if (MemberSpecializationInfo *Info = getMemberSpecializationInfo()) return cast<FunctionDecl>(Info->getInstantiatedFrom()); diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index bbbb19a..1cce35c 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -144,6 +144,19 @@ CXXRecordDecl::setBases(ASTContext &C, } } +/// Callback function for CXXRecordDecl::forallBases that acknowledges +/// that it saw a base class. +static bool SawBase(const CXXRecordDecl *, void *) { + return true; +} + +bool CXXRecordDecl::hasAnyDependentBases() const { + if (!isDependentContext()) + return false; + + return !forallBases(SawBase, 0); +} + bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const { return getCopyConstructor(Context, Qualifiers::Const) != 0; } @@ -643,23 +656,15 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const { return C.getPointerType(ClassTy); } -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 { + // If this function is a template instantiation, look at the template from + // which it was instantiated. + const FunctionDecl *CheckFn = getTemplateInstantiationPattern(); + if (!CheckFn) + CheckFn = this; + const FunctionDecl *fn; - return MethodHasBody(this, fn) && !fn->isOutOfLine(); + return CheckFn->getBody(fn) && !fn->isOutOfLine(); } CXXBaseOrMemberInitializer:: diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 60c40e2..ff81073 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -56,9 +56,14 @@ public: /// This identifier is stored here rather than directly in DeclarationName so as /// to allow Objective-C selectors, which are about a million times more common, /// to consume minimal memory. -class CXXLiteralOperatorIdName : public DeclarationNameExtra { +class CXXLiteralOperatorIdName + : public DeclarationNameExtra, public llvm::FoldingSetNode { public: IdentifierInfo *ID; + + void Profile(llvm::FoldingSetNodeID &FSID) { + FSID.AddPointer(ID); + } }; bool operator<(DeclarationName LHS, DeclarationName RHS) { @@ -180,6 +185,11 @@ DeclarationName::NameKind DeclarationName::getNameKind() const { return Identifier; } +bool DeclarationName::isDependentName() const { + QualType T = getCXXNameType(); + return !T.isNull() && T->isDependentType(); +} + std::string DeclarationName::getAsString() const { switch (getNameKind()) { case Identifier: @@ -353,6 +363,7 @@ void DeclarationName::dump() const { DeclarationNameTable::DeclarationNameTable() { CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>; + CXXLiteralOperatorNames = new llvm::FoldingSet<CXXLiteralOperatorIdName>; // Initialize the overloaded operator names. CXXOperatorNames = new CXXOperatorIdName[NUM_OVERLOADED_OPERATORS]; @@ -364,16 +375,30 @@ DeclarationNameTable::DeclarationNameTable() { } DeclarationNameTable::~DeclarationNameTable() { - llvm::FoldingSet<CXXSpecialName> *set = + llvm::FoldingSet<CXXSpecialName> *SpecialNames = static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl); - llvm::FoldingSetIterator<CXXSpecialName> I = set->begin(), E = set->end(); + llvm::FoldingSetIterator<CXXSpecialName> + SI = SpecialNames->begin(), SE = SpecialNames->end(); + + while (SI != SE) { + CXXSpecialName *n = &*SI++; + delete n; + } - while (I != E) { - CXXSpecialName *n = &*I++; + + llvm::FoldingSet<CXXLiteralOperatorIdName> *LiteralNames + = static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName>*> + (CXXLiteralOperatorNames); + llvm::FoldingSetIterator<CXXLiteralOperatorIdName> + LI = LiteralNames->begin(), LE = LiteralNames->end(); + + while (LI != LE) { + CXXLiteralOperatorIdName *n = &*LI++; delete n; } - delete set; + delete SpecialNames; + delete LiteralNames; delete [] CXXOperatorNames; } @@ -428,9 +453,23 @@ DeclarationNameTable::getCXXOperatorName(OverloadedOperatorKind Op) { DeclarationName DeclarationNameTable::getCXXLiteralOperatorName(IdentifierInfo *II) { + llvm::FoldingSet<CXXLiteralOperatorIdName> *LiteralNames + = static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName>*> + (CXXLiteralOperatorNames); + + llvm::FoldingSetNodeID ID; + ID.AddPointer(II); + + void *InsertPos = 0; + if (CXXLiteralOperatorIdName *Name = + LiteralNames->FindNodeOrInsertPos(ID, InsertPos)) + return DeclarationName (Name); + CXXLiteralOperatorIdName *LiteralName = new CXXLiteralOperatorIdName; LiteralName->ExtraKindOrNumArgs = DeclarationNameExtra::CXXLiteralOperator; LiteralName->ID = II; + + LiteralNames->InsertNode(LiteralName, InsertPos); return DeclarationName(LiteralName); } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 04a6abc..4c3046b 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -2154,7 +2154,8 @@ IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() { return getField()->getIdentifier(); } -DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators, +DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty, + unsigned NumDesignators, const Designator *Designators, SourceLocation EqualOrColonLoc, bool GNUSyntax, @@ -2165,7 +2166,7 @@ DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators, Init->isTypeDependent(), Init->isValueDependent()), EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax), NumDesignators(NumDesignators), NumSubExprs(NumIndexExprs + 1) { - this->Designators = new Designator[NumDesignators]; + this->Designators = new (C) Designator[NumDesignators]; // Record the initializer itself. child_iterator Child = child_begin(); @@ -2210,7 +2211,7 @@ DesignatedInitExpr::Create(ASTContext &C, Designator *Designators, bool UsesColonSyntax, Expr *Init) { void *Mem = C.Allocate(sizeof(DesignatedInitExpr) + sizeof(Stmt *) * (NumIndexExprs + 1), 8); - return new (Mem) DesignatedInitExpr(C.VoidTy, NumDesignators, Designators, + return new (Mem) DesignatedInitExpr(C, C.VoidTy, NumDesignators, Designators, ColonOrEqualLoc, UsesColonSyntax, IndexExprs, NumIndexExprs, Init); } @@ -2222,12 +2223,12 @@ DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C, return new (Mem) DesignatedInitExpr(NumIndexExprs + 1); } -void DesignatedInitExpr::setDesignators(const Designator *Desigs, +void DesignatedInitExpr::setDesignators(ASTContext &C, + const Designator *Desigs, unsigned NumDesigs) { - if (Designators) - delete [] Designators; + DestroyDesignators(C); - Designators = new Designator[NumDesigs]; + Designators = new (C) Designator[NumDesigs]; NumDesignators = NumDesigs; for (unsigned I = 0; I != NumDesigs; ++I) Designators[I] = Desigs[I]; @@ -2276,7 +2277,7 @@ Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator& D) { /// \brief Replaces the designator at index @p Idx with the series /// of designators in [First, Last). -void DesignatedInitExpr::ExpandDesignator(unsigned Idx, +void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx, const Designator *First, const Designator *Last) { unsigned NumNewDesignators = Last - First; @@ -2292,21 +2293,28 @@ void DesignatedInitExpr::ExpandDesignator(unsigned Idx, } Designator *NewDesignators - = new Designator[NumDesignators - 1 + NumNewDesignators]; + = new (C) Designator[NumDesignators - 1 + NumNewDesignators]; std::copy(Designators, Designators + Idx, NewDesignators); std::copy(First, Last, NewDesignators + Idx); std::copy(Designators + Idx + 1, Designators + NumDesignators, NewDesignators + Idx + NumNewDesignators); - delete [] Designators; + DestroyDesignators(C); Designators = NewDesignators; NumDesignators = NumDesignators - 1 + NumNewDesignators; } void DesignatedInitExpr::DoDestroy(ASTContext &C) { - delete [] Designators; + DestroyDesignators(C); Expr::DoDestroy(C); } +void DesignatedInitExpr::DestroyDesignators(ASTContext &C) { + for (unsigned I = 0; I != NumDesignators; ++I) + Designators[I].~Designator(); + C.Deallocate(Designators); + Designators = 0; +} + ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc, Expr **exprs, unsigned nexprs, SourceLocation rparenloc) diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 06afec7..dfff209 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -13,6 +13,7 @@ #include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/CharUnits.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/ASTDiagnostic.h" @@ -69,11 +70,12 @@ static bool EvaluateComplex(const Expr *E, APValue &Result, EvalInfo &Info); static bool EvalPointerValueAsBool(APValue& Value, bool& Result) { // FIXME: Is this accurate for all kinds of bases? If not, what would // the check look like? - Result = Value.getLValueBase() || Value.getLValueOffset(); + Result = Value.getLValueBase() || !Value.getLValueOffset().isZero(); return true; } -static bool HandleConversionToBool(Expr* E, bool& Result, EvalInfo &Info) { +static bool HandleConversionToBool(const Expr* E, bool& Result, + EvalInfo &Info) { if (E->getType()->isIntegralType()) { APSInt IntResult; if (!EvaluateInteger(E, IntResult, Info)) @@ -222,11 +224,11 @@ public: APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } APValue VisitDeclRefExpr(DeclRefExpr *E); - APValue VisitPredefinedExpr(PredefinedExpr *E) { return APValue(E, 0); } + APValue VisitPredefinedExpr(PredefinedExpr *E) { return APValue(E); } APValue VisitCompoundLiteralExpr(CompoundLiteralExpr *E); APValue VisitMemberExpr(MemberExpr *E); - APValue VisitStringLiteral(StringLiteral *E) { return APValue(E, 0); } - APValue VisitObjCEncodeExpr(ObjCEncodeExpr *E) { return APValue(E, 0); } + APValue VisitStringLiteral(StringLiteral *E) { return APValue(E); } + APValue VisitObjCEncodeExpr(ObjCEncodeExpr *E) { return APValue(E); } APValue VisitArraySubscriptExpr(ArraySubscriptExpr *E); APValue VisitUnaryDeref(UnaryOperator *E); APValue VisitUnaryExtension(const UnaryOperator *E) @@ -254,12 +256,12 @@ static bool EvaluateLValue(const Expr* E, APValue& Result, EvalInfo &Info) { APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) { if (isa<FunctionDecl>(E->getDecl())) { - return APValue(E, 0); + return APValue(E); } else if (VarDecl* VD = dyn_cast<VarDecl>(E->getDecl())) { if (!Info.AnyLValue && !VD->hasGlobalStorage()) return APValue(); if (!VD->getType()->isReferenceType()) - return APValue(E, 0); + return APValue(E); // FIXME: Check whether VD might be overridden! const VarDecl *Def = 0; if (const Expr *Init = VD->getDefinition(Def)) @@ -272,7 +274,7 @@ APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) { APValue LValueExprEvaluator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { if (!Info.AnyLValue && !E->isFileScope()) return APValue(); - return APValue(E, 0); + return APValue(E); } APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) { @@ -309,7 +311,8 @@ APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) { } result.setLValue(result.getLValueBase(), - result.getLValueOffset() + RL.getFieldOffset(i) / 8); + result.getLValueOffset() + + CharUnits::fromQuantity(RL.getFieldOffset(i) / 8)); return result; } @@ -324,9 +327,9 @@ APValue LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { if (!EvaluateInteger(E->getIdx(), Index, Info)) return APValue(); - uint64_t ElementSize = Info.Ctx.getTypeSize(E->getType()) / 8; + CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(E->getType()); - uint64_t Offset = Index.getSExtValue() * ElementSize; + CharUnits Offset = Index.getSExtValue() * ElementSize; Result.setLValue(Result.getLValueBase(), Result.getLValueOffset() + Offset); return Result; @@ -363,22 +366,22 @@ public: { return Visit(E->getSubExpr()); } APValue VisitUnaryAddrOf(const UnaryOperator *E); APValue VisitObjCStringLiteral(ObjCStringLiteral *E) - { return APValue(E, 0); } + { return APValue(E); } APValue VisitAddrLabelExpr(AddrLabelExpr *E) - { return APValue(E, 0); } + { return APValue(E); } APValue VisitCallExpr(CallExpr *E); APValue VisitBlockExpr(BlockExpr *E) { if (!E->hasBlockDeclRefExprs()) - return APValue(E, 0); + return APValue(E); return APValue(); } APValue VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) - { return APValue((Expr*)0, 0); } + { return APValue((Expr*)0); } APValue VisitConditionalOperator(ConditionalOperator *E); APValue VisitChooseExpr(ChooseExpr *E) { return Visit(E->getChosenSubExpr(Info.Ctx)); } APValue VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) - { return APValue((Expr*)0, 0); } + { return APValue((Expr*)0); } // FIXME: Missing: @protocol, @selector }; } // end anonymous namespace @@ -409,15 +412,15 @@ APValue PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { return APValue(); QualType PointeeType = PExp->getType()->getAs<PointerType>()->getPointeeType(); - uint64_t SizeOfPointee; + CharUnits SizeOfPointee; // Explicitly handle GNU void* and function pointer arithmetic extensions. if (PointeeType->isVoidType() || PointeeType->isFunctionType()) - SizeOfPointee = 1; + SizeOfPointee = CharUnits::One(); else - SizeOfPointee = Info.Ctx.getTypeSize(PointeeType) / 8; + SizeOfPointee = Info.Ctx.getTypeSizeInChars(PointeeType); - uint64_t Offset = ResultLValue.getLValueOffset(); + CharUnits Offset = ResultLValue.getLValueOffset(); if (E->getOpcode() == BinaryOperator::Add) Offset += AdditionalOffset.getLimitedValue() * SizeOfPointee; @@ -459,7 +462,8 @@ APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) { if (Result.isInt()) { Result.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType())); - return APValue(0, Result.getInt().getZExtValue()); + return APValue(0, + CharUnits::fromQuantity(Result.getInt().getZExtValue())); } // Cast is of an lvalue, no need to change value. @@ -481,7 +485,8 @@ APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) { if (Result.isInt()) { Result.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType())); - return APValue(0, Result.getInt().getZExtValue()); + return APValue(0, + CharUnits::fromQuantity(Result.getInt().getZExtValue())); } // Cast is of an lvalue, no need to change value. @@ -502,7 +507,7 @@ APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) { APValue PointerExprEvaluator::VisitCallExpr(CallExpr *E) { if (E->isBuiltinCall(Info.Ctx) == Builtin::BI__builtin___CFStringMakeConstantString) - return APValue(E, 0); + return APValue(E); return APValue(); } @@ -976,20 +981,20 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { && VD->getType()->isObjectType() && !VD->getType()->isVariablyModifiedType() && !VD->getType()->isDependentType()) { - uint64_t Size = Info.Ctx.getTypeSize(VD->getType()) / 8; - uint64_t Offset = Base.Val.getLValueOffset(); - if (Offset <= Size) - Size -= Base.Val.getLValueOffset(); + CharUnits Size = Info.Ctx.getTypeSizeInChars(VD->getType()); + CharUnits Offset = Base.Val.getLValueOffset(); + if (!Offset.isNegative() && Offset <= Size) + Size -= Offset; else - Size = 0; - return Success(Size, E); + Size = CharUnits::Zero(); + return Success(Size.getQuantity(), E); } } } // TODO: Perhaps we should let LLVM lower this? if (E->getArg(0)->HasSideEffects(Info.Ctx)) { - if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() == 0) + if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() <= 1) return Success(-1ULL, E); return Success(0, E); } @@ -1151,7 +1156,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (LHSValue.getLValueBase()) { if (!E->isEqualityOp()) return false; - if (RHSValue.getLValueBase() || RHSValue.getLValueOffset()) + if (RHSValue.getLValueBase() || !RHSValue.getLValueOffset().isZero()) return false; bool bres; if (!EvalPointerValueAsBool(LHSValue, bres)) @@ -1160,7 +1165,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { } else if (RHSValue.getLValueBase()) { if (!E->isEqualityOp()) return false; - if (LHSValue.getLValueBase() || LHSValue.getLValueOffset()) + if (LHSValue.getLValueBase() || !LHSValue.getLValueOffset().isZero()) return false; bool bres; if (!EvalPointerValueAsBool(RHSValue, bres)) @@ -1172,11 +1177,13 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { const QualType Type = E->getLHS()->getType(); const QualType ElementType = Type->getAs<PointerType>()->getPointeeType(); - uint64_t D = LHSValue.getLValueOffset() - RHSValue.getLValueOffset(); + CharUnits ElementSize = CharUnits::One(); if (!ElementType->isVoidType() && !ElementType->isFunctionType()) - D /= Info.Ctx.getTypeSize(ElementType) / 8; + ElementSize = Info.Ctx.getTypeSizeInChars(ElementType); - return Success(D, E); + CharUnits Diff = LHSValue.getLValueOffset() - + RHSValue.getLValueOffset(); + return Success(Diff / ElementSize, E); } bool Result; if (E->getOpcode() == BinaryOperator::EQ) { @@ -1204,21 +1211,23 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { // Handle cases like (unsigned long)&a + 4. if (E->isAdditiveOp() && Result.isLValue() && RHSVal.isInt()) { - uint64_t offset = Result.getLValueOffset(); + CharUnits Offset = Result.getLValueOffset(); + CharUnits AdditionalOffset = CharUnits::fromQuantity( + RHSVal.getInt().getZExtValue()); if (E->getOpcode() == BinaryOperator::Add) - offset += RHSVal.getInt().getZExtValue(); + Offset += AdditionalOffset; else - offset -= RHSVal.getInt().getZExtValue(); - Result = APValue(Result.getLValueBase(), offset); + Offset -= AdditionalOffset; + Result = APValue(Result.getLValueBase(), Offset); return true; } // Handle cases like 4 + (unsigned long)&a if (E->getOpcode() == BinaryOperator::Add && RHSVal.isLValue() && Result.isInt()) { - uint64_t offset = RHSVal.getLValueOffset(); - offset += Result.getInt().getZExtValue(); - Result = APValue(RHSVal.getLValueBase(), offset); + CharUnits Offset = RHSVal.getLValueOffset(); + Offset += CharUnits::fromQuantity(Result.getInt().getZExtValue()); + Result = APValue(RHSVal.getLValueBase(), Offset); return true; } @@ -1334,8 +1343,7 @@ bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) { return false; // Get information about the size. - unsigned BitWidth = Info.Ctx.getTypeSize(SrcTy); - return Success(BitWidth / Info.Ctx.Target.getCharWidth(), E); + return Success(Info.Ctx.getTypeSizeInChars(SrcTy).getQuantity(), E); } bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { @@ -1349,7 +1357,7 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { return false; if (LV.getLValueBase()) return false; - return Success(LV.getLValueOffset(), E); + return Success(LV.getLValueOffset().getQuantity(), E); } if (E->getOpcode() == UnaryOperator::LNot) { @@ -1432,7 +1440,8 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) { return true; } - APSInt AsInt = Info.Ctx.MakeIntValue(LV.getLValueOffset(), SrcType); + APSInt AsInt = Info.Ctx.MakeIntValue(LV.getLValueOffset().getQuantity(), + SrcType); return Success(HandleIntToIntCast(DestType, SrcType, AsInt, Info.Ctx), E); } @@ -1978,6 +1987,13 @@ bool Expr::EvaluateAsAny(EvalResult &Result, ASTContext &Ctx) const { return true; } +bool Expr::EvaluateAsBooleanCondition(bool &Result, ASTContext &Ctx) const { + EvalResult Scratch; + EvalInfo Info(Ctx, Scratch); + + return HandleConversionToBool(this, Result, Info); +} + bool Expr::EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const { EvalInfo Info(Ctx, Result); diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index c914f3f..cfd89ea 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -719,11 +719,6 @@ ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { // 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; @@ -741,13 +736,13 @@ ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { 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->isInlineSpecified()) + continue; if (MD->hasInlineBody()) continue; diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 7c7aeb8..104e336 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -337,12 +337,12 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces, //===----------------------------------------------------------------------===// AsmStmt::AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile, - unsigned numoutputs, unsigned numinputs, + bool msasm, unsigned numoutputs, unsigned numinputs, std::string *names, StringLiteral **constraints, Expr **exprs, StringLiteral *asmstr, unsigned numclobbers, StringLiteral **clobbers, SourceLocation rparenloc) : Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr) - , IsSimple(issimple), IsVolatile(isvolatile) + , IsSimple(issimple), IsVolatile(isvolatile), MSAsm(msasm) , NumOutputs(numoutputs), NumInputs(numinputs) { for (unsigned i = 0, e = numinputs + numoutputs; i != e; i++) { Names.push_back(names[i]); diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index a7e42af..bbb904d 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -739,9 +739,10 @@ void StmtPrinter::VisitCallExpr(CallExpr *Call) { void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { // FIXME: Suppress printing implicit bases (like "this") PrintExpr(Node->getBase()); + if (FieldDecl *FD = dyn_cast<FieldDecl>(Node->getMemberDecl())) + if (FD->isAnonymousStructOrUnion()) + return; OS << (Node->isArrow() ? "->" : "."); - // FIXME: Suppress printing references to unnamed objects - // representing anonymous unions/structs if (NestedNameSpecifier *Qualifier = Node->getQualifier()) Qualifier->print(OS, Policy); @@ -1120,6 +1121,13 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { } void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) { + // FIXME. For now we just print a trivial constructor call expression, + // constructing its first argument object. + if (E->getNumArgs() == 1) { + CXXConstructorDecl *CD = E->getConstructor(); + if (CD->isTrivial()) + PrintExpr(E->getArg(0)); + } // Nothing to print. } diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index 3ccb7a9..0840c52 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -13,6 +13,7 @@ #include "llvm/Support/raw_ostream.h" #include "clang/AST/TypeLocVisitor.h" +#include "clang/AST/Expr.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -123,3 +124,14 @@ bool TypeSpecTypeLoc::classof(const TypeLoc *TL) { if (TL->getType().hasLocalQualifiers()) return false; return TSTChecker().Visit(*TL); } + +// Reimplemented to account for GNU/C++ extension +// typeof unary-expression +// where there are no parentheses. +SourceRange TypeOfExprTypeLoc::getSourceRange() const { + if (getRParenLoc().isValid()) + return SourceRange(getTypeofLoc(), getRParenLoc()); + else + return SourceRange(getTypeofLoc(), + getUnderlyingExpr()->getSourceRange().getEnd()); +} diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 818657c..00b74bc 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -271,6 +271,10 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T, S += ")"; + if (T->getNoReturnAttr()) + S += " __attribute__((noreturn))"; + + if (T->hasExceptionSpec()) { S += " throw("; if (T->hasAnyExceptionSpec()) @@ -287,10 +291,9 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T, S += ")"; } - if (T->getNoReturnAttr()) - S += " __attribute__((noreturn))"; - Print(T->getResultType(), S); + AppendTypeQualList(S, T->getTypeQuals()); + Print(T->getResultType(), S); } void TypePrinter::PrintFunctionNoProto(const FunctionNoProtoType *T, diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp index 97e6d91..2093b5e 100644 --- a/lib/Analysis/AnalysisContext.cpp +++ b/lib/Analysis/AnalysisContext.cpp @@ -18,6 +18,7 @@ #include "clang/Analysis/CFG.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/ParentMap.h" #include "clang/AST/StmtVisitor.h" #include "clang/Analysis/Support/BumpVector.h" @@ -38,6 +39,9 @@ Stmt *AnalysisContext::getBody() { return MD->getBody(); else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) return BD->getBody(); + else if (const FunctionTemplateDecl *FunTmpl + = dyn_cast_or_null<FunctionTemplateDecl>(D)) + return FunTmpl->getTemplatedDecl()->getBody(); llvm_unreachable("unknown code decl"); } diff --git a/lib/Analysis/BasicConstraintManager.cpp b/lib/Analysis/BasicConstraintManager.cpp index 6c3f7b2..6dfc470 100644 --- a/lib/Analysis/BasicConstraintManager.cpp +++ b/lib/Analysis/BasicConstraintManager.cpp @@ -49,8 +49,9 @@ class BasicConstraintManager : public SimpleConstraintManager { GRState::IntSetTy::Factory ISetFactory; public: - BasicConstraintManager(GRStateManager& statemgr) - : ISetFactory(statemgr.getAllocator()) {} + BasicConstraintManager(GRStateManager &statemgr, GRSubEngine &subengine) + : SimpleConstraintManager(subengine), + ISetFactory(statemgr.getAllocator()) {} const GRState* AssumeSymNE(const GRState* state, SymbolRef sym, const llvm::APSInt& V); @@ -88,9 +89,9 @@ public: } // end anonymous namespace -ConstraintManager* clang::CreateBasicConstraintManager(GRStateManager& StateMgr) -{ - return new BasicConstraintManager(StateMgr); +ConstraintManager* clang::CreateBasicConstraintManager(GRStateManager& statemgr, + GRSubEngine &subengine) { + return new BasicConstraintManager(statemgr, subengine); } const GRState* diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp index e648269..2a9531d 100644 --- a/lib/Analysis/BugReporter.cpp +++ b/lib/Analysis/BugReporter.cpp @@ -1818,8 +1818,23 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) { R->getRanges(Beg, End); Diagnostic& Diag = getDiagnostic(); FullSourceLoc L(R->getLocation(), getSourceManager()); - unsigned ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning, - R->getShortDescription().c_str()); + + // Search the description for '%', as that will be interpretted as a + // format character by FormatDiagnostics. + llvm::StringRef desc = R->getShortDescription(); + unsigned ErrorDiag; + { + llvm::SmallString<512> TmpStr; + llvm::raw_svector_ostream Out(TmpStr); + for (llvm::StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I) + if (*I == '%') + Out << "%%"; + else + Out << *I; + + Out.flush(); + ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning, TmpStr); + } switch (End-Beg) { default: assert(0 && "Don't handle this many ranges yet!"); diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index a15a8f1..5a15fbf 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -52,8 +52,8 @@ using namespace clang; // not release it." // -using llvm::CStrInCStrNoCase; -using llvm::StringsEqualNoCase; +using llvm::StrInStrNoCase; +using llvm::StringRef; enum NamingConvention { NoConvention, CreateRule, InitRule }; @@ -122,20 +122,20 @@ static NamingConvention deriveNamingConvention(Selector S) { break; case 3: // Methods starting with 'new' follow the create rule. - if (AtBeginning && StringsEqualNoCase("new", s, len)) + if (AtBeginning && StringRef(s, len).equals_lower("new")) C = CreateRule; break; case 4: // Methods starting with 'alloc' or contain 'copy' follow the // create rule - if (C == NoConvention && StringsEqualNoCase("copy", s, len)) + if (C == NoConvention && StringRef(s, len).equals_lower("copy")) C = CreateRule; else // Methods starting with 'init' follow the init rule. - if (AtBeginning && StringsEqualNoCase("init", s, len)) + if (AtBeginning && StringRef(s, len).equals_lower("init")) C = InitRule; break; case 5: - if (AtBeginning && StringsEqualNoCase("alloc", s, len)) + if (AtBeginning && StringRef(s, len).equals_lower("alloc")) C = CreateRule; break; } @@ -1372,11 +1372,11 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { // "AppendValue", or "SetAttribute", then we assume that arguments may // "escape." This means that something else holds on to the object, // allowing it be used even after its local retain count drops to 0. - ArgEffect E = (CStrInCStrNoCase(FName, "InsertValue") || - CStrInCStrNoCase(FName, "AddValue") || - CStrInCStrNoCase(FName, "SetValue") || - CStrInCStrNoCase(FName, "AppendValue") || - CStrInCStrNoCase(FName, "SetAttribute")) + ArgEffect E = (StrInStrNoCase(FName, "InsertValue") != StringRef::npos|| + StrInStrNoCase(FName, "AddValue") != StringRef::npos || + StrInStrNoCase(FName, "SetValue") != StringRef::npos || + StrInStrNoCase(FName, "AppendValue") != StringRef::npos|| + StrInStrNoCase(FName, "SetAttribute") != StringRef::npos) ? MayEscape : DoNothing; S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, E); @@ -1555,7 +1555,8 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD, if (S.isKeywordSelector()) { const std::string &str = S.getAsString(); assert(!str.empty()); - if (CStrInCStrNoCase(&str[0], "delegate:")) ReceiverEff = StopTracking; + if (StrInStrNoCase(str, "delegate:") != StringRef::npos) + ReceiverEff = StopTracking; } // Look for methods that return an owned object. diff --git a/lib/Analysis/CheckSecuritySyntaxOnly.cpp b/lib/Analysis/CheckSecuritySyntaxOnly.cpp index 3214101..f4874a5 100644 --- a/lib/Analysis/CheckSecuritySyntaxOnly.cpp +++ b/lib/Analysis/CheckSecuritySyntaxOnly.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/Basic/TargetInfo.h" #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/LocalCheckers.h" #include "clang/AST/StmtVisitor.h" @@ -18,6 +19,12 @@ using namespace clang; +static bool isArc4RandomAvailable(const ASTContext &Ctx) { + const llvm::Triple &T = Ctx.Target.getTriple(); + return T.getVendor() == llvm::Triple::Apple || + T.getOS() == llvm::Triple::FreeBSD; +} + namespace { class WalkAST : public StmtVisitor<WalkAST> { BugReporter &BR; @@ -29,11 +36,14 @@ class WalkAST : public StmtVisitor<WalkAST> { IdentifierInfo *II_random; enum { num_setids = 6 }; IdentifierInfo *II_setid[num_setids]; + + const bool CheckRand; public: WalkAST(BugReporter &br) : BR(br), II_gets(0), II_getpw(0), II_mktemp(0), - II_rand(), II_random(0), II_setid() {} + II_rand(), II_random(0), II_setid(), + CheckRand(isArc4RandomAvailable(BR.getContext())) {} // Statement visitor methods. void VisitCallExpr(CallExpr *CE); @@ -83,8 +93,10 @@ void WalkAST::VisitCallExpr(CallExpr *CE) { CheckCall_gets(CE, FD); CheckCall_getpw(CE, FD); CheckCall_mktemp(CE, FD); - CheckCall_rand(CE, FD); - CheckCall_random(CE, FD); + if (CheckRand) { + CheckCall_rand(CE, FD); + CheckCall_random(CE, FD); + } } // Recurse and check children. diff --git a/lib/Analysis/Environment.cpp b/lib/Analysis/Environment.cpp index dd2f08b..f04cf7b 100644 --- a/lib/Analysis/Environment.cpp +++ b/lib/Analysis/Environment.cpp @@ -37,7 +37,12 @@ SVal Environment::GetSVal(const Stmt *E, ValueManager& ValMgr) const { } case Stmt::IntegerLiteralClass: { - return ValMgr.makeIntVal(cast<IntegerLiteral>(E)); + // In C++, this expression may have been bound to a temporary object. + SVal const *X = ExprBindings.lookup(E); + if (X) + return *X; + else + return ValMgr.makeIntVal(cast<IntegerLiteral>(E)); } // Casts where the source and target type are the same diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 2ce8edd..40c12c9 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -17,6 +17,7 @@ #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h" #include "clang/Analysis/PathSensitive/Checker.h" +#include "clang/AST/CharUnits.h" #include "clang/AST/ParentMap.h" #include "clang/AST/StmtObjC.h" #include "clang/Basic/Builtins.h" @@ -47,10 +48,9 @@ static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) { } -static bool CalleeReturnsReference(const CallExpr *CE) { +static QualType GetCalleeReturnType(const CallExpr *CE) { const Expr *Callee = CE->getCallee(); QualType T = Callee->getType(); - if (const PointerType *PT = T->getAs<PointerType>()) { const FunctionType *FT = PT->getPointeeType()->getAs<FunctionType>(); T = FT->getResultType(); @@ -58,16 +58,35 @@ static bool CalleeReturnsReference(const CallExpr *CE) { else { const BlockPointerType *BT = T->getAs<BlockPointerType>(); T = BT->getPointeeType()->getAs<FunctionType>()->getResultType(); - } - return T->isReferenceType(); + } + return T; +} + +static bool CalleeReturnsReference(const CallExpr *CE) { + return (bool) GetCalleeReturnType(CE)->getAs<ReferenceType>(); } static bool ReceiverReturnsReference(const ObjCMessageExpr *ME) { const ObjCMethodDecl *MD = ME->getMethodDecl(); if (!MD) return false; - return MD->getResultType()->isReferenceType(); + return MD->getResultType()->getAs<ReferenceType>(); +} + +#ifndef NDEBUG +static bool ReceiverReturnsReferenceOrRecord(const ObjCMessageExpr *ME) { + const ObjCMethodDecl *MD = ME->getMethodDecl(); + if (!MD) + return false; + QualType T = MD->getResultType(); + return T->getAs<RecordType>() || T->getAs<ReferenceType>(); +} + +static bool CalleeReturnsReferenceOrRecord(const CallExpr *CE) { + QualType T = GetCalleeReturnType(CE); + return T->getAs<ReferenceType>() || T->getAs<RecordType>(); } +#endif //===----------------------------------------------------------------------===// // Batch auditor. DEPRECATED. @@ -300,23 +319,27 @@ static void RegisterInternalChecks(GRExprEngine &Eng) { RegisterOSAtomicChecker(Eng); } -GRExprEngine::GRExprEngine(AnalysisManager &mgr) +GRExprEngine::GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf) : AMgr(mgr), CoreEngine(mgr.getASTContext(), *this), G(CoreEngine.getGraph()), Builder(NULL), StateMgr(G.getContext(), mgr.getStoreManagerCreator(), - mgr.getConstraintManagerCreator(), G.getAllocator()), + mgr.getConstraintManagerCreator(), G.getAllocator(), + *this), SymMgr(StateMgr.getSymbolManager()), ValMgr(StateMgr.getValueManager()), SVator(ValMgr.getSValuator()), CurrentStmt(NULL), NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL), RaiseSel(GetNullarySelector("raise", G.getContext())), - BR(mgr, *this) -{ + BR(mgr, *this), TF(tf) { // Register internal checks. RegisterInternalChecks(*this); + + // FIXME: Eventually remove the TF object entirely. + TF->RegisterChecks(*this); + TF->RegisterPrinters(getStateManager().Printers); } GRExprEngine::~GRExprEngine() { @@ -330,13 +353,6 @@ GRExprEngine::~GRExprEngine() { // Utility methods. //===----------------------------------------------------------------------===// -void GRExprEngine::setTransferFunctionsAndCheckers(GRTransferFuncs* tf) { - StateMgr.TF = tf; - StateMgr.Checkers = &Checkers; - tf->RegisterChecks(*this); - tf->RegisterPrinters(getStateManager().Printers); -} - void GRExprEngine::AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C) { if (!BatchAuditor) BatchAuditor.reset(new MappedBatchAuditor(getGraph().getAllocator())); @@ -415,6 +431,25 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) { // Top-level transfer function logic (Dispatcher). //===----------------------------------------------------------------------===// +/// EvalAssume - Called by ConstraintManager. Used to call checker-specific +/// logic for handling assumptions on symbolic values. +const GRState *GRExprEngine::ProcessAssume(const GRState *state, SVal cond, + bool assumption) { + for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end(); + I != E; ++I) { + + if (!state) + return NULL; + + state = I->second->EvalAssume(state, cond, assumption); + } + + if (!state) + return NULL; + + return TF->EvalAssume(state, cond, assumption); +} + void GRExprEngine::ProcessStmt(CFGElement CE, GRStmtNodeBuilder& builder) { CurrentStmt = CE.getStmt(); PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), @@ -809,7 +844,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, case Stmt::CallExprClass: case Stmt::CXXOperatorCallExprClass: { CallExpr *C = cast<CallExpr>(Ex); - assert(CalleeReturnsReference(C)); + assert(CalleeReturnsReferenceOrRecord(C)); VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true); break; } @@ -840,7 +875,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, case Stmt::ObjCMessageExprClass: { ObjCMessageExpr *ME = cast<ObjCMessageExpr>(Ex); - assert(ReceiverReturnsReference(ME)); + assert(ReceiverReturnsReferenceOrRecord(ME)); VisitObjCMessageExpr(ME, Pred, Dst, true); return; } @@ -871,6 +906,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, case Stmt::UnaryOperatorClass: VisitUnaryOperator(cast<UnaryOperator>(Ex), Pred, Dst, true); return; + + // In C++, binding an rvalue to a reference requires to create an object. + case Stmt::IntegerLiteralClass: + CreateCXXTemporaryObject(Ex, Pred, Dst); + return; default: // Arbitrary subexpressions can return aggregate temporaries that @@ -1205,7 +1245,8 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) { do { nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1.Val.getInt())); - DefinedOrUnknownSVal Res = SVator.EvalEQ(DefaultSt, CondV, CaseVal); + DefinedOrUnknownSVal Res = SVator.EvalEQ(DefaultSt ? DefaultSt : state, + CondV, CaseVal); // Now "assume" that the case matches. if (const GRState* stateNew = state->Assume(Res, true)) { @@ -1220,11 +1261,17 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) { // Now "assume" that the case doesn't match. Add this state // to the default state (if it is feasible). - if (const GRState *stateNew = DefaultSt->Assume(Res, false)) { - defaultIsFeasible = true; - DefaultSt = stateNew; + if (DefaultSt) { + if (const GRState *stateNew = DefaultSt->Assume(Res, false)) { + defaultIsFeasible = true; + DefaultSt = stateNew; + } + else { + defaultIsFeasible = false; + DefaultSt = NULL; + } } - + // Concretize the next value in the range. if (V1.Val.getInt() == V2.Val.getInt()) break; @@ -2375,12 +2422,12 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst) { QualType T = Ex->getTypeOfArgument(); - uint64_t amt; + CharUnits amt; if (Ex->isSizeOf()) { if (T == getContext().VoidTy) { // sizeof(void) == 1 byte. - amt = 1; + amt = CharUnits::One(); } else if (!T.getTypePtr()->isConstantSizeType()) { // FIXME: Add support for VLAs. @@ -2394,14 +2441,15 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, } else { // All other cases. - amt = getContext().getTypeSize(T) / 8; + amt = getContext().getTypeSizeInChars(T); } } else // Get alignment of the type. - amt = getContext().getTypeAlign(T) / 8; + amt = CharUnits::fromQuantity(getContext().getTypeAlign(T) / 8); MakeNode(Dst, Ex, Pred, - GetState(Pred)->BindExpr(Ex, ValMgr.makeIntVal(amt, Ex->getType()))); + GetState(Pred)->BindExpr(Ex, + ValMgr.makeIntVal(amt.getQuantity(), Ex->getType()))); } @@ -2695,8 +2743,13 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred, ExplodedNodeSet & Dst) { // Get the this object region from StoreManager. - Loc V = getStoreManager().getThisObject(TE->getType()->getPointeeType()); - MakeNode(Dst, TE, Pred, GetState(Pred)->BindExpr(TE, V)); + const MemRegion *R = + ValMgr.getRegionManager().getCXXThisRegion(TE->getType(), + Pred->getLocationContext()); + + const GRState *state = GetState(Pred); + SVal V = state->getSVal(loc::MemRegionVal(R)); + MakeNode(Dst, TE, Pred, state->BindExpr(TE, V)); } void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, @@ -2964,6 +3017,26 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, CheckerVisit(B, Dst, Tmp3, false); } +void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + ExplodedNodeSet Tmp; + Visit(Ex, Pred, Tmp); + for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { + const GRState *state = GetState(*I); + + // Bind the temporary object to the value of the expression. Then bind + // the expression to the location of the object. + SVal V = state->getSVal(Ex); + + const MemRegion *R = + ValMgr.getRegionManager().getCXXObjectRegion(Ex, + Pred->getLocationContext()); + + state = state->bindLoc(loc::MemRegionVal(R), V); + MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R))); + } +} + //===----------------------------------------------------------------------===// // Checker registration/lookup. //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp index 7415fa5..051d465 100644 --- a/lib/Analysis/GRState.cpp +++ b/lib/Analysis/GRState.cpp @@ -267,6 +267,9 @@ bool ScanReachableSymbols::scan(SVal val) { if (loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&val)) return scan(X->getRegion()); + if (nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(&val)) + return scan(X->getLoc()); + if (SymbolRef Sym = val.getAsSymbol()) return visitor.VisitSymbol(Sym); diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp index 74fe3bf..87d60d3 100644 --- a/lib/Analysis/MemRegion.cpp +++ b/lib/Analysis/MemRegion.cpp @@ -17,6 +17,7 @@ #include "clang/Analysis/PathSensitive/MemRegion.h" #include "clang/Analysis/PathSensitive/ValueManager.h" #include "clang/Analysis/PathSensitive/AnalysisContext.h" +#include "clang/AST/CharUnits.h" #include "clang/AST/StmtVisitor.h" using namespace clang; @@ -215,6 +216,18 @@ void CompoundLiteralRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, ID.AddPointer(superRegion); } +void CXXThisRegion::ProfileRegion(llvm::FoldingSetNodeID &ID, + const PointerType *PT, + const MemRegion *sRegion) { + ID.AddInteger((unsigned) CXXThisRegionKind); + ID.AddPointer(PT); + ID.AddPointer(sRegion); +} + +void CXXThisRegion::Profile(llvm::FoldingSetNodeID &ID) const { + CXXThisRegion::ProfileRegion(ID, ThisPointerTy, superRegion); +} + void DeclRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D, const MemRegion* superRegion, Kind k) { ID.AddInteger((unsigned) k); @@ -292,14 +305,14 @@ void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const { } void CXXObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID, - QualType T, + Expr const *Ex, const MemRegion *sReg) { - ID.AddPointer(T.getTypePtr()); + ID.AddPointer(Ex); ID.AddPointer(sReg); } void CXXObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const { - ProfileRegion(ID, T, getSuperRegion()); + ProfileRegion(ID, Ex, getSuperRegion()); } //===----------------------------------------------------------------------===// @@ -343,6 +356,10 @@ void CompoundLiteralRegion::dumpToStream(llvm::raw_ostream& os) const { os << "{ " << (void*) CL << " }"; } +void CXXThisRegion::dumpToStream(llvm::raw_ostream &os) const { + os << "this"; +} + void ElementRegion::dumpToStream(llvm::raw_ostream& os) const { os << "element{" << superRegion << ',' << Index << ',' << getElementType().getAsString() << '}'; @@ -551,7 +568,7 @@ const SymbolicRegion *MemRegionManager::getSymbolicRegion(SymbolRef sym) { return getSubRegion<SymbolicRegion>(sym, getUnknownRegion()); } -const FieldRegion * +const FieldRegion* MemRegionManager::getFieldRegion(const FieldDecl* d, const MemRegion* superRegion){ return getSubRegion<FieldRegion>(d, superRegion); @@ -563,9 +580,22 @@ MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d, return getSubRegion<ObjCIvarRegion>(d, superRegion); } -const CXXObjectRegion * -MemRegionManager::getCXXObjectRegion(QualType T) { - return getSubRegion<CXXObjectRegion>(T, getUnknownRegion()); +const CXXObjectRegion* +MemRegionManager::getCXXObjectRegion(Expr const *E, + LocationContext const *LC) { + const StackFrameContext *SFC = LC->getCurrentStackFrame(); + assert(SFC); + return getSubRegion<CXXObjectRegion>(E, getStackLocalsRegion(SFC)); +} + +const CXXThisRegion* +MemRegionManager::getCXXThisRegion(QualType thisPointerTy, + const LocationContext *LC) { + const StackFrameContext *STC = LC->getCurrentStackFrame(); + assert(STC); + const PointerType *PT = thisPointerTy->getAs<PointerType>(); + assert(PT); + return getSubRegion<CXXThisRegion>(PT, getStackArgumentsRegion(STC)); } const AllocaRegion* @@ -592,20 +622,11 @@ bool MemRegion::hasStackStorage() const { return isa<StackSpaceRegion>(getMemorySpace()); } -bool MemRegion::hasHeapStorage() const { - return isa<HeapSpaceRegion>(getMemorySpace()); -} - -bool MemRegion::hasHeapOrStackStorage() const { - const MemSpaceRegion *MS = getMemorySpace(); - return isa<StackSpaceRegion>(MS) || isa<HeapSpaceRegion>(MS); -} - -bool MemRegion::hasGlobalsStorage() const { - return isa<GlobalsSpaceRegion>(getMemorySpace()); +bool MemRegion::hasStackNonParametersStorage() const { + return isa<StackLocalsSpaceRegion>(getMemorySpace()); } -bool MemRegion::hasParametersStorage() const { +bool MemRegion::hasStackParametersStorage() const { return isa<StackArgumentsSpaceRegion>(getMemorySpace()); } @@ -669,7 +690,7 @@ static bool IsCompleteType(ASTContext &Ctx, QualType Ty) { } RegionRawOffset ElementRegion::getAsRawOffset() const { - int64_t offset = 0; + CharUnits offset = CharUnits::Zero(); const ElementRegion *ER = this; const MemRegion *superR = NULL; ASTContext &C = getContext(); @@ -694,7 +715,7 @@ RegionRawOffset ElementRegion::getAsRawOffset() const { break; } - int64_t size = (int64_t) (C.getTypeSize(elemType) / 8); + CharUnits size = C.getTypeSizeInChars(elemType); offset += (i * size); } @@ -707,7 +728,7 @@ RegionRawOffset ElementRegion::getAsRawOffset() const { } assert(superR && "super region cannot be NULL"); - return RegionRawOffset(superR, offset); + return RegionRawOffset(superR, offset.getQuantity()); } //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/OSAtomicChecker.cpp b/lib/Analysis/OSAtomicChecker.cpp index cf16796..9d34e9e 100644 --- a/lib/Analysis/OSAtomicChecker.cpp +++ b/lib/Analysis/OSAtomicChecker.cpp @@ -103,19 +103,9 @@ bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C, 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); - } + if (const TypedRegion *TR = + dyn_cast_or_null<TypedRegion>(location.getAsRegion())) { + LoadTy = TR->getValueType(Ctx); } Engine.EvalLoad(Tmp, const_cast<Expr *>(theValueExpr), C.getPredecessor(), state, location, OSAtomicLoadTag, LoadTy); @@ -184,14 +174,22 @@ bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C, E2 = TmpStore.end(); I2 != E2; ++I2) { ExplodedNode *predNew = *I2; const GRState *stateNew = predNew->getState(); - SVal Res = Engine.getValueManager().makeTruthVal(true, CE->getType()); + // Check for 'void' return type if we have a bogus function prototype. + SVal Res = UnknownVal(); + QualType T = CE->getType(); + if (!T->isVoidType()) + Res = Engine.getValueManager().makeTruthVal(true, T); 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()); + // Check for 'void' return type if we have a bogus function prototype. + SVal Res = UnknownVal(); + QualType T = CE->getType(); + if (!T->isVoidType()) + Res = Engine.getValueManager().makeTruthVal(false, CE->getType()); C.GenerateNode(stateNotEqual->BindExpr(CE, Res), N); } } diff --git a/lib/Analysis/RangeConstraintManager.cpp b/lib/Analysis/RangeConstraintManager.cpp index 7330b62..2cf3dfb 100644 --- a/lib/Analysis/RangeConstraintManager.cpp +++ b/lib/Analysis/RangeConstraintManager.cpp @@ -234,7 +234,8 @@ namespace { class RangeConstraintManager : public SimpleConstraintManager{ RangeSet GetRange(const GRState *state, SymbolRef sym); public: - RangeConstraintManager() {} + RangeConstraintManager(GRSubEngine &subengine) + : SimpleConstraintManager(subengine) {} const GRState* AssumeSymNE(const GRState* St, SymbolRef sym, const llvm::APSInt& V); @@ -273,8 +274,9 @@ private: } // end anonymous namespace -ConstraintManager* clang::CreateRangeConstraintManager(GRStateManager&) { - return new RangeConstraintManager(); +ConstraintManager* clang::CreateRangeConstraintManager(GRStateManager&, + GRSubEngine &subeng) { + return new RangeConstraintManager(subeng); } const llvm::APSInt* RangeConstraintManager::getSymVal(const GRState* St, diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index 3bc9dcc..9b5b44b 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -28,9 +28,12 @@ using namespace clang; -#define HEAP_UNDEFINED 0 #define USE_EXPLICIT_COMPOUND 0 +//===----------------------------------------------------------------------===// +// Representation of value bindings. +//===----------------------------------------------------------------------===// + namespace { class BindingVal { public: @@ -77,8 +80,41 @@ llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingVal V) { } } // end llvm namespace +//===----------------------------------------------------------------------===// +// Representation of binding keys. +//===----------------------------------------------------------------------===// + +namespace { + class BindingKey : public std::pair<const MemRegion*, uint64_t> { +public: + explicit BindingKey(const MemRegion *r, uint64_t offset) + : std::pair<const MemRegion*,uint64_t>(r, offset) { assert(r); } + + const MemRegion *getRegion() const { return first; } + uint64_t getOffset() const { return second; } + + void Profile(llvm::FoldingSetNodeID& ID) const { + ID.AddPointer(getRegion()); + ID.AddInteger(getOffset()); + } + + static BindingKey Make(const MemRegion *R); +}; +} // end anonymous namespace + +namespace llvm { + static inline + llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingKey K) { + os << '(' << K.getRegion() << ',' << K.getOffset() << ')'; + return os; + } +} // end llvm namespace + +//===----------------------------------------------------------------------===// // Actual Store type. -typedef llvm::ImmutableMap<const MemRegion*, BindingVal> RegionBindings; +//===----------------------------------------------------------------------===// + +typedef llvm::ImmutableMap<BindingKey, BindingVal> RegionBindings; //===----------------------------------------------------------------------===// // Fine-grained control of RegionStoreManager. @@ -283,6 +319,16 @@ private: void RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R, RegionStoreSubRegionMap &M); + RegionBindings Add(RegionBindings B, BindingKey K, BindingVal V); + RegionBindings Add(RegionBindings B, const MemRegion *R, BindingVal V); + + const BindingVal *Lookup(RegionBindings B, BindingKey K); + const BindingVal *Lookup(RegionBindings B, const MemRegion *R); + + RegionBindings Remove(RegionBindings B, BindingKey K); + RegionBindings Remove(RegionBindings B, const MemRegion *R); + Store Remove(Store store, BindingKey K); + public: const GRState *Bind(const GRState *state, Loc LV, SVal V); @@ -308,6 +354,7 @@ public: Store KillStruct(Store store, const TypedRegion* R); Store Remove(Store store, Loc LV); + //===------------------------------------------------------------------===// // Loading values from regions. @@ -438,7 +485,7 @@ RegionStoreManager::getRegionStoreSubRegionMap(Store store) { llvm::SmallVector<const SubRegion*, 10> WL; for (RegionBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) - if (const SubRegion *R = dyn_cast<SubRegion>(I.getKey())) + if (const SubRegion *R = dyn_cast<SubRegion>(I.getKey().getRegion())) M->process(WL, R); // We also need to record in the subregion map "intermediate" regions that @@ -467,8 +514,8 @@ void RegionStoreManager::RemoveSubRegionBindings(RegionBindings &B, for (llvm::tie(I, E) = M.begin_end(R); I != E; ++I) RemoveSubRegionBindings(B, *I, M); - - B = RBFactory.Remove(B, R); + + B = Remove(B, R); } const GRState *RegionStoreManager::InvalidateRegions(const GRState *state, @@ -544,8 +591,8 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state, // Invalidate the region by setting its default value to // conjured symbol. The type of the symbol is irrelavant. DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy, - Count); - B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default)); + Count); + B = Add(B, R, BindingVal(V, BindingVal::Default)); continue; } @@ -566,7 +613,7 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state, // conjured symbol. The type of the symbol is irrelavant. DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy, Count); - B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default)); + B = Add(B, R, BindingVal(V, BindingVal::Default)); continue; } @@ -574,7 +621,7 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state, // Set the default value of the array to conjured symbol. DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, AT->getElementType(), Count); - B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default)); + B = Add(B, R, BindingVal(V, BindingVal::Default)); continue; } @@ -583,14 +630,14 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state, // For fields and elements whose super region has also been invalidated, // only remove the old binding. The super region will get set with a // default value from which we can lazily derive a new symbolic value. - B = RBFactory.Remove(B, R); + B = Remove(B, R); continue; } // Invalidate the binding. DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, T, Count); assert(SymbolManager::canSymbolicate(T) || V.isUnknown()); - B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct)); + B = Add(B, R, BindingVal(V, BindingVal::Direct)); } // Create a new state with the updated bindings. @@ -723,6 +770,8 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, const MemRegion *R) { switch (R->getKind()) { + case MemRegion::CXXThisRegionKind: + assert(0 && "Cannot get size of 'this' region"); case MemRegion::GenericMemSpaceRegionKind: case MemRegion::StackLocalsSpaceRegionKind: case MemRegion::StackArgumentsSpaceRegionKind: @@ -877,6 +926,9 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state, // Technically this can happen if people do funny things with casts. return UnknownVal(); + case MemRegion::CXXThisRegionKind: + assert(0 && + "Cannot perform pointer arithmetic on implicit argument 'this'"); case MemRegion::GenericMemSpaceRegionKind: case MemRegion::StackLocalsSpaceRegionKind: case MemRegion::StackArgumentsSpaceRegionKind: @@ -921,7 +973,7 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state, Optional<SVal> RegionStoreManager::getDirectBinding(RegionBindings B, const MemRegion *R) { - if (const BindingVal *BV = B.lookup(R)) + if (const BindingVal *BV = Lookup(B, R)) return Optional<SVal>::create(BV->getDirectValue()); return Optional<SVal>(); @@ -935,7 +987,7 @@ Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B, if (TR->getValueType(getContext())->isUnionType()) return UnknownVal(); - if (BindingVal const *V = B.lookup(R)) + if (const BindingVal *V = Lookup(B, R)) return Optional<SVal>::create(V->getDefaultValue()); return Optional<SVal>(); @@ -943,7 +995,7 @@ Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B, Optional<SVal> RegionStoreManager::getBinding(RegionBindings B, const MemRegion *R) { - if (const BindingVal *BV = B.lookup(R)) + if (const BindingVal *BV = Lookup(B, R)) return Optional<SVal>::create(BV->getValue()); return Optional<SVal>(); @@ -1051,22 +1103,46 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { if (const FieldRegion* FR = dyn_cast<FieldRegion>(R)) return SValuator::CastResult(state, - CastRetrievedVal(RetrieveField(state, FR), FR, T)); - - if (const ElementRegion* ER = dyn_cast<ElementRegion>(R)) + CastRetrievedVal(RetrieveField(state, FR), FR, + T, false)); + + if (const ElementRegion* ER = dyn_cast<ElementRegion>(R)) { + // FIXME: Here we actually perform an implicit conversion from the loaded + // value to the element type. Eventually we want to compose these values + // more intelligently. For example, an 'element' can encompass multiple + // bound regions (e.g., several bound bytes), or could be a subset of + // a larger value. return SValuator::CastResult(state, - CastRetrievedVal(RetrieveElement(state, ER), ER, T)); - - if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) + CastRetrievedVal(RetrieveElement(state, ER), + ER, T, false)); + } + + if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) { + // FIXME: Here we actually perform an implicit conversion from the loaded + // value to the ivar type. What we should model is stores to ivars + // that blow past the extent of the ivar. If the address of the ivar is + // reinterpretted, it is possible we stored a different value that could + // fit within the ivar. Either we need to cast these when storing them + // or reinterpret them lazily (as we do here). return SValuator::CastResult(state, - CastRetrievedVal(RetrieveObjCIvar(state, IVR), IVR, T)); + CastRetrievedVal(RetrieveObjCIvar(state, IVR), + IVR, T, false)); + } - if (const VarRegion *VR = dyn_cast<VarRegion>(R)) + if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { + // FIXME: Here we actually perform an implicit conversion from the loaded + // value to the variable type. What we should model is stores to variables + // that blow past the extent of the variable. If the address of the + // variable is reinterpretted, it is possible we stored a different value + // that could fit within the variable. Either we need to cast these when + // storing them or reinterpret them lazily (as we do here). return SValuator::CastResult(state, - CastRetrievedVal(RetrieveVar(state, VR), VR, T)); + CastRetrievedVal(RetrieveVar(state, VR), VR, T, + false)); + } RegionBindings B = GetRegionBindings(state->getStore()); - RegionBindings::data_type* V = B.lookup(R); + const BindingVal *V = Lookup(B, R); // Check if the region has a binding. if (V) @@ -1076,12 +1152,7 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { // The location does not have a bound value. This means that it has // the value it had upon its creation and/or entry to the analyzed // function/method. These are either symbolic values or 'undefined'. - -#if HEAP_UNDEFINED - if (R->hasHeapOrStackStorage()) { -#else - if (R->hasStackStorage()) { -#endif + if (R->hasStackNonParametersStorage()) { // All stack variables are considered to have undefined values // upon creation. All heap allocated blocks are considered to // have undefined values as well unless they are explicitly bound @@ -1124,7 +1195,7 @@ SVal RegionStoreManager::RetrieveElement(const GRState* state, const ElementRegion* R) { // Check if the region has a binding. RegionBindings B = GetRegionBindings(state->getStore()); - if (Optional<SVal> V = getDirectBinding(B, R)) + if (Optional<SVal> V = getDirectBinding(B, R)) return *V; const MemRegion* superR = R->getSuperRegion(); @@ -1174,7 +1245,7 @@ SVal RegionStoreManager::RetrieveElement(const GRState* state, // Other cases: give up. return UnknownVal(); } - + return RetrieveFieldOrElementCommon(state, R, R->getElementType(), superR); } @@ -1240,8 +1311,7 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state, cast<FieldRegion>(lazyBindingRegion)); } - if (R->hasStackStorage() && !R->hasParametersStorage()) { - + if (R->hasStackNonParametersStorage()) { if (isa<ElementRegion>(R)) { // Currently we don't reason specially about Clang-style vectors. Check // if superR is a vector and if so return Unknown. @@ -1369,15 +1439,9 @@ SVal RegionStoreManager::RetrieveArray(const GRState *state, //===----------------------------------------------------------------------===// Store RegionStoreManager::Remove(Store store, Loc L) { - const MemRegion* R = 0; - if (isa<loc::MemRegionVal>(L)) - R = cast<loc::MemRegionVal>(L).getRegion(); - - if (R) { - RegionBindings B = GetRegionBindings(store); - return RBFactory.Remove(B, R).getRoot(); - } + if (const MemRegion* R = cast<loc::MemRegionVal>(L).getRegion()) + return Remove(store, BindingKey::Make(R)); return store; } @@ -1436,8 +1500,8 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) { // Perform the binding. RegionBindings B = GetRegionBindings(state->getStore()); - return state->makeWithStore( - RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct)).getRoot()); + return state->makeWithStore(Add(B, R, + BindingVal(V, BindingVal::Direct)).getRoot()); } const GRState *RegionStoreManager::BindDecl(const GRState *ST, @@ -1483,9 +1547,9 @@ const GRState *RegionStoreManager::setImplicitDefaultValue(const GRState *state, else { return state; } - - B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default)); - return state->makeWithStore(B.getRoot()); + + return state->makeWithStore(Add(B, R, + BindingVal(V, BindingVal::Default)).getRoot()); } const GRState *RegionStoreManager::BindArray(const GRState *state, @@ -1610,8 +1674,7 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R, if (FI != FE) { Store store = state->getStore(); RegionBindings B = GetRegionBindings(store); - B = RBFactory.Add(B, R, - BindingVal(ValMgr.makeIntVal(0, false), BindingVal::Default)); + B = Add(B, R, BindingVal(ValMgr.makeIntVal(0, false), BindingVal::Default)); state = state->makeWithStore(B.getRoot()); } @@ -1625,7 +1688,7 @@ Store RegionStoreManager::KillStruct(Store store, const TypedRegion* R) { RemoveSubRegionBindings(B, R, *SubRegions); // Set the default value of the struct region to "unknown". - B = RBFactory.Add(B, R, BindingVal(UnknownVal(), BindingVal::Default)); + B = Add(B, R, BindingVal(UnknownVal(), BindingVal::Default)); return B.getRoot(); } @@ -1646,8 +1709,58 @@ RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V, // Now copy the bindings. This amounts to just binding 'V' to 'R'. This // results in a zero-copy algorithm. - return state->makeWithStore( - RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct)).getRoot()); + return state->makeWithStore(Add(B, R, + BindingVal(V, BindingVal::Direct)).getRoot()); +} + +//===----------------------------------------------------------------------===// +// "Raw" retrievals and bindings. +//===----------------------------------------------------------------------===// + +BindingKey BindingKey::Make(const MemRegion *R) { + if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { + const RegionRawOffset &O = ER->getAsRawOffset(); + + if (O.getRegion()) + return BindingKey(O.getRegion(), O.getByteOffset()); + + // FIXME: There are some ElementRegions for which we cannot compute + // raw offsets yet, including regions with symbolic offsets. + } + + return BindingKey(R, 0); +} + +RegionBindings RegionStoreManager::Add(RegionBindings B, BindingKey K, + BindingVal V) { + return RBFactory.Add(B, K, V); +} + +RegionBindings RegionStoreManager::Add(RegionBindings B, const MemRegion *R, + BindingVal V) { + return Add(B, BindingKey::Make(R), V); +} + +const BindingVal *RegionStoreManager::Lookup(RegionBindings B, BindingKey K) { + return B.lookup(K); +} + +const BindingVal *RegionStoreManager::Lookup(RegionBindings B, + const MemRegion *R) { + return Lookup(B, BindingKey::Make(R)); +} + +RegionBindings RegionStoreManager::Remove(RegionBindings B, BindingKey K) { + return RBFactory.Remove(B, K); +} + +RegionBindings RegionStoreManager::Remove(RegionBindings B, const MemRegion *R){ + return Remove(B, BindingKey::Make(R)); +} + +Store RegionStoreManager::Remove(Store store, BindingKey K) { + RegionBindings B = GetRegionBindings(store); + return Remove(B, K).getRoot(); } //===----------------------------------------------------------------------===// @@ -1674,7 +1787,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, // Scan the direct bindings for "intermediate" roots. for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) { - const MemRegion *R = I.getKey(); + const MemRegion *R = I.getKey().getRegion(); IntermediateRoots.push_back(R); } @@ -1831,13 +1944,13 @@ tryAgain: // as live. We now remove all the regions that are dead from the store // as well as update DSymbols with the set symbols that are now dead. for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) { - const MemRegion* R = I.getKey(); + const MemRegion* R = I.getKey().getRegion(); // If this region live? Is so, none of its symbols are dead. if (Visited.count(std::make_pair(&state, R))) continue; // Remove this dead region from the store. - store = Remove(store, ValMgr.makeLoc(R)); + store = Remove(store, I.getKey()); // Mark all non-live symbols that this region references as dead. if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R)) diff --git a/lib/Analysis/ReturnStackAddressChecker.cpp b/lib/Analysis/ReturnStackAddressChecker.cpp index 3a6d8a4..4d7e8ad 100644 --- a/lib/Analysis/ReturnStackAddressChecker.cpp +++ b/lib/Analysis/ReturnStackAddressChecker.cpp @@ -67,6 +67,9 @@ void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C, llvm::raw_svector_ostream os(buf); SourceRange range; + // Get the base region, stripping away fields and elements. + R = R->getBaseRegion(); + // Check if the region is a compound literal. if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) { const CompoundLiteralExpr* CL = CR->getLiteralExpr(); @@ -92,13 +95,18 @@ void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C, << C.getSourceManager().getInstantiationLineNumber(L) << " returned to caller"; } - else { + else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { os << "Address of stack memory associated with local variable '" - << R->getString() << "' returned."; + << VR->getString() << "' returned"; + range = VR->getDecl()->getSourceRange(); + } + else { + assert(false && "Invalid region in ReturnStackAddressChecker."); + return; } RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); - report->addRange(RS->getSourceRange()); + report->addRange(RetE->getSourceRange()); if (range.isValid()) report->addRange(range); diff --git a/lib/Analysis/SVals.cpp b/lib/Analysis/SVals.cpp index 9163b27..fbdb73b 100644 --- a/lib/Analysis/SVals.cpp +++ b/lib/Analysis/SVals.cpp @@ -97,6 +97,10 @@ const MemRegion *SVal::getAsRegion() const { if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this)) return X->getRegion(); + if (const nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(this)) { + return X->getLoc().getAsRegion(); + } + return 0; } diff --git a/lib/Analysis/SValuator.cpp b/lib/Analysis/SValuator.cpp index 49bc0c4..8392fcf 100644 --- a/lib/Analysis/SValuator.cpp +++ b/lib/Analysis/SValuator.cpp @@ -62,8 +62,12 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state, ASTContext &C = ValMgr.getContext(); // For const casts, just propagate the value. - if (C.hasSameUnqualifiedType(castTy, originalTy)) - return CastResult(state, val); + if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType()) + if (C.hasSameUnqualifiedType(castTy, originalTy)) + return CastResult(state, val); + + if (castTy->isIntegerType() && originalTy->isIntegerType()) + return CastResult(state, EvalCastNL(cast<NonLoc>(val), castTy)); // Check for casts from pointers to integers. if (castTy->isIntegerType() && Loc::IsLocType(originalTy)) diff --git a/lib/Analysis/SimpleConstraintManager.cpp b/lib/Analysis/SimpleConstraintManager.cpp index 23c3b41..eca20d5 100644 --- a/lib/Analysis/SimpleConstraintManager.cpp +++ b/lib/Analysis/SimpleConstraintManager.cpp @@ -65,25 +65,10 @@ const GRState *SimpleConstraintManager::Assume(const GRState *state, return Assume(state, cast<Loc>(Cond), Assumption); } -const GRState *SimpleConstraintManager::Assume(const GRState *state, Loc Cond, - bool Assumption) { - - state = AssumeAux(state, Cond, Assumption); - - // EvalAssume is used to call into the GRTransferFunction object to perform - // any checker-specific update of the state based on this assumption being - // true or false. - - if (!state) - return 0; - - std::vector<std::pair<void *, Checker*> >::iterator - I = state->checker_begin(), E = state->checker_end(); - - for (; I != E; ++I) { - state = I->second->EvalAssume(state, Cond, Assumption); - } - return state->getTransferFuncs().EvalAssume(state, Cond, Assumption); +const GRState *SimpleConstraintManager::Assume(const GRState *state, Loc cond, + bool assumption) { + state = AssumeAux(state, cond, assumption); + return SU.ProcessAssume(state, cond, assumption); } const GRState *SimpleConstraintManager::AssumeAux(const GRState *state, @@ -130,26 +115,10 @@ const GRState *SimpleConstraintManager::AssumeAux(const GRState *state, } const GRState *SimpleConstraintManager::Assume(const GRState *state, - NonLoc Cond, - bool Assumption) { - - state = AssumeAux(state, Cond, Assumption); - - // EvalAssume is used to call into the GRTransferFunction object to perform - // any checker-specific update of the state based on this assumption being - // true or false. - - if (!state) - return 0; - - std::vector<std::pair<void *, Checker*> >::iterator - I = state->checker_begin(), E = state->checker_end(); - - for (; I != E; ++I) { - state = I->second->EvalAssume(state, Cond, Assumption); - } - - return state->getTransferFuncs().EvalAssume(state, Cond, Assumption); + NonLoc cond, + bool assumption) { + state = AssumeAux(state, cond, assumption); + return SU.ProcessAssume(state, cond, assumption); } const GRState *SimpleConstraintManager::AssumeAux(const GRState *state, diff --git a/lib/Analysis/SimpleConstraintManager.h b/lib/Analysis/SimpleConstraintManager.h index 0c58440..8182398 100644 --- a/lib/Analysis/SimpleConstraintManager.h +++ b/lib/Analysis/SimpleConstraintManager.h @@ -20,8 +20,9 @@ namespace clang { class SimpleConstraintManager : public ConstraintManager { + GRSubEngine &SU; public: - SimpleConstraintManager() {} + SimpleConstraintManager(GRSubEngine &subengine) : SU(subengine) {} virtual ~SimpleConstraintManager(); //===------------------------------------------------------------------===// diff --git a/lib/Analysis/SimpleSValuator.cpp b/lib/Analysis/SimpleSValuator.cpp index 2afcd3e..8f2f5a1 100644 --- a/lib/Analysis/SimpleSValuator.cpp +++ b/lib/Analysis/SimpleSValuator.cpp @@ -53,13 +53,13 @@ SVal SimpleSValuator::EvalCastNL(NonLoc val, QualType castTy) { if (isLocType) return LI->getLoc(); + // FIXME: Correctly support promotions/truncations. ASTContext &Ctx = ValMgr.getContext(); - - // FIXME: Support promotions/truncations. - if (Ctx.getTypeSize(castTy) == Ctx.getTypeSize(Ctx.VoidPtrTy)) + unsigned castSize = Ctx.getTypeSize(castTy); + if (castSize == LI->getNumBits()) return val; - return UnknownVal(); + return ValMgr.makeLocAsInteger(LI->getLoc(), castSize); } if (const SymExpr *se = val.getAsSymbolicExpression()) { diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp index 8d911b8..1724a92 100644 --- a/lib/Analysis/Store.cpp +++ b/lib/Analysis/Store.cpp @@ -13,6 +13,7 @@ #include "clang/Analysis/PathSensitive/Store.h" #include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/AST/CharUnits.h" using namespace clang; @@ -77,6 +78,7 @@ 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::CXXThisRegionKind: case MemRegion::GenericMemSpaceRegionKind: case MemRegion::StackLocalsSpaceRegionKind: case MemRegion::StackArgumentsSpaceRegionKind: @@ -137,9 +139,9 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) if (!baseR) return NULL; - int64_t off = rawOff.getByteOffset(); + CharUnits off = CharUnits::fromQuantity(rawOff.getByteOffset()); - if (off == 0) { + if (off.isZero()) { // Edge case: we are at 0 bytes off the beginning of baseR. We // check to see if type we are casting to is the same as the base // region. If so, just return the base region. @@ -167,7 +169,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) // We can only compute sizeof(PointeeTy) if it is a complete type. if (IsCompleteType(Ctx, PointeeTy)) { // Compute the size in **bytes**. - int64_t pointeeTySize = (int64_t) (Ctx.getTypeSize(PointeeTy) / 8); + CharUnits pointeeTySize = Ctx.getTypeSizeInChars(PointeeTy); // Is the offset a multiple of the size? If so, we can layer the // ElementRegion (with elementType == PointeeTy) directly on top of @@ -181,7 +183,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) if (!newSuperR) { // Create an intermediate ElementRegion to represent the raw byte. // This will be the super region of the final ElementRegion. - newSuperR = MakeElementRegion(baseR, Ctx.CharTy, off); + newSuperR = MakeElementRegion(baseR, Ctx.CharTy, off.getQuantity()); } return MakeElementRegion(newSuperR, PointeeTy, newIndex); @@ -196,23 +198,29 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) /// CastRetrievedVal - Used by subclasses of StoreManager to implement /// implicit casts that arise from loads from regions that are reinterpreted /// as another region. -SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R, - QualType castTy) { +SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R, + QualType castTy, bool performTestOnly) { -#ifndef NDEBUG if (castTy.isNull()) return V; ASTContext &Ctx = ValMgr.getContext(); - QualType T = R->getValueType(Ctx); - - // Automatically translate references to pointers. - if (const ReferenceType *RT = T->getAs<ReferenceType>()) - T = Ctx.getPointerType(RT->getPointeeType()); - - assert(ValMgr.getContext().hasSameUnqualifiedType(castTy, T)); -#endif + if (performTestOnly) { + // Automatically translate references to pointers. + QualType T = R->getValueType(Ctx); + if (const ReferenceType *RT = T->getAs<ReferenceType>()) + T = Ctx.getPointerType(RT->getPointeeType()); + + assert(ValMgr.getContext().hasSameUnqualifiedType(castTy, T)); + return V; + } + + if (const Loc *L = dyn_cast<Loc>(&V)) + return ValMgr.getSValuator().EvalCastL(*L, castTy); + else if (const NonLoc *NL = dyn_cast<NonLoc>(&V)) + return ValMgr.getSValuator().EvalCastNL(*NL, castTy); + return V; } @@ -240,8 +248,3 @@ SVal StoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL, const LocationContext *LC) { return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)); } - -Loc StoreManager::getThisObject(QualType T) { - const CXXObjectRegion *R = MRMgr.getCXXObjectRegion(T); - return loc::MemRegionVal(R); -} diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 4351f66..abbf6f9 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -541,19 +541,46 @@ static bool ModifierIs(const char *Modifier, unsigned ModifierLen, return StrLen-1 == ModifierLen && !memcmp(Modifier, Str, StrLen-1); } +/// ScanForward - Scans forward, looking for the given character, skipping +/// nested clauses and escaped characters. +static const char *ScanFormat(const char *I, const char *E, char Target) { + unsigned Depth = 0; + + for ( ; I != E; ++I) { + if (Depth == 0 && *I == Target) return I; + if (Depth != 0 && *I == '}') Depth--; + + if (*I == '%') { + I++; + if (I == E) break; + + // Escaped characters get implicitly skipped here. + + // Format specifier. + if (!isdigit(*I) && !ispunct(*I)) { + for (I++; I != E && !isdigit(*I) && *I != '{'; I++) ; + if (I == E) break; + if (*I == '{') + Depth++; + } + } + } + return E; +} + /// HandleSelectModifier - Handle the integer 'select' modifier. This is used /// like this: %select{foo|bar|baz}2. This means that the integer argument /// "%2" has a value from 0-2. If the value is 0, the diagnostic prints 'foo'. /// If the value is 1, it prints 'bar'. If it has the value 2, it prints 'baz'. /// This is very useful for certain classes of variant diagnostics. -static void HandleSelectModifier(unsigned ValNo, +static void HandleSelectModifier(const DiagnosticInfo &DInfo, unsigned ValNo, const char *Argument, unsigned ArgumentLen, llvm::SmallVectorImpl<char> &OutStr) { const char *ArgumentEnd = Argument+ArgumentLen; // Skip over 'ValNo' |'s. while (ValNo) { - const char *NextVal = std::find(Argument, ArgumentEnd, '|'); + const char *NextVal = ScanFormat(Argument, ArgumentEnd, '|'); assert(NextVal != ArgumentEnd && "Value for integer select modifier was" " larger than the number of options in the diagnostic string!"); Argument = NextVal+1; // Skip this string. @@ -561,9 +588,10 @@ static void HandleSelectModifier(unsigned ValNo, } // Get the end of the value. This is either the } or the |. - const char *EndPtr = std::find(Argument, ArgumentEnd, '|'); - // Add the value to the output string. - OutStr.append(Argument, EndPtr); + const char *EndPtr = ScanFormat(Argument, ArgumentEnd, '|'); + + // Recursively format the result of the select clause into the output string. + DInfo.FormatDiagnostic(Argument, EndPtr, OutStr); } /// HandleIntegerSModifier - Handle the integer 's' modifier. This adds the @@ -575,6 +603,37 @@ static void HandleIntegerSModifier(unsigned ValNo, OutStr.push_back('s'); } +/// HandleOrdinalModifier - Handle the integer 'ord' modifier. This +/// prints the ordinal form of the given integer, with 1 corresponding +/// to the first ordinal. Currently this is hard-coded to use the +/// English form. +static void HandleOrdinalModifier(unsigned ValNo, + llvm::SmallVectorImpl<char> &OutStr) { + assert(ValNo != 0 && "ValNo must be strictly positive!"); + + llvm::raw_svector_ostream Out(OutStr); + + // We could use text forms for the first N ordinals, but the numeric + // forms are actually nicer in diagnostics because they stand out. + Out << ValNo; + + // It is critically important that we do this perfectly for + // user-written sequences with over 100 elements. + switch (ValNo % 100) { + case 11: + case 12: + case 13: + Out << "th"; return; + default: + switch (ValNo % 10) { + case 1: Out << "st"; return; + case 2: Out << "nd"; return; + case 3: Out << "rd"; return; + default: Out << "th"; return; + } + } +} + /// PluralNumber - Parse an unsigned integer and advance Start. static unsigned PluralNumber(const char *&Start, const char *End) { @@ -685,11 +744,11 @@ static void HandlePluralModifier(unsigned ValNo, } if (EvalPluralExpr(ValNo, Argument, ExprEnd)) { Argument = ExprEnd + 1; - ExprEnd = std::find(Argument, ArgumentEnd, '|'); + ExprEnd = ScanFormat(Argument, ArgumentEnd, '|'); OutStr.append(Argument, ExprEnd); return; } - Argument = std::find(Argument, ArgumentEnd - 1, '|') + 1; + Argument = ScanFormat(Argument, ArgumentEnd - 1, '|') + 1; } } @@ -702,6 +761,13 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { const char *DiagStr = getDiags()->getDescription(getID()); const char *DiagEnd = DiagStr+strlen(DiagStr); + FormatDiagnostic(DiagStr, DiagEnd, OutStr); +} + +void DiagnosticInfo:: +FormatDiagnostic(const char *DiagStr, const char *DiagEnd, + llvm::SmallVectorImpl<char> &OutStr) const { + /// FormattedArgs - Keep track of all of the arguments formatted by /// ConvertArgToString and pass them into subsequent calls to /// ConvertArgToString, allowing the implementation to avoid redundancies in @@ -715,8 +781,8 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { OutStr.append(DiagStr, StrEnd); DiagStr = StrEnd; continue; - } else if (DiagStr[1] == '%') { - OutStr.push_back('%'); // %% -> %. + } else if (ispunct(DiagStr[1])) { + OutStr.push_back(DiagStr[1]); // %% -> %. DiagStr += 2; continue; } @@ -745,8 +811,8 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { ++DiagStr; // Skip {. Argument = DiagStr; - for (; DiagStr[0] != '}'; ++DiagStr) - assert(DiagStr[0] && "Mismatched {}'s in diagnostic string!"); + DiagStr = ScanFormat(DiagStr, DiagEnd, '}'); + assert(DiagStr != DiagEnd && "Mismatched {}'s in diagnostic string!"); ArgumentLen = DiagStr-Argument; ++DiagStr; // Skip }. } @@ -781,11 +847,13 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { int Val = getArgSInt(ArgNo); if (ModifierIs(Modifier, ModifierLen, "select")) { - HandleSelectModifier((unsigned)Val, Argument, ArgumentLen, OutStr); + HandleSelectModifier(*this, (unsigned)Val, Argument, ArgumentLen, OutStr); } else if (ModifierIs(Modifier, ModifierLen, "s")) { HandleIntegerSModifier(Val, OutStr); } else if (ModifierIs(Modifier, ModifierLen, "plural")) { HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr); + } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) { + HandleOrdinalModifier((unsigned)Val, OutStr); } else { assert(ModifierLen == 0 && "Unknown integer modifier"); llvm::raw_svector_ostream(OutStr) << Val; @@ -796,11 +864,13 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { unsigned Val = getArgUInt(ArgNo); if (ModifierIs(Modifier, ModifierLen, "select")) { - HandleSelectModifier(Val, Argument, ArgumentLen, OutStr); + HandleSelectModifier(*this, Val, Argument, ArgumentLen, OutStr); } else if (ModifierIs(Modifier, ModifierLen, "s")) { HandleIntegerSModifier(Val, OutStr); } else if (ModifierIs(Modifier, ModifierLen, "plural")) { HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr); + } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) { + HandleOrdinalModifier(Val, OutStr); } else { assert(ModifierLen == 0 && "Unknown integer modifier"); llvm::raw_svector_ostream(OutStr) << Val; diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index b6b5c6c..bba2c3f 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -18,51 +18,38 @@ #include "clang/Basic/LangOptions.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetOptions.h" +#include "clang/Frontend/Utils.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/MC/MCSectionMachO.h" +#include <algorithm> using namespace clang; //===----------------------------------------------------------------------===// // Common code shared among targets. //===----------------------------------------------------------------------===// -static void Define(std::vector<char> &Buf, const llvm::StringRef &Macro, - const llvm::StringRef &Val = "1") { - const char *Def = "#define "; - Buf.insert(Buf.end(), Def, Def+strlen(Def)); - Buf.insert(Buf.end(), Macro.begin(), Macro.end()); - Buf.push_back(' '); - Buf.insert(Buf.end(), Val.begin(), Val.end()); - Buf.push_back('\n'); -} - /// DefineStd - Define a macro name and standard variants. For example if /// MacroName is "unix", then this will define "__unix", "__unix__", and "unix" /// when in GNU mode. -static void DefineStd(std::vector<char> &Buf, const char *MacroName, +static void DefineStd(MacroBuilder &Builder, llvm::StringRef MacroName, const LangOptions &Opts) { assert(MacroName[0] != '_' && "Identifier should be in the user's namespace"); // If in GNU mode (e.g. -std=gnu99 but not -std=c99) define the raw identifier // in the user's namespace. if (Opts.GNUMode) - Define(Buf, MacroName); + Builder.defineMacro(MacroName); // Define __unix. - llvm::SmallString<20> TmpStr; - TmpStr = "__"; - TmpStr += MacroName; - Define(Buf, TmpStr.str()); + Builder.defineMacro("__" + MacroName); // Define __unix__. - TmpStr += "__"; - Define(Buf, TmpStr.str()); + Builder.defineMacro("__" + MacroName + "__"); } //===----------------------------------------------------------------------===// @@ -74,44 +61,44 @@ template<typename TgtInfo> class OSTargetInfo : public TgtInfo { protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - std::vector<char> &Defines) const=0; + MacroBuilder &Builder) const=0; public: OSTargetInfo(const std::string& triple) : TgtInfo(triple) {} virtual void getTargetDefines(const LangOptions &Opts, - std::vector<char> &Defines) const { - TgtInfo::getTargetDefines(Opts, Defines); - getOSDefines(Opts, TgtInfo::getTriple(), Defines); + MacroBuilder &Builder) const { + TgtInfo::getTargetDefines(Opts, Builder); + getOSDefines(Opts, TgtInfo::getTriple(), Builder); } }; } // end anonymous namespace -static void getDarwinDefines(std::vector<char> &Defs, const LangOptions &Opts) { - Define(Defs, "__APPLE_CC__", "5621"); - Define(Defs, "__APPLE__"); - Define(Defs, "__MACH__"); - Define(Defs, "OBJC_NEW_PROPERTIES"); +static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts) { + Builder.defineMacro("__APPLE_CC__", "5621"); + Builder.defineMacro("__APPLE__"); + Builder.defineMacro("__MACH__"); + Builder.defineMacro("OBJC_NEW_PROPERTIES"); // __weak is always defined, for use in blocks and with objc pointers. - Define(Defs, "__weak", "__attribute__((objc_gc(weak)))"); + Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))"); // Darwin defines __strong even in C mode (just to nothing). if (!Opts.ObjC1 || Opts.getGCMode() == LangOptions::NonGC) - Define(Defs, "__strong", ""); + Builder.defineMacro("__strong", ""); else - Define(Defs, "__strong", "__attribute__((objc_gc(strong)))"); + Builder.defineMacro("__strong", "__attribute__((objc_gc(strong)))"); if (Opts.Static) - Define(Defs, "__STATIC__"); + Builder.defineMacro("__STATIC__"); else - Define(Defs, "__DYNAMIC__"); + Builder.defineMacro("__DYNAMIC__"); if (Opts.POSIXThreads) - Define(Defs, "_REENTRANT", "1"); + Builder.defineMacro("_REENTRANT"); } -static void getDarwinOSXDefines(std::vector<char> &Defs, +static void getDarwinOSXDefines(MacroBuilder &Builder, const llvm::Triple &Triple) { if (Triple.getOS() != llvm::Triple::Darwin) return; @@ -129,10 +116,11 @@ static void getDarwinOSXDefines(std::vector<char> &Defs, // Handle minor version: 10.4.9 -> darwin8.9 -> "1049" // Cap 10.4.11 -> darwin8.11 -> "1049" MacOSXStr[3] = std::min(Min, 9U)+'0'; - Define(Defs, "__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", MacOSXStr); + Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", + MacOSXStr); } -static void getDarwinIPhoneOSDefines(std::vector<char> &Defs, +static void getDarwinIPhoneOSDefines(MacroBuilder &Builder, const llvm::Triple &Triple) { if (Triple.getOS() != llvm::Triple::Darwin) return; @@ -151,8 +139,8 @@ static void getDarwinIPhoneOSDefines(std::vector<char> &Defs, // Handle minor version: 2.2 -> darwin9.2.2 -> 20200 iPhoneOSStr[2] = std::min(Rev, 9U)+'0'; - Define(Defs, "__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", - iPhoneOSStr); + Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", + iPhoneOSStr); } namespace { @@ -160,9 +148,9 @@ template<typename Target> class DarwinTargetInfo : public OSTargetInfo<Target> { protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - std::vector<char> &Defines) const { - getDarwinDefines(Defines, Opts); - getDarwinOSXDefines(Defines, Triple); + MacroBuilder &Builder) const { + getDarwinDefines(Builder, Opts); + getDarwinOSXDefines(Builder, Triple); } public: @@ -190,14 +178,14 @@ template<typename Target> class DragonFlyBSDTargetInfo : public OSTargetInfo<Target> { protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - std::vector<char> &Defs) const { + MacroBuilder &Builder) const { // DragonFly defines; list based off of gcc output - Define(Defs, "__DragonFly__"); - Define(Defs, "__DragonFly_cc_version", "100001"); - Define(Defs, "__ELF__"); - Define(Defs, "__KPRINTF_ATTRIBUTE__"); - Define(Defs, "__tune_i386__"); - DefineStd(Defs, "unix", Opts); + Builder.defineMacro("__DragonFly__"); + Builder.defineMacro("__DragonFly_cc_version", "100001"); + Builder.defineMacro("__ELF__"); + Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); + Builder.defineMacro("__tune_i386__"); + DefineStd(Builder, "unix", Opts); } public: DragonFlyBSDTargetInfo(const std::string &triple) @@ -209,7 +197,7 @@ template<typename Target> class FreeBSDTargetInfo : public OSTargetInfo<Target> { protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - std::vector<char> &Defs) const { + MacroBuilder &Builder) const { // FreeBSD defines; list based off of gcc output // FIXME: Move version number handling to llvm::Triple. @@ -221,11 +209,11 @@ protected: char version[] = "X00001"; version[0] = FreeBSD[0]; - Define(Defs, "__FreeBSD__", release); - Define(Defs, "__FreeBSD_cc_version", version); - Define(Defs, "__KPRINTF_ATTRIBUTE__"); - DefineStd(Defs, "unix", Opts); - Define(Defs, "__ELF__", "1"); + Builder.defineMacro("__FreeBSD__", release); + Builder.defineMacro("__FreeBSD_cc_version", version); + Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__ELF__"); } public: FreeBSDTargetInfo(const std::string &triple) @@ -239,14 +227,14 @@ template<typename Target> class LinuxTargetInfo : public OSTargetInfo<Target> { protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - std::vector<char> &Defs) const { + MacroBuilder &Builder) const { // Linux defines; list based off of gcc output - DefineStd(Defs, "unix", Opts); - DefineStd(Defs, "linux", Opts); - Define(Defs, "__gnu_linux__"); - Define(Defs, "__ELF__", "1"); + DefineStd(Builder, "unix", Opts); + DefineStd(Builder, "linux", Opts); + Builder.defineMacro("__gnu_linux__"); + Builder.defineMacro("__ELF__"); if (Opts.POSIXThreads) - Define(Defs, "_REENTRANT", "1"); + Builder.defineMacro("_REENTRANT"); } public: LinuxTargetInfo(const std::string& triple) @@ -260,13 +248,13 @@ template<typename Target> class NetBSDTargetInfo : public OSTargetInfo<Target> { protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - std::vector<char> &Defs) const { + MacroBuilder &Builder) const { // NetBSD defines; list based off of gcc output - Define(Defs, "__NetBSD__", "1"); - Define(Defs, "__unix__", "1"); - Define(Defs, "__ELF__", "1"); + Builder.defineMacro("__NetBSD__"); + Builder.defineMacro("__unix__"); + Builder.defineMacro("__ELF__"); if (Opts.POSIXThreads) - Define(Defs, "_POSIX_THREADS", "1"); + Builder.defineMacro("_POSIX_THREADS"); } public: NetBSDTargetInfo(const std::string &triple) @@ -280,14 +268,14 @@ template<typename Target> class OpenBSDTargetInfo : public OSTargetInfo<Target> { protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - std::vector<char> &Defs) const { + MacroBuilder &Builder) const { // OpenBSD defines; list based off of gcc output - Define(Defs, "__OpenBSD__", "1"); - DefineStd(Defs, "unix", Opts); - Define(Defs, "__ELF__", "1"); + Builder.defineMacro("__OpenBSD__"); + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__ELF__"); if (Opts.POSIXThreads) - Define(Defs, "_POSIX_THREADS", "1"); + Builder.defineMacro("_POSIX_THREADS"); } public: OpenBSDTargetInfo(const std::string &triple) @@ -299,12 +287,12 @@ template<typename Target> class PSPTargetInfo : public OSTargetInfo<Target> { protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - std::vector<char> &Defs) const { + MacroBuilder &Builder) const { // PSP defines; list based on the output of the pspdev gcc toolchain. - Define(Defs, "PSP", "1"); - Define(Defs, "_PSP", "1"); - Define(Defs, "__psp__", "1"); - Define(Defs, "__ELF__", "1"); + Builder.defineMacro("PSP"); + Builder.defineMacro("_PSP"); + Builder.defineMacro("__psp__"); + Builder.defineMacro("__ELF__"); } public: PSPTargetInfo(const std::string& triple) @@ -318,12 +306,12 @@ template<typename Target> class PS3PPUTargetInfo : public OSTargetInfo<Target> { protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - std::vector<char> &Defs) const { + MacroBuilder &Builder) const { // PS3 PPU defines. - Define(Defs, "__PPU__", "1"); - Define(Defs, "__CELLOS_LV2__", "1"); - Define(Defs, "__ELF__", "1"); - Define(Defs, "__LP32__", "1"); + Builder.defineMacro("__PPU__"); + Builder.defineMacro("__CELLOS_LV2__"); + Builder.defineMacro("__ELF__"); + Builder.defineMacro("__LP32__"); } public: PS3PPUTargetInfo(const std::string& triple) @@ -340,10 +328,10 @@ template<typename Target> class PS3SPUTargetInfo : public OSTargetInfo<Target> { protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - std::vector<char> &Defs) const { + MacroBuilder &Builder) const { // PS3 PPU defines. - Define(Defs, "__SPU__", "1"); - Define(Defs, "__ELF__", "1"); + Builder.defineMacro("__SPU__"); + Builder.defineMacro("__ELF__"); } public: PS3SPUTargetInfo(const std::string& triple) @@ -357,12 +345,12 @@ template<typename Target> class AuroraUXTargetInfo : public OSTargetInfo<Target> { protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - std::vector<char> &Defs) const { - DefineStd(Defs, "sun", Opts); - DefineStd(Defs, "unix", Opts); - Define(Defs, "__ELF__"); - Define(Defs, "__svr4__"); - Define(Defs, "__SVR4"); + MacroBuilder &Builder) const { + DefineStd(Builder, "sun", Opts); + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__ELF__"); + Builder.defineMacro("__svr4__"); + Builder.defineMacro("__SVR4"); } public: AuroraUXTargetInfo(const std::string& triple) @@ -378,12 +366,12 @@ template<typename Target> class SolarisTargetInfo : public OSTargetInfo<Target> { protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - std::vector<char> &Defs) const { - DefineStd(Defs, "sun", Opts); - DefineStd(Defs, "unix", Opts); - Define(Defs, "__ELF__"); - Define(Defs, "__svr4__"); - Define(Defs, "__SVR4"); + MacroBuilder &Builder) const { + DefineStd(Builder, "sun", Opts); + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__ELF__"); + Builder.defineMacro("__svr4__"); + Builder.defineMacro("__SVR4"); } public: SolarisTargetInfo(const std::string& triple) @@ -416,7 +404,7 @@ public: } virtual void getTargetDefines(const LangOptions &Opts, - std::vector<char> &Defines) const; + MacroBuilder &Builder) const; virtual const char *getVAListDeclaration() const { return "typedef char* __builtin_va_list;"; @@ -460,34 +448,34 @@ const Builtin::Info PPCTargetInfo::BuiltinInfo[] = { /// PPCTargetInfo::getTargetDefines - Return a set of the PowerPC-specific /// #defines that are not tied to a specific subtarget. void PPCTargetInfo::getTargetDefines(const LangOptions &Opts, - std::vector<char> &Defs) const { + MacroBuilder &Builder) const { // Target identification. - Define(Defs, "__ppc__"); - Define(Defs, "_ARCH_PPC"); - Define(Defs, "__POWERPC__"); + Builder.defineMacro("__ppc__"); + Builder.defineMacro("_ARCH_PPC"); + Builder.defineMacro("__POWERPC__"); if (PointerWidth == 64) { - Define(Defs, "_ARCH_PPC64"); - Define(Defs, "_LP64"); - Define(Defs, "__LP64__"); - Define(Defs, "__ppc64__"); + Builder.defineMacro("_ARCH_PPC64"); + Builder.defineMacro("_LP64"); + Builder.defineMacro("__LP64__"); + Builder.defineMacro("__ppc64__"); } else { - Define(Defs, "__ppc__"); + Builder.defineMacro("__ppc__"); } // Target properties. - Define(Defs, "_BIG_ENDIAN"); - Define(Defs, "__BIG_ENDIAN__"); + Builder.defineMacro("_BIG_ENDIAN"); + Builder.defineMacro("__BIG_ENDIAN__"); // Subtarget options. - Define(Defs, "__NATURAL_ALIGNMENT__"); - Define(Defs, "__REGISTER_PREFIX__", ""); + Builder.defineMacro("__NATURAL_ALIGNMENT__"); + Builder.defineMacro("__REGISTER_PREFIX__", ""); // FIXME: Should be controlled by command line option. - Define(Defs, "__LONG_DOUBLE_128__"); + Builder.defineMacro("__LONG_DOUBLE_128__"); if (Opts.AltiVec) { - Define(Defs, "__VEC__", "10206"); - Define(Defs, "__ALTIVEC__", "1"); + Builder.defineMacro("__VEC__", "10206"); + Builder.defineMacro("__ALTIVEC__"); } } @@ -682,7 +670,7 @@ public: return "~{dirflag},~{fpsr},~{flags}"; } virtual void getTargetDefines(const LangOptions &Opts, - std::vector<char> &Defines) const; + MacroBuilder &Builder) const; virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features, const std::string &Name, bool Enabled) const; @@ -828,51 +816,51 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) { /// X86TargetInfo::getTargetDefines - Return a set of the X86-specific #defines /// that are not tied to a specific subtarget. void X86TargetInfo::getTargetDefines(const LangOptions &Opts, - std::vector<char> &Defs) const { + MacroBuilder &Builder) const { // Target identification. if (PointerWidth == 64) { - Define(Defs, "_LP64"); - Define(Defs, "__LP64__"); - Define(Defs, "__amd64__"); - Define(Defs, "__amd64"); - Define(Defs, "__x86_64"); - Define(Defs, "__x86_64__"); + Builder.defineMacro("_LP64"); + Builder.defineMacro("__LP64__"); + Builder.defineMacro("__amd64__"); + Builder.defineMacro("__amd64"); + Builder.defineMacro("__x86_64"); + Builder.defineMacro("__x86_64__"); } else { - DefineStd(Defs, "i386", Opts); + DefineStd(Builder, "i386", Opts); } // Target properties. - Define(Defs, "__LITTLE_ENDIAN__"); + Builder.defineMacro("__LITTLE_ENDIAN__"); // Subtarget options. - Define(Defs, "__nocona"); - Define(Defs, "__nocona__"); - Define(Defs, "__tune_nocona__"); - Define(Defs, "__REGISTER_PREFIX__", ""); + Builder.defineMacro("__nocona"); + Builder.defineMacro("__nocona__"); + Builder.defineMacro("__tune_nocona__"); + Builder.defineMacro("__REGISTER_PREFIX__", ""); // Define __NO_MATH_INLINES on linux/x86 so that we don't get inline // functions in glibc header files that use FP Stack inline asm which the // backend can't deal with (PR879). - Define(Defs, "__NO_MATH_INLINES"); + Builder.defineMacro("__NO_MATH_INLINES"); // Each case falls through to the previous one here. switch (SSELevel) { case SSE42: - Define(Defs, "__SSE4_2__"); + Builder.defineMacro("__SSE4_2__"); case SSE41: - Define(Defs, "__SSE4_1__"); + Builder.defineMacro("__SSE4_1__"); case SSSE3: - Define(Defs, "__SSSE3__"); + Builder.defineMacro("__SSSE3__"); case SSE3: - Define(Defs, "__SSE3__"); + Builder.defineMacro("__SSE3__"); case SSE2: - Define(Defs, "__SSE2__"); - Define(Defs, "__SSE2_MATH__"); // -mfp-math=sse always implied. + Builder.defineMacro("__SSE2__"); + Builder.defineMacro("__SSE2_MATH__"); // -mfp-math=sse always implied. case SSE1: - Define(Defs, "__SSE__"); - Define(Defs, "__SSE_MATH__"); // -mfp-math=sse always implied. + Builder.defineMacro("__SSE__"); + Builder.defineMacro("__SSE_MATH__"); // -mfp-math=sse always implied. case MMX: - Define(Defs, "__MMX__"); + Builder.defineMacro("__MMX__"); case NoMMXSSE: break; } @@ -999,13 +987,13 @@ public: "v128:128:128-a0:0:64-f80:32:32-n8:16:32"; } virtual void getTargetDefines(const LangOptions &Opts, - std::vector<char> &Defines) const { - X86_32TargetInfo::getTargetDefines(Opts, Defines); + MacroBuilder &Builder) const { + X86_32TargetInfo::getTargetDefines(Opts, Builder); // This list is based off of the the list of things MingW defines - Define(Defines, "_WIN32"); - DefineStd(Defines, "WIN32", Opts); - DefineStd(Defines, "WINNT", Opts); - Define(Defines, "_X86_"); + Builder.defineMacro("_WIN32"); + DefineStd(Builder, "WIN32", Opts); + DefineStd(Builder, "WINNT", Opts); + Builder.defineMacro("_X86_"); } }; } // end anonymous namespace @@ -1019,12 +1007,12 @@ public: : WindowsX86_32TargetInfo(triple) { } virtual void getTargetDefines(const LangOptions &Opts, - std::vector<char> &Defines) const { - WindowsX86_32TargetInfo::getTargetDefines(Opts, Defines); + MacroBuilder &Builder) const { + WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder); // The value of the following reflects processor type. // 300=386, 400=486, 500=Pentium, 600=Blend (default) // We lost the original triple, so we use the default. - Define(Defines, "_M_IX86", "600"); + Builder.defineMacro("_M_IX86", "600"); } }; } // end anonymous namespace @@ -1037,11 +1025,11 @@ public: : WindowsX86_32TargetInfo(triple) { } virtual void getTargetDefines(const LangOptions &Opts, - std::vector<char> &Defines) const { - WindowsX86_32TargetInfo::getTargetDefines(Opts, Defines); - Define(Defines, "__MSVCRT__"); - Define(Defines, "__MINGW32__"); - Define(Defines, "__declspec", "__declspec"); + MacroBuilder &Builder) const { + WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__MSVCRT__"); + Builder.defineMacro("__MINGW32__"); + Builder.defineMacro("__declspec", "__declspec"); } }; } // end anonymous namespace @@ -1060,11 +1048,11 @@ public: "a0:0:64-f80:32:32-n8:16:32"; } virtual void getTargetDefines(const LangOptions &Opts, - std::vector<char> &Defines) const { - X86_32TargetInfo::getTargetDefines(Opts, Defines); - Define(Defines, "__CYGWIN__"); - Define(Defines, "__CYGWIN32__"); - DefineStd(Defines, "unix", Opts); + MacroBuilder &Builder) const { + X86_32TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__CYGWIN__"); + Builder.defineMacro("__CYGWIN32__"); + DefineStd(Builder, "unix", Opts); } }; } // end anonymous namespace @@ -1116,10 +1104,10 @@ public: DoubleAlign = LongLongAlign = 64; } virtual void getTargetDefines(const LangOptions &Opts, - std::vector<char> &Defines) const { - X86_64TargetInfo::getTargetDefines(Opts, Defines); - Define(Defines, "_WIN64"); - DefineStd(Defines, "WIN64", Opts); + MacroBuilder &Builder) const { + X86_64TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("_WIN64"); + DefineStd(Builder, "WIN64", Opts); } }; } // end anonymous namespace @@ -1132,9 +1120,9 @@ public: : WindowsX86_64TargetInfo(triple) { } virtual void getTargetDefines(const LangOptions &Opts, - std::vector<char> &Defines) const { - WindowsX86_64TargetInfo::getTargetDefines(Opts, Defines); - Define(Defines, "_M_X64"); + MacroBuilder &Builder) const { + WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("_M_X64"); } virtual const char *getVAListDeclaration() const { return "typedef char* va_list;"; @@ -1150,11 +1138,11 @@ public: : WindowsX86_64TargetInfo(triple) { } virtual void getTargetDefines(const LangOptions &Opts, - std::vector<char> &Defines) const { - WindowsX86_64TargetInfo::getTargetDefines(Opts, Defines); - Define(Defines, "__MSVCRT__"); - Define(Defines, "__MINGW64__"); - Define(Defines, "__declspec"); + MacroBuilder &Builder) const { + WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__MSVCRT__"); + Builder.defineMacro("__MINGW64__"); + Builder.defineMacro("__declspec"); } }; } // end anonymous namespace @@ -1342,61 +1330,58 @@ public: return true; } virtual void getTargetDefines(const LangOptions &Opts, - std::vector<char> &Defs) const { + MacroBuilder &Builder) const { // Target identification. - Define(Defs, "__arm"); - Define(Defs, "__arm__"); + Builder.defineMacro("__arm"); + Builder.defineMacro("__arm__"); // Target properties. - Define(Defs, "__ARMEL__"); - Define(Defs, "__LITTLE_ENDIAN__"); - Define(Defs, "__REGISTER_PREFIX__", ""); + Builder.defineMacro("__ARMEL__"); + Builder.defineMacro("__LITTLE_ENDIAN__"); + Builder.defineMacro("__REGISTER_PREFIX__", ""); llvm::StringRef CPUArch = getCPUDefineSuffix(CPU); - std::string ArchName = "__ARM_ARCH_"; - ArchName += CPUArch; - ArchName += "__"; - Define(Defs, ArchName); + Builder.defineMacro("__ARM_ARCH_" + CPUArch + "__"); // Subtarget options. // FIXME: It's more complicated than this and we don't really support // interworking. if ('5' <= CPUArch[0] && CPUArch[0] <= '7') - Define(Defs, "__THUMB_INTERWORK__"); + Builder.defineMacro("__THUMB_INTERWORK__"); if (ABI == "aapcs" || ABI == "aapcs-linux") - Define(Defs, "__ARM_EABI__"); + Builder.defineMacro("__ARM_EABI__"); if (SoftFloat) - Define(Defs, "__SOFTFP__"); + Builder.defineMacro("__SOFTFP__"); if (CPU == "xscale") - Define(Defs, "__XSCALE__"); + Builder.defineMacro("__XSCALE__"); bool IsThumb2 = IsThumb && (CPUArch == "6T2" || CPUArch.startswith("7")); if (IsThumb) { - Define(Defs, "__THUMBEL__"); - Define(Defs, "__thumb__"); + Builder.defineMacro("__THUMBEL__"); + Builder.defineMacro("__thumb__"); if (IsThumb2) - Define(Defs, "__thumb2__"); + Builder.defineMacro("__thumb2__"); } // Note, this is always on in gcc, even though it doesn't make sense. - Define(Defs, "__APCS_32__"); + Builder.defineMacro("__APCS_32__"); if (FPUModeIsVFP((FPUMode) FPU)) - Define(Defs, "__VFP_FP__"); + Builder.defineMacro("__VFP_FP__"); // This only gets set when Neon instructions are actually available, unlike // the VFP define, hence the soft float and arch check. This is subtly // different from gcc, we follow the intent which was that it should be set // when Neon instructions are actually available. if (FPU == NeonFPU && !SoftFloat && IsThumb2) - Define(Defs, "__ARM_NEON__"); + Builder.defineMacro("__ARM_NEON__"); if (getTriple().getOS() == llvm::Triple::Darwin) - Define(Defs, "__USING_SJLJ_EXCEPTIONS__"); + Builder.defineMacro("__USING_SJLJ_EXCEPTIONS__"); } virtual void getTargetBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) const { @@ -1475,9 +1460,9 @@ class DarwinARMTargetInfo : public DarwinTargetInfo<ARMTargetInfo> { protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, - std::vector<char> &Defines) const { - getDarwinDefines(Defines, Opts); - getDarwinIPhoneOSDefines(Defines, Triple); + MacroBuilder &Builder) const { + getDarwinDefines(Builder, Opts); + getDarwinIPhoneOSDefines(Builder, Triple); } public: @@ -1497,10 +1482,10 @@ public: "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32"; } virtual void getTargetDefines(const LangOptions &Opts, - std::vector<char> &Defines) const { - DefineStd(Defines, "sparc", Opts); - Define(Defines, "__sparcv8"); - Define(Defines, "__REGISTER_PREFIX__", ""); + MacroBuilder &Builder) const { + DefineStd(Builder, "sparc", Opts); + Builder.defineMacro("__sparcv8"); + Builder.defineMacro("__REGISTER_PREFIX__", ""); } virtual void getTargetBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) const { @@ -1630,18 +1615,18 @@ namespace { virtual uint64_t getPointerWidthV(unsigned AddrSpace) const { return 16; } virtual uint64_t getPointerAlignV(unsigned AddrSpace) const { return 8; } virtual void getTargetDefines(const LangOptions &Opts, - std::vector<char> &Defines) const { - Define(Defines, "__pic16"); - Define(Defines, "rom", "__attribute__((address_space(1)))"); - Define(Defines, "ram", "__attribute__((address_space(0)))"); - Define(Defines, "_section(SectName)", + MacroBuilder &Builder) const { + Builder.defineMacro("__pic16"); + Builder.defineMacro("rom", "__attribute__((address_space(1)))"); + Builder.defineMacro("ram", "__attribute__((address_space(0)))"); + Builder.defineMacro("_section(SectName)", "__attribute__((section(SectName)))"); - Define(Defines, "near", + Builder.defineMacro("near", "__attribute__((section(\"Address=NEAR\")))"); - Define(Defines, "_address(Addr)", + Builder.defineMacro("_address(Addr)", "__attribute__((section(\"Address=\"#Addr)))"); - Define(Defines, "_CONFIG(conf)", "asm(\"CONFIG \"#conf)"); - Define(Defines, "_interrupt", + Builder.defineMacro("_CONFIG(conf)", "asm(\"CONFIG \"#conf)"); + Builder.defineMacro("_interrupt", "__attribute__((section(\"interrupt=0x4\"))) \ __attribute__((used))"); } @@ -1672,7 +1657,8 @@ namespace { MSP430TargetInfo(const std::string& triple) : TargetInfo(triple) { TLSSupported = false; IntWidth = 16; - LongWidth = LongLongWidth = 32; + LongWidth = 32; + LongLongWidth = 64; PointerWidth = 16; IntAlign = 8; LongAlign = LongLongAlign = 8; @@ -1686,9 +1672,9 @@ namespace { DescriptionString = "e-p:16:16:16-i8:8:8-i16:16:16-i32:16:32-n8:16"; } virtual void getTargetDefines(const LangOptions &Opts, - std::vector<char> &Defines) const { - Define(Defines, "MSP430"); - Define(Defines, "__MSP430__"); + MacroBuilder &Builder) const { + Builder.defineMacro("MSP430"); + Builder.defineMacro("__MSP430__"); // FIXME: defines for different 'flavours' of MCU } virtual void getTargetBuiltins(const Builtin::Info *&Records, @@ -1746,9 +1732,9 @@ namespace { "i64:64:64-f32:32:32-f64:64:64-f128:128:128-a0:16:16-n32:64"; } virtual void getTargetDefines(const LangOptions &Opts, - std::vector<char> &Defines) const { - Define(Defines, "__s390__"); - Define(Defines, "__s390x__"); + MacroBuilder &Builder) const { + Builder.defineMacro("__s390__"); + Builder.defineMacro("__s390x__"); } virtual void getTargetBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) const { @@ -1805,12 +1791,12 @@ namespace { } virtual void getTargetDefines(const LangOptions &Opts, - std::vector<char> &Defines) const { - DefineStd(Defines, "bfin", Opts); - DefineStd(Defines, "BFIN", Opts); - Define(Defines, "__ADSPBLACKFIN__"); + MacroBuilder &Builder) const { + DefineStd(Builder, "bfin", Opts); + DefineStd(Builder, "BFIN", Opts); + Builder.defineMacro("__ADSPBLACKFIN__"); // FIXME: This one is really dependent on -mcpu - Define(Defines, "__ADSPLPBLACKFIN__"); + Builder.defineMacro("__ADSPLPBLACKFIN__"); // FIXME: Add cpu-dependent defines and __SILICON_REVISION__ } @@ -1906,10 +1892,10 @@ namespace { } virtual void getTargetDefines(const LangOptions &Opts, - std::vector<char> &Defines) const { - DefineStd(Defines, "tce", Opts); - Define(Defines, "__TCE__"); - Define(Defines, "__TCE_V1__"); + MacroBuilder &Builder) const { + DefineStd(Builder, "tce", Opts); + Builder.defineMacro("__TCE__"); + Builder.defineMacro("__TCE_V1__"); } virtual void getTargetBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) const {} @@ -1940,12 +1926,12 @@ public: "i64:32:64-f32:32:32-f64:64:64-v64:64:64-n32"; } virtual void getTargetDefines(const LangOptions &Opts, - std::vector<char> &Defines) const { - DefineStd(Defines, "mips", Opts); - Define(Defines, "_mips"); - DefineStd(Defines, "MIPSEB", Opts); - Define(Defines, "_MIPSEB"); - Define(Defines, "__REGISTER_PREFIX__", ""); + MacroBuilder &Builder) const { + DefineStd(Builder, "mips", Opts); + Builder.defineMacro("_mips"); + DefineStd(Builder, "MIPSEB", Opts); + Builder.defineMacro("_MIPSEB"); + Builder.defineMacro("__REGISTER_PREFIX__", ""); } virtual void getTargetBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) const { @@ -2047,16 +2033,16 @@ public: } virtual void getTargetDefines(const LangOptions &Opts, - std::vector<char> &Defines) const; + MacroBuilder &Builder) const; }; void MipselTargetInfo::getTargetDefines(const LangOptions &Opts, - std::vector<char> &Defines) const { - DefineStd(Defines, "mips", Opts); - Define(Defines, "_mips"); - DefineStd(Defines, "MIPSEL", Opts); - Define(Defines, "_MIPSEL"); - Define(Defines, "__REGISTER_PREFIX__", ""); + MacroBuilder &Builder) const { + DefineStd(Builder, "mips", Opts); + Builder.defineMacro("_mips"); + DefineStd(Builder, "MIPSEL", Opts); + Builder.defineMacro("_MIPSEL"); + Builder.defineMacro("__REGISTER_PREFIX__", ""); } } // end anonymous namespace. @@ -2171,6 +2157,8 @@ static TargetInfo *AllocateTarget(const std::string &T) { return new DarwinX86_64TargetInfo(T); case llvm::Triple::Linux: return new LinuxTargetInfo<X86_64TargetInfo>(T); + case llvm::Triple::DragonFly: + return new DragonFlyBSDTargetInfo<X86_64TargetInfo>(T); case llvm::Triple::NetBSD: return new NetBSDTargetInfo<X86_64TargetInfo>(T); case llvm::Triple::OpenBSD: diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 1bece7f..1fa422f 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -24,7 +24,7 @@ using namespace clang; using namespace CodeGen; llvm::Constant *CodeGenFunction:: -BuildDescriptorBlockDecl(bool BlockHasCopyDispose, uint64_t Size, +BuildDescriptorBlockDecl(bool BlockHasCopyDispose, CharUnits Size, const llvm::StructType* Ty, std::vector<HelperInfo> *NoteForHelper) { const llvm::Type *UnsignedLongTy @@ -40,7 +40,7 @@ BuildDescriptorBlockDecl(bool BlockHasCopyDispose, uint64_t Size, // FIXME: What is the right way to say this doesn't fit? We should give // a user diagnostic in that case. Better fix would be to change the // API to size_t. - C = llvm::ConstantInt::get(UnsignedLongTy, Size); + C = llvm::ConstantInt::get(UnsignedLongTy, Size.getQuantity()); Elts.push_back(C); if (BlockHasCopyDispose) { @@ -176,7 +176,8 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { // We run this first so that we set BlockHasCopyDispose from the entire // block literal. // __invoke - uint64_t subBlockSize, subBlockAlign; + CharUnits subBlockSize; + uint64_t subBlockAlign; llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls; bool subBlockHasCopyDispose = false; llvm::Function *Fn @@ -321,13 +322,13 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { // compared to gcc by not grabbing the forwarding slot as this must // be done during Block_copy for us, and we can postpone the work // until then. - uint64_t offset = BlockDecls[BDRE->getDecl()]; + CharUnits offset = BlockDecls[BDRE->getDecl()]; llvm::Value *BlockLiteral = LoadBlockStruct(); Loc = Builder.CreateGEP(BlockLiteral, llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - offset), + offset.getQuantity()), "block.literal"); Ty = llvm::PointerType::get(Ty, 0); Loc = Builder.CreateBitCast(Loc, Ty); @@ -513,12 +514,12 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E, return EmitCall(FnInfo, Func, ReturnValue, Args); } -uint64_t CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) { +CharUnits CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) { const ValueDecl *VD = E->getDecl(); - uint64_t &offset = BlockDecls[VD]; + CharUnits &offset = BlockDecls[VD]; // See if we have already allocated an offset for this variable. - if (offset) + if (offset.isPositive()) return offset; // Don't run the expensive check, unless we have to. @@ -535,13 +536,13 @@ uint64_t CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) { llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) { const ValueDecl *VD = E->getDecl(); - uint64_t offset = AllocateBlockDecl(E); + CharUnits offset = AllocateBlockDecl(E); llvm::Value *BlockLiteral = LoadBlockStruct(); llvm::Value *V = Builder.CreateGEP(BlockLiteral, llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - offset), + offset.getQuantity()), "block.literal"); if (E->isByRef()) { const llvm::Type *PtrStructTy @@ -594,10 +595,10 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { // Block literal size. For global blocks we just use the size of the generic // block literal struct. - uint64_t BlockLiteralSize = - TheTargetData.getTypeStoreSizeInBits(getGenericBlockLiteralType()) / 8; + CharUnits BlockLiteralSize = CharUnits::fromQuantity( + TheTargetData.getTypeStoreSizeInBits(getGenericBlockLiteralType()) / 8); DescriptorFields[1] = - llvm::ConstantInt::get(UnsignedLongTy,BlockLiteralSize); + llvm::ConstantInt::get(UnsignedLongTy,BlockLiteralSize.getQuantity()); llvm::Constant *DescriptorStruct = llvm::ConstantStruct::get(VMContext, &DescriptorFields[0], 2, false); @@ -615,7 +616,8 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { std::vector<llvm::Constant*> LiteralFields(FieldCount); CodeGenFunction::BlockInfo Info(0, n); - uint64_t subBlockSize, subBlockAlign; + CharUnits subBlockSize; + uint64_t subBlockAlign; llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls; bool subBlockHasCopyDispose = false; llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap; @@ -677,7 +679,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, const BlockInfo& Info, const Decl *OuterFuncDecl, llvm::DenseMap<const Decl*, llvm::Value*> ldm, - uint64_t &Size, + CharUnits &Size, uint64_t &Align, llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls, bool &subBlockHasCopyDispose) { @@ -698,8 +700,9 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, LocalDeclMap[VD] = i->second; } - BlockOffset = CGM.getTargetData() - .getTypeStoreSizeInBits(CGM.getGenericBlockLiteralType()) / 8; + BlockOffset = CharUnits::fromQuantity( + CGM.getTargetData() + .getTypeStoreSizeInBits(CGM.getGenericBlockLiteralType()) / 8); BlockAlign = getContext().getTypeAlign(getContext().VoidPtrTy) / 8; const FunctionType *BlockFunctionType = BExpr->getFunctionType(); @@ -799,7 +802,8 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, // The runtime needs a minimum alignment of a void *. uint64_t MinAlign = getContext().getTypeAlign(getContext().VoidPtrTy) / 8; - BlockOffset = llvm::RoundUpToAlignment(BlockOffset, MinAlign); + BlockOffset = CharUnits::fromQuantity( + llvm::RoundUpToAlignment(BlockOffset.getQuantity(), MinAlign)); Size = BlockOffset; Align = BlockAlign; @@ -808,30 +812,32 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, return Fn; } -uint64_t BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) { +CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) { const ValueDecl *D = dyn_cast<ValueDecl>(BDRE->getDecl()); - uint64_t Size = getContext().getTypeSize(D->getType()) / 8; + CharUnits Size = getContext().getTypeSizeInChars(D->getType()); uint64_t Align = getContext().getDeclAlignInBytes(D); if (BDRE->isByRef()) { - Size = getContext().getTypeSize(getContext().VoidPtrTy) / 8; + Size = getContext().getTypeSizeInChars(getContext().VoidPtrTy); Align = getContext().getTypeAlign(getContext().VoidPtrTy) / 8; } assert ((Align > 0) && "alignment must be 1 byte or more"); - uint64_t OldOffset = BlockOffset; + CharUnits OldOffset = BlockOffset; // Ensure proper alignment, even if it means we have to have a gap - BlockOffset = llvm::RoundUpToAlignment(BlockOffset, Align); + BlockOffset = CharUnits::fromQuantity( + llvm::RoundUpToAlignment(BlockOffset.getQuantity(), Align)); BlockAlign = std::max(Align, BlockAlign); - uint64_t Pad = BlockOffset - OldOffset; - if (Pad) { - llvm::ArrayType::get(llvm::Type::getInt8Ty(VMContext), Pad); + CharUnits Pad = BlockOffset - OldOffset; + if (Pad.isPositive()) { + llvm::ArrayType::get(llvm::Type::getInt8Ty(VMContext), Pad.getQuantity()); QualType PadTy = getContext().getConstantArrayType(getContext().CharTy, - llvm::APInt(32, Pad), + llvm::APInt(32, + Pad.getQuantity()), ArrayType::Normal, 0); ValueDecl *PadDecl = VarDecl::Create(getContext(), 0, SourceLocation(), 0, QualType(PadTy), 0, VarDecl::None); diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h index 38e02a7..f42244c 100644 --- a/lib/CodeGen/CGBlocks.h +++ b/lib/CodeGen/CGBlocks.h @@ -20,6 +20,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "clang/Basic/TargetInfo.h" +#include "clang/AST/CharUnits.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" @@ -175,13 +176,13 @@ public: /// BlockOffset - The offset in bytes for the next allocation of an /// imported block variable. - uint64_t BlockOffset; + CharUnits BlockOffset; /// BlockAlign - Maximal alignment needed for the Block expressed in bytes. uint64_t BlockAlign; /// getBlockOffset - Allocate an offset for the ValueDecl from a /// BlockDeclRefExpr in a block literal (BlockExpr). - uint64_t getBlockOffset(const BlockDeclRefExpr *E); + CharUnits getBlockOffset(const BlockDeclRefExpr *E); /// BlockHasCopyDispose - True iff the block uses copy/dispose. bool BlockHasCopyDispose; @@ -191,7 +192,7 @@ public: llvm::SmallVector<const Expr *, 8> BlockDeclRefDecls; /// BlockDecls - Offsets for all Decls in BlockDeclRefExprs. - std::map<const Decl*, uint64_t> BlockDecls; + std::map<const Decl*, CharUnits> BlockDecls; ImplicitParamDecl *BlockStructDecl; ImplicitParamDecl *getBlockStructDecl() { return BlockStructDecl; } diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index cc006d9..4323f84 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -26,269 +26,7 @@ using namespace clang; using namespace CodeGen; -RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD, - llvm::Value *Callee, - ReturnValueSlot ReturnValue, - llvm::Value *This, - CallExpr::const_arg_iterator ArgBeg, - CallExpr::const_arg_iterator ArgEnd) { - assert(MD->isInstance() && - "Trying to emit a member call expr on a static method!"); - const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); - - CallArgList Args; - - // Push the this ptr. - Args.push_back(std::make_pair(RValue::get(This), - MD->getThisType(getContext()))); - - // And the rest of the call args - EmitCallArgs(Args, FPT, ArgBeg, ArgEnd); - - QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType(); - return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee, - ReturnValue, Args, MD); -} - -/// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given -/// expr can be devirtualized. -static bool canDevirtualizeMemberFunctionCalls(const Expr *Base) { - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) { - if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) { - // This is a record decl. We know the type and can devirtualize it. - return VD->getType()->isRecordType(); - } - - return false; - } - - // We can always devirtualize calls on temporary object expressions. - if (isa<CXXTemporaryObjectExpr>(Base)) - return true; - - // And calls on bound temporaries. - if (isa<CXXBindTemporaryExpr>(Base)) - return true; - - // Check if this is a call expr that returns a record type. - if (const CallExpr *CE = dyn_cast<CallExpr>(Base)) - return CE->getCallReturnType()->isRecordType(); - - // We can't devirtualize the call. - return false; -} - -RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, - ReturnValueSlot ReturnValue) { - if (isa<BinaryOperator>(CE->getCallee()->IgnoreParens())) - return EmitCXXMemberPointerCallExpr(CE, ReturnValue); - - const MemberExpr *ME = cast<MemberExpr>(CE->getCallee()->IgnoreParens()); - const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl()); - - if (MD->isStatic()) { - // The method is static, emit it as we would a regular call. - llvm::Value *Callee = CGM.GetAddrOfFunction(MD); - return EmitCall(getContext().getPointerType(MD->getType()), Callee, - ReturnValue, CE->arg_begin(), CE->arg_end()); - } - - const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); - - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - llvm::Value *This; - - if (ME->isArrow()) - This = EmitScalarExpr(ME->getBase()); - else { - LValue BaseLV = EmitLValue(ME->getBase()); - This = BaseLV.getAddress(); - } - - if (MD->isCopyAssignment() && MD->isTrivial()) { - // We don't like to generate the trivial copy assignment operator when - // it isn't necessary; just produce the proper effect here. - llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress(); - EmitAggregateCopy(This, RHS, CE->getType()); - return RValue::get(This); - } - - // C++ [class.virtual]p12: - // Explicit qualification with the scope operator (5.1) suppresses the - // virtual call mechanism. - // - // We also don't emit a virtual call if the base expression has a record type - // because then we know what the type is. - llvm::Value *Callee; - if (const CXXDestructorDecl *Destructor - = dyn_cast<CXXDestructorDecl>(MD)) { - if (Destructor->isTrivial()) - return RValue::get(0); - if (MD->isVirtual() && !ME->hasQualifier() && - !canDevirtualizeMemberFunctionCalls(ME->getBase())) { - Callee = BuildVirtualCall(Destructor, Dtor_Complete, This, Ty); - } else { - Callee = CGM.GetAddrOfFunction(GlobalDecl(Destructor, Dtor_Complete), Ty); - } - } else if (MD->isVirtual() && !ME->hasQualifier() && - !canDevirtualizeMemberFunctionCalls(ME->getBase())) { - Callee = BuildVirtualCall(MD, This, Ty); - } else { - Callee = CGM.GetAddrOfFunction(MD, Ty); - } - - return EmitCXXMemberCall(MD, Callee, ReturnValue, This, - CE->arg_begin(), CE->arg_end()); -} - -RValue -CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, - ReturnValueSlot ReturnValue) { - const BinaryOperator *BO = - cast<BinaryOperator>(E->getCallee()->IgnoreParens()); - const Expr *BaseExpr = BO->getLHS(); - const Expr *MemFnExpr = BO->getRHS(); - - const MemberPointerType *MPT = - MemFnExpr->getType()->getAs<MemberPointerType>(); - const FunctionProtoType *FPT = - MPT->getPointeeType()->getAs<FunctionProtoType>(); - const CXXRecordDecl *RD = - cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl()); - - const llvm::FunctionType *FTy = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT), - FPT->isVariadic()); - - const llvm::Type *Int8PtrTy = - llvm::Type::getInt8Ty(VMContext)->getPointerTo(); - - // Get the member function pointer. - llvm::Value *MemFnPtr = - CreateTempAlloca(ConvertType(MemFnExpr->getType()), "mem.fn"); - EmitAggExpr(MemFnExpr, MemFnPtr, /*VolatileDest=*/false); - - // Emit the 'this' pointer. - llvm::Value *This; - - if (BO->getOpcode() == BinaryOperator::PtrMemI) - This = EmitScalarExpr(BaseExpr); - else - This = EmitLValue(BaseExpr).getAddress(); - - // Adjust it. - llvm::Value *Adj = Builder.CreateStructGEP(MemFnPtr, 1); - Adj = Builder.CreateLoad(Adj, "mem.fn.adj"); - - llvm::Value *Ptr = Builder.CreateBitCast(This, Int8PtrTy, "ptr"); - Ptr = Builder.CreateGEP(Ptr, Adj, "adj"); - - This = Builder.CreateBitCast(Ptr, This->getType(), "this"); - - llvm::Value *FnPtr = Builder.CreateStructGEP(MemFnPtr, 0, "mem.fn.ptr"); - - const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType()); - - llvm::Value *FnAsInt = Builder.CreateLoad(FnPtr, "fn"); - - // If the LSB in the function pointer is 1, the function pointer points to - // a virtual function. - llvm::Value *IsVirtual - = Builder.CreateAnd(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1), - "and"); - - IsVirtual = Builder.CreateTrunc(IsVirtual, - llvm::Type::getInt1Ty(VMContext)); - - llvm::BasicBlock *FnVirtual = createBasicBlock("fn.virtual"); - llvm::BasicBlock *FnNonVirtual = createBasicBlock("fn.nonvirtual"); - llvm::BasicBlock *FnEnd = createBasicBlock("fn.end"); - - Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual); - EmitBlock(FnVirtual); - - const llvm::Type *VTableTy = - FTy->getPointerTo()->getPointerTo()->getPointerTo(); - - llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy); - VTable = Builder.CreateLoad(VTable); - - VTable = Builder.CreateGEP(VTable, FnAsInt, "fn"); - - // Since the function pointer is 1 plus the virtual table offset, we - // subtract 1 by using a GEP. - VTable = Builder.CreateConstGEP1_64(VTable, (uint64_t)-1); - - llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn"); - - EmitBranch(FnEnd); - EmitBlock(FnNonVirtual); - - // If the function is not virtual, just load the pointer. - llvm::Value *NonVirtualFn = Builder.CreateLoad(FnPtr, "fn"); - NonVirtualFn = Builder.CreateIntToPtr(NonVirtualFn, FTy->getPointerTo()); - - EmitBlock(FnEnd); - - llvm::PHINode *Callee = Builder.CreatePHI(FTy->getPointerTo()); - Callee->reserveOperandSpace(2); - Callee->addIncoming(VirtualFn, FnVirtual); - Callee->addIncoming(NonVirtualFn, FnNonVirtual); - - CallArgList Args; - - QualType ThisType = - getContext().getPointerType(getContext().getTagDeclType(RD)); - - // Push the this ptr. - Args.push_back(std::make_pair(RValue::get(This), ThisType)); - - // And the rest of the call args - EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end()); - QualType ResultType = BO->getType()->getAs<FunctionType>()->getResultType(); - return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee, - ReturnValue, Args); -} - -RValue -CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, - const CXXMethodDecl *MD, - ReturnValueSlot ReturnValue) { - assert(MD->isInstance() && - "Trying to emit a member call expr on a static method!"); - - if (MD->isCopyAssignment()) { - const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(MD->getDeclContext()); - if (ClassDecl->hasTrivialCopyAssignment()) { - assert(!ClassDecl->hasUserDeclaredCopyAssignment() && - "EmitCXXOperatorMemberCallExpr - user declared copy assignment"); - llvm::Value *This = EmitLValue(E->getArg(0)).getAddress(); - llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress(); - QualType Ty = E->getType(); - EmitAggregateCopy(This, Src, Ty); - return RValue::get(This); - } - } - - const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - - llvm::Value *This = EmitLValue(E->getArg(0)).getAddress(); - - llvm::Value *Callee; - if (MD->isVirtual() && !canDevirtualizeMemberFunctionCalls(E->getArg(0))) - Callee = BuildVirtualCall(MD, This, Ty); - else - Callee = CGM.GetAddrOfFunction(MD, Ty); - - return EmitCXXMemberCall(MD, Callee, ReturnValue, This, - E->arg_begin() + 1, E->arg_end()); -} llvm::Value *CodeGenFunction::LoadCXXThis() { assert(isa<CXXMethodDecl>(CurFuncDecl) && @@ -302,320 +40,6 @@ llvm::Value *CodeGenFunction::LoadCXXThis() { return Builder.CreateLoad(LocalDeclMap[CXXThisDecl], "this"); } -/// EmitCXXAggrConstructorCall - This routine essentially creates a (nested) -/// for-loop to call the default constructor on individual members of the -/// array. -/// 'D' is the default constructor for elements of the array, 'ArrayTy' is the -/// array type and 'ArrayPtr' points to the beginning fo the array. -/// It is assumed that all relevant checks have been made by the caller. -void -CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, - const ConstantArrayType *ArrayTy, - llvm::Value *ArrayPtr, - CallExpr::const_arg_iterator ArgBeg, - CallExpr::const_arg_iterator ArgEnd) { - - const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); - llvm::Value * NumElements = - llvm::ConstantInt::get(SizeTy, - getContext().getConstantArrayElementCount(ArrayTy)); - - EmitCXXAggrConstructorCall(D, NumElements, ArrayPtr, ArgBeg, ArgEnd); -} - -void -CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, - llvm::Value *NumElements, - llvm::Value *ArrayPtr, - CallExpr::const_arg_iterator ArgBeg, - CallExpr::const_arg_iterator ArgEnd) { - const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); - - // Create a temporary for the loop index and initialize it with 0. - llvm::Value *IndexPtr = CreateTempAlloca(SizeTy, "loop.index"); - llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy); - Builder.CreateStore(Zero, IndexPtr); - - // Start the loop with a block that tests the condition. - llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); - llvm::BasicBlock *AfterFor = createBasicBlock("for.end"); - - EmitBlock(CondBlock); - - llvm::BasicBlock *ForBody = createBasicBlock("for.body"); - - // Generate: if (loop-index < number-of-elements fall to the loop body, - // otherwise, go to the block after the for-loop. - llvm::Value *Counter = Builder.CreateLoad(IndexPtr); - llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElements, "isless"); - // If the condition is true, execute the body. - Builder.CreateCondBr(IsLess, ForBody, AfterFor); - - EmitBlock(ForBody); - - llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc"); - // Inside the loop body, emit the constructor call on the array element. - Counter = Builder.CreateLoad(IndexPtr); - llvm::Value *Address = Builder.CreateInBoundsGEP(ArrayPtr, Counter, - "arrayidx"); - - // 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 - // 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 - // before the construction of the next array element, if any. - - // Keep track of the current number of live temporaries. - unsigned OldNumLiveTemporaries = LiveTemporaries.size(); - - EmitCXXConstructorCall(D, Ctor_Complete, Address, ArgBeg, ArgEnd); - - // Pop temporaries. - while (LiveTemporaries.size() > OldNumLiveTemporaries) - PopCXXTemporary(); - - EmitBlock(ContinueBlock); - - // Emit the increment of the loop counter. - llvm::Value *NextVal = llvm::ConstantInt::get(SizeTy, 1); - Counter = Builder.CreateLoad(IndexPtr); - NextVal = Builder.CreateAdd(Counter, NextVal, "inc"); - Builder.CreateStore(NextVal, IndexPtr); - - // Finally, branch back up to the condition for the next iteration. - EmitBranch(CondBlock); - - // Emit the fall-through block. - EmitBlock(AfterFor, true); -} - -/// EmitCXXAggrDestructorCall - calls the default destructor on array -/// elements in reverse order of construction. -void -CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, - const ArrayType *Array, - llvm::Value *This) { - const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array); - assert(CA && "Do we support VLA for destruction ?"); - uint64_t ElementCount = getContext().getConstantArrayElementCount(CA); - - const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType()); - llvm::Value* ElementCountPtr = llvm::ConstantInt::get(SizeLTy, ElementCount); - EmitCXXAggrDestructorCall(D, ElementCountPtr, This); -} - -/// EmitCXXAggrDestructorCall - calls the default destructor on array -/// elements in reverse order of construction. -void -CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, - llvm::Value *UpperCount, - llvm::Value *This) { - 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(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. - llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); - llvm::BasicBlock *AfterFor = createBasicBlock("for.end"); - - EmitBlock(CondBlock); - - llvm::BasicBlock *ForBody = createBasicBlock("for.body"); - - // 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(SizeLTy); - llvm::Value *Counter = Builder.CreateLoad(IndexPtr); - llvm::Value *IsNE = Builder.CreateICmpNE(Counter, zeroConstant, - "isne"); - // If the condition is true, execute the body. - Builder.CreateCondBr(IsNE, ForBody, AfterFor); - - EmitBlock(ForBody); - - llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc"); - // Inside the loop body, emit the constructor call on the array element. - Counter = Builder.CreateLoad(IndexPtr); - Counter = Builder.CreateSub(Counter, One); - llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx"); - EmitCXXDestructorCall(D, Dtor_Complete, Address); - - EmitBlock(ContinueBlock); - - // Emit the decrement of the loop counter. - Counter = Builder.CreateLoad(IndexPtr); - Counter = Builder.CreateSub(Counter, One, "dec"); - Builder.CreateStore(Counter, IndexPtr); - - // Finally, branch back up to the condition for the next iteration. - EmitBranch(CondBlock); - - // Emit the fall-through block. - EmitBlock(AfterFor, true); -} - -/// GenerateCXXAggrDestructorHelper - Generates a helper function which when -/// invoked, calls the default destructor on array elements in reverse order of -/// construction. -llvm::Constant * -CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, - const ArrayType *Array, - llvm::Value *This) { - FunctionArgList Args; - ImplicitParamDecl *Dst = - ImplicitParamDecl::Create(getContext(), 0, - SourceLocation(), 0, - getContext().getPointerType(getContext().VoidTy)); - Args.push_back(std::make_pair(Dst, Dst->getType())); - - llvm::SmallString<16> Name; - llvm::raw_svector_ostream(Name) << "__tcf_" << (++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.str(), - &CGM.getModule()); - IdentifierInfo *II = &CGM.getContext().Idents.get(Name.str()); - FunctionDecl *FD = FunctionDecl::Create(getContext(), - getContext().getTranslationUnitDecl(), - SourceLocation(), II, R, 0, - FunctionDecl::Static, - false, true); - StartFunction(FD, R, Fn, Args, SourceLocation()); - QualType BaseElementTy = getContext().getBaseElementType(Array); - const llvm::Type *BasePtr = ConvertType(BaseElementTy); - BasePtr = llvm::PointerType::getUnqual(BasePtr); - llvm::Value *BaseAddrPtr = Builder.CreateBitCast(This, BasePtr); - EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); - FinishFunction(); - llvm::Type *Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), - 0); - llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty); - return m; -} - -void -CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, - CXXCtorType Type, - llvm::Value *This, - CallExpr::const_arg_iterator ArgBeg, - CallExpr::const_arg_iterator ArgEnd) { - if (D->isCopyConstructor()) { - const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D->getDeclContext()); - if (ClassDecl->hasTrivialCopyConstructor()) { - assert(!ClassDecl->hasUserDeclaredCopyConstructor() && - "EmitCXXConstructorCall - user declared copy constructor"); - const Expr *E = (*ArgBeg); - QualType Ty = E->getType(); - llvm::Value *Src = EmitLValue(E).getAddress(); - EmitAggregateCopy(This, Src, Ty); - return; - } - } else if (D->isTrivial()) { - // FIXME: Track down why we're trying to generate calls to the trivial - // default constructor! - return; - } - - llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type); - - EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, ArgBeg, ArgEnd); -} - -void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, - CXXDtorType Type, - llvm::Value *This) { - 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); - - Args.push_back(std::make_pair(RValue::get(CGM.EmitNullConstant(T)), T)); - } - - // FIXME: We should try to share this code with EmitCXXMemberCall. - - QualType ResultType = DD->getType()->getAs<FunctionType>()->getResultType(); - EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee, - ReturnValueSlot(), Args, DD); -} - -void -CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, - const CXXConstructExpr *E) { - assert(Dest && "Must have a destination!"); - const CXXConstructorDecl *CD = E->getConstructor(); - const ConstantArrayType *Array = - getContext().getAsConstantArrayType(E->getType()); - // For a copy constructor, even if it is trivial, must fall thru so - // its argument is code-gen'ed. - if (!CD->isCopyConstructor()) { - QualType InitType = E->getType(); - if (Array) - InitType = getContext().getBaseElementType(Array); - const CXXRecordDecl *RD = - cast<CXXRecordDecl>(InitType->getAs<RecordType>()->getDecl()); - if (RD->hasTrivialConstructor()) - return; - } - // Code gen optimization to eliminate copy constructor and return - // its first argument instead. - if (getContext().getLangOptions().ElideConstructors && E->isElidable()) { - const Expr *Arg = E->getArg(0); - - if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { - assert((ICE->getCastKind() == CastExpr::CK_NoOp || - ICE->getCastKind() == CastExpr::CK_ConstructorConversion || - ICE->getCastKind() == CastExpr::CK_UserDefinedConversion) && - "Unknown implicit cast kind in constructor elision"); - Arg = ICE->getSubExpr(); - } - - if (const CXXFunctionalCastExpr *FCE = dyn_cast<CXXFunctionalCastExpr>(Arg)) - Arg = FCE->getSubExpr(); - - if (const CXXBindTemporaryExpr *BindExpr = - dyn_cast<CXXBindTemporaryExpr>(Arg)) - Arg = BindExpr->getSubExpr(); - - EmitAggExpr(Arg, Dest, false); - return; - } - if (Array) { - QualType BaseElementTy = getContext().getBaseElementType(Array); - const llvm::Type *BasePtr = ConvertType(BaseElementTy); - BasePtr = llvm::PointerType::getUnqual(BasePtr); - llvm::Value *BaseAddrPtr = - Builder.CreateBitCast(Dest, BasePtr); - - EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr, - E->arg_begin(), E->arg_end()); - } - else - // Call the constructor. - EmitCXXConstructorCall(CD, Ctor_Complete, Dest, - E->arg_begin(), E->arg_end()); -} - void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) { EmitGlobal(GlobalDecl(D, Ctor_Complete)); EmitGlobal(GlobalDecl(D, Ctor_Base)); @@ -1001,33 +425,6 @@ CodeGenModule::BuildCovariantThunk(const GlobalDecl &GD, bool Extern, return m; } -llvm::Value * -CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl) { - const llvm::Type *Int8PtrTy = - llvm::Type::getInt8Ty(VMContext)->getPointerTo(); - - llvm::Value *VTablePtr = Builder.CreateBitCast(This, - Int8PtrTy->getPointerTo()); - VTablePtr = Builder.CreateLoad(VTablePtr, "vtable"); - - int64_t VBaseOffsetIndex = - CGM.getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl); - - llvm::Value *VBaseOffsetPtr = - Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetIndex, "vbase.offset.ptr"); - const llvm::Type *PtrDiffTy = - ConvertType(getContext().getPointerDiffType()); - - VBaseOffsetPtr = Builder.CreateBitCast(VBaseOffsetPtr, - PtrDiffTy->getPointerTo()); - - llvm::Value *VBaseOffset = Builder.CreateLoad(VBaseOffsetPtr, "vbase.offset"); - - return VBaseOffset; -} - static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VtableIndex, llvm::Value *This, const llvm::Type *Ty) { Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo(); @@ -1058,71 +455,3 @@ CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type, return ::BuildVirtualCall(*this, VtableIndex, This, Ty); } - -void CodeGenFunction::InitializeVtablePtrs(const CXXRecordDecl *ClassDecl) { - if (!ClassDecl->isDynamicClass()) - return; - - llvm::Constant *Vtable = CGM.getVtableInfo().getVtable(ClassDecl); - CodeGenModule::AddrSubMap_t& AddressPoints = - *(*CGM.AddressPoints[ClassDecl])[ClassDecl]; - llvm::Value *ThisPtr = LoadCXXThis(); - const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassDecl); - - // Store address points for virtual bases - for (CXXRecordDecl::base_class_const_iterator I = - ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); I != E; ++I) { - const CXXBaseSpecifier &Base = *I; - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); - uint64_t Offset = Layout.getVBaseClassOffset(BaseClassDecl); - InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints, - ThisPtr, Offset); - } - - // Store address points for non-virtual bases and current class - InitializeVtablePtrsRecursive(ClassDecl, Vtable, AddressPoints, ThisPtr, 0); -} - -void CodeGenFunction::InitializeVtablePtrsRecursive( - const CXXRecordDecl *ClassDecl, - llvm::Constant *Vtable, - CodeGenModule::AddrSubMap_t& AddressPoints, - llvm::Value *ThisPtr, - uint64_t Offset) { - if (!ClassDecl->isDynamicClass()) - return; - - // Store address points for non-virtual bases - const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassDecl); - for (CXXRecordDecl::base_class_const_iterator I = - ClassDecl->bases_begin(), E = ClassDecl->bases_end(); I != E; ++I) { - const CXXBaseSpecifier &Base = *I; - if (Base.isVirtual()) - continue; - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); - uint64_t NewOffset = Offset + Layout.getBaseClassOffset(BaseClassDecl); - InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints, - ThisPtr, NewOffset); - } - - // Compute the address point - assert(AddressPoints.count(std::make_pair(ClassDecl, Offset)) && - "Missing address point for class"); - uint64_t AddressPoint = AddressPoints[std::make_pair(ClassDecl, Offset)]; - llvm::Value *VtableAddressPoint = - Builder.CreateConstInBoundsGEP2_64(Vtable, 0, AddressPoint); - - // Compute the address to store the address point - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); - llvm::Value *VtableField = Builder.CreateBitCast(ThisPtr, Int8PtrTy); - VtableField = Builder.CreateConstInBoundsGEP1_64(VtableField, Offset/8); - const llvm::Type *AddressPointPtrTy = - VtableAddressPoint->getType()->getPointerTo(); - VtableField = Builder.CreateBitCast(VtableField, AddressPointPtrTy); - - // Store address point - Builder.CreateStore(VtableAddressPoint, VtableField); -} - diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 953b8c8..ab3fece 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -431,6 +431,37 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest, EmitBlock(AfterFor, true); } +/// GetVTTParameter - Return the VTT parameter that should be passed to a +/// base constructor/destructor with virtual bases. +static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) { + if (!CGVtableInfo::needsVTTParameter(GD)) { + // This constructor/destructor does not need a VTT parameter. + return 0; + } + + const CXXRecordDecl *RD = cast<CXXMethodDecl>(CGF.CurFuncDecl)->getParent(); + const CXXRecordDecl *Base = cast<CXXMethodDecl>(GD.getDecl())->getParent(); + + llvm::Value *VTT; + + uint64_t SubVTTIndex = + CGF.CGM.getVtableInfo().getSubVTTIndex(RD, Base); + assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!"); + + if (CGVtableInfo::needsVTTParameter(CGF.CurGD)) { + // A VTT parameter was passed to the constructor, use it. + VTT = CGF.LoadCXXVTT(); + VTT = CGF.Builder.CreateConstInBoundsGEP1_64(VTT, SubVTTIndex); + } else { + // We're the complete constructor, so get the VTT by name. + VTT = CGF.CGM.getVtableInfo().getVTT(RD); + VTT = CGF.Builder.CreateConstInBoundsGEP2_64(VTT, 0, SubVTTIndex); + } + + return VTT; +} + + /// EmitClassMemberwiseCopy - This routine generates code to copy a class /// object from SrcValue to DestValue. Copying can be either a bitwise copy /// or via a copy constructor call. @@ -438,11 +469,16 @@ void CodeGenFunction::EmitClassMemberwiseCopy( llvm::Value *Dest, llvm::Value *Src, const CXXRecordDecl *ClassDecl, const CXXRecordDecl *BaseClassDecl, QualType Ty) { + CXXCtorType CtorType = Ctor_Complete; + if (ClassDecl) { Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl, /*NullCheckValue=*/false); Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl, /*NullCheckValue=*/false); + + // We want to call the base constructor. + CtorType = Ctor_Base; } if (BaseClassDecl->hasTrivialCopyConstructor()) { EmitAggregateCopy(Dest, Src, Ty); @@ -451,13 +487,19 @@ void CodeGenFunction::EmitClassMemberwiseCopy( if (CXXConstructorDecl *BaseCopyCtor = BaseClassDecl->getCopyConstructor(getContext(), 0)) { - llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor, - Ctor_Complete); + llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor, CtorType); CallArgList CallArgs; // Push the this (Dest) ptr. CallArgs.push_back(std::make_pair(RValue::get(Dest), BaseCopyCtor->getThisType(getContext()))); + // Push the VTT parameter, if necessary. + if (llvm::Value *VTT = + GetVTTParameter(*this, GlobalDecl(BaseCopyCtor, CtorType))) { + QualType T = getContext().getPointerType(getContext().VoidPtrTy); + CallArgs.push_back(std::make_pair(RValue::get(VTT), T)); + } + // Push the Src ptr. CallArgs.push_back(std::make_pair(RValue::get(Src), BaseCopyCtor->getParamDecl(0)->getType())); @@ -787,10 +829,8 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, V = CGF.Builder.CreateConstInBoundsGEP1_64(V, Offset/8); V = CGF.Builder.CreateBitCast(V, BaseClassType->getPointerTo()); - // FIXME: This should always use Ctor_Base as the ctor type! (But that - // causes crashes in tests.) CGF.EmitCXXConstructorCall(BaseInit->getConstructor(), - CtorType, V, + Ctor_Base, V, BaseInit->const_arg_begin(), BaseInit->const_arg_end()); } @@ -1044,3 +1084,347 @@ void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor, EmitDtorEpilogue(Dtor, DtorType); FinishFunction(); } + +/// EmitCXXAggrConstructorCall - This routine essentially creates a (nested) +/// for-loop to call the default constructor on individual members of the +/// array. +/// 'D' is the default constructor for elements of the array, 'ArrayTy' is the +/// array type and 'ArrayPtr' points to the beginning fo the array. +/// It is assumed that all relevant checks have been made by the caller. +void +CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, + const ConstantArrayType *ArrayTy, + llvm::Value *ArrayPtr, + CallExpr::const_arg_iterator ArgBeg, + CallExpr::const_arg_iterator ArgEnd) { + + const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); + llvm::Value * NumElements = + llvm::ConstantInt::get(SizeTy, + getContext().getConstantArrayElementCount(ArrayTy)); + + EmitCXXAggrConstructorCall(D, NumElements, ArrayPtr, ArgBeg, ArgEnd); +} + +void +CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, + llvm::Value *NumElements, + llvm::Value *ArrayPtr, + CallExpr::const_arg_iterator ArgBeg, + CallExpr::const_arg_iterator ArgEnd) { + const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); + + // Create a temporary for the loop index and initialize it with 0. + llvm::Value *IndexPtr = CreateTempAlloca(SizeTy, "loop.index"); + llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy); + Builder.CreateStore(Zero, IndexPtr); + + // Start the loop with a block that tests the condition. + llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); + llvm::BasicBlock *AfterFor = createBasicBlock("for.end"); + + EmitBlock(CondBlock); + + llvm::BasicBlock *ForBody = createBasicBlock("for.body"); + + // Generate: if (loop-index < number-of-elements fall to the loop body, + // otherwise, go to the block after the for-loop. + llvm::Value *Counter = Builder.CreateLoad(IndexPtr); + llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElements, "isless"); + // If the condition is true, execute the body. + Builder.CreateCondBr(IsLess, ForBody, AfterFor); + + EmitBlock(ForBody); + + llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc"); + // Inside the loop body, emit the constructor call on the array element. + Counter = Builder.CreateLoad(IndexPtr); + llvm::Value *Address = Builder.CreateInBoundsGEP(ArrayPtr, Counter, + "arrayidx"); + + // 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 + // 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 + // before the construction of the next array element, if any. + + // Keep track of the current number of live temporaries. + unsigned OldNumLiveTemporaries = LiveTemporaries.size(); + + EmitCXXConstructorCall(D, Ctor_Complete, Address, ArgBeg, ArgEnd); + + // Pop temporaries. + while (LiveTemporaries.size() > OldNumLiveTemporaries) + PopCXXTemporary(); + + EmitBlock(ContinueBlock); + + // Emit the increment of the loop counter. + llvm::Value *NextVal = llvm::ConstantInt::get(SizeTy, 1); + Counter = Builder.CreateLoad(IndexPtr); + NextVal = Builder.CreateAdd(Counter, NextVal, "inc"); + Builder.CreateStore(NextVal, IndexPtr); + + // Finally, branch back up to the condition for the next iteration. + EmitBranch(CondBlock); + + // Emit the fall-through block. + EmitBlock(AfterFor, true); +} + +/// EmitCXXAggrDestructorCall - calls the default destructor on array +/// elements in reverse order of construction. +void +CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, + const ArrayType *Array, + llvm::Value *This) { + const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array); + assert(CA && "Do we support VLA for destruction ?"); + uint64_t ElementCount = getContext().getConstantArrayElementCount(CA); + + const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType()); + llvm::Value* ElementCountPtr = llvm::ConstantInt::get(SizeLTy, ElementCount); + EmitCXXAggrDestructorCall(D, ElementCountPtr, This); +} + +/// EmitCXXAggrDestructorCall - calls the default destructor on array +/// elements in reverse order of construction. +void +CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, + llvm::Value *UpperCount, + llvm::Value *This) { + 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(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. + llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); + llvm::BasicBlock *AfterFor = createBasicBlock("for.end"); + + EmitBlock(CondBlock); + + llvm::BasicBlock *ForBody = createBasicBlock("for.body"); + + // 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(SizeLTy); + llvm::Value *Counter = Builder.CreateLoad(IndexPtr); + llvm::Value *IsNE = Builder.CreateICmpNE(Counter, zeroConstant, + "isne"); + // If the condition is true, execute the body. + Builder.CreateCondBr(IsNE, ForBody, AfterFor); + + EmitBlock(ForBody); + + llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc"); + // Inside the loop body, emit the constructor call on the array element. + Counter = Builder.CreateLoad(IndexPtr); + Counter = Builder.CreateSub(Counter, One); + llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx"); + EmitCXXDestructorCall(D, Dtor_Complete, Address); + + EmitBlock(ContinueBlock); + + // Emit the decrement of the loop counter. + Counter = Builder.CreateLoad(IndexPtr); + Counter = Builder.CreateSub(Counter, One, "dec"); + Builder.CreateStore(Counter, IndexPtr); + + // Finally, branch back up to the condition for the next iteration. + EmitBranch(CondBlock); + + // Emit the fall-through block. + EmitBlock(AfterFor, true); +} + +/// GenerateCXXAggrDestructorHelper - Generates a helper function which when +/// invoked, calls the default destructor on array elements in reverse order of +/// construction. +llvm::Constant * +CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, + const ArrayType *Array, + llvm::Value *This) { + FunctionArgList Args; + ImplicitParamDecl *Dst = + ImplicitParamDecl::Create(getContext(), 0, + SourceLocation(), 0, + getContext().getPointerType(getContext().VoidTy)); + Args.push_back(std::make_pair(Dst, Dst->getType())); + + llvm::SmallString<16> Name; + llvm::raw_svector_ostream(Name) << "__tcf_" << (++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.str(), + &CGM.getModule()); + IdentifierInfo *II = &CGM.getContext().Idents.get(Name.str()); + FunctionDecl *FD = FunctionDecl::Create(getContext(), + getContext().getTranslationUnitDecl(), + SourceLocation(), II, R, 0, + FunctionDecl::Static, + false, true); + StartFunction(FD, R, Fn, Args, SourceLocation()); + QualType BaseElementTy = getContext().getBaseElementType(Array); + const llvm::Type *BasePtr = ConvertType(BaseElementTy); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = Builder.CreateBitCast(This, BasePtr); + EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); + FinishFunction(); + llvm::Type *Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), + 0); + llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty); + return m; +} + + +void +CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, + CXXCtorType Type, + llvm::Value *This, + CallExpr::const_arg_iterator ArgBeg, + CallExpr::const_arg_iterator ArgEnd) { + if (D->isCopyConstructor()) { + const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D->getDeclContext()); + if (ClassDecl->hasTrivialCopyConstructor()) { + assert(!ClassDecl->hasUserDeclaredCopyConstructor() && + "EmitCXXConstructorCall - user declared copy constructor"); + const Expr *E = (*ArgBeg); + QualType Ty = E->getType(); + llvm::Value *Src = EmitLValue(E).getAddress(); + EmitAggregateCopy(This, Src, Ty); + return; + } + } else if (D->isTrivial()) { + // FIXME: Track down why we're trying to generate calls to the trivial + // default constructor! + return; + } + + llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type)); + llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type); + + EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, VTT, ArgBeg, ArgEnd); +} + +void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, + CXXDtorType Type, + llvm::Value *This) { + llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type)); + llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(DD, Type); + + EmitCXXMemberCall(DD, Callee, ReturnValueSlot(), This, VTT, 0, 0); +} + +llvm::Value * +CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This, + const CXXRecordDecl *ClassDecl, + const CXXRecordDecl *BaseClassDecl) { + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8Ty(VMContext)->getPointerTo(); + + llvm::Value *VTablePtr = Builder.CreateBitCast(This, + Int8PtrTy->getPointerTo()); + VTablePtr = Builder.CreateLoad(VTablePtr, "vtable"); + + int64_t VBaseOffsetIndex = + CGM.getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl); + + llvm::Value *VBaseOffsetPtr = + Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetIndex, "vbase.offset.ptr"); + const llvm::Type *PtrDiffTy = + ConvertType(getContext().getPointerDiffType()); + + VBaseOffsetPtr = Builder.CreateBitCast(VBaseOffsetPtr, + PtrDiffTy->getPointerTo()); + + llvm::Value *VBaseOffset = Builder.CreateLoad(VBaseOffsetPtr, "vbase.offset"); + + return VBaseOffset; +} + +void CodeGenFunction::InitializeVtablePtrs(const CXXRecordDecl *ClassDecl) { + if (!ClassDecl->isDynamicClass()) + return; + + llvm::Constant *Vtable = CGM.getVtableInfo().getVtable(ClassDecl); + CGVtableInfo::AddrSubMap_t& AddressPoints = + *(*CGM.getVtableInfo().AddressPoints[ClassDecl])[ClassDecl]; + llvm::Value *ThisPtr = LoadCXXThis(); + const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassDecl); + + // Store address points for virtual bases + for (CXXRecordDecl::base_class_const_iterator I = + ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); I != E; ++I) { + const CXXBaseSpecifier &Base = *I; + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); + uint64_t Offset = Layout.getVBaseClassOffset(BaseClassDecl); + InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints, + ThisPtr, Offset); + } + + // Store address points for non-virtual bases and current class + InitializeVtablePtrsRecursive(ClassDecl, Vtable, AddressPoints, ThisPtr, 0); +} + +void CodeGenFunction::InitializeVtablePtrsRecursive( + const CXXRecordDecl *ClassDecl, + llvm::Constant *Vtable, + CGVtableInfo::AddrSubMap_t& AddressPoints, + llvm::Value *ThisPtr, + uint64_t Offset) { + if (!ClassDecl->isDynamicClass()) + return; + + // Store address points for non-virtual bases + const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassDecl); + for (CXXRecordDecl::base_class_const_iterator I = + ClassDecl->bases_begin(), E = ClassDecl->bases_end(); I != E; ++I) { + const CXXBaseSpecifier &Base = *I; + if (Base.isVirtual()) + continue; + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl()); + uint64_t NewOffset = Offset + Layout.getBaseClassOffset(BaseClassDecl); + InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints, + ThisPtr, NewOffset); + } + + // Compute the address point + assert(AddressPoints.count(std::make_pair(ClassDecl, Offset)) && + "Missing address point for class"); + uint64_t AddressPoint = AddressPoints[std::make_pair(ClassDecl, Offset)]; + llvm::Value *VtableAddressPoint = + Builder.CreateConstInBoundsGEP2_64(Vtable, 0, AddressPoint); + + // Compute the address to store the address point + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + llvm::Value *VtableField = Builder.CreateBitCast(ThisPtr, Int8PtrTy); + VtableField = Builder.CreateConstInBoundsGEP1_64(VtableField, Offset/8); + const llvm::Type *AddressPointPtrTy = + VtableAddressPoint->getType()->getPointerTo(); + VtableField = Builder.CreateBitCast(VtableField, AddressPointPtrTy); + + // Store address point + Builder.CreateStore(VtableAddressPoint, VtableField); +} + +llvm::Value *CodeGenFunction::LoadCXXVTT() { + assert((isa<CXXConstructorDecl>(CurFuncDecl) || + isa<CXXDestructorDecl>(CurFuncDecl)) && + "Must be in a C++ ctor or dtor to load the vtt parameter"); + + return Builder.CreateLoad(LocalDeclMap[CXXVTTDecl], "vtt"); +} diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 19695c8..ab8f663 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -65,6 +65,25 @@ llvm::DIDescriptor CGDebugInfo::getContext(const VarDecl *Decl, return CompileUnit; } +/// getFunctionName - Get function name for the given FunctionDecl. If the +/// name is constructred on demand (e.g. C++ destructor) then the name +/// is stored on the side. +llvm::StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) { + assert (FD && "Invalid FunctionDecl!"); + IdentifierInfo *FII = FD->getIdentifier(); + if (FII) + return FII->getName(); + + // Otherwise construct human readable name for debug info. + std::string NS = FD->getNameAsString(); + + // Copy this name on the side and use its reference. + unsigned Length = NS.length() + 1; + char *StrPtr = FunctionNames.Allocate<char>(Length); + strncpy(StrPtr, NS.c_str(), Length); + return llvm::StringRef(StrPtr); +} + /// getOrCreateCompileUnit - Get the compile unit from the cache or create a new /// one if necessary. This returns null for invalid source locations. llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) { @@ -972,18 +991,32 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, /// EmitFunctionStart - Constructs the debug code for entering a function - /// "llvm.dbg.func.start.". -void CGDebugInfo::EmitFunctionStart(llvm::StringRef Name, QualType FnType, +void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, llvm::Function *Fn, CGBuilderTy &Builder) { - 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.substr(1); + llvm::StringRef Name; + llvm::StringRef LinkageName; + + const Decl *D = GD.getDecl(); + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + Name = getFunctionName(FD); + if (Name[0] == '\01') + Name = Name.substr(1); + // Use mangled name as linkage name for c/c++ functions. + LinkageName = CGM.getMangledName(GD); + } else { + // Use llvm function name as linkage name. + Name = Fn->getName(); + // Skip the asm prefix if it exists. + if (Name[0] == '\01') + Name = Name.substr(1); + LinkageName = Name; + } - // FIXME: Why is this using CurLoc??? + // It is expected that CurLoc is set before using EmitFunctionStart. + // Usually, CurLoc points to the left bracket location of compound + // statement representing function body. llvm::DICompileUnit Unit = getOrCreateCompileUnit(CurLoc); SourceManager &SM = CGM.getContext().getSourceManager(); unsigned LineNo = SM.getPresumedLoc(CurLoc).getLine(); @@ -1379,7 +1412,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, else Unit = llvm::DICompileUnit(); - uint64_t offset = CGF->BlockDecls[Decl]; + CharUnits offset = CGF->BlockDecls[Decl]; llvm::SmallVector<llvm::Value *, 9> addr; llvm::LLVMContext &VMContext = CGM.getLLVMContext(); addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), @@ -1387,22 +1420,24 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), llvm::DIFactory::OpPlus)); addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - offset)); + offset.getQuantity())); if (BDRE->isByRef()) { addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), llvm::DIFactory::OpDeref)); addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), llvm::DIFactory::OpPlus)); - offset = CGF->LLVMPointerWidth/8; // offset of __forwarding field + // offset of __forwarding field + offset = CharUnits::fromQuantity(CGF->LLVMPointerWidth/8); addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - offset)); + offset.getQuantity())); addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), llvm::DIFactory::OpDeref)); addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), llvm::DIFactory::OpPlus)); - offset = XOffset/8; // offset of x field + // offset of x field + offset = CharUnits::fromQuantity(XOffset/8); addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - offset)); + offset.getQuantity())); } // Create the descriptor for the variable. diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index 7df2a62..8e88988 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -20,6 +20,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/Analysis/DebugInfo.h" #include "llvm/Support/ValueHandle.h" +#include "llvm/Support/Allocator.h" #include <map> #include "CGBuilder.h" @@ -35,6 +36,7 @@ namespace clang { namespace CodeGen { class CodeGenModule; class CodeGenFunction; + class GlobalDecl; /// CGDebugInfo - This class gathers all debug information during compilation /// and is responsible for emitting to llvm globals or pass directly to @@ -58,6 +60,10 @@ class CGDebugInfo { std::vector<llvm::TrackingVH<llvm::MDNode> > RegionStack; + /// FunctionNames - This is a storage for function names that are + /// constructed on demand. For example, C++ destructors, C++ operators etc.. + llvm::BumpPtrAllocator FunctionNames; + /// Helper functions for getOrCreateType. llvm::DIType CreateType(const BuiltinType *Ty, llvm::DICompileUnit U); llvm::DIType CreateType(const ComplexType *Ty, llvm::DICompileUnit U); @@ -93,7 +99,7 @@ public: /// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate /// start of a new function. - void EmitFunctionStart(llvm::StringRef Name, QualType FnType, + void EmitFunctionStart(GlobalDecl GD, QualType FnType, llvm::Function *Fn, CGBuilderTy &Builder); /// EmitRegionStart - Emit a call to llvm.dbg.region.start to indicate start @@ -149,6 +155,11 @@ private: /// CreateTypeNode - Create type metadata for a source language type. llvm::DIType CreateTypeNode(QualType Ty, llvm::DICompileUnit Unit); + + /// getFunctionName - Get function name for the given FunctionDecl. If the + /// name is constructred on demand (e.g. C++ destructor) then the name + /// is stored on the side. + llvm::StringRef getFunctionName(const FunctionDecl *FD); }; } // namespace CodeGen } // namespace clang diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 602cc9e..9606a71 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -473,7 +473,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { llvm::IntegerType::get(VMContext, LLVMPointerWidth); llvm::Value *SizeVal = llvm::ConstantInt::get(IntPtr, - getContext().getTypeSizeInChars(Ty).getRaw()); + getContext().getTypeSizeInChars(Ty).getQuantity()); const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext); if (Loc->getType() != BP) diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index 0b6ea5a..47773a0 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -120,6 +120,22 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, } void +CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D) { + const llvm::FunctionType *FTy + = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), + false); + + // Create a variable initialization function. + llvm::Function *Fn = + llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, + "__cxx_global_var_init", &TheModule); + + CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D); + + CXXGlobalInits.push_back(Fn); +} + +void CodeGenModule::EmitCXXGlobalInitFunc() { if (CXXGlobalInits.empty()) return; @@ -140,18 +156,26 @@ CodeGenModule::EmitCXXGlobalInitFunc() { AddGlobalCtor(Fn); } +void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, + const VarDecl *D) { + StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(), + SourceLocation()); + + llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D); + EmitCXXGlobalVarDeclInit(*D, DeclPtr); + + FinishFunction(); +} + void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, - const VarDecl **Decls, + llvm::Constant **Decls, unsigned NumDecls) { StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(), SourceLocation()); - for (unsigned i = 0; i != NumDecls; ++i) { - const VarDecl *D = Decls[i]; + for (unsigned i = 0; i != NumDecls; ++i) + Builder.CreateCall(Decls[i]); - llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D); - EmitCXXGlobalVarDeclInit(*D, DeclPtr); - } FinishFunction(); } diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index ab451cf..2358bb3 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -240,6 +240,132 @@ void CodeGenFunction::EmitCheck(llvm::Value *Address, unsigned Size) { EmitBlock(Cont); } + +llvm::Value *CodeGenFunction:: +EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, + bool isInc, bool isPre) { + QualType ValTy = E->getSubExpr()->getType(); + llvm::Value *InVal = EmitLoadOfLValue(LV, ValTy).getScalarVal(); + + int AmountVal = isInc ? 1 : -1; + + if (ValTy->isPointerType() && + ValTy->getAs<PointerType>()->isVariableArrayType()) { + // The amount of the addition/subtraction needs to account for the VLA size + ErrorUnsupported(E, "VLA pointer inc/dec"); + } + + llvm::Value *NextVal; + if (const llvm::PointerType *PT = + dyn_cast<llvm::PointerType>(InVal->getType())) { + llvm::Constant *Inc = + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), AmountVal); + if (!isa<llvm::FunctionType>(PT->getElementType())) { + QualType PTEE = ValTy->getPointeeType(); + if (const ObjCInterfaceType *OIT = + dyn_cast<ObjCInterfaceType>(PTEE)) { + // Handle interface types, which are not represented with a concrete + // type. + int size = getContext().getTypeSize(OIT) / 8; + if (!isInc) + size = -size; + Inc = llvm::ConstantInt::get(Inc->getType(), size); + const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext); + InVal = Builder.CreateBitCast(InVal, i8Ty); + NextVal = Builder.CreateGEP(InVal, Inc, "add.ptr"); + llvm::Value *lhs = LV.getAddress(); + lhs = Builder.CreateBitCast(lhs, llvm::PointerType::getUnqual(i8Ty)); + LV = LValue::MakeAddr(lhs, MakeQualifiers(ValTy)); + } else + NextVal = Builder.CreateInBoundsGEP(InVal, Inc, "ptrincdec"); + } else { + const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext); + NextVal = Builder.CreateBitCast(InVal, i8Ty, "tmp"); + NextVal = Builder.CreateGEP(NextVal, Inc, "ptrincdec"); + NextVal = Builder.CreateBitCast(NextVal, InVal->getType()); + } + } else if (InVal->getType() == llvm::Type::getInt1Ty(VMContext) && isInc) { + // Bool++ is an interesting case, due to promotion rules, we get: + // Bool++ -> Bool = Bool+1 -> Bool = (int)Bool+1 -> + // Bool = ((int)Bool+1) != 0 + // An interesting aspect of this is that increment is always true. + // Decrement does not have this property. + NextVal = llvm::ConstantInt::getTrue(VMContext); + } else if (isa<llvm::IntegerType>(InVal->getType())) { + NextVal = llvm::ConstantInt::get(InVal->getType(), AmountVal); + + // Signed integer overflow is undefined behavior. + if (ValTy->isSignedIntegerType()) + NextVal = Builder.CreateNSWAdd(InVal, NextVal, isInc ? "inc" : "dec"); + else + NextVal = Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec"); + } else { + // Add the inc/dec to the real part. + if (InVal->getType()->isFloatTy()) + NextVal = + llvm::ConstantFP::get(VMContext, + llvm::APFloat(static_cast<float>(AmountVal))); + else if (InVal->getType()->isDoubleTy()) + NextVal = + llvm::ConstantFP::get(VMContext, + llvm::APFloat(static_cast<double>(AmountVal))); + else { + llvm::APFloat F(static_cast<float>(AmountVal)); + bool ignored; + F.convert(Target.getLongDoubleFormat(), llvm::APFloat::rmTowardZero, + &ignored); + NextVal = llvm::ConstantFP::get(VMContext, F); + } + NextVal = Builder.CreateFAdd(InVal, NextVal, isInc ? "inc" : "dec"); + } + + // Store the updated result through the lvalue. + if (LV.isBitfield()) + EmitStoreThroughBitfieldLValue(RValue::get(NextVal), LV, ValTy, &NextVal); + else + EmitStoreThroughLValue(RValue::get(NextVal), LV, ValTy); + + // If this is a postinc, return the value read from memory, otherwise use the + // updated value. + return isPre ? NextVal : InVal; +} + + +CodeGenFunction::ComplexPairTy CodeGenFunction:: +EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV, + bool isInc, bool isPre) { + ComplexPairTy InVal = LoadComplexFromAddr(LV.getAddress(), + LV.isVolatileQualified()); + + llvm::Value *NextVal; + if (isa<llvm::IntegerType>(InVal.first->getType())) { + uint64_t AmountVal = isInc ? 1 : -1; + NextVal = llvm::ConstantInt::get(InVal.first->getType(), AmountVal, true); + + // Add the inc/dec to the real part. + NextVal = Builder.CreateAdd(InVal.first, NextVal, isInc ? "inc" : "dec"); + } else { + QualType ElemTy = E->getType()->getAs<ComplexType>()->getElementType(); + llvm::APFloat FVal(getContext().getFloatTypeSemantics(ElemTy), 1); + if (!isInc) + FVal.changeSign(); + NextVal = llvm::ConstantFP::get(getLLVMContext(), FVal); + + // Add the inc/dec to the real part. + NextVal = Builder.CreateFAdd(InVal.first, NextVal, isInc ? "inc" : "dec"); + } + + ComplexPairTy IncVal(NextVal, InVal.second); + + // Store the updated result through the lvalue. + StoreComplexToAddr(IncVal, LV.getAddress(), LV.isVolatileQualified()); + + // If this is a postinc, return the value read from memory, otherwise use the + // updated value. + return isPre ? IncVal : InVal; +} + + //===----------------------------------------------------------------------===// // LValue Expression Emission //===----------------------------------------------------------------------===// @@ -994,8 +1120,16 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { MakeQualifiers(ExprTy)); } case UnaryOperator::PreInc: - case UnaryOperator::PreDec: - return EmitUnsupportedLValue(E, "pre-inc/dec expression"); + case UnaryOperator::PreDec: { + LValue LV = EmitLValue(E->getSubExpr()); + bool isInc = E->getOpcode() == UnaryOperator::PreInc; + + if (E->getType()->isAnyComplexType()) + EmitComplexPrePostIncDec(E, LV, isInc, true/*isPre*/); + else + EmitScalarPrePostIncDec(E, LV, isInc, true/*isPre*/); + return LV; + } } } @@ -1139,16 +1273,16 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { QualType BaseType = getContext().getBaseElementType(VAT); - uint64_t BaseTypeSize = getContext().getTypeSize(BaseType) / 8; + CharUnits BaseTypeSize = getContext().getTypeSizeInChars(BaseType); Idx = Builder.CreateUDiv(Idx, llvm::ConstantInt::get(Idx->getType(), - BaseTypeSize)); + BaseTypeSize.getQuantity())); Address = Builder.CreateInBoundsGEP(Base, Idx, "arrayidx"); } else if (const ObjCInterfaceType *OIT = dyn_cast<ObjCInterfaceType>(E->getType())) { llvm::Value *InterfaceSize = llvm::ConstantInt::get(Idx->getType(), - getContext().getTypeSize(OIT) / 8); + getContext().getTypeSizeInChars(OIT).getQuantity()); Idx = Builder.CreateMul(Idx, InterfaceSize); @@ -1211,8 +1345,8 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { Base = EmitLValue(E->getBase()); } else { // Otherwise, the base is a normal rvalue (as in (V+V).x), emit it as such. - const VectorType *VT = E->getBase()->getType()->getAs<VectorType>(); - assert(VT && "Result must be a vector"); + assert(E->getBase()->getType()->getAs<VectorType>() && + "Result must be a vector"); llvm::Value *Vec = EmitScalarExpr(E->getBase()); // Store the vector to memory (because LValue wants an address). diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index b95fd79..c852d65 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -313,7 +313,8 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) { "Unexpected member pointer type!"); const DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr()); - const CXXMethodDecl *MD = cast<CXXMethodDecl>(DRE->getDecl()); + const CXXMethodDecl *MD = + cast<CXXMethodDecl>(DRE->getDecl())->getCanonicalDecl(); const llvm::Type *PtrDiffTy = CGF.ConvertType(CGF.getContext().getPointerDiffType()); diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 7992322..e264109 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -15,6 +15,334 @@ using namespace clang; using namespace CodeGen; +RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD, + llvm::Value *Callee, + ReturnValueSlot ReturnValue, + llvm::Value *This, + llvm::Value *VTT, + CallExpr::const_arg_iterator ArgBeg, + CallExpr::const_arg_iterator ArgEnd) { + assert(MD->isInstance() && + "Trying to emit a member call expr on a static method!"); + + const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + + CallArgList Args; + + // Push the this ptr. + Args.push_back(std::make_pair(RValue::get(This), + MD->getThisType(getContext()))); + + // If there is a VTT parameter, emit it. + if (VTT) { + QualType T = getContext().getPointerType(getContext().VoidPtrTy); + Args.push_back(std::make_pair(RValue::get(VTT), T)); + } + + // And the rest of the call args + EmitCallArgs(Args, FPT, ArgBeg, ArgEnd); + + QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType(); + return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee, + ReturnValue, Args, MD); +} + +/// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given +/// expr can be devirtualized. +static bool canDevirtualizeMemberFunctionCalls(const Expr *Base) { + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) { + if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) { + // This is a record decl. We know the type and can devirtualize it. + return VD->getType()->isRecordType(); + } + + return false; + } + + // We can always devirtualize calls on temporary object expressions. + if (isa<CXXTemporaryObjectExpr>(Base)) + return true; + + // And calls on bound temporaries. + if (isa<CXXBindTemporaryExpr>(Base)) + return true; + + // Check if this is a call expr that returns a record type. + if (const CallExpr *CE = dyn_cast<CallExpr>(Base)) + return CE->getCallReturnType()->isRecordType(); + + // We can't devirtualize the call. + return false; +} + +RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, + ReturnValueSlot ReturnValue) { + if (isa<BinaryOperator>(CE->getCallee()->IgnoreParens())) + return EmitCXXMemberPointerCallExpr(CE, ReturnValue); + + const MemberExpr *ME = cast<MemberExpr>(CE->getCallee()->IgnoreParens()); + const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl()); + + if (MD->isStatic()) { + // The method is static, emit it as we would a regular call. + llvm::Value *Callee = CGM.GetAddrOfFunction(MD); + return EmitCall(getContext().getPointerType(MD->getType()), Callee, + ReturnValue, CE->arg_begin(), CE->arg_end()); + } + + const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + llvm::Value *This; + + if (ME->isArrow()) + This = EmitScalarExpr(ME->getBase()); + else { + LValue BaseLV = EmitLValue(ME->getBase()); + This = BaseLV.getAddress(); + } + + if (MD->isCopyAssignment() && MD->isTrivial()) { + // We don't like to generate the trivial copy assignment operator when + // it isn't necessary; just produce the proper effect here. + llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress(); + EmitAggregateCopy(This, RHS, CE->getType()); + return RValue::get(This); + } + + // C++ [class.virtual]p12: + // Explicit qualification with the scope operator (5.1) suppresses the + // virtual call mechanism. + // + // We also don't emit a virtual call if the base expression has a record type + // because then we know what the type is. + llvm::Value *Callee; + if (const CXXDestructorDecl *Destructor + = dyn_cast<CXXDestructorDecl>(MD)) { + if (Destructor->isTrivial()) + return RValue::get(0); + if (MD->isVirtual() && !ME->hasQualifier() && + !canDevirtualizeMemberFunctionCalls(ME->getBase())) { + Callee = BuildVirtualCall(Destructor, Dtor_Complete, This, Ty); + } else { + Callee = CGM.GetAddrOfFunction(GlobalDecl(Destructor, Dtor_Complete), Ty); + } + } else if (MD->isVirtual() && !ME->hasQualifier() && + !canDevirtualizeMemberFunctionCalls(ME->getBase())) { + Callee = BuildVirtualCall(MD, This, Ty); + } else { + Callee = CGM.GetAddrOfFunction(MD, Ty); + } + + return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0, + CE->arg_begin(), CE->arg_end()); +} + +RValue +CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, + ReturnValueSlot ReturnValue) { + const BinaryOperator *BO = + cast<BinaryOperator>(E->getCallee()->IgnoreParens()); + const Expr *BaseExpr = BO->getLHS(); + const Expr *MemFnExpr = BO->getRHS(); + + const MemberPointerType *MPT = + MemFnExpr->getType()->getAs<MemberPointerType>(); + const FunctionProtoType *FPT = + MPT->getPointeeType()->getAs<FunctionProtoType>(); + const CXXRecordDecl *RD = + cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl()); + + const llvm::FunctionType *FTy = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT), + FPT->isVariadic()); + + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8Ty(VMContext)->getPointerTo(); + + // Get the member function pointer. + llvm::Value *MemFnPtr = + CreateTempAlloca(ConvertType(MemFnExpr->getType()), "mem.fn"); + EmitAggExpr(MemFnExpr, MemFnPtr, /*VolatileDest=*/false); + + // Emit the 'this' pointer. + llvm::Value *This; + + if (BO->getOpcode() == BinaryOperator::PtrMemI) + This = EmitScalarExpr(BaseExpr); + else + This = EmitLValue(BaseExpr).getAddress(); + + // Adjust it. + llvm::Value *Adj = Builder.CreateStructGEP(MemFnPtr, 1); + Adj = Builder.CreateLoad(Adj, "mem.fn.adj"); + + llvm::Value *Ptr = Builder.CreateBitCast(This, Int8PtrTy, "ptr"); + Ptr = Builder.CreateGEP(Ptr, Adj, "adj"); + + This = Builder.CreateBitCast(Ptr, This->getType(), "this"); + + llvm::Value *FnPtr = Builder.CreateStructGEP(MemFnPtr, 0, "mem.fn.ptr"); + + const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType()); + + llvm::Value *FnAsInt = Builder.CreateLoad(FnPtr, "fn"); + + // If the LSB in the function pointer is 1, the function pointer points to + // a virtual function. + llvm::Value *IsVirtual + = Builder.CreateAnd(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1), + "and"); + + IsVirtual = Builder.CreateTrunc(IsVirtual, + llvm::Type::getInt1Ty(VMContext)); + + llvm::BasicBlock *FnVirtual = createBasicBlock("fn.virtual"); + llvm::BasicBlock *FnNonVirtual = createBasicBlock("fn.nonvirtual"); + llvm::BasicBlock *FnEnd = createBasicBlock("fn.end"); + + Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual); + EmitBlock(FnVirtual); + + const llvm::Type *VTableTy = + FTy->getPointerTo()->getPointerTo()->getPointerTo(); + + llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy); + VTable = Builder.CreateLoad(VTable); + + VTable = Builder.CreateGEP(VTable, FnAsInt, "fn"); + + // Since the function pointer is 1 plus the virtual table offset, we + // subtract 1 by using a GEP. + VTable = Builder.CreateConstGEP1_64(VTable, (uint64_t)-1); + + llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn"); + + EmitBranch(FnEnd); + EmitBlock(FnNonVirtual); + + // If the function is not virtual, just load the pointer. + llvm::Value *NonVirtualFn = Builder.CreateLoad(FnPtr, "fn"); + NonVirtualFn = Builder.CreateIntToPtr(NonVirtualFn, FTy->getPointerTo()); + + EmitBlock(FnEnd); + + llvm::PHINode *Callee = Builder.CreatePHI(FTy->getPointerTo()); + Callee->reserveOperandSpace(2); + Callee->addIncoming(VirtualFn, FnVirtual); + Callee->addIncoming(NonVirtualFn, FnNonVirtual); + + CallArgList Args; + + QualType ThisType = + getContext().getPointerType(getContext().getTagDeclType(RD)); + + // Push the this ptr. + Args.push_back(std::make_pair(RValue::get(This), ThisType)); + + // And the rest of the call args + EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end()); + QualType ResultType = BO->getType()->getAs<FunctionType>()->getResultType(); + return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee, + ReturnValue, Args); +} + +RValue +CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, + const CXXMethodDecl *MD, + ReturnValueSlot ReturnValue) { + assert(MD->isInstance() && + "Trying to emit a member call expr on a static method!"); + + if (MD->isCopyAssignment()) { + const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(MD->getDeclContext()); + if (ClassDecl->hasTrivialCopyAssignment()) { + assert(!ClassDecl->hasUserDeclaredCopyAssignment() && + "EmitCXXOperatorMemberCallExpr - user declared copy assignment"); + llvm::Value *This = EmitLValue(E->getArg(0)).getAddress(); + llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress(); + QualType Ty = E->getType(); + EmitAggregateCopy(This, Src, Ty); + return RValue::get(This); + } + } + + const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + + llvm::Value *This = EmitLValue(E->getArg(0)).getAddress(); + + llvm::Value *Callee; + if (MD->isVirtual() && !canDevirtualizeMemberFunctionCalls(E->getArg(0))) + Callee = BuildVirtualCall(MD, This, Ty); + else + Callee = CGM.GetAddrOfFunction(MD, Ty); + + return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0, + E->arg_begin() + 1, E->arg_end()); +} + +void +CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, + const CXXConstructExpr *E) { + assert(Dest && "Must have a destination!"); + const CXXConstructorDecl *CD = E->getConstructor(); + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(E->getType()); + // For a copy constructor, even if it is trivial, must fall thru so + // its argument is code-gen'ed. + if (!CD->isCopyConstructor()) { + QualType InitType = E->getType(); + if (Array) + InitType = getContext().getBaseElementType(Array); + const CXXRecordDecl *RD = + cast<CXXRecordDecl>(InitType->getAs<RecordType>()->getDecl()); + if (RD->hasTrivialConstructor()) + return; + } + // Code gen optimization to eliminate copy constructor and return + // its first argument instead. + if (getContext().getLangOptions().ElideConstructors && E->isElidable()) { + const Expr *Arg = E->getArg(0); + + if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { + assert((ICE->getCastKind() == CastExpr::CK_NoOp || + ICE->getCastKind() == CastExpr::CK_ConstructorConversion || + ICE->getCastKind() == CastExpr::CK_UserDefinedConversion) && + "Unknown implicit cast kind in constructor elision"); + Arg = ICE->getSubExpr(); + } + + if (const CXXFunctionalCastExpr *FCE = dyn_cast<CXXFunctionalCastExpr>(Arg)) + Arg = FCE->getSubExpr(); + + if (const CXXBindTemporaryExpr *BindExpr = + dyn_cast<CXXBindTemporaryExpr>(Arg)) + Arg = BindExpr->getSubExpr(); + + EmitAggExpr(Arg, Dest, false); + return; + } + if (Array) { + QualType BaseElementTy = getContext().getBaseElementType(Array); + const llvm::Type *BasePtr = ConvertType(BaseElementTy); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + Builder.CreateBitCast(Dest, BasePtr); + + EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr, + E->arg_begin(), E->arg_end()); + } + else + // Call the constructor. + EmitCXXConstructorCall(CD, Ctor_Complete, Dest, + E->arg_begin(), E->arg_end()); +} + static uint64_t CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) { const RecordType *RT = ElementType->getAs<RecordType>(); if (!RT) @@ -405,7 +733,8 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { /*isVariadic=*/false); llvm::Value *Callee = BuildVirtualCall(Dtor, Dtor_Deleting, Ptr, Ty); - EmitCXXMemberCall(Dtor, Callee, ReturnValueSlot(), Ptr, 0, 0); + EmitCXXMemberCall(Dtor, Callee, ReturnValueSlot(), Ptr, /*VTT=*/0, + 0, 0); // The dtor took care of deleting the object. ShouldCallDelete = false; diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index be2239f..5ec336c 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -145,7 +145,10 @@ public: // Operators. ComplexPairTy VisitPrePostIncDec(const UnaryOperator *E, - bool isInc, bool isPre); + bool isInc, bool isPre) { + LValue LV = CGF.EmitLValue(E->getSubExpr()); + return CGF.EmitComplexPrePostIncDec(E, LV, isInc, isPre); + } ComplexPairTy VisitUnaryPostDec(const UnaryOperator *E) { return VisitPrePostIncDec(E, false, false); } @@ -355,40 +358,6 @@ ComplexPairTy ComplexExprEmitter::EmitCast(Expr *Op, QualType DestTy) { return ComplexPairTy(Elt, llvm::Constant::getNullValue(Elt->getType())); } -ComplexPairTy ComplexExprEmitter::VisitPrePostIncDec(const UnaryOperator *E, - bool isInc, bool isPre) { - LValue LV = CGF.EmitLValue(E->getSubExpr()); - ComplexPairTy InVal = EmitLoadOfComplex(LV.getAddress(), - LV.isVolatileQualified()); - - llvm::Value *NextVal; - if (isa<llvm::IntegerType>(InVal.first->getType())) { - uint64_t AmountVal = isInc ? 1 : -1; - NextVal = llvm::ConstantInt::get(InVal.first->getType(), AmountVal, true); - - // Add the inc/dec to the real part. - NextVal = Builder.CreateAdd(InVal.first, NextVal, isInc ? "inc" : "dec"); - } else { - QualType ElemTy = E->getType()->getAs<ComplexType>()->getElementType(); - llvm::APFloat FVal(CGF.getContext().getFloatTypeSemantics(ElemTy), 1); - if (!isInc) - FVal.changeSign(); - NextVal = llvm::ConstantFP::get(CGF.getLLVMContext(), FVal); - - // Add the inc/dec to the real part. - NextVal = Builder.CreateFAdd(InVal.first, NextVal, isInc ? "inc" : "dec"); - } - - ComplexPairTy IncVal(NextVal, InVal.second); - - // Store the updated result through the lvalue. - EmitStoreOfComplex(IncVal, LV.getAddress(), LV.isVolatileQualified()); - - // If this is a postinc, return the value read from memory, otherwise use the - // updated value. - return isPre ? IncVal : InVal; -} - ComplexPairTy ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *E) { TestAndClearIgnoreReal(); TestAndClearIgnoreImag(); diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index d428983..dec06e2 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -408,6 +408,8 @@ public: llvm::Constant *EmitMemberFunctionPointer(CXXMethodDecl *MD) { assert(MD->isInstance() && "Member function must not be static!"); + MD = MD->getCanonicalDecl(); + const llvm::Type *PtrDiffTy = CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); @@ -633,32 +635,6 @@ public: return ConstStructBuilder::BuildStruct(CGM, CGF, ILE); } - llvm::Constant *EmitVectorInitialization(InitListExpr *ILE) { - const llvm::VectorType *VType = - cast<llvm::VectorType>(ConvertType(ILE->getType())); - const llvm::Type *ElemTy = VType->getElementType(); - std::vector<llvm::Constant*> Elts; - unsigned NumElements = VType->getNumElements(); - unsigned NumInitElements = ILE->getNumInits(); - - unsigned NumInitableElts = std::min(NumInitElements, NumElements); - - // Copy initializer elements. - unsigned i = 0; - for (; i < NumInitableElts; ++i) { - Expr *Init = ILE->getInit(i); - llvm::Constant *C = CGM.EmitConstantExpr(Init, Init->getType(), CGF); - if (!C) - return 0; - Elts.push_back(C); - } - - for (; i < NumElements; ++i) - Elts.push_back(llvm::Constant::getNullValue(ElemTy)); - - return llvm::ConstantVector::get(VType, Elts); - } - llvm::Constant *VisitImplicitValueInitExpr(ImplicitValueInitExpr* E) { return CGM.EmitNullConstant(E->getType()); } @@ -682,8 +658,9 @@ public: if (ILE->getType()->isUnionType()) return EmitUnionInitialization(ILE); + // If ILE was a constant vector, we would have handled it already. if (ILE->getType()->isVectorType()) - return EmitVectorInitialization(ILE); + return 0; assert(0 && "Unable to handle InitListExpr"); // Get rid of control reaches end of void function warning. @@ -833,7 +810,7 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, const llvm::Type *DestTy = getTypes().ConvertTypeForMem(DestType); llvm::Constant *Offset = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), - Result.Val.getLValueOffset()); + Result.Val.getLValueOffset().getQuantity()); llvm::Constant *C; if (const Expr *LVBase = Result.Val.getLValueBase()) { diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 93646d6..690a7dc 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -181,12 +181,6 @@ public: Value *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { return EmitLoadOfLValue(E); } - Value *VisitStringLiteral(Expr *E) { return EmitLValue(E).getAddress(); } - Value *VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { - return EmitLValue(E).getAddress(); - } - - Value *VisitPredefinedExpr(Expr *E) { return EmitLValue(E).getAddress(); } Value *VisitInitListExpr(InitListExpr *E); @@ -214,7 +208,10 @@ public: Value *VisitBlockDeclRefExpr(const BlockDeclRefExpr *E); // Unary Operators. - Value *VisitPrePostIncDec(const UnaryOperator *E, bool isInc, bool isPre); + Value *VisitPrePostIncDec(const UnaryOperator *E, bool isInc, bool isPre) { + LValue LV = EmitLValue(E->getSubExpr()); + return CGF.EmitScalarPrePostIncDec(E, LV, isInc, isPre); + } Value *VisitUnaryPostDec(const UnaryOperator *E) { return VisitPrePostIncDec(E, false, false); } @@ -1009,98 +1006,6 @@ Value *ScalarExprEmitter::VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) { // Unary Operators //===----------------------------------------------------------------------===// -Value *ScalarExprEmitter::VisitPrePostIncDec(const UnaryOperator *E, - bool isInc, bool isPre) { - LValue LV = EmitLValue(E->getSubExpr()); - QualType ValTy = E->getSubExpr()->getType(); - Value *InVal = CGF.EmitLoadOfLValue(LV, ValTy).getScalarVal(); - - llvm::LLVMContext &VMContext = CGF.getLLVMContext(); - - int AmountVal = isInc ? 1 : -1; - - if (ValTy->isPointerType() && - ValTy->getAs<PointerType>()->isVariableArrayType()) { - // The amount of the addition/subtraction needs to account for the VLA size - CGF.ErrorUnsupported(E, "VLA pointer inc/dec"); - } - - Value *NextVal; - if (const llvm::PointerType *PT = - dyn_cast<llvm::PointerType>(InVal->getType())) { - llvm::Constant *Inc = - llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), AmountVal); - if (!isa<llvm::FunctionType>(PT->getElementType())) { - QualType PTEE = ValTy->getPointeeType(); - if (const ObjCInterfaceType *OIT = - dyn_cast<ObjCInterfaceType>(PTEE)) { - // Handle interface types, which are not represented with a concrete type. - int size = CGF.getContext().getTypeSize(OIT) / 8; - if (!isInc) - size = -size; - Inc = llvm::ConstantInt::get(Inc->getType(), size); - const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext); - InVal = Builder.CreateBitCast(InVal, i8Ty); - NextVal = Builder.CreateGEP(InVal, Inc, "add.ptr"); - llvm::Value *lhs = LV.getAddress(); - lhs = Builder.CreateBitCast(lhs, llvm::PointerType::getUnqual(i8Ty)); - LV = LValue::MakeAddr(lhs, CGF.MakeQualifiers(ValTy)); - } else - NextVal = Builder.CreateInBoundsGEP(InVal, Inc, "ptrincdec"); - } else { - const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext); - NextVal = Builder.CreateBitCast(InVal, i8Ty, "tmp"); - NextVal = Builder.CreateGEP(NextVal, Inc, "ptrincdec"); - NextVal = Builder.CreateBitCast(NextVal, InVal->getType()); - } - } else if (InVal->getType() == llvm::Type::getInt1Ty(VMContext) && isInc) { - // Bool++ is an interesting case, due to promotion rules, we get: - // Bool++ -> Bool = Bool+1 -> Bool = (int)Bool+1 -> - // Bool = ((int)Bool+1) != 0 - // An interesting aspect of this is that increment is always true. - // Decrement does not have this property. - NextVal = llvm::ConstantInt::getTrue(VMContext); - } else if (isa<llvm::IntegerType>(InVal->getType())) { - NextVal = llvm::ConstantInt::get(InVal->getType(), AmountVal); - - // Signed integer overflow is undefined behavior. - if (ValTy->isSignedIntegerType()) - NextVal = Builder.CreateNSWAdd(InVal, NextVal, isInc ? "inc" : "dec"); - else - NextVal = Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec"); - } else { - // Add the inc/dec to the real part. - if (InVal->getType()->isFloatTy()) - NextVal = - llvm::ConstantFP::get(VMContext, - llvm::APFloat(static_cast<float>(AmountVal))); - else if (InVal->getType()->isDoubleTy()) - NextVal = - llvm::ConstantFP::get(VMContext, - llvm::APFloat(static_cast<double>(AmountVal))); - else { - llvm::APFloat F(static_cast<float>(AmountVal)); - bool ignored; - F.convert(CGF.Target.getLongDoubleFormat(), llvm::APFloat::rmTowardZero, - &ignored); - NextVal = llvm::ConstantFP::get(VMContext, F); - } - NextVal = Builder.CreateFAdd(InVal, NextVal, isInc ? "inc" : "dec"); - } - - // Store the updated result through the lvalue. - if (LV.isBitfield()) - CGF.EmitStoreThroughBitfieldLValue(RValue::get(NextVal), LV, ValTy, - &NextVal); - else - CGF.EmitStoreThroughLValue(RValue::get(NextVal), LV, ValTy); - - // If this is a postinc, return the value read from memory, otherwise use the - // updated value. - return isPre ? NextVal : InVal; -} - - Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) { TestAndClearIgnoreResultAssign(); Value *Op = Visit(E->getSubExpr()); @@ -1405,7 +1310,7 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) { if (const ObjCInterfaceType *OIT = dyn_cast<ObjCInterfaceType>(ElementType)) { llvm::Value *InterfaceSize = llvm::ConstantInt::get(Idx->getType(), - CGF.getContext().getTypeSize(OIT) / 8); + CGF.getContext().getTypeSizeInChars(OIT).getQuantity()); Idx = Builder.CreateMul(Idx, InterfaceSize); const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext); Value *Casted = Builder.CreateBitCast(Ptr, i8Ty); @@ -1469,7 +1374,8 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { dyn_cast<ObjCInterfaceType>(LHSElementType)) { llvm::Value *InterfaceSize = llvm::ConstantInt::get(Idx->getType(), - CGF.getContext().getTypeSize(OIT) / 8); + CGF.getContext(). + getTypeSizeInChars(OIT).getQuantity()); Idx = Builder.CreateMul(Idx, InterfaceSize); const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext); Value *LHSCasted = Builder.CreateBitCast(Ops.LHS, i8Ty); @@ -1493,14 +1399,14 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { Value *LHS = Ops.LHS; Value *RHS = Ops.RHS; - uint64_t ElementSize; + CharUnits ElementSize; // Handle GCC extension for pointer arithmetic on void* and function pointer // types. if (LHSElementType->isVoidType() || LHSElementType->isFunctionType()) { - ElementSize = 1; + ElementSize = CharUnits::One(); } else { - ElementSize = CGF.getContext().getTypeSize(LHSElementType) / 8; + ElementSize = CGF.getContext().getTypeSizeInChars(LHSElementType); } const llvm::Type *ResultType = ConvertType(Ops.Ty); @@ -1509,13 +1415,14 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { Value *BytesBetween = Builder.CreateSub(LHS, RHS, "sub.ptr.sub"); // Optimize out the shift for element size of 1. - if (ElementSize == 1) + if (ElementSize.isOne()) return BytesBetween; // Otherwise, do a full sdiv. This uses the "exact" form of sdiv, since // pointer difference in C is only defined in the case where both operands // are pointing to elements of an array. - Value *BytesPerElt = llvm::ConstantInt::get(ResultType, ElementSize); + Value *BytesPerElt = + llvm::ConstantInt::get(ResultType, ElementSize.getQuantity()); return Builder.CreateExactSDiv(BytesBetween, BytesPerElt, "sub.ptr.div"); } } @@ -1971,47 +1878,6 @@ Value *CodeGenFunction::EmitComplexToScalarConversion(ComplexPairTy Src, DstTy); } -Value *CodeGenFunction::EmitShuffleVector(Value* V1, Value *V2, ...) { - assert(V1->getType() == V2->getType() && - "Vector operands must be of the same type"); - unsigned NumElements = - cast<llvm::VectorType>(V1->getType())->getNumElements(); - - va_list va; - va_start(va, V2); - - llvm::SmallVector<llvm::Constant*, 16> Args; - for (unsigned i = 0; i < NumElements; i++) { - int n = va_arg(va, int); - assert(n >= 0 && n < (int)NumElements * 2 && - "Vector shuffle index out of bounds!"); - Args.push_back(llvm::ConstantInt::get( - llvm::Type::getInt32Ty(VMContext), n)); - } - - const char *Name = va_arg(va, const char *); - va_end(va); - - llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], NumElements); - - return Builder.CreateShuffleVector(V1, V2, Mask, Name); -} - -llvm::Value *CodeGenFunction::EmitVector(llvm::Value * const *Vals, - unsigned NumVals, bool isSplat) { - llvm::Value *Vec - = llvm::UndefValue::get(llvm::VectorType::get(Vals[0]->getType(), NumVals)); - - for (unsigned i = 0, e = NumVals; i != e; ++i) { - llvm::Value *Val = isSplat ? Vals[0] : Vals[i]; - llvm::Value *Idx = llvm::ConstantInt::get( - llvm::Type::getInt32Ty(VMContext), i); - Vec = Builder.CreateInsertElement(Vec, Val, Idx, "tmp"); - } - - return Vec; -} - LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) { llvm::Value *V; // object->isa or (*object).isa diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index 95f67ae..e7a2093 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -114,9 +114,11 @@ private: llvm::Constant *ExportUniqueString(const std::string &Str, const std::string prefix); llvm::Constant *MakeGlobal(const llvm::StructType *Ty, - std::vector<llvm::Constant*> &V, const std::string &Name=""); + std::vector<llvm::Constant*> &V, const std::string &Name="", + llvm::GlobalValue::LinkageTypes linkage=llvm::GlobalValue::InternalLinkage); llvm::Constant *MakeGlobal(const llvm::ArrayType *Ty, - std::vector<llvm::Constant*> &V, const std::string &Name=""); + std::vector<llvm::Constant*> &V, const std::string &Name="", + llvm::GlobalValue::LinkageTypes linkage=llvm::GlobalValue::InternalLinkage); llvm::GlobalVariable *ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID, const ObjCIvarDecl *Ivar); void EmitClassRef(const std::string &className); @@ -215,8 +217,11 @@ static std::string SymbolNameForClass(const std::string &ClassName) { static std::string SymbolNameForMethod(const std::string &ClassName, const std::string &CategoryName, const std::string &MethodName, bool isClassMethod) { - return "_OBJC_METHOD_" + ClassName + "("+CategoryName+")"+ - (isClassMethod ? "+" : "-") + MethodName; + std::string MethodNameColonStripped = MethodName; + std::replace(MethodNameColonStripped.begin(), MethodNameColonStripped.end(), + ':', '_'); + return std::string(isClassMethod ? "_c_" : "_i_") + ClassName + "_" + + CategoryName + "_" + MethodNameColonStripped; } CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm) @@ -257,6 +262,10 @@ CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm) llvm::Value *CGObjCGNU::GetClass(CGBuilderTy &Builder, const ObjCInterfaceDecl *OID) { llvm::Value *ClassName = CGM.GetAddrOfConstantCString(OID->getNameAsString()); + // With the incompatible ABI, this will need to be replaced with a direct + // reference to the class symbol. For the compatible nonfragile ABI we are + // still performing this lookup at run time but emitting the symbol for the + // class externally so that we can make the switch later. EmitClassRef(OID->getNameAsString()); ClassName = Builder.CreateStructGEP(ClassName, 0); @@ -323,14 +332,16 @@ llvm::Constant *CGObjCGNU::ExportUniqueString(const std::string &Str, } llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::StructType *Ty, - std::vector<llvm::Constant*> &V, const std::string &Name) { + std::vector<llvm::Constant*> &V, const std::string &Name, + llvm::GlobalValue::LinkageTypes linkage) { llvm::Constant *C = llvm::ConstantStruct::get(Ty, V); return new llvm::GlobalVariable(TheModule, Ty, false, llvm::GlobalValue::InternalLinkage, C, Name); } llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty, - std::vector<llvm::Constant*> &V, const std::string &Name) { + std::vector<llvm::Constant*> &V, const std::string &Name, + llvm::GlobalValue::LinkageTypes linkage) { llvm::Constant *C = llvm::ConstantArray::get(Ty, V); return new llvm::GlobalVariable(TheModule, Ty, false, llvm::GlobalValue::InternalLinkage, C, Name); @@ -703,7 +714,10 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure( Elements.push_back(IvarOffsets); Elements.push_back(Properties); // Create an instance of the structure - return MakeGlobal(ClassTy, Elements, SymbolNameForClass(Name)); + // This is now an externally visible symbol, so that we can speed up class + // messages in the next ABI. + return MakeGlobal(ClassTy, Elements, SymbolNameForClass(Name), + llvm::GlobalValue::ExternalLinkage); } llvm::Constant *CGObjCGNU::GenerateProtocolMethodList( @@ -1607,7 +1621,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, Params.push_back(PtrTy); llvm::Value *RethrowFn = CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), - Params, false), "objc_exception_throw"); + Params, false), "_Unwind_Resume"); bool isTry = isa<ObjCAtTryStmt>(S); llvm::BasicBlock *TryBlock = CGF.createBasicBlock("try"); @@ -1923,7 +1937,7 @@ llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable( if (!IvarOffsetPointer) { uint64_t Offset = ComputeIvarBaseOffset(CGM, ID, Ivar); llvm::ConstantInt *OffsetGuess = - llvm::ConstantInt::get(LongTy, Offset, "ivar"); + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Offset, "ivar"); // Don't emit the guess in non-PIC code because the linker will not be able // to replace it with the real version for a library. In non-PIC code you // must compile with the fragile ABI if you want to use ivars from a diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp index db6c507..29552ce 100644 --- a/lib/CodeGen/CGRTTI.cpp +++ b/lib/CodeGen/CGRTTI.cpp @@ -360,28 +360,12 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(QualType Ty) { // If we're in an anonymous namespace, then we always want internal linkage. if (RD->isInAnonymousNamespace() || !RD->hasLinkage()) return llvm::GlobalVariable::InternalLinkage; - + + // If this class does not have a vtable, we want weak linkage. if (!RD->isDynamicClass()) return llvm::GlobalValue::WeakODRLinkage; - // Get the key function. - const CXXMethodDecl *KeyFunction = RD->getASTContext().getKeyFunction(RD); - if (!KeyFunction) { - // There is no key function, the RTTI descriptor is emitted with weak_odr - // linkage. - return llvm::GlobalValue::WeakODRLinkage; - } - - // If the key function is defined, but inlined, then the RTTI descriptor is - // emitted with weak_odr linkage. - const FunctionDecl* KeyFunctionDefinition; - KeyFunction->getBody(KeyFunctionDefinition); - - if (KeyFunctionDefinition->isInlined()) - return llvm::GlobalValue::WeakODRLinkage; - - // Otherwise, the RTTI descriptor is emitted with external linkage. - return llvm::GlobalValue::ExternalLinkage; + return CodeGenModule::getVtableLinkage(RD); } case Type::Vector: diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index 7930f71..ae900d6 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -160,17 +160,19 @@ private: // vtable for use in computing the initializers for the VTT. llvm::DenseMap<CtorVtable_t, int64_t> &subAddressPoints; + /// AddressPoints - Address points for this vtable. + CGVtableInfo::AddressPointsMapTy& AddressPoints; + typedef CXXRecordDecl::method_iterator method_iter; - const bool Extern; const uint32_t LLVMPointerWidth; Index_t extra; typedef std::vector<std::pair<const CXXRecordDecl *, int64_t> > Path_t; static llvm::DenseMap<CtorVtable_t, int64_t>& AllocAddressPoint(CodeGenModule &cgm, const CXXRecordDecl *l, const CXXRecordDecl *c) { - CodeGenModule::AddrMap_t *&oref = cgm.AddressPoints[l]; + CGVtableInfo::AddrMap_t *&oref = cgm.getVtableInfo().AddressPoints[l]; if (oref == 0) - oref = new CodeGenModule::AddrMap_t; + oref = new CGVtableInfo::AddrMap_t; llvm::DenseMap<CtorVtable_t, int64_t> *&ref = (*oref)[c]; if (ref == 0) @@ -193,14 +195,15 @@ private: public: VtableBuilder(const CXXRecordDecl *MostDerivedClass, const CXXRecordDecl *l, uint64_t lo, CodeGenModule &cgm, - bool build) + bool build, CGVtableInfo::AddressPointsMapTy& AddressPoints) : 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)) { + AddressPoints(AddressPoints), + LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) + { Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); if (BuildVtable) { QualType ClassType = CGM.getContext().getTagDeclType(MostDerivedClass); @@ -213,7 +216,7 @@ public: return VtableComponents; } - llvm::DenseMap<const CXXRecordDecl *, Index_t> &getVBIndex() + llvm::DenseMap<const CXXRecordDecl *, uint64_t> &getVBIndex() { return VBIndex; } SavedAdjustmentsVectorTy &getSavedAdjustments() @@ -463,6 +466,7 @@ public: RD->getNameAsCString(), Class->getNameAsCString(), LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint)); subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint; + AddressPoints[BaseSubobject(RD, Offset)] = AddressPoint; // Now also add the address point for all our primary bases. while (1) { @@ -479,6 +483,7 @@ public: RD->getNameAsCString(), Class->getNameAsCString(), LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint)); subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint; + AddressPoints[BaseSubobject(RD, Offset)] = AddressPoint; } } @@ -827,7 +832,6 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual, 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); @@ -844,6 +848,7 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual, SavedAdjustments.push_back( std::make_pair(GD, std::make_pair(OGD, ThisAdjustment))); } + VCall[GD] = idx; return true; } @@ -1090,7 +1095,8 @@ CGVtableInfo::getAdjustments(GlobalDecl GD) { if (!SavedAdjustmentRecords.insert(RD).second) return 0; - VtableBuilder b(RD, RD, 0, CGM, false); + AddressPointsMapTy AddressPoints; + VtableBuilder b(RD, RD, 0, CGM, false, AddressPoints); D1(printf("vtable %s\n", RD->getNameAsCString())); b.GenerateVtableForBase(RD); b.GenerateVtableForVBases(RD); @@ -1118,7 +1124,8 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, // FIXME: This seems expensive. Can we do a partial job to get // just this data. - VtableBuilder b(RD, RD, 0, CGM, false); + AddressPointsMapTy AddressPoints; + VtableBuilder b(RD, RD, 0, CGM, false, AddressPoints); D1(printf("vtable %s\n", RD->getNameAsCString())); b.GenerateVtableForBase(RD); b.GenerateVtableForVBases(RD); @@ -1139,7 +1146,7 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, uint64_t CGVtableInfo::getVtableAddressPoint(const CXXRecordDecl *RD) { uint64_t AddressPoint = - (*(*(CGM.AddressPoints[RD]))[RD])[std::make_pair(RD, 0)]; + (*(*(CGM.getVtableInfo().AddressPoints[RD]))[RD])[std::make_pair(RD, 0)]; return AddressPoint; } @@ -1148,7 +1155,8 @@ llvm::GlobalVariable * CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage, bool GenerateDefinition, const CXXRecordDecl *LayoutClass, - const CXXRecordDecl *RD, uint64_t Offset) { + const CXXRecordDecl *RD, uint64_t Offset, + AddressPointsMapTy& AddressPoints) { llvm::SmallString<256> OutName; if (LayoutClass != RD) CGM.getMangleContext().mangleCXXCtorVtable(LayoutClass, Offset / 8, @@ -1158,8 +1166,10 @@ CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage, llvm::StringRef Name = OutName.str(); llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name); - if (GV == 0 || CGM.AddressPoints[LayoutClass] == 0 || GV->isDeclaration()) { - VtableBuilder b(RD, LayoutClass, Offset, CGM, GenerateDefinition); + if (GV == 0 || CGM.getVtableInfo().AddressPoints[LayoutClass] == 0 || + GV->isDeclaration()) { + VtableBuilder b(RD, LayoutClass, Offset, CGM, GenerateDefinition, + AddressPoints); D1(printf("vtable %s\n", RD->getNameAsCString())); // First comes the vtables for all the non-virtual bases... @@ -1206,11 +1216,51 @@ class VTTBuilder { /// BLayout - Layout for the most derived class that this vtable is being /// built for. const ASTRecordLayout &BLayout; - CodeGenModule::AddrMap_t &AddressPoints; + CGVtableInfo::AddrMap_t &AddressPoints; // vtbl - A pointer to the vtable for Class. llvm::Constant *ClassVtbl; llvm::LLVMContext &VMContext; + llvm::DenseMap<const CXXRecordDecl *, uint64_t> SubVTTIndicies; + + bool GenerateDefinition; + + llvm::DenseMap<BaseSubobject, llvm::Constant *> CtorVtables; + llvm::DenseMap<std::pair<const CXXRecordDecl *, BaseSubobject>, uint64_t> + CtorVtableAddressPoints; + + llvm::Constant *getCtorVtable(const BaseSubobject &Base) { + if (!GenerateDefinition) + return 0; + + llvm::Constant *&CtorVtable = CtorVtables[Base]; + if (!CtorVtable) { + // Build the vtable. + CGVtableInfo::CtorVtableInfo Info + = CGM.getVtableInfo().getCtorVtable(Class, Base); + + CtorVtable = Info.Vtable; + + // Add the address points for this base. + for (CGVtableInfo::AddressPointsMapTy::const_iterator I = + Info.AddressPoints.begin(), E = Info.AddressPoints.end(); + I != E; ++I) { + uint64_t &AddressPoint = + CtorVtableAddressPoints[std::make_pair(Base.getBase(), I->first)]; + + // Check if we already have the address points for this base. + if (AddressPoint) + break; + + // Otherwise, insert it. + AddressPoint = I->second; + } + } + + return CtorVtable; + } + + /// BuildVtablePtr - Build up a referene to the given secondary vtable llvm::Constant *BuildVtablePtr(llvm::Constant *Vtable, const CXXRecordDecl *VtableClass, @@ -1270,14 +1320,17 @@ class VTTBuilder { // FIXME: Slightly too many of these for __ZTT8test8_B2 llvm::Constant *init; if (BaseMorallyVirtual) - init = BuildVtablePtr(vtbl, VtblClass, RD, Offset); + init = GenerateDefinition ? + BuildVtablePtr(vtbl, VtblClass, RD, Offset) : 0; else { - init = CGM.getVtableInfo().getCtorVtable(Class, Base, BaseOffset); + init = GenerateDefinition ? + getCtorVtable(BaseSubobject(Base, BaseOffset)) : 0; subvtbl = init; subVtblClass = Base; - init = BuildVtablePtr(init, Class, Base, BaseOffset); + init = GenerateDefinition ? + BuildVtablePtr(init, Class, Base, BaseOffset) : 0; } Inits.push_back(init); } @@ -1296,14 +1349,16 @@ class VTTBuilder { // First comes the primary virtual table pointer... if (MorallyVirtual) { - Vtable = ClassVtbl; + Vtable = GenerateDefinition ? ClassVtbl : 0; VtableClass = Class; } else { - Vtable = CGM.getVtableInfo().getCtorVtable(Class, RD, Offset); + Vtable = GenerateDefinition ? + getCtorVtable(BaseSubobject(RD, Offset)) : 0; VtableClass = RD; } - llvm::Constant *Init = BuildVtablePtr(Vtable, VtableClass, RD, Offset); + llvm::Constant *Init = GenerateDefinition ? + BuildVtablePtr(Vtable, VtableClass, RD, Offset) : 0; Inits.push_back(Init); // then the secondary VTTs.... @@ -1326,6 +1381,10 @@ class VTTBuilder { continue; const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base); + + // Remember the sub-VTT index. + SubVTTIndicies[Base] = Inits.size(); + BuildVTT(Base, BaseOffset, MorallyVirtual); } } @@ -1338,6 +1397,9 @@ class VTTBuilder { const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); if (i->isVirtual() && !SeenVBase.count(Base)) { + // Remember the sub-VTT index. + SubVTTIndicies[Base] = Inits.size(); + SeenVBase.insert(Base); uint64_t BaseOffset = BLayout.getVBaseClassOffset(Base); BuildVTT(Base, BaseOffset, true); @@ -1348,15 +1410,18 @@ class VTTBuilder { public: VTTBuilder(std::vector<llvm::Constant *> &inits, const CXXRecordDecl *c, - CodeGenModule &cgm) + CodeGenModule &cgm, bool GenerateDefinition) : Inits(inits), Class(c), CGM(cgm), BLayout(cgm.getContext().getASTRecordLayout(c)), - AddressPoints(*cgm.AddressPoints[c]), - VMContext(cgm.getModule().getContext()) { + AddressPoints(*cgm.getVtableInfo().AddressPoints[c]), + VMContext(cgm.getModule().getContext()), + GenerateDefinition(GenerateDefinition) { // First comes the primary virtual table pointer for the complete class... ClassVtbl = CGM.getVtableInfo().getVtable(Class); - Inits.push_back(BuildVtablePtr(ClassVtbl, Class, Class, 0)); + llvm::Constant *Init = GenerateDefinition ? + BuildVtablePtr(ClassVtbl, Class, Class, 0) : 0; + Inits.push_back(Init); // then the secondary VTTs... SecondaryVTTs(Class); @@ -1367,11 +1432,16 @@ public: // and last, the virtual VTTs. VirtualVTTs(Class); } + + llvm::DenseMap<const CXXRecordDecl *, uint64_t> &getSubVTTIndicies() { + return SubVTTIndicies; + } }; } llvm::GlobalVariable * CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, + bool GenerateDefinition, const CXXRecordDecl *RD) { // Only classes that have virtual bases need a VTT. if (RD->getNumVBases() == 0) @@ -1381,23 +1451,36 @@ CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, CGM.getMangleContext().mangleCXXVTT(RD, OutName); llvm::StringRef Name = OutName.str(); - D1(printf("vtt %s\n", RD->getNameAsCString())); - std::vector<llvm::Constant *> inits; - VTTBuilder b(inits, RD, CGM); + llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name); + if (GV == 0 || GV->isDeclaration()) { + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); - 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); + std::vector<llvm::Constant *> inits; + VTTBuilder b(inits, RD, CGM, GenerateDefinition); + + const llvm::ArrayType *Type = llvm::ArrayType::get(Int8PtrTy, inits.size()); + llvm::Constant *Init = 0; + if (GenerateDefinition) + Init = llvm::ConstantArray::get(Type, inits); + + llvm::GlobalVariable *OldGV = GV; + GV = new llvm::GlobalVariable(CGM.getModule(), Type, /*isConstant=*/true, + Linkage, Init, Name); + CGM.setGlobalVisibility(GV, RD); + + if (OldGV) { + GV->takeName(OldGV); + llvm::Constant *NewPtr = + llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); + OldGV->replaceAllUsesWith(NewPtr); + OldGV->eraseFromParent(); + } + } - return VTT; + return GV; } void CGVtableInfo::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, @@ -1408,28 +1491,44 @@ void CGVtableInfo::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, return; } - Vtable = GenerateVtable(Linkage, /*GenerateDefinition=*/true, RD, RD, 0); - GenerateVTT(Linkage, RD); + AddressPointsMapTy AddressPoints; + Vtable = GenerateVtable(Linkage, /*GenerateDefinition=*/true, RD, RD, 0, + AddressPoints); + GenerateVTT(Linkage, /*GenerateDefinition=*/true, RD); } llvm::GlobalVariable *CGVtableInfo::getVtable(const CXXRecordDecl *RD) { llvm::GlobalVariable *Vtable = Vtables.lookup(RD); - if (!Vtable) + if (!Vtable) { + AddressPointsMapTy AddressPoints; Vtable = GenerateVtable(llvm::GlobalValue::ExternalLinkage, - /*GenerateDefinition=*/false, RD, RD, 0); + /*GenerateDefinition=*/false, RD, RD, 0, + AddressPoints); + } return Vtable; } -llvm::GlobalVariable * -CGVtableInfo::getCtorVtable(const CXXRecordDecl *LayoutClass, - const CXXRecordDecl *RD, uint64_t Offset) { - return GenerateVtable(llvm::GlobalValue::InternalLinkage, - /*GenerateDefinition=*/true, - LayoutClass, RD, Offset); +CGVtableInfo::CtorVtableInfo +CGVtableInfo::getCtorVtable(const CXXRecordDecl *RD, + const BaseSubobject &Base) { + CtorVtableInfo Info; + + Info.Vtable = GenerateVtable(llvm::GlobalValue::InternalLinkage, + /*GenerateDefinition=*/true, + RD, Base.getBase(), Base.getBaseOffset(), + Info.AddressPoints); + return Info; +} + +llvm::GlobalVariable *CGVtableInfo::getVTT(const CXXRecordDecl *RD) { + return GenerateVTT(llvm::GlobalValue::ExternalLinkage, + /*GenerateDefinition=*/false, RD); + } + void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) { const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); const CXXRecordDecl *RD = MD->getParent(); @@ -1445,28 +1544,10 @@ void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) { // 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; } - 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; - // Emit the data. - GenerateClassData(Linkage, RD); + GenerateClassData(CGM.getVtableLinkage(RD), RD); for (CXXRecordDecl::method_iterator i = RD->method_begin(), e = RD->method_end(); i != e; ++i) { @@ -1481,3 +1562,47 @@ void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) { } } +bool CGVtableInfo::needsVTTParameter(GlobalDecl GD) { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + + // We don't have any virtual bases, just return early. + if (!MD->getParent()->getNumVBases()) + return false; + + // Check if we have a base constructor. + if (isa<CXXConstructorDecl>(MD) && GD.getCtorType() == Ctor_Base) + return true; + + // Check if we have a base destructor. + if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base) + return true; + + return false; +} + +uint64_t CGVtableInfo::getSubVTTIndex(const CXXRecordDecl *RD, + const CXXRecordDecl *Base) { + ClassPairTy ClassPair(RD, Base); + + SubVTTIndiciesTy::iterator I = + SubVTTIndicies.find(ClassPair); + if (I != SubVTTIndicies.end()) + return I->second; + + std::vector<llvm::Constant *> inits; + VTTBuilder Builder(inits, RD, CGM, /*GenerateDefinition=*/false); + + for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I = + Builder.getSubVTTIndicies().begin(), + E = Builder.getSubVTTIndicies().end(); I != E; ++I) { + // Insert all indices. + ClassPairTy ClassPair(RD, I->first); + + SubVTTIndicies.insert(std::make_pair(ClassPair, I->second)); + } + + I = SubVTTIndicies.find(ClassPair); + assert(I != SubVTTIndicies.end() && "Did not find index!"); + + return I->second; +} diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h index eed5b64..471d638 100644 --- a/lib/CodeGen/CGVtable.h +++ b/lib/CodeGen/CGVtable.h @@ -61,11 +61,83 @@ public: ThunkAdjustment ReturnAdjustment; }; +// BaseSubobject - Uniquely identifies a direct or indirect base class. +// Stores both the base class decl and the offset from the most derived class to +// the base class. +class BaseSubobject { + /// Base - The base class declaration. + const CXXRecordDecl *Base; + + /// BaseOffset - The offset from the most derived class to the base class. + uint64_t BaseOffset; + +public: + BaseSubobject(const CXXRecordDecl *Base, uint64_t BaseOffset) + : Base(Base), BaseOffset(BaseOffset) { } + + /// getBase - Returns the base class declaration. + const CXXRecordDecl *getBase() const { return Base; } + + /// getBaseOffset - Returns the base class offset. + uint64_t getBaseOffset() const { return BaseOffset; } + + friend bool operator==(const BaseSubobject &LHS, const BaseSubobject &RHS) { + return LHS.Base == RHS.Base && LHS.BaseOffset == RHS.BaseOffset; + } +}; + +} // end namespace CodeGen +} // end namespace clang + +namespace llvm { + +template<> struct DenseMapInfo<clang::CodeGen::BaseSubobject> { + static clang::CodeGen::BaseSubobject getEmptyKey() { + return clang::CodeGen::BaseSubobject( + DenseMapInfo<const clang::CXXRecordDecl *>::getEmptyKey(), + DenseMapInfo<uint64_t>::getEmptyKey()); + } + + static clang::CodeGen::BaseSubobject getTombstoneKey() { + return clang::CodeGen::BaseSubobject( + DenseMapInfo<const clang::CXXRecordDecl *>::getTombstoneKey(), + DenseMapInfo<uint64_t>::getTombstoneKey()); + } + + static unsigned getHashValue(const clang::CodeGen::BaseSubobject &Base) { + return + DenseMapInfo<const clang::CXXRecordDecl *>::getHashValue(Base.getBase()) ^ + DenseMapInfo<uint64_t>::getHashValue(Base.getBaseOffset()); + } + + static bool isEqual(const clang::CodeGen::BaseSubobject &LHS, + const clang::CodeGen::BaseSubobject &RHS) { + return LHS == RHS; + } +}; + +// It's OK to treat BaseSubobject as a POD type. +template <> struct isPodLike<clang::CodeGen::BaseSubobject> { + static const bool value = true; +}; + +} + +namespace clang { +namespace CodeGen { + class CGVtableInfo { public: typedef std::vector<std::pair<GlobalDecl, ThunkAdjustment> > AdjustmentVectorTy; + typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t; + typedef llvm::DenseMap<CtorVtable_t, int64_t> AddrSubMap_t; + typedef llvm::DenseMap<const CXXRecordDecl *, AddrSubMap_t *> AddrMap_t; + llvm::DenseMap<const CXXRecordDecl *, AddrMap_t*> AddressPoints; + + typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy; + private: CodeGenModule &CGM; @@ -93,6 +165,9 @@ private: SavedAdjustmentsTy SavedAdjustments; llvm::DenseSet<const CXXRecordDecl*> SavedAdjustmentRecords; + typedef llvm::DenseMap<ClassPairTy, uint64_t> SubVTTIndiciesTy; + SubVTTIndiciesTy SubVTTIndicies; + /// getNumVirtualFunctionPointers - Return the number of virtual function /// pointers in the vtable for a given record decl. uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD); @@ -110,15 +185,26 @@ private: llvm::GlobalVariable * GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage, bool GenerateDefinition, const CXXRecordDecl *LayoutClass, - const CXXRecordDecl *RD, uint64_t Offset); + const CXXRecordDecl *RD, uint64_t Offset, + AddressPointsMapTy& AddressPoints); llvm::GlobalVariable *GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, + bool GenerateDefinition, const CXXRecordDecl *RD); public: CGVtableInfo(CodeGenModule &CGM) : CGM(CGM) { } + /// needsVTTParameter - Return whether the given global decl needs a VTT + /// parameter, which it does if it's a base constructor or destructor with + /// virtual bases. + static bool needsVTTParameter(GlobalDecl GD); + + /// getSubVTTIndex - Return the index of the sub-VTT for the base class of the + /// given record decl. + uint64_t getSubVTTIndex(const CXXRecordDecl *RD, const CXXRecordDecl *Base); + /// getMethodVtableIndex - Return the index (relative to the vtable address /// point) where the function pointer for the given virtual function is /// stored. @@ -140,14 +226,26 @@ public: uint64_t getVtableAddressPoint(const CXXRecordDecl *RD); llvm::GlobalVariable *getVtable(const CXXRecordDecl *RD); - llvm::GlobalVariable *getCtorVtable(const CXXRecordDecl *RD, - const CXXRecordDecl *Class, - uint64_t Offset); + /// CtorVtableInfo - Information about a constructor vtable. + struct CtorVtableInfo { + /// Vtable - The vtable itself. + llvm::GlobalVariable *Vtable; + + /// AddressPoints - The address points in this constructor vtable. + AddressPointsMapTy AddressPoints; + + CtorVtableInfo() : Vtable(0) { } + }; + + CtorVtableInfo getCtorVtable(const CXXRecordDecl *RD, + const BaseSubobject &Base); + + llvm::GlobalVariable *getVTT(const CXXRecordDecl *RD); void MaybeEmitVtable(GlobalDecl GD); }; -} -} +} // end namespace CodeGen +} // end namespace clang #endif diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index 3c26484..45469d3 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -29,5 +29,5 @@ add_clang_library(clangCodeGen CodeGenTypes.cpp Mangle.cpp ModuleBuilder.cpp - TargetABIInfo.cpp + TargetInfo.cpp ) diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index f904f04..f0a5c64 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -190,15 +190,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, QualType FnType = getContext().getFunctionType(RetTy, 0, 0, false, 0); // Emit subprogram debug descriptor. - // FIXME: The cast here is a huge hack. if (CGDebugInfo *DI = getDebugInfo()) { DI->setLocation(StartLoc); - if (isa<FunctionDecl>(D)) { - DI->EmitFunctionStart(CGM.getMangledName(GD), FnType, CurFn, Builder); - } else { - // Just use LLVM function name. - DI->EmitFunctionStart(Fn->getName(), FnType, CurFn, Builder); - } + DI->EmitFunctionStart(GD, FnType, CurFn, Builder); } // FIXME: Leaked. @@ -230,26 +224,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, } } -static bool NeedsVTTParameter(GlobalDecl GD) { - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - - // We don't have any virtual bases, just return early. - if (!MD->getParent()->getNumVBases()) - return false; - - // Check if we have a base constructor. - if (isa<CXXConstructorDecl>(MD) && GD.getCtorType() == Ctor_Base) - return true; - - // Check if we have a base destructor. - if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base) - return true; - - return false; -} - -void CodeGenFunction::GenerateCode(GlobalDecl GD, - llvm::Function *Fn) { +void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) { const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); // Check if we should generate debug info for this function. @@ -271,7 +246,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, Args.push_back(std::make_pair(CXXThisDecl, CXXThisDecl->getType())); // Check if we need a VTT parameter as well. - if (NeedsVTTParameter(GD)) { + if (CGVtableInfo::needsVTTParameter(GD)) { // FIXME: The comment about using a fake decl above applies here too. QualType T = getContext().getPointerType(getContext().VoidPtrTy); CXXVTTDecl = @@ -597,7 +572,7 @@ llvm::Value *CodeGenFunction::EmitVLASize(QualType Ty) { ElemSize = EmitVLASize(ElemTy); else ElemSize = llvm::ConstantInt::get(SizeTy, - getContext().getTypeSize(ElemTy) / 8); + getContext().getTypeSizeInChars(ElemTy).getQuantity()); llvm::Value *NumElements = EmitScalarExpr(VAT->getSizeExpr()); NumElements = Builder.CreateIntCast(NumElements, SizeTy, false, "tmp"); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 273ddca..30ad663 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -17,6 +17,7 @@ #include "clang/AST/Type.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/CharUnits.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" @@ -463,7 +464,7 @@ public: llvm::Value *BuildBlockLiteralTmp(const BlockExpr *); llvm::Constant *BuildDescriptorBlockDecl(bool BlockHasCopyDispose, - uint64_t Size, + CharUnits Size, const llvm::StructType *, std::vector<HelperInfo> *); @@ -471,14 +472,14 @@ public: const BlockInfo& Info, const Decl *OuterFuncDecl, llvm::DenseMap<const Decl*, llvm::Value*> ldm, - uint64_t &Size, uint64_t &Align, + CharUnits &Size, uint64_t &Align, llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls, bool &subBlockHasCopyDispose); void BlockForwardSelf(); llvm::Value *LoadBlockStruct(); - uint64_t AllocateBlockDecl(const BlockDeclRefExpr *E); + CharUnits AllocateBlockDecl(const BlockDeclRefExpr *E); llvm::Value *GetAddrOfBlockDecl(const BlockDeclRefExpr *E); const llvm::Type *BuildByRefType(const ValueDecl *D); @@ -517,7 +518,7 @@ public: void InitializeVtablePtrsRecursive(const CXXRecordDecl *ClassDecl, llvm::Constant *Vtable, - CodeGenModule::AddrSubMap_t& AddressPoints, + CGVtableInfo::AddrSubMap_t& AddressPoints, llvm::Value *ThisPtr, uint64_t Offset); @@ -728,6 +729,10 @@ public: /// generating code for an C++ member function. llvm::Value *LoadCXXThis(); + /// LoadCXXVTT - Load the VTT parameter to base constructors/destructors have + /// virtual bases. + llvm::Value *LoadCXXVTT(); + /// GetAddressOfBaseClass - This function will add the necessary delta to the /// load of 'this' and returns address of the base class. // FIXME. This currently only does a derived to non-virtual base conversion. @@ -794,7 +799,7 @@ public: llvm::Value *NumElements, llvm::Value *This); - llvm::Constant * GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, + llvm::Constant *GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, const ArrayType *Array, llvm::Value *This); @@ -815,6 +820,10 @@ public: void EmitCheck(llvm::Value *, unsigned Size); + llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, + bool isInc, bool isPre); + ComplexPairTy EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV, + bool isInc, bool isPre); //===--------------------------------------------------------------------===// // Declaration Emission //===--------------------------------------------------------------------===// @@ -1057,6 +1066,7 @@ public: llvm::Value *Callee, ReturnValueSlot ReturnValue, llvm::Value *This, + llvm::Value *VTT, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd); RValue EmitCXXMemberCallExpr(const CXXMemberCallExpr *E, @@ -1081,10 +1091,6 @@ public: llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E); - llvm::Value *EmitShuffleVector(llvm::Value* V1, llvm::Value *V2, ...); - llvm::Value *EmitVector(llvm::Value * const *Vals, unsigned NumVals, - bool isSplat = false); - llvm::Value *EmitObjCProtocolExpr(const ObjCProtocolExpr *E); llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E); llvm::Value *EmitObjCSelectorExpr(const ObjCSelectorExpr *E); @@ -1184,9 +1190,11 @@ public: /// GenerateCXXGlobalInitFunc - Generates code for initializing global /// variables. void GenerateCXXGlobalInitFunc(llvm::Function *Fn, - const VarDecl **Decls, + llvm::Constant **Decls, unsigned NumDecls); + void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D); + void EmitCXXConstructExpr(llvm::Value *Dest, const CXXConstructExpr *E); RValue EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E, diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index d497471..5ecc30e 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -17,6 +17,7 @@ #include "CGCall.h" #include "CGObjCRuntime.h" #include "Mangle.h" +#include "TargetInfo.h" #include "clang/CodeGen/CodeGenOptions.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" @@ -42,8 +43,9 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, Diagnostic &diags) : BlockModule(C, M, TD, Types, *this), Context(C), Features(C.getLangOptions()), CodeGenOpts(CGO), TheModule(M), - TheTargetData(TD), Diags(diags), Types(C, M, TD), MangleCtx(C), - VtableInfo(*this), Runtime(0), + TheTargetData(TD), TheTargetCodeGenInfo(0), Diags(diags), + Types(C, M, TD, getTargetCodeGenInfo().getABIInfo()), + MangleCtx(C), VtableInfo(*this), Runtime(0), MemCpyFn(0), MemMoveFn(0), MemSetFn(0), CFConstantStringClassRef(0), VMContext(M.getContext()) { @@ -66,10 +68,8 @@ CodeGenModule::~CodeGenModule() { } void CodeGenModule::Release() { - // We need to call this first because it can add deferred declarations. - EmitCXXGlobalInitFunc(); - EmitDeferred(); + EmitCXXGlobalInitFunc(); if (Runtime) if (llvm::Function *ObjCInitFunction = Runtime->ModuleInitFunction()) AddGlobalCtor(ObjCInitFunction); @@ -378,6 +378,8 @@ void CodeGenModule::SetCommonAttributes(const Decl *D, if (const SectionAttr *SA = D->getAttr<SectionAttr>()) GV->setSection(SA->getName()); + + getTargetCodeGenInfo().SetTargetAttributes(D, GV, *this); } void CodeGenModule::SetInternalFunctionAttributes(const Decl *D, @@ -537,7 +539,8 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) { const CXXRecordDecl *RD = MD->getParent(); if (MD->isOutOfLine() && RD->isDynamicClass()) { const CXXMethodDecl *KeyFunction = getContext().getKeyFunction(RD); - if (KeyFunction == MD->getCanonicalDecl()) + if (KeyFunction && + KeyFunction->getCanonicalDecl() == MD->getCanonicalDecl()) return false; } } @@ -876,6 +879,57 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) { EmitGlobalVarDefinition(D); } +llvm::GlobalVariable::LinkageTypes +CodeGenModule::getVtableLinkage(const CXXRecordDecl *RD) { + if (RD->isInAnonymousNamespace() || !RD->hasLinkage()) + return llvm::GlobalVariable::InternalLinkage; + + if (const CXXMethodDecl *KeyFunction + = RD->getASTContext().getKeyFunction(RD)) { + // If this class has a key function, use that to determine the linkage of + // the vtable. + const FunctionDecl *Def = 0; + if (KeyFunction->getBody(Def)) + KeyFunction = cast<CXXMethodDecl>(Def); + + switch (KeyFunction->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + if (KeyFunction->isInlined()) + return llvm::GlobalVariable::WeakODRLinkage; + + return llvm::GlobalVariable::ExternalLinkage; + + case TSK_ImplicitInstantiation: + case TSK_ExplicitInstantiationDefinition: + return llvm::GlobalVariable::WeakODRLinkage; + + case TSK_ExplicitInstantiationDeclaration: + // FIXME: Use available_externally linkage. However, this currently + // breaks LLVM's build due to undefined symbols. + // return llvm::GlobalVariable::AvailableExternallyLinkage; + return llvm::GlobalVariable::WeakODRLinkage; + } + } + + switch (RD->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + case TSK_ImplicitInstantiation: + case TSK_ExplicitInstantiationDefinition: + return llvm::GlobalVariable::WeakODRLinkage; + + case TSK_ExplicitInstantiationDeclaration: + // FIXME: Use available_externally linkage. However, this currently + // breaks LLVM's build due to undefined symbols. + // return llvm::GlobalVariable::AvailableExternallyLinkage; + return llvm::GlobalVariable::WeakODRLinkage; + } + + // Silence GCC warning. + return llvm::GlobalVariable::WeakODRLinkage; +} + static CodeGenModule::GVALinkage GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) { // Everything located semantically within an anonymous namespace is @@ -909,6 +963,7 @@ GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) { void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { llvm::Constant *Init = 0; QualType ASTTy = D->getType(); + bool NonConstInit = false; if (D->getInit() == 0) { // This is a tentative definition; tentative definitions are @@ -928,8 +983,9 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { if (!Init) { QualType T = D->getInit()->getType(); if (getLangOptions().CPlusPlus) { - CXXGlobalInits.push_back(D); + EmitCXXGlobalVarDeclInitFunc(D); Init = EmitNullConstant(T); + NonConstInit = true; } else { ErrorUnsupported(D, "static initializer"); Init = llvm::UndefValue::get(getTypes().ConvertType(T)); @@ -990,7 +1046,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { // If it is safe to mark the global 'constant', do so now. GV->setConstant(false); - if (DeclIsConstantGlobal(Context, D)) + if (!NonConstInit && DeclIsConstantGlobal(Context, D)) GV->setConstant(true); GV->setAlignment(getContext().getDeclAlignInBytes(D)); diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 939c66c..c7aa7a4 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -43,6 +43,7 @@ namespace llvm { } namespace clang { + class TargetCodeGenInfo; class ASTContext; class FunctionDecl; class IdentifierInfo; @@ -85,6 +86,7 @@ class CodeGenModule : public BlockModule { const CodeGenOptions &CodeGenOpts; llvm::Module &TheModule; const llvm::TargetData &TheTargetData; + mutable const TargetCodeGenInfo *TheTargetCodeGenInfo; Diagnostic &Diags; CodeGenTypes Types; MangleContext MangleCtx; @@ -153,7 +155,7 @@ class CodeGenModule : public BlockModule { /// CXXGlobalInits - Variables with global initializers that need to run /// before main. - std::vector<const VarDecl*> CXXGlobalInits; + std::vector<llvm::Constant*> CXXGlobalInits; /// CFConstantStringClassRef - Cached reference to the class for constant /// strings. This value has type int * but is actually an Obj-C class pointer. @@ -191,6 +193,7 @@ public: Diagnostic &getDiags() const { return Diags; } const llvm::TargetData &getTargetData() const { return TheTargetData; } llvm::LLVMContext &getLLVMContext() { return VMContext; } + const TargetCodeGenInfo &getTargetCodeGenInfo() const; /// getDeclVisibilityMode - Compute the visibility of the decl \arg D. LangOptions::VisibilityMode getDeclVisibilityMode(const Decl *D) const; @@ -232,11 +235,6 @@ public: BuildCovariantThunk(const GlobalDecl &GD, bool Extern, const CovariantThunkAdjustment &Adjustment); - typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t; - typedef llvm::DenseMap<CtorVtable_t, int64_t> AddrSubMap_t; - typedef llvm::DenseMap<const CXXRecordDecl *, AddrSubMap_t *> AddrMap_t; - llvm::DenseMap<const CXXRecordDecl *, AddrMap_t*> AddressPoints; - /// GetCXXBaseClassOffset - Returns the offset from a derived class to its /// base class. Returns null if the offset is 0. llvm::Constant *GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl, @@ -412,6 +410,11 @@ public: GVA_TemplateInstantiation }; + /// getVtableLinkage - Return the appropriate linkage for the vtable, VTT, + /// and type information of the given class. + static llvm::GlobalVariable::LinkageTypes + getVtableLinkage(const CXXRecordDecl *RD); + private: /// UniqueMangledName - Unique a name by (if necessary) inserting it into the /// MangledNames string map. @@ -475,7 +478,9 @@ private: /// EmitCXXGlobalInitFunc - Emit a function that initializes C++ globals. void EmitCXXGlobalInitFunc(); - + + void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D); + // FIXME: Hardcoding priority here is gross. void AddGlobalCtor(llvm::Function *Ctor, int Priority=65535); void AddGlobalDtor(llvm::Function *Dtor, int Priority=65535); diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index cd34e0c..838f62a 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -28,9 +28,9 @@ using namespace clang; using namespace CodeGen; CodeGenTypes::CodeGenTypes(ASTContext &Ctx, llvm::Module& M, - const llvm::TargetData &TD) + const llvm::TargetData &TD, const ABIInfo &Info) : Context(Ctx), Target(Ctx.Target), TheModule(M), TheTargetData(TD), - TheABIInfo(0) { + TheABIInfo(Info) { } CodeGenTypes::~CodeGenTypes() { @@ -38,13 +38,10 @@ CodeGenTypes::~CodeGenTypes() { I = CGRecordLayouts.begin(), E = CGRecordLayouts.end(); I != E; ++I) delete I->second; - { - llvm::FoldingSet<CGFunctionInfo>::iterator - I = FunctionInfos.begin(), E = FunctionInfos.end(); - while (I != E) - delete &*I++; - } - delete TheABIInfo; + + for (llvm::FoldingSet<CGFunctionInfo>::iterator + I = FunctionInfos.begin(), E = FunctionInfos.end(); I != E; ) + delete &*I++; } /// ConvertType - Convert the specified type to its LLVM form. @@ -56,9 +53,8 @@ const llvm::Type *CodeGenTypes::ConvertType(QualType T) { // circular types. Loop through all these defered pointees, if any, and // resolve them now. while (!PointersToResolve.empty()) { - std::pair<QualType, llvm::OpaqueType*> P = - PointersToResolve.back(); - PointersToResolve.pop_back(); + std::pair<QualType, llvm::OpaqueType*> P = PointersToResolve.pop_back_val(); + // We can handle bare pointers here because we know that the only pointers // to the Opaque type are P.second and from other types. Refining the // opqaue type away will invalidate P.second, but we don't mind :). @@ -88,9 +84,10 @@ const llvm::Type *CodeGenTypes::ConvertTypeRecursive(QualType T) { const llvm::Type *CodeGenTypes::ConvertTypeForMemRecursive(QualType T) { const llvm::Type *ResultType = ConvertTypeRecursive(T); - if (ResultType == llvm::Type::getInt1Ty(getLLVMContext())) + if (ResultType->isInteger(1)) return llvm::IntegerType::get(getLLVMContext(), (unsigned)Context.getTypeSize(T)); + // FIXME: Should assert that the llvm type and AST type has the same size. return ResultType; } @@ -102,7 +99,7 @@ const llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T) { const llvm::Type *R = ConvertType(T); // If this is a non-bool type, don't map it. - if (R != llvm::Type::getInt1Ty(getLLVMContext())) + if (!R->isInteger(1)) return R; // Otherwise, return an integer of the target-specified size. @@ -384,11 +381,10 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { QualType ETy = cast<MemberPointerType>(Ty).getPointeeType(); const llvm::Type *PtrDiffTy = ConvertTypeRecursive(Context.getPointerDiffType()); - if (ETy->isFunctionType()) { + if (ETy->isFunctionType()) return llvm::StructType::get(TheModule.getContext(), PtrDiffTy, PtrDiffTy, NULL); - } else - return PtrDiffTy; + return PtrDiffTy; } case Type::TemplateSpecialization: @@ -436,10 +432,8 @@ const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) { // Okay, this is a definition of a type. Compile the implementation now. - if (TD->isEnum()) { - // Don't bother storing enums in TagDeclTypes. + if (TD->isEnum()) // Don't bother storing enums in TagDeclTypes. return ConvertTypeRecursive(cast<EnumDecl>(TD)->getIntegerType()); - } // This decl could well be recursive. In this case, insert an opaque // definition of this type, which the recursive uses will get. We will then @@ -450,15 +444,13 @@ const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) { llvm::PATypeHolder ResultHolder = llvm::OpaqueType::get(getLLVMContext()); TagDeclTypes.insert(std::make_pair(Key, ResultHolder)); - const llvm::Type *ResultType; const RecordDecl *RD = cast<const RecordDecl>(TD); // Layout fields. - CGRecordLayout *Layout = - CGRecordLayoutBuilder::ComputeLayout(*this, RD); + CGRecordLayout *Layout = CGRecordLayoutBuilder::ComputeLayout(*this, RD); CGRecordLayouts[Key] = Layout; - ResultType = Layout->getLLVMType(); + const llvm::Type *ResultType = Layout->getLLVMType(); // Refine our Opaque type to ResultType. This can invalidate ResultType, so // make sure to read the result out of the holder. @@ -500,8 +492,7 @@ void CodeGenTypes::addBitFieldInfo(const FieldDecl *FD, unsigned FieldNo, /// getCGRecordLayout - Return record layout info for the given llvm::Type. const CGRecordLayout & CodeGenTypes::getCGRecordLayout(const TagDecl *TD) const { - const Type *Key = - Context.getTagDeclType(TD).getTypePtr(); + const Type *Key = Context.getTagDeclType(TD).getTypePtr(); llvm::DenseMap<const Type*, CGRecordLayout *>::const_iterator I = CGRecordLayouts.find(Key); assert (I != CGRecordLayouts.end() diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index 2ff602f..7e34252 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -85,7 +85,7 @@ class CodeGenTypes { const TargetInfo &Target; llvm::Module& TheModule; const llvm::TargetData& TheTargetData; - mutable const ABIInfo* TheABIInfo; + const ABIInfo& TheABIInfo; llvm::SmallVector<std::pair<QualType, llvm::OpaqueType *>, 8> PointersToResolve; @@ -140,13 +140,14 @@ private: /// interface to convert type T into a llvm::Type. const llvm::Type *ConvertNewType(QualType T); public: - CodeGenTypes(ASTContext &Ctx, llvm::Module &M, const llvm::TargetData &TD); + CodeGenTypes(ASTContext &Ctx, llvm::Module &M, const llvm::TargetData &TD, + const ABIInfo &Info); ~CodeGenTypes(); const llvm::TargetData &getTargetData() const { return TheTargetData; } const TargetInfo &getTarget() const { return Target; } ASTContext &getContext() const { return Context; } - const ABIInfo &getABIInfo() const; + const ABIInfo &getABIInfo() const { return TheABIInfo; } llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); } /// ConvertType - Convert type T into a llvm::Type. diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index 10fd1f5..d873cfe 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -199,10 +199,13 @@ void CXXNameMangler::mangle(const NamedDecl *D, llvm::StringRef Prefix) { return; } - // <mangled-name> ::= _Z <encoding> + // <mangled-name> ::= _Z [L] <encoding> // ::= <data name> // ::= <special-name> Out << Prefix; + if (D->getLinkage() == NamedDecl::InternalLinkage) // match gcc behavior + Out << 'L'; + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) mangleFunctionEncoding(FD); else diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp new file mode 100644 index 0000000..e5fd47e --- /dev/null +++ b/lib/CodeGen/TargetInfo.cpp @@ -0,0 +1,1904 @@ +//===---- TargetInfo.cpp - Encapsulate target details -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// These classes wrap the information about a call or function +// definition used to handle ABI compliancy. +// +//===----------------------------------------------------------------------===// + +#include "TargetInfo.h" +#include "ABIInfo.h" +#include "CodeGenFunction.h" +#include "clang/AST/RecordLayout.h" +#include "llvm/Type.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; +using namespace CodeGen; + +ABIInfo::~ABIInfo() {} + +void ABIArgInfo::dump() const { + llvm::raw_ostream &OS = llvm::errs(); + OS << "(ABIArgInfo Kind="; + switch (TheKind) { + case Direct: + OS << "Direct"; + break; + case Extend: + OS << "Extend"; + break; + case Ignore: + OS << "Ignore"; + break; + case Coerce: + OS << "Coerce Type="; + getCoerceToType()->print(OS); + break; + case Indirect: + OS << "Indirect Align=" << getIndirectAlign(); + break; + case Expand: + OS << "Expand"; + break; + } + OS << ")\n"; +} + +TargetCodeGenInfo::~TargetCodeGenInfo() { delete Info; } + +static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays); + +/// isEmptyField - Return true iff a the field is "empty", that is it +/// is an unnamed bit-field or an (array of) empty record(s). +static bool isEmptyField(ASTContext &Context, const FieldDecl *FD, + bool AllowArrays) { + if (FD->isUnnamedBitfield()) + return true; + + QualType FT = FD->getType(); + + // Constant arrays of empty records count as empty, strip them off. + if (AllowArrays) + while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) + FT = AT->getElementType(); + + return isEmptyRecord(Context, FT, AllowArrays); +} + +/// isEmptyRecord - Return true iff a structure contains only empty +/// fields. Note that a structure with a flexible array member is not +/// considered empty. +static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays) { + const RecordType *RT = T->getAs<RecordType>(); + if (!RT) + return 0; + const RecordDecl *RD = RT->getDecl(); + if (RD->hasFlexibleArrayMember()) + return false; + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i) + if (!isEmptyField(Context, *i, AllowArrays)) + return false; + return true; +} + +/// hasNonTrivialDestructorOrCopyConstructor - Determine if a type has either +/// a non-trivial destructor or a non-trivial copy constructor. +static bool hasNonTrivialDestructorOrCopyConstructor(const RecordType *RT) { + const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); + if (!RD) + return false; + + return !RD->hasTrivialDestructor() || !RD->hasTrivialCopyConstructor(); +} + +/// isRecordWithNonTrivialDestructorOrCopyConstructor - Determine if a type is +/// a record type with either a non-trivial destructor or a non-trivial copy +/// constructor. +static bool isRecordWithNonTrivialDestructorOrCopyConstructor(QualType T) { + const RecordType *RT = T->getAs<RecordType>(); + if (!RT) + return false; + + return hasNonTrivialDestructorOrCopyConstructor(RT); +} + +/// isSingleElementStruct - Determine if a structure is a "single +/// element struct", i.e. it has exactly one non-empty field or +/// exactly one field which is itself a single element +/// struct. Structures with flexible array members are never +/// considered single element structs. +/// +/// \return The field declaration for the single non-empty field, if +/// it exists. +static const Type *isSingleElementStruct(QualType T, ASTContext &Context) { + const RecordType *RT = T->getAsStructureType(); + if (!RT) + return 0; + + const RecordDecl *RD = RT->getDecl(); + if (RD->hasFlexibleArrayMember()) + return 0; + + const Type *Found = 0; + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i) { + const FieldDecl *FD = *i; + QualType FT = FD->getType(); + + // Ignore empty fields. + if (isEmptyField(Context, FD, true)) + continue; + + // If we already found an element then this isn't a single-element + // struct. + if (Found) + return 0; + + // Treat single element arrays as the element. + while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) { + if (AT->getSize().getZExtValue() != 1) + break; + FT = AT->getElementType(); + } + + if (!CodeGenFunction::hasAggregateLLVMType(FT)) { + Found = FT.getTypePtr(); + } else { + Found = isSingleElementStruct(FT, Context); + if (!Found) + return 0; + } + } + + return Found; +} + +static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) { + if (!Ty->getAs<BuiltinType>() && !Ty->isAnyPointerType() && + !Ty->isAnyComplexType() && !Ty->isEnumeralType() && + !Ty->isBlockPointerType()) + return false; + + uint64_t Size = Context.getTypeSize(Ty); + return Size == 32 || Size == 64; +} + +/// canExpandIndirectArgument - Test whether an argument type which is to be +/// passed indirectly (on the stack) would have the equivalent layout if it was +/// expanded into separate arguments. If so, we prefer to do the latter to avoid +/// inhibiting optimizations. +/// +// FIXME: This predicate is missing many cases, currently it just follows +// llvm-gcc (checks that all fields are 32-bit or 64-bit primitive types). We +// should probably make this smarter, or better yet make the LLVM backend +// capable of handling it. +static bool canExpandIndirectArgument(QualType Ty, ASTContext &Context) { + // We can only expand structure types. + const RecordType *RT = Ty->getAs<RecordType>(); + if (!RT) + return false; + + // We can only expand (C) structures. + // + // FIXME: This needs to be generalized to handle classes as well. + const RecordDecl *RD = RT->getDecl(); + if (!RD->isStruct() || isa<CXXRecordDecl>(RD)) + return false; + + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i) { + const FieldDecl *FD = *i; + + if (!is32Or64BitBasicType(FD->getType(), Context)) + return false; + + // FIXME: Reject bit-fields wholesale; there are two problems, we don't know + // how to expand them yet, and the predicate for telling if a bitfield still + // counts as "basic" is more complicated than what we were doing previously. + if (FD->isBitField()) + return false; + } + + return true; +} + +static bool typeContainsSSEVector(const RecordDecl *RD, ASTContext &Context) { + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i) { + const FieldDecl *FD = *i; + + if (FD->getType()->isVectorType() && + Context.getTypeSize(FD->getType()) >= 128) + return true; + + if (const RecordType* RT = FD->getType()->getAs<RecordType>()) + if (typeContainsSSEVector(RT->getDecl(), Context)) + return true; + } + + return false; +} + +namespace { +/// DefaultABIInfo - The default implementation for ABI specific +/// details. This implementation provides information which results in +/// self-consistent and sensible LLVM IR generation, but does not +/// conform to any particular ABI. +class DefaultABIInfo : public ABIInfo { + ABIArgInfo classifyReturnType(QualType RetTy, + ASTContext &Context, + llvm::LLVMContext &VMContext) const; + + ABIArgInfo classifyArgumentType(QualType RetTy, + ASTContext &Context, + llvm::LLVMContext &VMContext) const; + + virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, + llvm::LLVMContext &VMContext) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context, + VMContext); + for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); + it != ie; ++it) + it->info = classifyArgumentType(it->type, Context, VMContext); + } + + virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const; +}; + +class DefaultTargetCodeGenInfo : public TargetCodeGenInfo { +public: + DefaultTargetCodeGenInfo():TargetCodeGenInfo(new DefaultABIInfo()) {}; +}; + +llvm::Value *DefaultABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const { + return 0; +} + +ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty, + ASTContext &Context, + llvm::LLVMContext &VMContext) const { + if (CodeGenFunction::hasAggregateLLVMType(Ty)) { + return ABIArgInfo::getIndirect(0); + } else { + return (Ty->isPromotableIntegerType() ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); + } +} + +/// X86_32ABIInfo - The X86-32 ABI information. +class X86_32ABIInfo : public ABIInfo { + ASTContext &Context; + bool IsDarwinVectorABI; + bool IsSmallStructInRegABI; + + static bool isRegisterSize(unsigned Size) { + return (Size == 8 || Size == 16 || Size == 32 || Size == 64); + } + + static bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context); + + static unsigned getIndirectArgumentAlignment(QualType Ty, + ASTContext &Context); + +public: + ABIArgInfo classifyReturnType(QualType RetTy, + ASTContext &Context, + llvm::LLVMContext &VMContext) const; + + ABIArgInfo classifyArgumentType(QualType RetTy, + ASTContext &Context, + llvm::LLVMContext &VMContext) const; + + virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, + llvm::LLVMContext &VMContext) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context, + VMContext); + for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); + it != ie; ++it) + it->info = classifyArgumentType(it->type, Context, VMContext); + } + + virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const; + + X86_32ABIInfo(ASTContext &Context, bool d, bool p) + : ABIInfo(), Context(Context), IsDarwinVectorABI(d), + IsSmallStructInRegABI(p) {} +}; + +class X86_32TargetCodeGenInfo : public TargetCodeGenInfo { +public: + X86_32TargetCodeGenInfo(ASTContext &Context, bool d, bool p) + :TargetCodeGenInfo(new X86_32ABIInfo(Context, d, p)) {}; +}; + +} + +/// shouldReturnTypeInRegister - Determine if the given type should be +/// passed in a register (for the Darwin ABI). +bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, + ASTContext &Context) { + uint64_t Size = Context.getTypeSize(Ty); + + // Type must be register sized. + if (!isRegisterSize(Size)) + return false; + + if (Ty->isVectorType()) { + // 64- and 128- bit vectors inside structures are not returned in + // registers. + if (Size == 64 || Size == 128) + return false; + + return true; + } + + // If this is a builtin, pointer, enum, or complex type, it is ok. + if (Ty->getAs<BuiltinType>() || Ty->isAnyPointerType() || + Ty->isAnyComplexType() || Ty->isEnumeralType() || + Ty->isBlockPointerType()) + return true; + + // Arrays are treated like records. + if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) + return shouldReturnTypeInRegister(AT->getElementType(), Context); + + // Otherwise, it must be a record type. + const RecordType *RT = Ty->getAs<RecordType>(); + if (!RT) return false; + + // Structure types are passed in register if all fields would be + // passed in a register. + for (RecordDecl::field_iterator i = RT->getDecl()->field_begin(), + e = RT->getDecl()->field_end(); i != e; ++i) { + const FieldDecl *FD = *i; + + // Empty fields are ignored. + if (isEmptyField(Context, FD, true)) + continue; + + // Check fields recursively. + if (!shouldReturnTypeInRegister(FD->getType(), Context)) + return false; + } + + return true; +} + +ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, + ASTContext &Context, + llvm::LLVMContext &VMContext) const { + if (RetTy->isVoidType()) { + return ABIArgInfo::getIgnore(); + } else if (const VectorType *VT = RetTy->getAs<VectorType>()) { + // On Darwin, some vectors are returned in registers. + if (IsDarwinVectorABI) { + uint64_t Size = Context.getTypeSize(RetTy); + + // 128-bit vectors are a special case; they are returned in + // registers and we need to make sure to pick a type the LLVM + // backend will like. + if (Size == 128) + return ABIArgInfo::getCoerce(llvm::VectorType::get( + llvm::Type::getInt64Ty(VMContext), 2)); + + // Always return in register if it fits in a general purpose + // register, or if it is 64 bits and has a single element. + if ((Size == 8 || Size == 16 || Size == 32) || + (Size == 64 && VT->getNumElements() == 1)) + return ABIArgInfo::getCoerce(llvm::IntegerType::get(VMContext, Size)); + + return ABIArgInfo::getIndirect(0); + } + + return ABIArgInfo::getDirect(); + } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { + if (const RecordType *RT = RetTy->getAsStructureType()) { + // Structures with either a non-trivial destructor or a non-trivial + // copy constructor are always indirect. + if (hasNonTrivialDestructorOrCopyConstructor(RT)) + return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + + // Structures with flexible arrays are always indirect. + if (RT->getDecl()->hasFlexibleArrayMember()) + return ABIArgInfo::getIndirect(0); + } + + // If specified, structs and unions are always indirect. + if (!IsSmallStructInRegABI && !RetTy->isAnyComplexType()) + return ABIArgInfo::getIndirect(0); + + // Classify "single element" structs as their element type. + if (const Type *SeltTy = isSingleElementStruct(RetTy, Context)) { + if (const BuiltinType *BT = SeltTy->getAs<BuiltinType>()) { + if (BT->isIntegerType()) { + // We need to use the size of the structure, padding + // bit-fields can adjust that to be larger than the single + // element type. + uint64_t Size = Context.getTypeSize(RetTy); + return ABIArgInfo::getCoerce( + llvm::IntegerType::get(VMContext, (unsigned) Size)); + } else if (BT->getKind() == BuiltinType::Float) { + assert(Context.getTypeSize(RetTy) == Context.getTypeSize(SeltTy) && + "Unexpect single element structure size!"); + return ABIArgInfo::getCoerce(llvm::Type::getFloatTy(VMContext)); + } else if (BT->getKind() == BuiltinType::Double) { + assert(Context.getTypeSize(RetTy) == Context.getTypeSize(SeltTy) && + "Unexpect single element structure size!"); + return ABIArgInfo::getCoerce(llvm::Type::getDoubleTy(VMContext)); + } + } else if (SeltTy->isPointerType()) { + // FIXME: It would be really nice if this could come out as the proper + // pointer type. + const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext); + return ABIArgInfo::getCoerce(PtrTy); + } else if (SeltTy->isVectorType()) { + // 64- and 128-bit vectors are never returned in a + // register when inside a structure. + uint64_t Size = Context.getTypeSize(RetTy); + if (Size == 64 || Size == 128) + return ABIArgInfo::getIndirect(0); + + return classifyReturnType(QualType(SeltTy, 0), Context, VMContext); + } + } + + // Small structures which are register sized are generally returned + // in a register. + if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, Context)) { + uint64_t Size = Context.getTypeSize(RetTy); + return ABIArgInfo::getCoerce(llvm::IntegerType::get(VMContext, Size)); + } + + return ABIArgInfo::getIndirect(0); + } else { + return (RetTy->isPromotableIntegerType() ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); + } +} + +unsigned X86_32ABIInfo::getIndirectArgumentAlignment(QualType Ty, + ASTContext &Context) { + unsigned Align = Context.getTypeAlign(Ty); + if (Align < 128) return 0; + if (const RecordType* RT = Ty->getAs<RecordType>()) + if (typeContainsSSEVector(RT->getDecl(), Context)) + return 16; + return 0; +} + +ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, + ASTContext &Context, + llvm::LLVMContext &VMContext) const { + // FIXME: Set alignment on indirect arguments. + if (CodeGenFunction::hasAggregateLLVMType(Ty)) { + // Structures with flexible arrays are always indirect. + if (const RecordType *RT = Ty->getAsStructureType()) + if (RT->getDecl()->hasFlexibleArrayMember()) + return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty, + Context)); + + // Ignore empty structs. + if (Ty->isStructureType() && Context.getTypeSize(Ty) == 0) + return ABIArgInfo::getIgnore(); + + // Expand small (<= 128-bit) record types when we know that the stack layout + // of those arguments will match the struct. This is important because the + // LLVM backend isn't smart enough to remove byval, which inhibits many + // optimizations. + if (Context.getTypeSize(Ty) <= 4*32 && + canExpandIndirectArgument(Ty, Context)) + return ABIArgInfo::getExpand(); + + return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty, Context)); + } else { + return (Ty->isPromotableIntegerType() ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); + } +} + +llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const { + const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + const llvm::Type *BPP = llvm::PointerType::getUnqual(BP); + + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, + "ap"); + llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur"); + llvm::Type *PTy = + llvm::PointerType::getUnqual(CGF.ConvertType(Ty)); + llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy); + + uint64_t Offset = + llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4); + llvm::Value *NextAddr = + Builder.CreateGEP(Addr, llvm::ConstantInt::get( + llvm::Type::getInt32Ty(CGF.getLLVMContext()), Offset), + "ap.next"); + Builder.CreateStore(NextAddr, VAListAddrAsBPP); + + return AddrTyped; +} + +namespace { +/// X86_64ABIInfo - The X86_64 ABI information. +class X86_64ABIInfo : public ABIInfo { + enum Class { + Integer = 0, + SSE, + SSEUp, + X87, + X87Up, + ComplexX87, + NoClass, + Memory + }; + + /// merge - Implement the X86_64 ABI merging algorithm. + /// + /// Merge an accumulating classification \arg Accum with a field + /// classification \arg Field. + /// + /// \param Accum - The accumulating classification. This should + /// always be either NoClass or the result of a previous merge + /// call. In addition, this should never be Memory (the caller + /// should just return Memory for the aggregate). + Class merge(Class Accum, Class Field) const; + + /// classify - Determine the x86_64 register classes in which the + /// given type T should be passed. + /// + /// \param Lo - The classification for the parts of the type + /// residing in the low word of the containing object. + /// + /// \param Hi - The classification for the parts of the type + /// residing in the high word of the containing object. + /// + /// \param OffsetBase - The bit offset of this type in the + /// containing object. Some parameters are classified different + /// depending on whether they straddle an eightbyte boundary. + /// + /// If a word is unused its result will be NoClass; if a type should + /// be passed in Memory then at least the classification of \arg Lo + /// will be Memory. + /// + /// The \arg Lo class will be NoClass iff the argument is ignored. + /// + /// If the \arg Lo class is ComplexX87, then the \arg Hi class will + /// also be ComplexX87. + void classify(QualType T, ASTContext &Context, uint64_t OffsetBase, + Class &Lo, Class &Hi) const; + + /// getCoerceResult - Given a source type \arg Ty and an LLVM type + /// to coerce to, chose the best way to pass Ty in the same place + /// that \arg CoerceTo would be passed, but while keeping the + /// emitted code as simple as possible. + /// + /// FIXME: Note, this should be cleaned up to just take an enumeration of all + /// the ways we might want to pass things, instead of constructing an LLVM + /// type. This makes this code more explicit, and it makes it clearer that we + /// are also doing this for correctness in the case of passing scalar types. + ABIArgInfo getCoerceResult(QualType Ty, + const llvm::Type *CoerceTo, + ASTContext &Context) const; + + /// getIndirectResult - Give a source type \arg Ty, return a suitable result + /// such that the argument will be passed in memory. + ABIArgInfo getIndirectResult(QualType Ty, + ASTContext &Context) const; + + ABIArgInfo classifyReturnType(QualType RetTy, + ASTContext &Context, + llvm::LLVMContext &VMContext) const; + + ABIArgInfo classifyArgumentType(QualType Ty, + ASTContext &Context, + llvm::LLVMContext &VMContext, + unsigned &neededInt, + unsigned &neededSSE) const; + +public: + virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, + llvm::LLVMContext &VMContext) const; + + virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const; +}; + +class X86_64TargetCodeGenInfo : public TargetCodeGenInfo { +public: + X86_64TargetCodeGenInfo():TargetCodeGenInfo(new X86_64ABIInfo()) {}; +}; + +} + +X86_64ABIInfo::Class X86_64ABIInfo::merge(Class Accum, + Class Field) const { + // AMD64-ABI 3.2.3p2: Rule 4. Each field of an object is + // classified recursively so that always two fields are + // considered. The resulting class is calculated according to + // the classes of the fields in the eightbyte: + // + // (a) If both classes are equal, this is the resulting class. + // + // (b) If one of the classes is NO_CLASS, the resulting class is + // the other class. + // + // (c) If one of the classes is MEMORY, the result is the MEMORY + // class. + // + // (d) If one of the classes is INTEGER, the result is the + // INTEGER. + // + // (e) If one of the classes is X87, X87UP, COMPLEX_X87 class, + // MEMORY is used as class. + // + // (f) Otherwise class SSE is used. + + // Accum should never be memory (we should have returned) or + // ComplexX87 (because this cannot be passed in a structure). + assert((Accum != Memory && Accum != ComplexX87) && + "Invalid accumulated classification during merge."); + if (Accum == Field || Field == NoClass) + return Accum; + else if (Field == Memory) + return Memory; + else if (Accum == NoClass) + return Field; + else if (Accum == Integer || Field == Integer) + return Integer; + else if (Field == X87 || Field == X87Up || Field == ComplexX87 || + Accum == X87 || Accum == X87Up) + return Memory; + else + return SSE; +} + +void X86_64ABIInfo::classify(QualType Ty, + ASTContext &Context, + uint64_t OffsetBase, + Class &Lo, Class &Hi) const { + // FIXME: This code can be simplified by introducing a simple value class for + // Class pairs with appropriate constructor methods for the various + // situations. + + // FIXME: Some of the split computations are wrong; unaligned vectors + // shouldn't be passed in registers for example, so there is no chance they + // can straddle an eightbyte. Verify & simplify. + + Lo = Hi = NoClass; + + Class &Current = OffsetBase < 64 ? Lo : Hi; + Current = Memory; + + if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) { + BuiltinType::Kind k = BT->getKind(); + + if (k == BuiltinType::Void) { + Current = NoClass; + } else if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + Lo = Integer; + Hi = Integer; + } else if (k >= BuiltinType::Bool && k <= BuiltinType::LongLong) { + Current = Integer; + } else if (k == BuiltinType::Float || k == BuiltinType::Double) { + Current = SSE; + } else if (k == BuiltinType::LongDouble) { + Lo = X87; + Hi = X87Up; + } + // FIXME: _Decimal32 and _Decimal64 are SSE. + // FIXME: _float128 and _Decimal128 are (SSE, SSEUp). + } else if (const EnumType *ET = Ty->getAs<EnumType>()) { + // Classify the underlying integer type. + classify(ET->getDecl()->getIntegerType(), Context, OffsetBase, Lo, Hi); + } else if (Ty->hasPointerRepresentation()) { + Current = Integer; + } else if (const VectorType *VT = Ty->getAs<VectorType>()) { + uint64_t Size = Context.getTypeSize(VT); + if (Size == 32) { + // gcc passes all <4 x char>, <2 x short>, <1 x int>, <1 x + // float> as integer. + Current = Integer; + + // If this type crosses an eightbyte boundary, it should be + // split. + uint64_t EB_Real = (OffsetBase) / 64; + uint64_t EB_Imag = (OffsetBase + Size - 1) / 64; + if (EB_Real != EB_Imag) + Hi = Lo; + } else if (Size == 64) { + // gcc passes <1 x double> in memory. :( + if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::Double)) + return; + + // gcc passes <1 x long long> as INTEGER. + if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::LongLong)) + Current = Integer; + else + Current = SSE; + + // If this type crosses an eightbyte boundary, it should be + // split. + if (OffsetBase && OffsetBase != 64) + Hi = Lo; + } else if (Size == 128) { + Lo = SSE; + Hi = SSEUp; + } + } else if (const ComplexType *CT = Ty->getAs<ComplexType>()) { + QualType ET = Context.getCanonicalType(CT->getElementType()); + + uint64_t Size = Context.getTypeSize(Ty); + if (ET->isIntegralType()) { + if (Size <= 64) + Current = Integer; + else if (Size <= 128) + Lo = Hi = Integer; + } else if (ET == Context.FloatTy) + Current = SSE; + else if (ET == Context.DoubleTy) + Lo = Hi = SSE; + else if (ET == Context.LongDoubleTy) + Current = ComplexX87; + + // If this complex type crosses an eightbyte boundary then it + // should be split. + uint64_t EB_Real = (OffsetBase) / 64; + uint64_t EB_Imag = (OffsetBase + Context.getTypeSize(ET)) / 64; + if (Hi == NoClass && EB_Real != EB_Imag) + Hi = Lo; + } else if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) { + // Arrays are treated like structures. + + uint64_t Size = Context.getTypeSize(Ty); + + // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger + // than two eightbytes, ..., it has class MEMORY. + if (Size > 128) + return; + + // AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned + // fields, it has class MEMORY. + // + // Only need to check alignment of array base. + if (OffsetBase % Context.getTypeAlign(AT->getElementType())) + return; + + // Otherwise implement simplified merge. We could be smarter about + // this, but it isn't worth it and would be harder to verify. + Current = NoClass; + uint64_t EltSize = Context.getTypeSize(AT->getElementType()); + uint64_t ArraySize = AT->getSize().getZExtValue(); + for (uint64_t i=0, Offset=OffsetBase; i<ArraySize; ++i, Offset += EltSize) { + Class FieldLo, FieldHi; + classify(AT->getElementType(), Context, Offset, FieldLo, FieldHi); + Lo = merge(Lo, FieldLo); + Hi = merge(Hi, FieldHi); + if (Lo == Memory || Hi == Memory) + break; + } + + // Do post merger cleanup (see below). Only case we worry about is Memory. + if (Hi == Memory) + Lo = Memory; + assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp array classification."); + } else if (const RecordType *RT = Ty->getAs<RecordType>()) { + uint64_t Size = Context.getTypeSize(Ty); + + // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger + // than two eightbytes, ..., it has class MEMORY. + if (Size > 128) + return; + + // AMD64-ABI 3.2.3p2: Rule 2. If a C++ object has either a non-trivial + // copy constructor or a non-trivial destructor, it is passed by invisible + // reference. + if (hasNonTrivialDestructorOrCopyConstructor(RT)) + return; + + const RecordDecl *RD = RT->getDecl(); + + // Assume variable sized types are passed in memory. + if (RD->hasFlexibleArrayMember()) + return; + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + // Reset Lo class, this will be recomputed. + Current = NoClass; + + // If this is a C++ record, classify the bases first. + if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { + for (CXXRecordDecl::base_class_const_iterator i = CXXRD->bases_begin(), + e = CXXRD->bases_end(); i != e; ++i) { + assert(!i->isVirtual() && !i->getType()->isDependentType() && + "Unexpected base class!"); + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + + // Classify this field. + // + // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate exceeds a + // single eightbyte, each is classified separately. Each eightbyte gets + // initialized to class NO_CLASS. + Class FieldLo, FieldHi; + uint64_t Offset = OffsetBase + Layout.getBaseClassOffset(Base); + classify(i->getType(), Context, Offset, FieldLo, FieldHi); + Lo = merge(Lo, FieldLo); + Hi = merge(Hi, FieldHi); + if (Lo == Memory || Hi == Memory) + break; + } + + // If this record has no fields but isn't empty, classify as INTEGER. + if (RD->field_empty() && Size) + Current = Integer; + } + + // Classify the fields one at a time, merging the results. + unsigned idx = 0; + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i, ++idx) { + uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx); + bool BitField = i->isBitField(); + + // AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned + // fields, it has class MEMORY. + // + // Note, skip this test for bit-fields, see below. + if (!BitField && Offset % Context.getTypeAlign(i->getType())) { + Lo = Memory; + return; + } + + // Classify this field. + // + // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate + // exceeds a single eightbyte, each is classified + // separately. Each eightbyte gets initialized to class + // NO_CLASS. + Class FieldLo, FieldHi; + + // Bit-fields require special handling, they do not force the + // structure to be passed in memory even if unaligned, and + // therefore they can straddle an eightbyte. + if (BitField) { + // Ignore padding bit-fields. + if (i->isUnnamedBitfield()) + continue; + + uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx); + uint64_t Size = i->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); + + uint64_t EB_Lo = Offset / 64; + uint64_t EB_Hi = (Offset + Size - 1) / 64; + FieldLo = FieldHi = NoClass; + if (EB_Lo) { + assert(EB_Hi == EB_Lo && "Invalid classification, type > 16 bytes."); + FieldLo = NoClass; + FieldHi = Integer; + } else { + FieldLo = Integer; + FieldHi = EB_Hi ? Integer : NoClass; + } + } else + classify(i->getType(), Context, Offset, FieldLo, FieldHi); + Lo = merge(Lo, FieldLo); + Hi = merge(Hi, FieldHi); + if (Lo == Memory || Hi == Memory) + break; + } + + // AMD64-ABI 3.2.3p2: Rule 5. Then a post merger cleanup is done: + // + // (a) If one of the classes is MEMORY, the whole argument is + // passed in memory. + // + // (b) If SSEUP is not preceeded by SSE, it is converted to SSE. + + // The first of these conditions is guaranteed by how we implement + // the merge (just bail). + // + // The second condition occurs in the case of unions; for example + // union { _Complex double; unsigned; }. + if (Hi == Memory) + Lo = Memory; + if (Hi == SSEUp && Lo != SSE) + Hi = SSE; + } +} + +ABIArgInfo X86_64ABIInfo::getCoerceResult(QualType Ty, + const llvm::Type *CoerceTo, + ASTContext &Context) const { + if (CoerceTo == llvm::Type::getInt64Ty(CoerceTo->getContext())) { + // Integer and pointer types will end up in a general purpose + // register. + if (Ty->isIntegralType() || Ty->hasPointerRepresentation()) + return (Ty->isPromotableIntegerType() ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); + } else if (CoerceTo == llvm::Type::getDoubleTy(CoerceTo->getContext())) { + // FIXME: It would probably be better to make CGFunctionInfo only map using + // canonical types than to canonize here. + QualType CTy = Context.getCanonicalType(Ty); + + // Float and double end up in a single SSE reg. + if (CTy == Context.FloatTy || CTy == Context.DoubleTy) + return ABIArgInfo::getDirect(); + + } + + return ABIArgInfo::getCoerce(CoerceTo); +} + +ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty, + ASTContext &Context) const { + // If this is a scalar LLVM value then assume LLVM will pass it in the right + // place naturally. + if (!CodeGenFunction::hasAggregateLLVMType(Ty)) + return (Ty->isPromotableIntegerType() ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); + + bool ByVal = !isRecordWithNonTrivialDestructorOrCopyConstructor(Ty); + + // FIXME: Set alignment correctly. + return ABIArgInfo::getIndirect(0, ByVal); +} + +ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy, + ASTContext &Context, + llvm::LLVMContext &VMContext) const { + // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the + // classification algorithm. + X86_64ABIInfo::Class Lo, Hi; + classify(RetTy, Context, 0, Lo, Hi); + + // Check some invariants. + assert((Hi != Memory || Lo == Memory) && "Invalid memory classification."); + assert((Lo != NoClass || Hi == NoClass) && "Invalid null classification."); + assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification."); + + const llvm::Type *ResType = 0; + switch (Lo) { + case NoClass: + return ABIArgInfo::getIgnore(); + + case SSEUp: + case X87Up: + assert(0 && "Invalid classification for lo word."); + + // AMD64-ABI 3.2.3p4: Rule 2. Types of class memory are returned via + // hidden argument. + case Memory: + return getIndirectResult(RetTy, Context); + + // AMD64-ABI 3.2.3p4: Rule 3. If the class is INTEGER, the next + // available register of the sequence %rax, %rdx is used. + case Integer: + ResType = llvm::Type::getInt64Ty(VMContext); break; + + // AMD64-ABI 3.2.3p4: Rule 4. If the class is SSE, the next + // available SSE register of the sequence %xmm0, %xmm1 is used. + case SSE: + ResType = llvm::Type::getDoubleTy(VMContext); break; + + // AMD64-ABI 3.2.3p4: Rule 6. If the class is X87, the value is + // returned on the X87 stack in %st0 as 80-bit x87 number. + case X87: + ResType = llvm::Type::getX86_FP80Ty(VMContext); break; + + // AMD64-ABI 3.2.3p4: Rule 8. If the class is COMPLEX_X87, the real + // part of the value is returned in %st0 and the imaginary part in + // %st1. + case ComplexX87: + assert(Hi == ComplexX87 && "Unexpected ComplexX87 classification."); + ResType = llvm::StructType::get(VMContext, llvm::Type::getX86_FP80Ty(VMContext), + llvm::Type::getX86_FP80Ty(VMContext), + NULL); + break; + } + + switch (Hi) { + // Memory was handled previously and X87 should + // never occur as a hi class. + case Memory: + case X87: + assert(0 && "Invalid classification for hi word."); + + case ComplexX87: // Previously handled. + case NoClass: break; + + case Integer: + ResType = llvm::StructType::get(VMContext, ResType, + llvm::Type::getInt64Ty(VMContext), NULL); + break; + case SSE: + ResType = llvm::StructType::get(VMContext, ResType, + llvm::Type::getDoubleTy(VMContext), NULL); + break; + + // AMD64-ABI 3.2.3p4: Rule 5. If the class is SSEUP, the eightbyte + // is passed in the upper half of the last used SSE register. + // + // SSEUP should always be preceeded by SSE, just widen. + case SSEUp: + assert(Lo == SSE && "Unexpected SSEUp classification."); + ResType = llvm::VectorType::get(llvm::Type::getDoubleTy(VMContext), 2); + break; + + // AMD64-ABI 3.2.3p4: Rule 7. If the class is X87UP, the value is + // returned together with the previous X87 value in %st0. + case X87Up: + // If X87Up is preceeded by X87, we don't need to do + // anything. However, in some cases with unions it may not be + // preceeded by X87. In such situations we follow gcc and pass the + // extra bits in an SSE reg. + if (Lo != X87) + ResType = llvm::StructType::get(VMContext, ResType, + llvm::Type::getDoubleTy(VMContext), NULL); + break; + } + + return getCoerceResult(RetTy, ResType, Context); +} + +ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context, + llvm::LLVMContext &VMContext, + unsigned &neededInt, + unsigned &neededSSE) const { + X86_64ABIInfo::Class Lo, Hi; + classify(Ty, Context, 0, Lo, Hi); + + // Check some invariants. + // FIXME: Enforce these by construction. + assert((Hi != Memory || Lo == Memory) && "Invalid memory classification."); + assert((Lo != NoClass || Hi == NoClass) && "Invalid null classification."); + assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification."); + + neededInt = 0; + neededSSE = 0; + const llvm::Type *ResType = 0; + switch (Lo) { + case NoClass: + return ABIArgInfo::getIgnore(); + + // AMD64-ABI 3.2.3p3: Rule 1. If the class is MEMORY, pass the argument + // on the stack. + case Memory: + + // AMD64-ABI 3.2.3p3: Rule 5. If the class is X87, X87UP or + // COMPLEX_X87, it is passed in memory. + case X87: + case ComplexX87: + return getIndirectResult(Ty, Context); + + case SSEUp: + case X87Up: + assert(0 && "Invalid classification for lo word."); + + // AMD64-ABI 3.2.3p3: Rule 2. If the class is INTEGER, the next + // available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8 + // and %r9 is used. + case Integer: + ++neededInt; + ResType = llvm::Type::getInt64Ty(VMContext); + break; + + // AMD64-ABI 3.2.3p3: Rule 3. If the class is SSE, the next + // available SSE register is used, the registers are taken in the + // order from %xmm0 to %xmm7. + case SSE: + ++neededSSE; + ResType = llvm::Type::getDoubleTy(VMContext); + break; + } + + switch (Hi) { + // Memory was handled previously, ComplexX87 and X87 should + // never occur as hi classes, and X87Up must be preceed by X87, + // which is passed in memory. + case Memory: + case X87: + case ComplexX87: + assert(0 && "Invalid classification for hi word."); + break; + + case NoClass: break; + case Integer: + ResType = llvm::StructType::get(VMContext, ResType, + llvm::Type::getInt64Ty(VMContext), NULL); + ++neededInt; + break; + + // X87Up generally doesn't occur here (long double is passed in + // memory), except in situations involving unions. + case X87Up: + case SSE: + ResType = llvm::StructType::get(VMContext, ResType, + llvm::Type::getDoubleTy(VMContext), NULL); + ++neededSSE; + break; + + // AMD64-ABI 3.2.3p3: Rule 4. If the class is SSEUP, the + // eightbyte is passed in the upper half of the last used SSE + // register. + case SSEUp: + assert(Lo == SSE && "Unexpected SSEUp classification."); + ResType = llvm::VectorType::get(llvm::Type::getDoubleTy(VMContext), 2); + break; + } + + return getCoerceResult(Ty, ResType, Context); +} + +void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context, + llvm::LLVMContext &VMContext) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), + Context, VMContext); + + // Keep track of the number of assigned registers. + unsigned freeIntRegs = 6, freeSSERegs = 8; + + // If the return value is indirect, then the hidden argument is consuming one + // integer register. + if (FI.getReturnInfo().isIndirect()) + --freeIntRegs; + + // AMD64-ABI 3.2.3p3: Once arguments are classified, the registers + // get assigned (in left-to-right order) for passing as follows... + for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); + it != ie; ++it) { + unsigned neededInt, neededSSE; + it->info = classifyArgumentType(it->type, Context, VMContext, + neededInt, neededSSE); + + // AMD64-ABI 3.2.3p3: If there are no registers available for any + // eightbyte of an argument, the whole argument is passed on the + // stack. If registers have already been assigned for some + // eightbytes of such an argument, the assignments get reverted. + if (freeIntRegs >= neededInt && freeSSERegs >= neededSSE) { + freeIntRegs -= neededInt; + freeSSERegs -= neededSSE; + } else { + it->info = getIndirectResult(it->type, Context); + } + } +} + +static llvm::Value *EmitVAArgFromMemory(llvm::Value *VAListAddr, + QualType Ty, + CodeGenFunction &CGF) { + llvm::Value *overflow_arg_area_p = + CGF.Builder.CreateStructGEP(VAListAddr, 2, "overflow_arg_area_p"); + llvm::Value *overflow_arg_area = + CGF.Builder.CreateLoad(overflow_arg_area_p, "overflow_arg_area"); + + // AMD64-ABI 3.5.7p5: Step 7. Align l->overflow_arg_area upwards to a 16 + // byte boundary if alignment needed by type exceeds 8 byte boundary. + uint64_t Align = CGF.getContext().getTypeAlign(Ty) / 8; + if (Align > 8) { + // Note that we follow the ABI & gcc here, even though the type + // could in theory have an alignment greater than 16. This case + // shouldn't ever matter in practice. + + // overflow_arg_area = (overflow_arg_area + 15) & ~15; + llvm::Value *Offset = + llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()), 15); + overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset); + llvm::Value *AsInt = CGF.Builder.CreatePtrToInt(overflow_arg_area, + llvm::Type::getInt64Ty(CGF.getLLVMContext())); + llvm::Value *Mask = llvm::ConstantInt::get( + llvm::Type::getInt64Ty(CGF.getLLVMContext()), ~15LL); + overflow_arg_area = + CGF.Builder.CreateIntToPtr(CGF.Builder.CreateAnd(AsInt, Mask), + overflow_arg_area->getType(), + "overflow_arg_area.align"); + } + + // AMD64-ABI 3.5.7p5: Step 8. Fetch type from l->overflow_arg_area. + const llvm::Type *LTy = CGF.ConvertTypeForMem(Ty); + llvm::Value *Res = + CGF.Builder.CreateBitCast(overflow_arg_area, + llvm::PointerType::getUnqual(LTy)); + + // AMD64-ABI 3.5.7p5: Step 9. Set l->overflow_arg_area to: + // l->overflow_arg_area + sizeof(type). + // AMD64-ABI 3.5.7p5: Step 10. Align l->overflow_arg_area upwards to + // an 8 byte boundary. + + uint64_t SizeInBytes = (CGF.getContext().getTypeSize(Ty) + 7) / 8; + llvm::Value *Offset = + llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()), + (SizeInBytes + 7) & ~7); + overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset, + "overflow_arg_area.next"); + CGF.Builder.CreateStore(overflow_arg_area, overflow_arg_area_p); + + // AMD64-ABI 3.5.7p5: Step 11. Return the fetched type. + return Res; +} + +llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const { + llvm::LLVMContext &VMContext = CGF.getLLVMContext(); + const llvm::Type *i32Ty = llvm::Type::getInt32Ty(VMContext); + const llvm::Type *DoubleTy = llvm::Type::getDoubleTy(VMContext); + + // Assume that va_list type is correct; should be pointer to LLVM type: + // struct { + // i32 gp_offset; + // i32 fp_offset; + // i8* overflow_arg_area; + // i8* reg_save_area; + // }; + unsigned neededInt, neededSSE; + ABIArgInfo AI = classifyArgumentType(Ty, CGF.getContext(), VMContext, + neededInt, neededSSE); + + // AMD64-ABI 3.5.7p5: Step 1. Determine whether type may be passed + // in the registers. If not go to step 7. + if (!neededInt && !neededSSE) + return EmitVAArgFromMemory(VAListAddr, Ty, CGF); + + // AMD64-ABI 3.5.7p5: Step 2. Compute num_gp to hold the number of + // general purpose registers needed to pass type and num_fp to hold + // the number of floating point registers needed. + + // AMD64-ABI 3.5.7p5: Step 3. Verify whether arguments fit into + // registers. In the case: l->gp_offset > 48 - num_gp * 8 or + // l->fp_offset > 304 - num_fp * 16 go to step 7. + // + // NOTE: 304 is a typo, there are (6 * 8 + 8 * 16) = 176 bytes of + // register save space). + + llvm::Value *InRegs = 0; + llvm::Value *gp_offset_p = 0, *gp_offset = 0; + llvm::Value *fp_offset_p = 0, *fp_offset = 0; + if (neededInt) { + gp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 0, "gp_offset_p"); + gp_offset = CGF.Builder.CreateLoad(gp_offset_p, "gp_offset"); + InRegs = + CGF.Builder.CreateICmpULE(gp_offset, + llvm::ConstantInt::get(i32Ty, + 48 - neededInt * 8), + "fits_in_gp"); + } + + if (neededSSE) { + fp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 1, "fp_offset_p"); + fp_offset = CGF.Builder.CreateLoad(fp_offset_p, "fp_offset"); + llvm::Value *FitsInFP = + CGF.Builder.CreateICmpULE(fp_offset, + llvm::ConstantInt::get(i32Ty, + 176 - neededSSE * 16), + "fits_in_fp"); + InRegs = InRegs ? CGF.Builder.CreateAnd(InRegs, FitsInFP) : FitsInFP; + } + + llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg"); + llvm::BasicBlock *InMemBlock = CGF.createBasicBlock("vaarg.in_mem"); + llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end"); + CGF.Builder.CreateCondBr(InRegs, InRegBlock, InMemBlock); + + // Emit code to load the value if it was passed in registers. + + CGF.EmitBlock(InRegBlock); + + // AMD64-ABI 3.5.7p5: Step 4. Fetch type from l->reg_save_area with + // an offset of l->gp_offset and/or l->fp_offset. This may require + // copying to a temporary location in case the parameter is passed + // in different register classes or requires an alignment greater + // than 8 for general purpose registers and 16 for XMM registers. + // + // FIXME: This really results in shameful code when we end up needing to + // collect arguments from different places; often what should result in a + // simple assembling of a structure from scattered addresses has many more + // loads than necessary. Can we clean this up? + const llvm::Type *LTy = CGF.ConvertTypeForMem(Ty); + llvm::Value *RegAddr = + CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(VAListAddr, 3), + "reg_save_area"); + if (neededInt && neededSSE) { + // FIXME: Cleanup. + assert(AI.isCoerce() && "Unexpected ABI info for mixed regs"); + const llvm::StructType *ST = cast<llvm::StructType>(AI.getCoerceToType()); + llvm::Value *Tmp = CGF.CreateTempAlloca(ST); + assert(ST->getNumElements() == 2 && "Unexpected ABI info for mixed regs"); + const llvm::Type *TyLo = ST->getElementType(0); + const llvm::Type *TyHi = ST->getElementType(1); + assert((TyLo->isFloatingPoint() ^ TyHi->isFloatingPoint()) && + "Unexpected ABI info for mixed regs"); + const llvm::Type *PTyLo = llvm::PointerType::getUnqual(TyLo); + const llvm::Type *PTyHi = llvm::PointerType::getUnqual(TyHi); + llvm::Value *GPAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset); + llvm::Value *FPAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset); + llvm::Value *RegLoAddr = TyLo->isFloatingPoint() ? FPAddr : GPAddr; + llvm::Value *RegHiAddr = TyLo->isFloatingPoint() ? GPAddr : FPAddr; + llvm::Value *V = + CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegLoAddr, PTyLo)); + CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0)); + V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegHiAddr, PTyHi)); + CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1)); + + RegAddr = CGF.Builder.CreateBitCast(Tmp, + llvm::PointerType::getUnqual(LTy)); + } else if (neededInt) { + RegAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset); + RegAddr = CGF.Builder.CreateBitCast(RegAddr, + llvm::PointerType::getUnqual(LTy)); + } else { + if (neededSSE == 1) { + RegAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset); + RegAddr = CGF.Builder.CreateBitCast(RegAddr, + llvm::PointerType::getUnqual(LTy)); + } else { + assert(neededSSE == 2 && "Invalid number of needed registers!"); + // SSE registers are spaced 16 bytes apart in the register save + // area, we need to collect the two eightbytes together. + llvm::Value *RegAddrLo = CGF.Builder.CreateGEP(RegAddr, fp_offset); + llvm::Value *RegAddrHi = + CGF.Builder.CreateGEP(RegAddrLo, + llvm::ConstantInt::get(i32Ty, 16)); + const llvm::Type *DblPtrTy = + llvm::PointerType::getUnqual(DoubleTy); + const llvm::StructType *ST = llvm::StructType::get(VMContext, DoubleTy, + DoubleTy, NULL); + llvm::Value *V, *Tmp = CGF.CreateTempAlloca(ST); + V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrLo, + DblPtrTy)); + CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0)); + V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrHi, + DblPtrTy)); + CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1)); + RegAddr = CGF.Builder.CreateBitCast(Tmp, + llvm::PointerType::getUnqual(LTy)); + } + } + + // AMD64-ABI 3.5.7p5: Step 5. Set: + // l->gp_offset = l->gp_offset + num_gp * 8 + // l->fp_offset = l->fp_offset + num_fp * 16. + if (neededInt) { + llvm::Value *Offset = llvm::ConstantInt::get(i32Ty, neededInt * 8); + CGF.Builder.CreateStore(CGF.Builder.CreateAdd(gp_offset, Offset), + gp_offset_p); + } + if (neededSSE) { + llvm::Value *Offset = llvm::ConstantInt::get(i32Ty, neededSSE * 16); + CGF.Builder.CreateStore(CGF.Builder.CreateAdd(fp_offset, Offset), + fp_offset_p); + } + CGF.EmitBranch(ContBlock); + + // Emit code to load the value if it was passed in memory. + + CGF.EmitBlock(InMemBlock); + llvm::Value *MemAddr = EmitVAArgFromMemory(VAListAddr, Ty, CGF); + + // Return the appropriate result. + + CGF.EmitBlock(ContBlock); + llvm::PHINode *ResAddr = CGF.Builder.CreatePHI(RegAddr->getType(), + "vaarg.addr"); + ResAddr->reserveOperandSpace(2); + ResAddr->addIncoming(RegAddr, InRegBlock); + ResAddr->addIncoming(MemAddr, InMemBlock); + + return ResAddr; +} + +// PIC16 ABI Implementation + +namespace { + +class PIC16ABIInfo : public ABIInfo { + ABIArgInfo classifyReturnType(QualType RetTy, + ASTContext &Context, + llvm::LLVMContext &VMContext) const; + + ABIArgInfo classifyArgumentType(QualType RetTy, + ASTContext &Context, + llvm::LLVMContext &VMContext) const; + + virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, + llvm::LLVMContext &VMContext) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context, + VMContext); + for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); + it != ie; ++it) + it->info = classifyArgumentType(it->type, Context, VMContext); + } + + virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const; +}; + +class PIC16TargetCodeGenInfo : public TargetCodeGenInfo { +public: + PIC16TargetCodeGenInfo():TargetCodeGenInfo(new PIC16ABIInfo()) {}; +}; + +} + +ABIArgInfo PIC16ABIInfo::classifyReturnType(QualType RetTy, + ASTContext &Context, + llvm::LLVMContext &VMContext) const { + if (RetTy->isVoidType()) { + return ABIArgInfo::getIgnore(); + } else { + return ABIArgInfo::getDirect(); + } +} + +ABIArgInfo PIC16ABIInfo::classifyArgumentType(QualType Ty, + ASTContext &Context, + llvm::LLVMContext &VMContext) const { + return ABIArgInfo::getDirect(); +} + +llvm::Value *PIC16ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const { + return 0; +} + +// ARM ABI Implementation + +namespace { + +class ARMABIInfo : public ABIInfo { +public: + enum ABIKind { + APCS = 0, + AAPCS = 1, + AAPCS_VFP + }; + +private: + ABIKind Kind; + +public: + ARMABIInfo(ABIKind _Kind) : Kind(_Kind) {} + +private: + ABIKind getABIKind() const { return Kind; } + + ABIArgInfo classifyReturnType(QualType RetTy, + ASTContext &Context, + llvm::LLVMContext &VMCOntext) const; + + ABIArgInfo classifyArgumentType(QualType RetTy, + ASTContext &Context, + llvm::LLVMContext &VMContext) const; + + virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, + llvm::LLVMContext &VMContext) const; + + virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const; +}; + +class ARMTargetCodeGenInfo : public TargetCodeGenInfo { +public: + ARMTargetCodeGenInfo(ARMABIInfo::ABIKind K) + :TargetCodeGenInfo(new ARMABIInfo(K)) {}; +}; + +} + +void ARMABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context, + llvm::LLVMContext &VMContext) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context, + VMContext); + for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); + it != ie; ++it) { + it->info = classifyArgumentType(it->type, Context, VMContext); + } + + // ARM always overrides the calling convention. + switch (getABIKind()) { + case APCS: + FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_APCS); + break; + + case AAPCS: + FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS); + break; + + case AAPCS_VFP: + FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS_VFP); + break; + } +} + +ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, + ASTContext &Context, + llvm::LLVMContext &VMContext) const { + if (!CodeGenFunction::hasAggregateLLVMType(Ty)) + return (Ty->isPromotableIntegerType() ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); + + // Ignore empty records. + if (isEmptyRecord(Context, Ty, true)) + return ABIArgInfo::getIgnore(); + + // FIXME: This is kind of nasty... but there isn't much choice because the ARM + // backend doesn't support byval. + // FIXME: This doesn't handle alignment > 64 bits. + const llvm::Type* ElemTy; + unsigned SizeRegs; + if (Context.getTypeAlign(Ty) > 32) { + ElemTy = llvm::Type::getInt64Ty(VMContext); + SizeRegs = (Context.getTypeSize(Ty) + 63) / 64; + } else { + ElemTy = llvm::Type::getInt32Ty(VMContext); + SizeRegs = (Context.getTypeSize(Ty) + 31) / 32; + } + std::vector<const llvm::Type*> LLVMFields; + LLVMFields.push_back(llvm::ArrayType::get(ElemTy, SizeRegs)); + const llvm::Type* STy = llvm::StructType::get(VMContext, LLVMFields, true); + return ABIArgInfo::getCoerce(STy); +} + +static bool isIntegerLikeType(QualType Ty, + ASTContext &Context, + llvm::LLVMContext &VMContext) { + // APCS, C Language Calling Conventions, Non-Simple Return Values: A structure + // is called integer-like if its size is less than or equal to one word, and + // the offset of each of its addressable sub-fields is zero. + + uint64_t Size = Context.getTypeSize(Ty); + + // Check that the type fits in a word. + if (Size > 32) + return false; + + // FIXME: Handle vector types! + if (Ty->isVectorType()) + return false; + + // Float types are never treated as "integer like". + if (Ty->isRealFloatingType()) + return false; + + // If this is a builtin or pointer type then it is ok. + if (Ty->getAs<BuiltinType>() || Ty->isPointerType()) + return true; + + // Complex types "should" be ok by the definition above, but they are not. + if (Ty->isAnyComplexType()) + return false; + + // Single element and zero sized arrays should be allowed, by the definition + // above, but they are not. + + // Otherwise, it must be a record type. + const RecordType *RT = Ty->getAs<RecordType>(); + if (!RT) return false; + + // Ignore records with flexible arrays. + const RecordDecl *RD = RT->getDecl(); + if (RD->hasFlexibleArrayMember()) + return false; + + // Check that all sub-fields are at offset 0, and are themselves "integer + // like". + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + bool HadField = false; + unsigned idx = 0; + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i, ++idx) { + const FieldDecl *FD = *i; + + // Check if this field is at offset 0. + uint64_t Offset = Layout.getFieldOffset(idx); + if (Offset != 0) { + // Allow padding bit-fields, but only if they are all at the end of the + // structure (despite the wording above, this matches gcc). + if (FD->isBitField() && + !FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) { + for (; i != e; ++i) + if (!i->isBitField() || + i->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) + return false; + + // All remaining fields are padding, allow this. + return true; + } + + return false; + } + + if (!isIntegerLikeType(FD->getType(), Context, VMContext)) + return false; + + // Only allow at most one field in a structure. Again this doesn't match the + // wording above, but follows gcc. + if (!RD->isUnion()) { + if (HadField) + return false; + + HadField = true; + } + } + + return true; +} + +ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, + ASTContext &Context, + llvm::LLVMContext &VMContext) const { + if (RetTy->isVoidType()) + return ABIArgInfo::getIgnore(); + + if (!CodeGenFunction::hasAggregateLLVMType(RetTy)) + return (RetTy->isPromotableIntegerType() ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); + + // Are we following APCS? + if (getABIKind() == APCS) { + if (isEmptyRecord(Context, RetTy, false)) + return ABIArgInfo::getIgnore(); + + // Integer like structures are returned in r0. + if (isIntegerLikeType(RetTy, Context, VMContext)) { + // Return in the smallest viable integer type. + uint64_t Size = Context.getTypeSize(RetTy); + if (Size <= 8) + return ABIArgInfo::getCoerce(llvm::Type::getInt8Ty(VMContext)); + if (Size <= 16) + return ABIArgInfo::getCoerce(llvm::Type::getInt16Ty(VMContext)); + return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(VMContext)); + } + + // Otherwise return in memory. + return ABIArgInfo::getIndirect(0); + } + + // Otherwise this is an AAPCS variant. + + if (isEmptyRecord(Context, RetTy, true)) + return ABIArgInfo::getIgnore(); + + // Aggregates <= 4 bytes are returned in r0; other aggregates + // are returned indirectly. + uint64_t Size = Context.getTypeSize(RetTy); + if (Size <= 32) { + // Return in the smallest viable integer type. + if (Size <= 8) + return ABIArgInfo::getCoerce(llvm::Type::getInt8Ty(VMContext)); + if (Size <= 16) + return ABIArgInfo::getCoerce(llvm::Type::getInt16Ty(VMContext)); + return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(VMContext)); + } + + return ABIArgInfo::getIndirect(0); +} + +llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const { + // FIXME: Need to handle alignment + const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + const llvm::Type *BPP = llvm::PointerType::getUnqual(BP); + + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, + "ap"); + llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur"); + llvm::Type *PTy = + llvm::PointerType::getUnqual(CGF.ConvertType(Ty)); + llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy); + + uint64_t Offset = + llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4); + llvm::Value *NextAddr = + Builder.CreateGEP(Addr, llvm::ConstantInt::get( + llvm::Type::getInt32Ty(CGF.getLLVMContext()), Offset), + "ap.next"); + Builder.CreateStore(NextAddr, VAListAddrAsBPP); + + return AddrTyped; +} + +ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy, + ASTContext &Context, + llvm::LLVMContext &VMContext) const { + if (RetTy->isVoidType()) { + return ABIArgInfo::getIgnore(); + } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { + return ABIArgInfo::getIndirect(0); + } else { + return (RetTy->isPromotableIntegerType() ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); + } +} + +// SystemZ ABI Implementation + +namespace { + +class SystemZABIInfo : public ABIInfo { + bool isPromotableIntegerType(QualType Ty) const; + + ABIArgInfo classifyReturnType(QualType RetTy, ASTContext &Context, + llvm::LLVMContext &VMContext) const; + + ABIArgInfo classifyArgumentType(QualType RetTy, ASTContext &Context, + llvm::LLVMContext &VMContext) const; + + virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, + llvm::LLVMContext &VMContext) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), + Context, VMContext); + for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); + it != ie; ++it) + it->info = classifyArgumentType(it->type, Context, VMContext); + } + + virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const; +}; + +class SystemZTargetCodeGenInfo : public TargetCodeGenInfo { +public: + SystemZTargetCodeGenInfo():TargetCodeGenInfo(new SystemZABIInfo()) {}; +}; + +} + +bool SystemZABIInfo::isPromotableIntegerType(QualType Ty) const { + // SystemZ ABI requires all 8, 16 and 32 bit quantities to be extended. + if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) + switch (BT->getKind()) { + case BuiltinType::Bool: + case BuiltinType::Char_S: + case BuiltinType::Char_U: + case BuiltinType::SChar: + case BuiltinType::UChar: + case BuiltinType::Short: + case BuiltinType::UShort: + case BuiltinType::Int: + case BuiltinType::UInt: + return true; + default: + return false; + } + return false; +} + +llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const { + // FIXME: Implement + return 0; +} + + +ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy, + ASTContext &Context, + llvm::LLVMContext &VMContext) const { + if (RetTy->isVoidType()) { + return ABIArgInfo::getIgnore(); + } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { + return ABIArgInfo::getIndirect(0); + } else { + return (isPromotableIntegerType(RetTy) ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); + } +} + +ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty, + ASTContext &Context, + llvm::LLVMContext &VMContext) const { + if (CodeGenFunction::hasAggregateLLVMType(Ty)) { + return ABIArgInfo::getIndirect(0); + } else { + return (isPromotableIntegerType(Ty) ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); + } +} + +// MSP430 ABI Implementation + +namespace { + +class MSP430TargetCodeGenInfo : public TargetCodeGenInfo { +public: + MSP430TargetCodeGenInfo():TargetCodeGenInfo(new DefaultABIInfo()) {}; + void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, + CodeGen::CodeGenModule &M) const; +}; + +} + +void MSP430TargetCodeGenInfo::SetTargetAttributes(const Decl *D, + llvm::GlobalValue *GV, + CodeGen::CodeGenModule &M) const { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (const MSP430InterruptAttr *attr = FD->getAttr<MSP430InterruptAttr>()) { + // Handle 'interrupt' attribute: + llvm::Function *F = cast<llvm::Function>(GV); + + // Step 1: Set ISR calling convention. + F->setCallingConv(llvm::CallingConv::MSP430_INTR); + + // Step 2: Add attributes goodness. + F->addFnAttr(llvm::Attribute::NoInline); + + // Step 3: Emit ISR vector alias. + unsigned Num = attr->getNumber() + 0xffe0; + new llvm::GlobalAlias(GV->getType(), llvm::Function::ExternalLinkage, + "vector_" + + llvm::LowercaseString(llvm::utohexstr(Num)), + GV, &M.getModule()); + } + } +} + +const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() const { + if (TheTargetCodeGenInfo) + return *TheTargetCodeGenInfo; + + // For now we just cache the TargetCodeGenInfo in CodeGenModule and don't + // free it. + + const llvm::Triple &Triple(getContext().Target.getTriple()); + switch (Triple.getArch()) { + default: + return *(TheTargetCodeGenInfo = new DefaultTargetCodeGenInfo); + + case llvm::Triple::arm: + case llvm::Triple::thumb: + // FIXME: We want to know the float calling convention as well. + if (strcmp(getContext().Target.getABI(), "apcs-gnu") == 0) + return *(TheTargetCodeGenInfo = + new ARMTargetCodeGenInfo(ARMABIInfo::APCS)); + + return *(TheTargetCodeGenInfo = + new ARMTargetCodeGenInfo(ARMABIInfo::AAPCS)); + + case llvm::Triple::pic16: + return *(TheTargetCodeGenInfo = new PIC16TargetCodeGenInfo()); + + case llvm::Triple::systemz: + return *(TheTargetCodeGenInfo = new SystemZTargetCodeGenInfo()); + + case llvm::Triple::msp430: + return *(TheTargetCodeGenInfo = new MSP430TargetCodeGenInfo()); + + case llvm::Triple::x86: + switch (Triple.getOS()) { + case llvm::Triple::Darwin: + return *(TheTargetCodeGenInfo = + new X86_32TargetCodeGenInfo(Context, true, true)); + case llvm::Triple::Cygwin: + case llvm::Triple::MinGW32: + case llvm::Triple::MinGW64: + case llvm::Triple::AuroraUX: + case llvm::Triple::DragonFly: + case llvm::Triple::FreeBSD: + case llvm::Triple::OpenBSD: + return *(TheTargetCodeGenInfo = + new X86_32TargetCodeGenInfo(Context, false, true)); + + default: + return *(TheTargetCodeGenInfo = + new X86_32TargetCodeGenInfo(Context, false, false)); + } + + case llvm::Triple::x86_64: + return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo()); + } +} diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h new file mode 100644 index 0000000..495b22f --- /dev/null +++ b/lib/CodeGen/TargetInfo.h @@ -0,0 +1,50 @@ +//===---- TargetInfo.h - Encapsulate target details -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// These classes wrap the information about a call or function +// definition used to handle ABI compliancy. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CODEGEN_TARGETINFO_H +#define CLANG_CODEGEN_TARGETINFO_H + +namespace llvm { + class GlobalValue; +} + +namespace clang { + class ABIInfo; + class Decl; + + namespace CodeGen { + class CodeGenModule; + } + + /// TargetCodeGenInfo - This class organizes various target-specific + /// codegeneration issues, like target-specific attributes, builtins and so + /// on. + class TargetCodeGenInfo { + ABIInfo *Info; + public: + // WARNING: Acquires the ownership of ABIInfo. + TargetCodeGenInfo(ABIInfo *info = 0):Info(info) { }; + virtual ~TargetCodeGenInfo(); + + /// getABIInfo() - Returns ABI info helper for the target. + const ABIInfo& getABIInfo() const { return *Info; } + + /// SetTargetAttributes - Provides a convenient hook to handle extra + /// target-specific attributes for the given global. + virtual void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, + CodeGen::CodeGenModule &M) const { }; + }; +} + +#endif // CLANG_CODEGEN_TARGETINFO_H diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index cc3febf..42657d9 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -203,8 +203,8 @@ void DarwinGCC::AddLinkRuntimeLibArgs(const ArgList &Args, CmdArgs.push_back("-lgcc_s.10.5"); } } else if (Args.hasArg(options::OPT_shared_libgcc) || - // FIXME: -fexceptions -fno-exceptions means no exceptions - Args.hasArg(options::OPT_fexceptions) || + Args.hasFlag(options::OPT_fexceptions, + options::OPT_fno_exceptions) || Args.hasArg(options::OPT_fgnu_runtime)) { // FIXME: This is probably broken on 10.3? if (isMacosxVersionLT(MacosxVersionMin, 10, 5)) @@ -516,10 +516,6 @@ DerivedArgList *Darwin::TranslateArgs(InputArgList &Args, return DAL; } -bool Darwin::IsMathErrnoDefault() const { - return false; -} - bool Darwin::IsUnwindTablesDefault() const { // FIXME: Gross; we should probably have some separate target // definition, possibly even reusing the one in clang. @@ -599,10 +595,6 @@ Tool &Generic_GCC::SelectTool(const Compilation &C, return *T; } -bool Generic_GCC::IsMathErrnoDefault() const { - return true; -} - bool Generic_GCC::IsUnwindTablesDefault() const { // FIXME: Gross; we should probably have some separate target // definition, possibly even reusing the one in clang. diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index be36344..374ad8c 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -38,7 +38,6 @@ public: virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; - virtual bool IsMathErrnoDefault() const; virtual bool IsUnwindTablesDefault() const; virtual const char *GetDefaultRelocationModel() const; virtual const char *GetForcedPicModel() const; @@ -136,7 +135,6 @@ public: virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; - virtual bool IsMathErrnoDefault() const; virtual bool IsBlocksDefault() const { // Blocks default to on for 10.6 (darwin10) and beyond. return (DarwinVersion[0] > 9); diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 8f0af21..010953d 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -837,11 +837,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, break; } - // -fmath-errno is default. - if (!Args.hasFlag(options::OPT_fmath_errno, + // -fno-math-errno is default. + if (Args.hasFlag(options::OPT_fmath_errno, options::OPT_fno_math_errno, - getToolChain().IsMathErrnoDefault())) - CmdArgs.push_back("-fno-math-errno"); + false)) + CmdArgs.push_back("-fmath-errno"); Arg *Unsupported; if ((Unsupported = Args.getLastArg(options::OPT_MG)) || @@ -935,6 +935,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue(Args)); } + if (Arg *A = Args.getLastArg(options::OPT_ftabstop_EQ)) { + CmdArgs.push_back("-ftabstop"); + CmdArgs.push_back(A->getValue(Args)); + } + // Pass -fmessage-length=. CmdArgs.push_back("-fmessage-length"); if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) { @@ -2069,13 +2074,7 @@ void darwin::Link::AddLinkArgs(const ArgList &Args, Args.AddAllArgs(CmdArgs, options::OPT_umbrella); Args.AddAllArgs(CmdArgs, options::OPT_undefined); Args.AddAllArgs(CmdArgs, options::OPT_unexported__symbols__list); - Args.AddAllArgs(CmdArgs, options::OPT_weak__reference__mismatches); - if (!Args.hasArg(options::OPT_weak__reference__mismatches)) { - CmdArgs.push_back("-weak_reference_mismatches"); - CmdArgs.push_back("non-weak"); - } - Args.AddLastArg(CmdArgs, options::OPT_X_Flag); Args.AddAllArgs(CmdArgs, options::OPT_y); Args.AddLastArg(CmdArgs, options::OPT_w); diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp index 433af03..60d86a6 100644 --- a/lib/Driver/Types.cpp +++ b/lib/Driver/Types.cpp @@ -77,6 +77,7 @@ bool types::isAcceptedByClang(ID Id) { case TY_Asm: case TY_C: case TY_PP_C: + case TY_CL: case TY_ObjC: case TY_PP_ObjC: case TY_CXX: case TY_PP_CXX: case TY_ObjCXX: case TY_PP_ObjCXX: @@ -133,6 +134,7 @@ types::ID types::lookupTypeForExtension(const char *Ext) { .Case("mm", TY_ObjCXX) .Case("cc", TY_CXX) .Case("CC", TY_CXX) + .Case("cl", TY_CL) .Case("cp", TY_CXX) .Case("hh", TY_CXXHeader) .Case("hpp", TY_CXXHeader) diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp index f1a6666..52b597e 100644 --- a/lib/Frontend/ASTConsumers.cpp +++ b/lib/Frontend/ASTConsumers.cpp @@ -408,6 +408,19 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "<function template> " << FTD->getNameAsString() << "\n"; break; } + case Decl::FileScopeAsm: { + Out << "<file-scope asm>\n"; + break; + } + case Decl::UsingDirective: { + Out << "<using directive>\n"; + break; + } + case Decl::NamespaceAlias: { + NamespaceAliasDecl* NAD = cast<NamespaceAliasDecl>(*I); + Out << "<namespace alias> " << NAD->getNameAsString() << "\n"; + break; + } default: Out << "DeclKind: " << DK << '"' << I->getDeclKindName() << "\"\n"; assert(0 && "decl unhandled"); diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp index 6824d8f..ad152d3 100644 --- a/lib/Frontend/AnalysisConsumer.cpp +++ b/lib/Frontend/AnalysisConsumer.cpp @@ -363,7 +363,7 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, if (!mgr.getLiveVariables(D)) return; - GRExprEngine Eng(mgr); + GRExprEngine Eng(mgr, TF.take()); if (C.Opts.EnableExperimentalInternalChecks) RegisterExperimentalInternalChecks(Eng); @@ -373,8 +373,6 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, if (C.Opts.EnableExperimentalChecks) RegisterExperimentalChecks(Eng); - Eng.setTransferFunctionsAndCheckers(tf); - // Set the graph auditor. llvm::OwningPtr<ExplodedNode::Auditor> Auditor; if (mgr.shouldVisualizeUbigraph()) { @@ -494,7 +492,9 @@ static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr, // Display progress. C.DisplayFunction(D); - GRExprEngine Eng(mgr); + // FIXME: Make a fake transfer function. The GRTransferFunc interface + // eventually will be removed. + GRExprEngine Eng(mgr, new GRTransferFuncs()); if (C.Opts.EnableExperimentalInternalChecks) RegisterExperimentalInternalChecks(Eng); @@ -503,10 +503,6 @@ static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr, if (C.Opts.EnableExperimentalChecks) RegisterExperimentalChecks(Eng); - - // Make a fake transfer function. The GRTransferFunc interface will be - // removed. - Eng.setTransferFunctionsAndCheckers(new GRTransferFuncs()); // Register call inliner as the last checker. RegisterCallInliner(Eng); diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 2a6a8a8..19c740d 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -14,10 +14,12 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Basic/Version.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PTHManager.h" #include "clang/Frontend/ChainedDiagnosticClient.h" +#include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/PCHReader.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/TextDiagnosticPrinter.h" @@ -28,6 +30,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Timer.h" +#include "llvm/System/Host.h" #include "llvm/System/Path.h" #include "llvm/System/Program.h" using namespace clang; @@ -155,7 +158,8 @@ void CompilerInstance::createPreprocessor() { PP.reset(createPreprocessor(getDiagnostics(), getLangOpts(), getPreprocessorOpts(), getHeaderSearchOpts(), getDependencyOutputOpts(), getTarget(), - getSourceManager(), getFileManager())); + getFrontendOpts(), getSourceManager(), + getFileManager())); } Preprocessor * @@ -165,6 +169,7 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags, const HeaderSearchOptions &HSOpts, const DependencyOutputOptions &DepOpts, const TargetInfo &Target, + const FrontendOptions &FEOpts, SourceManager &SourceMgr, FileManager &FileMgr) { // Create a PTH manager if we are using some form of a token cache. @@ -186,7 +191,7 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags, PP->setPTHManager(PTHMgr); } - InitializePreprocessor(*PP, PPOpts, HSOpts); + InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts); // Handle generating dependencies, if requested. if (!DepOpts.OutputFile.empty()) @@ -409,3 +414,87 @@ bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile, return true; } + +// High-Level Operations + +bool CompilerInstance::ExecuteAction(FrontendAction &Act) { + assert(hasDiagnostics() && "Diagnostics engine is not initialized!"); + assert(!getFrontendOpts().ShowHelp && "Client must handle '-help'!"); + assert(!getFrontendOpts().ShowVersion && "Client must handle '-version'!"); + + // FIXME: Take this as an argument, once all the APIs we used have moved to + // taking it as an input instead of hard-coding llvm::errs. + llvm::raw_ostream &OS = llvm::errs(); + + // Create the target instance. + setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getTargetOpts())); + if (!hasTarget()) + return false; + + // Inform the target of the language options. + // + // FIXME: We shouldn't need to do this, the target should be immutable once + // created. This complexity should be lifted elsewhere. + getTarget().setForcedLangOptions(getLangOpts()); + + // Validate/process some options. + if (getHeaderSearchOpts().Verbose) + OS << "clang -cc1 version " CLANG_VERSION_STRING + << " based upon " << PACKAGE_STRING + << " hosted on " << llvm::sys::getHostTriple() << "\n"; + + if (getFrontendOpts().ShowTimers) + createFrontendTimer(); + + for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) { + const std::string &InFile = getFrontendOpts().Inputs[i].second; + + // If we aren't using an AST file, setup the file and source managers and + // the preprocessor. + bool IsAST = getFrontendOpts().Inputs[i].first == FrontendOptions::IK_AST; + if (!IsAST) { + if (!i) { + // Create a file manager object to provide access to and cache the + // filesystem. + createFileManager(); + + // Create the source manager. + createSourceManager(); + } else { + // Reset the ID tables if we are reusing the SourceManager. + getSourceManager().clearIDTables(); + } + + // Create the preprocessor. + createPreprocessor(); + } + + if (Act.BeginSourceFile(*this, InFile, IsAST)) { + Act.Execute(); + Act.EndSourceFile(); + } + } + + if (getDiagnosticOpts().ShowCarets) + if (unsigned NumDiagnostics = getDiagnostics().getNumDiagnostics()) + OS << NumDiagnostics << " diagnostic" + << (NumDiagnostics == 1 ? "" : "s") + << " generated.\n"; + + if (getFrontendOpts().ShowStats) { + getFileManager().PrintStats(); + OS << "\n"; + } + + // Return the appropriate status when verifying diagnostics. + // + // FIXME: If we could make getNumErrors() do the right thing, we wouldn't need + // this. + if (getDiagnosticOpts().VerifyDiagnostics) + return !static_cast<VerifyDiagnosticsClient&>( + getDiagnosticClient()).HadErrors(); + + return !getDiagnostics().getNumErrors(); +} + + diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 63f66fa..0bca475 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -222,6 +222,10 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts, Res.push_back("-verify"); if (Opts.ShowOptionNames) Res.push_back("-fdiagnostics-show-option"); + if (Opts.TabStop != DiagnosticOptions::DefaultTabStop) { + Res.push_back("-ftabstop"); + Res.push_back(llvm::utostr(Opts.TabStop)); + } if (Opts.MessageLength) { Res.push_back("-fmessage-length"); Res.push_back(llvm::utostr(Opts.MessageLength)); @@ -479,8 +483,8 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-fblocks"); if (Opts.EmitAllDecls) Res.push_back("-femit-all-decls"); - if (!Opts.MathErrno) - Res.push_back("-fno-math-errno"); + if (Opts.MathErrno) + Res.push_back("-fmath-errno"); if (Opts.OverflowChecking) Res.push_back("-ftrapv"); if (Opts.HeinousExtensions) @@ -804,6 +808,13 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Opts.ShowOptionNames = Args.hasArg(OPT_fdiagnostics_show_option); Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info); Opts.VerifyDiagnostics = Args.hasArg(OPT_verify); + Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop, + DiagnosticOptions::DefaultTabStop, Diags); + if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) { + Diags.Report(diag::warn_ignoring_ftabstop_value) + << Opts.TabStop << DiagnosticOptions::DefaultTabStop; + Opts.TabStop = DiagnosticOptions::DefaultTabStop; + } Opts.MessageLength = getLastArgIntValue(Args, OPT_fmessage_length, 0, Diags); Opts.DumpBuildInformation = getLastArgValue(Args, OPT_dump_build_information); Opts.Warnings = getAllArgValues(Args, OPT_W); @@ -1147,7 +1158,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions); Opts.AccessControl = Args.hasArg(OPT_faccess_control); Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors); - Opts.MathErrno = !Args.hasArg(OPT_fno_math_errno); + Opts.MathErrno = Args.hasArg(OPT_fmath_errno); Opts.InstantiationDepth = getLastArgIntValue(Args, OPT_ftemplate_depth, 99, Diags); Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime); diff --git a/lib/Frontend/FixItRewriter.cpp b/lib/Frontend/FixItRewriter.cpp index 4fa2b3c..0b04cf2 100644 --- a/lib/Frontend/FixItRewriter.cpp +++ b/lib/Frontend/FixItRewriter.cpp @@ -115,6 +115,9 @@ void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel, if (!AcceptableLocation) return; + } else if (DiagLevel == Diagnostic::Note) { + // Don't apply fix-it modifications in notes. + return; } // Make sure that we can perform all of the modifications we diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 4c647fda..0baba3f 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -280,7 +280,9 @@ void PrintParseAction::ExecuteAction() { void PrintPreprocessedAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); - llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); + // Output file needs to be set to 'Binary', to avoid converting Unix style + // line feeds (<LF>) to Microsoft style line feeds (<CR><LF>). + llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); if (!OS) return; DoPrintPreprocessedInput(CI.getPreprocessor(), OS, diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index 9555125..6fceb98 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -477,6 +477,9 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0", "i686-apple-darwin8", "", "", triple); break; + case llvm::Triple::DragonFly: + AddPath("/usr/include/c++/4.1", System, true, false, false); + break; case llvm::Triple::Linux: // Exherbo (2009-10-26) AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", @@ -553,9 +556,6 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl "i686-pc-linux-gnu", "", "", triple); break; case llvm::Triple::FreeBSD: - // DragonFly - AddPath("/usr/include/c++/4.1", System, true, false, false); - // FreeBSD AddPath("/usr/include/c++/4.2", System, true, false, false); break; case llvm::Triple::Solaris: diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index c1fc92d..e4c380a 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -14,13 +14,12 @@ #include "clang/Frontend/Utils.h" #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/FrontendOptions.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/ADT/APFloat.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/System/Path.h" using namespace clang; @@ -28,43 +27,22 @@ 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, - Diagnostic *Diags = 0) { - const char *Command = "#define "; - Buf.insert(Buf.end(), Command, Command+strlen(Command)); - if (const char *Equal = strchr(Macro, '=')) { - // Turn the = into ' '. - Buf.insert(Buf.end(), Macro, Equal); - Buf.push_back(' '); - +static void DefineBuiltinMacro(MacroBuilder &Builder, llvm::StringRef Macro, + Diagnostic &Diags) { + std::pair<llvm::StringRef, llvm::StringRef> MacroPair = Macro.split('='); + llvm::StringRef MacroName = MacroPair.first; + llvm::StringRef MacroBody = MacroPair.second; + if (MacroName.size() != Macro.size()) { // Per GCC -D semantics, the macro ends at \n if it exists. - const char *End = strpbrk(Equal, "\n\r"); - if (End) { - 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); - } - - Buf.insert(Buf.end(), Equal+1, End); + llvm::StringRef::size_type End = MacroBody.find_first_of("\n\r"); + if (End != llvm::StringRef::npos) + Diags.Report(diag::warn_fe_macro_contains_embedded_newline) + << MacroName; + Builder.defineMacro(MacroName, MacroBody.substr(0, End)); } else { // Push "macroname 1". - Buf.insert(Buf.end(), Macro, Macro+strlen(Macro)); - Buf.push_back(' '); - Buf.push_back('1'); + Builder.defineMacro(Macro); } - Buf.push_back('\n'); -} - -// Append a #undef line to Buf for Macro. Macro should be of the form XXX -// and we emit "#undef XXX". -static void UndefineBuiltinMacro(std::vector<char> &Buf, const char *Macro) { - // Push "macroname". - const char *Command = "#undef "; - Buf.insert(Buf.end(), Command, Command+strlen(Command)); - Buf.insert(Buf.end(), Macro, Macro+strlen(Macro)); - Buf.push_back('\n'); } std::string clang::NormalizeDashIncludePath(llvm::StringRef File) { @@ -83,42 +61,25 @@ std::string clang::NormalizeDashIncludePath(llvm::StringRef File) { return Lexer::Stringify(Path.str()); } -/// Add the quoted name of an implicit include file. -static void AddQuotedIncludePath(std::vector<char> &Buf, - const std::string &File) { - - // Escape double quotes etc. - Buf.push_back('"'); - std::string EscapedFile = NormalizeDashIncludePath(File); - Buf.insert(Buf.end(), EscapedFile.begin(), EscapedFile.end()); - Buf.push_back('"'); -} - /// AddImplicitInclude - Add an implicit #include of the specified file to the /// predefines buffer. -static void AddImplicitInclude(std::vector<char> &Buf, - const std::string &File) { - const char *Inc = "#include "; - Buf.insert(Buf.end(), Inc, Inc+strlen(Inc)); - AddQuotedIncludePath(Buf, File); - Buf.push_back('\n'); +static void AddImplicitInclude(MacroBuilder &Builder, llvm::StringRef File) { + Builder.append("#include \"" + + llvm::Twine(NormalizeDashIncludePath(File)) + "\""); } -static void AddImplicitIncludeMacros(std::vector<char> &Buf, - const std::string &File) { - const char *Inc = "#__include_macros "; - Buf.insert(Buf.end(), Inc, Inc+strlen(Inc)); - AddQuotedIncludePath(Buf, File); - Buf.push_back('\n'); +static void AddImplicitIncludeMacros(MacroBuilder &Builder, + llvm::StringRef File) { + Builder.append("#__include_macros \"" + + llvm::Twine(NormalizeDashIncludePath(File)) + "\""); // Marker token to stop the __include_macros fetch loop. - const char *Marker = "##\n"; // ##? - Buf.insert(Buf.end(), Marker, Marker+strlen(Marker)); + Builder.append("##"); // ##? } /// AddImplicitIncludePTH - Add an implicit #include using the original file /// used to generate a PTH cache. -static void AddImplicitIncludePTH(std::vector<char> &Buf, Preprocessor &PP, - const std::string& ImplicitIncludePTH) { +static void AddImplicitIncludePTH(MacroBuilder &Builder, Preprocessor &PP, + llvm::StringRef ImplicitIncludePTH) { PTHManager *P = PP.getPTHManager(); assert(P && "No PTHManager."); const char *OriginalFile = P->getOriginalSourceFile(); @@ -129,7 +90,7 @@ static void AddImplicitIncludePTH(std::vector<char> &Buf, Preprocessor &PP, return; } - AddImplicitInclude(Buf, OriginalFile); + AddImplicitInclude(Builder, OriginalFile); } /// PickFP - This is used to pick a value based on the FP semantics of the @@ -150,7 +111,7 @@ static T PickFP(const llvm::fltSemantics *Sem, T IEEESingleVal, return IEEEQuadVal; } -static void DefineFloatMacros(std::vector<char> &Buf, const char *Prefix, +static void DefineFloatMacros(MacroBuilder &Builder, llvm::StringRef Prefix, const llvm::fltSemantics *Sem) { const char *DenormMin, *Epsilon, *Max, *Min; DenormMin = PickFP(Sem, "1.40129846e-45F", "4.9406564584124654e-324", @@ -162,7 +123,6 @@ static void DefineFloatMacros(std::vector<char> &Buf, const char *Prefix, "1.08420217248550443401e-19L", "4.94065645841246544176568792868221e-324L", "1.92592994438723585305597794258492732e-34L"); - int HasInifinity = 1, HasQuietNaN = 1; int MantissaDigits = PickFP(Sem, 24, 53, 64, 106, 113); int Min10Exp = PickFP(Sem, -37, -307, -4931, -291, -4931); int Max10Exp = PickFP(Sem, 38, 308, 4932, 308, 4932); @@ -177,312 +137,281 @@ static void DefineFloatMacros(std::vector<char> &Buf, const char *Prefix, "1.79769313486231580793728971405301e+308L", "1.18973149535723176508575932662800702e+4932L"); - char MacroBuf[100]; - sprintf(MacroBuf, "__%s_DENORM_MIN__=%s", Prefix, DenormMin); - DefineBuiltinMacro(Buf, MacroBuf); - sprintf(MacroBuf, "__%s_DIG__=%d", Prefix, Digits); - DefineBuiltinMacro(Buf, MacroBuf); - sprintf(MacroBuf, "__%s_EPSILON__=%s", Prefix, Epsilon); - DefineBuiltinMacro(Buf, MacroBuf); - sprintf(MacroBuf, "__%s_HAS_INFINITY__=%d", Prefix, HasInifinity); - DefineBuiltinMacro(Buf, MacroBuf); - sprintf(MacroBuf, "__%s_HAS_QUIET_NAN__=%d", Prefix, HasQuietNaN); - DefineBuiltinMacro(Buf, MacroBuf); - sprintf(MacroBuf, "__%s_MANT_DIG__=%d", Prefix, MantissaDigits); - DefineBuiltinMacro(Buf, MacroBuf); - sprintf(MacroBuf, "__%s_MAX_10_EXP__=%d", Prefix, Max10Exp); - DefineBuiltinMacro(Buf, MacroBuf); - sprintf(MacroBuf, "__%s_MAX_EXP__=%d", Prefix, MaxExp); - DefineBuiltinMacro(Buf, MacroBuf); - sprintf(MacroBuf, "__%s_MAX__=%s", Prefix, Max); - DefineBuiltinMacro(Buf, MacroBuf); - sprintf(MacroBuf, "__%s_MIN_10_EXP__=(%d)", Prefix, Min10Exp); - DefineBuiltinMacro(Buf, MacroBuf); - sprintf(MacroBuf, "__%s_MIN_EXP__=(%d)", Prefix, MinExp); - DefineBuiltinMacro(Buf, MacroBuf); - sprintf(MacroBuf, "__%s_MIN__=%s", Prefix, Min); - DefineBuiltinMacro(Buf, MacroBuf); - sprintf(MacroBuf, "__%s_HAS_DENORM__=1", Prefix); - DefineBuiltinMacro(Buf, MacroBuf); + llvm::Twine DefPrefix = "__" + Prefix + "_"; + + Builder.defineMacro(DefPrefix + "DENORM_MIN__", DenormMin); + Builder.defineMacro(DefPrefix + "HAS_DENORM__"); + Builder.defineMacro(DefPrefix + "DIG__", llvm::Twine(Digits)); + Builder.defineMacro(DefPrefix + "EPSILON__", llvm::Twine(Epsilon)); + Builder.defineMacro(DefPrefix + "HAS_INFINITY__"); + Builder.defineMacro(DefPrefix + "HAS_QUIET_NAN__"); + Builder.defineMacro(DefPrefix + "MANT_DIG__", llvm::Twine(MantissaDigits)); + + Builder.defineMacro(DefPrefix + "MAX_10_EXP__", llvm::Twine(Max10Exp)); + Builder.defineMacro(DefPrefix + "MAX_EXP__", llvm::Twine(MaxExp)); + Builder.defineMacro(DefPrefix + "MAX__", llvm::Twine(Max)); + + Builder.defineMacro(DefPrefix + "MIN_10_EXP__","("+llvm::Twine(Min10Exp)+")"); + Builder.defineMacro(DefPrefix + "MIN_EXP__", "("+llvm::Twine(MinExp)+")"); + Builder.defineMacro(DefPrefix + "MIN__", llvm::Twine(Min)); } /// DefineTypeSize - Emit a macro to the predefines buffer that declares a macro /// named MacroName with the max value for a type with width 'TypeWidth' a /// signedness of 'isSigned' and with a value suffix of 'ValSuffix' (e.g. LL). -static void DefineTypeSize(const char *MacroName, unsigned TypeWidth, - const char *ValSuffix, bool isSigned, - std::vector<char> &Buf) { - char MacroBuf[60]; +static void DefineTypeSize(llvm::StringRef MacroName, unsigned TypeWidth, + llvm::StringRef ValSuffix, bool isSigned, + MacroBuilder& Builder) { long long MaxVal; if (isSigned) MaxVal = (1LL << (TypeWidth - 1)) - 1; else MaxVal = ~0LL >> (64-TypeWidth); - // FIXME: Switch to using raw_ostream and avoid utostr(). - sprintf(MacroBuf, "%s=%s%s", MacroName, llvm::utostr(MaxVal).c_str(), - ValSuffix); - DefineBuiltinMacro(Buf, MacroBuf); + Builder.defineMacro(MacroName, llvm::Twine(MaxVal) + ValSuffix); } /// DefineTypeSize - An overloaded helper that uses TargetInfo to determine /// the width, suffix, and signedness of the given type -static void DefineTypeSize(const char *MacroName, TargetInfo::IntType Ty, - const TargetInfo &TI, std::vector<char> &Buf) { +static void DefineTypeSize(llvm::StringRef MacroName, TargetInfo::IntType Ty, + const TargetInfo &TI, MacroBuilder &Builder) { DefineTypeSize(MacroName, TI.getTypeWidth(Ty), TI.getTypeConstantSuffix(Ty), - TI.isTypeSigned(Ty), Buf); + TI.isTypeSigned(Ty), Builder); } -static void DefineType(const char *MacroName, TargetInfo::IntType Ty, - std::vector<char> &Buf) { - char MacroBuf[60]; - sprintf(MacroBuf, "%s=%s", MacroName, TargetInfo::getTypeName(Ty)); - DefineBuiltinMacro(Buf, MacroBuf); +static void DefineType(const llvm::Twine &MacroName, TargetInfo::IntType Ty, + MacroBuilder &Builder) { + Builder.defineMacro(MacroName, TargetInfo::getTypeName(Ty)); } -static void DefineTypeWidth(const char *MacroName, TargetInfo::IntType Ty, - const TargetInfo &TI, std::vector<char> &Buf) { - char MacroBuf[60]; - sprintf(MacroBuf, "%s=%d", MacroName, TI.getTypeWidth(Ty)); - DefineBuiltinMacro(Buf, MacroBuf); +static void DefineTypeWidth(llvm::StringRef MacroName, TargetInfo::IntType Ty, + const TargetInfo &TI, MacroBuilder &Builder) { + Builder.defineMacro(MacroName, llvm::Twine(TI.getTypeWidth(Ty))); } static void DefineExactWidthIntType(TargetInfo::IntType Ty, - const TargetInfo &TI, std::vector<char> &Buf) { - char MacroBuf[60]; + const TargetInfo &TI, MacroBuilder &Builder) { int TypeWidth = TI.getTypeWidth(Ty); - sprintf(MacroBuf, "__INT%d_TYPE__", TypeWidth); - DefineType(MacroBuf, Ty, Buf); + DefineType("__INT" + llvm::Twine(TypeWidth) + "_TYPE__", Ty, Builder); - - const char *ConstSuffix = TargetInfo::getTypeConstantSuffix(Ty); - if (strlen(ConstSuffix) > 0) { - sprintf(MacroBuf, "__INT%d_C_SUFFIX__=%s", TypeWidth, ConstSuffix); - DefineBuiltinMacro(Buf, MacroBuf); - } + llvm::StringRef ConstSuffix(TargetInfo::getTypeConstantSuffix(Ty)); + if (!ConstSuffix.empty()) + Builder.defineMacro("__INT" + llvm::Twine(TypeWidth) + "_C_SUFFIX__", + ConstSuffix); } static void InitializePredefinedMacros(const TargetInfo &TI, const LangOptions &LangOpts, - std::vector<char> &Buf) { - char MacroBuf[60]; + const FrontendOptions &FEOpts, + MacroBuilder &Builder) { // Compiler version introspection macros. - DefineBuiltinMacro(Buf, "__llvm__=1"); // LLVM Backend - DefineBuiltinMacro(Buf, "__clang__=1"); // Clang Frontend + Builder.defineMacro("__llvm__"); // LLVM Backend + Builder.defineMacro("__clang__"); // Clang Frontend // Currently claim to be compatible with GCC 4.2.1-5621. - DefineBuiltinMacro(Buf, "__GNUC_MINOR__=2"); - DefineBuiltinMacro(Buf, "__GNUC_PATCHLEVEL__=1"); - DefineBuiltinMacro(Buf, "__GNUC__=4"); - DefineBuiltinMacro(Buf, "__GXX_ABI_VERSION=1002"); - DefineBuiltinMacro(Buf, "__VERSION__=\"4.2.1 Compatible Clang Compiler\""); - + Builder.defineMacro("__GNUC_MINOR__", "2"); + Builder.defineMacro("__GNUC_PATCHLEVEL__", "1"); + Builder.defineMacro("__GNUC__", "4"); + Builder.defineMacro("__GXX_ABI_VERSION", "1002"); + Builder.defineMacro("__VERSION__", "\"4.2.1 Compatible Clang Compiler\""); // Initialize language-specific preprocessor defines. // These should all be defined in the preprocessor according to the // current language configuration. if (!LangOpts.Microsoft) - DefineBuiltinMacro(Buf, "__STDC__=1"); + Builder.defineMacro("__STDC__"); if (LangOpts.AsmPreprocessor) - DefineBuiltinMacro(Buf, "__ASSEMBLER__=1"); + Builder.defineMacro("__ASSEMBLER__"); if (!LangOpts.CPlusPlus) { if (LangOpts.C99) - DefineBuiltinMacro(Buf, "__STDC_VERSION__=199901L"); + Builder.defineMacro("__STDC_VERSION__", "199901L"); else if (!LangOpts.GNUMode && LangOpts.Digraphs) - DefineBuiltinMacro(Buf, "__STDC_VERSION__=199409L"); + Builder.defineMacro("__STDC_VERSION__", "199409L"); } // Standard conforming mode? if (!LangOpts.GNUMode) - DefineBuiltinMacro(Buf, "__STRICT_ANSI__=1"); + Builder.defineMacro("__STRICT_ANSI__"); if (LangOpts.CPlusPlus0x) - DefineBuiltinMacro(Buf, "__GXX_EXPERIMENTAL_CXX0X__"); + Builder.defineMacro("__GXX_EXPERIMENTAL_CXX0X__"); if (LangOpts.Freestanding) - DefineBuiltinMacro(Buf, "__STDC_HOSTED__=0"); + Builder.defineMacro("__STDC_HOSTED__", "0"); else - DefineBuiltinMacro(Buf, "__STDC_HOSTED__=1"); + Builder.defineMacro("__STDC_HOSTED__"); if (LangOpts.ObjC1) { - DefineBuiltinMacro(Buf, "__OBJC__=1"); + Builder.defineMacro("__OBJC__"); if (LangOpts.ObjCNonFragileABI) { - DefineBuiltinMacro(Buf, "__OBJC2__=1"); - DefineBuiltinMacro(Buf, "OBJC_ZEROCOST_EXCEPTIONS=1"); + Builder.defineMacro("__OBJC2__"); + Builder.defineMacro("OBJC_ZEROCOST_EXCEPTIONS"); } if (LangOpts.getGCMode() != LangOptions::NonGC) - DefineBuiltinMacro(Buf, "__OBJC_GC__=1"); + Builder.defineMacro("__OBJC_GC__"); if (LangOpts.NeXTRuntime) - DefineBuiltinMacro(Buf, "__NEXT_RUNTIME__=1"); + Builder.defineMacro("__NEXT_RUNTIME__"); } // darwin_constant_cfstrings controls this. This is also dependent // on other things like the runtime I believe. This is set even for C code. - DefineBuiltinMacro(Buf, "__CONSTANT_CFSTRINGS__=1"); + Builder.defineMacro("__CONSTANT_CFSTRINGS__"); if (LangOpts.ObjC2) - DefineBuiltinMacro(Buf, "OBJC_NEW_PROPERTIES"); + Builder.defineMacro("OBJC_NEW_PROPERTIES"); if (LangOpts.PascalStrings) - DefineBuiltinMacro(Buf, "__PASCAL_STRINGS__"); + Builder.defineMacro("__PASCAL_STRINGS__"); if (LangOpts.Blocks) { - DefineBuiltinMacro(Buf, "__block=__attribute__((__blocks__(byref)))"); - DefineBuiltinMacro(Buf, "__BLOCKS__=1"); + Builder.defineMacro("__block", "__attribute__((__blocks__(byref)))"); + Builder.defineMacro("__BLOCKS__"); } if (LangOpts.Exceptions) - DefineBuiltinMacro(Buf, "__EXCEPTIONS=1"); + Builder.defineMacro("__EXCEPTIONS"); if (LangOpts.CPlusPlus) { - DefineBuiltinMacro(Buf, "__DEPRECATED=1"); - DefineBuiltinMacro(Buf, "__GNUG__=4"); - DefineBuiltinMacro(Buf, "__GXX_WEAK__=1"); + Builder.defineMacro("__DEPRECATED"); + Builder.defineMacro("__GNUG__", "4"); + Builder.defineMacro("__GXX_WEAK__"); if (LangOpts.GNUMode) - DefineBuiltinMacro(Buf, "__cplusplus=1"); + Builder.defineMacro("__cplusplus"); else // C++ [cpp.predefined]p1: // The name_ _cplusplusis defined to the value199711Lwhen compiling a // C++ translation unit. - DefineBuiltinMacro(Buf, "__cplusplus=199711L"); - DefineBuiltinMacro(Buf, "__private_extern__=extern"); + Builder.defineMacro("__cplusplus", "199711L"); + Builder.defineMacro("__private_extern__", "extern"); // Ugly hack to work with GNU libstdc++. - DefineBuiltinMacro(Buf, "_GNU_SOURCE=1"); + Builder.defineMacro("_GNU_SOURCE"); } if (LangOpts.Microsoft) { // Filter out some microsoft extensions when trying to parse in ms-compat // mode. - DefineBuiltinMacro(Buf, "__int8=__INT8_TYPE__"); - DefineBuiltinMacro(Buf, "__int16=__INT16_TYPE__"); - DefineBuiltinMacro(Buf, "__int32=__INT32_TYPE__"); - DefineBuiltinMacro(Buf, "__int64=__INT64_TYPE__"); + Builder.defineMacro("__int8", "__INT8_TYPE__"); + Builder.defineMacro("__int16", "__INT16_TYPE__"); + Builder.defineMacro("__int32", "__INT32_TYPE__"); + Builder.defineMacro("__int64", "__INT64_TYPE__"); // Both __PRETTY_FUNCTION__ and __FUNCTION__ are GCC extensions, however // VC++ appears to only like __FUNCTION__. - DefineBuiltinMacro(Buf, "__PRETTY_FUNCTION__=__FUNCTION__"); + Builder.defineMacro("__PRETTY_FUNCTION__", "__FUNCTION__"); // Work around some issues with Visual C++ headerws. if (LangOpts.CPlusPlus) { // Since we define wchar_t in C++ mode. - DefineBuiltinMacro(Buf, "_WCHAR_T_DEFINED=1"); - DefineBuiltinMacro(Buf, "_NATIVE_WCHAR_T_DEFINED=1"); + Builder.defineMacro("_WCHAR_T_DEFINED"); + Builder.defineMacro("_NATIVE_WCHAR_T_DEFINED"); // FIXME: This should be temporary until we have a __pragma // solution, to avoid some errors flagged in VC++ headers. - DefineBuiltinMacro(Buf, "_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES=0"); + Builder.defineMacro("_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES", "0"); } } if (LangOpts.Optimize) - DefineBuiltinMacro(Buf, "__OPTIMIZE__=1"); + Builder.defineMacro("__OPTIMIZE__"); if (LangOpts.OptimizeSize) - DefineBuiltinMacro(Buf, "__OPTIMIZE_SIZE__=1"); + Builder.defineMacro("__OPTIMIZE_SIZE__"); // Initialize target-specific preprocessor defines. // Define type sizing macros based on the target properties. assert(TI.getCharWidth() == 8 && "Only support 8-bit char so far"); - DefineBuiltinMacro(Buf, "__CHAR_BIT__=8"); - - DefineTypeSize("__SCHAR_MAX__", TI.getCharWidth(), "", true, Buf); - DefineTypeSize("__SHRT_MAX__", TargetInfo::SignedShort, TI, Buf); - DefineTypeSize("__INT_MAX__", TargetInfo::SignedInt, TI, Buf); - DefineTypeSize("__LONG_MAX__", TargetInfo::SignedLong, TI, Buf); - DefineTypeSize("__LONG_LONG_MAX__", TargetInfo::SignedLongLong, TI, Buf); - DefineTypeSize("__WCHAR_MAX__", TI.getWCharType(), TI, Buf); - DefineTypeSize("__INTMAX_MAX__", TI.getIntMaxType(), TI, Buf); - - DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Buf); - DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Buf); - DefineTypeWidth("__INTMAX_WIDTH__", TI.getIntMaxType(), TI, Buf); - DefineType("__PTRDIFF_TYPE__", TI.getPtrDiffType(0), Buf); - DefineTypeWidth("__PTRDIFF_WIDTH__", TI.getPtrDiffType(0), TI, Buf); - DefineType("__INTPTR_TYPE__", TI.getIntPtrType(), Buf); - DefineTypeWidth("__INTPTR_WIDTH__", TI.getIntPtrType(), TI, Buf); - DefineType("__SIZE_TYPE__", TI.getSizeType(), Buf); - DefineTypeWidth("__SIZE_WIDTH__", TI.getSizeType(), TI, Buf); - DefineType("__WCHAR_TYPE__", TI.getWCharType(), Buf); - DefineTypeWidth("__WCHAR_WIDTH__", TI.getWCharType(), TI, Buf); - DefineType("__WINT_TYPE__", TI.getWIntType(), Buf); - DefineTypeWidth("__WINT_WIDTH__", TI.getWIntType(), TI, Buf); - DefineTypeWidth("__SIG_ATOMIC_WIDTH__", TI.getSigAtomicType(), TI, Buf); - - DefineFloatMacros(Buf, "FLT", &TI.getFloatFormat()); - DefineFloatMacros(Buf, "DBL", &TI.getDoubleFormat()); - DefineFloatMacros(Buf, "LDBL", &TI.getLongDoubleFormat()); + Builder.defineMacro("__CHAR_BIT__", "8"); + + DefineTypeSize("__SCHAR_MAX__", TI.getCharWidth(), "", true, Builder); + DefineTypeSize("__SHRT_MAX__", TargetInfo::SignedShort, TI, Builder); + DefineTypeSize("__INT_MAX__", TargetInfo::SignedInt, TI, Builder); + DefineTypeSize("__LONG_MAX__", TargetInfo::SignedLong, TI, Builder); + DefineTypeSize("__LONG_LONG_MAX__", TargetInfo::SignedLongLong, TI, Builder); + DefineTypeSize("__WCHAR_MAX__", TI.getWCharType(), TI, Builder); + DefineTypeSize("__INTMAX_MAX__", TI.getIntMaxType(), TI, Builder); + + DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Builder); + DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Builder); + DefineTypeWidth("__INTMAX_WIDTH__", TI.getIntMaxType(), TI, Builder); + DefineType("__PTRDIFF_TYPE__", TI.getPtrDiffType(0), Builder); + DefineTypeWidth("__PTRDIFF_WIDTH__", TI.getPtrDiffType(0), TI, Builder); + DefineType("__INTPTR_TYPE__", TI.getIntPtrType(), Builder); + DefineTypeWidth("__INTPTR_WIDTH__", TI.getIntPtrType(), TI, Builder); + DefineType("__SIZE_TYPE__", TI.getSizeType(), Builder); + DefineTypeWidth("__SIZE_WIDTH__", TI.getSizeType(), TI, Builder); + DefineType("__WCHAR_TYPE__", TI.getWCharType(), Builder); + DefineTypeWidth("__WCHAR_WIDTH__", TI.getWCharType(), TI, Builder); + DefineType("__WINT_TYPE__", TI.getWIntType(), Builder); + DefineTypeWidth("__WINT_WIDTH__", TI.getWIntType(), TI, Builder); + DefineTypeWidth("__SIG_ATOMIC_WIDTH__", TI.getSigAtomicType(), TI, Builder); + + DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat()); + DefineFloatMacros(Builder, "DBL", &TI.getDoubleFormat()); + DefineFloatMacros(Builder, "LDBL", &TI.getLongDoubleFormat()); // Define a __POINTER_WIDTH__ macro for stdint.h. - sprintf(MacroBuf, "__POINTER_WIDTH__=%d", (int)TI.getPointerWidth(0)); - DefineBuiltinMacro(Buf, MacroBuf); + Builder.defineMacro("__POINTER_WIDTH__", + llvm::Twine((int)TI.getPointerWidth(0))); if (!LangOpts.CharIsSigned) - DefineBuiltinMacro(Buf, "__CHAR_UNSIGNED__"); + Builder.defineMacro("__CHAR_UNSIGNED__"); // Define exact-width integer types for stdint.h - sprintf(MacroBuf, "__INT%d_TYPE__=char", TI.getCharWidth()); - DefineBuiltinMacro(Buf, MacroBuf); + Builder.defineMacro("__INT" + llvm::Twine(TI.getCharWidth()) + "_TYPE__", + "char"); if (TI.getShortWidth() > TI.getCharWidth()) - DefineExactWidthIntType(TargetInfo::SignedShort, TI, Buf); - + DefineExactWidthIntType(TargetInfo::SignedShort, TI, Builder); + if (TI.getIntWidth() > TI.getShortWidth()) - DefineExactWidthIntType(TargetInfo::SignedInt, TI, Buf); - + DefineExactWidthIntType(TargetInfo::SignedInt, TI, Builder); + if (TI.getLongWidth() > TI.getIntWidth()) - DefineExactWidthIntType(TargetInfo::SignedLong, TI, Buf); - + DefineExactWidthIntType(TargetInfo::SignedLong, TI, Builder); + if (TI.getLongLongWidth() > TI.getLongWidth()) - DefineExactWidthIntType(TargetInfo::SignedLongLong, TI, Buf); - + DefineExactWidthIntType(TargetInfo::SignedLongLong, TI, Builder); + // Add __builtin_va_list typedef. - { - const char *VAList = TI.getVAListDeclaration(); - Buf.insert(Buf.end(), VAList, VAList+strlen(VAList)); - Buf.push_back('\n'); - } + Builder.append(TI.getVAListDeclaration()); - if (const char *Prefix = TI.getUserLabelPrefix()) { - sprintf(MacroBuf, "__USER_LABEL_PREFIX__=%s", Prefix); - DefineBuiltinMacro(Buf, MacroBuf); - } + if (const char *Prefix = TI.getUserLabelPrefix()) + Builder.defineMacro("__USER_LABEL_PREFIX__", Prefix); // Build configuration options. FIXME: these should be controlled by // command line options or something. - DefineBuiltinMacro(Buf, "__FINITE_MATH_ONLY__=0"); + Builder.defineMacro("__FINITE_MATH_ONLY__", "0"); if (LangOpts.GNUInline) - DefineBuiltinMacro(Buf, "__GNUC_GNU_INLINE__=1"); + Builder.defineMacro("__GNUC_GNU_INLINE__"); else - DefineBuiltinMacro(Buf, "__GNUC_STDC_INLINE__=1"); + Builder.defineMacro("__GNUC_STDC_INLINE__"); if (LangOpts.NoInline) - DefineBuiltinMacro(Buf, "__NO_INLINE__=1"); + Builder.defineMacro("__NO_INLINE__"); if (unsigned PICLevel = LangOpts.PICLevel) { - sprintf(MacroBuf, "__PIC__=%d", PICLevel); - DefineBuiltinMacro(Buf, MacroBuf); - - sprintf(MacroBuf, "__pic__=%d", PICLevel); - DefineBuiltinMacro(Buf, MacroBuf); + Builder.defineMacro("__PIC__", llvm::Twine(PICLevel)); + Builder.defineMacro("__pic__", llvm::Twine(PICLevel)); } // Macros to control C99 numerics and <float.h> - DefineBuiltinMacro(Buf, "__FLT_EVAL_METHOD__=0"); - DefineBuiltinMacro(Buf, "__FLT_RADIX__=2"); - sprintf(MacroBuf, "__DECIMAL_DIG__=%d", - PickFP(&TI.getLongDoubleFormat(), -1/*FIXME*/, 17, 21, 33, 36)); - DefineBuiltinMacro(Buf, MacroBuf); + Builder.defineMacro("__FLT_EVAL_METHOD__", "0"); + Builder.defineMacro("__FLT_RADIX__", "2"); + int Dig = PickFP(&TI.getLongDoubleFormat(), -1/*FIXME*/, 17, 21, 33, 36); + Builder.defineMacro("__DECIMAL_DIG__", llvm::Twine(Dig)); if (LangOpts.getStackProtectorMode() == LangOptions::SSPOn) - DefineBuiltinMacro(Buf, "__SSP__=1"); + Builder.defineMacro("__SSP__"); else if (LangOpts.getStackProtectorMode() == LangOptions::SSPReq) - DefineBuiltinMacro(Buf, "__SSP_ALL__=2"); + Builder.defineMacro("__SSP_ALL__", "2"); + if (FEOpts.ProgramAction == frontend::RewriteObjC) + Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))"); // Get other target #defines. - TI.getTargetDefines(LangOpts, Buf); + TI.getTargetDefines(LangOpts, Builder); } // Initialize the remapping of files to alternative contents, e.g., @@ -536,58 +465,55 @@ static void InitializeFileRemapping(Diagnostic &Diags, /// void clang::InitializePreprocessor(Preprocessor &PP, const PreprocessorOptions &InitOpts, - const HeaderSearchOptions &HSOpts) { - std::vector<char> PredefineBuffer; + const HeaderSearchOptions &HSOpts, + const FrontendOptions &FEOpts) { + std::string PredefineBuffer; + PredefineBuffer.reserve(4080); + llvm::raw_string_ostream Predefines(PredefineBuffer); + MacroBuilder Builder(Predefines); InitializeFileRemapping(PP.getDiagnostics(), PP.getSourceManager(), PP.getFileManager(), InitOpts); - const char *LineDirective = "# 1 \"<built-in>\" 3\n"; - PredefineBuffer.insert(PredefineBuffer.end(), - LineDirective, LineDirective+strlen(LineDirective)); + Builder.append("# 1 \"<built-in>\" 3"); // Install things like __POWERPC__, __GNUC__, etc into the macro table. if (InitOpts.UsePredefines) InitializePredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(), - PredefineBuffer); + FEOpts, Builder); // Add on the predefines from the driver. Wrap in a #line directive to report // that they come from the command line. - LineDirective = "# 1 \"<command line>\" 1\n"; - PredefineBuffer.insert(PredefineBuffer.end(), - LineDirective, LineDirective+strlen(LineDirective)); + Builder.append("# 1 \"<command line>\" 1"); // Process #define's and #undef's in the order they are given. for (unsigned i = 0, e = InitOpts.Macros.size(); i != e; ++i) { if (InitOpts.Macros[i].second) // isUndef - UndefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str()); + Builder.undefineMacro(InitOpts.Macros[i].first); else - DefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str(), - &PP.getDiagnostics()); + DefineBuiltinMacro(Builder, InitOpts.Macros[i].first, + PP.getDiagnostics()); } // If -imacros are specified, include them now. These are processed before // any -include directives. for (unsigned i = 0, e = InitOpts.MacroIncludes.size(); i != e; ++i) - AddImplicitIncludeMacros(PredefineBuffer, InitOpts.MacroIncludes[i]); + AddImplicitIncludeMacros(Builder, InitOpts.MacroIncludes[i]); // Process -include directives. for (unsigned i = 0, e = InitOpts.Includes.size(); i != e; ++i) { const std::string &Path = InitOpts.Includes[i]; if (Path == InitOpts.ImplicitPTHInclude) - AddImplicitIncludePTH(PredefineBuffer, PP, Path); + AddImplicitIncludePTH(Builder, PP, Path); else - AddImplicitInclude(PredefineBuffer, Path); + AddImplicitInclude(Builder, 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)); + Builder.append("# 1 \"<built-in>\" 2"); - // Null terminate PredefinedBuffer and add it. - PredefineBuffer.push_back(0); - PP.setPredefines(&PredefineBuffer[0]); + // Copy PredefinedBuffer into the Preprocessor. + PP.setPredefines(Predefines.str()); // Initialize the header search object. ApplyHeaderSearchOptions(PP.getHeaderSearchInfo(), HSOpts, diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index d8fd791..07d5a78 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -1079,6 +1079,61 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) { } } +void PCHReader::ReadDefinedMacros() { + // If there was no preprocessor block, do nothing. + if (!MacroCursor.getBitStreamReader()) + return; + + llvm::BitstreamCursor Cursor = MacroCursor; + if (Cursor.EnterSubBlock(pch::PREPROCESSOR_BLOCK_ID)) { + Error("malformed preprocessor block record in PCH file"); + return; + } + + RecordData Record; + while (true) { + unsigned Code = Cursor.ReadCode(); + if (Code == llvm::bitc::END_BLOCK) { + if (Cursor.ReadBlockEnd()) + Error("error at end of preprocessor block in PCH file"); + return; + } + + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + // No known subblocks, always skip them. + Cursor.ReadSubBlockID(); + if (Cursor.SkipBlock()) { + Error("malformed block record in PCH file"); + return; + } + continue; + } + + if (Code == llvm::bitc::DEFINE_ABBREV) { + Cursor.ReadAbbrevRecord(); + continue; + } + + // Read a record. + const char *BlobStart; + unsigned BlobLen; + Record.clear(); + switch (Cursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { + default: // Default behavior: ignore. + break; + + case pch::PP_MACRO_OBJECT_LIKE: + case pch::PP_MACRO_FUNCTION_LIKE: + DecodeIdentifierInfo(Record[0]); + break; + + case pch::PP_TOKEN: + // Ignore tokens. + break; + } + } +} + /// \brief If we are loading a relocatable PCH file, and the filename is /// not an absolute path, add the system root to the beginning of the file /// name. @@ -1140,6 +1195,10 @@ PCHReader::ReadPCHBlock() { break; case pch::PREPROCESSOR_BLOCK_ID: + MacroCursor = Stream; + if (PP) + PP->setExternalSource(this); + if (Stream.SkipBlock()) { Error("malformed block record in PCH file"); return Failure; @@ -1494,7 +1553,8 @@ void PCHReader::InitializeContext(ASTContext &Ctx) { assert(PP && "Forgot to set Preprocessor ?"); PP->getIdentifierTable().setExternalIdentifierLookup(this); PP->getHeaderSearchInfo().SetExternalLookup(this); - + PP->setExternalSource(this); + // Load the translation unit declaration ReadDeclRecord(DeclOffsets[0], 0); @@ -2051,10 +2111,15 @@ void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } void TypeLocReader::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setTypeofLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setTypeofLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(Record, Idx)); } void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index 01e1a41..69343ed 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -208,7 +208,9 @@ void PCHDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { void PCHDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) { VisitNamedDecl(CD); - CD->setAtEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + SourceLocation A = SourceLocation::getFromRawEncoding(Record[Idx++]); + SourceLocation B = SourceLocation::getFromRawEncoding(Record[Idx++]); + CD->setAtEndRange(SourceRange(A, B)); } void PCHDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) { @@ -436,6 +438,9 @@ Attr *PCHReader::ReadAttributes() { bool IsInherited = Record[Idx++]; switch (Kind) { + default: + assert(0 && "Unknown attribute!"); + break; STRING_ATTR(Alias); UNSIGNED_ATTR(Aligned); SIMPLE_ATTR(AlwaysInline); diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp index ba82d26..138f1e1 100644 --- a/lib/Frontend/PCHReaderStmt.cpp +++ b/lib/Frontend/PCHReaderStmt.cpp @@ -304,6 +304,7 @@ unsigned PCHStmtReader::VisitAsmStmt(AsmStmt *S) { S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); S->setVolatile(Record[Idx++]); S->setSimple(Record[Idx++]); + S->setMSAsm(Record[Idx++]); unsigned StackIdx = StmtStack.size() - (NumOutputs*2 + NumInputs*2 + NumClobbers + 1); @@ -615,7 +616,8 @@ unsigned PCHStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) { } } } - E->setDesignators(Designators.data(), Designators.size()); + E->setDesignators(*Reader.getContext(), + Designators.data(), Designators.size()); return NumSubExprs; } diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 2875f09..3f6841b 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -344,10 +344,15 @@ void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); + Writer.AddSourceLocation(TL.getTypeofLoc(), Record); + Writer.AddSourceLocation(TL.getLParenLoc(), Record); + Writer.AddSourceLocation(TL.getRParenLoc(), Record); } void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); + Writer.AddSourceLocation(TL.getTypeofLoc(), Record); + Writer.AddSourceLocation(TL.getLParenLoc(), Record); + Writer.AddSourceLocation(TL.getRParenLoc(), Record); + Writer.AddTypeSourceInfo(TL.getUnderlyingTInfo(), Record); } void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); @@ -1148,7 +1153,6 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) { // Loop over all the macro definitions that are live at the end of the file, // emitting each to the PP section. - // FIXME: Make sure that this sees macros defined in included PCH files. for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end(); I != E; ++I) { // FIXME: This emits macros in hash table order, we should do it in a stable @@ -1160,7 +1164,6 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) { if (MI->isBuiltinMacro()) continue; - // FIXME: Remove this identifier reference? AddIdentifierRef(I->first, Record); MacroOffsets[I->first] = Stream.GetCurrentBitNo(); Record.push_back(MI->getDefinitionLoc().getRawEncoding()); @@ -1741,9 +1744,12 @@ void PCHWriter::WriteIdentifierTable(Preprocessor &PP) { void PCHWriter::WriteAttributeRecord(const Attr *Attr) { RecordData Record; for (; Attr; Attr = Attr->getNext()) { - Record.push_back(Attr->getKind()); // FIXME: stable encoding + Record.push_back(Attr->getKind()); // FIXME: stable encoding, target attrs Record.push_back(Attr->isInherited()); switch (Attr->getKind()) { + default: + assert(0 && "Does not support PCH writing for this attribute yet!"); + break; case Attr::Alias: AddString(cast<AliasAttr>(Attr)->getAliasee(), Record); break; diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index 049cdb0..2dbcc27 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -208,7 +208,9 @@ void PCHDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) { void PCHDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) { VisitNamedDecl(D); - Writer.AddSourceLocation(D->getAtEndLoc(), Record); + SourceRange R = D->getAtEndRange(); + Writer.AddSourceLocation(R.getBegin(), Record); + Writer.AddSourceLocation(R.getEnd(), Record); // Abstract class (no need to define a stable pch::DECL code). } diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp index abf4eaa..4be9b81 100644 --- a/lib/Frontend/PCHWriterStmt.cpp +++ b/lib/Frontend/PCHWriterStmt.cpp @@ -277,6 +277,7 @@ void PCHStmtWriter::VisitAsmStmt(AsmStmt *S) { Writer.AddSourceLocation(S->getRParenLoc(), Record); Record.push_back(S->isVolatile()); Record.push_back(S->isSimple()); + Record.push_back(S->isMSAsm()); Writer.WriteSubStmt(S->getAsmString()); // Outputs diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp index c5dc979..95afb90 100644 --- a/lib/Frontend/PrintParserCallbacks.cpp +++ b/lib/Frontend/PrintParserCallbacks.cpp @@ -394,7 +394,8 @@ namespace { MultiExprArg Exprs, ExprArg AsmString, MultiExprArg Clobbers, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, + bool MSAsm) { Out << __FUNCTION__ << "\n"; return StmtEmpty(); } diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index c347472..fc9401d 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -25,6 +25,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/DenseSet.h" using namespace clang; using llvm::utostr; @@ -75,7 +76,9 @@ namespace { llvm::SmallVector<int, 8> ObjCBcLabelNo; // Remember all the @protocol(<expr>) expressions. llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ProtocolExprDecls; - + + llvm::DenseSet<uint64_t> CopyDestroyCache; + unsigned NumObjCStringLiterals; FunctionDecl *MsgSendFunctionDecl; @@ -111,6 +114,7 @@ namespace { llvm::raw_ostream* OutFile; bool SilenceRewriteMacroWarning; + bool objc_impl_method; std::string Preamble; @@ -122,6 +126,7 @@ namespace { // Block related declarations. llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDecls; llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDecls; + llvm::DenseMap<ValueDecl *, unsigned> BlockByRefDeclNo; llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls; llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs; @@ -138,6 +143,7 @@ namespace { llvm::DenseMap<Stmt *, Stmt *> ReplacedNodes; FunctionDecl *CurFunctionDef; + FunctionDecl *CurFunctionDeclToDeclareForBlock; VarDecl *GlobalVarDecl; bool DisableReplaceStmt; @@ -247,12 +253,15 @@ namespace { void RewriteInterfaceDecl(ObjCInterfaceDecl *Dcl); void RewriteImplementationDecl(Decl *Dcl); void RewriteObjCMethodDecl(ObjCMethodDecl *MDecl, std::string &ResultStr); + void RewriteByRefString(std::string &ResultStr, const std::string &Name, + ValueDecl *VD); void RewriteCategoryDecl(ObjCCategoryDecl *Dcl); void RewriteProtocolDecl(ObjCProtocolDecl *Dcl); void RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *Dcl); void RewriteMethodDeclaration(ObjCMethodDecl *Method); void RewriteProperty(ObjCPropertyDecl *prop); void RewriteFunctionDecl(FunctionDecl *FD); + void RewriteBlockLiteralFunctionDecl(FunctionDecl *FD); void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl); void RewriteObjCQualifiedInterfaceTypes(Expr *E); bool needToScanForQualifiers(QualType T); @@ -347,7 +356,8 @@ namespace { void RewriteBlockCall(CallExpr *Exp); void RewriteBlockPointerDecl(NamedDecl *VD); void RewriteByRefVar(VarDecl *VD); - Stmt *RewriteBlockDeclRefExpr(BlockDeclRefExpr *VD); + std::string SynthesizeByrefCopyDestroyHelper(VarDecl *VD, int flag); + Stmt *RewriteBlockDeclRefExpr(Expr *VD); void RewriteBlockPointerFunctionArgs(FunctionDecl *FD); std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, @@ -362,7 +372,7 @@ namespace { unsigned hasCopy); Stmt *SynthesizeBlockCall(CallExpr *Exp, const Expr* BlockExp); void SynthesizeBlockLiterals(SourceLocation FunLocStart, - const char *FunName); + const char *FunName); void RewriteRecordBody(RecordDecl *RD); void CollectBlockDeclRefInfo(BlockExpr *Exp); @@ -483,6 +493,7 @@ void RewriteObjC::Initialize(ASTContext &context) { NSStringRecord = 0; CurMethodDef = 0; CurFunctionDef = 0; + CurFunctionDeclToDeclareForBlock = 0; GlobalVarDecl = 0; SuperStructDecl = 0; ProtocolTypeDecl = 0; @@ -493,6 +504,7 @@ void RewriteObjC::Initialize(ASTContext &context) { PropParentMap = 0; CurrentBody = 0; DisableReplaceStmt = false; + objc_impl_method = false; // Get the ID and start/end of the main file. MainFileID = SM->getMainFileID(); @@ -588,8 +600,8 @@ void RewriteObjC::Initialize(ASTContext &context) { 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 \"C\" void _Block_object_assign(void *, const void *, const int);\n"; - Preamble += "__OBJC_RW_DLLIMPORT \"C\" void _Block_object_dispose(const void *, const int);\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"; @@ -599,8 +611,10 @@ void RewriteObjC::Initialize(ASTContext &context) { Preamble += "#undef __OBJC_RW_STATICIMPORT\n"; Preamble += "#define __attribute__(X)\n"; } - else + else { Preamble += "#define __block\n"; + Preamble += "#define __weak\n"; + } } @@ -779,9 +793,17 @@ void RewriteObjC::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) { // as the class. As a convenience, we include the original declaration // as a comment. std::string typedefString; - typedefString += "// "; - typedefString.append(startBuf, semiPtr-startBuf+1); - typedefString += "\n"; + typedefString += "// @class "; + for (ObjCClassDecl::iterator I = ClassDecl->begin(), E = ClassDecl->end(); + I != E; ++I) { + ObjCInterfaceDecl *ForwardDecl = I->getInterface(); + typedefString += ForwardDecl->getNameAsString(); + if (I+1 != E) + typedefString += ", "; + else + typedefString += ";\n"; + } + for (ObjCClassDecl::iterator I = ClassDecl->begin(), E = ClassDecl->end(); I != E; ++I) { ObjCInterfaceDecl *ForwardDecl = I->getInterface(); @@ -838,7 +860,7 @@ void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) { RewriteMethodDeclaration(*I); // Lastly, comment out the @end. - ReplaceText(CatDecl->getAtEndLoc(), 0, "// ", 3); + ReplaceText(CatDecl->getAtEndRange().getBegin(), 0, "// ", 3); } void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) { @@ -859,7 +881,7 @@ void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) { RewriteMethodDeclaration(*I); // Lastly, comment out the @end. - SourceLocation LocEnd = PDecl->getAtEndLoc(); + SourceLocation LocEnd = PDecl->getAtEndRange().getBegin(); ReplaceText(LocEnd, 0, "// ", 3); // Must comment out @optional/@required @@ -1096,7 +1118,7 @@ void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) { RewriteMethodDeclaration(*I); // Lastly, comment out the @end. - ReplaceText(ClassDecl->getAtEndLoc(), 0, "// ", 3); + ReplaceText(ClassDecl->getAtEndRange().getBegin(), 0, "// ", 3); } Stmt *RewriteObjC::RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt, @@ -1177,10 +1199,12 @@ Stmt *RewriteObjC::RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr) { Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, SourceLocation OrigStart) { ObjCIvarDecl *D = IV->getDecl(); + const Expr *BaseExpr = IV->getBase(); if (CurMethodDef) { - if (const PointerType *pType = IV->getBase()->getType()->getAs<PointerType>()) { + if (BaseExpr->getType()->isObjCObjectPointerType() && + isa<DeclRefExpr>(BaseExpr)) { ObjCInterfaceType *iFaceDecl = - dyn_cast<ObjCInterfaceType>(pType->getPointeeType()); + dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType()); // lookup which class implements the instance variable. ObjCInterfaceDecl *clsDeclared = 0; iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(), @@ -1226,8 +1250,9 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, // Explicit ivar refs need to have a cast inserted. // FIXME: consider sharing some of this code with the code above. - if (const PointerType *pType = IV->getBase()->getType()->getAs<PointerType>()) { - ObjCInterfaceType *iFaceDecl = dyn_cast<ObjCInterfaceType>(pType->getPointeeType()); + if (BaseExpr->getType()->isObjCObjectPointerType()) { + ObjCInterfaceType *iFaceDecl = + dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType()); // lookup which class implements the instance variable. ObjCInterfaceDecl *clsDeclared = 0; iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(), @@ -1474,14 +1499,18 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, SynthCountByEnumWithState(buf); buf += ");\n\t"; buf += elementName; - buf += " = ((id)0);\n\t"; + buf += " = (("; + buf += elementTypeAsString; + buf += ")0);\n\t"; buf += "__break_label_"; buf += utostr(ObjCBcLabelNo.back()); buf += ": ;\n\t"; buf += "}\n\t"; buf += "else\n\t\t"; buf += elementName; - buf += " = ((id)0);\n"; + buf += " = (("; + buf += elementTypeAsString; + buf += ")0);\n\t"; buf += "}\n"; // Insert all these *after* the statement body. @@ -1735,10 +1764,10 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { buf += "1) { "; ReplaceText(startLoc, lParenLoc-startBuf+1, buf.c_str(), buf.size()); sawIdTypedCatch = true; - } else if (const PointerType *pType = t->getAs<PointerType>()) { - ObjCInterfaceType *cls; // Should be a pointer to a class. - - cls = dyn_cast<ObjCInterfaceType>(pType->getPointeeType().getTypePtr()); + } else if (t->isObjCObjectPointerType()) { + QualType InterfaceTy = t->getPointeeType(); + const ObjCInterfaceType *cls = // Should be a pointer to a class. + InterfaceTy->getAs<ObjCInterfaceType>(); if (cls) { buf += "objc_exception_match((struct objc_class *)objc_getClass(\""; buf += cls->getDecl()->getNameAsString(); @@ -2092,6 +2121,30 @@ void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) { RewriteObjCQualifiedInterfaceTypes(FD); } +void RewriteObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) { + SourceLocation FunLocStart = FD->getTypeSpecStartLoc(); + const FunctionType *funcType = FD->getType()->getAs<FunctionType>(); + const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(funcType); + if (!proto) + return; + QualType Type = proto->getResultType(); + std::string FdStr = Type.getAsString(); + FdStr += " "; + FdStr += FD->getNameAsCString(); + FdStr += "("; + unsigned numArgs = proto->getNumArgs(); + for (unsigned i = 0; i < numArgs; i++) { + QualType ArgType = proto->getArgType(i); + FdStr += ArgType.getAsString(); + + if (i+1 < numArgs) + FdStr += ", "; + } + FdStr += ");\n"; + InsertText(FunLocStart, FdStr.c_str(), FdStr.size()); + CurFunctionDeclToDeclareForBlock = 0; +} + // SynthSuperContructorFunctionDecl - id objc_super(id obj, id super); void RewriteObjC::SynthSuperContructorFunctionDecl() { if (SuperContructorFunctionDecl) @@ -2946,7 +2999,6 @@ void RewriteObjC::RewriteObjCMethodsMetaData(MethodIterator MethodBegin, std::string &Result) { if (MethodBegin == MethodEnd) return; - static bool objc_impl_method = false; if (!objc_impl_method) { /* struct _objc_method { SEL _cmd; @@ -3617,7 +3669,7 @@ void RewriteObjC::SynthesizeMetaDataIntoBuffer(std::string &Result) { int CatDefCount = CategoryImplementation.size(); // This is needed for determining instance variable offsets. - Result += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER)\n"; + Result += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long) &((TYPE *)0)->MEMBER)\n"; // For each implemented class, write out all its meta data. for (int i = 0; i < ClsDefCount; i++) RewriteObjCClassMetaData(ClassImplementation[i], Result); @@ -3711,6 +3763,15 @@ void RewriteObjC::SynthesizeMetaDataIntoBuffer(std::string &Result) { } } +void RewriteObjC::RewriteByRefString(std::string &ResultStr, + const std::string &Name, + ValueDecl *VD) { + assert(BlockByRefDeclNo.count(VD) && + "RewriteByRefString: ByRef decl missing"); + ResultStr += "struct __Block_byref_" + Name + + "_" + utostr(BlockByRefDeclNo[VD]) ; +} + std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, const char *funcName, std::string Tag) { @@ -3756,7 +3817,9 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, E = BlockByRefDecls.end(); I != E; ++I) { S += " "; std::string Name = (*I)->getNameAsString(); - std::string TypeString = "struct __Block_byref_" + Name + " *"; + std::string TypeString; + RewriteByRefString(TypeString, Name, (*I)); + TypeString += " *"; Name = TypeString + Name; S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n"; } @@ -3891,7 +3954,8 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, S += "struct __block_impl *"; Constructor += ", void *" + ArgName; } else { - std::string TypeString = "struct __Block_byref_" + FieldName; + std::string TypeString; + RewriteByRefString(TypeString, FieldName, (*I)); TypeString += " *"; FieldName = TypeString + FieldName; ArgName = TypeString + ArgName; @@ -3977,7 +4041,10 @@ std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag, } void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, - const char *FunName) { + const char *FunName) { + // Insert declaration for the function in which block literal is used. + if (CurFunctionDeclToDeclareForBlock) + RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock); // Insert closures that were part of the function. for (unsigned i = 0; i < Blocks.size(); i++) { @@ -4192,29 +4259,40 @@ void RewriteObjC::RewriteBlockCall(CallExpr *Exp) { // i = 77; // }; //} -Stmt *RewriteObjC::RewriteBlockDeclRefExpr(BlockDeclRefExpr *BDRE) { +Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) { // Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR - // for each BDRE where BYREFVAR is name of the variable. + // for each DeclRefExp where BYREFVAR is name of the variable. + ValueDecl *VD; + bool isArrow = true; + if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(DeclRefExp)) + VD = BDRE->getDecl(); + else { + VD = cast<DeclRefExpr>(DeclRefExp)->getDecl(); + isArrow = false; + } + FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(), &Context->Idents.get("__forwarding"), Context->VoidPtrTy, 0, /*BitWidth=*/0, /*Mutable=*/true); - MemberExpr *ME = new (Context) MemberExpr(BDRE, true, FD, SourceLocation(), + MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow, + FD, SourceLocation(), FD->getType()); - const char *Name = BDRE->getDecl()->getNameAsCString(); + + const char *Name = VD->getNameAsCString(); FD = FieldDecl::Create(*Context, 0, SourceLocation(), &Context->Idents.get(Name), Context->VoidPtrTy, 0, /*BitWidth=*/0, /*Mutable=*/true); ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(), - BDRE->getType()); + DeclRefExp->getType()); // Need parens to enforce precedence. ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), ME); - ReplaceStmt(BDRE, PE); + ReplaceStmt(DeclRefExp, PE); return PE; } @@ -4369,6 +4447,64 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) { return; } + +/// SynthesizeByrefCopyDestroyHelper - This routine synthesizes: +/// void __Block_byref_id_object_copy(struct Block_byref_id_object *dst, +/// struct Block_byref_id_object *src) { +/// _Block_object_assign (&_dest->object, _src->object, +/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT +/// [|BLOCK_FIELD_IS_WEAK]) // object +/// _Block_object_assign(&_dest->object, _src->object, +/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK +/// [|BLOCK_FIELD_IS_WEAK]) // block +/// } +/// And: +/// void __Block_byref_id_object_dispose(struct Block_byref_id_object *_src) { +/// _Block_object_dispose(_src->object, +/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT +/// [|BLOCK_FIELD_IS_WEAK]) // object +/// _Block_object_dispose(_src->object, +/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK +/// [|BLOCK_FIELD_IS_WEAK]) // block +/// } + +std::string RewriteObjC::SynthesizeByrefCopyDestroyHelper(VarDecl *VD, + int flag) { + std::string S; + if (CopyDestroyCache.count(flag)) + return S; + CopyDestroyCache.insert(flag); + S = "static void __Block_byref_id_object_copy_"; + S += utostr(flag); + S += "(void *dst, void *src) {\n"; + + // offset into the object pointer is computed as: + // void * + void* + int + int + void* + void * + unsigned IntSize = + static_cast<unsigned>(Context->getTypeSize(Context->IntTy)); + unsigned VoidPtrSize = + static_cast<unsigned>(Context->getTypeSize(Context->VoidPtrTy)); + + unsigned offset = (VoidPtrSize*4 + IntSize + IntSize)/8; + S += " _Block_object_assign((char*)dst + "; + S += utostr(offset); + S += ", *(void * *) ((char*)src + "; + S += utostr(offset); + S += "), "; + S += utostr(flag); + S += ");\n}\n"; + + S += "static void __Block_byref_id_object_dispose_"; + S += utostr(flag); + S += "(void *src) {\n"; + S += " _Block_object_dispose(*(void * *) ((char*)src + "; + S += utostr(offset); + S += "), "; + S += utostr(flag); + S += ");\n}\n"; + return S; +} + /// RewriteByRefVar - For each __block typex ND variable this routine transforms /// the declaration into: /// struct __Block_byref_ND { @@ -4376,8 +4512,8 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) { /// struct __Block_byref_ND *__forwarding; /// int32_t __flags; /// int32_t __size; -/// void *__ByrefKeepFuncPtr; // Only if variable is __block ObjC object -/// void *__ByrefDestroyFuncPtr; // Only if variable is __block ObjC object +/// void *__Block_byref_id_object_copy; // If variable is __block ObjC object +/// void *__Block_byref_id_object_dispose; // If variable is __block ObjC object /// typex ND; /// }; /// @@ -4388,54 +4524,110 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) { /// /// void RewriteObjC::RewriteByRefVar(VarDecl *ND) { + // Insert declaration for the function in which block literal is + // used. + if (CurFunctionDeclToDeclareForBlock) + RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock); + int flag = 0; + int isa = 0; SourceLocation DeclLoc = ND->getTypeSpecStartLoc(); const char *startBuf = SM->getCharacterData(DeclLoc); SourceLocation X = ND->getLocEnd(); X = SM->getInstantiationLoc(X); const char *endBuf = SM->getCharacterData(X); std::string Name(ND->getNameAsString()); - std::string ByrefType = "struct __Block_byref_"; - ByrefType += Name; + std::string ByrefType; + RewriteByRefString(ByrefType, Name, ND); ByrefType += " {\n"; ByrefType += " void *__isa;\n"; - ByrefType += " struct __Block_byref_" + Name + " *__forwarding;\n"; + RewriteByRefString(ByrefType, Name, ND); + ByrefType += " *__forwarding;\n"; ByrefType += " int __flags;\n"; ByrefType += " int __size;\n"; - // FIXME. Add void *__ByrefKeepFuncPtr; void *__ByrefDestroyFuncPtr; - // if needed. - ND->getType().getAsStringInternal(Name, Context->PrintingPolicy); + // Add void *__Block_byref_id_object_copy; + // void *__Block_byref_id_object_dispose; if needed. + QualType Ty = ND->getType(); + bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty); + if (HasCopyAndDispose) { + ByrefType += " void (*__Block_byref_id_object_copy)(void*, void*);\n"; + ByrefType += " void (*__Block_byref_id_object_dispose)(void*);\n"; + } + + Ty.getAsStringInternal(Name, Context->PrintingPolicy); ByrefType += " " + Name + ";\n"; ByrefType += "};\n"; // Insert this type in global scope. It is needed by helper function. assert(CurFunctionDef && "RewriteByRefVar - CurFunctionDef is null"); SourceLocation FunLocStart = CurFunctionDef->getTypeSpecStartLoc(); InsertText(FunLocStart, ByrefType.c_str(), ByrefType.size()); + if (Ty.isObjCGCWeak()) { + flag |= BLOCK_FIELD_IS_WEAK; + isa = 1; + } + + if (HasCopyAndDispose) { + flag = BLOCK_BYREF_CALLER; + QualType Ty = ND->getType(); + // FIXME. Handle __weak variable (BLOCK_FIELD_IS_WEAK) as well. + if (Ty->isBlockPointerType()) + flag |= BLOCK_FIELD_IS_BLOCK; + else + flag |= BLOCK_FIELD_IS_OBJECT; + std::string HF = SynthesizeByrefCopyDestroyHelper(ND, flag); + if (!HF.empty()) + InsertText(FunLocStart, HF.c_str(), HF.size()); + } // struct __Block_byref_ND ND = // {0, &ND, some_flag, __size=sizeof(struct __Block_byref_ND), // initializer-if-any}; bool hasInit = (ND->getInit() != 0); + unsigned flags = 0; + if (HasCopyAndDispose) + flags |= BLOCK_HAS_COPY_DISPOSE; Name = ND->getNameAsString(); - ByrefType = "struct __Block_byref_" + Name; + ByrefType.clear(); + RewriteByRefString(ByrefType, Name, ND); if (!hasInit) { - ByrefType += " " + Name + " = "; - ByrefType += "{0, &" + Name + ", "; - // FIXME. Compute the flag. - ByrefType += "0, "; - ByrefType += "sizeof(struct __Block_byref_" + Name + ")"; + ByrefType += " " + Name + " = {(void*)"; + ByrefType += utostr(isa); + ByrefType += ", &" + Name + ", "; + ByrefType += utostr(flags); + ByrefType += ", "; + ByrefType += "sizeof("; + RewriteByRefString(ByrefType, Name, ND); + ByrefType += ")"; + if (HasCopyAndDispose) { + ByrefType += ", __Block_byref_id_object_copy_"; + ByrefType += utostr(flag); + ByrefType += ", __Block_byref_id_object_dispose_"; + ByrefType += utostr(flag); + } ByrefType += "};\n"; ReplaceText(DeclLoc, endBuf-startBuf+Name.size(), ByrefType.c_str(), ByrefType.size()); } else { SourceLocation startLoc = ND->getInit()->getLocStart(); + startLoc = SM->getInstantiationLoc(startLoc); ByrefType += " " + Name; ReplaceText(DeclLoc, endBuf-startBuf, ByrefType.c_str(), ByrefType.size()); - ByrefType = " = {0, &" + Name + ", "; - // FIXME. Compute the flag. - ByrefType += "0, "; - ByrefType += "sizeof(struct __Block_byref_" + Name + "), "; + ByrefType = " = {(void*)"; + ByrefType += utostr(isa); + ByrefType += ", &" + Name + ", "; + ByrefType += utostr(flags); + ByrefType += ", "; + ByrefType += "sizeof("; + RewriteByRefString(ByrefType, Name, ND); + ByrefType += "), "; + if (HasCopyAndDispose) { + ByrefType += "__Block_byref_id_object_copy_"; + ByrefType += utostr(flag); + ByrefType += ", __Block_byref_id_object_dispose_"; + ByrefType += utostr(flag); + ByrefType += ", "; + } InsertText(startLoc, ByrefType.c_str(), ByrefType.size()); // Complete the newly synthesized compound expression by inserting a right @@ -4638,8 +4830,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { Stmts.push_back(S); else if (isa<ObjCForCollectionStmt>(S)) { Stmts.push_back(S); - ++BcLabelCount; - ObjCBcLabelNo.push_back(BcLabelCount); + ObjCBcLabelNo.push_back(++BcLabelCount); } SourceRange OrigStmtRange = S->getSourceRange(); @@ -4658,7 +4849,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { RewriteFunctionBodyOrGlobalInitializer(BE->getBody()); // Now we snarf the rewritten text and stash it away for later use. - std::string Str = Rewrite.getRewritenText(BE->getSourceRange()); + std::string Str = Rewrite.getRewrittenText(BE->getSourceRange()); RewrittenBlockExprs[BE] = Str; Stmt *blockTranscribed = SynthBlockInitExpr(BE); @@ -4801,8 +4992,13 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { else if (ND->getType()->isFunctionPointerType()) CheckFunctionPointerDecl(ND->getType(), ND); if (VarDecl *VD = dyn_cast<VarDecl>(SD)) - if (VD->hasAttr<BlocksAttr>()) + if (VD->hasAttr<BlocksAttr>()) { + static unsigned uniqueByrefDeclCount = 0; + assert(!BlockByRefDeclNo.count(ND) && + "RewriteFunctionBodyOrGlobalInitializer: Duplicate byref decl"); + BlockByRefDeclNo[ND] = uniqueByrefDeclCount++; RewriteByRefVar(VD); + } } if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) { if (isTopLevelBlockPointerType(TD->getUnderlyingType())) @@ -4829,6 +5025,12 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { if (BDRE->isByRef()) return RewriteBlockDeclRefExpr(BDRE); } + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) { + ValueDecl *VD = DRE->getDecl(); + if (VD->hasAttr<BlocksAttr>()) + return RewriteBlockDeclRefExpr(DRE); + } + if (CallExpr *CE = dyn_cast<CallExpr>(S)) { if (CE->getCallee()->getType()->isBlockPointerType()) { Stmt *BlockCall = SynthesizeBlockCall(CE, CE->getCallee()); @@ -4885,6 +5087,7 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) { // FIXME: If this should support Obj-C++, support CXXTryStmt if (CompoundStmt *Body = FD->getCompoundBody()) { CurFunctionDef = FD; + CurFunctionDeclToDeclareForBlock = FD; CollectPropertySetters(Body); CurrentBody = Body; Body = @@ -4899,6 +5102,7 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) { // and any copy/dispose helper functions. InsertBlockLiteralsWithinFunction(FD); CurFunctionDef = 0; + CurFunctionDeclToDeclareForBlock = 0; } return; } diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 61f8a70..fcefd4e 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -371,7 +371,7 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, CaretLine.push_back('^'); // Scan the source line, looking for tabs. If we find any, manually expand - // them to 8 characters and update the CaretLine to match. + // them to spaces and update the CaretLine to match. for (unsigned i = 0; i != SourceLine.size(); ++i) { if (SourceLine[i] != '\t') continue; @@ -379,8 +379,11 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, SourceLine[i] = ' '; // Compute the number of spaces we need to insert. - unsigned NumSpaces = ((i+8)&~7) - (i+1); - assert(NumSpaces < 8 && "Invalid computation of space amt"); + unsigned TabStop = DiagOpts->TabStop; + assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop && + "Invalid -ftabstop value"); + unsigned NumSpaces = ((i+TabStop)/TabStop * TabStop) - (i+1); + assert(NumSpaces < TabStop && "Invalid computation of space amt"); // Insert spaces into the SourceLine. SourceLine.insert(i+1, NumSpaces, ' '); diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h index 5d2bcbb..e270602 100644 --- a/lib/Headers/xmmintrin.h +++ b/lib/Headers/xmmintrin.h @@ -172,7 +172,7 @@ static inline __m128 __attribute__((__always_inline__, __nodebug__)) _mm_xor_ps(__m128 a, __m128 b) { typedef int __v4si __attribute__((__vector_size__(16))); - return (__m128)((__v4si)a ^ ~(__v4si)b); + return (__m128)((__v4si)a ^ (__v4si)b); } static inline __m128 __attribute__((__always_inline__, __nodebug__)) diff --git a/lib/Lex/HeaderMap.cpp b/lib/Lex/HeaderMap.cpp index df71276..4010d61 100644 --- a/lib/Lex/HeaderMap.cpp +++ b/lib/Lex/HeaderMap.cpp @@ -56,8 +56,9 @@ struct HMapHeader { /// HashHMapKey - This is the 'well known' hash function required by the file /// format, used to look up keys in the hash table. The hash table uses simple /// linear probing based on this function. -static inline unsigned HashHMapKey(const char *S, const char *End) { +static inline unsigned HashHMapKey(llvm::StringRef Str) { unsigned Result = 0; + const char *S = Str.begin(), *End = Str.end(); for (; S != End; S++) Result += tolower(*S) * 13; @@ -172,17 +173,6 @@ const char *HeaderMap::getString(unsigned StrTabIdx) const { return FileBuffer->getBufferStart()+StrTabIdx; } -/// StringsEqualWithoutCase - Compare the specified two strings for case- -/// insensitive equality, returning true if they are equal. Both strings are -/// known to have the same length. -static bool StringsEqualWithoutCase(const char *S1, const char *S2, - unsigned Len) { - for (; Len; ++S1, ++S2, --Len) - if (tolower(*S1) != tolower(*S2)) - return false; - return true; -} - //===----------------------------------------------------------------------===// // The Main Drivers //===----------------------------------------------------------------------===// @@ -209,8 +199,7 @@ void HeaderMap::dump() const { /// LookupFile - Check to see if the specified relative filename is located in /// this HeaderMap. If so, open it and return its FileEntry. -const FileEntry *HeaderMap::LookupFile(const char *FilenameStart, - const char *FilenameEnd, +const FileEntry *HeaderMap::LookupFile(llvm::StringRef Filename, FileManager &FM) const { const HMapHeader &Hdr = getHeader(); unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets); @@ -221,18 +210,12 @@ const FileEntry *HeaderMap::LookupFile(const char *FilenameStart, return 0; // Linearly probe the hash table. - for (unsigned Bucket = HashHMapKey(FilenameStart, FilenameEnd);; ++Bucket) { + for (unsigned Bucket = HashHMapKey(Filename);; ++Bucket) { HMapBucket B = getBucket(Bucket & (NumBuckets-1)); if (B.Key == HMAP_EmptyBucketKey) return 0; // Hash miss. // See if the key matches. If not, probe on. - const char *Key = getString(B.Key); - unsigned BucketKeyLen = strlen(Key); - if (BucketKeyLen != unsigned(FilenameEnd-FilenameStart)) - continue; - - // See if the actual strings equal. - if (!StringsEqualWithoutCase(FilenameStart, Key, BucketKeyLen)) + if (!Filename.equals_lower(getString(B.Key))) continue; // If so, we have a match in the hash table. Construct the destination diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp index 2b9b7c9..4554aba 100644 --- a/lib/Lex/HeaderSearch.cpp +++ b/lib/Lex/HeaderSearch.cpp @@ -109,8 +109,7 @@ const char *DirectoryLookup::getName() const { /// LookupFile - Lookup the specified file in this search path, returning it /// if it exists or returning null if not. -const FileEntry *DirectoryLookup::LookupFile(const char *FilenameStart, - const char *FilenameEnd, +const FileEntry *DirectoryLookup::LookupFile(llvm::StringRef Filename, HeaderSearch &HS) const { llvm::SmallString<1024> TmpDir; if (isNormalDir()) { @@ -118,33 +117,32 @@ const FileEntry *DirectoryLookup::LookupFile(const char *FilenameStart, // FIXME: Portability. Filename concatenation should be in sys::Path. TmpDir += getDir()->getName(); TmpDir.push_back('/'); - TmpDir.append(FilenameStart, FilenameEnd); + TmpDir.append(Filename.begin(), Filename.end()); return HS.getFileMgr().getFile(TmpDir.begin(), TmpDir.end()); } if (isFramework()) - return DoFrameworkLookup(FilenameStart, FilenameEnd, HS); + return DoFrameworkLookup(Filename, HS); assert(isHeaderMap() && "Unknown directory lookup"); - return getHeaderMap()->LookupFile(FilenameStart, FilenameEnd,HS.getFileMgr()); + return getHeaderMap()->LookupFile(Filename, HS.getFileMgr()); } /// DoFrameworkLookup - Do a lookup of the specified file in the current /// DirectoryLookup, which is a framework directory. -const FileEntry *DirectoryLookup::DoFrameworkLookup(const char *FilenameStart, - const char *FilenameEnd, +const FileEntry *DirectoryLookup::DoFrameworkLookup(llvm::StringRef Filename, HeaderSearch &HS) const { FileManager &FileMgr = HS.getFileMgr(); // Framework names must have a '/' in the filename. - const char *SlashPos = std::find(FilenameStart, FilenameEnd, '/'); - if (SlashPos == FilenameEnd) return 0; + size_t SlashPos = Filename.find('/'); + if (SlashPos == llvm::StringRef::npos) return 0; // Find out if this is the home for the specified framework, by checking // HeaderSearch. Possible answer are yes/no and unknown. const DirectoryEntry *&FrameworkDirCache = - HS.LookupFrameworkCache(FilenameStart, SlashPos); + HS.LookupFrameworkCache(Filename.substr(0, SlashPos)); // If it is known and in some other directory, fail. if (FrameworkDirCache && FrameworkDirCache != getFrameworkDir()) @@ -159,7 +157,7 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(const char *FilenameStart, FrameworkName.push_back('/'); // FrameworkName = "/System/Library/Frameworks/Cocoa" - FrameworkName.append(FilenameStart, SlashPos); + FrameworkName.append(Filename.begin(), Filename.begin()+SlashPos); // FrameworkName = "/System/Library/Frameworks/Cocoa.framework/" FrameworkName += ".framework/"; @@ -184,7 +182,7 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(const char *FilenameStart, unsigned OrigSize = FrameworkName.size(); FrameworkName += "Headers/"; - FrameworkName.append(SlashPos+1, FilenameEnd); + FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end()); if (const FileEntry *FE = FileMgr.getFile(FrameworkName.begin(), FrameworkName.end())) { return FE; @@ -208,21 +206,20 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(const char *FilenameStart, /// for system #include's or not (i.e. using <> instead of ""). CurFileEnt, if /// non-null, indicates where the #including file is, in case a relative search /// is needed. -const FileEntry *HeaderSearch::LookupFile(const char *FilenameStart, - const char *FilenameEnd, +const FileEntry *HeaderSearch::LookupFile(llvm::StringRef Filename, bool isAngled, const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir, const FileEntry *CurFileEnt) { // If 'Filename' is absolute, check to see if it exists and no searching. - if (llvm::sys::Path::isAbsolute(FilenameStart, FilenameEnd-FilenameStart)) { + if (llvm::sys::Path::isAbsolute(Filename.begin(), Filename.size())) { CurDir = 0; // If this was an #include_next "/absolute/file", fail. if (FromDir) return 0; // Otherwise, just return the file. - return FileMgr.getFile(FilenameStart, FilenameEnd); + return FileMgr.getFile(Filename); } // Step #0, unless disabled, check to see if the file is in the #includer's @@ -236,8 +233,8 @@ const FileEntry *HeaderSearch::LookupFile(const char *FilenameStart, // FIXME: Portability. Filename concatenation should be in sys::Path. TmpDir += CurFileEnt->getDir()->getName(); TmpDir.push_back('/'); - TmpDir.append(FilenameStart, FilenameEnd); - if (const FileEntry *FE = FileMgr.getFile(TmpDir.begin(), TmpDir.end())) { + TmpDir.append(Filename.begin(), Filename.end()); + if (const FileEntry *FE = FileMgr.getFile(TmpDir.str())) { // Leave CurDir unset. // This file is a system header or C++ unfriendly if the old file is. // @@ -265,7 +262,7 @@ const FileEntry *HeaderSearch::LookupFile(const char *FilenameStart, // being relex/pp'd, but they would still have to search through a // (potentially huge) series of SearchDirs to find it. std::pair<unsigned, unsigned> &CacheLookup = - LookupFileCache.GetOrCreateValue(FilenameStart, FilenameEnd).getValue(); + LookupFileCache.GetOrCreateValue(Filename).getValue(); // If the entry has been previously looked up, the first value will be // non-zero. If the value is equal to i (the start point of our search), then @@ -283,7 +280,7 @@ const FileEntry *HeaderSearch::LookupFile(const char *FilenameStart, // Check each directory in sequence to see if it contains this file. for (; i != SearchDirs.size(); ++i) { const FileEntry *FE = - SearchDirs[i].LookupFile(FilenameStart, FilenameEnd, *this); + SearchDirs[i].LookupFile(Filename, *this); if (!FE) continue; CurDir = &SearchDirs[i]; @@ -307,14 +304,13 @@ const FileEntry *HeaderSearch::LookupFile(const char *FilenameStart, /// is a subframework within Carbon.framework. If so, return the FileEntry /// for the designated file, otherwise return null. const FileEntry *HeaderSearch:: -LookupSubframeworkHeader(const char *FilenameStart, - const char *FilenameEnd, +LookupSubframeworkHeader(llvm::StringRef Filename, const FileEntry *ContextFileEnt) { assert(ContextFileEnt && "No context file?"); // Framework names must have a '/' in the filename. Find it. - const char *SlashPos = std::find(FilenameStart, FilenameEnd, '/'); - if (SlashPos == FilenameEnd) return 0; + size_t SlashPos = Filename.find('/'); + if (SlashPos == llvm::StringRef::npos) return 0; // Look up the base framework name of the ContextFileEnt. const char *ContextName = ContextFileEnt->getName(); @@ -329,11 +325,11 @@ LookupSubframeworkHeader(const char *FilenameStart, // Append Frameworks/HIToolbox.framework/ FrameworkName += "Frameworks/"; - FrameworkName.append(FilenameStart, SlashPos); + FrameworkName.append(Filename.begin(), Filename.begin()+SlashPos); FrameworkName += ".framework/"; llvm::StringMapEntry<const DirectoryEntry *> &CacheLookup = - FrameworkMap.GetOrCreateValue(FilenameStart, SlashPos); + FrameworkMap.GetOrCreateValue(Filename.begin(), Filename.begin()+SlashPos); // Some other location? if (CacheLookup.getValue() && @@ -361,14 +357,14 @@ LookupSubframeworkHeader(const char *FilenameStart, // Check ".../Frameworks/HIToolbox.framework/Headers/HIToolbox.h" llvm::SmallString<1024> HeadersFilename(FrameworkName); HeadersFilename += "Headers/"; - HeadersFilename.append(SlashPos+1, FilenameEnd); + HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end()); if (!(FE = FileMgr.getFile(HeadersFilename.begin(), HeadersFilename.end()))) { // Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h" HeadersFilename = FrameworkName; HeadersFilename += "PrivateHeaders/"; - HeadersFilename.append(SlashPos+1, FilenameEnd); + HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end()); if (!(FE = FileMgr.getFile(HeadersFilename.begin(), HeadersFilename.end()))) return 0; } diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index d5a4643..0a74b26 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -643,14 +643,17 @@ void Lexer::LexIdentifier(Token &Result, const char *CurPtr) { // Match [_A-Za-z0-9]*, we have already matched [_A-Za-z$] unsigned Size; unsigned char C = *CurPtr++; - while (isIdentifierBody(C)) { + while (isIdentifierBody(C)) C = *CurPtr++; - } + --CurPtr; // Back up over the skipped character. // Fast path, no $,\,? in identifier found. '\' might be an escaped newline // or UCN, and ? might be a trigraph for '\', an escaped newline or UCN. // FIXME: UCNs. + // + // TODO: Could merge these checks into a CharInfo flag to make the comparison + // cheaper if (C != '\\' && C != '?' && (C != '$' || !Features.DollarIdents)) { FinishIdentifier: const char *IdStart = BufferPtr; @@ -724,7 +727,8 @@ void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) { return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result)); // If we have a hex FP constant, continue. - if ((C == '-' || C == '+') && (PrevCh == 'P' || PrevCh == 'p')) + if ((C == '-' || C == '+') && (PrevCh == 'P' || PrevCh == 'p') && + (!PP || !PP->getLangOptions().CPlusPlus0x)) return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result)); // Update the location of token as well as BufferPtr. diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp index 9aaa82d..5cd5497 100644 --- a/lib/Lex/LiteralSupport.cpp +++ b/lib/Lex/LiteralSupport.cpp @@ -458,7 +458,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) { } // A binary exponent can appear with or with a '.'. If dotted, the // binary exponent is required. - if (*s == 'p' || *s == 'P') { + if ((*s == 'p' || *s == 'P') && !PP.getLangOptions().CPlusPlus0x) { const char *Exponent = s; s++; saw_exponent = true; @@ -472,7 +472,12 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) { } s = first_non_digit; - if (!PP.getLangOptions().HexFloats) + // In C++0x, we cannot support hexadecmial floating literals because + // they conflict with user-defined literals, so we warn in previous + // versions of C++ by default. + if (PP.getLangOptions().CPlusPlus) + PP.Diag(TokLoc, diag::ext_hexconstant_cplusplus); + else if (!PP.getLangOptions().HexFloats) PP.Diag(TokLoc, diag::ext_hexconstant_invalid); } else if (saw_period) { PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin), diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 9e3d283..aa807f8 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -404,8 +404,8 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() { /// LookupFile - Given a "foo" or <foo> reference, look up the indicated file, /// return null on failure. isAngled indicates whether the file reference is /// for system #include's or not (i.e. using <> instead of ""). -const FileEntry *Preprocessor::LookupFile(const char *FilenameStart, - const char *FilenameEnd, +const FileEntry *Preprocessor::LookupFile(llvm::StringRef Filename, + SourceLocation FilenameTokLoc, bool isAngled, const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir) { @@ -431,17 +431,24 @@ const FileEntry *Preprocessor::LookupFile(const char *FilenameStart, // Do a standard file entry lookup. CurDir = CurDirLookup; const FileEntry *FE = - HeaderInfo.LookupFile(FilenameStart, FilenameEnd, - isAngled, FromDir, CurDir, CurFileEnt); - if (FE) return FE; + HeaderInfo.LookupFile(Filename, isAngled, FromDir, CurDir, CurFileEnt); + if (FE) { + // Warn about normal quoted #include from framework headers. Since + // framework headers are published (both public and private ones) they + // should not do relative searches, they should do an include with the + // framework path included. + if (!isAngled && CurDir && FilenameTokLoc.isValid() && + CurDir->isFramework() && CurDir == CurDirLookup) + Diag(FilenameTokLoc, diag::warn_pp_relative_include_from_framework); + return FE; + } // Otherwise, see if this is a subframework header. If so, this is relative // to one of the headers on the #include stack. Walk the list of the current // headers on the #include stack and pass them to HeaderInfo. if (IsFileLexer()) { if ((CurFileEnt = SourceMgr.getFileEntryForID(CurPPLexer->getFileID()))) - if ((FE = HeaderInfo.LookupSubframeworkHeader(FilenameStart, FilenameEnd, - CurFileEnt))) + if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt))) return FE; } @@ -450,8 +457,7 @@ const FileEntry *Preprocessor::LookupFile(const char *FilenameStart, if (IsFileLexer(ISEntry)) { if ((CurFileEnt = SourceMgr.getFileEntryForID(ISEntry.ThePPLexer->getFileID()))) - if ((FE = HeaderInfo.LookupSubframeworkHeader(FilenameStart, - FilenameEnd, CurFileEnt))) + if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt))) return FE; } } @@ -922,43 +928,41 @@ void Preprocessor::HandleIdentSCCSDirective(Token &Tok) { /// spelling of the filename, but is also expected to handle the case when /// this method decides to use a different buffer. bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc, - const char *&BufStart, - const char *&BufEnd) { + llvm::StringRef &Buffer) { // Get the text form of the filename. - assert(BufStart != BufEnd && "Can't have tokens with empty spellings!"); + assert(!Buffer.empty() && "Can't have tokens with empty spellings!"); // Make sure the filename is <x> or "x". bool isAngled; - if (BufStart[0] == '<') { - if (BufEnd[-1] != '>') { + if (Buffer[0] == '<') { + if (Buffer.back() != '>') { Diag(Loc, diag::err_pp_expects_filename); - BufStart = 0; + Buffer = llvm::StringRef(); return true; } isAngled = true; - } else if (BufStart[0] == '"') { - if (BufEnd[-1] != '"') { + } else if (Buffer[0] == '"') { + if (Buffer.back() != '"') { Diag(Loc, diag::err_pp_expects_filename); - BufStart = 0; + Buffer = llvm::StringRef(); return true; } isAngled = false; } else { Diag(Loc, diag::err_pp_expects_filename); - BufStart = 0; + Buffer = llvm::StringRef(); return true; } // Diagnose #include "" as invalid. - if (BufEnd-BufStart <= 2) { + if (Buffer.size() <= 2) { Diag(Loc, diag::err_pp_empty_filename); - BufStart = 0; - return ""; + Buffer = llvm::StringRef(); + return true; } // Skip the brackets. - ++BufStart; - --BufEnd; + Buffer = Buffer.substr(1, Buffer.size()-2); return isAngled; } @@ -1024,8 +1028,8 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok, CurPPLexer->LexIncludeFilename(FilenameTok); // Reserve a buffer to get the spelling. - llvm::SmallVector<char, 128> FilenameBuffer; - const char *FilenameStart, *FilenameEnd; + llvm::SmallString<128> FilenameBuffer; + llvm::StringRef Filename; switch (FilenameTok.getKind()) { case tok::eom: @@ -1035,9 +1039,9 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok, case tok::angle_string_literal: case tok::string_literal: { FilenameBuffer.resize(FilenameTok.getLength()); - FilenameStart = &FilenameBuffer[0]; + const char *FilenameStart = &FilenameBuffer[0]; unsigned Len = getSpelling(FilenameTok, FilenameStart); - FilenameEnd = FilenameStart+Len; + Filename = llvm::StringRef(FilenameStart, Len); break; } @@ -1047,8 +1051,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok, FilenameBuffer.push_back('<'); if (ConcatenateIncludeName(FilenameBuffer)) return; // Found <eom> but no ">"? Diagnostic already emitted. - FilenameStart = FilenameBuffer.data(); - FilenameEnd = FilenameStart + FilenameBuffer.size(); + Filename = FilenameBuffer.str(); break; default: Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename); @@ -1056,11 +1059,11 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok, return; } - bool isAngled = GetIncludeFilenameSpelling(FilenameTok.getLocation(), - FilenameStart, FilenameEnd); + bool isAngled = + GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename); // If GetIncludeFilenameSpelling set the start ptr to null, there was an // error. - if (FilenameStart == 0) { + if (Filename.empty()) { DiscardUntilEndOfDirective(); return; } @@ -1079,14 +1082,13 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok, // Search include directories. const DirectoryLookup *CurDir; - const FileEntry *File = LookupFile(FilenameStart, FilenameEnd, + const FileEntry *File = LookupFile(Filename, FilenameTok.getLocation(), isAngled, LookupFrom, CurDir); if (File == 0) { - Diag(FilenameTok, diag::err_pp_file_not_found) - << std::string(FilenameStart, FilenameEnd); + Diag(FilenameTok, diag::err_pp_file_not_found) << Filename; return; } - + // Ask HeaderInfo if we should enter this #include file. If not, #including // this file will have no effect. if (!HeaderInfo.ShouldEnterIncludeFile(File, isImport)) @@ -1103,8 +1105,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok, FileID FID = SourceMgr.createFileID(File, FilenameTok.getLocation(), FileCharacter); if (FID.isInvalid()) { - Diag(FilenameTok, diag::err_pp_file_not_found) - << std::string(FilenameStart, FilenameEnd); + Diag(FilenameTok, diag::err_pp_file_not_found) << Filename; return; } diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp index ce1b19c..0b26ccb 100644 --- a/lib/Lex/PPLexerChange.cpp +++ b/lib/Lex/PPLexerChange.cpp @@ -249,7 +249,8 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { // diagnostic is enabled, look for macros that have not been used. if (getDiagnostics().getDiagnosticLevel(diag::pp_macro_not_used) != Diagnostic::Ignored) { - for (macro_iterator I = macro_begin(), E = macro_end(); I != E; ++I) + for (macro_iterator I = macro_begin(false), E = macro_end(false); + I != E; ++I) if (!I->second->isUsed()) Diag(I->second->getDefinitionLoc(), diag::pp_macro_not_used); } diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index dfb14ff..3792782 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -18,6 +18,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" #include "clang/Lex/LexDiagnostic.h" +#include "llvm/ADT/StringSwitch.h" #include <cstdio> #include <ctime> using namespace clang; @@ -481,34 +482,27 @@ static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc, static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { const LangOptions &LangOpts = PP.getLangOptions(); - switch (II->getLength()) { - default: return false; - 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; - case 22: - if (II->isStr("attribute_overloadable")) return true; - return false; - case 25: - if (II->isStr("attribute_ext_vector_type")) return true; - return false; - case 27: - if (II->isStr("attribute_analyzer_noreturn")) return true; - return false; - case 29: - if (II->isStr("attribute_ns_returns_retained")) return true; - if (II->isStr("attribute_cf_returns_retained")) return true; - return false; - } + return llvm::StringSwitch<bool>(II->getName()) + .Case("blocks", LangOpts.Blocks) + .Case("cxx_rtti", LangOpts.RTTI) + //.Case("cxx_lambdas", false) + //.Case("cxx_nullptr", false) + //.Case("cxx_concepts", false) + .Case("cxx_decltype", LangOpts.CPlusPlus0x) + .Case("cxx_auto_type", LangOpts.CPlusPlus0x) + .Case("cxx_exceptions", LangOpts.Exceptions) + .Case("cxx_attributes", LangOpts.CPlusPlus0x) + .Case("cxx_static_assert", LangOpts.CPlusPlus0x) + .Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI) + .Case("cxx_deleted_functions", LangOpts.CPlusPlus0x) + //.Case("cxx_rvalue_references", false) + .Case("attribute_overloadable", true) + //.Case("cxx_variadic_templates", false) + .Case("attribute_ext_vector_type", true) + .Case("attribute_analyzer_noreturn", true) + .Case("attribute_ns_returns_retained", true) + .Case("attribute_cf_returns_retained", true) + .Default(false); } /// EvaluateHasIncludeCommon - Process a '__has_include("path")' @@ -535,8 +529,8 @@ static bool EvaluateHasIncludeCommon(bool &Result, Token &Tok, PP.getCurrentLexer()->LexIncludeFilename(Tok); // Reserve a buffer to get the spelling. - llvm::SmallVector<char, 128> FilenameBuffer; - const char *FilenameStart, *FilenameEnd; + llvm::SmallString<128> FilenameBuffer; + llvm::StringRef Filename; switch (Tok.getKind()) { case tok::eom: @@ -546,9 +540,9 @@ static bool EvaluateHasIncludeCommon(bool &Result, Token &Tok, case tok::angle_string_literal: case tok::string_literal: { FilenameBuffer.resize(Tok.getLength()); - FilenameStart = &FilenameBuffer[0]; + const char *FilenameStart = &FilenameBuffer[0]; unsigned Len = PP.getSpelling(Tok, FilenameStart); - FilenameEnd = FilenameStart+Len; + Filename = llvm::StringRef(FilenameStart, Len); break; } @@ -558,26 +552,24 @@ static bool EvaluateHasIncludeCommon(bool &Result, Token &Tok, FilenameBuffer.push_back('<'); if (PP.ConcatenateIncludeName(FilenameBuffer)) return false; // Found <eom> but no ">"? Diagnostic already emitted. - FilenameStart = FilenameBuffer.data(); - FilenameEnd = FilenameStart + FilenameBuffer.size(); + Filename = FilenameBuffer.str(); break; default: PP.Diag(Tok.getLocation(), diag::err_pp_expects_filename); return false; } - bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), - FilenameStart, FilenameEnd); + bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename); // If GetIncludeFilenameSpelling set the start ptr to null, there was an // error. - if (FilenameStart == 0) { + if (Filename.empty()) return false; - } // Search include directories. const DirectoryLookup *CurDir; - const FileEntry *File = PP.LookupFile(FilenameStart, FilenameEnd, - isAngled, LookupFrom, CurDir); + const FileEntry *File = PP.LookupFile(Filename, + SourceLocation(),// produce no warnings. + isAngled, LookupFrom, CurDir); // Get the result value. Result = true means the file exists. Result = File != 0; diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp index 8b46f71..856b3bd 100644 --- a/lib/Lex/Pragma.cpp +++ b/lib/Lex/Pragma.cpp @@ -286,26 +286,25 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { return; // Reserve a buffer to get the spelling. - llvm::SmallVector<char, 128> FilenameBuffer; + llvm::SmallString<128> FilenameBuffer; FilenameBuffer.resize(FilenameTok.getLength()); const char *FilenameStart = &FilenameBuffer[0]; unsigned Len = getSpelling(FilenameTok, FilenameStart); - const char *FilenameEnd = FilenameStart+Len; - bool isAngled = GetIncludeFilenameSpelling(FilenameTok.getLocation(), - FilenameStart, FilenameEnd); + llvm::StringRef Filename(FilenameStart, Len); + bool isAngled = + GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename); // If GetIncludeFilenameSpelling set the start ptr to null, there was an // error. - if (FilenameStart == 0) + if (Filename.empty()) return; // Search include directories for this file. const DirectoryLookup *CurDir; - const FileEntry *File = LookupFile(FilenameStart, FilenameEnd, + const FileEntry *File = LookupFile(Filename, FilenameTok.getLocation(), isAngled, 0, CurDir); if (File == 0) { - Diag(FilenameTok, diag::err_pp_file_not_found) - << std::string(FilenameStart, FilenameEnd); + Diag(FilenameTok, diag::err_pp_file_not_found) << Filename; return; } diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index 81966cb..26bb3a9 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -27,6 +27,7 @@ #include "clang/Lex/Preprocessor.h" #include "MacroArgs.h" +#include "clang/Lex/ExternalPreprocessorSource.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Pragma.h" @@ -43,6 +44,7 @@ using namespace clang; //===----------------------------------------------------------------------===// +ExternalPreprocessorSource::~ExternalPreprocessorSource() { } Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, const TargetInfo &target, SourceManager &SM, @@ -50,9 +52,9 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, IdentifierInfoLookup* IILookup, bool OwnsHeaders) : Diags(&diags), Features(opts), Target(target),FileMgr(Headers.getFileMgr()), - SourceMgr(SM), HeaderInfo(Headers), Identifiers(opts, IILookup), - BuiltinInfo(Target), CodeCompletionFile(0), CurPPLexer(0), CurDirLookup(0), - Callbacks(0), MacroArgCache(0) { + SourceMgr(SM), HeaderInfo(Headers), ExternalSource(0), + Identifiers(opts, IILookup), BuiltinInfo(Target), CodeCompletionFile(0), + CurPPLexer(0), CurDirLookup(0), Callbacks(0), MacroArgCache(0) { ScratchBuf = new ScratchBuffer(SourceMgr); CounterValue = 0; // __COUNTER__ starts at 0. OwnsHeaderSearch = OwnsHeaders; @@ -77,6 +79,9 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, CachedLexPos = 0; + // We haven't read anything from the external source. + ReadMacrosFromExternalSource = false; + // "Poison" __VA_ARGS__, which can only appear in the expansion of a macro. // This gets unpoisoned where it is allowed. (Ident__VA_ARGS__ = getIdentifierInfo("__VA_ARGS__"))->setIsPoisoned(); @@ -194,6 +199,28 @@ void Preprocessor::PrintStats() { << NumFastTokenPaste << " on the fast path.\n"; } +Preprocessor::macro_iterator +Preprocessor::macro_begin(bool IncludeExternalMacros) const { + if (IncludeExternalMacros && ExternalSource && + !ReadMacrosFromExternalSource) { + ReadMacrosFromExternalSource = true; + ExternalSource->ReadDefinedMacros(); + } + + return Macros.begin(); +} + +Preprocessor::macro_iterator +Preprocessor::macro_end(bool IncludeExternalMacros) const { + if (IncludeExternalMacros && ExternalSource && + !ReadMacrosFromExternalSource) { + ReadMacrosFromExternalSource = true; + ExternalSource->ReadDefinedMacros(); + } + + return Macros.end(); +} + bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File, unsigned TruncateAtLine, unsigned TruncateAtColumn) { diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index 4cd8fe8..f52d8b9 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -36,6 +36,14 @@ void UnqualifiedId::setTemplateId(TemplateIdAnnotation *TemplateId) { EndLocation = TemplateId->RAngleLoc; } +void UnqualifiedId::setConstructorTemplateId(TemplateIdAnnotation *TemplateId) { + assert(TemplateId && "NULL template-id annotation?"); + Kind = IK_ConstructorTemplateId; + this->TemplateId = TemplateId; + StartLocation = TemplateId->TemplateNameLoc; + EndLocation = TemplateId->RAngleLoc; +} + /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function. /// "TheDeclarator" is the declarator that this will be added to. DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index f429ac9..b5ba8ac 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -356,7 +356,8 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context, ParsingDeclSpec DS(*this); if (Attr) DS.AddAttributes(Attr); - ParseDeclarationSpecifiers(DS); + ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, + getDeclSpecContextFromDeclaratorContext(Context)); // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" // declaration-specifiers init-declarator-list[opt] ';' @@ -786,6 +787,20 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, return false; } +/// \brief Determine the declaration specifier context from the declarator +/// context. +/// +/// \param Context the declarator context, which is one of the +/// Declarator::TheContext enumerator values. +Parser::DeclSpecContext +Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) { + if (Context == Declarator::MemberContext) + return DSC_class; + if (Context == Declarator::FileContext) + return DSC_top_level; + return DSC_normal; +} + /// ParseDeclarationSpecifiers /// declaration-specifiers: [C99 6.7] /// storage-class-specifier declaration-specifiers[opt] @@ -814,7 +829,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, AccessSpecifier AS, DeclSpecContext DSContext) { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteOrdinaryName(CurScope); + Action::CodeCompletionContext CCC = Action::CCC_Namespace; + if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) + CCC = DSContext == DSC_class? Action::CCC_MemberTemplate + : Action::CCC_Template; + else if (DSContext == DSC_class) + CCC = Action::CCC_Class; + else if (ObjCImpDecl) + CCC = Action::CCC_ObjCImplementation; + + Actions.CodeCompleteOrdinaryName(CurScope, CCC); ConsumeToken(); } @@ -854,6 +878,47 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue()) ->Kind == TNK_Type_template) { // We have a qualified template-id, e.g., N::A<int> + + // C++ [class.qual]p2: + // In a lookup in which the constructor is an acceptable lookup + // result and the nested-name-specifier nominates a class C: + // + // - if the name specified after the + // nested-name-specifier, when looked up in C, is the + // injected-class-name of C (Clause 9), or + // + // - if the name specified after the nested-name-specifier + // is the same as the identifier or the + // simple-template-id's template-name in the last + // component of the nested-name-specifier, + // + // the name is instead considered to name the constructor of + // class C. + // + // Thus, if the template-name is actually the constructor + // name, then the code is ill-formed; this interpretation is + // reinforced by the NAD status of core issue 635. + TemplateIdAnnotation *TemplateId + = static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue()); + if (DSContext == DSC_top_level && TemplateId->Name && + Actions.isCurrentClassName(*TemplateId->Name, CurScope, &SS)) { + if (isConstructorDeclarator()) { + // The user meant this to be an out-of-line constructor + // definition, but template arguments are not allowed + // there. Just allow this as a constructor; we'll + // complain about it later. + goto DoneWithDeclSpec; + } + + // The user meant this to name a type, but it actually names + // a constructor with some extraneous template + // arguments. Complain, then parse it as a type as the user + // intended. + Diag(TemplateId->TemplateNameLoc, + diag::err_out_of_line_template_id_names_constructor) + << TemplateId->Name; + } + DS.getTypeSpecScope() = SS; ConsumeToken(); // The C++ scope. assert(Tok.is(tok::annot_template_id) && @@ -878,13 +943,23 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (Next.isNot(tok::identifier)) goto DoneWithDeclSpec; - // 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. - if (Actions.isCurrentClassName(*Next.getIdentifierInfo(), - CurScope, &SS) && - GetLookAheadToken(2).is(tok::l_paren)) - goto DoneWithDeclSpec; + // If we're in a context where the identifier could be a class name, + // check whether this is a constructor declaration. + if (DSContext == DSC_top_level && + Actions.isCurrentClassName(*Next.getIdentifierInfo(), CurScope, + &SS)) { + if (isConstructorDeclarator()) + goto DoneWithDeclSpec; + + // As noted in C++ [class.qual]p2 (cited above), when the name + // of the class is qualified in a context where it could name + // a constructor, its a constructor name. However, we've + // looked at the declarator, and the user probably meant this + // to be a type. Complain that it isn't supposed to be treated + // as a type, then proceed to parse it as a type. + Diag(Next.getLocation(), diag::err_out_of_line_type_names_constructor) + << Next.getIdentifierInfo(); + } TypeTy *TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(), Next.getLocation(), CurScope, &SS); @@ -965,16 +1040,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, goto DoneWithDeclSpec; } - // C++: If the identifier is actually the name of the class type - // being defined and the next token is a '(', then this is a - // constructor declaration. We're done with the decl-specifiers - // and will treat this token as an identifier. - if (getLang().CPlusPlus && - (CurScope->isClassScope() || - (CurScope->isTemplateParamScope() && - CurScope->getParent()->isClassScope())) && + // If we're in a context where the identifier could be a class name, + // check whether this is a constructor declaration. + if (getLang().CPlusPlus && DSContext == DSC_class && Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope) && - NextToken().getKind() == tok::l_paren) + isConstructorDeclarator()) goto DoneWithDeclSpec; isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, @@ -1017,6 +1087,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, goto DoneWithDeclSpec; } + // If we're in a context where the template-id could be a + // constructor name or specialization, check whether this is a + // constructor declaration. + if (getLang().CPlusPlus && DSContext == DSC_class && + Actions.isCurrentClassName(*TemplateId->Name, CurScope) && + isConstructorDeclarator()) + goto DoneWithDeclSpec; + // Turn the template-id annotation token into a type annotation // token, then try again to parse it as a type-specifier. AnnotateTemplateIdTokenAsType(); @@ -2082,6 +2160,48 @@ bool Parser::isDeclarationSpecifier() { } } +bool Parser::isConstructorDeclarator() { + TentativeParsingAction TPA(*this); + + // Parse the C++ scope specifier. + CXXScopeSpec SS; + ParseOptionalCXXScopeSpecifier(SS, 0, true); + + // Parse the constructor name. + if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) { + // We already know that we have a constructor name; just consume + // the token. + ConsumeToken(); + } else { + TPA.Revert(); + return false; + } + + // Current class name must be followed by a left parentheses. + if (Tok.isNot(tok::l_paren)) { + TPA.Revert(); + return false; + } + ConsumeParen(); + + // A right parentheses or ellipsis signals that we have a constructor. + if (Tok.is(tok::r_paren) || Tok.is(tok::ellipsis)) { + TPA.Revert(); + return true; + } + + // If we need to, enter the specified scope. + DeclaratorScopeObj DeclScopeObj(*this, SS); + if (SS.isSet() && Actions.ShouldEnterDeclaratorScope(CurScope, SS)) + DeclScopeObj.EnterDeclaratorScope(); + + // Check whether the next token(s) are part of a declaration + // specifier, in which case we have the start of a parameter and, + // therefore, we know that this is a constructor. + bool IsConstructor = isDeclarationSpecifier(); + TPA.Revert(); + return IsConstructor; +} /// ParseTypeQualifierListOpt /// type-qualifier-list: [C99 6.7.5] @@ -2366,10 +2486,16 @@ void Parser::ParseDirectDeclarator(Declarator &D) { Tok.is(tok::annot_template_id) || Tok.is(tok::tilde)) { // We found something that indicates the start of an unqualified-id. // Parse that unqualified-id. + bool AllowConstructorName + = ((D.getCXXScopeSpec().isSet() && + D.getContext() == Declarator::FileContext) || + (!D.getCXXScopeSpec().isSet() && + D.getContext() == Declarator::MemberContext)) && + !D.getDeclSpec().hasTypeSpecifier(); if (ParseUnqualifiedId(D.getCXXScopeSpec(), /*EnteringContext=*/true, /*AllowDestructorName=*/true, - /*AllowConstructorName=*/!D.getDeclSpec().hasTypeSpecifier(), + AllowConstructorName, /*ObjectType=*/0, D.getName())) { D.SetIdentifier(0, Tok.getLocation()); @@ -2396,6 +2522,16 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // direct-declarator: '(' attributes declarator ')' // Example: 'char (*X)' or 'int (*XX)(void)' ParseParenDeclarator(D); + + // If the declarator was parenthesized, we entered the declarator + // scope when parsing the parenthesized declarator, then exited + // the scope already. Re-enter the scope, if we need to. + if (D.getCXXScopeSpec().isSet()) { + 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(); + } } else if (D.mayOmitIdentifier()) { // This could be something simple like "int" (in which case the declarator // portion is empty), if an abstract-declarator is allowed. @@ -3020,6 +3156,8 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { Token OpTok = Tok; SourceLocation StartLoc = ConsumeToken(); + const bool hasParens = Tok.is(tok::l_paren); + bool isCastExpr; TypeTy *CastTy; SourceRange CastRange; @@ -3027,6 +3165,8 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { isCastExpr, CastTy, CastRange); + if (hasParens) + DS.setTypeofParensRange(CastRange); if (CastRange.getEnd().isInvalid()) // FIXME: Not accurate, the range gets one token more than it should. diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 265d0f3..90040c5 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -468,7 +468,8 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); - if (TemplateId->Kind == TNK_Type_template) { + if (TemplateId->Kind == TNK_Type_template || + TemplateId->Kind == TNK_Dependent_template_name) { AnnotateTemplateIdTokenAsType(SS); assert(Tok.is(tok::annot_typename) && "template-id -> type failed"); @@ -489,18 +490,57 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, return true; } + IdentifierInfo *Id = Tok.getIdentifierInfo(); + SourceLocation IdLoc = ConsumeToken(); + + if (Tok.is(tok::less)) { + // It looks the user intended to write a template-id here, but the + // template-name was wrong. Try to fix that. + TemplateNameKind TNK = TNK_Type_template; + TemplateTy Template; + if (!Actions.DiagnoseUnknownTemplateName(*Id, IdLoc, CurScope, + SS, Template, TNK)) { + Diag(IdLoc, diag::err_unknown_template_name) + << Id; + } + + if (!Template) + return true; + + // Form the template name + UnqualifiedId TemplateName; + TemplateName.setIdentifier(Id, IdLoc); + + // Parse the full template-id, then turn it into a type. + if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName, + SourceLocation(), true)) + return true; + if (TNK == TNK_Dependent_template_name) + AnnotateTemplateIdTokenAsType(SS); + + // If we didn't end up with a typename token, there's nothing more we + // can do. + if (Tok.isNot(tok::annot_typename)) + return true; + + // Retrieve the type from the annotation token, consume that token, and + // return. + EndLocation = Tok.getAnnotationEndLoc(); + TypeTy *Type = Tok.getAnnotationValue(); + ConsumeToken(); + return Type; + } + // We have an identifier; check whether it is actually a type. - TypeTy *Type = Actions.getTypeName(*Tok.getIdentifierInfo(), - Tok.getLocation(), CurScope, SS, - true); - if (!Type) { - Diag(Tok, DestrExpected ? diag::err_destructor_class_name + TypeTy *Type = Actions.getTypeName(*Id, IdLoc, CurScope, SS, true); + if (!Type) { + Diag(IdLoc, DestrExpected ? diag::err_destructor_class_name : diag::err_expected_class_name); return true; } // Consume the identifier. - EndLocation = ConsumeToken(); + EndLocation = IdLoc; return Type; } @@ -1527,12 +1567,12 @@ Parser::MemInitResult Parser::ParseMemInitializer(DeclPtrTy ConstructorDecl) { if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); - if (TemplateId->Kind == TNK_Type_template) { + if (TemplateId->Kind == TNK_Type_template || + TemplateId->Kind == TNK_Dependent_template_name) { AnnotateTemplateIdTokenAsType(&SS); assert(Tok.is(tok::annot_typename) && "template-id -> type failed"); TemplateTypeTy = Tok.getAnnotationValue(); } - // FIXME. May need to check for TNK_Dependent_template as well. } if (!TemplateTypeTy && Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_member_or_base_name); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index bdbc67f..669575c 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -200,11 +200,6 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind, /// expression ',' assignment-expression /// Parser::OwningExprResult Parser::ParseExpression() { - if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteOrdinaryName(CurScope); - ConsumeToken(); - } - OwningExprResult LHS(ParseAssignmentExpression()); if (LHS.isInvalid()) return move(LHS); @@ -248,6 +243,11 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { /// ParseAssignmentExpression - Parse an expr that doesn't include commas. /// Parser::OwningExprResult Parser::ParseAssignmentExpression() { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Expression); + ConsumeToken(); + } + if (Tok.is(tok::kw_throw)) return ParseThrowExpression(); @@ -616,9 +616,17 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, // Turn a potentially qualified name into a annot_typename or // annot_cxxscope if it would be valid. This handles things like x::y, etc. if (getLang().CPlusPlus) { - // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse. - if (TryAnnotateTypeOrScopeToken()) - return ParseCastExpression(isUnaryExpression, isAddressOfOperand); + // Avoid the unnecessary parse-time lookup in the common case + // where the syntax forbids a type. + const Token &Next = NextToken(); + if (Next.is(tok::coloncolon) || + (!ColonIsSacred && Next.is(tok::colon)) || + Next.is(tok::less) || + Next.is(tok::l_paren)) { + // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse. + if (TryAnnotateTypeOrScopeToken()) + return ParseCastExpression(isUnaryExpression, isAddressOfOperand); + } } // Consume the identifier so that we can see if it is followed by a '(' or diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index abd26d7..ca50ef4 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -585,6 +585,11 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { /// \returns true if there was a parsing, false otherwise. bool Parser::ParseCXXCondition(OwningExprResult &ExprResult, DeclPtrTy &DeclResult) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Condition); + ConsumeToken(); + } + if (!isCXXConditionDeclaration()) { ExprResult = ParseExpression(); // expression DeclResult = DeclPtrTy(); @@ -1148,6 +1153,13 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, IdentifierInfo *Id = Tok.getIdentifierInfo(); SourceLocation IdLoc = ConsumeToken(); + if (!getLang().CPlusPlus) { + // If we're not in C++, only identifiers matter. Record the + // identifier and return. + Result.setIdentifier(Id, IdLoc); + return false; + } + if (AllowConstructorName && Actions.isCurrentClassName(*Id, CurScope, &SS)) { // We have parsed a constructor name. @@ -1170,12 +1182,41 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, // unqualified-id: // template-id (already parsed and annotated) if (Tok.is(tok::annot_template_id)) { - // FIXME: Could this be a constructor name??? - + TemplateIdAnnotation *TemplateId + = static_cast<TemplateIdAnnotation*>(Tok.getAnnotationValue()); + + // If the template-name names the current class, then this is a constructor + if (AllowConstructorName && TemplateId->Name && + Actions.isCurrentClassName(*TemplateId->Name, CurScope, &SS)) { + if (SS.isSet()) { + // C++ [class.qual]p2 specifies that a qualified template-name + // is taken as the constructor name where a constructor can be + // declared. Thus, the template arguments are extraneous, so + // complain about them and remove them entirely. + Diag(TemplateId->TemplateNameLoc, + diag::err_out_of_line_constructor_template_id) + << TemplateId->Name + << CodeModificationHint::CreateRemoval( + SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)); + Result.setConstructorName(Actions.getTypeName(*TemplateId->Name, + TemplateId->TemplateNameLoc, + CurScope, + &SS, false), + TemplateId->TemplateNameLoc, + TemplateId->RAngleLoc); + TemplateId->Destroy(); + ConsumeToken(); + return false; + } + + Result.setConstructorTemplateId(TemplateId); + ConsumeToken(); + return false; + } + // We have already parsed a template-id; consume the annotation token as // our unqualified-id. - Result.setTemplateId( - static_cast<TemplateIdAnnotation*>(Tok.getAnnotationValue())); + Result.setTemplateId(TemplateId); ConsumeToken(); return false; } @@ -1202,7 +1243,8 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, return false; } - if ((AllowDestructorName || SS.isSet()) && Tok.is(tok::tilde)) { + if (getLang().CPlusPlus && + (AllowDestructorName || SS.isSet()) && Tok.is(tok::tilde)) { // C++ [expr.unary.op]p10: // There is an ambiguity in the unary-expression ~X(), where X is a // class-name. The ambiguity is resolved in favor of treating ~ as a diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 9904a2c..5e23635 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -309,7 +309,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, llvm::SmallVector<DeclGroupPtrTy, 8> allTUVariables; tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword; - SourceLocation AtEndLoc; + SourceRange AtEnd; while (1) { // If this is a method prototype, parse it. @@ -334,6 +334,14 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, if (Tok.is(tok::eof)) break; + // Code completion within an Objective-C interface. + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(CurScope, + ObjCImpDecl? Action::CCC_ObjCImplementation + : Action::CCC_ObjCInterface); + ConsumeToken(); + } + // If we don't have an @ directive, parse it as a function definition. if (Tok.isNot(tok::at)) { // The code below does not consume '}'s because it is afraid of eating the @@ -359,7 +367,8 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, tok::ObjCKeywordKind DirectiveKind = Tok.getObjCKeywordID(); if (DirectiveKind == tok::objc_end) { // @end -> terminate list - AtEndLoc = AtLoc; + AtEnd.setBegin(AtLoc); + AtEnd.setEnd(Tok.getLocation()); break; } @@ -422,7 +431,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, // Insert collected methods declarations into the @interface object. // This passes in an invalid SourceLocation for AtEndLoc when EOF is hit. - Actions.ActOnAtEnd(AtEndLoc, interfaceDecl, + Actions.ActOnAtEnd(AtEnd, interfaceDecl, allMethods.data(), allMethods.size(), allProperties.data(), allProperties.size(), allTUVariables.data(), allTUVariables.size()); @@ -964,6 +973,12 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, // Set the default visibility to private. if (Tok.is(tok::at)) { // parse objc-visibility-spec ConsumeToken(); // eat the @ sign + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCAtVisibility(CurScope); + ConsumeToken(); + } + switch (Tok.getObjCKeywordID()) { case tok::objc_private: case tok::objc_public: @@ -978,6 +993,12 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, } } + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(CurScope, + Action::CCC_ObjCInstanceVariableList); + ConsumeToken(); + } + struct ObjCIvarCallback : FieldCallback { Parser &P; DeclPtrTy IDecl; @@ -1197,18 +1218,20 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration( return DeclPtrTy(); } -Parser::DeclPtrTy Parser::ParseObjCAtEndDeclaration(SourceLocation atLoc) { +Parser::DeclPtrTy Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) { assert(Tok.isObjCAtKeyword(tok::objc_end) && "ParseObjCAtEndDeclaration(): Expected @end"); DeclPtrTy Result = ObjCImpDecl; ConsumeToken(); // the "end" identifier if (ObjCImpDecl) { - Actions.ActOnAtEnd(atLoc, ObjCImpDecl); + Actions.ActOnAtEnd(atEnd, ObjCImpDecl); ObjCImpDecl = DeclPtrTy(); PendingObjCImpDecl.pop_back(); } - else - Diag(atLoc, diag::warn_expected_implementation); // missing @implementation + else { + // missing @implementation + Diag(atEnd.getBegin(), diag::warn_expected_implementation); + } return Result; } @@ -1216,7 +1239,7 @@ Parser::DeclGroupPtrTy Parser::RetrievePendingObjCImpDecl() { if (PendingObjCImpDecl.empty()) return Actions.ConvertDeclToDeclGroup(DeclPtrTy()); DeclPtrTy ImpDecl = PendingObjCImpDecl.pop_back_val(); - Actions.ActOnAtEnd(SourceLocation(), ImpDecl); + Actions.ActOnAtEnd(SourceRange(), ImpDecl); return Actions.ConvertDeclToDeclGroup(ImpDecl); } diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 9085b87..21e960a 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -95,7 +95,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { } case tok::code_completion: - Actions.CodeCompleteOrdinaryName(CurScope); + Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Statement); ConsumeToken(); return ParseStatementOrDeclaration(OnlyStatement); @@ -955,7 +955,9 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) { DeclPtrTy SecondVar; if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteOrdinaryName(CurScope); + Actions.CodeCompleteOrdinaryName(CurScope, + C99orCXXorObjC? Action::CCC_ForInit + : Action::CCC_Expression); ConsumeToken(); } @@ -1182,7 +1184,7 @@ Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() { return Actions.ActOnAsmStmt(Tok.getLocation(), true, true, 0, 0, Names.data(), move_arg(Constraints), move_arg(Exprs), move(AsmString), move_arg(Clobbers), - Tok.getLocation()); + Tok.getLocation(), true); } /// ParseAsmStatement - Parse a GNU extended asm statement. diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 8b8af99..797c1df 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -196,7 +196,8 @@ Parser::ParseSingleDeclarationAfterTemplate( if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) DS.AddAttributes(ParseCXX0XAttributes().AttrList); - ParseDeclarationSpecifiers(DS, TemplateInfo, AS); + ParseDeclarationSpecifiers(DS, TemplateInfo, AS, + getDeclSpecContextFromDeclaratorContext(Context)); if (Tok.is(tok::semi)) { DeclEnd = ConsumeToken(); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 52c0153..0aecac9 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -455,7 +455,9 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr) SingleDecl = ParseObjCMethodDefinition(); break; case tok::code_completion: - Actions.CodeCompleteOrdinaryName(CurScope); + Actions.CodeCompleteOrdinaryName(CurScope, + ObjCImpDecl? Action::CCC_ObjCImplementation + : Action::CCC_Namespace); ConsumeToken(); return ParseExternalDeclaration(Attr); case tok::kw_using: @@ -541,7 +543,7 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS, if (Attr) DS.AddAttributes(Attr); - ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS); + ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC_top_level); // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" // declaration-specifiers init-declarator-list[opt] ';' diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Rewriter.cpp index 27a5f8b..9744496 100644 --- a/lib/Rewrite/Rewriter.cpp +++ b/lib/Rewrite/Rewriter.cpp @@ -97,13 +97,13 @@ int Rewriter::getRangeSize(SourceRange Range) const { return EndOff-StartOff; } -/// getRewritenText - Return the rewritten form of the text in the specified +/// getRewrittenText - Return the rewritten form of the text in the specified /// range. If the start or end of the range was unrewritable or if they are /// in different buffers, this returns an empty string. /// /// Note that this method is not particularly efficient. /// -std::string Rewriter::getRewritenText(SourceRange Range) const { +std::string Rewriter::getRewrittenText(SourceRange Range) const { if (!isRewritable(Range.getBegin()) || !isRewritable(Range.getEnd())) return ""; diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index fd3265d..5be6712 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -29,6 +29,7 @@ add_clang_library(clangSema SemaTemplateInstantiate.cpp SemaTemplateInstantiateDecl.cpp SemaType.cpp + TargetAttributesSema.cpp ) add_dependencies(clangSema ClangDiagnosticSema) diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index b9b85df..fbd1450 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -85,6 +85,26 @@ CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text) case CK_Comma: this->Text = ", "; break; + + case CK_Colon: + this->Text = ": "; + break; + + case CK_SemiColon: + this->Text = ";"; + break; + + case CK_Equal: + this->Text = " = "; + break; + + case CK_HorizontalSpace: + this->Text = " "; + break; + + case CK_VerticalSpace: + this->Text = "\n"; + break; } } @@ -140,6 +160,11 @@ CodeCompletionString::Chunk CodeCompletionString::Chunk::Clone() const { case CK_LeftAngle: case CK_RightAngle: case CK_Comma: + case CK_Colon: + case CK_SemiColon: + case CK_Equal: + case CK_HorizontalSpace: + case CK_VerticalSpace: return Chunk(Kind, Text); case CK_Optional: { @@ -177,6 +202,11 @@ CodeCompletionString::Chunk::Destroy() { case CK_LeftAngle: case CK_RightAngle: case CK_Comma: + case CK_Colon: + case CK_SemiColon: + case CK_Equal: + case CK_HorizontalSpace: + case CK_VerticalSpace: break; } } @@ -271,6 +301,11 @@ void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const { case CK_LeftAngle: case CK_RightAngle: case CK_Comma: + case CK_Colon: + case CK_SemiColon: + case CK_Equal: + case CK_HorizontalSpace: + case CK_VerticalSpace: break; } } @@ -326,6 +361,11 @@ CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str, case CK_LeftAngle: case CK_RightAngle: case CK_Comma: + case CK_Colon: + case CK_SemiColon: + case CK_Equal: + case CK_HorizontalSpace: + case CK_VerticalSpace: Result->AddChunk(Chunk(Kind)); break; } @@ -386,8 +426,7 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, OS << "COMPLETION: "; switch (Results[I].Kind) { case Result::RK_Declaration: - OS << Results[I].Declaration->getNameAsString() << " : " - << Results[I].Rank; + OS << Results[I].Declaration->getNameAsString() ; if (Results[I].Hidden) OS << " (Hidden)"; if (CodeCompletionString *CCS @@ -400,13 +439,13 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, break; case Result::RK_Keyword: - OS << Results[I].Keyword << " : " << Results[I].Rank << '\n'; + OS << Results[I].Keyword << '\n'; break; case Result::RK_Macro: { - OS << Results[I].Macro->getName() << " : " << Results[I].Rank; + OS << Results[I].Macro->getName(); if (CodeCompletionString *CCS - = Results[I].CreateCodeCompletionString(SemaRef)) { + = Results[I].CreateCodeCompletionString(SemaRef)) { OS << " : " << CCS->getAsString(); delete CCS; } @@ -415,7 +454,7 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, } case Result::RK_Pattern: { - OS << "Pattern : " << Results[I].Rank << " : " + OS << "Pattern : " << Results[I].Pattern->getAsString() << '\n'; break; } diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp index 0dbf219..bff4751 100644 --- a/lib/Sema/IdentifierResolver.cpp +++ b/lib/Sema/IdentifierResolver.cpp @@ -46,22 +46,6 @@ public: // IdDeclInfo Implementation //===----------------------------------------------------------------------===// -/// AddShadowed - Add a decl by putting it directly above the 'Shadow' decl. -/// Later lookups will find the 'Shadow' decl first. The 'Shadow' decl must -/// be already added to the scope chain and must be in the same context as -/// the decl that we want to add. -void IdentifierResolver::IdDeclInfo::AddShadowed(NamedDecl *D, - NamedDecl *Shadow) { - for (DeclsTy::iterator I = Decls.end(); I != Decls.begin(); --I) { - if (Shadow == *(I-1)) { - Decls.insert(I-1, D); - return; - } - } - - assert(0 && "Shadow wasn't in scope chain!"); -} - /// RemoveDecl - Remove the decl from the scope chain. /// The decl must already be part of the decl chain. void IdentifierResolver::IdDeclInfo::RemoveDecl(NamedDecl *D) { @@ -160,32 +144,6 @@ void IdentifierResolver::AddDecl(NamedDecl *D) { IDI->AddDecl(D); } -/// AddShadowedDecl - Link the decl to its shadowed decl chain putting it -/// after the decl that the iterator points to, thus the 'Shadow' decl will be -/// encountered before the 'D' decl. -void IdentifierResolver::AddShadowedDecl(NamedDecl *D, NamedDecl *Shadow) { - assert(D->getDeclName() == Shadow->getDeclName() && "Different ids!"); - - DeclarationName Name = D->getDeclName(); - void *Ptr = Name.getFETokenInfo<void>(); - assert(Ptr && "No decl from Ptr ?"); - - IdDeclInfo *IDI; - - if (isDeclPtr(Ptr)) { - Name.setFETokenInfo(NULL); - IDI = &(*IdDeclInfos)[Name]; - NamedDecl *PrevD = static_cast<NamedDecl*>(Ptr); - assert(PrevD == Shadow && "Invalid shadow decl ?"); - IDI->AddDecl(D); - IDI->AddDecl(PrevD); - return; - } - - IDI = toIdDeclInfo(Ptr); - IDI->AddShadowed(D, Shadow); -} - /// RemoveDecl - Unlink the decl from its shadowed decl chain. /// The decl must already be part of the decl chain. void IdentifierResolver::RemoveDecl(NamedDecl *D) { diff --git a/lib/Sema/IdentifierResolver.h b/lib/Sema/IdentifierResolver.h index 65f3256..59bd834 100644 --- a/lib/Sema/IdentifierResolver.h +++ b/lib/Sema/IdentifierResolver.h @@ -41,12 +41,6 @@ class IdentifierResolver { void AddDecl(NamedDecl *D) { Decls.push_back(D); } - /// AddShadowed - Add a decl by putting it directly above the 'Shadow' decl. - /// Later lookups will find the 'Shadow' decl first. The 'Shadow' decl must - /// be already added to the scope chain and must be in the same context as - /// the decl that we want to add. - void AddShadowed(NamedDecl *D, NamedDecl *Shadow); - /// RemoveDecl - Remove the decl from the scope chain. /// The decl must already be part of the decl chain. void RemoveDecl(NamedDecl *D); @@ -163,11 +157,6 @@ public: /// AddDecl - Link the decl to its shadowed decl chain. void AddDecl(NamedDecl *D); - /// AddShadowedDecl - Link the decl to its shadowed decl chain putting it - /// after the decl that the iterator points to, thus the 'Shadow' decl will be - /// encountered before the 'D' decl. - void AddShadowedDecl(NamedDecl *D, NamedDecl *Shadow); - /// RemoveDecl - Unlink the decl from its shadowed decl chain. /// The decl must already be part of the decl chain. void RemoveDecl(NamedDecl *D); diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h index c5eecda..9064de6 100644 --- a/lib/Sema/Lookup.h +++ b/lib/Sema/Lookup.h @@ -32,6 +32,11 @@ public: /// @brief No entity found met the criteria. NotFound = 0, + /// @brief No entity found met the criteria within the current + /// instantiation,, but there were dependent base classes of the + /// current instantiation that could not be searched. + NotFoundInCurrentInstantiation, + /// @brief Name lookup found a single declaration that met the /// criteria. getFoundDecl() will return this declaration. Found, @@ -268,6 +273,19 @@ public: Decls.set_size(N); } + /// \brief Determine whether no result was found because we could not + /// search into dependent base classes of the current instantiation. + bool wasNotFoundInCurrentInstantiation() const { + return ResultKind == NotFoundInCurrentInstantiation; + } + + /// \brief Note that while no result was found in the current instantiation, + /// there were dependent base classes that could not be searched. + void setNotFoundInCurrentInstantiation() { + assert(ResultKind == NotFound && Decls.empty()); + ResultKind = NotFoundInCurrentInstantiation; + } + /// \brief Resolves the result kind of the lookup, possibly hiding /// decls. /// @@ -278,9 +296,10 @@ public: /// \brief Re-resolves the result kind of the lookup after a set of /// removals has been performed. void resolveKindAfterFilter() { - if (Decls.empty()) - ResultKind = NotFound; - else { + if (Decls.empty()) { + if (ResultKind != NotFoundInCurrentInstantiation) + ResultKind = NotFound; + } else { ResultKind = Found; resolveKind(); } @@ -524,7 +543,11 @@ private: /// /// \param Hiding a declaration that hides the declaration \p ND, /// or NULL if no such declaration exists. - virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding) = 0; + /// + /// \param InBaseClass whether this declaration was found in base + /// class of the context we searched. + virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, + bool InBaseClass) = 0; }; } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 40ad90a..171101b 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "TargetAttributesSema.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/APFloat.h" #include "clang/AST/ASTConsumer.h" @@ -109,6 +110,12 @@ static bool ShouldAKA(ASTContext &Context, QualType QT, if (isa<VectorType>(Underlying)) break; + // Don't desugar through the primary typedef of an anonymous type. + if (isa<TagType>(Underlying) && isa<TypedefType>(QT)) + if (cast<TagType>(Underlying)->getDecl()->getTypedefForAnonDecl() == + cast<TypedefType>(QT)->getDecl()) + break; + // Otherwise, we're tearing through something opaque; note that // we'll eventually need an a.k.a. clause and keep going. AKA = true; @@ -347,7 +354,8 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, bool CompleteTranslationUnit, CodeCompleteConsumer *CodeCompleter) - : LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), + : TheTargetAttributesSema(0), + LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0), CurBlock(0), PackContext(0), ParsingDeclDepth(0), @@ -368,313 +376,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0)); } -/// Retrieves the width and signedness of the given integer type, -/// or returns false if it is not an integer type. -/// -/// \param T must be canonical -static bool getIntProperties(ASTContext &C, const Type *T, - unsigned &BitWidth, bool &Signed) { - assert(T->isCanonicalUnqualified()); - - if (const VectorType *VT = dyn_cast<VectorType>(T)) - T = VT->getElementType().getTypePtr(); - if (const ComplexType *CT = dyn_cast<ComplexType>(T)) - T = CT->getElementType().getTypePtr(); - - if (const BuiltinType *BT = dyn_cast<BuiltinType>(T)) { - if (!BT->isInteger()) return false; - - BitWidth = C.getIntWidth(QualType(T, 0)); - Signed = BT->isSignedInteger(); - return true; - } - - return false; -} - -/// Checks whether the given value will have the same value if it it -/// is truncated to the given width, then extended back to the -/// original width. -static bool IsSameIntAfterCast(const llvm::APSInt &value, - unsigned TargetWidth) { - unsigned SourceWidth = value.getBitWidth(); - llvm::APSInt truncated = value; - truncated.trunc(TargetWidth); - truncated.extend(SourceWidth); - return (truncated == value); -} - -/// Checks whether the given value will have the same value if it -/// is truncated to the given width, then extended back to the original -/// width. -/// -/// The value might be a vector or a complex. -static bool IsSameIntAfterCast(const APValue &value, unsigned TargetWidth) { - if (value.isInt()) - return IsSameIntAfterCast(value.getInt(), TargetWidth); - - if (value.isVector()) { - for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i) - if (!IsSameIntAfterCast(value.getVectorElt(i), TargetWidth)) - return false; - return true; - } - - if (value.isComplexInt()) { - return IsSameIntAfterCast(value.getComplexIntReal(), TargetWidth) && - IsSameIntAfterCast(value.getComplexIntImag(), TargetWidth); - } - - // This can happen with lossless casts to intptr_t of "based" lvalues. - // Assume it might use arbitrary bits. - assert(value.isLValue()); - return false; -} - - -/// Checks whether the given value, which currently has the given -/// source semantics, has the same value when coerced through the -/// target semantics. -static bool IsSameFloatAfterCast(const llvm::APFloat &value, - const llvm::fltSemantics &Src, - const llvm::fltSemantics &Tgt) { - llvm::APFloat truncated = value; - - bool ignored; - truncated.convert(Src, llvm::APFloat::rmNearestTiesToEven, &ignored); - truncated.convert(Tgt, llvm::APFloat::rmNearestTiesToEven, &ignored); - - return truncated.bitwiseIsEqual(value); -} - -/// Checks whether the given value, which currently has the given -/// source semantics, has the same value when coerced through the -/// target semantics. -/// -/// The value might be a vector of floats (or a complex number). -static bool IsSameFloatAfterCast(const APValue &value, - const llvm::fltSemantics &Src, - const llvm::fltSemantics &Tgt) { - if (value.isFloat()) - return IsSameFloatAfterCast(value.getFloat(), Src, Tgt); - - if (value.isVector()) { - for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i) - if (!IsSameFloatAfterCast(value.getVectorElt(i), Src, Tgt)) - return false; - return true; - } - - assert(value.isComplexFloat()); - return (IsSameFloatAfterCast(value.getComplexFloatReal(), Src, Tgt) && - IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt)); -} - -/// Determines if it's reasonable for the given expression to be truncated -/// down to the given integer width. -/// * Boolean expressions are automatically white-listed. -/// * Arithmetic operations on implicitly-promoted operands of the -/// target width or less are okay --- not because the results are -/// actually guaranteed to fit within the width, but because the -/// user is effectively pretending that the operations are closed -/// within the implicitly-promoted type. -static bool IsExprValueWithinWidth(ASTContext &C, Expr *E, unsigned Width) { - E = E->IgnoreParens(); - -#ifndef NDEBUG - { - const Type *ETy = E->getType()->getCanonicalTypeInternal().getTypePtr(); - unsigned EWidth; - bool ESigned; - - if (!getIntProperties(C, ETy, EWidth, ESigned)) - assert(0 && "expression not of integer type"); - - // The caller should never let this happen. - assert(EWidth > Width && "called on expr whose type is too small"); - } -#endif - - // Strip implicit casts off. - while (isa<ImplicitCastExpr>(E)) { - E = cast<ImplicitCastExpr>(E)->getSubExpr(); - - const Type *ETy = E->getType()->getCanonicalTypeInternal().getTypePtr(); - - unsigned EWidth; - bool ESigned; - if (!getIntProperties(C, ETy, EWidth, ESigned)) - return false; - - if (EWidth <= Width) - return true; - } - - if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { - switch (BO->getOpcode()) { - - // Boolean-valued operations are white-listed. - case BinaryOperator::LAnd: - case BinaryOperator::LOr: - case BinaryOperator::LT: - case BinaryOperator::GT: - case BinaryOperator::LE: - case BinaryOperator::GE: - case BinaryOperator::EQ: - case BinaryOperator::NE: - return true; - - // Operations with opaque sources are black-listed. - case BinaryOperator::PtrMemD: - case BinaryOperator::PtrMemI: - return false; - - // Left shift gets black-listed based on a judgement call. - case BinaryOperator::Shl: - return false; - - // Various special cases. - case BinaryOperator::Shr: - return IsExprValueWithinWidth(C, BO->getLHS(), Width); - case BinaryOperator::Comma: - return IsExprValueWithinWidth(C, BO->getRHS(), Width); - case BinaryOperator::Sub: - if (BO->getLHS()->getType()->isPointerType()) - return false; - // fallthrough - - // Any other operator is okay if the operands are - // promoted from expressions of appropriate size. - default: - return IsExprValueWithinWidth(C, BO->getLHS(), Width) && - IsExprValueWithinWidth(C, BO->getRHS(), Width); - } - } - - if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { - switch (UO->getOpcode()) { - // Boolean-valued operations are white-listed. - case UnaryOperator::LNot: - return true; - - // Operations with opaque sources are black-listed. - case UnaryOperator::Deref: - case UnaryOperator::AddrOf: // should be impossible - return false; - - case UnaryOperator::OffsetOf: - return false; - - default: - return IsExprValueWithinWidth(C, UO->getSubExpr(), Width); - } - } - - // Don't diagnose if the expression is an integer constant - // whose value in the target type is the same as it was - // in the original type. - Expr::EvalResult result; - if (E->Evaluate(result, C)) - if (IsSameIntAfterCast(result.Val, Width)) - return true; - - return false; -} - -/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. -static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) { - S.Diag(E->getExprLoc(), diag) << E->getType() << T << E->getSourceRange(); -} - -/// Implements -Wconversion. -static void CheckImplicitConversion(Sema &S, Expr *E, QualType T) { - // Don't diagnose in unevaluated contexts. - if (S.ExprEvalContexts.back().Context == Sema::Unevaluated) - return; - - // Don't diagnose for value-dependent expressions. - if (E->isValueDependent()) - return; - - const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr(); - const Type *Target = S.Context.getCanonicalType(T).getTypePtr(); - - // Never diagnose implicit casts to bool. - if (Target->isSpecificBuiltinType(BuiltinType::Bool)) - return; - - // Strip vector types. - if (isa<VectorType>(Source)) { - if (!isa<VectorType>(Target)) - return DiagnoseImpCast(S, E, T, diag::warn_impcast_vector_scalar); - - Source = cast<VectorType>(Source)->getElementType().getTypePtr(); - Target = cast<VectorType>(Target)->getElementType().getTypePtr(); - } - - // Strip complex types. - if (isa<ComplexType>(Source)) { - if (!isa<ComplexType>(Target)) - return DiagnoseImpCast(S, E, T, diag::warn_impcast_complex_scalar); - - Source = cast<ComplexType>(Source)->getElementType().getTypePtr(); - Target = cast<ComplexType>(Target)->getElementType().getTypePtr(); - } - - const BuiltinType *SourceBT = dyn_cast<BuiltinType>(Source); - const BuiltinType *TargetBT = dyn_cast<BuiltinType>(Target); - - // If the source is floating point... - if (SourceBT && SourceBT->isFloatingPoint()) { - // ...and the target is floating point... - if (TargetBT && TargetBT->isFloatingPoint()) { - // ...then warn if we're dropping FP rank. - - // Builtin FP kinds are ordered by increasing FP rank. - if (SourceBT->getKind() > TargetBT->getKind()) { - // Don't warn about float constants that are precisely - // representable in the target type. - Expr::EvalResult result; - if (E->Evaluate(result, S.Context)) { - // Value might be a float, a float vector, or a float complex. - if (IsSameFloatAfterCast(result.Val, - S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)), - S.Context.getFloatTypeSemantics(QualType(SourceBT, 0)))) - return; - } - - DiagnoseImpCast(S, E, T, diag::warn_impcast_float_precision); - } - return; - } - - // If the target is integral, always warn. - if ((TargetBT && TargetBT->isInteger())) - // TODO: don't warn for integer values? - return DiagnoseImpCast(S, E, T, diag::warn_impcast_float_integer); - - return; - } - - unsigned SourceWidth, TargetWidth; - bool SourceSigned, TargetSigned; - - if (!getIntProperties(S.Context, Source, SourceWidth, SourceSigned) || - !getIntProperties(S.Context, Target, TargetWidth, TargetSigned)) - return; - - if (SourceWidth > TargetWidth) { - if (IsExprValueWithinWidth(S.Context, E, TargetWidth)) - return; - - // People want to build with -Wshorten-64-to-32 and not -Wconversion - // and by god we'll let them. - if (SourceWidth == 64 && TargetWidth == 32) - return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_64_32); - return DiagnoseImpCast(S, E, T, diag::warn_impcast_integer_precision); - } - - return; +Sema::~Sema() { + if (PackContext) FreePackedContext(); + delete TheTargetAttributesSema; } /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast. @@ -697,7 +401,7 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, } } - CheckImplicitConversion(*this, Expr, Ty); + CheckImplicitConversion(Expr, Ty); if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) { if (ImpCast->getCastKind() == Kind) { diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 4cecee4..fab7292 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -42,6 +42,7 @@ namespace llvm { } namespace clang { + class AnalysisContext; class ASTContext; class ASTConsumer; class CodeCompleteConsumer; @@ -101,6 +102,7 @@ namespace clang { class InitializationKind; class InitializationSequence; class VisibleDeclConsumer; + class TargetAttributesSema; /// BlockSemaInfo - When a block is being parsed, this contains information /// about the block. It is pointed to from Sema::CurBlock. @@ -176,6 +178,7 @@ public: class Sema : public Action { Sema(const Sema&); // DO NOT IMPLEMENT void operator=(const Sema&); // DO NOT IMPLEMENT + mutable const TargetAttributesSema* TheTargetAttributesSema; public: const LangOptions &LangOpts; Preprocessor &PP; @@ -426,13 +429,12 @@ public: Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, bool CompleteTranslationUnit = true, CodeCompleteConsumer *CompletionConsumer = 0); - ~Sema() { - if (PackContext) FreePackedContext(); - } + ~Sema(); const LangOptions &getLangOptions() const { return LangOpts; } Diagnostic &getDiagnostics() const { return Diags; } SourceManager &getSourceManager() const { return SourceMgr; } + const TargetAttributesSema &getTargetAttributesSema() const; /// \brief Helper class that creates diagnostics with optional /// template instantiation stacks. @@ -561,8 +563,6 @@ public: const FunctionProtoType *Target, SourceLocation TargetLoc, const FunctionProtoType *Source, SourceLocation SourceLoc); - QualType ObjCGetTypeForMethodDefinition(DeclPtrTy D); - bool UnwrapSimilarPointerTypes(QualType& T1, QualType& T2); virtual TypeResult ActOnTypeName(Scope *S, Declarator &D); @@ -1030,10 +1030,25 @@ public: OverloadingResult BestViableFunction(OverloadCandidateSet& CandidateSet, SourceLocation Loc, OverloadCandidateSet::iterator& Best); + + enum OverloadCandidateDisplayKind { + /// Requests that all candidates be shown. Viable candidates will + /// be printed first. + OCD_AllCandidates, + + /// Requests that only viable candidates be shown. + OCD_ViableCandidates + }; void PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, - bool OnlyViable, - const char *Opc=0, - SourceLocation Loc=SourceLocation()); + OverloadCandidateDisplayKind OCD, + Expr **Args, unsigned NumArgs, + const char *Opc = 0, + SourceLocation Loc = SourceLocation()); + + void NoteOverloadCandidate(FunctionDecl *Fn); + void DiagnoseAmbiguousConversion(const ImplicitConversionSequence &ICS, + SourceLocation CaretLoc, + const PartialDiagnostic &PDiag); FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, bool Complain); @@ -1083,6 +1098,9 @@ public: OwningExprResult BuildOverloadedArrowExpr(Scope *S, ExprArg Base, SourceLocation OpLoc); + /// CheckUnreachable - Check for unreachable code. + void CheckUnreachable(AnalysisContext &); + /// CheckCallReturnType - Checks that a call expression's return type is /// complete. Returns true on failure. The location passed in is the location /// that best represents the call. @@ -1090,14 +1108,14 @@ public: CallExpr *CE, FunctionDecl *FD); /// Helpers for dealing with blocks and functions. - void CheckFallThroughForFunctionDef(Decl *D, Stmt *Body); - void CheckFallThroughForBlock(QualType BlockTy, Stmt *Body); + void CheckFallThroughForFunctionDef(Decl *D, Stmt *Body, AnalysisContext &); + void CheckFallThroughForBlock(QualType BlockTy, Stmt *, AnalysisContext &); bool CheckParmsForFunctionDef(FunctionDecl *FD); void CheckCXXDefaultArguments(FunctionDecl *FD); void CheckExtraCXXDefaultArguments(Declarator &D); enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1, AlwaysFallThrough = 2, NeverFallThroughOrReturn = 3 }; - ControlFlowKind CheckFallThrough(Stmt *); + ControlFlowKind CheckFallThrough(AnalysisContext &); Scope *getNonFieldDeclScope(Scope *S); @@ -1168,8 +1186,14 @@ public: LookupObjCImplementationName }; + /// \brief Specifies whether (or how) name lookup is being performed for a + /// redeclaration (vs. a reference). enum RedeclarationKind { - NotForRedeclaration, + /// \brief The lookup is a reference to this name that is not for the + /// purpose of redeclaring the name. + NotForRedeclaration = 0, + /// \brief The lookup results will be used for redeclaration of a name, + /// if an entity by that name already exists. ForRedeclaration }; @@ -1188,7 +1212,8 @@ public: = NotForRedeclaration); bool LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation = false); - bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx); + bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, + bool InUnqualifiedLookup = false); bool LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS, bool AllowBuiltinCreation = false, bool EnteringContext = false); @@ -1210,7 +1235,8 @@ public: bool CorrectTypo(LookupResult &R, Scope *S, const CXXScopeSpec *SS, DeclContext *MemberContext = 0, - bool EnteringContext = false); + bool EnteringContext = false, + const ObjCObjectPointerType *OPT = 0); void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs, AssociatedNamespaceSet &AssociatedNamespaces, @@ -1219,7 +1245,8 @@ public: bool DiagnoseAmbiguousLookup(LookupResult &Result); //@} - ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id); + ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *&Id, + SourceLocation RecoverLoc = SourceLocation()); NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, Scope *S, bool ForRedeclaration, SourceLocation Loc); @@ -1383,7 +1410,8 @@ public: MultiExprArg Exprs, ExprArg AsmString, MultiExprArg Clobbers, - SourceLocation RParenLoc); + SourceLocation RParenLoc, + bool MSAsm = false); virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc, SourceLocation RParen, @@ -1437,10 +1465,6 @@ public: void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, Expr **Args, unsigned NumArgs); - void CheckSignCompare(Expr *LHS, Expr *RHS, SourceLocation Loc, - const PartialDiagnostic &PD, - bool Equality = false); - virtual void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext); @@ -1462,7 +1486,8 @@ public: OwningExprResult LookupInObjCMethod(LookupResult &R, Scope *S, - IdentifierInfo *II); + IdentifierInfo *II, + bool AllowBuiltinCreation=false); OwningExprResult ActOnDependentIdExpression(const CXXScopeSpec &SS, DeclarationName Name, @@ -1571,13 +1596,13 @@ public: QualType BaseType, SourceLocation OpLoc, bool IsArrow, const CXXScopeSpec &SS, + NamedDecl *FirstQualifierInScope, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs); OwningExprResult LookupMemberExpr(LookupResult &R, Expr *&Base, bool &IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, - NamedDecl *FirstQualifierInScope, DeclPtrTy ObjCImpDecl); bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType, @@ -2008,6 +2033,7 @@ public: bool isDependentScopeSpecifier(const CXXScopeSpec &SS); CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS); bool isUnknownSpecialization(const CXXScopeSpec &SS); + bool isCurrentInstantiationWithDependentBases(const CXXScopeSpec &SS); /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the /// global scope ('::'). @@ -2175,11 +2201,11 @@ public: 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; + /// members need to be marked as referenced at the end of the translation + /// unit. It will contain polymorphic classes that do not have a key + /// function or have a key function that has been defined. + llvm::SmallVector<std::pair<CXXRecordDecl *, SourceLocation>, 4> + ClassesWithUnmarkedVirtualMembers; /// MaybeMarkVirtualMembersReferenced - If the passed in method is the /// key function of the record decl, will mark virtual member functions as @@ -2236,8 +2262,6 @@ public: void CheckConversionDeclarator(Declarator &D, QualType &R, FunctionDecl::StorageClass& SC); DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion); - - bool isImplicitMemberReference(const LookupResult &R, QualType &ThisType); //===--------------------------------------------------------------------===// // C++ Derived Classes @@ -2338,6 +2362,8 @@ public: bool CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl); + bool CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl); + //===--------------------------------------------------------------------===// // C++ Templates [C++ 14] // @@ -2350,6 +2376,14 @@ public: TypeTy *ObjectType, bool EnteringContext, TemplateTy &Template); + + virtual bool DiagnoseUnknownTemplateName(const IdentifierInfo &II, + SourceLocation IILoc, + Scope *S, + const CXXScopeSpec *SS, + TemplateTy &SuggestedTemplate, + TemplateNameKind &SuggestedKind); + bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); TemplateDecl *AdjustDeclIfTemplate(DeclPtrTy &Decl); @@ -3348,10 +3382,11 @@ public: void MergeOneProtocolPropertiesIntoClass(Decl *CDecl, ObjCProtocolDecl *PDecl); - virtual void ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl, - DeclPtrTy *allMethods = 0, unsigned allNum = 0, - DeclPtrTy *allProperties = 0, unsigned pNum = 0, - DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0); + virtual void ActOnAtEnd(SourceRange AtEnd, + DeclPtrTy classDecl, + DeclPtrTy *allMethods = 0, unsigned allNum = 0, + DeclPtrTy *allProperties = 0, unsigned pNum = 0, + DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0); virtual DeclPtrTy ActOnProperty(Scope *S, SourceLocation AtLoc, FieldDeclarator &FD, ObjCDeclSpec &ODS, @@ -3617,9 +3652,6 @@ public: bool PerformImplicitConversion(Expr *&From, QualType ToType, const StandardConversionSequence& SCS, AssignmentAction Action, bool IgnoreBaseAccess); - - bool BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind, - const ImplicitConversionSequence& ICS); /// the following "Check" methods will return a valid/converted QualType /// or a null QualType (indicating an error diagnostic was issued). @@ -3629,7 +3661,8 @@ public: QualType CheckPointerToMemberOperands( // C++ 5.5 Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isIndirect); QualType CheckMultiplyDivideOperands( // C99 6.5.5 - Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign, + bool isDivide); QualType CheckRemainderOperands( // C99 6.5.5 Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); QualType CheckAdditionOperands( // C99 6.5.6 @@ -3801,7 +3834,8 @@ public: /// \name Code completion //@{ - virtual void CodeCompleteOrdinaryName(Scope *S); + virtual void CodeCompleteOrdinaryName(Scope *S, + CodeCompletionContext CompletionContext); virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base, SourceLocation OpLoc, bool IsArrow); @@ -3819,6 +3853,7 @@ public: virtual void CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl, bool InInterface); + virtual void CodeCompleteObjCAtVisibility(Scope *S); virtual void CodeCompleteObjCAtStatement(Scope *S); virtual void CodeCompleteObjCAtExpression(Scope *S); virtual void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS); @@ -3895,6 +3930,11 @@ private: void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc); void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex); + void CheckSignCompare(Expr *LHS, Expr *RHS, SourceLocation Loc, + const PartialDiagnostic &PD, + bool Equality = false); + void CheckImplicitConversion(Expr *E, QualType Target); + }; //===--------------------------------------------------------------------===// diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 800c544..f924bd3 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -893,7 +893,7 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, /*InOverloadResolution=*/false, /*one of user provided casts*/true); - if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) + if (ICS.isBad()) return TC_NotApplicable; // The conversion is possible, so commit to it. diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 82d58ea..8594583 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -210,6 +210,28 @@ bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) { return getCurrentInstantiationOf(NNS) == 0; } +/// \brief Determine whether the given scope specifier refers to a +/// current instantiation that has any dependent base clases. +/// +/// This check is typically used when we've performed lookup into the +/// current instantiation of a template, but that lookup failed. When +/// there are dependent bases present, however, the lookup needs to be +/// delayed until template instantiation time. +bool Sema::isCurrentInstantiationWithDependentBases(const CXXScopeSpec &SS) { + if (!SS.isSet()) + return false; + + NestedNameSpecifier *NNS = (NestedNameSpecifier*)SS.getScopeRep(); + if (!NNS->isDependent()) + return false; + + CXXRecordDecl *CurrentInstantiation = getCurrentInstantiationOf(NNS); + if (!CurrentInstantiation) + return false; + + return CurrentInstantiation->hasAnyDependentBases(); +} + /// \brief If the given nested name specifier refers to the current /// instantiation, return the declaration that corresponds to that /// current instantiation (C++0x [temp.dep.type]p1). @@ -446,6 +468,10 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, << Name << Found.getLookupName() << CodeModificationHint::CreateReplacement(Found.getNameLoc(), Found.getLookupName().getAsString()); + + if (NamedDecl *ND = Found.getAsSingle<NamedDecl>()) + Diag(ND->getLocation(), diag::note_previous_decl) + << ND->getDeclName(); } else Found.clear(); } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index f10fa07..5f124e4 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -14,6 +14,7 @@ #include "Sema.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/CharUnits.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" @@ -318,7 +319,7 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { // Determine the index of the size. unsigned SizeIndex; - switch (Context.getTypeSize(ValType)/8) { + switch (Context.getTypeSizeInChars(ValType).getQuantity()) { case 1: SizeIndex = 0; break; case 2: SizeIndex = 1; break; case 4: SizeIndex = 2; break; @@ -966,9 +967,6 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull, /// /// (8) Check that the format string is a wide literal. /// -/// (9) Also check the arguments of functions with the __format__ attribute. -/// (TODO). -/// /// All of these checks can be done by parsing the format string. /// /// For now, we ONLY do (1), (3), (5), (6), (7), and (8). @@ -1559,3 +1557,475 @@ void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) { Diag(loc, diag::warn_floatingpoint_eq) << lex->getSourceRange() << rex->getSourceRange(); } + +//===--- CHECK: Integer mixed-sign comparisons (-Wsign-compare) --------===// +//===--- CHECK: Lossy implicit conversions (-Wconversion) --------------===// + +namespace { + +/// Structure recording the 'active' range of an integer-valued +/// expression. +struct IntRange { + /// The number of bits active in the int. + unsigned Width; + + /// True if the int is known not to have negative values. + bool NonNegative; + + IntRange() {} + IntRange(unsigned Width, bool NonNegative) + : Width(Width), NonNegative(NonNegative) + {} + + // Returns the range of the bool type. + static IntRange forBoolType() { + return IntRange(1, true); + } + + // Returns the range of an integral type. + static IntRange forType(ASTContext &C, QualType T) { + return forCanonicalType(C, T->getCanonicalTypeInternal().getTypePtr()); + } + + // Returns the range of an integeral type based on its canonical + // representation. + static IntRange forCanonicalType(ASTContext &C, const Type *T) { + assert(T->isCanonicalUnqualified()); + + if (const VectorType *VT = dyn_cast<VectorType>(T)) + T = VT->getElementType().getTypePtr(); + if (const ComplexType *CT = dyn_cast<ComplexType>(T)) + T = CT->getElementType().getTypePtr(); + if (const EnumType *ET = dyn_cast<EnumType>(T)) + T = ET->getDecl()->getIntegerType().getTypePtr(); + + const BuiltinType *BT = cast<BuiltinType>(T); + assert(BT->isInteger()); + + return IntRange(C.getIntWidth(QualType(T, 0)), BT->isUnsignedInteger()); + } + + // Returns the supremum of two ranges: i.e. their conservative merge. + static IntRange join(const IntRange &L, const IntRange &R) { + return IntRange(std::max(L.Width, R.Width), + L.NonNegative && R.NonNegative); + } + + // Returns the infinum of two ranges: i.e. their aggressive merge. + static IntRange meet(const IntRange &L, const IntRange &R) { + return IntRange(std::min(L.Width, R.Width), + L.NonNegative || R.NonNegative); + } +}; + +IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, unsigned MaxWidth) { + if (value.isSigned() && value.isNegative()) + return IntRange(value.getMinSignedBits(), false); + + if (value.getBitWidth() > MaxWidth) + value.trunc(MaxWidth); + + // isNonNegative() just checks the sign bit without considering + // signedness. + return IntRange(value.getActiveBits(), true); +} + +IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty, + unsigned MaxWidth) { + if (result.isInt()) + return GetValueRange(C, result.getInt(), MaxWidth); + + if (result.isVector()) { + IntRange R = GetValueRange(C, result.getVectorElt(0), Ty, MaxWidth); + for (unsigned i = 1, e = result.getVectorLength(); i != e; ++i) { + IntRange El = GetValueRange(C, result.getVectorElt(i), Ty, MaxWidth); + R = IntRange::join(R, El); + } + return R; + } + + if (result.isComplexInt()) { + IntRange R = GetValueRange(C, result.getComplexIntReal(), MaxWidth); + IntRange I = GetValueRange(C, result.getComplexIntImag(), MaxWidth); + return IntRange::join(R, I); + } + + // This can happen with lossless casts to intptr_t of "based" lvalues. + // Assume it might use arbitrary bits. + // FIXME: The only reason we need to pass the type in here is to get + // the sign right on this one case. It would be nice if APValue + // preserved this. + assert(result.isLValue()); + return IntRange(MaxWidth, Ty->isUnsignedIntegerType()); +} + +/// Pseudo-evaluate the given integer expression, estimating the +/// range of values it might take. +/// +/// \param MaxWidth - the width to which the value will be truncated +IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { + E = E->IgnoreParens(); + + // Try a full evaluation first. + Expr::EvalResult result; + if (E->Evaluate(result, C)) + return GetValueRange(C, result.Val, E->getType(), MaxWidth); + + // I think we only want to look through implicit casts here; if the + // user has an explicit widening cast, we should treat the value as + // being of the new, wider type. + if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E)) { + if (CE->getCastKind() == CastExpr::CK_NoOp) + return GetExprRange(C, CE->getSubExpr(), MaxWidth); + + IntRange OutputTypeRange = IntRange::forType(C, CE->getType()); + + bool isIntegerCast = (CE->getCastKind() == CastExpr::CK_IntegralCast); + if (!isIntegerCast && CE->getCastKind() == CastExpr::CK_Unknown) + isIntegerCast = CE->getSubExpr()->getType()->isIntegerType(); + + // Assume that non-integer casts can span the full range of the type. + if (!isIntegerCast) + return OutputTypeRange; + + IntRange SubRange + = GetExprRange(C, CE->getSubExpr(), + std::min(MaxWidth, OutputTypeRange.Width)); + + // Bail out if the subexpr's range is as wide as the cast type. + if (SubRange.Width >= OutputTypeRange.Width) + return OutputTypeRange; + + // Otherwise, we take the smaller width, and we're non-negative if + // either the output type or the subexpr is. + return IntRange(SubRange.Width, + SubRange.NonNegative || OutputTypeRange.NonNegative); + } + + if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) { + // If we can fold the condition, just take that operand. + bool CondResult; + if (CO->getCond()->EvaluateAsBooleanCondition(CondResult, C)) + return GetExprRange(C, CondResult ? CO->getTrueExpr() + : CO->getFalseExpr(), + MaxWidth); + + // Otherwise, conservatively merge. + IntRange L = GetExprRange(C, CO->getTrueExpr(), MaxWidth); + IntRange R = GetExprRange(C, CO->getFalseExpr(), MaxWidth); + return IntRange::join(L, R); + } + + if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { + switch (BO->getOpcode()) { + + // Boolean-valued operations are single-bit and positive. + case BinaryOperator::LAnd: + case BinaryOperator::LOr: + case BinaryOperator::LT: + case BinaryOperator::GT: + case BinaryOperator::LE: + case BinaryOperator::GE: + case BinaryOperator::EQ: + case BinaryOperator::NE: + return IntRange::forBoolType(); + + // Operations with opaque sources are black-listed. + case BinaryOperator::PtrMemD: + case BinaryOperator::PtrMemI: + return IntRange::forType(C, E->getType()); + + // Bitwise-and uses the *infinum* of the two source ranges. + case BinaryOperator::And: + return IntRange::meet(GetExprRange(C, BO->getLHS(), MaxWidth), + GetExprRange(C, BO->getRHS(), MaxWidth)); + + // Left shift gets black-listed based on a judgement call. + case BinaryOperator::Shl: + return IntRange::forType(C, E->getType()); + + // Right shift by a constant can narrow its left argument. + case BinaryOperator::Shr: { + IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth); + + // If the shift amount is a positive constant, drop the width by + // that much. + llvm::APSInt shift; + if (BO->getRHS()->isIntegerConstantExpr(shift, C) && + shift.isNonNegative()) { + unsigned zext = shift.getZExtValue(); + if (zext >= L.Width) + L.Width = (L.NonNegative ? 0 : 1); + else + L.Width -= zext; + } + + return L; + } + + // Comma acts as its right operand. + case BinaryOperator::Comma: + return GetExprRange(C, BO->getRHS(), MaxWidth); + + // Black-list pointer subtractions. + case BinaryOperator::Sub: + if (BO->getLHS()->getType()->isPointerType()) + return IntRange::forType(C, E->getType()); + // fallthrough + + default: + break; + } + + // Treat every other operator as if it were closed on the + // narrowest type that encompasses both operands. + IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth); + IntRange R = GetExprRange(C, BO->getRHS(), MaxWidth); + return IntRange::join(L, R); + } + + if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { + switch (UO->getOpcode()) { + // Boolean-valued operations are white-listed. + case UnaryOperator::LNot: + return IntRange::forBoolType(); + + // Operations with opaque sources are black-listed. + case UnaryOperator::Deref: + case UnaryOperator::AddrOf: // should be impossible + case UnaryOperator::OffsetOf: + return IntRange::forType(C, E->getType()); + + default: + return GetExprRange(C, UO->getSubExpr(), MaxWidth); + } + } + + FieldDecl *BitField = E->getBitField(); + if (BitField) { + llvm::APSInt BitWidthAP = BitField->getBitWidth()->EvaluateAsInt(C); + unsigned BitWidth = BitWidthAP.getZExtValue(); + + return IntRange(BitWidth, BitField->getType()->isUnsignedIntegerType()); + } + + return IntRange::forType(C, E->getType()); +} + +/// Checks whether the given value, which currently has the given +/// source semantics, has the same value when coerced through the +/// target semantics. +bool IsSameFloatAfterCast(const llvm::APFloat &value, + const llvm::fltSemantics &Src, + const llvm::fltSemantics &Tgt) { + llvm::APFloat truncated = value; + + bool ignored; + truncated.convert(Src, llvm::APFloat::rmNearestTiesToEven, &ignored); + truncated.convert(Tgt, llvm::APFloat::rmNearestTiesToEven, &ignored); + + return truncated.bitwiseIsEqual(value); +} + +/// Checks whether the given value, which currently has the given +/// source semantics, has the same value when coerced through the +/// target semantics. +/// +/// The value might be a vector of floats (or a complex number). +bool IsSameFloatAfterCast(const APValue &value, + const llvm::fltSemantics &Src, + const llvm::fltSemantics &Tgt) { + if (value.isFloat()) + return IsSameFloatAfterCast(value.getFloat(), Src, Tgt); + + if (value.isVector()) { + for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i) + if (!IsSameFloatAfterCast(value.getVectorElt(i), Src, Tgt)) + return false; + return true; + } + + assert(value.isComplexFloat()); + return (IsSameFloatAfterCast(value.getComplexFloatReal(), Src, Tgt) && + IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt)); +} + +} // end anonymous namespace + +/// \brief Implements -Wsign-compare. +/// +/// \param lex the left-hand expression +/// \param rex the right-hand expression +/// \param OpLoc the location of the joining operator +/// \param Equality whether this is an "equality-like" join, which +/// suppresses the warning in some cases +void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc, + const PartialDiagnostic &PD, bool Equality) { + // Don't warn if we're in an unevaluated context. + if (ExprEvalContexts.back().Context == Unevaluated) + return; + + // If either expression is value-dependent, don't warn. We'll get another + // chance at instantiation time. + if (lex->isValueDependent() || rex->isValueDependent()) + return; + + QualType lt = lex->getType(), rt = rex->getType(); + + // Only warn if both operands are integral. + if (!lt->isIntegerType() || !rt->isIntegerType()) + return; + + // In C, the width of a bitfield determines its type, and the + // declared type only contributes the signedness. This duplicates + // the work that will later be done by UsualUnaryConversions. + // Eventually, this check will be reorganized in a way that avoids + // this duplication. + if (!getLangOptions().CPlusPlus) { + QualType tmp; + tmp = Context.isPromotableBitField(lex); + if (!tmp.isNull()) lt = tmp; + tmp = Context.isPromotableBitField(rex); + if (!tmp.isNull()) rt = tmp; + } + + // The rule is that the signed operand becomes unsigned, so isolate the + // signed operand. + Expr *signedOperand = lex, *unsignedOperand = rex; + QualType signedType = lt, unsignedType = rt; + if (lt->isSignedIntegerType()) { + if (rt->isSignedIntegerType()) return; + } else { + if (!rt->isSignedIntegerType()) return; + std::swap(signedOperand, unsignedOperand); + std::swap(signedType, unsignedType); + } + + unsigned unsignedWidth = Context.getIntWidth(unsignedType); + unsigned signedWidth = Context.getIntWidth(signedType); + + // If the unsigned type is strictly smaller than the signed type, + // then (1) the result type will be signed and (2) the unsigned + // value will fit fully within the signed type, and thus the result + // of the comparison will be exact. + if (signedWidth > unsignedWidth) + return; + + // Otherwise, calculate the effective ranges. + IntRange signedRange = GetExprRange(Context, signedOperand, signedWidth); + IntRange unsignedRange = GetExprRange(Context, unsignedOperand, unsignedWidth); + + // We should never be unable to prove that the unsigned operand is + // non-negative. + assert(unsignedRange.NonNegative && "unsigned range includes negative?"); + + // If the signed operand is non-negative, then the signed->unsigned + // conversion won't change it. + if (signedRange.NonNegative) + return; + + // For (in)equality comparisons, if the unsigned operand is a + // constant which cannot collide with a overflowed signed operand, + // then reinterpreting the signed operand as unsigned will not + // change the result of the comparison. + if (Equality && unsignedRange.Width < unsignedWidth) + return; + + Diag(OpLoc, PD) + << lt << rt << lex->getSourceRange() << rex->getSourceRange(); +} + +/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. +static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) { + S.Diag(E->getExprLoc(), diag) << E->getType() << T << E->getSourceRange(); +} + +/// Implements -Wconversion. +void Sema::CheckImplicitConversion(Expr *E, QualType T) { + // Don't diagnose in unevaluated contexts. + if (ExprEvalContexts.back().Context == Sema::Unevaluated) + return; + + // Don't diagnose for value-dependent expressions. + if (E->isValueDependent()) + return; + + const Type *Source = Context.getCanonicalType(E->getType()).getTypePtr(); + const Type *Target = Context.getCanonicalType(T).getTypePtr(); + + // Never diagnose implicit casts to bool. + if (Target->isSpecificBuiltinType(BuiltinType::Bool)) + return; + + // Strip vector types. + if (isa<VectorType>(Source)) { + if (!isa<VectorType>(Target)) + return DiagnoseImpCast(*this, E, T, diag::warn_impcast_vector_scalar); + + Source = cast<VectorType>(Source)->getElementType().getTypePtr(); + Target = cast<VectorType>(Target)->getElementType().getTypePtr(); + } + + // Strip complex types. + if (isa<ComplexType>(Source)) { + if (!isa<ComplexType>(Target)) + return DiagnoseImpCast(*this, E, T, diag::warn_impcast_complex_scalar); + + Source = cast<ComplexType>(Source)->getElementType().getTypePtr(); + Target = cast<ComplexType>(Target)->getElementType().getTypePtr(); + } + + const BuiltinType *SourceBT = dyn_cast<BuiltinType>(Source); + const BuiltinType *TargetBT = dyn_cast<BuiltinType>(Target); + + // If the source is floating point... + if (SourceBT && SourceBT->isFloatingPoint()) { + // ...and the target is floating point... + if (TargetBT && TargetBT->isFloatingPoint()) { + // ...then warn if we're dropping FP rank. + + // Builtin FP kinds are ordered by increasing FP rank. + if (SourceBT->getKind() > TargetBT->getKind()) { + // Don't warn about float constants that are precisely + // representable in the target type. + Expr::EvalResult result; + if (E->Evaluate(result, Context)) { + // Value might be a float, a float vector, or a float complex. + if (IsSameFloatAfterCast(result.Val, + Context.getFloatTypeSemantics(QualType(TargetBT, 0)), + Context.getFloatTypeSemantics(QualType(SourceBT, 0)))) + return; + } + + DiagnoseImpCast(*this, E, T, diag::warn_impcast_float_precision); + } + return; + } + + // If the target is integral, always warn. + if ((TargetBT && TargetBT->isInteger())) + // TODO: don't warn for integer values? + return DiagnoseImpCast(*this, E, T, diag::warn_impcast_float_integer); + + return; + } + + if (!Source->isIntegerType() || !Target->isIntegerType()) + return; + + IntRange SourceRange = GetExprRange(Context, E, Context.getIntWidth(E->getType())); + IntRange TargetRange = IntRange::forCanonicalType(Context, Target); + + // FIXME: also signed<->unsigned? + + if (SourceRange.Width > TargetRange.Width) { + // People want to build with -Wshorten-64-to-32 and not -Wconversion + // and by god we'll let them. + if (SourceRange.Width == 64 && TargetRange.Width == 32) + return DiagnoseImpCast(*this, E, T, diag::warn_impcast_integer_64_32); + return DiagnoseImpCast(*this, E, T, diag::warn_impcast_integer_precision); + } + + return; +} + diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index ef82a94..a4cda01 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// #include "Sema.h" +#include "Lookup.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" @@ -111,14 +112,18 @@ namespace { /// \brief If non-NULL, a filter function used to remove any code-completion /// results that are not desirable. LookupFilter Filter; - + + /// \brief Whether we should allow declarations as + /// nested-name-specifiers that would otherwise be filtered out. + bool AllowNestedNameSpecifiers; + /// \brief A list of shadow maps, which is used to model name hiding at /// different levels of, e.g., the inheritance hierarchy. std::list<ShadowMap> ShadowMaps; public: explicit ResultBuilder(Sema &SemaRef, LookupFilter Filter = 0) - : SemaRef(SemaRef), Filter(Filter) { } + : SemaRef(SemaRef), Filter(Filter), AllowNestedNameSpecifiers(false) { } /// \brief Set the filter used for code-completion results. void setFilter(LookupFilter Filter) { @@ -133,15 +138,55 @@ namespace { unsigned size() const { return Results.size(); } bool empty() const { return Results.empty(); } + /// \brief Specify whether nested-name-specifiers are allowed. + void allowNestedNameSpecifiers(bool Allow = true) { + AllowNestedNameSpecifiers = Allow; + } + + /// \brief Determine whether the given declaration is at all interesting + /// as a code-completion result. + /// + /// \param ND the declaration that we are inspecting. + /// + /// \param AsNestedNameSpecifier will be set true if this declaration is + /// only interesting when it is a nested-name-specifier. + bool isInterestingDecl(NamedDecl *ND, bool &AsNestedNameSpecifier) const; + + /// \brief Check whether the result is hidden by the Hiding declaration. + /// + /// \returns true if the result is hidden and cannot be found, false if + /// the hidden result could still be found. When false, \p R may be + /// modified to describe how the result can be found (e.g., via extra + /// qualification). + bool CheckHiddenResult(Result &R, DeclContext *CurContext, + NamedDecl *Hiding); + /// \brief Add a new result to this result set (if it isn't already in one /// of the shadow maps), or replace an existing result (for, e.g., a /// redeclaration). /// - /// \param R the result to add (if it is unique). + /// \param CurContext the result to add (if it is unique). /// /// \param R the context in which this result will be named. void MaybeAddResult(Result R, DeclContext *CurContext = 0); + /// \brief Add a new result to this result set, where we already know + /// the hiding declation (if any). + /// + /// \param R the result to add (if it is unique). + /// + /// \param CurContext the context in which this result will be named. + /// + /// \param Hiding the declaration that hides the result. + /// + /// \param InBaseClass whether the result was found in a base + /// class of the searched context. + void AddResult(Result R, DeclContext *CurContext, NamedDecl *Hiding, + bool InBaseClass); + + /// \brief Add a new non-declaration result to this result set. + void AddResult(Result R); + /// \brief Enter into a new scope. void EnterNewScope(); @@ -158,6 +203,7 @@ namespace { /// //@{ bool IsOrdinaryName(NamedDecl *ND) const; + bool IsOrdinaryNonValueName(NamedDecl *ND) const; bool IsNestedNameSpecifier(NamedDecl *ND) const; bool IsEnum(NamedDecl *ND) const; bool IsClassOrStruct(NamedDecl *ND) const; @@ -166,6 +212,7 @@ namespace { bool IsNamespaceOrAlias(NamedDecl *ND) const; bool IsType(NamedDecl *ND) const; bool IsMember(NamedDecl *ND) const; + bool IsObjCIvar(NamedDecl *ND) const; //@} }; } @@ -259,31 +306,6 @@ ResultBuilder::ShadowMapEntry::end() const { 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. -/// -/// \param Hidden the declaration that is hidden by the currenly \p Visible -/// declaration. -/// -/// \param Visible the declaration with the same name that is already visible. -/// -/// \returns true if the hidden result can be found by some mechanism, -/// false otherwise. -static bool canHiddenResultBeFound(const LangOptions &LangOpts, - NamedDecl *Hidden, NamedDecl *Visible) { - // In C, there is no way to refer to a hidden name. - if (!LangOpts.CPlusPlus) - return false; - - DeclContext *HiddenCtx = Hidden->getDeclContext()->getLookupContext(); - - // There is no way to qualify a name declared in a function or method. - if (HiddenCtx->isFunctionOrMethod()) - return false; - - return HiddenCtx != Visible->getDeclContext()->getLookupContext(); -} - /// \brief Compute the qualification required to get from the current context /// (\p CurContext) to the target context (\p TargetContext). /// @@ -330,46 +352,37 @@ getRequiredQualification(ASTContext &Context, return Result; } -void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { - assert(!ShadowMaps.empty() && "Must enter into a results scope"); - - if (R.Kind != Result::RK_Declaration) { - // For non-declaration results, just add the result. - Results.push_back(R); - return; - } +bool ResultBuilder::isInterestingDecl(NamedDecl *ND, + bool &AsNestedNameSpecifier) const { + AsNestedNameSpecifier = false; + + ND = ND->getUnderlyingDecl(); + unsigned IDNS = ND->getIdentifierNamespace(); // Skip unnamed entities. - if (!R.Declaration->getDeclName()) - return; - - // Look through using declarations. - if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) - MaybeAddResult(Result(Using->getTargetDecl(), R.Rank, R.Qualifier), - CurContext); - - Decl *CanonDecl = R.Declaration->getCanonicalDecl(); - unsigned IDNS = CanonDecl->getIdentifierNamespace(); + if (!ND->getDeclName()) + return false; // Friend declarations and declarations introduced due to friends are never // added as results. - if (isa<FriendDecl>(CanonDecl) || + if (isa<FriendDecl>(ND) || (IDNS & (Decl::IDNS_OrdinaryFriend | Decl::IDNS_TagFriend))) - return; - + return false; + // Class template (partial) specializations are never added as results. - if (isa<ClassTemplateSpecializationDecl>(CanonDecl) || - isa<ClassTemplatePartialSpecializationDecl>(CanonDecl)) - return; + if (isa<ClassTemplateSpecializationDecl>(ND) || + isa<ClassTemplatePartialSpecializationDecl>(ND)) + return false; // Using declarations themselves are never added as results. - if (isa<UsingDecl>(CanonDecl)) - return; - - if (const IdentifierInfo *Id = R.Declaration->getIdentifier()) { + if (isa<UsingDecl>(ND)) + return false; + + // Some declarations have reserved names that we don't want to ever show. + if (const IdentifierInfo *Id = ND->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")) - return; + return false; // Filter out names reserved for the implementation (C99 7.1.3, // C++ [lib.global.names]). Users don't need to see those. @@ -379,18 +392,83 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { const char *Name = Id->getNameStart(); if (Name[0] == '_' && (Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z'))) - return; + return false; } } - + // C++ constructors are never found by name lookup. - if (isa<CXXConstructorDecl>(CanonDecl)) - return; + if (isa<CXXConstructorDecl>(ND)) + return false; // Filter out any unwanted results. - if (Filter && !(this->*Filter)(R.Declaration)) + if (Filter && !(this->*Filter)(ND)) { + // Check whether it is interesting as a nested-name-specifier. + if (AllowNestedNameSpecifiers && SemaRef.getLangOptions().CPlusPlus && + IsNestedNameSpecifier(ND) && + (Filter != &ResultBuilder::IsMember || + (isa<CXXRecordDecl>(ND) && + cast<CXXRecordDecl>(ND)->isInjectedClassName()))) { + AsNestedNameSpecifier = true; + return true; + } + + return false; + } + + // ... then it must be interesting! + return true; +} + +bool ResultBuilder::CheckHiddenResult(Result &R, DeclContext *CurContext, + NamedDecl *Hiding) { + // In C, there is no way to refer to a hidden name. + // FIXME: This isn't true; we can find a tag name hidden by an ordinary + // name if we introduce the tag type. + if (!SemaRef.getLangOptions().CPlusPlus) + return true; + + DeclContext *HiddenCtx = R.Declaration->getDeclContext()->getLookupContext(); + + // There is no way to qualify a name declared in a function or method. + if (HiddenCtx->isFunctionOrMethod()) + return true; + + if (HiddenCtx == Hiding->getDeclContext()->getLookupContext()) + return true; + + // We can refer to the result with the appropriate qualification. Do it. + R.Hidden = true; + R.QualifierIsInformative = false; + + if (!R.Qualifier) + R.Qualifier = getRequiredQualification(SemaRef.Context, + CurContext, + R.Declaration->getDeclContext()); + return false; +} + +void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { + assert(!ShadowMaps.empty() && "Must enter into a results scope"); + + if (R.Kind != Result::RK_Declaration) { + // For non-declaration results, just add the result. + Results.push_back(R); return; + } + + // Look through using declarations. + if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) { + MaybeAddResult(Result(Using->getTargetDecl(), R.Qualifier), CurContext); + return; + } + Decl *CanonDecl = R.Declaration->getCanonicalDecl(); + unsigned IDNS = CanonDecl->getIdentifierNamespace(); + + bool AsNestedNameSpecifier = false; + if (!isInterestingDecl(R.Declaration, AsNestedNameSpecifier)) + return; + ShadowMap &SMap = ShadowMaps.back(); ShadowMapEntry::iterator I, IEnd; ShadowMap::iterator NamePos = SMap.find(R.Declaration->getDeclName()); @@ -406,9 +484,6 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { // This is a redeclaration. Always pick the newer declaration. Results[Index].Declaration = R.Declaration; - // Pick the best rank of the two. - Results[Index].Rank = std::min(Results[Index].Rank, R.Rank); - // We're done. return; } @@ -440,21 +515,8 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { continue; // The newly-added result is hidden by an entry in the shadow map. - if (canHiddenResultBeFound(SemaRef.getLangOptions(), R.Declaration, - I->first)) { - // Note that this result was hidden. - R.Hidden = true; - R.QualifierIsInformative = false; - - if (!R.Qualifier) - R.Qualifier = getRequiredQualification(SemaRef.Context, - CurContext, - R.Declaration->getDeclContext()); - } else { - // This result was hidden and cannot be found; don't bother adding - // it. + if (CheckHiddenResult(R, CurContext, I->first)) return; - } break; } @@ -466,10 +528,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { // If the filter is for nested-name-specifiers, then this result starts a // nested-name-specifier. - if ((Filter == &ResultBuilder::IsNestedNameSpecifier) || - (Filter == &ResultBuilder::IsMember && - isa<CXXRecordDecl>(R.Declaration) && - cast<CXXRecordDecl>(R.Declaration)->isInjectedClassName())) + if (AsNestedNameSpecifier) R.StartsNestedNameSpecifier = true; // If this result is supposed to have an informative qualifier, add one. @@ -491,6 +550,63 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { Results.push_back(R); } +void ResultBuilder::AddResult(Result R, DeclContext *CurContext, + NamedDecl *Hiding, bool InBaseClass = false) { + if (R.Kind != Result::RK_Declaration) { + // For non-declaration results, just add the result. + Results.push_back(R); + return; + } + + // Look through using declarations. + if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) { + AddResult(Result(Using->getTargetDecl(), R.Qualifier), CurContext, Hiding); + return; + } + + bool AsNestedNameSpecifier = false; + if (!isInterestingDecl(R.Declaration, AsNestedNameSpecifier)) + return; + + if (Hiding && CheckHiddenResult(R, CurContext, Hiding)) + return; + + // Make sure that any given declaration only shows up in the result set once. + if (!AllDeclsFound.insert(R.Declaration->getCanonicalDecl())) + return; + + // If the filter is for nested-name-specifiers, then this result starts a + // nested-name-specifier. + if (AsNestedNameSpecifier) + R.StartsNestedNameSpecifier = true; + else if (Filter == &ResultBuilder::IsMember && !R.Qualifier && InBaseClass && + isa<CXXRecordDecl>(R.Declaration->getDeclContext() + ->getLookupContext())) + R.QualifierIsInformative = true; + + // If this result is supposed to have an informative qualifier, add one. + if (R.QualifierIsInformative && !R.Qualifier && + !R.StartsNestedNameSpecifier) { + DeclContext *Ctx = R.Declaration->getDeclContext(); + if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Ctx)) + R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, Namespace); + else if (TagDecl *Tag = dyn_cast<TagDecl>(Ctx)) + R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, false, + SemaRef.Context.getTypeDeclType(Tag).getTypePtr()); + else + R.QualifierIsInformative = false; + } + + // Insert this result into the set of results. + Results.push_back(R); +} + +void ResultBuilder::AddResult(Result R) { + assert(R.Kind != Result::RK_Declaration && + "Declaration results need more context"); + Results.push_back(R); +} + /// \brief Enter into a new scope. void ResultBuilder::EnterNewScope() { ShadowMaps.push_back(ShadowMap()); @@ -513,10 +629,23 @@ bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const { unsigned IDNS = Decl::IDNS_Ordinary; if (SemaRef.getLangOptions().CPlusPlus) IDNS |= Decl::IDNS_Tag; - + else if (SemaRef.getLangOptions().ObjC1 && isa<ObjCIvarDecl>(ND)) + return true; + return ND->getIdentifierNamespace() & IDNS; } +/// \brief Determines whether this given declaration will be found by +/// ordinary name lookup. +bool ResultBuilder::IsOrdinaryNonValueName(NamedDecl *ND) const { + unsigned IDNS = Decl::IDNS_Ordinary; + if (SemaRef.getLangOptions().CPlusPlus) + IDNS |= Decl::IDNS_Tag; + + return (ND->getIdentifierNamespace() & IDNS) && + !isa<ValueDecl>(ND) && !isa<FunctionTemplateDecl>(ND); +} + /// \brief Determines whether the given declaration is suitable as the /// start of a C++ nested-name-specifier, e.g., a class or namespace. bool ResultBuilder::IsNestedNameSpecifier(NamedDecl *ND) const { @@ -584,251 +713,601 @@ bool ResultBuilder::IsMember(NamedDecl *ND) const { isa<ObjCPropertyDecl>(ND); } -// Find the next outer declaration context corresponding to this scope. -static DeclContext *findOuterContext(Scope *S) { - for (S = S->getParent(); S; S = S->getParent()) - if (S->getEntity()) - return static_cast<DeclContext *>(S->getEntity())->getPrimaryContext(); - - return 0; -} - -/// \brief Collect the results of searching for members within the given -/// declaration context. -/// -/// \param Ctx the declaration context from which we will gather results. -/// -/// \param Rank the rank given to results in this declaration context. -/// -/// \param Visited the set of declaration contexts that have already been -/// visited. Declaration contexts will only be visited once. -/// -/// \param Results the result set that will be extended with any results -/// found within this declaration context (and, for a C++ class, its bases). -/// -/// \param InBaseClass whether we are in a base class. -/// -/// \returns the next higher rank value, after considering all of the -/// names within this declaration context. -static unsigned CollectMemberLookupResults(DeclContext *Ctx, - unsigned Rank, - DeclContext *CurContext, - llvm::SmallPtrSet<DeclContext *, 16> &Visited, - ResultBuilder &Results, - bool InBaseClass = false) { - // Make sure we don't visit the same context twice. - if (!Visited.insert(Ctx->getPrimaryContext())) - return Rank; - - // Enumerate all of the results in this context. - typedef CodeCompleteConsumer::Result Result; - Results.EnterNewScope(); - for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx; - CurCtx = CurCtx->getNextContext()) { - for (DeclContext::decl_iterator D = CurCtx->decls_begin(), - DEnd = CurCtx->decls_end(); - D != DEnd; ++D) { - if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) - Results.MaybeAddResult(Result(ND, Rank, 0, InBaseClass), CurContext); - - // Visit transparent contexts inside this context. - if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D)) { - if (InnerCtx->isTransparentContext()) - CollectMemberLookupResults(InnerCtx, Rank, CurContext, Visited, - Results, InBaseClass); - } - } - } - - // Traverse the contexts of inherited classes. - if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) { - for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(), - BEnd = Record->bases_end(); - B != BEnd; ++B) { - QualType BaseType = B->getType(); - - // Don't look into dependent bases, because name lookup can't look - // there anyway. - if (BaseType->isDependentType()) - continue; - - const RecordType *Record = BaseType->getAs<RecordType>(); - if (!Record) - continue; - - // FIXME: It would be nice to be able to determine whether referencing - // a particular member would be ambiguous. For example, given - // - // struct A { int member; }; - // struct B { int member; }; - // struct C : A, B { }; - // - // void f(C *c) { c->### } - // accessing 'member' would result in an ambiguity. However, code - // completion could be smart enough to qualify the member with the - // base class, e.g., - // - // c->B::member - // - // or - // - // c->A::member - - // Collect results from this base class (and its bases). - CollectMemberLookupResults(Record->getDecl(), Rank, CurContext, Visited, - Results, /*InBaseClass=*/true); - } - } - - // FIXME: Look into base classes in Objective-C! - - Results.ExitScope(); - return Rank + 1; +/// \rief Determines whether the given declaration is an Objective-C +/// instance variable. +bool ResultBuilder::IsObjCIvar(NamedDecl *ND) const { + return isa<ObjCIvarDecl>(ND); } -/// \brief Collect the results of searching for members within the given -/// declaration context. -/// -/// \param Ctx the declaration context from which we will gather results. -/// -/// \param InitialRank the initial rank given to results in this declaration -/// context. Larger rank values will be used for, e.g., members found in -/// base classes. -/// -/// \param Results the result set that will be extended with any results -/// found within this declaration context (and, for a C++ class, its bases). -/// -/// \returns the next higher rank value, after considering all of the -/// names within this declaration context. -static unsigned CollectMemberLookupResults(DeclContext *Ctx, - unsigned InitialRank, - DeclContext *CurContext, - ResultBuilder &Results) { - llvm::SmallPtrSet<DeclContext *, 16> Visited; - return CollectMemberLookupResults(Ctx, InitialRank, CurContext, Visited, - Results); -} - -/// \brief Collect the results of searching for declarations within the given -/// scope and its parent scopes. -/// -/// \param S the scope in which we will start looking for declarations. -/// -/// \param InitialRank the initial rank given to results in this scope. -/// Larger rank values will be used for results found in parent scopes. -/// -/// \param CurContext the context from which lookup results will be found. -/// -/// \param Results the builder object that will receive each result. -static unsigned CollectLookupResults(Scope *S, - TranslationUnitDecl *TranslationUnit, - unsigned InitialRank, - DeclContext *CurContext, - ResultBuilder &Results) { - if (!S) - return InitialRank; - - // FIXME: Using directives! - - unsigned NextRank = InitialRank; - Results.EnterNewScope(); - if (S->getEntity() && - !((DeclContext *)S->getEntity())->isFunctionOrMethod()) { - // Look into this scope's declaration context, along with any of its - // parent lookup contexts (e.g., enclosing classes), up to the point - // where we hit the context stored in the next outer scope. - DeclContext *Ctx = (DeclContext *)S->getEntity(); - DeclContext *OuterCtx = findOuterContext(S); - - for (; Ctx && Ctx->getPrimaryContext() != OuterCtx; - Ctx = Ctx->getLookupParent()) { - if (Ctx->isFunctionOrMethod()) - continue; - - NextRank = CollectMemberLookupResults(Ctx, NextRank + 1, CurContext, - Results); - } - } else if (!S->getParent()) { - // Look into the translation unit scope. We walk through the translation - // unit's declaration context, because the Scope itself won't have all of - // the declarations if we loaded a precompiled header. - // FIXME: We would like the translation unit's Scope object to point to the - // translation unit, so we don't need this special "if" branch. However, - // doing so would force the normal C++ name-lookup code to look into the - // translation unit decl when the IdentifierInfo chains would suffice. - // Once we fix that problem (which is part of a more general "don't look - // in DeclContexts unless we have to" optimization), we can eliminate the - // TranslationUnit parameter entirely. - NextRank = CollectMemberLookupResults(TranslationUnit, NextRank + 1, - CurContext, Results); - } else { - // Walk through the declarations in this Scope. - for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); - D != DEnd; ++D) { - if (NamedDecl *ND = dyn_cast<NamedDecl>((Decl *)((*D).get()))) - Results.MaybeAddResult(CodeCompleteConsumer::Result(ND, NextRank), - CurContext); - } +namespace { + /// \brief Visible declaration consumer that adds a code-completion result + /// for each visible declaration. + class CodeCompletionDeclConsumer : public VisibleDeclConsumer { + ResultBuilder &Results; + DeclContext *CurContext; - NextRank = NextRank + 1; - } - - // Lookup names in the parent scope. - NextRank = CollectLookupResults(S->getParent(), TranslationUnit, NextRank, - CurContext, Results); - Results.ExitScope(); - - return NextRank; + public: + CodeCompletionDeclConsumer(ResultBuilder &Results, DeclContext *CurContext) + : Results(Results), CurContext(CurContext) { } + + virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass) { + Results.AddResult(ND, CurContext, Hiding, InBaseClass); + } + }; } /// \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, ResultBuilder &Results) { typedef CodeCompleteConsumer::Result Result; - Results.MaybeAddResult(Result("short", Rank)); - Results.MaybeAddResult(Result("long", Rank)); - Results.MaybeAddResult(Result("signed", Rank)); - Results.MaybeAddResult(Result("unsigned", Rank)); - Results.MaybeAddResult(Result("void", Rank)); - Results.MaybeAddResult(Result("char", Rank)); - Results.MaybeAddResult(Result("int", Rank)); - Results.MaybeAddResult(Result("float", Rank)); - Results.MaybeAddResult(Result("double", Rank)); - Results.MaybeAddResult(Result("enum", Rank)); - Results.MaybeAddResult(Result("struct", Rank)); - Results.MaybeAddResult(Result("union", Rank)); - + Results.AddResult(Result("short")); + Results.AddResult(Result("long")); + Results.AddResult(Result("signed")); + Results.AddResult(Result("unsigned")); + Results.AddResult(Result("void")); + Results.AddResult(Result("char")); + Results.AddResult(Result("int")); + Results.AddResult(Result("float")); + Results.AddResult(Result("double")); + Results.AddResult(Result("enum")); + Results.AddResult(Result("struct")); + Results.AddResult(Result("union")); + Results.AddResult(Result("const")); + Results.AddResult(Result("volatile")); + if (LangOpts.C99) { // C99-specific - Results.MaybeAddResult(Result("_Complex", Rank)); - Results.MaybeAddResult(Result("_Imaginary", Rank)); - Results.MaybeAddResult(Result("_Bool", Rank)); + Results.AddResult(Result("_Complex")); + Results.AddResult(Result("_Imaginary")); + Results.AddResult(Result("_Bool")); + Results.AddResult(Result("restrict")); } if (LangOpts.CPlusPlus) { // C++-specific - Results.MaybeAddResult(Result("bool", Rank)); - Results.MaybeAddResult(Result("class", Rank)); - Results.MaybeAddResult(Result("typename", Rank)); - Results.MaybeAddResult(Result("wchar_t", Rank)); + Results.AddResult(Result("bool")); + Results.AddResult(Result("class")); + Results.AddResult(Result("wchar_t")); + // typename qualified-id + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("typename"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("qualified-id"); + Results.AddResult(Result(Pattern)); + if (LangOpts.CPlusPlus0x) { - Results.MaybeAddResult(Result("char16_t", Rank)); - Results.MaybeAddResult(Result("char32_t", Rank)); - Results.MaybeAddResult(Result("decltype", Rank)); + Results.AddResult(Result("auto")); + Results.AddResult(Result("char16_t")); + Results.AddResult(Result("char32_t")); + Results.AddResult(Result("decltype")); } } // GNU extensions if (LangOpts.GNUMode) { // FIXME: Enable when we actually support decimal floating point. - // Results.MaybeAddResult(Result("_Decimal32", Rank)); - // Results.MaybeAddResult(Result("_Decimal64", Rank)); - // Results.MaybeAddResult(Result("_Decimal128", Rank)); - Results.MaybeAddResult(Result("typeof", Rank)); + // Results.AddResult(Result("_Decimal32")); + // Results.AddResult(Result("_Decimal64")); + // Results.AddResult(Result("_Decimal128")); + + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("typeof"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression-or-type"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); } } +static void AddStorageSpecifiers(Action::CodeCompletionContext CCC, + const LangOptions &LangOpts, + ResultBuilder &Results) { + typedef CodeCompleteConsumer::Result Result; + // Note: we don't suggest either "auto" or "register", because both + // are pointless as storage specifiers. Elsewhere, we suggest "auto" + // in C++0x as a type specifier. + Results.AddResult(Result("extern")); + Results.AddResult(Result("static")); +} + +static void AddFunctionSpecifiers(Action::CodeCompletionContext CCC, + const LangOptions &LangOpts, + ResultBuilder &Results) { + typedef CodeCompleteConsumer::Result Result; + switch (CCC) { + case Action::CCC_Class: + case Action::CCC_MemberTemplate: + if (LangOpts.CPlusPlus) { + Results.AddResult(Result("explicit")); + Results.AddResult(Result("friend")); + Results.AddResult(Result("mutable")); + Results.AddResult(Result("virtual")); + } + // Fall through + + case Action::CCC_ObjCInterface: + case Action::CCC_ObjCImplementation: + case Action::CCC_Namespace: + case Action::CCC_Template: + if (LangOpts.CPlusPlus || LangOpts.C99) + Results.AddResult(Result("inline")); + break; + + case Action::CCC_ObjCInstanceVariableList: + case Action::CCC_Expression: + case Action::CCC_Statement: + case Action::CCC_ForInit: + case Action::CCC_Condition: + break; + } +} + +static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt); +static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt); +static void AddObjCVisibilityResults(const LangOptions &LangOpts, + ResultBuilder &Results, + bool NeedAt); +static void AddObjCImplementationResults(const LangOptions &LangOpts, + ResultBuilder &Results, + bool NeedAt); +static void AddObjCInterfaceResults(const LangOptions &LangOpts, + ResultBuilder &Results, + bool NeedAt); +static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt); + +/// \brief Add language constructs that show up for "ordinary" names. +static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, + Scope *S, + Sema &SemaRef, + ResultBuilder &Results) { + typedef CodeCompleteConsumer::Result Result; + switch (CCC) { + case Action::CCC_Namespace: + if (SemaRef.getLangOptions().CPlusPlus) { + // namespace <identifier> { } + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("namespace"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("identifier"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("declarations"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Pattern)); + + // namespace identifier = identifier ; + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("namespace"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("identifier"); + Pattern->AddChunk(CodeCompletionString::CK_Equal); + Pattern->AddPlaceholderChunk("identifier"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + + // Using directives + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("using"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddTextChunk("namespace"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("identifier"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + + // asm(string-literal) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("asm"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("string-literal"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + + // Explicit template instantiation + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("template"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("declaration"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + } + + if (SemaRef.getLangOptions().ObjC1) + AddObjCTopLevelResults(Results, true); + + // Fall through + + case Action::CCC_Class: + Results.AddResult(Result("typedef")); + if (SemaRef.getLangOptions().CPlusPlus) { + // Using declaration + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("using"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("qualified-id"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + + // using typename qualified-id; (only in a dependent context) + if (SemaRef.CurContext->isDependentContext()) { + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("using"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddTextChunk("typename"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("qualified-id"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + } + + if (CCC == Action::CCC_Class) { + // public: + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("public"); + Pattern->AddChunk(CodeCompletionString::CK_Colon); + Results.AddResult(Result(Pattern)); + + // protected: + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("protected"); + Pattern->AddChunk(CodeCompletionString::CK_Colon); + Results.AddResult(Result(Pattern)); + + // private: + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("private"); + Pattern->AddChunk(CodeCompletionString::CK_Colon); + Results.AddResult(Result(Pattern)); + } + } + // Fall through + + case Action::CCC_Template: + case Action::CCC_MemberTemplate: + if (SemaRef.getLangOptions().CPlusPlus) { + // template < parameters > + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("template"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("parameters"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Results.AddResult(Result(Pattern)); + } + + AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results); + AddFunctionSpecifiers(CCC, SemaRef.getLangOptions(), Results); + break; + + case Action::CCC_ObjCInterface: + AddObjCInterfaceResults(SemaRef.getLangOptions(), Results, true); + AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results); + AddFunctionSpecifiers(CCC, SemaRef.getLangOptions(), Results); + break; + + case Action::CCC_ObjCImplementation: + AddObjCImplementationResults(SemaRef.getLangOptions(), Results, true); + AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results); + AddFunctionSpecifiers(CCC, SemaRef.getLangOptions(), Results); + break; + + case Action::CCC_ObjCInstanceVariableList: + AddObjCVisibilityResults(SemaRef.getLangOptions(), Results, true); + break; + + case Action::CCC_Statement: { + Results.AddResult(Result("typedef")); + + CodeCompletionString *Pattern = 0; + if (SemaRef.getLangOptions().CPlusPlus) { + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("try"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Pattern->AddTextChunk("catch"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("declaration"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Pattern)); + } + if (SemaRef.getLangOptions().ObjC1) + AddObjCStatementResults(Results, true); + + // if (condition) { statements } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("if"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + if (SemaRef.getLangOptions().CPlusPlus) + Pattern->AddPlaceholderChunk("condition"); + else + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Pattern)); + + // switch (condition) { } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("switch"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + if (SemaRef.getLangOptions().CPlusPlus) + Pattern->AddPlaceholderChunk("condition"); + else + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Pattern)); + + // Switch-specific statements. + if (!SemaRef.getSwitchStack().empty()) { + // case expression: + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("case"); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_Colon); + Results.AddResult(Result(Pattern)); + + // default: + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("default"); + Pattern->AddChunk(CodeCompletionString::CK_Colon); + Results.AddResult(Result(Pattern)); + } + + /// while (condition) { statements } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("while"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + if (SemaRef.getLangOptions().CPlusPlus) + Pattern->AddPlaceholderChunk("condition"); + else + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Pattern)); + + // do { statements } while ( expression ); + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("do"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Pattern->AddTextChunk("while"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + + // for ( for-init-statement ; condition ; expression ) { statements } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("for"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + if (SemaRef.getLangOptions().CPlusPlus || SemaRef.getLangOptions().C99) + Pattern->AddPlaceholderChunk("init-statement"); + else + Pattern->AddPlaceholderChunk("init-expression"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Pattern->AddPlaceholderChunk("condition"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Pattern->AddPlaceholderChunk("inc-expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.AddResult(Result(Pattern)); + + if (S->getContinueParent()) { + // continue ; + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("continue"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + } + + if (S->getBreakParent()) { + // break ; + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("break"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + } + + // "return expression ;" or "return ;", depending on whether we + // know the function is void or not. + bool isVoid = false; + if (FunctionDecl *Function = dyn_cast<FunctionDecl>(SemaRef.CurContext)) + isVoid = Function->getResultType()->isVoidType(); + else if (ObjCMethodDecl *Method + = dyn_cast<ObjCMethodDecl>(SemaRef.CurContext)) + isVoid = Method->getResultType()->isVoidType(); + else if (SemaRef.CurBlock && !SemaRef.CurBlock->ReturnType.isNull()) + isVoid = SemaRef.CurBlock->ReturnType->isVoidType(); + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("return"); + if (!isVoid) + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + + // goto identifier ; + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("goto"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("identifier"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + + // Using directives + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("using"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddTextChunk("namespace"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("identifier"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + } + + // Fall through (for statement expressions). + case Action::CCC_ForInit: + case Action::CCC_Condition: + AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results); + // Fall through: conditions and statements can have expressions. + + case Action::CCC_Expression: { + CodeCompletionString *Pattern = 0; + if (SemaRef.getLangOptions().CPlusPlus) { + // 'this', if we're in a non-static member function. + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(SemaRef.CurContext)) + if (!Method->isStatic()) + Results.AddResult(Result("this")); + + // true, false + Results.AddResult(Result("true")); + Results.AddResult(Result("false")); + + // dynamic_cast < type-id > ( expression ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("dynamic_cast"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + + // static_cast < type-id > ( expression ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("static_cast"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + + // reinterpret_cast < type-id > ( expression ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("reinterpret_cast"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + + // const_cast < type-id > ( expression ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("const_cast"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + + // typeid ( expression-or-type ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("typeid"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression-or-type"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + + // new T ( ... ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("new"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expressions"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + + // new T [ ] ( ... ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("new"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBracket); + Pattern->AddPlaceholderChunk("size"); + Pattern->AddChunk(CodeCompletionString::CK_RightBracket); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expressions"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + + // delete expression + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("delete"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("expression"); + Results.AddResult(Result(Pattern)); + + // delete [] expression + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("delete"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBracket); + Pattern->AddChunk(CodeCompletionString::CK_RightBracket); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("expression"); + Results.AddResult(Result(Pattern)); + + // throw expression + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("throw"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("expression"); + Results.AddResult(Result(Pattern)); + } + + if (SemaRef.getLangOptions().ObjC1) { + // Add "super", if we're in an Objective-C class with a superclass. + if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl()) + if (Method->getClassInterface()->getSuperClass()) + Results.AddResult(Result("super")); + + AddObjCExpressionResults(Results, true); + } + + // sizeof expression + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("sizeof"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression-or-type"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Pattern)); + break; + } + } + + AddTypeSpecifierResults(SemaRef.getLangOptions(), Results); + + if (SemaRef.getLangOptions().CPlusPlus) + Results.AddResult(Result("operator")); +} + /// \brief If the given declaration has an associated type, add it as a result /// type chunk. static void AddResultTypeChunk(ASTContext &Context, @@ -1178,7 +1657,7 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { if (Idx > 0) { std::string Keyword; if (Idx > StartParameter) - Keyword = " "; + Result->AddChunk(CodeCompletionString::CK_HorizontalSpace); if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Idx)) Keyword += II->getName().str(); Keyword += ":"; @@ -1344,29 +1823,49 @@ namespace { Y.getAsString()) < 0; } - bool operator()(const Result &X, const Result &Y) const { - // Sort first by rank. - if (X.Rank < Y.Rank) - return true; - else if (X.Rank > Y.Rank) - return false; - - // We use a special ordering for keywords and patterns, based on the - // typed text. - if ((X.Kind == Result::RK_Keyword || X.Kind == Result::RK_Pattern) && - (Y.Kind == Result::RK_Keyword || Y.Kind == Result::RK_Pattern)) { - const char *XStr = (X.Kind == Result::RK_Keyword)? X.Keyword - : X.Pattern->getTypedText(); - const char *YStr = (Y.Kind == Result::RK_Keyword)? Y.Keyword - : Y.Pattern->getTypedText(); - return llvm::StringRef(XStr).compare_lower(YStr) < 0; + /// \brief Retrieve the name that should be used to order a result. + /// + /// If the name needs to be constructed as a string, that string will be + /// saved into Saved and the returned StringRef will refer to it. + static llvm::StringRef getOrderedName(const Result &R, + std::string &Saved) { + switch (R.Kind) { + case Result::RK_Keyword: + return R.Keyword; + + case Result::RK_Pattern: + return R.Pattern->getTypedText(); + + case Result::RK_Macro: + return R.Macro->getName(); + + case Result::RK_Declaration: + // Handle declarations below. + break; } + + DeclarationName Name = R.Declaration->getDeclName(); - // Result kinds are ordered by decreasing importance. - if (X.Kind < Y.Kind) - return true; - else if (X.Kind > Y.Kind) - return false; + // If the name is a simple identifier (by far the common case), or a + // zero-argument selector, just return a reference to that identifier. + if (IdentifierInfo *Id = Name.getAsIdentifierInfo()) + return Id->getName(); + if (Name.isObjCZeroArgSelector()) + if (IdentifierInfo *Id + = Name.getObjCSelector().getIdentifierInfoForSlot(0)) + return Id->getName(); + + Saved = Name.getAsString(); + return Saved; + } + + bool operator()(const Result &X, const Result &Y) const { + std::string XSaved, YSaved; + llvm::StringRef XStr = getOrderedName(X, XSaved); + llvm::StringRef YStr = getOrderedName(Y, YSaved); + int cmp = XStr.compare_lower(YStr); + if (cmp) + return cmp < 0; // Non-hidden names precede hidden names. if (X.Hidden != Y.Hidden) @@ -1376,35 +1875,17 @@ namespace { if (X.StartsNestedNameSpecifier != Y.StartsNestedNameSpecifier) return !X.StartsNestedNameSpecifier; - // Ordering depends on the kind of result. - switch (X.Kind) { - case Result::RK_Declaration: - // Order based on the declaration names. - return isEarlierDeclarationName(X.Declaration->getDeclName(), - Y.Declaration->getDeclName()); - - case Result::RK_Macro: - return X.Macro->getName().compare_lower(Y.Macro->getName()) < 0; - - case Result::RK_Keyword: - case Result::RK_Pattern: - llvm_unreachable("Result kinds handled above"); - break; - } - - // Silence GCC warning. return false; } }; } -static void AddMacroResults(Preprocessor &PP, unsigned Rank, - ResultBuilder &Results) { +static void AddMacroResults(Preprocessor &PP, ResultBuilder &Results) { Results.EnterNewScope(); for (Preprocessor::macro_iterator M = PP.macro_begin(), MEnd = PP.macro_end(); M != MEnd; ++M) - Results.MaybeAddResult(CodeCompleteConsumer::Result(M->first, Rank)); + Results.AddResult(M->first); Results.ExitScope(); } @@ -1412,7 +1893,6 @@ static void HandleCodeCompleteResults(Sema *S, CodeCompleteConsumer *CodeCompleter, CodeCompleteConsumer::Result *Results, unsigned NumResults) { - // Sort the results by rank/kind/etc. std::stable_sort(Results, Results + NumResults, SortCodeCompleteResult()); if (CodeCompleter) @@ -1422,26 +1902,42 @@ static void HandleCodeCompleteResults(Sema *S, Results[I].Destroy(); } -void Sema::CodeCompleteOrdinaryName(Scope *S) { +void Sema::CodeCompleteOrdinaryName(Scope *S, + CodeCompletionContext CompletionContext) { typedef CodeCompleteConsumer::Result Result; - ResultBuilder Results(*this, &ResultBuilder::IsOrdinaryName); - unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), - 0, CurContext, Results); + ResultBuilder Results(*this); - 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)); + // Determine how to filter results, e.g., so that the names of + // values (functions, enumerators, function templates, etc.) are + // only allowed where we can have an expression. + switch (CompletionContext) { + case CCC_Namespace: + case CCC_Class: + case CCC_ObjCInterface: + case CCC_ObjCImplementation: + case CCC_ObjCInstanceVariableList: + case CCC_Template: + case CCC_MemberTemplate: + Results.setFilter(&ResultBuilder::IsOrdinaryNonValueName); + break; + + case CCC_Expression: + case CCC_Statement: + case CCC_ForInit: + case CCC_Condition: + Results.setFilter(&ResultBuilder::IsOrdinaryName); + break; } + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer); + + Results.EnterNewScope(); + AddOrdinaryNameResults(CompletionContext, S, *this, Results); Results.ExitScope(); if (CodeCompleter->includeMacros()) - AddMacroResults(PP, NextRank, Results); + AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -1513,13 +2009,12 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, } ResultBuilder Results(*this, &ResultBuilder::IsMember); - unsigned NextRank = 0; - Results.EnterNewScope(); if (const RecordType *Record = BaseType->getAs<RecordType>()) { // Access to a C/C++ class, struct, or union. - NextRank = CollectMemberLookupResults(Record->getDecl(), NextRank, - Record->getDecl(), Results); + Results.allowNestedNameSpecifiers(); + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(Record->getDecl(), LookupMemberName, Consumer); if (getLangOptions().CPlusPlus) { if (!Results.empty()) { @@ -1536,16 +2031,8 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, } if (IsDependent) - Results.MaybeAddResult(Result("template", NextRank++)); + Results.AddResult(Result("template")); } - - // 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); } } else if (!IsArrow && BaseType->getAsObjCInterfacePointerType()) { // Objective-C property reference. @@ -1561,9 +2048,6 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, E = ObjCPtr->qual_end(); I != E; ++I) AddObjCProperties(*I, true, CurContext, Results); - - // FIXME: We could (should?) also look for "implicit" properties, identified - // only by the presence of nullary and unary selectors. } else if ((IsArrow && BaseType->isObjCObjectPointerType()) || (!IsArrow && BaseType->isObjCInterfaceType())) { // Objective-C instance variable access. @@ -1575,11 +2059,10 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, Class = BaseType->getAs<ObjCInterfaceType>()->getDecl(); // Add all ivars from this class and its superclasses. - for (; Class; Class = Class->getSuperClass()) { - for (ObjCInterfaceDecl::ivar_iterator IVar = Class->ivar_begin(), - IVarEnd = Class->ivar_end(); - IVar != IVarEnd; ++IVar) - Results.MaybeAddResult(Result(*IVar, 0), CurContext); + if (Class) { + CodeCompletionDeclConsumer Consumer(Results, CurContext); + Results.setFilter(&ResultBuilder::IsObjCIvar); + LookupVisibleDecls(Class, LookupMemberName, Consumer); } } @@ -1589,7 +2072,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, // Add macros if (CodeCompleter->includeMacros()) - AddMacroResults(PP, NextRank, Results); + AddMacroResults(PP, Results); // Hand off the results found for code completion. HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); @@ -1621,19 +2104,12 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { } ResultBuilder Results(*this, Filter); - unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), - 0, CurContext, Results); - - if (getLangOptions().CPlusPlus) { - // We could have the start of a nested-name-specifier. Add those - // results as well. - Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); - NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), - NextRank, CurContext, Results); - } + Results.allowNestedNameSpecifiers(); + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(S, LookupTagName, Consumer); if (CodeCompleter->includeMacros()) - AddMacroResults(PP, NextRank, Results); + AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -1707,12 +2183,13 @@ void Sema::CodeCompleteCase(Scope *S) { if (EnumeratorsSeen.count(*E)) continue; - Results.MaybeAddResult(CodeCompleteConsumer::Result(*E, 0, Qualifier)); + Results.AddResult(CodeCompleteConsumer::Result(*E, Qualifier), + CurContext, 0, false); } Results.ExitScope(); if (CodeCompleter->includeMacros()) - AddMacroResults(PP, 1, Results); + AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -1746,7 +2223,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, // Ignore type-dependent call expressions entirely. if (Fn->isTypeDependent() || Expr::hasAnyTypeDependentArguments(Args, NumArgs)) { - CodeCompleteOrdinaryName(S); + CodeCompleteOrdinaryName(S, CCC_Expression); return; } @@ -1784,7 +2261,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, } if (Results.empty()) - CodeCompleteOrdinaryName(S); + CodeCompleteOrdinaryName(S, CCC_Expression); else CodeCompleter->ProcessOverloadCandidates(*this, NumArgs, Results.data(), Results.size()); @@ -1805,16 +2282,17 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, return; ResultBuilder Results(*this); - unsigned NextRank = CollectMemberLookupResults(Ctx, 0, Ctx, Results); + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer); // The "template" keyword can follow "::" in the grammar, but only // put it into the grammar if the nested-name-specifier is dependent. NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep(); if (!Results.empty() && NNS->isDependent()) - Results.MaybeAddResult(CodeCompleteConsumer::Result("template", NextRank)); + Results.AddResult("template"); if (CodeCompleter->includeMacros()) - AddMacroResults(PP, NextRank + 1, Results); + AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -1827,16 +2305,16 @@ void Sema::CodeCompleteUsing(Scope *S) { // If we aren't in class scope, we could see the "namespace" keyword. if (!S->isClassScope()) - Results.MaybeAddResult(CodeCompleteConsumer::Result("namespace", 0)); + Results.AddResult(CodeCompleteConsumer::Result("namespace")); // After "using", we can see anything that would start a // nested-name-specifier. - unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), - 0, CurContext, Results); + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer); Results.ExitScope(); if (CodeCompleter->includeMacros()) - AddMacroResults(PP, NextRank, Results); + AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -1848,11 +2326,11 @@ void Sema::CodeCompleteUsingDirective(Scope *S) { // alias. ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); Results.EnterNewScope(); - unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), - 0, CurContext, Results); + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer); Results.ExitScope(); if (CodeCompleter->includeMacros()) - AddMacroResults(PP, NextRank, Results); + AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -1882,13 +2360,13 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) { for (std::map<NamespaceDecl *, NamespaceDecl *>::iterator NS = OrigToLatest.begin(), NSEnd = OrigToLatest.end(); NS != NSEnd; ++NS) - Results.MaybeAddResult(CodeCompleteConsumer::Result(NS->second, 0), - CurContext); + Results.AddResult(CodeCompleteConsumer::Result(NS->second, 0), + CurContext, 0, false); Results.ExitScope(); } if (CodeCompleter->includeMacros()) - AddMacroResults(PP, 1, Results); + AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -1898,10 +2376,10 @@ void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) { // After "namespace", we expect to see a namespace or alias. ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); - unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), - 0, CurContext, Results); + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer); if (CodeCompleter->includeMacros()) - AddMacroResults(PP, NextRank, Results); + AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -1916,155 +2394,168 @@ void Sema::CodeCompleteOperatorName(Scope *S) { // Add the names of overloadable operators. #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ if (std::strcmp(Spelling, "?")) \ - Results.MaybeAddResult(Result(Spelling, 0)); + Results.AddResult(Result(Spelling)); #include "clang/Basic/OperatorKinds.def" // Add any type names visible from the current scope - unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), - 0, CurContext, Results); + Results.allowNestedNameSpecifiers(); + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer); // Add any type specifiers - AddTypeSpecifierResults(getLangOptions(), 0, Results); - - // Add any nested-name-specifiers - Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); - NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), - NextRank + 1, CurContext, Results); + AddTypeSpecifierResults(getLangOptions(), Results); Results.ExitScope(); if (CodeCompleter->includeMacros()) - AddMacroResults(PP, NextRank, Results); + AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } -void Sema::CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl, - bool InInterface) { +// Macro that expands to @Keyword or Keyword, depending on whether NeedAt is +// true or false. +#define OBJC_AT_KEYWORD_NAME(NeedAt,Keyword) NeedAt? "@" #Keyword : #Keyword +static void AddObjCImplementationResults(const LangOptions &LangOpts, + ResultBuilder &Results, + bool NeedAt) { 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 ; + // Since we have an implementation, we can end it. + Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,end))); + + CodeCompletionString *Pattern = 0; + if (LangOpts.ObjC2) { + // @dynamic 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->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,dynamic)); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("property"); + Results.AddResult(Result(Pattern)); + + // @synthesize Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("interface"); - Pattern->AddTextChunk(" "); - Pattern->AddPlaceholderChunk("class"); - Results.MaybeAddResult(Result(Pattern, 0)); + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,synthesize)); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("property"); + Results.AddResult(Result(Pattern)); + } +} - // @protocol name - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("protocol"); - Pattern->AddTextChunk(" "); - Pattern->AddPlaceholderChunk("protocol"); - Results.MaybeAddResult(Result(Pattern, 0)); +static void AddObjCInterfaceResults(const LangOptions &LangOpts, + ResultBuilder &Results, + bool NeedAt) { + typedef CodeCompleteConsumer::Result Result; + + // Since we have an interface or protocol, we can end it. + Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,end))); + + if (LangOpts.ObjC2) { + // @property + Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,property))); + + // @required + Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,required))); + + // @optional + Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,optional))); + } +} - // @implementation name - Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("implementation"); - Pattern->AddTextChunk(" "); - Pattern->AddPlaceholderChunk("class"); - Results.MaybeAddResult(Result(Pattern, 0)); +static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) { + typedef CodeCompleteConsumer::Result Result; + CodeCompletionString *Pattern = 0; + + // @class name ; + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,class)); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("identifier"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + + // @interface name + // FIXME: Could introduce the whole pattern, including superclasses and + // such. + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,interface)); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("class"); + Results.AddResult(Result(Pattern)); + + // @protocol name + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,protocol)); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("protocol"); + Results.AddResult(Result(Pattern)); + + // @implementation name + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,implementation)); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("class"); + Results.AddResult(Result(Pattern)); + + // @compatibility_alias name + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,compatibility_alias)); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("alias"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("class"); + Results.AddResult(Result(Pattern)); +} - // @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)); - } +void Sema::CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl, + bool InInterface) { + typedef CodeCompleteConsumer::Result Result; + ResultBuilder Results(*this); + Results.EnterNewScope(); + if (ObjCImpDecl) + AddObjCImplementationResults(getLangOptions(), Results, false); + else if (InInterface) + AddObjCInterfaceResults(getLangOptions(), Results, false); + else + AddObjCTopLevelResults(Results, false); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } -static void AddObjCExpressionResults(unsigned Rank, ResultBuilder &Results) { +static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) { typedef CodeCompleteConsumer::Result Result; CodeCompletionString *Pattern = 0; // @encode ( type-name ) Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("encode"); + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,encode)); Pattern->AddChunk(CodeCompletionString::CK_LeftParen); Pattern->AddPlaceholderChunk("type-name"); Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.MaybeAddResult(Result(Pattern, Rank)); + Results.AddResult(Result(Pattern)); // @protocol ( protocol-name ) Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("protocol"); + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,protocol)); Pattern->AddChunk(CodeCompletionString::CK_LeftParen); Pattern->AddPlaceholderChunk("protocol-name"); Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.MaybeAddResult(Result(Pattern, Rank)); + Results.AddResult(Result(Pattern)); // @selector ( selector ) Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("selector"); + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,selector)); Pattern->AddChunk(CodeCompletionString::CK_LeftParen); Pattern->AddPlaceholderChunk("selector"); Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.MaybeAddResult(Result(Pattern, Rank)); + Results.AddResult(Result(Pattern)); } -void Sema::CodeCompleteObjCAtStatement(Scope *S) { +static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) { 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->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,try)); Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); Pattern->AddPlaceholderChunk("statements"); Pattern->AddChunk(CodeCompletionString::CK_RightBrace); @@ -2079,29 +2570,53 @@ void Sema::CodeCompleteObjCAtStatement(Scope *S) { Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); Pattern->AddPlaceholderChunk("statements"); Pattern->AddChunk(CodeCompletionString::CK_RightBrace); - Results.MaybeAddResult(Result(Pattern, 0)); - + Results.AddResult(Result(Pattern)); + // @throw Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("throw"); - Pattern->AddTextChunk(" "); + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,throw)); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddPlaceholderChunk("expression"); - Pattern->AddTextChunk(";"); - Results.MaybeAddResult(Result(Pattern, 0)); // FIXME: add ';' chunk - + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Pattern)); + // @synchronized ( expression ) { statements } Pattern = new CodeCompletionString; - Pattern->AddTypedTextChunk("synchronized"); - Pattern->AddTextChunk(" "); + Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,synchronized)); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); 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 + Results.AddResult(Result(Pattern)); +} + +static void AddObjCVisibilityResults(const LangOptions &LangOpts, + ResultBuilder &Results, + bool NeedAt) { + typedef CodeCompleteConsumer::Result Result; + Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,private))); + Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,protected))); + Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,public))); + if (LangOpts.ObjC2) + Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,package))); +} - AddObjCExpressionResults(0, Results); +void Sema::CodeCompleteObjCAtVisibility(Scope *S) { + ResultBuilder Results(*this); + Results.EnterNewScope(); + AddObjCVisibilityResults(getLangOptions(), Results, false); + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} + +void Sema::CodeCompleteObjCAtStatement(Scope *S) { + ResultBuilder Results(*this); + Results.EnterNewScope(); + AddObjCStatementResults(Results, false); + AddObjCExpressionResults(Results, false); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -2109,7 +2624,7 @@ void Sema::CodeCompleteObjCAtStatement(Scope *S) { void Sema::CodeCompleteObjCAtExpression(Scope *S) { ResultBuilder Results(*this); Results.EnterNewScope(); - AddObjCExpressionResults(0, Results); + AddObjCExpressionResults(Results, false); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -2154,30 +2669,30 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) { ResultBuilder Results(*this); Results.EnterNewScope(); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_readonly)) - Results.MaybeAddResult(CodeCompleteConsumer::Result("readonly", 0)); + Results.AddResult(CodeCompleteConsumer::Result("readonly")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_assign)) - Results.MaybeAddResult(CodeCompleteConsumer::Result("assign", 0)); + Results.AddResult(CodeCompleteConsumer::Result("assign")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_readwrite)) - Results.MaybeAddResult(CodeCompleteConsumer::Result("readwrite", 0)); + Results.AddResult(CodeCompleteConsumer::Result("readwrite")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_retain)) - Results.MaybeAddResult(CodeCompleteConsumer::Result("retain", 0)); + Results.AddResult(CodeCompleteConsumer::Result("retain")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_copy)) - Results.MaybeAddResult(CodeCompleteConsumer::Result("copy", 0)); + Results.AddResult(CodeCompleteConsumer::Result("copy")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_nonatomic)) - Results.MaybeAddResult(CodeCompleteConsumer::Result("nonatomic", 0)); + Results.AddResult(CodeCompleteConsumer::Result("nonatomic")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_setter)) { CodeCompletionString *Setter = new CodeCompletionString; Setter->AddTypedTextChunk("setter"); Setter->AddTextChunk(" = "); Setter->AddPlaceholderChunk("method"); - Results.MaybeAddResult(CodeCompleteConsumer::Result(Setter, 0)); + Results.AddResult(CodeCompleteConsumer::Result(Setter)); } if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_getter)) { CodeCompletionString *Getter = new CodeCompletionString; Getter->AddTypedTextChunk("getter"); Getter->AddTextChunk(" = "); Getter->AddPlaceholderChunk("method"); - Results.MaybeAddResult(CodeCompleteConsumer::Result(Getter, 0)); + Results.AddResult(CodeCompleteConsumer::Result(Getter)); } Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); @@ -2522,7 +3037,7 @@ static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext, // Record any protocols we find. if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(*D)) if (!OnlyForwardDeclarations || Proto->isForwardDecl()) - Results.MaybeAddResult(Result(Proto, 0), CurContext); + Results.AddResult(Result(Proto, 0), CurContext, 0, false); // Record any forward-declared protocols we find. if (ObjCForwardProtocolDecl *Forward @@ -2532,7 +3047,7 @@ static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext, PEnd = Forward->protocol_end(); P != PEnd; ++P) if (!OnlyForwardDeclarations || (*P)->isForwardDecl()) - Results.MaybeAddResult(Result(*P, 0), CurContext); + Results.AddResult(Result(*P, 0), CurContext, 0, false); } } } @@ -2583,7 +3098,7 @@ static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext, if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(*D)) if ((!OnlyForwardDeclarations || Class->isForwardDecl()) && (!OnlyUnimplemented || !Class->getImplementation())) - Results.MaybeAddResult(Result(Class, 0), CurContext); + Results.AddResult(Result(Class, 0), CurContext, 0, false); // Record any forward-declared interfaces we find. if (ObjCClassDecl *Forward = dyn_cast<ObjCClassDecl>(*D)) { @@ -2591,7 +3106,8 @@ static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext, C != CEnd; ++C) if ((!OnlyForwardDeclarations || C->getInterface()->isForwardDecl()) && (!OnlyUnimplemented || !C->getInterface()->getImplementation())) - Results.MaybeAddResult(Result(C->getInterface(), 0), CurContext); + Results.AddResult(Result(C->getInterface(), 0), CurContext, + 0, false); } } } @@ -2662,7 +3178,7 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S, D != DEnd; ++D) if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(*D)) if (CategoryNames.insert(Category->getIdentifier())) - Results.MaybeAddResult(Result(Category, 0), CurContext); + Results.AddResult(Result(Category, 0), CurContext, 0, false); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); @@ -2694,7 +3210,7 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S, Category = Category->getNextClassCategory()) if ((!IgnoreImplemented || !Category->getImplementation()) && CategoryNames.insert(Category->getIdentifier())) - Results.MaybeAddResult(Result(Category, 0), CurContext); + Results.AddResult(Result(Category, 0), CurContext, 0, false); Class = Class->getSuperClass(); IgnoreImplemented = false; @@ -2768,7 +3284,7 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, for (ObjCInterfaceDecl::ivar_iterator IVar = Class->ivar_begin(), IVarEnd = Class->ivar_end(); IVar != IVarEnd; ++IVar) - Results.MaybeAddResult(Result(*IVar, 0), CurContext); + Results.AddResult(Result(*IVar, 0), CurContext, 0, false); } Results.ExitScope(); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 2253f09..0ccb8f2 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -14,6 +14,7 @@ #include "Sema.h" #include "SemaInit.h" #include "Lookup.h" +#include "clang/Analysis/PathSensitive/AnalysisContext.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -137,6 +138,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, NamedDecl *IIDecl = 0; switch (Result.getResultKind()) { case LookupResult::NotFound: + case LookupResult::NotFoundInCurrentInstantiation: case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: return 0; @@ -281,6 +283,9 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, else llvm_unreachable("could not have corrected a typo here"); + Diag(Result->getLocation(), diag::note_previous_decl) + << Result->getDeclName(); + SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS); return true; } @@ -555,11 +560,38 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { /// getObjCInterfaceDecl - Look up a for a class declaration in the scope. /// return 0 if one not found. -ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) { +/// +/// \param Id the name of the Objective-C class we're looking for. If +/// typo-correction fixes this name, the Id will be updated +/// to the fixed name. +/// +/// \param RecoverLoc if provided, this routine will attempt to +/// recover from a typo in the name of an existing Objective-C class +/// and, if successful, will return the lookup that results from +/// typo-correction. +ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id, + SourceLocation RecoverLoc) { // The third "scope" argument is 0 since we aren't enabling lazy built-in // creation from this context. NamedDecl *IDecl = LookupSingleName(TUScope, Id, LookupOrdinaryName); + if (!IDecl && !RecoverLoc.isInvalid()) { + // Perform typo correction at the given location, but only if we + // find an Objective-C class name. + LookupResult R(*this, Id, RecoverLoc, LookupOrdinaryName); + if (CorrectTypo(R, TUScope, 0) && + (IDecl = R.getAsSingle<ObjCInterfaceDecl>())) { + Diag(RecoverLoc, diag::err_undef_interface_suggest) + << Id << IDecl->getDeclName() + << CodeModificationHint::CreateReplacement(RecoverLoc, + IDecl->getNameAsString()); + Diag(IDecl->getLocation(), diag::note_previous_decl) + << IDecl->getDeclName(); + + Id = IDecl->getIdentifier(); + } + } + return dyn_cast_or_null<ObjCInterfaceDecl>(IDecl); } @@ -773,13 +805,38 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) { if (getLangOptions().Microsoft) return; - // C++ [dcl.typedef]p2: - // In a given non-class scope, a typedef specifier can be used to - // redefine the name of any type declared in that scope to refer - // to the type to which it already refers. if (getLangOptions().CPlusPlus) { + // C++ [dcl.typedef]p2: + // In a given non-class scope, a typedef specifier can be used to + // redefine the name of any type declared in that scope to refer + // to the type to which it already refers. if (!isa<CXXRecordDecl>(CurContext)) return; + + // C++0x [dcl.typedef]p4: + // In a given class scope, a typedef specifier can be used to redefine + // any class-name declared in that scope that is not also a typedef-name + // to refer to the type to which it already refers. + // + // This wording came in via DR424, which was a correction to the + // wording in DR56, which accidentally banned code like: + // + // struct S { + // typedef struct A { } A; + // }; + // + // in the C++03 standard. We implement the C++0x semantics, which + // allow the above but disallow + // + // struct S { + // typedef int I; + // typedef int I; + // }; + // + // since that was the intent of DR56. + if (!isa<TypedefDecl >(Old)) + return; + Diag(New->getLocation(), diag::err_redefinition) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); @@ -1250,34 +1307,61 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { New->setPreviousDeclaration(Old); } -/// CheckFallThrough - Check that we don't fall off the end of a -/// Statement that should return a value. -/// -/// \returns AlwaysFallThrough iff we always fall off the end of the statement, -/// MaybeFallThrough iff we might or might not fall off the end, -/// NeverFallThroughOrReturn iff we never fall off the end of the statement or -/// return. We assume NeverFallThrough iff we never fall off the end of the -/// statement but we may return. We assume that functions not marked noreturn -/// will return. -Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { - // FIXME: Eventually share this CFG object when we have other warnings based - // of the CFG. This can be done using AnalysisContext. - llvm::OwningPtr<CFG> cfg (CFG::buildCFG(Root, &Context)); +static void MarkLive(CFGBlock *e, llvm::BitVector &live) { + std::queue<CFGBlock*> workq; + // Prep work queue + workq.push(e); + // Solve + while (!workq.empty()) { + CFGBlock *item = workq.front(); + workq.pop(); + live.set(item->getBlockID()); + for (CFGBlock::succ_iterator I=item->succ_begin(), + E=item->succ_end(); + I != E; + ++I) { + if ((*I) && !live[(*I)->getBlockID()]) { + live.set((*I)->getBlockID()); + workq.push(*I); + } + } + } +} - // FIXME: They should never return 0, fix that, delete this code. - if (cfg == 0) - // FIXME: This should be NeverFallThrough - return NeverFallThroughOrReturn; - // The CFG leaves in dead things, and we don't want to dead code paths to - // confuse us, so we mark all live things first. +static SourceLocation MarkLiveTop(CFGBlock *e, llvm::BitVector &live, + SourceManager &SM) { std::queue<CFGBlock*> workq; - llvm::BitVector live(cfg->getNumBlockIDs()); // Prep work queue - workq.push(&cfg->getEntry()); + workq.push(e); + SourceLocation top; + if (!e->empty()) + top = e[0][0].getStmt()->getLocStart(); + bool FromMainFile = false; + bool FromSystemHeader = false; + bool TopValid = false; + if (top.isValid()) { + FromMainFile = SM.isFromMainFile(top); + FromSystemHeader = SM.isInSystemHeader(top); + TopValid = true; + } // Solve while (!workq.empty()) { CFGBlock *item = workq.front(); workq.pop(); + SourceLocation c; + if (!item->empty()) + c = item[0][0].getStmt()->getLocStart(); + else if (item->getTerminator()) + c = item->getTerminator()->getLocStart(); + if (c.isValid() + && (!TopValid + || (SM.isFromMainFile(c) && !FromMainFile) + || (FromSystemHeader && !SM.isInSystemHeader(c)) + || SM.isBeforeInTranslationUnit(c, top))) { + top = c; + FromMainFile = SM.isFromMainFile(top); + FromSystemHeader = SM.isInSystemHeader(top); + } live.set(item->getBlockID()); for (CFGBlock::succ_iterator I=item->succ_begin(), E=item->succ_end(); @@ -1289,6 +1373,92 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { } } } + return top; +} + +namespace { +class LineCmp { + SourceManager &SM; +public: + LineCmp(SourceManager &sm) : SM(sm) { + } + bool operator () (SourceLocation l1, SourceLocation l2) { + return l1 < l2; + } +}; +} + +/// CheckUnreachable - Check for unreachable code. +void Sema::CheckUnreachable(AnalysisContext &AC) { + // We avoid checking when there are errors, as the CFG won't faithfully match + // the user's code. + if (getDiagnostics().hasErrorOccurred()) + return; + if (Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored) + return; + + CFG *cfg = AC.getCFG(); + if (cfg == 0) + return; + + llvm::BitVector live(cfg->getNumBlockIDs()); + // Mark all live things first. + MarkLive(&cfg->getEntry(), live); + + llvm::SmallVector<SourceLocation, 24> lines; + // First, give warnings for blocks with no predecessors, as they + // can't be part of a loop. + for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { + CFGBlock &b = **I; + if (!live[b.getBlockID()]) { + if (b.pred_begin() == b.pred_end()) { + if (!b.empty()) + lines.push_back(b[0].getStmt()->getLocStart()); + else if (b.getTerminator()) + lines.push_back(b.getTerminator()->getLocStart()); + // Avoid excessive errors by marking everything reachable from here + MarkLive(&b, live); + } + } + } + + // And then give warnings for the tops of loops. + for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { + CFGBlock &b = **I; + if (!live[b.getBlockID()]) + // Avoid excessive errors by marking everything reachable from here + lines.push_back(MarkLiveTop(&b, live, Context.getSourceManager())); + } + + std::sort(lines.begin(), lines.end(), LineCmp(Context.getSourceManager())); + for (llvm::SmallVector<SourceLocation, 24>::iterator I = lines.begin(), + E = lines.end(); + I != E; + ++I) + if (I->isValid()) + Diag(*I, diag::warn_unreachable); +} + +/// CheckFallThrough - Check that we don't fall off the end of a +/// Statement that should return a value. +/// +/// \returns AlwaysFallThrough iff we always fall off the end of the statement, +/// MaybeFallThrough iff we might or might not fall off the end, +/// NeverFallThroughOrReturn iff we never fall off the end of the statement or +/// return. We assume NeverFallThrough iff we never fall off the end of the +/// statement but we may return. We assume that functions not marked noreturn +/// will return. +Sema::ControlFlowKind Sema::CheckFallThrough(AnalysisContext &AC) { + CFG *cfg = AC.getCFG(); + if (cfg == 0) + // FIXME: This should be NeverFallThrough + return NeverFallThroughOrReturn; + + // The CFG leaves in dead things, and we don't want to dead code paths to + // confuse us, so we mark all live things first. + std::queue<CFGBlock*> workq; + llvm::BitVector live(cfg->getNumBlockIDs()); + MarkLive(&cfg->getEntry(), live); // Now we know what is live, we check the live precessors of the exit block // and look for fall through paths, being careful to ignore normal returns, @@ -1321,6 +1491,14 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { HasFakeEdge = true; continue; } + if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) { + if (AS->isMSAsm()) { + HasFakeEdge = true; + HasLiveReturn = true; + continue; + } + } + bool NoReturnEdge = false; if (CallExpr *C = dyn_cast<CallExpr>(S)) { Expr *CEE = C->getCallee()->IgnoreParenCasts(); @@ -1356,7 +1534,8 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { /// function that should return a value. Check that we don't fall off the end /// of a noreturn function. We assume that functions and blocks not marked /// noreturn will return. -void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) { +void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body, + AnalysisContext &AC) { // FIXME: Would be nice if we had a better way to control cascading errors, // but for now, avoid them. The problem is that when Parse sees: // int foo() { return a; } @@ -1394,7 +1573,7 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) { return; // FIXME: Function try block if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { - switch (CheckFallThrough(Body)) { + switch (CheckFallThrough(AC)) { case MaybeFallThrough: if (HasNoReturn) Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function); @@ -1421,7 +1600,8 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) { /// that should return a value. Check that we don't fall off the end of a /// noreturn block. We assume that functions and blocks not marked noreturn /// will return. -void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body) { +void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body, + AnalysisContext &AC) { // FIXME: Would be nice if we had a better way to control cascading errors, // but for now, avoid them. The problem is that when Parse sees: // int foo() { return a; } @@ -1447,7 +1627,7 @@ void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body) { return; // FIXME: Funtion try block if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { - switch (CheckFallThrough(Body)) { + switch (CheckFallThrough(AC)) { case MaybeFallThrough: if (HasNoReturn) Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr); @@ -1878,6 +2058,30 @@ DeclarationName Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) { Context.getCanonicalType(Ty)); } + case UnqualifiedId::IK_ConstructorTemplateId: { + // In well-formed code, we can only have a constructor + // template-id that refers to the current context, so go there + // to find the actual type being constructed. + CXXRecordDecl *CurClass = dyn_cast<CXXRecordDecl>(CurContext); + if (!CurClass || CurClass->getIdentifier() != Name.TemplateId->Name) + return DeclarationName(); + + // Determine the type of the class being constructed. + QualType CurClassType; + if (ClassTemplateDecl *ClassTemplate + = CurClass->getDescribedClassTemplate()) + CurClassType = ClassTemplate->getInjectedClassNameType(Context); + else + CurClassType = Context.getTypeDeclType(CurClass); + + // FIXME: Check two things: that the template-id names the same type as + // CurClassType, and that the template-id does not occur when the name + // was qualified. + + return Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(CurClassType)); + } + case UnqualifiedId::IK_DestructorName: { QualType Ty = GetTypeFromParser(Name.DestructorName); if (Ty.isNull()) @@ -3393,7 +3597,12 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, if (NewFD->isOverloadedOperator() && CheckOverloadedOperatorDeclaration(NewFD)) return NewFD->setInvalidDecl(); - + + // Extra checking for C++0x literal operators (C++0x [over.literal]). + if (NewFD->getLiteralIdentifier() && + CheckLiteralOperatorDeclaration(NewFD)) + return NewFD->setInvalidDecl(); + // In C++, check default arguments now that we have merged decls. Unless // the lexical context is the class, because in this case this is done // during delayed parsing anyway. @@ -3717,7 +3926,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { if (getLangOptions().CPlusPlus) { // Make sure we mark the destructor as used if necessary. QualType InitType = VDecl->getType(); - if (const ArrayType *Array = Context.getAsArrayType(InitType)) + while (const ArrayType *Array = Context.getAsArrayType(InitType)) InitType = Context.getBaseElementType(Array); if (InitType->isRecordType()) FinalizeVarWithDestructor(VDecl, InitType); @@ -4267,6 +4476,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, Decl *dcl = D.getAs<Decl>(); Stmt *Body = BodyArg.takeAs<Stmt>(); + AnalysisContext AC(dcl); FunctionDecl *FD = 0; FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(dcl); if (FunTmpl) @@ -4281,7 +4491,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, // Implements C++ [basic.start.main]p5 and C99 5.1.2.2.3. FD->setHasImplicitReturnZero(true); else - CheckFallThroughForFunctionDef(FD, Body); + CheckFallThroughForFunctionDef(FD, Body, AC); if (!FD->isInvalidDecl()) DiagnoseUnusedParameters(FD->param_begin(), FD->param_end()); @@ -4293,7 +4503,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, } else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) { assert(MD == getCurMethodDecl() && "Method parsing confused"); MD->setBody(Body); - CheckFallThroughForFunctionDef(MD, Body); + CheckFallThroughForFunctionDef(MD, Body, AC); MD->setEndLoc(Body->getLocEnd()); if (!MD->isInvalidDecl()) @@ -4351,6 +4561,8 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, if (!Body) return D; + CheckUnreachable(AC); + // Verify that that gotos and switch cases don't jump into scopes illegally. if (CurFunctionNeedsScopeChecking) DiagnoseInvalidJumps(Body); @@ -4657,8 +4869,18 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, if (Previous.isAmbiguous()) return DeclPtrTy(); - // A tag 'foo::bar' must already exist. if (Previous.empty()) { + // Name lookup did not find anything. However, if the + // nested-name-specifier refers to the current instantiation, + // and that current instantiation has any dependent base + // classes, we might find something at instantiation time: treat + // this as a dependent elaborated-type-specifier. + if (Previous.wasNotFoundInCurrentInstantiation()) { + IsDependent = true; + return DeclPtrTy(); + } + + // A tag 'foo::bar' must already exist. Diag(NameLoc, diag::err_not_tag_in_scope) << Name << SS.getRange(); Name = 0; Invalid = true; @@ -5054,6 +5276,29 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, DeclPtrTy TagD, "Broken injected-class-name"); } +// Traverses the class and any nested classes, making a note of any +// dynamic classes that have no key function so that we can mark all of +// their virtual member functions as "used" at the end of the translation +// unit. This ensures that all functions needed by the vtable will get +// instantiated/synthesized. +static void +RecordDynamicClassesWithNoKeyFunction(Sema &S, CXXRecordDecl *Record, + SourceLocation Loc) { + // We don't look at dependent or undefined classes. + if (Record->isDependentContext() || !Record->isDefinition()) + return; + + if (Record->isDynamicClass() && !S.Context.getKeyFunction(Record)) + S.ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Record, Loc)); + + for (DeclContext::decl_iterator D = Record->decls_begin(), + DEnd = Record->decls_end(); + D != DEnd; ++D) { + if (CXXRecordDecl *Nested = dyn_cast<CXXRecordDecl>(*D)) + RecordDynamicClassesWithNoKeyFunction(S, Nested, Loc); + } +} + void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD, SourceLocation RBraceLoc) { AdjustDeclIfTemplate(TagD); @@ -5066,6 +5311,10 @@ void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD, // Exit this scope of this tag's definition. PopDeclContext(); + if (isa<CXXRecordDecl>(Tag) && !Tag->getDeclContext()->isRecord()) + RecordDynamicClassesWithNoKeyFunction(*this, cast<CXXRecordDecl>(Tag), + RBraceLoc); + // Notify the consumer that we've defined a tag. Consumer.HandleTagDeclDefinition(Tag); } diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 094e5b5..1a12208 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "TargetAttributesSema.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" @@ -925,14 +926,19 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) { // If the target wants to validate the section specifier, make it happen. std::string Error = S.Context.Target.isValidSectionSpecifier(SE->getString()); - if (Error.empty()) { - D->addAttr(::new (S.Context) SectionAttr(SE->getString())); + if (!Error.empty()) { + S.Diag(SE->getLocStart(), diag::err_attribute_section_invalid_for_target) + << Error; return; } - S.Diag(SE->getLocStart(), diag::err_attribute_section_invalid_for_target) - << Error; - + // This attribute cannot be applied to local variables. + if (isa<VarDecl>(D) && cast<VarDecl>(D)->hasLocalStorage()) { + S.Diag(SE->getLocStart(), diag::err_attribute_section_local_variable); + return; + } + + D->addAttr(::new (S.Context) SectionAttr(SE->getString())); } static void HandleCDeclAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -1959,7 +1965,10 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, // Just ignore break; default: - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); + // Ask target about the attribute. + const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema(); + if (!TargetAttrs.ProcessDeclAttribute(scope, D, Attr, S)) + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); break; } } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 204d776..a81a04e 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -270,18 +270,18 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { ParmVarDecl *NewParam = New->getParamDecl(p); if (OldParam->hasDefaultArg() && NewParam->hasDefaultArg()) { - // FIXME: If the parameter doesn't have an identifier then the location - // points to the '=' which means that the fixit hint won't remove any - // extra spaces between the type and the '='. - SourceLocation Begin = NewParam->getLocation(); - if (NewParam->getIdentifier()) - Begin = PP.getLocForEndOfToken(Begin); - + // FIXME: If we knew where the '=' was, we could easily provide a fix-it + // hint here. Alternatively, we could walk the type-source information + // for NewParam to find the last source location in the type... but it + // isn't worth the effort right now. This is the kind of test case that + // is hard to get right: + + // int f(int); + // void g(int (*fp)(int) = f); + // void g(int (*fp)(int) = &f); Diag(NewParam->getLocation(), diag::err_param_default_argument_redefinition) - << NewParam->getDefaultArgRange() - << CodeModificationHint::CreateRemoval(SourceRange(Begin, - NewParam->getLocEnd())); + << NewParam->getDefaultArgRange(); // Look for the function declaration where the default argument was // actually written, which may be a declaration prior to Old. @@ -424,6 +424,8 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { /// the innermost class. bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *, const CXXScopeSpec *SS) { + assert(getLangOptions().CPlusPlus && "No class names in C!"); + CXXRecordDecl *CurDecl; if (SS && SS->isSet() && !SS->isInvalid()) { DeclContext *DC = computeDeclContext(*SS, true); @@ -1072,6 +1074,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, << MemberOrBase << true << R.getLookupName() << CodeModificationHint::CreateReplacement(R.getNameLoc(), R.getLookupName().getAsString()); + Diag(Member->getLocation(), diag::note_previous_decl) + << Member->getDeclName(); return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc, LParenLoc, RParenLoc); @@ -1089,7 +1093,14 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, << MemberOrBase << false << R.getLookupName() << CodeModificationHint::CreateReplacement(R.getNameLoc(), R.getLookupName().getAsString()); - + + const CXXBaseSpecifier *BaseSpec = DirectBaseSpec? DirectBaseSpec + : VirtualBaseSpec; + Diag(BaseSpec->getSourceRange().getBegin(), + diag::note_base_class_specified_here) + << BaseSpec->getType() + << BaseSpec->getSourceRange(); + TyD = Type; } } @@ -2054,7 +2065,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { if (!Record->isDependentType()) AddImplicitlyDeclaredMembersToClass(Record); - + if (Record->isInvalidDecl()) return; @@ -2734,18 +2745,23 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { << ClassType << ConvType; } - if (Conversion->getPreviousDeclaration()) { - const NamedDecl *ExpectedPrevDecl = Conversion->getPreviousDeclaration(); + if (Conversion->getPrimaryTemplate()) { + // ignore specializations + } else if (Conversion->getPreviousDeclaration()) { if (FunctionTemplateDecl *ConversionTemplate - = Conversion->getDescribedFunctionTemplate()) - ExpectedPrevDecl = ConversionTemplate->getPreviousDeclaration(); - if (ClassDecl->replaceConversion(ExpectedPrevDecl, Conversion)) + = Conversion->getDescribedFunctionTemplate()) { + if (ClassDecl->replaceConversion( + ConversionTemplate->getPreviousDeclaration(), + ConversionTemplate)) + return DeclPtrTy::make(ConversionTemplate); + } else if (ClassDecl->replaceConversion(Conversion->getPreviousDeclaration(), + Conversion)) return DeclPtrTy::make(Conversion); assert(Conversion->isInvalidDecl() && "Conversion should not get here."); } else if (FunctionTemplateDecl *ConversionTemplate = Conversion->getDescribedFunctionTemplate()) ClassDecl->addConversionFunction(ConversionTemplate); - else if (!Conversion->getPrimaryTemplate()) // ignore specializations + else ClassDecl->addConversionFunction(Conversion); return DeclPtrTy::make(Conversion); @@ -2986,6 +3002,7 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, break; case UnqualifiedId::IK_ConstructorName: + case UnqualifiedId::IK_ConstructorTemplateId: // C++0x inherited constructors. if (getLangOptions().CPlusPlus0x) break; @@ -4184,7 +4201,7 @@ Sema::PerformInitializationByConstructor(QualType ClassType, else Diag(Loc, diag::err_ovl_no_viable_function_in_init) << ClassType << Range; - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); return 0; case OR_Ambiguous: @@ -4192,7 +4209,7 @@ Sema::PerformInitializationByConstructor(QualType ClassType, Diag(Loc, diag::err_ovl_ambiguous_init) << InitEntity << Range; else Diag(Loc, diag::err_ovl_ambiguous_init) << ClassType << Range; - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, NumArgs); return 0; case OR_Deleted: @@ -4207,7 +4224,7 @@ Sema::PerformInitializationByConstructor(QualType ClassType, << Best->Function->isDeleted() << RD->getDeclName() << Range; } - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); return 0; } @@ -4373,8 +4390,10 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, = CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase); // Most paths end in a failed conversion. - if (ICS) - ICS->ConversionKind = ImplicitConversionSequence::BadConversion; + if (ICS) { + ICS->setBad(); + ICS->Bad.init(BadConversionSequence::no_conversion, Init, DeclType); + } // C++ [dcl.init.ref]p5: // A reference to type "cv1 T1" is initialized by an expression @@ -4412,7 +4431,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // has a type that is a derived class of the parameter type, // in which case the implicit conversion sequence is a // derived-to-base Conversion (13.3.3.1). - ICS->ConversionKind = ImplicitConversionSequence::StandardConversion; + ICS->setStandard(); ICS->Standard.First = ICK_Identity; ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; ICS->Standard.Third = ICK_Identity; @@ -4497,7 +4516,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // conversion or, if the conversion function returns an // entity of a type that is a derived class of the parameter // type, a derived-to-base Conversion. - ICS->ConversionKind = ImplicitConversionSequence::UserDefinedConversion; + ICS->setUserDefined(); ICS->UserDefined.Before = Best->Conversions[0].Standard; ICS->UserDefined.After = Best->FinalConversion; ICS->UserDefined.ConversionFunction = Best->Function; @@ -4523,15 +4542,16 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, case OR_Ambiguous: if (ICS) { + ICS->setAmbiguous(); for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); Cand != CandidateSet.end(); ++Cand) if (Cand->Viable) - ICS->ConversionFunctionSet.push_back(Cand->Function); + ICS->Ambiguous.addConversion(Cand->Function); break; } Diag(DeclLoc, diag::err_ref_init_ambiguous) << DeclType << Init->getType() << Init->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, &Init, 1); return true; case OR_No_Viable_Function: @@ -4600,7 +4620,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, if (InitLvalue != Expr::LV_Valid && T2->isRecordType() && RefRelationship >= Ref_Compatible_With_Added_Qualification) { if (ICS) { - ICS->ConversionKind = ImplicitConversionSequence::StandardConversion; + ICS->setStandard(); ICS->Standard.First = ICK_Identity; ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; ICS->Standard.Third = ICK_Identity; @@ -4672,30 +4692,27 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, /*InOverloadResolution=*/false); // Of course, that's still a reference binding. - if (ICS->ConversionKind == ImplicitConversionSequence::StandardConversion) { + if (ICS->isStandard()) { ICS->Standard.ReferenceBinding = true; ICS->Standard.RRefBinding = isRValRef; - } else if (ICS->ConversionKind == - ImplicitConversionSequence::UserDefinedConversion) { + } else if (ICS->isUserDefined()) { ICS->UserDefined.After.ReferenceBinding = true; ICS->UserDefined.After.RRefBinding = isRValRef; } - return ICS->ConversionKind == ImplicitConversionSequence::BadConversion; + return ICS->isBad(); } else { ImplicitConversionSequence Conversions; bool badConversion = PerformImplicitConversion(Init, T1, AA_Initializing, false, false, Conversions); if (badConversion) { - if ((Conversions.ConversionKind == - ImplicitConversionSequence::BadConversion) - && !Conversions.ConversionFunctionSet.empty()) { + if (Conversions.isAmbiguous()) { Diag(DeclLoc, diag::err_lvalue_to_rvalue_ambig_ref) << Init->getSourceRange(); - for (int j = Conversions.ConversionFunctionSet.size()-1; + for (int j = Conversions.Ambiguous.conversions().size()-1; j >= 0; j--) { - FunctionDecl *Func = Conversions.ConversionFunctionSet[j]; - Diag(Func->getLocation(), diag::err_ovl_candidate); + FunctionDecl *Func = Conversions.Ambiguous.conversions()[j]; + NoteOverloadCandidate(Func); } } else { @@ -4993,6 +5010,88 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { return false; } +/// CheckLiteralOperatorDeclaration - Check whether the declaration +/// of this literal operator function is well-formed. If so, returns +/// false; otherwise, emits appropriate diagnostics and returns true. +bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { + DeclContext *DC = FnDecl->getDeclContext(); + Decl::Kind Kind = DC->getDeclKind(); + if (Kind != Decl::TranslationUnit && Kind != Decl::Namespace && + Kind != Decl::LinkageSpec) { + Diag(FnDecl->getLocation(), diag::err_literal_operator_outside_namespace) + << FnDecl->getDeclName(); + return true; + } + + bool Valid = false; + + // FIXME: Check for the one valid template signature + // template <char...> type operator "" name(); + + if (FunctionDecl::param_iterator Param = FnDecl->param_begin()) { + // Check the first parameter + QualType T = (*Param)->getType(); + + // unsigned long long int and long double are allowed, but only + // alone. + // We also allow any character type; their omission seems to be a bug + // in n3000 + if (Context.hasSameType(T, Context.UnsignedLongLongTy) || + Context.hasSameType(T, Context.LongDoubleTy) || + Context.hasSameType(T, Context.CharTy) || + Context.hasSameType(T, Context.WCharTy) || + Context.hasSameType(T, Context.Char16Ty) || + Context.hasSameType(T, Context.Char32Ty)) { + if (++Param == FnDecl->param_end()) + Valid = true; + goto FinishedParams; + } + + // Otherwise it must be a pointer to const; let's strip those. + const PointerType *PT = T->getAs<PointerType>(); + if (!PT) + goto FinishedParams; + T = PT->getPointeeType(); + if (!T.isConstQualified()) + goto FinishedParams; + T = T.getUnqualifiedType(); + + // Move on to the second parameter; + ++Param; + + // If there is no second parameter, the first must be a const char * + if (Param == FnDecl->param_end()) { + if (Context.hasSameType(T, Context.CharTy)) + Valid = true; + goto FinishedParams; + } + + // const char *, const wchar_t*, const char16_t*, and const char32_t* + // are allowed as the first parameter to a two-parameter function + if (!(Context.hasSameType(T, Context.CharTy) || + Context.hasSameType(T, Context.WCharTy) || + Context.hasSameType(T, Context.Char16Ty) || + Context.hasSameType(T, Context.Char32Ty))) + goto FinishedParams; + + // The second and final parameter must be an std::size_t + T = (*Param)->getType().getUnqualifiedType(); + if (Context.hasSameType(T, Context.getSizeType()) && + ++Param == FnDecl->param_end()) + Valid = true; + } + + // FIXME: This diagnostic is absolutely terrible. +FinishedParams: + if (!Valid) { + Diag(FnDecl->getLocation(), diag::err_literal_operator_params) + << FnDecl->getDeclName(); + return true; + } + + return false; +} + /// ActOnStartLinkageSpecification - Parsed the beginning of a C++ /// linkage specification, including the language and (if present) /// the '{'. ExternLoc is the location of the 'extern', LangLoc is @@ -5693,55 +5792,56 @@ void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc, 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)); + // Ignore declarations that are not definitions. + if (!MD->isThisDeclarationADefinition()) 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)) + if (isa<CXXConstructorDecl>(MD)) { + switch (MD->getParent()->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + // Classes that aren't instantiations of templates don't need their + // virtual methods marked until we see the definition of the key + // function. + return; + + case TSK_ImplicitInstantiation: + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + // This is a constructor of a class template; mark all of the virtual + // members as referenced to ensure that they get instantiatied. + break; + } + } else if (!MD->isOutOfLine()) { + // Consider only out-of-line definitions of member functions. When we see + // an inline definition, it's too early to compute the key function. + return; + } else if (const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD)) { + // If this is not the key function, we don't need to mark virtual members. + if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) return; - } else if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) { - // We don't have the right key function. + } else { + // The class has no key function, so we've already noted that we need to + // mark the virtual members of this class. return; } - // Mark the members as referenced. - MarkVirtualMembersReferenced(Loc, RD); - ClassesWithUnmarkedVirtualMembers.erase(RD); + // We will need to mark all of the virtual members as referenced to build the + // vtable. + ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(RD, Loc)); } 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; + while (!ClassesWithUnmarkedVirtualMembers.empty()) { + CXXRecordDecl *RD = ClassesWithUnmarkedVirtualMembers.back().first; + SourceLocation Loc = ClassesWithUnmarkedVirtualMembers.back().second; + ClassesWithUnmarkedVirtualMembers.pop_back(); MarkVirtualMembersReferenced(Loc, RD); } - ClassesWithUnmarkedVirtualMembers.clear(); return true; } diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index beadb58..f2fc1f4 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "Lookup.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/AST/Expr.h" #include "clang/AST/ASTContext.h" @@ -133,6 +134,19 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, if (SuperName) { // Check if a different kind of symbol declared in this scope. PrevDecl = LookupSingleName(TUScope, SuperName, LookupOrdinaryName); + + if (!PrevDecl) { + // Try to correct for a typo in the superclass name. + LookupResult R(*this, SuperName, SuperLoc, LookupOrdinaryName); + if (CorrectTypo(R, TUScope, 0) && + (PrevDecl = R.getAsSingle<ObjCInterfaceDecl>())) { + Diag(SuperLoc, diag::err_undef_superclass_suggest) + << SuperName << ClassName << PrevDecl->getDeclName(); + Diag(PrevDecl->getLocation(), diag::note_previous_decl) + << PrevDecl->getDeclName(); + } + } + if (PrevDecl == IDecl) { Diag(SuperLoc, diag::err_recursive_superclass) << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); @@ -317,6 +331,18 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, for (unsigned i = 0; i != NumProtocols; ++i) { ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first); if (!PDecl) { + LookupResult R(*this, ProtocolId[i].first, ProtocolId[i].second, + LookupObjCProtocolName); + if (CorrectTypo(R, TUScope, 0) && + (PDecl = R.getAsSingle<ObjCProtocolDecl>())) { + Diag(ProtocolId[i].second, diag::err_undeclared_protocol_suggest) + << ProtocolId[i].first << R.getLookupName(); + Diag(PDecl->getLocation(), diag::note_previous_decl) + << PDecl->getDeclName(); + } + } + + if (!PDecl) { Diag(ProtocolId[i].second, diag::err_undeclared_protocol) << ProtocolId[i].first; continue; @@ -568,7 +594,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, // FIXME: PushOnScopeChains? CurContext->addDecl(CDecl); - ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName); + ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc); /// Check that class of this category is already completely declared. if (!IDecl || IDecl->isForwardDecl()) { CDecl->setInvalidDecl(); @@ -616,7 +642,7 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation( SourceLocation AtCatImplLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *CatName, SourceLocation CatLoc) { - ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName); + ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc); ObjCCategoryDecl *CatIDecl = 0; if (IDecl) { CatIDecl = IDecl->FindCategoryDeclaration(CatName); @@ -667,13 +693,33 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation( if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) { Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName; Diag(PrevDecl->getLocation(), diag::note_previous_definition); - } else { - // Is there an interface declaration of this class; if not, warn! - IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); - if (!IDecl || IDecl->isForwardDecl()) { + } else if ((IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl))) { + // If this is a forward declaration of an interface, warn. + if (IDecl->isForwardDecl()) { Diag(ClassLoc, diag::warn_undef_interface) << ClassName; IDecl = 0; } + } else { + // We did not find anything with the name ClassName; try to correct for + // typos in the class name. + LookupResult R(*this, ClassName, ClassLoc, LookupOrdinaryName); + if (CorrectTypo(R, TUScope, 0) && + (IDecl = R.getAsSingle<ObjCInterfaceDecl>())) { + // Suggest the (potentially) correct interface name. However, put the + // fix-it hint itself in a separate note, since changing the name in + // the warning would make the fix-it change semantics.However, don't + // provide a code-modification hint or use the typo name for recovery, + // because this is just a warning. The program may actually be correct. + Diag(ClassLoc, diag::warn_undef_interface_suggest) + << ClassName << R.getLookupName(); + Diag(IDecl->getLocation(), diag::note_previous_decl) + << R.getLookupName() + << CodeModificationHint::CreateReplacement(ClassLoc, + R.getLookupName().getAsString()); + IDecl = 0; + } else { + Diag(ClassLoc, diag::warn_undef_interface) << ClassName; + } } // Check that super class name is valid class name @@ -1437,8 +1483,11 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, property->getLocation()); if (SetterMethod) { - if (Context.getCanonicalType(SetterMethod->getResultType()) - != Context.VoidTy) + ObjCPropertyDecl::PropertyAttributeKind CAttr = + property->getPropertyAttributes(); + if ((!(CAttr & ObjCPropertyDecl::OBJC_PR_readonly)) && + Context.getCanonicalType(SetterMethod->getResultType()) != + Context.VoidTy) Diag(SetterMethod->getLocation(), diag::err_setter_type_void); if (SetterMethod->param_size() != 1 || ((*SetterMethod->param_begin())->getType() != property->getType())) { @@ -1563,7 +1612,8 @@ void Sema::CompareMethodParamsInBaseAndSuper(Decl *ClassDecl, // Note: For class/category implemenations, allMethods/allProperties is // always null. -void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl, +void Sema::ActOnAtEnd(SourceRange AtEnd, + DeclPtrTy classDecl, DeclPtrTy *allMethods, unsigned allNum, DeclPtrTy *allProperties, unsigned pNum, DeclGroupPtrTy *allTUVars, unsigned tuvNum) { @@ -1580,9 +1630,13 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl, || isa<ObjCProtocolDecl>(ClassDecl); bool checkIdenticalMethods = isa<ObjCImplementationDecl>(ClassDecl); - if (!isInterfaceDeclKind && AtEndLoc.isInvalid()) { - AtEndLoc = ClassDecl->getLocation(); - Diag(AtEndLoc, diag::warn_missing_atend); + if (!isInterfaceDeclKind && AtEnd.isInvalid()) { + // FIXME: This is wrong. We shouldn't be pretending that there is + // an '@end' in the declaration. + SourceLocation L = ClassDecl->getLocation(); + AtEnd.setBegin(L); + AtEnd.setEnd(L); + Diag(L, diag::warn_missing_atend); } DeclContext *DC = dyn_cast<DeclContext>(ClassDecl); @@ -1659,17 +1713,17 @@ void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl, E = CDecl->prop_end(); I != E; ++I) ProcessPropertyDecl(*I, CDecl); - CDecl->setAtEndLoc(AtEndLoc); + CDecl->setAtEndRange(AtEnd); } if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) { - IC->setAtEndLoc(AtEndLoc); + IC->setAtEndRange(AtEnd); if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) { ImplMethodsVsClassMethods(IC, IDecl); AtomicPropertySetterGetterRules(IC, IDecl); } } else if (ObjCCategoryImplDecl* CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) { - CatImplClass->setAtEndLoc(AtEndLoc); + CatImplClass->setAtEndRange(AtEnd); // Find category interface decl and then check that all methods declared // in this interface are implemented in the category @implementation. @@ -1980,6 +2034,32 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, Diag(AtLoc, diag::warn_property_attr_mismatch); Diag(PIDecl->getLocation(), diag::note_property_declare); } + DeclContext *DC = dyn_cast<DeclContext>(CCPrimary); + assert(DC && "ClassDecl is not a DeclContext"); + DeclContext::lookup_result Found = + DC->lookup(PIDecl->getDeclName()); + bool PropertyInPrimaryClass = false; + for (; Found.first != Found.second; ++Found.first) + if (isa<ObjCPropertyDecl>(*Found.first)) { + PropertyInPrimaryClass = true; + break; + } + if (!PropertyInPrimaryClass) { + // Protocol is not in the primary class. Must build one for it. + ObjCDeclSpec ProtocolPropertyODS; + // FIXME. Assuming that ObjCDeclSpec::ObjCPropertyAttributeKind and + // ObjCPropertyDecl::PropertyAttributeKind have identical values. + // Should consolidate both into one enum type. + ProtocolPropertyODS.setPropertyAttributes( + (ObjCDeclSpec::ObjCPropertyAttributeKind)PIkind); + DeclPtrTy ProtocolPtrTy = + ActOnProperty(S, AtLoc, FD, ProtocolPropertyODS, + PIDecl->getGetterName(), + PIDecl->getSetterName(), + DeclPtrTy::make(CCPrimary), isOverridingProperty, + MethodImplKind); + PIDecl = ProtocolPtrTy.getAs<ObjCPropertyDecl>(); + } PIDecl->makeitReadWriteAttribute(); if (Attributes & ObjCDeclSpec::DQ_PR_retain) PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 7bf04d8..034accd 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -14,6 +14,7 @@ #include "Sema.h" #include "SemaInit.h" #include "Lookup.h" +#include "clang/Analysis/PathSensitive/AnalysisContext.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" @@ -565,7 +566,8 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, IsDerivedFrom(ThisType, AnonFieldType)) { // Our base object expression is "this". BaseObjectExpr = new (Context) CXXThisExpr(Loc, - MD->getThisType(Context)); + MD->getThisType(Context), + /*isImplicit=*/true); BaseObjectIsPointer = true; } } else { @@ -943,7 +945,10 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, << SS.getRange() << CodeModificationHint::CreateReplacement(R.getNameLoc(), R.getLookupName().getAsString()); - + if (NamedDecl *ND = R.getAsSingle<NamedDecl>()) + Diag(ND->getLocation(), diag::note_previous_decl) + << ND->getDeclName(); + // Tell the callee to try to recover. return false; } @@ -1006,11 +1011,18 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // C++ [temp.dep.expr]p3: // An id-expression is type-dependent if it contains: + // -- an identifier that was declared with a dependent type, + // (note: handled after lookup) + // -- a template-id that is dependent, + // (note: handled in BuildTemplateIdExpr) + // -- a conversion-function-id that specifies a dependent type, // -- a nested-name-specifier that contains a class-name that // names a dependent type. // Determine whether this is a member of an unknown specialization; // we need to handle these differently. - if (SS.isSet() && IsDependentIdExpression(*this, SS)) { + if ((Name.getNameKind() == DeclarationName::CXXConversionFunctionName && + Name.getCXXNameType()->isDependentType()) || + (SS.isSet() && IsDependentIdExpression(*this, SS))) { return ActOnDependentIdExpression(SS, Name, NameLoc, isAddressOfOperand, TemplateArgs); @@ -1022,12 +1034,13 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // Just re-use the lookup done by isTemplateName. DecomposeTemplateName(R, Id); } else { - LookupParsedName(R, S, &SS, true); + bool IvarLookupFollowUp = (!SS.isSet() && II && getCurMethodDecl()); + LookupParsedName(R, S, &SS, !IvarLookupFollowUp); // If this reference is in an Objective-C method, then we need to do // some special Objective-C lookup, too. - if (!SS.isSet() && II && getCurMethodDecl()) { - OwningExprResult E(LookupInObjCMethod(R, S, II)); + if (IvarLookupFollowUp) { + OwningExprResult E(LookupInObjCMethod(R, S, II, true)); if (E.isInvalid()) return ExprError(); @@ -1059,6 +1072,16 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, assert(!R.empty() && "DiagnoseEmptyLookup returned false but added no results"); + + // If we found an Objective-C instance variable, let + // LookupInObjCMethod build the appropriate expression to + // reference the ivar. + if (ObjCIvarDecl *Ivar = R.getAsSingle<ObjCIvarDecl>()) { + R.clear(); + OwningExprResult E(LookupInObjCMethod(R, S, Ivar->getIdentifier())); + assert(E.isInvalid() || E.get()); + return move(E); + } } } @@ -1197,7 +1220,8 @@ Sema::BuildQualifiedDeclarationNameExpr(const CXXScopeSpec &SS, /// Returns a null sentinel to indicate trivial success. Sema::OwningExprResult Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, - IdentifierInfo *II) { + IdentifierInfo *II, + bool AllowBuiltinCreation) { SourceLocation Loc = Lookup.getNameLoc(); // There are two cases to handle here. 1) scoped lookup could have failed, @@ -1278,7 +1302,18 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, T = Context.getObjCClassType(); return Owned(new (Context) ObjCSuperExpr(Loc, T)); } - + if (Lookup.empty() && II && AllowBuiltinCreation) { + // FIXME. Consolidate this with similar code in LookupName. + if (unsigned BuiltinID = II->getBuiltinID()) { + if (!(getLangOptions().CPlusPlus && + Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))) { + NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID, + S, Lookup.isForRedeclaration(), + Lookup.getNameLoc()); + if (D) Lookup.addDecl(D); + } + } + } // Sentinel value saying that we didn't do anything special. return Owned((Expr*) 0); } @@ -1353,13 +1388,18 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, QualType ThisType = cast<CXXMethodDecl>(CurContext)->getThisType(Context); Expr *This = 0; // null signifies implicit access if (IsKnownInstance) { - This = new (Context) CXXThisExpr(SourceLocation(), ThisType); + SourceLocation Loc = R.getNameLoc(); + if (SS.getRange().isValid()) + Loc = SS.getRange().getBegin(); + This = new (Context) CXXThisExpr(Loc, ThisType, /*isImplicit=*/true); } return BuildMemberReferenceExpr(ExprArg(*this, This), ThisType, /*OpLoc*/ SourceLocation(), /*IsArrow*/ true, - SS, R, TemplateArgs); + SS, + /*FirstQualifierInScope*/ 0, + R, TemplateArgs); } bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS, @@ -1521,6 +1561,18 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, // as they do not get snapshotted. // if (CurBlock && ShouldSnapshotBlockValueReference(CurBlock, VD)) { + if (VD->getType().getTypePtr()->isVariablyModifiedType()) { + Diag(Loc, diag::err_ref_vm_type); + Diag(D->getLocation(), diag::note_declared_at); + return ExprError(); + } + + if (VD->getType()->isArrayType()) { + Diag(Loc, diag::err_ref_array_type); + Diag(D->getLocation(), diag::note_declared_at); + return ExprError(); + } + MarkDeclarationReferenced(Loc, VD); QualType ExprTy = VD->getType().getNonReferenceType(); // The BlocksAttr indicates the variable is bound by-reference. @@ -2252,7 +2304,7 @@ Sema::ActOnDependentMemberExpr(ExprArg Base, QualType BaseType, } } - assert(BaseType->isDependentType()); + assert(BaseType->isDependentType() || Name.isDependentName()); // 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. @@ -2378,6 +2430,9 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, << Name << DC << R.getLookupName() << SS.getRange() << CodeModificationHint::CreateReplacement(R.getNameLoc(), R.getLookupName().getAsString()); + if (NamedDecl *ND = R.getAsSingle<NamedDecl>()) + SemaRef.Diag(ND->getLocation(), diag::note_previous_decl) + << ND->getDeclName(); return false; } else { R.clear(); @@ -2418,8 +2473,7 @@ Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType, } else { OwningExprResult Result = LookupMemberExpr(R, Base, IsArrow, OpLoc, - SS, FirstQualifierInScope, - /*ObjCImpDecl*/ DeclPtrTy()); + SS, /*ObjCImpDecl*/ DeclPtrTy()); if (Result.isInvalid()) { Owned(Base); @@ -2431,13 +2485,15 @@ Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType, } return BuildMemberReferenceExpr(ExprArg(*this, Base), BaseType, - OpLoc, IsArrow, SS, R, TemplateArgs); + OpLoc, IsArrow, SS, FirstQualifierInScope, + R, TemplateArgs); } Sema::OwningExprResult Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, SourceLocation OpLoc, bool IsArrow, const CXXScopeSpec &SS, + NamedDecl *FirstQualifierInScope, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs) { Expr *BaseExpr = Base.takeAs<Expr>(); @@ -2467,11 +2523,17 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, return ExprError(); } - // 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)) + // Diagnose lookups that find only declarations from a non-base + // type. This is possible for either qualified lookups (which may + // have been qualified with an unrelated type) or implicit member + // expressions (which were found with unqualified lookup and thus + // may have come from an enclosing scope). 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() || !BaseExpr || + (isa<CXXThisExpr>(BaseExpr) && + cast<CXXThisExpr>(BaseExpr)->isImplicit())) && + CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R)) return ExprError(); // Construct an unresolved result if we in fact got an unresolved @@ -2513,7 +2575,10 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, if (!IsInstanceMember(MemberDecl)) return BuildDeclarationNameExpr(SS, R.getNameLoc(), MemberDecl); - BaseExpr = new (Context) CXXThisExpr(SourceLocation(), BaseExprType); + SourceLocation Loc = R.getNameLoc(); + if (SS.getRange().isValid()) + Loc = SS.getRange().getBegin(); + BaseExpr = new (Context) CXXThisExpr(Loc, BaseExprType,/*isImplicit=*/true); } bool ShouldCheckUse = true; @@ -2610,7 +2675,6 @@ Sema::OwningExprResult Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, bool &IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, - NamedDecl *FirstQualifierInScope, DeclPtrTy ObjCImpDecl) { assert(BaseExpr && "no base expression"); @@ -2848,6 +2912,22 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, ObjCInterfaceDecl *ClassDeclared; ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared); + if (!IV) { + // Attempt to correct for typos in ivar names. + LookupResult Res(*this, R.getLookupName(), R.getNameLoc(), + LookupMemberName); + if (CorrectTypo(Res, 0, 0, IDecl) && + (IV = Res.getAsSingle<ObjCIvarDecl>())) { + Diag(R.getNameLoc(), + diag::err_typecheck_member_reference_ivar_suggest) + << IDecl->getDeclName() << MemberName << IV->getDeclName() + << CodeModificationHint::CreateReplacement(R.getNameLoc(), + IV->getNameAsString()); + Diag(IV->getLocation(), diag::note_previous_decl) + << IV->getDeclName(); + } + } + if (IV) { // If the decl being referenced had an error, return an error for this // sub-expr without emitting another error, in order to avoid cascading @@ -3014,6 +3094,24 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType, Setter, MemberLoc, BaseExpr)); } + + // Attempt to correct for typos in property names. + LookupResult Res(*this, R.getLookupName(), R.getNameLoc(), + LookupOrdinaryName); + if (CorrectTypo(Res, 0, 0, IFace, false, OPT) && + Res.getAsSingle<ObjCPropertyDecl>()) { + Diag(R.getNameLoc(), diag::err_property_not_found_suggest) + << MemberName << BaseType << Res.getLookupName() + << CodeModificationHint::CreateReplacement(R.getNameLoc(), + Res.getLookupName().getAsString()); + ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>(); + Diag(Property->getLocation(), diag::note_previous_decl) + << Property->getDeclName(); + + return LookupMemberExpr(Res, BaseExpr, IsArrow, OpLoc, SS, + ObjCImpDecl); + } + return ExprError(Diag(MemberLoc, diag::err_property_not_found) << MemberName << BaseType); } @@ -3101,7 +3199,7 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, Expr *Base = BaseArg.takeAs<Expr>(); OwningExprResult Result(*this); - if (Base->getType()->isDependentType()) { + if (Base->getType()->isDependentType() || Name.isDependentName()) { Result = ActOnDependentMemberExpr(ExprArg(*this, Base), Base->getType(), IsArrow, OpLoc, SS, FirstQualifierInScope, @@ -3114,8 +3212,7 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, DecomposeTemplateName(R, Id); } else { Result = LookupMemberExpr(R, Base, IsArrow, OpLoc, - SS, FirstQualifierInScope, - ObjCImpDecl); + SS, ObjCImpDecl); if (Result.isInvalid()) { Owned(Base); @@ -3136,7 +3233,8 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, } Result = BuildMemberReferenceExpr(ExprArg(*this, Base), Base->getType(), - OpLoc, IsArrow, SS, R, TemplateArgs); + OpLoc, IsArrow, SS, FirstQualifierInScope, + R, TemplateArgs); } return move(Result); @@ -4717,8 +4815,7 @@ QualType Sema::InvalidOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) { return QualType(); } -inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, - Expr *&rex) { +QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) { // For conversion purposes, we ignore any qualifiers. // For example, "const float" and "float" are equivalent. QualType lhsType = @@ -4779,19 +4876,27 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, return QualType(); } -inline QualType Sema::CheckMultiplyDivideOperands( - Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) { +QualType Sema::CheckMultiplyDivideOperands( + Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign, bool isDiv) { if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) return CheckVectorOperands(Loc, lex, rex); QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); - if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) - return compType; - return InvalidOperands(Loc, lex, rex); + if (!lex->getType()->isArithmeticType() || + !rex->getType()->isArithmeticType()) + return InvalidOperands(Loc, lex, rex); + + // Check for division by zero. + if (isDiv && + rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) + DiagRuntimeBehavior(Loc, PDiag(diag::warn_division_by_zero) + << rex->getSourceRange()); + + return compType; } -inline QualType Sema::CheckRemainderOperands( +QualType Sema::CheckRemainderOperands( Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) { if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) { if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType()) @@ -4801,12 +4906,18 @@ inline QualType Sema::CheckRemainderOperands( QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); - if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType()) - return compType; - return InvalidOperands(Loc, lex, rex); + if (!lex->getType()->isIntegerType() || !rex->getType()->isIntegerType()) + return InvalidOperands(Loc, lex, rex); + + // Check for remainder by zero. + if (rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) + DiagRuntimeBehavior(Loc, PDiag(diag::warn_remainder_by_zero) + << rex->getSourceRange()); + + return compType; } -inline QualType Sema::CheckAdditionOperands( // C99 6.5.6 +QualType Sema::CheckAdditionOperands( // C99 6.5.6 Expr *&lex, Expr *&rex, SourceLocation Loc, QualType* CompLHSTy) { if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) { QualType compType = CheckVectorOperands(Loc, lex, rex); @@ -5072,80 +5183,6 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, return LHSTy; } -/// \brief Implements -Wsign-compare. -/// -/// \param lex the left-hand expression -/// \param rex the right-hand expression -/// \param OpLoc the location of the joining operator -/// \param Equality whether this is an "equality-like" join, which -/// suppresses the warning in some cases -void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc, - const PartialDiagnostic &PD, bool Equality) { - // Don't warn if we're in an unevaluated context. - if (ExprEvalContexts.back().Context == Unevaluated) - return; - - QualType lt = lex->getType(), rt = rex->getType(); - - // Only warn if both operands are integral. - if (!lt->isIntegerType() || !rt->isIntegerType()) - return; - - // If either expression is value-dependent, don't warn. We'll get another - // chance at instantiation time. - if (lex->isValueDependent() || rex->isValueDependent()) - return; - - // The rule is that the signed operand becomes unsigned, so isolate the - // signed operand. - Expr *signedOperand, *unsignedOperand; - if (lt->isSignedIntegerType()) { - if (rt->isSignedIntegerType()) return; - signedOperand = lex; - unsignedOperand = rex; - } else { - if (!rt->isSignedIntegerType()) return; - signedOperand = rex; - unsignedOperand = lex; - } - - // If the unsigned type is strictly smaller than the signed type, - // then (1) the result type will be signed and (2) the unsigned - // value will fit fully within the signed type, and thus the result - // of the comparison will be exact. - if (Context.getIntWidth(signedOperand->getType()) > - Context.getIntWidth(unsignedOperand->getType())) - return; - - // If the value is a non-negative integer constant, then the - // signed->unsigned conversion won't change it. - llvm::APSInt value; - if (signedOperand->isIntegerConstantExpr(value, Context)) { - assert(value.isSigned() && "result of signed expression not signed"); - - if (value.isNonNegative()) - return; - } - - if (Equality) { - // For (in)equality comparisons, if the unsigned operand is a - // constant which cannot collide with a overflowed signed operand, - // then reinterpreting the signed operand as unsigned will not - // change the result of the comparison. - if (unsignedOperand->isIntegerConstantExpr(value, Context)) { - assert(!value.isSigned() && "result of unsigned expression is signed"); - - // 2's complement: test the top bit. - if (value.isNonNegative()) - return; - } - } - - Diag(OpLoc, PD) - << lex->getType() << rex->getType() - << lex->getSourceRange() << rex->getSourceRange(); -} - // C99 6.5.8, C++ [expr.rel] QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, unsigned OpaqueOpc, bool isRelational) { @@ -5181,7 +5218,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RHSStripped)) if (DRL->getDecl() == DRR->getDecl() && !isa<EnumConstantDecl>(DRL->getDecl())) - Diag(Loc, diag::warn_selfcomparison); + DiagRuntimeBehavior(Loc, PDiag(diag::warn_selfcomparison)); if (isa<CastExpr>(LHSStripped)) LHSStripped = LHSStripped->IgnoreParenCasts(); @@ -5216,15 +5253,17 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, case BinaryOperator::NE: resultComparison = ") != 0"; break; default: assert(false && "Invalid comparison operator"); } - Diag(Loc, diag::warn_stringcompare) - << isa<ObjCEncodeExpr>(literalStringStripped) - << literalString->getSourceRange() - << CodeModificationHint::CreateReplacement(SourceRange(Loc), ", ") - << CodeModificationHint::CreateInsertion(lex->getLocStart(), - "strcmp(") - << CodeModificationHint::CreateInsertion( - PP.getLocForEndOfToken(rex->getLocEnd()), - resultComparison); + + DiagRuntimeBehavior(Loc, + PDiag(diag::warn_stringcompare) + << isa<ObjCEncodeExpr>(literalStringStripped) + << literalString->getSourceRange() + << CodeModificationHint::CreateReplacement(SourceRange(Loc), ", ") + << CodeModificationHint::CreateInsertion(lex->getLocStart(), + "strcmp(") + << CodeModificationHint::CreateInsertion( + PP.getLocForEndOfToken(rex->getLocEnd()), + resultComparison)); } } @@ -5488,7 +5527,7 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex, if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(lex->IgnoreParens())) if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(rex->IgnoreParens())) if (DRL->getDecl() == DRR->getDecl()) - Diag(Loc, diag::warn_selfcomparison); + DiagRuntimeBehavior(Loc, PDiag(diag::warn_selfcomparison)); } // Check for comparisons of floating point operands using != and ==. @@ -5776,7 +5815,7 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, << PointeeTy << Op->getSourceRange(); return QualType(); } - } else if (ResType->isComplexType()) { + } else if (ResType->isAnyComplexType()) { // C99 does not support ++/-- on complex types, we allow as an extension. Diag(OpLoc, diag::ext_integer_increment_complex) << ResType << Op->getSourceRange(); @@ -5877,7 +5916,22 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { NamedDecl *dcl = getPrimaryDecl(op); Expr::isLvalueResult lval = op->isLvalue(Context); - if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) { + MemberExpr *ME = dyn_cast<MemberExpr>(op); + if (lval == Expr::LV_MemberFunction && ME && + isa<CXXMethodDecl>(ME->getMemberDecl())) { + ValueDecl *dcl = cast<MemberExpr>(op)->getMemberDecl(); + // &f where f is a member of the current object, or &o.f, or &p->f + // All these are not allowed, and we need to catch them before the dcl + // branch of the if, below. + Diag(OpLoc, diag::err_unqualified_pointer_member_function) + << dcl; + // FIXME: Improve this diagnostic and provide a fixit. + + // Now recover by acting as if the function had been accessed qualified. + return Context.getMemberPointerType(op->getType(), + Context.getTypeDeclType(cast<RecordDecl>(dcl->getDeclContext())) + .getTypePtr()); + } else if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) { // C99 6.5.3.2p1 // The operand must be either an l-value or a function designator if (!op->getType()->isFunctionType()) { @@ -6065,7 +6119,8 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, break; case BinaryOperator::Mul: case BinaryOperator::Div: - ResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc); + ResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, false, + Opc == BinaryOperator::Div); break; case BinaryOperator::Rem: ResultTy = CheckRemainderOperands(lhs, rhs, OpLoc); @@ -6101,7 +6156,8 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, break; case BinaryOperator::MulAssign: case BinaryOperator::DivAssign: - CompResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true); + CompResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true, + Opc == BinaryOperator::DivAssign); CompLHSTy = CompResultTy; if (!CompResultTy.isNull()) ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); @@ -6155,8 +6211,9 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, /// ParenRange in parentheses. static void SuggestParentheses(Sema &Self, SourceLocation Loc, const PartialDiagnostic &PD, - SourceRange ParenRange) -{ + SourceRange ParenRange, + const PartialDiagnostic &SecondPD = PartialDiagnostic(0), + SourceRange SecondParenRange = SourceRange()) { SourceLocation EndLoc = Self.PP.getLocForEndOfToken(ParenRange.getEnd()); if (!ParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { // We can't display the parentheses, so just dig the @@ -6168,6 +6225,21 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc, Self.Diag(Loc, PD) << CodeModificationHint::CreateInsertion(ParenRange.getBegin(), "(") << CodeModificationHint::CreateInsertion(EndLoc, ")"); + + if (!SecondPD.getDiagID()) + return; + + EndLoc = Self.PP.getLocForEndOfToken(SecondParenRange.getEnd()); + if (!SecondParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { + // We can't display the parentheses, so just dig the + // warning/error and return. + Self.Diag(Loc, SecondPD); + return; + } + + Self.Diag(Loc, SecondPD) + << CodeModificationHint::CreateInsertion(SecondParenRange.getBegin(), "(") + << CodeModificationHint::CreateInsertion(EndLoc, ")"); } /// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison @@ -6199,12 +6271,18 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperator::Opcode Opc, PDiag(diag::warn_precedence_bitwise_rel) << SourceRange(lhs->getLocStart(), OpLoc) << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc), + lhs->getSourceRange(), + PDiag(diag::note_precedence_bitwise_first) + << BinOp::getOpcodeStr(Opc), SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd())); else if (BinOp::isComparisonOp(rhsopc)) SuggestParentheses(Self, OpLoc, PDiag(diag::warn_precedence_bitwise_rel) << SourceRange(OpLoc, rhs->getLocEnd()) << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc), + rhs->getSourceRange(), + PDiag(diag::note_precedence_bitwise_first) + << BinOp::getOpcodeStr(Opc), SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart())); } @@ -6790,7 +6868,9 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, CurFunctionNeedsScopeChecking = BSI->SavedFunctionNeedsScopeChecking; BSI->TheDecl->setBody(body.takeAs<CompoundStmt>()); - CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody()); + AnalysisContext AC(BSI->TheDecl); + CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody(), AC); + CheckUnreachable(AC); return Owned(new (Context) BlockExpr(BSI->TheDecl, BlockTy, BSI->hasBlockDeclRefExprs)); } @@ -7256,6 +7336,8 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) { << E->getSourceRange() << CodeModificationHint::CreateInsertion(Open, "(") << CodeModificationHint::CreateInsertion(Close, ")"); + Diag(Loc, diag::note_condition_assign_to_comparison) + << CodeModificationHint::CreateReplacement(Loc, "=="); } bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) { diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 5f723f9..d10e11f 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -179,7 +179,8 @@ Action::OwningExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) { if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) if (MD->isInstance()) return Owned(new (Context) CXXThisExpr(ThisLoc, - MD->getThisType(Context))); + MD->getThisType(Context), + /*isImplicit=*/false)); return ExprError(Diag(ThisLoc, diag::err_invalid_this_use)); } @@ -672,20 +673,20 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, case OR_No_Viable_Function: Diag(StartLoc, diag::err_ovl_no_viable_function_in_call) << Name << Range; - PrintOverloadCandidates(Candidates, /*OnlyViable=*/false); + PrintOverloadCandidates(Candidates, OCD_AllCandidates, Args, NumArgs); return true; case OR_Ambiguous: Diag(StartLoc, diag::err_ovl_ambiguous_call) << Name << Range; - PrintOverloadCandidates(Candidates, /*OnlyViable=*/true); + PrintOverloadCandidates(Candidates, OCD_ViableCandidates, Args, NumArgs); return true; case OR_Deleted: Diag(StartLoc, diag::err_ovl_deleted_call) << Best->Function->isDeleted() << Name << Range; - PrintOverloadCandidates(Candidates, /*OnlyViable=*/true); + PrintOverloadCandidates(Candidates, OCD_AllCandidates, Args, NumArgs); return true; } assert(false && "Unreachable, bad result from BestViableFunction"); @@ -921,7 +922,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, << Type << Ex->getSourceRange(); for (unsigned i= 0; i < ObjectPtrConversions.size(); i++) { CXXConversionDecl *Conv = ObjectPtrConversions[i]; - Diag(Conv->getLocation(), diag::err_ovl_candidate); + NoteOverloadCandidate(Conv); } return ExprError(); } @@ -1074,7 +1075,8 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, AssignmentAction Action, bool AllowExplicit, bool Elidable, ImplicitConversionSequence& ICS) { - ICS.ConversionKind = ImplicitConversionSequence::BadConversion; + ICS.setBad(); + ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType); if (Elidable && getLangOptions().CPlusPlus0x) { ICS = TryImplicitConversion(From, ToType, /*SuppressUserConversions=*/false, @@ -1082,7 +1084,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, /*ForceRValue=*/true, /*InOverloadResolution=*/false); } - if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) { + if (ICS.isBad()) { ICS = TryImplicitConversion(From, ToType, /*SuppressUserConversions=*/false, AllowExplicit, @@ -1092,39 +1094,6 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, return PerformImplicitConversion(From, ToType, ICS, Action); } -/// BuildCXXDerivedToBaseExpr - This routine generates the suitable AST -/// for the derived to base conversion of the expression 'From'. All -/// necessary information is passed in ICS. -bool -Sema::BuildCXXDerivedToBaseExpr(Expr *&From, CastExpr::CastKind CastKind, - const ImplicitConversionSequence& ICS) { - QualType BaseType = - QualType::getFromOpaquePtr(ICS.UserDefined.After.ToTypePtr); - // Must do additional defined to base conversion. - QualType DerivedType = - QualType::getFromOpaquePtr(ICS.UserDefined.After.FromTypePtr); - - From = new (Context) ImplicitCastExpr( - DerivedType.getNonReferenceType(), - CastKind, - From, - DerivedType->isLValueReferenceType()); - From = new (Context) ImplicitCastExpr(BaseType.getNonReferenceType(), - CastExpr::CK_DerivedToBase, From, - BaseType->isLValueReferenceType()); - ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); - OwningExprResult FromResult = - BuildCXXConstructExpr( - ICS.UserDefined.After.CopyConstructor->getLocation(), - BaseType, - ICS.UserDefined.After.CopyConstructor, - MultiExprArg(*this, (void **)&From, 1)); - if (FromResult.isInvalid()) - return true; - From = FromResult.takeAs<Expr>(); - return false; -} - /// PerformImplicitConversion - Perform an implicit conversion of the /// expression From to the type ToType using the pre-computed implicit /// conversion sequence ICS. Returns true if there was an error, false @@ -1135,7 +1104,7 @@ bool Sema::PerformImplicitConversion(Expr *&From, QualType ToType, const ImplicitConversionSequence &ICS, AssignmentAction Action, bool IgnoreBaseAccess) { - switch (ICS.ConversionKind) { + switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: if (PerformImplicitConversion(From, ToType, ICS.Standard, Action, IgnoreBaseAccess)) @@ -1186,23 +1155,15 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, From = CastArg.takeAs<Expr>(); - // FIXME: This and the following if statement shouldn't be necessary, but - // there's some nasty stuff involving MaybeBindToTemporary going on here. - if (ICS.UserDefined.After.Second == ICK_Derived_To_Base && - ICS.UserDefined.After.CopyConstructor) { - return BuildCXXDerivedToBaseExpr(From, CastKind, ICS); - } - - if (ICS.UserDefined.After.CopyConstructor) { - From = new (Context) ImplicitCastExpr(ToType.getNonReferenceType(), - CastKind, From, - ToType->isLValueReferenceType()); - return false; - } - return PerformImplicitConversion(From, ToType, ICS.UserDefined.After, AA_Converting, IgnoreBaseAccess); } + + case ImplicitConversionSequence::AmbiguousConversion: + DiagnoseAmbiguousConversion(ICS, From->getExprLoc(), + PDiag(diag::err_typecheck_ambiguous_condition) + << From->getSourceRange()); + return true; case ImplicitConversionSequence::EllipsisConversion: assert(false && "Cannot perform an ellipsis conversion"); @@ -1520,14 +1481,18 @@ QualType Sema::CheckPointerToMemberOperands( /// \brief Get the target type of a standard or user-defined conversion. static QualType TargetType(const ImplicitConversionSequence &ICS) { - assert((ICS.ConversionKind == - ImplicitConversionSequence::StandardConversion || - ICS.ConversionKind == - ImplicitConversionSequence::UserDefinedConversion) && - "function only valid for standard or user-defined conversions"); - if (ICS.ConversionKind == ImplicitConversionSequence::StandardConversion) - return QualType::getFromOpaquePtr(ICS.Standard.ToTypePtr); - return QualType::getFromOpaquePtr(ICS.UserDefined.After.ToTypePtr); + switch (ICS.getKind()) { + case ImplicitConversionSequence::StandardConversion: + return ICS.Standard.getToType(); + case ImplicitConversionSequence::UserDefinedConversion: + return ICS.UserDefined.After.getToType(); + case ImplicitConversionSequence::AmbiguousConversion: + return ICS.Ambiguous.getToType(); + case ImplicitConversionSequence::EllipsisConversion: + case ImplicitConversionSequence::BadConversion: + llvm_unreachable("function not valid for ellipsis or bad conversions"); + } + return QualType(); // silence warnings } /// \brief Try to convert a type to another according to C++0x 5.16p3. @@ -1557,19 +1522,16 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, /*ForceRValue=*/false, &ICS)) { - assert((ICS.ConversionKind == - ImplicitConversionSequence::StandardConversion || - ICS.ConversionKind == - ImplicitConversionSequence::UserDefinedConversion) && + assert((ICS.isStandard() || ICS.isUserDefined()) && "expected a definite conversion"); bool DirectBinding = - ICS.ConversionKind == ImplicitConversionSequence::StandardConversion ? - ICS.Standard.DirectBinding : ICS.UserDefined.After.DirectBinding; + ICS.isStandard() ? ICS.Standard.DirectBinding + : ICS.UserDefined.After.DirectBinding; if (DirectBinding) return false; } } - ICS.ConversionKind = ImplicitConversionSequence::BadConversion; + ICS.setBad(); // -- If E2 is an rvalue, or if the conversion above cannot be done: // -- if E1 and E2 have class type, and the underlying class types are // the same or one is a base class of the other: @@ -1665,8 +1627,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, /// handles the reference binding specially. static bool ConvertForConditional(Sema &Self, Expr *&E, const ImplicitConversionSequence &ICS) { - if (ICS.ConversionKind == ImplicitConversionSequence::StandardConversion && - ICS.Standard.ReferenceBinding) { + if (ICS.isStandard() && ICS.Standard.ReferenceBinding) { assert(ICS.Standard.DirectBinding && "TryClassUnification should never generate indirect ref bindings"); // FIXME: CheckReferenceInit should be able to reuse the ICS instead of @@ -1678,8 +1639,7 @@ static bool ConvertForConditional(Sema &Self, Expr *&E, /*AllowExplicit=*/false, /*ForceRValue=*/false); } - if (ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion && - ICS.UserDefined.After.ReferenceBinding) { + if (ICS.isUserDefined() && ICS.UserDefined.After.ReferenceBinding) { assert(ICS.UserDefined.After.DirectBinding && "TryClassUnification should never generate indirect ref bindings"); return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType( @@ -1767,10 +1727,8 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (TryClassUnification(*this, RHS, LHS, QuestionLoc, ICSRightToLeft)) return QualType(); - bool HaveL2R = ICSLeftToRight.ConversionKind != - ImplicitConversionSequence::BadConversion; - bool HaveR2L = ICSRightToLeft.ConversionKind != - ImplicitConversionSequence::BadConversion; + bool HaveL2R = !ICSLeftToRight.isBad(); + bool HaveR2L = !ICSRightToLeft.isBad(); // If both can be converted, [...] the program is ill-formed. if (HaveL2R && HaveR2L) { Diag(QuestionLoc, diag::err_conditional_ambiguous) @@ -1837,6 +1795,12 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // type and the other is a null pointer constant; pointer conversions // and qualification conversions are performed to bring them to their // composite pointer type. The result is of the composite pointer type. + // -- The second and third operands have pointer to member type, or one has + // pointer to member type and the other is a null pointer constant; + // pointer to member conversions and qualification conversions are + // performed to bring them to a common type, whose cv-qualification + // shall match the cv-qualification of either the second or the third + // operand. The result is of the common type. QualType Composite = FindCompositePointerType(LHS, RHS); if (!Composite.isNull()) return Composite; @@ -1846,83 +1810,6 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, 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 - // containing class, and second-level cv-ness. - // cv-ness is not a union, but must match one of the two operands. (Which, - // frankly, is stupid.) - const MemberPointerType *LMemPtr = LTy->getAs<MemberPointerType>(); - const MemberPointerType *RMemPtr = RTy->getAs<MemberPointerType>(); - if (LMemPtr && - RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(RHS, LTy, CastExpr::CK_NullToMemberPointer); - return LTy; - } - if (RMemPtr && - LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(LHS, RTy, CastExpr::CK_NullToMemberPointer); - return RTy; - } - if (LMemPtr && RMemPtr) { - QualType LPointee = LMemPtr->getPointeeType(); - QualType RPointee = RMemPtr->getPointeeType(); - - QualifierCollector LPQuals, RPQuals; - const Type *LPCan = LPQuals.strip(Context.getCanonicalType(LPointee)); - const Type *RPCan = RPQuals.strip(Context.getCanonicalType(RPointee)); - - // First, we check that the unqualified pointee type is the same. If it's - // not, there's no conversion that will unify the two pointers. - if (LPCan == RPCan) { - - // Second, we take the greater of the two qualifications. If neither - // is greater than the other, the conversion is not possible. - - Qualifiers MergedQuals = LPQuals + RPQuals; - - bool CompatibleQuals = true; - if (MergedQuals.getCVRQualifiers() != LPQuals.getCVRQualifiers() && - MergedQuals.getCVRQualifiers() != RPQuals.getCVRQualifiers()) - CompatibleQuals = false; - else if (LPQuals.getAddressSpace() != RPQuals.getAddressSpace()) - // FIXME: - // C99 6.5.15 as modified by TR 18037: - // If the second and third operands are pointers into different - // address spaces, the address spaces must overlap. - CompatibleQuals = false; - // FIXME: GC qualifiers? - - if (CompatibleQuals) { - // Third, we check if either of the container classes is derived from - // the other. - QualType LContainer(LMemPtr->getClass(), 0); - QualType RContainer(RMemPtr->getClass(), 0); - QualType MoreDerived; - if (Context.getCanonicalType(LContainer) == - Context.getCanonicalType(RContainer)) - MoreDerived = LContainer; - else if (IsDerivedFrom(LContainer, RContainer)) - MoreDerived = LContainer; - else if (IsDerivedFrom(RContainer, LContainer)) - MoreDerived = RContainer; - - if (!MoreDerived.isNull()) { - // The type 'Q Pointee (MoreDerived::*)' is the common type. - // We don't use ImpCastExprToType here because this could still fail - // for ambiguous or inaccessible conversions. - LPointee = Context.getQualifiedType(LPointee, MergedQuals); - QualType Common - = Context.getMemberPointerType(LPointee, MoreDerived.getTypePtr()); - if (PerformImplicitConversion(LHS, Common, Sema::AA_Converting)) - return QualType(); - if (PerformImplicitConversion(RHS, Common, Sema::AA_Converting)) - return QualType(); - return Common; - } - } - } - } - Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) << LHS->getType() << RHS->getType() << LHS->getSourceRange() << RHS->getSourceRange(); @@ -2055,8 +1942,8 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { /*InOverloadResolution=*/false); ImplicitConversionSequence E1ToC2, E2ToC2; - E1ToC2.ConversionKind = ImplicitConversionSequence::BadConversion; - E2ToC2.ConversionKind = ImplicitConversionSequence::BadConversion; + E1ToC2.setBad(); + E2ToC2.setBad(); if (Context.getCanonicalType(Composite1) != Context.getCanonicalType(Composite2)) { E1ToC2 = TryImplicitConversion(E1, Composite2, @@ -2071,14 +1958,8 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { /*InOverloadResolution=*/false); } - bool ToC1Viable = E1ToC1.ConversionKind != - ImplicitConversionSequence::BadConversion - && E2ToC1.ConversionKind != - ImplicitConversionSequence::BadConversion; - bool ToC2Viable = E1ToC2.ConversionKind != - ImplicitConversionSequence::BadConversion - && E2ToC2.ConversionKind != - ImplicitConversionSequence::BadConversion; + bool ToC1Viable = !E1ToC1.isBad() && !E2ToC1.isBad(); + bool ToC2Viable = !E1ToC2.isBad() && !E2ToC2.isBad(); if (ToC1Viable && !ToC2Viable) { if (!PerformImplicitConversion(E1, Composite1, E1ToC1, Sema::AA_Converting) && !PerformImplicitConversion(E2, Composite1, E2ToC1, Sema::AA_Converting)) @@ -2305,71 +2186,3 @@ Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) { return Owned(FullExpr); } - -/// \brief Determine whether a reference to the given declaration in the -/// current context is an implicit member access -/// (C++ [class.mfct.non-static]p2). -/// -/// FIXME: Should Objective-C also use this approach? -/// -/// \param D the declaration being referenced from the current scope. -/// -/// \param NameLoc the location of the name in the source. -/// -/// \param ThisType if the reference to this declaration is an implicit member -/// access, will be set to the type of the "this" pointer to be used when -/// building that implicit member access. -/// -/// \returns true if this is an implicit member reference (in which case -/// \p ThisType and \p MemberType will be set), or false if it is not an -/// implicit member reference. -bool Sema::isImplicitMemberReference(const LookupResult &R, - QualType &ThisType) { - // If this isn't a C++ method, then it isn't an implicit member reference. - CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext); - if (!MD || MD->isStatic()) - return false; - - // C++ [class.mfct.nonstatic]p2: - // [...] if name lookup (3.4.1) resolves the name in the - // id-expression to a nonstatic nontype member of class X or of - // a base class of X, the id-expression is transformed into a - // class member access expression (5.2.5) using (*this) (9.3.2) - // as the postfix-expression to the left of the '.' operator. - DeclContext *Ctx = 0; - if (R.isUnresolvableResult()) { - // FIXME: this is just picking one at random - Ctx = R.getRepresentativeDecl()->getDeclContext(); - } else if (FieldDecl *FD = R.getAsSingle<FieldDecl>()) { - Ctx = FD->getDeclContext(); - } else { - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { - CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*I); - FunctionTemplateDecl *FunTmpl = 0; - if (!Method && (FunTmpl = dyn_cast<FunctionTemplateDecl>(*I))) - Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl()); - - // FIXME: Do we have to know if there are explicit template arguments? - if (Method && !Method->isStatic()) { - Ctx = Method->getParent(); - break; - } - } - } - - if (!Ctx || !Ctx->isRecord()) - return false; - - // Determine whether the declaration(s) we found are actually in a base - // class. If not, this isn't an implicit member reference. - ThisType = MD->getThisType(Context); - - // FIXME: this doesn't really work for overloaded lookups. - - QualType CtxType = Context.getTypeDeclType(cast<CXXRecordDecl>(Ctx)); - QualType ClassType - = Context.getTypeDeclType(cast<CXXRecordDecl>(MD->getParent())); - return Context.hasSameType(CtxType, ClassType) || - IsDerivedFrom(ClassType, CtxType); -} - diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 2e31e47..85889fa 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -287,7 +287,8 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr( SourceLocation &receiverNameLoc, SourceLocation &propertyNameLoc) { - ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(&receiverName); + IdentifierInfo *receiverNamePtr = &receiverName; + ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr); // Search for a declared property first. @@ -400,7 +401,7 @@ Sema::ExprResult Sema::ActOnClassMessage( return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName; } } else - ClassDecl = getObjCInterfaceDecl(receiverName); + ClassDecl = getObjCInterfaceDecl(receiverName, receiverLoc); // The following code allows for the following GCC-ism: // diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 3ef5156..1970f56 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -88,7 +88,7 @@ static bool CheckSingleInitializer(Expr *&Init, QualType DeclType, S.Diag(Init->getSourceRange().getBegin(), diag::err_typecheck_convert_ambiguous) << DeclType << Init->getType() << Init->getSourceRange(); - S.PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + S.PrintOverloadCandidates(CandidateSet, Sema::OCD_AllCandidates, &Init, 1); return true; } return false; @@ -670,7 +670,7 @@ void InitListChecker::CheckSubElementType(InitListExpr *IList, /*ForceRValue=*/false, /*InOverloadResolution=*/false); - if (ICS.ConversionKind != ImplicitConversionSequence::BadConversion) { + if (!ICS.isBad()) { if (SemaRef.PerformImplicitConversion(expr, ElemType, ICS, Sema::AA_Initializing)) hadError = true; @@ -1136,7 +1136,7 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef, // Expand the current designator into the set of replacement // designators, so we have a full subobject path down to where the // member of the anonymous struct/union is actually stored. - DIE->ExpandDesignator(DesigIdx, &Replacements[0], + DIE->ExpandDesignator(SemaRef.Context, DesigIdx, &Replacements[0], &Replacements[0] + Replacements.size()); // Update FieldIter/FieldIndex; @@ -1302,6 +1302,9 @@ InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, << FieldName << CurrentObjectType << R.getLookupName() << CodeModificationHint::CreateReplacement(D->getFieldLoc(), R.getLookupName().getAsString()); + SemaRef.Diag(ReplacementField->getLocation(), + diag::note_previous_decl) + << ReplacementField->getDeclName(); } else { SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown) << FieldName << CurrentObjectType; @@ -2224,9 +2227,11 @@ static void TryReferenceInitialization(Sema &S, QualType DestType = Entity.getType(); QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType(); - QualType T1 = cv1T1.getUnqualifiedType(); + Qualifiers T1Quals; + QualType T1 = S.Context.getUnqualifiedArrayType(cv1T1, T1Quals); QualType cv2T2 = Initializer->getType(); - QualType T2 = cv2T2.getUnqualifiedType(); + Qualifiers T2Quals; + QualType T2 = S.Context.getUnqualifiedArrayType(cv2T2, T2Quals); SourceLocation DeclLoc = Initializer->getLocStart(); // If the initializer is the address of an overloaded function, try @@ -2276,9 +2281,9 @@ static void TryReferenceInitialization(Sema &S, // can occur. This property will be checked by PerformInitialization. if (DerivedToBase) Sequence.AddDerivedToBaseCastStep( - S.Context.getQualifiedType(T1, cv2T2.getQualifiers()), + S.Context.getQualifiedType(T1, T2Quals), /*isLValue=*/true); - if (cv1T1.getQualifiers() != cv2T2.getQualifiers()) + if (T1Quals != T2Quals) Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/true); Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/false); return; @@ -2297,6 +2302,11 @@ static void TryReferenceInitialization(Sema &S, Sequence); if (ConvOvlResult == OR_Success) return; + if (ConvOvlResult != OR_No_Viable_Function) { + Sequence.SetOverloadFailure( + InitializationSequence::FK_ReferenceInitOverloadFailed, + ConvOvlResult); + } } } @@ -2304,7 +2314,7 @@ static void TryReferenceInitialization(Sema &S, // 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) || + if (!((isLValueRef && T1Quals.hasConst()) || (isRValueRef && InitLvalue != Expr::LV_Valid))) { if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty()) Sequence.SetOverloadFailure( @@ -2331,9 +2341,9 @@ static void TryReferenceInitialization(Sema &S, RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { if (DerivedToBase) Sequence.AddDerivedToBaseCastStep( - S.Context.getQualifiedType(T1, cv2T2.getQualifiers()), + S.Context.getQualifiedType(T1, T2Quals), /*isLValue=*/false); - if (cv1T1.getQualifiers() != cv2T2.getQualifiers()) + if (T1Quals != T2Quals) Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/false); Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true); return; @@ -2381,7 +2391,7 @@ static void TryReferenceInitialization(Sema &S, /*FIXME:InOverloadResolution=*/false, /*UserCast=*/Kind.isExplicitCast()); - if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) { + if (ICS.isBad()) { // 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 @@ -2398,8 +2408,10 @@ static void TryReferenceInitialization(Sema &S, // [...] 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. + unsigned T1CVRQuals = T1Quals.getCVRQualifiers(); + unsigned T2CVRQuals = T2Quals.getCVRQualifiers(); if (RefRelationship == Sema::Ref_Related && - !cv1T1.isAtLeastAsQualifiedAs(cv2T2)) { + (T1CVRQuals | T2CVRQuals) != T1CVRQuals) { Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers); return; } @@ -2682,14 +2694,14 @@ static void TryUserDefinedConversion(Sema &S, // Perform overload resolution. If it fails, return the failed result. OverloadCandidateSet::iterator Best; - if (OverloadingResult Result + if (OverloadingResult Result = S.BestViableFunction(CandidateSet, DeclLoc, Best)) { Sequence.SetOverloadFailure( InitializationSequence::FK_UserConversionOverloadFailed, Result); return; } - + FunctionDecl *Function = Best->Function; if (isa<CXXConstructorDecl>(Function)) { @@ -2708,7 +2720,7 @@ static void TryUserDefinedConversion(Sema &S, if (Best->FinalConversion.First || Best->FinalConversion.Second || Best->FinalConversion.Third) { ImplicitConversionSequence ICS; - ICS.ConversionKind = ImplicitConversionSequence::StandardConversion; + ICS.setStandard(); ICS.Standard = Best->FinalConversion; Sequence.AddConversionSequenceStep(ICS, DestType); } @@ -2729,7 +2741,7 @@ static void TryImplicitConversion(Sema &S, /*FIXME:InOverloadResolution=*/false, /*UserCast=*/Kind.isExplicitCast()); - if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) { + if (ICS.isBad()) { Sequence.SetFailed(InitializationSequence::FK_ConversionFailed); return; } @@ -3007,14 +3019,16 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S, S.Diag(Loc, diag::err_temp_copy_no_viable) << (int)Entity.getKind() << CurInitExpr->getType() << CurInitExpr->getSourceRange(); - S.PrintOverloadCandidates(CandidateSet, false); + S.PrintOverloadCandidates(CandidateSet, Sema::OCD_AllCandidates, + &CurInitExpr, 1); return S.ExprError(); case OR_Ambiguous: S.Diag(Loc, diag::err_temp_copy_ambiguous) << (int)Entity.getKind() << CurInitExpr->getType() << CurInitExpr->getSourceRange(); - S.PrintOverloadCandidates(CandidateSet, true); + S.PrintOverloadCandidates(CandidateSet, Sema::OCD_ViableCandidates, + &CurInitExpr, 1); return S.ExprError(); case OR_Deleted: @@ -3429,14 +3443,16 @@ bool InitializationSequence::Diagnose(Sema &S, << DestType << Args[0]->getType() << Args[0]->getSourceRange(); - S.PrintOverloadCandidates(FailedCandidateSet, true); + S.PrintOverloadCandidates(FailedCandidateSet, Sema::OCD_ViableCandidates, + Args, NumArgs); 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); + S.PrintOverloadCandidates(FailedCandidateSet, Sema::OCD_AllCandidates, + Args, NumArgs); break; case OR_Deleted: { @@ -3538,13 +3554,15 @@ bool InitializationSequence::Diagnose(Sema &S, case OR_Ambiguous: S.Diag(Kind.getLocation(), diag::err_ovl_ambiguous_init) << DestType << ArgsRange; - S.PrintOverloadCandidates(FailedCandidateSet, true); + S.PrintOverloadCandidates(FailedCandidateSet, + Sema::OCD_ViableCandidates, Args, NumArgs); break; case OR_No_Viable_Function: S.Diag(Kind.getLocation(), diag::err_ovl_no_viable_function_in_init) << DestType << ArgsRange; - S.PrintOverloadCandidates(FailedCandidateSet, false); + S.PrintOverloadCandidates(FailedCandidateSet, Sema::OCD_AllCandidates, + Args, NumArgs); break; case OR_Deleted: { diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 1419ceb..cda245d 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -444,10 +444,83 @@ static bool LookupDirect(LookupResult &R, const DeclContext *DC) { bool Found = false; DeclContext::lookup_const_iterator I, E; - for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) - if (R.isAcceptableDecl(*I)) - R.addDecl(*I), Found = true; + for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) { + if (R.isAcceptableDecl(*I)) { + R.addDecl(*I); + Found = true; + } + } + if (R.getLookupName().getNameKind() + == DeclarationName::CXXConversionFunctionName && + !R.getLookupName().getCXXNameType()->isDependentType() && + isa<CXXRecordDecl>(DC)) { + // C++ [temp.mem]p6: + // A specialization of a conversion function template is not found by + // name lookup. Instead, any conversion function templates visible in the + // context of the use are considered. [...] + const CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); + if (!Record->isDefinition()) + return Found; + + const UnresolvedSet *Unresolved = Record->getConversionFunctions(); + for (UnresolvedSet::iterator U = Unresolved->begin(), + UEnd = Unresolved->end(); + U != UEnd; ++U) { + FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U); + if (!ConvTemplate) + continue; + + // When we're performing lookup for the purposes of redeclaration, just + // add the conversion function template. When we deduce template + // arguments for specializations, we'll end up unifying the return + // type of the new declaration with the type of the function template. + if (R.isForRedeclaration()) { + R.addDecl(ConvTemplate); + Found = true; + continue; + } + + // C++ [temp.mem]p6: + // [...] For each such operator, if argument deduction succeeds + // (14.9.2.3), the resulting specialization is used as if found by + // name lookup. + // + // When referencing a conversion function for any purpose other than + // a redeclaration (such that we'll be building an expression with the + // result), perform template argument deduction and place the + // specialization into the result set. We do this to avoid forcing all + // callers to perform special deduction for conversion functions. + Sema::TemplateDeductionInfo Info(R.getSema().Context); + FunctionDecl *Specialization = 0; + + const FunctionProtoType *ConvProto + = ConvTemplate->getTemplatedDecl()->getType() + ->getAs<FunctionProtoType>(); + assert(ConvProto && "Nonsensical conversion function template type"); + + // Compute the type of the function that we would expect the conversion + // function to have, if it were to match the name given. + // FIXME: Calling convention! + QualType ExpectedType + = R.getSema().Context.getFunctionType( + R.getLookupName().getCXXNameType(), + 0, 0, ConvProto->isVariadic(), + ConvProto->getTypeQuals(), + false, false, 0, 0, + ConvProto->getNoReturnAttr()); + + // Perform template argument deduction against the type that we would + // expect the function to have. + if (R.getSema().DeduceTemplateArguments(ConvTemplate, 0, ExpectedType, + Specialization, Info) + == Sema::TDK_Success) { + R.addDecl(Specialization); + Found = true; + } + } + } + return Found; } @@ -550,7 +623,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // example, inside a class without any base classes, we never need to // perform qualified lookup because all of the members are on top of the // identifier chain. - if (LookupQualifiedName(R, Ctx)) + if (LookupQualifiedName(R, Ctx, /*InUnqualifiedLookup=*/true)) return true; } } @@ -577,7 +650,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { for (; S; S = S->getParent()) { DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity()); - if (Ctx->isTransparentContext()) + if (!Ctx || Ctx->isTransparentContext()) continue; assert(Ctx && Ctx->isFileContext() && @@ -854,11 +927,11 @@ static bool LookupQualifiedNameInUsingDirectives(LookupResult &R, return Found; } -/// @brief Perform qualified name lookup into a given context. +/// \brief Perform qualified name lookup into a given context. /// /// Qualified name lookup (C++ [basic.lookup.qual]) is used to find /// names when the context of those names is explicit specified, e.g., -/// "std::vector" or "x->member". +/// "std::vector" or "x->member", or as part of unqualified name lookup. /// /// Different lookup criteria can find different names. For example, a /// particular scope can have both a struct and a function of the same @@ -866,25 +939,18 @@ static bool LookupQualifiedNameInUsingDirectives(LookupResult &R, /// information about lookup criteria, see the documentation for the /// class LookupCriteria. /// -/// @param LookupCtx The context in which qualified name lookup will +/// \param R captures both the lookup criteria and any lookup results found. +/// +/// \param LookupCtx The context in which qualified name lookup will /// search. If the lookup criteria permits, name lookup may also search /// in the parent contexts or (for C++ classes) base classes. /// -/// @param Name The name of the entity that we are searching for. +/// \param InUnqualifiedLookup true if this is qualified name lookup that +/// occurs as part of unqualified name lookup. /// -/// @param Criteria The criteria that this routine will use to -/// determine which names are visible and which names will be -/// found. Note that name lookup will find a name that is visible by -/// the given criteria, but the entity itself may not be semantically -/// correct or even the kind of entity expected based on the -/// lookup. For example, searching for a nested-name-specifier name -/// might result in an EnumDecl, which is visible but is not permitted -/// as a nested-name-specifier in C++03. -/// -/// @returns The result of name lookup, which includes zero or more -/// declarations and possibly additional information used to diagnose -/// ambiguities. -bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx) { +/// \returns true if lookup succeeded, false if it failed. +bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, + bool InUnqualifiedLookup) { assert(LookupCtx && "Sema::LookupQualifiedName requires a lookup context"); if (!R.getLookupName()) @@ -922,11 +988,22 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx) { // If this isn't a C++ class, we aren't allowed to look into base // classes, we're done. - if (!isa<CXXRecordDecl>(LookupCtx)) + CXXRecordDecl *LookupRec = dyn_cast<CXXRecordDecl>(LookupCtx); + if (!LookupRec) return false; + // If we're performing qualified name lookup into a dependent class, + // then we are actually looking into a current instantiation. If we have any + // dependent base classes, then we either have to delay lookup until + // template instantiation time (at which point all bases will be available) + // or we have to fail. + if (!InUnqualifiedLookup && LookupRec->isDependentContext() && + LookupRec->hasAnyDependentBases()) { + R.setNotFoundInCurrentInstantiation(); + return false; + } + // Perform lookup into our base classes. - CXXRecordDecl *LookupRec = cast<CXXRecordDecl>(LookupCtx); CXXBasePaths Paths; Paths.setOrigin(LookupRec); @@ -1843,6 +1920,9 @@ VisibleDeclsRecord::ShadowMapEntry::end() { } NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { + // Look through using declarations. + ND = ND->getUnderlyingDecl(); + unsigned IDNS = ND->getIdentifierNamespace(); std::list<ShadowMap>::reverse_iterator SM = ShadowMaps.rbegin(); for (std::list<ShadowMap>::reverse_iterator SMEnd = ShadowMaps.rend(); @@ -1866,6 +1946,14 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { (*I)->getIdentifierNamespace() != IDNS) continue; + // Functions and function templates in the same scope overload + // rather than hide. FIXME: Look for hiding based on function + // signatures! + if ((*I)->isFunctionOrFunctionTemplate() && + ND->isFunctionOrFunctionTemplate() && + SM == ShadowMaps.rbegin()) + continue; + // We've found a declaration that hides this one. return *I; } @@ -1876,6 +1964,7 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, bool QualifiedNameLookup, + bool InBaseClass, VisibleDeclConsumer &Consumer, VisibleDeclsRecord &Visited) { // Make sure we don't visit the same context twice. @@ -1890,14 +1979,14 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, D != DEnd; ++D) { if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) if (Result.isAcceptableDecl(ND)) { - Consumer.FoundDecl(ND, Visited.checkHidden(ND)); + Consumer.FoundDecl(ND, Visited.checkHidden(ND), InBaseClass); Visited.add(ND); } // Visit transparent contexts inside this context. if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D)) { if (InnerCtx->isTransparentContext()) - LookupVisibleDecls(InnerCtx, Result, QualifiedNameLookup, + LookupVisibleDecls(InnerCtx, Result, QualifiedNameLookup, InBaseClass, Consumer, Visited); } } @@ -1909,11 +1998,11 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, DeclContext::udir_iterator I, E; for (llvm::tie(I, E) = Ctx->getUsingDirectives(); I != E; ++I) { LookupVisibleDecls((*I)->getNominatedNamespace(), Result, - QualifiedNameLookup, Consumer, Visited); + QualifiedNameLookup, InBaseClass, Consumer, Visited); } } - // Traverse the contexts of inherited classes. + // Traverse the contexts of inherited C++ classes. if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) { for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(), BEnd = Record->bases_end(); @@ -1951,11 +2040,49 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, // Find results in this base class (and its bases). ShadowContextRAII Shadow(Visited); LookupVisibleDecls(Record->getDecl(), Result, QualifiedNameLookup, - Consumer, Visited); + true, Consumer, Visited); } } - // FIXME: Look into base classes in Objective-C! + // Traverse the contexts of Objective-C classes. + if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Ctx)) { + // Traverse categories. + for (ObjCCategoryDecl *Category = IFace->getCategoryList(); + Category; Category = Category->getNextClassCategory()) { + ShadowContextRAII Shadow(Visited); + LookupVisibleDecls(Category, Result, QualifiedNameLookup, false, + Consumer, Visited); + } + + // Traverse protocols. + for (ObjCInterfaceDecl::protocol_iterator I = IFace->protocol_begin(), + E = IFace->protocol_end(); I != E; ++I) { + ShadowContextRAII Shadow(Visited); + LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, + Visited); + } + + // Traverse the superclass. + if (IFace->getSuperClass()) { + ShadowContextRAII Shadow(Visited); + LookupVisibleDecls(IFace->getSuperClass(), Result, QualifiedNameLookup, + true, Consumer, Visited); + } + } else if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Ctx)) { + for (ObjCProtocolDecl::protocol_iterator I = Protocol->protocol_begin(), + E = Protocol->protocol_end(); I != E; ++I) { + ShadowContextRAII Shadow(Visited); + LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, + Visited); + } + } else if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Ctx)) { + for (ObjCCategoryDecl::protocol_iterator I = Category->protocol_begin(), + E = Category->protocol_end(); I != E; ++I) { + ShadowContextRAII Shadow(Visited); + LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, + Visited); + } + } } static void LookupVisibleDecls(Scope *S, LookupResult &Result, @@ -1965,9 +2092,21 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, if (!S) return; + if (!S->getEntity() || !S->getParent() || + ((DeclContext *)S->getEntity())->isFunctionOrMethod()) { + // Walk through the declarations in this Scope. + for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); + D != DEnd; ++D) { + if (NamedDecl *ND = dyn_cast<NamedDecl>((Decl *)((*D).get()))) + if (Result.isAcceptableDecl(ND)) { + Consumer.FoundDecl(ND, Visited.checkHidden(ND), false); + Visited.add(ND); + } + } + } + DeclContext *Entity = 0; - if (S->getEntity() && - !((DeclContext *)S->getEntity())->isFunctionOrMethod()) { + if (S->getEntity()) { // Look into this scope's declaration context, along with any of its // parent lookup contexts (e.g., enclosing classes), up to the point // where we hit the context stored in the next outer scope. @@ -1976,11 +2115,27 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, for (DeclContext *Ctx = Entity; Ctx && Ctx->getPrimaryContext() != OuterCtx; Ctx = Ctx->getLookupParent()) { + if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(Ctx)) { + if (Method->isInstanceMethod()) { + // For instance methods, look for ivars in the method's interface. + LookupResult IvarResult(Result.getSema(), Result.getLookupName(), + Result.getNameLoc(), Sema::LookupMemberName); + ObjCInterfaceDecl *IFace = Method->getClassInterface(); + LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false, + /*InBaseClass=*/false, Consumer, Visited); + } + + // We've already performed all of the name lookup that we need + // to for Objective-C methods; the next context will be the + // outer scope. + break; + } + if (Ctx->isFunctionOrMethod()) continue; LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/false, - Consumer, Visited); + /*InBaseClass=*/false, Consumer, Visited); } } else if (!S->getParent()) { // Look into the translation unit scope. We walk through the translation @@ -1991,22 +2146,11 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, // doing so would force the normal C++ name-lookup code to look into the // translation unit decl when the IdentifierInfo chains would suffice. // Once we fix that problem (which is part of a more general "don't look - // in DeclContexts unless we have to" optimization), we can eliminate the - // TranslationUnit parameter entirely. + // in DeclContexts unless we have to" optimization), we can eliminate this. Entity = Result.getSema().Context.getTranslationUnitDecl(); LookupVisibleDecls(Entity, Result, /*QualifiedNameLookup=*/false, - Consumer, Visited); - } else { - // Walk through the declarations in this Scope. - for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); - D != DEnd; ++D) { - if (NamedDecl *ND = dyn_cast<NamedDecl>((Decl *)((*D).get()))) - if (Result.isAcceptableDecl(ND)) { - Consumer.FoundDecl(ND, Visited.checkHidden(ND)); - Visited.add(ND); - } - } - } + /*InBaseClass=*/false, Consumer, Visited); + } if (Entity) { // Lookup visible declarations in any namespaces found by using @@ -2015,8 +2159,8 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, llvm::tie(UI, UEnd) = UDirs.getNamespacesFor(Entity); for (; UI != UEnd; ++UI) LookupVisibleDecls(const_cast<DeclContext *>(UI->getNominatedNamespace()), - Result, /*QualifiedNameLookup=*/false, Consumer, - Visited); + Result, /*QualifiedNameLookup=*/false, + /*InBaseClass=*/false, Consumer, Visited); } // Lookup names in the parent scope. @@ -2051,8 +2195,8 @@ void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind); VisibleDeclsRecord Visited; ShadowContextRAII Shadow(Visited); - ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, Consumer, - Visited); + ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, + /*InBaseClass=*/false, Consumer, Visited); } //---------------------------------------------------------------------------- @@ -2075,7 +2219,7 @@ public: explicit TypoCorrectionConsumer(IdentifierInfo *Typo) : Typo(Typo->getName()) { } - virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding); + virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass); typedef llvm::SmallVector<NamedDecl *, 4>::const_iterator iterator; iterator begin() const { return BestResults.begin(); } @@ -2087,7 +2231,8 @@ public: } -void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding) { +void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, + bool InBaseClass) { // Don't consider hidden names for typo correction. if (Hiding) return; @@ -2140,11 +2285,19 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding) { /// \param EnteringContext whether we're entering the context described by /// the nested-name-specifier SS. /// +/// \param OPT when non-NULL, the search for visible declarations will +/// also walk the protocols in the qualified interfaces of \p OPT. +/// /// \returns true if the typo was corrected, in which case the \p Res /// structure will contain the results of name lookup for the /// corrected name. Otherwise, returns false. bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, - DeclContext *MemberContext, bool EnteringContext) { + DeclContext *MemberContext, bool EnteringContext, + const ObjCObjectPointerType *OPT) { + + if (Diags.hasFatalErrorOccurred()) + return false; + // We only attempt to correct typos for identifiers. IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo(); if (!Typo) @@ -2161,9 +2314,17 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, return false; TypoCorrectionConsumer Consumer(Typo); - if (MemberContext) + if (MemberContext) { LookupVisibleDecls(MemberContext, Res.getLookupKind(), Consumer); - else if (SS && SS->isSet()) { + + // Look in qualified interfaces. + if (OPT) { + for (ObjCObjectPointerType::qual_iterator + I = OPT->qual_begin(), E = OPT->qual_end(); + I != E; ++I) + LookupVisibleDecls(*I, Res.getLookupKind(), Consumer); + } + } else if (SS && SS->isSet()) { DeclContext *DC = computeDeclContext(*SS, EnteringContext); if (!DC) return false; @@ -2180,10 +2341,22 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, // have overloads of that name, though). TypoCorrectionConsumer::iterator I = Consumer.begin(); DeclarationName BestName = (*I)->getDeclName(); + + // If we've found an Objective-C ivar or property, don't perform + // name lookup again; we'll just return the result directly. + NamedDecl *FoundBest = 0; + if (isa<ObjCIvarDecl>(*I) || isa<ObjCPropertyDecl>(*I)) + FoundBest = *I; ++I; for(TypoCorrectionConsumer::iterator IEnd = Consumer.end(); I != IEnd; ++I) { if (BestName != (*I)->getDeclName()) return false; + + // FIXME: If there are both ivars and properties of the same name, + // don't return both because the callee can't handle two + // results. We really need to separate ivar lookup from property + // lookup to avoid this problem. + FoundBest = 0; } // BestName is the closest viable name to what the user @@ -2198,8 +2371,16 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, // success if we found something that was not ambiguous. Res.clear(); Res.setLookupName(BestName); - if (MemberContext) + + // If we found an ivar or property, add that result; no further + // lookup is required. + if (FoundBest) + Res.addDecl(FoundBest); + // If we're looking into the context of a member, perform qualified + // name lookup on the best name. + else if (MemberContext) LookupQualifiedName(Res, MemberContext); + // Perform lookup as if we had just parsed the best name. else LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false, EnteringContext); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 5892081..6ec4d1b 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -145,15 +145,12 @@ ImplicitConversionRank StandardConversionSequence::getRank() const { /// used as part of the ranking of standard conversion sequences /// (C++ 13.3.3.2p4). bool StandardConversionSequence::isPointerConversionToBool() const { - QualType FromType = QualType::getFromOpaquePtr(FromTypePtr); - QualType ToType = QualType::getFromOpaquePtr(ToTypePtr); - // Note that FromType has not necessarily been transformed by the // array-to-pointer or function-to-pointer implicit conversions, so // check for their presence as well as checking whether FromType is // a pointer. - if (ToType->isBooleanType() && - (FromType->isPointerType() || FromType->isBlockPointerType() || + if (getToType()->isBooleanType() && + (getFromType()->isPointerType() || getFromType()->isBlockPointerType() || First == ICK_Array_To_Pointer || First == ICK_Function_To_Pointer)) return true; @@ -167,8 +164,8 @@ bool StandardConversionSequence::isPointerConversionToBool() const { bool StandardConversionSequence:: isPointerConversionToVoidPointer(ASTContext& Context) const { - QualType FromType = QualType::getFromOpaquePtr(FromTypePtr); - QualType ToType = QualType::getFromOpaquePtr(ToTypePtr); + QualType FromType = getFromType(); + QualType ToType = getToType(); // Note that FromType has not necessarily been transformed by the // array-to-pointer implicit conversion, so check for its presence @@ -250,6 +247,9 @@ void ImplicitConversionSequence::DebugPrint() const { case EllipsisConversion: fprintf(stderr, "Ellipsis conversion"); break; + case AmbiguousConversion: + fprintf(stderr, "Ambiguous conversion"); + break; case BadConversion: fprintf(stderr, "Bad conversion"); break; @@ -258,6 +258,22 @@ void ImplicitConversionSequence::DebugPrint() const { fprintf(stderr, "\n"); } +void AmbiguousConversionSequence::construct() { + new (&conversions()) ConversionSet(); +} + +void AmbiguousConversionSequence::destruct() { + conversions().~ConversionSet(); +} + +void +AmbiguousConversionSequence::copyFrom(const AmbiguousConversionSequence &O) { + FromTypePtr = O.FromTypePtr; + ToTypePtr = O.ToTypePtr; + new (&conversions()) ConversionSet(O.conversions()); +} + + // IsOverload - Determine whether the given New declaration is an // overload of the declarations in Old. This routine returns false if // New and Old cannot be overloaded, e.g., if New has the same @@ -432,14 +448,14 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, OverloadCandidateSet Conversions; OverloadingResult UserDefResult = OR_Success; if (IsStandardConversion(From, ToType, InOverloadResolution, ICS.Standard)) - ICS.ConversionKind = ImplicitConversionSequence::StandardConversion; + ICS.setStandard(); else if (getLangOptions().CPlusPlus && (UserDefResult = IsUserDefinedConversion(From, ToType, ICS.UserDefined, Conversions, !SuppressUserConversions, AllowExplicit, ForceRValue, UserCast)) == OR_Success) { - ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion; + ICS.setUserDefined(); // C++ [over.ics.user]p4: // A conversion of an expression of class type to the same class // type is given Exact Match rank, and a conversion of an @@ -456,10 +472,10 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon))) { // Turn this into a "standard" conversion sequence, so that it // gets ranked with standard conversion sequences. - ICS.ConversionKind = ImplicitConversionSequence::StandardConversion; + ICS.setStandard(); ICS.Standard.setAsIdentityConversion(); - ICS.Standard.FromTypePtr = From->getType().getAsOpaquePtr(); - ICS.Standard.ToTypePtr = ToType.getAsOpaquePtr(); + ICS.Standard.setFromType(From->getType()); + ICS.Standard.setToType(ToType); ICS.Standard.CopyConstructor = Constructor; if (ToCanon != FromCanon) ICS.Standard.Second = ICK_Derived_To_Base; @@ -473,17 +489,21 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, // of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or // 13.3.1.6 in all cases, only standard conversion sequences and // ellipsis conversion sequences are allowed. - if (SuppressUserConversions && - ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion) - ICS.ConversionKind = ImplicitConversionSequence::BadConversion; - } else { - ICS.ConversionKind = ImplicitConversionSequence::BadConversion; - if (UserDefResult == OR_Ambiguous) { - for (OverloadCandidateSet::iterator Cand = Conversions.begin(); - Cand != Conversions.end(); ++Cand) - if (Cand->Viable) - ICS.ConversionFunctionSet.push_back(Cand->Function); + if (SuppressUserConversions && ICS.isUserDefined()) { + ICS.setBad(); + ICS.Bad.init(BadConversionSequence::suppressed_user, From, ToType); } + } else if (UserDefResult == OR_Ambiguous && !SuppressUserConversions) { + ICS.setAmbiguous(); + ICS.Ambiguous.setFromType(From->getType()); + ICS.Ambiguous.setToType(ToType); + for (OverloadCandidateSet::iterator Cand = Conversions.begin(); + Cand != Conversions.end(); ++Cand) + if (Cand->Viable) + ICS.Ambiguous.addConversion(Cand->Function); + } else { + ICS.setBad(); + ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType); } return ICS; @@ -524,7 +544,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, SCS.setAsIdentityConversion(); SCS.Deprecated = false; SCS.IncompatibleObjC = false; - SCS.FromTypePtr = FromType.getAsOpaquePtr(); + SCS.setFromType(FromType); SCS.CopyConstructor = 0; // There are no standard conversions for class types in C++, so @@ -573,7 +593,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // conversion (4.4). (C++ 4.2p2) SCS.Second = ICK_Identity; SCS.Third = ICK_Qualification; - SCS.ToTypePtr = ToType.getAsOpaquePtr(); + SCS.setToType(ToType); return true; } } else if (FromType->isFunctionType() && argIsLvalue == Expr::LV_Valid) { @@ -639,7 +659,6 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, } else if ((FromType->isIntegralType() || FromType->isEnumeralType()) && (ToType->isIntegralType() && !ToType->isEnumeralType())) { // Integral conversions (C++ 4.7). - // FIXME: isIntegralType shouldn't be true for enums in C++. SCS.Second = ICK_Integral_Conversion; FromType = ToType.getUnqualifiedType(); } else if (FromType->isFloatingType() && ToType->isFloatingType()) { @@ -656,7 +675,6 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, ((FromType->isIntegralType() || FromType->isEnumeralType()) && ToType->isFloatingType())) { // Floating-integral conversions (C++ 4.9). - // FIXME: isIntegralType shouldn't be true for enums in C++. SCS.Second = ICK_Floating_Integral; FromType = ToType.getUnqualifiedType(); } else if ((FromType->isComplexType() && ToType->isArithmeticType()) || @@ -726,7 +744,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, if (CanonFrom != CanonTo) return false; - SCS.ToTypePtr = FromType.getAsOpaquePtr(); + SCS.setToType(FromType); return true; } @@ -1546,8 +1564,7 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, // the argument of the constructor. // QualType ThisType = Constructor->getThisType(Context); - if (Best->Conversions[0].ConversionKind == - ImplicitConversionSequence::EllipsisConversion) + if (Best->Conversions[0].isEllipsis()) User.EllipsisConversion = true; else { User.Before = Best->Conversions[0].Standard; @@ -1555,9 +1572,9 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, } User.ConversionFunction = Constructor; User.After.setAsIdentityConversion(); - User.After.FromTypePtr - = ThisType->getAs<PointerType>()->getPointeeType().getAsOpaquePtr(); - User.After.ToTypePtr = ToType.getAsOpaquePtr(); + User.After.setFromType( + ThisType->getAs<PointerType>()->getPointeeType()); + User.After.setToType(ToType); return OR_Success; } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(Best->Function)) { @@ -1617,7 +1634,7 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) { << From->getType() << ToType << From->getSourceRange(); else return false; - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, &From, 1); return true; } @@ -1637,18 +1654,28 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1, // conversion sequence than an ellipsis conversion sequence // (13.3.3.1.3). // - if (ICS1.ConversionKind < ICS2.ConversionKind) - return ImplicitConversionSequence::Better; - else if (ICS2.ConversionKind < ICS1.ConversionKind) - return ImplicitConversionSequence::Worse; + // C++0x [over.best.ics]p10: + // For the purpose of ranking implicit conversion sequences as + // described in 13.3.3.2, the ambiguous conversion sequence is + // treated as a user-defined sequence that is indistinguishable + // from any other user-defined conversion sequence. + if (ICS1.getKind() < ICS2.getKind()) { + if (!(ICS1.isUserDefined() && ICS2.isAmbiguous())) + return ImplicitConversionSequence::Better; + } else if (ICS2.getKind() < ICS1.getKind()) { + if (!(ICS2.isUserDefined() && ICS1.isAmbiguous())) + return ImplicitConversionSequence::Worse; + } + + if (ICS1.isAmbiguous() || ICS2.isAmbiguous()) + return ImplicitConversionSequence::Indistinguishable; // Two implicit conversion sequences of the same form are // indistinguishable conversion sequences unless one of the // following rules apply: (C++ 13.3.3.2p3): - if (ICS1.ConversionKind == ImplicitConversionSequence::StandardConversion) + if (ICS1.isStandard()) return CompareStandardConversionSequences(ICS1.Standard, ICS2.Standard); - else if (ICS1.ConversionKind == - ImplicitConversionSequence::UserDefinedConversion) { + else if (ICS1.isUserDefined()) { // User-defined conversion sequence U1 is a better conversion // sequence than another user-defined conversion sequence U2 if // they contain the same user-defined conversion function or @@ -1741,8 +1768,8 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, // Both conversion sequences are conversions to void // pointers. Compare the source types to determine if there's an // inheritance relationship in their sources. - QualType FromType1 = QualType::getFromOpaquePtr(SCS1.FromTypePtr); - QualType FromType2 = QualType::getFromOpaquePtr(SCS2.FromTypePtr); + QualType FromType1 = SCS1.getFromType(); + QualType FromType2 = SCS2.getFromType(); // Adjust the types we're converting from via the array-to-pointer // conversion, if we need to. @@ -1798,8 +1825,8 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, // top-level cv-qualifiers, and the type to which the reference // initialized by S2 refers is more cv-qualified than the type // to which the reference initialized by S1 refers. - QualType T1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr); - QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr); + QualType T1 = SCS1.getToType(); + QualType T2 = SCS2.getToType(); T1 = Context.getCanonicalType(T1); T2 = Context.getCanonicalType(T2); Qualifiers T1Quals, T2Quals; @@ -1929,10 +1956,10 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1, ImplicitConversionSequence::CompareKind Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, const StandardConversionSequence& SCS2) { - QualType FromType1 = QualType::getFromOpaquePtr(SCS1.FromTypePtr); - QualType ToType1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr); - QualType FromType2 = QualType::getFromOpaquePtr(SCS2.FromTypePtr); - QualType ToType2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr); + QualType FromType1 = SCS1.getFromType(); + QualType ToType1 = SCS1.getToType(); + QualType FromType2 = SCS2.getFromType(); + QualType ToType2 = SCS2.getToType(); // Adjust the types we're converting from via the array-to-pointer // conversion, if we need to. @@ -2105,6 +2132,7 @@ Sema::TryCopyInitialization(Expr *From, QualType ToType, bool InOverloadResolution) { if (ToType->isReferenceType()) { ImplicitConversionSequence ICS; + ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType); CheckReferenceInit(From, ToType, /*FIXME:*/From->getLocStart(), SuppressUserConversions, @@ -2163,7 +2191,7 @@ bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType, /// parameter of the given member function (@c Method) from the /// expression @p From. ImplicitConversionSequence -Sema::TryObjectArgumentInitialization(QualType FromType, +Sema::TryObjectArgumentInitialization(QualType OrigFromType, CXXMethodDecl *Method, CXXRecordDecl *ActingContext) { QualType ClassType = Context.getTypeDeclType(ActingContext); @@ -2177,9 +2205,10 @@ Sema::TryObjectArgumentInitialization(QualType FromType, // to exit early. ImplicitConversionSequence ICS; ICS.Standard.setAsIdentityConversion(); - ICS.ConversionKind = ImplicitConversionSequence::BadConversion; + ICS.setBad(); // We need to have an object of class type. + QualType FromType = OrigFromType; if (const PointerType *PT = FromType->getAs<PointerType>()) FromType = PT->getPointeeType(); @@ -2199,8 +2228,11 @@ Sema::TryObjectArgumentInitialization(QualType FromType, QualType FromTypeCanon = Context.getCanonicalType(FromType); if (ImplicitParamType.getCVRQualifiers() != FromTypeCanon.getLocalCVRQualifiers() && - !ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) + !ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) { + ICS.Bad.init(BadConversionSequence::bad_qualifiers, + OrigFromType, ImplicitParamType); return ICS; + } // Check that we have either the same type or a derived type. It // affects the conversion rank. @@ -2209,13 +2241,15 @@ Sema::TryObjectArgumentInitialization(QualType FromType, ICS.Standard.Second = ICK_Identity; else if (IsDerivedFrom(FromType, ClassType)) ICS.Standard.Second = ICK_Derived_To_Base; - else + else { + ICS.Bad.init(BadConversionSequence::unrelated_class, FromType, ImplicitParamType); return ICS; + } // Success. Mark this as a reference binding. - ICS.ConversionKind = ImplicitConversionSequence::StandardConversion; - ICS.Standard.FromTypePtr = FromType.getAsOpaquePtr(); - ICS.Standard.ToTypePtr = ImplicitParamType.getAsOpaquePtr(); + ICS.setStandard(); + ICS.Standard.setFromType(FromType); + ICS.Standard.setToType(ImplicitParamType); ICS.Standard.ReferenceBinding = true; ICS.Standard.DirectBinding = true; ICS.Standard.RRefBinding = false; @@ -2244,7 +2278,7 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method) { ImplicitConversionSequence ICS = TryObjectArgumentInitialization(From->getType(), Method, Method->getParent()); - if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) + if (ICS.isBad()) return Diag(From->getSourceRange().getBegin(), diag::err_implicit_object_parameter_init) << ImplicitParamRecordType << FromRecordType << From->getSourceRange(); @@ -2276,8 +2310,8 @@ ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) { /// of the expression From to bool (C++0x [conv]p3). bool Sema::PerformContextuallyConvertToBool(Expr *&From) { ImplicitConversionSequence ICS = TryContextuallyConvertToBool(From); - if (!PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting)) - return false; + if (!ICS.isBad()) + return PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting); if (!DiagnoseMultipleUserDefinedConversion(From, Context.BoolTy)) return Diag(From->getSourceRange().getBegin(), @@ -2307,8 +2341,6 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, const FunctionProtoType* Proto = dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>()); assert(Proto && "Functions without a prototype cannot be overloaded"); - assert(!isa<CXXConversionDecl>(Function) && - "Use AddConversionCandidate for conversion functions"); assert(!Function->getDescribedFunctionTemplate() && "Use AddTemplateOverloadCandidate for function templates"); @@ -2363,6 +2395,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, if ((NumArgs + (PartialOverloading && NumArgs)) > NumArgsInProto && !Proto->isVariadic()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_too_many_arguments; return; } @@ -2375,6 +2408,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, if (NumArgs < MinRequiredArgs && !PartialOverloading) { // Not enough arguments. Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_too_few_arguments; return; } @@ -2392,35 +2426,16 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, = TryCopyInitialization(Args[ArgIdx], ParamType, SuppressUserConversions, ForceRValue, /*InOverloadResolution=*/true); - if (Candidate.Conversions[ArgIdx].ConversionKind - == ImplicitConversionSequence::BadConversion) { - // 13.3.3.1-p10 If several different sequences of conversions exist that - // each convert the argument to the parameter type, the implicit conversion - // sequence associated with the parameter is defined to be the unique conversion - // sequence designated the ambiguous conversion sequence. For the purpose of - // ranking implicit conversion sequences as described in 13.3.3.2, the ambiguous - // conversion sequence is treated as a user-defined sequence that is - // indistinguishable from any other user-defined conversion sequence - if (!Candidate.Conversions[ArgIdx].ConversionFunctionSet.empty()) { - Candidate.Conversions[ArgIdx].ConversionKind = - ImplicitConversionSequence::UserDefinedConversion; - // Set the conversion function to one of them. As due to ambiguity, - // they carry the same weight and is needed for overload resolution - // later. - Candidate.Conversions[ArgIdx].UserDefined.ConversionFunction = - Candidate.Conversions[ArgIdx].ConversionFunctionSet[0]; - } - else { - Candidate.Viable = false; - break; - } + if (Candidate.Conversions[ArgIdx].isBad()) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; + break; } } else { // (C++ 13.3.2p2): For the purposes of overload resolution, any // argument for which there is no corresponding parameter is // considered to ""match the ellipsis" (C+ 13.3.3.1.3). - Candidate.Conversions[ArgIdx].ConversionKind - = ImplicitConversionSequence::EllipsisConversion; + Candidate.Conversions[ArgIdx].setEllipsis(); } } } @@ -2470,8 +2485,6 @@ void Sema::AddMethodCandidate(NamedDecl *Decl, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions, bool ForceRValue) { - - // FIXME: use this CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(Decl->getDeclContext()); if (isa<UsingShadowDecl>(Decl)) @@ -2509,8 +2522,6 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, const FunctionProtoType* Proto = dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>()); assert(Proto && "Methods without a prototype cannot be overloaded"); - assert(!isa<CXXConversionDecl>(Method) && - "Use AddConversionCandidate for conversion functions"); assert(!isa<CXXConstructorDecl>(Method) && "Use AddOverloadCandidate for constructors"); @@ -2534,6 +2545,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, // list (8.3.5). if (NumArgs > NumArgsInProto && !Proto->isVariadic()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_too_many_arguments; return; } @@ -2546,6 +2558,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, if (NumArgs < MinRequiredArgs) { // Not enough arguments. Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_too_few_arguments; return; } @@ -2560,9 +2573,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, // parameter. Candidate.Conversions[0] = TryObjectArgumentInitialization(ObjectType, Method, ActingContext); - if (Candidate.Conversions[0].ConversionKind - == ImplicitConversionSequence::BadConversion) { + if (Candidate.Conversions[0].isBad()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; return; } } @@ -2580,17 +2593,16 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext, = TryCopyInitialization(Args[ArgIdx], ParamType, SuppressUserConversions, ForceRValue, /*InOverloadResolution=*/true); - if (Candidate.Conversions[ArgIdx + 1].ConversionKind - == ImplicitConversionSequence::BadConversion) { + if (Candidate.Conversions[ArgIdx + 1].isBad()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; break; } } else { // (C++ 13.3.2p2): For the purposes of overload resolution, any // argument for which there is no corresponding parameter is // considered to ""match the ellipsis" (C+ 13.3.3.1.3). - Candidate.Conversions[ArgIdx + 1].ConversionKind - = ImplicitConversionSequence::EllipsisConversion; + Candidate.Conversions[ArgIdx + 1].setEllipsis(); } } } @@ -2675,6 +2687,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, OverloadCandidate &Candidate = CandidateSet.back(); Candidate.Function = FunctionTemplate->getTemplatedDecl(); Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_deduction; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; return; @@ -2714,9 +2727,8 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; Candidate.FinalConversion.setAsIdentityConversion(); - Candidate.FinalConversion.FromTypePtr - = Conversion->getConversionType().getAsOpaquePtr(); - Candidate.FinalConversion.ToTypePtr = ToType.getAsOpaquePtr(); + Candidate.FinalConversion.setFromType(Conversion->getConversionType()); + Candidate.FinalConversion.setToType(ToType); // Determine the implicit conversion sequence for the implicit // object parameter. @@ -2730,9 +2742,9 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, // in overload resolution. if (Candidate.Conversions[0].Standard.Second == ICK_Derived_To_Base) Candidate.Conversions[0].Standard.Second = ICK_Identity; - if (Candidate.Conversions[0].ConversionKind - == ImplicitConversionSequence::BadConversion) { + if (Candidate.Conversions[0].isBad()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; return; } @@ -2744,6 +2756,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType(); if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; return; } @@ -2774,13 +2787,14 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, /*ForceRValue=*/false, /*InOverloadResolution=*/false); - switch (ICS.ConversionKind) { + switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: Candidate.FinalConversion = ICS.Standard; break; case ImplicitConversionSequence::BadConversion: Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; break; default: @@ -2852,16 +2866,16 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, // object parameter. ImplicitConversionSequence ObjectInit = TryObjectArgumentInitialization(ObjectType, Conversion, ActingContext); - if (ObjectInit.ConversionKind == ImplicitConversionSequence::BadConversion) { + if (ObjectInit.isBad()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; return; } // The first conversion is actually a user-defined conversion whose // first conversion is ObjectInit's standard conversion (which is // effectively a reference binding). Record it as such. - Candidate.Conversions[0].ConversionKind - = ImplicitConversionSequence::UserDefinedConversion; + Candidate.Conversions[0].setUserDefined(); Candidate.Conversions[0].UserDefined.Before = ObjectInit.Standard; Candidate.Conversions[0].UserDefined.EllipsisConversion = false; Candidate.Conversions[0].UserDefined.ConversionFunction = Conversion; @@ -2877,6 +2891,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, // list (8.3.5). if (NumArgs > NumArgsInProto && !Proto->isVariadic()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_too_many_arguments; return; } @@ -2885,6 +2900,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, if (NumArgs < NumArgsInProto) { // Not enough arguments. Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_too_few_arguments; return; } @@ -2902,17 +2918,16 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, /*SuppressUserConversions=*/false, /*ForceRValue=*/false, /*InOverloadResolution=*/false); - if (Candidate.Conversions[ArgIdx + 1].ConversionKind - == ImplicitConversionSequence::BadConversion) { + if (Candidate.Conversions[ArgIdx + 1].isBad()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; break; } } else { // (C++ 13.3.2p2): For the purposes of overload resolution, any // argument for which there is no corresponding parameter is // considered to ""match the ellipsis" (C+ 13.3.3.1.3). - Candidate.Conversions[ArgIdx + 1].ConversionKind - = ImplicitConversionSequence::EllipsisConversion; + Candidate.Conversions[ArgIdx + 1].setEllipsis(); } } } @@ -3046,9 +3061,9 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, /*ForceRValue=*/false, /*InOverloadResolution=*/false); } - if (Candidate.Conversions[ArgIdx].ConversionKind - == ImplicitConversionSequence::BadConversion) { + if (Candidate.Conversions[ArgIdx].isBad()) { Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_bad_conversion; break; } } @@ -4274,130 +4289,386 @@ OverloadingResult Sema::BestViableFunction(OverloadCandidateSet& CandidateSet, return OR_Success; } +namespace { + +enum OverloadCandidateKind { + oc_function, + oc_method, + oc_constructor, + oc_function_template, + oc_method_template, + oc_constructor_template, + oc_implicit_default_constructor, + oc_implicit_copy_constructor, + oc_implicit_copy_assignment +}; + +OverloadCandidateKind ClassifyOverloadCandidate(Sema &S, + FunctionDecl *Fn, + std::string &Description) { + bool isTemplate = false; + + if (FunctionTemplateDecl *FunTmpl = Fn->getPrimaryTemplate()) { + isTemplate = true; + Description = S.getTemplateArgumentBindingsText( + FunTmpl->getTemplateParameters(), *Fn->getTemplateSpecializationArgs()); + } + + if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Fn)) { + if (!Ctor->isImplicit()) + return isTemplate ? oc_constructor_template : oc_constructor; + + return Ctor->isCopyConstructor() ? oc_implicit_copy_constructor + : oc_implicit_default_constructor; + } + + if (CXXMethodDecl *Meth = dyn_cast<CXXMethodDecl>(Fn)) { + // This actually gets spelled 'candidate function' for now, but + // it doesn't hurt to split it out. + if (!Meth->isImplicit()) + return isTemplate ? oc_method_template : oc_method; + + assert(Meth->isCopyAssignment() + && "implicit method is not copy assignment operator?"); + return oc_implicit_copy_assignment; + } + + return isTemplate ? oc_function_template : oc_function; +} + +} // end anonymous namespace + +// Notes the location of an overload candidate. +void Sema::NoteOverloadCandidate(FunctionDecl *Fn) { + std::string FnDesc; + OverloadCandidateKind K = ClassifyOverloadCandidate(*this, Fn, FnDesc); + Diag(Fn->getLocation(), diag::note_ovl_candidate) + << (unsigned) K << FnDesc; +} + +/// Diagnoses an ambiguous conversion. The partial diagnostic is the +/// "lead" diagnostic; it will be given two arguments, the source and +/// target types of the conversion. +void Sema::DiagnoseAmbiguousConversion(const ImplicitConversionSequence &ICS, + SourceLocation CaretLoc, + const PartialDiagnostic &PDiag) { + Diag(CaretLoc, PDiag) + << ICS.Ambiguous.getFromType() << ICS.Ambiguous.getToType(); + for (AmbiguousConversionSequence::const_iterator + I = ICS.Ambiguous.begin(), E = ICS.Ambiguous.end(); I != E; ++I) { + NoteOverloadCandidate(*I); + } +} + +namespace { + +void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { + const ImplicitConversionSequence &Conv = Cand->Conversions[I]; + assert(Conv.isBad()); + assert(Cand->Function && "for now, candidate must be a function"); + FunctionDecl *Fn = Cand->Function; + + // There's a conversion slot for the object argument if this is a + // non-constructor method. Note that 'I' corresponds the + // conversion-slot index. + bool isObjectArgument = false; + if (isa<CXXMethodDecl>(Fn) && !isa<CXXConstructorDecl>(Fn)) { + if (I == 0) + isObjectArgument = true; + else + I--; + } + + std::string FnDesc; + OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, FnDesc); + + Expr *FromExpr = Conv.Bad.FromExpr; + QualType FromTy = Conv.Bad.getFromType(); + QualType ToTy = Conv.Bad.getToType(); + + // Do some hand-waving analysis to see if the non-viability is due to a + CanQualType CFromTy = S.Context.getCanonicalType(FromTy); + CanQualType CToTy = S.Context.getCanonicalType(ToTy); + if (CanQual<ReferenceType> RT = CToTy->getAs<ReferenceType>()) + CToTy = RT->getPointeeType(); + else { + // TODO: detect and diagnose the full richness of const mismatches. + if (CanQual<PointerType> FromPT = CFromTy->getAs<PointerType>()) + if (CanQual<PointerType> ToPT = CToTy->getAs<PointerType>()) + CFromTy = FromPT->getPointeeType(), CToTy = ToPT->getPointeeType(); + } + + if (CToTy.getUnqualifiedType() == CFromTy.getUnqualifiedType() && + !CToTy.isAtLeastAsQualifiedAs(CFromTy)) { + // It is dumb that we have to do this here. + while (isa<ArrayType>(CFromTy)) + CFromTy = CFromTy->getAs<ArrayType>()->getElementType(); + while (isa<ArrayType>(CToTy)) + CToTy = CFromTy->getAs<ArrayType>()->getElementType(); + + Qualifiers FromQs = CFromTy.getQualifiers(); + Qualifiers ToQs = CToTy.getQualifiers(); + + if (FromQs.getAddressSpace() != ToQs.getAddressSpace()) { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace) + << (unsigned) FnKind << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromTy + << FromQs.getAddressSpace() << ToQs.getAddressSpace() + << (unsigned) isObjectArgument << I+1; + return; + } + + unsigned CVR = FromQs.getCVRQualifiers() & ~ToQs.getCVRQualifiers(); + assert(CVR && "unexpected qualifiers mismatch"); + + if (isObjectArgument) { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_cvr_this) + << (unsigned) FnKind << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromTy << (CVR - 1); + } else { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_cvr) + << (unsigned) FnKind << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromTy << (CVR - 1) << I+1; + } + return; + } + + // TODO: specialize more based on the kind of mismatch + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv) + << (unsigned) FnKind << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromTy << ToTy << (unsigned) isObjectArgument << I+1; +} + +void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand, + unsigned NumFormalArgs) { + // TODO: treat calls to a missing default constructor as a special case + + FunctionDecl *Fn = Cand->Function; + const FunctionProtoType *FnTy = Fn->getType()->getAs<FunctionProtoType>(); + + unsigned MinParams = Fn->getMinRequiredArguments(); + + // at least / at most / exactly + unsigned mode, modeCount; + if (NumFormalArgs < MinParams) { + assert(Cand->FailureKind == ovl_fail_too_few_arguments); + if (MinParams != FnTy->getNumArgs() || FnTy->isVariadic()) + mode = 0; // "at least" + else + mode = 2; // "exactly" + modeCount = MinParams; + } else { + assert(Cand->FailureKind == ovl_fail_too_many_arguments); + if (MinParams != FnTy->getNumArgs()) + mode = 1; // "at most" + else + mode = 2; // "exactly" + modeCount = FnTy->getNumArgs(); + } + + std::string Description; + OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, Description); + + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity) + << (unsigned) FnKind << Description << mode << modeCount << NumFormalArgs; +} + +void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, + Expr **Args, unsigned NumArgs) { + FunctionDecl *Fn = Cand->Function; + + // Note deleted candidates, but only if they're viable. + if (Cand->Viable && (Fn->isDeleted() || Fn->hasAttr<UnavailableAttr>())) { + std::string FnDesc; + OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, FnDesc); + + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted) + << FnKind << FnDesc << Fn->isDeleted(); + return; + } + + // We don't really have anything else to say about viable candidates. + if (Cand->Viable) { + S.NoteOverloadCandidate(Fn); + return; + } + + switch (Cand->FailureKind) { + case ovl_fail_too_many_arguments: + case ovl_fail_too_few_arguments: + return DiagnoseArityMismatch(S, Cand, NumArgs); + + case ovl_fail_bad_deduction: + return S.NoteOverloadCandidate(Fn); + + case ovl_fail_bad_conversion: + for (unsigned I = 0, N = Cand->Conversions.size(); I != N; ++I) + if (Cand->Conversions[I].isBad()) + return DiagnoseBadConversion(S, Cand, I); + + // FIXME: this currently happens when we're called from SemaInit + // when user-conversion overload fails. Figure out how to handle + // those conditions and diagnose them well. + return S.NoteOverloadCandidate(Fn); + } +} + +void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) { + // Desugar the type of the surrogate down to a function type, + // retaining as many typedefs as possible while still showing + // the function type (and, therefore, its parameter types). + QualType FnType = Cand->Surrogate->getConversionType(); + bool isLValueReference = false; + bool isRValueReference = false; + bool isPointer = false; + if (const LValueReferenceType *FnTypeRef = + FnType->getAs<LValueReferenceType>()) { + FnType = FnTypeRef->getPointeeType(); + isLValueReference = true; + } else if (const RValueReferenceType *FnTypeRef = + FnType->getAs<RValueReferenceType>()) { + FnType = FnTypeRef->getPointeeType(); + isRValueReference = true; + } + if (const PointerType *FnTypePtr = FnType->getAs<PointerType>()) { + FnType = FnTypePtr->getPointeeType(); + isPointer = true; + } + // Desugar down to a function type. + FnType = QualType(FnType->getAs<FunctionType>(), 0); + // Reconstruct the pointer/reference as appropriate. + if (isPointer) FnType = S.Context.getPointerType(FnType); + if (isRValueReference) FnType = S.Context.getRValueReferenceType(FnType); + if (isLValueReference) FnType = S.Context.getLValueReferenceType(FnType); + + S.Diag(Cand->Surrogate->getLocation(), diag::note_ovl_surrogate_cand) + << FnType; +} + +void NoteBuiltinOperatorCandidate(Sema &S, + const char *Opc, + SourceLocation OpLoc, + OverloadCandidate *Cand) { + assert(Cand->Conversions.size() <= 2 && "builtin operator is not binary"); + std::string TypeStr("operator"); + TypeStr += Opc; + TypeStr += "("; + TypeStr += Cand->BuiltinTypes.ParamTypes[0].getAsString(); + if (Cand->Conversions.size() == 1) { + TypeStr += ")"; + S.Diag(OpLoc, diag::note_ovl_builtin_unary_candidate) << TypeStr; + } else { + TypeStr += ", "; + TypeStr += Cand->BuiltinTypes.ParamTypes[1].getAsString(); + TypeStr += ")"; + S.Diag(OpLoc, diag::note_ovl_builtin_binary_candidate) << TypeStr; + } +} + +void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc, + OverloadCandidate *Cand) { + unsigned NoOperands = Cand->Conversions.size(); + for (unsigned ArgIdx = 0; ArgIdx < NoOperands; ++ArgIdx) { + const ImplicitConversionSequence &ICS = Cand->Conversions[ArgIdx]; + if (ICS.isBad()) break; // all meaningless after first invalid + if (!ICS.isAmbiguous()) continue; + + S.DiagnoseAmbiguousConversion(ICS, OpLoc, + PDiag(diag::note_ambiguous_type_conversion)); + } +} + +struct CompareOverloadCandidatesForDisplay { + Sema &S; + CompareOverloadCandidatesForDisplay(Sema &S) : S(S) {} + + bool operator()(const OverloadCandidate *L, + const OverloadCandidate *R) { + // Order first by viability. + if (L->Viable) { + if (!R->Viable) return true; + + // TODO: introduce a tri-valued comparison for overload + // candidates. Would be more worthwhile if we had a sort + // that could exploit it. + if (S.isBetterOverloadCandidate(*L, *R)) return true; + if (S.isBetterOverloadCandidate(*R, *L)) return false; + } else if (R->Viable) + return false; + + // Put declared functions first. + if (L->Function) { + if (!R->Function) return true; + return S.SourceMgr.isBeforeInTranslationUnit(L->Function->getLocation(), + R->Function->getLocation()); + } else if (R->Function) return false; + + // Then surrogates. + if (L->IsSurrogate) { + if (!R->IsSurrogate) return true; + return S.SourceMgr.isBeforeInTranslationUnit(L->Surrogate->getLocation(), + R->Surrogate->getLocation()); + } else if (R->IsSurrogate) return false; + + // And builtins just come in a jumble. + return false; + } +}; + +} // end anonymous namespace + /// PrintOverloadCandidates - When overload resolution fails, prints /// diagnostic messages containing the candidates in the candidate -/// set. If OnlyViable is true, only viable candidates will be printed. +/// set. void Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, - bool OnlyViable, + OverloadCandidateDisplayKind OCD, + Expr **Args, unsigned NumArgs, const char *Opc, SourceLocation OpLoc) { - OverloadCandidateSet::iterator Cand = CandidateSet.begin(), - LastCand = CandidateSet.end(); - bool Reported = false; - for (; Cand != LastCand; ++Cand) { - if (Cand->Viable || !OnlyViable) { - if (Cand->Function) { - if (Cand->Function->isDeleted() || - Cand->Function->getAttr<UnavailableAttr>()) { - // Deleted or "unavailable" function. - Diag(Cand->Function->getLocation(), diag::err_ovl_candidate_deleted) - << Cand->Function->isDeleted(); - } else if (FunctionTemplateDecl *FunTmpl - = Cand->Function->getPrimaryTemplate()) { - // Function template specialization - // FIXME: Give a better reason! - Diag(Cand->Function->getLocation(), diag::err_ovl_template_candidate) - << getTemplateArgumentBindingsText(FunTmpl->getTemplateParameters(), - *Cand->Function->getTemplateSpecializationArgs()); - } else { - // Normal function - bool errReported = false; - if (!Cand->Viable && Cand->Conversions.size() > 0) { - for (int i = Cand->Conversions.size()-1; i >= 0; i--) { - const ImplicitConversionSequence &Conversion = - Cand->Conversions[i]; - if ((Conversion.ConversionKind != - ImplicitConversionSequence::BadConversion) || - Conversion.ConversionFunctionSet.size() == 0) - continue; - Diag(Cand->Function->getLocation(), - diag::err_ovl_candidate_not_viable) << (i+1); - errReported = true; - for (int j = Conversion.ConversionFunctionSet.size()-1; - j >= 0; j--) { - FunctionDecl *Func = Conversion.ConversionFunctionSet[j]; - Diag(Func->getLocation(), diag::err_ovl_candidate); - } - } - } - if (!errReported) - Diag(Cand->Function->getLocation(), diag::err_ovl_candidate); - } - } else if (Cand->IsSurrogate) { - // Desugar the type of the surrogate down to a function type, - // retaining as many typedefs as possible while still showing - // the function type (and, therefore, its parameter types). - QualType FnType = Cand->Surrogate->getConversionType(); - bool isLValueReference = false; - bool isRValueReference = false; - bool isPointer = false; - if (const LValueReferenceType *FnTypeRef = - FnType->getAs<LValueReferenceType>()) { - FnType = FnTypeRef->getPointeeType(); - isLValueReference = true; - } else if (const RValueReferenceType *FnTypeRef = - FnType->getAs<RValueReferenceType>()) { - FnType = FnTypeRef->getPointeeType(); - isRValueReference = true; - } - if (const PointerType *FnTypePtr = FnType->getAs<PointerType>()) { - FnType = FnTypePtr->getPointeeType(); - isPointer = true; - } - // Desugar down to a function type. - FnType = QualType(FnType->getAs<FunctionType>(), 0); - // Reconstruct the pointer/reference as appropriate. - if (isPointer) FnType = Context.getPointerType(FnType); - if (isRValueReference) FnType = Context.getRValueReferenceType(FnType); - if (isLValueReference) FnType = Context.getLValueReferenceType(FnType); - - Diag(Cand->Surrogate->getLocation(), diag::err_ovl_surrogate_cand) - << FnType; - } else if (OnlyViable) { - assert(Cand->Conversions.size() <= 2 && - "builtin-binary-operator-not-binary"); - std::string TypeStr("operator"); - TypeStr += Opc; - TypeStr += "("; - TypeStr += Cand->BuiltinTypes.ParamTypes[0].getAsString(); - if (Cand->Conversions.size() == 1) { - TypeStr += ")"; - Diag(OpLoc, diag::err_ovl_builtin_unary_candidate) << TypeStr; - } - else { - TypeStr += ", "; - TypeStr += Cand->BuiltinTypes.ParamTypes[1].getAsString(); - TypeStr += ")"; - Diag(OpLoc, diag::err_ovl_builtin_binary_candidate) << TypeStr; - } - } - else if (!Cand->Viable && !Reported) { - // Non-viability might be due to ambiguous user-defined conversions, - // needed for built-in operators. Report them as well, but only once - // as we have typically many built-in candidates. - unsigned NoOperands = Cand->Conversions.size(); - for (unsigned ArgIdx = 0; ArgIdx < NoOperands; ++ArgIdx) { - const ImplicitConversionSequence &ICS = Cand->Conversions[ArgIdx]; - if (ICS.ConversionKind != ImplicitConversionSequence::BadConversion || - ICS.ConversionFunctionSet.empty()) - continue; - if (CXXConversionDecl *Func = dyn_cast<CXXConversionDecl>( - Cand->Conversions[ArgIdx].ConversionFunctionSet[0])) { - QualType FromTy = - QualType( - static_cast<Type*>(ICS.UserDefined.Before.FromTypePtr),0); - Diag(OpLoc,diag::note_ambiguous_type_conversion) - << FromTy << Func->getConversionType(); - } - for (unsigned j = 0; j < ICS.ConversionFunctionSet.size(); j++) { - FunctionDecl *Func = - Cand->Conversions[ArgIdx].ConversionFunctionSet[j]; - Diag(Func->getLocation(),diag::err_ovl_candidate); - } - } - Reported = true; + // Sort the candidates by viability and position. Sorting directly would + // be prohibitive, so we make a set of pointers and sort those. + llvm::SmallVector<OverloadCandidate*, 32> Cands; + if (OCD == OCD_AllCandidates) Cands.reserve(CandidateSet.size()); + for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), + LastCand = CandidateSet.end(); + Cand != LastCand; ++Cand) + if (Cand->Viable || OCD == OCD_AllCandidates) + Cands.push_back(Cand); + std::sort(Cands.begin(), Cands.end(), + CompareOverloadCandidatesForDisplay(*this)); + + bool ReportedAmbiguousConversions = false; + + llvm::SmallVectorImpl<OverloadCandidate*>::iterator I, E; + for (I = Cands.begin(), E = Cands.end(); I != E; ++I) { + OverloadCandidate *Cand = *I; + + if (Cand->Function) + NoteFunctionCandidate(*this, Cand, Args, NumArgs); + else if (Cand->IsSurrogate) + NoteSurrogateCandidate(*this, Cand); + + // This a builtin candidate. We do not, in general, want to list + // every possible builtin candidate. + else if (Cand->Viable) { + // Generally we only see ambiguities including viable builtin + // operators if overload resolution got screwed up by an + // ambiguous user-defined conversion. + // + // FIXME: It's quite possible for different conversions to see + // different ambiguities, though. + if (!ReportedAmbiguousConversions) { + NoteAmbiguousUserConversions(*this, OpLoc, Cand); + ReportedAmbiguousConversions = true; } + + // If this is a viable builtin, print it. + NoteBuiltinOperatorCandidate(*this, Opc, OpLoc, Cand); } } } @@ -4586,7 +4857,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, PDiag(), PDiag(diag::err_addr_ovl_ambiguous) << TemplateMatches[0]->getDeclName(), - PDiag(diag::err_ovl_template_candidate)); + PDiag(diag::note_ovl_candidate) + << (unsigned) oc_function_template); MarkDeclarationReferenced(From->getLocStart(), Result); return Result; } @@ -4611,7 +4883,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous) << RemainingMatches[0]->getDeclName(); for (unsigned I = 0, N = RemainingMatches.size(); I != N; ++I) - Diag(RemainingMatches[I]->getLocation(), diag::err_ovl_candidate); + NoteOverloadCandidate(RemainingMatches[I]); return 0; } @@ -4681,7 +4953,6 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) { // resulting template argument list is used to generate a single // function template specialization, which is added to the set of // overloaded functions considered. - // FIXME: We don't really want to build the specialization here, do we? FunctionDecl *Specialization = 0; TemplateDeductionInfo Info(Context); if (TemplateDeductionResult Result @@ -4906,13 +5177,13 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE, Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_no_viable_function_in_call) << ULE->getName() << Fn->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); break; case OR_Ambiguous: Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_ambiguous_call) << ULE->getName() << Fn->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, NumArgs); break; case OR_Deleted: @@ -4920,7 +5191,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE, << Best->Function->isDeleted() << ULE->getName() << Fn->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); break; } @@ -5075,7 +5346,7 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, Diag(OpLoc, diag::err_ovl_ambiguous_oper) << UnaryOperator::getOpcodeStr(Opc) << Input->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true, + PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, NumArgs, UnaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); @@ -5084,7 +5355,7 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, << Best->Function->isDeleted() << UnaryOperator::getOpcodeStr(Opc) << Input->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); return ExprError(); } @@ -5291,7 +5562,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, assert(Result.isInvalid() && "C++ binary operator overloading is missing candidates!"); if (Result.isInvalid()) - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false, + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, 2, BinaryOperator::getOpcodeStr(Opc), OpLoc); return move(Result); } @@ -5300,7 +5571,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, Diag(OpLoc, diag::err_ovl_ambiguous_oper) << BinaryOperator::getOpcodeStr(Opc) << Args[0]->getSourceRange() << Args[1]->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true, + PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, 2, BinaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); @@ -5309,9 +5580,9 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, << Best->Function->isDeleted() << BinaryOperator::getOpcodeStr(Opc) << Args[0]->getSourceRange() << Args[1]->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, 2); return ExprError(); - } + } // We matched a built-in operator; build it. return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); @@ -5411,22 +5682,23 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, } case OR_No_Viable_Function: { - // No viable function; try to create a built-in operation, which will - // produce an error. Then, show the non-viable candidates. - OwningExprResult Result = - CreateBuiltinArraySubscriptExpr(move(Base), LLoc, move(Idx), RLoc); - assert(Result.isInvalid() && - "C++ subscript operator overloading is missing candidates!"); - if (Result.isInvalid()) - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false, - "[]", LLoc); - return move(Result); + if (CandidateSet.empty()) + Diag(LLoc, diag::err_ovl_no_oper) + << Args[0]->getType() << /*subscript*/ 0 + << Args[0]->getSourceRange() << Args[1]->getSourceRange(); + else + Diag(LLoc, diag::err_ovl_no_viable_subscript) + << Args[0]->getType() + << Args[0]->getSourceRange() << Args[1]->getSourceRange(); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, 2, + "[]", LLoc); + return ExprError(); } case OR_Ambiguous: Diag(LLoc, diag::err_ovl_ambiguous_oper) << "[]" << Args[0]->getSourceRange() << Args[1]->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true, + PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, 2, "[]", LLoc); return ExprError(); @@ -5434,7 +5706,8 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, Diag(LLoc, diag::err_ovl_deleted_oper) << Best->Function->isDeleted() << "[]" << Args[0]->getSourceRange() << Args[1]->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, 2, + "[]", LLoc); return ExprError(); } @@ -5518,14 +5791,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, Diag(UnresExpr->getMemberLoc(), diag::err_ovl_no_viable_member_function_in_call) << DeclName << MemExprE->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); // FIXME: Leaking incoming expressions! return ExprError(); case OR_Ambiguous: Diag(UnresExpr->getMemberLoc(), diag::err_ovl_ambiguous_member_call) << DeclName << MemExprE->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); // FIXME: Leaking incoming expressions! return ExprError(); @@ -5533,7 +5806,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, Diag(UnresExpr->getMemberLoc(), diag::err_ovl_deleted_member_call) << Best->Function->isDeleted() << DeclName << MemExprE->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); // FIXME: Leaking incoming expressions! return ExprError(); } @@ -5636,9 +5909,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // functions for each conversion function declared in an // accessible base class provided the function is not hidden // within T by another intervening declaration. - // FIXME: Look in base classes for more conversion operators! const UnresolvedSet *Conversions - = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions(); + = cast<CXXRecordDecl>(Record->getDecl())->getVisibleConversionFunctions(); for (UnresolvedSet::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { NamedDecl *D = *I; @@ -5674,17 +5946,22 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, break; case OR_No_Viable_Function: - Diag(Object->getSourceRange().getBegin(), - diag::err_ovl_no_viable_object_call) - << Object->getType() << Object->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + if (CandidateSet.empty()) + Diag(Object->getSourceRange().getBegin(), diag::err_ovl_no_oper) + << Object->getType() << /*call*/ 1 + << Object->getSourceRange(); + else + Diag(Object->getSourceRange().getBegin(), + diag::err_ovl_no_viable_object_call) + << Object->getType() << Object->getSourceRange(); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); break; case OR_Ambiguous: Diag(Object->getSourceRange().getBegin(), diag::err_ovl_ambiguous_object_call) << Object->getType() << Object->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, NumArgs); break; case OR_Deleted: @@ -5692,7 +5969,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, diag::err_ovl_deleted_object_call) << Best->Function->isDeleted() << Object->getType() << Object->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); break; } @@ -5873,20 +6150,20 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { else Diag(OpLoc, diag::err_ovl_no_viable_oper) << "operator->" << Base->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, &Base, 1); return ExprError(); case OR_Ambiguous: Diag(OpLoc, diag::err_ovl_ambiguous_oper) << "->" << Base->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, &Base, 1); return ExprError(); case OR_Deleted: Diag(OpLoc, diag::err_ovl_deleted_oper) << Best->Function->isDeleted() << "->" << Base->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, &Base, 1); return ExprError(); } @@ -6020,9 +6297,14 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { MemExpr->getMemberLoc(), Fn->getType(), TemplateArgs); - } else - Base = new (Context) CXXThisExpr(SourceLocation(), - MemExpr->getBaseType()); + } else { + SourceLocation Loc = MemExpr->getMemberLoc(); + if (MemExpr->getQualifier()) + Loc = MemExpr->getQualifierRange().getBegin(); + Base = new (Context) CXXThisExpr(Loc, + MemExpr->getBaseType(), + /*isImplicit=*/true); + } } else Base = MemExpr->getBase()->Retain(); diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index 3613d60..20add00 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -16,6 +16,7 @@ #define LLVM_CLANG_SEMA_OVERLOAD_H #include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" #include "clang/AST/Type.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" @@ -149,6 +150,15 @@ namespace clang { /// conversions. CXXConstructorDecl *CopyConstructor; + void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); } + void setToType(QualType T) { ToTypePtr = T.getAsOpaquePtr(); } + QualType getFromType() const { + return QualType::getFromOpaquePtr(FromTypePtr); + } + QualType getToType() const { + return QualType::getFromOpaquePtr(ToTypePtr); + } + void setAsIdentityConversion(); ImplicitConversionRank getRank() const; bool isPointerConversionToBool() const; @@ -190,6 +200,93 @@ namespace clang { void DebugPrint() const; }; + /// Represents an ambiguous user-defined conversion sequence. + struct AmbiguousConversionSequence { + typedef llvm::SmallVector<FunctionDecl*, 4> ConversionSet; + + void *FromTypePtr; + void *ToTypePtr; + char Buffer[sizeof(ConversionSet)]; + + QualType getFromType() const { + return QualType::getFromOpaquePtr(FromTypePtr); + } + QualType getToType() const { + return QualType::getFromOpaquePtr(ToTypePtr); + } + void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); } + void setToType(QualType T) { ToTypePtr = T.getAsOpaquePtr(); } + + ConversionSet &conversions() { + return *reinterpret_cast<ConversionSet*>(Buffer); + } + + const ConversionSet &conversions() const { + return *reinterpret_cast<const ConversionSet*>(Buffer); + } + + void addConversion(FunctionDecl *D) { + conversions().push_back(D); + } + + typedef ConversionSet::iterator iterator; + iterator begin() { return conversions().begin(); } + iterator end() { return conversions().end(); } + + typedef ConversionSet::const_iterator const_iterator; + const_iterator begin() const { return conversions().begin(); } + const_iterator end() const { return conversions().end(); } + + void construct(); + void destruct(); + void copyFrom(const AmbiguousConversionSequence &); + }; + + /// BadConversionSequence - Records information about an invalid + /// conversion sequence. + struct BadConversionSequence { + enum FailureKind { + no_conversion, + unrelated_class, + suppressed_user, + bad_qualifiers + }; + + // This can be null, e.g. for implicit object arguments. + Expr *FromExpr; + + FailureKind Kind; + + private: + // The type we're converting from (an opaque QualType). + void *FromTy; + + // The type we're converting to (an opaque QualType). + void *ToTy; + + public: + void init(FailureKind K, Expr *From, QualType To) { + init(K, From->getType(), To); + FromExpr = From; + } + void init(FailureKind K, QualType From, QualType To) { + Kind = K; + FromExpr = 0; + setFromType(From); + setToType(To); + } + + QualType getFromType() const { return QualType::getFromOpaquePtr(FromTy); } + QualType getToType() const { return QualType::getFromOpaquePtr(ToTy); } + + void setFromExpr(Expr *E) { + FromExpr = E; + setFromType(E->getType()); + } + void setFromType(QualType T) { FromTy = T.getAsOpaquePtr(); } + void setToType(QualType T) { ToTy = T.getAsOpaquePtr(); } + }; + /// ImplicitConversionSequence - Represents an implicit conversion /// sequence, which may be a standard conversion sequence /// (C++ 13.3.3.1.1), user-defined conversion sequence (C++ 13.3.3.1.2), @@ -197,18 +294,26 @@ namespace clang { struct ImplicitConversionSequence { /// Kind - The kind of implicit conversion sequence. BadConversion /// specifies that there is no conversion from the source type to - /// the target type. The enumerator values are ordered such that - /// better implicit conversions have smaller values. + /// the target type. AmbiguousConversion represents the unique + /// ambiguous conversion (C++0x [over.best.ics]p10). enum Kind { StandardConversion = 0, UserDefinedConversion, + AmbiguousConversion, EllipsisConversion, BadConversion }; + private: /// ConversionKind - The kind of implicit conversion sequence. Kind ConversionKind; + void setKind(Kind K) { + if (isAmbiguous()) Ambiguous.destruct(); + ConversionKind = K; + } + + public: union { /// When ConversionKind == StandardConversion, provides the /// details of the standard conversion sequence. @@ -217,12 +322,58 @@ namespace clang { /// When ConversionKind == UserDefinedConversion, provides the /// details of the user-defined conversion sequence. UserDefinedConversionSequence UserDefined; + + /// When ConversionKind == AmbiguousConversion, provides the + /// details of the ambiguous conversion. + AmbiguousConversionSequence Ambiguous; + + /// When ConversionKind == BadConversion, provides the details + /// of the bad conversion. + BadConversionSequence Bad; }; + + ImplicitConversionSequence() : ConversionKind(BadConversion) {} + ~ImplicitConversionSequence() { + if (isAmbiguous()) Ambiguous.destruct(); + } + ImplicitConversionSequence(const ImplicitConversionSequence &Other) + : ConversionKind(Other.ConversionKind) + { + switch (ConversionKind) { + case StandardConversion: Standard = Other.Standard; break; + case UserDefinedConversion: UserDefined = Other.UserDefined; break; + case AmbiguousConversion: Ambiguous.copyFrom(Other.Ambiguous); break; + case EllipsisConversion: break; + case BadConversion: Bad = Other.Bad; break; + } + } + + ImplicitConversionSequence & + operator=(const ImplicitConversionSequence &Other) { + if (isAmbiguous()) Ambiguous.destruct(); + new (this) ImplicitConversionSequence(Other); + return *this; + } - /// When ConversionKind == BadConversion due to multiple conversion - /// functions, this will list those functions. - llvm::SmallVector<FunctionDecl*, 4> ConversionFunctionSet; - + Kind getKind() const { return ConversionKind; } + bool isBad() const { return ConversionKind == BadConversion; } + bool isStandard() const { return ConversionKind == StandardConversion; } + bool isEllipsis() const { return ConversionKind == EllipsisConversion; } + bool isAmbiguous() const { return ConversionKind == AmbiguousConversion; } + bool isUserDefined() const { + return ConversionKind == UserDefinedConversion; + } + + void setBad() { setKind(BadConversion); } + void setStandard() { setKind(StandardConversion); } + void setEllipsis() { setKind(EllipsisConversion); } + void setUserDefined() { setKind(UserDefinedConversion); } + void setAmbiguous() { + if (isAmbiguous()) return; + ConversionKind = AmbiguousConversion; + Ambiguous.construct(); + } + // The result of a comparison between implicit conversion // sequences. Use Sema::CompareImplicitConversionSequences to // actually perform the comparison. @@ -235,6 +386,13 @@ namespace clang { void DebugPrint() const; }; + enum OverloadFailureKind { + ovl_fail_too_many_arguments, + ovl_fail_too_few_arguments, + ovl_fail_bad_conversion, + ovl_fail_bad_deduction + }; + /// OverloadCandidate - A single candidate in an overload set (C++ 13.3). struct OverloadCandidate { /// Function - The actual function that this candidate @@ -275,11 +433,25 @@ namespace clang { /// object argument. bool IgnoreObjectArgument; + /// FailureKind - The reason why this candidate is not viable. + /// Actually an OverloadFailureKind. + unsigned char FailureKind; + /// FinalConversion - For a conversion function (where Function is /// a CXXConversionDecl), the standard conversion that occurs /// after the call to the overload candidate to convert the result /// of calling the conversion function to the required type. StandardConversionSequence FinalConversion; + + /// hasAmbiguousConversion - Returns whether this overload + /// candidate requires an ambiguous conversion or not. + bool hasAmbiguousConversion() const { + for (llvm::SmallVectorImpl<ImplicitConversionSequence>::const_iterator + I = Conversions.begin(), E = Conversions.end(); I != E; ++I) { + if (I->isAmbiguous()) return true; + } + return false; + } }; /// OverloadCandidateSet - A set of overload candidates, used in C++ diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index b8928c3..7855a7f 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -1157,7 +1157,8 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, MultiExprArg exprs, ExprArg asmString, MultiExprArg clobbers, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, + bool MSAsm) { unsigned NumClobbers = clobbers.size(); StringLiteral **Constraints = reinterpret_cast<StringLiteral**>(constraints.get()); @@ -1261,9 +1262,9 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, asmString.release(); clobbers.release(); AsmStmt *NS = - new (Context) AsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs, - Names, Constraints, Exprs, AsmString, NumClobbers, - Clobbers, RParenLoc); + new (Context) AsmStmt(AsmLoc, IsSimple, IsVolatile, MSAsm, NumOutputs, + NumInputs, Names, Constraints, Exprs, AsmString, + NumClobbers, Clobbers, RParenLoc); // Validate the asm string, ensuring it makes sense given the operands we // have. llvm::SmallVector<AsmStmt::AsmStringPiece, 8> Pieces; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 8c6aa6a..2fad832 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -80,6 +80,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S, TypeTy *ObjectTypePtr, bool EnteringContext, TemplateTy &TemplateResult) { + assert(getLangOptions().CPlusPlus && "No template names in C!"); + DeclarationName TName; switch (Name.getKind()) { @@ -141,6 +143,30 @@ TemplateNameKind Sema::isTemplateName(Scope *S, return TemplateKind; } +bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, + SourceLocation IILoc, + Scope *S, + const CXXScopeSpec *SS, + TemplateTy &SuggestedTemplate, + TemplateNameKind &SuggestedKind) { + // We can't recover unless there's a dependent scope specifier preceding the + // template name. + if (!SS || !SS->isSet() || !isDependentScopeSpecifier(*SS) || + computeDeclContext(*SS)) + return false; + + // The code is missing a 'template' keyword prior to the dependent template + // name. + NestedNameSpecifier *Qualifier = (NestedNameSpecifier*)SS->getScopeRep(); + Diag(IILoc, diag::err_template_kw_missing) + << Qualifier << II.getName() + << CodeModificationHint::CreateInsertion(IILoc, "template "); + SuggestedTemplate + = TemplateTy::make(Context.getDependentTemplateName(Qualifier, &II)); + SuggestedKind = TNK_Dependent_template_name; + return true; +} + void Sema::LookupTemplateName(LookupResult &Found, Scope *S, const CXXScopeSpec &SS, QualType ObjectType, @@ -192,7 +218,8 @@ void Sema::LookupTemplateName(LookupResult &Found, ObjectTypeSearchedInScope = true; } } else if (isDependent) { - // We cannot look into a dependent object type or + // We cannot look into a dependent object type or nested nme + // specifier. return; } else { // Perform unqualified name lookup in the current scope. @@ -203,7 +230,7 @@ void Sema::LookupTemplateName(LookupResult &Found, assert(!Found.isAmbiguous() && "Cannot handle template name-lookup ambiguities"); - if (Found.empty()) { + if (Found.empty() && !isDependent) { // If we did not find any names, attempt to correct any typos. DeclarationName Name = Found.getLookupName(); if (CorrectTypo(Found, S, &SS, LookupCtx)) { @@ -219,6 +246,9 @@ void Sema::LookupTemplateName(LookupResult &Found, << Name << Found.getLookupName() << CodeModificationHint::CreateReplacement(Found.getNameLoc(), Found.getLookupName().getAsString()); + if (TemplateDecl *Template = Found.getAsSingle<TemplateDecl>()) + Diag(Template->getLocation(), diag::note_previous_decl) + << Template->getDeclName(); } else Found.clear(); } else { @@ -1578,15 +1608,19 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, TemplateTy Template; TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType, EnteringContext, Template); - if (TNK == TNK_Non_template) { + if (TNK == TNK_Non_template && + isCurrentInstantiationWithDependentBases(SS)) { + // This is a dependent template. + } else if (TNK == TNK_Non_template) { Diag(Name.getSourceRange().getBegin(), diag::err_template_kw_refers_to_non_template) << GetNameFromUnqualifiedId(Name) << Name.getSourceRange(); return TemplateTy(); + } else { + // We found something; return it. + return Template; } - - return Template; } NestedNameSpecifier *Qualifier @@ -4537,8 +4571,10 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Prev)) { if (Context.hasSameUnqualifiedType(Method->getType(), R)) { Matches.clear(); + Matches.push_back(Method); - break; + if (Method->getTemplateSpecializationKind() == TSK_Undeclared) + break; } } } @@ -4550,7 +4586,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, TemplateDeductionInfo Info(Context); FunctionDecl *Specialization = 0; if (TemplateDeductionResult TDK - = DeduceTemplateArguments(FunTmpl, + = DeduceTemplateArguments(FunTmpl, (HasExplicitTemplateArgs ? &TemplateArgs : 0), R, Specialization, Info)) { // FIXME: Keep track of almost-matches? @@ -4735,6 +4771,10 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, case LookupResult::NotFound: DiagID = diag::err_typename_nested_not_found; break; + + case LookupResult::NotFoundInCurrentInstantiation: + // Okay, it's a member of an unknown instantiation. + return Context.getTypenameType(NNS, &II); case LookupResult::Found: if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) { diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 21f7996..7b433e9 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -542,13 +542,13 @@ DeduceTemplateArguments(ASTContext &Context, // type [i] case Type::DependentSizedArray: { - const ArrayType *ArrayArg = dyn_cast<ArrayType>(Arg); + const ArrayType *ArrayArg = Context.getAsArrayType(Arg); if (!ArrayArg) return Sema::TDK_NonDeducedMismatch; // Check the element type of the arrays const DependentSizedArrayType *DependentArrayParm - = cast<DependentSizedArrayType>(Param); + = Context.getAsDependentSizedArrayType(Param); if (Sema::TemplateDeductionResult Result = DeduceTemplateArguments(Context, TemplateParams, DependentArrayParm->getElementType(), @@ -1312,20 +1312,18 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, /// \param FunctionTemplate the function template for which we are performing /// template argument deduction. /// -/// \param HasExplicitTemplateArgs whether any template arguments were -/// explicitly specified. -/// -/// \param ExplicitTemplateArguments when @p HasExplicitTemplateArgs is true, -/// the explicitly-specified template arguments. -/// -/// \param NumExplicitTemplateArguments when @p HasExplicitTemplateArgs is true, -/// the number of explicitly-specified template arguments in -/// @p ExplicitTemplateArguments. This value may be zero. +/// \param ExplicitTemplateArguments the explicit template arguments provided +/// for this call. /// /// \param Args the function call arguments /// /// \param NumArgs the number of arguments in Args /// +/// \param Name the name of the function being called. This is only significant +/// when the function template is a conversion function template, in which +/// case this routine will also perform template argument deduction based on +/// the function to which +/// /// \param Specialization if template argument deduction was successful, /// this will be set to the function template specialization produced by /// template argument deduction. @@ -1336,7 +1334,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, /// \returns the result of template argument deduction. Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - const TemplateArgumentListInfo *ExplicitTemplateArgs, + const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, FunctionDecl *&Specialization, TemplateDeductionInfo &Info) { @@ -1475,8 +1473,11 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, return TDK_FailedOverloadResolution; } - // Get the type of the resolved argument. + // Get the type of the resolved argument, and adjust it per + // C++0x [temp.deduct.call]p3. ArgType = ResolvedArg->getType(); + if (!ParamWasReference && ArgType->isFunctionType()) + ArgType = Context.getPointerType(ArgType); if (ArgType->isPointerType() || ArgType->isMemberPointerType()) TDF |= TDF_IgnoreQualifiers; @@ -2173,7 +2174,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, // FIXME: if !OnlyDeduced, we have to walk the whole subexpression to // find other occurrences of template parameters. const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E); - if (!E) + if (!DRE) return; const NonTypeTemplateParmDecl *NTTP diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index d974f89..2db0deb 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -1060,6 +1060,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // Exit the scope of this instantiation. CurContext = PreviousContext; + // If this is a polymorphic C++ class without a key function, we'll + // have to mark all of the virtual members to allow emission of a vtable + // in this translation unit. + if (Instantiation->isDynamicClass() && !Context.getKeyFunction(Instantiation)) + ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(Instantiation, + PointOfInstantiation)); + if (!Invalid) Consumer.HandleTagDeclDefinition(Instantiation); diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index ed30229..9515834 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -743,7 +743,8 @@ QualType Sema::BuildFunctionType(QualType T, bool Variadic, unsigned Quals, SourceLocation Loc, DeclarationName Entity) { if (T->isArrayType() || T->isFunctionType()) { - Diag(Loc, diag::err_func_returning_array_function) << T; + Diag(Loc, diag::err_func_returning_array_function) + << T->isFunctionType() << T; return QualType(); } @@ -896,13 +897,18 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, break; case UnqualifiedId::IK_ConstructorName: + case UnqualifiedId::IK_ConstructorTemplateId: case UnqualifiedId::IK_DestructorName: - case UnqualifiedId::IK_ConversionFunctionId: // Constructors and destructors don't have return types. Use - // "void" instead. Conversion operators will check their return - // types separately. + // "void" instead. T = Context.VoidTy; break; + + case UnqualifiedId::IK_ConversionFunctionId: + // The result type of a conversion function is the type that it + // converts to. + T = GetTypeFromParser(D.getName().ConversionFunctionId); + break; } if (T.isNull()) @@ -1041,8 +1047,11 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; // C99 6.7.5.3p1: The return type may not be a function or array type. - if (T->isArrayType() || T->isFunctionType()) { - Diag(DeclType.Loc, diag::err_func_returning_array_function) << T; + // For conversion functions, we'll diagnose this particular error later. + if ((T->isArrayType() || T->isFunctionType()) && + (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId)) { + Diag(DeclType.Loc, diag::err_func_returning_array_function) + << T->isFunctionType() << T; T = Context.IntTy; D.setInvalidType(true); } @@ -1351,6 +1360,20 @@ namespace { cast<TemplateSpecializationTypeLoc>(TInfo->getTypeLoc()); TL.copy(OldTL); } + void VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { + assert(DS.getTypeSpecType() == DeclSpec::TST_typeofExpr); + TL.setTypeofLoc(DS.getTypeSpecTypeLoc()); + TL.setParensRange(DS.getTypeofParensRange()); + } + void VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { + assert(DS.getTypeSpecType() == DeclSpec::TST_typeofType); + TL.setTypeofLoc(DS.getTypeSpecTypeLoc()); + TL.setParensRange(DS.getTypeofParensRange()); + assert(DS.getTypeRep()); + TypeSourceInfo *TInfo = 0; + Sema::GetTypeFromParser(DS.getTypeRep(), &TInfo); + TL.setUnderlyingTInfo(TInfo); + } void VisitTypeLoc(TypeLoc TL) { // FIXME: add other typespec types and change this to an assert. TL.initialize(DS.getTypeSpecTypeLoc()); @@ -1461,34 +1484,6 @@ void LocInfoType::getAsStringInternal(std::string &Str, " GetTypeFromParser"); } -/// ObjCGetTypeForMethodDefinition - Builds the type for a method definition -/// declarator -QualType Sema::ObjCGetTypeForMethodDefinition(DeclPtrTy D) { - ObjCMethodDecl *MDecl = cast<ObjCMethodDecl>(D.getAs<Decl>()); - QualType T = MDecl->getResultType(); - llvm::SmallVector<QualType, 16> ArgTys; - - // Add the first two invisible argument types for self and _cmd. - if (MDecl->isInstanceMethod()) { - QualType selfTy = Context.getObjCInterfaceType(MDecl->getClassInterface()); - selfTy = Context.getPointerType(selfTy); - ArgTys.push_back(selfTy); - } else - ArgTys.push_back(Context.getObjCIdType()); - ArgTys.push_back(Context.getObjCSelType()); - - for (ObjCMethodDecl::param_iterator PI = MDecl->param_begin(), - E = MDecl->param_end(); PI != E; ++PI) { - QualType ArgTy = (*PI)->getType(); - assert(!ArgTy.isNull() && "Couldn't parse type?"); - ArgTy = adjustParameterType(ArgTy); - ArgTys.push_back(ArgTy); - } - T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(), - MDecl->isVariadic(), 0); - return T; -} - /// UnwrapSimilarPointerTypes - If T1 and T2 are pointer types that /// may be similar (C++ 4.4), replaces T1 and T2 with the type that /// they point to and return true. If T1 and T2 aren't pointer types diff --git a/lib/Sema/TargetAttributesSema.cpp b/lib/Sema/TargetAttributesSema.cpp new file mode 100644 index 0000000..7c19bf6 --- /dev/null +++ b/lib/Sema/TargetAttributesSema.cpp @@ -0,0 +1,86 @@ +//===-- TargetAttributesSema.cpp - Encapsulate target attributes-*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains semantic analysis implementation for target-specific +// attributes. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "TargetAttributesSema.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/Triple.h" + +using namespace clang; + +TargetAttributesSema::~TargetAttributesSema() {} +bool TargetAttributesSema::ProcessDeclAttribute(Scope *scope, Decl *D, + const AttributeList &Attr, Sema &S) const { + return false; +} + +static void HandleMSP430InterruptAttr(Decl *d, + const AttributeList &Attr, Sema &S) { + // Check the attribute arguments. + if (Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + + // FIXME: Check for decl - it should be void ()(void). + + Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0)); + llvm::APSInt NumParams(32); + if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) + << "interrupt" << NumParamsExpr->getSourceRange(); + return; + } + + unsigned Num = NumParams.getLimitedValue(255); + if ((Num & 1) || Num > 30) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) + << "interrupt" << (int)NumParams.getSExtValue() + << NumParamsExpr->getSourceRange(); + return; + } + + d->addAttr(::new (S.Context) MSP430InterruptAttr(Num)); + d->addAttr(::new (S.Context) UsedAttr()); + } + +namespace { + class MSP430AttributesSema : public TargetAttributesSema { + public: + MSP430AttributesSema() { } + bool ProcessDeclAttribute(Scope *scope, Decl *D, + const AttributeList &Attr, Sema &S) const { + if (Attr.getName()->getName() == "interrupt") { + HandleMSP430InterruptAttr(D, Attr, S); + return true; + } + return false; + } + }; +} + +const TargetAttributesSema &Sema::getTargetAttributesSema() const { + if (TheTargetAttributesSema) + return *TheTargetAttributesSema; + + const llvm::Triple &Triple(Context.Target.getTriple()); + switch (Triple.getArch()) { + default: + return *(TheTargetAttributesSema = new TargetAttributesSema); + + case llvm::Triple::msp430: + return *(TheTargetAttributesSema = new MSP430AttributesSema); + } +} + diff --git a/lib/Sema/TargetAttributesSema.h b/lib/Sema/TargetAttributesSema.h new file mode 100644 index 0000000..8794e40 --- /dev/null +++ b/lib/Sema/TargetAttributesSema.h @@ -0,0 +1,27 @@ +//===--- TargetAttributesSema.h - Semantic Analysis For Target Attributes -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_SEMA_TARGETSEMA_H +#define CLANG_SEMA_TARGETSEMA_H + +namespace clang { + class Scope; + class Decl; + class Attr; + class Sema; + + class TargetAttributesSema { + public: + virtual ~TargetAttributesSema(); + virtual bool ProcessDeclAttribute(Scope *scope, Decl *D, + const AttributeList &Attr, Sema &S) const; + }; +} + +#endif diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 208c885..445ef0d 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -975,12 +975,15 @@ public: QualType BaseType = ((Expr*) Base.get())->getType(); - // FIXME: wait, this is re-performing lookup? + LookupResult R(getSema(), Member->getDeclName(), MemberLoc, + Sema::LookupMemberName); + R.addDecl(Member); + R.resolveKind(); + return getSema().BuildMemberReferenceExpr(move(Base), BaseType, OpLoc, isArrow, SS, FirstQualifierInScope, - Member->getDeclName(), MemberLoc, - ExplicitTemplateArgs); + R, ExplicitTemplateArgs); } /// \brief Build a new binary operator expression. @@ -1344,9 +1347,11 @@ public: /// semantic analysis. Subclasses may override this routine to provide /// different behavior. OwningExprResult RebuildCXXThisExpr(SourceLocation ThisLoc, - QualType ThisType) { + QualType ThisType, + bool isImplicit) { return getSema().Owned( - new (getSema().Context) CXXThisExpr(ThisLoc, ThisType)); + new (getSema().Context) CXXThisExpr(ThisLoc, ThisType, + isImplicit)); } /// \brief Build a new C++ throw expression. @@ -1559,6 +1564,7 @@ public: bool IsArrow, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, + NamedDecl *FirstQualifierInScope, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs) { CXXScopeSpec SS; @@ -1567,7 +1573,8 @@ public: return SemaRef.BuildMemberReferenceExpr(move(BaseE), BaseType, OperatorLoc, IsArrow, - SS, R, TemplateArgs); + SS, FirstQualifierInScope, + R, TemplateArgs); } /// \brief Build a new Objective-C @encode expression. @@ -2617,18 +2624,16 @@ QualType TreeTransform<Derived>::TransformTypedefType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB, TypeOfExprTypeLoc TL) { - TypeOfExprType *T = TL.getTypePtr(); - // typeof expressions are not potentially evaluated contexts EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); - Sema::OwningExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr()); + Sema::OwningExprResult E = getDerived().TransformExpr(TL.getUnderlyingExpr()); if (E.isInvalid()) return QualType(); QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || - E.get() != T->getUnderlyingExpr()) { + E.get() != TL.getUnderlyingExpr()) { Result = getDerived().RebuildTypeOfExprType(move(E)); if (Result.isNull()) return QualType(); @@ -2636,7 +2641,9 @@ QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB, else E.take(); TypeOfExprTypeLoc NewTL = TLB.push<TypeOfExprTypeLoc>(Result); - NewTL.setNameLoc(TL.getNameLoc()); + NewTL.setTypeofLoc(TL.getTypeofLoc()); + NewTL.setLParenLoc(TL.getLParenLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); return Result; } @@ -2644,23 +2651,23 @@ QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformTypeOfType(TypeLocBuilder &TLB, TypeOfTypeLoc TL) { - TypeOfType *T = TL.getTypePtr(); - - // FIXME: should be an inner type, or at least have a TypeSourceInfo. - QualType Underlying = getDerived().TransformType(T->getUnderlyingType()); - if (Underlying.isNull()) + TypeSourceInfo* Old_Under_TI = TL.getUnderlyingTInfo(); + TypeSourceInfo* New_Under_TI = getDerived().TransformType(Old_Under_TI); + if (!New_Under_TI) return QualType(); QualType Result = TL.getType(); - if (getDerived().AlwaysRebuild() || - Underlying != T->getUnderlyingType()) { - Result = getDerived().RebuildTypeOfType(Underlying); + if (getDerived().AlwaysRebuild() || New_Under_TI != Old_Under_TI) { + Result = getDerived().RebuildTypeOfType(New_Under_TI->getType()); if (Result.isNull()) return QualType(); } TypeOfTypeLoc NewTL = TLB.push<TypeOfTypeLoc>(Result); - NewTL.setNameLoc(TL.getNameLoc()); + NewTL.setTypeofLoc(TL.getTypeofLoc()); + NewTL.setLParenLoc(TL.getLParenLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); + NewTL.setUnderlyingTInfo(New_Under_TI); return Result; } @@ -3711,6 +3718,12 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) { SourceLocation FakeOperatorLoc = SemaRef.PP.getLocForEndOfToken(E->getBase()->getSourceRange().getEnd()); + // FIXME: to do this check properly, we will need to preserve the + // first-qualifier-in-scope here, just in case we had a dependent + // base (and therefore couldn't do the check) and a + // nested-name-qualifier (and therefore could do the lookup). + NamedDecl *FirstQualifierInScope = 0; + return getDerived().RebuildMemberExpr(move(Base), FakeOperatorLoc, E->isArrow(), Qualifier, @@ -3719,7 +3732,7 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) { Member, (E->hasExplicitTemplateArgumentList() ? &TransArgs : 0), - 0); + FirstQualifierInScope); } template<typename Derived> @@ -4386,7 +4399,7 @@ TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) { T == E->getType()) return SemaRef.Owned(E->Retain()); - return getDerived().RebuildCXXThisExpr(E->getLocStart(), T); + return getDerived().RebuildCXXThisExpr(E->getLocStart(), T, E->isImplicit()); } template<typename Derived> @@ -5027,6 +5040,12 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) TransArgs.addArgument(Loc); } } + + // FIXME: to do this check properly, we will need to preserve the + // first-qualifier-in-scope here, just in case we had a dependent + // base (and therefore couldn't do the check) and a + // nested-name-qualifier (and therefore could do the lookup). + NamedDecl *FirstQualifierInScope = 0; return getDerived().RebuildUnresolvedMemberExpr(move(Base), BaseType, @@ -5034,6 +5053,7 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) Old->isArrow(), Qualifier, Old->getQualifierRange(), + FirstQualifierInScope, R, (Old->hasExplicitTemplateArgs() ? &TransArgs : 0)); |