diff options
Diffstat (limited to 'lib')
117 files changed, 7108 insertions, 4005 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 7f5fa35..aef3d29 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -22,9 +22,10 @@ #include "clang/Basic/Builtins.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/MathExtras.h" -#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" #include "RecordLayoutBuilder.h" using namespace clang; @@ -138,9 +139,9 @@ void ASTContext::PrintStats() const { } -void ASTContext::InitBuiltinType(QualType &R, BuiltinType::Kind K) { +void ASTContext::InitBuiltinType(CanQualType &R, BuiltinType::Kind K) { BuiltinType *Ty = new (*this, TypeAlignment) BuiltinType(K); - R = QualType(Ty, 0); + R = CanQualType::CreateUnsafe(QualType(Ty, 0)); Types.push_back(Ty); } @@ -872,6 +873,55 @@ void ASTContext::CollectSynthesizedIvars(const ObjCInterfaceDecl *OI, } } +/// CollectInheritedProtocols - Collect all protocols in current class and +/// those inherited by it. +void ASTContext::CollectInheritedProtocols(const Decl *CDecl, + llvm::SmallVectorImpl<ObjCProtocolDecl*> &Protocols) { + if (const ObjCInterfaceDecl *OI = dyn_cast<ObjCInterfaceDecl>(CDecl)) { + for (ObjCInterfaceDecl::protocol_iterator P = OI->protocol_begin(), + PE = OI->protocol_end(); P != PE; ++P) { + ObjCProtocolDecl *Proto = (*P); + Protocols.push_back(Proto); + for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(), + PE = Proto->protocol_end(); P != PE; ++P) + CollectInheritedProtocols(*P, Protocols); + } + + // Categories of this Interface. + for (const ObjCCategoryDecl *CDeclChain = OI->getCategoryList(); + CDeclChain; CDeclChain = CDeclChain->getNextClassCategory()) + CollectInheritedProtocols(CDeclChain, Protocols); + if (ObjCInterfaceDecl *SD = OI->getSuperClass()) + while (SD) { + CollectInheritedProtocols(SD, Protocols); + SD = SD->getSuperClass(); + } + return; + } + if (const ObjCCategoryDecl *OC = dyn_cast<ObjCCategoryDecl>(CDecl)) { + for (ObjCInterfaceDecl::protocol_iterator P = OC->protocol_begin(), + PE = OC->protocol_end(); P != PE; ++P) { + ObjCProtocolDecl *Proto = (*P); + Protocols.push_back(Proto); + for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(), + PE = Proto->protocol_end(); P != PE; ++P) + CollectInheritedProtocols(*P, Protocols); + } + return; + } + if (const ObjCProtocolDecl *OP = dyn_cast<ObjCProtocolDecl>(CDecl)) { + for (ObjCProtocolDecl::protocol_iterator P = OP->protocol_begin(), + PE = OP->protocol_end(); P != PE; ++P) { + ObjCProtocolDecl *Proto = (*P); + Protocols.push_back(Proto); + for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(), + PE = Proto->protocol_end(); P != PE; ++P) + CollectInheritedProtocols(*P, Protocols); + } + return; + } +} + unsigned ASTContext::CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD) { unsigned count = 0; for (ObjCContainerDecl::prop_iterator I = PD->prop_begin(), @@ -955,6 +1005,13 @@ DeclaratorInfo *ASTContext::CreateDeclaratorInfo(QualType T, return DInfo; } +DeclaratorInfo *ASTContext::getTrivialDeclaratorInfo(QualType T, + SourceLocation L) { + DeclaratorInfo *DI = CreateDeclaratorInfo(T); + DI->getTypeLoc().initialize(L); + return DI; +} + /// getInterfaceLayoutImpl - Get or compute information about the /// layout of the given interface. /// @@ -1757,6 +1814,19 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, QualType ASTContext::getTemplateSpecializationType(TemplateName Template, + const TemplateArgumentLoc *Args, + unsigned NumArgs, + QualType Canon) { + llvm::SmallVector<TemplateArgument, 4> ArgVec; + ArgVec.reserve(NumArgs); + for (unsigned i = 0; i != NumArgs; ++i) + ArgVec.push_back(Args[i].getArgument()); + + return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs, Canon); +} + +QualType +ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgument *Args, unsigned NumArgs, QualType Canon) { @@ -2235,7 +2305,7 @@ CanQualType ASTContext::getCanonicalType(QualType T) { DSAT->getSizeExpr()->Retain() : 0, DSAT->getSizeModifier(), DSAT->getIndexTypeCVRQualifiers(), - DSAT->getBracketsRange())); + DSAT->getBracketsRange())->getCanonicalTypeInternal()); VariableArrayType *VAT = cast<VariableArrayType>(AT); return CanQualType::CreateUnsafe(getVariableArrayType(NewEltTy, @@ -2290,17 +2360,14 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) { return Arg; case TemplateArgument::Declaration: - return TemplateArgument(SourceLocation(), - Arg.getAsDecl()->getCanonicalDecl()); + return TemplateArgument(Arg.getAsDecl()->getCanonicalDecl()); case TemplateArgument::Integral: - return TemplateArgument(SourceLocation(), - *Arg.getAsIntegral(), + return TemplateArgument(*Arg.getAsIntegral(), getCanonicalType(Arg.getIntegralType())); case TemplateArgument::Type: - return TemplateArgument(SourceLocation(), - getCanonicalType(Arg.getAsType())); + return TemplateArgument(getCanonicalType(Arg.getAsType())); case TemplateArgument::Pack: { // FIXME: Allocate in ASTContext @@ -2847,12 +2914,13 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) { bool HasCopyAndDispose = BlockRequiresCopying(Ty); // FIXME: Move up - static int UniqueBlockByRefTypeID = 0; - char Name[36]; - sprintf(Name, "__Block_byref_%d_%s", ++UniqueBlockByRefTypeID, DeclName); + static unsigned int UniqueBlockByRefTypeID = 0; + llvm::SmallString<36> Name; + llvm::raw_svector_ostream(Name) << "__Block_byref_" << + ++UniqueBlockByRefTypeID << '_' << DeclName; RecordDecl *T; T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), - &Idents.get(Name)); + &Idents.get(Name.str())); T->startDefinition(); QualType Int32Ty = IntTy; assert(getIntWidth(IntTy) == 32 && "non-32bit int not supported"); @@ -2896,12 +2964,13 @@ QualType ASTContext::getBlockParmType( bool BlockHasCopyDispose, llvm::SmallVector<const Expr *, 8> &BlockDeclRefDecls) { // FIXME: Move up - static int UniqueBlockParmTypeID = 0; - char Name[36]; - sprintf(Name, "__block_literal_%u", ++UniqueBlockParmTypeID); + static unsigned int UniqueBlockParmTypeID = 0; + llvm::SmallString<36> Name; + llvm::raw_svector_ostream(Name) << "__block_literal_" + << ++UniqueBlockParmTypeID; RecordDecl *T; T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), - &Idents.get(Name)); + &Idents.get(Name.str())); QualType FieldTypes[] = { getPointerType(VoidPtrTy), IntTy, @@ -3409,7 +3478,10 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, return; } - if (OPT->isObjCClassType()) { + if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) { + // FIXME: Consider if we need to output qualifiers for 'Class<p>'. + // Since this is a binary compatibility issue, need to consult with runtime + // folks. Fortunately, this is a *very* obsure construct. S += '#'; return; } @@ -3447,9 +3519,9 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, } S += '@'; - if (FD || EncodingProperty) { + if (OPT->getInterfaceDecl() && (FD || EncodingProperty)) { S += '"'; - S += OPT->getInterfaceDecl()->getNameAsCString(); + S += OPT->getInterfaceDecl()->getIdentifier()->getName(); for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), E = OPT->qual_end(); I != E; ++I) { S += '<'; @@ -3590,12 +3662,42 @@ TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, return TemplateName(QTN); } +/// \brief Retrieve the template name that represents a dependent +/// template name such as \c MetaFun::template operator+. +TemplateName +ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, + OverloadedOperatorKind Operator) { + assert((!NNS || NNS->isDependent()) && + "Nested name specifier must be dependent"); + + llvm::FoldingSetNodeID ID; + DependentTemplateName::Profile(ID, NNS, Operator); + + void *InsertPos = 0; + DependentTemplateName *QTN = + DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos); + + if (QTN) + return TemplateName(QTN); + + NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS); + if (CanonNNS == NNS) { + QTN = new (*this,4) DependentTemplateName(NNS, Operator); + } else { + TemplateName Canon = getDependentTemplateName(CanonNNS, Operator); + QTN = new (*this,4) DependentTemplateName(NNS, Operator, Canon); + } + + DependentTemplateNames.InsertNode(QTN, InsertPos); + return TemplateName(QTN); +} + /// getFromTargetType - Given one of the integer types provided by /// TargetInfo, produce the corresponding type. The unsigned @p Type /// is actually a value of type @c TargetInfo::IntType. -QualType ASTContext::getFromTargetType(unsigned Type) const { +CanQualType ASTContext::getFromTargetType(unsigned Type) const { switch (Type) { - case TargetInfo::NoInt: return QualType(); + case TargetInfo::NoInt: return CanQualType(); case TargetInfo::SignedShort: return ShortTy; case TargetInfo::UnsignedShort: return UnsignedShortTy; case TargetInfo::SignedInt: return IntTy; @@ -3607,7 +3709,7 @@ QualType ASTContext::getFromTargetType(unsigned Type) const { } assert(false && "Unhandled TargetInfo::IntType value"); - return QualType(); + return CanQualType(); } //===----------------------------------------------------------------------===// @@ -3836,6 +3938,79 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, return false; } +/// getIntersectionOfProtocols - This routine finds the intersection of set +/// of protocols inherited from two distinct objective-c pointer objects. +/// It is used to build composite qualifier list of the composite type of +/// the conditional expression involving two objective-c pointer objects. +static +void getIntersectionOfProtocols(ASTContext &Context, + const ObjCObjectPointerType *LHSOPT, + const ObjCObjectPointerType *RHSOPT, + llvm::SmallVectorImpl<ObjCProtocolDecl *> &IntersectionOfProtocols) { + + const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType(); + const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType(); + + llvm::SmallPtrSet<ObjCProtocolDecl *, 8> InheritedProtocolSet; + unsigned LHSNumProtocols = LHS->getNumProtocols(); + if (LHSNumProtocols > 0) + InheritedProtocolSet.insert(LHS->qual_begin(), LHS->qual_end()); + else { + llvm::SmallVector<ObjCProtocolDecl *, 8> LHSInheritedProtocols; + Context.CollectInheritedProtocols(LHS->getDecl(), LHSInheritedProtocols); + InheritedProtocolSet.insert(LHSInheritedProtocols.begin(), + LHSInheritedProtocols.end()); + } + + unsigned RHSNumProtocols = RHS->getNumProtocols(); + if (RHSNumProtocols > 0) { + ObjCProtocolDecl **RHSProtocols = (ObjCProtocolDecl **)RHS->qual_begin(); + for (unsigned i = 0; i < RHSNumProtocols; ++i) + if (InheritedProtocolSet.count(RHSProtocols[i])) + IntersectionOfProtocols.push_back(RHSProtocols[i]); + } + else { + llvm::SmallVector<ObjCProtocolDecl *, 8> RHSInheritedProtocols; + Context.CollectInheritedProtocols(RHS->getDecl(), RHSInheritedProtocols); + // FIXME. This may cause duplication of protocols in the list, but should + // be harmless. + for (unsigned i = 0, len = RHSInheritedProtocols.size(); i < len; ++i) + if (InheritedProtocolSet.count(RHSInheritedProtocols[i])) + IntersectionOfProtocols.push_back(RHSInheritedProtocols[i]); + } +} + +/// areCommonBaseCompatible - Returns common base class of the two classes if +/// one found. Note that this is O'2 algorithm. But it will be called as the +/// last type comparison in a ?-exp of ObjC pointer types before a +/// warning is issued. So, its invokation is extremely rare. +QualType ASTContext::areCommonBaseCompatible( + const ObjCObjectPointerType *LHSOPT, + const ObjCObjectPointerType *RHSOPT) { + const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType(); + const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType(); + if (!LHS || !RHS) + return QualType(); + + while (const ObjCInterfaceDecl *LHSIDecl = LHS->getDecl()->getSuperClass()) { + QualType LHSTy = getObjCInterfaceType(LHSIDecl); + LHS = LHSTy->getAs<ObjCInterfaceType>(); + if (canAssignObjCInterfaces(LHS, RHS)) { + llvm::SmallVector<ObjCProtocolDecl *, 8> IntersectionOfProtocols; + getIntersectionOfProtocols(*this, + LHSOPT, RHSOPT, IntersectionOfProtocols); + if (IntersectionOfProtocols.empty()) + LHSTy = getObjCObjectPointerType(LHSTy); + else + LHSTy = getObjCObjectPointerType(LHSTy, &IntersectionOfProtocols[0], + IntersectionOfProtocols.size()); + return LHSTy; + } + } + + return QualType(); +} + bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS, const ObjCInterfaceType *RHS) { // Verify that the base decls are compatible: the RHS must be a subclass of diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 20e1150..e541406 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -26,6 +26,7 @@ add_clang_library(clangAST StmtPrinter.cpp StmtProfile.cpp StmtViz.cpp + TemplateBase.cpp TemplateName.cpp Type.cpp TypeLoc.cpp diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index d270a95..a6996a4 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -91,13 +91,6 @@ ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, DInfo, S, DefArg); } -QualType ParmVarDecl::getOriginalType() const { - if (const OriginalParmVarDecl *PVD = - dyn_cast<OriginalParmVarDecl>(this)) - return PVD->OriginalType; - return getType(); -} - SourceRange ParmVarDecl::getDefaultArgRange() const { if (const Expr *E = getInit()) return E->getSourceRange(); @@ -140,14 +133,6 @@ bool VarDecl::isExternC() const { return false; } -OriginalParmVarDecl *OriginalParmVarDecl::Create( - ASTContext &C, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id, - QualType T, DeclaratorInfo *DInfo, - QualType OT, StorageClass S, Expr *DefArg) { - return new (C) OriginalParmVarDecl(DC, L, Id, T, DInfo, OT, S, DefArg); -} - FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName N, QualType T, @@ -193,9 +178,9 @@ void EnumConstantDecl::Destroy(ASTContext& C) { } TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, - IdentifierInfo *Id, QualType T) { - return new (C) TypedefDecl(DC, L, Id, T); + SourceLocation L, IdentifierInfo *Id, + DeclaratorInfo *DInfo) { + return new (C) TypedefDecl(DC, L, Id, DInfo); } EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, @@ -398,6 +383,19 @@ bool VarDecl::isOutOfLine() const { return false; } +VarDecl *VarDecl::getOutOfLineDefinition() { + if (!isStaticDataMember()) + return 0; + + for (VarDecl::redecl_iterator RD = redecls_begin(), RDEnd = redecls_end(); + RD != RDEnd; ++RD) { + if (RD->getLexicalDeclContext()->isFileContext()) + return *RD; + } + + return 0; +} + VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const { if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) return cast<VarDecl>(MSI->getInstantiatedFrom()); @@ -644,7 +642,34 @@ unsigned FunctionDecl::getMinRequiredArguments() const { return NumRequiredArgs; } -/// \brief For an inline function definition in C, determine whether the +bool FunctionDecl::isInlined() const { + if (isInlineSpecified() || (isa<CXXMethodDecl>(this) && !isOutOfLine())) + return true; + + switch (getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + return false; + + case TSK_ImplicitInstantiation: + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + // Handle below. + break; + } + + const FunctionDecl *PatternDecl = getTemplateInstantiationPattern(); + Stmt *Pattern = 0; + if (PatternDecl) + Pattern = PatternDecl->getBody(PatternDecl); + + if (Pattern && PatternDecl) + return PatternDecl->isInlined(); + + return false; +} + +/// \brief For an inline function definition in C or C++, determine whether the /// definition will be externally visible. /// /// Inline function definitions are always available for inlining optimizations. @@ -663,9 +688,10 @@ unsigned FunctionDecl::getMinRequiredArguments() const { /// externally visible symbol. bool FunctionDecl::isInlineDefinitionExternallyVisible() const { assert(isThisDeclarationADefinition() && "Must have the function definition"); - assert(isInline() && "Function must be inline"); + assert(isInlined() && "Function must be inline"); + ASTContext &Context = getASTContext(); - if (!getASTContext().getLangOptions().C99 || hasAttr<GNUInlineAttr>()) { + if (!Context.getLangOptions().C99 || hasAttr<GNUInlineAttr>()) { // GNU inline semantics. Based on a number of examples, we came up with the // following heuristic: if the "inline" keyword is present on a // declaration of the function but "extern" is not present on that @@ -675,7 +701,7 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const { for (redecl_iterator Redecl = redecls_begin(), RedeclEnd = redecls_end(); Redecl != RedeclEnd; ++Redecl) { - if (Redecl->isInline() && Redecl->getStorageClass() != Extern) + if (Redecl->isInlineSpecified() && Redecl->getStorageClass() != Extern) return true; } @@ -694,7 +720,7 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const { if (!Redecl->getLexicalDeclContext()->isTranslationUnit()) continue; - if (!Redecl->isInline() || Redecl->getStorageClass() == Extern) + if (!Redecl->isInlineSpecified() || Redecl->getStorageClass() == Extern) return true; // Not an inline definition } @@ -755,6 +781,59 @@ FunctionDecl::setInstantiationOfMemberFunction(FunctionDecl *FD, TemplateOrSpecialization = Info; } +bool FunctionDecl::isImplicitlyInstantiable() const { + // If this function already has a definition or is invalid, it can't be + // implicitly instantiated. + if (isInvalidDecl() || getBody()) + return false; + + switch (getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + case TSK_ExplicitInstantiationDefinition: + return false; + + case TSK_ImplicitInstantiation: + return true; + + case TSK_ExplicitInstantiationDeclaration: + // Handled below. + break; + } + + // Find the actual template from which we will instantiate. + const FunctionDecl *PatternDecl = getTemplateInstantiationPattern(); + Stmt *Pattern = 0; + if (PatternDecl) + Pattern = PatternDecl->getBody(PatternDecl); + + // C++0x [temp.explicit]p9: + // Except for inline functions, other explicit instantiation declarations + // have the effect of suppressing the implicit instantiation of the entity + // to which they refer. + if (!Pattern || !PatternDecl) + return true; + + return PatternDecl->isInlined(); +} + +FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const { + if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) { + while (Primary->getInstantiatedFromMemberTemplate()) { + // If we have hit a point where the user provided a specialization of + // this template, we're done looking. + if (Primary->isMemberSpecialization()) + break; + + Primary = Primary->getInstantiatedFromMemberTemplate(); + } + + return Primary->getTemplatedDecl(); + } + + return getInstantiatedFromMemberFunction(); +} + FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const { if (FunctionTemplateSpecializationInfo *Info = TemplateOrSpecialization diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 224bf87..6cfdcdd 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -199,7 +199,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case Var: case ImplicitParam: case ParmVar: - case OriginalParmVar: case NonTypeTemplateParm: case Using: case UnresolvedUsing: diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 457f4c8..b4c0c59 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -189,7 +189,10 @@ bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context, // A user-declared copy assignment operator is a non-static non-template // member function of class X with exactly one parameter of type X, X&, // const X&, volatile X& or const volatile X&. - const CXXMethodDecl* Method = cast<CXXMethodDecl>(*Op); + const CXXMethodDecl* Method = dyn_cast<CXXMethodDecl>(*Op); + if (!Method) + continue; + if (Method->isStatic()) continue; if (Method->getPrimaryTemplate()) @@ -364,34 +367,36 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD, } } } - + if (getNumBases() == 0 && getNumVBases() == 0) return; - + llvm::SmallPtrSet<CanQualType, 8> ConversionFunctions; if (!inTopClass) collectConversionFunctions(ConversionFunctions); - + for (CXXRecordDecl::base_class_iterator VBase = vbases_begin(), E = vbases_end(); VBase != E; ++VBase) { - CXXRecordDecl *VBaseClassDecl - = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl()); - VBaseClassDecl->getNestedVisibleConversionFunctions(RD, - TopConversionsTypeSet, - (inTopClass ? TopConversionsTypeSet : ConversionFunctions)); - + if (const RecordType *RT = VBase->getType()->getAs<RecordType>()) { + CXXRecordDecl *VBaseClassDecl + = cast<CXXRecordDecl>(RT->getDecl()); + VBaseClassDecl->getNestedVisibleConversionFunctions(RD, + TopConversionsTypeSet, + (inTopClass ? TopConversionsTypeSet : ConversionFunctions)); + } } for (CXXRecordDecl::base_class_iterator Base = bases_begin(), E = bases_end(); Base != E; ++Base) { if (Base->isVirtual()) continue; - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - - BaseClassDecl->getNestedVisibleConversionFunctions(RD, - TopConversionsTypeSet, - (inTopClass ? TopConversionsTypeSet : ConversionFunctions)); - + if (const RecordType *RT = Base->getType()->getAs<RecordType>()) { + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(RT->getDecl()); + + BaseClassDecl->getNestedVisibleConversionFunctions(RD, + TopConversionsTypeSet, + (inTopClass ? TopConversionsTypeSet : ConversionFunctions)); + } } } diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 7f38ac1..7b48b72 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -118,6 +118,27 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { return 0; } +/// FindPropertyVisibleInPrimaryClass - Finds declaration of the property +/// with name 'PropertyId' in the primary class; including those in protocols +/// (direct or indirect) used by the promary class. +/// FIXME: Convert to DeclContext lookup... +/// +ObjCPropertyDecl * +ObjCContainerDecl::FindPropertyVisibleInPrimaryClass( + IdentifierInfo *PropertyId) const { + assert(isa<ObjCInterfaceDecl>(this) && "FindPropertyVisibleInPrimaryClass"); + for (prop_iterator I = prop_begin(), E = prop_end(); I != E; ++I) + if ((*I)->getIdentifier() == PropertyId) + return *I; + const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(this); + // Look through protocols. + for (ObjCInterfaceDecl::protocol_iterator I = OID->protocol_begin(), + E = OID->protocol_end(); I != E; ++I) + if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) + return P; + return 0; +} + void ObjCInterfaceDecl::mergeClassExtensionProtocolList( ObjCProtocolDecl *const* ExtList, unsigned ExtNum, ASTContext &C) @@ -288,7 +309,7 @@ ObjCMethodDecl *ObjCMethodDecl::getNextRedeclaration() { } else if (ObjCCategoryImplDecl *CImplD = dyn_cast<ObjCCategoryImplDecl>(CtxD)) { - if (ObjCCategoryDecl *CatD = CImplD->getCategoryClass()) + if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl()) Redecl = CatD->getMethod(getSelector(), isInstanceMethod()); } @@ -306,7 +327,7 @@ ObjCMethodDecl *ObjCMethodDecl::getCanonicalDecl() { } else if (ObjCCategoryImplDecl *CImplD = dyn_cast<ObjCCategoryImplDecl>(CtxD)) { - if (ObjCCategoryDecl *CatD = CImplD->getCategoryClass()) + if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl()) if (ObjCMethodDecl *MD = CatD->getMethod(getSelector(), isInstanceMethod())) return MD; @@ -635,7 +656,7 @@ ObjCCategoryImplDecl::Create(ASTContext &C, DeclContext *DC, return new (C) ObjCCategoryImplDecl(DC, L, Id, ClassInterface); } -ObjCCategoryDecl *ObjCCategoryImplDecl::getCategoryClass() const { +ObjCCategoryDecl *ObjCCategoryImplDecl::getCategoryDecl() const { return getClassInterface()->FindCategoryDeclaration(getIdentifier()); } diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 9d0d836..d9d1950 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -52,7 +52,6 @@ namespace { void VisitFieldDecl(FieldDecl *D); void VisitVarDecl(VarDecl *D); void VisitParmVarDecl(ParmVarDecl *D); - void VisitOriginalParmVarDecl(OriginalParmVarDecl *D); void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); void VisitOverloadedFunctionDecl(OverloadedFunctionDecl *D); void VisitNamespaceDecl(NamespaceDecl *D); @@ -324,7 +323,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { case FunctionDecl::PrivateExtern: Out << "__private_extern__ "; break; } - if (D->isInline()) Out << "inline "; + if (D->isInlineSpecified()) Out << "inline "; if (D->isVirtualAsWritten()) Out << "virtual "; } @@ -489,7 +488,7 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { std::string Name = D->getNameAsString(); QualType T = D->getType(); - if (OriginalParmVarDecl *Parm = dyn_cast<OriginalParmVarDecl>(D)) + if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) T = Parm->getOriginalType(); T.getAsStringInternal(Name, Policy); Out << Name; @@ -508,10 +507,6 @@ void DeclPrinter::VisitParmVarDecl(ParmVarDecl *D) { VisitVarDecl(D); } -void DeclPrinter::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) { - VisitVarDecl(D); -} - void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { Out << "__asm ("; D->getAsmString()->printPretty(Out, Context, 0, Policy, Indentation); diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 9a1c654..9ebc91a 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -1,4 +1,4 @@ -//===--- DeclCXX.cpp - C++ Declaration AST Node Implementation ------------===// +//===--- DeclTemplate.cpp - Template Declaration AST Node Implementation --===// // // The LLVM Compiler Infrastructure // @@ -15,6 +15,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/TypeLoc.h" #include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/STLExtras.h" using namespace clang; @@ -67,6 +68,21 @@ unsigned TemplateParameterList::getMinRequiredArguments() const { return NumRequiredArgs; } +unsigned TemplateParameterList::getDepth() const { + if (size() == 0) + return 0; + + const NamedDecl *FirstParm = getParam(0); + if (const TemplateTypeParmDecl *TTP + = dyn_cast<TemplateTypeParmDecl>(FirstParm)) + return TTP->getDepth(); + else if (const NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(FirstParm)) + return NTTP->getDepth(); + else + return cast<TemplateTemplateParmDecl>(FirstParm)->getDepth(); +} + //===----------------------------------------------------------------------===// // TemplateDecl Implementation //===----------------------------------------------------------------------===// @@ -194,8 +210,7 @@ QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) { Param != ParamEnd; ++Param) { if (isa<TemplateTypeParmDecl>(*Param)) { QualType ParamType = Context.getTypeDeclType(cast<TypeDecl>(*Param)); - TemplateArgs.push_back(TemplateArgument((*Param)->getLocation(), - ParamType)); + TemplateArgs.push_back(TemplateArgument(ParamType)); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { Expr *E = new (Context) DeclRefExpr(NTTP, NTTP->getType(), @@ -205,7 +220,7 @@ QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) { TemplateArgs.push_back(TemplateArgument(E)); } else { TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param); - TemplateArgs.push_back(TemplateArgument(TTP->getLocation(), TTP)); + TemplateArgs.push_back(TemplateArgument(TTP)); } } @@ -229,6 +244,18 @@ TemplateTypeParmDecl::Create(ASTContext &C, DeclContext *DC, return new (C) TemplateTypeParmDecl(DC, L, Id, Typename, Type, ParameterPack); } +SourceLocation TemplateTypeParmDecl::getDefaultArgumentLoc() const { + return DefaultArgument->getTypeLoc().getFullSourceRange().getBegin(); +} + +unsigned TemplateTypeParmDecl::getDepth() const { + return TypeForDecl->getAs<TemplateTypeParmType>()->getDepth(); +} + +unsigned TemplateTypeParmDecl::getIndex() const { + return TypeForDecl->getAs<TemplateTypeParmType>()->getIndex(); +} + //===----------------------------------------------------------------------===// // NonTypeTemplateParmDecl Method Implementations //===----------------------------------------------------------------------===// @@ -264,34 +291,6 @@ SourceLocation TemplateTemplateParmDecl::getDefaultArgumentLoc() const { } //===----------------------------------------------------------------------===// -// TemplateArgument Implementation -//===----------------------------------------------------------------------===// - -TemplateArgument::TemplateArgument(Expr *E) : Kind(Expression) { - TypeOrValue = reinterpret_cast<uintptr_t>(E); - StartLoc = E->getSourceRange().getBegin(); -} - -/// \brief Construct a template argument pack. -void TemplateArgument::setArgumentPack(TemplateArgument *args, unsigned NumArgs, - bool CopyArgs) { - assert(isNull() && "Must call setArgumentPack on a null argument"); - - Kind = Pack; - Args.NumArgs = NumArgs; - Args.CopyArgs = CopyArgs; - if (!Args.CopyArgs) { - Args.Args = args; - return; - } - - // FIXME: Allocate in ASTContext - Args.Args = new TemplateArgument[NumArgs]; - for (unsigned I = 0; I != Args.NumArgs; ++I) - Args.Args[I] = args[I]; -} - -//===----------------------------------------------------------------------===// // TemplateArgumentListBuilder Implementation //===----------------------------------------------------------------------===// @@ -459,12 +458,19 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, TemplateArgumentListBuilder &Builder, + TemplateArgumentLoc *ArgInfos, unsigned N, ClassTemplatePartialSpecializationDecl *PrevDecl) { + TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N]; + for (unsigned I = 0; I != N; ++I) + ClonedArgs[I] = ArgInfos[I]; + ClassTemplatePartialSpecializationDecl *Result = new (Context)ClassTemplatePartialSpecializationDecl(Context, DC, L, Params, SpecializedTemplate, - Builder, PrevDecl); + Builder, + ClonedArgs, N, + PrevDecl); Result->setSpecializationKind(TSK_ExplicitSpecialization); Context.getTypeDeclType(Result, PrevDecl); return Result; diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index a4de3e5..a8ea752 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -22,6 +22,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> using namespace clang; @@ -30,6 +31,91 @@ using namespace clang; // Primary Expressions. //===----------------------------------------------------------------------===// +DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + NamedDecl *D, SourceLocation NameLoc, + bool HasExplicitTemplateArgumentList, + SourceLocation LAngleLoc, + const TemplateArgumentLoc *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + SourceLocation RAngleLoc, + QualType T, bool TD, bool VD) + : Expr(DeclRefExprClass, T, TD, VD), + DecoratedD(D, + (Qualifier? HasQualifierFlag : 0) | + (HasExplicitTemplateArgumentList? + HasExplicitTemplateArgumentListFlag : 0)), + Loc(NameLoc) { + if (Qualifier) { + NameQualifier *NQ = getNameQualifier(); + NQ->NNS = Qualifier; + NQ->Range = QualifierRange; + } + + if (HasExplicitTemplateArgumentList) { + ExplicitTemplateArgumentList *ETemplateArgs + = getExplicitTemplateArgumentList(); + ETemplateArgs->LAngleLoc = LAngleLoc; + ETemplateArgs->RAngleLoc = RAngleLoc; + ETemplateArgs->NumTemplateArgs = NumExplicitTemplateArgs; + + TemplateArgumentLoc *TemplateArgs = ETemplateArgs->getTemplateArgs(); + for (unsigned I = 0; I < NumExplicitTemplateArgs; ++I) + new (TemplateArgs + I) TemplateArgumentLoc(ExplicitTemplateArgs[I]); + } +} + +DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + NamedDecl *D, + SourceLocation NameLoc, + QualType T, bool TD, bool VD) { + return Create(Context, Qualifier, QualifierRange, D, NameLoc, + false, SourceLocation(), 0, 0, SourceLocation(), + T, TD, VD); +} + +DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + NamedDecl *D, + SourceLocation NameLoc, + bool HasExplicitTemplateArgumentList, + SourceLocation LAngleLoc, + const TemplateArgumentLoc *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + SourceLocation RAngleLoc, + QualType T, bool TD, bool VD) { + std::size_t Size = sizeof(DeclRefExpr); + if (Qualifier != 0) + Size += sizeof(NameQualifier); + + if (HasExplicitTemplateArgumentList) + Size += sizeof(ExplicitTemplateArgumentList) + + sizeof(TemplateArgumentLoc) * NumExplicitTemplateArgs; + + void *Mem = Context.Allocate(Size, llvm::alignof<DeclRefExpr>()); + return new (Mem) DeclRefExpr(Qualifier, QualifierRange, D, NameLoc, + HasExplicitTemplateArgumentList, + LAngleLoc, + ExplicitTemplateArgs, + NumExplicitTemplateArgs, + RAngleLoc, + T, TD, VD); +} + +SourceRange DeclRefExpr::getSourceRange() const { + // FIXME: Does not handle multi-token names well, e.g., operator[]. + SourceRange R(Loc); + + if (hasQualifier()) + R.setBegin(getQualifierRange().getBegin()); + if (hasExplicitTemplateArgumentList()) + R.setEnd(getRAngleLoc()); + return R; +} + // FIXME: Maybe this should use DeclPrinter with a special "print predefined // expr" policy instead. std::string PredefinedExpr::ComputeName(ASTContext &Context, IdentType IT, @@ -343,7 +429,7 @@ MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, SourceRange qualrange, NamedDecl *memberdecl, SourceLocation l, bool has_explicit, SourceLocation langle, - const TemplateArgument *targs, unsigned numtargs, + const TemplateArgumentLoc *targs, unsigned numtargs, SourceLocation rangle, QualType ty) : Expr(MemberExprClass, ty, base->isTypeDependent() || (qual && qual->isDependent()), @@ -365,9 +451,9 @@ MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, ETemplateArgs->RAngleLoc = rangle; ETemplateArgs->NumTemplateArgs = numtargs; - TemplateArgument *TemplateArgs = ETemplateArgs->getTemplateArgs(); + TemplateArgumentLoc *TemplateArgs = ETemplateArgs->getTemplateArgs(); for (unsigned I = 0; I < numtargs; ++I) - new (TemplateArgs + I) TemplateArgument(targs[I]); + new (TemplateArgs + I) TemplateArgumentLoc(targs[I]); } } @@ -378,7 +464,7 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, SourceLocation l, bool has_explicit, SourceLocation langle, - const TemplateArgument *targs, + const TemplateArgumentLoc *targs, unsigned numtargs, SourceLocation rangle, QualType ty) { @@ -388,7 +474,7 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, if (has_explicit) Size += sizeof(ExplicitTemplateArgumentList) + - sizeof(TemplateArgument) * numtargs; + sizeof(TemplateArgumentLoc) * numtargs; void *Mem = C.Allocate(Size, llvm::alignof<MemberExpr>()); return new (Mem) MemberExpr(base, isarrow, qual, qualrange, memberdecl, l, @@ -418,6 +504,8 @@ const char *CastExpr::getCastKindName() const { return "NullToMemberPointer"; case CastExpr::CK_BaseToDerivedMemberPointer: return "BaseToDerivedMemberPointer"; + case CastExpr::CK_DerivedToBaseMemberPointer: + return "DerivedToBaseMemberPointer"; case CastExpr::CK_UserDefinedConversion: return "UserDefinedConversion"; case CastExpr::CK_ConstructorConversion: @@ -610,7 +698,7 @@ Stmt *BlockExpr::getBody() { /// with location to warn on and the source range[s] to report with the /// warning. bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, - SourceRange &R2) const { + SourceRange &R2, ASTContext &Ctx) const { // Don't warn if the expr is type dependent. The type could end up // instantiating to void. if (isTypeDependent()) @@ -623,7 +711,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, return true; case ParenExprClass: return cast<ParenExpr>(this)->getSubExpr()-> - isUnusedResultAWarning(Loc, R1, R2); + isUnusedResultAWarning(Loc, R1, R2, Ctx); case UnaryOperatorClass: { const UnaryOperator *UO = cast<UnaryOperator>(this); @@ -636,17 +724,18 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, return false; // Not a warning. case UnaryOperator::Deref: // Dereferencing a volatile pointer is a side-effect. - if (getType().isVolatileQualified()) + if (Ctx.getCanonicalType(getType()).isVolatileQualified()) return false; break; case UnaryOperator::Real: case UnaryOperator::Imag: // accessing a piece of a volatile complex is a side-effect. - if (UO->getSubExpr()->getType().isVolatileQualified()) + if (Ctx.getCanonicalType(UO->getSubExpr()->getType()) + .isVolatileQualified()) return false; break; case UnaryOperator::Extension: - return UO->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2); + return UO->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx); } Loc = UO->getOperatorLoc(); R1 = UO->getSubExpr()->getSourceRange(); @@ -656,8 +745,8 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, const BinaryOperator *BO = cast<BinaryOperator>(this); // Consider comma to have side effects if the LHS or RHS does. if (BO->getOpcode() == BinaryOperator::Comma) - return BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2) || - BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2); + return (BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) || + BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); if (BO->isAssignmentOp()) return false; @@ -674,15 +763,15 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, // warning, warn about them. const ConditionalOperator *Exp = cast<ConditionalOperator>(this); if (Exp->getLHS() && - Exp->getLHS()->isUnusedResultAWarning(Loc, R1, R2)) + Exp->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx)) return true; - return Exp->getRHS()->isUnusedResultAWarning(Loc, R1, R2); + return Exp->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx); } case MemberExprClass: // If the base pointer or element is to a volatile pointer/field, accessing // it is a side effect. - if (getType().isVolatileQualified()) + if (Ctx.getCanonicalType(getType()).isVolatileQualified()) return false; Loc = cast<MemberExpr>(this)->getMemberLoc(); R1 = SourceRange(Loc, Loc); @@ -692,7 +781,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, case ArraySubscriptExprClass: // If the base pointer or element is to a volatile pointer/field, accessing // it is a side effect. - if (getType().isVolatileQualified()) + if (Ctx.getCanonicalType(getType()).isVolatileQualified()) return false; Loc = cast<ArraySubscriptExpr>(this)->getRBracketLoc(); R1 = cast<ArraySubscriptExpr>(this)->getLHS()->getSourceRange(); @@ -750,7 +839,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, const CompoundStmt *CS = cast<StmtExpr>(this)->getSubStmt(); if (!CS->body_empty()) if (const Expr *E = dyn_cast<Expr>(CS->body_back())) - return E->isUnusedResultAWarning(Loc, R1, R2); + return E->isUnusedResultAWarning(Loc, R1, R2, Ctx); Loc = cast<StmtExpr>(this)->getLParenLoc(); R1 = getSourceRange(); @@ -768,20 +857,20 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, // If this is a cast to void, check the operand. Otherwise, the result of // the cast is unused. if (getType()->isVoidType()) - return cast<CastExpr>(this)->getSubExpr() - ->isUnusedResultAWarning(Loc, R1, R2); + return (cast<CastExpr>(this)->getSubExpr() + ->isUnusedResultAWarning(Loc, R1, R2, Ctx)); Loc = cast<CXXFunctionalCastExpr>(this)->getTypeBeginLoc(); R1 = cast<CXXFunctionalCastExpr>(this)->getSubExpr()->getSourceRange(); return true; case ImplicitCastExprClass: // Check the operand, since implicit casts are inserted by Sema - return cast<ImplicitCastExpr>(this) - ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2); + return (cast<ImplicitCastExpr>(this) + ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); case CXXDefaultArgExprClass: - return cast<CXXDefaultArgExpr>(this) - ->getExpr()->isUnusedResultAWarning(Loc, R1, R2); + return (cast<CXXDefaultArgExpr>(this) + ->getExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); case CXXNewExprClass: // FIXME: In theory, there might be new expressions that don't have side @@ -789,11 +878,11 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, case CXXDeleteExprClass: return false; case CXXBindTemporaryExprClass: - return cast<CXXBindTemporaryExpr>(this) - ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2); + return (cast<CXXBindTemporaryExpr>(this) + ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); case CXXExprWithTemporariesClass: - return cast<CXXExprWithTemporaries>(this) - ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2); + return (cast<CXXExprWithTemporaries>(this) + ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); } } @@ -855,8 +944,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { if (cast<ArraySubscriptExpr>(this)->getBase()->getType()->isVectorType()) return cast<ArraySubscriptExpr>(this)->getBase()->isLvalue(Ctx); return LV_Valid; - case DeclRefExprClass: - case QualifiedDeclRefExprClass: { // C99 6.5.1p2 + case DeclRefExprClass: { // C99 6.5.1p2 const NamedDecl *RefdDecl = cast<DeclRefExpr>(this)->getDecl(); if (DeclCanBeLvalue(RefdDecl, Ctx)) return LV_Valid; @@ -1042,6 +1130,18 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { return LV_Valid; } + case TemplateIdRefExprClass: { + const TemplateIdRefExpr *TID = cast<TemplateIdRefExpr>(this); + TemplateName Template = TID->getTemplateName(); + NamedDecl *ND = Template.getAsTemplateDecl(); + if (!ND) + ND = Template.getAsOverloadedFunctionDecl(); + if (ND && DeclCanBeLvalue(ND, Ctx)) + return LV_Valid; + + break; + } + default: break; } @@ -1133,8 +1233,7 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const { return cast<ImplicitCastExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx); case CStyleCastExprClass: return cast<CStyleCastExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx); - case DeclRefExprClass: - case QualifiedDeclRefExprClass: { + case DeclRefExprClass: { const Decl *D = cast<DeclRefExpr>(this)->getDecl(); if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { if (VD->hasGlobalStorage()) @@ -1432,7 +1531,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { return ICEDiag(2, E->getLocStart()); } case Expr::DeclRefExprClass: - case Expr::QualifiedDeclRefExprClass: if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl())) return NoDiag(); if (Ctx.getLangOptions().CPlusPlus && @@ -1442,16 +1540,35 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { // type initialized by an ICE can be used in ICEs. if (const VarDecl *Dcl = dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl())) { - if (Dcl->isInitKnownICE()) { - // We have already checked whether this subexpression is an - // integral constant expression. - if (Dcl->isInitICE()) - return NoDiag(); - else - return ICEDiag(2, E->getLocStart()); - } + Qualifiers Quals = Ctx.getCanonicalType(Dcl->getType()).getQualifiers(); + if (Quals.hasVolatile() || !Quals.hasConst()) + return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); + + // Look for the definition of this variable, which will actually have + // an initializer. + const VarDecl *Def = 0; + const Expr *Init = Dcl->getDefinition(Def); + if (Init) { + if (Def->isInitKnownICE()) { + // We have already checked whether this subexpression is an + // integral constant expression. + if (Def->isInitICE()) + return NoDiag(); + else + return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); + } - if (const Expr *Init = Dcl->getInit()) { + // C++ [class.static.data]p4: + // If a static data member is of const integral or const + // enumeration type, its declaration in the class definition can + // specify a constant-initializer which shall be an integral + // constant expression (5.19). In that case, the member can appear + // in integral constant expressions. + if (Def->isOutOfLine()) { + Dcl->setInitKnownICE(Ctx, false); + return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); + } + ICEDiag Result = CheckICE(Init, Ctx); // Cache the result of the ICE test. Dcl->setInitKnownICE(Ctx, Result.Val == 0); @@ -1654,7 +1771,7 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, } EvalResult EvalResult; if (!Evaluate(EvalResult, Ctx)) - assert(0 && "ICE cannot be evaluated!"); + llvm::llvm_unreachable("ICE cannot be evaluated!"); assert(!EvalResult.HasSideEffects && "ICE with side effects!"); assert(EvalResult.Val.isInt() && "ICE that isn't integer!"); Result = EvalResult.Val.getInt(); diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index cba0e22..7c6fc41 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -151,7 +151,7 @@ TemplateIdRefExpr::TemplateIdRefExpr(QualType T, TemplateName Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc) : Expr(TemplateIdRefExprClass, T, @@ -164,10 +164,10 @@ TemplateIdRefExpr::TemplateIdRefExpr(QualType T, Qualifier(Qualifier), QualifierRange(QualifierRange), Template(Template), TemplateNameLoc(TemplateNameLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc), NumTemplateArgs(NumTemplateArgs) { - TemplateArgument *StoredTemplateArgs - = reinterpret_cast<TemplateArgument *> (this+1); + TemplateArgumentLoc *StoredTemplateArgs + = reinterpret_cast<TemplateArgumentLoc *> (this+1); for (unsigned I = 0; I != NumTemplateArgs; ++I) - new (StoredTemplateArgs + I) TemplateArgument(TemplateArgs[I]); + new (StoredTemplateArgs + I) TemplateArgumentLoc(TemplateArgs[I]); } TemplateIdRefExpr * @@ -176,19 +176,19 @@ TemplateIdRefExpr::Create(ASTContext &Context, QualType T, SourceRange QualifierRange, TemplateName Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc) { void *Mem = Context.Allocate(sizeof(TemplateIdRefExpr) + - sizeof(TemplateArgument) * NumTemplateArgs); + sizeof(TemplateArgumentLoc) * NumTemplateArgs); return new (Mem) TemplateIdRefExpr(T, Qualifier, QualifierRange, Template, TemplateNameLoc, LAngleLoc, TemplateArgs, NumTemplateArgs, RAngleLoc); } void TemplateIdRefExpr::DoDestroy(ASTContext &Context) { - const TemplateArgument *TemplateArgs = getTemplateArgs(); + const TemplateArgumentLoc *TemplateArgs = getTemplateArgs(); for (unsigned I = 0; I != NumTemplateArgs; ++I) - if (Expr *E = TemplateArgs[I].getAsExpr()) + if (Expr *E = TemplateArgs[I].getArgument().getAsExpr()) E->Destroy(Context); this->~TemplateIdRefExpr(); Context.Deallocate(this); @@ -528,7 +528,7 @@ CXXUnresolvedMemberExpr::CXXUnresolvedMemberExpr(ASTContext &C, SourceLocation MemberLoc, bool HasExplicitTemplateArgs, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc) : Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true), @@ -545,9 +545,9 @@ CXXUnresolvedMemberExpr::CXXUnresolvedMemberExpr(ASTContext &C, ETemplateArgs->RAngleLoc = RAngleLoc; ETemplateArgs->NumTemplateArgs = NumTemplateArgs; - TemplateArgument *SavedTemplateArgs = ETemplateArgs->getTemplateArgs(); + TemplateArgumentLoc *SavedTemplateArgs = ETemplateArgs->getTemplateArgs(); for (unsigned I = 0; I < NumTemplateArgs; ++I) - new (SavedTemplateArgs + I) TemplateArgument(TemplateArgs[I]); + new (SavedTemplateArgs + I) TemplateArgumentLoc(TemplateArgs[I]); } } @@ -562,7 +562,7 @@ CXXUnresolvedMemberExpr::Create(ASTContext &C, SourceLocation MemberLoc, bool HasExplicitTemplateArgs, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc) { if (!HasExplicitTemplateArgs) @@ -573,7 +573,7 @@ CXXUnresolvedMemberExpr::Create(ASTContext &C, void *Mem = C.Allocate(sizeof(CXXUnresolvedMemberExpr) + sizeof(ExplicitTemplateArgumentList) + - sizeof(TemplateArgument) * NumTemplateArgs, + sizeof(TemplateArgumentLoc) * NumTemplateArgs, llvm::alignof<CXXUnresolvedMemberExpr>()); return new (Mem) CXXUnresolvedMemberExpr(C, Base, IsArrow, OperatorLoc, Qualifier, QualifierRange, diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 94d2299..7862c57 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -58,7 +58,8 @@ struct EvalInfo { static bool EvaluateLValue(const Expr *E, APValue &Result, EvalInfo &Info); static bool EvaluatePointer(const Expr *E, APValue &Result, EvalInfo &Info); static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info); -static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result, EvalInfo &Info); +static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result, + EvalInfo &Info); static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info); static bool EvaluateComplex(const Expr *E, APValue &Result, EvalInfo &Info); @@ -151,6 +152,67 @@ static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType, return Result; } +namespace { +class VISIBILITY_HIDDEN HasSideEffect + : public StmtVisitor<HasSideEffect, bool> { + EvalInfo &Info; +public: + + HasSideEffect(EvalInfo &info) : Info(info) {} + + // Unhandled nodes conservatively default to having side effects. + bool VisitStmt(Stmt *S) { + return true; + } + + bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } + bool VisitDeclRefExpr(DeclRefExpr *E) { + if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified()) + return true; + return false; + } + // We don't want to evaluate BlockExprs multiple times, as they generate + // a ton of code. + bool VisitBlockExpr(BlockExpr *E) { return true; } + bool VisitPredefinedExpr(PredefinedExpr *E) { return false; } + bool VisitCompoundLiteralExpr(CompoundLiteralExpr *E) + { return Visit(E->getInitializer()); } + bool VisitMemberExpr(MemberExpr *E) { return Visit(E->getBase()); } + bool VisitIntegerLiteral(IntegerLiteral *E) { return false; } + bool VisitFloatingLiteral(FloatingLiteral *E) { return false; } + bool VisitStringLiteral(StringLiteral *E) { return false; } + bool VisitCharacterLiteral(CharacterLiteral *E) { return false; } + bool VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { return false; } + bool VisitArraySubscriptExpr(ArraySubscriptExpr *E) + { return Visit(E->getLHS()) || Visit(E->getRHS()); } + bool VisitChooseExpr(ChooseExpr *E) + { return Visit(E->getChosenSubExpr(Info.Ctx)); } + bool VisitCastExpr(CastExpr *E) { return Visit(E->getSubExpr()); } + bool VisitBinAssign(BinaryOperator *E) { return true; } + bool VisitCompoundAssignOperator(BinaryOperator *E) { return true; } + bool VisitBinaryOperator(BinaryOperator *E) + { return Visit(E->getLHS()) || Visit(E->getRHS()); } + bool VisitUnaryPreInc(UnaryOperator *E) { return true; } + bool VisitUnaryPostInc(UnaryOperator *E) { return true; } + bool VisitUnaryPreDec(UnaryOperator *E) { return true; } + bool VisitUnaryPostDec(UnaryOperator *E) { return true; } + bool VisitUnaryDeref(UnaryOperator *E) { + if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified()) + return true; + return Visit(E->getSubExpr()); + } + bool VisitUnaryOperator(UnaryOperator *E) { return Visit(E->getSubExpr()); } +}; + +bool HasSideEffects(const Expr* E, ASTContext &Ctx) { + Expr::EvalResult Result; + EvalInfo Info(Ctx, Result); + + return HasSideEffect(Info).Visit(const_cast<Expr*>(E)); +} + +} // end anonymous namespace + //===----------------------------------------------------------------------===// // LValue Evaluation //===----------------------------------------------------------------------===// @@ -208,8 +270,9 @@ APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) { if (!VD->getType()->isReferenceType()) return APValue(E, 0); // FIXME: Check whether VD might be overridden! - if (VD->getInit()) - return Visit(VD->getInit()); + const VarDecl *Def = 0; + if (const Expr *Init = VD->getDefinition(Def)) + return Visit(const_cast<Expr *>(Init)); } return APValue(); @@ -793,11 +856,14 @@ bool IntExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { // In C++, const, non-volatile integers initialized with ICEs are ICEs. // In C, they can also be folded, although they are not ICEs. - if (E->getType().getCVRQualifiers() == Qualifiers::Const) { + if (Info.Ctx.getCanonicalType(E->getType()).getCVRQualifiers() + == Qualifiers::Const) { if (const VarDecl *D = dyn_cast<VarDecl>(E->getDecl())) { - if (APValue *V = D->getEvaluatedValue()) - return Success(V->getInt(), E); - if (const Expr *Init = D->getInit()) { + const VarDecl *Def = 0; + if (const Expr *Init = D->getDefinition(Def)) { + if (APValue *V = D->getEvaluatedValue()) + return Success(V->getInt(), E); + if (Visit(const_cast<Expr*>(Init))) { // Cache the evaluated value in the variable declaration. D->setEvaluatedValue(Info.Ctx, Result); @@ -873,6 +939,40 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { switch (E->isBuiltinCall(Info.Ctx)) { default: return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + + case Builtin::BI__builtin_object_size: { + const Expr *Arg = E->getArg(0)->IgnoreParens(); + Expr::EvalResult Base; + if (Arg->EvaluateAsAny(Base, Info.Ctx) + && Base.Val.getKind() == APValue::LValue + && !Base.HasSideEffects) + if (const Expr *LVBase = Base.Val.getLValueBase()) + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(LVBase)) { + if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) { + if (!VD->getType()->isIncompleteType() + && 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(); + else + Size = 0; + return Success(Size, E); + } + } + } + + if (HasSideEffects(E->getArg(0), Info.Ctx)) { + if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() < 2) + return Success(-1ULL, E); + return Success(0, E); + } + + return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + } + case Builtin::BI__builtin_classify_type: return Success(EvaluateBuiltinClassifyType(E), E); @@ -1801,6 +1901,33 @@ bool Expr::Evaluate(EvalResult &Result, ASTContext &Ctx) const { return true; } +bool Expr::EvaluateAsAny(EvalResult &Result, ASTContext &Ctx) const { + EvalInfo Info(Ctx, Result, true); + + if (getType()->isVectorType()) { + if (!EvaluateVector(this, Result.Val, Info)) + return false; + } else if (getType()->isIntegerType()) { + if (!IntExprEvaluator(Info, Result.Val).Visit(const_cast<Expr*>(this))) + return false; + } else if (getType()->hasPointerRepresentation()) { + if (!EvaluatePointer(this, Result.Val, Info)) + return false; + } else if (getType()->isRealFloatingType()) { + llvm::APFloat f(0.0); + if (!EvaluateFloat(this, f, Info)) + return false; + + Result.Val = APValue(f); + } else if (getType()->isAnyComplexType()) { + if (!EvaluateComplex(this, Result.Val, Info)) + return false; + } else + return false; + + return true; +} + 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 c79cc3c..0b159c3 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -47,6 +47,8 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { if (!i->isVirtual()) { + assert(!i->getType()->isDependentType() && + "Cannot layout class with dependent bases."); const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); // Skip the PrimaryBase here, as it is laid down first. @@ -82,6 +84,8 @@ void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) { // Now traverse all bases and find primary bases for them. for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { + assert(!i->getType()->isDependentType() && + "Cannot layout class with dependent bases."); const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); @@ -97,6 +101,8 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD, const CXXRecordDecl *&FirstPrimary) { for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { + assert(!i->getType()->isDependentType() && + "Cannot layout class with dependent bases."); const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); if (!i->isVirtual()) { @@ -123,6 +129,8 @@ void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) { // indirect bases, and record all their primary virtual base classes. for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { + assert(!i->getType()->isDependentType() && + "Cannot layout class with dependent bases."); const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); IdentifyPrimaryBases(Base); @@ -173,6 +181,8 @@ void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary) { for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { + assert(!i->getType()->isDependentType() && + "Cannot layout class with dependent bases."); const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); #if 0 @@ -235,6 +245,8 @@ bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD, // Check bases. for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { + assert(!I->getType()->isDependentType() && + "Cannot layout class with dependent bases."); if (I->isVirtual()) continue; @@ -305,6 +317,8 @@ void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD, // Update bases. for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { + assert(!I->getType()->isDependentType() && + "Cannot layout class with dependent bases."); if (I->isVirtual()) continue; diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h index 6e4cdd2..b57b37d 100644 --- a/lib/AST/RecordLayoutBuilder.h +++ b/lib/AST/RecordLayoutBuilder.h @@ -12,7 +12,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallSet.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/System/DataTypes.h" #include <map> namespace clang { diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 2af1976..4bd7f96 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -473,14 +473,14 @@ void StmtPrinter::VisitExpr(Expr *Node) { } void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { + if (NestedNameSpecifier *Qualifier = Node->getQualifier()) + Qualifier->print(OS, Policy); OS << Node->getDecl()->getNameAsString(); -} - -void StmtPrinter::VisitQualifiedDeclRefExpr(QualifiedDeclRefExpr *Node) { - NamedDecl *D = Node->getDecl(); - - Node->getQualifier()->print(OS, Policy); - OS << D->getNameAsString(); + if (Node->hasExplicitTemplateArgumentList()) + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Node->getTemplateArgs(), + Node->getNumTemplateArgs(), + Policy); } void StmtPrinter::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *Node) { diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index c4d42f6..02e0c74 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -60,7 +60,10 @@ namespace { /// \brief Visit template arguments that occur within an expression or /// statement. - void VisitTemplateArguments(const TemplateArgument *Args, unsigned NumArgs); + void VisitTemplateArguments(const TemplateArgumentLoc *Args, unsigned NumArgs); + + /// \brief Visit a single template argument. + void VisitTemplateArgument(const TemplateArgument &Arg); }; } @@ -206,7 +209,9 @@ void StmtProfiler::VisitExpr(Expr *S) { void StmtProfiler::VisitDeclRefExpr(DeclRefExpr *S) { VisitExpr(S); + VisitNestedNameSpecifier(S->getQualifier()); VisitDecl(S->getDecl()); + VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); } void StmtProfiler::VisitPredefinedExpr(PredefinedExpr *S) { @@ -521,11 +526,6 @@ void StmtProfiler::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *S) { VisitType(S->getQueriedType()); } -void StmtProfiler::VisitQualifiedDeclRefExpr(QualifiedDeclRefExpr *S) { - VisitDeclRefExpr(S); - VisitNestedNameSpecifier(S->getQualifier()); -} - void StmtProfiler::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *S) { VisitExpr(S); VisitName(S->getDeclName()); @@ -677,39 +677,42 @@ void StmtProfiler::VisitTemplateName(TemplateName Name) { Name.Profile(ID); } -void StmtProfiler::VisitTemplateArguments(const TemplateArgument *Args, +void StmtProfiler::VisitTemplateArguments(const TemplateArgumentLoc *Args, unsigned NumArgs) { ID.AddInteger(NumArgs); - for (unsigned I = 0; I != NumArgs; ++I) { - const TemplateArgument &Arg = Args[I]; - - // Mostly repetitive with TemplateArgument::Profile! - ID.AddInteger(Arg.getKind()); - switch (Arg.getKind()) { - case TemplateArgument::Null: - break; - - case TemplateArgument::Type: - VisitType(Arg.getAsType()); - break; - - case TemplateArgument::Declaration: - VisitDecl(Arg.getAsDecl()); - break; - - case TemplateArgument::Integral: - Arg.getAsIntegral()->Profile(ID); - VisitType(Arg.getIntegralType()); - break; - - case TemplateArgument::Expression: - Visit(Arg.getAsExpr()); - break; - - case TemplateArgument::Pack: - VisitTemplateArguments(Arg.pack_begin(), Arg.pack_size()); - break; - } + for (unsigned I = 0; I != NumArgs; ++I) + VisitTemplateArgument(Args[I].getArgument()); +} + +void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) { + // Mostly repetitive with TemplateArgument::Profile! + ID.AddInteger(Arg.getKind()); + switch (Arg.getKind()) { + case TemplateArgument::Null: + break; + + case TemplateArgument::Type: + VisitType(Arg.getAsType()); + break; + + case TemplateArgument::Declaration: + VisitDecl(Arg.getAsDecl()); + break; + + case TemplateArgument::Integral: + Arg.getAsIntegral()->Profile(ID); + VisitType(Arg.getIntegralType()); + break; + + case TemplateArgument::Expression: + Visit(Arg.getAsExpr()); + break; + + case TemplateArgument::Pack: + const TemplateArgument *Pack = Arg.pack_begin(); + for (unsigned i = 0, e = Arg.pack_size(); i != e; ++i) + VisitTemplateArgument(Pack[i]); + break; } } diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp new file mode 100644 index 0000000..94e1ca1 --- /dev/null +++ b/lib/AST/TemplateBase.cpp @@ -0,0 +1,97 @@ +//===--- TemplateBase.cpp - Common template AST class implementation ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements common classes used throughout C++ template +// representations. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/FoldingSet.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/Expr.h" +#include "clang/AST/TypeLoc.h" + +using namespace clang; + +//===----------------------------------------------------------------------===// +// TemplateArgument Implementation +//===----------------------------------------------------------------------===// + +/// \brief Construct a template argument pack. +void TemplateArgument::setArgumentPack(TemplateArgument *args, unsigned NumArgs, + bool CopyArgs) { + assert(isNull() && "Must call setArgumentPack on a null argument"); + + Kind = Pack; + Args.NumArgs = NumArgs; + Args.CopyArgs = CopyArgs; + if (!Args.CopyArgs) { + Args.Args = args; + return; + } + + // FIXME: Allocate in ASTContext + Args.Args = new TemplateArgument[NumArgs]; + for (unsigned I = 0; I != Args.NumArgs; ++I) + Args.Args[I] = args[I]; +} + +void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID, + ASTContext &Context) const { + ID.AddInteger(Kind); + switch (Kind) { + case Null: + break; + + case Type: + getAsType().Profile(ID); + break; + + case Declaration: + ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : 0); + break; + + case Integral: + getAsIntegral()->Profile(ID); + getIntegralType().Profile(ID); + break; + + case Expression: + getAsExpr()->Profile(ID, Context, true); + break; + + case Pack: + ID.AddInteger(Args.NumArgs); + for (unsigned I = 0; I != Args.NumArgs; ++I) + Args.Args[I].Profile(ID, Context); + } +} + +//===----------------------------------------------------------------------===// +// TemplateArgumentLoc Implementation +//===----------------------------------------------------------------------===// + +SourceRange TemplateArgumentLoc::getSourceRange() const { + switch (Argument.getKind()) { + case TemplateArgument::Expression: + return getSourceExpression()->getSourceRange(); + case TemplateArgument::Declaration: + return getSourceDeclExpression()->getSourceRange(); + case TemplateArgument::Type: + return getSourceDeclaratorInfo()->getTypeLoc().getFullSourceRange(); + case TemplateArgument::Integral: + case TemplateArgument::Pack: + case TemplateArgument::Null: + return SourceRange(); + } + + // Silence bonus gcc warning. + return SourceRange(); +} diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp index 24588bc..5b4cf0a 100644 --- a/lib/AST/TemplateName.cpp +++ b/lib/AST/TemplateName.cpp @@ -56,7 +56,7 @@ void TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, bool SuppressNNS) const { if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>()) - OS << Template->getIdentifier()->getName(); + OS << Template->getNameAsString(); else if (OverloadedFunctionDecl *Ovl = Storage.dyn_cast<OverloadedFunctionDecl *>()) OS << Ovl->getNameAsString(); @@ -70,8 +70,11 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, if (!SuppressNNS && DTN->getQualifier()) DTN->getQualifier()->print(OS, Policy); OS << "template "; - // FIXME: Shouldn't we have a more general kind of name? - OS << DTN->getName()->getName(); + + if (DTN->isIdentifier()) + OS << DTN->getIdentifier()->getName(); + else + OS << "operator " << getOperatorSpelling(DTN->getOperator()); } } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 5fb0178..3608d34 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -224,6 +224,8 @@ QualType Type::getPointeeType() const { return OPT->getPointeeType(); if (const BlockPointerType *BPT = getAs<BlockPointerType>()) return BPT->getPointeeType(); + if (const ReferenceType *RT = getAs<ReferenceType>()) + return RT->getPointeeType(); return QualType(); } @@ -791,40 +793,48 @@ bool EnumType::classof(const TagType *TT) { return isa<EnumDecl>(TT->getDecl()); } -bool -TemplateSpecializationType:: -anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs) { - for (unsigned Idx = 0; Idx < NumArgs; ++Idx) { - switch (Args[Idx].getKind()) { - case TemplateArgument::Null: - assert(false && "Should not have a NULL template argument"); - break; - - case TemplateArgument::Type: - if (Args[Idx].getAsType()->isDependentType()) - return true; - break; - - case TemplateArgument::Declaration: - case TemplateArgument::Integral: - // Never dependent - break; - - case TemplateArgument::Expression: - if (Args[Idx].getAsExpr()->isTypeDependent() || - Args[Idx].getAsExpr()->isValueDependent()) - return true; - break; - - case TemplateArgument::Pack: - assert(0 && "FIXME: Implement!"); - break; - } +static bool isDependent(const TemplateArgument &Arg) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + assert(false && "Should not have a NULL template argument"); + return false; + + case TemplateArgument::Type: + return Arg.getAsType()->isDependentType(); + + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + // Never dependent + return false; + + case TemplateArgument::Expression: + return (Arg.getAsExpr()->isTypeDependent() || + Arg.getAsExpr()->isValueDependent()); + + case TemplateArgument::Pack: + assert(0 && "FIXME: Implement!"); + return false; } return false; } +bool TemplateSpecializationType:: +anyDependentTemplateArguments(const TemplateArgumentLoc *Args, unsigned N) { + for (unsigned i = 0; i != N; ++i) + if (isDependent(Args[i].getArgument())) + return true; + return false; +} + +bool TemplateSpecializationType:: +anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N) { + for (unsigned i = 0; i != N; ++i) + if (isDependent(Args[i])) + return true; + return false; +} + TemplateSpecializationType:: TemplateSpecializationType(ASTContext &Context, TemplateName T, const TemplateArgument *Args, @@ -1260,6 +1270,38 @@ void SubstTemplateTypeParmType::getAsStringInternal(std::string &InnerString, co getReplacementType().getAsStringInternal(InnerString, Policy); } +static void PrintTemplateArgument(std::string &Buffer, + const TemplateArgument &Arg, + const PrintingPolicy &Policy) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + assert(false && "Null template argument"); + break; + + case TemplateArgument::Type: + Arg.getAsType().getAsStringInternal(Buffer, Policy); + break; + + case TemplateArgument::Declaration: + Buffer = cast<NamedDecl>(Arg.getAsDecl())->getNameAsString(); + break; + + case TemplateArgument::Integral: + Buffer = Arg.getAsIntegral()->toString(10, true); + break; + + case TemplateArgument::Expression: { + llvm::raw_string_ostream s(Buffer); + Arg.getAsExpr()->printPretty(s, 0, Policy); + break; + } + + case TemplateArgument::Pack: + assert(0 && "FIXME: Implement!"); + break; + } +} + std::string TemplateSpecializationType::PrintTemplateArgumentList( const TemplateArgument *Args, @@ -1273,32 +1315,41 @@ TemplateSpecializationType::PrintTemplateArgumentList( // Print the argument into a string. std::string ArgString; - switch (Args[Arg].getKind()) { - case TemplateArgument::Null: - assert(false && "Null template argument"); - break; - - case TemplateArgument::Type: - Args[Arg].getAsType().getAsStringInternal(ArgString, Policy); - break; - - case TemplateArgument::Declaration: - ArgString = cast<NamedDecl>(Args[Arg].getAsDecl())->getNameAsString(); - break; - - case TemplateArgument::Integral: - ArgString = Args[Arg].getAsIntegral()->toString(10, true); - break; - - case TemplateArgument::Expression: { - llvm::raw_string_ostream s(ArgString); - Args[Arg].getAsExpr()->printPretty(s, 0, Policy); - break; - } - case TemplateArgument::Pack: - assert(0 && "FIXME: Implement!"); - break; - } + PrintTemplateArgument(ArgString, Args[Arg], Policy); + + // If this is the first argument and its string representation + // begins with the global scope specifier ('::foo'), add a space + // to avoid printing the diagraph '<:'. + if (!Arg && !ArgString.empty() && ArgString[0] == ':') + SpecString += ' '; + + SpecString += ArgString; + } + + // If the last character of our string is '>', add another space to + // keep the two '>''s separate tokens. We don't *have* to do this in + // C++0x, but it's still good hygiene. + if (SpecString[SpecString.size() - 1] == '>') + SpecString += ' '; + + SpecString += '>'; + + return SpecString; +} + +// Sadly, repeat all that with TemplateArgLoc. +std::string TemplateSpecializationType:: +PrintTemplateArgumentList(const TemplateArgumentLoc *Args, unsigned NumArgs, + const PrintingPolicy &Policy) { + std::string SpecString; + SpecString += '<'; + for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { + if (Arg) + SpecString += ", "; + + // Print the argument into a string. + std::string ArgString; + PrintTemplateArgument(ArgString, Args[Arg].getArgument(), Policy); // If this is the first argument and its string representation // begins with the global scope specifier ('::foo'), add a space diff --git a/lib/Analysis/AttrNonNullChecker.cpp b/lib/Analysis/AttrNonNullChecker.cpp new file mode 100644 index 0000000..1cf5d0c --- /dev/null +++ b/lib/Analysis/AttrNonNullChecker.cpp @@ -0,0 +1,100 @@ +//===--- AttrNonNullChecker.h - Undefined arguments checker ----*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines AttrNonNullChecker, a builtin check in GRExprEngine that +// performs checks for arguments declared to have nonnull attribute. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/Checkers/AttrNonNullChecker.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" + +using namespace clang; + +void *AttrNonNullChecker::getTag() { + static int x = 0; + return &x; +} + +void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C, + const CallExpr *CE) { + const GRState *state = C.getState(); + const GRState *originalState = state; + + // Check if the callee has a 'nonnull' attribute. + SVal X = state->getSVal(CE->getCallee()); + + const FunctionDecl* FD = X.getAsFunctionDecl(); + if (!FD) + return; + + const NonNullAttr* Att = FD->getAttr<NonNullAttr>(); + if (!Att) + return; + + // Iterate through the arguments of CE and check them for null. + unsigned idx = 0; + + for (CallExpr::const_arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E; + ++I, ++idx) { + + if (!Att->isNonNull(idx)) + continue; + + const SVal &V = state->getSVal(*I); + const DefinedSVal *DV = dyn_cast<DefinedSVal>(&V); + + if (!DV) + continue; + + ConstraintManager &CM = C.getConstraintManager(); + const GRState *stateNotNull, *stateNull; + llvm::tie(stateNotNull, stateNull) = CM.AssumeDual(state, *DV); + + if (stateNull && !stateNotNull) { + // Generate an error node. Check for a null node in case + // we cache out. + if (ExplodedNode *errorNode = C.GenerateNode(CE, stateNull, true)) { + + // Lazily allocate the BugType object if it hasn't already been + // created. Ownership is transferred to the BugReporter object once + // the BugReport is passed to 'EmitWarning'. + if (!BT) + BT = new BugType("Argument with 'nonnull' attribute passed null", + "API"); + + EnhancedBugReport *R = + new EnhancedBugReport(*BT, + "Null pointer passed as an argument to a " + "'nonnull' parameter", errorNode); + + // Highlight the range of the argument that was null. + const Expr *arg = *I; + R->addRange(arg->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, arg); + + // Emit the bug report. + C.EmitReport(R); + } + + // Always return. Either we cached out or we just emitted an error. + return; + } + + // If a pointer value passed the check we should assume that it is + // indeed not null from this point forward. + assert(stateNotNull); + state = stateNotNull; + } + + // If we reach here all of the arguments passed the nonnull check. + // If 'state' has been updated generated a new node. + if (state != originalState) + C.addTransition(C.GenerateNode(CE, state)); +} diff --git a/lib/Analysis/BadCallChecker.cpp b/lib/Analysis/BadCallChecker.cpp new file mode 100644 index 0000000..33bb515 --- /dev/null +++ b/lib/Analysis/BadCallChecker.cpp @@ -0,0 +1,44 @@ +//===--- BadCallChecker.h - Bad call checker --------------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines BadCallChecker, a builtin check in GRExprEngine that performs +// checks for bad callee at call sites. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/Checkers/BadCallChecker.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" + +using namespace clang; + +void *BadCallChecker::getTag() { + static int x = 0; + return &x; +} + +void BadCallChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { + const Expr *Callee = CE->getCallee()->IgnoreParens(); + SVal L = C.getState()->getSVal(Callee); + + if (L.isUndef() || isa<loc::ConcreteInt>(L)) { + if (ExplodedNode *N = C.GenerateNode(CE, true)) { + if (!BT) + BT = new BuiltinBug(0, "Invalid function call", + "Called function pointer is a null or undefined pointer value"); + + EnhancedBugReport *R = + new EnhancedBugReport(*BT, BT->getDescription().c_str(), N); + + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, + bugreporter::GetCalleeExpr(N)); + + C.EmitReport(R); + } + } +} diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp index aa2d0ab..4781d5e 100644 --- a/lib/Analysis/BasicObjCFoundationChecks.cpp +++ b/lib/Analysis/BasicObjCFoundationChecks.cpp @@ -535,4 +535,5 @@ void clang::RegisterAppleChecks(GRExprEngine& Eng, const Decl &D) { Eng.AddCheck(CreateAuditCFRetainRelease(Ctx, BR), Stmt::CallExprClass); RegisterNSErrorChecks(BR, Eng, D); + RegisterNSAutoreleasePoolChecks(Eng); } diff --git a/lib/Analysis/BasicObjCFoundationChecks.h b/lib/Analysis/BasicObjCFoundationChecks.h index 1271ae4..ea4d3ec 100644 --- a/lib/Analysis/BasicObjCFoundationChecks.h +++ b/lib/Analysis/BasicObjCFoundationChecks.h @@ -42,6 +42,7 @@ GRSimpleAPICheck *CreateAuditCFRetainRelease(ASTContext& Ctx, BugReporter& BR); void RegisterNSErrorChecks(BugReporter& BR, GRExprEngine &Eng, const Decl &D); +void RegisterNSAutoreleasePoolChecks(GRExprEngine &Eng); } // end clang namespace diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp index d81d83c..888af9b 100644 --- a/lib/Analysis/BasicStore.cpp +++ b/lib/Analysis/BasicStore.cpp @@ -92,19 +92,17 @@ public: void iterBindings(Store store, BindingsHandler& f); - const GRState *BindDecl(const GRState *state, const VarDecl *VD, - const LocationContext *LC, SVal InitVal) { - return state->makeWithStore(BindDeclInternal(state->getStore(),VD, LC, + const GRState *BindDecl(const GRState *state, const VarRegion *VR, + SVal InitVal) { + return state->makeWithStore(BindDeclInternal(state->getStore(), VR, &InitVal)); } - const GRState *BindDeclWithNoInit(const GRState *state, const VarDecl *VD, - const LocationContext *LC) { - return state->makeWithStore(BindDeclInternal(state->getStore(), VD, LC, 0)); + const GRState *BindDeclWithNoInit(const GRState *state, const VarRegion *VR) { + return state->makeWithStore(BindDeclInternal(state->getStore(), VR, 0)); } - Store BindDeclInternal(Store store, const VarDecl *VD, - const LocationContext *LC, SVal *InitVal); + Store BindDeclInternal(Store store, const VarRegion *VR, SVal *InitVal); static inline BindingsTy GetBindings(Store store) { return BindingsTy(static_cast<const BindingsTy::TreeTy*>(store)); @@ -532,11 +530,11 @@ Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) { return St; } -Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD, - const LocationContext *LC, +Store BasicStoreManager::BindDeclInternal(Store store, const VarRegion* VR, SVal* InitVal) { BasicValueFactory& BasicVals = StateMgr.getBasicVals(); + const VarDecl *VD = VR->getDecl(); // BasicStore does not model arrays and structs. if (VD->getType()->isArrayType() || VD->getType()->isStructureType()) @@ -564,16 +562,16 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD, if (!InitVal) { QualType T = VD->getType(); if (Loc::IsLocType(T)) - store = BindInternal(store, getLoc(VD, LC), + store = BindInternal(store, loc::MemRegionVal(VR), loc::ConcreteInt(BasicVals.getValue(0, T))); else if (T->isIntegerType()) - store = BindInternal(store, getLoc(VD, LC), + store = BindInternal(store, loc::MemRegionVal(VR), nonloc::ConcreteInt(BasicVals.getValue(0, T))); else { // assert(0 && "ignore other types of variables"); } } else { - store = BindInternal(store, getLoc(VD, LC), *InitVal); + store = BindInternal(store, loc::MemRegionVal(VR), *InitVal); } } } else { @@ -581,7 +579,7 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarDecl* VD, QualType T = VD->getType(); if (ValMgr.getSymbolManager().canSymbolicate(T)) { SVal V = InitVal ? *InitVal : UndefinedVal(); - store = BindInternal(store, getLoc(VD, LC), V); + store = BindInternal(store, loc::MemRegionVal(VR), V); } } diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index c629ad1..03614e8 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -193,20 +193,6 @@ public: } // end anonymous namespace //===----------------------------------------------------------------------===// -// Selector creation functions. -//===----------------------------------------------------------------------===// - -static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) { - IdentifierInfo* II = &Ctx.Idents.get(name); - return Ctx.Selectors.getSelector(0, &II); -} - -static inline Selector GetUnarySelector(const char* name, ASTContext& Ctx) { - IdentifierInfo* II = &Ctx.Idents.get(name); - return Ctx.Selectors.getSelector(1, &II); -} - -//===----------------------------------------------------------------------===// // Type querying functions. //===----------------------------------------------------------------------===// @@ -1031,11 +1017,25 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { // Eventually this can be improved by recognizing that the pixel // buffer passed to CVPixelBufferCreateWithBytes is released via // a callback and doing full IPA to make sure this is done correctly. + // FIXME: This function has an out parameter that returns an + // allocated object. ScratchArgs = AF.Add(ScratchArgs, 7, StopTracking); S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); } break; + + case 29: + if (!memcmp(FName, "CGBitmapContextCreateWithData", 29)) { + // FIXES: <rdar://problem/7358899> + // Eventually this can be improved by recognizing that 'releaseInfo' + // passed to CGBitmapContextCreateWithData is released via + // a callback and doing full IPA to make sure this is done correctly. + ScratchArgs = AF.Add(ScratchArgs, 8, StopTracking); + S = getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true), + DoNothing,DoNothing); + } + break; case 32: if (!memcmp(FName, "IOServiceAddMatchingNotification", 32)) { @@ -1899,7 +1899,7 @@ public: virtual ~CFRefCount() {} - void RegisterChecks(BugReporter &BR); + void RegisterChecks(GRExprEngine &Eng); virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) { Printers.push_back(new BindingsPrinter()); @@ -2193,7 +2193,9 @@ namespace { }; } // end anonymous namespace -void CFRefCount::RegisterChecks(BugReporter& BR) { +void CFRefCount::RegisterChecks(GRExprEngine& Eng) { + BugReporter &BR = Eng.getBugReporter(); + useAfterRelease = new UseAfterRelease(this); BR.Register(useAfterRelease); diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index 89c1783..cd4697f 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -3,6 +3,8 @@ set(LLVM_NO_RTTI 1) add_clang_library(clangAnalysis AnalysisContext.cpp AnalysisManager.cpp + AttrNonNullChecker.cpp + BadCallChecker.cpp BasicConstraintManager.cpp BasicObjCFoundationChecks.cpp BasicStore.cpp @@ -14,11 +16,12 @@ add_clang_library(clangAnalysis CallGraph.cpp CallInliner.cpp CheckDeadStores.cpp - CheckNSError.cpp CheckObjCDealloc.cpp CheckObjCInstMethSignature.cpp CheckObjCUnusedIVars.cpp CheckSecuritySyntaxOnly.cpp + DereferenceChecker.cpp + DivZeroChecker.cpp Environment.cpp ExplodedGraph.cpp GRBlockCounter.cpp @@ -28,6 +31,8 @@ add_clang_library(clangAnalysis GRState.cpp LiveVariables.cpp MemRegion.cpp + NSAutoreleasePoolChecker.cpp + NSErrorChecker.cpp PathDiagnostic.cpp RangeConstraintManager.cpp RegionStore.cpp @@ -37,8 +42,11 @@ add_clang_library(clangAnalysis SimpleSValuator.cpp Store.cpp SymbolManager.cpp + UndefinedArgChecker.cpp + UndefinedAssignmentChecker.cpp UninitializedValues.cpp ValueManager.cpp + VLASizeChecker.cpp ) add_dependencies(clangAnalysis ClangDiagnosticAnalysis) diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp index ae8845d..17dc068 100644 --- a/lib/Analysis/CallGraph.cpp +++ b/lib/Analysis/CallGraph.cpp @@ -68,10 +68,8 @@ CallGraph::~CallGraph() { } } -void CallGraph::addTU(ASTUnit &AST) { - ASTContext &Ctx = AST.getASTContext(); +void CallGraph::addTU(ASTContext& Ctx) { DeclContext *DC = Ctx.getTranslationUnitDecl(); - for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) { diff --git a/lib/Analysis/CheckObjCUnusedIVars.cpp b/lib/Analysis/CheckObjCUnusedIVars.cpp index 1a900f8..2d9b531 100644 --- a/lib/Analysis/CheckObjCUnusedIVars.cpp +++ b/lib/Analysis/CheckObjCUnusedIVars.cpp @@ -62,6 +62,29 @@ static void Scan(IvarUsageMap& M, const ObjCPropertyImplDecl* D) { I->second = Used; } +static void Scan(IvarUsageMap& M, const ObjCContainerDecl* D) { + // Scan the methods for accesses. + for (ObjCContainerDecl::instmeth_iterator I = D->instmeth_begin(), + E = D->instmeth_end(); I!=E; ++I) + Scan(M, (*I)->getBody()); + + if (const ObjCImplementationDecl *ID = dyn_cast<ObjCImplementationDecl>(D)) { + // Scan for @synthesized property methods that act as setters/getters + // to an ivar. + for (ObjCImplementationDecl::propimpl_iterator I = ID->propimpl_begin(), + E = ID->propimpl_end(); I!=E; ++I) + Scan(M, *I); + + // Scan the associated categories as well. + for (const ObjCCategoryDecl *CD = + ID->getClassInterface()->getCategoryList(); CD ; + CD = CD->getNextClassCategory()) { + if (const ObjCCategoryImplDecl *CID = CD->getImplementation()) + Scan(M, CID); + } + } +} + void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D, BugReporter &BR) { @@ -88,16 +111,8 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D, if (M.empty()) return; - // Now scan the methods for accesses. - for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(), - E = D->instmeth_end(); I!=E; ++I) - Scan(M, (*I)->getBody()); - - // Scan for @synthesized property methods that act as setters/getters - // to an ivar. - for (ObjCImplementationDecl::propimpl_iterator I = D->propimpl_begin(), - E = D->propimpl_end(); I!=E; ++I) - Scan(M, *I); + // Now scan the implementation declaration. + Scan(M, D); // Find ivars that are unused. for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I) diff --git a/lib/Analysis/DereferenceChecker.cpp b/lib/Analysis/DereferenceChecker.cpp new file mode 100644 index 0000000..33c85d5 --- /dev/null +++ b/lib/Analysis/DereferenceChecker.cpp @@ -0,0 +1,112 @@ +//== NullDerefChecker.cpp - Null dereference checker ------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines NullDerefChecker, a builtin check in GRExprEngine that performs +// checks for null pointers at loads and stores. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h" +#include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" + +using namespace clang; + +void *NullDerefChecker::getTag() { + static int x = 0; + return &x; +} + +ExplodedNode *NullDerefChecker::CheckLocation(const Stmt *S, ExplodedNode *Pred, + const GRState *state, SVal V, + GRExprEngine &Eng) { + Loc *LV = dyn_cast<Loc>(&V); + + // If the value is not a location, don't touch the node. + if (!LV) + return Pred; + + const GRState *NotNullState = state->Assume(*LV, true); + const GRState *NullState = state->Assume(*LV, false); + + GRStmtNodeBuilder &Builder = Eng.getBuilder(); + BugReporter &BR = Eng.getBugReporter(); + + // The explicit NULL case. + if (NullState) { + // Use the GDM to mark in the state what lval was null. + const SVal *PersistentLV = Eng.getBasicVals().getPersistentSVal(*LV); + NullState = NullState->set<GRState::NullDerefTag>(PersistentLV); + + ExplodedNode *N = Builder.generateNode(S, NullState, Pred, + ProgramPoint::PostNullCheckFailedKind); + if (N) { + N->markAsSink(); + + if (!NotNullState) { // Explicit null case. + if (!BT) + BT = new BuiltinBug(NULL, "Null dereference", + "Dereference of null pointer"); + + EnhancedBugReport *R = + new EnhancedBugReport(*BT, BT->getDescription().c_str(), N); + + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, + bugreporter::GetDerefExpr(N)); + + BR.EmitReport(R); + + return 0; + } else // Implicit null case. + ImplicitNullDerefNodes.push_back(N); + } + } + + if (!NotNullState) + return 0; + + return Builder.generateNode(S, NotNullState, Pred, + ProgramPoint::PostLocationChecksSucceedKind); +} + + +void *UndefDerefChecker::getTag() { + static int x = 0; + return &x; +} + +ExplodedNode *UndefDerefChecker::CheckLocation(const Stmt *S, + ExplodedNode *Pred, + const GRState *state, SVal V, + GRExprEngine &Eng) { + GRStmtNodeBuilder &Builder = Eng.getBuilder(); + BugReporter &BR = Eng.getBugReporter(); + + if (V.isUndef()) { + ExplodedNode *N = Builder.generateNode(S, state, Pred, + ProgramPoint::PostUndefLocationCheckFailedKind); + if (N) { + N->markAsSink(); + + if (!BT) + BT = new BuiltinBug(0, "Undefined dereference", + "Dereference of undefined pointer value"); + + EnhancedBugReport *R = + new EnhancedBugReport(*BT, BT->getDescription().c_str(), N); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, + bugreporter::GetDerefExpr(N)); + BR.EmitReport(R); + } + return 0; + } + + return Pred; +} + diff --git a/lib/Analysis/DivZeroChecker.cpp b/lib/Analysis/DivZeroChecker.cpp new file mode 100644 index 0000000..9c2359f --- /dev/null +++ b/lib/Analysis/DivZeroChecker.cpp @@ -0,0 +1,70 @@ +//== DivZeroChecker.cpp - Division by zero checker --------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines DivZeroChecker, a builtin check in GRExprEngine that performs +// checks for division by zeros. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/Checkers/DivZeroChecker.h" + +using namespace clang; + +void *DivZeroChecker::getTag() { + static int x; + return &x; +} + +void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C, + const BinaryOperator *B) { + BinaryOperator::Opcode Op = B->getOpcode(); + if (Op != BinaryOperator::Div && + Op != BinaryOperator::Rem && + Op != BinaryOperator::DivAssign && + Op != BinaryOperator::RemAssign) + return; + + if (!B->getRHS()->getType()->isIntegerType() || + !B->getRHS()->getType()->isScalarType()) + return; + + SVal Denom = C.getState()->getSVal(B->getRHS()); + const DefinedSVal *DV = dyn_cast<DefinedSVal>(&Denom); + + // Divide-by-undefined handled in the generic checking for uses of + // undefined values. + if (!DV) + return; + + // Check for divide by zero. + ConstraintManager &CM = C.getConstraintManager(); + const GRState *stateNotZero, *stateZero; + llvm::tie(stateNotZero, stateZero) = CM.AssumeDual(C.getState(), *DV); + + if (stateZero && !stateNotZero) { + if (ExplodedNode *N = C.GenerateNode(B, stateZero, true)) { + if (!BT) + BT = new BuiltinBug(0, "Division by zero"); + + EnhancedBugReport *R = + new EnhancedBugReport(*BT, BT->getDescription().c_str(), N); + + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, + bugreporter::GetDenomExpr(N)); + + C.EmitReport(R); + } + return; + } + + // If we get here, then the denom should not be zero. We abandon the implicit + // zero denom case for now. + if (stateNotZero != C.getState()) + C.addTransition(C.GenerateNode(B, stateNotZero)); +} diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index ea0255d..c71882e 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -25,6 +25,7 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/ImmutableList.h" +#include "llvm/ADT/StringSwitch.h" #ifndef NDEBUG #include "llvm/Support/GraphWriter.h" @@ -117,17 +118,18 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet Tmp; ExplodedNodeSet *PrevSet = &Src; - for (std::vector<Checker*>::iterator I = Checkers.begin(), E = Checkers.end(); - I != E; ++I) { - - ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) + { + ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst : (PrevSet == &Tmp) ? &Src : &Tmp; + CurrSet->clear(); - Checker *checker = *I; + void *tag = I->first; + Checker *checker = I->second; for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); NI != NE; ++NI) - checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, isPrevisit); + checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit); // Update which NodeSet is the current one. PrevSet = CurrSet; @@ -137,6 +139,41 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, // automatically. } +// FIXME: This is largely copy-paste from CheckerVisit(). Need to +// unify. +void GRExprEngine::CheckerVisitBind(Stmt *S, ExplodedNodeSet &Dst, + ExplodedNodeSet &Src, + SVal location, SVal val, bool isPrevisit) { + + if (Checkers.empty()) { + Dst = Src; + return; + } + + ExplodedNodeSet Tmp; + ExplodedNodeSet *PrevSet = &Src; + + for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) + { + ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst + : (PrevSet == &Tmp) ? &Src : &Tmp; + + CurrSet->clear(); + void *tag = I->first; + Checker *checker = I->second; + + for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); + NI != NE; ++NI) + checker->GR_VisitBind(*CurrSet, *Builder, *this, S, *NI, tag, location, + val, isPrevisit); + + // Update which NodeSet is the current one. + PrevSet = CurrSet; + } + + // Don't autotransition. The CheckerContext objects should do this + // automatically. +} //===----------------------------------------------------------------------===// // Engine construction and deletion. //===----------------------------------------------------------------------===// @@ -165,9 +202,8 @@ GRExprEngine::GRExprEngine(AnalysisManager &mgr) GRExprEngine::~GRExprEngine() { BR.FlushReports(); delete [] NSExceptionInstanceRaiseSelectors; - for (std::vector<Checker*>::iterator I=Checkers.begin(), E=Checkers.end(); - I!=E; ++I) - delete *I; + for (CheckersOrdered::iterator I=Checkers.begin(), E=Checkers.end(); I!=E;++I) + delete I->second; } //===----------------------------------------------------------------------===// @@ -177,7 +213,7 @@ GRExprEngine::~GRExprEngine() { void GRExprEngine::setTransferFunctions(GRTransferFuncs* tf) { StateMgr.TF = tf; - tf->RegisterChecks(getBugReporter()); + tf->RegisterChecks(*this); tf->RegisterPrinters(getStateManager().Printers); } @@ -369,11 +405,11 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { if (AMgr.shouldEagerlyAssume() && (B->isRelationalOp() || B->isEqualityOp())) { ExplodedNodeSet Tmp; - VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp); + VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp, false); EvalEagerlyAssume(Dst, Tmp, cast<Expr>(S)); } else - VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst); + VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst, false); break; } @@ -395,7 +431,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { } case Stmt::CompoundAssignOperatorClass: - VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst); + VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst, false); break; case Stmt::CompoundLiteralExprClass: @@ -409,7 +445,6 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { } case Stmt::DeclRefExprClass: - case Stmt::QualifiedDeclRefExprClass: VisitDeclRefExpr(cast<DeclRefExpr>(S), Pred, Dst, false); break; @@ -522,7 +557,6 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, return; case Stmt::DeclRefExprClass: - case Stmt::QualifiedDeclRefExprClass: VisitDeclRefExpr(cast<DeclRefExpr>(Ex), Pred, Dst, true); return; @@ -565,6 +599,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, return; } + case Stmt::BinaryOperatorClass: + case Stmt::CompoundAssignOperatorClass: + VisitBinaryOperator(cast<BinaryOperator>(Ex), Pred, Dst, true); + return; + default: // Arbitrary subexpressions can return aggregate temporaries that // can be used in a lvalue context. We need to enhance our support @@ -1078,8 +1117,7 @@ void GRExprEngine::VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred, SVal L = state->getLValue(Field, state->getSVal(Base)); if (asLValue) - MakeNode(Dst, M, *I, state->BindExpr(M, L), - ProgramPoint::PostLValueKind); + MakeNode(Dst, M, *I, state->BindExpr(M, L), ProgramPoint::PostLValueKind); else EvalLoad(Dst, M, *I, state, L); } @@ -1087,30 +1125,52 @@ void GRExprEngine::VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred, /// EvalBind - Handle the semantics of binding a value to a specific location. /// This method is used by EvalStore and (soon) VisitDeclStmt, and others. -void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred, - const GRState* state, SVal location, SVal Val) { +void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, Stmt* Ex, ExplodedNode* Pred, + const GRState* state, SVal location, SVal Val, + bool atDeclInit) { + + + // Do a previsit of the bind. + ExplodedNodeSet CheckedSet, Src; + Src.Add(Pred); + CheckerVisitBind(Ex, CheckedSet, Src, location, Val, true); + + for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); + I!=E; ++I) { + + if (Pred != *I) + state = GetState(*I); + + const GRState* newState = 0; - const GRState* newState = 0; + if (atDeclInit) { + const VarRegion *VR = + cast<VarRegion>(cast<loc::MemRegionVal>(location).getRegion()); - if (location.isUnknown()) { - // We know that the new state will be the same as the old state since - // the location of the binding is "unknown". Consequently, there - // is no reason to just create a new node. - newState = state; - } - else { - // We are binding to a value other than 'unknown'. Perform the binding - // using the StoreManager. - newState = state->bindLoc(cast<Loc>(location), Val); - } + newState = state->bindDecl(VR, Val); + } + else { + if (location.isUnknown()) { + // We know that the new state will be the same as the old state since + // the location of the binding is "unknown". Consequently, there + // is no reason to just create a new node. + newState = state; + } + else { + // We are binding to a value other than 'unknown'. Perform the binding + // using the StoreManager. + newState = state->bindLoc(cast<Loc>(location), Val); + } + } - // The next thing to do is check if the GRTransferFuncs object wants to - // update the state based on the new binding. If the GRTransferFunc object - // doesn't do anything, just auto-propagate the current state. - GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, Pred, newState, Ex, - newState != state); + // The next thing to do is check if the GRTransferFuncs object wants to + // update the state based on the new binding. If the GRTransferFunc object + // doesn't do anything, just auto-propagate the current state. + GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, newState, Ex, + newState != state); - getTF().EvalBind(BuilderRef, location, Val); + getTF().EvalBind(BuilderRef, location, Val); + } } /// EvalStore - Handle the semantics of a store via an assignment. @@ -1189,58 +1249,18 @@ ExplodedNode* GRExprEngine::EvalLocation(Stmt* Ex, ExplodedNode* Pred, SaveAndRestore<const void*> OldTag(Builder->Tag); Builder->Tag = tag; - // Check for loads/stores from/to undefined values. - if (location.isUndef()) { - ExplodedNode* N = - Builder->generateNode(Ex, state, Pred, - ProgramPoint::PostUndefLocationCheckFailedKind); - - if (N) { - N->markAsSink(); - UndefDeref.insert(N); - } - - return 0; - } - - // Check for loads/stores from/to unknown locations. Treat as No-Ops. - if (location.isUnknown()) + if (location.isUnknown() || Checkers.empty()) return Pred; - // During a load, one of two possible situations arise: - // (1) A crash, because the location (pointer) was NULL. - // (2) The location (pointer) is not NULL, and the dereference works. - // - // We add these assumptions. - - Loc LV = cast<Loc>(location); - - // "Assume" that the pointer is not NULL. - const GRState *StNotNull = state->Assume(LV, true); - - // "Assume" that the pointer is NULL. - const GRState *StNull = state->Assume(LV, false); - - if (StNull) { - // Use the Generic Data Map to mark in the state what lval was null. - const SVal* PersistentLV = getBasicVals().getPersistentSVal(LV); - StNull = StNull->set<GRState::NullDerefTag>(PersistentLV); - - // We don't use "MakeNode" here because the node will be a sink - // and we have no intention of processing it later. - ExplodedNode* NullNode = - Builder->generateNode(Ex, StNull, Pred, - ProgramPoint::PostNullCheckFailedKind); - - if (NullNode) { - NullNode->markAsSink(); - if (StNotNull) ImplicitNullDeref.insert(NullNode); - else ExplicitNullDeref.insert(NullNode); - } + + for (CheckersOrdered::iterator I=Checkers.begin(), E=Checkers.end(); I!=E;++I) + { + Pred = I->second->CheckLocation(Ex, Pred, state, location, *this); + if (!Pred) + break; } - - if (!StNotNull) - return NULL; + + return Pred; // FIXME: Temporarily disable out-of-bounds checking until we make // the logic reflect recent changes to CastRegion and friends. @@ -1283,10 +1303,6 @@ ExplodedNode* GRExprEngine::EvalLocation(Stmt* Ex, ExplodedNode* Pred, } } #endif - - // Generate a new node indicating the checks succeed. - return Builder->generateNode(Ex, StNotNull, Pred, - ProgramPoint::PostLocationChecksSucceedKind); } //===----------------------------------------------------------------------===// @@ -1445,75 +1461,30 @@ static void MarkNoReturnFunction(const FunctionDecl *FD, CallExpr *CE, // HACK: Some functions are not marked noreturn, and don't return. // Here are a few hardwired ones. If this takes too long, we can // potentially cache these results. - const char* s = FD->getIdentifier()->getNameStart(); - - switch (FD->getIdentifier()->getLength()) { - default: - break; - - case 4: - if (!memcmp(s, "exit", 4)) Builder->BuildSinks = true; - break; - - case 5: - if (!memcmp(s, "panic", 5)) Builder->BuildSinks = true; - else if (!memcmp(s, "error", 5)) { - if (CE->getNumArgs() > 0) { - SVal X = state->getSVal(*CE->arg_begin()); - // FIXME: use Assume to inspect the possible symbolic value of - // X. Also check the specific signature of error(). - nonloc::ConcreteInt* CI = dyn_cast<nonloc::ConcreteInt>(&X); - if (CI && CI->getValue() != 0) - Builder->BuildSinks = true; - } - } - break; - - case 6: - if (!memcmp(s, "Assert", 6)) { - Builder->BuildSinks = true; - break; - } - - // FIXME: This is just a wrapper around throwing an exception. - // Eventually inter-procedural analysis should handle this easily. - if (!memcmp(s, "ziperr", 6)) Builder->BuildSinks = true; - - break; - - case 7: - if (!memcmp(s, "assfail", 7)) Builder->BuildSinks = true; - break; - - case 8: - if (!memcmp(s ,"db_error", 8) || - !memcmp(s, "__assert", 8)) - Builder->BuildSinks = true; - break; - - case 12: - if (!memcmp(s, "__assert_rtn", 12)) Builder->BuildSinks = true; - break; - - case 13: - if (!memcmp(s, "__assert_fail", 13)) Builder->BuildSinks = true; - break; - - case 14: - if (!memcmp(s, "dtrace_assfail", 14) || - !memcmp(s, "yy_fatal_error", 14)) - Builder->BuildSinks = true; - break; - - case 26: - if (!memcmp(s, "_XCAssertionFailureHandler", 26) || - !memcmp(s, "_DTAssertionFailureHandler", 26) || - !memcmp(s, "_TSAssertionFailureHandler", 26)) - Builder->BuildSinks = true; - - break; - } - + using llvm::StringRef; + bool BuildSinks + = llvm::StringSwitch<bool>(StringRef(FD->getIdentifier()->getName())) + .Case("exit", true) + .Case("panic", true) + .Case("error", true) + .Case("Assert", true) + // FIXME: This is just a wrapper around throwing an exception. + // Eventually inter-procedural analysis should handle this easily. + .Case("ziperr", true) + .Case("assfail", true) + .Case("db_error", true) + .Case("__assert", true) + .Case("__assert_rtn", true) + .Case("__assert_fail", true) + .Case("dtrace_assfail", true) + .Case("yy_fatal_error", true) + .Case("_XCAssertionFailureHandler", true) + .Case("_DTAssertionFailureHandler", true) + .Case("_TSAssertionFailureHandler", true) + .Default(false); + + if (BuildSinks) + Builder->BuildSinks = true; } } @@ -2042,24 +2013,27 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, } } + // Handle previsits checks. + ExplodedNodeSet Src, DstTmp; + Src.Add(Pred); + CheckerVisit(ME, DstTmp, Src, true); + // Check if we raise an exception. For now treat these as sinks. Eventually // we will want to handle exceptions properly. - SaveAndRestore<bool> OldSink(Builder->BuildSinks); - if (RaisesException) Builder->BuildSinks = true; // Dispatch to plug-in transfer function. - unsigned size = Dst.size(); SaveOr OldHasGen(Builder->HasGeneratedNode); - - EvalObjCMessageExpr(Dst, ME, Pred); + + for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); + DI!=DE; ++DI) + EvalObjCMessageExpr(Dst, ME, *DI); // Handle the case where no nodes where generated. Auto-generate that // contains the updated state if we aren't generating sinks. - if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode) MakeNode(Dst, ME, Pred, state); } @@ -2141,45 +2115,25 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, Tmp.Add(Pred); for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - const GRState* state = GetState(*I); - unsigned Count = Builder->getCurrentBlockCount(); - - // Check if 'VD' is a VLA and if so check if has a non-zero size. - QualType T = getContext().getCanonicalType(VD->getType()); - if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) { - // FIXME: Handle multi-dimensional VLAs. - - Expr* SE = VLA->getSizeExpr(); - SVal Size_untested = state->getSVal(SE); - - if (Size_untested.isUndef()) { - if (ExplodedNode* N = Builder->generateNode(DS, state, Pred)) { - N->markAsSink(); - ExplicitBadSizedVLA.insert(N); - } - continue; - } - - DefinedOrUnknownSVal Size = cast<DefinedOrUnknownSVal>(Size_untested); - const GRState *zeroState = state->Assume(Size, false); - state = state->Assume(Size, true); + ExplodedNode *N = *I; + const GRState *state; + + for (CheckersOrdered::iterator CI = Checkers.begin(), CE = Checkers.end(); + CI != CE; ++CI) { + state = GetState(N); + N = CI->second->CheckType(getContext().getCanonicalType(VD->getType()), + N, state, DS, *this); + if (!N) + break; + } - if (zeroState) { - if (ExplodedNode* N = Builder->generateNode(DS, zeroState, Pred)) { - N->markAsSink(); - if (state) - ImplicitBadSizedVLA.insert(N); - else - ExplicitBadSizedVLA.insert(N); - } - } + if (!N) + continue; - if (!state) - continue; - } + state = GetState(N); // Decls without InitExpr are not initialized explicitly. - const LocationContext *LC = (*I)->getLocationContext(); + const LocationContext *LC = N->getLocationContext(); if (InitEx) { SVal InitVal = state->getSVal(InitEx); @@ -2189,20 +2143,15 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, // UnknownVal. if (InitVal.isUnknown() || !getConstraintManager().canReasonAbout(InitVal)) { - InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx, Count); + InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx, + Builder->getCurrentBlockCount()); } - - state = state->bindDecl(VD, LC, InitVal); - - // The next thing to do is check if the GRTransferFuncs object wants to - // update the state based on the new binding. If the GRTransferFunc - // object doesn't do anything, just auto-propagate the current state. - GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, state, DS,true); - getTF().EvalBind(BuilderRef, loc::MemRegionVal(state->getRegion(VD, LC)), - InitVal); + + EvalBind(Dst, DS, *I, state, loc::MemRegionVal(state->getRegion(VD, LC)), + InitVal, true); } else { - state = state->bindDeclWithNoInit(VD, LC); + state = state->bindDeclWithNoInit(state->getRegion(VD, LC)); MakeNode(Dst, DS, *I, state); } } @@ -2752,7 +2701,7 @@ void GRExprEngine::VisitReturnStmt(ReturnStmt* S, ExplodedNode* Pred, void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, ExplodedNode* Pred, - ExplodedNodeSet& Dst) { + ExplodedNodeSet& Dst, bool asLValue) { ExplodedNodeSet Tmp1; Expr* LHS = B->getLHS()->IgnoreParens(); @@ -2798,10 +2747,12 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, unsigned Count = Builder->getCurrentBlockCount(); RightV = ValMgr.getConjuredSymbolVal(NULL, B->getRHS(), Count); } - + + SVal ExprVal = asLValue ? LeftV : RightV; + // Simulate the effects of a "store": bind the value of the RHS // to the L-Value represented by the LHS. - EvalStore(Dst, B, LHS, *I2, state->BindExpr(B, RightV), LeftV, RightV); + EvalStore(Dst, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV, RightV); continue; } @@ -2930,6 +2881,15 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, } //===----------------------------------------------------------------------===// +// Checker registration/lookup. +//===----------------------------------------------------------------------===// + +Checker *GRExprEngine::lookupChecker(void *tag) const { + CheckerMap::iterator I = CheckerM.find(tag); + return (I == CheckerM.end()) ? NULL : Checkers[I->second].second; +} + +//===----------------------------------------------------------------------===// // Visualization. //===----------------------------------------------------------------------===// @@ -2941,7 +2901,8 @@ namespace llvm { template<> struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> : public DefaultDOTGraphTraits { - + // FIXME: Since we do not cache error nodes in GRExprEngine now, this does not + // work. static std::string getNodeAttributes(const ExplodedNode* N, void*) { if (GraphPrintCheckerState->isImplicitNullDeref(N) || diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp index da24192..695f0b0 100644 --- a/lib/Analysis/GRExprEngineInternalChecks.cpp +++ b/lib/Analysis/GRExprEngineInternalChecks.cpp @@ -15,6 +15,13 @@ #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h" +#include "clang/Analysis/PathSensitive/Checkers/DivZeroChecker.h" +#include "clang/Analysis/PathSensitive/Checkers/BadCallChecker.h" +#include "clang/Analysis/PathSensitive/Checkers/UndefinedArgChecker.h" +#include "clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h" +#include "clang/Analysis/PathSensitive/Checkers/AttrNonNullChecker.h" +#include "clang/Analysis/PathSensitive/Checkers/VLASizeChecker.h" #include "clang/Analysis/PathDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/Compiler.h" @@ -40,10 +47,8 @@ ExplodedNode* GetNode(GRExprEngine::undef_arg_iterator I) { //===----------------------------------------------------------------------===// // Bug Descriptions. //===----------------------------------------------------------------------===// - -namespace { - -class VISIBILITY_HIDDEN BuiltinBugReport : public RangedBugReport { +namespace clang { +class BuiltinBugReport : public RangedBugReport { public: BuiltinBugReport(BugType& bt, const char* desc, ExplodedNode *n) @@ -57,30 +62,10 @@ public: const ExplodedNode* N); }; -class VISIBILITY_HIDDEN BuiltinBug : public BugType { - GRExprEngine &Eng; -protected: - const std::string desc; -public: - BuiltinBug(GRExprEngine *eng, const char* n, const char* d) - : BugType(n, "Logic errors"), Eng(*eng), desc(d) {} - - BuiltinBug(GRExprEngine *eng, const char* n) - : BugType(n, "Logic errors"), Eng(*eng), desc(n) {} - - const std::string &getDescription() const { return desc; } - - virtual void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {} - - void FlushReports(BugReporter& BR) { FlushReportsImpl(BR, Eng); } - - virtual void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) {} - - template <typename ITER> void Emit(BugReporter& BR, ITER I, ITER E); -}; - +void BuiltinBugReport::registerInitialVisitors(BugReporterContext& BRC, + const ExplodedNode* N) { + static_cast<BuiltinBug&>(getBugType()).registerInitialVisitors(BRC, N, this); +} template <typename ITER> void BuiltinBug::Emit(BugReporter& BR, ITER I, ITER E) { @@ -88,27 +73,6 @@ void BuiltinBug::Emit(BugReporter& BR, ITER I, ITER E) { GetNode(I))); } -void BuiltinBugReport::registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N) { - static_cast<BuiltinBug&>(getBugType()).registerInitialVisitors(BRC, N, this); -} - -class VISIBILITY_HIDDEN NullDeref : public BuiltinBug { -public: - NullDeref(GRExprEngine* eng) - : BuiltinBug(eng,"Null dereference", "Dereference of null pointer") {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - Emit(BR, Eng.null_derefs_begin(), Eng.null_derefs_end()); - } - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - registerTrackNullOrUndefValue(BRC, GetDerefExpr(N), N); - } -}; - class VISIBILITY_HIDDEN NilReceiverStructRet : public BuiltinBug { public: NilReceiverStructRet(GRExprEngine* eng) : @@ -175,34 +139,6 @@ public: } }; -class VISIBILITY_HIDDEN UndefinedDeref : public BuiltinBug { -public: - UndefinedDeref(GRExprEngine* eng) - : BuiltinBug(eng,"Dereference of undefined pointer value") {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - Emit(BR, Eng.undef_derefs_begin(), Eng.undef_derefs_end()); - } - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - registerTrackNullOrUndefValue(BRC, GetDerefExpr(N), N); - } -}; - -class VISIBILITY_HIDDEN DivZero : public BuiltinBug { -public: - DivZero(GRExprEngine* eng = 0) - : BuiltinBug(eng,"Division by zero") {} - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - registerTrackNullOrUndefValue(BRC, GetDenomExpr(N), N); - } -}; - class VISIBILITY_HIDDEN UndefResult : public BuiltinBug { public: UndefResult(GRExprEngine* eng) @@ -279,20 +215,6 @@ public: } }; -class VISIBILITY_HIDDEN BadCall : public BuiltinBug { -public: - BadCall(GRExprEngine *eng = 0) - : BuiltinBug(eng, "Invalid function call", - "Called function pointer is a null or undefined pointer value") {} - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - registerTrackNullOrUndefValue(BRC, GetCalleeExpr(N), N); - } -}; - - class VISIBILITY_HIDDEN ArgReport : public BuiltinBugReport { const Stmt *Arg; public: @@ -528,276 +450,8 @@ public: } }; -class VISIBILITY_HIDDEN BadSizeVLA : public BuiltinBug { -public: - BadSizeVLA(GRExprEngine* eng) : - BuiltinBug(eng, "Bad variable-length array (VLA) size") {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - for (GRExprEngine::ErrorNodes::iterator - I = Eng.ExplicitBadSizedVLA.begin(), - E = Eng.ExplicitBadSizedVLA.end(); I!=E; ++I) { - - // Determine whether this was a 'zero-sized' VLA or a VLA with an - // undefined size. - ExplodedNode* N = *I; - PostStmt PS = cast<PostStmt>(N->getLocation()); - const DeclStmt *DS = cast<DeclStmt>(PS.getStmt()); - VarDecl* VD = cast<VarDecl>(*DS->decl_begin()); - QualType T = Eng.getContext().getCanonicalType(VD->getType()); - VariableArrayType* VT = cast<VariableArrayType>(T); - Expr* SizeExpr = VT->getSizeExpr(); - - std::string buf; - llvm::raw_string_ostream os(buf); - os << "The expression used to specify the number of elements in the " - "variable-length array (VLA) '" - << VD->getNameAsString() << "' evaluates to "; - - bool isUndefined = N->getState()->getSVal(SizeExpr).isUndef(); - - if (isUndefined) - os << "an undefined or garbage value."; - else - os << "0. VLAs with no elements have undefined behavior."; - - std::string shortBuf; - llvm::raw_string_ostream os_short(shortBuf); - os_short << "Variable-length array '" << VD->getNameAsString() << "' " - << (isUndefined ? "garbage value for array size" - : "has zero elements (undefined behavior)"); - - ArgReport *report = new ArgReport(*this, os_short.str().c_str(), - os.str().c_str(), N, SizeExpr); - - report->addRange(SizeExpr->getSourceRange()); - BR.EmitReport(report); - } - } - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - registerTrackNullOrUndefValue(BRC, static_cast<ArgReport*>(R)->getArg(), - N); - } -}; - -//===----------------------------------------------------------------------===// -// __attribute__(nonnull) checking - -class VISIBILITY_HIDDEN CheckAttrNonNull : - public CheckerVisitor<CheckAttrNonNull> { - - BugType *BT; - -public: - CheckAttrNonNull() : BT(0) {} - ~CheckAttrNonNull() {} - - const void *getTag() { - static int x = 0; - return &x; - } - - void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { - const GRState *state = C.getState(); - const GRState *originalState = state; - - // Check if the callee has a 'nonnull' attribute. - SVal X = state->getSVal(CE->getCallee()); - - const FunctionDecl* FD = X.getAsFunctionDecl(); - if (!FD) - return; +} // end clang namespace - const NonNullAttr* Att = FD->getAttr<NonNullAttr>(); - if (!Att) - return; - - // Iterate through the arguments of CE and check them for null. - unsigned idx = 0; - - for (CallExpr::const_arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E; - ++I, ++idx) { - - if (!Att->isNonNull(idx)) - continue; - - const SVal &V = state->getSVal(*I); - const DefinedSVal *DV = dyn_cast<DefinedSVal>(&V); - - if (!DV) - continue; - - ConstraintManager &CM = C.getConstraintManager(); - const GRState *stateNotNull, *stateNull; - llvm::tie(stateNotNull, stateNull) = CM.AssumeDual(state, *DV); - - if (stateNull && !stateNotNull) { - // Generate an error node. Check for a null node in case - // we cache out. - if (ExplodedNode *errorNode = C.GenerateNode(CE, stateNull, true)) { - - // Lazily allocate the BugType object if it hasn't already been - // created. Ownership is transferred to the BugReporter object once - // the BugReport is passed to 'EmitWarning'. - if (!BT) - BT = new BugType("Argument with 'nonnull' attribute passed null", - "API"); - - EnhancedBugReport *R = - new EnhancedBugReport(*BT, - "Null pointer passed as an argument to a " - "'nonnull' parameter", errorNode); - - // Highlight the range of the argument that was null. - const Expr *arg = *I; - R->addRange(arg->getSourceRange()); - R->addVisitorCreator(registerTrackNullOrUndefValue, arg); - - // Emit the bug report. - C.EmitReport(R); - } - - // Always return. Either we cached out or we just emitted an error. - return; - } - - // If a pointer value passed the check we should assume that it is - // indeed not null from this point forward. - assert(stateNotNull); - state = stateNotNull; - } - - // If we reach here all of the arguments passed the nonnull check. - // If 'state' has been updated generated a new node. - if (state != originalState) - C.addTransition(C.GenerateNode(CE, state)); - } -}; -} // end anonymous namespace - -// Undefined arguments checking. -namespace { -class VISIBILITY_HIDDEN CheckUndefinedArg - : public CheckerVisitor<CheckUndefinedArg> { - - BadArg *BT; - -public: - CheckUndefinedArg() : BT(0) {} - ~CheckUndefinedArg() {} - - const void *getTag() { - static int x = 0; - return &x; - } - - void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); -}; - -void CheckUndefinedArg::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE){ - for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end(); - I != E; ++I) { - if (C.getState()->getSVal(*I).isUndef()) { - if (ExplodedNode *ErrorNode = C.GenerateNode(CE, true)) { - if (!BT) - BT = new BadArg(); - // Generate a report for this bug. - ArgReport *Report = new ArgReport(*BT, BT->getDescription().c_str(), - ErrorNode, *I); - Report->addRange((*I)->getSourceRange()); - C.EmitReport(Report); - } - } - } -} - -class VISIBILITY_HIDDEN CheckBadCall : public CheckerVisitor<CheckBadCall> { - BadCall *BT; - -public: - CheckBadCall() : BT(0) {} - ~CheckBadCall() {} - - const void *getTag() { - static int x = 0; - return &x; - } - - void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); -}; - -void CheckBadCall::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { - const Expr *Callee = CE->getCallee()->IgnoreParens(); - SVal L = C.getState()->getSVal(Callee); - - if (L.isUndef() || isa<loc::ConcreteInt>(L)) { - if (ExplodedNode *N = C.GenerateNode(CE, true)) { - if (!BT) - BT = new BadCall(); - C.EmitReport(new BuiltinBugReport(*BT, BT->getDescription().c_str(), N)); - } - } -} - -class VISIBILITY_HIDDEN CheckDivZero : public CheckerVisitor<CheckDivZero> { - DivZero *BT; -public: - CheckDivZero() : BT(0) {} - ~CheckDivZero() {} - - const void *getTag() { - static int x; - return &x; - } - - void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B); -}; - -void CheckDivZero::PreVisitBinaryOperator(CheckerContext &C, - const BinaryOperator *B) { - BinaryOperator::Opcode Op = B->getOpcode(); - if (Op != BinaryOperator::Div && - Op != BinaryOperator::Rem && - Op != BinaryOperator::DivAssign && - Op != BinaryOperator::RemAssign) - return; - - if (!B->getRHS()->getType()->isIntegerType() || - !B->getRHS()->getType()->isScalarType()) - return; - - SVal Denom = C.getState()->getSVal(B->getRHS()); - const DefinedSVal *DV = dyn_cast<DefinedSVal>(&Denom); - - // Divide-by-undefined handled in the generic checking for uses of - // undefined values. - if (!DV) - return; - - // Check for divide by zero. - ConstraintManager &CM = C.getConstraintManager(); - const GRState *stateNotZero, *stateZero; - llvm::tie(stateNotZero, stateZero) = CM.AssumeDual(C.getState(), *DV); - - if (stateZero && !stateNotZero) { - if (ExplodedNode *N = C.GenerateNode(B, stateZero, true)) { - if (!BT) - BT = new DivZero(); - - C.EmitReport(new BuiltinBugReport(*BT, BT->getDescription().c_str(), N)); - } - return; - } - - // If we get here, then the denom should not be zero. We abandon the implicit - // zero denom case for now. - if (stateNotZero != C.getState()) - C.addTransition(C.GenerateNode(B, stateNotZero)); -} -} //===----------------------------------------------------------------------===// // Check registration. //===----------------------------------------------------------------------===// @@ -808,8 +462,6 @@ void GRExprEngine::RegisterInternalChecks() { // create BugReports on-the-fly but instead wait until GRExprEngine finishes // analyzing a function. Generation of BugReport objects is done via a call // to 'FlushReports' from BugReporter. - BR.Register(new NullDeref(this)); - BR.Register(new UndefinedDeref(this)); BR.Register(new UndefBranch(this)); BR.Register(new UndefResult(this)); BR.Register(new RetStack(this)); @@ -817,7 +469,6 @@ void GRExprEngine::RegisterInternalChecks() { BR.Register(new BadMsgExprArg(this)); BR.Register(new BadReceiver(this)); BR.Register(new OutOfBoundMemoryAccess(this)); - BR.Register(new BadSizeVLA(this)); BR.Register(new NilReceiverStructRet(this)); BR.Register(new NilReceiverLargerThanVoidPtrRet(this)); @@ -826,8 +477,13 @@ void GRExprEngine::RegisterInternalChecks() { // their associated BugType will get registered with the BugReporter // automatically. Note that the check itself is owned by the GRExprEngine // object. - registerCheck(new CheckAttrNonNull()); - registerCheck(new CheckUndefinedArg()); - registerCheck(new CheckBadCall()); - registerCheck(new CheckDivZero()); + registerCheck(new AttrNonNullChecker()); + registerCheck(new UndefinedArgChecker()); + registerCheck(new UndefinedAssignmentChecker()); + registerCheck(new BadCallChecker()); + registerCheck(new DivZeroChecker()); + registerCheck(new UndefDerefChecker()); + registerCheck(new NullDerefChecker()); + registerCheck(new UndefSizedVLAChecker()); + registerCheck(new ZeroSizedVLAChecker()); } diff --git a/lib/Analysis/NSAutoreleasePoolChecker.cpp b/lib/Analysis/NSAutoreleasePoolChecker.cpp new file mode 100644 index 0000000..e0a8d0d --- /dev/null +++ b/lib/Analysis/NSAutoreleasePoolChecker.cpp @@ -0,0 +1,84 @@ +//=- NSAutoreleasePoolChecker.cpp --------------------------------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a NSAutoreleasePoolChecker, a small checker that warns +// about subpar uses of NSAutoreleasePool. Note that while the check itself +// (in it's current form) could be written as a flow-insensitive check, in +// can be potentially enhanced in the future with flow-sensitive information. +// It is also a good example of the CheckerVisitor interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "BasicObjCFoundationChecks.h" +#include "llvm/Support/Compiler.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Decl.h" + +using namespace clang; + +namespace { +class VISIBILITY_HIDDEN NSAutoreleasePoolChecker + : public CheckerVisitor<NSAutoreleasePoolChecker> { + + Selector releaseS; + +public: + NSAutoreleasePoolChecker(Selector release_s) : releaseS(release_s) {} + + static void *getTag() { + static int x = 0; + return &x; + } + + void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME); +}; + +} // end anonymous namespace + + +void clang::RegisterNSAutoreleasePoolChecks(GRExprEngine &Eng) { + ASTContext &Ctx = Eng.getContext(); + if (Ctx.getLangOptions().getGCMode() != LangOptions::NonGC) { + Eng.registerCheck(new NSAutoreleasePoolChecker(GetNullarySelector("release", + Ctx))); + } +} + +void +NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C, + const ObjCMessageExpr *ME) { + + const Expr *receiver = ME->getReceiver(); + if (!receiver) + return; + + // FIXME: Enhance with value-tracking information instead of consulting + // the type of the expression. + const ObjCObjectPointerType* PT = + receiver->getType()->getAs<ObjCObjectPointerType>(); + const ObjCInterfaceDecl* OD = PT->getInterfaceDecl(); + if (!OD) + return; + if (!OD->getIdentifier()->getName().equals("NSAutoreleasePool")) + return; + + // Sending 'release' message? + if (ME->getSelector() != releaseS) + return; + + SourceRange R = ME->getSourceRange(); + + C.getBugReporter().EmitBasicReport("Use -drain instead of -release", + "API Upgrade (Apple)", + "Use -drain instead of -release when using NSAutoreleasePool " + "and garbage collection", ME->getLocStart(), &R, 1); +} diff --git a/lib/Analysis/CheckNSError.cpp b/lib/Analysis/NSErrorChecker.cpp index 8086da5..307686f 100644 --- a/lib/Analysis/CheckNSError.cpp +++ b/lib/Analysis/NSErrorChecker.cpp @@ -1,4 +1,4 @@ -//=- CheckNSError.cpp - Coding conventions for uses of NSError ---*- C++ -*-==// +//=- NSErrorCheckerer.cpp - Coding conventions for uses of NSError -*- C++ -*-==// // // The LLVM Compiler Infrastructure // @@ -18,6 +18,7 @@ #include "clang/Analysis/LocalCheckers.h" #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h" #include "BasicObjCFoundationChecks.h" #include "llvm/Support/Compiler.h" #include "clang/AST/DeclObjC.h" @@ -27,7 +28,7 @@ using namespace clang; namespace { -class VISIBILITY_HIDDEN NSErrorCheck : public BugType { +class VISIBILITY_HIDDEN NSErrorChecker : public BugType { const Decl &CodeDecl; const bool isNSErrorWarning; IdentifierInfo * const II; @@ -48,7 +49,7 @@ class VISIBILITY_HIDDEN NSErrorCheck : public BugType { void EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl); public: - NSErrorCheck(const Decl &D, bool isNSError, GRExprEngine& eng) + NSErrorChecker(const Decl &D, bool isNSError, GRExprEngine& eng) : BugType(isNSError ? "NSError** null dereference" : "CFErrorRef* null dereference", "Coding conventions (Apple)"), @@ -64,11 +65,11 @@ public: void clang::RegisterNSErrorChecks(BugReporter& BR, GRExprEngine &Eng, const Decl &D) { - BR.Register(new NSErrorCheck(D, true, Eng)); - BR.Register(new NSErrorCheck(D, false, Eng)); + BR.Register(new NSErrorChecker(D, true, Eng)); + BR.Register(new NSErrorChecker(D, false, Eng)); } -void NSErrorCheck::FlushReports(BugReporter& BR) { +void NSErrorChecker::FlushReports(BugReporter& BR) { // Get the analysis engine and the exploded analysis graph. ExplodedGraph& G = Eng.getGraph(); @@ -99,7 +100,7 @@ void NSErrorCheck::FlushReports(BugReporter& BR) { } } -void NSErrorCheck::EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl) { +void NSErrorChecker::EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl) { std::string sbuf; llvm::raw_string_ostream os(sbuf); @@ -121,7 +122,7 @@ void NSErrorCheck::EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl) { } void -NSErrorCheck::CheckSignature(const ObjCMethodDecl& M, QualType& ResultTy, +NSErrorChecker::CheckSignature(const ObjCMethodDecl& M, QualType& ResultTy, llvm::SmallVectorImpl<VarDecl*>& ErrorParams) { ResultTy = M.getResultType(); @@ -140,7 +141,7 @@ NSErrorCheck::CheckSignature(const ObjCMethodDecl& M, QualType& ResultTy, } void -NSErrorCheck::CheckSignature(const FunctionDecl& F, QualType& ResultTy, +NSErrorChecker::CheckSignature(const FunctionDecl& F, QualType& ResultTy, llvm::SmallVectorImpl<VarDecl*>& ErrorParams) { ResultTy = F.getResultType(); @@ -159,7 +160,7 @@ NSErrorCheck::CheckSignature(const FunctionDecl& F, QualType& ResultTy, } -bool NSErrorCheck::CheckNSErrorArgument(QualType ArgTy) { +bool NSErrorChecker::CheckNSErrorArgument(QualType ArgTy) { const PointerType* PPT = ArgTy->getAs<PointerType>(); if (!PPT) @@ -180,7 +181,7 @@ bool NSErrorCheck::CheckNSErrorArgument(QualType ArgTy) { return false; } -bool NSErrorCheck::CheckCFErrorArgument(QualType ArgTy) { +bool NSErrorChecker::CheckCFErrorArgument(QualType ArgTy) { const PointerType* PPT = ArgTy->getAs<PointerType>(); if (!PPT) return false; @@ -191,7 +192,7 @@ bool NSErrorCheck::CheckCFErrorArgument(QualType ArgTy) { return TT->getDecl()->getIdentifier() == II; } -void NSErrorCheck::CheckParamDeref(const VarDecl *Param, +void NSErrorChecker::CheckParamDeref(const VarDecl *Param, const LocationContext *LC, const GRState *rootState, BugReporter& BR) { @@ -208,8 +209,10 @@ void NSErrorCheck::CheckParamDeref(const VarDecl *Param, return; // Iterate over the implicit-null dereferences. - for (GRExprEngine::null_deref_iterator I=Eng.implicit_null_derefs_begin(), - E=Eng.implicit_null_derefs_end(); I!=E; ++I) { + NullDerefChecker *Checker = Eng.getChecker<NullDerefChecker>(); + assert(Checker && "NullDerefChecker not exist."); + for (NullDerefChecker::iterator I = Checker->implicit_nodes_begin(), + E = Checker->implicit_nodes_end(); I != E; ++I) { const GRState *state = (*I)->getState(); const SVal* X = state->get<GRState::NullDerefTag>(); diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index 780772a..dbf8c42 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -275,11 +275,11 @@ public: const GRState *BindCompoundLiteral(const GRState *state, const CompoundLiteralExpr* CL, SVal V); - const GRState *BindDecl(const GRState *ST, const VarDecl *VD, - const LocationContext *LC, SVal InitVal); + const GRState *BindDecl(const GRState *ST, const VarRegion *VR, + SVal InitVal); - const GRState *BindDeclWithNoInit(const GRState *state, const VarDecl*, - const LocationContext *) { + const GRState *BindDeclWithNoInit(const GRState *state, + const VarRegion *) { return state; } @@ -1409,12 +1409,10 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) { } const GRState *RegionStoreManager::BindDecl(const GRState *ST, - const VarDecl *VD, - const LocationContext *LC, + const VarRegion *VR, SVal InitVal) { - QualType T = VD->getType(); - VarRegion* VR = MRMgr.getVarRegion(VD, LC); + QualType T = VR->getDecl()->getType(); if (T->isArrayType()) return BindArray(ST, VR, InitVal); @@ -1630,6 +1628,8 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, // Process the "intermediate" roots to find if they are referenced by // real roots. llvm::SmallVector<RBDNode, 10> WorkList; + llvm::SmallVector<RBDNode, 10> Postponed; + llvm::DenseSet<const MemRegion*> IntermediateVisited; while (!IntermediateRoots.empty()) { @@ -1647,8 +1647,11 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, } if (const SymbolicRegion* SR = dyn_cast<SymbolicRegion>(R)) { - if (SymReaper.isLive(SR->getSymbol())) - WorkList.push_back(std::make_pair(&state, SR)); + llvm::SmallVectorImpl<RBDNode> &Q = + SymReaper.isLive(SR->getSymbol()) ? WorkList : Postponed; + + Q.push_back(std::make_pair(&state, SR)); + continue; } @@ -1667,6 +1670,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, llvm::DenseSet<RBDNode> Visited; +tryAgain: while (!WorkList.empty()) { RBDNode N = WorkList.back(); WorkList.pop_back(); @@ -1740,6 +1744,21 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc, } } + // See if any postponed SymbolicRegions are actually live now, after + // having done a scan. + for (llvm::SmallVectorImpl<RBDNode>::iterator I = Postponed.begin(), + E = Postponed.end() ; I != E ; ++I) { + if (const SymbolicRegion *SR = cast_or_null<SymbolicRegion>(I->second)) { + if (SymReaper.isLive(SR->getSymbol())) { + WorkList.push_back(*I); + I->second = NULL; + } + } + } + + if (!WorkList.empty()) + goto tryAgain; + // We have now scanned the store, marking reachable regions and symbols // 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. diff --git a/lib/Analysis/UndefinedArgChecker.cpp b/lib/Analysis/UndefinedArgChecker.cpp new file mode 100644 index 0000000..a229f55 --- /dev/null +++ b/lib/Analysis/UndefinedArgChecker.cpp @@ -0,0 +1,43 @@ +//===--- UndefinedArgChecker.h - Undefined arguments checker ----*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines BadCallChecker, a builtin check in GRExprEngine that performs +// checks for undefined arguments. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/Checkers/UndefinedArgChecker.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" + +using namespace clang; + +void *UndefinedArgChecker::getTag() { + static int x = 0; + return &x; +} + +void UndefinedArgChecker::PreVisitCallExpr(CheckerContext &C, + const CallExpr *CE){ + for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end(); + I != E; ++I) { + if (C.getState()->getSVal(*I).isUndef()) { + if (ExplodedNode *N = C.GenerateNode(CE, true)) { + if (!BT) + BT = new BugType("Pass-by-value argument in function call is " + "undefined", "Logic error"); + // Generate a report for this bug. + EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName().c_str(), + N); + R->addRange((*I)->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I); + C.EmitReport(R); + } + } + } +} diff --git a/lib/Analysis/UndefinedAssignmentChecker.cpp b/lib/Analysis/UndefinedAssignmentChecker.cpp new file mode 100644 index 0000000..c5b2401 --- /dev/null +++ b/lib/Analysis/UndefinedAssignmentChecker.cpp @@ -0,0 +1,61 @@ +//===--- UndefinedAssignmentChecker.h ---------------------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines UndefinedAssginmentChecker, a builtin check in GRExprEngine that +// checks for assigning undefined values. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" + +using namespace clang; + +void *UndefinedAssignmentChecker::getTag() { + static int x = 0; + return &x; +} + +void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C, + const Stmt *S, + SVal location, + SVal val) { + if (!val.isUndef()) + return; + + ExplodedNode *N = C.GenerateNode(S, true); + + if (!N) + return; + + if (!BT) + BT = new BugType("Assigned value is garbage or undefined", + "Logic error"); + + // Generate a report for this bug. + EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName().c_str(), N); + const Expr *ex = 0; + + // FIXME: This check needs to be done on the expression doing the + // assignment, not the "store" expression. + if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) + ex = B->getRHS(); + else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) { + const VarDecl* VD = dyn_cast<VarDecl>(DS->getSingleDecl()); + ex = VD->getInit(); + } + + if (ex) { + R->addRange(ex->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, ex); + } + + C.EmitReport(R); +} + diff --git a/lib/Analysis/VLASizeChecker.cpp b/lib/Analysis/VLASizeChecker.cpp new file mode 100644 index 0000000..76e4477 --- /dev/null +++ b/lib/Analysis/VLASizeChecker.cpp @@ -0,0 +1,102 @@ +//=== VLASizeChecker.cpp - Undefined dereference checker --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines two VLASizeCheckers, a builtin check in GRExprEngine that +// performs checks for declaration of VLA of undefined or zero size. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/Checkers/VLASizeChecker.h" +#include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" + +using namespace clang; + +void *UndefSizedVLAChecker::getTag() { + static int x = 0; + return &x; +} + +ExplodedNode *UndefSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred, + const GRState *state, + Stmt *S, GRExprEngine &Eng) { + GRStmtNodeBuilder &Builder = Eng.getBuilder(); + BugReporter &BR = Eng.getBugReporter(); + + if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) { + // FIXME: Handle multi-dimensional VLAs. + Expr* SE = VLA->getSizeExpr(); + SVal Size_untested = state->getSVal(SE); + + if (Size_untested.isUndef()) { + if (ExplodedNode* N = Builder.generateNode(S, state, Pred)) { + N->markAsSink(); + if (!BT) + BT = new BugType("Declare variable-length array (VLA) of undefined " + "size", "Logic error"); + + EnhancedBugReport *R = + new EnhancedBugReport(*BT, BT->getName().c_str(), N); + R->addRange(SE->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE); + BR.EmitReport(R); + } + return 0; + } + } + return Pred; +} + +void *ZeroSizedVLAChecker::getTag() { + static int x; + return &x; +} + +ExplodedNode *ZeroSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred, + const GRState *state, Stmt *S, + GRExprEngine &Eng) { + GRStmtNodeBuilder &Builder = Eng.getBuilder(); + BugReporter &BR = Eng.getBugReporter(); + + if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) { + // FIXME: Handle multi-dimensional VLAs. + Expr* SE = VLA->getSizeExpr(); + SVal Size_untested = state->getSVal(SE); + + DefinedOrUnknownSVal *Size = dyn_cast<DefinedOrUnknownSVal>(&Size_untested); + // Undefined size is checked in another checker. + if (!Size) + return Pred; + + const GRState *zeroState = state->Assume(*Size, false); + state = state->Assume(*Size, true); + + if (zeroState && !state) { + if (ExplodedNode* N = Builder.generateNode(S, zeroState, Pred)) { + N->markAsSink(); + if (!BT) + BT = new BugType("Declare variable-length array (VLA) of zero size", + "Logic error"); + + EnhancedBugReport *R = + new EnhancedBugReport(*BT, BT->getName().c_str(), N); + R->addRange(SE->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE); + BR.EmitReport(R); + } + } + if (!state) + return 0; + + return Builder.generateNode(S, state, Pred); + } + else + return Pred; +} + diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt index 527ebf9..1a89acc 100644 --- a/lib/Basic/CMakeLists.txt +++ b/lib/Basic/CMakeLists.txt @@ -18,7 +18,7 @@ add_clang_library(clangBasic # FIXME: This only gets updated when CMake is run, so this revision number # may be out-of-date! find_package(Subversion) -if (Subversion_FOUND) +if (Subversion_FOUND AND EXISTS "${CLANG_SOURCE_DIR}/.svn") Subversion_WC_INFO(${CLANG_SOURCE_DIR} CLANG) set_source_files_properties(Version.cpp PROPERTIES COMPILE_DEFINITIONS "SVN_REVISION=\"${CLANG_WC_REVISION}\"") diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 16aa0c5..401e6cb 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -381,3 +381,17 @@ SelectorTable::~SelectorTable() { delete &getSelectorTableImpl(Impl); } +const char *clang::getOperatorSpelling(OverloadedOperatorKind Operator) { + switch (Operator) { + case OO_None: + case NUM_OVERLOADED_OPERATORS: + return 0; + +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + case OO_##Name: return Spelling; +#include "clang/Basic/OperatorKinds.def" + } + + return 0; +} + diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index 8f3c777..12caf0c 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -106,9 +106,9 @@ unsigned TargetInfo::getTypeWidth(IntType T) const { }; } -/// getTypeSigned - Return whether an integer types is signed. Returns true if +/// isTypeSigned - Return whether an integer types is signed. Returns true if /// the type is signed; false otherwise. -bool TargetInfo::getTypeSigned(IntType T) const { +bool TargetInfo::isTypeSigned(IntType T) const { switch (T) { default: assert(0 && "not an integer!"); case SignedShort: diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 66d6824..f418c5a 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -1533,6 +1533,8 @@ namespace { Define(Defines, "ram", "__attribute__((address_space(0)))"); Define(Defines, "_section(SectName)", "__attribute__((section(SectName)))"); + Define(Defines, "near", + "__attribute__((section(\"Address=NEAR\")))"); Define(Defines, "_address(Addr)", "__attribute__((section(\"Address=\"#Addr)))"); Define(Defines, "_CONFIG(conf)", "asm(\"CONFIG \"#conf)"); diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 987cd24..c269219 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -199,6 +199,18 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Builder.CreateCall(F, ArgValue, "tmp")); } case Builtin::BI__builtin_object_size: { + // FIXME: We're awaiting the llvm intrincis. +#if 0 + // We pass this builtin onto the optimizer so that it can + // figure out the object size in more complex cases. + const llvm::Type *ResType[] = { + ConvertType(E->getType()) + }; + Value *F = CGM.getIntrinsic(Intrinsic::objectsize, ResType, 1); + return RValue::get(Builder.CreateCall2(F, + EmitScalarExpr(E->getArg(0)), + EmitScalarExpr(E->getArg(1)))); +#else // FIXME: Implement. For now we just always fail and pretend we // don't know the object size. llvm::APSInt TypeArg = E->getArg(1)->EvaluateAsInt(CGM.getContext()); @@ -207,6 +219,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, bool UseMinimum = TypeArg.getZExtValue() & 2; return RValue::get( llvm::ConstantInt::get(ResType, UseMinimum ? 0 : -1LL)); +#endif } case Builtin::BI__builtin_prefetch: { Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0)); diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index cfa669d..3e854ca 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -71,16 +71,17 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, const Expr *Init = D.getInit(); QualType T = D.getType(); + bool isVolatile = getContext().getCanonicalType(T).isVolatileQualified(); if (T->isReferenceType()) { ErrorUnsupported(Init, "global variable that binds to a reference"); } else if (!hasAggregateLLVMType(T)) { llvm::Value *V = EmitScalarExpr(Init); - EmitStoreOfScalar(V, DeclPtr, T.isVolatileQualified(), T); + EmitStoreOfScalar(V, DeclPtr, isVolatile, T); } else if (T->isAnyComplexType()) { - EmitComplexExprIntoAddr(Init, DeclPtr, T.isVolatileQualified()); + EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile); } else { - EmitAggExpr(Init, DeclPtr, T.isVolatileQualified()); + EmitAggExpr(Init, DeclPtr, isVolatile); if (const RecordType *RT = T->getAs<RecordType>()) { CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); @@ -95,8 +96,9 @@ CodeGenModule::EmitCXXGlobalInitFunc() { if (CXXGlobalInits.empty()) return; - const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), - false); + const llvm::FunctionType *FTy + = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), + false); // Create our global initialization function. // FIXME: Should this be tweakable by targets? @@ -139,18 +141,20 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, // Create the guard variable. llvm::GlobalValue *GuardV = - new llvm::GlobalVariable(CGM.getModule(), llvm::Type::getInt64Ty(VMContext), false, - GV->getLinkage(), - llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)), + new llvm::GlobalVariable(CGM.getModule(), llvm::Type::getInt64Ty(VMContext), + false, GV->getLinkage(), + llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)), GuardVName.str()); // Load the first byte of the guard variable. - const llvm::Type *PtrTy = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); + const llvm::Type *PtrTy + = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); llvm::Value *V = Builder.CreateLoad(Builder.CreateBitCast(GuardV, PtrTy), "tmp"); // Compare it against 0. - llvm::Value *nullValue = llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext)); + llvm::Value *nullValue + = llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext)); llvm::Value *ICmp = Builder.CreateICmpEQ(V, nullValue , "tobool"); llvm::BasicBlock *InitBlock = createBasicBlock("init"); @@ -163,7 +167,8 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, EmitCXXGlobalVarDeclInit(D, GV); - Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 1), + Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), + 1), Builder.CreateBitCast(GuardV, PtrTy)); EmitBlock(EndBlock); @@ -591,11 +596,16 @@ 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(getContext())) { + QualType InitType = E->getType(); + if (Array) + InitType = getContext().getBaseElementType(Array); const CXXRecordDecl *RD = - cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl()); + cast<CXXRecordDecl>(InitType->getAs<RecordType>()->getDecl()); if (RD->hasTrivialConstructor()) return; } @@ -606,9 +616,18 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, EmitAggExpr((*i), Dest, false); return; } - // Call the constructor. - EmitCXXConstructorCall(CD, Ctor_Complete, Dest, - E->arg_begin(), E->arg_end()); + 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); + } + else + // Call the constructor. + EmitCXXConstructorCall(CD, Ctor_Complete, Dest, + E->arg_begin(), E->arg_end()); } void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) { @@ -688,32 +707,39 @@ llvm::Constant *CodeGenFunction::GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD, bool Extern, int64_t nv, int64_t v) { - QualType R = MD->getType()->getAs<FunctionType>()->getResultType(); + return GenerateCovariantThunk(Fn, MD, Extern, nv, v, 0, 0); +} - FunctionArgList Args; - ImplicitParamDecl *ThisDecl = - ImplicitParamDecl::Create(getContext(), 0, SourceLocation(), 0, - MD->getThisType(getContext())); - Args.push_back(std::make_pair(ThisDecl, ThisDecl->getType())); - for (FunctionDecl::param_const_iterator i = MD->param_begin(), - e = MD->param_end(); - i != e; ++i) { - ParmVarDecl *D = *i; - Args.push_back(std::make_pair(D, D->getType())); +llvm::Value *CodeGenFunction::DynamicTypeAdjust(llvm::Value *V, int64_t nv, + int64_t v) { + llvm::Type *Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), + 0); + const llvm::Type *OrigTy = V->getType(); + if (nv) { + // Do the non-virtual adjustment + V = Builder.CreateBitCast(V, Ptr8Ty); + V = Builder.CreateConstInBoundsGEP1_64(V, nv); + V = Builder.CreateBitCast(V, OrigTy); } - IdentifierInfo *II - = &CGM.getContext().Idents.get("__thunk_named_foo_"); - FunctionDecl *FD = FunctionDecl::Create(getContext(), - getContext().getTranslationUnitDecl(), - SourceLocation(), II, R, 0, - Extern - ? FunctionDecl::Extern - : FunctionDecl::Static, - false, true); - StartFunction(FD, R, Fn, Args, SourceLocation()); - // FIXME: generate body - FinishFunction(); - return Fn; + if (v) { + // Do the virtual this adjustment + const llvm::Type *PtrDiffTy = + ConvertType(getContext().getPointerDiffType()); + llvm::Type *PtrPtr8Ty, *PtrPtrDiffTy; + PtrPtr8Ty = llvm::PointerType::get(Ptr8Ty, 0); + PtrPtrDiffTy = llvm::PointerType::get(PtrDiffTy, 0); + llvm::Value *ThisVal = Builder.CreateBitCast(V, Ptr8Ty); + V = Builder.CreateBitCast(V, PtrPtrDiffTy->getPointerTo()); + V = Builder.CreateLoad(V, "vtable"); + llvm::Value *VTablePtr = V; + assert(v % (LLVMPointerWidth/8) == 0 && "vtable entry unaligned"); + v /= LLVMPointerWidth/8; + V = Builder.CreateConstInBoundsGEP1_64(VTablePtr, v); + V = Builder.CreateLoad(V); + V = Builder.CreateGEP(ThisVal, V); + V = Builder.CreateBitCast(V, OrigTy); + } + return V; } llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, @@ -723,7 +749,7 @@ llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, int64_t v_t, int64_t nv_r, int64_t v_r) { - QualType R = MD->getType()->getAs<FunctionType>()->getResultType(); + QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType(); FunctionArgList Args; ImplicitParamDecl *ThisDecl = @@ -740,13 +766,57 @@ llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, = &CGM.getContext().Idents.get("__thunk_named_foo_"); FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), - SourceLocation(), II, R, 0, + SourceLocation(), II, ResultType, 0, Extern ? FunctionDecl::Extern : FunctionDecl::Static, false, true); - StartFunction(FD, R, Fn, Args, SourceLocation()); - // FIXME: generate body + StartFunction(FD, ResultType, Fn, Args, SourceLocation()); + + // generate body + const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + llvm::Value *Callee = CGM.GetAddrOfFunction(MD, Ty); + CallArgList CallArgs; + + QualType ArgType = MD->getThisType(getContext()); + llvm::Value *Arg = Builder.CreateLoad(LocalDeclMap[ThisDecl], "this"); + if (nv_t || v_t) { + // Do the this adjustment. + const llvm::Type *OrigTy = Callee->getType(); + Arg = DynamicTypeAdjust(Arg, nv_t, v_t); + if (nv_r || v_r) { + Callee = CGM.BuildCovariantThunk(MD, Extern, 0, 0, nv_r, v_r); + Callee = Builder.CreateBitCast(Callee, OrigTy); + nv_r = v_r = 0; + } + } + + CallArgs.push_back(std::make_pair(RValue::get(Arg), ArgType)); + + for (FunctionDecl::param_const_iterator i = MD->param_begin(), + e = MD->param_end(); + i != e; ++i) { + ParmVarDecl *D = *i; + QualType ArgType = D->getType(); + + // llvm::Value *Arg = CGF.GetAddrOfLocalVar(Dst); + Expr *Arg = new (getContext()) DeclRefExpr(D, ArgType, SourceLocation()); + CallArgs.push_back(std::make_pair(EmitCallArg(Arg, ArgType), ArgType)); + } + + RValue RV = EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + Callee, CallArgs, MD); + if (nv_r || v_r) { + // Do the return result adjustment. + RV = RValue::get(DynamicTypeAdjust(RV.getScalarVal(), nv_r, v_r)); + } + + if (!ResultType->isVoidType()) + EmitReturnOfRValue(RV, ResultType); + FinishFunction(); return Fn; } @@ -769,7 +839,6 @@ llvm::Constant *CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern, llvm::Function *Fn = llvm::Function::Create(FTy, linktype, Out.str(), &getModule()); CodeGenFunction(*this).GenerateThunk(Fn, MD, Extern, nv, v); - // Fn = Builder.CreateBitCast(Fn, Ptr8Ty); llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty); return m; } @@ -795,7 +864,6 @@ llvm::Constant *CodeGenModule::BuildCovariantThunk(const CXXMethodDecl *MD, &getModule()); CodeGenFunction(*this).GenerateCovariantThunk(Fn, MD, Extern, nv_t, v_t, nv_r, v_r); - // Fn = Builder.CreateBitCast(Fn, Ptr8Ty); llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty); return m; } @@ -815,7 +883,7 @@ CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This, CGM.getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl); llvm::Value *VBaseOffsetPtr = - Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetIndex, "vbase.offset.ptr"); + Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetIndex, "vbase.offset.ptr"); const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType()); @@ -899,7 +967,7 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest, // Push the Src ptr. CallArgs.push_back(std::make_pair(RValue::get(Src), - BaseCopyCtor->getParamDecl(0)->getType())); + BaseCopyCtor->getParamDecl(0)->getType())); QualType ResultType = BaseCopyCtor->getType()->getAs<FunctionType>()->getResultType(); EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), @@ -1099,11 +1167,11 @@ CodeGenFunction::SynthesizeDefaultConstructor(const CXXConstructorDecl *Ctor, FinishFunction(); } -/// SynthesizeCXXCopyConstructor - This routine implicitly defines body of a copy -/// constructor, in accordance with section 12.8 (p7 and p8) of C++03 +/// SynthesizeCXXCopyConstructor - This routine implicitly defines body of a +/// copy constructor, in accordance with section 12.8 (p7 and p8) of C++03 /// The implicitly-defined copy constructor for class X performs a memberwise -/// copy of its subobjects. The order of copying is the same as the order -/// of initialization of bases and members in a user-defined constructor +/// copy of its subobjects. The order of copying is the same as the order of +/// initialization of bases and members in a user-defined constructor /// Each subobject is copied in the manner appropriate to its type: /// if the subobject is of class type, the copy constructor for the class is /// used; @@ -1121,7 +1189,7 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor, const FunctionArgList &Args) { const CXXRecordDecl *ClassDecl = Ctor->getParent(); assert(!ClassDecl->hasUserDeclaredCopyConstructor() && - "SynthesizeCXXCopyConstructor - copy constructor has definition already"); + "SynthesizeCXXCopyConstructor - copy constructor has definition already"); StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args, SourceLocation()); diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 7865516..06cd05c 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -441,6 +441,8 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, RetAttrs |= llvm::Attribute::NoAlias; } + if (CompileOpts.OptimizeSize) + FuncAttrs |= llvm::Attribute::OptimizeForSize; if (CompileOpts.DisableRedZone) FuncAttrs |= llvm::Attribute::NoRedZone; if (CompileOpts.NoImplicitFloat) diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 1728c67..b1ceb46 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -19,6 +19,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Frontend/CompileOptions.h" #include "llvm/GlobalVariable.h" #include "llvm/Intrinsics.h" #include "llvm/Target/TargetData.h" @@ -316,6 +317,20 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { llvm::Value *DeclPtr; if (Ty->isConstantSizeType()) { if (!Target.useGlobalsForAutomaticVariables()) { + + // All constant structs and arrays should be global if + // their initializer is constant and if the element type is POD. + if (CGM.getCompileOpts().MergeAllConstants) { + if (Ty.isConstant(getContext()) + && (Ty->isArrayType() || Ty->isRecordType()) + && (D.getInit() + && D.getInit()->isConstantInitializer(getContext())) + && Ty->isPODType()) { + EmitStaticBlockVarDecl(D); + return; + } + } + // A normal fixed sized variable becomes an alloca in the entry block. const llvm::Type *LTy = ConvertTypeForMem(Ty); Align = getContext().getDeclAlignInBytes(&D); @@ -417,17 +432,18 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D), D.getNameAsString()); + bool isVolatile = (getContext().getCanonicalType(D.getType()) + .isVolatileQualified()); if (Ty->isReferenceType()) { RValue RV = EmitReferenceBindingToExpr(Init, Ty, /*IsInitializer=*/true); EmitStoreOfScalar(RV.getScalarVal(), Loc, false, Ty); } else if (!hasAggregateLLVMType(Init->getType())) { llvm::Value *V = EmitScalarExpr(Init); - EmitStoreOfScalar(V, Loc, D.getType().isVolatileQualified(), - D.getType()); + EmitStoreOfScalar(V, Loc, isVolatile, D.getType()); } else if (Init->getType()->isAnyComplexType()) { - EmitComplexExprIntoAddr(Init, Loc, D.getType().isVolatileQualified()); + EmitComplexExprIntoAddr(Init, Loc, isVolatile); } else { - EmitAggExpr(Init, Loc, D.getType().isVolatileQualified()); + EmitAggExpr(Init, Loc, isVolatile); } } @@ -492,16 +508,25 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { // Handle CXX destruction of variables. QualType DtorTy(Ty); if (const ArrayType *Array = DtorTy->getAs<ArrayType>()) - DtorTy = Array->getElementType(); + DtorTy = getContext().getBaseElementType(Array); if (const RecordType *RT = DtorTy->getAs<RecordType>()) if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { if (!ClassDecl->hasTrivialDestructor()) { const CXXDestructorDecl *D = ClassDecl->getDestructor(getContext()); assert(D && "EmitLocalBlockVarDecl - destructor is nul"); - assert(!Ty->getAs<ArrayType>() && "FIXME - destruction of arrays NYI"); - + CleanupScope scope(*this); - EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); + if (const ConstantArrayType *Array = + getContext().getAsConstantArrayType(Ty)) { + QualType BaseElementTy = getContext().getBaseElementType(Array); + const llvm::Type *BasePtr = ConvertType(BaseElementTy); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + Builder.CreateBitCast(DeclPtr, BasePtr); + EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); + } + else + EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); } } @@ -547,6 +572,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) { assert((isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D)) && "Invalid argument to EmitParmDecl"); QualType Ty = D.getType(); + CanQualType CTy = getContext().getCanonicalType(Ty); llvm::Value *DeclPtr; if (!Ty->isConstantSizeType()) { @@ -563,7 +589,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) { DeclPtr->setName(Name.c_str()); // Store the initial value into the alloca. - EmitStoreOfScalar(Arg, DeclPtr, Ty.isVolatileQualified(), Ty); + EmitStoreOfScalar(Arg, DeclPtr, CTy.isVolatileQualified(), Ty); } else { // Otherwise, if this is an aggregate, just use the input pointer. DeclPtr = Arg; diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp new file mode 100644 index 0000000..adfd005 --- /dev/null +++ b/lib/CodeGen/CGException.cpp @@ -0,0 +1,105 @@ +//===--- CGException.cpp - Emit LLVM Code for C++ exceptions --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with C++ exception related code generation. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +using namespace clang; +using namespace CodeGen; + +static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) { + // void *__cxa_allocate_exception(size_t thrown_size); + const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); + std::vector<const llvm::Type*> Args(1, SizeTy); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getInt8PtrTy(CGF.getLLVMContext()), + Args, false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception"); +} + +static llvm::Constant *getThrowFn(CodeGenFunction &CGF) { + // void __cxa_throw (void *thrown_exception, std::type_info *tinfo, + // void (*dest) (void *) ); + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + std::vector<const llvm::Type*> Args(3, Int8PtrTy); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), + Args, false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw"); +} + +void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { + // FIXME: Handle rethrows. + if (!E->getSubExpr()) { + ErrorUnsupported(E, "rethrow expression"); + return; + } + + QualType ThrowType = E->getSubExpr()->getType(); + // FIXME: We only handle non-class types for now. + if (ThrowType->isRecordType()) { + ErrorUnsupported(E, "throw expression"); + return; + } + + // FIXME: Handle cleanup. + if (!CleanupEntries.empty()){ + ErrorUnsupported(E, "throw expression"); + return; + } + + // Now allocate the exception object. + const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); + uint64_t TypeSize = getContext().getTypeSize(ThrowType) / 8; + + llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this); + llvm::Value *ExceptionPtr = + Builder.CreateCall(AllocExceptionFn, + llvm::ConstantInt::get(SizeTy, TypeSize), + "exception"); + + // Store the throw exception in the exception object. + if (!hasAggregateLLVMType(ThrowType)) { + llvm::Value *Value = EmitScalarExpr(E->getSubExpr()); + const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); + + Builder.CreateStore(Value, Builder.CreateBitCast(ExceptionPtr, ValuePtrTy)); + } else { + // FIXME: Handle complex and aggregate expressions. + ErrorUnsupported(E, "throw expression"); + } + + // Now throw the exception. + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); + + llvm::SmallString<256> OutName; + llvm::raw_svector_ostream Out(OutName); + mangleCXXRtti(CGM.getMangleContext(), ThrowType, Out); + + // FIXME: Is it OK to use CreateRuntimeVariable for this? + llvm::Constant *TypeInfo = + CGM.CreateRuntimeVariable(llvm::Type::getInt8Ty(getLLVMContext()), + OutName.c_str()); + llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy); + + llvm::CallInst *ThrowCall = + Builder.CreateCall3(getThrowFn(*this), ExceptionPtr, TypeInfo, Dtor); + ThrowCall->setDoesNotReturn(); + Builder.CreateUnreachable(); + + // Clear the insertion point to indicate we are in unreachable code. + Builder.ClearInsertionPoint(); +} diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index bb487f6..d9dd70a 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -84,10 +84,9 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, if (const CXXExprWithTemporaries *TE = dyn_cast<CXXExprWithTemporaries>(E)) { ShouldDestroyTemporaries = TE->shouldDestroyTemporaries(); - if (ShouldDestroyTemporaries) { - // Keep track of the current cleanup stack depth. + // Keep track of the current cleanup stack depth. + if (ShouldDestroyTemporaries) OldNumLiveTemporaries = LiveTemporaries.size(); - } E = TE->getSubExpr(); } @@ -148,7 +147,6 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, // Check if need to perform the derived-to-base cast. if (BaseClassDecl) { llvm::Value *Derived = Val.getAggregateAddr(); - llvm::Value *Base = GetAddressCXXOfBaseClass(Derived, DerivedClassDecl, BaseClassDecl, /*NullCheckValue=*/false); @@ -189,18 +187,21 @@ unsigned CodeGenFunction::getAccessedFieldNo(unsigned Idx, //===----------------------------------------------------------------------===// RValue CodeGenFunction::GetUndefRValue(QualType Ty) { - if (Ty->isVoidType()) { + if (Ty->isVoidType()) return RValue::get(0); - } else if (const ComplexType *CTy = Ty->getAs<ComplexType>()) { + + if (const ComplexType *CTy = Ty->getAs<ComplexType>()) { const llvm::Type *EltTy = ConvertType(CTy->getElementType()); llvm::Value *U = llvm::UndefValue::get(EltTy); return RValue::getComplex(std::make_pair(U, U)); - } else if (hasAggregateLLVMType(Ty)) { + } + + if (hasAggregateLLVMType(Ty)) { const llvm::Type *LTy = llvm::PointerType::getUnqual(ConvertType(Ty)); return RValue::getAggregate(llvm::UndefValue::get(LTy)); - } else { - return RValue::get(llvm::UndefValue::get(ConvertType(Ty))); } + + return RValue::get(llvm::UndefValue::get(ConvertType(Ty))); } RValue CodeGenFunction::EmitUnsupportedRValue(const Expr *E, @@ -245,7 +246,6 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { case Expr::VAArgExprClass: return EmitVAArgExprLValue(cast<VAArgExpr>(E)); case Expr::DeclRefExprClass: - case Expr::QualifiedDeclRefExprClass: return EmitDeclRefLValue(cast<DeclRefExpr>(E)); case Expr::ParenExprClass:return EmitLValue(cast<ParenExpr>(E)->getSubExpr()); case Expr::PredefinedExprClass: @@ -343,9 +343,8 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) { if (LV.isObjCWeak()) { // load of a __weak object. llvm::Value *AddrWeakObj = LV.getAddress(); - llvm::Value *read_weak = CGM.getObjCRuntime().EmitObjCWeakRead(*this, - AddrWeakObj); - return RValue::get(read_weak); + return RValue::get(CGM.getObjCRuntime().EmitObjCWeakRead(*this, + AddrWeakObj)); } if (LV.isSimple()) { @@ -522,10 +521,8 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, if (Dst.isPropertyRef()) return EmitStoreThroughPropertyRefLValue(Src, Dst, Ty); - if (Dst.isKVCRef()) - return EmitStoreThroughKVCRefLValue(Src, Dst, Ty); - - assert(0 && "Unknown LValue type"); + assert(Dst.isKVCRef() && "Unknown LValue type"); + return EmitStoreThroughKVCRefLValue(Src, Dst, Ty); } if (Dst.isObjCWeak() && !Dst.isNonGC()) { @@ -551,8 +548,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, llvm::Value *BytesBetween = Builder.CreateSub(LHS, RHS, "ivar.offset"); CGM.getObjCRuntime().EmitObjCIvarAssign(*this, src, dst, BytesBetween); - } - else if (Dst.isGlobalObjCRef()) + } else if (Dst.isGlobalObjCRef()) CGM.getObjCRuntime().EmitObjCGlobalAssign(*this, src, LvalueDst); else CGM.getObjCRuntime().EmitObjCStrongCastAssign(*this, src, LvalueDst); @@ -702,13 +698,12 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, // FIXME: since we're shuffling with undef, can we just use the indices // into that? This could be simpler. llvm::SmallVector<llvm::Constant*, 4> ExtMask; + const llvm::Type *Int32Ty = llvm::Type::getInt32Ty(VMContext); unsigned i; for (i = 0; i != NumSrcElts; ++i) - ExtMask.push_back(llvm::ConstantInt::get( - llvm::Type::getInt32Ty(VMContext), i)); + ExtMask.push_back(llvm::ConstantInt::get(Int32Ty, i)); for (; i != NumDstElts; ++i) - ExtMask.push_back(llvm::UndefValue::get( - llvm::Type::getInt32Ty(VMContext))); + ExtMask.push_back(llvm::UndefValue::get(Int32Ty)); llvm::Value *ExtMaskV = llvm::ConstantVector::get(&ExtMask[0], ExtMask.size()); llvm::Value *ExtSrcVal = @@ -717,15 +712,13 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, ExtMaskV, "tmp"); // build identity llvm::SmallVector<llvm::Constant*, 4> Mask; - for (unsigned i = 0; i != NumDstElts; ++i) { - Mask.push_back(llvm::ConstantInt::get( - llvm::Type::getInt32Ty(VMContext), i)); - } + for (unsigned i = 0; i != NumDstElts; ++i) + Mask.push_back(llvm::ConstantInt::get(Int32Ty, i)); + // modify when what gets shuffled in for (unsigned i = 0; i != NumSrcElts; ++i) { unsigned Idx = getAccessedFieldNo(i, Elts); - Mask[Idx] = llvm::ConstantInt::get( - llvm::Type::getInt32Ty(VMContext), i+NumDstElts); + Mask[Idx] = llvm::ConstantInt::get(Int32Ty, i+NumDstElts); } llvm::Value *MaskV = llvm::ConstantVector::get(&Mask[0], Mask.size()); Vec = Builder.CreateShuffleVector(Vec, ExtSrcVal, MaskV, "tmp"); @@ -736,8 +729,8 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, } else { // If the Src is a scalar (not a vector) it must be updating one element. unsigned InIdx = getAccessedFieldNo(0, Elts); - llvm::Value *Elt = llvm::ConstantInt::get( - llvm::Type::getInt32Ty(VMContext), InIdx); + const llvm::Type *Int32Ty = llvm::Type::getInt32Ty(VMContext); + llvm::Value *Elt = llvm::ConstantInt::get(Int32Ty, InIdx); Vec = Builder.CreateInsertElement(Vec, SrcVal, Elt, "tmp"); } @@ -747,8 +740,8 @@ void CodeGenFunction::EmitStoreThroughExtVectorComponentLValue(RValue Src, // setObjCGCLValueClass - sets class of he lvalue for the purpose of // generating write-barries API. It is currently a global, ivar, // or neither. -static -void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, LValue &LV) { +static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, + LValue &LV) { if (Ctx.getLangOptions().getGCMode() == LangOptions::NonGC) return; @@ -759,6 +752,7 @@ void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, LValue &LV) { LV.SetObjCArray(LV, E->getType()->isArrayType()); return; } + if (const DeclRefExpr *Exp = dyn_cast<DeclRefExpr>(E)) { if (const VarDecl *VD = dyn_cast<VarDecl>(Exp->getDecl())) { if ((VD->isBlockVarDecl() && !VD->hasLocalStorage()) || @@ -766,10 +760,15 @@ void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, LValue &LV) { LV.SetGlobalObjCRef(LV, true); } LV.SetObjCArray(LV, E->getType()->isArrayType()); + return; } - else if (const UnaryOperator *Exp = dyn_cast<UnaryOperator>(E)) + + if (const UnaryOperator *Exp = dyn_cast<UnaryOperator>(E)) { setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV); - else if (const ParenExpr *Exp = dyn_cast<ParenExpr>(E)) { + return; + } + + if (const ParenExpr *Exp = dyn_cast<ParenExpr>(E)) { setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV); if (LV.isObjCIvar()) { // If cast is to a structure pointer, follow gcc's behavior and make it @@ -779,13 +778,20 @@ void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, LValue &LV) { ExpTy = ExpTy->getAs<PointerType>()->getPointeeType(); if (ExpTy->isRecordType()) LV.SetObjCIvar(LV, false); - } + } + return; } - else if (const ImplicitCastExpr *Exp = dyn_cast<ImplicitCastExpr>(E)) + if (const ImplicitCastExpr *Exp = dyn_cast<ImplicitCastExpr>(E)) { setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV); - else if (const CStyleCastExpr *Exp = dyn_cast<CStyleCastExpr>(E)) + return; + } + + if (const CStyleCastExpr *Exp = dyn_cast<CStyleCastExpr>(E)) { setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV); - else if (const ArraySubscriptExpr *Exp = dyn_cast<ArraySubscriptExpr>(E)) { + return; + } + + if (const ArraySubscriptExpr *Exp = dyn_cast<ArraySubscriptExpr>(E)) { setObjCGCLValueClass(Ctx, Exp->getBase(), LV); if (LV.isObjCIvar() && !LV.isObjCArray()) // Using array syntax to assigning to what an ivar points to is not @@ -795,12 +801,15 @@ void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, LValue &LV) { // Using array syntax to assigning to what global points to is not // same as assigning to the global itself. {id *G;} G[i] = 0; LV.SetGlobalObjCRef(LV, false); + return; } - else if (const MemberExpr *Exp = dyn_cast<MemberExpr>(E)) { + + if (const MemberExpr *Exp = dyn_cast<MemberExpr>(E)) { setObjCGCLValueClass(Ctx, Exp->getBase(), LV); // We don't know if member is an 'ivar', but this flag is looked at // only in the context of LV.isObjCIvar(). LV.SetObjCArray(LV, E->getType()->isArrayType()); + return; } } @@ -839,14 +848,18 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { LValue::SetObjCNonGC(LV, NonGCable); setObjCGCLValueClass(getContext(), E, LV); return LV; - } else if (VD && VD->isFileVarDecl()) { + } + + if (VD && VD->isFileVarDecl()) { llvm::Value *V = CGM.GetAddrOfGlobalVar(VD); if (VD->getType()->isReferenceType()) V = Builder.CreateLoad(V, "tmp"); LValue LV = LValue::MakeAddr(V, MakeQualifiers(E->getType())); setObjCGCLValueClass(getContext(), E, LV); return LV; - } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(E->getDecl())) { + } + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(E->getDecl())) { llvm::Value* V = CGM.GetAddrOfFunction(FD); if (!FD->hasPrototype()) { if (const FunctionProtoType *Proto = @@ -861,15 +874,19 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { } } return LValue::MakeAddr(V, MakeQualifiers(E->getType())); - } else if (const ImplicitParamDecl *IPD = - dyn_cast<ImplicitParamDecl>(E->getDecl())) { + } + + if (const ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(E->getDecl())){ llvm::Value *V = LocalDeclMap[IPD]; assert(V && "BlockVarDecl not entered in LocalDeclMap?"); return LValue::MakeAddr(V, MakeQualifiers(E->getType())); - } else if (const QualifiedDeclRefExpr *QDRExpr = - dyn_cast<QualifiedDeclRefExpr>(E)) { - return EmitPointerToDataMemberLValue(QDRExpr); } + + if (E->getQualifier()) { + // FIXME: the qualifier check does not seem sufficient here + return EmitPointerToDataMemberLValue(E); + } + assert(0 && "Unimp declref"); //an invalid LValue, but the assert will //ensure that this point is never reached. @@ -888,25 +905,24 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { QualType ExprTy = getContext().getCanonicalType(E->getSubExpr()->getType()); switch (E->getOpcode()) { default: assert(0 && "Unknown unary operator lvalue!"); - case UnaryOperator::Deref: - { - QualType T = E->getSubExpr()->getType()->getPointeeType(); - assert(!T.isNull() && "CodeGenFunction::EmitUnaryOpLValue: Illegal type"); - - Qualifiers Quals = MakeQualifiers(T); - Quals.setAddressSpace(ExprTy.getAddressSpace()); - - LValue LV = LValue::MakeAddr(EmitScalarExpr(E->getSubExpr()), Quals); - // We should not generate __weak write barrier on indirect reference - // of a pointer to object; as in void foo (__weak id *param); *param = 0; - // But, we continue to generate __strong write barrier on indirect write - // into a pointer to object. - if (getContext().getLangOptions().ObjC1 && - getContext().getLangOptions().getGCMode() != LangOptions::NonGC && - LV.isObjCWeak()) - LValue::SetObjCNonGC(LV, !E->isOBJCGCCandidate(getContext())); - return LV; - } + case UnaryOperator::Deref: { + QualType T = E->getSubExpr()->getType()->getPointeeType(); + assert(!T.isNull() && "CodeGenFunction::EmitUnaryOpLValue: Illegal type"); + + Qualifiers Quals = MakeQualifiers(T); + Quals.setAddressSpace(ExprTy.getAddressSpace()); + + LValue LV = LValue::MakeAddr(EmitScalarExpr(E->getSubExpr()), Quals); + // We should not generate __weak write barrier on indirect reference + // of a pointer to object; as in void foo (__weak id *param); *param = 0; + // But, we continue to generate __strong write barrier on indirect write + // into a pointer to object. + if (getContext().getLangOptions().ObjC1 && + getContext().getLangOptions().getGCMode() != LangOptions::NonGC && + LV.isObjCWeak()) + LValue::SetObjCNonGC(LV, !E->isOBJCGCCandidate(getContext())); + return LV; + } case UnaryOperator::Real: case UnaryOperator::Imag: LValue LV = EmitLValue(E->getSubExpr()); @@ -932,8 +948,7 @@ LValue CodeGenFunction::EmitPredefinedFunctionName(unsigned Type) { std::string GlobalVarName; switch (Type) { - default: - assert(0 && "Invalid type"); + default: assert(0 && "Invalid type"); case PredefinedExpr::Func: GlobalVarName = "__func__."; break; @@ -1089,12 +1104,12 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { llvm::Constant *BaseElts = Base.getExtVectorElts(); llvm::SmallVector<llvm::Constant *, 4> CElts; + const llvm::Type *Int32Ty = llvm::Type::getInt32Ty(VMContext); for (unsigned i = 0, e = Indices.size(); i != e; ++i) { if (isa<llvm::ConstantAggregateZero>(BaseElts)) - CElts.push_back(llvm::ConstantInt::get( - llvm::Type::getInt32Ty(VMContext), 0)); + CElts.push_back(llvm::ConstantInt::get(Int32Ty, 0)); else - CElts.push_back(BaseElts->getOperand(Indices[i])); + CElts.push_back(cast<llvm::Constant>(BaseElts->getOperand(Indices[i]))); } llvm::Constant *CV = llvm::ConstantVector::get(&CElts[0], CElts.size()); return LValue::MakeExtVectorElt(Base.getExtVectorAddr(), CV, @@ -1211,13 +1226,12 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr* E){ const Expr* InitExpr = E->getInitializer(); LValue Result = LValue::MakeAddr(DeclPtr, MakeQualifiers(E->getType())); - if (E->getType()->isComplexType()) { + if (E->getType()->isComplexType()) EmitComplexExprIntoAddr(InitExpr, DeclPtr, false); - } else if (hasAggregateLLVMType(E->getType())) { + else if (hasAggregateLLVMType(E->getType())) EmitAnyExpr(InitExpr, DeclPtr, false); - } else { + else EmitStoreThroughLValue(EmitAnyExpr(InitExpr), Result, E->getType()); - } return Result; } @@ -1238,9 +1252,7 @@ CodeGenFunction::EmitConditionalOperatorLValue(const ConditionalOperator* E) { if (!LHS.isSimple()) return EmitUnsupportedLValue(E, "conditional operator"); - llvm::Value *Temp = CreateTempAlloca(LHS.getAddress()->getType(), - "condtmp"); - + llvm::Value *Temp = CreateTempAlloca(LHS.getAddress()->getType(),"condtmp"); Builder.CreateStore(LHS.getAddress(), Temp); EmitBranch(ContBlock); @@ -1379,7 +1391,8 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { return EmitLValue(E->getRHS()); } - if (E->getOpcode() == BinaryOperator::PtrMemD) + if (E->getOpcode() == BinaryOperator::PtrMemD || + E->getOpcode() == BinaryOperator::PtrMemI) return EmitPointerToDataMemberBinaryExpr(E); // Can only get l-value for binary operator expressions which are a @@ -1406,15 +1419,14 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) { RValue RV = EmitCallExpr(E); - if (RV.isScalar()) { - assert(E->getCallReturnType()->isReferenceType() && - "Can't have a scalar return unless the return type is a " - "reference type!"); - - return LValue::MakeAddr(RV.getScalarVal(), MakeQualifiers(E->getType())); - } + if (!RV.isScalar()) + return LValue::MakeAddr(RV.getAggregateAddr(),MakeQualifiers(E->getType())); + + assert(E->getCallReturnType()->isReferenceType() && + "Can't have a scalar return unless the return type is a " + "reference type!"); - return LValue::MakeAddr(RV.getAggregateAddr(), MakeQualifiers(E->getType())); + return LValue::MakeAddr(RV.getScalarVal(), MakeQualifiers(E->getType())); } LValue CodeGenFunction::EmitVAArgExprLValue(const VAArgExpr *E) { @@ -1439,9 +1451,7 @@ LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) { LValue CodeGenFunction::EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E) { LValue LV = EmitLValue(E->getSubExpr()); - PushCXXTemporary(E->getTemporary(), LV.getAddress()); - return LV; } @@ -1497,21 +1507,18 @@ CodeGenFunction::EmitObjCPropertyRefLValue(const ObjCPropertyRefExpr *E) { return LValue::MakePropertyRef(E, E->getType().getCVRQualifiers()); } -LValue -CodeGenFunction::EmitObjCKVCRefLValue( +LValue CodeGenFunction::EmitObjCKVCRefLValue( const ObjCImplicitSetterGetterRefExpr *E) { // This is a special l-value that just issues sends when we load or store // through it. return LValue::MakeKVCRef(E, E->getType().getCVRQualifiers()); } -LValue -CodeGenFunction::EmitObjCSuperExprLValue(const ObjCSuperExpr *E) { +LValue CodeGenFunction::EmitObjCSuperExprLValue(const ObjCSuperExpr *E) { return EmitUnsupportedLValue(E, "use of super"); } LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) { - // Can only get l-value for message expression returning aggregate type RValue RV = EmitAnyExprToTemp(E); // FIXME: can this be volatile? @@ -1519,8 +1526,7 @@ LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) { } -LValue CodeGenFunction::EmitPointerToDataMemberLValue( - const QualifiedDeclRefExpr *E) { +LValue CodeGenFunction::EmitPointerToDataMemberLValue(const DeclRefExpr *E) { const FieldDecl *Field = cast<FieldDecl>(E->getDecl()); const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Field->getDeclContext()); QualType NNSpecTy = @@ -1530,12 +1536,9 @@ LValue CodeGenFunction::EmitPointerToDataMemberLValue( llvm::Value *V = llvm::Constant::getNullValue(ConvertType(NNSpecTy)); LValue MemExpLV = EmitLValueForField(V, const_cast<FieldDecl*>(Field), /*isUnion*/false, /*Qualifiers*/0); - const llvm::Type* ResultType = ConvertType( - getContext().getPointerDiffType()); - V = Builder.CreatePtrToInt(MemExpLV.getAddress(), ResultType, - "datamember"); - LValue LV = LValue::MakeAddr(V, MakeQualifiers(E->getType())); - return LV; + const llvm::Type *ResultType = ConvertType(getContext().getPointerDiffType()); + V = Builder.CreatePtrToInt(MemExpLV.getAddress(), ResultType, "datamember"); + return LValue::MakeAddr(V, MakeQualifiers(E->getType())); } RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType, @@ -1566,9 +1569,11 @@ RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType, Callee, Args, TargetDecl); } -LValue CodeGenFunction::EmitPointerToDataMemberBinaryExpr( - const BinaryOperator *E) { +LValue CodeGenFunction:: +EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) { llvm::Value *BaseV = EmitLValue(E->getLHS()).getAddress(); + if (E->getOpcode() == BinaryOperator::PtrMemI) + BaseV = Builder.CreateLoad(BaseV, "indir.ptr"); const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(getLLVMContext()); BaseV = Builder.CreateBitCast(BaseV, i8Ty); LValue RHSLV = EmitLValue(E->getRHS()); @@ -1577,13 +1582,12 @@ LValue CodeGenFunction::EmitPointerToDataMemberBinaryExpr( const llvm::Type* ResultType = ConvertType(getContext().getPointerDiffType()); OffsetV = Builder.CreateBitCast(OffsetV, ResultType); llvm::Value *AddV = Builder.CreateInBoundsGEP(BaseV, OffsetV, "add.ptr"); + QualType Ty = E->getRHS()->getType(); - const MemberPointerType *MemPtrType = Ty->getAs<MemberPointerType>(); - Ty = MemPtrType->getPointeeType(); - const llvm::Type* PType = - ConvertType(getContext().getPointerType(Ty)); + Ty = Ty->getAs<MemberPointerType>()->getPointeeType(); + + const llvm::Type *PType = ConvertType(getContext().getPointerType(Ty)); AddV = Builder.CreateBitCast(AddV, PType); - LValue LV = LValue::MakeAddr(AddV, MakeQualifiers(Ty)); - return LV; + return LValue::MakeAddr(AddV, MakeQualifiers(Ty)); } diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index f47b6ab..901f867 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -297,7 +297,7 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) { assert(MPT->getPointeeType()->isFunctionProtoType() && "Unexpected member pointer type!"); - const QualifiedDeclRefExpr *DRE = cast<QualifiedDeclRefExpr>(E->getSubExpr()); + const DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr()); const CXXMethodDecl *MD = cast<CXXMethodDecl>(DRE->getDecl()); const llvm::Type *PtrDiffTy = @@ -329,7 +329,8 @@ void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) { } void AggExprEmitter::VisitBinaryOperator(const BinaryOperator *E) { - if (E->getOpcode() == BinaryOperator::PtrMemD) + if (E->getOpcode() == BinaryOperator::PtrMemD || + E->getOpcode() == BinaryOperator::PtrMemI) VisitPointerToDataMemberBinaryOperator(E); else CGF.ErrorUnsupported(E, "aggregate binary expression"); diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index fc3748c..9145d92 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -228,7 +228,7 @@ class VISIBILITY_HIDDEN ConstStructBuilder { if (NumBytes > 1) Ty = llvm::ArrayType::get(Ty, NumBytes); - llvm::Constant *C = llvm::Constant::getNullValue(Ty); + llvm::Constant *C = llvm::UndefValue::get(Ty); Elements.push_back(C); assert(getAlignment(C) == 1 && "Padding must have 1 byte alignment!"); @@ -266,7 +266,7 @@ class VISIBILITY_HIDDEN ConstStructBuilder { if (NumBytes > 1) Ty = llvm::ArrayType::get(Ty, NumBytes); - llvm::Constant *Padding = llvm::Constant::getNullValue(Ty); + llvm::Constant *Padding = llvm::UndefValue::get(Ty); PackedElements.push_back(Padding); ElementOffsetInBytes += getSizeInBytes(Padding); } @@ -434,7 +434,7 @@ public: E->getType()->getAs<MemberPointerType>()) { QualType T = MPT->getPointeeType(); if (T->isFunctionProtoType()) { - QualifiedDeclRefExpr *DRE = cast<QualifiedDeclRefExpr>(E->getSubExpr()); + DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr()); return EmitMemberFunctionPointer(cast<CXXMethodDecl>(DRE->getDecl())); } @@ -496,7 +496,7 @@ public: if (NumPadBytes > 1) Ty = llvm::ArrayType::get(Ty, NumPadBytes); - Elts.push_back(llvm::Constant::getNullValue(Ty)); + Elts.push_back(llvm::UndefValue::get(Ty)); Types.push_back(Ty); } @@ -739,8 +739,7 @@ public: E->getType().getAddressSpace()); return C; } - case Expr::DeclRefExprClass: - case Expr::QualifiedDeclRefExprClass: { + case Expr::DeclRefExprClass: { NamedDecl *Decl = cast<DeclRefExpr>(E)->getDecl(); if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Decl)) return CGM.GetAddrOfFunction(FD); @@ -777,11 +776,17 @@ public: } case Expr::AddrLabelExprClass: { assert(CGF && "Invalid address of label expression outside function."); +#ifndef USEINDIRECTBRANCH unsigned id = CGF->GetIDForAddrOfLabel(cast<AddrLabelExpr>(E)->getLabel()); llvm::Constant *C = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), id); return llvm::ConstantExpr::getIntToPtr(C, ConvertType(E->getType())); +#else + llvm::Constant *Ptr = + CGF->GetAddrOfLabel(cast<AddrLabelExpr>(E)->getLabel()); + return llvm::ConstantExpr::getBitCast(Ptr, ConvertType(E->getType())); +#endif } case Expr::CallExprClass: { CallExpr* CE = cast<CallExpr>(E); diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 69604f9..96b58d8 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -135,11 +135,16 @@ public: } Value *VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E); Value *VisitAddrLabelExpr(const AddrLabelExpr *E) { +#ifndef USEINDIRECTBRANCH llvm::Value *V = llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()), CGF.GetIDForAddrOfLabel(E->getLabel())); return Builder.CreateIntToPtr(V, ConvertType(E->getType())); +#else + llvm::Value *V = CGF.GetAddrOfLabel(E->getLabel()); + return Builder.CreateBitCast(V, ConvertType(E->getType())); +#endif } // l-values. @@ -272,7 +277,12 @@ public: Value *VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) { return llvm::Constant::getNullValue(ConvertType(E->getType())); } - + + Value *VisitCXXThrowExpr(const CXXThrowExpr *E) { + CGF.EmitCXXThrowExpr(E); + return 0; + } + // Binary Operators. Value *EmitMul(const BinOpInfo &Ops) { if (CGF.getContext().getLangOptions().OverflowChecking @@ -678,14 +688,13 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) { // If the initializer is an ExtVecEltExpr (a swizzle), and the swizzle's // input is the same width as the vector being constructed, generate an // optimized shuffle of the swizzle input into the result. + unsigned Offset = (CurIdx == 0) ? 0 : ResElts; if (isa<ExtVectorElementExpr>(IE)) { llvm::ShuffleVectorInst *SVI = cast<llvm::ShuffleVectorInst>(Init); Value *SVOp = SVI->getOperand(0); const llvm::VectorType *OpTy = cast<llvm::VectorType>(SVOp->getType()); if (OpTy->getNumElements() == ResElts) { - unsigned Offset = (CurIdx == 0) ? 0 : ResElts; - for (unsigned j = 0; j != CurIdx; ++j) { // If the current vector initializer is a shuffle with undef, merge // this shuffle directly into it. @@ -717,13 +726,13 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) { Args.push_back(llvm::UndefValue::get(I32Ty)); llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], ResElts); Init = Builder.CreateShuffleVector(Init, llvm::UndefValue::get(VVT), - Mask, "vecext"); + Mask, "vext"); Args.clear(); for (unsigned j = 0; j != CurIdx; ++j) Args.push_back(llvm::ConstantInt::get(I32Ty, j)); for (unsigned j = 0; j != InitElts; ++j) - Args.push_back(llvm::ConstantInt::get(I32Ty, j+ResElts)); + Args.push_back(llvm::ConstantInt::get(I32Ty, j+Offset)); for (unsigned j = CurIdx + InitElts; j != ResElts; ++j) Args.push_back(llvm::UndefValue::get(I32Ty)); } @@ -1639,9 +1648,10 @@ Value *ScalarExprEmitter::VisitBinComma(const BinaryOperator *E) { /// expression is cheap enough and side-effect-free enough to evaluate /// unconditionally instead of conditionally. This is used to convert control /// flow into selects in some cases. -static bool isCheapEnoughToEvaluateUnconditionally(const Expr *E) { +static bool isCheapEnoughToEvaluateUnconditionally(const Expr *E, + CodeGenFunction &CGF) { if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) - return isCheapEnoughToEvaluateUnconditionally(PE->getSubExpr()); + return isCheapEnoughToEvaluateUnconditionally(PE->getSubExpr(), CGF); // TODO: Allow anything we can constant fold to an integer or fp constant. if (isa<IntegerLiteral>(E) || isa<CharacterLiteral>(E) || @@ -1652,7 +1662,9 @@ static bool isCheapEnoughToEvaluateUnconditionally(const Expr *E) { // X and Y are local variables. if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) - if (VD->hasLocalStorage() && !VD->getType().isVolatileQualified()) + if (VD->hasLocalStorage() && !(CGF.getContext() + .getCanonicalType(VD->getType()) + .isVolatileQualified())) return true; return false; @@ -1681,8 +1693,9 @@ VisitConditionalOperator(const ConditionalOperator *E) { // If this is a really simple expression (like x ? 4 : 5), emit this as a // select instead of as control flow. We can only do this if it is cheap and // safe to evaluate the LHS and RHS unconditionally. - if (E->getLHS() && isCheapEnoughToEvaluateUnconditionally(E->getLHS()) && - isCheapEnoughToEvaluateUnconditionally(E->getRHS())) { + if (E->getLHS() && isCheapEnoughToEvaluateUnconditionally(E->getLHS(), + CGF) && + isCheapEnoughToEvaluateUnconditionally(E->getRHS(), CGF)) { llvm::Value *CondV = CGF.EvaluateExprAsBool(E->getCond()); llvm::Value *LHS = Visit(E->getLHS()); llvm::Value *RHS = Visit(E->getRHS()); diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index cadba32..2fe3f5b 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -280,17 +280,29 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args), SetPropertyFn, Args); } else { + // FIXME: Find a clean way to avoid AST node creation. SourceLocation Loc = PD->getLocation(); ValueDecl *Self = OMD->getSelfDecl(); ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl(); DeclRefExpr Base(Self, Self->getType(), Loc); ParmVarDecl *ArgDecl = *OMD->param_begin(); DeclRefExpr Arg(ArgDecl, ArgDecl->getType(), Loc); - ObjCIvarRefExpr IvarRef(Ivar, Ivar->getType(), Loc, &Base, - true, true); - BinaryOperator Assign(&IvarRef, &Arg, BinaryOperator::Assign, - Ivar->getType(), Loc); - EmitStmt(&Assign); + ObjCIvarRefExpr IvarRef(Ivar, Ivar->getType(), Loc, &Base, true, true); + + // The property type can differ from the ivar type in some situations with + // Objective-C pointer types, we can always bit cast the RHS in these cases. + if (getContext().getCanonicalType(Ivar->getType()) != + getContext().getCanonicalType(ArgDecl->getType())) { + ImplicitCastExpr ArgCasted(Ivar->getType(), CastExpr::CK_BitCast, &Arg, + false); + BinaryOperator Assign(&IvarRef, &ArgCasted, BinaryOperator::Assign, + Ivar->getType(), Loc); + EmitStmt(&Assign); + } else { + BinaryOperator Assign(&IvarRef, &Arg, BinaryOperator::Assign, + Ivar->getType(), Loc); + EmitStmt(&Assign); + } } FinishFunction(); diff --git a/lib/CodeGen/CGRecordLayoutBuilder.h b/lib/CodeGen/CGRecordLayoutBuilder.h index d1a13aa..4ebf4e8 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.h +++ b/lib/CodeGen/CGRecordLayoutBuilder.h @@ -15,7 +15,7 @@ #define CLANG_CODEGEN_CGRECORDLAYOUTBUILDER_H #include "llvm/ADT/SmallVector.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/System/DataTypes.h" #include <vector> namespace llvm { diff --git a/lib/CodeGen/CGRtti.cpp b/lib/CodeGen/CGRtti.cpp index 7bc774f..7af15f0 100644 --- a/lib/CodeGen/CGRtti.cpp +++ b/lib/CodeGen/CGRtti.cpp @@ -16,32 +16,31 @@ using namespace clang; using namespace CodeGen; llvm::Constant *CodeGenModule::GenerateRtti(const CXXRecordDecl *RD) { - llvm::Type *Ptr8Ty; - Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); - llvm::Constant *Rtti = llvm::Constant::getNullValue(Ptr8Ty); + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); if (!getContext().getLangOptions().Rtti) - return Rtti; + return llvm::Constant::getNullValue(Int8PtrTy); llvm::SmallString<256> OutName; llvm::raw_svector_ostream Out(OutName); - mangleCXXRtti(getMangleContext(), RD, Out); + mangleCXXRtti(getMangleContext(), Context.getTagDeclType(RD), Out); llvm::GlobalVariable::LinkageTypes linktype; linktype = llvm::GlobalValue::WeakAnyLinkage; std::vector<llvm::Constant *> info; // assert(0 && "FIXME: implement rtti descriptor"); // FIXME: descriptor - info.push_back(llvm::Constant::getNullValue(Ptr8Ty)); + info.push_back(llvm::Constant::getNullValue(Int8PtrTy)); // assert(0 && "FIXME: implement rtti ts"); // FIXME: TS - info.push_back(llvm::Constant::getNullValue(Ptr8Ty)); + info.push_back(llvm::Constant::getNullValue(Int8PtrTy)); llvm::Constant *C; - llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, info.size()); + llvm::ArrayType *type = llvm::ArrayType::get(Int8PtrTy, info.size()); C = llvm::ConstantArray::get(type, info); - Rtti = new llvm::GlobalVariable(getModule(), type, true, linktype, C, - Out.str()); - Rtti = llvm::ConstantExpr::getBitCast(Rtti, Ptr8Ty); + llvm::Constant *Rtti = + new llvm::GlobalVariable(getModule(), type, true, linktype, C, + Out.str()); + Rtti = llvm::ConstantExpr::getBitCast(Rtti, Int8PtrTy); return Rtti; } diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index f58b579..9126c2c 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -287,8 +287,13 @@ void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) { // Emit initial switch which will be patched up later by // EmitIndirectSwitches(). We need a default dest, so we use the // current BB, but this is overwritten. +#ifndef USEINDIRECTBRANCH llvm::Value *V = Builder.CreatePtrToInt(EmitScalarExpr(S.getTarget()), llvm::Type::getInt32Ty(VMContext), +#else + llvm::Value *V = Builder.CreateBitCast(EmitScalarExpr(S.getTarget()), + llvm::Type::getInt8PtrTy(VMContext), +#endif "addr"); llvm::BasicBlock *CurBB = Builder.GetInsertBlock(); diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h index 2a06f51..fa77471 100644 --- a/lib/CodeGen/CGValue.h +++ b/lib/CodeGen/CGValue.h @@ -47,7 +47,7 @@ public: bool isVolatileQualified() const { return Volatile; } - /// getScalar() - Return the Value* of this scalar value. + /// getScalarVal() - Return the Value* of this scalar value. llvm::Value *getScalarVal() const { assert(isScalar() && "Not a scalar!"); return V1; diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index 9df0e1a..e2e1147 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -43,6 +43,9 @@ private: llvm::DenseMap<const CXXMethodDecl *, Index_t> VCall; llvm::DenseMap<const CXXMethodDecl *, Index_t> VCallOffset; llvm::DenseMap<const CXXRecordDecl *, Index_t> VBIndex; + + typedef llvm::DenseMap<const CXXMethodDecl *, int> Pures_t; + Pures_t Pures; typedef std::pair<Index_t, Index_t> CallOffset; typedef llvm::DenseMap<const CXXMethodDecl *, CallOffset> Thunks_t; Thunks_t Thunks; @@ -58,6 +61,7 @@ private: Index_t extra; int CurrentVBaseOffset; typedef std::vector<std::pair<const CXXRecordDecl *, int64_t> > Path_t; + llvm::Constant *cxa_pure; public: VtableBuilder(std::vector<llvm::Constant *> &meth, const CXXRecordDecl *c, @@ -68,6 +72,13 @@ public: LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)), CurrentVBaseOffset(0) { Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); + + // Calculate pointer for ___cxa_pure_virtual. + const llvm::FunctionType *FTy; + std::vector<const llvm::Type*> ArgTys; + const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext); + FTy = llvm::FunctionType::get(ResultType, ArgTys, false); + cxa_pure = wrap(CGM.CreateRuntimeFunction(FTy, "__cxa_pure_virtual")); } llvm::DenseMap<const CXXMethodDecl *, Index_t> &getIndex() { return Index; } @@ -84,8 +95,10 @@ public: return llvm::ConstantExpr::getBitCast(m, Ptr8Ty); } - void GenerateVBaseOffsets(std::vector<llvm::Constant *> &offsets, - const CXXRecordDecl *RD, uint64_t Offset, +#define D1(x) +//#define D1(X) do { if (getenv("DEBUG")) { X; } } while (0) + + void GenerateVBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset, bool updateVBIndex, Index_t current_vbindex) { for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { @@ -94,22 +107,24 @@ public: Index_t next_vbindex = current_vbindex; if (i->isVirtual() && !SeenVBase.count(Base)) { SeenVBase.insert(Base); - int64_t BaseOffset = -(Offset/8) + BLayout.getVBaseClassOffset(Base)/8; - llvm::Constant *m = wrap(BaseOffset); - m = wrap((0?700:0) + BaseOffset); if (updateVBIndex) { - next_vbindex = (ssize_t)(-(offsets.size()*LLVMPointerWidth/8) + next_vbindex = (ssize_t)(-(VCalls.size()*LLVMPointerWidth/8) - 3*LLVMPointerWidth/8); VBIndex[Base] = next_vbindex; } - offsets.push_back(m); + int64_t BaseOffset = -(Offset/8) + BLayout.getVBaseClassOffset(Base)/8; + VCalls.push_back((0?700:0) + BaseOffset); + D1(printf(" vbase for %s at %d delta %d most derived %s\n", + Base->getNameAsCString(), + (int)-VCalls.size()-3, (int)BaseOffset, + Class->getNameAsCString())); } // We also record offsets for non-virtual bases to closest enclosing // virtual base. We do this so that we don't have to search // for the nearst virtual base class when generating thunks. if (updateVBIndex && VBIndex.count(Base) == 0) VBIndex[Base] = next_vbindex; - GenerateVBaseOffsets(offsets, Base, Offset, updateVBIndex, next_vbindex); + GenerateVBaseOffsets(Base, Offset, updateVBIndex, next_vbindex); } } @@ -144,8 +159,8 @@ public: /// getNVOffset - Returns the non-virtual offset for the given (B) base of the /// derived class D. Index_t getNVOffset(QualType qB, QualType qD) { - qD = qD->getAs<PointerType>()->getPointeeType(); - qB = qB->getAs<PointerType>()->getPointeeType(); + qD = qD->getPointeeType(); + qB = qB->getPointeeType(); CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl()); CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl()); int64_t o = getNVOffset_1(D, B); @@ -159,8 +174,8 @@ public: /// getVbaseOffset - Returns the index into the vtable for the virtual base /// offset for the given (B) virtual base of the derived class D. Index_t getVbaseOffset(QualType qB, QualType qD) { - qD = qD->getAs<PointerType>()->getPointeeType(); - qB = qB->getAs<PointerType>()->getPointeeType(); + qD = qD->getPointeeType(); + qB = qB->getPointeeType(); CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl()); CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl()); if (D != Class) @@ -177,6 +192,7 @@ public: bool OverrideMethod(const CXXMethodDecl *MD, llvm::Constant *m, bool MorallyVirtual, Index_t OverrideOffset, Index_t Offset) { + const bool isPure = MD->isPure(); typedef CXXMethodDecl::method_iterator meth_iter; // FIXME: Should OverrideOffset's be Offset? @@ -215,7 +231,9 @@ public: } Index[MD] = i; submethods[i] = m; - + if (isPure) + Pures[MD] = 1; + Pures.erase(OMD); Thunks.erase(OMD); if (MorallyVirtual) { Index_t &idx = VCall[OMD]; @@ -223,9 +241,17 @@ public: VCallOffset[MD] = OverrideOffset/8; idx = VCalls.size()+1; VCalls.push_back(0); + D1(printf(" vcall for %s at %d with delta %d most derived %s\n", + MD->getNameAsCString(), + (int)-VCalls.size()-3, (int)VCallOffset[MD], + Class->getNameAsCString())); } else { VCallOffset[MD] = VCallOffset[OMD]; VCalls[idx-1] = -VCallOffset[OMD] + OverrideOffset/8; + D1(printf(" vcall patch for %s at %d with delta %d most derived %s\n", + MD->getNameAsCString(), + (int)-VCalls.size()-3, (int)VCallOffset[MD], + Class->getNameAsCString())); } VCall[MD] = idx; CallOffset ThisOffset; @@ -237,7 +263,7 @@ public: CovariantThunks[MD] = std::make_pair(std::make_pair(ThisOffset, ReturnOffset), oret); - else + else if (!isPure) Thunks[MD] = ThisOffset; return true; } @@ -252,7 +278,7 @@ public: CovariantThunks[MD] = std::make_pair(std::make_pair(ThisOffset, ReturnOffset), oret); - else + else if (!isPure) Thunks[MD] = ThisOffset; } return true; @@ -266,6 +292,7 @@ public: for (Thunks_t::iterator i = Thunks.begin(), e = Thunks.end(); i != e; ++i) { const CXXMethodDecl *MD = i->first; + assert(!MD->isPure() && "Trying to thunk a pure"); Index_t idx = Index[MD]; Index_t nv_O = i->second.first; Index_t v_O = i->second.second; @@ -276,6 +303,8 @@ public: e = CovariantThunks.end(); i != e; ++i) { const CXXMethodDecl *MD = i->first; + if (MD->isPure()) + continue; Index_t idx = Index[MD]; Index_t nv_t = i->second.first.first.first; Index_t v_t = i->second.first.first.second; @@ -285,6 +314,25 @@ public: v_r); } CovariantThunks.clear(); + for (Pures_t::iterator i = Pures.begin(), e = Pures.end(); + i != e; ++i) { + const CXXMethodDecl *MD = i->first; + Index_t idx = Index[MD]; + submethods[idx] = cxa_pure; + } + Pures.clear(); + } + + llvm::Constant *WrapAddrOf(const CXXMethodDecl *MD) { + if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) + return wrap(CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete)); + + const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + const llvm::Type *Ty = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + FPT->isVariadic()); + + return wrap(CGM.GetAddrOfFunction(MD, Ty)); } void OverrideMethods(Path_t *Path, bool MorallyVirtual, int64_t Offset) { @@ -298,37 +346,16 @@ public: continue; const CXXMethodDecl *MD = *mi; - llvm::Constant *m = 0; - if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) - m = wrap(CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete)); - else { - const FunctionProtoType *FPT = - MD->getType()->getAs<FunctionProtoType>(); - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - - m = wrap(CGM.GetAddrOfFunction(MD, Ty)); - } - + llvm::Constant *m = WrapAddrOf(MD); OverrideMethod(MD, m, MorallyVirtual, OverrideOffset, Offset); } } } - void AddMethod(const CXXMethodDecl *MD, bool MorallyVirtual, Index_t Offset) { - llvm::Constant *m = 0; - if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) - m = wrap(CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete)); - else { - const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - - m = wrap(CGM.GetAddrOfFunction(MD, Ty)); - } - + void AddMethod(const CXXMethodDecl *MD, bool MorallyVirtual, Index_t Offset, + bool ForVirtualBase) { + llvm::Constant *m = WrapAddrOf(MD); + // If we can find a previously allocated slot for this, reuse it. if (OverrideMethod(MD, m, MorallyVirtual, Offset, Offset)) return; @@ -336,6 +363,9 @@ public: // else allocate a new slot. Index[MD] = submethods.size(); submethods.push_back(m); + D1(printf(" vfn for %s at %d\n", MD->getNameAsCString(), (int)Index[MD])); + if (MD->isPure()) + Pures[MD] = 1; if (MorallyVirtual) { VCallOffset[MD] = Offset/8; Index_t &idx = VCall[MD]; @@ -343,16 +373,19 @@ public: if (idx == 0) { idx = VCalls.size()+1; VCalls.push_back(0); + D1(printf(" vcall for %s at %d with delta %d\n", + MD->getNameAsCString(), (int)-VCalls.size()-3, + (int)VCallOffset[MD])); } } } void AddMethods(const CXXRecordDecl *RD, bool MorallyVirtual, - Index_t Offset) { + Index_t Offset, bool RDisVirtualBase) { for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me; ++mi) if (mi->isVirtual()) - AddMethod(*mi, MorallyVirtual, Offset); + AddMethod(*mi, MorallyVirtual, Offset, RDisVirtualBase); } void NonVirtualBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout, @@ -381,6 +414,7 @@ public: void insertVCalls(int InsertionPoint) { llvm::Constant *e = 0; + D1(printf("============= combining vbase/vcall\n")); D(VCalls.insert(VCalls.begin(), 673)); D(VCalls.push_back(672)); methods.insert(methods.begin() + InsertionPoint, VCalls.size(), e); @@ -392,11 +426,10 @@ public: VCalls.clear(); } - Index_t end(const CXXRecordDecl *RD, std::vector<llvm::Constant *> &offsets, - const ASTRecordLayout &Layout, - const CXXRecordDecl *PrimaryBase, - bool PrimaryBaseWasVirtual, bool MorallyVirtual, - int64_t Offset, bool ForVirtualBase, Path_t *Path) { + Index_t end(const CXXRecordDecl *RD, const ASTRecordLayout &Layout, + const CXXRecordDecl *PrimaryBase, bool PrimaryBaseWasVirtual, + bool MorallyVirtual, int64_t Offset, bool ForVirtualBase, + Path_t *Path) { bool alloc = false; if (Path == 0) { alloc = true; @@ -405,16 +438,6 @@ public: StartNewTable(); extra = 0; - // FIXME: Cleanup. - if (!ForVirtualBase) { - D(methods.push_back(wrap(666))); - // then virtual base offsets... - for (std::vector<llvm::Constant *>::reverse_iterator i = offsets.rbegin(), - e = offsets.rend(); i != e; ++i) - methods.push_back(*i); - D(methods.push_back(wrap(667))); - } - bool DeferVCalls = MorallyVirtual || ForVirtualBase; int VCallInsertionPoint = methods.size(); if (!DeferVCalls) { @@ -423,20 +446,12 @@ public: // FIXME: just for extra, or for all uses of VCalls.size post this? extra = -VCalls.size(); - if (ForVirtualBase) { - D(methods.push_back(wrap(668))); - // then virtual base offsets... - for (std::vector<llvm::Constant *>::reverse_iterator i = offsets.rbegin(), - e = offsets.rend(); i != e; ++i) - methods.push_back(*i); - D(methods.push_back(wrap(669))); - } - methods.push_back(wrap(-(Offset/8))); methods.push_back(rtti); Index_t AddressPoint = methods.size(); InstallThunks(); + D1(printf("============= combining methods\n")); methods.insert(methods.end(), submethods.begin(), submethods.end()); submethods.clear(); @@ -445,10 +460,8 @@ public: MorallyVirtual, Offset, Path); if (ForVirtualBase) { - D(methods.push_back(wrap(670))); insertVCalls(VCallInsertionPoint); AddressPoint += VCalls.size(); - D(methods.push_back(wrap(671))); } if (alloc) { @@ -457,7 +470,36 @@ public: return AddressPoint; } - void Primaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset) { + void Primaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset, + bool updateVBIndex, Index_t current_vbindex, + bool RDisVirtualBase) { + if (!RD->isDynamicClass()) + return; + + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); + + // vtables are composed from the chain of primaries. + if (PrimaryBase) { + D1(printf(" doing primaries for %s most derived %s\n", + RD->getNameAsCString(), Class->getNameAsCString())); + + if (!PrimaryBaseWasVirtual) + Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset, + updateVBIndex, current_vbindex, PrimaryBaseWasVirtual); + } + + D1(printf(" doing vcall entries for %s most derived %s\n", + RD->getNameAsCString(), Class->getNameAsCString())); + + // And add the virtuals for the class to the primary vtable. + AddMethods(RD, MorallyVirtual, Offset, RDisVirtualBase); + } + + void VBPrimaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset, + bool updateVBIndex, Index_t current_vbindex, + bool RDisVirtualBase, bool bottom=false) { if (!RD->isDynamicClass()) return; @@ -469,11 +511,22 @@ public: if (PrimaryBase) { if (PrimaryBaseWasVirtual) IndirectPrimary.insert(PrimaryBase); - Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset); + + D1(printf(" doing primaries for %s most derived %s\n", + RD->getNameAsCString(), Class->getNameAsCString())); + + VBPrimaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset, + updateVBIndex, current_vbindex, PrimaryBaseWasVirtual); } - // And add the virtuals for the class to the primary vtable. - AddMethods(RD, MorallyVirtual, Offset); + D1(printf(" doing vbase entries for %s most derived %s\n", + RD->getNameAsCString(), Class->getNameAsCString())); + GenerateVBaseOffsets(RD, Offset, updateVBIndex, current_vbindex); + + if (RDisVirtualBase || bottom) { + Primaries(RD, MorallyVirtual, Offset, updateVBIndex, current_vbindex, + RDisVirtualBase); + } } int64_t GenerateVtableForBase(const CXXRecordDecl *RD, @@ -487,27 +540,21 @@ public: const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); - std::vector<llvm::Constant *> offsets; extra = 0; - GenerateVBaseOffsets(offsets, RD, Offset, !ForVirtualBase, 0); - if (ForVirtualBase) - extra = offsets.size(); + D1(printf("building entries for base %s most derived %s\n", + RD->getNameAsCString(), Class->getNameAsCString())); - // vtables are composed from the chain of primaries. - if (PrimaryBase) { - if (PrimaryBaseWasVirtual) - IndirectPrimary.insert(PrimaryBase); - Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset); - } + if (ForVirtualBase) + extra = VCalls.size(); - // And add the virtuals for the class to the primary vtable. - AddMethods(RD, MorallyVirtual, Offset); + VBPrimaries(RD, MorallyVirtual, Offset, !ForVirtualBase, 0, ForVirtualBase, + true); if (Path) OverrideMethods(Path, MorallyVirtual, Offset); - return end(RD, offsets, Layout, PrimaryBase, PrimaryBaseWasVirtual, - MorallyVirtual, Offset, ForVirtualBase, Path); + return end(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, MorallyVirtual, + Offset, ForVirtualBase, Path); } void GenerateVtableForVBases(const CXXRecordDecl *RD, @@ -532,6 +579,8 @@ public: VCall.clear(); int64_t BaseOffset = BLayout.getVBaseClassOffset(Base); CurrentVBaseOffset = BaseOffset; + D1(printf("vtable %s virtual base %s\n", + Class->getNameAsCString(), Base->getNameAsCString())); GenerateVtableForBase(Base, true, BaseOffset, true, Path); } int64_t BaseOffset = Offset; @@ -567,6 +616,7 @@ int64_t CGVtableInfo::getMethodVtableIndex(const CXXMethodDecl *MD) { // FIXME: This seems expensive. Can we do a partial job to get // just this data. VtableBuilder b(methods, RD, CGM); + D1(printf("vtable %s\n", RD->getNameAsCString())); b.GenerateVtableForBase(RD); b.GenerateVtableForVBases(RD); @@ -591,6 +641,7 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, // FIXME: This seems expensive. Can we do a partial job to get // just this data. VtableBuilder b(methods, RD, CGM); + D1(printf("vtable %s\n", RD->getNameAsCString())); b.GenerateVtableForBase(RD); b.GenerateVtableForVBases(RD); @@ -614,13 +665,14 @@ llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) { mangleCXXVtable(CGM.getMangleContext(), RD, Out); llvm::GlobalVariable::LinkageTypes linktype; - linktype = llvm::GlobalValue::WeakAnyLinkage; + linktype = llvm::GlobalValue::LinkOnceODRLinkage; std::vector<llvm::Constant *> methods; llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0); int64_t AddressPoint; VtableBuilder b(methods, RD, CGM); + D1(printf("vtable %s\n", RD->getNameAsCString())); // First comes the vtables for all the non-virtual bases... AddressPoint = b.GenerateVtableForBase(RD); diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index 2f46313..10884a7 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -10,6 +10,7 @@ add_clang_library(clangCodeGen CGCall.cpp CGDebugInfo.cpp CGDecl.cpp + CGException.cpp CGExpr.cpp CGExprAgg.cpp CGExprComplex.cpp diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index ba93e5d..88beadf 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -27,7 +27,11 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) : BlockFunction(cgm, *this, Builder), CGM(cgm), Target(CGM.getContext().Target), Builder(cgm.getModule().getContext()), +#ifndef USEINDIRECTBRANCH DebugInfo(0), IndirectGotoSwitch(0), +#else + DebugInfo(0), IndirectBranch(0), +#endif SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0), CXXThisDecl(0) { LLVMIntTy = ConvertType(getContext().IntTy); @@ -130,10 +134,33 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { EmitFunctionEpilog(*CurFnInfo, ReturnValue); +#ifdef USEINDIRECTBRANCH + // If someone did an indirect goto, emit the indirect goto block at the end of + // the function. + if (IndirectBranch) { + EmitBlock(IndirectBranch->getParent()); + Builder.ClearInsertionPoint(); + } + + +#endif // Remove the AllocaInsertPt instruction, which is just a convenience for us. llvm::Instruction *Ptr = AllocaInsertPt; AllocaInsertPt = 0; Ptr->eraseFromParent(); +#ifdef USEINDIRECTBRANCH + + // If someone took the address of a label but never did an indirect goto, we + // made a zero entry PHI node, which is illegal, zap it now. + if (IndirectBranch) { + llvm::PHINode *PN = cast<llvm::PHINode>(IndirectBranch->getAddress()); + if (PN->getNumIncomingValues() == 0) { + PN->replaceAllUsesWith(llvm::UndefValue::get(PN->getType())); + PN->eraseFromParent(); + } + } + +#endif } void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, @@ -466,13 +493,26 @@ void CodeGenFunction::EmitMemSetToZero(llvm::Value *DestPtr, QualType Ty) { TypeInfo.second/8)); } +#ifndef USEINDIRECTBRANCH unsigned CodeGenFunction::GetIDForAddrOfLabel(const LabelStmt *L) { // Use LabelIDs.size()+1 as the new ID if one hasn't been assigned. unsigned &Entry = LabelIDs[L]; if (Entry) return Entry; +#else + +llvm::BlockAddress *CodeGenFunction::GetAddrOfLabel(const LabelStmt *L) { + // Make sure that there is a block for the indirect goto. + if (IndirectBranch == 0) + GetIndirectGotoBlock(); +#endif +#ifndef USEINDIRECTBRANCH Entry = LabelIDs.size(); +#else + llvm::BasicBlock *BB = getBasicBlockForLabel(L); +#endif +#ifndef USEINDIRECTBRANCH // If this is the first "address taken" of a label and the indirect goto has // already been seen, add this to it. if (IndirectGotoSwitch) { @@ -488,18 +528,42 @@ unsigned CodeGenFunction::GetIDForAddrOfLabel(const LabelStmt *L) { } return Entry; +#else + // Make sure the indirect branch includes all of the address-taken blocks. + IndirectBranch->addDestination(BB); + return llvm::BlockAddress::get(CurFn, BB); +#endif } llvm::BasicBlock *CodeGenFunction::GetIndirectGotoBlock() { +#ifndef USEINDIRECTBRANCH // If we already made the switch stmt for indirect goto, return its block. if (IndirectGotoSwitch) return IndirectGotoSwitch->getParent(); +#else + // If we already made the indirect branch for indirect goto, return its block. + if (IndirectBranch) return IndirectBranch->getParent(); +#endif +#ifndef USEINDIRECTBRANCH EmitBlock(createBasicBlock("indirectgoto")); +#else + CGBuilderTy TmpBuilder(createBasicBlock("indirectgoto")); +#endif +#ifndef USEINDIRECTBRANCH + const llvm::IntegerType *Int32Ty = llvm::Type::getInt32Ty(VMContext); +#else + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); +#endif + // Create the PHI node that indirect gotos will add entries to. - llvm::Value *DestVal = - Builder.CreatePHI(llvm::Type::getInt32Ty(VMContext), "indirect.goto.dest"); +#ifndef USEINDIRECTBRANCH + llvm::Value *DestVal = Builder.CreatePHI(Int32Ty, "indirect.goto.dest"); +#else + llvm::Value *DestVal = TmpBuilder.CreatePHI(Int8PtrTy, "indirect.goto.dest"); +#endif +#ifndef USEINDIRECTBRANCH // Create the switch instruction. For now, set the insert block to this block // which will be fixed as labels are added. IndirectGotoSwitch = Builder.CreateSwitch(DestVal, Builder.GetInsertBlock()); @@ -524,8 +588,6 @@ llvm::BasicBlock *CodeGenFunction::GetIndirectGotoBlock() { IndirectGotoSwitch->setSuccessor(0, getBasicBlockForLabel(AddrTakenLabelsByID[0])); - const llvm::IntegerType *Int32Ty = llvm::Type::getInt32Ty(VMContext); - // FIXME: The iteration order of this is nondeterminstic! for (unsigned i = 1, e = AddrTakenLabelsByID.size(); i != e; ++i) IndirectGotoSwitch->addCase(llvm::ConstantInt::get(Int32Ty, i+1), @@ -541,6 +603,11 @@ llvm::BasicBlock *CodeGenFunction::GetIndirectGotoBlock() { } return IndirectGotoSwitch->getParent(); +#else + // Create the indirect branch instruction. + IndirectBranch = TmpBuilder.CreateIndirectBr(DestVal); + return IndirectBranch->getParent(); +#endif } llvm::Value *CodeGenFunction::GetVLASize(const VariableArrayType *VAT) { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 639e683..9bb2196 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -183,13 +183,22 @@ public: void PopConditionalTempDestruction(); private: - CGDebugInfo* DebugInfo; + CGDebugInfo *DebugInfo; +#ifndef USEINDIRECTBRANCH /// LabelIDs - Track arbitrary ids assigned to labels for use in implementing /// the GCC address-of-label extension and indirect goto. IDs are assigned to /// labels inside getIDForAddrOfLabel(). std::map<const LabelStmt*, unsigned> LabelIDs; +#else + /// IndirectBranch - The first time an indirect goto is seen we create a + /// block with an indirect branch. Every time we see the address of a label + /// taken, we add the label to the indirect goto. Every subsequent indirect + /// goto is codegen'd as a jump to the IndirectBranch's basic block. + llvm::IndirectBrInst *IndirectBranch; +#endif +#ifndef USEINDIRECTBRANCH /// IndirectGotoSwitch - The first time an indirect goto is seen we create a /// block with the switch for the indirect gotos. Every time we see the /// address of a label taken, we add the label to the indirect goto. Every @@ -197,6 +206,7 @@ private: /// IndirectGotoSwitch's basic block. llvm::SwitchInst *IndirectGotoSwitch; +#endif /// LocalDeclMap - This keeps track of the LLVM allocas or globals for local C /// decls. llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap; @@ -377,6 +387,11 @@ public: /// GenerateVtable - Generate the vtable for the given type. llvm::Value *GenerateVtable(const CXXRecordDecl *RD); + /// DynamicTypeAdjust - Do the non-virtual and virtual adjustments on an + /// object pointer to alter the dynamic type of the pointer. Used by + /// GenerateCovariantThunk for building thunks. + llvm::Value *DynamicTypeAdjust(llvm::Value *V, int64_t nv, int64_t v); + /// GenerateThunk - Generate a thunk for the given method llvm::Constant *GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD, bool Extern, int64_t nv, int64_t v); @@ -502,7 +517,7 @@ public: //===--------------------------------------------------------------------===// Qualifiers MakeQualifiers(QualType T) { - Qualifiers Quals = T.getQualifiers(); + Qualifiers Quals = getContext().getCanonicalType(T).getQualifiers(); Quals.setObjCGCAttr(getContext().getObjCGCAttrKind(T)); return Quals; } @@ -558,7 +573,11 @@ public: /// the input field number being accessed. static unsigned getAccessedFieldNo(unsigned Idx, const llvm::Constant *Elts); +#ifndef USEINDIRECTBRANCH unsigned GetIDForAddrOfLabel(const LabelStmt *L); +#else + llvm::BlockAddress *GetAddrOfLabel(const LabelStmt *L); +#endif llvm::BasicBlock *GetIndirectGotoBlock(); /// EmitMemSetToZero - Generate code to memset a value of the given type to 0. @@ -819,7 +838,7 @@ public: LValue EmitConditionalOperatorLValue(const ConditionalOperator *E); LValue EmitCastLValue(const CastExpr *E); LValue EmitNullInitializationLValue(const CXXZeroInitValueExpr *E); - LValue EmitPointerToDataMemberLValue(const QualifiedDeclRefExpr *E); + LValue EmitPointerToDataMemberLValue(const DeclRefExpr *E); llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar); @@ -1000,6 +1019,8 @@ public: bool IsAggLocVolatile = false, bool IsInitializer = false); + void EmitCXXThrowExpr(const CXXThrowExpr *E); + //===--------------------------------------------------------------------===// // Internal Helpers //===--------------------------------------------------------------------===// diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index ea84829..db609f6 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -253,6 +253,10 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, if (FD->isInAnonymousNamespace()) return CodeGenModule::GVA_Internal; + // "static" functions get internal linkage. + if (FD->getStorageClass() == FunctionDecl::Static && !isa<CXXMethodDecl>(FD)) + return CodeGenModule::GVA_Internal; + // The kind of external linkage this function will have, if it is not // inline or static. CodeGenModule::GVALinkage External = CodeGenModule::GVA_StrongExternal; @@ -260,19 +264,7 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) External = CodeGenModule::GVA_TemplateInstantiation; - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { - // C++ member functions defined inside the class are always inline. - if (MD->isInline() || !MD->isOutOfLine()) - return CodeGenModule::GVA_CXXInline; - - return External; - } - - // "static" functions get internal linkage. - if (FD->getStorageClass() == FunctionDecl::Static) - return CodeGenModule::GVA_Internal; - - if (!FD->isInline()) + if (!FD->isInlined()) return External; if (!Features.CPlusPlus || FD->hasAttr<GNUInlineAttr>()) { @@ -285,8 +277,16 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, return CodeGenModule::GVA_C99Inline; } - // C++ inline semantics - assert(Features.CPlusPlus && "Must be in C++ mode"); + // C++0x [temp.explicit]p9: + // [ Note: The intent is that an inline function that is the subject of + // an explicit instantiation declaration will still be implicitly + // instantiated when used so that the body can be considered for + // inlining, but that no out-of-line copy of the inline function would be + // generated in the translation unit. -- end note ] + if (FD->getTemplateSpecializationKind() + == TSK_ExplicitInstantiationDeclaration) + return CodeGenModule::GVA_C99Inline; + return CodeGenModule::GVA_CXXInline; } @@ -601,6 +601,10 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { const ValueDecl *D = cast<ValueDecl>(GD.getDecl()); + PrettyStackTraceDecl CrashInfo((ValueDecl *)D, D->getLocation(), + Context.getSourceManager(), + "Generating code for declaration"); + if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D)) EmitCXXConstructor(CD, GD.getCtorType()); else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D)) @@ -949,7 +953,7 @@ GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) { return CodeGenModule::GVA_StrongExternal; case TSK_ExplicitInstantiationDeclaration: - assert(false && "Variable should not be instantiated"); + llvm::llvm_unreachable("Variable should not be instantiated"); // Fall through to treat this like any other instantiation. case TSK_ImplicitInstantiation: diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index dedf824..d43d13e 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -180,7 +180,7 @@ static const llvm::Type* getTypeForFormat(llvm::LLVMContext &VMContext, } const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { - const clang::Type &Ty = *Context.getCanonicalType(T); + const clang::Type &Ty = *Context.getCanonicalType(T).getTypePtr(); switch (Ty.getTypeClass()) { #define TYPE(Class, Base) diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index 2e6034b..a5b3452 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -52,7 +52,8 @@ namespace { void mangleGuardVariable(const VarDecl *D); void mangleCXXVtable(const CXXRecordDecl *RD); - void mangleCXXRtti(const CXXRecordDecl *RD); + void mangleCXXVTT(const CXXRecordDecl *RD); + void mangleCXXRtti(QualType Ty); void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type); void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type); @@ -114,6 +115,7 @@ namespace { } static bool isInCLinkageSpecification(const Decl *D) { + D = D->getCanonicalDecl(); for (const DeclContext *DC = D->getDeclContext(); !DC->isTranslationUnit(); DC = DC->getParent()) { if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) @@ -204,10 +206,17 @@ void CXXNameMangler::mangleCXXVtable(const CXXRecordDecl *RD) { mangleName(RD); } -void CXXNameMangler::mangleCXXRtti(const CXXRecordDecl *RD) { +void CXXNameMangler::mangleCXXVTT(const CXXRecordDecl *RD) { + // <special-name> ::= TT <type> # VTT structure + Out << "_ZTT"; + mangleName(RD); +} + +void CXXNameMangler::mangleCXXRtti(QualType Ty) { // <special-name> ::= TI <type> # typeinfo structure Out << "_ZTI"; - mangleName(RD); + + mangleType(Ty); } void CXXNameMangler::mangleGuardVariable(const VarDecl *D) { @@ -1355,7 +1364,7 @@ namespace clang { "Mangling declaration"); CXXNameMangler Mangler(Context, os); - if (!Mangler.mangle(cast<NamedDecl>(D->getCanonicalDecl()))) + if (!Mangler.mangle(D)) return false; os.flush(); @@ -1424,10 +1433,10 @@ namespace clang { os.flush(); } - void mangleCXXRtti(MangleContext &Context, const CXXRecordDecl *RD, + void mangleCXXRtti(MangleContext &Context, QualType Ty, llvm::raw_ostream &os) { CXXNameMangler Mangler(Context, os); - Mangler.mangleCXXRtti(RD); + Mangler.mangleCXXRtti(Ty); os.flush(); } diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h index 2cdb4e2..7f46a10 100644 --- a/lib/CodeGen/Mangle.h +++ b/lib/CodeGen/Mangle.h @@ -65,7 +65,9 @@ namespace clang { llvm::raw_ostream &os); void mangleCXXVtable(MangleContext &Context, const CXXRecordDecl *RD, llvm::raw_ostream &os); - void mangleCXXRtti(MangleContext &Context, const CXXRecordDecl *RD, + void mangleCXXVTT(MangleContext &Context, const CXXRecordDecl *RD, + llvm::raw_ostream &os); + void mangleCXXRtti(MangleContext &Context, QualType T, llvm::raw_ostream &os); void mangleCXXCtor(MangleContext &Context, const CXXConstructorDecl *D, CXXCtorType Type, llvm::raw_ostream &os); diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index c9d0b26..808c31c 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -12,8 +12,8 @@ #include "clang/Driver/Action.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" -#include "clang/Driver/Driver.h" // FIXME: Remove? -#include "clang/Driver/DriverDiagnostic.h" // FIXME: Remove? +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Job.h" #include "clang/Driver/HostInfo.h" @@ -22,9 +22,11 @@ #include "clang/Driver/Util.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/System/Process.h" #include "InputInfo.h" #include "ToolChains.h" @@ -32,13 +34,6 @@ using namespace clang::driver; using namespace clang::driver::tools; -static const char *MakeFormattedString(const ArgList &Args, - const llvm::format_object_base &Fmt) { - llvm::SmallString<256> Str; - llvm::raw_svector_ostream(Str) << Fmt; - return Args.MakeArgString(Str.str()); -} - /// CheckPreprocessingOptions - Perform some validation of preprocessing /// arguments that is shared with gcc. static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) { @@ -203,6 +198,10 @@ void Clang::AddPreprocessingOptions(const Driver &D, // those options. :( Args.AddAllArgValues(CmdArgs, options::OPT_Wp_COMMA, options::OPT_Xpreprocessor); + + // -I- is a deprecated GCC feature, reject it. + if (Arg *A = Args.getLastArg(options::OPT_I_)) + D.Diag(clang::diag::err_drv_I_dash_not_supported) << A->getAsString(Args); } /// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targetting. @@ -417,8 +416,6 @@ void Clang::AddARMTargetArgs(const ArgList &Args, void Clang::AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - // FIXME: This needs to change to use a clang-cc option, and set the attribute - // on functions. if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) || @@ -426,8 +423,6 @@ void Clang::AddX86TargetArgs(const ArgList &Args, Args.hasArg(options::OPT_fapple_kext)) CmdArgs.push_back("--disable-red-zone"); - // FIXME: This needs to change to use a clang-cc option, and set the attribute - // on functions. if (Args.hasFlag(options::OPT_msoft_float, options::OPT_mno_soft_float, false)) @@ -507,6 +502,57 @@ static bool needsExceptions(const ArgList &Args, types::ID InputType, } } +/// getEffectiveClangTriple - Get the "effective" target triple, which is the +/// triple for the target but with the OS version potentially modified for +/// Darwin's -mmacosx-version-min. +static std::string getEffectiveClangTriple(const Driver &D, + const ToolChain &TC, + const ArgList &Args) { + llvm::Triple Triple(getLLVMTriple(TC, Args)); + + if (Triple.getOS() != llvm::Triple::Darwin) { + // Diagnose use of -mmacosx-version-min and -miphoneos-version-min on + // non-Darwin. + if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ, + options::OPT_miphoneos_version_min_EQ)) + D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + return Triple.getTriple(); + } + + // If -mmacosx-version-min=10.3.9 is specified, change the effective triple + // from being something like powerpc-apple-darwin9 to powerpc-apple-darwin7. + if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ)) { + unsigned Major, Minor, Micro; + bool HadExtra; + if (!Driver::GetReleaseVersion(A->getValue(Args), Major, Minor, Micro, + HadExtra) || HadExtra || + Major != 10) + D.Diag(clang::diag::err_drv_invalid_version_number) + << A->getAsString(Args); + + // Mangle the MacOS version min number into the Darwin number: e.g. 10.3.9 + // is darwin7.9. + llvm::SmallString<16> Str; + llvm::raw_svector_ostream(Str) << "darwin" << Minor + 4 << "." << Micro; + Triple.setOSName(Str.str()); + } else if (Arg *A = Args.getLastArg(options::OPT_miphoneos_version_min_EQ)) { + unsigned Major, Minor, Micro; + bool HadExtra; + if (!Driver::GetReleaseVersion(A->getValue(Args), Major, Minor, Micro, + HadExtra) || HadExtra) + D.Diag(clang::diag::err_drv_invalid_version_number) + << A->getAsString(Args); + + // Mangle the iPhoneOS version number into the Darwin number: e.g. 2.0 is 2 + // -> 9.2.0. + llvm::SmallString<16> Str; + llvm::raw_svector_ostream(Str) << "darwin9." << Major << "." << Minor; + Triple.setOSName(Str.str()); + } + + return Triple.getTriple(); +} + void Clang::ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, const InputInfo &Output, @@ -518,12 +564,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); + // Add the "effective" target triple. CmdArgs.push_back("-triple"); + std::string TripleStr = getEffectiveClangTriple(D, getToolChain(), Args); + CmdArgs.push_back(Args.MakeArgString(TripleStr)); - const char *TripleStr = - Args.MakeArgString(getLLVMTriple(getToolChain(), Args)); - CmdArgs.push_back(TripleStr); - + // Select the appropriate action. if (isa<AnalyzeJobAction>(JA)) { assert(JA.getType() == types::TY_Plist && "Invalid output type."); CmdArgs.push_back("-analyze"); @@ -606,9 +652,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // issue is that llvm-gcc translates these options based on // the values in cc1, whereas we are processing based on // the driver arguments. - // - // FIXME: This is currently broken for -f flags when -fno - // variants are present. // This comes from the default translation the driver + cc1 // would do to enable flag_pic. @@ -661,8 +704,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("--debug-pass=Structure"); if (Args.hasArg(options::OPT_fdebug_pass_arguments)) CmdArgs.push_back("--debug-pass=Arguments"); - // FIXME: set --inline-threshhold=50 if (optimize_size || optimize - // < 3) + if (!Args.hasFlag(options::OPT_fmerge_all_constants, + options::OPT_fno_merge_all_constants)) + CmdArgs.push_back("--no-merge-all-constants"); // This is a coarse approximation of what llvm-gcc actually does, both // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more @@ -714,9 +758,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue(Args)); } - // FIXME: Add --stack-protector-buffer-size=<xxx> on - // -fstack-protect. - Arg *Unsupported; if ((Unsupported = Args.getLastArg(options::OPT_MG)) || (Unsupported = Args.getLastArg(options::OPT_MQ)) || @@ -726,8 +767,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_v); Args.AddLastArg(CmdArgs, options::OPT_P); - Args.AddLastArg(CmdArgs, options::OPT_mmacosx_version_min_EQ); - Args.AddLastArg(CmdArgs, options::OPT_miphoneos_version_min_EQ); Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout); // Special case debug options to only pass -g to clang. This is @@ -736,7 +775,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-g"); Args.AddLastArg(CmdArgs, options::OPT_nostdinc); - Args.AddLastArg(CmdArgs, options::OPT_nostdclanginc); + Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc); Args.AddLastArg(CmdArgs, options::OPT_isysroot); @@ -759,7 +798,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->render(Args, CmdArgs); } - Args.AddAllArgs(CmdArgs, options::OPT_W_Group, options::OPT_pedantic_Group); + Args.AddAllArgs(CmdArgs, options::OPT_W_Group); + Args.AddLastArg(CmdArgs, options::OPT_pedantic); + Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors); Args.AddLastArg(CmdArgs, options::OPT_w); // Handle -{std, ansi, trigraphs} -- take the last of -{std, ansi} @@ -770,9 +811,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) { if (Std->getOption().matches(options::OPT_ansi)) if (types::isCXX(InputType)) - CmdArgs.push_back("-std=c++98"); + CmdArgs.push_back("-std=c++98"); else - CmdArgs.push_back("-std=c89"); + CmdArgs.push_back("-std=c89"); else Std->render(Args, CmdArgs); @@ -794,10 +835,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT__relocatable_pch, true)) CmdArgs.push_back("--relocatable-pch"); - if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) { - CmdArgs.push_back("-fconstant-string-class"); - CmdArgs.push_back(A->getValue(Args)); - } + if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) { + CmdArgs.push_back("-fconstant-string-class"); + CmdArgs.push_back(A->getValue(Args)); + } + + // Pass -fmessage-length=. + if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) { + A->render(Args, CmdArgs); + } else { + // If -fmessage-length=N was not specified, determine whether this is a + // terminal and, if so, implicitly define -fmessage-length appropriately. + unsigned N = llvm::sys::Process::StandardErrColumns(); + CmdArgs.push_back("-fmessage-length"); + CmdArgs.push_back(Args.MakeArgString(llvm::Twine(N))); + } // Forward -f options which we can pass directly. Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); @@ -805,7 +857,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); Args.AddLastArg(CmdArgs, options::OPT_fgnu_runtime); Args.AddLastArg(CmdArgs, options::OPT_flax_vector_conversions); - Args.AddLastArg(CmdArgs, options::OPT_fmessage_length_EQ); Args.AddLastArg(CmdArgs, options::OPT_fms_extensions); Args.AddLastArg(CmdArgs, options::OPT_fnext_runtime); Args.AddLastArg(CmdArgs, options::OPT_fno_caret_diagnostics); @@ -871,9 +922,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fsigned-char=0"); } - // -fno-pascal-strings is default, only pass non-default. If the - // -tool chain happened to translate to -mpascal-strings, we want to - // -back translate here. + // -fno-pascal-strings is default, only pass non-default. If the tool chain + // happened to translate to -mpascal-strings, we want to back translate here. // // FIXME: This is gross; that translation should be pulled from the // tool chain. @@ -905,9 +955,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasFlag(options::OPT_fdiagnostics_show_option, options::OPT_fno_diagnostics_show_option)) CmdArgs.push_back("-fdiagnostics-show-option"); - if (!Args.hasFlag(options::OPT_fcolor_diagnostics, - options::OPT_fno_color_diagnostics)) - CmdArgs.push_back("-fno-color-diagnostics"); + + // Color diagnostics are the default, unless the terminal doesn't support + // them. + if (Args.hasFlag(options::OPT_fcolor_diagnostics, + options::OPT_fno_color_diagnostics) && + llvm::sys::Process::StandardErrHasColors()) + CmdArgs.push_back("-fcolor-diagnostics"); + if (!Args.hasFlag(options::OPT_fshow_source_location, options::OPT_fno_show_source_location)) CmdArgs.push_back("-fno-show-source-location"); @@ -979,6 +1034,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, II.getInputArg().renderAsInput(Args, CmdArgs); } + Args.AddAllArgs(CmdArgs, options::OPT_undef); + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(C, "clang-cc")); Dest.addCommand(new Command(JA, Exec, CmdArgs)); @@ -1667,23 +1724,18 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA, static bool isSourceSuffix(const char *Str) { // match: 'C', 'CPP', 'c', 'cc', 'cp', 'c++', 'cpp', 'cxx', 'm', // 'mm'. - switch (strlen(Str)) { - default: - return false; - case 1: - return (memcmp(Str, "C", 1) == 0 || - memcmp(Str, "c", 1) == 0 || - memcmp(Str, "m", 1) == 0); - case 2: - return (memcmp(Str, "cc", 2) == 0 || - memcmp(Str, "cp", 2) == 0 || - memcmp(Str, "mm", 2) == 0); - case 3: - return (memcmp(Str, "CPP", 3) == 0 || - memcmp(Str, "c++", 3) == 0 || - memcmp(Str, "cpp", 3) == 0 || - memcmp(Str, "cxx", 3) == 0); - } + return llvm::StringSwitch<bool>(Str) + .Case("C", true) + .Case("c", true) + .Case("m", true) + .Case("cc", true) + .Case("cp", true) + .Case("mm", true) + .Case("CPP", true) + .Case("c++", true) + .Case("cpp", true) + .Case("cxx", true) + .Default(false); } // FIXME: Can we tablegen this? @@ -1861,7 +1913,7 @@ void darwin::Link::AddLinkArgs(const ArgList &Args, // Adding all arguments doesn't make sense here but this is what // gcc does. Args.AddAllArgsTranslated(CmdArgs, options::OPT_mmacosx_version_min_EQ, - "-macosx_version_min"); + "-macosx_version_min"); Args.AddAllArgsTranslated(CmdArgs, options::OPT_miphoneos_version_min_EQ, "-iphoneos_version_min"); Args.AddLastArg(CmdArgs, options::OPT_nomultidefs); @@ -2137,10 +2189,10 @@ void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA, } void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { + Job &Dest, const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { ArgStringList CmdArgs; Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, @@ -2167,15 +2219,15 @@ void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA, } void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { + Job &Dest, const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { const Driver &D = getToolChain().getHost().getDriver(); ArgStringList CmdArgs; if ((!Args.hasArg(options::OPT_nostdlib)) && - (!Args.hasArg(options::OPT_shared))) { + (!Args.hasArg(options::OPT_shared))) { CmdArgs.push_back("-e"); CmdArgs.push_back("_start"); } @@ -2212,14 +2264,13 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbegin.o"))); } else { CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o"))); -// CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbeginS.o"))); } CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtn.o"))); } - CmdArgs.push_back(MakeFormattedString(Args, - llvm::format("-L/opt/gcc4/lib/gcc/%s/4.2.4", - getToolChain().getTripleString().c_str()))); + CmdArgs.push_back(Args.MakeArgString("-L/opt/gcc4/lib/gcc/" + + getToolChain().getTripleString() + + "/4.2.4")); Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); @@ -2307,7 +2358,7 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, ArgStringList CmdArgs; if ((!Args.hasArg(options::OPT_nostdlib)) && - (!Args.hasArg(options::OPT_shared))) { + (!Args.hasArg(options::OPT_shared))) { CmdArgs.push_back("-e"); CmdArgs.push_back("__start"); } @@ -2345,9 +2396,11 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, } } - CmdArgs.push_back(MakeFormattedString(Args, - llvm::format("-L/usr/lib/gcc-lib/%s/3.3.5", - getToolChain().getTripleString().c_str()))); + std::string Triple = getToolChain().getTripleString(); + if (Triple.substr(0, 6) == "x86_64") + Triple.replace(0, 6, "amd64"); + CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc-lib/" + Triple + + "/3.3.5")); Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); @@ -2547,10 +2600,10 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, // For now, DragonFly Assemble does just about the same as for // FreeBSD, but this may change soon. void dragonfly::Assemble::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { + Job &Dest, const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { ArgStringList CmdArgs; // When building 32-bit code on DragonFly/pc64, we have to explicitly @@ -2678,7 +2731,7 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_pthread)) - CmdArgs.push_back("-lthread_xu"); + CmdArgs.push_back("-lpthread"); if (!Args.hasArg(options::OPT_nolibc)) { CmdArgs.push_back("-lc"); diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp index eee8c19..c616c6a 100644 --- a/lib/Driver/Types.cpp +++ b/lib/Driver/Types.cpp @@ -9,6 +9,7 @@ #include "clang/Driver/Types.h" +#include "llvm/ADT/StringSwitch.h" #include <string.h> #include <cassert> @@ -102,51 +103,42 @@ bool types::isCXX(ID Id) { } types::ID types::lookupTypeForExtension(const char *Ext) { - unsigned N = strlen(Ext); - - switch (N) { - case 1: - if (memcmp(Ext, "c", 1) == 0) return TY_C; - if (memcmp(Ext, "i", 1) == 0) return TY_PP_C; - if (memcmp(Ext, "m", 1) == 0) return TY_ObjC; - if (memcmp(Ext, "M", 1) == 0) return TY_ObjCXX; - if (memcmp(Ext, "h", 1) == 0) return TY_CHeader; - if (memcmp(Ext, "C", 1) == 0) return TY_CXX; - if (memcmp(Ext, "H", 1) == 0) return TY_CXXHeader; - if (memcmp(Ext, "f", 1) == 0) return TY_PP_Fortran; - if (memcmp(Ext, "F", 1) == 0) return TY_Fortran; - if (memcmp(Ext, "s", 1) == 0) return TY_PP_Asm; - if (memcmp(Ext, "S", 1) == 0) return TY_Asm; - case 2: - if (memcmp(Ext, "ii", 2) == 0) return TY_PP_CXX; - if (memcmp(Ext, "mi", 2) == 0) return TY_PP_ObjC; - if (memcmp(Ext, "mm", 2) == 0) return TY_ObjCXX; - if (memcmp(Ext, "cc", 2) == 0) return TY_CXX; - if (memcmp(Ext, "cc", 2) == 0) return TY_CXX; - if (memcmp(Ext, "cp", 2) == 0) return TY_CXX; - if (memcmp(Ext, "hh", 2) == 0) return TY_CXXHeader; - break; - case 3: - if (memcmp(Ext, "ads", 3) == 0) return TY_Ada; - if (memcmp(Ext, "adb", 3) == 0) return TY_Ada; - if (memcmp(Ext, "ast", 3) == 0) return TY_AST; - if (memcmp(Ext, "cxx", 3) == 0) return TY_CXX; - if (memcmp(Ext, "cpp", 3) == 0) return TY_CXX; - if (memcmp(Ext, "CPP", 3) == 0) return TY_CXX; - if (memcmp(Ext, "cXX", 3) == 0) return TY_CXX; - if (memcmp(Ext, "for", 3) == 0) return TY_PP_Fortran; - if (memcmp(Ext, "FOR", 3) == 0) return TY_PP_Fortran; - if (memcmp(Ext, "fpp", 3) == 0) return TY_Fortran; - if (memcmp(Ext, "FPP", 3) == 0) return TY_Fortran; - if (memcmp(Ext, "f90", 3) == 0) return TY_PP_Fortran; - if (memcmp(Ext, "f95", 3) == 0) return TY_PP_Fortran; - if (memcmp(Ext, "F90", 3) == 0) return TY_Fortran; - if (memcmp(Ext, "F95", 3) == 0) return TY_Fortran; - if (memcmp(Ext, "mii", 3) == 0) return TY_PP_ObjCXX; - break; - } - - return TY_INVALID; + return llvm::StringSwitch<types::ID>(Ext) + .Case("c", TY_C) + .Case("i", TY_PP_C) + .Case("m", TY_ObjC) + .Case("M", TY_ObjCXX) + .Case("h", TY_CHeader) + .Case("C", TY_CXX) + .Case("H", TY_CXXHeader) + .Case("f", TY_PP_Fortran) + .Case("F", TY_Fortran) + .Case("s", TY_PP_Asm) + .Case("S", TY_Asm) + .Case("ii", TY_PP_CXX) + .Case("mi", TY_PP_ObjC) + .Case("mm", TY_ObjCXX) + .Case("cc", TY_CXX) + .Case("CC", TY_CXX) + .Case("cp", TY_CXX) + .Case("hh", TY_CXXHeader) + .Case("ads", TY_Ada) + .Case("adb", TY_Ada) + .Case("ast", TY_AST) + .Case("cxx", TY_CXX) + .Case("cpp", TY_CXX) + .Case("CPP", TY_CXX) + .Case("CXX", TY_CXX) + .Case("for", TY_PP_Fortran) + .Case("FOR", TY_PP_Fortran) + .Case("fpp", TY_Fortran) + .Case("FPP", TY_Fortran) + .Case("f90", TY_PP_Fortran) + .Case("f95", TY_PP_Fortran) + .Case("F90", TY_Fortran) + .Case("F95", TY_Fortran) + .Case("mii", TY_PP_ObjCXX) + .Default(TY_INVALID); } types::ID types::lookupTypeForTypeSpecifier(const char *Name) { diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp index 8d76680..9a30f59 100644 --- a/lib/Frontend/ASTConsumers.cpp +++ b/lib/Frontend/ASTConsumers.cpp @@ -400,11 +400,6 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "<parameter> " << PVD->getNameAsString() << "\n"; break; } - case Decl::OriginalParmVar: { - OriginalParmVarDecl* OPVD = cast<OriginalParmVarDecl>(*I); - Out << "<original parameter> " << OPVD->getNameAsString() << "\n"; - break; - } case Decl::ObjCProperty: { ObjCPropertyDecl* OPD = cast<ObjCPropertyDecl>(*I); Out << "<objc property> " << OPD->getNameAsString() << "\n"; @@ -457,6 +452,8 @@ class RecordLayoutDumper : public ASTConsumer { // Dump (non-virtual) bases for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { + assert(!I->getType()->isDependentType() && + "Cannot layout class with dependent bases."); if (I->isVirtual()) continue; diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp index 55f2740..049f3bd 100644 --- a/lib/Frontend/AnalysisConsumer.cpp +++ b/lib/Frontend/AnalysisConsumer.cpp @@ -29,7 +29,6 @@ #include "clang/Analysis/LocalCheckers.h" #include "clang/Analysis/PathSensitive/GRTransferFuncs.h" #include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index 25316be..c0b4eba 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -241,11 +241,9 @@ bool getVisualStudioDir(std::string &path) { return(false); } -void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, - const llvm::Triple &triple) { +void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple) { // FIXME: temporary hack: hard-coded paths. llvm::Triple::OSType os = triple.getOS(); - switch (os) { case llvm::Triple::Win32: { @@ -276,162 +274,186 @@ void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, } } break; - case llvm::Triple::Cygwin: - if (Lang.CPlusPlus) { - AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include", - System, false, false, false); - AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include/c++", - System, false, false, false); - } - AddPath("/usr/include", System, false, false, false); - break; case llvm::Triple::MinGW64: - if (Lang.CPlusPlus) { // I'm guessing here. - // Try gcc 4.4.0 - AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.4.0"); - // Try gcc 4.3.0 - AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.3.0"); - } - // Fall through. case llvm::Triple::MinGW32: - if (Lang.CPlusPlus) { - // Try gcc 4.4.0 - AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0"); - // Try gcc 4.3.0 - AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.3.0"); - } AddPath("c:/mingw/include", System, true, false, false); break; default: - if (Lang.CPlusPlus) { - switch (os) { - case llvm::Triple::Darwin: - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", - "i686-apple-darwin10", - "i686-apple-darwin10/x86_64", - triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0", - "i686-apple-darwin8", - "i686-apple-darwin8", - triple); - break; - case llvm::Triple::Linux: - // Ubuntu 7.10 - Gutsy Gibbon - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.3", - "i486-linux-gnu", - "i486-linux-gnu", - triple); - // Ubuntu 9.04 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.3", - "x86_64-linux-gnu/32", - "x86_64-linux-gnu", - triple); - // Fedora 8 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2", - "i386-redhat-linux", - "i386-redhat-linux", - triple); - // Fedora 9 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.0", - "i386-redhat-linux", - "i386-redhat-linux", - triple); - // Fedora 10 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2", - "i386-redhat-linux", - "i386-redhat-linux", - triple); - // openSUSE 11.1 32 bit - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "i586-suse-linux", - "i586-suse-linux", - triple); - // openSUSE 11.1 64 bit - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "x86_64-suse-linux/32", - "x86_64-suse-linux", - triple); - // openSUSE 11.2 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", - "i586-suse-linux", - "i586-suse-linux", - triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", - "x86_64-suse-linux", - "x86_64-suse-linux", - triple); - // Arch Linux 2008-06-24 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1", - "i686-pc-linux-gnu", - "i686-pc-linux-gnu", - triple); - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1", - "x86_64-unknown-linux-gnu", - "x86_64-unknown-linux-gnu", - triple); - // Gentoo x86 2009.1 stable - AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4", - "i686-pc-linux-gnu", - "i686-pc-linux-gnu", - triple); - // Gentoo x86 2009.0 stable - AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/i686-pc-linux-gnu/4.3.2/include/g++-v4", - "i686-pc-linux-gnu", - "i686-pc-linux-gnu", - triple); - // Gentoo x86 2008.0 stable - AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4", - "i686-pc-linux-gnu", - "i686-pc-linux-gnu", - triple); - // Ubuntu 8.10 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "i486-pc-linux-gnu", - "i486-pc-linux-gnu", - triple); - // Ubuntu 9.04 - AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", - "i486-linux-gnu", - "i486-linux-gnu", - triple); - // Gentoo amd64 stable - AddGnuCPlusPlusIncludePaths( - "/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4", - "i686-pc-linux-gnu", - "i686-pc-linux-gnu", - triple); - 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: - // Solaris - Fall though.. - case llvm::Triple::AuroraUX: - // AuroraUX - AddGnuCPlusPlusIncludePaths("/opt/gcc4/include/c++/4.2.4", - "i386-pc-solaris2.11", - "i386-pc-solaris2.11", - triple); - break; - default: - break; - } - } break; } AddPath("/usr/local/include", System, false, false, false); AddPath("/usr/include", System, false, false, false); +} + +void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { + llvm::Triple::OSType os = triple.getOS(); + // FIXME: temporary hack: hard-coded paths. + switch (os) { + case llvm::Triple::Cygwin: + AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include", + System, true, false, false); + AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include/c++", + System, true, false, false); + break; + case llvm::Triple::MinGW64: + // Try gcc 4.4.0 + AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.4.0"); + // Try gcc 4.3.0 + AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.3.0"); + // Fall through. + case llvm::Triple::MinGW32: + // Try gcc 4.4.0 + AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0"); + // Try gcc 4.3.0 + AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.3.0"); + break; + case llvm::Triple::Darwin: + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", + "i686-apple-darwin10", + "i686-apple-darwin10/x86_64", + triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0", + "i686-apple-darwin8", + "i686-apple-darwin8", + triple); + break; + case llvm::Triple::Linux: + // Ubuntu 7.10 - Gutsy Gibbon + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.3", + "i486-linux-gnu", + "i486-linux-gnu", + triple); + // Ubuntu 9.04 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.3", + "x86_64-linux-gnu/32", + "x86_64-linux-gnu", + triple); + // Fedora 8 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2", + "i386-redhat-linux", + "i386-redhat-linux", + triple); + // Fedora 9 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.0", + "i386-redhat-linux", + "i386-redhat-linux", + triple); + // Fedora 10 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2", + "i386-redhat-linux", + "i386-redhat-linux", + triple); + // openSUSE 11.1 32 bit + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", + "i586-suse-linux", + "i586-suse-linux", + triple); + // openSUSE 11.1 64 bit + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", + "x86_64-suse-linux/32", + "x86_64-suse-linux", + triple); + // openSUSE 11.2 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", + "i586-suse-linux", + "i586-suse-linux", + triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", + "x86_64-suse-linux", + "x86_64-suse-linux", + triple); + // Arch Linux 2008-06-24 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1", + "i686-pc-linux-gnu", + "i686-pc-linux-gnu", + triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1", + "x86_64-unknown-linux-gnu", + "x86_64-unknown-linux-gnu", + triple); + // Gentoo x86 2009.1 stable + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4", + "i686-pc-linux-gnu", + "i686-pc-linux-gnu", + triple); + // Gentoo x86 2009.0 stable + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/i686-pc-linux-gnu/4.3.2/include/g++-v4", + "i686-pc-linux-gnu", + "i686-pc-linux-gnu", + triple); + // Gentoo x86 2008.0 stable + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4", + "i686-pc-linux-gnu", + "i686-pc-linux-gnu", + triple); + // Ubuntu 8.10 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", + "i486-pc-linux-gnu", + "i486-pc-linux-gnu", + triple); + // Ubuntu 9.04 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", + "i486-linux-gnu", + "i486-linux-gnu", + triple); + // Gentoo amd64 stable + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4", + "i686-pc-linux-gnu", + "i686-pc-linux-gnu", + triple); + // Exherbo (2009-10-26) + AddGnuCPlusPlusIncludePaths( + "/usr/include/c++/4.4.2", + "x86_64-pc-linux-gnu/32", + "x86_64-pc-linux-gnu", + triple); + AddGnuCPlusPlusIncludePaths( + "/usr/include/c++/4.4.2", + "i686-pc-linux-gnu", + "i686-pc-linux-gnu", + triple); + 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: + // Solaris - Fall though.. + case llvm::Triple::AuroraUX: + // AuroraUX + AddGnuCPlusPlusIncludePaths("/opt/gcc4/include/c++/4.2.4", + "i386-pc-solaris2.11", + "i386-pc-solaris2.11", + triple); + break; + default: + break; + } +} + +void InitHeaderSearch::AddDefaultFrameworkIncludePaths(const llvm::Triple &triple) { + llvm::Triple::OSType os = triple.getOS(); + if (os != llvm::Triple::Darwin) + return; AddPath("/System/Library/Frameworks", System, true, false, true); AddPath("/Library/Frameworks", System, true, false, true); } +void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, + const llvm::Triple &triple) { + AddDefaultCIncludePaths(triple); + AddDefaultFrameworkIncludePaths(triple); + if (Lang.CPlusPlus) + AddDefaultCPlusPlusIncludePaths(triple); +} + void InitHeaderSearch::AddDefaultEnvVarPaths(const LangOptions &Lang) { AddEnvVarPaths("CPATH"); if (Lang.CPlusPlus && Lang.ObjC1) diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index b1a0a5e..ec5c106 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -17,8 +17,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/STLExtras.h" #include "llvm/System/Path.h" - -namespace clang { +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 @@ -346,27 +345,15 @@ static void InitializePredefinedMacros(const TargetInfo &TI, assert(TI.getCharWidth() == 8 && "Only support 8-bit char so far"); DefineBuiltinMacro(Buf, "__CHAR_BIT__=8"); - unsigned IntMaxWidth; - const char *IntMaxSuffix; - if (TI.getIntMaxType() == TargetInfo::SignedLongLong) { - IntMaxWidth = TI.getLongLongWidth(); - IntMaxSuffix = "LL"; - } else if (TI.getIntMaxType() == TargetInfo::SignedLong) { - IntMaxWidth = TI.getLongWidth(); - IntMaxSuffix = "L"; - } else { - assert(TI.getIntMaxType() == TargetInfo::SignedInt); - IntMaxWidth = TI.getIntWidth(); - IntMaxSuffix = ""; - } - DefineTypeSize("__SCHAR_MAX__", TI.getCharWidth(), "", true, Buf); DefineTypeSize("__SHRT_MAX__", TI.getShortWidth(), "", true, Buf); DefineTypeSize("__INT_MAX__", TI.getIntWidth(), "", true, Buf); DefineTypeSize("__LONG_MAX__", TI.getLongWidth(), "L", true, Buf); DefineTypeSize("__LONG_LONG_MAX__", TI.getLongLongWidth(), "LL", true, Buf); DefineTypeSize("__WCHAR_MAX__", TI.getWCharWidth(), "", true, Buf); - DefineTypeSize("__INTMAX_MAX__", IntMaxWidth, IntMaxSuffix, true, Buf); + TargetInfo::IntType IntMaxType = TI.getIntMaxType(); + DefineTypeSize("__INTMAX_MAX__", TI.getTypeWidth(IntMaxType), + TI.getTypeConstantSuffix(IntMaxType), true, Buf); DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Buf); DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Buf); @@ -455,8 +442,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI, /// InitializePreprocessor - Initialize the preprocessor getting it and the /// environment ready to process a single file. This returns true on error. /// -bool InitializePreprocessor(Preprocessor &PP, - const PreprocessorInitOptions& InitOpts) { +bool clang::InitializePreprocessor(Preprocessor &PP, + const PreprocessorInitOptions &InitOpts, + bool undef_macros) { std::vector<char> PredefineBuffer; const char *LineDirective = "# 1 \"<built-in>\" 3\n"; @@ -464,8 +452,9 @@ bool InitializePreprocessor(Preprocessor &PP, LineDirective, LineDirective+strlen(LineDirective)); // Install things like __POWERPC__, __GNUC__, etc into the macro table. - InitializePredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(), - PredefineBuffer); + if (!undef_macros) + InitializePredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(), + PredefineBuffer); // Add on the predefines from the driver. Wrap in a #line directive to report // that they come from the command line. @@ -504,5 +493,3 @@ bool InitializePreprocessor(Preprocessor &PP, // Once we've read this, we're done. return false; } - -} // namespace clang diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 9c6059b..26f426ba 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -32,6 +32,7 @@ #include "llvm/Bitcode/BitstreamReader.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/ErrorHandling.h" #include <algorithm> #include <iterator> #include <cstdio> @@ -2104,7 +2105,13 @@ void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc( } void TypeLocReader::VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setTemplateNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) + TL.setArgLocInfo(i, + Reader.GetTemplateArgumentLocInfo(TL.getTypePtr()->getArg(i).getKind(), + Record, Idx)); } void TypeLocReader::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); @@ -2197,6 +2204,25 @@ QualType PCHReader::GetType(pch::TypeID ID) { return TypesLoaded[Index].withFastQualifiers(FastQuals); } +TemplateArgumentLocInfo +PCHReader::GetTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, + const RecordData &Record, + unsigned &Index) { + switch (Kind) { + case TemplateArgument::Expression: + return ReadDeclExpr(); + case TemplateArgument::Type: + return GetDeclaratorInfo(Record, Index); + case TemplateArgument::Null: + case TemplateArgument::Integral: + case TemplateArgument::Declaration: + case TemplateArgument::Pack: + return TemplateArgumentLocInfo(); + } + llvm::llvm_unreachable("unexpected template argument loc"); + return TemplateArgumentLocInfo(); +} + Decl *PCHReader::GetDecl(pch::DeclID ID) { if (ID == 0) return 0; diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index d1cb461..b9ece21 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -52,7 +52,6 @@ namespace { void VisitVarDecl(VarDecl *VD); void VisitImplicitParamDecl(ImplicitParamDecl *PD); void VisitParmVarDecl(ParmVarDecl *PD); - void VisitOriginalParmVarDecl(OriginalParmVarDecl *PD); void VisitFileScopeAsmDecl(FileScopeAsmDecl *AD); void VisitBlockDecl(BlockDecl *BD); std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC); @@ -107,9 +106,9 @@ void PCHDeclReader::VisitTypedefDecl(TypedefDecl *TD) { // set the underlying type of the typedef *before* we try to read // the type associated with the TypedefDecl. VisitNamedDecl(TD); - TD->setUnderlyingType(Reader.GetType(Record[Idx + 1])); - TD->setTypeForDecl(Reader.GetType(Record[Idx]).getTypePtr()); - Idx += 2; + uint64_t TypeData = Record[Idx++]; + TD->setTypeDeclaratorInfo(Reader.GetDeclaratorInfo(Record, Idx)); + TD->setTypeForDecl(Reader.GetType(TypeData).getTypePtr()); } void PCHDeclReader::VisitTagDecl(TagDecl *TD) { @@ -163,7 +162,7 @@ void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) { FD->setPreviousDeclaration( cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++]))); FD->setStorageClass((FunctionDecl::StorageClass)Record[Idx++]); - FD->setInline(Record[Idx++]); + FD->setInlineSpecified(Record[Idx++]); FD->setVirtualAsWritten(Record[Idx++]); FD->setPure(Record[Idx++]); FD->setHasInheritedPrototype(Record[Idx++]); @@ -370,11 +369,6 @@ void PCHDeclReader::VisitParmVarDecl(ParmVarDecl *PD) { PD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]); } -void PCHDeclReader::VisitOriginalParmVarDecl(OriginalParmVarDecl *PD) { - VisitParmVarDecl(PD); - PD->setOriginalType(Reader.GetType(Record[Idx++])); -} - void PCHDeclReader::VisitFileScopeAsmDecl(FileScopeAsmDecl *AD) { VisitDecl(AD); AD->setAsmString(cast<StringLiteral>(Reader.ReadDeclExpr())); @@ -618,7 +612,7 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { D = Context->getTranslationUnitDecl(); break; case pch::DECL_TYPEDEF: - D = TypedefDecl::Create(*Context, 0, SourceLocation(), 0, QualType()); + D = TypedefDecl::Create(*Context, 0, SourceLocation(), 0, 0); break; case pch::DECL_ENUM: D = EnumDecl::Create(*Context, 0, SourceLocation(), 0, SourceLocation(), 0); @@ -696,10 +690,6 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { D = ParmVarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0, VarDecl::None, 0); break; - case pch::DECL_ORIGINAL_PARM_VAR: - D = OriginalParmVarDecl::Create(*Context, 0, SourceLocation(), 0, - QualType(),0, QualType(), VarDecl::None, 0); - break; case pch::DECL_FILE_SCOPE_ASM: D = FileScopeAsmDecl::Create(*Context, 0, SourceLocation(), 0); break; diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp index 4b9496e..01af67d 100644 --- a/lib/Frontend/PCHReaderStmt.cpp +++ b/lib/Frontend/PCHReaderStmt.cpp @@ -347,6 +347,8 @@ unsigned PCHStmtReader::VisitDeclRefExpr(DeclRefExpr *E) { VisitExpr(E); E->setDecl(cast<NamedDecl>(Reader.GetDecl(Record[Idx++]))); E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + // FIXME: read qualifier + // FIXME: read explicit template arguments return 0; } @@ -422,7 +424,7 @@ unsigned PCHStmtReader::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { E->setArgument(cast<Expr>(StmtStack.back())); ++Idx; } else { - E->setArgument(Reader.GetType(Record[Idx++])); + E->setArgument(Reader.GetDeclaratorInfo(Record, Idx)); } E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index fb48df3..de56166 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -368,7 +368,11 @@ void TypeLocWriter::VisitSubstTemplateTypeParmTypeLoc( } void TypeLocWriter::VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); + Writer.AddSourceLocation(TL.getTemplateNameLoc(), Record); + Writer.AddSourceLocation(TL.getLAngleLoc(), Record); + Writer.AddSourceLocation(TL.getRAngleLoc(), Record); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) + Writer.AddTemplateArgumentLoc(TL.getArgLoc(i), Record); } void TypeLocWriter::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); @@ -589,7 +593,6 @@ void PCHWriter::WriteBlockInfoBlock() { RECORD(DECL_VAR); RECORD(DECL_IMPLICIT_PARAM); RECORD(DECL_PARM_VAR); - RECORD(DECL_ORIGINAL_PARM_VAR); RECORD(DECL_FILE_SCOPE_ASM); RECORD(DECL_BLOCK); RECORD(DECL_CONTEXT_LEXICAL); @@ -2106,6 +2109,23 @@ void PCHWriter::AddSelectorRef(const Selector SelRef, RecordData &Record) { Record.push_back(SID); } +void PCHWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg, + RecordData &Record) { + switch (Arg.getArgument().getKind()) { + case TemplateArgument::Expression: + AddStmt(Arg.getLocInfo().getAsExpr()); + break; + case TemplateArgument::Type: + AddDeclaratorInfo(Arg.getLocInfo().getAsDeclaratorInfo(), Record); + break; + case TemplateArgument::Null: + case TemplateArgument::Integral: + case TemplateArgument::Declaration: + case TemplateArgument::Pack: + break; + } +} + void PCHWriter::AddDeclaratorInfo(DeclaratorInfo *DInfo, RecordData &Record) { if (DInfo == 0) { AddTypeRef(QualType(), Record); diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index fbd9929..8997e66 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -55,7 +55,6 @@ namespace { void VisitVarDecl(VarDecl *D); void VisitImplicitParamDecl(ImplicitParamDecl *D); void VisitParmVarDecl(ParmVarDecl *D); - void VisitOriginalParmVarDecl(OriginalParmVarDecl *D); void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); void VisitBlockDecl(BlockDecl *D); void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, @@ -107,7 +106,7 @@ void PCHDeclWriter::VisitTypeDecl(TypeDecl *D) { void PCHDeclWriter::VisitTypedefDecl(TypedefDecl *D) { VisitTypeDecl(D); - Writer.AddTypeRef(D->getUnderlyingType(), Record); + Writer.AddDeclaratorInfo(D->getTypeDeclaratorInfo(), Record); Code = pch::DECL_TYPEDEF; } @@ -162,7 +161,7 @@ void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) { Writer.AddStmt(D->getBody()); Writer.AddDeclRef(D->getPreviousDeclaration(), Record); Record.push_back(D->getStorageClass()); // FIXME: stable encoding - Record.push_back(D->isInline()); + Record.push_back(D->isInlineSpecified()); Record.push_back(D->isVirtualAsWritten()); Record.push_back(D->isPure()); Record.push_back(D->hasInheritedPrototype()); @@ -390,13 +389,6 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { assert(D->getInit() == 0 && "PARM_VAR_DECL never has init"); } -void PCHDeclWriter::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) { - VisitParmVarDecl(D); - Writer.AddTypeRef(D->getOriginalType(), Record); - Code = pch::DECL_ORIGINAL_PARM_VAR; - AbbrevToUse = 0; -} - void PCHDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { VisitDecl(D); Writer.AddStmt(D->getAsmString()); diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp index 9497f97..78a56db 100644 --- a/lib/Frontend/PCHWriterStmt.cpp +++ b/lib/Frontend/PCHWriterStmt.cpp @@ -314,6 +314,8 @@ void PCHStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) { VisitExpr(E); Writer.AddDeclRef(E->getDecl(), Record); Writer.AddSourceLocation(E->getLocation(), Record); + // FIXME: write qualifier + // FIXME: write explicit template arguments Code = pch::EXPR_DECL_REF; } @@ -382,7 +384,7 @@ void PCHStmtWriter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { VisitExpr(E); Record.push_back(E->isSizeOf()); if (E->isArgumentType()) - Writer.AddTypeRef(E->getArgumentType(), Record); + Writer.AddDeclaratorInfo(E->getArgumentTypeInfo(), Record); else { Record.push_back(0); Writer.WriteSubStmt(E->getArgumentExpr()); diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index f3cb206..630a093 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -66,7 +66,7 @@ static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI, OS << ' '; // Make sure we have enough space in the spelling buffer. - if (I->getLength() < SpellingBuffer.size()) + if (I->getLength() > SpellingBuffer.size()) SpellingBuffer.resize(I->getLength()); const char *Buffer = SpellingBuffer.data(); unsigned SpellingLen = PP.getSpelling(*I, Buffer); diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index 0ea0a58..24ad69e 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -2569,7 +2569,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { // Build sizeof(returnType) SizeOfAlignOfExpr *sizeofExpr = new (Context) SizeOfAlignOfExpr(true, - returnType, + Context->getTrivialDeclaratorInfo(returnType), Context->getSizeType(), SourceLocation(), SourceLocation()); // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) @@ -2609,10 +2609,12 @@ Stmt *RewriteObjC::RewriteMessageExpr(ObjCMessageExpr *Exp) { // typedef struct objc_object Protocol; QualType RewriteObjC::getProtocolType() { if (!ProtocolTypeDecl) { + DeclaratorInfo *DInfo + = Context->getTrivialDeclaratorInfo(Context->getObjCIdType()); ProtocolTypeDecl = TypedefDecl::Create(*Context, TUDecl, SourceLocation(), &Context->Idents.get("Protocol"), - Context->getObjCIdType()); + DInfo); } return Context->getTypeDeclType(ProtocolTypeDecl); } diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 14769c1..b1d8800 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -13,6 +13,7 @@ #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Basic/SourceManager.h" +#include "clang/Frontend/DiagnosticOptions.h" #include "clang/Lex/Lexer.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" @@ -37,6 +38,12 @@ static const enum llvm::raw_ostream::Colors savedColor = /// \brief Number of spaces to indent when word-wrapping. const unsigned WordWrapIndentation = 6; +TextDiagnosticPrinter::TextDiagnosticPrinter(llvm::raw_ostream &os, + const DiagnosticOptions &diags) + : OS(os), LangOpts(0), DiagOpts(&diags), + LastCaretDiagnosticWasNote(false) { +} + void TextDiagnosticPrinter:: PrintIncludeStack(SourceLocation Loc, const SourceManager &SM) { if (Loc.isInvalid()) return; @@ -46,7 +53,7 @@ PrintIncludeStack(SourceLocation Loc, const SourceManager &SM) { // Print out the other include frames first. PrintIncludeStack(PLoc.getIncludeLoc(), SM); - if (ShowLocation) + if (DiagOpts->ShowLocation) OS << "In file included from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n"; else @@ -281,13 +288,13 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, Ranges[i] = SourceRange(S, E); } - if (ShowLocation) { + if (DiagOpts->ShowLocation) { std::pair<FileID, unsigned> IInfo = SM.getDecomposedInstantiationLoc(Loc); // Emit the file/line/column that this expansion came from. OS << SM.getBuffer(IInfo.first)->getBufferIdentifier() << ':' << SM.getLineNumber(IInfo.first, IInfo.second) << ':'; - if (ShowColumn) + if (DiagOpts->ShowColumn) OS << SM.getColumnNumber(IInfo.first, IInfo.second) << ':'; OS << ' '; } @@ -370,13 +377,13 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, // produce easily machine parsable output. Add a space before the source line // and the caret to make it trivial to tell the main diagnostic line from what // the user is intended to see. - if (PrintRangeInfo) { + if (DiagOpts->ShowSourceRanges) { SourceLine = ' ' + SourceLine; CaretLine = ' ' + CaretLine; } std::string FixItInsertionLine; - if (NumHints && PrintFixItInfo) { + if (NumHints && DiagOpts->ShowFixits) { for (const CodeModificationHint *Hint = Hints, *LastHint = Hints + NumHints; Hint != LastHint; ++Hint) { if (Hint->InsertionLoc.isValid()) { @@ -417,20 +424,20 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, // Emit what we have computed. OS << SourceLine << '\n'; - if (UseColors) + if (DiagOpts->ShowColors) OS.changeColor(caretColor, true); OS << CaretLine << '\n'; - if (UseColors) + if (DiagOpts->ShowColors) OS.resetColor(); if (!FixItInsertionLine.empty()) { - if (UseColors) + if (DiagOpts->ShowColors) // Print fixit line in color OS.changeColor(fixitColor, false); - if (PrintRangeInfo) + if (DiagOpts->ShowSourceRanges) OS << ' '; OS << FixItInsertionLine << '\n'; - if (UseColors) + if (DiagOpts->ShowColors) OS.resetColor(); } } @@ -627,15 +634,15 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, } // Compute the column number. - if (ShowLocation) { - if (UseColors) + if (DiagOpts->ShowLocation) { + if (DiagOpts->ShowColors) OS.changeColor(savedColor, true); OS << PLoc.getFilename() << ':' << LineNo << ':'; - if (ShowColumn) + if (DiagOpts->ShowColumn) if (unsigned ColNo = PLoc.getColumn()) OS << ColNo << ':'; - if (PrintRangeInfo && Info.getNumRanges()) { + if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) { FileID CaretFileID = SM.getFileID(SM.getInstantiationLoc(Info.getLocation())); bool PrintedRange = false; @@ -679,12 +686,12 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, OS << ':'; } OS << ' '; - if (UseColors) + if (DiagOpts->ShowColors) OS.resetColor(); } } - if (UseColors) { + if (DiagOpts->ShowColors) { // Print diagnostic category in bold and color switch (Level) { case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type"); @@ -703,20 +710,20 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, case Diagnostic::Fatal: OS << "fatal error: "; break; } - if (UseColors) + if (DiagOpts->ShowColors) OS.resetColor(); llvm::SmallString<100> OutStr; Info.FormatDiagnostic(OutStr); - if (PrintDiagnosticOption) + if (DiagOpts->ShowOptionNames) if (const char *Opt = Diagnostic::getWarningOptionForDiag(Info.getID())) { OutStr += " [-W"; OutStr += Opt; OutStr += ']'; } - if (UseColors) { + if (DiagOpts->ShowColors) { // Print warnings, errors and fatal errors in bold, no color switch (Level) { case Diagnostic::Warning: OS.changeColor(savedColor, true); break; @@ -726,17 +733,17 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, } } - if (MessageLength) { + if (DiagOpts->MessageLength) { // We will be word-wrapping the error message, so compute the // column number where we currently are (after printing the // location information). unsigned Column = OS.tell() - StartOfLocationInfo; - PrintWordWrapped(OS, OutStr, MessageLength, Column); + PrintWordWrapped(OS, OutStr, DiagOpts->MessageLength, Column); } else { OS.write(OutStr.begin(), OutStr.size()); } OS << '\n'; - if (UseColors) + if (DiagOpts->ShowColors) OS.resetColor(); // If caret diagnostics are enabled and we have location, we want to @@ -745,7 +752,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, // was part of a different warning or error diagnostic, or if the // diagnostic has ranges. We don't want to emit the same caret // multiple times if one loc has multiple diagnostics. - if (CaretDiagnostics && Info.getLocation().isValid() && + if (DiagOpts->ShowCarets && Info.getLocation().isValid() && ((LastLoc != Info.getLocation()) || Info.getNumRanges() || (LastCaretDiagnosticWasNote && Level != Diagnostic::Note) || Info.getNumCodeModificationHints())) { @@ -772,7 +779,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, EmitCaretDiagnostic(LastLoc, Ranges, NumRanges, LastLoc.getManager(), Info.getCodeModificationHints(), Info.getNumCodeModificationHints(), - MessageLength); + DiagOpts->MessageLength); } OS.flush(); diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt index 6c874f4..e63291b 100644 --- a/lib/Headers/CMakeLists.txt +++ b/lib/Headers/CMakeLists.txt @@ -35,4 +35,4 @@ add_custom_target(clang-headers ALL install(FILES ${files} PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ - DESTINATION lib/clang/${CLANG_VERSION}/include) + DESTINATION lib${LLVM_LIBDIR_SUFFIX}/clang/${CLANG_VERSION}/include) diff --git a/lib/Headers/stdint.h b/lib/Headers/stdint.h index a7020d8..f79a0f4 100644 --- a/lib/Headers/stdint.h +++ b/lib/Headers/stdint.h @@ -28,7 +28,8 @@ /* If we're hosted, fall back to the system's stdint.h, which might have * additional definitions. */ -#if __STDC_HOSTED__ +#if __STDC_HOSTED__ && \ + defined(__has_include_next) && __has_include_next(<stdint.h>) # include_next <stdint.h> #else diff --git a/lib/Index/ResolveLocation.cpp b/lib/Index/ResolveLocation.cpp index 8edd634..73b584b 100644 --- a/lib/Index/ResolveLocation.cpp +++ b/lib/Index/ResolveLocation.cpp @@ -45,6 +45,9 @@ protected: if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) if (ContainsLocation(DD->getDeclaratorInfo())) return ContainsLoc; + if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) + if (ContainsLocation(TD->getTypeDeclaratorInfo())) + return ContainsLoc; return CheckRange(D->getSourceRange()); } @@ -57,11 +60,6 @@ protected: } template <typename T> - bool ContainsLocation(T Node) { - return CheckRange(Node) == ContainsLoc; - } - - template <typename T> bool isAfterLocation(T Node) { return CheckRange(Node) == AfterLoc; } @@ -69,6 +67,11 @@ protected: public: LocResolverBase(ASTContext &ctx, SourceLocation loc) : Ctx(ctx), Loc(loc) {} + + template <typename T> + bool ContainsLocation(T Node) { + return CheckRange(Node) == ContainsLoc; + } #ifndef NDEBUG /// \brief Debugging output. @@ -89,6 +92,7 @@ public: StmtLocResolver(ASTContext &ctx, SourceLocation loc, Decl *parent) : LocResolverBase(ctx, loc), Parent(parent) {} + ASTLocation VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node); ASTLocation VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node); ASTLocation VisitDeclStmt(DeclStmt *Node); ASTLocation VisitStmt(Stmt *Node); @@ -109,6 +113,7 @@ public: ASTLocation VisitVarDecl(VarDecl *D); ASTLocation VisitFunctionDecl(FunctionDecl *D); ASTLocation VisitObjCMethodDecl(ObjCMethodDecl *D); + ASTLocation VisitTypedefDecl(TypedefDecl *D); ASTLocation VisitDecl(Decl *D); }; @@ -132,6 +137,25 @@ public: } // anonymous namespace ASTLocation +StmtLocResolver::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { + assert(ContainsLocation(Node) && + "Should visit only after verifying that loc is in range"); + + if (Node->isArgumentType()) { + DeclaratorInfo *DInfo = Node->getArgumentTypeInfo(); + if (ContainsLocation(DInfo)) + return ResolveInDeclarator(Parent, Node, DInfo); + } else { + Expr *SubNode = Node->getArgumentExpr(); + if (ContainsLocation(SubNode)) + return Visit(SubNode); + } + + return ASTLocation(Parent, Node); +} + + +ASTLocation StmtLocResolver::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) { assert(ContainsLocation(Node) && "Should visit only after verifying that loc is in range"); @@ -278,6 +302,16 @@ ASTLocation DeclLocResolver::VisitDeclaratorDecl(DeclaratorDecl *D) { return ASTLocation(D); } +ASTLocation DeclLocResolver::VisitTypedefDecl(TypedefDecl *D) { + assert(ContainsLocation(D) && + "Should visit only after verifying that loc is in range"); + + if (ContainsLocation(D->getTypeDeclaratorInfo())) + return ResolveInDeclarator(D, /*Stmt=*/0, D->getTypeDeclaratorInfo()); + + return ASTLocation(D); +} + ASTLocation DeclLocResolver::VisitVarDecl(VarDecl *D) { assert(ContainsLocation(D) && "Should visit only after verifying that loc is in range"); @@ -529,11 +563,40 @@ void LocResolverBase::print(Stmt *Node) { /// \brief Returns the AST node that a source location points to. /// ASTLocation idx::ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc, - Decl *RelativeToDecl) { + ASTLocation *LastLoc) { if (Loc.isInvalid()) return ASTLocation(); - if (RelativeToDecl) - return DeclLocResolver(Ctx, Loc).Visit(RelativeToDecl); + if (LastLoc && LastLoc->isValid()) { + DeclContext *DC = 0; + + if (Decl *Dcl = LastLoc->dyn_AsDecl()) { + DC = Dcl->getDeclContext(); + } else if (LastLoc->isStmt()) { + Decl *Parent = LastLoc->getParentDecl(); + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Parent)) + DC = FD; + else { + // This is needed to handle statements within an initializer. + // Example: + // void func() { long double fabsf = __builtin_fabsl(__x); } + // In this case, the 'parent' of __builtin_fabsl is fabsf. + DC = Parent->getDeclContext(); + } + } else { // We have 'N_NamedRef' or 'N_Type' + DC = LastLoc->getParentDecl()->getDeclContext(); + } + assert(DC && "Missing DeclContext"); + + FunctionDecl *FD = dyn_cast<FunctionDecl>(DC); + DeclLocResolver DLocResolver(Ctx, Loc); + + if (FD && FD->isThisDeclarationADefinition() && + DLocResolver.ContainsLocation(FD)) { + return DLocResolver.VisitFunctionDecl(FD); + } + // Fall through and try the slow path... + // FIXME: Optimize more cases. + } return DeclLocResolver(Ctx, Loc).Visit(Ctx.getTranslationUnitDecl()); } diff --git a/lib/Lex/HeaderMap.cpp b/lib/Lex/HeaderMap.cpp index c9a10dc..df71276 100644 --- a/lib/Lex/HeaderMap.cpp +++ b/lib/Lex/HeaderMap.cpp @@ -15,7 +15,7 @@ #include "clang/Basic/FileManager.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/System/DataTypes.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include <cstdio> diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index e264efa..dc7d95e 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -974,11 +974,11 @@ bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc, /// This code concatenates and consumes tokens up to the '>' token. It returns /// false if the > was found, otherwise it returns true if it finds and consumes /// the EOM marker. -static bool ConcatenateIncludeName(llvm::SmallVector<char, 128> &FilenameBuffer, - Preprocessor &PP) { +bool Preprocessor::ConcatenateIncludeName( + llvm::SmallVector<char, 128> &FilenameBuffer) { Token CurTok; - PP.Lex(CurTok); + Lex(CurTok); while (CurTok.isNot(tok::eom)) { // Append the spelling of this token to the buffer. If there was a space // before it, add it now. @@ -990,7 +990,7 @@ static bool ConcatenateIncludeName(llvm::SmallVector<char, 128> &FilenameBuffer, FilenameBuffer.resize(PreAppendSize+CurTok.getLength()); const char *BufPtr = &FilenameBuffer[PreAppendSize]; - unsigned ActualLen = PP.getSpelling(CurTok, BufPtr); + unsigned ActualLen = getSpelling(CurTok, BufPtr); // If the token was spelled somewhere else, copy it into FilenameBuffer. if (BufPtr != &FilenameBuffer[PreAppendSize]) @@ -1004,12 +1004,12 @@ static bool ConcatenateIncludeName(llvm::SmallVector<char, 128> &FilenameBuffer, if (CurTok.is(tok::greater)) return false; - PP.Lex(CurTok); + Lex(CurTok); } // If we hit the eom marker, emit an error and return true so that the caller // knows the EOM has been read. - PP.Diag(CurTok.getLocation(), diag::err_pp_expects_filename); + Diag(CurTok.getLocation(), diag::err_pp_expects_filename); return true; } @@ -1047,7 +1047,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok, // This could be a <foo/bar.h> file coming from a macro expansion. In this // case, glue the tokens together into FilenameBuffer and interpret those. FilenameBuffer.push_back('<'); - if (ConcatenateIncludeName(FilenameBuffer, *this)) + if (ConcatenateIncludeName(FilenameBuffer)) return; // Found <eom> but no ">"? Diagnostic already emitted. FilenameStart = FilenameBuffer.data(); FilenameEnd = FilenameStart + FilenameBuffer.size(); diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp index 908385c..a74396c 100644 --- a/lib/Lex/PPExpressions.cpp +++ b/lib/Lex/PPExpressions.cpp @@ -71,6 +71,61 @@ struct DefinedTracker { IdentifierInfo *TheMacro; }; +/// EvaluateDefined - Process a 'defined(sym)' expression. +static bool EvaluateDefined(PPValue &Result, Token &PeekTok, + DefinedTracker &DT, bool ValueLive, Preprocessor &PP) { + IdentifierInfo *II; + Result.setBegin(PeekTok.getLocation()); + + // Get the next token, don't expand it. + PP.LexUnexpandedToken(PeekTok); + + // Two options, it can either be a pp-identifier or a (. + SourceLocation LParenLoc; + if (PeekTok.is(tok::l_paren)) { + // Found a paren, remember we saw it and skip it. + LParenLoc = PeekTok.getLocation(); + PP.LexUnexpandedToken(PeekTok); + } + + // If we don't have a pp-identifier now, this is an error. + if ((II = PeekTok.getIdentifierInfo()) == 0) { + PP.Diag(PeekTok, diag::err_pp_defined_requires_identifier); + return true; + } + + // Otherwise, we got an identifier, is it defined to something? + Result.Val = II->hasMacroDefinition(); + Result.Val.setIsUnsigned(false); // Result is signed intmax_t. + + // If there is a macro, mark it used. + if (Result.Val != 0 && ValueLive) { + MacroInfo *Macro = PP.getMacroInfo(II); + Macro->setIsUsed(true); + } + + // Consume identifier. + Result.setEnd(PeekTok.getLocation()); + PP.LexNonComment(PeekTok); + + // If we are in parens, ensure we have a trailing ). + if (LParenLoc.isValid()) { + if (PeekTok.isNot(tok::r_paren)) { + PP.Diag(PeekTok.getLocation(), diag::err_pp_missing_rparen) << "defined"; + PP.Diag(LParenLoc, diag::note_matching) << "("; + return true; + } + // Consume the ). + Result.setEnd(PeekTok.getLocation()); + PP.LexNonComment(PeekTok); + } + + // Success, remember that we saw defined(X). + DT.State = DefinedTracker::DefinedMacro; + DT.TheMacro = II; + return false; +} + /// EvaluateValue - Evaluate the token PeekTok (and any others needed) and /// return the computed value in Result. Return true if there was an error /// parsing. This function also returns information about the form of the @@ -87,10 +142,14 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, // 'defined' or if it is a macro. Note that we check here because many // keywords are pp-identifiers, so we can't check the kind. if (IdentifierInfo *II = PeekTok.getIdentifierInfo()) { - // If this identifier isn't 'defined' and it wasn't macro expanded, it turns - // into a simple 0, unless it is the C++ keyword "true", in which case it - // turns into "1". - if (!II->isStr("defined")) { + if (II->isStr("defined")) { + // Handle "defined X" and "defined(X)". + return(EvaluateDefined(Result, PeekTok, DT, ValueLive, PP)); + } else { + // If this identifier isn't 'defined' or one of the special + // preprocessor keywords and it wasn't macro expanded, it turns + // into a simple 0, unless it is the C++ keyword "true", in which case it + // turns into "1". if (ValueLive) PP.Diag(PeekTok, diag::warn_pp_undef_identifier) << II; Result.Val = II->getTokenID() == tok::kw_true; @@ -99,57 +158,6 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, PP.LexNonComment(PeekTok); return false; } - - // Handle "defined X" and "defined(X)". - Result.setBegin(PeekTok.getLocation()); - - // Get the next token, don't expand it. - PP.LexUnexpandedToken(PeekTok); - - // Two options, it can either be a pp-identifier or a (. - SourceLocation LParenLoc; - if (PeekTok.is(tok::l_paren)) { - // Found a paren, remember we saw it and skip it. - LParenLoc = PeekTok.getLocation(); - PP.LexUnexpandedToken(PeekTok); - } - - // If we don't have a pp-identifier now, this is an error. - if ((II = PeekTok.getIdentifierInfo()) == 0) { - PP.Diag(PeekTok, diag::err_pp_defined_requires_identifier); - return true; - } - - // Otherwise, we got an identifier, is it defined to something? - Result.Val = II->hasMacroDefinition(); - Result.Val.setIsUnsigned(false); // Result is signed intmax_t. - - // If there is a macro, mark it used. - if (Result.Val != 0 && ValueLive) { - MacroInfo *Macro = PP.getMacroInfo(II); - Macro->setIsUsed(true); - } - - // Consume identifier. - Result.setEnd(PeekTok.getLocation()); - PP.LexNonComment(PeekTok); - - // If we are in parens, ensure we have a trailing ). - if (LParenLoc.isValid()) { - if (PeekTok.isNot(tok::r_paren)) { - PP.Diag(PeekTok.getLocation(), diag::err_pp_missing_rparen); - PP.Diag(LParenLoc, diag::note_matching) << "("; - return true; - } - // Consume the ). - Result.setEnd(PeekTok.getLocation()); - PP.LexNonComment(PeekTok); - } - - // Success, remember that we saw defined(X). - DT.State = DefinedTracker::DefinedMacro; - DT.TheMacro = II; - return false; } switch (PeekTok.getKind()) { diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 7ddf215..699b701 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -64,8 +64,10 @@ void Preprocessor::RegisterBuiltinMacros() { Ident__TIMESTAMP__ = RegisterBuiltinMacro(*this, "__TIMESTAMP__"); // Clang Extensions. - Ident__has_feature = RegisterBuiltinMacro(*this, "__has_feature"); - Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin"); + Ident__has_feature = RegisterBuiltinMacro(*this, "__has_feature"); + Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin"); + Ident__has_include = RegisterBuiltinMacro(*this, "__has_include"); + Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next"); } /// isTrivialSingleTokenExpansion - Return true if MI, which has a single token @@ -503,6 +505,117 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { } } +/// EvaluateHasIncludeCommon - Process a '__has_include("path")' +/// or '__has_include_next("path")' expression. +/// Returns true if successful. +static bool EvaluateHasIncludeCommon(bool &Result, Token &Tok, + IdentifierInfo *II, Preprocessor &PP, + const DirectoryLookup *LookupFrom) { + SourceLocation LParenLoc; + + // Get '('. + PP.LexNonComment(Tok); + + // Ensure we have a '('. + if (Tok.isNot(tok::l_paren)) { + PP.Diag(Tok.getLocation(), diag::err_pp_missing_lparen) << II->getName(); + return false; + } + + // Save '(' location for possible missing ')' message. + LParenLoc = Tok.getLocation(); + + // Get the file name. + PP.getCurrentLexer()->LexIncludeFilename(Tok); + + // Reserve a buffer to get the spelling. + llvm::SmallVector<char, 128> FilenameBuffer; + const char *FilenameStart, *FilenameEnd; + + switch (Tok.getKind()) { + case tok::eom: + // If the token kind is EOM, the error has already been diagnosed. + return false; + + case tok::angle_string_literal: + case tok::string_literal: { + FilenameBuffer.resize(Tok.getLength()); + FilenameStart = &FilenameBuffer[0]; + unsigned Len = PP.getSpelling(Tok, FilenameStart); + FilenameEnd = FilenameStart+Len; + break; + } + + case tok::less: + // This could be a <foo/bar.h> file coming from a macro expansion. In this + // case, glue the tokens together into FilenameBuffer and interpret those. + FilenameBuffer.push_back('<'); + if (PP.ConcatenateIncludeName(FilenameBuffer)) + return false; // Found <eom> but no ">"? Diagnostic already emitted. + FilenameStart = FilenameBuffer.data(); + FilenameEnd = FilenameStart + FilenameBuffer.size(); + break; + default: + PP.Diag(Tok.getLocation(), diag::err_pp_expects_filename); + return false; + } + + bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), + FilenameStart, FilenameEnd); + // If GetIncludeFilenameSpelling set the start ptr to null, there was an + // error. + if (FilenameStart == 0) { + return false; + } + + // Search include directories. + const DirectoryLookup *CurDir; + const FileEntry *File = PP.LookupFile(FilenameStart, FilenameEnd, + isAngled, LookupFrom, CurDir); + + // Get the result value. Result = true means the file exists. + Result = File != 0; + + // Get ')'. + PP.LexNonComment(Tok); + + // Ensure we have a trailing ). + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Tok.getLocation(), diag::err_pp_missing_rparen) << II->getName(); + PP.Diag(LParenLoc, diag::note_matching) << "("; + return false; + } + + return true; +} + +/// EvaluateHasInclude - Process a '__has_include("path")' expression. +/// Returns true if successful. +static bool EvaluateHasInclude(bool &Result, Token &Tok, IdentifierInfo *II, + Preprocessor &PP) { + return(EvaluateHasIncludeCommon(Result, Tok, II, PP, NULL)); +} + +/// EvaluateHasIncludeNext - Process '__has_include_next("path")' expression. +/// Returns true if successful. +static bool EvaluateHasIncludeNext(bool &Result, Token &Tok, + IdentifierInfo *II, Preprocessor &PP) { + // __has_include_next is like __has_include, except that we start + // searching after the current found directory. If we can't do this, + // issue a diagnostic. + const DirectoryLookup *Lookup = PP.GetCurDirLookup(); + if (PP.isInPrimaryFile()) { + Lookup = 0; + PP.Diag(Tok, diag::pp_include_next_in_primary); + } else if (Lookup == 0) { + PP.Diag(Tok, diag::pp_include_next_absolute_path); + } else { + // Start looking up in the next directory. + ++Lookup; + } + + return(EvaluateHasIncludeCommon(Result, Tok, II, PP, Lookup)); +} /// ExpandBuiltinMacro - If an identifier token is read that is to be expanded /// as a builtin macro, handle it and return the next token as 'Tok'. @@ -671,6 +784,20 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { sprintf(TmpBuffer, "%d", (int)Value); Tok.setKind(tok::numeric_constant); CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation()); + } else if (II == Ident__has_include || + II == Ident__has_include_next) { + // The argument to these two builtins should be a parenthesized + // file name string literal using angle brackets (<>) or + // double-quotes (""). + bool Value = false; + bool IsValid; + if (II == Ident__has_include) + IsValid = EvaluateHasInclude(Value, Tok, II, *this); + else + IsValid = EvaluateHasIncludeNext(Value, Tok, II, *this); + sprintf(TmpBuffer, "%d", (int)Value); + Tok.setKind(tok::numeric_constant); + CreateString(TmpBuffer, strlen(TmpBuffer), Tok, Tok.getLocation()); } else { assert(0 && "Unknown identifier!"); } diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp index 224a31c..344ce9e 100644 --- a/lib/Parse/AttributeList.cpp +++ b/lib/Parse/AttributeList.cpp @@ -13,6 +13,7 @@ #include "clang/Parse/AttributeList.h" #include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/StringSwitch.h" using namespace clang; AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc, @@ -52,94 +53,58 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { AttrName = AttrName.substr(2, AttrName.size() - 4); // FIXME: Hand generating this is neither smart nor efficient. - const char *Str = AttrName.data(); - switch (AttrName.size()) { - case 4: - if (!memcmp(Str, "weak", 4)) return AT_weak; - if (!memcmp(Str, "pure", 4)) return AT_pure; - if (!memcmp(Str, "mode", 4)) return AT_mode; - if (!memcmp(Str, "used", 4)) return AT_used; - break; - case 5: - if (!memcmp(Str, "alias", 5)) return AT_alias; - if (!memcmp(Str, "const", 5)) return AT_const; - break; - case 6: - if (!memcmp(Str, "packed", 6)) return AT_packed; - if (!memcmp(Str, "malloc", 6)) return AT_malloc; - if (!memcmp(Str, "format", 6)) return AT_format; - if (!memcmp(Str, "unused", 6)) return AT_unused; - if (!memcmp(Str, "blocks", 6)) return AT_blocks; - break; - case 7: - if (!memcmp(Str, "aligned", 7)) return AT_aligned; - if (!memcmp(Str, "cleanup", 7)) return AT_cleanup; - if (!memcmp(Str, "nodebug", 7)) return AT_nodebug; - if (!memcmp(Str, "nonnull", 7)) return AT_nonnull; - if (!memcmp(Str, "nothrow", 7)) return AT_nothrow; - if (!memcmp(Str, "objc_gc", 7)) return AT_objc_gc; - if (!memcmp(Str, "regparm", 7)) return AT_regparm; - if (!memcmp(Str, "section", 7)) return AT_section; - if (!memcmp(Str, "stdcall", 7)) return AT_stdcall; - break; - case 8: - if (!memcmp(Str, "annotate", 8)) return AT_annotate; - if (!memcmp(Str, "noreturn", 8)) return AT_noreturn; - if (!memcmp(Str, "noinline", 8)) return AT_noinline; - if (!memcmp(Str, "fastcall", 8)) return AT_fastcall; - if (!memcmp(Str, "iboutlet", 8)) return AT_IBOutlet; - if (!memcmp(Str, "sentinel", 8)) return AT_sentinel; - if (!memcmp(Str, "NSObject", 8)) return AT_nsobject; - break; - case 9: - if (!memcmp(Str, "dllimport", 9)) return AT_dllimport; - if (!memcmp(Str, "dllexport", 9)) return AT_dllexport; - if (!memcmp(Str, "may_alias", 9)) return IgnoredAttribute; // FIXME: TBAA - break; - case 10: - if (!memcmp(Str, "deprecated", 10)) return AT_deprecated; - if (!memcmp(Str, "visibility", 10)) return AT_visibility; - if (!memcmp(Str, "destructor", 10)) return AT_destructor; - if (!memcmp(Str, "format_arg", 10)) return AT_format_arg; - if (!memcmp(Str, "gnu_inline", 10)) return AT_gnu_inline; - break; - case 11: - if (!memcmp(Str, "weak_import", 11)) return AT_weak_import; - if (!memcmp(Str, "vector_size", 11)) return AT_vector_size; - if (!memcmp(Str, "constructor", 11)) return AT_constructor; - if (!memcmp(Str, "unavailable", 11)) return AT_unavailable; - break; - case 12: - if (!memcmp(Str, "overloadable", 12)) return AT_overloadable; - break; - case 13: - if (!memcmp(Str, "address_space", 13)) return AT_address_space; - if (!memcmp(Str, "always_inline", 13)) return AT_always_inline; - if (!memcmp(Str, "vec_type_hint", 13)) return IgnoredAttribute; - break; - case 14: - if (!memcmp(Str, "objc_exception", 14)) return AT_objc_exception; - break; - case 15: - if (!memcmp(Str, "ext_vector_type", 15)) return AT_ext_vector_type; - break; - case 17: - if (!memcmp(Str, "transparent_union", 17)) return AT_transparent_union; - if (!memcmp(Str, "analyzer_noreturn", 17)) return AT_analyzer_noreturn; - break; - case 18: - if (!memcmp(Str, "warn_unused_result", 18)) return AT_warn_unused_result; - break; - case 19: - if (!memcmp(Str, "ns_returns_retained", 19)) return AT_ns_returns_retained; - if (!memcmp(Str, "cf_returns_retained", 19)) return AT_cf_returns_retained; - break; - case 20: - if (!memcmp(Str, "reqd_work_group_size", 20)) return AT_reqd_wg_size; - case 22: - if (!memcmp(Str, "no_instrument_function", 22)) - return AT_no_instrument_function; - break; - } - return UnknownAttribute; + return llvm::StringSwitch<AttributeList::Kind>(AttrName) + .Case("weak", AT_weak) + .Case("pure", AT_pure) + .Case("mode", AT_mode) + .Case("used", AT_used) + .Case("alias", AT_alias) + .Case("const", AT_const) + .Case("packed", AT_packed) + .Case("malloc", AT_malloc) + .Case("format", AT_format) + .Case("unused", AT_unused) + .Case("blocks", AT_blocks) + .Case("aligned", AT_aligned) + .Case("cleanup", AT_cleanup) + .Case("nodebug", AT_nodebug) + .Case("nonnull", AT_nonnull) + .Case("nothrow", AT_nothrow) + .Case("objc_gc", AT_objc_gc) + .Case("regparm", AT_regparm) + .Case("section", AT_section) + .Case("stdcall", AT_stdcall) + .Case("annotate", AT_annotate) + .Case("noreturn", AT_noreturn) + .Case("noinline", AT_noinline) + .Case("fastcall", AT_fastcall) + .Case("iboutlet", AT_IBOutlet) + .Case("sentinel", AT_sentinel) + .Case("NSObject", AT_nsobject) + .Case("dllimport", AT_dllimport) + .Case("dllexport", AT_dllexport) + .Case("may_alias", IgnoredAttribute) // FIXME: TBAA + .Case("deprecated", AT_deprecated) + .Case("visibility", AT_visibility) + .Case("destructor", AT_destructor) + .Case("format_arg", AT_format_arg) + .Case("gnu_inline", AT_gnu_inline) + .Case("weak_import", AT_weak_import) + .Case("vector_size", AT_vector_size) + .Case("constructor", AT_constructor) + .Case("unavailable", AT_unavailable) + .Case("overloadable", AT_overloadable) + .Case("address_space", AT_address_space) + .Case("always_inline", AT_always_inline) + .Case("vec_type_hint", IgnoredAttribute) + .Case("objc_exception", AT_objc_exception) + .Case("ext_vector_type", AT_ext_vector_type) + .Case("transparent_union", AT_transparent_union) + .Case("analyzer_noreturn", AT_analyzer_noreturn) + .Case("warn_unused_result", AT_warn_unused_result) + .Case("ns_returns_retained", AT_ns_returns_retained) + .Case("cf_returns_retained", AT_cf_returns_retained) + .Case("reqd_work_group_size", AT_reqd_wg_size) + .Case("no_instrument_function", AT_no_instrument_function) + .Default(UnknownAttribute); } diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index b8422aa..3436900 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -446,3 +446,28 @@ bool DeclSpec::isMissingDeclaratorOk() { || tst == TST_enum ) && getTypeRep() != 0 && StorageClassSpec != DeclSpec::SCS_typedef; } + +void UnqualifiedId::clear() { + if (Kind == IK_TemplateId) + TemplateId->Destroy(); + + Kind = IK_Identifier; + Identifier = 0; + StartLocation = SourceLocation(); + EndLocation = SourceLocation(); +} + +void UnqualifiedId::setOperatorFunctionId(SourceLocation OperatorLoc, + OverloadedOperatorKind Op, + SourceLocation SymbolLocations[3]) { + Kind = IK_OperatorFunctionId; + StartLocation = OperatorLoc; + EndLocation = OperatorLoc; + OperatorFunctionId.Operator = Op; + for (unsigned I = 0; I != 3; ++I) { + OperatorFunctionId.SymbolLocations[I] = SymbolLocations[I].getRawEncoding(); + + if (SymbolLocations[I].isValid()) + EndLocation = SymbolLocations[I]; + } +} diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp index 71b22ca..1e7d397 100644 --- a/lib/Parse/MinimalAction.cpp +++ b/lib/Parse/MinimalAction.cpp @@ -161,9 +161,8 @@ bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *, TemplateNameKind MinimalAction::isTemplateName(Scope *S, - const IdentifierInfo &II, - SourceLocation IdLoc, - const CXXScopeSpec *SS, + const CXXScopeSpec &SS, + UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringScope, TemplateTy &TemplateDecl) { diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index b56c331..e905553 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -336,10 +336,9 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context, /// If RequireSemi is false, this does not check for a ';' at the end of the /// declaration. Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context, - SourceLocation &DeclEnd, - bool RequireSemi) { + SourceLocation &DeclEnd) { // Parse the common declaration-specifiers piece. - DeclSpec DS; + ParsingDeclSpec DS(*this); ParseDeclarationSpecifiers(DS); // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" @@ -347,32 +346,109 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context, if (Tok.is(tok::semi)) { ConsumeToken(); DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + DS.complete(TheDecl); return Actions.ConvertDeclToDeclGroup(TheDecl); } - Declarator DeclaratorInfo(DS, (Declarator::TheContext)Context); - ParseDeclarator(DeclaratorInfo); + DeclGroupPtrTy DG = ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, + &DeclEnd); + return DG; +} - DeclGroupPtrTy DG = - ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo); +/// ParseDeclGroup - Having concluded that this is either a function +/// definition or a group of object declarations, actually parse the +/// result. +Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, + unsigned Context, + bool AllowFunctionDefinitions, + SourceLocation *DeclEnd) { + // Parse the first declarator. + ParsingDeclarator D(*this, DS, static_cast<Declarator::TheContext>(Context)); + ParseDeclarator(D); + + // Bail out if the first declarator didn't seem well-formed. + if (!D.hasName() && !D.mayOmitIdentifier()) { + // Skip until ; or }. + SkipUntil(tok::r_brace, true, true); + if (Tok.is(tok::semi)) + ConsumeToken(); + return DeclGroupPtrTy(); + } + + if (AllowFunctionDefinitions && D.isFunctionDeclarator()) { + if (isDeclarationAfterDeclarator()) { + // Fall though. We have to check this first, though, because + // __attribute__ might be the start of a function definition in + // (extended) K&R C. + } else if (isStartOfFunctionDefinition()) { + if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { + Diag(Tok, diag::err_function_declared_typedef); + + // Recover by treating the 'typedef' as spurious. + DS.ClearStorageClassSpecs(); + } - DeclEnd = Tok.getLocation(); + DeclPtrTy TheDecl = ParseFunctionDefinition(D); + return Actions.ConvertDeclToDeclGroup(TheDecl); + } else { + Diag(Tok, diag::err_expected_fn_body); + SkipUntil(tok::semi); + return DeclGroupPtrTy(); + } + } - // If the client wants to check what comes after the declaration, just return - // immediately without checking anything! - if (!RequireSemi) return DG; + llvm::SmallVector<DeclPtrTy, 8> DeclsInGroup; + DeclPtrTy FirstDecl = ParseDeclarationAfterDeclarator(D); + D.complete(FirstDecl); + if (FirstDecl.get()) + DeclsInGroup.push_back(FirstDecl); - if (Tok.is(tok::semi)) { + // If we don't have a comma, it is either the end of the list (a ';') or an + // error, bail out. + while (Tok.is(tok::comma)) { + // Consume the comma. ConsumeToken(); - return DG; + + // Parse the next declarator. + D.clear(); + + // Accept attributes in an init-declarator. In the first declarator in a + // declaration, these would be part of the declspec. In subsequent + // declarators, they become part of the declarator itself, so that they + // don't apply to declarators after *this* one. Examples: + // short __attribute__((common)) var; -> declspec + // short var __attribute__((common)); -> declarator + // short x, __attribute__((common)) var; -> declarator + if (Tok.is(tok::kw___attribute)) { + SourceLocation Loc; + AttributeList *AttrList = ParseAttributes(&Loc); + D.AddAttributes(AttrList, Loc); + } + + ParseDeclarator(D); + + DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(D); + D.complete(ThisDecl); + if (ThisDecl.get()) + DeclsInGroup.push_back(ThisDecl); } - Diag(Tok, diag::err_expected_semi_declaration); - // Skip to end of block or statement - SkipUntil(tok::r_brace, true, true); - if (Tok.is(tok::semi)) - ConsumeToken(); - return DG; + if (DeclEnd) + *DeclEnd = Tok.getLocation(); + + if (Context != Declarator::ForContext && + ExpectAndConsume(tok::semi, + Context == Declarator::FileContext + ? diag::err_invalid_token_after_toplevel_declarator + : diag::err_expected_semi_declaration)) { + SkipUntil(tok::r_brace, true, true); + if (Tok.is(tok::semi)) + ConsumeToken(); + } + + return Actions.FinalizeDeclaratorGroup(CurScope, DS, + DeclsInGroup.data(), + DeclsInGroup.size()); } /// \brief Parse 'declaration' after parsing 'declaration-specifiers @@ -498,63 +574,6 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D, return ThisDecl; } -/// ParseInitDeclaratorListAfterFirstDeclarator - Parse 'declaration' after -/// parsing 'declaration-specifiers declarator'. This method is split out this -/// way to handle the ambiguity between top-level function-definitions and -/// declarations. -/// -/// init-declarator-list: [C99 6.7] -/// init-declarator -/// init-declarator-list ',' init-declarator -/// -/// According to the standard grammar, =default and =delete are function -/// definitions, but that definitely doesn't fit with the parser here. -/// -Parser::DeclGroupPtrTy Parser:: -ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) { - // Declarators may be grouped together ("int X, *Y, Z();"). Remember the decls - // that we parse together here. - llvm::SmallVector<DeclPtrTy, 8> DeclsInGroup; - - // At this point, we know that it is not a function definition. Parse the - // rest of the init-declarator-list. - while (1) { - DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(D); - if (ThisDecl.get()) - DeclsInGroup.push_back(ThisDecl); - - // If we don't have a comma, it is either the end of the list (a ';') or an - // error, bail out. - if (Tok.isNot(tok::comma)) - break; - - // Consume the comma. - ConsumeToken(); - - // Parse the next declarator. - D.clear(); - - // Accept attributes in an init-declarator. In the first declarator in a - // declaration, these would be part of the declspec. In subsequent - // declarators, they become part of the declarator itself, so that they - // don't apply to declarators after *this* one. Examples: - // short __attribute__((common)) var; -> declspec - // short var __attribute__((common)); -> declarator - // short x, __attribute__((common)) var; -> declarator - if (Tok.is(tok::kw___attribute)) { - SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); - D.AddAttributes(AttrList, Loc); - } - - ParseDeclarator(D); - } - - return Actions.FinalizeDeclaratorGroup(CurScope, D.getDeclSpec(), - DeclsInGroup.data(), - DeclsInGroup.size()); -} - /// ParseSpecifierQualifierList /// specifier-qualifier-list: /// type-specifier specifier-qualifier-list[opt] @@ -1468,8 +1487,7 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, /// [GNU] declarator[opt] ':' constant-expression attributes[opt] /// void Parser:: -ParseStructDeclaration(DeclSpec &DS, - llvm::SmallVectorImpl<FieldDeclarator> &Fields) { +ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { if (Tok.is(tok::kw___extension__)) { // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. @@ -1489,9 +1507,17 @@ ParseStructDeclaration(DeclSpec &DS, } // Read struct-declarators until we find the semicolon. - Fields.push_back(FieldDeclarator(DS)); + bool FirstDeclarator = true; while (1) { - FieldDeclarator &DeclaratorInfo = Fields.back(); + ParsingDeclRAIIObject PD(*this); + FieldDeclarator DeclaratorInfo(DS); + + // Attributes are only allowed here on successive declarators. + if (!FirstDeclarator && Tok.is(tok::kw___attribute)) { + SourceLocation Loc; + AttributeList *AttrList = ParseAttributes(&Loc); + DeclaratorInfo.D.AddAttributes(AttrList, Loc); + } /// struct-declarator: declarator /// struct-declarator: declarator[opt] ':' constant-expression @@ -1514,6 +1540,10 @@ ParseStructDeclaration(DeclSpec &DS, DeclaratorInfo.D.AddAttributes(AttrList, Loc); } + // We're done with this declarator; invoke the callback. + DeclPtrTy D = Fields.invoke(DeclaratorInfo); + PD.complete(D); + // If we don't have a comma, it is either the end of the list (a ';') // or an error, bail out. if (Tok.isNot(tok::comma)) @@ -1522,15 +1552,7 @@ ParseStructDeclaration(DeclSpec &DS, // Consume the comma. ConsumeToken(); - // Parse the next declarator. - Fields.push_back(FieldDeclarator(DS)); - - // Attributes are only allowed on the second declarator. - if (Tok.is(tok::kw___attribute)) { - SourceLocation Loc; - AttributeList *AttrList = ParseAttributes(&Loc); - Fields.back().D.AddAttributes(AttrList, Loc); - } + FirstDeclarator = false; } } @@ -1562,7 +1584,6 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, << DeclSpec::getSpecifierName((DeclSpec::TST)TagType); llvm::SmallVector<DeclPtrTy, 32> FieldDecls; - llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators; // While we still have something to read, read the declarations in the struct. while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { @@ -1578,28 +1599,28 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, // Parse all the comma separated declarators. DeclSpec DS; - FieldDeclarators.clear(); + if (!Tok.is(tok::at)) { - ParseStructDeclaration(DS, FieldDeclarators); - - // Convert them all to fields. - for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) { - FieldDeclarator &FD = FieldDeclarators[i]; - DeclPtrTy Field; - // Install the declarator into the current TagDecl. - if (FD.D.getExtension()) { - // Silences extension warnings - ExtensionRAIIObject O(Diags); - Field = Actions.ActOnField(CurScope, TagDecl, - DS.getSourceRange().getBegin(), - FD.D, FD.BitfieldSize); - } else { - Field = Actions.ActOnField(CurScope, TagDecl, - DS.getSourceRange().getBegin(), - FD.D, FD.BitfieldSize); + struct CFieldCallback : FieldCallback { + Parser &P; + DeclPtrTy TagDecl; + llvm::SmallVectorImpl<DeclPtrTy> &FieldDecls; + + CFieldCallback(Parser &P, DeclPtrTy TagDecl, + llvm::SmallVectorImpl<DeclPtrTy> &FieldDecls) : + P(P), TagDecl(TagDecl), FieldDecls(FieldDecls) {} + + virtual DeclPtrTy invoke(FieldDeclarator &FD) { + // Install the declarator into the current TagDecl. + DeclPtrTy Field = P.Actions.ActOnField(P.CurScope, TagDecl, + FD.D.getDeclSpec().getSourceRange().getBegin(), + FD.D, FD.BitfieldSize); + FieldDecls.push_back(Field); + return Field; } - FieldDecls.push_back(Field); - } + } Callback(*this, TagDecl, FieldDecls); + + ParseStructDeclaration(DS, Callback); } else { // Handle @defs ConsumeToken(); if (!Tok.isObjCAtKeyword(tok::objc_defs)) { @@ -2107,7 +2128,6 @@ void Parser::ParseDeclarator(Declarator &D) { /// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt] void Parser::ParseDeclaratorInternal(Declarator &D, DirectDeclParseFunction DirectDeclParser) { - if (Diags.hasAllExtensionsSilenced()) D.setExtension(); // C++ member pointers start with a '::' or a nested-name. @@ -2270,97 +2290,47 @@ void Parser::ParseDeclaratorInternal(Declarator &D, void Parser::ParseDirectDeclarator(Declarator &D) { DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec()); - if (getLang().CPlusPlus) { - if (D.mayHaveIdentifier()) { - // ParseDeclaratorInternal might already have parsed the scope. - bool afterCXXScope = D.getCXXScopeSpec().isSet() || - ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0, - true); - if (afterCXXScope) { - // Change the declaration context for name lookup, until this function - // is exited (and the declarator has been parsed). - DeclScopeObj.EnterDeclaratorScope(); - } - - if (Tok.is(tok::identifier)) { - assert(Tok.getIdentifierInfo() && "Not an identifier?"); - - // If this identifier is the name of the current class, it's a - // constructor name. - if (!D.getDeclSpec().hasTypeSpecifier() && - Actions.isCurrentClassName(*Tok.getIdentifierInfo(),CurScope)) { - CXXScopeSpec *SS = afterCXXScope? &D.getCXXScopeSpec() : 0; - D.setConstructor(Actions.getTypeName(*Tok.getIdentifierInfo(), - Tok.getLocation(), CurScope, SS), - Tok.getLocation()); - // This is a normal identifier. - } else - D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); - ConsumeToken(); - goto PastIdentifier; - } else if (Tok.is(tok::annot_template_id)) { - TemplateIdAnnotation *TemplateId - = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); - - D.setTemplateId(TemplateId); - ConsumeToken(); - goto PastIdentifier; - } else if (Tok.is(tok::kw_operator)) { - SourceLocation OperatorLoc = Tok.getLocation(); - SourceLocation EndLoc; - - // First try the name of an overloaded operator - if (OverloadedOperatorKind Op = TryParseOperatorFunctionId(&EndLoc)) { - D.setOverloadedOperator(Op, OperatorLoc, EndLoc); - } else { - // This must be a conversion function (C++ [class.conv.fct]). - if (TypeTy *ConvType = ParseConversionFunctionId(&EndLoc)) - D.setConversionFunction(ConvType, OperatorLoc, EndLoc); - else { - D.SetIdentifier(0, Tok.getLocation()); - } - } - goto PastIdentifier; - } else if (Tok.is(tok::tilde)) { - // This should be a C++ destructor. - SourceLocation TildeLoc = ConsumeToken(); - if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) { - // FIXME: Inaccurate. - SourceLocation NameLoc = Tok.getLocation(); - SourceLocation EndLoc; - CXXScopeSpec *SS = afterCXXScope? &D.getCXXScopeSpec() : 0; - TypeResult Type = ParseClassName(EndLoc, SS, true); - if (Type.isInvalid()) - D.SetIdentifier(0, TildeLoc); - else - D.setDestructor(Type.get(), TildeLoc, NameLoc); - } else { - Diag(Tok, diag::err_destructor_class_name); - D.SetIdentifier(0, TildeLoc); - } - goto PastIdentifier; - } - - // If we reached this point, token is not identifier and not '~'. - - if (afterCXXScope) { - Diag(Tok, diag::err_expected_unqualified_id); + if (getLang().CPlusPlus && D.mayHaveIdentifier()) { + // ParseDeclaratorInternal might already have parsed the scope. + bool afterCXXScope = D.getCXXScopeSpec().isSet() || + ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0, + true); + if (afterCXXScope) { + // Change the declaration context for name lookup, until this function + // is exited (and the declarator has been parsed). + DeclScopeObj.EnterDeclaratorScope(); + } + + if (Tok.is(tok::identifier) || Tok.is(tok::kw_operator) || + 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. + if (ParseUnqualifiedId(D.getCXXScopeSpec(), + /*EnteringContext=*/true, + /*AllowDestructorName=*/true, + /*AllowConstructorName=*/!D.getDeclSpec().hasTypeSpecifier(), + /*ObjectType=*/0, + D.getName())) { D.SetIdentifier(0, Tok.getLocation()); D.setInvalidType(true); - goto PastIdentifier; + } else { + // Parsed the unqualified-id; update range information and move along. + if (D.getSourceRange().getBegin().isInvalid()) + D.SetRangeBegin(D.getName().getSourceRange().getBegin()); + D.SetRangeEnd(D.getName().getSourceRange().getEnd()); } + goto PastIdentifier; } - } - - // If we reached this point, we are either in C/ObjC or the token didn't - // satisfy any of the C++-specific checks. - if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) { + } else if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) { assert(!getLang().CPlusPlus && "There's a C++-specific check for tok::identifier above"); assert(Tok.getIdentifierInfo() && "Not an identifier?"); D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); ConsumeToken(); - } else if (Tok.is(tok::l_paren)) { + goto PastIdentifier; + } + + if (Tok.is(tok::l_paren)) { // direct-declarator: '(' declarator ')' // direct-declarator: '(' attributes declarator ')' // Example: 'char (*X)' or 'int (*XX)(void)' @@ -2374,7 +2344,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { Diag(Tok, diag::err_expected_member_name_or_semi) << D.getDeclSpec().getSourceRange(); else if (getLang().CPlusPlus) - Diag(Tok, diag::err_expected_unqualified_id); + Diag(Tok, diag::err_expected_unqualified_id) << getLang().CPlusPlus; else Diag(Tok, diag::err_expected_ident_lparen); D.SetIdentifier(0, Tok.getLocation()); @@ -2623,6 +2593,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, SourceLocation DSStart = Tok.getLocation(); // Parse the declaration-specifiers. + // Just use the ParsingDeclaration "scope" of the declarator. DeclSpec DS; // If the caller parsed attributes for the first argument, add them now. diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index d381e3e..91f8686 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -323,6 +323,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, SkipUntil(tok::semi); return DeclPtrTy(); } + // FIXME: what about conversion functions? } else if (Tok.is(tok::identifier)) { // Parse identifier. TargetName = Tok.getIdentifierInfo(); @@ -589,6 +590,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) Diag(Tok, diag::err_expected_ident); + TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; + // Parse the (optional) class name or simple-template-id. IdentifierInfo *Name = 0; SourceLocation NameLoc; @@ -596,6 +599,56 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (Tok.is(tok::identifier)) { Name = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); + + if (Tok.is(tok::less)) { + // The name was supposed to refer to a template, but didn't. + // Eat the template argument list and try to continue parsing this as + // a class (or template thereof). + TemplateArgList TemplateArgs; + TemplateArgIsTypeList TemplateArgIsType; + TemplateArgLocationList TemplateArgLocations; + SourceLocation LAngleLoc, RAngleLoc; + if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, &SS, + true, LAngleLoc, + TemplateArgs, TemplateArgIsType, + TemplateArgLocations, RAngleLoc)) { + // We couldn't parse the template argument list at all, so don't + // try to give any location information for the list. + LAngleLoc = RAngleLoc = SourceLocation(); + } + + Diag(NameLoc, diag::err_explicit_spec_non_template) + << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) + << (TagType == DeclSpec::TST_class? 0 + : TagType == DeclSpec::TST_struct? 1 + : 2) + << Name + << SourceRange(LAngleLoc, RAngleLoc); + + // Strip off the last template parameter list if it was empty, since + // we've removed its template argument list. + if (TemplateParams && TemplateInfo.LastParameterListWasEmpty) { + if (TemplateParams && TemplateParams->size() > 1) { + TemplateParams->pop_back(); + } else { + TemplateParams = 0; + const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind + = ParsedTemplateInfo::NonTemplate; + } + } else if (TemplateInfo.Kind + == ParsedTemplateInfo::ExplicitInstantiation) { + // Pretend this is just a forward declaration. + TemplateParams = 0; + const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind + = ParsedTemplateInfo::NonTemplate; + const_cast<ParsedTemplateInfo&>(TemplateInfo).TemplateLoc + = SourceLocation(); + const_cast<ParsedTemplateInfo&>(TemplateInfo).ExternLoc + = SourceLocation(); + } + + + } } else if (Tok.is(tok::annot_template_id)) { TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); NameLoc = ConsumeToken(); @@ -660,7 +713,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Create the tag portion of the class or class template. Action::DeclResult TagOrTempResult = true; // invalid Action::TypeResult TypeResult = true; // invalid - TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; // FIXME: When TUK == TUK_Reference and we have a template-id, we need // to turn that template-id into a type. @@ -1047,7 +1099,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SourceLocation DSStart = Tok.getLocation(); // decl-specifier-seq: // Parse the common declaration-specifiers piece. - DeclSpec DS; + ParsingDeclSpec DS(*this); ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class); Action::MultiTemplateParamsArg TemplateParams(Actions, @@ -1060,7 +1112,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return; } - Declarator DeclaratorInfo(DS, Declarator::MemberContext); + ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext); if (Tok.isNot(tok::colon)) { // Parse the first declarator. @@ -1179,6 +1231,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, HandleMemberFunctionDefaultArgs(DeclaratorInfo, ThisDecl); } + DeclaratorInfo.complete(ThisDecl); + // If we don't have a comma, it is either the end of the list (a ';') // or an error, bail out. if (Tok.isNot(tok::comma)) diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 8be89a8..95a0e98 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -340,7 +340,18 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { // Eat the colon. ColonLoc = ConsumeToken(); } - + + if ((OpToken.is(tok::periodstar) || OpToken.is(tok::arrowstar)) + && Tok.is(tok::identifier)) { + CXXScopeSpec SS; + if (Actions.getTypeName(*Tok.getIdentifierInfo(), + Tok.getLocation(), CurScope, &SS)) { + const char *Opc = OpToken.is(tok::periodstar) ? "'.*'" : "'->*'"; + Diag(OpToken, diag::err_pointer_to_member_type) << Opc; + return ExprError(); + } + + } // Parse another leaf here for the RHS of the operator. // ParseCastExpression works here because all RHS expressions in C have it // as a prefix, at least. However, in C++, an assignment-expression could @@ -612,36 +623,39 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, return ParseCastExpression(isUnaryExpression, isAddressOfOperand); } - // Support 'Class.property' notation. - // We don't use isTokObjCMessageIdentifierReceiver(), since it allows - // 'super' (which is inappropriate here). - if (getLang().ObjC1 && - Actions.getTypeName(*Tok.getIdentifierInfo(), - Tok.getLocation(), CurScope) && - NextToken().is(tok::period)) { - IdentifierInfo &ReceiverName = *Tok.getIdentifierInfo(); - SourceLocation IdentLoc = ConsumeToken(); + // Consume the identifier so that we can see if it is followed by a '(' or + // '.'. + IdentifierInfo &II = *Tok.getIdentifierInfo(); + SourceLocation ILoc = ConsumeToken(); + + // Support 'Class.property' notation. We don't use + // isTokObjCMessageIdentifierReceiver(), since it allows 'super' (which is + // inappropriate here). + if (getLang().ObjC1 && Tok.is(tok::period) && + Actions.getTypeName(II, ILoc, CurScope)) { SourceLocation DotLoc = ConsumeToken(); - + if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); + Diag(Tok, diag::err_expected_property_name); return ExprError(); } IdentifierInfo &PropertyName = *Tok.getIdentifierInfo(); SourceLocation PropertyLoc = ConsumeToken(); - - Res = Actions.ActOnClassPropertyRefExpr(ReceiverName, PropertyName, - IdentLoc, PropertyLoc); + + Res = Actions.ActOnClassPropertyRefExpr(II, PropertyName, + ILoc, PropertyLoc); // These can be followed by postfix-expr pieces. return ParsePostfixExpressionSuffix(move(Res)); } - // Consume the identifier so that we can see if it is followed by a '('. + // Function designators are allowed to be undeclared (C99 6.5.1p2), so we // need to know whether or not this identifier is a function designator or // not. - IdentifierInfo &II = *Tok.getIdentifierInfo(); - SourceLocation L = ConsumeToken(); - Res = Actions.ActOnIdentifierExpr(CurScope, L, II, Tok.is(tok::l_paren)); + UnqualifiedId Name; + CXXScopeSpec ScopeSpec; + Name.setIdentifier(&II, ILoc); + Res = Actions.ActOnIdExpression(CurScope, ScopeSpec, Name, + Tok.is(tok::l_paren), false); // These can be followed by postfix-expr pieces. return ParsePostfixExpressionSuffix(move(Res)); } @@ -954,110 +968,20 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { ConsumeToken(); } - if (Tok.is(tok::identifier)) { - if (!LHS.isInvalid()) - LHS = Actions.ActOnMemberReferenceExpr(CurScope, move(LHS), OpLoc, - OpKind, Tok.getLocation(), - *Tok.getIdentifierInfo(), - ObjCImpDecl, &SS); - ConsumeToken(); - } else if (getLang().CPlusPlus && Tok.is(tok::tilde)) { - // We have a C++ pseudo-destructor or a destructor call, e.g., t.~T() - - // Consume the tilde. - ConsumeToken(); - - if (!Tok.is(tok::identifier)) { - Diag(Tok, diag::err_expected_ident); - return ExprError(); - } - - if (NextToken().is(tok::less)) { - // class-name: - // ~ simple-template-id - TemplateTy Template - = Actions.ActOnDependentTemplateName(SourceLocation(), - *Tok.getIdentifierInfo(), - Tok.getLocation(), - SS, - ObjectType); - if (AnnotateTemplateIdToken(Template, TNK_Type_template, &SS, - SourceLocation(), true)) - return ExprError(); - - assert(Tok.is(tok::annot_typename) && - "AnnotateTemplateIdToken didn't work?"); - if (!LHS.isInvalid()) - LHS = Actions.ActOnDestructorReferenceExpr(CurScope, move(LHS), - OpLoc, OpKind, - Tok.getAnnotationRange(), - Tok.getAnnotationValue(), - SS, - NextToken().is(tok::l_paren)); - } else { - // class-name: - // ~ identifier - if (!LHS.isInvalid()) - LHS = Actions.ActOnDestructorReferenceExpr(CurScope, move(LHS), - OpLoc, OpKind, - Tok.getLocation(), - Tok.getIdentifierInfo(), - SS, - NextToken().is(tok::l_paren)); - } - - // Consume the identifier or template-id token. - ConsumeToken(); - } else if (getLang().CPlusPlus && Tok.is(tok::kw_operator)) { - // We have a reference to a member operator, e.g., t.operator int or - // t.operator+. - SourceLocation OperatorLoc = Tok.getLocation(); - - if (OverloadedOperatorKind Op = TryParseOperatorFunctionId()) { - if (!LHS.isInvalid()) - LHS = Actions.ActOnOverloadedOperatorReferenceExpr(CurScope, - move(LHS), OpLoc, - OpKind, - OperatorLoc, - Op, &SS); - // TryParseOperatorFunctionId already consumed our token, so - // don't bother - } else if (TypeTy *ConvType = ParseConversionFunctionId()) { - if (!LHS.isInvalid()) - LHS = Actions.ActOnConversionOperatorReferenceExpr(CurScope, - move(LHS), OpLoc, - OpKind, - OperatorLoc, - ConvType, &SS); - } else { - // Don't emit a diagnostic; ParseConversionFunctionId does it for us - return ExprError(); - } - } else if (getLang().CPlusPlus && Tok.is(tok::annot_template_id)) { - // We have a reference to a member template along with explicitly- - // specified template arguments, e.g., t.f<int>. - TemplateIdAnnotation *TemplateId - = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); - if (!LHS.isInvalid()) { - ASTTemplateArgsPtr TemplateArgsPtr(Actions, - TemplateId->getTemplateArgs(), - TemplateId->getTemplateArgIsType(), - TemplateId->NumArgs); - - LHS = Actions.ActOnMemberTemplateIdReferenceExpr(CurScope, move(LHS), - OpLoc, OpKind, SS, - TemplateTy::make(TemplateId->Template), - TemplateId->TemplateNameLoc, - TemplateId->LAngleLoc, - TemplateArgsPtr, - TemplateId->getTemplateArgLocations(), - TemplateId->RAngleLoc); - } - ConsumeToken(); - } else { - Diag(Tok, diag::err_expected_ident); + UnqualifiedId Name; + if (ParseUnqualifiedId(SS, + /*EnteringContext=*/false, + /*AllowDestructorName=*/true, + /*AllowConstructorName=*/false, + ObjectType, + Name)) return ExprError(); - } + + if (!LHS.isInvalid()) + LHS = Actions.ActOnMemberAccessExpr(CurScope, move(LHS), OpLoc, OpKind, + SS, Name, ObjCImpDecl, + Tok.is(tok::l_paren)); + break; } case tok::plusplus: // postfix-expression: postfix-expression '++' diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index fa65156..a7ca0c5 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -14,6 +14,8 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/DeclSpec.h" +#include "llvm/Support/ErrorHandling.h" + using namespace clang; /// \brief Parse global scope or nested-name-specifier if present. @@ -107,31 +109,58 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, break; SourceLocation TemplateKWLoc = ConsumeToken(); - - if (Tok.isNot(tok::identifier)) { + + UnqualifiedId TemplateName; + if (Tok.is(tok::identifier)) { + TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + + // If the next token is not '<', we may have a stray 'template' keyword. + // Complain and suggest removing the template keyword, but otherwise + // allow parsing to continue. + if (NextToken().isNot(tok::less)) { + Diag(NextToken().getLocation(), + diag::err_less_after_template_name_in_nested_name_spec) + << Tok.getIdentifierInfo()->getName() + << CodeModificationHint::CreateRemoval(SourceRange(TemplateKWLoc)); + break; + } + + // Consume the identifier. + ConsumeToken(); + } else if (Tok.is(tok::kw_operator)) { + if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, + TemplateName)) + break; + + if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId) { + Diag(TemplateName.getSourceRange().getBegin(), + diag::err_id_after_template_in_nested_name_spec) + << TemplateName.getSourceRange(); + break; + } else if (Tok.isNot(tok::less)) { + std::string OperatorName = "operator "; + OperatorName += getOperatorSpelling( + TemplateName.OperatorFunctionId.Operator); + Diag(Tok.getLocation(), + diag::err_less_after_template_name_in_nested_name_spec) + << OperatorName + << TemplateName.getSourceRange(); + break; + } + } else { Diag(Tok.getLocation(), diag::err_id_after_template_in_nested_name_spec) << SourceRange(TemplateKWLoc); break; } - if (NextToken().isNot(tok::less)) { - Diag(NextToken().getLocation(), - diag::err_less_after_template_name_in_nested_name_spec) - << Tok.getIdentifierInfo()->getName() - << SourceRange(TemplateKWLoc, Tok.getLocation()); - break; - } - TemplateTy Template - = Actions.ActOnDependentTemplateName(TemplateKWLoc, - *Tok.getIdentifierInfo(), - Tok.getLocation(), SS, + = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, TemplateName, ObjectType); if (!Template) break; if (AnnotateTemplateIdToken(Template, TNK_Dependent_template_name, - &SS, TemplateKWLoc, false)) + &SS, TemplateName, TemplateKWLoc, false)) break; continue; @@ -218,9 +247,10 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // type-name '<' if (Next.is(tok::less)) { TemplateTy Template; - if (TemplateNameKind TNK = Actions.isTemplateName(CurScope, II, - Tok.getLocation(), - &SS, + UnqualifiedId TemplateName; + TemplateName.setIdentifier(&II, Tok.getLocation()); + if (TemplateNameKind TNK = Actions.isTemplateName(CurScope, SS, + TemplateName, ObjectType, EnteringContext, Template)) { @@ -230,8 +260,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // because some clients (e.g., the parsing of class template // specializations) still want to see the original template-id // token. - if (AnnotateTemplateIdToken(Template, TNK, &SS, SourceLocation(), - false)) + ConsumeToken(); + if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName, + SourceLocation(), false)) break; continue; } @@ -251,25 +282,12 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, /// unqualified-id /// qualified-id /// -/// unqualified-id: -/// identifier -/// operator-function-id -/// conversion-function-id [TODO] -/// '~' class-name [TODO] -/// template-id -/// /// qualified-id: /// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id /// '::' identifier /// '::' operator-function-id /// '::' template-id /// -/// nested-name-specifier: -/// type-name '::' -/// namespace-name '::' -/// nested-name-specifier identifier '::' -/// nested-name-specifier 'template'[opt] simple-template-id '::' [TODO] -/// /// NOTE: The standard specifies that, for qualified-id, the parser does not /// expect: /// @@ -307,69 +325,19 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { // CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); - - // unqualified-id: - // identifier - // operator-function-id - // conversion-function-id - // '~' class-name [TODO] - // template-id - // - switch (Tok.getKind()) { - default: - return ExprError(Diag(Tok, diag::err_expected_unqualified_id)); - - case tok::identifier: { - // Consume the identifier so that we can see if it is followed by a '('. - IdentifierInfo &II = *Tok.getIdentifierInfo(); - SourceLocation L = ConsumeToken(); - return Actions.ActOnIdentifierExpr(CurScope, L, II, Tok.is(tok::l_paren), - &SS, isAddressOfOperand); - } - - case tok::kw_operator: { - SourceLocation OperatorLoc = Tok.getLocation(); - if (OverloadedOperatorKind Op = TryParseOperatorFunctionId()) - return Actions.ActOnCXXOperatorFunctionIdExpr( - CurScope, OperatorLoc, Op, Tok.is(tok::l_paren), SS, - isAddressOfOperand); - if (TypeTy *Type = ParseConversionFunctionId()) - return Actions.ActOnCXXConversionFunctionExpr(CurScope, OperatorLoc, Type, - Tok.is(tok::l_paren), SS, - isAddressOfOperand); - - // We already complained about a bad conversion-function-id, - // above. + + UnqualifiedId Name; + if (ParseUnqualifiedId(SS, + /*EnteringContext=*/false, + /*AllowDestructorName=*/false, + /*AllowConstructorName=*/false, + /*ObjectType=*/0, + Name)) return ExprError(); - } - - case tok::annot_template_id: { - TemplateIdAnnotation *TemplateId - = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); - assert((TemplateId->Kind == TNK_Function_template || - TemplateId->Kind == TNK_Dependent_template_name) && - "A template type name is not an ID expression"); - - ASTTemplateArgsPtr TemplateArgsPtr(Actions, - TemplateId->getTemplateArgs(), - TemplateId->getTemplateArgIsType(), - TemplateId->NumArgs); - - OwningExprResult Result - = Actions.ActOnTemplateIdExpr(SS, - TemplateTy::make(TemplateId->Template), - TemplateId->TemplateNameLoc, - TemplateId->LAngleLoc, - TemplateArgsPtr, - TemplateId->getTemplateArgLocations(), - TemplateId->RAngleLoc); - ConsumeToken(); // Consume the template-id token - return move(Result); - } - - } // switch. - - assert(0 && "The switch was supposed to take care everything."); + + return Actions.ActOnIdExpression(CurScope, SS, Name, Tok.is(tok::l_paren), + isAddressOfOperand); + } /// ParseCXXCasts - This handles the various ways to cast expressions to another @@ -761,6 +729,473 @@ bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) { return false; } +/// \brief Finish parsing a C++ unqualified-id that is a template-id of +/// some form. +/// +/// This routine is invoked when a '<' is encountered after an identifier or +/// operator-function-id is parsed by \c ParseUnqualifiedId() to determine +/// whether the unqualified-id is actually a template-id. This routine will +/// then parse the template arguments and form the appropriate template-id to +/// return to the caller. +/// +/// \param SS the nested-name-specifier that precedes this template-id, if +/// we're actually parsing a qualified-id. +/// +/// \param Name for constructor and destructor names, this is the actual +/// identifier that may be a template-name. +/// +/// \param NameLoc the location of the class-name in a constructor or +/// destructor. +/// +/// \param EnteringContext whether we're entering the scope of the +/// nested-name-specifier. +/// +/// \param ObjectType if this unqualified-id occurs within a member access +/// expression, the type of the base object whose member is being accessed. +/// +/// \param Id as input, describes the template-name or operator-function-id +/// that precedes the '<'. If template arguments were parsed successfully, +/// will be updated with the template-id. +/// +/// \returns true if a parse error occurred, false otherwise. +bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool EnteringContext, + TypeTy *ObjectType, + UnqualifiedId &Id) { + assert(Tok.is(tok::less) && "Expected '<' to finish parsing a template-id"); + + TemplateTy Template; + TemplateNameKind TNK = TNK_Non_template; + switch (Id.getKind()) { + case UnqualifiedId::IK_Identifier: + case UnqualifiedId::IK_OperatorFunctionId: + TNK = Actions.isTemplateName(CurScope, SS, Id, ObjectType, EnteringContext, + Template); + break; + + case UnqualifiedId::IK_ConstructorName: { + UnqualifiedId TemplateName; + TemplateName.setIdentifier(Name, NameLoc); + TNK = Actions.isTemplateName(CurScope, SS, TemplateName, ObjectType, + EnteringContext, Template); + break; + } + + case UnqualifiedId::IK_DestructorName: { + UnqualifiedId TemplateName; + TemplateName.setIdentifier(Name, NameLoc); + if (ObjectType) { + Template = Actions.ActOnDependentTemplateName(SourceLocation(), SS, + TemplateName, ObjectType); + TNK = TNK_Dependent_template_name; + if (!Template.get()) + return true; + } else { + TNK = Actions.isTemplateName(CurScope, SS, TemplateName, ObjectType, + EnteringContext, Template); + + if (TNK == TNK_Non_template && Id.DestructorName == 0) { + // The identifier following the destructor did not refer to a template + // or to a type. Complain. + if (ObjectType) + Diag(NameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) + << Name; + else + Diag(NameLoc, diag::err_destructor_class_name); + return true; + } + } + break; + } + + default: + return false; + } + + if (TNK == TNK_Non_template) + return false; + + // Parse the enclosed template argument list. + SourceLocation LAngleLoc, RAngleLoc; + TemplateArgList TemplateArgs; + TemplateArgIsTypeList TemplateArgIsType; + TemplateArgLocationList TemplateArgLocations; + if (ParseTemplateIdAfterTemplateName(Template, Id.StartLocation, + &SS, true, LAngleLoc, + TemplateArgs, + TemplateArgIsType, + TemplateArgLocations, + RAngleLoc)) + return true; + + if (Id.getKind() == UnqualifiedId::IK_Identifier || + Id.getKind() == UnqualifiedId::IK_OperatorFunctionId) { + // Form a parsed representation of the template-id to be stored in the + // UnqualifiedId. + TemplateIdAnnotation *TemplateId + = TemplateIdAnnotation::Allocate(TemplateArgs.size()); + + if (Id.getKind() == UnqualifiedId::IK_Identifier) { + TemplateId->Name = Id.Identifier; + TemplateId->Operator = OO_None; + TemplateId->TemplateNameLoc = Id.StartLocation; + } else { + TemplateId->Name = 0; + TemplateId->Operator = Id.OperatorFunctionId.Operator; + TemplateId->TemplateNameLoc = Id.StartLocation; + } + + TemplateId->Template = Template.getAs<void*>(); + TemplateId->Kind = TNK; + TemplateId->LAngleLoc = LAngleLoc; + TemplateId->RAngleLoc = RAngleLoc; + void **Args = TemplateId->getTemplateArgs(); + bool *ArgIsType = TemplateId->getTemplateArgIsType(); + SourceLocation *ArgLocs = TemplateId->getTemplateArgLocations(); + for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); + Arg != ArgEnd; ++Arg) { + Args[Arg] = TemplateArgs[Arg]; + ArgIsType[Arg] = TemplateArgIsType[Arg]; + ArgLocs[Arg] = TemplateArgLocations[Arg]; + } + + Id.setTemplateId(TemplateId); + return false; + } + + // Bundle the template arguments together. + ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(), + TemplateArgIsType.data(), + TemplateArgs.size()); + + // Constructor and destructor names. + Action::TypeResult Type + = Actions.ActOnTemplateIdType(Template, NameLoc, + LAngleLoc, TemplateArgsPtr, + &TemplateArgLocations[0], + RAngleLoc); + if (Type.isInvalid()) + return true; + + if (Id.getKind() == UnqualifiedId::IK_ConstructorName) + Id.setConstructorName(Type.get(), NameLoc, RAngleLoc); + else + Id.setDestructorName(Id.StartLocation, Type.get(), RAngleLoc); + + return false; +} + +/// \brief Parse an operator-function-id or conversion-function-id as part +/// of a C++ unqualified-id. +/// +/// This routine is responsible only for parsing the operator-function-id or +/// conversion-function-id; it does not handle template arguments in any way. +/// +/// \code +/// operator-function-id: [C++ 13.5] +/// 'operator' operator +/// +/// operator: one of +/// new delete new[] delete[] +/// + - * / % ^ & | ~ +/// ! = < > += -= *= /= %= +/// ^= &= |= << >> >>= <<= == != +/// <= >= && || ++ -- , ->* -> +/// () [] +/// +/// conversion-function-id: [C++ 12.3.2] +/// operator conversion-type-id +/// +/// conversion-type-id: +/// type-specifier-seq conversion-declarator[opt] +/// +/// conversion-declarator: +/// ptr-operator conversion-declarator[opt] +/// \endcode +/// +/// \param The nested-name-specifier that preceded this unqualified-id. If +/// non-empty, then we are parsing the unqualified-id of a qualified-id. +/// +/// \param EnteringContext whether we are entering the scope of the +/// nested-name-specifier. +/// +/// \param ObjectType if this unqualified-id occurs within a member access +/// expression, the type of the base object whose member is being accessed. +/// +/// \param Result on a successful parse, contains the parsed unqualified-id. +/// +/// \returns true if parsing fails, false otherwise. +bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, + TypeTy *ObjectType, + UnqualifiedId &Result) { + assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword"); + + // Consume the 'operator' keyword. + SourceLocation KeywordLoc = ConsumeToken(); + + // Determine what kind of operator name we have. + unsigned SymbolIdx = 0; + SourceLocation SymbolLocations[3]; + OverloadedOperatorKind Op = OO_None; + switch (Tok.getKind()) { + case tok::kw_new: + case tok::kw_delete: { + bool isNew = Tok.getKind() == tok::kw_new; + // Consume the 'new' or 'delete'. + SymbolLocations[SymbolIdx++] = ConsumeToken(); + if (Tok.is(tok::l_square)) { + // Consume the '['. + SourceLocation LBracketLoc = ConsumeBracket(); + // Consume the ']'. + SourceLocation RBracketLoc = MatchRHSPunctuation(tok::r_square, + LBracketLoc); + if (RBracketLoc.isInvalid()) + return true; + + SymbolLocations[SymbolIdx++] = LBracketLoc; + SymbolLocations[SymbolIdx++] = RBracketLoc; + Op = isNew? OO_Array_New : OO_Array_Delete; + } else { + Op = isNew? OO_New : OO_Delete; + } + break; + } + +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + case tok::Token: \ + SymbolLocations[SymbolIdx++] = ConsumeToken(); \ + Op = OO_##Name; \ + break; +#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly) +#include "clang/Basic/OperatorKinds.def" + + case tok::l_paren: { + // Consume the '('. + SourceLocation LParenLoc = ConsumeParen(); + // Consume the ')'. + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, + LParenLoc); + if (RParenLoc.isInvalid()) + return true; + + SymbolLocations[SymbolIdx++] = LParenLoc; + SymbolLocations[SymbolIdx++] = RParenLoc; + Op = OO_Call; + break; + } + + case tok::l_square: { + // Consume the '['. + SourceLocation LBracketLoc = ConsumeBracket(); + // Consume the ']'. + SourceLocation RBracketLoc = MatchRHSPunctuation(tok::r_square, + LBracketLoc); + if (RBracketLoc.isInvalid()) + return true; + + SymbolLocations[SymbolIdx++] = LBracketLoc; + SymbolLocations[SymbolIdx++] = RBracketLoc; + Op = OO_Subscript; + break; + } + + case tok::code_completion: { + // Code completion for the operator name. + Actions.CodeCompleteOperatorName(CurScope); + + // Consume the operator token. + ConsumeToken(); + + // Don't try to parse any further. + return true; + } + + default: + break; + } + + if (Op != OO_None) { + // We have parsed an operator-function-id. + Result.setOperatorFunctionId(KeywordLoc, Op, SymbolLocations); + return false; + } + + // Parse a conversion-function-id. + // + // conversion-function-id: [C++ 12.3.2] + // operator conversion-type-id + // + // conversion-type-id: + // type-specifier-seq conversion-declarator[opt] + // + // conversion-declarator: + // ptr-operator conversion-declarator[opt] + + // Parse the type-specifier-seq. + DeclSpec DS; + if (ParseCXXTypeSpecifierSeq(DS)) + return true; + + // Parse the conversion-declarator, which is merely a sequence of + // ptr-operators. + Declarator D(DS, Declarator::TypeNameContext); + ParseDeclaratorInternal(D, /*DirectDeclParser=*/0); + + // Finish up the type. + Action::TypeResult Ty = Actions.ActOnTypeName(CurScope, D); + if (Ty.isInvalid()) + return true; + + // Note that this is a conversion-function-id. + Result.setConversionFunctionId(KeywordLoc, Ty.get(), + D.getSourceRange().getEnd()); + return false; +} + +/// \brief Parse a C++ unqualified-id (or a C identifier), which describes the +/// name of an entity. +/// +/// \code +/// unqualified-id: [C++ expr.prim.general] +/// identifier +/// operator-function-id +/// conversion-function-id +/// [C++0x] literal-operator-id [TODO] +/// ~ class-name +/// template-id +/// +/// \endcode +/// +/// \param The nested-name-specifier that preceded this unqualified-id. If +/// non-empty, then we are parsing the unqualified-id of a qualified-id. +/// +/// \param EnteringContext whether we are entering the scope of the +/// nested-name-specifier. +/// +/// \param AllowDestructorName whether we allow parsing of a destructor name. +/// +/// \param AllowConstructorName whether we allow parsing a constructor name. +/// +/// \param ObjectType if this unqualified-id occurs within a member access +/// expression, the type of the base object whose member is being accessed. +/// +/// \param Result on a successful parse, contains the parsed unqualified-id. +/// +/// \returns true if parsing fails, false otherwise. +bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, + bool AllowDestructorName, + bool AllowConstructorName, + TypeTy *ObjectType, + UnqualifiedId &Result) { + // unqualified-id: + // identifier + // template-id (when it hasn't already been annotated) + if (Tok.is(tok::identifier)) { + // Consume the identifier. + IdentifierInfo *Id = Tok.getIdentifierInfo(); + SourceLocation IdLoc = ConsumeToken(); + + if (AllowConstructorName && + Actions.isCurrentClassName(*Id, CurScope, &SS)) { + // We have parsed a constructor name. + Result.setConstructorName(Actions.getTypeName(*Id, IdLoc, CurScope, + &SS, false), + IdLoc, IdLoc); + } else { + // We have parsed an identifier. + Result.setIdentifier(Id, IdLoc); + } + + // If the next token is a '<', we may have a template. + if (Tok.is(tok::less)) + return ParseUnqualifiedIdTemplateId(SS, Id, IdLoc, EnteringContext, + ObjectType, Result); + + return false; + } + + // unqualified-id: + // template-id (already parsed and annotated) + if (Tok.is(tok::annot_template_id)) { + // FIXME: Could this be a constructor name??? + + // We have already parsed a template-id; consume the annotation token as + // our unqualified-id. + Result.setTemplateId( + static_cast<TemplateIdAnnotation*>(Tok.getAnnotationValue())); + ConsumeToken(); + return false; + } + + // unqualified-id: + // operator-function-id + // conversion-function-id + if (Tok.is(tok::kw_operator)) { + if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, Result)) + return true; + + // If we have an operator-function-id and the next token is a '<', we may + // have a + // + // template-id: + // operator-function-id < template-argument-list[opt] > + if (Result.getKind() == UnqualifiedId::IK_OperatorFunctionId && + Tok.is(tok::less)) + return ParseUnqualifiedIdTemplateId(SS, 0, SourceLocation(), + EnteringContext, ObjectType, + Result); + + return false; + } + + if ((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 + // unary complement rather than treating ~X as referring to a destructor. + + // Parse the '~'. + SourceLocation TildeLoc = ConsumeToken(); + + // Parse the class-name. + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_destructor_class_name); + return true; + } + + // Parse the class-name (or template-name in a simple-template-id). + IdentifierInfo *ClassName = Tok.getIdentifierInfo(); + SourceLocation ClassNameLoc = ConsumeToken(); + + if (Tok.is(tok::less)) { + Result.setDestructorName(TildeLoc, 0, ClassNameLoc); + return ParseUnqualifiedIdTemplateId(SS, ClassName, ClassNameLoc, + EnteringContext, ObjectType, Result); + } + + // Note that this is a destructor name. + Action::TypeTy *Ty = Actions.getTypeName(*ClassName, ClassNameLoc, + CurScope, &SS); + if (!Ty) { + if (ObjectType) + Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) + << ClassName; + else + Diag(ClassNameLoc, diag::err_destructor_class_name); + return true; + } + + Result.setDestructorName(TildeLoc, Ty, ClassNameLoc); + return false; + } + + Diag(Tok, diag::err_expected_unqualified_id) + << getLang().CPlusPlus; + return true; +} + /// TryParseOperatorFunctionId - Attempts to parse a C++ overloaded /// operator name (C++ [over.oper]). If successful, returns the /// predefined identifier that corresponds to that overloaded diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 2e0cd6d..b043dd99 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -305,51 +305,68 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, if (Tok.is(tok::l_paren)) ParseObjCPropertyAttribute(OCDS); + struct ObjCPropertyCallback : FieldCallback { + Parser &P; + DeclPtrTy IDecl; + llvm::SmallVectorImpl<DeclPtrTy> &Props; + ObjCDeclSpec &OCDS; + SourceLocation AtLoc; + tok::ObjCKeywordKind MethodImplKind; + + ObjCPropertyCallback(Parser &P, DeclPtrTy IDecl, + llvm::SmallVectorImpl<DeclPtrTy> &Props, + ObjCDeclSpec &OCDS, SourceLocation AtLoc, + tok::ObjCKeywordKind MethodImplKind) : + P(P), IDecl(IDecl), Props(Props), OCDS(OCDS), AtLoc(AtLoc), + MethodImplKind(MethodImplKind) { + } + + DeclPtrTy invoke(FieldDeclarator &FD) { + if (FD.D.getIdentifier() == 0) { + P.Diag(AtLoc, diag::err_objc_property_requires_field_name) + << FD.D.getSourceRange(); + return DeclPtrTy(); + } + if (FD.BitfieldSize) { + P.Diag(AtLoc, diag::err_objc_property_bitfield) + << FD.D.getSourceRange(); + return DeclPtrTy(); + } + + // Install the property declarator into interfaceDecl. + IdentifierInfo *SelName = + OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier(); + + Selector GetterSel = + P.PP.getSelectorTable().getNullarySelector(SelName); + IdentifierInfo *SetterName = OCDS.getSetterName(); + Selector SetterSel; + if (SetterName) + SetterSel = P.PP.getSelectorTable().getSelector(1, &SetterName); + else + SetterSel = SelectorTable::constructSetterName(P.PP.getIdentifierTable(), + P.PP.getSelectorTable(), + FD.D.getIdentifier()); + bool isOverridingProperty = false; + DeclPtrTy Property = + P.Actions.ActOnProperty(P.CurScope, AtLoc, FD, OCDS, + GetterSel, SetterSel, IDecl, + &isOverridingProperty, + MethodImplKind); + if (!isOverridingProperty) + Props.push_back(Property); + + return Property; + } + } Callback(*this, interfaceDecl, allProperties, + OCDS, AtLoc, MethodImplKind); + // Parse all the comma separated declarators. DeclSpec DS; - llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators; - ParseStructDeclaration(DS, FieldDeclarators); + ParseStructDeclaration(DS, Callback); ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list, "", tok::at); - - // Convert them all to property declarations. - for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) { - FieldDeclarator &FD = FieldDeclarators[i]; - if (FD.D.getIdentifier() == 0) { - Diag(AtLoc, diag::err_objc_property_requires_field_name) - << FD.D.getSourceRange(); - continue; - } - if (FD.BitfieldSize) { - Diag(AtLoc, diag::err_objc_property_bitfield) - << FD.D.getSourceRange(); - continue; - } - - // Install the property declarator into interfaceDecl. - IdentifierInfo *SelName = - OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier(); - - Selector GetterSel = - PP.getSelectorTable().getNullarySelector(SelName); - IdentifierInfo *SetterName = OCDS.getSetterName(); - Selector SetterSel; - if (SetterName) - SetterSel = PP.getSelectorTable().getSelector(1, &SetterName); - else - SetterSel = SelectorTable::constructSetterName(PP.getIdentifierTable(), - PP.getSelectorTable(), - FD.D.getIdentifier()); - bool isOverridingProperty = false; - DeclPtrTy Property = Actions.ActOnProperty(CurScope, AtLoc, FD, OCDS, - GetterSel, SetterSel, - interfaceDecl, - &isOverridingProperty, - MethodImplKind); - if (!isOverridingProperty) - allProperties.push_back(Property); - } break; } } @@ -681,6 +698,8 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, tok::TokenKind mType, DeclPtrTy IDecl, tok::ObjCKeywordKind MethodImplKind) { + ParsingDeclRAIIObject PD(*this); + // Parse the return type if present. TypeTy *ReturnType = 0; ObjCDeclSpec DSRet; @@ -707,10 +726,13 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, MethodAttrs = ParseAttributes(); Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent); - return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), + DeclPtrTy Result + = Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), mType, IDecl, DSRet, ReturnType, Sel, 0, CargNames, MethodAttrs, MethodImplKind); + PD.complete(Result); + return Result; } llvm::SmallVector<IdentifierInfo *, 12> KeyIdents; @@ -783,10 +805,13 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, return DeclPtrTy(); Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(), &KeyIdents[0]); - return Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), + DeclPtrTy Result + = Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), mType, IDecl, DSRet, ReturnType, Sel, &ArgInfos[0], CargNames, MethodAttrs, MethodImplKind, isVariadic); + PD.complete(Result); + return Result; } /// objc-protocol-refs: @@ -858,7 +883,6 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, SourceLocation atLoc) { assert(Tok.is(tok::l_brace) && "expected {"); llvm::SmallVector<DeclPtrTy, 32> AllIvarDecls; - llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators; ParseScope ClassScope(this, Scope::DeclScope|Scope::ClassScope); @@ -893,21 +917,31 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, } } + struct ObjCIvarCallback : FieldCallback { + Parser &P; + DeclPtrTy IDecl; + tok::ObjCKeywordKind visibility; + llvm::SmallVectorImpl<DeclPtrTy> &AllIvarDecls; + + ObjCIvarCallback(Parser &P, DeclPtrTy IDecl, tok::ObjCKeywordKind V, + llvm::SmallVectorImpl<DeclPtrTy> &AllIvarDecls) : + P(P), IDecl(IDecl), visibility(V), AllIvarDecls(AllIvarDecls) { + } + + DeclPtrTy invoke(FieldDeclarator &FD) { + // Install the declarator into the interface decl. + DeclPtrTy Field + = P.Actions.ActOnIvar(P.CurScope, + FD.D.getDeclSpec().getSourceRange().getBegin(), + IDecl, FD.D, FD.BitfieldSize, visibility); + AllIvarDecls.push_back(Field); + return Field; + } + } Callback(*this, interfaceDecl, visibility, AllIvarDecls); + // Parse all the comma separated declarators. DeclSpec DS; - FieldDeclarators.clear(); - ParseStructDeclaration(DS, FieldDeclarators); - - // Convert them all to fields. - for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) { - FieldDeclarator &FD = FieldDeclarators[i]; - // Install the declarator into interfaceDecl. - DeclPtrTy Field = Actions.ActOnIvar(CurScope, - DS.getSourceRange().getBegin(), - interfaceDecl, - FD.D, FD.BitfieldSize, visibility); - AllIvarDecls.push_back(Field); - } + ParseStructDeclaration(DS, Callback); if (Tok.is(tok::semi)) { ConsumeToken(); diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 272be2f..7637382 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -938,8 +938,7 @@ Parser::OwningStmtResult Parser::ParseForStatement() { Diag(Tok, diag::ext_c99_variable_decl_in_for_loop); SourceLocation DeclStart = Tok.getLocation(), DeclEnd; - DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd, - false); + DeclGroupPtrTy DG = ParseSimpleDeclaration(Declarator::ForContext, DeclEnd); FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); if (Tok.is(tok::semi)) { // for (int x = 4; diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 8e63fb8..045acd8 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -101,6 +101,7 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, // (and retrieves the outer template parameter list from its // context). bool isSpecialization = true; + bool LastParamListWasEmpty = false; TemplateParameterLists ParamLists; TemplateParameterDepthCounter Depth(TemplateParameterDepth); do { @@ -140,13 +141,16 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, if (!TemplateParams.empty()) { isSpecialization = false; ++Depth; + } else { + LastParamListWasEmpty = true; } } while (Tok.is(tok::kw_export) || Tok.is(tok::kw_template)); // Parse the actual template declaration. return ParseSingleDeclarationAfterTemplate(Context, ParsedTemplateInfo(&ParamLists, - isSpecialization), + isSpecialization, + LastParamListWasEmpty), DeclEnd, AS); } @@ -186,16 +190,18 @@ Parser::ParseSingleDeclarationAfterTemplate( } // Parse the declaration specifiers. - DeclSpec DS; + ParsingDeclSpec DS(*this); ParseDeclarationSpecifiers(DS, TemplateInfo, AS); if (Tok.is(tok::semi)) { DeclEnd = ConsumeToken(); - return Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + DeclPtrTy Decl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + DS.complete(Decl); + return Decl; } // Parse the declarator. - Declarator DeclaratorInfo(DS, (Declarator::TheContext)Context); + ParsingDeclarator DeclaratorInfo(*this, DS, (Declarator::TheContext)Context); ParseDeclarator(DeclaratorInfo); // Error parsing the declarator? if (!DeclaratorInfo.hasName()) { @@ -221,6 +227,7 @@ Parser::ParseSingleDeclarationAfterTemplate( // Eat the semi colon after the declaration. ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration); + DS.complete(ThisDecl); return ThisDecl; } @@ -668,22 +675,23 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, /// bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, const CXXScopeSpec *SS, + UnqualifiedId &TemplateName, SourceLocation TemplateKWLoc, bool AllowTypeAnnotation) { assert(getLang().CPlusPlus && "Can only annotate template-ids in C++"); - assert(Template && Tok.is(tok::identifier) && NextToken().is(tok::less) && + assert(Template && Tok.is(tok::less) && "Parser isn't at the beginning of a template-id"); // Consume the template-name. - IdentifierInfo *Name = Tok.getIdentifierInfo(); - SourceLocation TemplateNameLoc = ConsumeToken(); + SourceLocation TemplateNameLoc = TemplateName.getSourceRange().getBegin(); // Parse the enclosed template argument list. SourceLocation LAngleLoc, RAngleLoc; TemplateArgList TemplateArgs; TemplateArgIsTypeList TemplateArgIsType; TemplateArgLocationList TemplateArgLocations; - bool Invalid = ParseTemplateIdAfterTemplateName(Template, TemplateNameLoc, + bool Invalid = ParseTemplateIdAfterTemplateName(Template, + TemplateNameLoc, SS, false, LAngleLoc, TemplateArgs, TemplateArgIsType, @@ -732,7 +740,13 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Allocate(TemplateArgs.size()); TemplateId->TemplateNameLoc = TemplateNameLoc; - TemplateId->Name = Name; + if (TemplateName.getKind() == UnqualifiedId::IK_Identifier) { + TemplateId->Name = TemplateName.Identifier; + TemplateId->Operator = OO_None; + } else { + TemplateId->Name = 0; + TemplateId->Operator = TemplateName.OperatorFunctionId.Operator; + } TemplateId->Template = Template.getAs<void*>(); TemplateId->Kind = TNK; TemplateId->LAngleLoc = LAngleLoc; diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index bc737e9..335a6cf 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -526,7 +526,7 @@ bool Parser::isStartOfFunctionDefinition() { Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { // Parse the common declaration-specifiers piece. - DeclSpec DS; + ParsingDeclSpec DS(*this); ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS); // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" @@ -534,6 +534,7 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { if (Tok.is(tok::semi)) { ConsumeToken(); DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(CurScope, DS); + DS.complete(TheDecl); return Actions.ConvertDeclToDeclGroup(TheDecl); } @@ -548,6 +549,9 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { SkipUntil(tok::semi); // FIXME: better skip? return DeclGroupPtrTy(); } + + DS.abort(); + const char *PrevSpec = 0; unsigned DiagID; if (DS.SetTypeSpecType(DeclSpec::TST_unspecified, AtLoc, PrevSpec, DiagID)) @@ -567,58 +571,12 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { if (Tok.is(tok::string_literal) && getLang().CPlusPlus && DS.getStorageClassSpec() == DeclSpec::SCS_extern && DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) { + DS.abort(); DeclPtrTy TheDecl = ParseLinkage(Declarator::FileContext); return Actions.ConvertDeclToDeclGroup(TheDecl); } - // Parse the first declarator. - Declarator DeclaratorInfo(DS, Declarator::FileContext); - ParseDeclarator(DeclaratorInfo); - // Error parsing the declarator? - if (!DeclaratorInfo.hasName()) { - // If so, skip until the semi-colon or a }. - SkipUntil(tok::r_brace, true, true); - if (Tok.is(tok::semi)) - ConsumeToken(); - return DeclGroupPtrTy(); - } - - // If we have a declaration or declarator list, handle it. - if (isDeclarationAfterDeclarator()) { - // Parse the init-declarator-list for a normal declaration. - DeclGroupPtrTy DG = - ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo); - // Eat the semi colon after the declaration. - ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration); - return DG; - } - - if (DeclaratorInfo.isFunctionDeclarator() && - isStartOfFunctionDefinition()) { - if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { - Diag(Tok, diag::err_function_declared_typedef); - - if (Tok.is(tok::l_brace)) { - // This recovery skips the entire function body. It would be nice - // to simply call ParseFunctionDefinition() below, however Sema - // assumes the declarator represents a function, not a typedef. - ConsumeBrace(); - SkipUntil(tok::r_brace, true); - } else { - SkipUntil(tok::semi); - } - return DeclGroupPtrTy(); - } - DeclPtrTy TheDecl = ParseFunctionDefinition(DeclaratorInfo); - return Actions.ConvertDeclToDeclGroup(TheDecl); - } - - if (DeclaratorInfo.isFunctionDeclarator()) - Diag(Tok, diag::err_expected_fn_body); - else - Diag(Tok, diag::err_invalid_token_after_toplevel_declarator); - SkipUntil(tok::semi); - return DeclGroupPtrTy(); + return ParseDeclGroup(DS, Declarator::FileContext, true); } /// ParseFunctionDefinition - We parsed and verified that the specified @@ -635,7 +593,7 @@ Parser::ParseDeclarationOrFunctionDefinition(AccessSpecifier AS) { /// [C++] function-definition: [C++ 8.4] /// decl-specifier-seq[opt] declarator function-try-block /// -Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D, +Parser::DeclPtrTy Parser::ParseFunctionDefinition(ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo) { const DeclaratorChunk &FnTypeInfo = D.getTypeObject(0); assert(FnTypeInfo.Kind == DeclaratorChunk::Function && @@ -687,6 +645,13 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D, D) : Actions.ActOnStartOfFunctionDef(CurScope, D); + // Break out of the ParsingDeclarator context before we parse the body. + D.complete(Res); + + // Break out of the ParsingDeclSpec context, too. This const_cast is + // safe because we're always the sole owner. + D.getMutableDeclSpec().abort(); + if (Tok.is(tok::kw_try)) return ParseFunctionTryBlock(Res); @@ -981,17 +946,21 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { // If this is a template-id, annotate with a template-id or type token. if (NextToken().is(tok::less)) { TemplateTy Template; + UnqualifiedId TemplateName; + TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); if (TemplateNameKind TNK - = Actions.isTemplateName(CurScope, *Tok.getIdentifierInfo(), - Tok.getLocation(), &SS, + = Actions.isTemplateName(CurScope, SS, TemplateName, /*ObjectType=*/0, EnteringContext, - Template)) - if (AnnotateTemplateIdToken(Template, TNK, &SS)) { + Template)) { + // Consume the identifier. + ConsumeToken(); + if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName)) { // If an unrecoverable error occurred, we need to return true here, // because the token stream is in a damaged state. We may not return // a valid identifier. return Tok.isNot(tok::identifier); } + } } // The current token, which is either an identifier or a @@ -1065,3 +1034,10 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { PP.AnnotateCachedTokens(Tok); return true; } + +// Anchor the Parser::FieldCallback vtable to this translation unit. +// We use a spurious method instead of the destructor because +// destroying FieldCallbacks can actually be slightly +// performance-sensitive. +void Parser::FieldCallback::_anchor() { +} diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index c78ab5b..9b24d55 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -156,6 +156,17 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results, case Result::RK_Keyword: OS << Results[I].Keyword << " : " << Results[I].Rank << '\n'; break; + + case Result::RK_Macro: { + OS << Results[I].Macro->getName() << " : " << Results[I].Rank; + if (CodeCompletionString *CCS + = Results[I].CreateCodeCompletionString(SemaRef)) { + OS << " : " << CCS->getAsString(); + delete CCS; + } + OS << '\n'; + break; + } } } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index fc9c14f..8104dd3 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -277,15 +277,20 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { PushDeclContext(S, Context.getTranslationUnitDecl()); if (PP.getTargetInfo().getPointerWidth(0) >= 64) { + DeclaratorInfo *DInfo; + // Install [u]int128_t for 64-bit targets. + DInfo = Context.getTrivialDeclaratorInfo(Context.Int128Ty); PushOnScopeChains(TypedefDecl::Create(Context, CurContext, SourceLocation(), &Context.Idents.get("__int128_t"), - Context.Int128Ty), TUScope); + DInfo), TUScope); + + DInfo = Context.getTrivialDeclaratorInfo(Context.UnsignedInt128Ty); PushOnScopeChains(TypedefDecl::Create(Context, CurContext, SourceLocation(), &Context.Idents.get("__uint128_t"), - Context.UnsignedInt128Ty), TUScope); + DInfo), TUScope); } @@ -298,10 +303,10 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { PushOnScopeChains(SelTag, TUScope); QualType SelT = Context.getPointerType(Context.getTagDeclType(SelTag)); - TypedefDecl *SelTypedef = TypedefDecl::Create(Context, CurContext, - SourceLocation(), - &Context.Idents.get("SEL"), - SelT); + DeclaratorInfo *SelInfo = Context.getTrivialDeclaratorInfo(SelT); + TypedefDecl *SelTypedef + = TypedefDecl::Create(Context, CurContext, SourceLocation(), + &Context.Idents.get("SEL"), SelInfo); PushOnScopeChains(SelTypedef, TUScope); Context.setObjCSelType(Context.getTypeDeclType(SelTypedef)); } @@ -317,22 +322,23 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { } // Create the built-in typedef for 'id'. if (Context.getObjCIdType().isNull()) { - TypedefDecl *IdTypedef = - TypedefDecl::Create( - Context, CurContext, SourceLocation(), &Context.Idents.get("id"), - Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy) - ); + QualType IdT = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy); + DeclaratorInfo *IdInfo = Context.getTrivialDeclaratorInfo(IdT); + TypedefDecl *IdTypedef + = TypedefDecl::Create(Context, CurContext, SourceLocation(), + &Context.Idents.get("id"), IdInfo); PushOnScopeChains(IdTypedef, TUScope); Context.setObjCIdType(Context.getTypeDeclType(IdTypedef)); Context.ObjCIdRedefinitionType = Context.getObjCIdType(); } // Create the built-in typedef for 'Class'. if (Context.getObjCClassType().isNull()) { - TypedefDecl *ClassTypedef = - TypedefDecl::Create( - Context, CurContext, SourceLocation(), &Context.Idents.get("Class"), - Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy) - ); + QualType ClassType + = Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy); + DeclaratorInfo *ClassInfo = Context.getTrivialDeclaratorInfo(ClassType); + TypedefDecl *ClassTypedef + = TypedefDecl::Create(Context, CurContext, SourceLocation(), + &Context.Idents.get("Class"), ClassInfo); PushOnScopeChains(ClassTypedef, TUScope); Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef)); Context.ObjCClassRedefinitionType = Context.getObjCClassType(); @@ -344,7 +350,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, : LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), ExternalSource(0), CodeCompleter(0), CurContext(0), - PreDeclaratorDC(0), CurBlock(0), PackContext(0), + PreDeclaratorDC(0), CurBlock(0), PackContext(0), ParsingDeclDepth(0), IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0), GlobalNewDeleteDeclared(false), ExprEvalContext(PotentiallyEvaluated), CompleteTranslationUnit(CompleteTranslationUnit), diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 6dd081b..0f84b46 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -73,6 +73,7 @@ namespace clang { class TypedefDecl; class TemplateDecl; class TemplateArgument; + class TemplateArgumentLoc; class TemplateArgumentList; class TemplateParameterList; class TemplateTemplateParmDecl; @@ -271,6 +272,15 @@ public: llvm::DenseMap<DeclarationName, VarDecl *> TentativeDefinitions; std::vector<DeclarationName> TentativeDefinitionList; + /// \brief The collection of delayed deprecation warnings. + llvm::SmallVector<std::pair<SourceLocation,NamedDecl*>, 8> + DelayedDeprecationWarnings; + + /// \brief The depth of the current ParsingDeclaration stack. + /// If nonzero, we are currently parsing a declaration (and + /// hence should delay deprecation warnings). + unsigned ParsingDeclDepth; + /// WeakUndeclaredIdentifiers - Identifiers contained in /// #pragma weak before declared. rare. may alias another /// identifier, declared or undeclared @@ -447,8 +457,6 @@ public: // Type Analysis / Processing: SemaType.cpp. // QualType adjustParameterType(QualType T); - QualType ConvertDeclSpecToType(const DeclSpec &DS, SourceLocation DeclLoc, - bool &IsInvalid); void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL); QualType BuildPointerType(QualType T, unsigned Quals, SourceLocation Loc, DeclarationName Entity); @@ -470,12 +478,12 @@ public: SourceLocation Loc, DeclarationName Entity); QualType GetTypeForDeclarator(Declarator &D, Scope *S, DeclaratorInfo **DInfo = 0, - unsigned Skip = 0, TagDecl **OwnedDecl = 0); - DeclaratorInfo *GetDeclaratorInfoForDeclarator(Declarator &D, QualType T, - unsigned Skip); + TagDecl **OwnedDecl = 0); + DeclaratorInfo *GetDeclaratorInfoForDeclarator(Declarator &D, QualType T); /// \brief Create a LocInfoType to hold the given QualType and DeclaratorInfo. QualType CreateLocInfoType(QualType T, DeclaratorInfo *DInfo); DeclarationName GetNameForDeclarator(Declarator &D); + DeclarationName GetNameFromUnqualifiedId(UnqualifiedId &Name); static QualType GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo = 0); bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range); bool CheckDistantExceptionSpec(QualType T); @@ -767,7 +775,8 @@ public: /// Subroutines of ActOnDeclarator(). - TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T); + TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T, + DeclaratorInfo *DInfo); void MergeTypeDefDecl(TypedefDecl *New, Decl *Old); bool MergeFunctionDecl(FunctionDecl *New, Decl *Old); bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old); @@ -868,7 +877,7 @@ public: bool ForceRValue = false); void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, Expr *Object, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, @@ -876,7 +885,7 @@ public: bool ForceRValue = false); void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, @@ -914,7 +923,7 @@ public: void AddArgumentDependentLookupCandidates(DeclarationName Name, Expr **Args, unsigned NumArgs, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, OverloadCandidateSet& CandidateSet, bool PartialOverloading = false); @@ -936,7 +945,7 @@ public: DeclarationName &UnqualifiedName, bool &ArgumentDependentLookup, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet &CandidateSet, @@ -945,7 +954,7 @@ public: FunctionDecl *ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee, DeclarationName UnqualifiedName, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, @@ -963,6 +972,10 @@ public: FunctionSet &Functions, Expr *LHS, Expr *RHS); + OwningExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, + SourceLocation RLoc, + ExprArg Base,ExprArg Idx); + ExprResult BuildCallToMemberFunction(Scope *S, Expr *MemExpr, SourceLocation LParenLoc, Expr **Args, @@ -990,7 +1003,7 @@ public: void CheckCXXDefaultArguments(FunctionDecl *FD); void CheckExtraCXXDefaultArguments(Declarator &D); enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1, - AlwaysFallThrough = 2 }; + AlwaysFallThrough = 2, NeverFallThroughOrReturn = 3 }; ControlFlowKind CheckFallThrough(Stmt *); Scope *getNonFieldDeclScope(Scope *S); @@ -1377,7 +1390,7 @@ public: QualType T1, QualType T2, FunctionSet &Functions); - void ArgumentDependentLookup(DeclarationName Name, + void ArgumentDependentLookup(DeclarationName Name, bool Operator, Expr **Args, unsigned NumArgs, FunctionSet &Functions); @@ -1582,6 +1595,10 @@ public: /// whose result is unused, warn. void DiagnoseUnusedExprResult(const Stmt *S); + ParsingDeclStackState PushParsingDeclaration(); + void PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy D); + void EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc); + //===--------------------------------------------------------------------===// // Expression Parsing Callbacks: SemaExpr.cpp. @@ -1604,23 +1621,12 @@ public: // Primary Expressions. virtual SourceRange getExprRange(ExprTy *E) const; - virtual OwningExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc, - IdentifierInfo &II, - bool HasTrailingLParen, - const CXXScopeSpec *SS = 0, - bool isAddressOfOperand = false); - virtual OwningExprResult ActOnCXXOperatorFunctionIdExpr(Scope *S, - SourceLocation OperatorLoc, - OverloadedOperatorKind Op, - bool HasTrailingLParen, - const CXXScopeSpec &SS, - bool isAddressOfOperand); - virtual OwningExprResult ActOnCXXConversionFunctionExpr(Scope *S, - SourceLocation OperatorLoc, - TypeTy *Ty, - bool HasTrailingLParen, - const CXXScopeSpec &SS, - bool isAddressOfOperand); + virtual OwningExprResult ActOnIdExpression(Scope *S, + const CXXScopeSpec &SS, + UnqualifiedId &Name, + bool HasTrailingLParen, + bool IsAddressOfOperand); + OwningExprResult BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc, bool TypeDependent, bool ValueDependent, @@ -1664,7 +1670,8 @@ public: virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Op, ExprArg Input); - OwningExprResult CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc, + OwningExprResult CreateSizeOfAlignOfExpr(DeclaratorInfo *T, + SourceLocation OpLoc, bool isSizeOf, SourceRange R); OwningExprResult CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc, bool isSizeOf, SourceRange R); @@ -1684,6 +1691,10 @@ public: SourceLocation LLoc, ExprArg Idx, SourceLocation RLoc); + OwningExprResult CreateBuiltinArraySubscriptExpr(ExprArg Base, + SourceLocation LLoc, + ExprArg Idx, + SourceLocation RLoc); OwningExprResult BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, @@ -1709,20 +1720,21 @@ public: DeclarationName MemberName, bool HasExplicitTemplateArgs, SourceLocation LAngleLoc, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, SourceLocation RAngleLoc, DeclPtrTy ImplDecl, const CXXScopeSpec *SS, NamedDecl *FirstQualifierInScope = 0); - virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation MemberLoc, - IdentifierInfo &Member, - DeclPtrTy ImplDecl, - const CXXScopeSpec *SS = 0); + virtual OwningExprResult ActOnMemberAccessExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + UnqualifiedId &Member, + DeclPtrTy ObjCImpDecl, + bool HasTrailingLParen); + virtual void ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl); bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, FunctionDecl *FDecl, @@ -1742,7 +1754,7 @@ public: SourceRange &QualifierRange, bool &ArgumentDependentLookup, bool &HasExplicitTemplateArguments, - const TemplateArgument *&ExplicitTemplateArgs, + const TemplateArgumentLoc *&ExplicitTemplateArgs, unsigned &NumExplicitTemplateArgs); /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. @@ -1900,7 +1912,6 @@ public: /// and sets it as the initializer for the the passed in VarDecl. bool InitializeVarWithConstructor(VarDecl *VD, CXXConstructorDecl *Constructor, - QualType DeclInitType, MultiExprArg Exprs); /// BuildCXXConstructExpr - Creates a complete call to a constructor, @@ -2099,52 +2110,6 @@ public: tok::TokenKind OpKind, TypeTy *&ObjectType); - virtual OwningExprResult - ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation ClassNameLoc, - IdentifierInfo *ClassName, - const CXXScopeSpec &SS, - bool HasTrailingLParen); - - virtual OwningExprResult - ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceRange TypeRange, - TypeTy *Type, - const CXXScopeSpec &SS, - bool HasTrailingLParen); - - virtual OwningExprResult - ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation ClassNameLoc, - OverloadedOperatorKind OverOpKind, - const CXXScopeSpec *SS = 0); - virtual OwningExprResult - ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation ClassNameLoc, - TypeTy *Ty, - const CXXScopeSpec *SS = 0); - - virtual OwningExprResult - ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - const CXXScopeSpec &SS, - // FIXME: "template" keyword? - TemplateTy Template, - SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgs, - SourceLocation *TemplateArgLocs, - SourceLocation RAngleLoc); - /// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is /// non-empty, will create a new CXXExprWithTemporaries expression. /// Otherwise, just returs the passed in expression. @@ -2305,7 +2270,7 @@ public: SourceLocation RParenLoc, CXXRecordDecl *ClassDecl); - void setBaseOrMemberInitializers(CXXConstructorDecl *Constructor, + void SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, CXXBaseOrMemberInitializer **Initializers, unsigned NumInitializers, llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases, @@ -2445,9 +2410,8 @@ public: // C++ Templates [C++ 14] // virtual TemplateNameKind isTemplateName(Scope *S, - const IdentifierInfo &II, - SourceLocation IdLoc, - const CXXScopeSpec *SS, + const CXXScopeSpec &SS, + UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringContext, TemplateTy &Template); @@ -2507,13 +2471,13 @@ public: AccessSpecifier AS); void translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, - SourceLocation *TemplateArgLocs, - llvm::SmallVector<TemplateArgument, 16> &TemplateArgs); + SourceLocation *TemplateArgLocsIn, + llvm::SmallVector<TemplateArgumentLoc, 16> &TempArgs); QualType CheckTemplateIdType(TemplateName Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc); @@ -2534,22 +2498,21 @@ public: TemplateName Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc); - virtual OwningExprResult ActOnTemplateIdExpr(const CXXScopeSpec &SS, - TemplateTy Template, - SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgs, - SourceLocation *TemplateArgLocs, - SourceLocation RAngleLoc); + OwningExprResult ActOnTemplateIdExpr(const CXXScopeSpec &SS, + TemplateTy Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc); virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc, - const IdentifierInfo &Name, - SourceLocation NameLoc, const CXXScopeSpec &SS, + UnqualifiedId &Name, TypeTy *ObjectType); bool CheckClassTemplatePartialSpecializationArgs( @@ -2578,10 +2541,18 @@ public: MultiTemplateParamsArg TemplateParameterLists, Declarator &D); + bool + CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, + TemplateSpecializationKind NewTSK, + NamedDecl *PrevDecl, + TemplateSpecializationKind PrevTSK, + SourceLocation PrevPointOfInstantiation, + bool &SuppressNew); + bool CheckFunctionTemplateSpecialization(FunctionDecl *FD, bool HasExplicitTemplateArgs, SourceLocation LAngleLoc, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, SourceLocation RAngleLoc, NamedDecl *&PrevDecl); @@ -2621,18 +2592,18 @@ public: bool CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc, bool PartialTemplateArgs, TemplateArgumentListBuilder &Converted); bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, - const TemplateArgument &Arg, + const TemplateArgumentLoc &Arg, TemplateArgumentListBuilder &Converted); - bool CheckTemplateArgument(TemplateTypeParmDecl *Param, QualType Arg, - SourceLocation ArgLoc); + bool CheckTemplateArgument(TemplateTypeParmDecl *Param, + DeclaratorInfo *Arg); bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, NamedDecl *&Entity); bool CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member); @@ -2807,7 +2778,7 @@ public: TemplateDeductionResult SubstituteExplicitTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, llvm::SmallVectorImpl<TemplateArgument> &Deduced, llvm::SmallVectorImpl<QualType> &ParamTypes, @@ -2823,7 +2794,7 @@ public: TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, Expr **Args, unsigned NumArgs, FunctionDecl *&Specialization, @@ -2832,7 +2803,7 @@ public: TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, QualType ArgFunctionType, FunctionDecl *&Specialization, @@ -2863,6 +2834,7 @@ public: void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, bool OnlyDeduced, + unsigned Depth, llvm::SmallVectorImpl<bool> &Used); void MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, llvm::SmallVectorImpl<bool> &Deduced); @@ -3101,7 +3073,7 @@ public: llvm::DenseMap<const Decl *, Decl *> LocalDecls; /// \brief The outer scope, in which contains local variable - /// definitions from some other instantiation (that is not + /// definitions from some other instantiation (that may not be /// relevant to this particular scope). LocalInstantiationScope *Outer; @@ -3110,9 +3082,13 @@ public: LocalInstantiationScope &operator=(const LocalInstantiationScope &); public: - LocalInstantiationScope(Sema &SemaRef) + LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false) : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope) { - SemaRef.CurrentInstantiationScope = this; + if (!CombineWithOuterScope) + SemaRef.CurrentInstantiationScope = this; + else + assert(SemaRef.CurrentInstantiationScope && + "No outer instantiation scope?"); } ~LocalInstantiationScope() { @@ -3133,6 +3109,11 @@ public: return cast<ParmVarDecl>(getInstantiationOf(cast<Decl>(Var))); } + NonTypeTemplateParmDecl *getInstantiationOf( + const NonTypeTemplateParmDecl *Var) { + return cast<NonTypeTemplateParmDecl>(getInstantiationOf(cast<Decl>(Var))); + } + void InstantiatedLocal(const Decl *D, Decl *Inst) { Decl *&Stored = LocalDecls[D]; assert(!Stored && "Already instantiated this local"); @@ -3190,7 +3171,7 @@ public: bool Complain = true); bool - InstantiateClassTemplateSpecialization( + InstantiateClassTemplateSpecialization(SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, TemplateSpecializationKind TSK, bool Complain = true); @@ -3213,8 +3194,8 @@ public: TemplateName SubstTemplateName(TemplateName Name, SourceLocation Loc, const MultiLevelTemplateArgumentList &TemplateArgs); - TemplateArgument Subst(TemplateArgument Arg, - const MultiLevelTemplateArgumentList &TemplateArgs); + bool Subst(const TemplateArgumentLoc &Arg, TemplateArgumentLoc &Result, + const MultiLevelTemplateArgumentList &TemplateArgs); void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index bf39604..8bb3348 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -83,7 +83,8 @@ static TryCastResult TryStaticDowncast(Sema &Self, QualType SrcType, static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType,bool CStyle, const SourceRange &OpRange, - unsigned &msg); + unsigned &msg, + CastExpr::CastKind &Kind); static TryCastResult TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, @@ -480,7 +481,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *SrcExpr, // conversion. C++ 5.2.9p9 has additional information. // DR54's access restrictions apply here also. tcr = TryStaticMemberPointerUpcast(Self, SrcType, DestType, CStyle, - OpRange, msg); + OpRange, msg, Kind); if (tcr != TC_NotApplicable) return tcr; @@ -706,7 +707,7 @@ TryStaticDowncast(Sema &Self, QualType SrcType, QualType DestType, TryCastResult TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType, bool CStyle, const SourceRange &OpRange, - unsigned &msg) { + unsigned &msg, CastExpr::CastKind &Kind) { const MemberPointerType *DestMemPtr = DestType->getAs<MemberPointerType>(); if (!DestMemPtr) return TC_NotApplicable; @@ -760,6 +761,7 @@ TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType, return TC_Failed; } + Kind = CastExpr::CK_DerivedToBaseMemberPointer; return TC_Success; } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 589b0c6..38b6ebe 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -1272,10 +1272,15 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, // Skip over implicit cast expressions when checking for block expressions. RetValExp = RetValExp->IgnoreParenCasts(); - if (BlockExpr *C = dyn_cast_or_null<BlockExpr>(RetValExp)) + if (BlockExpr *C = dyn_cast<BlockExpr>(RetValExp)) if (C->hasBlockDeclRefExprs()) Diag(C->getLocStart(), diag::err_ret_local_block) << C->getSourceRange(); + + if (AddrLabelExpr *ALE = dyn_cast<AddrLabelExpr>(RetValExp)) + Diag(ALE->getLocStart(), diag::warn_ret_addr_label) + << ALE->getSourceRange(); + } else if (lhsType->isReferenceType()) { // Perform checking for stack values returned by reference. // Check for a reference to the stack @@ -1420,8 +1425,7 @@ static DeclRefExpr* EvalVal(Expr *E) { // viewed AST node. We then recursively traverse the AST by calling // EvalAddr and EvalVal appropriately. switch (E->getStmtClass()) { - case Stmt::DeclRefExprClass: - case Stmt::QualifiedDeclRefExprClass: { + case Stmt::DeclRefExprClass: { // DeclRefExpr: the base case. When we hit a DeclRefExpr we are looking // at code that refers to a variable's name. We check if it has local // storage within the function, and if so, return the expression. diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 3811513..e9df17d 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -13,6 +13,8 @@ #include "Sema.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/AST/ExprCXX.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/Preprocessor.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringExtras.h" #include <list> @@ -801,9 +803,45 @@ void AddQualifierToCompletionString(CodeCompletionString *Result, /// result is all that is needed. CodeCompletionString * CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { - if (Kind != RK_Declaration) + if (Kind == RK_Keyword) return 0; + if (Kind == RK_Macro) { + MacroInfo *MI = S.PP.getMacroInfo(Macro); + if (!MI || !MI->isFunctionLike()) + return 0; + + // Format a function-like macro with placeholders for the arguments. + CodeCompletionString *Result = new CodeCompletionString; + Result->AddTextChunk(Macro->getName().str().c_str()); + Result->AddTextChunk("("); + for (MacroInfo::arg_iterator A = MI->arg_begin(), AEnd = MI->arg_end(); + A != AEnd; ++A) { + if (A != MI->arg_begin()) + Result->AddTextChunk(", "); + + if (!MI->isVariadic() || A != AEnd - 1) { + // Non-variadic argument. + Result->AddPlaceholderChunk((*A)->getName().str().c_str()); + continue; + } + + // Variadic argument; cope with the different between GNU and C99 + // variadic macros, providing a single placeholder for the rest of the + // arguments. + if ((*A)->isStr("__VA_ARGS__")) + Result->AddPlaceholderChunk("..."); + else { + std::string Arg = (*A)->getName(); + Arg += "..."; + Result->AddPlaceholderChunk(Arg.c_str()); + } + } + Result->AddTextChunk(")"); + return Result; + } + + assert(Kind == RK_Declaration && "Missed a macro kind?"); NamedDecl *ND = Declaration; if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) { @@ -999,6 +1037,10 @@ namespace { case Result::RK_Keyword: return strcmp(X.Keyword, Y.Keyword) < 0; + + case Result::RK_Macro: + return llvm::LowercaseString(X.Macro->getName()) < + llvm::LowercaseString(Y.Macro->getName()); } // Silence GCC warning. @@ -1007,6 +1049,16 @@ namespace { }; } +// Add all of the known macros as code-completion results. +static void AddMacroResults(Preprocessor &PP, unsigned Rank, + ResultBuilder &Results) { + Results.EnterNewScope(); + for (Preprocessor::macro_iterator M = PP.macro_begin(), MEnd = PP.macro_end(); + M != MEnd; ++M) + Results.MaybeAddResult(CodeCompleteConsumer::Result(M->first, Rank)); + Results.ExitScope(); +} + static void HandleCodeCompleteResults(CodeCompleteConsumer *CodeCompleter, CodeCompleteConsumer::Result *Results, unsigned NumResults) { @@ -1019,8 +1071,9 @@ static void HandleCodeCompleteResults(CodeCompleteConsumer *CodeCompleter, void Sema::CodeCompleteOrdinaryName(Scope *S) { ResultBuilder Results(*this, &ResultBuilder::IsOrdinaryName); - CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, - Results); + unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), + 0, CurContext, Results); + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1076,6 +1129,9 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, CurContext, Results); } + // Add macros + AddMacroResults(PP, NextRank, Results); + // Hand off the results found for code completion. HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); @@ -1117,10 +1173,11 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { // We could have the start of a nested-name-specifier. Add those // results as well. Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); - CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank, - CurContext, Results); + NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), + NextRank, CurContext, Results); } + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1171,8 +1228,7 @@ void Sema::CodeCompleteCase(Scope *S) { // At the XXX, our completions are TagDecl::TK_union, // TagDecl::TK_struct, and TagDecl::TK_class, rather than TK_union, // TK_struct, and TK_class. - if (QualifiedDeclRefExpr *QDRE = dyn_cast<QualifiedDeclRefExpr>(DRE)) - Qualifier = QDRE->getQualifier(); + Qualifier = DRE->getQualifier(); } } @@ -1199,6 +1255,7 @@ void Sema::CodeCompleteCase(Scope *S) { } Results.ExitScope(); + AddMacroResults(PP, 1, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1235,7 +1292,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, SourceRange QualifierRange; bool ArgumentDependentLookup; bool HasExplicitTemplateArgs; - const TemplateArgument *ExplicitTemplateArgs; + const TemplateArgumentLoc *ExplicitTemplateArgs; unsigned NumExplicitTemplateArgs; DeconstructCallFunction(Fn, @@ -1293,6 +1350,7 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, if (!Results.empty() && NNS->isDependent()) Results.MaybeAddResult(CodeCompleteConsumer::Result("template", NextRank)); + AddMacroResults(PP, NextRank + 1, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1309,10 +1367,11 @@ void Sema::CodeCompleteUsing(Scope *S) { // After "using", we can see anything that would start a // nested-name-specifier. - CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, - CurContext, Results); + unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), + 0, CurContext, Results); Results.ExitScope(); + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1324,9 +1383,10 @@ void Sema::CodeCompleteUsingDirective(Scope *S) { // alias. ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); Results.EnterNewScope(); - CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, - Results); + unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), + 0, CurContext, Results); Results.ExitScope(); + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1361,6 +1421,7 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) { Results.ExitScope(); } + AddMacroResults(PP, 1, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1370,8 +1431,9 @@ void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) { // After "namespace", we expect to see a namespace or alias. ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); - CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, - Results); + unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), + 0, CurContext, Results); + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } @@ -1398,10 +1460,11 @@ void Sema::CodeCompleteOperatorName(Scope *S) { // Add any nested-name-specifiers Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); - CollectLookupResults(S, Context.getTranslationUnitDecl(), NextRank + 1, - CurContext, Results); + NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), + NextRank + 1, CurContext, Results); Results.ExitScope(); + AddMacroResults(PP, NextRank, Results); HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index b83181b..d89cb5f 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -95,7 +95,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, case LookupResult::FoundOverloaded: return 0; - case LookupResult::Ambiguous: { + case LookupResult::Ambiguous: // Recover from type-hiding ambiguities by hiding the type. We'll // do the lookup again when looking for an object, and we can // diagnose the error then. If we don't do this, then the error @@ -131,51 +131,43 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, // perform the name lookup again. DiagnoseAmbiguousLookup(Result, DeclarationName(&II), NameLoc); break; - } case LookupResult::Found: IIDecl = Result.getFoundDecl(); break; } - if (IIDecl) { - QualType T; - - if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) { - // Check whether we can use this type - (void)DiagnoseUseOfDecl(IIDecl, NameLoc); - - if (getLangOptions().CPlusPlus) { - // C++ [temp.local]p2: - // Within the scope of a class template specialization or - // partial specialization, when the injected-class-name is - // not followed by a <, it is equivalent to the - // injected-class-name followed by the template-argument s - // of the class template specialization or partial - // specialization enclosed in <>. - if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD)) - if (RD->isInjectedClassName()) - if (ClassTemplateDecl *Template = RD->getDescribedClassTemplate()) - T = Template->getInjectedClassNameType(Context); - } - - if (T.isNull()) - T = Context.getTypeDeclType(TD); - } else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) { - // Check whether we can use this interface. - (void)DiagnoseUseOfDecl(IIDecl, NameLoc); - - T = Context.getObjCInterfaceType(IDecl); - } else - return 0; + assert(IIDecl && "Didn't find decl"); + QualType T; + if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) { + DiagnoseUseOfDecl(IIDecl, NameLoc); + + // C++ [temp.local]p2: + // Within the scope of a class template specialization or + // partial specialization, when the injected-class-name is + // not followed by a <, it is equivalent to the + // injected-class-name followed by the template-argument s + // of the class template specialization or partial + // specialization enclosed in <>. + if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD)) + if (RD->isInjectedClassName()) + if (ClassTemplateDecl *Template = RD->getDescribedClassTemplate()) + T = Template->getInjectedClassNameType(Context); + + if (T.isNull()) + T = Context.getTypeDeclType(TD); + if (SS) T = getQualifiedNameType(*SS, T); + + } else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) { + DiagnoseUseOfDecl(IIDecl, NameLoc); + T = Context.getObjCInterfaceType(IDecl); + } else + return 0; - return T.getAsOpaquePtr(); - } - - return 0; + return T.getAsOpaquePtr(); } /// isTagName() - This method is called *for error recovery purposes only* @@ -1055,9 +1047,11 @@ void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) { /// 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 and -/// NeverFallThrough iff we never fall off the end of the statement. We assume -/// that functions not marked noreturn will return. +/// 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. @@ -1065,7 +1059,8 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { // FIXME: They should never return 0, fix that, delete this code. if (cfg == 0) - return NeverFallThrough; + // 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; @@ -1094,7 +1089,7 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { bool HasLiveReturn = false; bool HasFakeEdge = false; bool HasPlainEdge = false; - for (CFGBlock::succ_iterator I=cfg->getExit().pred_begin(), + for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(), E = cfg->getExit().pred_end(); I != E; ++I) { @@ -1138,8 +1133,11 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { if (NoReturnEdge == false) HasPlainEdge = true; } - if (!HasPlainEdge) - return NeverFallThrough; + if (!HasPlainEdge) { + if (HasLiveReturn) + return NeverFallThrough; + return NeverFallThroughOrReturn; + } if (HasFakeEdge || HasLiveReturn) return MaybeFallThrough; // This says AlwaysFallThrough for calls to functions that are not marked @@ -1161,6 +1159,7 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) { // which this code would then warn about. if (getDiagnostics().hasErrorOccurred()) return; + bool ReturnsVoid = false; bool HasNoReturn = false; if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { @@ -1202,10 +1201,12 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) { else if (!ReturnsVoid) Diag(Compound->getRBracLoc(), diag::warn_falloff_nonvoid_function); break; - case NeverFallThrough: - if (ReturnsVoid) + case NeverFallThroughOrReturn: + if (ReturnsVoid && !HasNoReturn) Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_function); break; + case NeverFallThrough: + break; } } } @@ -1225,7 +1226,7 @@ void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body) { return; bool ReturnsVoid = false; bool HasNoReturn = false; - if (const FunctionType *FT = BlockTy->getPointeeType()->getAs<FunctionType>()) { + if (const FunctionType *FT =BlockTy->getPointeeType()->getAs<FunctionType>()){ if (FT->getResultType()->isVoidType()) ReturnsVoid = true; if (FT->getNoReturnAttr()) @@ -1253,10 +1254,12 @@ void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body) { else if (!ReturnsVoid) Diag(Compound->getRBracLoc(), diag::err_falloff_nonvoid_block); break; - case NeverFallThrough: + case NeverFallThroughOrReturn: if (ReturnsVoid) Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_block); break; + case NeverFallThrough: + break; } } } @@ -1330,6 +1333,10 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { } if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) { + // If there are attributes in the DeclSpec, apply them to the record. + if (const AttributeList *AL = DS.getAttributes()) + ProcessDeclAttributeList(S, Record, AL); + if (!Record->getDeclName() && Record->isDefinition() && DS.getStorageClassSpec() != DeclSpec::SCS_typedef) { if (getLangOptions().CPlusPlus || @@ -1602,53 +1609,60 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, /// GetNameForDeclarator - Determine the full declaration name for the /// given Declarator. DeclarationName Sema::GetNameForDeclarator(Declarator &D) { - switch (D.getKind()) { - case Declarator::DK_Abstract: - assert(D.getIdentifier() == 0 && "abstract declarators have no name"); - return DeclarationName(); - - case Declarator::DK_Normal: - assert (D.getIdentifier() != 0 && "normal declarators have an identifier"); - return DeclarationName(D.getIdentifier()); - - case Declarator::DK_Constructor: { - QualType Ty = GetTypeFromParser(D.getDeclaratorIdType()); - return Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(Ty)); - } - - case Declarator::DK_Destructor: { - QualType Ty = GetTypeFromParser(D.getDeclaratorIdType()); - return Context.DeclarationNames.getCXXDestructorName( - Context.getCanonicalType(Ty)); - } - - case Declarator::DK_Conversion: { - // FIXME: We'd like to keep the non-canonical type for diagnostics! - QualType Ty = GetTypeFromParser(D.getDeclaratorIdType()); - return Context.DeclarationNames.getCXXConversionFunctionName( - Context.getCanonicalType(Ty)); - } + return GetNameFromUnqualifiedId(D.getName()); +} - case Declarator::DK_Operator: - assert(D.getIdentifier() == 0 && "operator names have no identifier"); - return Context.DeclarationNames.getCXXOperatorName( - D.getOverloadedOperator()); +/// \brief Retrieves the canonicalized name from a parsed unqualified-id. +DeclarationName Sema::GetNameFromUnqualifiedId(UnqualifiedId &Name) { + switch (Name.getKind()) { + case UnqualifiedId::IK_Identifier: + return DeclarationName(Name.Identifier); - case Declarator::DK_TemplateId: { - TemplateName Name - = TemplateName::getFromVoidPointer(D.getTemplateId()->Template); - if (TemplateDecl *Template = Name.getAsTemplateDecl()) - return Template->getDeclName(); - if (OverloadedFunctionDecl *Ovl = Name.getAsOverloadedFunctionDecl()) - return Ovl->getDeclName(); - - return DeclarationName(); - } + case UnqualifiedId::IK_OperatorFunctionId: + return Context.DeclarationNames.getCXXOperatorName( + Name.OperatorFunctionId.Operator); + + case UnqualifiedId::IK_ConversionFunctionId: { + QualType Ty = GetTypeFromParser(Name.ConversionFunctionId); + if (Ty.isNull()) + return DeclarationName(); + + return Context.DeclarationNames.getCXXConversionFunctionName( + Context.getCanonicalType(Ty)); + } + + case UnqualifiedId::IK_ConstructorName: { + QualType Ty = GetTypeFromParser(Name.ConstructorName); + if (Ty.isNull()) + return DeclarationName(); + + return Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(Ty)); + } + + case UnqualifiedId::IK_DestructorName: { + QualType Ty = GetTypeFromParser(Name.DestructorName); + if (Ty.isNull()) + return DeclarationName(); + + return Context.DeclarationNames.getCXXDestructorName( + Context.getCanonicalType(Ty)); + } + + case UnqualifiedId::IK_TemplateId: { + TemplateName TName + = TemplateName::getFromVoidPointer(Name.TemplateId->Template); + if (TemplateDecl *Template = TName.getAsTemplateDecl()) + return Template->getDeclName(); + if (OverloadedFunctionDecl *Ovl = TName.getAsOverloadedFunctionDecl()) + return Ovl->getDeclName(); + + return DeclarationName(); + } } - + assert(false && "Unknown name kind"); - return DeclarationName(); + return DeclarationName(); } /// isNearlyMatchingFunction - Determine whether the C++ functions @@ -1986,12 +2000,9 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); - TypedefDecl *NewTD = ParseTypedefDecl(S, D, R); + TypedefDecl *NewTD = ParseTypedefDecl(S, D, R, DInfo); if (!NewTD) return 0; - if (D.isInvalidType()) - NewTD->setInvalidDecl(); - // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewTD, D); // Merge the decl with the existing one if appropriate. If the decl is @@ -2013,7 +2024,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative); if (!FixedTy.isNull()) { Diag(D.getIdentifierLoc(), diag::warn_illegal_constant_array_size); - NewTD->setUnderlyingType(FixedTy); + NewTD->setTypeDeclaratorInfo(Context.getTrivialDeclaratorInfo(FixedTy)); } else { if (SizeIsNegative) Diag(D.getIdentifierLoc(), diag::err_typecheck_negative_array_size); @@ -2516,7 +2527,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, isInline |= IsFunctionDefinition; } - if (D.getKind() == Declarator::DK_Constructor) { + if (Name.getNameKind() == DeclarationName::CXXConstructorName) { // This is a C++ constructor declaration. assert(DC->isRecord() && "Constructors can only be declared in a member context"); @@ -2529,7 +2540,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, D.getIdentifierLoc(), Name, R, DInfo, isExplicit, isInline, /*isImplicitlyDeclared=*/false); - } else if (D.getKind() == Declarator::DK_Destructor) { + } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { // This is a C++ destructor declaration. if (DC->isRecord()) { R = CheckDestructorDeclarator(D, SC); @@ -2551,7 +2562,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, /*hasPrototype=*/true); D.setInvalidType(); } - } else if (D.getKind() == Declarator::DK_Conversion) { + } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { if (!DC->isRecord()) { Diag(D.getIdentifierLoc(), diag::err_conv_function_not_member); @@ -2795,10 +2806,10 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // If the declarator is a template-id, translate the parser's template // argument list into our AST format. bool HasExplicitTemplateArgs = false; - llvm::SmallVector<TemplateArgument, 16> TemplateArgs; + llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs; SourceLocation LAngleLoc, RAngleLoc; - if (D.getKind() == Declarator::DK_TemplateId) { - TemplateIdAnnotation *TemplateId = D.getTemplateId(); + if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { + TemplateIdAnnotation *TemplateId = D.getName().TemplateId; ASTTemplateArgsPtr TemplateArgsPtr(*this, TemplateId->getTemplateArgs(), TemplateId->getTemplateArgIsType(), @@ -3101,7 +3112,7 @@ void Sema::CheckMain(FunctionDecl* FD) { // C99 6.7.4p4: In a hosted environment, the inline function specifier // shall not appear in a declaration of main. // static main is not an error under C99, but we should warn about it. - bool isInline = FD->isInline(); + bool isInline = FD->isInlineSpecified(); bool isStatic = FD->getStorageClass() == FunctionDecl::Static; if (isInline || isStatic) { unsigned diagID = diag::warn_unusual_main_decl; @@ -3442,7 +3453,7 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, if (getLangOptions().CPlusPlus) { QualType InitType = Type; if (const ArrayType *Array = Context.getAsArrayType(Type)) - InitType = Array->getElementType(); + InitType = Context.getBaseElementType(Array); if ((!Var->hasExternalStorage() && !Var->isExternC()) && InitType->isRecordType() && !InitType->isDependentType()) { if (!RequireCompleteType(Var->getLocation(), InitType, @@ -3465,7 +3476,7 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, else { // FIXME: Cope with initialization of arrays if (!Constructor->isTrivial() && - InitializeVarWithConstructor(Var, Constructor, InitType, + InitializeVarWithConstructor(Var, Constructor, move_arg(ConstructorArgs))) Var->setInvalidDecl(); @@ -3626,8 +3637,7 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { DeclaratorInfo *DInfo = 0; TagDecl *OwnedDecl = 0; - QualType parmDeclType = GetTypeForDeclarator(D, S, &DInfo, /*Skip=*/0, - &OwnedDecl); + QualType parmDeclType = GetTypeForDeclarator(D, S, &DInfo, &OwnedDecl); if (getLangOptions().CPlusPlus && OwnedDecl && OwnedDecl->isDefinition()) { // C++ [dcl.fct]p6: @@ -3668,16 +3678,9 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { QualType T = adjustParameterType(parmDeclType); - ParmVarDecl *New; - if (T == parmDeclType) // parameter type did not need adjustment - New = ParmVarDecl::Create(Context, CurContext, - D.getIdentifierLoc(), II, - parmDeclType, DInfo, StorageClass, - 0); - else // keep track of both the adjusted and unadjusted types - New = OriginalParmVarDecl::Create(Context, CurContext, - D.getIdentifierLoc(), II, T, DInfo, - parmDeclType, StorageClass, 0); + ParmVarDecl *New + = ParmVarDecl::Create(Context, CurContext, D.getIdentifierLoc(), II, + T, DInfo, StorageClass, 0); if (D.isInvalidType()) New->setInvalidDecl(); @@ -3776,6 +3779,9 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, } Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { + // Clear the last template instantiation error context. + LastTemplateInstantiationErrorContext = ActiveTemplateInstantiation(); + if (!D) return D; FunctionDecl *FD = 0; @@ -4104,15 +4110,21 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { } } -TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T) { +TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, + DeclaratorInfo *DInfo) { assert(D.getIdentifier() && "Wrong callback for declspec without declarator"); assert(!T.isNull() && "GetTypeForDeclarator() returned null type"); + if (!DInfo) { + assert(D.isInvalidType() && "no declarator info for valid type"); + DInfo = Context.getTrivialDeclaratorInfo(T); + } + // Scope manipulation handled by caller. TypedefDecl *NewTD = TypedefDecl::Create(Context, CurContext, D.getIdentifierLoc(), D.getIdentifier(), - T); + DInfo); if (const TagType *TT = T->getAs<TagType>()) { TagDecl *TD = TT->getDecl(); @@ -4321,9 +4333,6 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } if (PrevDecl) { - // Check whether the previous declaration is usable. - (void)DiagnoseUseOfDecl(PrevDecl, NameLoc); - if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) { // If this is a use of a previous tag, or if the tag is already declared // in the same scope (so that the definition/declaration completes or @@ -4955,12 +4964,16 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { case CXXDefaultConstructor: if (RD->hasUserDeclaredConstructor()) { typedef CXXRecordDecl::ctor_iterator ctor_iter; - for (ctor_iter ci = RD->ctor_begin(), ce = RD->ctor_end(); ci != ce; ++ci) - if (!ci->isImplicitlyDefined(Context)) { + for (ctor_iter ci = RD->ctor_begin(), ce = RD->ctor_end(); ci != ce;++ci){ + const FunctionDecl *body = 0; + ci->getBody(body); + if (!body || + !cast<CXXConstructorDecl>(body)->isImplicitlyDefined(Context)) { SourceLocation CtorLoc = ci->getLocation(); Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member; return; } + } assert(0 && "found no user-declared constructors"); return; @@ -5038,7 +5051,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { // Check for nontrivial bases (and recurse). for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; ++bi) { const RecordType *BaseRT = bi->getType()->getAs<RecordType>(); - assert(BaseRT); + assert(BaseRT && "Don't know how to handle dependent bases"); CXXRecordDecl *BaseRecTy = cast<CXXRecordDecl>(BaseRT->getDecl()); if (!(BaseRecTy->*hasTrivial)()) { SourceLocation BaseLoc = bi->getSourceRange().getBegin(); diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 341d49e..18f57da 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -193,7 +193,8 @@ static void HandleExtVectorTypeAttr(Scope *scope, Decl *d, // This will run the reguired checks. QualType T = S.BuildExtVectorType(curType, S.Owned(sizeExpr), Attr.getLoc()); if (!T.isNull()) { - tDecl->setUnderlyingType(T); + // FIXME: preserve the old source info. + tDecl->setTypeDeclaratorInfo(S.Context.getTrivialDeclaratorInfo(T)); // Remember this typedef decl, we will need it later for diagnostics. S.ExtVectorDecls.push_back(tDecl); @@ -278,8 +279,11 @@ static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) { if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) VD->setType(CurType); - else - cast<TypedefDecl>(D)->setUnderlyingType(CurType); + else { + // FIXME: preserve existing source info. + DeclaratorInfo *DInfo = S.Context.getTrivialDeclaratorInfo(CurType); + cast<TypedefDecl>(D)->setTypeDeclaratorInfo(DInfo); + } } static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -897,7 +901,7 @@ static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { // Currently, the dllimport attribute is ignored for inlined functions. // Warning is emitted. - if (FD->isInline()) { + if (FD->isInlineSpecified()) { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport"; return; } @@ -942,7 +946,7 @@ static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) { // Currently, the dllexport attribute is ignored for inlined functions, unless // the -fkeep-inline-functions flag has been used. Warning is emitted; - if (FD->isInline()) { + if (FD->isInlineSpecified()) { // FIXME: ... unless the -fkeep-inline-functions flag has been used. S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport"; return; @@ -1028,6 +1032,22 @@ static void HandleStdCallAttr(Decl *d, const AttributeList &Attr, Sema &S) { d->addAttr(::new (S.Context) StdCallAttr()); } +/// Diagnose the use of a non-standard calling convention on the given +/// function. +static void DiagnoseCConv(FunctionDecl *D, const char *CConv, + SourceLocation Loc, Sema &S) { + if (!D->hasPrototype()) { + S.Diag(Loc, diag::err_cconv_knr) << CConv; + return; + } + + const FunctionProtoType *T = D->getType()->getAs<FunctionProtoType>(); + if (T->isVariadic()) { + S.Diag(Loc, diag::err_cconv_varargs) << CConv; + return; + } +} + static void HandleFastCallAttr(Decl *d, const AttributeList &Attr, Sema &S) { // Attribute has no arguments. if (Attr.getNumArgs() != 0) { @@ -1041,6 +1061,8 @@ static void HandleFastCallAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } + DiagnoseCConv(cast<FunctionDecl>(d), "fastcall", Attr.getLoc(), S); + // stdcall and fastcall attributes are mutually incompatible. if (d->getAttr<StdCallAttr>()) { S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) @@ -1636,9 +1658,10 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) { } // Install the new type. - if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) - TD->setUnderlyingType(NewTy); - else + if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { + // FIXME: preserve existing source info. + TD->setTypeDeclaratorInfo(S.Context.getTrivialDeclaratorInfo(NewTy)); + } else cast<ValueDecl>(D)->setType(NewTy); } @@ -1688,7 +1711,7 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - if (!Fn->isInline()) { + if (!Fn->isInlineSpecified()) { S.Diag(Attr.getLoc(), diag::warn_gnu_inline_attribute_requires_inline); return; } @@ -1944,3 +1967,62 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { if (const AttributeList *Attrs = PD.getAttributes()) ProcessDeclAttributeList(S, D, Attrs); } + +/// PushParsingDeclaration - Enter a new "scope" of deprecation +/// warnings. +/// +/// The state token we use is the start index of this scope +/// on the warning stack. +Action::ParsingDeclStackState Sema::PushParsingDeclaration() { + ParsingDeclDepth++; + return (ParsingDeclStackState) DelayedDeprecationWarnings.size(); +} + +static bool isDeclDeprecated(Decl *D) { + do { + if (D->hasAttr<DeprecatedAttr>()) + return true; + } while ((D = cast_or_null<Decl>(D->getDeclContext()))); + return false; +} + +void Sema::PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy Ctx) { + assert(ParsingDeclDepth > 0 && "empty ParsingDeclaration stack"); + ParsingDeclDepth--; + + if (DelayedDeprecationWarnings.empty()) + return; + + unsigned SavedIndex = (unsigned) S; + assert(SavedIndex <= DelayedDeprecationWarnings.size() && + "saved index is out of bounds"); + + if (Ctx && !isDeclDeprecated(Ctx.getAs<Decl>())) { + for (unsigned I = 0, E = DelayedDeprecationWarnings.size(); I != E; ++I) { + SourceLocation Loc = DelayedDeprecationWarnings[I].first; + NamedDecl *&ND = DelayedDeprecationWarnings[I].second; + if (ND) { + Diag(Loc, diag::warn_deprecated) << ND->getDeclName(); + + // Prevent this from triggering multiple times. + ND = 0; + } + } + } + + DelayedDeprecationWarnings.set_size(SavedIndex); +} + +void Sema::EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc) { + // Delay if we're currently parsing a declaration. + if (ParsingDeclDepth) { + DelayedDeprecationWarnings.push_back(std::make_pair(Loc, D)); + return; + } + + // Otherwise, don't warn if our current context is deprecated. + if (isDeclDeprecated(cast<Decl>(CurContext))) + return; + + Diag(Loc, diag::warn_deprecated) << D->getDeclName(); +} diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 6d1f4ea..bc25513 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1123,7 +1123,7 @@ Sema::BuildBaseInitializer(QualType BaseType, Expr **Args, } void -Sema::setBaseOrMemberInitializers(CXXConstructorDecl *Constructor, +Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, CXXBaseOrMemberInitializer **Initializers, unsigned NumInitializers, llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases, @@ -1179,7 +1179,7 @@ Sema::setBaseOrMemberInitializers(CXXConstructorDecl *Constructor, AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) { CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl()); - assert(BaseDecl && "setBaseOrMemberInitializers - BaseDecl null"); + assert(BaseDecl && "SetBaseOrMemberInitializers - BaseDecl null"); if (CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context)) MarkDeclarationReferenced(Value->getSourceLocation(), Ctor); AllToInit.push_back(Value); @@ -1187,18 +1187,26 @@ Sema::setBaseOrMemberInitializers(CXXConstructorDecl *Constructor, else { CXXRecordDecl *VBaseDecl = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl()); - assert(VBaseDecl && "setBaseOrMemberInitializers - VBaseDecl null"); + assert(VBaseDecl && "SetBaseOrMemberInitializers - VBaseDecl null"); CXXConstructorDecl *Ctor = VBaseDecl->getDefaultConstructor(Context); - if (!Ctor) + if (!Ctor) { Bases.push_back(VBase); - else - MarkDeclarationReferenced(Constructor->getLocation(), Ctor); + continue; + } + ASTOwningVector<&ActionBase::DeleteExpr> CtorArgs(*this); + if (CompleteConstructorCall(Ctor, MultiExprArg(*this, 0, 0), + Constructor->getLocation(), CtorArgs)) + continue; + + MarkDeclarationReferenced(Constructor->getLocation(), Ctor); + CXXBaseOrMemberInitializer *Member = - new (Context) CXXBaseOrMemberInitializer(VBase->getType(), 0, 0, - Ctor, - SourceLocation(), - SourceLocation()); + new (Context) CXXBaseOrMemberInitializer(VBase->getType(), + CtorArgs.takeAs<Expr>(), + CtorArgs.size(), Ctor, + SourceLocation(), + SourceLocation()); AllToInit.push_back(Member); } } @@ -1216,7 +1224,7 @@ Sema::setBaseOrMemberInitializers(CXXConstructorDecl *Constructor, AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) { CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - assert(BaseDecl && "setBaseOrMemberInitializers - BaseDecl null"); + assert(BaseDecl && "SetBaseOrMemberInitializers - BaseDecl null"); if (CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context)) MarkDeclarationReferenced(Value->getSourceLocation(), Ctor); AllToInit.push_back(Value); @@ -1224,18 +1232,26 @@ Sema::setBaseOrMemberInitializers(CXXConstructorDecl *Constructor, else { CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - assert(BaseDecl && "setBaseOrMemberInitializers - BaseDecl null"); + assert(BaseDecl && "SetBaseOrMemberInitializers - BaseDecl null"); CXXConstructorDecl *Ctor = BaseDecl->getDefaultConstructor(Context); - if (!Ctor) + if (!Ctor) { Bases.push_back(Base); - else - MarkDeclarationReferenced(Constructor->getLocation(), Ctor); + continue; + } + + ASTOwningVector<&ActionBase::DeleteExpr> CtorArgs(*this); + if (CompleteConstructorCall(Ctor, MultiExprArg(*this, 0, 0), + Constructor->getLocation(), CtorArgs)) + continue; + + MarkDeclarationReferenced(Constructor->getLocation(), Ctor); CXXBaseOrMemberInitializer *Member = - new (Context) CXXBaseOrMemberInitializer(Base->getType(), 0, 0, - BaseDecl->getDefaultConstructor(Context), - SourceLocation(), - SourceLocation()); + new (Context) CXXBaseOrMemberInitializer(Base->getType(), + CtorArgs.takeAs<Expr>(), + CtorArgs.size(), Ctor, + SourceLocation(), + SourceLocation()); AllToInit.push_back(Member); } } @@ -1268,7 +1284,7 @@ Sema::setBaseOrMemberInitializers(CXXConstructorDecl *Constructor, QualType FT = (*Field)->getType(); if (const RecordType* RT = FT->getAs<RecordType>()) { CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RT->getDecl()); - assert(FieldRecDecl && "setBaseOrMemberInitializers - BaseDecl null"); + assert(FieldRecDecl && "SetBaseOrMemberInitializers - BaseDecl null"); if (CXXConstructorDecl *Ctor = FieldRecDecl->getDefaultConstructor(Context)) MarkDeclarationReferenced(Value->getSourceLocation(), Ctor); @@ -1281,13 +1297,22 @@ Sema::setBaseOrMemberInitializers(CXXConstructorDecl *Constructor, if (const RecordType* RT = FT->getAs<RecordType>()) { CXXConstructorDecl *Ctor = cast<CXXRecordDecl>(RT->getDecl())->getDefaultConstructor(Context); - if (!Ctor && !FT->isDependentType()) + if (!Ctor && !FT->isDependentType()) { Fields.push_back(*Field); + continue; + } + + ASTOwningVector<&ActionBase::DeleteExpr> CtorArgs(*this); + if (CompleteConstructorCall(Ctor, MultiExprArg(*this, 0, 0), + Constructor->getLocation(), CtorArgs)) + continue; + CXXBaseOrMemberInitializer *Member = - new (Context) CXXBaseOrMemberInitializer((*Field), 0, 0, - Ctor, - SourceLocation(), - SourceLocation()); + new (Context) CXXBaseOrMemberInitializer(*Field,CtorArgs.takeAs<Expr>(), + CtorArgs.size(), Ctor, + SourceLocation(), + SourceLocation()); + AllToInit.push_back(Member); if (Ctor) MarkDeclarationReferenced(Constructor->getLocation(), Ctor); @@ -1327,10 +1352,10 @@ Sema::BuildBaseOrMemberInitializers(ASTContext &C, CXXBaseOrMemberInitializer **Initializers, unsigned NumInitializers ) { - llvm::SmallVector<CXXBaseSpecifier *, 4>Bases; - llvm::SmallVector<FieldDecl *, 4>Members; + llvm::SmallVector<CXXBaseSpecifier *, 4> Bases; + llvm::SmallVector<FieldDecl *, 4> Members; - setBaseOrMemberInitializers(Constructor, + SetBaseOrMemberInitializers(Constructor, Initializers, NumInitializers, Bases, Members); for (unsigned int i = 0; i < Bases.size(); i++) Diag(Bases[i]->getSourceRange().getBegin(), @@ -1976,6 +2001,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { // and for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(); HasConstCopyAssignment && Base != ClassDecl->bases_end(); ++Base) { + assert(!Base->getType()->isDependentType() && + "Cannot generate implicit members for class with dependent bases."); const CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); const CXXMethodDecl *MD = 0; @@ -2268,7 +2295,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, // (7.1.3); however, a typedef-name that names a class shall not // be used as the identifier in the declarator for a destructor // declaration. - QualType DeclaratorType = GetTypeFromParser(D.getDeclaratorIdType()); + QualType DeclaratorType = GetTypeFromParser(D.getName().DestructorName); if (isa<TypedefType>(DeclaratorType)) { Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name) << DeclaratorType; @@ -2394,7 +2421,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, // C++ [class.conv.fct]p4: // The conversion-type-id shall not represent a function type nor // an array type. - QualType ConvType = GetTypeFromParser(D.getDeclaratorIdType()); + QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId); if (ConvType->isArrayType()) { Diag(D.getIdentifierLoc(), diag::err_conv_function_to_array); ConvType = Context.getPointerType(ConvType); @@ -3152,10 +3179,9 @@ Sema::BuildCXXTemporaryObjectExpr(CXXConstructorDecl *Constructor, bool Sema::InitializeVarWithConstructor(VarDecl *VD, CXXConstructorDecl *Constructor, - QualType DeclInitType, MultiExprArg Exprs) { OwningExprResult TempResult = - BuildCXXConstructExpr(VD->getLocation(), DeclInitType, Constructor, + BuildCXXConstructExpr(VD->getLocation(), VD->getType(), Constructor, move(Exprs)); if (TempResult.isInvalid()) return true; @@ -3235,7 +3261,7 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, // class type. QualType DeclInitType = VDecl->getType(); if (const ArrayType *Array = Context.getAsArrayType(DeclInitType)) - DeclInitType = Array->getElementType(); + DeclInitType = Context.getBaseElementType(Array); // FIXME: This isn't the right place to complete the type. if (RequireCompleteType(VDecl->getLocation(), VDecl->getType(), @@ -3260,7 +3286,7 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, RealDecl->setInvalidDecl(); else { VDecl->setCXXDirectInitializer(true); - if (InitializeVarWithConstructor(VDecl, Constructor, DeclInitType, + if (InitializeVarWithConstructor(VDecl, Constructor, move_arg(ConstructorArgs))) RealDecl->setInvalidDecl(); FinalizeVarWithDestructor(VDecl, DeclInitType); @@ -4269,8 +4295,7 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc, /// We permit this as a special case; if there are any template /// parameters present at all, require proper matching, i.e. /// template <> template <class T> friend class A<int>::B; -Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, - const DeclSpec &DS, +Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, MultiTemplateParamsArg TempParams) { SourceLocation Loc = DS.getSourceRange().getBegin(); @@ -4280,9 +4305,10 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, // Try to convert the decl specifier to a type. This works for // friend templates because ActOnTag never produces a ClassTemplateDecl // for a TUK_Friend. - bool invalid = false; - QualType T = ConvertDeclSpecToType(DS, Loc, invalid); - if (invalid) return DeclPtrTy(); + Declarator TheDeclarator(DS, Declarator::MemberContext); + QualType T = GetTypeForDeclarator(TheDeclarator, S); + if (TheDeclarator.isInvalidType()) + return DeclPtrTy(); // This is definitely an error in C++98. It's probably meant to // be forbidden in C++0x, too, but the specification is just @@ -4489,12 +4515,12 @@ Sema::ActOnFriendFunctionDecl(Scope *S, if (DC->isFileContext()) { // This implies that it has to be an operator or function. - if (D.getKind() == Declarator::DK_Constructor || - D.getKind() == Declarator::DK_Destructor || - D.getKind() == Declarator::DK_Conversion) { + if (D.getName().getKind() == UnqualifiedId::IK_ConstructorName || + D.getName().getKind() == UnqualifiedId::IK_DestructorName || + D.getName().getKind() == UnqualifiedId::IK_ConversionFunctionId) { Diag(Loc, diag::err_introducing_special_friend) << - (D.getKind() == Declarator::DK_Constructor ? 0 : - D.getKind() == Declarator::DK_Destructor ? 1 : 2); + (D.getName().getKind() == UnqualifiedId::IK_ConstructorName ? 0 : + D.getName().getKind() == UnqualifiedId::IK_DestructorName ? 1 : 2); return DeclPtrTy(); } } diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 22a5179..93f8d0d 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -1707,29 +1707,22 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( llvm::SmallVector<ParmVarDecl*, 16> Params; for (unsigned i = 0, e = Sel.getNumArgs(); i != e; ++i) { - QualType ArgType, UnpromotedArgType; + QualType ArgType; + DeclaratorInfo *DI; if (ArgInfo[i].Type == 0) { - UnpromotedArgType = ArgType = Context.getObjCIdType(); + ArgType = Context.getObjCIdType(); + DI = 0; } else { - UnpromotedArgType = ArgType = GetTypeFromParser(ArgInfo[i].Type); + ArgType = GetTypeFromParser(ArgInfo[i].Type, &DI); // Perform the default array/function conversions (C99 6.7.5.3p[7,8]). ArgType = adjustParameterType(ArgType); } - ParmVarDecl* Param; - if (ArgType == UnpromotedArgType) - Param = ParmVarDecl::Create(Context, ObjCMethod, ArgInfo[i].NameLoc, - ArgInfo[i].Name, ArgType, - /*DInfo=*/0, //FIXME: Pass info here. - VarDecl::None, 0); - else - Param = OriginalParmVarDecl::Create(Context, ObjCMethod, - ArgInfo[i].NameLoc, - ArgInfo[i].Name, ArgType, - /*DInfo=*/0, //FIXME: Pass info here. - UnpromotedArgType, - VarDecl::None, 0); + ParmVarDecl* Param + = ParmVarDecl::Create(Context, ObjCMethod, ArgInfo[i].NameLoc, + ArgInfo[i].Name, ArgType, DI, + VarDecl::None, 0); if (ArgType->isObjCInterfaceType()) { Diag(ArgInfo[i].NameLoc, @@ -1755,6 +1748,8 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( if (AttrList) ProcessDeclAttributeList(TUScope, ObjCMethod, AttrList); + const ObjCMethodDecl *InterfaceMD = 0; + // For implementations (which can be very "coarse grain"), we add the // method now. This allows the AST to implement lookup methods that work // incrementally (without waiting until we parse the @end). It also allows @@ -1768,6 +1763,8 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( PrevMethod = ImpDecl->getClassMethod(Sel); ImpDecl->addClassMethod(ObjCMethod); } + InterfaceMD = ImpDecl->getClassInterface()->getMethod(Sel, + MethodType == tok::minus); if (AttrList) Diag(EndLoc, diag::warn_attribute_method_def); } else if (ObjCCategoryImplDecl *CatImpDecl = @@ -1788,6 +1785,12 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( << ObjCMethod->getDeclName(); Diag(PrevMethod->getLocation(), diag::note_previous_declaration); } + + // If the interface declared this method, and it was deprecated there, + // mark it deprecated here. + if (InterfaceMD && InterfaceMD->hasAttr<DeprecatedAttr>()) + ObjCMethod->addAttr(::new (Context) DeprecatedAttr()); + return DeclPtrTy::make(ObjCMethod); } @@ -1900,33 +1903,34 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, // handling. if ((CCPrimary = CDecl->getClassInterface())) { // Find the property in continuation class's primary class only. - ObjCPropertyDecl *PIDecl = 0; IdentifierInfo *PropertyId = FD.D.getIdentifier(); - for (ObjCInterfaceDecl::prop_iterator - I = CCPrimary->prop_begin(), E = CCPrimary->prop_end(); - I != E; ++I) - if ((*I)->getIdentifier() == PropertyId) { - PIDecl = *I; - break; - } - - if (PIDecl) { + if (ObjCPropertyDecl *PIDecl = + CCPrimary->FindPropertyVisibleInPrimaryClass(PropertyId)) { // property 'PIDecl's readonly attribute will be over-ridden // with continuation class's readwrite property attribute! unsigned PIkind = PIDecl->getPropertyAttributes(); if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) { - if ((Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) != - (PIkind & ObjCPropertyDecl::OBJC_PR_nonatomic)) + unsigned assignRetainCopyNonatomic = + (ObjCPropertyDecl::OBJC_PR_assign | + ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_copy | + ObjCPropertyDecl::OBJC_PR_nonatomic); + if ((Attributes & assignRetainCopyNonatomic) != + (PIkind & assignRetainCopyNonatomic)) { Diag(AtLoc, diag::warn_property_attr_mismatch); + Diag(PIDecl->getLocation(), diag::note_property_declare); + } PIDecl->makeitReadWriteAttribute(); if (Attributes & ObjCDeclSpec::DQ_PR_retain) PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); if (Attributes & ObjCDeclSpec::DQ_PR_copy) PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); PIDecl->setSetterName(SetterSel); - } else + } else { Diag(AtLoc, diag::err_use_continuation_class) << CCPrimary->getDeclName(); + Diag(PIDecl->getLocation(), diag::note_property_declare); + } *isOverridingProperty = true; // Make sure setter decl is synthesized, and added to primary // class's list. @@ -2054,6 +2058,14 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName(); return DeclPtrTy(); } + if (const ObjCCategoryDecl *CD = + dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) { + if (CD->getIdentifier()) { + Diag(PropertyLoc, diag::error_category_property) << CD->getDeclName(); + Diag(property->getLocation(), diag::note_property_declare); + return DeclPtrTy(); + } + } } else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) { if (Synthesize) { Diag(AtLoc, diag::error_synthesize_category_decl); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index ae45429..ac7cced 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -37,40 +37,24 @@ using namespace clang; /// used, or produce an error (and return true) if a C++0x deleted /// function is being used. /// +/// If IgnoreDeprecated is set to true, this should not want about deprecated +/// decls. +/// /// \returns true if there was an error (this declaration cannot be /// referenced), false otherwise. +/// bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) { // See if the decl is deprecated. if (D->getAttr<DeprecatedAttr>()) { - // Implementing deprecated stuff requires referencing deprecated - // stuff. Don't warn if we are implementing a deprecated - // construct. - bool isSilenced = false; - - if (NamedDecl *ND = getCurFunctionOrMethodDecl()) { - // If this reference happens *in* a deprecated function or method, don't - // warn. - isSilenced = ND->getAttr<DeprecatedAttr>(); - - // If this is an Objective-C method implementation, check to see if the - // method was deprecated on the declaration, not the definition. - if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ND)) { - // The semantic decl context of a ObjCMethodDecl is the - // ObjCImplementationDecl. - if (ObjCImplementationDecl *Impl - = dyn_cast<ObjCImplementationDecl>(MD->getParent())) { - - MD = Impl->getClassInterface()->getMethod(MD->getSelector(), - MD->isInstanceMethod()); - isSilenced |= MD && MD->getAttr<DeprecatedAttr>(); - } - } - } - - if (!isSilenced) - Diag(Loc, diag::warn_deprecated) << D->getDeclName(); + EmitDeprecationWarning(D, Loc); } + // See if the decl is unavailable + if (D->getAttr<UnavailableAttr>()) { + Diag(Loc, diag::warn_unavailable) << D->getDeclName(); + Diag(D->getLocation(), diag::note_unavailable_here) << 0; + } + // See if this is a deleted function. if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { if (FD->isDeleted()) { @@ -80,12 +64,6 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) { } } - // See if the decl is unavailable - if (D->getAttr<UnavailableAttr>()) { - Diag(Loc, diag::warn_unavailable) << D->getDeclName(); - Diag(D->getLocation(), diag::note_unavailable_here) << 0; - } - return false; } @@ -432,23 +410,7 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock, -/// ActOnIdentifierExpr - The parser read an identifier in expression context, -/// validate it per-C99 6.5.1. HasTrailingLParen indicates whether this -/// identifier is used in a function call context. -/// SS is only used for a C++ qualified-id (foo::bar) to indicate the -/// class or namespace that the identifier must be a member of. -Sema::OwningExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc, - IdentifierInfo &II, - bool HasTrailingLParen, - const CXXScopeSpec *SS, - bool isAddressOfOperand) { - return ActOnDeclarationNameExpr(S, Loc, &II, HasTrailingLParen, SS, - isAddressOfOperand); -} - -/// BuildDeclRefExpr - Build either a DeclRefExpr or a -/// QualifiedDeclRefExpr based on whether or not SS is a -/// nested-name-specifier. +/// BuildDeclRefExpr - Build a DeclRefExpr. Sema::OwningExprResult Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc, bool TypeDependent, bool ValueDependent, @@ -476,15 +438,11 @@ Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc, MarkDeclarationReferenced(Loc, D); - Expr *E; - if (SS && !SS->isEmpty()) { - E = new (Context) QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent, - ValueDependent, SS->getRange(), - static_cast<NestedNameSpecifier *>(SS->getScopeRep())); - } else - E = new (Context) DeclRefExpr(D, Ty, Loc, TypeDependent, ValueDependent); - - return Owned(E); + return Owned(DeclRefExpr::Create(Context, + SS? (NestedNameSpecifier *)SS->getScopeRep() : 0, + SS? SS->getRange() : SourceRange(), + D, Loc, + Ty, TypeDependent, ValueDependent)); } /// getObjectForAnonymousRecordDecl - Retrieve the (unnamed) field or @@ -656,15 +614,43 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, return Owned(Result); } +Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, + const CXXScopeSpec &SS, + UnqualifiedId &Name, + bool HasTrailingLParen, + bool IsAddressOfOperand) { + if (Name.getKind() == UnqualifiedId::IK_TemplateId) { + ASTTemplateArgsPtr TemplateArgsPtr(*this, + Name.TemplateId->getTemplateArgs(), + Name.TemplateId->getTemplateArgIsType(), + Name.TemplateId->NumArgs); + return ActOnTemplateIdExpr(SS, + TemplateTy::make(Name.TemplateId->Template), + Name.TemplateId->TemplateNameLoc, + Name.TemplateId->LAngleLoc, + TemplateArgsPtr, + Name.TemplateId->getTemplateArgLocations(), + Name.TemplateId->RAngleLoc); + } + + // FIXME: We lose a bunch of source information by doing this. Later, + // we'll want to merge ActOnDeclarationNameExpr's logic into + // ActOnIdExpression. + return ActOnDeclarationNameExpr(S, + Name.StartLocation, + GetNameFromUnqualifiedId(Name), + HasTrailingLParen, + &SS, + IsAddressOfOperand); +} + /// ActOnDeclarationNameExpr - The parser has read some kind of name /// (e.g., a C++ id-expression (C++ [expr.prim]p1)). This routine /// performs lookup on that name and returns an expression that refers /// to that name. This routine isn't directly called from the parser, /// because the parser doesn't know about DeclarationName. Rather, -/// this routine is called by ActOnIdentifierExpr, -/// ActOnOperatorFunctionIdExpr, and ActOnConversionFunctionExpr, -/// which form the DeclarationName from the corresponding syntactic -/// forms. +/// this routine is called by ActOnIdExpression, which contains a +/// parsed UnqualifiedId. /// /// HasTrailingLParen indicates whether this identifier is used in a /// function call context. LookupCtx is only used for a C++ @@ -745,8 +731,11 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, // FIXME: This should use a new expr for a direct reference, don't // turn this into Self->ivar, just return a BareIVarExpr or something. IdentifierInfo &II = Context.Idents.get("self"); - OwningExprResult SelfExpr = ActOnIdentifierExpr(S, SourceLocation(), - II, false); + UnqualifiedId SelfName; + SelfName.setIdentifier(&II, SourceLocation()); + CXXScopeSpec SelfScopeSpec; + OwningExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec, + SelfName, false, false); MarkDeclarationReferenced(Loc, IV); return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(), Loc, @@ -1083,7 +1072,8 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D, // - a constant with integral or enumeration type and is // initialized with an expression that is value-dependent else if (const VarDecl *Dcl = dyn_cast<VarDecl>(VD)) { - if (Dcl->getType().getCVRQualifiers() == Qualifiers::Const && + if (Context.getCanonicalType(Dcl->getType()).getCVRQualifiers() + == Qualifiers::Const && Dcl->getInit()) { ValueDependent = Dcl->getInit()->isValueDependent(); } @@ -1300,7 +1290,7 @@ bool Sema::CheckSizeOfAlignOfOperand(QualType exprType, return false; // C99 6.5.3.4p1: - if (isa<FunctionType>(exprType)) { + if (exprType->isFunctionType()) { // alignof(function) is allowed as an extension. if (isSizeof) Diag(OpLoc, diag::ext_sizeof_function_type) << ExprRange; @@ -1358,17 +1348,20 @@ bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, /// \brief Build a sizeof or alignof expression given a type operand. Action::OwningExprResult -Sema::CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc, +Sema::CreateSizeOfAlignOfExpr(DeclaratorInfo *DInfo, + SourceLocation OpLoc, bool isSizeOf, SourceRange R) { - if (T.isNull()) + if (!DInfo) return ExprError(); + QualType T = DInfo->getType(); + if (!T->isDependentType() && CheckSizeOfAlignOfOperand(T, OpLoc, R, isSizeOf)) return ExprError(); // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t. - return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, T, + return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, DInfo, Context.getSizeType(), OpLoc, R.getEnd())); } @@ -1410,12 +1403,11 @@ Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, if (TyOrEx == 0) return ExprError(); if (isType) { - // FIXME: Preserve type source info. - QualType ArgTy = GetTypeFromParser(TyOrEx); - return CreateSizeOfAlignOfExpr(ArgTy, OpLoc, isSizeof, ArgRange); + DeclaratorInfo *DInfo; + (void) GetTypeFromParser(TyOrEx, &DInfo); + return CreateSizeOfAlignOfExpr(DInfo, OpLoc, isSizeof, ArgRange); } - // Get the end location. Expr *ArgEx = (Expr *)TyOrEx; Action::OwningExprResult Result = CreateSizeOfAlignOfExpr(ArgEx, OpLoc, isSizeof, ArgEx->getSourceRange()); @@ -1602,103 +1594,18 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, LHSExp->getType()->isEnumeralType() || RHSExp->getType()->isRecordType() || RHSExp->getType()->isEnumeralType())) { - // Add the appropriate overloaded operators (C++ [over.match.oper]) - // to the candidate set. - OverloadCandidateSet CandidateSet; - Expr *Args[2] = { LHSExp, RHSExp }; - AddOperatorCandidates(OO_Subscript, S, LLoc, Args, 2, CandidateSet, - SourceRange(LLoc, RLoc)); - - // Perform overload resolution. - OverloadCandidateSet::iterator Best; - switch (BestViableFunction(CandidateSet, LLoc, Best)) { - case OR_Success: { - // We found a built-in operator or an overloaded operator. - FunctionDecl *FnDecl = Best->Function; - - if (FnDecl) { - // We matched an overloaded operator. Build a call to that - // operator. - - // Convert the arguments. - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { - if (PerformObjectArgumentInitialization(LHSExp, Method) || - PerformCopyInitialization(RHSExp, - FnDecl->getParamDecl(0)->getType(), - "passing")) - return ExprError(); - } else { - // Convert the arguments. - if (PerformCopyInitialization(LHSExp, - FnDecl->getParamDecl(0)->getType(), - "passing") || - PerformCopyInitialization(RHSExp, - FnDecl->getParamDecl(1)->getType(), - "passing")) - return ExprError(); - } - - // Determine the result type - QualType ResultTy = FnDecl->getResultType().getNonReferenceType(); - - // Build the actual expression node. - Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(), - SourceLocation()); - UsualUnaryConversions(FnExpr); - - Base.release(); - Idx.release(); - Args[0] = LHSExp; - Args[1] = RHSExp; - - ExprOwningPtr<CXXOperatorCallExpr> - TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Subscript, - FnExpr, Args, 2, - ResultTy, RLoc)); - if (CheckCallReturnType(FnDecl->getResultType(), LLoc, TheCall.get(), - FnDecl)) - return ExprError(); - - return Owned(TheCall.release()); - } else { - // We matched a built-in operator. Convert the arguments, then - // break out so that we will build the appropriate built-in - // operator node. - if (PerformCopyInitialization(LHSExp, Best->BuiltinTypes.ParamTypes[0], - "passing") || - PerformCopyInitialization(RHSExp, Best->BuiltinTypes.ParamTypes[1], - "passing")) - return ExprError(); - - break; - } - } - - case OR_No_Viable_Function: - // No viable function; fall through to handling this as a - // built-in operator, which will produce an error message for us. - break; + return CreateOverloadedArraySubscriptExpr(LLoc, RLoc, move(Base),move(Idx)); + } - case OR_Ambiguous: - Diag(LLoc, diag::err_ovl_ambiguous_oper) - << "[]" - << LHSExp->getSourceRange() << RHSExp->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); - return ExprError(); + return CreateBuiltinArraySubscriptExpr(move(Base), LLoc, move(Idx), RLoc); +} - case OR_Deleted: - Diag(LLoc, diag::err_ovl_deleted_oper) - << Best->Function->isDeleted() - << "[]" - << LHSExp->getSourceRange() << RHSExp->getSourceRange(); - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); - return ExprError(); - } - // Either we found no viable overloaded operator or we matched a - // built-in operator. In either case, fall through to trying to - // build a built-in operation. - } +Action::OwningExprResult +Sema::CreateBuiltinArraySubscriptExpr(ExprArg Base, SourceLocation LLoc, + ExprArg Idx, SourceLocation RLoc) { + Expr *LHSExp = static_cast<Expr*>(Base.get()); + Expr *RHSExp = static_cast<Expr*>(Idx.get()); // Perform default conversions. DefaultFunctionArrayConversion(LHSExp); @@ -1961,7 +1868,7 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, DeclarationName MemberName, bool HasExplicitTemplateArgs, SourceLocation LAngleLoc, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, SourceLocation RAngleLoc, DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS, @@ -2549,13 +2456,77 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, return ExprError(); } -Action::OwningExprResult -Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, - tok::TokenKind OpKind, SourceLocation MemberLoc, - IdentifierInfo &Member, - DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS) { - return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, MemberLoc, - DeclarationName(&Member), ObjCImpDecl, SS); +Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + UnqualifiedId &Member, + DeclPtrTy ObjCImpDecl, + bool HasTrailingLParen) { + if (Member.getKind() == UnqualifiedId::IK_TemplateId) { + TemplateName Template + = TemplateName::getFromVoidPointer(Member.TemplateId->Template); + + // FIXME: We're going to end up looking up the template based on its name, + // twice! + DeclarationName Name; + if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl()) + Name = ActualTemplate->getDeclName(); + else if (OverloadedFunctionDecl *Ovl = Template.getAsOverloadedFunctionDecl()) + Name = Ovl->getDeclName(); + else { + DependentTemplateName *DTN = Template.getAsDependentTemplateName(); + if (DTN->isIdentifier()) + Name = DTN->getIdentifier(); + else + Name = Context.DeclarationNames.getCXXOperatorName(DTN->getOperator()); + } + + // Translate the parser's template argument list in our AST format. + ASTTemplateArgsPtr TemplateArgsPtr(*this, + Member.TemplateId->getTemplateArgs(), + Member.TemplateId->getTemplateArgIsType(), + Member.TemplateId->NumArgs); + + llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs; + translateTemplateArguments(TemplateArgsPtr, + Member.TemplateId->getTemplateArgLocations(), + TemplateArgs); + TemplateArgsPtr.release(); + + // Do we have the save the actual template name? We might need it... + return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, + Member.TemplateId->TemplateNameLoc, + Name, true, Member.TemplateId->LAngleLoc, + TemplateArgs.data(), TemplateArgs.size(), + Member.TemplateId->RAngleLoc, DeclPtrTy(), + &SS); + } + + // FIXME: We lose a lot of source information by mapping directly to the + // DeclarationName. + OwningExprResult Result + = BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, + Member.getSourceRange().getBegin(), + GetNameFromUnqualifiedId(Member), + ObjCImpDecl, &SS); + + if (Result.isInvalid() || HasTrailingLParen || + Member.getKind() != UnqualifiedId::IK_DestructorName) + return move(Result); + + // The only way a reference to a destructor can be used is to + // immediately call them. Since the next token is not a '(', produce a + // diagnostic and build the call now. + Expr *E = (Expr *)Result.get(); + SourceLocation ExpectedLParenLoc + = PP.getLocForEndOfToken(Member.getSourceRange().getEnd()); + Diag(E->getLocStart(), diag::err_dtor_expr_without_call) + << isa<CXXPseudoDestructorExpr>(E) + << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()"); + + return ActOnCallExpr(0, move(Result), ExpectedLParenLoc, + MultiExprArg(*this, 0, 0), 0, ExpectedLParenLoc); } Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, @@ -2713,7 +2684,7 @@ void Sema::DeconstructCallFunction(Expr *FnExpr, SourceRange &QualifierRange, bool &ArgumentDependentLookup, bool &HasExplicitTemplateArguments, - const TemplateArgument *&ExplicitTemplateArgs, + const TemplateArgumentLoc *&ExplicitTemplateArgs, unsigned &NumExplicitTemplateArgs) { // Set defaults for all of the output parameters. Function = 0; @@ -2738,16 +2709,12 @@ void Sema::DeconstructCallFunction(Expr *FnExpr, cast<UnaryOperator>(FnExpr)->getOpcode() == UnaryOperator::AddrOf) { FnExpr = cast<UnaryOperator>(FnExpr)->getSubExpr(); - } else if (QualifiedDeclRefExpr *QDRExpr - = dyn_cast<QualifiedDeclRefExpr>(FnExpr)) { - // Qualified names disable ADL (C++0x [basic.lookup.argdep]p1). - ArgumentDependentLookup = false; - Qualifier = QDRExpr->getQualifier(); - QualifierRange = QDRExpr->getQualifierRange(); - Function = dyn_cast<NamedDecl>(QDRExpr->getDecl()); - break; } else if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(FnExpr)) { Function = dyn_cast<NamedDecl>(DRExpr->getDecl()); + if ((Qualifier = DRExpr->getQualifier())) { + ArgumentDependentLookup = false; + QualifierRange = DRExpr->getQualifierRange(); + } break; } else if (UnresolvedFunctionNameExpr *DepName = dyn_cast<UnresolvedFunctionNameExpr>(FnExpr)) { @@ -2866,24 +2833,29 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, if (BinaryOperator *BO = dyn_cast<BinaryOperator>(Fn->IgnoreParens())) { if (BO->getOpcode() == BinaryOperator::PtrMemD || BO->getOpcode() == BinaryOperator::PtrMemI) { - const FunctionProtoType *FPT = cast<FunctionProtoType>(BO->getType()); - QualType ResultTy = FPT->getResultType().getNonReferenceType(); + if (const FunctionProtoType *FPT = + dyn_cast<FunctionProtoType>(BO->getType())) { + QualType ResultTy = FPT->getResultType().getNonReferenceType(); - ExprOwningPtr<CXXMemberCallExpr> - TheCall(this, new (Context) CXXMemberCallExpr(Context, BO, Args, - NumArgs, ResultTy, - RParenLoc)); + ExprOwningPtr<CXXMemberCallExpr> + TheCall(this, new (Context) CXXMemberCallExpr(Context, BO, Args, + NumArgs, ResultTy, + RParenLoc)); - if (CheckCallReturnType(FPT->getResultType(), - BO->getRHS()->getSourceRange().getBegin(), - TheCall.get(), 0)) - return ExprError(); + if (CheckCallReturnType(FPT->getResultType(), + BO->getRHS()->getSourceRange().getBegin(), + TheCall.get(), 0)) + return ExprError(); - if (ConvertArgumentsForCall(&*TheCall, BO, 0, FPT, Args, NumArgs, - RParenLoc)) - return ExprError(); + if (ConvertArgumentsForCall(&*TheCall, BO, 0, FPT, Args, NumArgs, + RParenLoc)) + return ExprError(); - return Owned(MaybeBindToTemporary(TheCall.release()).release()); + return Owned(MaybeBindToTemporary(TheCall.release()).release()); + } + return ExprError(Diag(Fn->getLocStart(), + diag::err_typecheck_call_not_function) + << Fn->getType() << Fn->getSourceRange()); } } } @@ -2893,7 +2865,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, // lookup and whether there were any explicitly-specified template arguments. bool ADL = true; bool HasExplicitTemplateArgs = 0; - const TemplateArgument *ExplicitTemplateArgs = 0; + const TemplateArgumentLoc *ExplicitTemplateArgs = 0; unsigned NumExplicitTemplateArgs = 0; NestedNameSpecifier *Qualifier = 0; SourceRange QualifierRange; @@ -2932,19 +2904,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, if (!FDecl) return ExprError(); - // Update Fn to refer to the actual function selected. - Expr *NewFn = 0; - if (Qualifier) - NewFn = new (Context) QualifiedDeclRefExpr(FDecl, FDecl->getType(), - Fn->getLocStart(), - false, false, - QualifierRange, - Qualifier); - else - NewFn = new (Context) DeclRefExpr(FDecl, FDecl->getType(), - Fn->getLocStart()); - Fn->Destroy(Context); - Fn = NewFn; + Fn = FixOverloadedFunctionReference(Fn, FDecl); } } @@ -3543,7 +3503,10 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, compositeType = Context.getObjCIdType(); } else if (LHSTy->isObjCIdType() || RHSTy->isObjCIdType()) { compositeType = Context.getObjCIdType(); - } else { + } else if (!(compositeType = + Context.areCommonBaseCompatible(LHSOPT, RHSOPT)).isNull()) + ; + else { Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands) << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); @@ -4080,7 +4043,7 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { // This check seems unnatural, however it is necessary to ensure the proper // conversion of functions/arrays. If the conversion were done for all - // DeclExpr's (created by ActOnIdentifierExpr), it would mess up the unary + // DeclExpr's (created by ActOnIdExpression), it would mess up the unary // expressions that surpress this implicit conversion (&, sizeof). // // Suppress this for references: C++ 8.5.3p5. @@ -4428,6 +4391,10 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if (!lex->getType()->isIntegerType() || !rex->getType()->isIntegerType()) return InvalidOperands(Loc, lex, rex); + // Vector shifts promote their scalar inputs to vector type. + if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) + return CheckVectorOperands(Loc, lex, rex); + // Shifts don't perform usual arithmetic conversions, they just do integer // promotions on each operand. C99 6.5.7p3 QualType LHSTy = Context.isPromotableBitField(lex); @@ -5083,7 +5050,6 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, static NamedDecl *getPrimaryDecl(Expr *E) { switch (E->getStmtClass()) { case Stmt::DeclRefExprClass: - case Stmt::QualifiedDeclRefExprClass: return cast<DeclRefExpr>(E)->getDecl(); case Stmt::MemberExprClass: // If this is an arrow operator, the address is an offset from @@ -5199,7 +5165,7 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { // Okay: we can take the address of a field. // Could be a pointer to member, though, if there is an explicit // scope qualifier for the class. - if (isa<QualifiedDeclRefExpr>(op)) { + if (isa<DeclRefExpr>(op) && cast<DeclRefExpr>(op)->getQualifier()) { DeclContext *Ctx = dcl->getDeclContext(); if (Ctx && Ctx->isRecord()) { if (FD->getType()->isReferenceType()) { @@ -5216,7 +5182,8 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { } else if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(dcl)) { // Okay: we can take the address of a function. // As above. - if (isa<QualifiedDeclRefExpr>(op) && MD->isInstance()) + if (isa<DeclRefExpr>(op) && cast<DeclRefExpr>(op)->getQualifier() && + MD->isInstance()) return Context.getMemberPointerType(op->getType(), Context.getTypeDeclType(MD->getParent()).getTypePtr()); } else if (!isa<FunctionDecl>(dcl)) @@ -5426,6 +5393,72 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, OpLoc)); } +/// SuggestParentheses - Emit a diagnostic together with a fixit hint that wraps +/// ParenRange in parentheses. +static void SuggestParentheses(Sema &Self, SourceLocation Loc, + const PartialDiagnostic &PD, + SourceRange ParenRange) +{ + SourceLocation EndLoc = Self.PP.getLocForEndOfToken(ParenRange.getEnd()); + if (!ParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { + // We can't display the parentheses, so just dig the + // warning/error and return. + Self.Diag(Loc, PD); + return; + } + + Self.Diag(Loc, PD) + << CodeModificationHint::CreateInsertion(ParenRange.getBegin(), "(") + << CodeModificationHint::CreateInsertion(EndLoc, ")"); +} + +/// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison +/// operators are mixed in a way that suggests that the programmer forgot that +/// comparison operators have higher precedence. The most typical example of +/// such code is "flags & 0x0020 != 0", which is equivalent to "flags & 1". +static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperator::Opcode Opc, + SourceLocation OpLoc,Expr *lhs,Expr *rhs){ + typedef BinaryOperator BinOp; + BinOp::Opcode lhsopc = static_cast<BinOp::Opcode>(-1), + rhsopc = static_cast<BinOp::Opcode>(-1); + if (BinOp *BO = dyn_cast<BinOp>(lhs)) + lhsopc = BO->getOpcode(); + if (BinOp *BO = dyn_cast<BinOp>(rhs)) + rhsopc = BO->getOpcode(); + + // Subs are not binary operators. + if (lhsopc == -1 && rhsopc == -1) + return; + + // Bitwise operations are sometimes used as eager logical ops. + // Don't diagnose this. + if ((BinOp::isComparisonOp(lhsopc) || BinOp::isBitwiseOp(lhsopc)) && + (BinOp::isComparisonOp(rhsopc) || BinOp::isBitwiseOp(rhsopc))) + return; + + if (BinOp::isComparisonOp(lhsopc)) + SuggestParentheses(Self, OpLoc, + PDiag(diag::warn_precedence_bitwise_rel) + << SourceRange(lhs->getLocStart(), OpLoc) + << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc), + 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), + SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart())); +} + +/// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky +/// precedence. This currently diagnoses only "arg1 'bitwise' arg2 'eq' arg3". +/// But it could also warn about arg1 && arg2 || arg3, as GCC 4.3+ does. +static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperator::Opcode Opc, + SourceLocation OpLoc, Expr *lhs, Expr *rhs){ + if (BinaryOperator::isBitwiseOp(Opc)) + DiagnoseBitwisePrecedence(Self, Opc, OpLoc, lhs, rhs); +} + // Binary Operators. 'Tok' is the token for the operator. Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, tok::TokenKind Kind, @@ -5436,6 +5469,9 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, assert((lhs != 0) && "ActOnBinOp(): missing left expression"); assert((rhs != 0) && "ActOnBinOp(): missing right expression"); + // Emit warnings for tricky precedence issues, e.g. "bitfield & 0x4 == 0" + DiagnoseBinOpPrecedence(*this, Opc, TokLoc, lhs, rhs); + if (getLangOptions().CPlusPlus && (lhs->getType()->isOverloadableType() || rhs->getType()->isOverloadableType())) { @@ -5451,7 +5487,7 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, Expr *Args[2] = { lhs, rhs }; DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OverOp); - ArgumentDependentLookup(OpName, Args, 2, Functions); + ArgumentDependentLookup(OpName, /*Operator*/true, Args, 2, Functions); } // Build the (potentially-overloaded, potentially-dependent) @@ -5569,7 +5605,7 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, Functions); DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OverOp); - ArgumentDependentLookup(OpName, &Input, 1, Functions); + ArgumentDependentLookup(OpName, /*Operator*/true, &Input, 1, Functions); } return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(input)); @@ -5673,6 +5709,10 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, if (!Dependent) { bool DidWarnAboutNonPOD = false; + if (RequireCompleteType(TypeLoc, Res->getType(), + diag::err_offsetof_incomplete_type)) + return ExprError(); + // FIXME: Dependent case loses a lot of information here. And probably // leaks like a sieve. for (unsigned i = 0; i != NumComponents; ++i) { @@ -6240,21 +6280,21 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { // Implicit instantiation of function templates and member functions of // class templates. - if (!Function->getBody() && - Function->getTemplateSpecializationKind() - == TSK_ImplicitInstantiation) { + if (!Function->getBody() && Function->isImplicitlyInstantiable()) { bool AlreadyInstantiated = false; if (FunctionTemplateSpecializationInfo *SpecInfo = Function->getTemplateSpecializationInfo()) { if (SpecInfo->getPointOfInstantiation().isInvalid()) SpecInfo->setPointOfInstantiation(Loc); - else + else if (SpecInfo->getTemplateSpecializationKind() + == TSK_ImplicitInstantiation) AlreadyInstantiated = true; } else if (MemberSpecializationInfo *MSInfo = Function->getMemberSpecializationInfo()) { if (MSInfo->getPointOfInstantiation().isInvalid()) MSInfo->setPointOfInstantiation(Loc); - else + else if (MSInfo->getTemplateSpecializationKind() + == TSK_ImplicitInstantiation) AlreadyInstantiated = true; } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index d4d031f..4868c14 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -22,41 +22,6 @@ #include "llvm/ADT/STLExtras.h" using namespace clang; -/// ActOnCXXConversionFunctionExpr - Parse a C++ conversion function -/// name (e.g., operator void const *) as an expression. This is -/// very similar to ActOnIdentifierExpr, except that instead of -/// providing an identifier the parser provides the type of the -/// conversion function. -Sema::OwningExprResult -Sema::ActOnCXXConversionFunctionExpr(Scope *S, SourceLocation OperatorLoc, - TypeTy *Ty, bool HasTrailingLParen, - const CXXScopeSpec &SS, - bool isAddressOfOperand) { - //FIXME: Preserve type source info. - QualType ConvType = GetTypeFromParser(Ty); - CanQualType ConvTypeCanon = Context.getCanonicalType(ConvType); - DeclarationName ConvName - = Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon); - return ActOnDeclarationNameExpr(S, OperatorLoc, ConvName, HasTrailingLParen, - &SS, isAddressOfOperand); -} - -/// ActOnCXXOperatorFunctionIdExpr - Parse a C++ overloaded operator -/// name (e.g., @c operator+ ) as an expression. This is very -/// similar to ActOnIdentifierExpr, except that instead of providing -/// an identifier the parser provides the kind of overloaded -/// operator that was parsed. -Sema::OwningExprResult -Sema::ActOnCXXOperatorFunctionIdExpr(Scope *S, SourceLocation OperatorLoc, - OverloadedOperatorKind Op, - bool HasTrailingLParen, - const CXXScopeSpec &SS, - bool isAddressOfOperand) { - DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(Op); - return ActOnDeclarationNameExpr(S, OperatorLoc, Name, HasTrailingLParen, &SS, - isAddressOfOperand); -} - /// ActOnCXXTypeidOfType - Parse typeid( type-id ). Action::OwningExprResult Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, @@ -212,7 +177,7 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, PDiag(diag::err_invalid_incomplete_type_use) << FullRange)) return ExprError(); - + if (RequireNonAbstractType(TyBeginLoc, Ty, diag::err_allocation_of_abstract_type)) return ExprError(); @@ -288,7 +253,6 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, << FullRange); assert(NumExprs == 0 && "Expected 0 expressions"); - // C++ [expr.type.conv]p2: // The expression T(), where T is a simple-type-specifier for a non-array // complete object type or the (possibly cv-qualified) void type, creates an @@ -312,7 +276,6 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, MultiExprArg ConstructorArgs, SourceLocation ConstructorRParen) { Expr *ArraySize = 0; - unsigned Skip = 0; // If the specified type is an array, unwrap it and save the expression. if (D.getNumTypeObjects() > 0 && D.getTypeObject(0).Kind == DeclaratorChunk::Array) { @@ -323,14 +286,25 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, if (!Chunk.Arr.NumElts) return ExprError(Diag(Chunk.Loc, diag::err_array_new_needs_size) << D.getSourceRange()); + + if (ParenTypeId) { + // Can't have dynamic array size when the type-id is in parentheses. + Expr *NumElts = (Expr *)Chunk.Arr.NumElts; + if (!NumElts->isTypeDependent() && !NumElts->isValueDependent() && + !NumElts->isIntegerConstantExpr(Context)) { + Diag(D.getTypeObject(0).Loc, diag::err_new_paren_array_nonconst) + << NumElts->getSourceRange(); + return ExprError(); + } + } + ArraySize = static_cast<Expr*>(Chunk.Arr.NumElts); - Skip = 1; + D.DropFirstTypeObject(); } // Every dimension shall be of constant size. - if (D.getNumTypeObjects() > 0 && - D.getTypeObject(0).Kind == DeclaratorChunk::Array) { - for (unsigned I = 1, N = D.getNumTypeObjects(); I < N; ++I) { + if (ArraySize) { + for (unsigned I = 0, N = D.getNumTypeObjects(); I < N; ++I) { if (D.getTypeObject(I).Kind != DeclaratorChunk::Array) break; @@ -345,10 +319,10 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, } } } - + //FIXME: Store DeclaratorInfo in CXXNew expression. DeclaratorInfo *DInfo = 0; - QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, &DInfo, Skip); + QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, &DInfo); if (D.isInvalidType()) return ExprError(); @@ -935,7 +909,7 @@ Sema::ActOnCXXConditionDeclarationExpr(Scope *S, SourceLocation StartLoc, // FIXME: Store DeclaratorInfo in the expression. DeclaratorInfo *DInfo = 0; TagDecl *OwnedTag = 0; - QualType Ty = GetTypeForDeclarator(D, S, &DInfo, /*Skip=*/0, &OwnedTag); + QualType Ty = GetTypeForDeclarator(D, S, &DInfo, &OwnedTag); if (Ty->isFunctionType()) { // The declarator shall not specify a function... // We exit without creating a CXXConditionDeclExpr because a FunctionDecl @@ -1139,6 +1113,10 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, From = CastArg.takeAs<Expr>(); return BuildCXXDerivedToBaseExpr(From, CastKind, ICS, Flavor); } + + if (ICS.UserDefined.After.Second == ICK_Pointer_Member && + ToType.getNonReferenceType()->isMemberFunctionPointerType()) + CastKind = CastExpr::CK_BaseToDerivedMemberPointer; From = new (Context) ImplicitCastExpr(ToType.getNonReferenceType(), CastKind, CastArg.takeAs<Expr>(), @@ -1390,7 +1368,8 @@ QualType Sema::CheckPointerToMemberOperands( LType = Ptr->getPointeeType().getNonReferenceType(); else { Diag(Loc, diag::err_bad_memptr_lhs) - << OpSpelling << 1 << LType << lex->getSourceRange(); + << OpSpelling << 1 << LType + << CodeModificationHint::CreateReplacement(SourceRange(Loc), ".*"); return QualType(); } } @@ -1403,8 +1382,10 @@ QualType Sema::CheckPointerToMemberOperands( // overkill? if (!IsDerivedFrom(LType, Class, Paths) || Paths.isAmbiguous(Context.getCanonicalType(Class))) { + const char *ReplaceStr = isIndirect ? ".*" : "->*"; Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling - << (int)isIndirect << lex->getType() << lex->getSourceRange(); + << (int)isIndirect << lex->getType() << + CodeModificationHint::CreateReplacement(SourceRange(Loc), ReplaceStr); return QualType(); } } @@ -2105,110 +2086,6 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, return move(Base); } -Sema::OwningExprResult -Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation ClassNameLoc, - IdentifierInfo *ClassName, - const CXXScopeSpec &SS, - bool HasTrailingLParen) { - if (SS.isInvalid()) - return ExprError(); - - QualType BaseType; - if (isUnknownSpecialization(SS)) - BaseType = Context.getTypenameType((NestedNameSpecifier *)SS.getScopeRep(), - ClassName); - else { - TypeTy *BaseTy = getTypeName(*ClassName, ClassNameLoc, S, &SS); - - // FIXME: If Base is dependent, we might not be able to resolve it here. - if (!BaseTy) { - Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) - << ClassName; - return ExprError(); - } - - BaseType = GetTypeFromParser(BaseTy); - } - - return ActOnDestructorReferenceExpr(S, move(Base), OpLoc, OpKind, - SourceRange(ClassNameLoc), - BaseType.getAsOpaquePtr(), - SS, HasTrailingLParen); -} - -Sema::OwningExprResult -Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceRange TypeRange, - TypeTy *T, - const CXXScopeSpec &SS, - bool HasTrailingLParen) { - QualType Type = QualType::getFromOpaquePtr(T); - CanQualType CanType = Context.getCanonicalType(Type); - DeclarationName DtorName = - Context.DeclarationNames.getCXXDestructorName(CanType); - - OwningExprResult Result - = BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, - TypeRange.getBegin(), DtorName, DeclPtrTy(), - &SS); - if (Result.isInvalid() || HasTrailingLParen) - return move(Result); - - // The only way a reference to a destructor can be used is to - // immediately call them. Since the next token is not a '(', produce a - // diagnostic and build the call now. - Expr *E = (Expr *)Result.get(); - SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(TypeRange.getEnd()); - Diag(E->getLocStart(), diag::err_dtor_expr_without_call) - << isa<CXXPseudoDestructorExpr>(E) - << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()"); - - return ActOnCallExpr(0, move(Result), ExpectedLParenLoc, - MultiExprArg(*this, 0, 0), 0, ExpectedLParenLoc); -} - -Sema::OwningExprResult -Sema::ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation ClassNameLoc, - OverloadedOperatorKind OverOpKind, - const CXXScopeSpec *SS) { - if (SS && SS->isInvalid()) - return ExprError(); - - DeclarationName Name = - Context.DeclarationNames.getCXXOperatorName(OverOpKind); - - return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc, - Name, DeclPtrTy(), SS); -} - -Sema::OwningExprResult -Sema::ActOnConversionOperatorReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation ClassNameLoc, - TypeTy *Ty, - const CXXScopeSpec *SS) { - if (SS && SS->isInvalid()) - return ExprError(); - - //FIXME: Preserve type source info. - QualType ConvType = GetTypeFromParser(Ty); - CanQualType ConvTypeCanon = Context.getCanonicalType(ConvType); - DeclarationName ConvName = - Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon); - - return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc, - ConvName, DeclPtrTy(), SS); -} - CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, CXXMethodDecl *Method) { MemberExpr *ME = @@ -2333,6 +2210,7 @@ bool Sema::isImplicitMemberReference(const CXXScopeSpec *SS, NamedDecl *D, if (!Method && (FunTmpl = dyn_cast<FunctionTemplateDecl>(*Ovl))) 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(); if (isa<CXXMethodDecl>(D) && !FunTmpl) @@ -2350,6 +2228,12 @@ bool Sema::isImplicitMemberReference(const CXXScopeSpec *SS, NamedDecl *D, // 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); + + // If the type of "this" is dependent, we can't tell if the member is in a + // base class or not, so treat this as a dependent implicit member reference. + if (ThisType->isDependentType()) + return true; + QualType CtxType = Context.getTypeDeclType(cast<CXXRecordDecl>(Ctx)); QualType ClassType = Context.getTypeDeclType(cast<CXXRecordDecl>(MD->getParent())); diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index dd877c1..93752e1 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1239,6 +1239,14 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class, BaseEnd = Class->bases_end(); Base != BaseEnd; ++Base) { const RecordType *BaseType = Base->getType()->getAs<RecordType>(); + // In dependent contexts, we do ADL twice, and the first time around, + // the base type might be a dependent TemplateSpecializationType, or a + // TemplateTypeParmType. If that happens, simply ignore it. + // FIXME: If we want to support export, we probably need to add the + // namespace of the template in a TemplateSpecializationType, or even + // the classes and namespaces of known non-dependent arguments. + if (!BaseType) + continue; CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(BaseType->getDecl()); if (AssociatedClasses.insert(BaseDecl)) { // Find the associated namespace for this base class. @@ -1561,7 +1569,7 @@ static void CollectFunctionDecl(Sema::FunctionSet &Functions, Functions.insert(FunTmpl); } -void Sema::ArgumentDependentLookup(DeclarationName Name, +void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator, Expr **Args, unsigned NumArgs, FunctionSet &Functions) { // Find all of the associated namespaces and classes based on the @@ -1572,6 +1580,13 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, AssociatedNamespaces, AssociatedClasses); + QualType T1, T2; + if (Operator) { + T1 = Args[0]->getType(); + if (NumArgs >= 2) + T2 = Args[1]->getType(); + } + // C++ [basic.lookup.argdep]p3: // Let X be the lookup set produced by unqualified lookup (3.4.1) // and let Y be the lookup set produced by argument dependent @@ -1608,7 +1623,10 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, continue; } - CollectFunctionDecl(Functions, D); + FunctionDecl *Fn; + if (!Operator || !(Fn = dyn_cast<FunctionDecl>(D)) || + IsAcceptableNonMemberOperatorCandidate(Fn, T1, T2, Context)) + CollectFunctionDecl(Functions, D); } } } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index ebcf3ad..946e282 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -999,6 +999,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, // here. That is handled by CheckPointerConversion. if (getLangOptions().CPlusPlus && FromPointeeType->isRecordType() && ToPointeeType->isRecordType() && + !RequireCompleteType(From->getLocStart(), FromPointeeType, PDiag()) && IsDerivedFrom(FromPointeeType, ToPointeeType)) { ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, ToPointeeType, @@ -2444,7 +2445,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object, void Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, Expr *Object, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, @@ -2489,7 +2490,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, void Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, @@ -2761,7 +2762,7 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); if (S) LookupOverloadedOperatorName(Op, S, T1, T2, Functions); - ArgumentDependentLookup(OpName, Args, NumArgs, Functions); + ArgumentDependentLookup(OpName, /*Operator*/true, Args, NumArgs, Functions); AddFunctionCandidates(Functions, Args, NumArgs, CandidateSet); AddMemberOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet, OpRange); AddBuiltinOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet); @@ -3119,9 +3120,8 @@ static void AddBuiltinAssignmentOperatorCandidates(Sema &S, } } -/// CollectVRQualifiers - This routine returns Volatile/Restrict qualifiers -/// , if any, found in visible type conversion functions found in ArgExpr's -/// type. +/// CollectVRQualifiers - This routine returns Volatile/Restrict qualifiers, +/// if any, found in visible type conversion functions found in ArgExpr's type. static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { Qualifiers VRQuals; const RecordType *TyRec; @@ -3139,7 +3139,7 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl()); OverloadedFunctionDecl *Conversions = - ClassDecl->getVisibleConversionFunctions(); + ClassDecl->getVisibleConversionFunctions(); for (OverloadedFunctionDecl::function_iterator Func = Conversions->function_begin(); @@ -3887,7 +3887,7 @@ void Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, Expr **Args, unsigned NumArgs, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, OverloadCandidateSet& CandidateSet, bool PartialOverloading) { @@ -3908,7 +3908,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, } // FIXME: Pass in the explicit template arguments? - ArgumentDependentLookup(Name, Args, NumArgs, Functions); + ArgumentDependentLookup(Name, /*Operator*/false, Args, NumArgs, Functions); // Erase all of the candidates we already knew about. // FIXME: This is suboptimal. Is there a better way? @@ -4279,7 +4279,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, } bool HasExplicitTemplateArgs = false; - const TemplateArgument *ExplicitTemplateArgs = 0; + const TemplateArgumentLoc *ExplicitTemplateArgs = 0; unsigned NumExplicitTemplateArgs = 0; // Try to dig out the overloaded function. @@ -4287,10 +4287,15 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(OvlExpr)) { Ovl = dyn_cast<OverloadedFunctionDecl>(DR->getDecl()); FunctionTemplate = dyn_cast<FunctionTemplateDecl>(DR->getDecl()); + HasExplicitTemplateArgs = DR->hasExplicitTemplateArgumentList(); + ExplicitTemplateArgs = DR->getTemplateArgs(); + NumExplicitTemplateArgs = DR->getNumTemplateArgs(); } else if (MemberExpr *ME = dyn_cast<MemberExpr>(OvlExpr)) { Ovl = dyn_cast<OverloadedFunctionDecl>(ME->getMemberDecl()); FunctionTemplate = dyn_cast<FunctionTemplateDecl>(ME->getMemberDecl()); - // FIXME: Explicit template arguments + HasExplicitTemplateArgs = ME->hasExplicitTemplateArgumentList(); + ExplicitTemplateArgs = ME->getTemplateArgs(); + NumExplicitTemplateArgs = ME->getNumTemplateArgs(); } else if (TemplateIdRefExpr *TIRE = dyn_cast<TemplateIdRefExpr>(OvlExpr)) { TemplateName Name = TIRE->getTemplateName(); Ovl = Name.getAsOverloadedFunctionDecl(); @@ -4367,6 +4372,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // when converting to member pointer. if (Method->isStatic() == IsMember) continue; + + // If we have explicit template arguments, skip non-templates. + if (HasExplicitTemplateArgs) + continue; } else if (IsMember) continue; @@ -4443,7 +4452,7 @@ static void AddOverloadedCallCandidate(Sema &S, AnyFunctionDecl Callee, bool &ArgumentDependentLookup, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet &CandidateSet, @@ -4475,7 +4484,7 @@ void Sema::AddOverloadedCallCandidates(NamedDecl *Callee, DeclarationName &UnqualifiedName, bool &ArgumentDependentLookup, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet &CandidateSet, @@ -4543,7 +4552,7 @@ void Sema::AddOverloadedCallCandidates(NamedDecl *Callee, FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee, DeclarationName UnqualifiedName, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, @@ -4934,6 +4943,134 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); } +Action::OwningExprResult +Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, + SourceLocation RLoc, + ExprArg Base, ExprArg Idx) { + Expr *Args[2] = { static_cast<Expr*>(Base.get()), + static_cast<Expr*>(Idx.get()) }; + DeclarationName OpName = + Context.DeclarationNames.getCXXOperatorName(OO_Subscript); + + // If either side is type-dependent, create an appropriate dependent + // expression. + if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) { + + OverloadedFunctionDecl *Overloads + = OverloadedFunctionDecl::Create(Context, CurContext, OpName); + + DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy, + LLoc, false, false); + + Base.release(); + Idx.release(); + return Owned(new (Context) CXXOperatorCallExpr(Context, OO_Subscript, Fn, + Args, 2, + Context.DependentTy, + RLoc)); + } + + // Build an empty overload set. + OverloadCandidateSet CandidateSet; + + // Subscript can only be overloaded as a member function. + + // Add operator candidates that are member functions. + AddMemberOperatorCandidates(OO_Subscript, LLoc, Args, 2, CandidateSet); + + // Add builtin operator candidates. + AddBuiltinOperatorCandidates(OO_Subscript, LLoc, Args, 2, CandidateSet); + + // Perform overload resolution. + OverloadCandidateSet::iterator Best; + switch (BestViableFunction(CandidateSet, LLoc, Best)) { + case OR_Success: { + // We found a built-in operator or an overloaded operator. + FunctionDecl *FnDecl = Best->Function; + + if (FnDecl) { + // We matched an overloaded operator. Build a call to that + // operator. + + // Convert the arguments. + CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl); + if (PerformObjectArgumentInitialization(Args[0], Method) || + PerformCopyInitialization(Args[1], + FnDecl->getParamDecl(0)->getType(), + "passing")) + return ExprError(); + + // Determine the result type + QualType ResultTy + = FnDecl->getType()->getAs<FunctionType>()->getResultType(); + ResultTy = ResultTy.getNonReferenceType(); + + // Build the actual expression node. + Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(), + LLoc); + UsualUnaryConversions(FnExpr); + + Base.release(); + Idx.release(); + ExprOwningPtr<CXXOperatorCallExpr> + TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Subscript, + FnExpr, Args, 2, + ResultTy, RLoc)); + + if (CheckCallReturnType(FnDecl->getResultType(), LLoc, TheCall.get(), + FnDecl)) + return ExprError(); + + return MaybeBindToTemporary(TheCall.release()); + } else { + // We matched a built-in operator. Convert the arguments, then + // break out so that we will build the appropriate built-in + // operator node. + if (PerformImplicitConversion(Args[0], Best->BuiltinTypes.ParamTypes[0], + Best->Conversions[0], "passing") || + PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1], + Best->Conversions[1], "passing")) + return ExprError(); + + break; + } + } + + 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); + } + + case OR_Ambiguous: + Diag(LLoc, diag::err_ovl_ambiguous_oper) + << "[]" << Args[0]->getSourceRange() << Args[1]->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true, + "[]", LLoc); + return ExprError(); + + case OR_Deleted: + Diag(LLoc, diag::err_ovl_deleted_oper) + << Best->Function->isDeleted() << "[]" + << Args[0]->getSourceRange() << Args[1]->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + return ExprError(); + } + + // We matched a built-in operator; build it. + Base.release(); + Idx.release(); + return CreateBuiltinArraySubscriptExpr(Owned(Args[0]), LLoc, + Owned(Args[1]), RLoc); +} + /// BuildCallToMemberFunction - Build a call to a member /// function. MemExpr is the expression that refers to the member /// function (and includes the object parameter), Args/NumArgs are the @@ -4967,10 +5104,15 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, for (OverloadIterator Func(MemExpr->getMemberDecl()), FuncEnd; Func != FuncEnd; ++Func) { - if ((Method = dyn_cast<CXXMethodDecl>(*Func))) + if ((Method = dyn_cast<CXXMethodDecl>(*Func))) { + // If explicit template arguments were provided, we can't call a + // non-template member function. + if (MemExpr->hasExplicitTemplateArgumentList()) + continue; + AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/false); - else + } else AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(*Func), MemExpr->hasExplicitTemplateArgumentList(), MemExpr->getTemplateArgs(), @@ -5361,8 +5503,14 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) { Expr *NewExpr = FixOverloadedFunctionReference(PE->getSubExpr(), Fn); - NewExpr->setType(PE->getSubExpr()->getType()); - return NewExpr; + PE->setSubExpr(NewExpr); + PE->setType(NewExpr->getType()); + } else if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { + Expr *NewExpr = FixOverloadedFunctionReference(ICE->getSubExpr(), Fn); + assert(Context.hasSameType(ICE->getSubExpr()->getType(), + NewExpr->getType()) && + "Implicit cast type cannot be determined from overload"); + ICE->setSubExpr(NewExpr); } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(E)) { assert(UnOp->getOpcode() == UnaryOperator::AddrOf && "Can only take the address of an overloaded function"); @@ -5370,18 +5518,19 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { if (Method->isStatic()) { // Do nothing: static member functions aren't any different // from non-member functions. - } else if (QualifiedDeclRefExpr *DRE - = dyn_cast<QualifiedDeclRefExpr>(UnOp->getSubExpr())) { - // We have taken the address of a pointer to member - // function. Perform the computation here so that we get the - // appropriate pointer to member type. - DRE->setDecl(Fn); - DRE->setType(Fn->getType()); - QualType ClassType - = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext())); - E->setType(Context.getMemberPointerType(Fn->getType(), - ClassType.getTypePtr())); - return E; + } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(UnOp->getSubExpr())) { + if (DRE->getQualifier()) { + // We have taken the address of a pointer to member + // function. Perform the computation here so that we get the + // appropriate pointer to member type. + DRE->setDecl(Fn); + DRE->setType(Fn->getType()); + QualType ClassType + = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext())); + E->setType(Context.getMemberPointerType(Fn->getType(), + ClassType.getTypePtr())); + return E; + } } // FIXME: TemplateIdRefExpr referring to a member function template // specialization! @@ -5393,26 +5542,35 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { return UnOp; } else if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) { assert((isa<OverloadedFunctionDecl>(DR->getDecl()) || - isa<FunctionTemplateDecl>(DR->getDecl())) && - "Expected overloaded function or function template"); + isa<FunctionTemplateDecl>(DR->getDecl()) || + isa<FunctionDecl>(DR->getDecl())) && + "Expected function or function template"); DR->setDecl(Fn); E->setType(Fn->getType()); } else if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(E)) { MemExpr->setMemberDecl(Fn); E->setType(Fn->getType()); } else if (TemplateIdRefExpr *TID = dyn_cast<TemplateIdRefExpr>(E)) { - // FIXME: We should capture the template arguments here. - if (NestedNameSpecifier *Qualifier = TID->getQualifier()) - E = new (Context) QualifiedDeclRefExpr(Fn, Fn->getType(), - TID->getTemplateNameLoc(), - /*FIXME?*/false, /*FIXME?*/false, - TID->getQualifierRange(), - Qualifier); - else - E = new (Context) DeclRefExpr(Fn, Fn->getType(), - TID->getTemplateNameLoc()); + E = DeclRefExpr::Create(Context, + TID->getQualifier(), TID->getQualifierRange(), + Fn, TID->getTemplateNameLoc(), + true, + TID->getLAngleLoc(), + TID->getTemplateArgs(), + TID->getNumTemplateArgs(), + TID->getRAngleLoc(), + Fn->getType(), + /*FIXME?*/false, /*FIXME?*/false); - TID->Destroy(Context); + // FIXME: Don't destroy TID here, since we need its template arguments + // to survive. + // TID->Destroy(Context); + } else if (isa<UnresolvedFunctionNameExpr>(E)) { + return DeclRefExpr::Create(Context, + /*Qualifier=*/0, + /*QualifierRange=*/SourceRange(), + Fn, E->getLocStart(), + Fn->getType(), false, false); } else { assert(false && "Invalid reference to overloaded function"); } diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 1453424..6a65bd1 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -70,7 +70,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { SourceLocation Loc; SourceRange R1, R2; - if (!E->isUnusedResultAWarning(Loc, R1, R2)) + if (!E->isUnusedResultAWarning(Loc, R1, R2, Context)) return; // Okay, we have an unused result. Depending on what the base expression is, diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 0f22320..3c56358 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -98,29 +98,43 @@ static NamedDecl *isAcceptableTemplateName(ASTContext &Context, NamedDecl *D) { } TemplateNameKind Sema::isTemplateName(Scope *S, - const IdentifierInfo &II, - SourceLocation IdLoc, - const CXXScopeSpec *SS, + const CXXScopeSpec &SS, + UnqualifiedId &Name, TypeTy *ObjectTypePtr, bool EnteringContext, TemplateTy &TemplateResult) { + DeclarationName TName; + + switch (Name.getKind()) { + case UnqualifiedId::IK_Identifier: + TName = DeclarationName(Name.Identifier); + break; + + case UnqualifiedId::IK_OperatorFunctionId: + TName = Context.DeclarationNames.getCXXOperatorName( + Name.OperatorFunctionId.Operator); + break; + + default: + return TNK_Non_template; + } + // Determine where to perform name lookup DeclContext *LookupCtx = 0; bool isDependent = false; if (ObjectTypePtr) { // This nested-name-specifier occurs in a member access expression, e.g., // x->B::f, and we are looking into the type of the object. - assert((!SS || !SS->isSet()) && - "ObjectType and scope specifier cannot coexist"); + assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr); LookupCtx = computeDeclContext(ObjectType); isDependent = ObjectType->isDependentType(); - } else if (SS && SS->isSet()) { + } else if (SS.isSet()) { // This nested-name-specifier occurs after another nested-name-specifier, // so long into the context associated with the prior nested-name-specifier. - LookupCtx = computeDeclContext(*SS, EnteringContext); - isDependent = isDependentScopeSpecifier(*SS); + LookupCtx = computeDeclContext(SS, EnteringContext); + isDependent = isDependentScopeSpecifier(SS); } LookupResult Found; @@ -132,10 +146,10 @@ TemplateNameKind Sema::isTemplateName(Scope *S, // nested-name-specifier. // The declaration context must be complete. - if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS)) + if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS)) return TNK_Non_template; - LookupQualifiedName(Found, LookupCtx, &II, LookupOrdinaryName); + LookupQualifiedName(Found, LookupCtx, TName, LookupOrdinaryName); if (ObjectTypePtr && Found.getKind() == LookupResult::NotFound) { // C++ [basic.lookup.classref]p1: @@ -150,7 +164,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S, // // FIXME: When we're instantiating a template, do we actually have to // look in the scope of the template? Seems fishy... - LookupName(Found, S, &II, LookupOrdinaryName); + LookupName(Found, S, TName, LookupOrdinaryName); ObjectTypeSearchedInScope = true; } } else if (isDependent) { @@ -158,7 +172,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S, return TNK_Non_template; } else { // Perform unqualified name lookup in the current scope. - LookupName(Found, S, &II, LookupOrdinaryName); + LookupName(Found, S, TName, LookupOrdinaryName); } // FIXME: Cope with ambiguous name-lookup results. @@ -177,7 +191,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S, // postfix-expression and [...] // LookupResult FoundOuter; - LookupName(FoundOuter, S, &II, LookupOrdinaryName); + LookupName(FoundOuter, S, TName, LookupOrdinaryName); // FIXME: Handle ambiguities in this lookup better NamedDecl *OuterTemplate = isAcceptableTemplateName(Context, FoundOuter.getAsSingleDecl(Context)); @@ -194,8 +208,10 @@ TemplateNameKind Sema::isTemplateName(Scope *S, // entity as the one found in the class of the object expression, // otherwise the program is ill-formed. if (OuterTemplate->getCanonicalDecl() != Template->getCanonicalDecl()) { - Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous) - << &II; + Diag(Name.getSourceRange().getBegin(), + diag::err_nested_name_member_ref_lookup_ambiguous) + << TName + << Name.getSourceRange(); Diag(Template->getLocation(), diag::note_ambig_member_ref_object_type) << QualType::getFromOpaquePtr(ObjectTypePtr); Diag(OuterTemplate->getLocation(), diag::note_ambig_member_ref_scope); @@ -206,9 +222,9 @@ TemplateNameKind Sema::isTemplateName(Scope *S, } } - if (SS && SS->isSet() && !SS->isInvalid()) { + if (SS.isSet() && !SS.isInvalid()) { NestedNameSpecifier *Qualifier - = static_cast<NestedNameSpecifier *>(SS->getScopeRep()); + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(Template)) TemplateResult @@ -321,8 +337,11 @@ void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam, TypeTy *DefaultT) { TemplateTypeParmDecl *Parm = cast<TemplateTypeParmDecl>(TypeParam.getAs<Decl>()); - // FIXME: Preserve type source info. - QualType Default = GetTypeFromParser(DefaultT); + + DeclaratorInfo *DefaultDInfo; + GetTypeFromParser(DefaultT, &DefaultDInfo); + + assert(DefaultDInfo && "expected source information for type"); // C++0x [temp.param]p9: // A default template-argument may be specified for any kind of @@ -337,12 +356,12 @@ void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam, // FIXME: Implement this check! Needs a recursive walk over the types. // Check the template argument itself. - if (CheckTemplateArgument(Parm, Default, DefaultLoc)) { + if (CheckTemplateArgument(Parm, DefaultDInfo)) { Parm->setInvalidDecl(); return; } - Parm->setDefaultArgument(Default, DefaultLoc, false); + Parm->setDefaultArgument(DefaultDInfo, false); } /// \brief Check that the type of a non-type template parameter is @@ -610,11 +629,19 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, SemanticContext = PrevDecl->getDeclContext(); } else { // Declarations in outer scopes don't matter. However, the outermost - // context we computed is the semntic context for our new + // context we computed is the semantic context for our new // declaration. PrevDecl = 0; SemanticContext = OutermostContext; } + + if (CurContext->isDependentContext()) { + // If this is a dependent context, we don't want to link the friend + // class template to the template in scope, because that would perform + // checking of the template parameter lists that can't be performed + // until the outer context is instantiated. + PrevDecl = 0; + } } else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S)) PrevDecl = 0; @@ -843,7 +870,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, SawParameterPack = true; ParameterPackLoc = NewTypeParm->getLocation(); } else if (OldTypeParm && OldTypeParm->hasDefaultArgument() && - NewTypeParm->hasDefaultArgument()) { + NewTypeParm->hasDefaultArgument()) { OldDefaultLoc = OldTypeParm->getDefaultArgumentLoc(); NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc(); SawDefaultArgument = true; @@ -853,8 +880,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, // Merge the default argument from the old declaration to the // new declaration. SawDefaultArgument = true; - NewTypeParm->setDefaultArgument(OldTypeParm->getDefaultArgument(), - OldTypeParm->getDefaultArgumentLoc(), + NewTypeParm->setDefaultArgument(OldTypeParm->getDefaultArgumentInfo(), true); PreviousDefaultArgLoc = OldTypeParm->getDefaultArgumentLoc(); } else if (NewTypeParm->hasDefaultArgument()) { @@ -1096,24 +1122,28 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, /// into template arguments used by semantic analysis. void Sema::translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, SourceLocation *TemplateArgLocs, - llvm::SmallVector<TemplateArgument, 16> &TemplateArgs) { + llvm::SmallVector<TemplateArgumentLoc, 16> &TemplateArgs) { TemplateArgs.reserve(TemplateArgsIn.size()); void **Args = TemplateArgsIn.getArgs(); bool *ArgIsType = TemplateArgsIn.getArgIsType(); for (unsigned Arg = 0, Last = TemplateArgsIn.size(); Arg != Last; ++Arg) { - TemplateArgs.push_back( - ArgIsType[Arg]? TemplateArgument(TemplateArgLocs[Arg], - //FIXME: Preserve type source info. - Sema::GetTypeFromParser(Args[Arg])) - : TemplateArgument(reinterpret_cast<Expr *>(Args[Arg]))); + if (ArgIsType[Arg]) { + DeclaratorInfo *DI; + QualType T = Sema::GetTypeFromParser(Args[Arg], &DI); + if (!DI) DI = Context.getTrivialDeclaratorInfo(T, TemplateArgLocs[Arg]); + TemplateArgs.push_back(TemplateArgumentLoc(TemplateArgument(T), DI)); + } else { + Expr *E = reinterpret_cast<Expr *>(Args[Arg]); + TemplateArgs.push_back(TemplateArgumentLoc(TemplateArgument(E), E)); + } } } QualType Sema::CheckTemplateIdType(TemplateName Name, SourceLocation TemplateLoc, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc) { TemplateDecl *Template = Name.getAsTemplateDecl(); @@ -1155,7 +1185,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, Converted.flatSize()); // FIXME: CanonType is not actually the canonical type, and unfortunately - // it is a TemplateTypeSpecializationType that we will never use again. + // it is a TemplateSpecializationType that we will never use again. // In the future, we need to teach getTemplateSpecializationType to only // build the canonical type and return that to us. CanonType = Context.getCanonicalType(CanonType); @@ -1190,7 +1220,6 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // Build the fully-sugared type for this class template // specialization, which refers back to the class template // specialization we created or found. - //FIXME: Preserve type source info. return Context.getTemplateSpecializationType(Name, TemplateArgs, NumTemplateArgs, CanonType); } @@ -1199,13 +1228,13 @@ Action::TypeResult Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, - SourceLocation *TemplateArgLocs, + SourceLocation *TemplateArgLocsIn, SourceLocation RAngleLoc) { TemplateName Template = TemplateD.getAsVal<TemplateName>(); // Translate the parser's template argument list in our AST format. - llvm::SmallVector<TemplateArgument, 16> TemplateArgs; - translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); + llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs; + translateTemplateArguments(TemplateArgsIn, TemplateArgLocsIn, TemplateArgs); QualType Result = CheckTemplateIdType(Template, TemplateLoc, LAngleLoc, TemplateArgs.data(), @@ -1216,7 +1245,16 @@ Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc, if (Result.isNull()) return true; - return Result.getAsOpaquePtr(); + DeclaratorInfo *DI = Context.CreateDeclaratorInfo(Result); + TemplateSpecializationTypeLoc TL + = cast<TemplateSpecializationTypeLoc>(DI->getTypeLoc()); + TL.setTemplateNameLoc(TemplateLoc); + TL.setLAngleLoc(LAngleLoc); + TL.setRAngleLoc(RAngleLoc); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) + TL.setArgLocInfo(i, TemplateArgs[i].getLocInfo()); + + return CreateLocInfoType(Result, DI).getAsOpaquePtr(); } Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult, @@ -1226,7 +1264,9 @@ Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult, if (TypeResult.isInvalid()) return Sema::TypeResult(); - QualType Type = QualType::getFromOpaquePtr(TypeResult.get()); + // FIXME: preserve source info, ideally without copying the DI. + DeclaratorInfo *DI; + QualType Type = GetTypeFromParser(TypeResult.get(), &DI); // Verify the tag specifier. TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec); @@ -1256,7 +1296,7 @@ Sema::OwningExprResult Sema::BuildTemplateIdExpr(NestedNameSpecifier *Qualifier, TemplateName Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc) { // FIXME: Can we do any checking at this point? I guess we could check the @@ -1296,13 +1336,13 @@ Sema::OwningExprResult Sema::ActOnTemplateIdExpr(const CXXScopeSpec &SS, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, - SourceLocation *TemplateArgLocs, + SourceLocation *TemplateArgSLs, SourceLocation RAngleLoc) { TemplateName Template = TemplateD.getAsVal<TemplateName>(); // Translate the parser's template argument list in our AST format. - llvm::SmallVector<TemplateArgument, 16> TemplateArgs; - translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); + llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs; + translateTemplateArguments(TemplateArgsIn, TemplateArgSLs, TemplateArgs); TemplateArgsIn.release(); return BuildTemplateIdExpr((NestedNameSpecifier *)SS.getScopeRep(), @@ -1312,41 +1352,6 @@ Sema::OwningExprResult Sema::ActOnTemplateIdExpr(const CXXScopeSpec &SS, RAngleLoc); } -Sema::OwningExprResult -Sema::ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - const CXXScopeSpec &SS, - TemplateTy TemplateD, - SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgsIn, - SourceLocation *TemplateArgLocs, - SourceLocation RAngleLoc) { - TemplateName Template = TemplateD.getAsVal<TemplateName>(); - - // FIXME: We're going to end up looking up the template based on its name, - // twice! - DeclarationName Name; - if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl()) - Name = ActualTemplate->getDeclName(); - else if (OverloadedFunctionDecl *Ovl = Template.getAsOverloadedFunctionDecl()) - Name = Ovl->getDeclName(); - else - Name = Template.getAsDependentTemplateName()->getName(); - - // Translate the parser's template argument list in our AST format. - llvm::SmallVector<TemplateArgument, 16> TemplateArgs; - translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); - TemplateArgsIn.release(); - - // Do we have the save the actual template name? We might need it... - return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, TemplateNameLoc, - Name, true, LAngleLoc, - TemplateArgs.data(), TemplateArgs.size(), - RAngleLoc, DeclPtrTy(), &SS); -} - /// \brief Form a dependent template name. /// /// This action forms a dependent template name given the template @@ -1356,9 +1361,8 @@ Sema::ActOnMemberTemplateIdReferenceExpr(Scope *S, ExprArg Base, /// of the "template" keyword, and "apply" is the \p Name. Sema::TemplateTy Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, - const IdentifierInfo &Name, - SourceLocation NameLoc, const CXXScopeSpec &SS, + UnqualifiedId &Name, TypeTy *ObjectType) { if ((ObjectType && computeDeclContext(QualType::getFromOpaquePtr(ObjectType))) || @@ -1380,11 +1384,13 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, // "template" keyword is now permitted). We follow the C++0x // rules, even in C++03 mode, retroactively applying the DR. TemplateTy Template; - TemplateNameKind TNK = isTemplateName(0, Name, NameLoc, &SS, ObjectType, + TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType, false, Template); if (TNK == TNK_Non_template) { - Diag(NameLoc, diag::err_template_kw_refers_to_non_template) - << &Name; + Diag(Name.getSourceRange().getBegin(), + diag::err_template_kw_refers_to_non_template) + << GetNameFromUnqualifiedId(Name) + << Name.getSourceRange(); return TemplateTy(); } @@ -1393,12 +1399,32 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, NestedNameSpecifier *Qualifier = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); - return TemplateTy::make(Context.getDependentTemplateName(Qualifier, &Name)); + + switch (Name.getKind()) { + case UnqualifiedId::IK_Identifier: + return TemplateTy::make(Context.getDependentTemplateName(Qualifier, + Name.Identifier)); + + case UnqualifiedId::IK_OperatorFunctionId: + return TemplateTy::make(Context.getDependentTemplateName(Qualifier, + Name.OperatorFunctionId.Operator)); + + default: + break; + } + + Diag(Name.getSourceRange().getBegin(), + diag::err_template_kw_refers_to_non_template) + << GetNameFromUnqualifiedId(Name) + << Name.getSourceRange(); + return TemplateTy(); } bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, - const TemplateArgument &Arg, + const TemplateArgumentLoc &AL, TemplateArgumentListBuilder &Converted) { + const TemplateArgument &Arg = AL.getArgument(); + // Check template type parameter. if (Arg.getKind() != TemplateArgument::Type) { // C++ [temp.arg.type]p1: @@ -1407,19 +1433,19 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, // We have a template type parameter but the template argument // is not a type. - Diag(Arg.getLocation(), diag::err_template_arg_must_be_type); + SourceRange SR = AL.getSourceRange(); + Diag(SR.getBegin(), diag::err_template_arg_must_be_type) << SR; Diag(Param->getLocation(), diag::note_template_param_here); return true; } - if (CheckTemplateArgument(Param, Arg.getAsType(), Arg.getLocation())) + if (CheckTemplateArgument(Param, AL.getSourceDeclaratorInfo())) return true; // Add the converted template type argument. Converted.Append( - TemplateArgument(Arg.getLocation(), - Context.getCanonicalType(Arg.getAsType()))); + TemplateArgument(Context.getCanonicalType(Arg.getAsType()))); return false; } @@ -1428,7 +1454,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc, bool PartialTemplateArgs, @@ -1474,7 +1500,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, break; // Decode the template argument - TemplateArgument Arg; + TemplateArgumentLoc Arg; + if (ArgIdx >= NumArgs) { // Retrieve the default template argument from the template // parameter. @@ -1489,11 +1516,11 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, if (!TTP->hasDefaultArgument()) break; - QualType ArgType = TTP->getDefaultArgument(); + DeclaratorInfo *ArgType = TTP->getDefaultArgumentInfo(); // If the argument type is dependent, instantiate it now based // on the previously-computed template arguments. - if (ArgType->isDependentType()) { + if (ArgType->getType()->isDependentType()) { InstantiatingTemplate Inst(*this, TemplateLoc, Template, Converted.getFlatArguments(), Converted.flatSize(), @@ -1507,10 +1534,10 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, TTP->getDeclName()); } - if (ArgType.isNull()) + if (!ArgType) return true; - Arg = TemplateArgument(TTP->getLocation(), ArgType); + Arg = TemplateArgumentLoc(TemplateArgument(ArgType->getType()), ArgType); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { if (!NTTP->hasDefaultArgument()) @@ -1530,7 +1557,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, if (E.isInvalid()) return true; - Arg = TemplateArgument(E.takeAs<Expr>()); + Expr *Ex = E.takeAs<Expr>(); + Arg = TemplateArgumentLoc(TemplateArgument(Ex), Ex); } else { TemplateTemplateParmDecl *TempParm = cast<TemplateTemplateParmDecl>(*Param); @@ -1539,7 +1567,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, break; // FIXME: Subst default argument - Arg = TemplateArgument(TempParm->getDefaultArgument()); + Arg = TemplateArgumentLoc(TemplateArgument(TempParm->getDefaultArgument()), + TempParm->getDefaultArgument()); } } else { // Retrieve the template argument produced by the user. @@ -1592,13 +1621,13 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, } } - switch (Arg.getKind()) { + switch (Arg.getArgument().getKind()) { case TemplateArgument::Null: assert(false && "Should never see a NULL template argument here"); break; case TemplateArgument::Expression: { - Expr *E = Arg.getAsExpr(); + Expr *E = Arg.getArgument().getAsExpr(); TemplateArgument Result; if (CheckTemplateArgument(NTTP, NTTPType, E, Result)) Invalid = true; @@ -1611,10 +1640,10 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, case TemplateArgument::Integral: // We've already checked this template argument, so just copy // it to the list of converted arguments. - Converted.Append(Arg); + Converted.Append(Arg.getArgument()); break; - case TemplateArgument::Type: + case TemplateArgument::Type: { // We have a non-type template parameter but the template // argument is a type. @@ -1625,14 +1654,17 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // // We warn specifically about this case, since it can be rather // confusing for users. - if (Arg.getAsType()->isFunctionType()) - Diag(Arg.getLocation(), diag::err_template_arg_nontype_ambig) - << Arg.getAsType(); + QualType T = Arg.getArgument().getAsType(); + SourceRange SR = Arg.getSourceRange(); + if (T->isFunctionType()) + Diag(SR.getBegin(), diag::err_template_arg_nontype_ambig) + << SR << T; else - Diag(Arg.getLocation(), diag::err_template_arg_must_be_expr); + Diag(SR.getBegin(), diag::err_template_arg_must_be_expr) << SR; Diag((*Param)->getLocation(), diag::note_template_param_here); Invalid = true; break; + } case TemplateArgument::Pack: assert(0 && "FIXME: Implement!"); @@ -1643,13 +1675,13 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, TemplateTemplateParmDecl *TempParm = cast<TemplateTemplateParmDecl>(*Param); - switch (Arg.getKind()) { + switch (Arg.getArgument().getKind()) { case TemplateArgument::Null: assert(false && "Should never see a NULL template argument here"); break; case TemplateArgument::Expression: { - Expr *ArgExpr = Arg.getAsExpr(); + Expr *ArgExpr = Arg.getArgument().getAsExpr(); if (ArgExpr && isa<DeclRefExpr>(ArgExpr) && isa<TemplateDecl>(cast<DeclRefExpr>(ArgExpr)->getDecl())) { if (CheckTemplateArgument(TempParm, cast<DeclRefExpr>(ArgExpr))) @@ -1658,7 +1690,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // Add the converted template argument. Decl *D = cast<DeclRefExpr>(ArgExpr)->getDecl()->getCanonicalDecl(); - Converted.Append(TemplateArgument(Arg.getLocation(), D)); + Converted.Append(TemplateArgument(D)); continue; } } @@ -1675,7 +1707,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, case TemplateArgument::Declaration: // We've already checked this template argument, so just copy // it to the list of converted arguments. - Converted.Append(Arg); + Converted.Append(Arg.getArgument()); break; case TemplateArgument::Integral: @@ -1698,7 +1730,10 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, /// This routine implements the semantics of C++ [temp.arg.type]. It /// returns true if an error occurred, and false otherwise. bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, - QualType Arg, SourceLocation ArgLoc) { + DeclaratorInfo *ArgInfo) { + assert(ArgInfo && "invalid DeclaratorInfo"); + QualType Arg = ArgInfo->getType(); + // C++ [temp.arg.type]p2: // A local type, a type with no linkage, an unnamed type or a type // compounded from any of these types shall not be used as a @@ -1710,12 +1745,14 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, Tag = EnumT; else if (const RecordType *RecordT = Arg->getAs<RecordType>()) Tag = RecordT; - if (Tag && Tag->getDecl()->getDeclContext()->isFunctionOrMethod()) - return Diag(ArgLoc, diag::err_template_arg_local_type) - << QualType(Tag, 0); - else if (Tag && !Tag->getDecl()->getDeclName() && + if (Tag && Tag->getDecl()->getDeclContext()->isFunctionOrMethod()) { + SourceRange SR = ArgInfo->getTypeLoc().getFullSourceRange(); + return Diag(SR.getBegin(), diag::err_template_arg_local_type) + << QualType(Tag, 0) << SR; + } else if (Tag && !Tag->getDecl()->getDeclName() && !Tag->getDecl()->getTypedefForAnonDecl()) { - Diag(ArgLoc, diag::err_template_arg_unnamed_type); + SourceRange SR = ArgInfo->getTypeLoc().getFullSourceRange(); + Diag(SR.getBegin(), diag::err_template_arg_unnamed_type) << SR; Diag(Tag->getDecl()->getLocation(), diag::note_template_unnamed_type_here); return true; } @@ -1845,7 +1882,7 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { // template-parameter shall be one of: [...] // // -- a pointer to member expressed as described in 5.3.1. - QualifiedDeclRefExpr *DRE = 0; + DeclRefExpr *DRE = 0; // Ignore (and complain about) any excess parentheses. while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) { @@ -1860,8 +1897,11 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { } if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) - if (UnOp->getOpcode() == UnaryOperator::AddrOf) - DRE = dyn_cast<QualifiedDeclRefExpr>(UnOp->getSubExpr()); + if (UnOp->getOpcode() == UnaryOperator::AddrOf) { + DRE = dyn_cast<DeclRefExpr>(UnOp->getSubExpr()); + if (DRE && !DRE->getQualifier()) + DRE = 0; + } if (!DRE) return Diag(Arg->getSourceRange().getBegin(), @@ -2012,7 +2052,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return false; } - Converted = TemplateArgument(StartLoc, Value, + Converted = TemplateArgument(Value, ParamType->isEnumeralType() ? ParamType : IntegerType); return false; @@ -2086,7 +2126,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (Member) Member = cast<NamedDecl>(Member->getCanonicalDecl()); - Converted = TemplateArgument(StartLoc, Member); + Converted = TemplateArgument(Member); return false; } @@ -2096,7 +2136,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (Entity) Entity = cast<NamedDecl>(Entity->getCanonicalDecl()); - Converted = TemplateArgument(StartLoc, Entity); + Converted = TemplateArgument(Entity); return false; } @@ -2136,7 +2176,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (Entity) Entity = cast<NamedDecl>(Entity->getCanonicalDecl()); - Converted = TemplateArgument(StartLoc, Entity); + Converted = TemplateArgument(Entity); return false; } @@ -2177,7 +2217,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return true; Entity = cast<NamedDecl>(Entity->getCanonicalDecl()); - Converted = TemplateArgument(StartLoc, Entity); + Converted = TemplateArgument(Entity); return false; } @@ -2207,7 +2247,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (Member) Member = cast<NamedDecl>(Member->getCanonicalDecl()); - Converted = TemplateArgument(StartLoc, Member); + Converted = TemplateArgument(Member); return false; } @@ -2719,7 +2759,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, if (TTP->hasDefaultArgument()) { Diag(TTP->getDefaultArgumentLoc(), diag::err_default_arg_in_partial_spec); - TTP->setDefaultArgument(QualType(), SourceLocation(), false); + TTP->removeDefaultArgument(); } } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) { @@ -2778,7 +2818,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, } // Translate the parser's template argument list in our AST format. - llvm::SmallVector<TemplateArgument, 16> TemplateArgs; + llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs; translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); // Check that the template argument list is well-formed for this @@ -2877,8 +2917,6 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, Converted.flatSize()); // Create a new class template partial specialization declaration node. - TemplateParameterList *TemplateParams - = static_cast<TemplateParameterList*>(*TemplateParameterLists.get()); ClassTemplatePartialSpecializationDecl *PrevPartial = cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl); ClassTemplatePartialSpecializationDecl *Partial @@ -2888,6 +2926,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TemplateParams, ClassTemplate, Converted, + TemplateArgs.data(), + TemplateArgs.size(), PrevPartial); if (PrevPartial) { @@ -2898,6 +2938,11 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, } Specialization = Partial; + // If we are providing an explicit specialization of a member class + // template specialization, make a note of that. + if (PrevPartial && PrevPartial->getInstantiatedFromMember()) + PrevPartial->setMemberSpecialization(); + // Check that all of the template parameters of the class template // partial specialization are deducible from the template // arguments. If not, this class template partial specialization @@ -2905,6 +2950,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, llvm::SmallVector<bool, 8> DeducibleParams; DeducibleParams.resize(TemplateParams->size()); MarkUsedTemplateParameters(Partial->getTemplateArgs(), true, + TemplateParams->getDepth(), DeducibleParams); unsigned NumNonDeducible = 0; for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) @@ -3070,8 +3116,6 @@ Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, /// for those cases where they are required and determining whether the /// new specialization/instantiation will have any effect. /// -/// \param S the semantic analysis object. -/// /// \param NewLoc the location of the new explicit specialization or /// instantiation. /// @@ -3089,14 +3133,13 @@ Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, /// /// \returns true if there was an error that should prevent the introduction of /// the new declaration into the AST, false otherwise. -static bool -CheckSpecializationInstantiationRedecl(Sema &S, - SourceLocation NewLoc, - TemplateSpecializationKind NewTSK, - NamedDecl *PrevDecl, - TemplateSpecializationKind PrevTSK, - SourceLocation PrevPointOfInstantiation, - bool &SuppressNew) { +bool +Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, + TemplateSpecializationKind NewTSK, + NamedDecl *PrevDecl, + TemplateSpecializationKind PrevTSK, + SourceLocation PrevPointOfInstantiation, + bool &SuppressNew) { SuppressNew = false; switch (NewTSK) { @@ -3134,9 +3177,9 @@ CheckSpecializationInstantiationRedecl(Sema &S, // before the first use of that specialization that would cause an // implicit instantiation to take place, in every translation unit in // which such a use occurs; no diagnostic is required. - S.Diag(NewLoc, diag::err_specialization_after_instantiation) + Diag(NewLoc, diag::err_specialization_after_instantiation) << PrevDecl; - S.Diag(PrevPointOfInstantiation, diag::note_instantiation_required_here) + Diag(PrevPointOfInstantiation, diag::note_instantiation_required_here) << (PrevTSK != TSK_ImplicitInstantiation); return true; @@ -3169,10 +3212,10 @@ CheckSpecializationInstantiationRedecl(Sema &S, // If an entity is the subject of both an explicit instantiation // declaration and an explicit instantiation definition in the same // translation unit, the definition shall follow the declaration. - S.Diag(NewLoc, - diag::err_explicit_instantiation_declaration_after_definition); - S.Diag(PrevPointOfInstantiation, - diag::note_explicit_instantiation_definition_here); + Diag(NewLoc, + diag::err_explicit_instantiation_declaration_after_definition); + Diag(PrevPointOfInstantiation, + diag::note_explicit_instantiation_definition_here); assert(PrevPointOfInstantiation.isValid() && "Explicit instantiation without point of instantiation?"); SuppressNew = true; @@ -3198,10 +3241,10 @@ CheckSpecializationInstantiationRedecl(Sema &S, // In C++98/03 mode, we only give an extension warning here, because it // is not not harmful to try to explicitly instantiate something that // has been explicitly specialized. - if (!S.getLangOptions().CPlusPlus0x) { - S.Diag(NewLoc, diag::ext_explicit_instantiation_after_specialization) + if (!getLangOptions().CPlusPlus0x) { + Diag(NewLoc, diag::ext_explicit_instantiation_after_specialization) << PrevDecl; - S.Diag(PrevDecl->getLocation(), + Diag(PrevDecl->getLocation(), diag::note_previous_template_specialization); } SuppressNew = true; @@ -3217,10 +3260,10 @@ CheckSpecializationInstantiationRedecl(Sema &S, // For a given template and a given set of template-arguments, // - an explicit instantiation definition shall appear at most once // in a program, - S.Diag(NewLoc, diag::err_explicit_instantiation_duplicate) + Diag(NewLoc, diag::err_explicit_instantiation_duplicate) << PrevDecl; - S.Diag(PrevPointOfInstantiation, - diag::note_previous_explicit_instantiation); + Diag(PrevPointOfInstantiation, + diag::note_previous_explicit_instantiation); SuppressNew = true; return false; } @@ -3264,7 +3307,7 @@ bool Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, bool HasExplicitTemplateArgs, SourceLocation LAngleLoc, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, SourceLocation RAngleLoc, NamedDecl *&PrevDecl) { @@ -3333,7 +3376,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // C++ [temp.expl.spec]p6: // If a template, a member template or the member of a class template is - // explicitly specialized then that spe- cialization shall be declared + // explicitly specialized then that specialization shall be declared // before the first use of that specialization that would cause an implicit // instantiation to take place, in every translation unit in which such a // use occurs; no diagnostic is required. @@ -3620,7 +3663,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, : TSK_ExplicitInstantiationDeclaration; // Translate the parser's template argument list in our AST format. - llvm::SmallVector<TemplateArgument, 16> TemplateArgs; + llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs; translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); // Check that the template argument list is well-formed for this @@ -3659,7 +3702,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, if (PrevDecl) { bool SuppressNew = false; - if (CheckSpecializationInstantiationRedecl(*this, TemplateNameLoc, TSK, + if (CheckSpecializationInstantiationRedecl(TemplateNameLoc, TSK, PrevDecl, PrevDecl->getSpecializationKind(), PrevDecl->getPointOfInstantiation(), @@ -3723,8 +3766,6 @@ Sema::ActOnExplicitInstantiation(Scope *S, Specialization->setLexicalDeclContext(CurContext); CurContext->addDecl(Specialization); - Specialization->setPointOfInstantiation(TemplateNameLoc); - // C++ [temp.explicit]p3: // A definition of a class template or class member template // shall be in scope at the point of the explicit instantiation of @@ -3736,8 +3777,12 @@ Sema::ActOnExplicitInstantiation(Scope *S, = cast_or_null<ClassTemplateSpecializationDecl>( Specialization->getDefinition(Context)); if (!Def) - InstantiateClassTemplateSpecialization(Specialization, TSK); - else // Instantiate the members of this class template specialization. + InstantiateClassTemplateSpecialization(TemplateNameLoc, Specialization, TSK); + + // Instantiate the members of this class template specialization. + Def = cast_or_null<ClassTemplateSpecializationDecl>( + Specialization->getDefinition(Context)); + if (Def) InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK); return DeclPtrTy::make(Specialization); @@ -3819,7 +3864,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, MemberSpecializationInfo *MSInfo = PrevDecl->getMemberSpecializationInfo(); bool SuppressNew = false; assert(MSInfo && "No member specialization information?"); - if (CheckSpecializationInstantiationRedecl(*this, TemplateLoc, TSK, + if (CheckSpecializationInstantiationRedecl(TemplateLoc, TSK, PrevDecl, MSInfo->getTemplateSpecializationKind(), MSInfo->getPointOfInstantiation(), @@ -3843,13 +3888,21 @@ Sema::ActOnExplicitInstantiation(Scope *S, Diag(Pattern->getLocation(), diag::note_forward_declaration) << Pattern; return true; - } else if (InstantiateClass(NameLoc, Record, Def, - getTemplateInstantiationArgs(Record), - TSK)) - return true; - } else // Instantiate all of the members of the class. - InstantiateClassMembers(NameLoc, RecordDef, - getTemplateInstantiationArgs(Record), TSK); + } else { + if (InstantiateClass(NameLoc, Record, Def, + getTemplateInstantiationArgs(Record), + TSK)) + return true; + + RecordDef = cast_or_null<CXXRecordDecl>(Record->getDefinition(Context)); + if (!RecordDef) + return true; + } + } + + // Instantiate all of the members of the class. + InstantiateClassMembers(NameLoc, RecordDef, + getTemplateInstantiationArgs(Record), TSK); // FIXME: We don't have any representation for explicit instantiations of // member classes. Such a representation is not needed for compilation, but it @@ -3968,8 +4021,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, MemberSpecializationInfo *MSInfo = Prev->getMemberSpecializationInfo(); assert(MSInfo && "Missing static data member specialization info?"); bool SuppressNew = false; - if (CheckSpecializationInstantiationRedecl(*this, D.getIdentifierLoc(), TSK, - Prev, + if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK, Prev, MSInfo->getTemplateSpecializationKind(), MSInfo->getPointOfInstantiation(), SuppressNew)) @@ -3990,9 +4042,9 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // If the declarator is a template-id, translate the parser's template // argument list into our AST format. bool HasExplicitTemplateArgs = false; - llvm::SmallVector<TemplateArgument, 16> TemplateArgs; - if (D.getKind() == Declarator::DK_TemplateId) { - TemplateIdAnnotation *TemplateId = D.getTemplateId(); + llvm::SmallVector<TemplateArgumentLoc, 16> TemplateArgs; + if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { + TemplateIdAnnotation *TemplateId = D.getName().TemplateId; ASTTemplateArgsPtr TemplateArgsPtr(*this, TemplateId->getTemplateArgs(), TemplateId->getTemplateArgIsType(), @@ -4068,7 +4120,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (PrevDecl) { bool SuppressNew = false; - if (CheckSpecializationInstantiationRedecl(*this, D.getIdentifierLoc(), TSK, + if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK, PrevDecl, PrevDecl->getTemplateSpecializationKind(), PrevDecl->getPointOfInstantiation(), @@ -4095,7 +4147,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // // C++98 has the same restriction, just worded differently. FunctionTemplateDecl *FunTmpl = Specialization->getPrimaryTemplate(); - if (D.getKind() != Declarator::DK_TemplateId && !FunTmpl && + if (D.getName().getKind() != UnqualifiedId::IK_TemplateId && !FunTmpl && D.getCXXScopeSpec().isSet() && !ScopeSpecifierHasTemplateId(D.getCXXScopeSpec())) Diag(D.getIdentifierLoc(), @@ -4277,6 +4329,13 @@ namespace { /// \brief Returns the name of the entity whose type is being rebuilt. DeclarationName getBaseEntity() { return Entity; } + /// \brief Sets the "base" location and entity when that + /// information is known based on another transformation. + void setBase(SourceLocation Loc, DeclarationName Entity) { + this->Loc = Loc; + this->Entity = Entity; + } + /// \brief Transforms an expression by returning the expression itself /// (an identity function). /// @@ -4290,25 +4349,13 @@ namespace { /// refers to a member of the current instantiation, and then /// type-checking and building a QualifiedNameType (when possible). QualType TransformTypenameType(TypeLocBuilder &TLB, TypenameTypeLoc TL); - QualType TransformTypenameType(TypenameType *T); }; } QualType CurrentInstantiationRebuilder::TransformTypenameType(TypeLocBuilder &TLB, TypenameTypeLoc TL) { - QualType Result = TransformTypenameType(TL.getTypePtr()); - if (Result.isNull()) - return QualType(); - - TypenameTypeLoc NewTL = TLB.push<TypenameTypeLoc>(Result); - NewTL.setNameLoc(TL.getNameLoc()); - - return Result; -} - -QualType -CurrentInstantiationRebuilder::TransformTypenameType(TypenameType *T) { + TypenameType *T = TL.getTypePtr(); NestedNameSpecifier *NNS = TransformNestedNameSpecifier(T->getQualifier(), @@ -4322,12 +4369,14 @@ CurrentInstantiationRebuilder::TransformTypenameType(TypenameType *T) { CXXScopeSpec SS; SS.setRange(SourceRange(getBaseLocation())); SS.setScopeRep(NNS); + + QualType Result; if (NNS == T->getQualifier() && getSema().computeDeclContext(SS) == 0) - return QualType(T, 0); + Result = QualType(T, 0); // Rebuild the typename type, which will probably turn into a // QualifiedNameType. - if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) { + else if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) { QualType NewTemplateId = TransformType(QualType(TemplateId, 0)); if (NewTemplateId.isNull()) @@ -4335,12 +4384,16 @@ CurrentInstantiationRebuilder::TransformTypenameType(TypenameType *T) { if (NNS == T->getQualifier() && NewTemplateId == QualType(TemplateId, 0)) - return QualType(T, 0); - - return getDerived().RebuildTypenameType(NNS, NewTemplateId); - } + Result = QualType(T, 0); + else + Result = getDerived().RebuildTypenameType(NNS, NewTemplateId); + } else + Result = getDerived().RebuildTypenameType(NNS, T->getIdentifier(), + SourceRange(TL.getNameLoc())); - return getDerived().RebuildTypenameType(NNS, T->getIdentifier()); + TypenameTypeLoc NewTL = TLB.push<TypenameTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; } /// \brief Rebuilds a type within the context of the current instantiation. diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 2a44f83..7b5ad7f 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -90,7 +90,7 @@ DeduceNonTypeTemplateArgument(ASTContext &Context, Value.extOrTrunc(AllowedBits); Value.setIsSigned(T->isSignedIntegerType()); - Deduced[NTTP->getIndex()] = TemplateArgument(SourceLocation(), Value, T); + Deduced[NTTP->getIndex()] = TemplateArgument(Value, T); return Sema::TDK_Success; } @@ -102,7 +102,7 @@ DeduceNonTypeTemplateArgument(ASTContext &Context, if (PrevValuePtr->isNegative()) { Info.Param = NTTP; Info.FirstArg = Deduced[NTTP->getIndex()]; - Info.SecondArg = TemplateArgument(SourceLocation(), Value, NTTP->getType()); + Info.SecondArg = TemplateArgument(Value, NTTP->getType()); return Sema::TDK_Inconsistent; } @@ -115,7 +115,7 @@ DeduceNonTypeTemplateArgument(ASTContext &Context, if (Value != PrevValue) { Info.Param = NTTP; Info.FirstArg = Deduced[NTTP->getIndex()]; - Info.SecondArg = TemplateArgument(SourceLocation(), Value, NTTP->getType()); + Info.SecondArg = TemplateArgument(Value, NTTP->getType()); return Sema::TDK_Inconsistent; } @@ -433,7 +433,7 @@ DeduceTemplateArguments(ASTContext &Context, if (Param.isMoreQualifiedThan(Arg) && !(TDF & TDF_IgnoreQualifiers)) { Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index)); Info.FirstArg = Deduced[Index]; - Info.SecondArg = TemplateArgument(SourceLocation(), Arg); + Info.SecondArg = TemplateArgument(Arg); return Sema::TDK_InconsistentQuals; } @@ -445,7 +445,7 @@ DeduceTemplateArguments(ASTContext &Context, DeducedType = Context.getCanonicalType(DeducedType); if (Deduced[Index].isNull()) - Deduced[Index] = TemplateArgument(SourceLocation(), DeducedType); + Deduced[Index] = TemplateArgument(DeducedType); else { // C++ [temp.deduct.type]p2: // [...] If type deduction cannot be done for any P/A pair, or if for @@ -457,7 +457,7 @@ DeduceTemplateArguments(ASTContext &Context, Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index)); Info.FirstArg = Deduced[Index]; - Info.SecondArg = TemplateArgument(SourceLocation(), Arg); + Info.SecondArg = TemplateArgument(Arg); return Sema::TDK_Inconsistent; } } @@ -465,8 +465,8 @@ DeduceTemplateArguments(ASTContext &Context, } // Set up the template argument deduction information for a failure. - Info.FirstArg = TemplateArgument(SourceLocation(), ParamIn); - Info.SecondArg = TemplateArgument(SourceLocation(), ArgIn); + Info.FirstArg = TemplateArgument(ParamIn); + Info.SecondArg = TemplateArgument(ArgIn); // Check the cv-qualifiers on the parameter and argument types. if (!(TDF & TDF_IgnoreQualifiers)) { @@ -695,7 +695,7 @@ DeduceTemplateArguments(ASTContext &Context, CXXRecordDecl *Next = cast<CXXRecordDecl>(NextT->getDecl()); for (CXXRecordDecl::base_class_iterator Base = Next->bases_begin(), BaseEnd = Next->bases_end(); - Base != BaseEnd; ++Base) { + Base != BaseEnd; ++Base) { assert(Base->getType()->isRecordType() && "Base class that isn't a record?"); ToVisit.push_back(Base->getType()->getAs<RecordType>()); @@ -982,18 +982,41 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, // and are equivalent to the template arguments originally provided // to the class template. ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate(); - const TemplateArgumentList &PartialTemplateArgs = Partial->getTemplateArgs(); - for (unsigned I = 0, N = PartialTemplateArgs.flat_size(); I != N; ++I) { + const TemplateArgumentLoc *PartialTemplateArgs + = Partial->getTemplateArgsAsWritten(); + unsigned N = Partial->getNumTemplateArgsAsWritten(); + llvm::SmallVector<TemplateArgumentLoc, 16> InstArgs(N); + for (unsigned I = 0; I != N; ++I) { Decl *Param = const_cast<NamedDecl *>( ClassTemplate->getTemplateParameters()->getParam(I)); - TemplateArgument InstArg - = Subst(PartialTemplateArgs[I], - MultiLevelTemplateArgumentList(*DeducedArgumentList)); - if (InstArg.isNull()) { + if (Subst(PartialTemplateArgs[I], InstArgs[I], + MultiLevelTemplateArgumentList(*DeducedArgumentList))) { Info.Param = makeTemplateParameter(Param); - Info.FirstArg = PartialTemplateArgs[I]; + Info.FirstArg = PartialTemplateArgs[I].getArgument(); return TDK_SubstitutionFailure; } + } + + TemplateArgumentListBuilder ConvertedInstArgs( + ClassTemplate->getTemplateParameters(), N); + + if (CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(), + /*LAngle*/ SourceLocation(), + InstArgs.data(), N, + /*RAngle*/ SourceLocation(), + false, ConvertedInstArgs)) { + // FIXME: fail with more useful information? + return TDK_SubstitutionFailure; + } + + for (unsigned I = 0, E = ConvertedInstArgs.flatSize(); I != E; ++I) { + // We don't really care if we overwrite the internal structures of + // the arg list builder, because we're going to throw it all away. + TemplateArgument &InstArg + = const_cast<TemplateArgument&>(ConvertedInstArgs.getFlatArguments()[I]); + + Decl *Param = const_cast<NamedDecl *>( + ClassTemplate->getTemplateParameters()->getParam(I)); if (InstArg.getKind() == TemplateArgument::Expression) { // When the argument is an expression, check the expression result @@ -1004,7 +1027,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, = dyn_cast<NonTypeTemplateParmDecl>(Param)) { if (CheckTemplateArgument(NTTP, NTTP->getType(), InstExpr, InstArg)) { Info.Param = makeTemplateParameter(Param); - Info.FirstArg = PartialTemplateArgs[I]; + Info.FirstArg = Partial->getTemplateArgs()[I]; return TDK_SubstitutionFailure; } } else if (TemplateTemplateParmDecl *TTP @@ -1013,7 +1036,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InstExpr); if (!DRE || CheckTemplateArgument(TTP, DRE)) { Info.Param = makeTemplateParameter(Param); - Info.FirstArg = PartialTemplateArgs[I]; + Info.FirstArg = Partial->getTemplateArgs()[I]; return TDK_SubstitutionFailure; } } @@ -1072,7 +1095,7 @@ static bool isSimpleTemplateIdType(QualType T) { Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( FunctionTemplateDecl *FunctionTemplate, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, llvm::SmallVectorImpl<TemplateArgument> &Deduced, llvm::SmallVectorImpl<QualType> &ParamTypes, @@ -1290,7 +1313,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, Expr **Args, unsigned NumArgs, FunctionDecl *&Specialization, @@ -1460,7 +1483,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, bool HasExplicitTemplateArgs, - const TemplateArgument *ExplicitTemplateArgs, + const TemplateArgumentLoc *ExplicitTemplateArgs, unsigned NumExplicitTemplateArgs, QualType ArgFunctionType, FunctionDecl *&Specialization, @@ -1643,15 +1666,15 @@ DeduceTemplateArgumentsDuringPartialOrdering(ASTContext &Context, // performed on the types used for partial ordering: // - If P is a reference type, P is replaced by the type referred to. CanQual<ReferenceType> ParamRef = Param->getAs<ReferenceType>(); - if (ParamRef) + if (!ParamRef.isNull()) Param = ParamRef->getPointeeType(); // - If A is a reference type, A is replaced by the type referred to. CanQual<ReferenceType> ArgRef = Arg->getAs<ReferenceType>(); - if (ArgRef) + if (!ArgRef.isNull()) Arg = ArgRef->getPointeeType(); - if (QualifierComparisons && ParamRef && ArgRef) { + if (QualifierComparisons && !ParamRef.isNull() && !ArgRef.isNull()) { // C++0x [temp.deduct.partial]p6: // If both P and A were reference types (before being replaced with the // type referred to above), determine which of the two types (if any) is @@ -1690,6 +1713,7 @@ DeduceTemplateArgumentsDuringPartialOrdering(ASTContext &Context, static void MarkUsedTemplateParameters(Sema &SemaRef, QualType T, bool OnlyDeduced, + unsigned Level, llvm::SmallVectorImpl<bool> &Deduced); /// \brief Determine whether the function template \p FT1 is at least as @@ -1782,18 +1806,22 @@ static bool isAtLeastAsSpecializedAs(Sema &S, case TPOC_Call: { unsigned NumParams = std::min(Proto1->getNumArgs(), Proto2->getNumArgs()); for (unsigned I = 0; I != NumParams; ++I) - ::MarkUsedTemplateParameters(S, Proto2->getArgType(I), false, + ::MarkUsedTemplateParameters(S, Proto2->getArgType(I), false, + TemplateParams->getDepth(), UsedParameters); break; } case TPOC_Conversion: - ::MarkUsedTemplateParameters(S, Proto2->getResultType(), false, + ::MarkUsedTemplateParameters(S, Proto2->getResultType(), false, + TemplateParams->getDepth(), UsedParameters); break; case TPOC_Other: - ::MarkUsedTemplateParameters(S, FD2->getType(), false, UsedParameters); + ::MarkUsedTemplateParameters(S, FD2->getType(), false, + TemplateParams->getDepth(), + UsedParameters); break; } @@ -2065,6 +2093,7 @@ static void MarkUsedTemplateParameters(Sema &SemaRef, const TemplateArgument &TemplateArg, bool OnlyDeduced, + unsigned Depth, llvm::SmallVectorImpl<bool> &Used); /// \brief Mark the template parameters that are used by the given @@ -2073,6 +2102,7 @@ static void MarkUsedTemplateParameters(Sema &SemaRef, const Expr *E, bool OnlyDeduced, + unsigned Depth, llvm::SmallVectorImpl<bool> &Used) { // FIXME: if !OnlyDeduced, we have to walk the whole subexpression to // find other occurrences of template parameters. @@ -2085,7 +2115,8 @@ MarkUsedTemplateParameters(Sema &SemaRef, if (!NTTP) return; - Used[NTTP->getIndex()] = true; + if (NTTP->getDepth() == Depth) + Used[NTTP->getIndex()] = true; } /// \brief Mark the template parameters that are used by the given @@ -2094,13 +2125,15 @@ static void MarkUsedTemplateParameters(Sema &SemaRef, NestedNameSpecifier *NNS, bool OnlyDeduced, + unsigned Depth, llvm::SmallVectorImpl<bool> &Used) { if (!NNS) return; - MarkUsedTemplateParameters(SemaRef, NNS->getPrefix(), OnlyDeduced, Used); + MarkUsedTemplateParameters(SemaRef, NNS->getPrefix(), OnlyDeduced, Depth, + Used); MarkUsedTemplateParameters(SemaRef, QualType(NNS->getAsType(), 0), - OnlyDeduced, Used); + OnlyDeduced, Depth, Used); } /// \brief Mark the template parameters that are used by the given @@ -2109,16 +2142,20 @@ static void MarkUsedTemplateParameters(Sema &SemaRef, TemplateName Name, bool OnlyDeduced, + unsigned Depth, llvm::SmallVectorImpl<bool> &Used) { if (TemplateDecl *Template = Name.getAsTemplateDecl()) { if (TemplateTemplateParmDecl *TTP - = dyn_cast<TemplateTemplateParmDecl>(Template)) - Used[TTP->getIndex()] = true; + = dyn_cast<TemplateTemplateParmDecl>(Template)) { + if (TTP->getDepth() == Depth) + Used[TTP->getIndex()] = true; + } return; } if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) - MarkUsedTemplateParameters(SemaRef, DTN->getQualifier(), OnlyDeduced, Used); + MarkUsedTemplateParameters(SemaRef, DTN->getQualifier(), OnlyDeduced, + Depth, Used); } /// \brief Mark the template parameters that are used by the given @@ -2126,6 +2163,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, static void MarkUsedTemplateParameters(Sema &SemaRef, QualType T, bool OnlyDeduced, + unsigned Depth, llvm::SmallVectorImpl<bool> &Used) { if (T.isNull()) return; @@ -2140,6 +2178,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, MarkUsedTemplateParameters(SemaRef, cast<PointerType>(T)->getPointeeType(), OnlyDeduced, + Depth, Used); break; @@ -2147,6 +2186,7 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, MarkUsedTemplateParameters(SemaRef, cast<BlockPointerType>(T)->getPointeeType(), OnlyDeduced, + Depth, Used); break; @@ -2155,69 +2195,74 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, MarkUsedTemplateParameters(SemaRef, cast<ReferenceType>(T)->getPointeeType(), OnlyDeduced, + Depth, Used); break; case Type::MemberPointer: { const MemberPointerType *MemPtr = cast<MemberPointerType>(T.getTypePtr()); MarkUsedTemplateParameters(SemaRef, MemPtr->getPointeeType(), OnlyDeduced, - Used); + Depth, Used); MarkUsedTemplateParameters(SemaRef, QualType(MemPtr->getClass(), 0), - OnlyDeduced, Used); + OnlyDeduced, Depth, Used); break; } case Type::DependentSizedArray: MarkUsedTemplateParameters(SemaRef, cast<DependentSizedArrayType>(T)->getSizeExpr(), - OnlyDeduced, Used); + OnlyDeduced, Depth, Used); // Fall through to check the element type case Type::ConstantArray: case Type::IncompleteArray: MarkUsedTemplateParameters(SemaRef, cast<ArrayType>(T)->getElementType(), - OnlyDeduced, Used); + OnlyDeduced, Depth, Used); break; case Type::Vector: case Type::ExtVector: MarkUsedTemplateParameters(SemaRef, cast<VectorType>(T)->getElementType(), - OnlyDeduced, Used); + OnlyDeduced, Depth, Used); break; case Type::DependentSizedExtVector: { const DependentSizedExtVectorType *VecType = cast<DependentSizedExtVectorType>(T); MarkUsedTemplateParameters(SemaRef, VecType->getElementType(), OnlyDeduced, - Used); + Depth, Used); MarkUsedTemplateParameters(SemaRef, VecType->getSizeExpr(), OnlyDeduced, - Used); + Depth, Used); break; } case Type::FunctionProto: { const FunctionProtoType *Proto = cast<FunctionProtoType>(T); MarkUsedTemplateParameters(SemaRef, Proto->getResultType(), OnlyDeduced, - Used); + Depth, Used); for (unsigned I = 0, N = Proto->getNumArgs(); I != N; ++I) MarkUsedTemplateParameters(SemaRef, Proto->getArgType(I), OnlyDeduced, - Used); + Depth, Used); break; } - case Type::TemplateTypeParm: - Used[cast<TemplateTypeParmType>(T)->getIndex()] = true; + case Type::TemplateTypeParm: { + const TemplateTypeParmType *TTP = cast<TemplateTypeParmType>(T); + if (TTP->getDepth() == Depth) + Used[TTP->getIndex()] = true; break; + } case Type::TemplateSpecialization: { const TemplateSpecializationType *Spec = cast<TemplateSpecializationType>(T); MarkUsedTemplateParameters(SemaRef, Spec->getTemplateName(), OnlyDeduced, - Used); + Depth, Used); for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) - MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Used); + MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Depth, + Used); break; } @@ -2225,14 +2270,14 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, if (!OnlyDeduced) MarkUsedTemplateParameters(SemaRef, cast<ComplexType>(T)->getElementType(), - OnlyDeduced, Used); + OnlyDeduced, Depth, Used); break; case Type::Typename: if (!OnlyDeduced) MarkUsedTemplateParameters(SemaRef, cast<TypenameType>(T)->getQualifier(), - OnlyDeduced, Used); + OnlyDeduced, Depth, Used); break; // None of these types have any template parameters in them. @@ -2259,6 +2304,7 @@ static void MarkUsedTemplateParameters(Sema &SemaRef, const TemplateArgument &TemplateArg, bool OnlyDeduced, + unsigned Depth, llvm::SmallVectorImpl<bool> &Used) { switch (TemplateArg.getKind()) { case TemplateArgument::Null: @@ -2267,25 +2313,27 @@ MarkUsedTemplateParameters(Sema &SemaRef, case TemplateArgument::Type: MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsType(), OnlyDeduced, - Used); + Depth, Used); break; case TemplateArgument::Declaration: if (TemplateTemplateParmDecl *TTP - = dyn_cast<TemplateTemplateParmDecl>(TemplateArg.getAsDecl())) - Used[TTP->getIndex()] = true; + = dyn_cast<TemplateTemplateParmDecl>(TemplateArg.getAsDecl())) { + if (TTP->getDepth() == Depth) + Used[TTP->getIndex()] = true; + } break; case TemplateArgument::Expression: MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsExpr(), OnlyDeduced, - Used); + Depth, Used); break; case TemplateArgument::Pack: for (TemplateArgument::pack_iterator P = TemplateArg.pack_begin(), PEnd = TemplateArg.pack_end(); P != PEnd; ++P) - MarkUsedTemplateParameters(SemaRef, *P, OnlyDeduced, Used); + MarkUsedTemplateParameters(SemaRef, *P, OnlyDeduced, Depth, Used); break; } } @@ -2301,10 +2349,11 @@ MarkUsedTemplateParameters(Sema &SemaRef, /// deduced. void Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, - bool OnlyDeduced, + bool OnlyDeduced, unsigned Depth, llvm::SmallVectorImpl<bool> &Used) { for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) - ::MarkUsedTemplateParameters(*this, TemplateArgs[I], OnlyDeduced, Used); + ::MarkUsedTemplateParameters(*this, TemplateArgs[I], OnlyDeduced, + Depth, Used); } /// \brief Marks all of the template parameters that will be deduced by a @@ -2319,5 +2368,5 @@ void Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, FunctionDecl *Function = FunctionTemplate->getTemplatedDecl(); for (unsigned I = 0, N = Function->getNumParams(); I != N; ++I) ::MarkUsedTemplateParameters(*this, Function->getParamDecl(I)->getType(), - true, Deduced); + true, TemplateParams->getDepth(), Deduced); } diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 53d1580..dfe37d8 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -392,6 +392,13 @@ namespace { /// \brief Returns the name of the entity being instantiated, if any. DeclarationName getBaseEntity() { return Entity; } + /// \brief Sets the "base" location and entity when that + /// information is known based on another transformation. + void setBase(SourceLocation Loc, DeclarationName Entity) { + this->Loc = Loc; + this->Entity = Entity; + } + /// \brief Transform the given declaration by instantiating a reference to /// this declaration. Decl *TransformDecl(Decl *D); @@ -415,8 +422,10 @@ namespace { /// elaborated type. QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag); - Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E); - Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E); + Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E, + bool isAddressOfOperand); + Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E, + bool isAddressOfOperand); /// \brief Transforms a template type parameter type by performing /// substitution of the corresponding template type argument. @@ -528,7 +537,8 @@ TemplateInstantiator::RebuildElaboratedType(QualType T, } Sema::OwningExprResult -TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) { +TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E, + bool isAddressOfOperand) { if (!E->isTypeDependent()) return SemaRef.Owned(E->Retain()); @@ -551,62 +561,64 @@ TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) { } Sema::OwningExprResult -TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) { +TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E, + bool isAddressOfOperand) { // FIXME: Clean this up a bit NamedDecl *D = E->getDecl(); if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) { - if (NTTP->getDepth() >= TemplateArgs.getNumLevels()) { - assert(false && "Cannot reduce non-type template parameter depth yet"); - return getSema().ExprError(); - } - - // If the corresponding template argument is NULL or non-existent, it's - // because we are performing instantiation from explicitly-specified - // template arguments in a function template, but there were some - // arguments left unspecified. - if (!TemplateArgs.hasTemplateArgument(NTTP->getDepth(), - NTTP->getPosition())) - return SemaRef.Owned(E->Retain()); - - const TemplateArgument &Arg = TemplateArgs(NTTP->getDepth(), - NTTP->getPosition()); - - // The template argument itself might be an expression, in which - // case we just return that expression. - if (Arg.getKind() == TemplateArgument::Expression) - return SemaRef.Owned(Arg.getAsExpr()->Retain()); - - if (Arg.getKind() == TemplateArgument::Declaration) { - ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl()); - - VD = cast_or_null<ValueDecl>( + if (NTTP->getDepth() < TemplateArgs.getNumLevels()) { + + // If the corresponding template argument is NULL or non-existent, it's + // because we are performing instantiation from explicitly-specified + // template arguments in a function template, but there were some + // arguments left unspecified. + if (!TemplateArgs.hasTemplateArgument(NTTP->getDepth(), + NTTP->getPosition())) + return SemaRef.Owned(E->Retain()); + + const TemplateArgument &Arg = TemplateArgs(NTTP->getDepth(), + NTTP->getPosition()); + + // The template argument itself might be an expression, in which + // case we just return that expression. + if (Arg.getKind() == TemplateArgument::Expression) + return SemaRef.Owned(Arg.getAsExpr()->Retain()); + + if (Arg.getKind() == TemplateArgument::Declaration) { + ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl()); + + VD = cast_or_null<ValueDecl>( getSema().FindInstantiatedDecl(VD, TemplateArgs)); - if (!VD) - return SemaRef.ExprError(); + if (!VD) + return SemaRef.ExprError(); - return SemaRef.BuildDeclRefExpr(VD, VD->getType(), E->getLocation(), - /*FIXME:*/false, /*FIXME:*/false); - } + return SemaRef.BuildDeclRefExpr(VD, VD->getType(), E->getLocation(), + /*FIXME:*/false, /*FIXME:*/false); + } - assert(Arg.getKind() == TemplateArgument::Integral); - QualType T = Arg.getIntegralType(); - if (T->isCharType() || T->isWideCharType()) - return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral( - Arg.getAsIntegral()->getZExtValue(), - T->isWideCharType(), - T, - E->getSourceRange().getBegin())); - if (T->isBooleanType()) - return SemaRef.Owned(new (SemaRef.Context) CXXBoolLiteralExpr( - Arg.getAsIntegral()->getBoolValue(), - T, - E->getSourceRange().getBegin())); - - assert(Arg.getAsIntegral()->getBitWidth() == SemaRef.Context.getIntWidth(T)); - return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral( - *Arg.getAsIntegral(), + assert(Arg.getKind() == TemplateArgument::Integral); + QualType T = Arg.getIntegralType(); + if (T->isCharType() || T->isWideCharType()) + return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral( + Arg.getAsIntegral()->getZExtValue(), + T->isWideCharType(), T, E->getSourceRange().getBegin())); + if (T->isBooleanType()) + return SemaRef.Owned(new (SemaRef.Context) CXXBoolLiteralExpr( + Arg.getAsIntegral()->getBoolValue(), + T, + E->getSourceRange().getBegin())); + + assert(Arg.getAsIntegral()->getBitWidth() == SemaRef.Context.getIntWidth(T)); + return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral( + *Arg.getAsIntegral(), + T, + E->getSourceRange().getBegin())); + } + + // We have a non-type template parameter that isn't fully substituted; + // FindInstantiatedDecl will find it in the local instantiation scope. } NamedDecl *InstD = SemaRef.FindInstantiatedDecl(D, TemplateArgs); @@ -618,11 +630,22 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) { // FIXME: Is this correct? Maybe FindInstantiatedDecl should do this? InstD = InstD->getUnderlyingDecl(); - // FIXME: nested-name-specifier for QualifiedDeclRefExpr + CXXScopeSpec SS; + NestedNameSpecifier *Qualifier = 0; + if (E->getQualifier()) { + Qualifier = TransformNestedNameSpecifier(E->getQualifier(), + E->getQualifierRange()); + if (!Qualifier) + return SemaRef.ExprError(); + + SS.setScopeRep(Qualifier); + SS.setRange(E->getQualifierRange()); + } + return SemaRef.BuildDeclarationNameExpr(E->getLocation(), InstD, /*FIXME:*/false, - /*FIXME:*/0, - /*FIXME:*/false); + &SS, + isAddressOfOperand); } QualType @@ -838,6 +861,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, = Instantiation->getMemberSpecializationInfo()) { MSInfo->setTemplateSpecializationKind(TSK); MSInfo->setPointOfInstantiation(PointOfInstantiation); + } else if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(Instantiation)) { + Spec->setTemplateSpecializationKind(TSK); + Spec->setPointOfInstantiation(PointOfInstantiation); } InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); @@ -892,18 +919,12 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, if (!Invalid) Consumer.HandleTagDeclDefinition(Instantiation); - // If this is an explicit instantiation, instantiate our members, too. - if (!Invalid && TSK != TSK_ImplicitInstantiation) { - Inst.Clear(); - InstantiateClassMembers(PointOfInstantiation, Instantiation, TemplateArgs, - TSK); - } - return Invalid; } bool Sema::InstantiateClassTemplateSpecialization( + SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, TemplateSpecializationKind TSK, bool Complain) { @@ -921,10 +942,6 @@ Sema::InstantiateClassTemplateSpecialization( // declaration (C++0x [temp.explicit]p10); go ahead and perform the // explicit instantiation. ClassTemplateSpec->setSpecializationKind(TSK); - InstantiateClassTemplateSpecializationMembers( - /*FIXME?*/ClassTemplateSpec->getPointOfInstantiation(), - ClassTemplateSpec, - TSK); return false; } @@ -969,62 +986,72 @@ Sema::InstantiateClassTemplateSpecialization( } } - if (Matched.size() == 1) { - // -- If exactly one matching specialization is found, the - // instantiation is generated from that specialization. - Pattern = Matched[0].first; - ClassTemplateSpec->setInstantiationOf(Matched[0].first, Matched[0].second); - } else if (Matched.size() > 1) { - // -- If more than one matching specialization is found, the - // partial order rules (14.5.4.2) are used to determine - // whether one of the specializations is more specialized - // than the others. If none of the specializations is more - // specialized than all of the other matching - // specializations, then the use of the class template is - // ambiguous and the program is ill-formed. + if (Matched.size() >= 1) { llvm::SmallVector<MatchResult, 4>::iterator Best = Matched.begin(); - for (llvm::SmallVector<MatchResult, 4>::iterator P = Best + 1, - PEnd = Matched.end(); - P != PEnd; ++P) { - if (getMoreSpecializedPartialSpecialization(P->first, Best->first) - == P->first) - Best = P; - } - - // Determine if the best partial specialization is more specialized than - // the others. - bool Ambiguous = false; - for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(), - PEnd = Matched.end(); - P != PEnd; ++P) { - if (P != Best && - getMoreSpecializedPartialSpecialization(P->first, Best->first) - != Best->first) { - Ambiguous = true; - break; + if (Matched.size() == 1) { + // -- If exactly one matching specialization is found, the + // instantiation is generated from that specialization. + // We don't need to do anything for this. + } else { + // -- If more than one matching specialization is found, the + // partial order rules (14.5.4.2) are used to determine + // whether one of the specializations is more specialized + // than the others. If none of the specializations is more + // specialized than all of the other matching + // specializations, then the use of the class template is + // ambiguous and the program is ill-formed. + for (llvm::SmallVector<MatchResult, 4>::iterator P = Best + 1, + PEnd = Matched.end(); + P != PEnd; ++P) { + if (getMoreSpecializedPartialSpecialization(P->first, Best->first) + == P->first) + Best = P; } - } - - if (Ambiguous) { - // Partial ordering did not produce a clear winner. Complain. - ClassTemplateSpec->setInvalidDecl(); - Diag(ClassTemplateSpec->getPointOfInstantiation(), - diag::err_partial_spec_ordering_ambiguous) - << ClassTemplateSpec; - // Print the matching partial specializations. + // Determine if the best partial specialization is more specialized than + // the others. + bool Ambiguous = false; for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(), PEnd = Matched.end(); - P != PEnd; ++P) - Diag(P->first->getLocation(), diag::note_partial_spec_match) - << getTemplateArgumentBindingsText(P->first->getTemplateParameters(), - *P->second); - - return true; + P != PEnd; ++P) { + if (P != Best && + getMoreSpecializedPartialSpecialization(P->first, Best->first) + != Best->first) { + Ambiguous = true; + break; + } + } + + if (Ambiguous) { + // Partial ordering did not produce a clear winner. Complain. + ClassTemplateSpec->setInvalidDecl(); + Diag(PointOfInstantiation, diag::err_partial_spec_ordering_ambiguous) + << ClassTemplateSpec; + + // Print the matching partial specializations. + for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(), + PEnd = Matched.end(); + P != PEnd; ++P) + Diag(P->first->getLocation(), diag::note_partial_spec_match) + << getTemplateArgumentBindingsText(P->first->getTemplateParameters(), + *P->second); + + return true; + } } // Instantiate using the best class template partial specialization. - Pattern = Best->first; + ClassTemplatePartialSpecializationDecl *OrigPartialSpec = Best->first; + while (OrigPartialSpec->getInstantiatedFromMember()) { + // If we've found an explicit specialization of this class template, + // stop here and use that as the pattern. + if (OrigPartialSpec->isMemberSpecialization()) + break; + + OrigPartialSpec = OrigPartialSpec->getInstantiatedFromMember(); + } + + Pattern = OrigPartialSpec; ClassTemplateSpec->setInstantiationOf(Best->first, Best->second); } else { // -- If no matches are found, the instantiation is generated @@ -1042,12 +1069,9 @@ Sema::InstantiateClassTemplateSpecialization( Pattern = OrigTemplate->getTemplatedDecl(); } - // Note that this is an instantiation. - ClassTemplateSpec->setSpecializationKind(TSK); - - bool Result = InstantiateClass(ClassTemplateSpec->getPointOfInstantiation(), - ClassTemplateSpec, Pattern, - getTemplateInstantiationArgs(ClassTemplateSpec), + bool Result = InstantiateClass(PointOfInstantiation, ClassTemplateSpec, + Pattern, + getTemplateInstantiationArgs(ClassTemplateSpec), TSK, Complain); @@ -1071,48 +1095,112 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, for (DeclContext::decl_iterator D = Instantiation->decls_begin(), DEnd = Instantiation->decls_end(); D != DEnd; ++D) { + bool SuppressNew = false; if (FunctionDecl *Function = dyn_cast<FunctionDecl>(*D)) { - if (Function->getInstantiatedFromMemberFunction()) { - // If this member was explicitly specialized, do nothing. - if (Function->getTemplateSpecializationKind() == - TSK_ExplicitSpecialization) + if (FunctionDecl *Pattern + = Function->getInstantiatedFromMemberFunction()) { + MemberSpecializationInfo *MSInfo + = Function->getMemberSpecializationInfo(); + assert(MSInfo && "No member specialization information?"); + if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, + Function, + MSInfo->getTemplateSpecializationKind(), + MSInfo->getPointOfInstantiation(), + SuppressNew) || + SuppressNew) + continue; + + if (Function->getBody()) continue; + + if (TSK == TSK_ExplicitInstantiationDefinition) { + // C++0x [temp.explicit]p8: + // An explicit instantiation definition that names a class template + // specialization explicitly instantiates the class template + // specialization and is only an explicit instantiation definition + // of members whose definition is visible at the point of + // instantiation. + if (!Pattern->getBody()) + continue; - Function->setTemplateSpecializationKind(TSK, PointOfInstantiation); + Function->setTemplateSpecializationKind(TSK, PointOfInstantiation); + + InstantiateFunctionDefinition(PointOfInstantiation, Function); + } else { + Function->setTemplateSpecializationKind(TSK, PointOfInstantiation); + } } - - if (!Function->getBody() && TSK == TSK_ExplicitInstantiationDefinition) - InstantiateFunctionDefinition(PointOfInstantiation, Function); } else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) { if (Var->isStaticDataMember()) { - // If this member was explicitly specialized, do nothing. - if (Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo(); + assert(MSInfo && "No member specialization information?"); + if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, + Var, + MSInfo->getTemplateSpecializationKind(), + MSInfo->getPointOfInstantiation(), + SuppressNew) || + SuppressNew) continue; - Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); - - if (TSK == TSK_ExplicitInstantiationDefinition) + if (TSK == TSK_ExplicitInstantiationDefinition) { + // C++0x [temp.explicit]p8: + // An explicit instantiation definition that names a class template + // specialization explicitly instantiates the class template + // specialization and is only an explicit instantiation definition + // of members whose definition is visible at the point of + // instantiation. + if (!Var->getInstantiatedFromStaticDataMember() + ->getOutOfLineDefinition()) + continue; + + Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var); - } + } else { + Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); + } + } } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) { if (Record->isInjectedClassName()) continue; - assert(Record->getInstantiatedFromMemberClass() && - "Missing instantiated-from-template information"); - - // If this member was explicitly specialized, do nothing. - if (Record->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + MemberSpecializationInfo *MSInfo = Record->getMemberSpecializationInfo(); + assert(MSInfo && "No member specialization information?"); + if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, + Record, + MSInfo->getTemplateSpecializationKind(), + MSInfo->getPointOfInstantiation(), + SuppressNew) || + SuppressNew) continue; - if (!Record->getDefinition(Context)) - InstantiateClass(PointOfInstantiation, Record, - Record->getInstantiatedFromMemberClass(), + CXXRecordDecl *Pattern = Record->getInstantiatedFromMemberClass(); + assert(Pattern && "Missing instantiated-from-template information"); + + if (!Record->getDefinition(Context)) { + if (!Pattern->getDefinition(Context)) { + // C++0x [temp.explicit]p8: + // An explicit instantiation definition that names a class template + // specialization explicitly instantiates the class template + // specialization and is only an explicit instantiation definition + // of members whose definition is visible at the point of + // instantiation. + if (TSK == TSK_ExplicitInstantiationDeclaration) { + MSInfo->setTemplateSpecializationKind(TSK); + MSInfo->setPointOfInstantiation(PointOfInstantiation); + } + + continue; + } + + InstantiateClass(PointOfInstantiation, Record, Pattern, TemplateArgs, TSK); + } - InstantiateClassMembers(PointOfInstantiation, Record, TemplateArgs, - TSK); + Pattern = cast_or_null<CXXRecordDecl>(Record->getDefinition(Context)); + if (Pattern) + InstantiateClassMembers(PointOfInstantiation, Pattern, TemplateArgs, + TSK); } } } @@ -1178,9 +1266,10 @@ Sema::SubstTemplateName(TemplateName Name, SourceLocation Loc, return Instantiator.TransformTemplateName(Name); } -TemplateArgument Sema::Subst(TemplateArgument Arg, - const MultiLevelTemplateArgumentList &TemplateArgs) { +bool Sema::Subst(const TemplateArgumentLoc &Input, TemplateArgumentLoc &Output, + const MultiLevelTemplateArgumentList &TemplateArgs) { TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(), DeclarationName()); - return Instantiator.TransformTemplateArgument(Arg); + + return Instantiator.TransformTemplateArgument(Input, Output); } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index be4adbc..7288ae2 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -56,12 +56,12 @@ namespace { Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D); Decl *VisitCXXConversionDecl(CXXConversionDecl *D); ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D); - Decl *VisitOriginalParmVarDecl(OriginalParmVarDecl *D); Decl *VisitClassTemplateDecl(ClassTemplateDecl *D); Decl *VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D); Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *D); Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); + Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); Decl *VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D); // Base case. FIXME: Remove once we can instantiate everything. @@ -82,6 +82,10 @@ namespace { TemplateParameterList * SubstTemplateParams(TemplateParameterList *List); + + bool InstantiateClassTemplatePartialSpecialization( + ClassTemplateDecl *ClassTemplate, + ClassTemplatePartialSpecializationDecl *PartialSpec); }; } @@ -99,20 +103,20 @@ TemplateDeclInstantiator::VisitNamespaceDecl(NamespaceDecl *D) { Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { bool Invalid = false; - QualType T = D->getUnderlyingType(); - if (T->isDependentType()) { - T = SemaRef.SubstType(T, TemplateArgs, - D->getLocation(), D->getDeclName()); - if (T.isNull()) { + DeclaratorInfo *DI = D->getTypeDeclaratorInfo(); + if (DI->getType()->isDependentType()) { + DI = SemaRef.SubstType(DI, TemplateArgs, + D->getLocation(), D->getDeclName()); + if (!DI) { Invalid = true; - T = SemaRef.Context.IntTy; + DI = SemaRef.Context.getTrivialDeclaratorInfo(SemaRef.Context.IntTy); } } // Create the new typedef TypedefDecl *Typedef = TypedefDecl::Create(SemaRef.Context, Owner, D->getLocation(), - D->getIdentifier(), T); + D->getIdentifier(), DI); if (Invalid) Typedef->setInvalidDecl(); @@ -161,7 +165,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // which they were instantiated. if (Var->isStaticDataMember()) SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D, - TSK_ImplicitInstantiation); + TSK_ImplicitInstantiation); if (D->getInit()) { OwningExprResult Init @@ -389,7 +393,25 @@ Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) { return 0; } +namespace { + class SortDeclByLocation { + SourceManager &SourceMgr; + + public: + explicit SortDeclByLocation(SourceManager &SourceMgr) + : SourceMgr(SourceMgr) { } + + bool operator()(const Decl *X, const Decl *Y) const { + return SourceMgr.isBeforeInTranslationUnit(X->getLocation(), + Y->getLocation()); + } + }; +} + Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { + // Create a local instantiation scope for this class template, which + // will contain the instantiations of the template parameters. + Sema::LocalInstantiationScope Scope(SemaRef); TemplateParameterList *TempParams = D->getTemplateParameters(); TemplateParameterList *InstParams = SubstTemplateParams(TempParams); if (!InstParams) @@ -406,32 +428,83 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { = ClassTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), InstParams, RecordInst, 0); RecordInst->setDescribedClassTemplate(Inst); - Inst->setAccess(D->getAccess()); + if (D->getFriendObjectKind()) + Inst->setObjectOfFriendDecl(true); + else + Inst->setAccess(D->getAccess()); Inst->setInstantiatedFromMemberTemplate(D); // Trigger creation of the type for the instantiation. SemaRef.Context.getTypeDeclType(RecordInst); + // Finish handling of friends. + if (Inst->getFriendObjectKind()) { + return Inst; + } + Owner->addDecl(Inst); + + // First, we sort the partial specializations by location, so + // that we instantiate them in the order they were declared. + llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; + for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator + P = D->getPartialSpecializations().begin(), + PEnd = D->getPartialSpecializations().end(); + P != PEnd; ++P) + PartialSpecs.push_back(&*P); + std::sort(PartialSpecs.begin(), PartialSpecs.end(), + SortDeclByLocation(SemaRef.SourceMgr)); + + // Instantiate all of the partial specializations of this member class + // template. + for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) + InstantiateClassTemplatePartialSpecialization(Inst, PartialSpecs[I]); + return Inst; } Decl * TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D) { - assert(false &&"Partial specializations of member templates are unsupported"); + ClassTemplateDecl *ClassTemplate = D->getSpecializedTemplate(); + + // Lookup the already-instantiated declaration in the instantiation + // of the class template and return that. + DeclContext::lookup_result Found + = Owner->lookup(ClassTemplate->getDeclName()); + if (Found.first == Found.second) + return 0; + + ClassTemplateDecl *InstClassTemplate + = dyn_cast<ClassTemplateDecl>(*Found.first); + if (!InstClassTemplate) + return 0; + + Decl *DCanon = D->getCanonicalDecl(); + for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator + P = InstClassTemplate->getPartialSpecializations().begin(), + PEnd = InstClassTemplate->getPartialSpecializations().end(); + P != PEnd; ++P) { + if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon) + return &*P; + } + return 0; } Decl * TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { - // FIXME: Dig out the out-of-line definition of this function template? - + // Create a local instantiation scope for this function template, which + // will contain the instantiations of the template parameters and then get + // merged with the local instantiation scope for the function template + // itself. + Sema::LocalInstantiationScope Scope(SemaRef); + TemplateParameterList *TempParams = D->getTemplateParameters(); TemplateParameterList *InstParams = SubstTemplateParams(TempParams); if (!InstParams) return NULL; - + FunctionDecl *Instantiated = 0; if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(D->getTemplatedDecl())) Instantiated = cast_or_null<FunctionDecl>(VisitCXXMethodDecl(DMethod, @@ -516,7 +589,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { return Info->Function; } - Sema::LocalInstantiationScope Scope(SemaRef); + Sema::LocalInstantiationScope Scope(SemaRef, TemplateParams != 0); llvm::SmallVector<ParmVarDecl *, 4> Params; QualType T = SubstFunctionType(D, Params); @@ -530,7 +603,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(), D->getDeclName(), T, D->getDeclaratorInfo(), D->getStorageClass(), - D->isInline(), D->hasWrittenPrototype()); + D->isInlineSpecified(), D->hasWrittenPrototype()); Function->setLexicalDeclContext(Owner); // Attach the parameters @@ -645,7 +718,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, return Info->Function; } - Sema::LocalInstantiationScope Scope(SemaRef); + Sema::LocalInstantiationScope Scope(SemaRef, TemplateParams != 0); llvm::SmallVector<ParmVarDecl *, 4> Params; QualType T = SubstFunctionType(D, Params); @@ -666,14 +739,14 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Name, T, Constructor->getDeclaratorInfo(), Constructor->isExplicit(), - Constructor->isInline(), false); + Constructor->isInlineSpecified(), false); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { QualType ClassTy = SemaRef.Context.getTypeDeclType(Record); Name = SemaRef.Context.DeclarationNames.getCXXDestructorName( SemaRef.Context.getCanonicalType(ClassTy)); Method = CXXDestructorDecl::Create(SemaRef.Context, Record, Destructor->getLocation(), Name, - T, Destructor->isInline(), false); + T, Destructor->isInlineSpecified(), false); } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) { CanQualType ConvTy = SemaRef.Context.getCanonicalType( @@ -683,12 +756,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method = CXXConversionDecl::Create(SemaRef.Context, Record, Conversion->getLocation(), Name, T, Conversion->getDeclaratorInfo(), - Conversion->isInline(), + Conversion->isInlineSpecified(), Conversion->isExplicit()); } else { Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(), D->getDeclName(), T, D->getDeclaratorInfo(), - D->isStatic(), D->isInline()); + D->isStatic(), D->isInlineSpecified()); } if (TemplateParams) { @@ -776,24 +849,27 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) { } ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) { - QualType OrigT = SemaRef.SubstType(D->getOriginalType(), TemplateArgs, - D->getLocation(), D->getDeclName()); - if (OrigT.isNull()) + QualType T; + DeclaratorInfo *DI = D->getDeclaratorInfo(); + if (DI) { + DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(), + D->getDeclName()); + if (DI) T = DI->getType(); + } else { + T = SemaRef.SubstType(D->getType(), TemplateArgs, D->getLocation(), + D->getDeclName()); + DI = 0; + } + + if (T.isNull()) return 0; - QualType T = SemaRef.adjustParameterType(OrigT); + T = SemaRef.adjustParameterType(T); // Allocate the parameter - ParmVarDecl *Param = 0; - if (T == OrigT) - Param = ParmVarDecl::Create(SemaRef.Context, Owner, D->getLocation(), - D->getIdentifier(), T, D->getDeclaratorInfo(), - D->getStorageClass(), 0); - else - Param = OriginalParmVarDecl::Create(SemaRef.Context, Owner, - D->getLocation(), D->getIdentifier(), - T, D->getDeclaratorInfo(), OrigT, - D->getStorageClass(), 0); + ParmVarDecl *Param + = ParmVarDecl::Create(SemaRef.Context, Owner, D->getLocation(), + D->getIdentifier(), T, DI, D->getStorageClass(), 0); // Mark the default argument as being uninstantiated. if (D->hasUninstantiatedDefaultArg()) @@ -808,15 +884,6 @@ ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) { return Param; } -Decl * -TemplateDeclInstantiator::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) { - // Since parameter types can decay either before or after - // instantiation, we simply treat OriginalParmVarDecls as - // ParmVarDecls the same way, and create one or the other depending - // on what happens after template instantiation. - return VisitParmVarDecl(D); -} - Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( TemplateTypeParmDecl *D) { // TODO: don't always clone when decls are refcounted. @@ -826,26 +893,71 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( TemplateTypeParmDecl *Inst = TemplateTypeParmDecl::Create(SemaRef.Context, Owner, D->getLocation(), - TTPT->getDepth(), TTPT->getIndex(), + TTPT->getDepth() - 1, TTPT->getIndex(), TTPT->getName(), D->wasDeclaredWithTypename(), D->isParameterPack()); + // FIXME: Do we actually want to perform substitution here? I don't think + // we do. if (D->hasDefaultArgument()) { - QualType DefaultPattern = D->getDefaultArgument(); - QualType DefaultInst + DeclaratorInfo *DefaultPattern = D->getDefaultArgumentInfo(); + DeclaratorInfo *DefaultInst = SemaRef.SubstType(DefaultPattern, TemplateArgs, D->getDefaultArgumentLoc(), D->getDeclName()); Inst->setDefaultArgument(DefaultInst, - D->getDefaultArgumentLoc(), D->defaultArgumentWasInherited() /* preserve? */); } + // Introduce this template parameter's instantiation into the instantiation + // scope. + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Inst); + return Inst; } +Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( + NonTypeTemplateParmDecl *D) { + // Substitute into the type of the non-type template parameter. + QualType T; + DeclaratorInfo *DI = D->getDeclaratorInfo(); + if (DI) { + DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(), + D->getDeclName()); + if (DI) T = DI->getType(); + } else { + T = SemaRef.SubstType(D->getType(), TemplateArgs, D->getLocation(), + D->getDeclName()); + DI = 0; + } + if (T.isNull()) + return 0; + + // Check that this type is acceptable for a non-type template parameter. + bool Invalid = false; + T = SemaRef.CheckNonTypeTemplateParameterType(T, D->getLocation()); + if (T.isNull()) { + T = SemaRef.Context.IntTy; + Invalid = true; + } + + NonTypeTemplateParmDecl *Param + = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, D->getLocation(), + D->getDepth() - 1, D->getPosition(), + D->getIdentifier(), T, DI); + if (Invalid) + Param->setInvalidDecl(); + + Param->setDefaultArgument(D->getDefaultArgument()); + + // Introduce this template parameter's instantiation into the instantiation + // scope. + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param); + return Param; +} + Decl * TemplateDeclInstantiator::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) { NestedNameSpecifier *NNS = @@ -913,6 +1025,136 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) { return InstL; } +/// \brief Instantiate the declaration of a class template partial +/// specialization. +/// +/// \param ClassTemplate the (instantiated) class template that is partially +// specialized by the instantiation of \p PartialSpec. +/// +/// \param PartialSpec the (uninstantiated) class template partial +/// specialization that we are instantiating. +/// +/// \returns true if there was an error, false otherwise. +bool +TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( + ClassTemplateDecl *ClassTemplate, + ClassTemplatePartialSpecializationDecl *PartialSpec) { + // Create a local instantiation scope for this class template partial + // specialization, which will contain the instantiations of the template + // parameters. + Sema::LocalInstantiationScope Scope(SemaRef); + + // Substitute into the template parameters of the class template partial + // specialization. + TemplateParameterList *TempParams = PartialSpec->getTemplateParameters(); + TemplateParameterList *InstParams = SubstTemplateParams(TempParams); + if (!InstParams) + return true; + + // Substitute into the template arguments of the class template partial + // specialization. + const TemplateArgumentLoc *PartialSpecTemplateArgs + = PartialSpec->getTemplateArgsAsWritten(); + unsigned N = PartialSpec->getNumTemplateArgsAsWritten(); + + llvm::SmallVector<TemplateArgumentLoc, 4> InstTemplateArgs(N); + for (unsigned I = 0; I != N; ++I) { + if (SemaRef.Subst(PartialSpecTemplateArgs[I], InstTemplateArgs[I], + TemplateArgs)) + return true; + } + + + // Check that the template argument list is well-formed for this + // class template. + TemplateArgumentListBuilder Converted(ClassTemplate->getTemplateParameters(), + InstTemplateArgs.size()); + if (SemaRef.CheckTemplateArgumentList(ClassTemplate, + PartialSpec->getLocation(), + /*FIXME:*/PartialSpec->getLocation(), + InstTemplateArgs.data(), + InstTemplateArgs.size(), + /*FIXME:*/PartialSpec->getLocation(), + false, + Converted)) + return true; + + // Figure out where to insert this class template partial specialization + // in the member template's set of class template partial specializations. + llvm::FoldingSetNodeID ID; + ClassTemplatePartialSpecializationDecl::Profile(ID, + Converted.getFlatArguments(), + Converted.flatSize(), + SemaRef.Context); + void *InsertPos = 0; + ClassTemplateSpecializationDecl *PrevDecl + = ClassTemplate->getPartialSpecializations().FindNodeOrInsertPos(ID, + InsertPos); + + // Build the canonical type that describes the converted template + // arguments of the class template partial specialization. + QualType CanonType + = SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate), + Converted.getFlatArguments(), + Converted.flatSize()); + + // Build the fully-sugared type for this class template + // specialization as the user wrote in the specialization + // itself. This means that we'll pretty-print the type retrieved + // from the specialization's declaration the way that the user + // actually wrote the specialization, rather than formatting the + // name based on the "canonical" representation used to store the + // template arguments in the specialization. + QualType WrittenTy + = SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate), + InstTemplateArgs.data(), + InstTemplateArgs.size(), + CanonType); + + if (PrevDecl) { + // We've already seen a partial specialization with the same template + // parameters and template arguments. This can happen, for example, when + // substituting the outer template arguments ends up causing two + // class template partial specializations of a member class template + // to have identical forms, e.g., + // + // template<typename T, typename U> + // struct Outer { + // template<typename X, typename Y> struct Inner; + // template<typename Y> struct Inner<T, Y>; + // template<typename Y> struct Inner<U, Y>; + // }; + // + // Outer<int, int> outer; // error: the partial specializations of Inner + // // have the same signature. + SemaRef.Diag(PartialSpec->getLocation(), diag::err_partial_spec_redeclared) + << WrittenTy; + SemaRef.Diag(PrevDecl->getLocation(), diag::note_prev_partial_spec_here) + << SemaRef.Context.getTypeDeclType(PrevDecl); + return true; + } + + + // Create the class template partial specialization declaration. + ClassTemplatePartialSpecializationDecl *InstPartialSpec + = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context, Owner, + PartialSpec->getLocation(), + InstParams, + ClassTemplate, + Converted, + InstTemplateArgs.data(), + InstTemplateArgs.size(), + 0); + InstPartialSpec->setInstantiatedFromMember(PartialSpec); + InstPartialSpec->setTypeAsWritten(WrittenTy); + + // Add this partial specialization to the set of class template partial + // specializations. + ClassTemplate->getPartialSpecializations().InsertNode(InstPartialSpec, + InsertPos); + return false; +} + /// \brief Does substitution on the type of the given function, including /// all of the function parameters. /// @@ -1065,20 +1307,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, return; // Find the function body that we'll be substituting. - const FunctionDecl *PatternDecl = 0; - if (FunctionTemplateDecl *Primary = Function->getPrimaryTemplate()) { - while (Primary->getInstantiatedFromMemberTemplate()) { - // If we have hit a point where the user provided a specialization of - // this template, we're done looking. - if (Primary->isMemberSpecialization()) - break; - - Primary = Primary->getInstantiatedFromMemberTemplate(); - } - - PatternDecl = Primary->getTemplatedDecl(); - } else - PatternDecl = Function->getInstantiatedFromMemberFunction(); + const FunctionDecl *PatternDecl = Function->getTemplateInstantiationPattern(); Stmt *Pattern = 0; if (PatternDecl) Pattern = PatternDecl->getBody(PatternDecl); @@ -1108,7 +1337,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // to which they refer. if (Function->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDeclaration && - PatternDecl->isOutOfLine() && !PatternDecl->isInline()) + !PatternDecl->isInlined()) return; InstantiatingTemplate Inst(*this, PointOfInstantiation, Function); @@ -1199,24 +1428,17 @@ void Sema::InstantiateStaticDataMemberDefinition( // Find the out-of-line definition of this static data member. VarDecl *Def = Var->getInstantiatedFromStaticDataMember(); - bool FoundOutOfLineDef = false; assert(Def && "This data member was not instantiated from a template?"); - assert(Def->isStaticDataMember() && "Not a static data member?"); - for (VarDecl::redecl_iterator RD = Def->redecls_begin(), - RDEnd = Def->redecls_end(); - RD != RDEnd; ++RD) { - if (RD->getLexicalDeclContext()->isFileContext()) { - Def = *RD; - FoundOutOfLineDef = true; - } - } + assert(Def->isStaticDataMember() && "Not a static data member?"); + Def = Def->getOutOfLineDefinition(); - if (!FoundOutOfLineDef) { + if (!Def) { // We did not find an out-of-line definition of this static data member, // so we won't perform any instantiation. Rather, we rely on the user to // instantiate this definition (or provide a specialization for it) in // another translation unit. if (DefinitionRequired) { + Def = Var->getInstantiatedFromStaticDataMember(); Diag(PointOfInstantiation, diag::err_explicit_instantiation_undefined_member) << 2 << Var->getDeclName() << Var->getDeclContext(); @@ -1379,6 +1601,22 @@ static bool isInstantiationOf(FunctionTemplateDecl *Pattern, return false; } +static bool +isInstantiationOf(ClassTemplatePartialSpecializationDecl *Pattern, + ClassTemplatePartialSpecializationDecl *Instance) { + Pattern + = cast<ClassTemplatePartialSpecializationDecl>(Pattern->getCanonicalDecl()); + do { + Instance = cast<ClassTemplatePartialSpecializationDecl>( + Instance->getCanonicalDecl()); + if (Pattern == Instance) + return true; + Instance = Instance->getInstantiatedFromMember(); + } while (Instance); + + return false; +} + static bool isInstantiationOf(CXXRecordDecl *Pattern, CXXRecordDecl *Instance) { Pattern = Pattern->getCanonicalDecl(); @@ -1469,6 +1707,11 @@ static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { if (FunctionTemplateDecl *Temp = dyn_cast<FunctionTemplateDecl>(Other)) return isInstantiationOf(cast<FunctionTemplateDecl>(D), Temp); + if (ClassTemplatePartialSpecializationDecl *PartialSpec + = dyn_cast<ClassTemplatePartialSpecializationDecl>(Other)) + return isInstantiationOf(cast<ClassTemplatePartialSpecializationDecl>(D), + PartialSpec); + if (FieldDecl *Field = dyn_cast<FieldDecl>(Other)) { if (!Field->getDeclName()) { // This is an unnamed field. @@ -1550,7 +1793,9 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D, } DeclContext *ParentDC = D->getDeclContext(); - if (isa<ParmVarDecl>(D) || ParentDC->isFunctionOrMethod()) { + if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) || + isa<TemplateTypeParmDecl>(D) || isa<TemplateTypeParmDecl>(D) || + ParentDC->isFunctionOrMethod()) { // D is a local of some kind. Look into the map of local // declarations to their instantiations. return cast<NamedDecl>(CurrentInstantiationScope->getInstantiationOf(D)); diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 49f7119..0003b1b 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -31,36 +31,58 @@ using namespace clang; /// C++ [dcl.fct]p3). The adjusted parameter type is returned. QualType Sema::adjustParameterType(QualType T) { // C99 6.7.5.3p7: - if (T->isArrayType()) { - // C99 6.7.5.3p7: - // A declaration of a parameter as "array of type" shall be - // adjusted to "qualified pointer to type", where the type - // qualifiers (if any) are those specified within the [ and ] of - // the array type derivation. + // A declaration of a parameter as "array of type" shall be + // adjusted to "qualified pointer to type", where the type + // qualifiers (if any) are those specified within the [ and ] of + // the array type derivation. + if (T->isArrayType()) return Context.getArrayDecayedType(T); - } else if (T->isFunctionType()) - // C99 6.7.5.3p8: - // A declaration of a parameter as "function returning type" - // shall be adjusted to "pointer to function returning type", as - // in 6.3.2.1. + + // C99 6.7.5.3p8: + // A declaration of a parameter as "function returning type" + // shall be adjusted to "pointer to function returning type", as + // in 6.3.2.1. + if (T->isFunctionType()) return Context.getPointerType(T); return T; } + + +/// isOmittedBlockReturnType - Return true if this declarator is missing a +/// return type because this is a omitted return type on a block literal. +static bool isOmittedBlockReturnType(const Declarator &D) { + if (D.getContext() != Declarator::BlockLiteralContext || + D.getDeclSpec().hasTypeSpecifier()) + return false; + + if (D.getNumTypeObjects() == 0) + return true; // ^{ ... } + + if (D.getNumTypeObjects() == 1 && + D.getTypeObject(0).Kind == DeclaratorChunk::Function) + return true; // ^(int X, float Y) { ... } + + return false; +} + /// \brief Convert the specified declspec to the appropriate type /// object. -/// \param DS the declaration specifiers -/// \param DeclLoc The location of the declarator identifier or invalid if none. +/// \param D the declarator containing the declaration specifier. /// \returns The type described by the declaration specifiers. This function /// never returns null. -QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, - SourceLocation DeclLoc, - bool &isInvalid) { +static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){ // FIXME: Should move the logic from DeclSpec::Finish to here for validity // checking. - QualType Result; + const DeclSpec &DS = TheDeclarator.getDeclSpec(); + SourceLocation DeclLoc = TheDeclarator.getIdentifierLoc(); + if (DeclLoc.isInvalid()) + DeclLoc = DS.getSourceRange().getBegin(); + + ASTContext &Context = TheSema.Context; + QualType Result; switch (DS.getTypeSpecType()) { case DeclSpec::TST_void: Result = Context.VoidTy; @@ -80,13 +102,13 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified) Result = Context.WCharTy; else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed) { - Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) + TheSema.Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) << DS.getSpecifierName(DS.getTypeSpecType()); Result = Context.getSignedWCharType(); } else { assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned && "Unknown TSS value"); - Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) + TheSema.Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) << DS.getSpecifierName(DS.getTypeSpecType()); Result = Context.getUnsignedWCharType(); } @@ -109,6 +131,13 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, DS.getNumProtocolQualifiers()); break; } + + // If this is a missing declspec in a block literal return context, then it + // is inferred from the return statements inside the block. + if (isOmittedBlockReturnType(TheDeclarator)) { + Result = Context.DependentTy; + break; + } // Unspecified typespec defaults to int in C90. However, the C90 grammar // [C90 6.5] only allows a decl-spec if there was *some* type-specifier, @@ -117,13 +146,11 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, // allowed to be completely missing a declspec. This is handled in the // parser already though by it pretending to have seen an 'int' in this // case. - if (getLangOptions().ImplicitInt) { + if (TheSema.getLangOptions().ImplicitInt) { // In C89 mode, we only warn if there is a completely missing declspec // when one is not allowed. if (DS.isEmpty()) { - if (DeclLoc.isInvalid()) - DeclLoc = DS.getSourceRange().getBegin(); - Diag(DeclLoc, diag::ext_missing_declspec) + TheSema.Diag(DeclLoc, diag::ext_missing_declspec) << DS.getSourceRange() << CodeModificationHint::CreateInsertion(DS.getSourceRange().getBegin(), "int"); @@ -134,19 +161,17 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, // specifiers in each declaration, and in the specifier-qualifier list in // each struct declaration and type name." // FIXME: Does Microsoft really have the implicit int extension in C++? - if (DeclLoc.isInvalid()) - DeclLoc = DS.getSourceRange().getBegin(); - - if (getLangOptions().CPlusPlus && !getLangOptions().Microsoft) { - Diag(DeclLoc, diag::err_missing_type_specifier) + if (TheSema.getLangOptions().CPlusPlus && + !TheSema.getLangOptions().Microsoft) { + TheSema.Diag(DeclLoc, diag::err_missing_type_specifier) << DS.getSourceRange(); // When this occurs in C++ code, often something is very broken with the // value being declared, poison it as invalid so we don't get chains of // errors. - isInvalid = true; + TheDeclarator.setInvalidType(true); } else { - Diag(DeclLoc, diag::ext_missing_type_specifier) + TheSema.Diag(DeclLoc, diag::ext_missing_type_specifier) << DS.getSourceRange(); } } @@ -158,14 +183,28 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, case DeclSpec::TSW_unspecified: Result = Context.IntTy; break; case DeclSpec::TSW_short: Result = Context.ShortTy; break; case DeclSpec::TSW_long: Result = Context.LongTy; break; - case DeclSpec::TSW_longlong: Result = Context.LongLongTy; break; + case DeclSpec::TSW_longlong: + Result = Context.LongLongTy; + + // long long is a C99 feature. + if (!TheSema.getLangOptions().C99 && + !TheSema.getLangOptions().CPlusPlus0x) + TheSema.Diag(DS.getTypeSpecWidthLoc(), diag::ext_longlong); + break; } } else { switch (DS.getTypeSpecWidth()) { case DeclSpec::TSW_unspecified: Result = Context.UnsignedIntTy; break; case DeclSpec::TSW_short: Result = Context.UnsignedShortTy; break; case DeclSpec::TSW_long: Result = Context.UnsignedLongTy; break; - case DeclSpec::TSW_longlong: Result =Context.UnsignedLongLongTy; break; + case DeclSpec::TSW_longlong: + Result = Context.UnsignedLongLongTy; + + // long long is a C99 feature. + if (!TheSema.getLangOptions().C99 && + !TheSema.getLangOptions().CPlusPlus0x) + TheSema.Diag(DS.getTypeSpecWidthLoc(), diag::ext_longlong); + break; } } break; @@ -181,44 +220,47 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, case DeclSpec::TST_decimal32: // _Decimal32 case DeclSpec::TST_decimal64: // _Decimal64 case DeclSpec::TST_decimal128: // _Decimal128 - Diag(DS.getTypeSpecTypeLoc(), diag::err_decimal_unsupported); + TheSema.Diag(DS.getTypeSpecTypeLoc(), diag::err_decimal_unsupported); Result = Context.IntTy; - isInvalid = true; + TheDeclarator.setInvalidType(true); break; case DeclSpec::TST_class: case DeclSpec::TST_enum: case DeclSpec::TST_union: case DeclSpec::TST_struct: { - Decl *D = static_cast<Decl *>(DS.getTypeRep()); + TypeDecl *D = cast_or_null<TypeDecl>(static_cast<Decl *>(DS.getTypeRep())); if (!D) { // This can happen in C++ with ambiguous lookups. Result = Context.IntTy; - isInvalid = true; + TheDeclarator.setInvalidType(true); break; } + // If the type is deprecated or unavailable, diagnose it. + TheSema.DiagnoseUseOfDecl(D, DS.getTypeSpecTypeLoc()); + assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && - DS.getTypeSpecSign() == 0 && - "Can't handle qualifiers on typedef names yet!"); + DS.getTypeSpecSign() == 0 && "No qualifiers on tag names!"); + // TypeQuals handled by caller. - Result = Context.getTypeDeclType(cast<TypeDecl>(D)); + Result = Context.getTypeDeclType(D); // In C++, make an ElaboratedType. - if (getLangOptions().CPlusPlus) { + if (TheSema.getLangOptions().CPlusPlus) { TagDecl::TagKind Tag = TagDecl::getTagKindForTypeSpec(DS.getTypeSpecType()); Result = Context.getElaboratedType(Result, Tag); } if (D->isInvalidDecl()) - isInvalid = true; + TheDeclarator.setInvalidType(true); break; } case DeclSpec::TST_typename: { assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && DS.getTypeSpecSign() == 0 && "Can't handle qualifiers on typedef names yet!"); - Result = GetTypeFromParser(DS.getTypeRep()); + Result = TheSema.GetTypeFromParser(DS.getTypeRep()); if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { if (const ObjCInterfaceType * @@ -240,31 +282,22 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy, (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); else if (Result->isObjCClassType()) { - if (DeclLoc.isInvalid()) - DeclLoc = DS.getSourceRange().getBegin(); // Class<protocol-list> Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy, (ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); } else { - if (DeclLoc.isInvalid()) - DeclLoc = DS.getSourceRange().getBegin(); - Diag(DeclLoc, diag::err_invalid_protocol_qualifiers) + TheSema.Diag(DeclLoc, diag::err_invalid_protocol_qualifiers) << DS.getSourceRange(); - isInvalid = true; + TheDeclarator.setInvalidType(true); } } - // If this is a reference to an invalid typedef, propagate the invalidity. - if (TypedefType *TDT = dyn_cast<TypedefType>(Result)) - if (TDT->getDecl()->isInvalidDecl()) - isInvalid = true; - // TypeQuals handled by caller. break; } case DeclSpec::TST_typeofType: // FIXME: Preserve type source info. - Result = GetTypeFromParser(DS.getTypeRep()); + Result = TheSema.GetTypeFromParser(DS.getTypeRep()); assert(!Result.isNull() && "Didn't get a type for typeof?"); // TypeQuals handled by caller. Result = Context.getTypeOfType(Result); @@ -280,10 +313,10 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, Expr *E = static_cast<Expr *>(DS.getTypeRep()); assert(E && "Didn't get an expression for decltype?"); // TypeQuals handled by caller. - Result = BuildDecltypeType(E); + Result = TheSema.BuildDecltypeType(E); if (Result.isNull()) { Result = Context.IntTy; - isInvalid = true; + TheDeclarator.setInvalidType(true); } break; } @@ -295,14 +328,14 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, case DeclSpec::TST_error: Result = Context.IntTy; - isInvalid = true; + TheDeclarator.setInvalidType(true); break; } // Handle complex types. if (DS.getTypeSpecComplex() == DeclSpec::TSC_complex) { - if (getLangOptions().Freestanding) - Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex); + if (TheSema.getLangOptions().Freestanding) + TheSema.Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex); Result = Context.getComplexType(Result); } @@ -312,7 +345,7 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, // See if there are any attributes on the declspec that apply to the type (as // opposed to the decl). if (const AttributeList *AL = DS.getAttributes()) - ProcessTypeAttributeList(Result, AL); + TheSema.ProcessTypeAttributeList(Result, AL); // Apply const/volatile/restrict qualifiers to T. if (unsigned TypeQuals = DS.getTypeQualifiers()) { @@ -329,13 +362,13 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, // If we have a pointer or reference, the pointee must have an object // incomplete type. if (!EltTy->isIncompleteOrObjectType()) { - Diag(DS.getRestrictSpecLoc(), + TheSema.Diag(DS.getRestrictSpecLoc(), diag::err_typecheck_invalid_restrict_invalid_pointee) << EltTy << DS.getSourceRange(); TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier. } } else { - Diag(DS.getRestrictSpecLoc(), + TheSema.Diag(DS.getRestrictSpecLoc(), diag::err_typecheck_invalid_restrict_not_pointer) << Result << DS.getSourceRange(); TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier. @@ -357,7 +390,7 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, "Has CVR quals but not C, V, or R?"); Loc = DS.getRestrictSpecLoc(); } - Diag(Loc, diag::warn_typecheck_function_qualifiers) + TheSema.Diag(Loc, diag::warn_typecheck_function_qualifiers) << Result << DS.getSourceRange(); } @@ -407,7 +440,7 @@ QualType Sema::BuildPointerType(QualType T, unsigned Quals, if (T->isReferenceType()) { // C++ 8.3.2p4: There shall be no ... pointers to references ... Diag(Loc, diag::err_illegal_decl_pointer_to_reference) - << getPrintableNameForEntity(Entity); + << getPrintableNameForEntity(Entity) << T; return QualType(); } @@ -535,14 +568,14 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, if (T->isFunctionType()) { Diag(Loc, diag::err_illegal_decl_array_of_functions) - << getPrintableNameForEntity(Entity); + << getPrintableNameForEntity(Entity) << T; return QualType(); } // C++ 8.3.2p4: There shall be no ... arrays of references ... if (T->isReferenceType()) { Diag(Loc, diag::err_illegal_decl_array_of_references) - << getPrintableNameForEntity(Entity); + << getPrintableNameForEntity(Entity) << T; return QualType(); } @@ -746,7 +779,7 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class, // with reference type, or "cv void." if (T->isReferenceType()) { Diag(Loc, diag::err_illegal_decl_mempointer_to_reference) - << (Entity? Entity.getAsString() : "type name"); + << (Entity? Entity.getAsString() : "type name") << T; return QualType(); } @@ -805,6 +838,11 @@ QualType Sema::BuildBlockPointerType(QualType T, unsigned CVR, QualType Sema::GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo) { QualType QT = QualType::getFromOpaquePtr(Ty); + if (QT.isNull()) { + if (DInfo) *DInfo = 0; + return QualType(); + } + DeclaratorInfo *DI = 0; if (LocInfoType *LIT = dyn_cast<LocInfoType>(QT)) { QT = LIT->getType(); @@ -816,58 +854,31 @@ QualType Sema::GetTypeFromParser(TypeTy *Ty, DeclaratorInfo **DInfo) { } /// GetTypeForDeclarator - Convert the type for the specified -/// declarator to Type instances. Skip the outermost Skip type -/// objects. +/// declarator to Type instances. /// /// If OwnedDecl is non-NULL, and this declarator's decl-specifier-seq /// owns the declaration of a type (e.g., the definition of a struct /// type), then *OwnedDecl will receive the owned declaration. QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, - DeclaratorInfo **DInfo, unsigned Skip, + DeclaratorInfo **DInfo, TagDecl **OwnedDecl) { - bool OmittedReturnType = false; - - if (D.getContext() == Declarator::BlockLiteralContext - && Skip == 0 - && !D.getDeclSpec().hasTypeSpecifier() - && (D.getNumTypeObjects() == 0 - || (D.getNumTypeObjects() == 1 - && D.getTypeObject(0).Kind == DeclaratorChunk::Function))) - OmittedReturnType = true; - - // long long is a C99 feature. - if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x && - D.getDeclSpec().getTypeSpecWidth() == DeclSpec::TSW_longlong) - Diag(D.getDeclSpec().getTypeSpecWidthLoc(), diag::ext_longlong); - // Determine the type of the declarator. Not all forms of declarator // have a type. QualType T; - switch (D.getKind()) { - case Declarator::DK_Abstract: - case Declarator::DK_Normal: - case Declarator::DK_Operator: - case Declarator::DK_TemplateId: { - const DeclSpec &DS = D.getDeclSpec(); - if (OmittedReturnType) { - // We default to a dependent type initially. Can be modified by - // the first return statement. - T = Context.DependentTy; - } else { - bool isInvalid = false; - T = ConvertDeclSpecToType(DS, D.getIdentifierLoc(), isInvalid); - if (isInvalid) - D.setInvalidType(true); - else if (OwnedDecl && DS.isTypeSpecOwned()) - *OwnedDecl = cast<TagDecl>((Decl *)DS.getTypeRep()); - } + switch (D.getName().getKind()) { + case UnqualifiedId::IK_Identifier: + case UnqualifiedId::IK_OperatorFunctionId: + case UnqualifiedId::IK_TemplateId: + T = ConvertDeclSpecToType(D, *this); + + if (!D.isInvalidType() && OwnedDecl && D.getDeclSpec().isTypeSpecOwned()) + *OwnedDecl = cast<TagDecl>((Decl *)D.getDeclSpec().getTypeRep()); break; - } - case Declarator::DK_Constructor: - case Declarator::DK_Destructor: - case Declarator::DK_Conversion: + case UnqualifiedId::IK_ConstructorName: + 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. @@ -926,8 +937,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // Walk the DeclTypeInfo, building the recursive type as we go. // DeclTypeInfos are ordered from the identifier out, which is // opposite of what we want :). - for (unsigned i = Skip, e = D.getNumTypeObjects(); i != e; ++i) { - DeclaratorChunk &DeclType = D.getTypeObject(e-i-1+Skip); + for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { + DeclaratorChunk &DeclType = D.getTypeObject(e-i-1); switch (DeclType.Kind) { default: assert(0 && "Unknown decltype!"); case DeclaratorChunk::BlockPointer: @@ -1190,7 +1201,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (getLangOptions().CPlusPlus && T->isFunctionType()) { const FunctionProtoType *FnTy = T->getAs<FunctionProtoType>(); - assert(FnTy && "Why oh why is there not a FunctionProtoType here ?"); + assert(FnTy && "Why oh why is there not a FunctionProtoType here?"); // C++ 8.3.5p4: A cv-qualifier-seq shall only be part of the function type // for a nonstatic member function, the function type to which a pointer @@ -1224,7 +1235,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (D.isInvalidType()) *DInfo = 0; else - *DInfo = GetDeclaratorInfoForDeclarator(D, T, Skip); + *DInfo = GetDeclaratorInfoForDeclarator(D, T); } return T; @@ -1289,6 +1300,21 @@ namespace { Visit(TL.getBaseTypeLoc()); } } + void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) { + DeclaratorInfo *DInfo = 0; + Sema::GetTypeFromParser(DS.getTypeRep(), &DInfo); + + // If we got no declarator info from previous Sema routines, + // just fill with the typespec loc. + if (!DInfo) { + TL.initialize(DS.getTypeSpecTypeLoc()); + return; + } + + TemplateSpecializationTypeLoc OldTL = + cast<TemplateSpecializationTypeLoc>(DInfo->getTypeLoc()); + TL.copy(OldTL); + } void VisitTypeLoc(TypeLoc TL) { // FIXME: add other typespec types and change this to an assert. TL.initialize(DS.getTypeSpecTypeLoc()); @@ -1366,11 +1392,11 @@ namespace { /// /// \param T QualType referring to the type as written in source code. DeclaratorInfo * -Sema::GetDeclaratorInfoForDeclarator(Declarator &D, QualType T, unsigned Skip) { +Sema::GetDeclaratorInfoForDeclarator(Declarator &D, QualType T) { DeclaratorInfo *DInfo = Context.CreateDeclaratorInfo(T); UnqualTypeLoc CurrTL = DInfo->getTypeLoc().getUnqualifiedLoc(); - for (unsigned i = Skip, e = D.getNumTypeObjects(); i != e; ++i) { + for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { DeclaratorLocFiller(D.getTypeObject(i)).Visit(CurrTL); CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc(); } @@ -1463,7 +1489,7 @@ Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { DeclaratorInfo *DInfo = 0; TagDecl *OwnedTag = 0; - QualType T = GetTypeForDeclarator(D, S, &DInfo, /*Skip=*/0, &OwnedTag); + QualType T = GetTypeForDeclarator(D, S, &DInfo, &OwnedTag); if (D.isInvalidType()) return true; @@ -1655,13 +1681,10 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, if (const RecordType *Record = T->getAs<RecordType>()) { if (ClassTemplateSpecializationDecl *ClassTemplateSpec = dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) { - if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) { - if (Loc.isValid()) - ClassTemplateSpec->setPointOfInstantiation(Loc); - return InstantiateClassTemplateSpecialization(ClassTemplateSpec, + if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) + return InstantiateClassTemplateSpecialization(Loc, ClassTemplateSpec, TSK_ImplicitInstantiation, /*Complain=*/diag != 0); - } } else if (CXXRecordDecl *Rec = dyn_cast<CXXRecordDecl>(Record->getDecl())) { if (CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass()) { @@ -1669,13 +1692,11 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, assert(MSInfo && "Missing member specialization information?"); // This record was instantiated from a class within a template. if (MSInfo->getTemplateSpecializationKind() - != TSK_ExplicitSpecialization) { - MSInfo->setPointOfInstantiation(Loc); + != TSK_ExplicitSpecialization) return InstantiateClass(Loc, Rec, Pattern, getTemplateInstantiationArgs(Rec), TSK_ImplicitInstantiation, /*Complain=*/diag != 0); - } } } } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 7e0972f..5713da9 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -290,23 +290,43 @@ public: /// declaration stored within the template argument and constructs a /// new template argument from the transformed result. Subclasses may /// override this function to provide alternate behavior. - TemplateArgument TransformTemplateArgument(const TemplateArgument &Arg); + /// + /// Returns true if there was an error. + bool TransformTemplateArgument(const TemplateArgumentLoc &Input, + TemplateArgumentLoc &Output); + + /// \brief Fakes up a TemplateArgumentLoc for a given TemplateArgument. + void InventTemplateArgumentLoc(const TemplateArgument &Arg, + TemplateArgumentLoc &ArgLoc); + + /// \brief Fakes up a DeclaratorInfo for a type. + DeclaratorInfo *InventDeclaratorInfo(QualType T) { + return SemaRef.Context.getTrivialDeclaratorInfo(T, + getDerived().getBaseLocation()); + } #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T); #include "clang/AST/TypeLocNodes.def" + QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL); + QualType TransformTemplateSpecializationType(const TemplateSpecializationType *T, QualType ObjectType); + + QualType + TransformTemplateSpecializationType(TypeLocBuilder &TLB, + TemplateSpecializationTypeLoc TL, + QualType ObjectType); OwningStmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr); #define STMT(Node, Parent) \ OwningStmtResult Transform##Node(Node *S); #define EXPR(Node, Parent) \ - OwningExprResult Transform##Node(Node *E); + OwningExprResult Transform##Node(Node *E, bool isAddressOfOperand); #define ABSTRACT_EXPR(Node, Parent) #include "clang/AST/StmtNodes.def" @@ -314,35 +334,37 @@ public: /// /// By default, performs semantic analysis when building the pointer type. /// Subclasses may override this routine to provide different behavior. - QualType RebuildPointerType(QualType PointeeType); + QualType RebuildPointerType(QualType PointeeType, SourceLocation Sigil); /// \brief Build a new block pointer type given its pointee type. /// /// By default, performs semantic analysis when building the block pointer /// type. Subclasses may override this routine to provide different behavior. - QualType RebuildBlockPointerType(QualType PointeeType); + QualType RebuildBlockPointerType(QualType PointeeType, SourceLocation Sigil); - /// \brief Build a new lvalue reference type given the type it references. + /// \brief Build a new reference type given the type it references. /// - /// By default, performs semantic analysis when building the lvalue reference - /// type. Subclasses may override this routine to provide different behavior. - QualType RebuildLValueReferenceType(QualType ReferentType); - - /// \brief Build a new rvalue reference type given the type it references. + /// By default, performs semantic analysis when building the + /// reference type. Subclasses may override this routine to provide + /// different behavior. /// - /// By default, performs semantic analysis when building the rvalue reference - /// type. Subclasses may override this routine to provide different behavior. - QualType RebuildRValueReferenceType(QualType ReferentType); + /// \param LValue whether the type was written with an lvalue sigil + /// or an rvalue sigil. + QualType RebuildReferenceType(QualType ReferentType, + bool LValue, + SourceLocation Sigil); /// \brief Build a new member pointer type given the pointee type and the /// class type it refers into. /// /// By default, performs semantic analysis when building the member pointer /// type. Subclasses may override this routine to provide different behavior. - QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType); + QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType, + SourceLocation Sigil); /// \brief Build a new Objective C object pointer type. - QualType RebuildObjCObjectPointerType(QualType PointeeType); + QualType RebuildObjCObjectPointerType(QualType PointeeType, + SourceLocation Sigil); /// \brief Build a new array type given the element type, size /// modifier, size of the array (if known), size expression, and index type @@ -366,7 +388,8 @@ public: QualType RebuildConstantArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, const llvm::APInt &Size, - unsigned IndexTypeQuals); + unsigned IndexTypeQuals, + SourceRange BracketsRange); /// \brief Build a new incomplete array type given the element type, size /// modifier, and index type qualifiers. @@ -375,7 +398,8 @@ public: /// Subclasses may override this routine to provide different behavior. QualType RebuildIncompleteArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, - unsigned IndexTypeQuals); + unsigned IndexTypeQuals, + SourceRange BracketsRange); /// \brief Build a new variable-length array type given the element type, /// size modifier, size expression, and index type qualifiers. @@ -478,8 +502,11 @@ public: /// specialization type. Subclasses may override this routine to provide /// different behavior. QualType RebuildTemplateSpecializationType(TemplateName Template, - const TemplateArgument *Args, - unsigned NumArgs); + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + const TemplateArgumentLoc *Args, + unsigned NumArgs, + SourceLocation RAngleLoc); /// \brief Build a new qualified name type. /// @@ -509,9 +536,9 @@ public: /// (or qualified name type). Subclasses may override this routine to provide /// different behavior. QualType RebuildTypenameType(NestedNameSpecifier *NNS, - const IdentifierInfo *Id) { - return SemaRef.CheckTypenameType(NNS, *Id, - SourceRange(getDerived().getBaseLocation())); + const IdentifierInfo *Id, + SourceRange SR) { + return SemaRef.CheckTypenameType(NNS, *Id, SR); } /// \brief Build a new nested-name-specifier given the prefix and an @@ -578,7 +605,17 @@ public: const IdentifierInfo &II, QualType ObjectType); - + /// \brief Build a new template name given a nested name specifier and the + /// overloaded operator name that is referred to as a template. + /// + /// By default, performs semantic analysis to determine whether the name can + /// be resolved to a specific template, then builds the appropriate kind of + /// template name. Subclasses may override this routine to provide different + /// behavior. + TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier, + OverloadedOperatorKind Operator, + QualType ObjectType); + /// \brief Build a new compound statement. /// /// By default, performs semantic analysis to build the new statement. @@ -781,11 +818,17 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildDeclRefExpr(NamedDecl *ND, SourceLocation Loc) { + OwningExprResult RebuildDeclRefExpr(NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + NamedDecl *ND, SourceLocation Loc, + bool isAddressOfOperand) { + CXXScopeSpec SS; + SS.setScopeRep(Qualifier); + SS.setRange(QualifierRange); return getSema().BuildDeclarationNameExpr(Loc, ND, /*FIXME:*/false, - /*SS=*/0, - /*FIXME:*/false); + &SS, + isAddressOfOperand); } /// \brief Build a new expression in parentheses. @@ -841,9 +884,10 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildSizeOfAlignOf(QualType T, SourceLocation OpLoc, + OwningExprResult RebuildSizeOfAlignOf(DeclaratorInfo *DInfo, + SourceLocation OpLoc, bool isSizeOf, SourceRange R) { - return getSema().CreateSizeOfAlignOfExpr(T, OpLoc, isSizeOf, R); + return getSema().CreateSizeOfAlignOfExpr(DInfo, OpLoc, isSizeOf, R); } /// \brief Build a new sizeof or alignof expression with an expression @@ -1002,9 +1046,9 @@ public: SourceLocation OpLoc, SourceLocation AccessorLoc, IdentifierInfo &Accessor) { - return getSema().ActOnMemberReferenceExpr(/*Scope=*/0, move(Base), OpLoc, + return getSema().BuildMemberReferenceExpr(/*Scope=*/0, move(Base), OpLoc, tok::period, AccessorLoc, - Accessor, + DeclarationName(&Accessor), /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0)); } @@ -1392,26 +1436,6 @@ public: T.getAsOpaquePtr(), RParenLoc); } - /// \brief Build a new qualified declaration reference expression. - /// - /// By default, performs semantic analysis to build the new expression. - /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildQualifiedDeclRefExpr(NestedNameSpecifier *NNS, - SourceRange QualifierRange, - NamedDecl *ND, - SourceLocation Location, - bool IsAddressOfOperand) { - CXXScopeSpec SS; - SS.setRange(QualifierRange); - SS.setScopeRep(NNS); - return getSema().ActOnDeclarationNameExpr(/*Scope=*/0, - Location, - ND->getDeclName(), - /*Trailing lparen=*/false, - &SS, - IsAddressOfOperand); - } - /// \brief Build a new (previously unresolved) declaration reference /// expression. /// @@ -1442,7 +1466,7 @@ public: TemplateName Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, - TemplateArgument *TemplateArgs, + TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc) { return getSema().BuildTemplateIdExpr(Qualifier, QualifierRange, @@ -1545,7 +1569,7 @@ public: SourceLocation TemplateNameLoc, NamedDecl *FirstQualifierInScope, SourceLocation LAngleLoc, - const TemplateArgument *TemplateArgs, + const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc) { OwningExprResult Base = move(BaseE); @@ -1556,16 +1580,21 @@ public: SS.setScopeRep(Qualifier); // FIXME: We're going to end up looking up the template based on its name, - // twice! Also, duplicates part of Sema::ActOnMemberTemplateIdReferenceExpr. + // twice! Also, duplicates part of Sema::BuildMemberAccessExpr. DeclarationName Name; if (TemplateDecl *ActualTemplate = Template.getAsTemplateDecl()) Name = ActualTemplate->getDeclName(); else if (OverloadedFunctionDecl *Ovl = Template.getAsOverloadedFunctionDecl()) Name = Ovl->getDeclName(); - else - Name = Template.getAsDependentTemplateName()->getName(); - + else { + DependentTemplateName *DTN = Template.getAsDependentTemplateName(); + if (DTN->isIdentifier()) + Name = DTN->getIdentifier(); + else + Name = SemaRef.Context.DeclarationNames.getCXXOperatorName( + DTN->getOperator()); + } return SemaRef.BuildMemberReferenceExpr(/*Scope=*/0, move(Base), OperatorLoc, OpKind, TemplateNameLoc, Name, true, @@ -1683,7 +1712,8 @@ Sema::OwningExprResult TreeTransform<Derived>::TransformExpr(Expr *E, case Stmt::NoStmtClass: break; #define STMT(Node, Parent) case Stmt::Node##Class: break; #define EXPR(Node, Parent) \ - case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(E)); + case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(E), \ + isAddressOfOperand); #include "clang/AST/StmtNodes.def" } @@ -1746,6 +1776,7 @@ TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS, case NestedNameSpecifier::TypeSpecWithTemplate: case NestedNameSpecifier::TypeSpec: { + TemporaryBase Rebase(*this, Range.getBegin(), DeclarationName()); QualType T = getDerived().TransformType(QualType(NNS->getAsType(), 0)); if (T.isNull()) return 0; @@ -1860,7 +1891,12 @@ TreeTransform<Derived>::TransformTemplateName(TemplateName Name, ObjectType.isNull()) return Name; - return getDerived().RebuildTemplateName(NNS, *DTN->getName(), ObjectType); + if (DTN->isIdentifier()) + return getDerived().RebuildTemplateName(NNS, *DTN->getIdentifier(), + ObjectType); + + return getDerived().RebuildTemplateName(NNS, DTN->getOperator(), + ObjectType); } if (TemplateDecl *Template = Name.getAsTemplateDecl()) { @@ -1891,25 +1927,80 @@ TreeTransform<Derived>::TransformTemplateName(TemplateName Name, } template<typename Derived> -TemplateArgument -TreeTransform<Derived>::TransformTemplateArgument(const TemplateArgument &Arg) { +void TreeTransform<Derived>::InventTemplateArgumentLoc( + const TemplateArgument &Arg, + TemplateArgumentLoc &Output) { + SourceLocation Loc = getDerived().getBaseLocation(); + switch (Arg.getKind()) { + case TemplateArgument::Null: + llvm::llvm_unreachable("null template argument in TreeTransform"); + break; + + case TemplateArgument::Type: + Output = TemplateArgumentLoc(Arg, + SemaRef.Context.getTrivialDeclaratorInfo(Arg.getAsType(), Loc)); + + break; + + case TemplateArgument::Expression: + Output = TemplateArgumentLoc(Arg, Arg.getAsExpr()); + break; + + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + case TemplateArgument::Pack: + Output = TemplateArgumentLoc(Arg, TemplateArgumentLocInfo()); + break; + } +} + +template<typename Derived> +bool TreeTransform<Derived>::TransformTemplateArgument( + const TemplateArgumentLoc &Input, + TemplateArgumentLoc &Output) { + const TemplateArgument &Arg = Input.getArgument(); switch (Arg.getKind()) { case TemplateArgument::Null: case TemplateArgument::Integral: - return Arg; + Output = Input; + return false; case TemplateArgument::Type: { - QualType T = getDerived().TransformType(Arg.getAsType()); - if (T.isNull()) - return TemplateArgument(); - return TemplateArgument(Arg.getLocation(), T); + DeclaratorInfo *DI = Input.getSourceDeclaratorInfo(); + if (DI == NULL) + DI = InventDeclaratorInfo(Input.getArgument().getAsType()); + + DI = getDerived().TransformType(DI); + if (!DI) return true; + + Output = TemplateArgumentLoc(TemplateArgument(DI->getType()), DI); + return false; } case TemplateArgument::Declaration: { + // FIXME: we should never have to transform one of these. + DeclarationName Name; + if (NamedDecl *ND = dyn_cast<NamedDecl>(Arg.getAsDecl())) + Name = ND->getDeclName(); + TemporaryBase Rebase(*this, SourceLocation(), Name); Decl *D = getDerived().TransformDecl(Arg.getAsDecl()); - if (!D) - return TemplateArgument(); - return TemplateArgument(Arg.getLocation(), D); + if (!D) return true; + + Expr *SourceExpr = Input.getSourceDeclExpression(); + if (SourceExpr) { + EnterExpressionEvaluationContext Unevaluated(getSema(), + Action::Unevaluated); + Sema::OwningExprResult E = getDerived().TransformExpr(SourceExpr); + if (E.isInvalid()) + SourceExpr = NULL; + else { + SourceExpr = E.takeAs<Expr>(); + SourceExpr->Retain(); + } + } + + Output = TemplateArgumentLoc(TemplateArgument(D), SourceExpr); + return false; } case TemplateArgument::Expression: { @@ -1917,10 +2008,17 @@ TreeTransform<Derived>::TransformTemplateArgument(const TemplateArgument &Arg) { EnterExpressionEvaluationContext Unevaluated(getSema(), Action::Unevaluated); - Sema::OwningExprResult E = getDerived().TransformExpr(Arg.getAsExpr()); - if (E.isInvalid()) - return TemplateArgument(); - return TemplateArgument(E.takeAs<Expr>()); + Expr *InputExpr = Input.getSourceExpression(); + if (!InputExpr) InputExpr = Input.getArgument().getAsExpr(); + + Sema::OwningExprResult E + = getDerived().TransformExpr(InputExpr); + if (E.isInvalid()) return true; + + Expr *ETaken = E.takeAs<Expr>(); + ETaken->Retain(); + Output = TemplateArgumentLoc(TemplateArgument(ETaken), ETaken); + return false; } case TemplateArgument::Pack: { @@ -1929,21 +2027,28 @@ TreeTransform<Derived>::TransformTemplateArgument(const TemplateArgument &Arg) { for (TemplateArgument::pack_iterator A = Arg.pack_begin(), AEnd = Arg.pack_end(); A != AEnd; ++A) { - TemplateArgument TA = getDerived().TransformTemplateArgument(*A); - if (TA.isNull()) - return TA; - TransformedArgs.push_back(TA); + // FIXME: preserve source information here when we start + // caring about parameter packs. + + TemplateArgumentLoc InputArg; + TemplateArgumentLoc OutputArg; + getDerived().InventTemplateArgumentLoc(*A, InputArg); + if (getDerived().TransformTemplateArgument(InputArg, OutputArg)) + return true; + + TransformedArgs.push_back(OutputArg.getArgument()); } TemplateArgument Result; Result.setArgumentPack(TransformedArgs.data(), TransformedArgs.size(), true); - return Result; + Output = TemplateArgumentLoc(Result, Input.getLocInfo()); + return false; } } // Work around bogus GCC warning - return TemplateArgument(); + return true; } //===----------------------------------------------------------------------===// @@ -2048,7 +2153,8 @@ QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) { QualType Result = TL.getType(); \ if (getDerived().AlwaysRebuild() || \ PointeeType != TL.getPointeeLoc().getType()) { \ - Result = getDerived().Rebuild##TypeClass(PointeeType); \ + Result = getDerived().Rebuild##TypeClass(PointeeType, \ + TL.getSigilLoc()); \ if (Result.isNull()) \ return QualType(); \ } \ @@ -2059,35 +2165,6 @@ QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) { return Result; \ } while(0) -// Reference collapsing forces us to transform reference types -// differently from the other pointer-like types. -#define TransformReferenceType(TypeClass) do { \ - QualType PointeeType \ - = getDerived().TransformType(TLB, TL.getPointeeLoc()); \ - if (PointeeType.isNull()) \ - return QualType(); \ - \ - QualType Result = TL.getType(); \ - if (getDerived().AlwaysRebuild() || \ - PointeeType != TL.getPointeeLoc().getType()) { \ - Result = getDerived().Rebuild##TypeClass(PointeeType); \ - if (Result.isNull()) \ - return QualType(); \ - } \ - \ - /* Workaround: rebuild doesn't always change the type */ \ - /* FIXME: avoid losing this location information. */ \ - if (Result == PointeeType) \ - return Result; \ - ReferenceTypeLoc NewTL; \ - if (isa<LValueReferenceType>(Result)) \ - NewTL = TLB.push<LValueReferenceTypeLoc>(Result); \ - else \ - NewTL = TLB.push<RValueReferenceTypeLoc>(Result); \ - NewTL.setSigilLoc(TL.getSigilLoc()); \ - return Result; \ -} while (0) - template<typename Derived> QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB, BuiltinTypeLoc T) { @@ -2121,18 +2198,54 @@ TreeTransform<Derived>::TransformBlockPointerType(TypeLocBuilder &TLB, TransformPointerLikeType(BlockPointerType); } +/// Transforms a reference type. Note that somewhat paradoxically we +/// don't care whether the type itself is an l-value type or an r-value +/// type; we only care if the type was *written* as an l-value type +/// or an r-value type. +template<typename Derived> +QualType +TreeTransform<Derived>::TransformReferenceType(TypeLocBuilder &TLB, + ReferenceTypeLoc TL) { + const ReferenceType *T = TL.getTypePtr(); + + // Note that this works with the pointee-as-written. + QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc()); + if (PointeeType.isNull()) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + PointeeType != T->getPointeeTypeAsWritten()) { + Result = getDerived().RebuildReferenceType(PointeeType, + T->isSpelledAsLValue(), + TL.getSigilLoc()); + if (Result.isNull()) + return QualType(); + } + + // r-value references can be rebuilt as l-value references. + ReferenceTypeLoc NewTL; + if (isa<LValueReferenceType>(Result)) + NewTL = TLB.push<LValueReferenceTypeLoc>(Result); + else + NewTL = TLB.push<RValueReferenceTypeLoc>(Result); + NewTL.setSigilLoc(TL.getSigilLoc()); + + return Result; +} + template<typename Derived> QualType TreeTransform<Derived>::TransformLValueReferenceType(TypeLocBuilder &TLB, LValueReferenceTypeLoc TL) { - TransformReferenceType(LValueReferenceType); + return TransformReferenceType(TLB, TL); } template<typename Derived> QualType TreeTransform<Derived>::TransformRValueReferenceType(TypeLocBuilder &TLB, RValueReferenceTypeLoc TL) { - TransformReferenceType(RValueReferenceType); + return TransformReferenceType(TLB, TL); } template<typename Derived> @@ -2155,7 +2268,8 @@ TreeTransform<Derived>::TransformMemberPointerType(TypeLocBuilder &TLB, if (getDerived().AlwaysRebuild() || PointeeType != T->getPointeeType() || ClassType != QualType(T->getClass(), 0)) { - Result = getDerived().RebuildMemberPointerType(PointeeType, ClassType); + Result = getDerived().RebuildMemberPointerType(PointeeType, ClassType, + TL.getStarLoc()); if (Result.isNull()) return QualType(); } @@ -2181,7 +2295,8 @@ TreeTransform<Derived>::TransformConstantArrayType(TypeLocBuilder &TLB, Result = getDerived().RebuildConstantArrayType(ElementType, T->getSizeModifier(), T->getSize(), - T->getIndexTypeCVRQualifiers()); + T->getIndexTypeCVRQualifiers(), + TL.getBracketsRange()); if (Result.isNull()) return QualType(); } @@ -2214,7 +2329,8 @@ QualType TreeTransform<Derived>::TransformIncompleteArrayType( ElementType != T->getElementType()) { Result = getDerived().RebuildIncompleteArrayType(ElementType, T->getSizeModifier(), - T->getIndexTypeCVRQualifiers()); + T->getIndexTypeCVRQualifiers(), + TL.getBracketsRange()); if (Result.isNull()) return QualType(); } @@ -2254,7 +2370,7 @@ TreeTransform<Derived>::TransformVariableArrayType(TypeLocBuilder &TLB, T->getSizeModifier(), move(SizeResult), T->getIndexTypeCVRQualifiers(), - T->getBracketsRange()); + TL.getBracketsRange()); if (Result.isNull()) return QualType(); } @@ -2295,7 +2411,7 @@ TreeTransform<Derived>::TransformDependentSizedArrayType(TypeLocBuilder &TLB, T->getSizeModifier(), move(SizeResult), T->getIndexTypeCVRQualifiers(), - T->getBracketsRange()); + TL.getBracketsRange()); if (Result.isNull()) return QualType(); } @@ -2331,7 +2447,8 @@ QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType( QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || - (ElementType != T->getElementType() && Size.get() != T->getSizeExpr())) { + ElementType != T->getElementType() || + Size.get() != T->getSizeExpr()) { Result = getDerived().RebuildDependentSizedExtVectorType(ElementType, move(Size), T->getAttributeLoc()); @@ -2687,46 +2804,76 @@ inline QualType TreeTransform<Derived>::TransformTemplateSpecializationType( TypeLocBuilder &TLB, TemplateSpecializationTypeLoc TL) { - // TODO: figure out how make this work with an ObjectType. - QualType Result - = TransformTemplateSpecializationType(TL.getTypePtr(), QualType()); - if (Result.isNull()) - return QualType(); + return TransformTemplateSpecializationType(TLB, TL, QualType()); +} - TemplateSpecializationTypeLoc NewTL - = TLB.push<TemplateSpecializationTypeLoc>(Result); - NewTL.setNameLoc(TL.getNameLoc()); +template<typename Derived> +QualType TreeTransform<Derived>::TransformTemplateSpecializationType( + const TemplateSpecializationType *TST, + QualType ObjectType) { + // FIXME: this entire method is a temporary workaround; callers + // should be rewritten to provide real type locs. - return Result; + // Fake up a TemplateSpecializationTypeLoc. + TypeLocBuilder TLB; + TemplateSpecializationTypeLoc TL + = TLB.push<TemplateSpecializationTypeLoc>(QualType(TST, 0)); + + SourceLocation BaseLoc = getDerived().getBaseLocation(); + + TL.setTemplateNameLoc(BaseLoc); + TL.setLAngleLoc(BaseLoc); + TL.setRAngleLoc(BaseLoc); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { + const TemplateArgument &TA = TST->getArg(i); + TemplateArgumentLoc TAL; + getDerived().InventTemplateArgumentLoc(TA, TAL); + TL.setArgLocInfo(i, TAL.getLocInfo()); + } + + TypeLocBuilder IgnoredTLB; + return TransformTemplateSpecializationType(IgnoredTLB, TL, ObjectType); } template<typename Derived> QualType TreeTransform<Derived>::TransformTemplateSpecializationType( - const TemplateSpecializationType *T, - QualType ObjectType) { + TypeLocBuilder &TLB, + TemplateSpecializationTypeLoc TL, + QualType ObjectType) { + const TemplateSpecializationType *T = TL.getTypePtr(); + TemplateName Template = getDerived().TransformTemplateName(T->getTemplateName(), ObjectType); if (Template.isNull()) return QualType(); - llvm::SmallVector<TemplateArgument, 4> NewTemplateArgs; - NewTemplateArgs.reserve(T->getNumArgs()); - for (TemplateSpecializationType::iterator Arg = T->begin(), ArgEnd = T->end(); - Arg != ArgEnd; ++Arg) { - TemplateArgument NewArg = getDerived().TransformTemplateArgument(*Arg); - if (NewArg.isNull()) + llvm::SmallVector<TemplateArgumentLoc, 4> NewTemplateArgs(T->getNumArgs()); + for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i) + if (getDerived().TransformTemplateArgument(TL.getArgLoc(i), + NewTemplateArgs[i])) return QualType(); - NewTemplateArgs.push_back(NewArg); - } + // FIXME: maybe don't rebuild if all the template arguments are the same. - // FIXME: early abort if all of the template arguments and such are the - // same. + QualType Result = + getDerived().RebuildTemplateSpecializationType(Template, + TL.getTemplateNameLoc(), + TL.getLAngleLoc(), + NewTemplateArgs.data(), + NewTemplateArgs.size(), + TL.getRAngleLoc()); - // FIXME: We're missing the locations of the template name, '<', and '>'. - return getDerived().RebuildTemplateSpecializationType(Template, - NewTemplateArgs.data(), - NewTemplateArgs.size()); + if (!Result.isNull()) { + TemplateSpecializationTypeLoc NewTL + = TLB.push<TemplateSpecializationTypeLoc>(Result); + NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); + NewTL.setLAngleLoc(TL.getLAngleLoc()); + NewTL.setRAngleLoc(TL.getRAngleLoc()); + for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i) + NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo()); + } + + return Result; } template<typename Derived> @@ -2763,9 +2910,12 @@ template<typename Derived> QualType TreeTransform<Derived>::TransformTypenameType(TypeLocBuilder &TLB, TypenameTypeLoc TL) { TypenameType *T = TL.getTypePtr(); + + /* FIXME: preserve source information better than this */ + SourceRange SR(TL.getNameLoc()); + NestedNameSpecifier *NNS - = getDerived().TransformNestedNameSpecifier(T->getQualifier(), - SourceRange(/*FIXME:*/getDerived().getBaseLocation())); + = getDerived().TransformNestedNameSpecifier(T->getQualifier(), SR); if (!NNS) return QualType(); @@ -2784,7 +2934,7 @@ QualType TreeTransform<Derived>::TransformTypenameType(TypeLocBuilder &TLB, Result = getDerived().RebuildTypenameType(NNS, NewTemplateId); } else { - Result = getDerived().RebuildTypenameType(NNS, T->getIdentifier()); + Result = getDerived().RebuildTypenameType(NNS, T->getIdentifier(), SR); } if (Result.isNull()) return QualType(); @@ -3268,57 +3418,88 @@ TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) { //===----------------------------------------------------------------------===// template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformPredefinedExpr(PredefinedExpr *E) { +TreeTransform<Derived>::TransformPredefinedExpr(PredefinedExpr *E, + bool isAddressOfOperand) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) { +TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E, + bool isAddressOfOperand) { + NestedNameSpecifier *Qualifier = 0; + if (E->getQualifier()) { + Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), + E->getQualifierRange()); + if (!Qualifier) + return SemaRef.ExprError(); + } + NamedDecl *ND = dyn_cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getDecl())); if (!ND) return SemaRef.ExprError(); - if (!getDerived().AlwaysRebuild() && ND == E->getDecl()) + if (!getDerived().AlwaysRebuild() && + Qualifier == E->getQualifier() && + ND == E->getDecl() && + !E->hasExplicitTemplateArgumentList()) return SemaRef.Owned(E->Retain()); - return getDerived().RebuildDeclRefExpr(ND, E->getLocation()); + // FIXME: We're losing the explicit template arguments in this transformation. + + llvm::SmallVector<TemplateArgumentLoc, 4> TransArgs(E->getNumTemplateArgs()); + for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { + if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], + TransArgs[I])) + return SemaRef.ExprError(); + } + + // FIXME: Pass the qualifier/qualifier range along. + return getDerived().RebuildDeclRefExpr(Qualifier, E->getQualifierRange(), + ND, E->getLocation(), + isAddressOfOperand); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformIntegerLiteral(IntegerLiteral *E) { +TreeTransform<Derived>::TransformIntegerLiteral(IntegerLiteral *E, + bool isAddressOfOperand) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformFloatingLiteral(FloatingLiteral *E) { +TreeTransform<Derived>::TransformFloatingLiteral(FloatingLiteral *E, + bool isAddressOfOperand) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformImaginaryLiteral(ImaginaryLiteral *E) { +TreeTransform<Derived>::TransformImaginaryLiteral(ImaginaryLiteral *E, + bool isAddressOfOperand) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformStringLiteral(StringLiteral *E) { +TreeTransform<Derived>::TransformStringLiteral(StringLiteral *E, + bool isAddressOfOperand) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E) { +TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E, + bool isAddressOfOperand) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformParenExpr(ParenExpr *E) { +TreeTransform<Derived>::TransformParenExpr(ParenExpr *E, + bool isAddressOfOperand) { OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -3332,8 +3513,10 @@ TreeTransform<Derived>::TransformParenExpr(ParenExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E) { - OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); +TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E, + bool isAddressOfOperand) { + OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr(), + E->getOpcode() == UnaryOperator::AddrOf); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -3347,16 +3530,19 @@ TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { +TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, + bool isAddressOfOperand) { if (E->isArgumentType()) { - QualType T = getDerived().TransformType(E->getArgumentType()); - if (T.isNull()) + DeclaratorInfo *OldT = E->getArgumentTypeInfo(); + + DeclaratorInfo *NewT = getDerived().TransformType(OldT); + if (!NewT) return SemaRef.ExprError(); - if (!getDerived().AlwaysRebuild() && T == E->getArgumentType()) + if (!getDerived().AlwaysRebuild() && OldT == NewT) return SemaRef.Owned(E->Retain()); - return getDerived().RebuildSizeOfAlignOf(T, E->getOperatorLoc(), + return getDerived().RebuildSizeOfAlignOf(NewT, E->getOperatorLoc(), E->isSizeOf(), E->getSourceRange()); } @@ -3383,7 +3569,8 @@ TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformArraySubscriptExpr(ArraySubscriptExpr *E) { +TreeTransform<Derived>::TransformArraySubscriptExpr(ArraySubscriptExpr *E, + bool isAddressOfOperand) { OwningExprResult LHS = getDerived().TransformExpr(E->getLHS()); if (LHS.isInvalid()) return SemaRef.ExprError(); @@ -3406,7 +3593,8 @@ TreeTransform<Derived>::TransformArraySubscriptExpr(ArraySubscriptExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCallExpr(CallExpr *E) { +TreeTransform<Derived>::TransformCallExpr(CallExpr *E, + bool isAddressOfOperand) { // Transform the callee. OwningExprResult Callee = getDerived().TransformExpr(E->getCallee()); if (Callee.isInvalid()) @@ -3445,7 +3633,8 @@ TreeTransform<Derived>::TransformCallExpr(CallExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) { +TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E, + bool isAddressOfOperand) { OwningExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) return SemaRef.ExprError(); @@ -3484,14 +3673,16 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCastExpr(CastExpr *E) { +TreeTransform<Derived>::TransformCastExpr(CastExpr *E, + bool isAddressOfOperand) { assert(false && "Cannot transform abstract class"); return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) { +TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E, + bool isAddressOfOperand) { OwningExprResult LHS = getDerived().TransformExpr(E->getLHS()); if (LHS.isInvalid()) return SemaRef.ExprError(); @@ -3512,13 +3703,15 @@ TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCompoundAssignOperator( - CompoundAssignOperator *E) { - return getDerived().TransformBinaryOperator(E); + CompoundAssignOperator *E, + bool isAddressOfOperand) { + return getDerived().TransformBinaryOperator(E, isAddressOfOperand); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformConditionalOperator(ConditionalOperator *E) { +TreeTransform<Derived>::TransformConditionalOperator(ConditionalOperator *E, + bool isAddressOfOperand) { OwningExprResult Cond = getDerived().TransformExpr(E->getCond()); if (Cond.isInvalid()) return SemaRef.ExprError(); @@ -3546,7 +3739,12 @@ TreeTransform<Derived>::TransformConditionalOperator(ConditionalOperator *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformImplicitCastExpr(ImplicitCastExpr *E) { +TreeTransform<Derived>::TransformImplicitCastExpr(ImplicitCastExpr *E, + bool isAddressOfOperand) { + TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName()); + + // FIXME: Will we ever have type information here? It seems like we won't, + // so do we even need to transform the type? QualType T = getDerived().TransformType(E->getType()); if (T.isNull()) return SemaRef.ExprError(); @@ -3567,14 +3765,16 @@ TreeTransform<Derived>::TransformImplicitCastExpr(ImplicitCastExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformExplicitCastExpr(ExplicitCastExpr *E) { +TreeTransform<Derived>::TransformExplicitCastExpr(ExplicitCastExpr *E, + bool isAddressOfOperand) { assert(false && "Cannot transform abstract class"); return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) { +TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E, + bool isAddressOfOperand) { QualType T; { // FIXME: Source location isn't quite accurate. @@ -3603,7 +3803,8 @@ TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCompoundLiteralExpr(CompoundLiteralExpr *E) { +TreeTransform<Derived>::TransformCompoundLiteralExpr(CompoundLiteralExpr *E, + bool isAddressOfOperand) { QualType T; { // FIXME: Source location isn't quite accurate. @@ -3632,7 +3833,8 @@ TreeTransform<Derived>::TransformCompoundLiteralExpr(CompoundLiteralExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformExtVectorElementExpr(ExtVectorElementExpr *E) { +TreeTransform<Derived>::TransformExtVectorElementExpr(ExtVectorElementExpr *E, + bool isAddressOfOperand) { OwningExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) return SemaRef.ExprError(); @@ -3651,7 +3853,8 @@ TreeTransform<Derived>::TransformExtVectorElementExpr(ExtVectorElementExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E) { +TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E, + bool isAddressOfOperand) { bool InitChanged = false; ASTOwningVector<&ActionBase::DeleteExpr, 4> Inits(SemaRef); @@ -3673,7 +3876,8 @@ TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) { +TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E, + bool isAddressOfOperand) { Designation Desig; // transform the initializer value @@ -3742,7 +3946,12 @@ TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformImplicitValueInitExpr( - ImplicitValueInitExpr *E) { + ImplicitValueInitExpr *E, + bool isAddressOfOperand) { + TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName()); + + // FIXME: Will we ever have proper type location here? Will we actually + // need to transform the type? QualType T = getDerived().TransformType(E->getType()); if (T.isNull()) return SemaRef.ExprError(); @@ -3756,7 +3965,8 @@ TreeTransform<Derived>::TransformImplicitValueInitExpr( template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformVAArgExpr(VAArgExpr *E) { +TreeTransform<Derived>::TransformVAArgExpr(VAArgExpr *E, + bool isAddressOfOperand) { // FIXME: Do we want the type as written? QualType T; @@ -3783,7 +3993,8 @@ TreeTransform<Derived>::TransformVAArgExpr(VAArgExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformParenListExpr(ParenListExpr *E) { +TreeTransform<Derived>::TransformParenListExpr(ParenListExpr *E, + bool isAddressOfOperand) { bool ArgumentChanged = false; ASTOwningVector<&ActionBase::DeleteExpr, 4> Inits(SemaRef); for (unsigned I = 0, N = E->getNumExprs(); I != N; ++I) { @@ -3807,13 +4018,16 @@ TreeTransform<Derived>::TransformParenListExpr(ParenListExpr *E) { /// the corresponding label statement by semantic analysis. template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformAddrLabelExpr(AddrLabelExpr *E) { +TreeTransform<Derived>::TransformAddrLabelExpr(AddrLabelExpr *E, + bool isAddressOfOperand) { return getDerived().RebuildAddrLabelExpr(E->getAmpAmpLoc(), E->getLabelLoc(), E->getLabel()); } template<typename Derived> -Sema::OwningExprResult TreeTransform<Derived>::TransformStmtExpr(StmtExpr *E) { +Sema::OwningExprResult +TreeTransform<Derived>::TransformStmtExpr(StmtExpr *E, + bool isAddressOfOperand) { OwningStmtResult SubStmt = getDerived().TransformCompoundStmt(E->getSubStmt(), true); if (SubStmt.isInvalid()) @@ -3830,7 +4044,8 @@ Sema::OwningExprResult TreeTransform<Derived>::TransformStmtExpr(StmtExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformTypesCompatibleExpr(TypesCompatibleExpr *E) { +TreeTransform<Derived>::TransformTypesCompatibleExpr(TypesCompatibleExpr *E, + bool isAddressOfOperand) { QualType T1, T2; { // FIXME: Source location isn't quite accurate. @@ -3856,7 +4071,8 @@ TreeTransform<Derived>::TransformTypesCompatibleExpr(TypesCompatibleExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformChooseExpr(ChooseExpr *E) { +TreeTransform<Derived>::TransformChooseExpr(ChooseExpr *E, + bool isAddressOfOperand) { OwningExprResult Cond = getDerived().TransformExpr(E->getCond()); if (Cond.isInvalid()) return SemaRef.ExprError(); @@ -3882,18 +4098,22 @@ TreeTransform<Derived>::TransformChooseExpr(ChooseExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformGNUNullExpr(GNUNullExpr *E) { +TreeTransform<Derived>::TransformGNUNullExpr(GNUNullExpr *E, + bool isAddressOfOperand) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) { +TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E, + bool isAddressOfOperand) { OwningExprResult Callee = getDerived().TransformExpr(E->getCallee()); if (Callee.isInvalid()) return SemaRef.ExprError(); - OwningExprResult First = getDerived().TransformExpr(E->getArg(0)); + OwningExprResult First + = getDerived().TransformExpr(E->getArg(0), + E->getNumArgs() == 1 && E->getOperator() == OO_Amp); if (First.isInvalid()) return SemaRef.ExprError(); @@ -3919,13 +4139,15 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXMemberCallExpr(CXXMemberCallExpr *E) { - return getDerived().TransformCallExpr(E); +TreeTransform<Derived>::TransformCXXMemberCallExpr(CXXMemberCallExpr *E, + bool isAddressOfOperand) { + return getDerived().TransformCallExpr(E, isAddressOfOperand); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { +TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E, + bool isAddressOfOperand) { QualType ExplicitTy; { // FIXME: Source location isn't quite accurate. @@ -3966,33 +4188,38 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXStaticCastExpr(CXXStaticCastExpr *E) { - return getDerived().TransformCXXNamedCastExpr(E); +TreeTransform<Derived>::TransformCXXStaticCastExpr(CXXStaticCastExpr *E, + bool isAddressOfOperand) { + return getDerived().TransformCXXNamedCastExpr(E, isAddressOfOperand); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXDynamicCastExpr(CXXDynamicCastExpr *E) { - return getDerived().TransformCXXNamedCastExpr(E); +TreeTransform<Derived>::TransformCXXDynamicCastExpr(CXXDynamicCastExpr *E, + bool isAddressOfOperand) { + return getDerived().TransformCXXNamedCastExpr(E, isAddressOfOperand); } template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXReinterpretCastExpr( - CXXReinterpretCastExpr *E) { - return getDerived().TransformCXXNamedCastExpr(E); + CXXReinterpretCastExpr *E, + bool isAddressOfOperand) { + return getDerived().TransformCXXNamedCastExpr(E, isAddressOfOperand); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXConstCastExpr(CXXConstCastExpr *E) { - return getDerived().TransformCXXNamedCastExpr(E); +TreeTransform<Derived>::TransformCXXConstCastExpr(CXXConstCastExpr *E, + bool isAddressOfOperand) { + return getDerived().TransformCXXNamedCastExpr(E, isAddressOfOperand); } template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXFunctionalCastExpr( - CXXFunctionalCastExpr *E) { + CXXFunctionalCastExpr *E, + bool isAddressOfOperand) { QualType ExplicitTy; { TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); @@ -4022,7 +4249,8 @@ TreeTransform<Derived>::TransformCXXFunctionalCastExpr( template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) { +TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E, + bool isAddressOfOperand) { if (E->isTypeOperand()) { TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName()); @@ -4062,20 +4290,23 @@ TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { +TreeTransform<Derived>::TransformCXXBoolLiteralExpr(CXXBoolLiteralExpr *E, + bool isAddressOfOperand) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXNullPtrLiteralExpr( - CXXNullPtrLiteralExpr *E) { + CXXNullPtrLiteralExpr *E, + bool isAddressOfOperand) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) { +TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E, + bool isAddressOfOperand) { TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName()); QualType T = getDerived().TransformType(E->getType()); @@ -4091,7 +4322,8 @@ TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXThrowExpr(CXXThrowExpr *E) { +TreeTransform<Derived>::TransformCXXThrowExpr(CXXThrowExpr *E, + bool isAddressOfOperand) { OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -4105,7 +4337,8 @@ TreeTransform<Derived>::TransformCXXThrowExpr(CXXThrowExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) { +TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E, + bool isAddressOfOperand) { ParmVarDecl *Param = cast_or_null<ParmVarDecl>(getDerived().TransformDecl(E->getParam())); if (!Param) @@ -4120,7 +4353,8 @@ TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) { +TreeTransform<Derived>::TransformCXXZeroInitValueExpr(CXXZeroInitValueExpr *E, + bool isAddressOfOperand) { TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); QualType T = getDerived().TransformType(E->getType()); @@ -4139,7 +4373,8 @@ TreeTransform<Derived>::TransformCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXConditionDeclExpr(CXXConditionDeclExpr *E) { +TreeTransform<Derived>::TransformCXXConditionDeclExpr(CXXConditionDeclExpr *E, + bool isAddressOfOperand) { VarDecl *Var = cast_or_null<VarDecl>(getDerived().TransformDefinition(E->getVarDecl())); if (!Var) @@ -4156,7 +4391,8 @@ TreeTransform<Derived>::TransformCXXConditionDeclExpr(CXXConditionDeclExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { +TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E, + bool isAddressOfOperand) { // Transform the type that we're allocating TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName()); QualType AllocType = getDerived().TransformType(E->getAllocatedType()); @@ -4214,7 +4450,8 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E) { +TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E, + bool isAddressOfOperand) { OwningExprResult Operand = getDerived().TransformExpr(E->getArgument()); if (Operand.isInvalid()) return SemaRef.ExprError(); @@ -4232,7 +4469,8 @@ TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXPseudoDestructorExpr( - CXXPseudoDestructorExpr *E) { + CXXPseudoDestructorExpr *E, + bool isAddressOfOperand) { OwningExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) return SemaRef.ExprError(); @@ -4269,14 +4507,16 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr( template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformUnresolvedFunctionNameExpr( - UnresolvedFunctionNameExpr *E) { + UnresolvedFunctionNameExpr *E, + bool isAddressOfOperand) { // There is no transformation we can apply to an unresolved function name. return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { +TreeTransform<Derived>::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E, + bool isAddressOfOperand) { TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName()); QualType T = getDerived().TransformType(E->getQueriedType()); @@ -4300,34 +4540,9 @@ TreeTransform<Derived>::TransformUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformQualifiedDeclRefExpr(QualifiedDeclRefExpr *E) { - NestedNameSpecifier *NNS - = getDerived().TransformNestedNameSpecifier(E->getQualifier(), - E->getQualifierRange()); - if (!NNS) - return SemaRef.ExprError(); - - NamedDecl *ND - = dyn_cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getDecl())); - if (!ND) - return SemaRef.ExprError(); - - if (!getDerived().AlwaysRebuild() && - NNS == E->getQualifier() && - ND == E->getDecl()) - return SemaRef.Owned(E->Retain()); - - return getDerived().RebuildQualifiedDeclRefExpr(NNS, - E->getQualifierRange(), - ND, - E->getLocation(), - /*FIXME:*/false); -} - -template<typename Derived> -Sema::OwningExprResult TreeTransform<Derived>::TransformUnresolvedDeclRefExpr( - UnresolvedDeclRefExpr *E) { + UnresolvedDeclRefExpr *E, + bool isAddressOfOperand) { NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(E->getQualifier(), E->getQualifierRange()); @@ -4348,12 +4563,15 @@ TreeTransform<Derived>::TransformUnresolvedDeclRefExpr( E->getQualifierRange(), Name, E->getLocation(), - /*FIXME:*/false); + isAddressOfOperand); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformTemplateIdRefExpr(TemplateIdRefExpr *E) { +TreeTransform<Derived>::TransformTemplateIdRefExpr(TemplateIdRefExpr *E, + bool isAddressOfOperand) { + TemporaryBase Rebase(*this, E->getTemplateNameLoc(), DeclarationName()); + TemplateName Template = getDerived().TransformTemplateName(E->getTemplateName()); if (Template.isNull()) @@ -4367,14 +4585,11 @@ TreeTransform<Derived>::TransformTemplateIdRefExpr(TemplateIdRefExpr *E) { return SemaRef.ExprError(); } - llvm::SmallVector<TemplateArgument, 4> TransArgs; + llvm::SmallVector<TemplateArgumentLoc, 4> TransArgs(E->getNumTemplateArgs()); for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { - TemplateArgument TransArg - = getDerived().TransformTemplateArgument(E->getTemplateArgs()[I]); - if (TransArg.isNull()) + if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], + TransArgs[I])) return SemaRef.ExprError(); - - TransArgs.push_back(TransArg); } // FIXME: Would like to avoid rebuilding if nothing changed, but we can't @@ -4393,7 +4608,8 @@ TreeTransform<Derived>::TransformTemplateIdRefExpr(TemplateIdRefExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) { +TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E, + bool isAddressOfOperand) { TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName()); QualType T = getDerived().TransformType(E->getType()); @@ -4437,7 +4653,8 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) { /// must be unique. template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { +TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E, + bool isAddressOfOperand) { OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -4455,7 +4672,8 @@ TreeTransform<Derived>::TransformCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXExprWithTemporaries( - CXXExprWithTemporaries *E) { + CXXExprWithTemporaries *E, + bool isAddressOfOperand) { OwningExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) return SemaRef.ExprError(); @@ -4468,7 +4686,8 @@ TreeTransform<Derived>::TransformCXXExprWithTemporaries( template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXTemporaryObjectExpr( - CXXTemporaryObjectExpr *E) { + CXXTemporaryObjectExpr *E, + bool isAddressOfOperand) { TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); QualType T = getDerived().TransformType(E->getType()); if (T.isNull()) @@ -4518,7 +4737,8 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr( template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr( - CXXUnresolvedConstructExpr *E) { + CXXUnresolvedConstructExpr *E, + bool isAddressOfOperand) { TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); QualType T = getDerived().TransformType(E->getTypeAsWritten()); if (T.isNull()) @@ -4557,7 +4777,8 @@ TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr( template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr( - CXXUnresolvedMemberExpr *E) { + CXXUnresolvedMemberExpr *E, + bool isAddressOfOperand) { // Transform the base of the expression. OwningExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) @@ -4617,9 +4838,14 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr( // FIXME: This is an ugly hack, which forces the same template name to // be looked up multiple times. Yuck! - // FIXME: This also won't work for, e.g., x->template operator+<int> - TemplateName OrigTemplateName - = SemaRef.Context.getDependentTemplateName(0, Name.getAsIdentifierInfo()); + TemporaryBase Rebase(*this, E->getMemberLoc(), DeclarationName()); + TemplateName OrigTemplateName; + if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) + OrigTemplateName = SemaRef.Context.getDependentTemplateName(0, II); + else + OrigTemplateName + = SemaRef.Context.getDependentTemplateName(0, + Name.getCXXOverloadedOperator()); TemplateName Template = getDerived().TransformTemplateName(OrigTemplateName, @@ -4627,14 +4853,11 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr( if (Template.isNull()) return SemaRef.ExprError(); - llvm::SmallVector<TemplateArgument, 4> TransArgs; + llvm::SmallVector<TemplateArgumentLoc, 4> TransArgs(E->getNumTemplateArgs()); for (unsigned I = 0, N = E->getNumTemplateArgs(); I != N; ++I) { - TemplateArgument TransArg - = getDerived().TransformTemplateArgument(E->getTemplateArgs()[I]); - if (TransArg.isNull()) + if (getDerived().TransformTemplateArgument(E->getTemplateArgs()[I], + TransArgs[I])) return SemaRef.ExprError(); - - TransArgs.push_back(TransArg); } return getDerived().RebuildCXXUnresolvedMemberExpr(move(Base), @@ -4653,13 +4876,15 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr( template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) { +TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E, + bool isAddressOfOperand) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E) { +TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E, + bool isAddressOfOperand) { // FIXME: poor source location TemporaryBase Rebase(*this, E->getAtLoc(), DeclarationName()); QualType EncodedType = getDerived().TransformType(E->getEncodedType()); @@ -4677,7 +4902,8 @@ TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) { +TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E, + bool isAddressOfOperand) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -4685,13 +4911,15 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCSelectorExpr(ObjCSelectorExpr *E) { +TreeTransform<Derived>::TransformObjCSelectorExpr(ObjCSelectorExpr *E, + bool isAddressOfOperand) { return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E) { +TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E, + bool isAddressOfOperand) { ObjCProtocolDecl *Protocol = cast_or_null<ObjCProtocolDecl>( getDerived().TransformDecl(E->getProtocol())); @@ -4712,7 +4940,8 @@ TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) { +TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E, + bool isAddressOfOperand) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -4720,7 +4949,8 @@ TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { +TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E, + bool isAddressOfOperand) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -4729,7 +4959,8 @@ TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformObjCImplicitSetterGetterRefExpr( - ObjCImplicitSetterGetterRefExpr *E) { + ObjCImplicitSetterGetterRefExpr *E, + bool isAddressOfOperand) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -4737,7 +4968,8 @@ TreeTransform<Derived>::TransformObjCImplicitSetterGetterRefExpr( template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCSuperExpr(ObjCSuperExpr *E) { +TreeTransform<Derived>::TransformObjCSuperExpr(ObjCSuperExpr *E, + bool isAddressOfOperand) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -4745,7 +4977,8 @@ TreeTransform<Derived>::TransformObjCSuperExpr(ObjCSuperExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E) { +TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E, + bool isAddressOfOperand) { // FIXME: Implement this! assert(false && "Cannot transform Objective-C expressions yet"); return SemaRef.Owned(E->Retain()); @@ -4753,7 +4986,8 @@ TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) { +TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E, + bool isAddressOfOperand) { bool ArgumentChanged = false; ASTOwningVector<&ActionBase::DeleteExpr> SubExprs(SemaRef); for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I) { @@ -4776,7 +5010,8 @@ TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) { +TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E, + bool isAddressOfOperand) { // FIXME: Implement this! assert(false && "Cannot transform block expressions yet"); return SemaRef.Owned(E->Retain()); @@ -4784,7 +5019,8 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) { template<typename Derived> Sema::OwningExprResult -TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) { +TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E, + bool isAddressOfOperand) { // FIXME: Implement this! assert(false && "Cannot transform block-related expressions yet"); return SemaRef.Owned(E->Retain()); @@ -4795,48 +5031,42 @@ TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) { //===----------------------------------------------------------------------===// template<typename Derived> -QualType TreeTransform<Derived>::RebuildPointerType(QualType PointeeType) { - return SemaRef.BuildPointerType(PointeeType, Qualifiers(), - getDerived().getBaseLocation(), +QualType TreeTransform<Derived>::RebuildPointerType(QualType PointeeType, + SourceLocation Star) { + return SemaRef.BuildPointerType(PointeeType, Qualifiers(), Star, getDerived().getBaseEntity()); } template<typename Derived> -QualType TreeTransform<Derived>::RebuildBlockPointerType(QualType PointeeType) { - return SemaRef.BuildBlockPointerType(PointeeType, Qualifiers(), - getDerived().getBaseLocation(), +QualType TreeTransform<Derived>::RebuildBlockPointerType(QualType PointeeType, + SourceLocation Star) { + return SemaRef.BuildBlockPointerType(PointeeType, Qualifiers(), Star, getDerived().getBaseEntity()); } template<typename Derived> QualType -TreeTransform<Derived>::RebuildLValueReferenceType(QualType ReferentType) { - return SemaRef.BuildReferenceType(ReferentType, true, Qualifiers(), - getDerived().getBaseLocation(), - getDerived().getBaseEntity()); +TreeTransform<Derived>::RebuildReferenceType(QualType ReferentType, + bool WrittenAsLValue, + SourceLocation Sigil) { + return SemaRef.BuildReferenceType(ReferentType, WrittenAsLValue, Qualifiers(), + Sigil, getDerived().getBaseEntity()); } template<typename Derived> QualType -TreeTransform<Derived>::RebuildRValueReferenceType(QualType ReferentType) { - return SemaRef.BuildReferenceType(ReferentType, false, Qualifiers(), - getDerived().getBaseLocation(), - getDerived().getBaseEntity()); -} - -template<typename Derived> -QualType TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType, - QualType ClassType) { +TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType, + QualType ClassType, + SourceLocation Sigil) { return SemaRef.BuildMemberPointerType(PointeeType, ClassType, Qualifiers(), - getDerived().getBaseLocation(), - getDerived().getBaseEntity()); + Sigil, getDerived().getBaseEntity()); } template<typename Derived> QualType -TreeTransform<Derived>::RebuildObjCObjectPointerType(QualType PointeeType) { - return SemaRef.BuildPointerType(PointeeType, Qualifiers(), - getDerived().getBaseLocation(), +TreeTransform<Derived>::RebuildObjCObjectPointerType(QualType PointeeType, + SourceLocation Sigil) { + return SemaRef.BuildPointerType(PointeeType, Qualifiers(), Sigil, getDerived().getBaseEntity()); } @@ -4880,18 +5110,20 @@ QualType TreeTransform<Derived>::RebuildConstantArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, const llvm::APInt &Size, - unsigned IndexTypeQuals) { + unsigned IndexTypeQuals, + SourceRange BracketsRange) { return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, 0, - IndexTypeQuals, SourceRange()); + IndexTypeQuals, BracketsRange); } template<typename Derived> QualType TreeTransform<Derived>::RebuildIncompleteArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, - unsigned IndexTypeQuals) { + unsigned IndexTypeQuals, + SourceRange BracketsRange) { return getDerived().RebuildArrayType(ElementType, SizeMod, 0, 0, - IndexTypeQuals, SourceRange()); + IndexTypeQuals, BracketsRange); } template<typename Derived> @@ -4980,13 +5212,14 @@ QualType TreeTransform<Derived>::RebuildDecltypeType(ExprArg E) { template<typename Derived> QualType TreeTransform<Derived>::RebuildTemplateSpecializationType( - TemplateName Template, - const TemplateArgument *Args, - unsigned NumArgs) { - // FIXME: Missing source locations for the template name, <, >. - return SemaRef.CheckTemplateIdType(Template, getDerived().getBaseLocation(), - SourceLocation(), Args, NumArgs, - SourceLocation()); + TemplateName Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + const TemplateArgumentLoc *Args, + unsigned NumArgs, + SourceLocation RAngleLoc) { + return SemaRef.CheckTemplateIdType(Template, TemplateNameLoc, LAngleLoc, + Args, NumArgs, RAngleLoc); } template<typename Derived> @@ -5058,16 +5291,37 @@ TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier, CXXScopeSpec SS; SS.setRange(SourceRange(getDerived().getBaseLocation())); SS.setScopeRep(Qualifier); + UnqualifiedId Name; + Name.setIdentifier(&II, /*FIXME:*/getDerived().getBaseLocation()); return getSema().ActOnDependentTemplateName( /*FIXME:*/getDerived().getBaseLocation(), - II, - /*FIXME:*/getDerived().getBaseLocation(), SS, + Name, ObjectType.getAsOpaquePtr()) .template getAsVal<TemplateName>(); } template<typename Derived> +TemplateName +TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier, + OverloadedOperatorKind Operator, + QualType ObjectType) { + CXXScopeSpec SS; + SS.setRange(SourceRange(getDerived().getBaseLocation())); + SS.setScopeRep(Qualifier); + UnqualifiedId Name; + SourceLocation SymbolLocations[3]; // FIXME: Bogus location information. + Name.setOperatorFunctionId(/*FIXME:*/getDerived().getBaseLocation(), + Operator, SymbolLocations); + return getSema().ActOnDependentTemplateName( + /*FIXME:*/getDerived().getBaseLocation(), + SS, + Name, + ObjectType.getAsOpaquePtr()) + .template getAsVal<TemplateName>(); +} + +template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, SourceLocation OpLoc, @@ -5076,10 +5330,18 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, ExprArg Second) { Expr *FirstExpr = (Expr *)First.get(); Expr *SecondExpr = (Expr *)Second.get(); + DeclRefExpr *DRE + = cast<DeclRefExpr>(((Expr *)Callee.get())->IgnoreParenCasts()); bool isPostIncDec = SecondExpr && (Op == OO_PlusPlus || Op == OO_MinusMinus); // Determine whether this should be a builtin operation. - if (SecondExpr == 0 || isPostIncDec) { + if (Op == OO_Subscript) { + if (!FirstExpr->getType()->isOverloadableType() && + !SecondExpr->getType()->isOverloadableType()) + return getSema().CreateBuiltinArraySubscriptExpr(move(First), + DRE->getLocStart(), + move(Second), OpLoc); + } else if (SecondExpr == 0 || isPostIncDec) { if (!FirstExpr->getType()->isOverloadableType()) { // The argument is not of overloadable type, so try to create a // built-in unary operation. @@ -5109,9 +5371,6 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, // used during overload resolution. Sema::FunctionSet Functions; - DeclRefExpr *DRE - = cast<DeclRefExpr>(((Expr *)Callee.get())->IgnoreParenCasts()); - // FIXME: Do we have to check // IsAcceptableNonMemberOperatorCandidate for each of these? for (OverloadIterator F(DRE->getDecl()), FEnd; F != FEnd; ++F) @@ -5122,7 +5381,8 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, unsigned NumArgs = 1 + (SecondExpr != 0); DeclarationName OpName = SemaRef.Context.DeclarationNames.getCXXOperatorName(Op); - SemaRef.ArgumentDependentLookup(OpName, Args, NumArgs, Functions); + SemaRef.ArgumentDependentLookup(OpName, /*Operator*/true, Args, NumArgs, + Functions); // Create the overloaded operator invocation for unary operators. if (NumArgs == 1 || isPostIncDec) { @@ -5131,6 +5391,10 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, return SemaRef.CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(First)); } + if (Op == OO_Subscript) + return SemaRef.CreateOverloadedArraySubscriptExpr(DRE->getLocStart(), OpLoc, + move(First),move(Second)); + // Create the overloaded operator invocation for binary operators. BinaryOperator::Opcode Opc = BinaryOperator::getOverloadedOpcode(Op); |