From 07b2cfcdb817cc0790420f159a313d61e7241cb9 Mon Sep 17 00:00:00 2001 From: rdivacky Date: Fri, 2 Apr 2010 08:55:10 +0000 Subject: Update clang to r100181. --- lib/Sema/AnalysisBasedWarnings.cpp | 110 ++++- lib/Sema/AnalysisBasedWarnings.h | 42 +- lib/Sema/Lookup.h | 6 + lib/Sema/Sema.cpp | 27 +- lib/Sema/Sema.h | 162 ++++--- lib/Sema/SemaAccess.cpp | 760 +++++++++++++++++++++++-------- lib/Sema/SemaCXXCast.cpp | 58 +-- lib/Sema/SemaCXXScopeSpec.cpp | 8 +- lib/Sema/SemaChecking.cpp | 64 ++- lib/Sema/SemaDecl.cpp | 391 ++++++++++------ lib/Sema/SemaDeclAttr.cpp | 31 +- lib/Sema/SemaDeclCXX.cpp | 704 ++++++++++++++-------------- lib/Sema/SemaDeclObjC.cpp | 48 +- lib/Sema/SemaExceptionSpec.cpp | 154 +++++-- lib/Sema/SemaExpr.cpp | 243 ++++++---- lib/Sema/SemaExprCXX.cpp | 249 +++++----- lib/Sema/SemaExprObjC.cpp | 5 +- lib/Sema/SemaInit.cpp | 86 +++- lib/Sema/SemaInit.h | 10 +- lib/Sema/SemaLookup.cpp | 21 +- lib/Sema/SemaObjCProperty.cpp | 29 +- lib/Sema/SemaOverload.cpp | 130 +++--- lib/Sema/SemaStmt.cpp | 57 ++- lib/Sema/SemaTemplate.cpp | 672 +++++++++++++++++---------- lib/Sema/SemaTemplate.h | 34 ++ lib/Sema/SemaTemplateDeduction.cpp | 273 ++++++++--- lib/Sema/SemaTemplateInstantiate.cpp | 131 ++---- lib/Sema/SemaTemplateInstantiateDecl.cpp | 316 ++++++++++--- lib/Sema/SemaType.cpp | 84 +++- lib/Sema/TreeTransform.h | 126 ++++- 30 files changed, 3292 insertions(+), 1739 deletions(-) (limited to 'lib/Sema') diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index c4ceec0..d1f00ca 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -154,7 +154,7 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { continue; } Expr *CEE = C->getCallee()->IgnoreParenCasts(); - if (CEE->getType().getNoReturnAttr()) { + if (getFunctionExtInfo(CEE->getType()).getNoReturn()) { NoReturnEdge = true; HasFakeEdge = true; } else if (DeclRefExpr *DRE = dyn_cast(CEE)) { @@ -189,7 +189,7 @@ struct CheckFallThroughDiagnostics { unsigned diag_AlwaysFallThrough_ReturnsNonVoid; unsigned diag_NeverFallThroughOrReturn; bool funMode; - + static CheckFallThroughDiagnostics MakeForFunction() { CheckFallThroughDiagnostics D; D.diag_MaybeFallThrough_HasNoReturn = @@ -205,7 +205,7 @@ struct CheckFallThroughDiagnostics { D.funMode = true; return D; } - + static CheckFallThroughDiagnostics MakeForBlock() { CheckFallThroughDiagnostics D; D.diag_MaybeFallThrough_HasNoReturn = @@ -221,7 +221,7 @@ struct CheckFallThroughDiagnostics { D.funMode = false; return D; } - + bool checkDiagnostics(Diagnostic &D, bool ReturnsVoid, bool HasNoReturn) const { if (funMode) { @@ -232,7 +232,7 @@ struct CheckFallThroughDiagnostics { && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block) == Diagnostic::Ignored || !ReturnsVoid); } - + // For blocks. return ReturnsVoid && !HasNoReturn && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block) @@ -255,14 +255,14 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, if (const FunctionDecl *FD = dyn_cast(D)) { ReturnsVoid = FD->getResultType()->isVoidType(); HasNoReturn = FD->hasAttr() || - FD->getType()->getAs()->getNoReturnAttr(); + FD->getType()->getAs()->getNoReturnAttr(); } else if (const ObjCMethodDecl *MD = dyn_cast(D)) { ReturnsVoid = MD->getResultType()->isVoidType(); HasNoReturn = MD->hasAttr(); } else if (isa(D)) { - if (const FunctionType *FT = + if (const FunctionType *FT = BlockTy->getPointeeType()->getAs()) { if (FT->getResultType()->isVoidType()) ReturnsVoid = true; @@ -276,7 +276,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, // Short circuit for compilation speed. if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn)) return; - + // FIXME: Function try block if (const CompoundStmt *Compound = dyn_cast(Body)) { switch (CheckFallThrough(AC)) { @@ -312,25 +312,23 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, // warnings on a function, method, or block. //===----------------------------------------------------------------------===// -clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) { - Diagnostic &D = S.getDiagnostics(); - +clang::sema::AnalysisBasedWarnings::Policy::Policy() { enableCheckFallThrough = 1; + enableCheckUnreachable = 0; +} - enableCheckUnreachable = (unsigned) +clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) { + Diagnostic &D = S.getDiagnostics(); + DefaultPolicy.enableCheckUnreachable = (unsigned) (D.getDiagnosticLevel(diag::warn_unreachable) != Diagnostic::Ignored); } -void clang::sema::AnalysisBasedWarnings::IssueWarnings(const Decl *D, - QualType BlockTy) { - +void clang::sema:: +AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, + const Decl *D, QualType BlockTy, + const bool analyzeStaticInline) { + assert(BlockTy.isNull() || isa(D)); - - // Do not do any analysis for declarations in system headers if we are - // going to just ignore them. - if (S.getDiagnostics().getSuppressSystemWarnings() && - S.SourceMgr.isInSystemHeader(D->getLocation())) - return; // We avoid doing analysis-based warnings when there are errors for // two reasons: @@ -339,13 +337,30 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(const Decl *D, // (2) The code already has problems; running the analysis just takes more // time. if (S.getDiagnostics().hasErrorOccurred()) - return; - + return; + + // Do not do any analysis for declarations in system headers if we are + // going to just ignore them. + if (S.getDiagnostics().getSuppressSystemWarnings() && + S.SourceMgr.isInSystemHeader(D->getLocation())) + return; + if (const FunctionDecl *FD = dyn_cast(D)) { // For function templates, class templates and member function templates // we'll do the analysis at instantiation time. if (FD->isDependentContext()) return; + + // Only analyze 'static inline' functions when explicitly asked. + if (!analyzeStaticInline && FD->isInlineSpecified() && + FD->getStorageClass() == FunctionDecl::Static) { + FD = FD->getCanonicalDecl(); + VisitFlag &visitFlag = VisitedFD[FD]; + if (visitFlag == Pending) + visitFlag = Visited; + else + return; + } } const Stmt *Body = D->getBody(); @@ -354,16 +369,61 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(const Decl *D, // Don't generate EH edges for CallExprs as we'd like to avoid the n^2 // explosion for destrutors that can result and the compile time hit. AnalysisContext AC(D, false); + bool performedCheck = false; // Warning: check missing 'return' - if (enableCheckFallThrough) { + if (P.enableCheckFallThrough) { const CheckFallThroughDiagnostics &CD = (isa(D) ? CheckFallThroughDiagnostics::MakeForBlock() : CheckFallThroughDiagnostics::MakeForFunction()); CheckFallThroughForBody(S, D, Body, BlockTy, CD, AC); + performedCheck = true; } // Warning: check for unreachable code - if (enableCheckUnreachable) + if (P.enableCheckUnreachable) { CheckUnreachable(S, AC); + performedCheck = true; + } + + // If this block or function calls a 'static inline' function, + // we should analyze those functions as well. + if (performedCheck) { + // The CFG should already be constructed, so this should not + // incur any extra cost. We might not have a CFG, however, for + // invalid code. + if (const CFG *cfg = AC.getCFG()) { + // All CallExprs are block-level expressions in the CFG. This means + // that walking the basic blocks in the CFG is more efficient + // than walking the entire AST to find all calls. + for (CFG::const_iterator I=cfg->begin(), E=cfg->end(); I!=E; ++I) { + const CFGBlock *B = *I; + for (CFGBlock::const_iterator BI=B->begin(), BE=B->end(); BI!=BE; ++BI) + if (const CallExpr *CE = dyn_cast(*BI)) + if (const DeclRefExpr *DR = + dyn_cast(CE->getCallee()->IgnoreParenCasts())) + if (const FunctionDecl *calleeD = + dyn_cast(DR->getDecl())) { + calleeD = calleeD->getCanonicalDecl(); + if (calleeD->isInlineSpecified() && + calleeD->getStorageClass() == FunctionDecl::Static) { + // Have we analyzed this static inline function before? + VisitFlag &visitFlag = VisitedFD[calleeD]; + if (visitFlag == NotVisited) { + // Mark the callee visited prior to analyzing it + // so we terminate in case of recursion. + if (calleeD->getBody()) { + visitFlag = Visited; + IssueWarnings(DefaultPolicy, calleeD, QualType(), true); + } + else { + // Delay warnings until we encounter the definition. + visitFlag = Pending; + } + } + } + } + } + } + } } diff --git a/lib/Sema/AnalysisBasedWarnings.h b/lib/Sema/AnalysisBasedWarnings.h index 39da1b1..b5db8af 100644 --- a/lib/Sema/AnalysisBasedWarnings.h +++ b/lib/Sema/AnalysisBasedWarnings.h @@ -14,22 +14,44 @@ #ifndef LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H #define LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H -namespace clang { namespace sema { +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { + +class Sema; + +namespace sema { class AnalysisBasedWarnings { - Sema &S; - // The warnings to run. - unsigned enableCheckFallThrough : 1; - unsigned enableCheckUnreachable : 1; - public: + class Policy { + friend class AnalysisBasedWarnings; + // The warnings to run. + unsigned enableCheckFallThrough : 1; + unsigned enableCheckUnreachable : 1; + public: + Policy(); + void disableCheckFallThrough() { enableCheckFallThrough = 0; } + }; + +private: + Sema &S; + Policy DefaultPolicy; + enum VisitFlag { NotVisited = 0, Visited = 1, Pending = 2 }; + llvm::DenseMap VisitedFD; + +public: AnalysisBasedWarnings(Sema &s); - void IssueWarnings(const Decl *D, QualType BlockTy = QualType()); - - void disableCheckFallThrough() { enableCheckFallThrough = 0; } + + Policy getDefaultPolicy() { return DefaultPolicy; } + + void IssueWarnings(Policy P, const Decl *D, QualType BlockTy = QualType(), + const bool analyzeStaticInline = false); + }; - + }} // end namespace clang::sema #endif diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h index 6b26945..f310c25 100644 --- a/lib/Sema/Lookup.h +++ b/lib/Sema/Lookup.h @@ -397,6 +397,12 @@ public: configure(); } + /// \brief Change this lookup's redeclaration kind. + void setRedeclarationKind(Sema::RedeclarationKind RK) { + Redecl = RK; + configure(); + } + void print(llvm::raw_ostream &); /// Suppress the diagnostics that would normally fire because of this diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 7112687..ccfbe1e 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -132,7 +132,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, GlobalNewDeleteDeclared(false), CompleteTranslationUnit(CompleteTranslationUnit), NumSFINAEErrors(0), NonInstantiationEntries(0), - CurrentInstantiationScope(0), TyposCorrected(0) + CurrentInstantiationScope(0), TyposCorrected(0), + AnalysisWarnings(*this) { TUScope = 0; if (getLangOptions().CPlusPlus) @@ -347,6 +348,30 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { } } +Sema::SemaDiagnosticBuilder Sema::Diag(SourceLocation Loc, unsigned DiagID) { + if (isSFINAEContext()) { + switch (Diagnostic::getDiagnosticSFINAEResponse(DiagID)) { + case Diagnostic::SFINAE_Report: + // Fall through; we'll report the diagnostic below. + break; + + case Diagnostic::SFINAE_SubstitutionFailure: + // Count this failure so that we know that template argument deduction + // has failed. + ++NumSFINAEErrors; + // Fall through + + case Diagnostic::SFINAE_Suppress: + // Suppress this diagnostic. + Diags.setLastDiagnosticIgnored(); + return SemaDiagnosticBuilder(*this); + } + } + + DiagnosticBuilder DB = Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID); + return SemaDiagnosticBuilder(DB, *this, DiagID); +} + Sema::SemaDiagnosticBuilder Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) { SemaDiagnosticBuilder Builder(Diag(Loc, PD.getDiagID())); diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index b529e5b..0766b1e 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -19,6 +19,7 @@ #include "CXXFieldCollector.h" #include "SemaOverload.h" #include "SemaTemplate.h" +#include "AnalysisBasedWarnings.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclBase.h" #include "clang/AST/Decl.h" @@ -298,7 +299,7 @@ public: /// \brief The set of static functions seen so far that have not been used. std::vector UnusedStaticFuncs; - + class AccessedEntity { public: /// A member declaration found through lookup. The target is the @@ -311,30 +312,33 @@ public: bool isMemberAccess() const { return IsMember; } - AccessedEntity(MemberNonce _, + AccessedEntity(ASTContext &Context, + MemberNonce _, CXXRecordDecl *NamingClass, AccessSpecifier Access, NamedDecl *Target) : Access(Access), IsMember(true), Target(Target), NamingClass(NamingClass), - Diag(0) { + Diag(0, Context.getDiagAllocator()) { } - AccessedEntity(MemberNonce _, + AccessedEntity(ASTContext &Context, + MemberNonce _, CXXRecordDecl *NamingClass, DeclAccessPair FoundDecl) : Access(FoundDecl.getAccess()), IsMember(true), Target(FoundDecl.getDecl()), NamingClass(NamingClass), - Diag(0) { + Diag(0, Context.getDiagAllocator()) { } - AccessedEntity(BaseNonce _, + AccessedEntity(ASTContext &Context, + BaseNonce _, CXXRecordDecl *BaseClass, CXXRecordDecl *DerivedClass, AccessSpecifier Access) : Access(Access), IsMember(false), Target(BaseClass), NamingClass(DerivedClass), - Diag(0) { + Diag(0, Context.getDiagAllocator()) { } bool isQuiet() const { return Diag.getDiagID() == 0; } @@ -362,7 +366,7 @@ public: PartialDiagnostic &setDiag(unsigned DiagID) { assert(isQuiet() && "partial diagnostic already defined"); assert(DiagID && "creating null diagnostic"); - Diag = PartialDiagnostic(DiagID); + Diag.Reset(DiagID); return Diag; } const PartialDiagnostic &getDiag() const { @@ -609,23 +613,16 @@ public: }; /// \brief Emit a diagnostic. - SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { - if (isSFINAEContext() && Diagnostic::isBuiltinSFINAEDiag(DiagID)) { - // If we encountered an error during template argument - // deduction, and that error is one of the SFINAE errors, - // suppress the diagnostic. - ++NumSFINAEErrors; - Diags.setLastDiagnosticIgnored(); - return SemaDiagnosticBuilder(*this); - } - - DiagnosticBuilder DB = Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID); - return SemaDiagnosticBuilder(DB, *this, DiagID); - } + SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID); /// \brief Emit a partial diagnostic. SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic& PD); + /// \brief Build a partial diagnostic. + PartialDiagnostic PDiag(unsigned DiagID = 0) { + return PartialDiagnostic(DiagID, Context.getDiagAllocator()); + } + virtual void DeleteExpr(ExprTy *E); virtual void DeleteStmt(StmtTy *S); @@ -727,6 +724,7 @@ public: const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, const FunctionProtoType *Old, SourceLocation OldLoc, const FunctionProtoType *New, SourceLocation NewLoc, + bool *MissingExceptionSpecification = 0, bool *MissingEmptyExceptionSpecification = 0); bool CheckExceptionSpecSubset( const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, @@ -742,10 +740,12 @@ public: bool RequireCompleteType(SourceLocation Loc, QualType T, const PartialDiagnostic &PD, - std::pair Note = - std::make_pair(SourceLocation(), PDiag())); - + std::pair Note); + bool RequireCompleteType(SourceLocation Loc, QualType T, + const PartialDiagnostic &PD); + bool RequireCompleteType(SourceLocation Loc, QualType T, + unsigned DiagID); + QualType getQualifiedNameType(const CXXScopeSpec &SS, QualType T); QualType BuildTypeofExprType(Expr *E); @@ -783,7 +783,8 @@ public: const LookupResult &Previous, Scope *S); void DiagnoseFunctionSpecifiers(Declarator& D); - void DiagnoseShadow(Scope *S, Declarator &D, const LookupResult& R); + void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R); + void CheckShadow(Scope *S, VarDecl *D); NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, bool &Redeclaration); @@ -827,6 +828,7 @@ public: virtual void AddInitializerToDecl(DeclPtrTy dcl, ExprArg init); void AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit); void ActOnUninitializedDecl(DeclPtrTy dcl, bool TypeContainsUndeducedAuto); + virtual void ActOnInitializerError(DeclPtrTy Dcl); virtual void SetDeclDeleted(DeclPtrTy dcl, SourceLocation DelLoc); virtual DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, DeclPtrTy *Group, @@ -1110,9 +1112,6 @@ public: bool SuppressUserConversions, bool ForceRValue, bool InOverloadResolution); - bool PerformCopyInitialization(Expr *&From, QualType ToType, - AssignmentAction Action, bool Elidable = false); - OwningExprResult PerformCopyInitialization(const InitializedEntity &Entity, SourceLocation EqualLoc, OwningExprResult Init); @@ -1121,6 +1120,7 @@ public: CXXRecordDecl *ActingContext); bool PerformObjectArgumentInitialization(Expr *&From, NestedNameSpecifier *Qualifier, + NamedDecl *FoundDecl, CXXMethodDecl *Method); ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From); @@ -1128,6 +1128,7 @@ public: bool PerformObjectMemberConversion(Expr *&From, NestedNameSpecifier *Qualifier, + NamedDecl *FoundDecl, NamedDecl *Member); // Members have to be NamespaceDecl* or TranslationUnitDecl*. @@ -1248,11 +1249,15 @@ public: const PartialDiagnostic &PDiag); FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, - bool Complain); + bool Complain, + DeclAccessPair &Found); FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From); - Expr *FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn); + Expr *FixOverloadedFunctionReference(Expr *E, + NamedDecl *FoundDecl, + FunctionDecl *Fn); OwningExprResult FixOverloadedFunctionReference(OwningExprResult, + NamedDecl *FoundDecl, FunctionDecl *Fn); void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, @@ -1448,7 +1453,7 @@ public: void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AttrList); void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method, - bool &IncompleteImpl); + bool &IncompleteImpl, unsigned DiagID); void WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethod, ObjCMethodDecl *IntfMethod); @@ -1464,7 +1469,7 @@ public: bool& IncompleteImpl, const llvm::DenseSet &InsMap, const llvm::DenseSet &ClsMap, - ObjCInterfaceDecl *IDecl); + ObjCContainerDecl *CDecl); /// CheckImplementationIvars - This routine checks if the instance variables /// listed in the implelementation match those listed in the interface. @@ -2397,7 +2402,9 @@ public: Expr *BuildObjCEncodeExpression(SourceLocation AtLoc, QualType EncodedType, SourceLocation RParenLoc); - CXXMemberCallExpr *BuildCXXMemberCallExpr(Expr *Exp, CXXMethodDecl *Method); + CXXMemberCallExpr *BuildCXXMemberCallExpr(Expr *Exp, + NamedDecl *FoundDecl, + CXXMethodDecl *Method); virtual ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc, SourceLocation EncodeLoc, @@ -2471,9 +2478,7 @@ public: bool SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, CXXBaseOrMemberInitializer **Initializers, - unsigned NumInitializers, - bool IsImplicitConstructor, - bool AnyErrors); + unsigned NumInitializers, bool AnyErrors); /// MarkBaseAndMemberDestructorsReferenced - Given a record decl, /// mark all the non-trivial destructors of its members and bases as @@ -2495,7 +2500,8 @@ public: /// MarkVirtualMembersReferenced - Will mark all virtual members of the given /// CXXRecordDecl referenced. - void MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD); + void MarkVirtualMembersReferenced(SourceLocation Loc, + const CXXRecordDecl *RD); /// ProcessPendingClassesWithUnmarkedVirtualMembers - Will process classes /// that might need to have their virtual members marked as referenced. @@ -2513,7 +2519,8 @@ public: virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, DeclPtrTy TagDecl, SourceLocation LBrac, - SourceLocation RBrac); + SourceLocation RBrac, + AttributeList *AttrList); virtual void ActOnReenterTemplateScope(Scope *S, DeclPtrTy Template); virtual void ActOnStartDelayedMemberDeclarations(Scope *S, @@ -2640,15 +2647,21 @@ public: Expr *ObjectExpr, Expr *ArgExpr, DeclAccessPair FoundDecl); + AccessResult CheckAddressOfMemberAccess(Expr *OvlExpr, + DeclAccessPair FoundDecl); AccessResult CheckBaseClassAccess(SourceLocation AccessLoc, QualType Base, QualType Derived, const CXXBasePath &Path, unsigned DiagID, bool ForceCheck = false, bool ForceUnprivileged = false); - void CheckLookupAccess(const LookupResult &R); + void HandleDependentAccessCheck(const DependentDiagnostic &DD, + const MultiLevelTemplateArgumentList &TemplateArgs); + void PerformDependentDiagnostics(const DeclContext *Pattern, + const MultiLevelTemplateArgumentList &TemplateArgs); + void HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx); enum AbstractDiagSelID { @@ -2869,12 +2882,29 @@ public: Decl *Param, TemplateArgumentListBuilder &Converted); + /// \brief Specifies the context in which a particular template + /// argument is being checked. + enum CheckTemplateArgumentKind { + /// \brief The template argument was specified in the code or was + /// instantiated with some deduced template arguments. + CTAK_Specified, + + /// \brief The template argument was deduced via template argument + /// deduction. + CTAK_Deduced, + + /// \brief The template argument was deduced from an array bound + /// via template argument deduction. + CTAK_DeducedFromArrayBound + }; + bool CheckTemplateArgument(NamedDecl *Param, const TemplateArgumentLoc &Arg, TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, - TemplateArgumentListBuilder &Converted); + TemplateArgumentListBuilder &Converted, + CheckTemplateArgumentKind CTAK = CTAK_Specified); bool CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, @@ -2888,15 +2918,22 @@ public: bool CheckTemplateArgument(TemplateTypeParmDecl *Param, TypeSourceInfo *Arg); - bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, - NamedDecl *&Entity); bool CheckTemplateArgumentPointerToMember(Expr *Arg, TemplateArgument &Converted); bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *&Arg, - TemplateArgument &Converted); + TemplateArgument &Converted, + CheckTemplateArgumentKind CTAK = CTAK_Specified); bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, const TemplateArgumentLoc &Arg); + + OwningExprResult + BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, + QualType ParamType, + SourceLocation Loc); + OwningExprResult + BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, + SourceLocation Loc); /// \brief Enumeration describing how template parameter lists are compared /// for equality. @@ -3119,14 +3156,15 @@ public: TemplateDeductionResult SubstituteExplicitTemplateArguments(FunctionTemplateDecl *FunctionTemplate, const TemplateArgumentListInfo &ExplicitTemplateArgs, - llvm::SmallVectorImpl &Deduced, + llvm::SmallVectorImpl &Deduced, llvm::SmallVectorImpl &ParamTypes, QualType *FunctionType, TemplateDeductionInfo &Info); TemplateDeductionResult FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, - llvm::SmallVectorImpl &Deduced, + llvm::SmallVectorImpl &Deduced, + unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, TemplateDeductionInfo &Info); @@ -3480,15 +3518,27 @@ public: /// \brief Whether we have already exited this scope. bool Exited; + /// \brief Whether this scope is temporary, meaning that we should + /// remove any additions we make once we exit this + /// scope. Temporary scopes are always combined with their outer + /// scopes. + bool Temporary; + + /// \brief List of the declarations that we have added into this + /// temporary scope. They will be removed when we exit the + /// temporary scope. + llvm::SmallVector AddedTemporaryDecls; + // This class is non-copyable LocalInstantiationScope(const LocalInstantiationScope &); LocalInstantiationScope &operator=(const LocalInstantiationScope &); public: - LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false) + LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false, + bool Temporary = false) : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope), - Exited(false) { - if (!CombineWithOuterScope) + Exited(false), Temporary(Temporary) { + if (!CombineWithOuterScope && !Temporary) SemaRef.CurrentInstantiationScope = this; else assert(SemaRef.CurrentInstantiationScope && @@ -3496,8 +3546,11 @@ public: } ~LocalInstantiationScope() { - if (!Exited) + if (!Exited) { SemaRef.CurrentInstantiationScope = Outer; + for (unsigned I = 0, N = AddedTemporaryDecls.size(); I != N; ++I) + LocalDecls.erase(AddedTemporaryDecls[I]); + } } /// \brief Exit this local instantiation scope early. @@ -3530,6 +3583,10 @@ public: void InstantiatedLocal(const Decl *D, Decl *Inst) { Decl *&Stored = LocalDecls[D]; assert((!Stored || Stored == Inst) && "Already instantiated this local"); + + if (Temporary && !Stored) + AddedTemporaryDecls.push_back(D); + Stored = Inst; } }; @@ -3541,6 +3598,9 @@ public: /// \brief The number of typos corrected by CorrectTypo. unsigned TyposCorrected; + /// \brief Worker object for performing CFG-based warnings. + sema::AnalysisBasedWarnings AnalysisWarnings; + /// \brief An entity for which implicit template instantiation is required. /// /// The source location associated with the declaration is the first place in @@ -3714,7 +3774,7 @@ public: /// Ensure attributes are consistent with type. /// \param [in, out] Attributes The attributes to check; they will /// be modified to be consistent with \arg PropertyTy. - void CheckObjCPropertyAttributes(QualType PropertyTy, + void CheckObjCPropertyAttributes(DeclPtrTy PropertyPtrTy, SourceLocation Loc, unsigned &Attributes); void ProcessPropertyDecl(ObjCPropertyDecl *property, ObjCContainerDecl *DC); diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index 40b320c..f628884 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -17,6 +17,7 @@ #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclFriend.h" +#include "clang/AST/DependentDiagnostic.h" #include "clang/AST/ExprCXX.h" using namespace clang; @@ -52,136 +53,323 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, namespace { struct EffectiveContext { - EffectiveContext() : Function(0) {} + EffectiveContext() : Inner(0), Dependent(false) {} - explicit EffectiveContext(DeclContext *DC) { - if (isa(DC)) { - Function = cast(DC)->getCanonicalDecl(); - DC = Function->getDeclContext(); - } else - Function = 0; + explicit EffectiveContext(DeclContext *DC) + : Inner(DC), + Dependent(DC->isDependentContext()) { // C++ [class.access.nest]p1: // A nested class is a member and as such has the same access // rights as any other member. // C++ [class.access]p2: // A member of a class can also access all the names to which - // the class has access. - // This implies that the privileges of nesting are transitive. - while (isa(DC)) { - CXXRecordDecl *Record = cast(DC)->getCanonicalDecl(); - Records.push_back(Record); - DC = Record->getDeclContext(); + // the class has access. A local class of a member function + // may access the same names that the member function itself + // may access. + // This almost implies that the privileges of nesting are transitive. + // Technically it says nothing about the local classes of non-member + // functions (which can gain privileges through friendship), but we + // take that as an oversight. + while (true) { + if (isa(DC)) { + CXXRecordDecl *Record = cast(DC)->getCanonicalDecl(); + Records.push_back(Record); + DC = Record->getDeclContext(); + } else if (isa(DC)) { + FunctionDecl *Function = cast(DC)->getCanonicalDecl(); + Functions.push_back(Function); + DC = Function->getDeclContext(); + } else if (DC->isFileContext()) { + break; + } else { + DC = DC->getParent(); + } } } + bool isDependent() const { return Dependent; } + bool includesClass(const CXXRecordDecl *R) const { R = R->getCanonicalDecl(); return std::find(Records.begin(), Records.end(), R) != Records.end(); } + /// Retrieves the innermost "useful" context. Can be null if we're + /// doing access-control without privileges. + DeclContext *getInnerContext() const { + return Inner; + } + + typedef llvm::SmallVectorImpl::const_iterator record_iterator; + + DeclContext *Inner; + llvm::SmallVector Functions; llvm::SmallVector Records; - FunctionDecl *Function; + bool Dependent; }; } static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) { - CXXRecordDecl *DeclaringClass = cast(D->getDeclContext()); + DeclContext *DC = D->getDeclContext(); + + // This can only happen at top: enum decls only "publish" their + // immediate members. + if (isa(DC)) + DC = cast(DC)->getDeclContext(); + + CXXRecordDecl *DeclaringClass = cast(DC); while (DeclaringClass->isAnonymousStructOrUnion()) DeclaringClass = cast(DeclaringClass->getDeclContext()); return DeclaringClass; } +static bool MightInstantiateTo(Sema &S, DeclContext *Context, + DeclContext *Friend) { + if (Friend == Context) + return true; + + assert(!Friend->isDependentContext() && + "can't handle friends with dependent contexts here"); + + if (!Context->isDependentContext()) + return false; + + if (Friend->isFileContext()) + return false; + + // TODO: this is very conservative + return true; +} + +// Asks whether the type in 'context' can ever instantiate to the type +// in 'friend'. +static bool MightInstantiateTo(Sema &S, CanQualType Context, CanQualType Friend) { + if (Friend == Context) + return true; + + if (!Friend->isDependentType() && !Context->isDependentType()) + return false; + + // TODO: this is very conservative. + return true; +} + +static bool MightInstantiateTo(Sema &S, + FunctionDecl *Context, + FunctionDecl *Friend) { + if (Context->getDeclName() != Friend->getDeclName()) + return false; + + if (!MightInstantiateTo(S, + Context->getDeclContext(), + Friend->getDeclContext())) + return false; + + CanQual FriendTy + = S.Context.getCanonicalType(Friend->getType()) + ->getAs(); + CanQual ContextTy + = S.Context.getCanonicalType(Context->getType()) + ->getAs(); + + // There isn't any way that I know of to add qualifiers + // during instantiation. + if (FriendTy.getQualifiers() != ContextTy.getQualifiers()) + return false; + + if (FriendTy->getNumArgs() != ContextTy->getNumArgs()) + return false; + + if (!MightInstantiateTo(S, + ContextTy->getResultType(), + FriendTy->getResultType())) + return false; + + for (unsigned I = 0, E = FriendTy->getNumArgs(); I != E; ++I) + if (!MightInstantiateTo(S, + ContextTy->getArgType(I), + FriendTy->getArgType(I))) + return false; + + return true; +} + +static bool MightInstantiateTo(Sema &S, + FunctionTemplateDecl *Context, + FunctionTemplateDecl *Friend) { + return MightInstantiateTo(S, + Context->getTemplatedDecl(), + Friend->getTemplatedDecl()); +} + static Sema::AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC, const CXXRecordDecl *Friend) { - // FIXME: close matches becuse of dependency if (EC.includesClass(Friend)) return Sema::AR_accessible; + if (EC.isDependent()) { + CanQualType FriendTy + = S.Context.getCanonicalType(S.Context.getTypeDeclType(Friend)); + + for (EffectiveContext::record_iterator + I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { + CanQualType ContextTy + = S.Context.getCanonicalType(S.Context.getTypeDeclType(*I)); + if (MightInstantiateTo(S, ContextTy, FriendTy)) + return Sema::AR_dependent; + } + } + return Sema::AR_inaccessible; } static Sema::AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC, - FriendDecl *Friend) { - if (Type *T = Friend->getFriendType()) { - CanQualType CT = T->getCanonicalTypeUnqualified(); - if (const RecordType *RT = CT->getAs()) - return MatchesFriend(S, EC, cast(RT->getDecl())); - - // TODO: we can fail early for a lot of type classes. - if (T->isDependentType()) - return Sema::AR_dependent; + CanQualType Friend) { + if (const RecordType *RT = Friend->getAs()) + return MatchesFriend(S, EC, cast(RT->getDecl())); - return Sema::AR_inaccessible; - } + // TODO: we can do better than this + if (Friend->isDependentType()) + return Sema::AR_dependent; - NamedDecl *D - = cast(Friend->getFriendDecl()->getCanonicalDecl()); + return Sema::AR_inaccessible; +} - // FIXME: declarations with dependent or templated scope. +/// Determines whether the given friend class template matches +/// anything in the effective context. +static Sema::AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + ClassTemplateDecl *Friend) { + Sema::AccessResult OnFailure = Sema::AR_inaccessible; - // For class templates, we want to check whether any of the records - // are possible specializations of the template. - if (isa(D)) { - for (llvm::SmallVectorImpl::const_iterator - I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { - CXXRecordDecl *Record = *I; - ClassTemplateDecl *CTD; + // Check whether the friend is the template of a class in the + // context chain. + for (llvm::SmallVectorImpl::const_iterator + I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { + CXXRecordDecl *Record = *I; - // A specialization of the template... - if (isa(Record)) { - CTD = cast(Record) - ->getSpecializedTemplate(); + // Figure out whether the current class has a template: + ClassTemplateDecl *CTD; - // ... or the template pattern itself. - } else { - CTD = Record->getDescribedClassTemplate(); - } + // A specialization of the template... + if (isa(Record)) { + CTD = cast(Record) + ->getSpecializedTemplate(); - if (CTD && D == CTD->getCanonicalDecl()) - return Sema::AR_accessible; + // ... or the template pattern itself. + } else { + CTD = Record->getDescribedClassTemplate(); + if (!CTD) continue; } - return Sema::AR_inaccessible; + // It's a match. + if (Friend == CTD->getCanonicalDecl()) + return Sema::AR_accessible; + + // If the context isn't dependent, it can't be a dependent match. + if (!EC.isDependent()) + continue; + + // If the template names don't match, it can't be a dependent + // match. This isn't true in C++0x because of template aliases. + if (!S.LangOpts.CPlusPlus0x && CTD->getDeclName() != Friend->getDeclName()) + continue; + + // If the class's context can't instantiate to the friend's + // context, it can't be a dependent match. + if (!MightInstantiateTo(S, CTD->getDeclContext(), + Friend->getDeclContext())) + continue; + + // Otherwise, it's a dependent match. + OnFailure = Sema::AR_dependent; + } + + return OnFailure; +} + +/// Determines whether the given friend function matches anything in +/// the effective context. +static Sema::AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + FunctionDecl *Friend) { + Sema::AccessResult OnFailure = Sema::AR_inaccessible; + + for (llvm::SmallVectorImpl::const_iterator + I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { + if (Friend == *I) + return Sema::AR_accessible; + + if (EC.isDependent() && MightInstantiateTo(S, *I, Friend)) + OnFailure = Sema::AR_dependent; } - // Same thing for function templates. - if (isa(D)) { - if (!EC.Function) return Sema::AR_inaccessible; + return OnFailure; +} + +/// Determines whether the given friend function template matches +/// anything in the effective context. +static Sema::AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + FunctionTemplateDecl *Friend) { + if (EC.Functions.empty()) return Sema::AR_inaccessible; - FunctionTemplateDecl *FTD = EC.Function->getPrimaryTemplate(); + Sema::AccessResult OnFailure = Sema::AR_inaccessible; + + for (llvm::SmallVectorImpl::const_iterator + I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { + + FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate(); if (!FTD) - FTD = EC.Function->getDescribedFunctionTemplate(); + FTD = (*I)->getDescribedFunctionTemplate(); + if (!FTD) + continue; + + FTD = FTD->getCanonicalDecl(); - if (FTD && D == FTD->getCanonicalDecl()) + if (Friend == FTD) return Sema::AR_accessible; - - return Sema::AR_inaccessible; + + if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend)) + OnFailure = Sema::AR_dependent; } - // Friend functions. FIXME: close matches due to dependency. - // - // The decl pointers in EC have been canonicalized, so pointer - // equality is sufficient. - if (D == EC.Function) - return Sema::AR_accessible; + return OnFailure; +} - if (isa(D)) - return MatchesFriend(S, EC, cast(D)); +/// Determines whether the given friend declaration matches anything +/// in the effective context. +static Sema::AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + FriendDecl *FriendD) { + if (TypeSourceInfo *T = FriendD->getFriendType()) + return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified()); - return Sema::AR_inaccessible; + NamedDecl *Friend + = cast(FriendD->getFriendDecl()->getCanonicalDecl()); + + // FIXME: declarations with dependent or templated scope. + + if (isa(Friend)) + return MatchesFriend(S, EC, cast(Friend)); + + if (isa(Friend)) + return MatchesFriend(S, EC, cast(Friend)); + + if (isa(Friend)) + return MatchesFriend(S, EC, cast(Friend)); + + assert(isa(Friend) && "unknown friend decl kind"); + return MatchesFriend(S, EC, cast(Friend)); } static Sema::AccessResult GetFriendKind(Sema &S, const EffectiveContext &EC, const CXXRecordDecl *Class) { - // A class always has access to its own members. - if (EC.includesClass(Class)) - return Sema::AR_accessible; - Sema::AccessResult OnFailure = Sema::AR_inaccessible; // Okay, check friends. @@ -209,9 +397,88 @@ static Sema::AccessResult GetFriendKind(Sema &S, return OnFailure; } +static Sema::AccessResult HasAccess(Sema &S, + const EffectiveContext &EC, + const CXXRecordDecl *NamingClass, + AccessSpecifier Access) { + assert(NamingClass->getCanonicalDecl() == NamingClass && + "declaration should be canonicalized before being passed here"); + + if (Access == AS_public) return Sema::AR_accessible; + assert(Access == AS_private || Access == AS_protected); + + for (EffectiveContext::record_iterator + I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { + // All the declarations in EC have been canonicalized, so pointer + // equality from this point on will work fine. + const CXXRecordDecl *ECRecord = *I; + + // [B2] and [M2] + if (ECRecord == NamingClass) + return Sema::AR_accessible; + + // [B3] and [M3] + if (Access == AS_protected && + ECRecord->isDerivedFrom(const_cast(NamingClass))) + return Sema::AR_accessible; + } + + return GetFriendKind(S, EC, NamingClass); +} + /// Finds the best path from the naming class to the declaring class, /// taking friend declarations into account. /// +/// C++0x [class.access.base]p5: +/// A member m is accessible at the point R when named in class N if +/// [M1] m as a member of N is public, or +/// [M2] m as a member of N is private, and R occurs in a member or +/// friend of class N, or +/// [M3] m as a member of N is protected, and R occurs in a member or +/// friend of class N, or in a member or friend of a class P +/// derived from N, where m as a member of P is public, private, +/// or protected, or +/// [M4] there exists a base class B of N that is accessible at R, and +/// m is accessible at R when named in class B. +/// +/// C++0x [class.access.base]p4: +/// A base class B of N is accessible at R, if +/// [B1] an invented public member of B would be a public member of N, or +/// [B2] R occurs in a member or friend of class N, and an invented public +/// member of B would be a private or protected member of N, or +/// [B3] R occurs in a member or friend of a class P derived from N, and an +/// invented public member of B would be a private or protected member +/// of P, or +/// [B4] there exists a class S such that B is a base class of S accessible +/// at R and S is a base class of N accessible at R. +/// +/// Along a single inheritance path we can restate both of these +/// iteratively: +/// +/// First, we note that M1-4 are equivalent to B1-4 if the member is +/// treated as a notional base of its declaring class with inheritance +/// access equivalent to the member's access. Therefore we need only +/// ask whether a class B is accessible from a class N in context R. +/// +/// Let B_1 .. B_n be the inheritance path in question (i.e. where +/// B_1 = N, B_n = B, and for all i, B_{i+1} is a direct base class of +/// B_i). For i in 1..n, we will calculate ACAB(i), the access to the +/// closest accessible base in the path: +/// Access(a, b) = (* access on the base specifier from a to b *) +/// Merge(a, forbidden) = forbidden +/// Merge(a, private) = forbidden +/// Merge(a, b) = min(a,b) +/// Accessible(c, forbidden) = false +/// Accessible(c, private) = (R is c) || IsFriend(c, R) +/// Accessible(c, protected) = (R derived from c) || IsFriend(c, R) +/// Accessible(c, public) = true +/// ACAB(n) = public +/// ACAB(i) = +/// let AccessToBase = Merge(Access(B_i, B_{i+1}), ACAB(i+1)) in +/// if Accessible(B_i, AccessToBase) then public else AccessToBase +/// +/// B is an accessible base of N at R iff ACAB(1) = public. +/// /// \param FinalAccess the access of the "final step", or AS_none if /// there is no final step. /// \return null if friendship is dependent @@ -230,6 +497,8 @@ static CXXBasePath *FindBestPath(Sema &S, assert(FinalAccess != AS_none && "forbidden access after declaring class"); + bool AnyDependent = false; + // Derive the friend-modified access along each path. for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end(); PI != PE; ++PI) { @@ -251,19 +520,15 @@ static CXXBasePath *FindBestPath(Sema &S, } AccessSpecifier BaseAccess = I->Base->getAccessSpecifier(); - if (BaseAccess != AS_public) { - switch (GetFriendKind(S, EC, I->Class)) { - case Sema::AR_inaccessible: - PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess); - break; - case Sema::AR_accessible: - PathAccess = AS_public; - break; - case Sema::AR_dependent: - return 0; - case Sema::AR_delayed: - llvm_unreachable("friend resolution is never delayed"); break; - } + PathAccess = std::max(PathAccess, BaseAccess); + switch (HasAccess(S, EC, I->Class, PathAccess)) { + case Sema::AR_inaccessible: break; + case Sema::AR_accessible: PathAccess = AS_public; break; + case Sema::AR_dependent: + AnyDependent = true; + goto Next; + case Sema::AR_delayed: + llvm_unreachable("friend resolution is never delayed"); break; } } @@ -272,9 +537,23 @@ static CXXBasePath *FindBestPath(Sema &S, if (BestPath == 0 || PathAccess < BestPath->Access) { BestPath = &*PI; BestPath->Access = PathAccess; + + // Short-circuit if we found a public path. + if (BestPath->Access == AS_public) + return BestPath; } + + Next: ; } + assert((!BestPath || BestPath->Access != AS_public) && + "fell out of loop with public path"); + + // We didn't find a public path, but at least one path was subject + // to dependent friendship, so delay the check. + if (AnyDependent) + return 0; + return BestPath; } @@ -282,16 +561,27 @@ static CXXBasePath *FindBestPath(Sema &S, /// to become inaccessible. static void DiagnoseAccessPath(Sema &S, const EffectiveContext &EC, - CXXRecordDecl *NamingClass, - CXXRecordDecl *DeclaringClass, - NamedDecl *D, AccessSpecifier Access) { + const Sema::AccessedEntity &Entity) { + AccessSpecifier Access = Entity.getAccess(); + CXXRecordDecl *NamingClass = Entity.getNamingClass(); + NamingClass = NamingClass->getCanonicalDecl(); + + NamedDecl *D; + CXXRecordDecl *DeclaringClass; + if (Entity.isMemberAccess()) { + D = Entity.getTargetDecl(); + DeclaringClass = FindDeclaringClass(D); + } else { + D = 0; + DeclaringClass = Entity.getBaseClass(); + } + DeclaringClass = DeclaringClass->getCanonicalDecl(); + // Easy case: the decl's natural access determined its path access. // We have to check against AS_private here in case Access is AS_none, // indicating a non-public member of a private base class. - // - // DependentFriend should be impossible here. if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) { - switch (GetFriendKind(S, EC, DeclaringClass)) { + switch (HasAccess(S, EC, DeclaringClass, D->getAccess())) { case Sema::AR_inaccessible: { S.Diag(D->getLocation(), diag::note_access_natural) << (unsigned) (Access == AS_protected) @@ -357,144 +647,166 @@ static void DiagnoseAccessPath(Sema &S, llvm_unreachable("access not apparently constrained by path"); } -/// Diagnose an inaccessible class member. -static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc, - const EffectiveContext &EC, - CXXRecordDecl *NamingClass, - AccessSpecifier Access, - const Sema::AccessedEntity &Entity) { - NamedDecl *D = Entity.getTargetDecl(); - CXXRecordDecl *DeclaringClass = FindDeclaringClass(D); +static void DiagnoseBadAccess(Sema &S, SourceLocation Loc, + const EffectiveContext &EC, + const Sema::AccessedEntity &Entity) { + const CXXRecordDecl *NamingClass = Entity.getNamingClass(); + NamedDecl *D; + const CXXRecordDecl *DeclaringClass; + if (Entity.isMemberAccess()) { + D = Entity.getTargetDecl(); + DeclaringClass = FindDeclaringClass(D); + } else { + D = 0; + DeclaringClass = Entity.getBaseClass(); + } S.Diag(Loc, Entity.getDiag()) - << (Access == AS_protected) - << D->getDeclName() + << (Entity.getAccess() == AS_protected) + << (D ? D->getDeclName() : DeclarationName()) << S.Context.getTypeDeclType(NamingClass) << S.Context.getTypeDeclType(DeclaringClass); - DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access); + DiagnoseAccessPath(S, EC, Entity); } -/// Diagnose an inaccessible hierarchy conversion. -static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc, - const EffectiveContext &EC, - AccessSpecifier Access, - const Sema::AccessedEntity &Entity) { - S.Diag(Loc, Entity.getDiag()) - << (Access == AS_protected) - << DeclarationName() - << S.Context.getTypeDeclType(Entity.getDerivedClass()) - << S.Context.getTypeDeclType(Entity.getBaseClass()); - DiagnoseAccessPath(S, EC, Entity.getDerivedClass(), - Entity.getBaseClass(), 0, Access); -} +/// Determines whether the accessed entity is accessible. Public members +/// have been weeded out by this point. +static Sema::AccessResult IsAccessible(Sema &S, + const EffectiveContext &EC, + const Sema::AccessedEntity &Entity) { + // Determine the actual naming class. + CXXRecordDecl *NamingClass = Entity.getNamingClass(); + while (NamingClass->isAnonymousStructOrUnion()) + NamingClass = cast(NamingClass->getParent()); + NamingClass = NamingClass->getCanonicalDecl(); -static void DiagnoseBadAccess(Sema &S, SourceLocation Loc, - const EffectiveContext &EC, - CXXRecordDecl *NamingClass, - AccessSpecifier Access, - const Sema::AccessedEntity &Entity) { - if (Entity.isMemberAccess()) - DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity); - else - DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity); -} + AccessSpecifier UnprivilegedAccess = Entity.getAccess(); + assert(UnprivilegedAccess != AS_public && "public access not weeded out"); + // Before we try to recalculate access paths, try to white-list + // accesses which just trade in on the final step, i.e. accesses + // which don't require [M4] or [B4]. These are by far the most + // common forms of access. + if (UnprivilegedAccess != AS_none) { + switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess)) { + case Sema::AR_dependent: + // This is actually an interesting policy decision. We don't + // *have* to delay immediately here: we can do the full access + // calculation in the hope that friendship on some intermediate + // class will make the declaration accessible non-dependently. + // But that's not cheap, and odds are very good (note: assertion + // made without data) that the friend declaration will determine + // access. + return Sema::AR_dependent; + + case Sema::AR_accessible: return Sema::AR_accessible; + case Sema::AR_inaccessible: break; + case Sema::AR_delayed: + llvm_unreachable("friendship never subject to contextual delay"); + } + } -/// Try to elevate access using friend declarations. This is -/// potentially quite expensive. -static void TryElevateAccess(Sema &S, - const EffectiveContext &EC, - const Sema::AccessedEntity &Entity, - AccessSpecifier &Access) { + // Determine the declaring class. CXXRecordDecl *DeclaringClass; if (Entity.isMemberAccess()) { DeclaringClass = FindDeclaringClass(Entity.getTargetDecl()); } else { DeclaringClass = Entity.getBaseClass(); } - CXXRecordDecl *NamingClass = Entity.getNamingClass(); + DeclaringClass = DeclaringClass->getCanonicalDecl(); + + // We lower member accesses to base accesses by pretending that the + // member is a base class of its declaring class. + AccessSpecifier FinalAccess; - // Adjust the declaration of the referred entity. - AccessSpecifier DeclAccess = AS_public; if (Entity.isMemberAccess()) { + // Determine if the declaration is accessible from EC when named + // in its declaring class. NamedDecl *Target = Entity.getTargetDecl(); - DeclAccess = Target->getAccess(); - if (DeclAccess != AS_public) { - switch (GetFriendKind(S, EC, DeclaringClass)) { - case Sema::AR_accessible: DeclAccess = AS_public; break; - case Sema::AR_inaccessible: break; - case Sema::AR_dependent: /* FIXME: delay dependent friendship */ return; - case Sema::AR_delayed: llvm_unreachable("friend status is never delayed"); - } + FinalAccess = Target->getAccess(); + switch (HasAccess(S, EC, DeclaringClass, FinalAccess)) { + case Sema::AR_accessible: FinalAccess = AS_public; break; + case Sema::AR_inaccessible: break; + case Sema::AR_dependent: return Sema::AR_dependent; // see above + case Sema::AR_delayed: llvm_unreachable("friend status is never delayed"); } - if (DeclaringClass == NamingClass) { - Access = DeclAccess; - return; - } + if (DeclaringClass == NamingClass) + return (FinalAccess == AS_public + ? Sema::AR_accessible + : Sema::AR_inaccessible); + } else { + FinalAccess = AS_public; } assert(DeclaringClass != NamingClass); // Append the declaration's access if applicable. CXXBasePaths Paths; - CXXBasePath *Path = FindBestPath(S, EC, Entity.getNamingClass(), - DeclaringClass, DeclAccess, Paths); - if (!Path) { - // FIXME: delay dependent friendship - return; - } + CXXBasePath *Path = FindBestPath(S, EC, NamingClass, DeclaringClass, + FinalAccess, Paths); + if (!Path) + return Sema::AR_dependent; + + assert(Path->Access <= UnprivilegedAccess && + "access along best path worse than direct?"); + if (Path->Access == AS_public) + return Sema::AR_accessible; + return Sema::AR_inaccessible; +} - // Grab the access along the best path (note that this includes the - // final-step access). - AccessSpecifier NewAccess = Path->Access; - assert(NewAccess <= Access && "access along best path worse than direct?"); - Access = NewAccess; +static void DelayAccess(Sema &S, + const EffectiveContext &EC, + SourceLocation Loc, + const Sema::AccessedEntity &Entity) { + assert(EC.isDependent() && "delaying non-dependent access"); + DeclContext *DC = EC.getInnerContext(); + assert(DC->isDependentContext() && "delaying non-dependent access"); + DependentDiagnostic::Create(S.Context, DC, DependentDiagnostic::Access, + Loc, + Entity.isMemberAccess(), + Entity.getAccess(), + Entity.getTargetDecl(), + Entity.getNamingClass(), + Entity.getDiag()); } /// Checks access to an entity from the given effective context. static Sema::AccessResult CheckEffectiveAccess(Sema &S, const EffectiveContext &EC, SourceLocation Loc, - Sema::AccessedEntity const &Entity) { - AccessSpecifier Access = Entity.getAccess(); - assert(Access != AS_public && "called for public access!"); + const Sema::AccessedEntity &Entity) { + assert(Entity.getAccess() != AS_public && "called for public access!"); - // Find a non-anonymous naming class. For records with access, - // there should always be one of these. - CXXRecordDecl *NamingClass = Entity.getNamingClass(); - while (NamingClass->isAnonymousStructOrUnion()) - NamingClass = cast(NamingClass->getParent()); + switch (IsAccessible(S, EC, Entity)) { + case Sema::AR_dependent: + DelayAccess(S, EC, Loc, Entity); + return Sema::AR_dependent; - // White-list accesses from classes with privileges equivalent to the - // naming class --- but only if the access path isn't forbidden - // (i.e. an access of a private member from a subclass). - if (Access != AS_none && EC.includesClass(NamingClass)) - return Sema::AR_accessible; + case Sema::AR_delayed: + llvm_unreachable("IsAccessible cannot contextually delay"); - // Try to elevate access. - // FIXME: delay if elevation was dependent? - // TODO: on some code, it might be better to do the protected check - // without trying to elevate first. - TryElevateAccess(S, EC, Entity, Access); - if (Access == AS_public) return Sema::AR_accessible; + case Sema::AR_inaccessible: + if (!Entity.isQuiet()) + DiagnoseBadAccess(S, Loc, EC, Entity); + return Sema::AR_inaccessible; - // Protected access. - if (Access == AS_protected) { - // FIXME: implement [class.protected]p1 - for (llvm::SmallVectorImpl::const_iterator - I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) - if ((*I)->isDerivedFrom(NamingClass)) - return Sema::AR_accessible; + case Sema::AR_accessible: + break; + } - // FIXME: delay if we can't decide class derivation yet. + // We only consider the natural access of the declaration when + // deciding whether to do the protected check. + if (Entity.isMemberAccess() && Entity.getAccess() == AS_protected) { + NamedDecl *D = Entity.getTargetDecl(); + if (isa(D) || + (isa(D) && cast(D)->isInstance())) { + // FIXME: implement [class.protected] + } } - // Okay, that's it, reject it. - if (!Entity.isQuiet()) - DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity); - return Sema::AR_inaccessible; + return Sema::AR_accessible; } static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, @@ -526,6 +838,37 @@ void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) { DD.Triggered = true; } +void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD, + const MultiLevelTemplateArgumentList &TemplateArgs) { + SourceLocation Loc = DD.getAccessLoc(); + AccessSpecifier Access = DD.getAccess(); + + Decl *NamingD = FindInstantiatedDecl(Loc, DD.getAccessNamingClass(), + TemplateArgs); + if (!NamingD) return; + Decl *TargetD = FindInstantiatedDecl(Loc, DD.getAccessTarget(), + TemplateArgs); + if (!TargetD) return; + + if (DD.isAccessToMember()) { + AccessedEntity Entity(Context, + AccessedEntity::Member, + cast(NamingD), + Access, + cast(TargetD)); + Entity.setDiag(DD.getDiagnostic()); + CheckAccess(*this, Loc, Entity); + } else { + AccessedEntity Entity(Context, + AccessedEntity::Base, + cast(TargetD), + cast(NamingD), + Access); + Entity.setDiag(DD.getDiagnostic()); + CheckAccess(*this, Loc, Entity); + } +} + Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, DeclAccessPair Found) { if (!getLangOptions().AccessControl || @@ -533,7 +876,8 @@ Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, Found.getAccess() == AS_public) return AR_accessible; - AccessedEntity Entity(AccessedEntity::Member, E->getNamingClass(), Found); + AccessedEntity Entity(Context, AccessedEntity::Member, E->getNamingClass(), + Found); Entity.setDiag(diag::err_access) << E->getSourceRange(); return CheckAccess(*this, E->getNameLoc(), Entity); @@ -547,7 +891,8 @@ Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, Found.getAccess() == AS_public) return AR_accessible; - AccessedEntity Entity(AccessedEntity::Member, E->getNamingClass(), Found); + AccessedEntity Entity(Context, AccessedEntity::Member, E->getNamingClass(), + Found); Entity.setDiag(diag::err_access) << E->getSourceRange(); return CheckAccess(*this, E->getMemberLoc(), Entity); @@ -565,7 +910,7 @@ Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc, return AR_accessible; CXXRecordDecl *NamingClass = Dtor->getParent(); - AccessedEntity Entity(AccessedEntity::Member, NamingClass, + AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, DeclAccessPair::make(Dtor, Access)); Entity.setDiag(PDiag); // TODO: avoid copy @@ -581,7 +926,7 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, return AR_accessible; CXXRecordDecl *NamingClass = Constructor->getParent(); - AccessedEntity Entity(AccessedEntity::Member, NamingClass, + AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, DeclAccessPair::make(Constructor, Access)); Entity.setDiag(diag::err_access_ctor); @@ -599,7 +944,7 @@ Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc, return AR_accessible; CXXRecordDecl *NamingClass = cast(Target->getDeclContext()); - AccessedEntity Entity(AccessedEntity::Member, NamingClass, + AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, DeclAccessPair::make(Target, Access)); Entity.setDiag(Diag); return CheckAccess(*this, UseLoc, Entity); @@ -616,7 +961,7 @@ Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, Found.getAccess() == AS_public) return AR_accessible; - AccessedEntity Entity(AccessedEntity::Member, NamingClass, Found); + AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found); Entity.setDiag(diag::err_access) << PlacementRange; @@ -637,7 +982,7 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, assert(RT && "found member operator but object expr not of record type"); CXXRecordDecl *NamingClass = cast(RT->getDecl()); - AccessedEntity Entity(AccessedEntity::Member, NamingClass, Found); + AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found); Entity.setDiag(diag::err_access) << ObjectExpr->getSourceRange() << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange()); @@ -645,6 +990,32 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, return CheckAccess(*this, OpLoc, Entity); } +Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr, + DeclAccessPair Found) { + if (!getLangOptions().AccessControl || + Found.getAccess() == AS_none || + Found.getAccess() == AS_public) + return AR_accessible; + + OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).getPointer(); + NestedNameSpecifier *Qualifier = Ovl->getQualifier(); + assert(Qualifier && "address of overloaded member without qualifier"); + + CXXScopeSpec SS; + SS.setScopeRep(Qualifier); + SS.setRange(Ovl->getQualifierRange()); + DeclContext *DC = computeDeclContext(SS); + assert(DC && DC->isRecord() && "scope did not resolve to record"); + CXXRecordDecl *NamingClass = cast(DC); + + AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found); + Entity.setDiag(diag::err_access) + << Ovl->getSourceRange(); + + return CheckAccess(*this, Ovl->getNameLoc(), Entity); +} + + /// Checks access for a hierarchy conversion. /// /// \param IsBaseToDerived whether this is a base-to-derived conversion (true) @@ -671,7 +1042,8 @@ Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc, BaseD = cast(Base->getAs()->getDecl()); DerivedD = cast(Derived->getAs()->getDecl()); - AccessedEntity Entity(AccessedEntity::Base, BaseD, DerivedD, Path.Access); + AccessedEntity Entity(Context, AccessedEntity::Base, BaseD, DerivedD, + Path.Access); if (DiagID) Entity.setDiag(DiagID) << Derived << Base; @@ -688,7 +1060,7 @@ void Sema::CheckLookupAccess(const LookupResult &R) { for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { if (I.getAccess() != AS_public) { - AccessedEntity Entity(AccessedEntity::Member, + AccessedEntity Entity(Context, AccessedEntity::Member, R.getNamingClass(), I.getPair()); Entity.setDiag(diag::err_access); diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 014cec2..11c8e6d 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -315,7 +315,7 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, assert(DestPointer && "Reference to void is not possible"); } else if (DestRecord) { if (Self.RequireCompleteType(OpRange.getBegin(), DestPointee, - PDiag(diag::err_bad_dynamic_cast_incomplete) + Self.PDiag(diag::err_bad_dynamic_cast_incomplete) << DestRange)) return; } else { @@ -353,7 +353,7 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const RecordType *SrcRecord = SrcPointee->getAs(); if (SrcRecord) { if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee, - PDiag(diag::err_bad_dynamic_cast_incomplete) + Self.PDiag(diag::err_bad_dynamic_cast_incomplete) << SrcExpr->getSourceRange())) return; } else { @@ -621,8 +621,8 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, return TC_Failed; } - // FIXME: Similar to CheckReferenceInit, we actually need more AST annotation - // than nothing. + // FIXME: We should probably have an AST node for lvalue-to-rvalue + // conversions. return TC_Success; } @@ -698,8 +698,8 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, QualType OrigDestType, unsigned &msg, CastExpr::CastKind &Kind) { // We can only work with complete types. But don't complain if it doesn't work - if (Self.RequireCompleteType(OpRange.getBegin(), SrcType, PDiag(0)) || - Self.RequireCompleteType(OpRange.getBegin(), DestType, PDiag(0))) + if (Self.RequireCompleteType(OpRange.getBegin(), SrcType, Self.PDiag(0)) || + Self.RequireCompleteType(OpRange.getBegin(), DestType, Self.PDiag(0))) return TC_NotApplicable; // Downcast can only happen in class hierarchies, so we need classes. @@ -808,8 +808,10 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, return TC_NotApplicable; bool WasOverloadedFunction = false; + DeclAccessPair FoundOverload; if (FunctionDecl *Fn - = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, false)) { + = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, false, + FoundOverload)) { CXXMethodDecl *M = cast(Fn); SrcType = Self.Context.getMemberPointerType(Fn->getType(), Self.Context.getTypeDeclType(M->getParent()).getTypePtr()); @@ -870,13 +872,14 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, // allowing complaints if something goes wrong. FunctionDecl *Fn = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, - true); + true, + FoundOverload); if (!Fn) { msg = 0; return TC_Failed; } - SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr, Fn); + SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr, FoundOverload, Fn); if (!SrcExpr) { msg = 0; return TC_Failed; @@ -913,27 +916,24 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, // At this point of CheckStaticCast, if the destination is a reference, // this has to work. There is no other way that works. // On the other hand, if we're checking a C-style cast, we've still got - // the reinterpret_cast way. So in C-style mode, we first try the call - // with an ICS to suppress errors. - if (CStyle) { - ImplicitConversionSequence ICS; - if(Self.CheckReferenceInit(SrcExpr, DestType, OpRange.getBegin(), - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, /*ForceRValue=*/false, - &ICS)) - return TC_NotApplicable; + // the reinterpret_cast way. + InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType); + InitializationKind InitKind = InitializationKind::CreateCast(OpRange, + CStyle); + InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExpr, 1); + if (InitSeq.getKind() == InitializationSequence::FailedSequence && CStyle) + return TC_NotApplicable; + + Sema::OwningExprResult Result + = InitSeq.Perform(Self, Entity, InitKind, + Action::MultiExprArg(Self, (void**)&SrcExpr, 1)); + if (Result.isInvalid()) { + msg = 0; + return TC_Failed; } - // Now we're committed either way. - if(!Self.CheckReferenceInit(SrcExpr, DestType, OpRange.getBegin(), - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, - /*ForceRValue=*/false, 0, - /*IgnoreBaseAccess=*/CStyle)) - return TC_Success; - - // We already got an error message. - msg = 0; - return TC_Failed; + + SrcExpr = Result.takeAs(); + return TC_Success; } if (DestType->isRecordType()) { diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 95b79ab..c90f75e 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -486,13 +486,13 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, if (LookupCtx) Diag(Found.getNameLoc(), diag::err_no_member_suggest) << Name << LookupCtx << Found.getLookupName() << SS.getRange() - << CodeModificationHint::CreateReplacement(Found.getNameLoc(), - Found.getLookupName().getAsString()); + << FixItHint::CreateReplacement(Found.getNameLoc(), + Found.getLookupName().getAsString()); else Diag(Found.getNameLoc(), diag::err_undeclared_var_use_suggest) << Name << Found.getLookupName() - << CodeModificationHint::CreateReplacement(Found.getNameLoc(), - Found.getLookupName().getAsString()); + << FixItHint::CreateReplacement(Found.getNameLoc(), + Found.getLookupName().getAsString()); if (NamedDecl *ND = Found.getAsSingle()) Diag(ND->getLocation(), diag::note_previous_decl) diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 0a33485..f2520fc 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -184,13 +184,11 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case Builtin::BI__sync_fetch_and_or: case Builtin::BI__sync_fetch_and_and: case Builtin::BI__sync_fetch_and_xor: - case Builtin::BI__sync_fetch_and_nand: case Builtin::BI__sync_add_and_fetch: case Builtin::BI__sync_sub_and_fetch: case Builtin::BI__sync_and_and_fetch: case Builtin::BI__sync_or_and_fetch: case Builtin::BI__sync_xor_and_fetch: - case Builtin::BI__sync_nand_and_fetch: case Builtin::BI__sync_val_compare_and_swap: case Builtin::BI__sync_bool_compare_and_swap: case Builtin::BI__sync_lock_test_and_set: @@ -222,11 +220,6 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { if (const FormatAttr *Format = FDecl->getAttr()) { if (CheckablePrintfAttr(Format, TheCall)) { bool HasVAListArg = Format->getFirstArg() == 0; - if (!HasVAListArg) { - if (const FunctionProtoType *Proto - = FDecl->getType()->getAs()) - HasVAListArg = !Proto->isVariadic(); - } CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1, HasVAListArg ? 0 : Format->getFirstArg() - 1); } @@ -257,12 +250,6 @@ bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) { return false; bool HasVAListArg = Format->getFirstArg() == 0; - if (!HasVAListArg) { - const FunctionType *FT = - Ty->getAs()->getPointeeType()->getAs(); - if (const FunctionProtoType *Proto = dyn_cast(FT)) - HasVAListArg = !Proto->isVariadic(); - } CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1, HasVAListArg ? 0 : Format->getFirstArg() - 1); @@ -315,14 +302,12 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { BUILTIN_ROW(__sync_fetch_and_or), BUILTIN_ROW(__sync_fetch_and_and), BUILTIN_ROW(__sync_fetch_and_xor), - BUILTIN_ROW(__sync_fetch_and_nand), BUILTIN_ROW(__sync_add_and_fetch), BUILTIN_ROW(__sync_sub_and_fetch), BUILTIN_ROW(__sync_and_and_fetch), BUILTIN_ROW(__sync_or_and_fetch), BUILTIN_ROW(__sync_xor_and_fetch), - BUILTIN_ROW(__sync_nand_and_fetch), BUILTIN_ROW(__sync_val_compare_and_swap), BUILTIN_ROW(__sync_bool_compare_and_swap), @@ -357,26 +342,24 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { case Builtin::BI__sync_fetch_and_or: BuiltinIndex = 2; break; case Builtin::BI__sync_fetch_and_and: BuiltinIndex = 3; break; case Builtin::BI__sync_fetch_and_xor: BuiltinIndex = 4; break; - case Builtin::BI__sync_fetch_and_nand:BuiltinIndex = 5; break; - case Builtin::BI__sync_add_and_fetch: BuiltinIndex = 6; break; - case Builtin::BI__sync_sub_and_fetch: BuiltinIndex = 7; break; - case Builtin::BI__sync_and_and_fetch: BuiltinIndex = 8; break; - case Builtin::BI__sync_or_and_fetch: BuiltinIndex = 9; break; - case Builtin::BI__sync_xor_and_fetch: BuiltinIndex =10; break; - case Builtin::BI__sync_nand_and_fetch:BuiltinIndex =11; break; + case Builtin::BI__sync_add_and_fetch: BuiltinIndex = 5; break; + case Builtin::BI__sync_sub_and_fetch: BuiltinIndex = 6; break; + case Builtin::BI__sync_and_and_fetch: BuiltinIndex = 7; break; + case Builtin::BI__sync_or_and_fetch: BuiltinIndex = 8; break; + case Builtin::BI__sync_xor_and_fetch: BuiltinIndex = 9; break; case Builtin::BI__sync_val_compare_and_swap: - BuiltinIndex = 12; + BuiltinIndex = 10; NumFixed = 2; break; case Builtin::BI__sync_bool_compare_and_swap: - BuiltinIndex = 13; + BuiltinIndex = 11; NumFixed = 2; break; - case Builtin::BI__sync_lock_test_and_set: BuiltinIndex = 14; break; + case Builtin::BI__sync_lock_test_and_set: BuiltinIndex = 12; break; case Builtin::BI__sync_lock_release: - BuiltinIndex = 15; + BuiltinIndex = 13; NumFixed = 0; break; } @@ -1045,6 +1028,7 @@ class CheckPrintfHandler : public analyze_printf::FormatStringHandler { Sema &S; const StringLiteral *FExpr; const Expr *OrigFormatExpr; + const unsigned FirstDataArg; const unsigned NumDataArgs; const bool IsObjCLiteral; const char *Beg; // Start of format string. @@ -1056,11 +1040,12 @@ class CheckPrintfHandler : public analyze_printf::FormatStringHandler { bool atFirstArg; public: CheckPrintfHandler(Sema &s, const StringLiteral *fexpr, - const Expr *origFormatExpr, + const Expr *origFormatExpr, unsigned firstDataArg, unsigned numDataArgs, bool isObjCLiteral, const char *beg, bool hasVAListArg, const CallExpr *theCall, unsigned formatIdx) : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), + FirstDataArg(firstDataArg), NumDataArgs(numDataArgs), IsObjCLiteral(isObjCLiteral), Beg(beg), HasVAListArg(hasVAListArg), @@ -1183,11 +1168,9 @@ void CheckPrintfHandler::HandleNullChar(const char *nullCharacter) { } const Expr *CheckPrintfHandler::getDataArg(unsigned i) const { - return TheCall->getArg(FormatIdx + i + 1); + return TheCall->getArg(FirstDataArg + i); } - - void CheckPrintfHandler::HandleFlags(const analyze_printf::FormatSpecifier &FS, llvm::StringRef flag, llvm::StringRef cspec, @@ -1329,9 +1312,18 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier return true; if (argIndex >= NumDataArgs) { - S.Diag(getLocationOfByte(CS.getStart()), - diag::warn_printf_insufficient_data_args) - << getFormatSpecifierRange(startSpecifier, specifierLen); + if (FS.usesPositionalArg()) { + S.Diag(getLocationOfByte(CS.getStart()), + diag::warn_printf_positional_arg_exceeds_data_args) + << (argIndex+1) << NumDataArgs + << getFormatSpecifierRange(startSpecifier, specifierLen); + } + else { + S.Diag(getLocationOfByte(CS.getStart()), + diag::warn_printf_insufficient_data_args) + << getFormatSpecifierRange(startSpecifier, specifierLen); + } + // Don't do any more checking. return false; } @@ -1400,7 +1392,7 @@ void Sema::CheckPrintfString(const StringLiteral *FExpr, return; } - CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, + CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, TheCall->getNumArgs() - firstDataArg, isa(OrigFormatExpr), Str, HasVAListArg, TheCall, format_idx); @@ -2262,10 +2254,6 @@ bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) { Diag(Param->getLocation(), diag::err_array_star_in_function_definition); } } - - if (getLangOptions().CPlusPlus) - if (const RecordType *RT = Param->getType()->getAs()) - FinalizeVarWithDestructor(Param, RT); } return HasInvalidParm; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index e11e161..f3d0dcf 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -14,7 +14,6 @@ #include "Sema.h" #include "SemaInit.h" #include "Lookup.h" -#include "AnalysisBasedWarnings.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -89,8 +88,8 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, return 0; // We know from the grammar that this name refers to a type, so build a - // TypenameType node to describe the type. - // FIXME: Record somewhere that this TypenameType node has no "typename" + // DependentNameType node to describe the type. + // FIXME: Record somewhere that this DependentNameType node has no "typename" // keyword associated with it. return CheckTypenameType((NestedNameSpecifier *)SS->getScopeRep(), II, SS->getRange()).getAsOpaquePtr(); @@ -199,7 +198,9 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, } else if (UnresolvedUsingTypenameDecl *UUDecl = dyn_cast(IIDecl)) { // FIXME: preserve source structure information. - T = Context.getTypenameType(UUDecl->getTargetNestedNameSpecifier(), &II); + T = Context.getDependentNameType(ETK_None, + UUDecl->getTargetNestedNameSpecifier(), + &II); } else { // If it's not plausibly a type, suppress diagnostics. Result.suppressDiagnostics(); @@ -256,13 +257,13 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, if (!SS || !SS->isSet()) Diag(IILoc, diag::err_unknown_typename_suggest) << &II << Lookup.getLookupName() - << CodeModificationHint::CreateReplacement(SourceRange(IILoc), - Result->getNameAsString()); + << FixItHint::CreateReplacement(SourceRange(IILoc), + Result->getNameAsString()); else if (DeclContext *DC = computeDeclContext(*SS, false)) Diag(IILoc, diag::err_unknown_nested_typename_suggest) << &II << DC << Lookup.getLookupName() << SS->getRange() - << CodeModificationHint::CreateReplacement(SourceRange(IILoc), - Result->getNameAsString()); + << FixItHint::CreateReplacement(SourceRange(IILoc), + Result->getNameAsString()); else llvm_unreachable("could not have corrected a typo here"); @@ -286,8 +287,7 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, Diag(SS->getRange().getBegin(), diag::err_typename_missing) << (NestedNameSpecifier *)SS->getScopeRep() << II.getName() << SourceRange(SS->getRange().getBegin(), IILoc) - << CodeModificationHint::CreateInsertion(SS->getRange().getBegin(), - "typename "); + << FixItHint::CreateInsertion(SS->getRange().getBegin(), "typename "); SuggestedType = ActOnTypenameType(SourceLocation(), *SS, II, IILoc).get(); } else { assert(SS && SS->isInvalid() && @@ -512,14 +512,30 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { // Types of valid local variables should be complete, so this should succeed. if (const ValueDecl *VD = dyn_cast(D)) { - if (const RecordType *RT = VD->getType()->getAs()) { - if (const CXXRecordDecl *RD = dyn_cast(RT->getDecl())) { + + // White-list anything with an __attribute__((unused)) type. + QualType Ty = VD->getType(); + + // Only look at the outermost level of typedef. + if (const TypedefType *TT = dyn_cast(Ty)) { + if (TT->getDecl()->hasAttr()) + return false; + } + + if (const TagType *TT = Ty->getAs()) { + const TagDecl *Tag = TT->getDecl(); + if (Tag->hasAttr()) + return false; + + if (const CXXRecordDecl *RD = dyn_cast(Tag)) { if (!RD->hasTrivialConstructor()) return false; if (!RD->hasTrivialDestructor()) return false; } } + + // TODO: __attribute__((unused)) templates? } return true; @@ -575,8 +591,7 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id, (IDecl = R.getAsSingle())) { Diag(RecoverLoc, diag::err_undef_interface_suggest) << Id << IDecl->getDeclName() - << CodeModificationHint::CreateReplacement(RecoverLoc, - IDecl->getNameAsString()); + << FixItHint::CreateReplacement(RecoverLoc, IDecl->getNameAsString()); Diag(IDecl->getLocation(), diag::note_previous_decl) << IDecl->getDeclName(); @@ -982,25 +997,28 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // other tests to run. const FunctionType *OldType = OldQType->getAs(); const FunctionType *NewType = New->getType()->getAs(); - if (OldType->getCallConv() != CC_Default && - NewType->getCallConv() == CC_Default) { - NewQType = Context.getCallConvType(NewQType, OldType->getCallConv()); + const FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo(); + const FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo(); + if (OldTypeInfo.getCC() != CC_Default && + NewTypeInfo.getCC() == CC_Default) { + NewQType = Context.getCallConvType(NewQType, OldTypeInfo.getCC()); New->setType(NewQType); NewQType = Context.getCanonicalType(NewQType); - } else if (!Context.isSameCallConv(OldType->getCallConv(), - NewType->getCallConv())) { + } else if (!Context.isSameCallConv(OldTypeInfo.getCC(), + NewTypeInfo.getCC())) { // Calling conventions really aren't compatible, so complain. Diag(New->getLocation(), diag::err_cconv_change) - << FunctionType::getNameForCallConv(NewType->getCallConv()) - << (OldType->getCallConv() == CC_Default) - << (OldType->getCallConv() == CC_Default ? "" : - FunctionType::getNameForCallConv(OldType->getCallConv())); + << FunctionType::getNameForCallConv(NewTypeInfo.getCC()) + << (OldTypeInfo.getCC() == CC_Default) + << (OldTypeInfo.getCC() == CC_Default ? "" : + FunctionType::getNameForCallConv(OldTypeInfo.getCC())); Diag(Old->getLocation(), diag::note_previous_declaration); return true; } // FIXME: diagnose the other way around? - if (OldType->getNoReturnAttr() && !NewType->getNoReturnAttr()) { + if (OldType->getNoReturnAttr() && + !NewType->getNoReturnAttr()) { NewQType = Context.getNoReturnType(NewQType); New->setType(NewQType); assert(NewQType.isCanonical()); @@ -1094,8 +1112,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { OldProto->isVariadic(), OldProto->getTypeQuals(), false, false, 0, 0, - OldProto->getNoReturnAttr(), - OldProto->getCallConv()); + OldProto->getExtInfo()); New->setType(NewQType); New->setHasInheritedPrototype(); @@ -1176,8 +1193,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { ArgTypes.size(), OldProto->isVariadic(), 0, false, false, 0, 0, - OldProto->getNoReturnAttr(), - OldProto->getCallConv())); + OldProto->getExtInfo())); return MergeCompatibleFunctionDecls(New, Old); } @@ -2132,7 +2148,8 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, << D.getCXXScopeSpec().getRange(); D.setInvalidType(); // Pretend we didn't see the scope specifier. - DC = 0; + DC = CurContext; + Previous.clear(); } if (getLangOptions().CPlusPlus) { @@ -2328,8 +2345,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (SC == VarDecl::Static) { Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_static_out_of_line) - << CodeModificationHint::CreateRemoval( - D.getDeclSpec().getStorageClassSpecLoc()); + << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); } else if (SC == VarDecl::None) SC = VarDecl::Static; } @@ -2405,7 +2421,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Diagnose shadowed variables before filtering for scope. if (!D.getCXXScopeSpec().isSet()) - DiagnoseShadow(S, D, Previous); + CheckShadow(S, NewVD, Previous); // Don't consider existing declarations that are in a different // scope and are out-of-semantic-context declarations (if the new @@ -2458,19 +2474,16 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, return NewVD; } -/// \brief Diagnose variable or built-in function shadowing. -/// -/// This method is called as soon as a NamedDecl materializes to check -/// if it shadows another local or global variable, or a built-in function. +/// \brief Diagnose variable or built-in function shadowing. Implements +/// -Wshadow. /// -/// For performance reasons, the lookup results are reused from the calling -/// context. +/// This method is called whenever a VarDecl is added to a "useful" +/// scope. /// /// \param S the scope in which the shadowing name is being declared /// \param R the lookup of the name /// -void Sema::DiagnoseShadow(Scope *S, Declarator &D, - const LookupResult& R) { +void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { // Return if warning is ignored. if (Diags.getDiagnosticLevel(diag::warn_decl_shadow) == Diagnostic::Ignored) return; @@ -2524,6 +2537,14 @@ void Sema::DiagnoseShadow(Scope *S, Declarator &D, Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration); } +/// \brief Check -Wshadow without the advantage of a previous lookup. +void Sema::CheckShadow(Scope *S, VarDecl *D) { + LookupResult R(*this, D->getDeclName(), D->getLocation(), + Sema::LookupOrdinaryName, Sema::ForRedeclaration); + LookupName(R, S); + CheckShadow(S, D, R); +} + /// \brief Perform semantic checking on a newly-created variable /// declaration. /// @@ -2913,6 +2934,28 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } else { // This is a function template specialization. isFunctionTemplateSpecialization = true; + + // C++0x [temp.expl.spec]p20 forbids "template<> void foo(int);". + if (isFriend && isFunctionTemplateSpecialization) { + // We want to remove the "template<>", found here. + SourceRange RemoveRange = TemplateParams->getSourceRange(); + + // If we remove the template<> and the name is not a + // template-id, we're actually silently creating a problem: + // the friend declaration will refer to an untemplated decl, + // and clearly the user wants a template specialization. So + // we need to insert '<>' after the name. + SourceLocation InsertLoc; + if (D.getName().getKind() != UnqualifiedId::IK_TemplateId) { + InsertLoc = D.getName().getSourceRange().getEnd(); + InsertLoc = PP.getLocForEndOfToken(InsertLoc); + } + + Diag(D.getIdentifierLoc(), diag::err_template_spec_decl_friend) + << Name << RemoveRange + << FixItHint::CreateRemoval(RemoveRange) + << FixItHint::CreateInsertion(InsertLoc, "<>"); + } } // FIXME: Free this memory properly. @@ -2931,8 +2974,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } else if (!CurContext->isRecord()) { // 'virtual' was specified outside of the class. Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_out_of_class) - << CodeModificationHint::CreateRemoval( - D.getDeclSpec().getVirtualSpecLoc()); + << FixItHint::CreateRemoval(D.getDeclSpec().getVirtualSpecLoc()); } else { // Okay: Add virtual to the method. CXXRecordDecl *CurClass = cast(DC); @@ -2949,16 +2991,14 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // 'explicit' was specified outside of the class. Diag(D.getDeclSpec().getExplicitSpecLoc(), diag::err_explicit_out_of_class) - << CodeModificationHint::CreateRemoval( - D.getDeclSpec().getExplicitSpecLoc()); + << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc()); } else if (!isa(NewFD) && !isa(NewFD)) { // 'explicit' was specified on a function that wasn't a constructor // or conversion function. Diag(D.getDeclSpec().getExplicitSpecLoc(), diag::err_explicit_non_ctor_or_conv_function) - << CodeModificationHint::CreateRemoval( - D.getDeclSpec().getExplicitSpecLoc()); + << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc()); } } @@ -2971,13 +3011,13 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, "previously-undeclared friend function being created " "in a non-namespace context"); + // For now, claim that the objects have no previous declaration. if (FunctionTemplate) { - FunctionTemplate->setObjectOfFriendDecl( - /* PreviouslyDeclared= */ !Previous.empty()); + FunctionTemplate->setObjectOfFriendDecl(false); FunctionTemplate->setAccess(AS_public); + } else { + NewFD->setObjectOfFriendDecl(false); } - else - NewFD->setObjectOfFriendDecl(/* PreviouslyDeclared= */ !Previous.empty()); NewFD->setAccess(AS_public); } @@ -2993,8 +3033,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // member function definition. Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_static_out_of_line) - << CodeModificationHint::CreateRemoval( - D.getDeclSpec().getStorageClassSpecLoc()); + << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); } // Handle GNU asm-label extension (encoded as an attribute). @@ -3092,18 +3131,28 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // too few of them). Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header) << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc) - << CodeModificationHint::CreateInsertion( + << FixItHint::CreateInsertion( D.getDeclSpec().getSourceRange().getBegin(), "template<> "); isFunctionTemplateSpecialization = true; + } else { + // "friend void foo<>(int);" is an implicit specialization decl. + isFunctionTemplateSpecialization = true; } } if (isFunctionTemplateSpecialization) { - if (CheckFunctionTemplateSpecialization(NewFD, - (HasExplicitTemplateArgs ? &TemplateArgs : 0), - Previous)) - NewFD->setInvalidDecl(); + if (isFriend && NewFD->getType()->isDependentType()) { + // FIXME: When we see a friend of a function template + // specialization with a dependent type, we can't match it now; + // for now, we just drop it, until we have a reasonable way to + // represent the parsed-but-not-matched friend function template + // specialization in the AST. + return 0; + } else if (CheckFunctionTemplateSpecialization(NewFD, + (HasExplicitTemplateArgs ? &TemplateArgs : 0), + Previous)) + NewFD->setInvalidDecl(); } else if (isExplicitSpecialization && isa(NewFD) && CheckMemberSpecialization(NewFD, Previous)) NewFD->setInvalidDecl(); @@ -3117,6 +3166,17 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); + if (isFriend && Redeclaration) { + AccessSpecifier Access = NewFD->getPreviousDeclaration()->getAccess(); + if (FunctionTemplate) { + FunctionTemplate->setObjectOfFriendDecl(true); + FunctionTemplate->setAccess(Access); + } else { + NewFD->setObjectOfFriendDecl(true); + } + NewFD->setAccess(Access); + } + // If we have a function template, check the template parameter // list. This will check and merge default template arguments. if (FunctionTemplate) { @@ -3303,7 +3363,8 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // Turn this into a variadic function with no parameters. QualType R = Context.getFunctionType( NewFD->getType()->getAs()->getResultType(), - 0, 0, true, 0, false, false, 0, 0, false, CC_Default); + 0, 0, true, 0, false, false, 0, 0, + FunctionType::ExtInfo()); NewFD->setType(R); return NewFD->setInvalidDecl(); } @@ -3747,6 +3808,41 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { return; } +/// ActOnInitializerError - Given that there was an error parsing an +/// initializer for the given declaration, try to return to some form +/// of sanity. +void Sema::ActOnInitializerError(DeclPtrTy dcl) { + // Our main concern here is re-establishing invariants like "a + // variable's type is either dependent or complete". + Decl *D = dcl.getAs(); + if (!D || D->isInvalidDecl()) return; + + VarDecl *VD = dyn_cast(D); + if (!VD) return; + + QualType Ty = VD->getType(); + if (Ty->isDependentType()) return; + + // Require a complete type. + if (RequireCompleteType(VD->getLocation(), + Context.getBaseElementType(Ty), + diag::err_typecheck_decl_incomplete_type)) { + VD->setInvalidDecl(); + return; + } + + // Require an abstract type. + if (RequireNonAbstractType(VD->getLocation(), Ty, + diag::err_abstract_type_in_decl, + AbstractVariableType)) { + VD->setInvalidDecl(); + return; + } + + // Don't bother complaining about constructors or destructors, + // though. +} + void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, bool TypeContainsUndeducedAuto) { Decl *RealDecl = dcl.getAs(); @@ -3984,8 +4080,6 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { II = 0; D.SetIdentifier(0, D.getIdentifierLoc()); D.setInvalidType(true); - } else { - DiagnoseShadow(S, D, R); } } } @@ -4075,7 +4169,7 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, << ";\n"; Diag(FTI.ArgInfo[i].IdentLoc, diag::ext_param_not_declared) << FTI.ArgInfo[i].Ident - << CodeModificationHint::CreateInsertion(LocAfterDecls, Code.str()); + << FixItHint::CreateInsertion(LocAfterDecls, Code.str()); // Implicitly declare the argument as type 'int' for lack of a better // type. @@ -4213,14 +4307,21 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { // Check the validity of our function parameters CheckParmsForFunctionDef(FD); + bool ShouldCheckShadow = + Diags.getDiagnosticLevel(diag::warn_decl_shadow) != Diagnostic::Ignored; + // Introduce our parameters into the function scope for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) { ParmVarDecl *Param = FD->getParamDecl(p); Param->setOwningFunction(FD); // If this has an identifier, add it to the scope stack. - if (Param->getIdentifier() && FnBodyScope) + if (Param->getIdentifier() && FnBodyScope) { + if (ShouldCheckShadow) + CheckShadow(FnBodyScope, Param); + PushOnScopeChains(Param, FnBodyScope); + } } // Checking attributes of current function definition @@ -4266,7 +4367,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, else FD = dyn_cast_or_null(dcl); - sema::AnalysisBasedWarnings W(*this); + sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy(); if (FD) { FD->setBody(Body); @@ -4274,7 +4375,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, // C and C++ allow for main to automagically return 0. // Implements C++ [basic.start.main]p5 and C99 5.1.2.2.3. FD->setHasImplicitReturnZero(true); - W.disableCheckFallThrough(); + WP.disableCheckFallThrough(); } if (!FD->isInvalidDecl()) @@ -4294,8 +4395,6 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, Body->Destroy(Context); return DeclPtrTy(); } - if (!IsInstantiation) - PopDeclContext(); // Verify and clean out per-function state. @@ -4371,12 +4470,15 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, ObjCMethodDecl *MD = cast(dcl); ResultType = MD->getResultType(); } - W.IssueWarnings(dcl); + AnalysisWarnings.IssueWarnings(WP, dcl); } assert(ExprTemporaries.empty() && "Leftover temporaries in function"); } + if (!IsInstantiation) + PopDeclContext(); + PopFunctionOrBlockScope(); // If any errors have occurred, clear out any temporaries that may have @@ -4577,7 +4679,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) << (NewTag == TagDecl::TK_class) << isTemplate << &Name - << CodeModificationHint::CreateReplacement(SourceRange(NewTagLoc), + << FixItHint::CreateReplacement(SourceRange(NewTagLoc), OldTag == TagDecl::TK_class? "class" : "struct"); Diag(Previous->getLocation(), diag::note_previous_use); return true; @@ -4684,7 +4786,8 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } // A tag 'foo::bar' must already exist. - Diag(NameLoc, diag::err_not_tag_in_scope) << Name << SS.getRange(); + Diag(NameLoc, diag::err_not_tag_in_scope) + << Kind << Name << DC << SS.getRange(); Name = 0; Invalid = true; goto CreateNewDecl; @@ -4732,6 +4835,79 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } } + // If we didn't find a previous declaration, and this is a reference + // (or friend reference), move to the correct scope. In C++, we + // also need to do a redeclaration lookup there, just in case + // there's a shadow friend decl. + if (Name && Previous.empty() && + (TUK == TUK_Reference || TUK == TUK_Friend)) { + if (Invalid) goto CreateNewDecl; + assert(SS.isEmpty()); + + if (TUK == TUK_Reference) { + // C++ [basic.scope.pdecl]p5: + // -- for an elaborated-type-specifier of the form + // + // class-key identifier + // + // if the elaborated-type-specifier is used in the + // decl-specifier-seq or parameter-declaration-clause of a + // function defined in namespace scope, the identifier is + // declared as a class-name in the namespace that contains + // the declaration; otherwise, except as a friend + // declaration, the identifier is declared in the smallest + // non-class, non-function-prototype scope that contains the + // declaration. + // + // C99 6.7.2.3p8 has a similar (but not identical!) provision for + // C structs and unions. + // + // It is an error in C++ to declare (rather than define) an enum + // type, including via an elaborated type specifier. We'll + // diagnose that later; for now, declare the enum in the same + // scope as we would have picked for any other tag type. + // + // GNU C also supports this behavior as part of its incomplete + // enum types extension, while GNU C++ does not. + // + // Find the context where we'll be declaring the tag. + // FIXME: We would like to maintain the current DeclContext as the + // lexical context, + while (SearchDC->isRecord()) + SearchDC = SearchDC->getParent(); + + // Find the scope where we'll be declaring the tag. + while (S->isClassScope() || + (getLangOptions().CPlusPlus && + S->isFunctionPrototypeScope()) || + ((S->getFlags() & Scope::DeclScope) == 0) || + (S->getEntity() && + ((DeclContext *)S->getEntity())->isTransparentContext())) + S = S->getParent(); + } else { + assert(TUK == TUK_Friend); + // C++ [namespace.memdef]p3: + // If a friend declaration in a non-local class first declares a + // class or function, the friend class or function is a member of + // the innermost enclosing namespace. + SearchDC = SearchDC->getEnclosingNamespaceContext(); + + // Look up through our scopes until we find one with an entity which + // matches our declaration context. + while (S->getEntity() && + ((DeclContext *)S->getEntity())->getPrimaryContext() != SearchDC) { + S = S->getParent(); + assert(S && "No enclosing scope matching the enclosing namespace."); + } + } + + // In C++, look for a shadow friend decl. + if (getLangOptions().CPlusPlus) { + Previous.setRedeclarationKind(ForRedeclaration); + LookupQualifiedName(Previous, SearchDC); + } + } + if (!Previous.empty()) { assert(Previous.isSingleResult()); NamedDecl *PrevDecl = Previous.getFoundDecl(); @@ -4750,8 +4926,8 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, if (SafeToContinue) Diag(KWLoc, diag::err_use_with_wrong_tag) << Name - << CodeModificationHint::CreateReplacement(SourceRange(KWLoc), - PrevTagDecl->getKindName()); + << FixItHint::CreateReplacement(SourceRange(KWLoc), + PrevTagDecl->getKindName()); else Diag(KWLoc, diag::err_use_with_wrong_tag) << Name; Diag(PrevTagDecl->getLocation(), diag::note_previous_use); @@ -4829,7 +5005,8 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } else { // PrevDecl is a namespace, template, or anything else // that lives in the IDNS_Tag identifier namespace. - if (isDeclInScope(PrevDecl, SearchDC, S)) { + if (TUK == TUK_Reference || TUK == TUK_Friend || + isDeclInScope(PrevDecl, SearchDC, S)) { // The tag name clashes with a namespace name, issue an error and // recover by making this tag be anonymous. Diag(NameLoc, diag::err_redefinition_different_kind) << Name; @@ -4843,60 +5020,6 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, Previous.clear(); } } - } else if (TUK == TUK_Reference && SS.isEmpty() && Name) { - // C++ [basic.scope.pdecl]p5: - // -- for an elaborated-type-specifier of the form - // - // class-key identifier - // - // if the elaborated-type-specifier is used in the - // decl-specifier-seq or parameter-declaration-clause of a - // function defined in namespace scope, the identifier is - // declared as a class-name in the namespace that contains - // the declaration; otherwise, except as a friend - // declaration, the identifier is declared in the smallest - // non-class, non-function-prototype scope that contains the - // declaration. - // - // C99 6.7.2.3p8 has a similar (but not identical!) provision for - // C structs and unions. - // - // It is an error in C++ to declare (rather than define) an enum - // type, including via an elaborated type specifier. We'll - // diagnose that later; for now, declare the enum in the same - // scope as we would have picked for any other tag type. - // - // GNU C also supports this behavior as part of its incomplete - // enum types extension, while GNU C++ does not. - // - // Find the context where we'll be declaring the tag. - // FIXME: We would like to maintain the current DeclContext as the - // lexical context, - while (SearchDC->isRecord()) - SearchDC = SearchDC->getParent(); - - // Find the scope where we'll be declaring the tag. - while (S->isClassScope() || - (getLangOptions().CPlusPlus && S->isFunctionPrototypeScope()) || - ((S->getFlags() & Scope::DeclScope) == 0) || - (S->getEntity() && - ((DeclContext *)S->getEntity())->isTransparentContext())) - S = S->getParent(); - - } else if (TUK == TUK_Friend && SS.isEmpty() && Name) { - // C++ [namespace.memdef]p3: - // If a friend declaration in a non-local class first declares a - // class or function, the friend class or function is a member of - // the innermost enclosing namespace. - SearchDC = SearchDC->getEnclosingNamespaceContext(); - - // Look up through our scopes until we find one with an entity which - // matches our declaration context. - while (S->getEntity() && - ((DeclContext *)S->getEntity())->getPrimaryContext() != SearchDC) { - S = S->getParent(); - assert(S && "No enclosing scope matching the enclosing namespace."); - } } CreateNewDecl: @@ -5013,7 +5136,7 @@ CreateNewDecl: New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ !Previous.empty()); // Set the access specifier. - if (!Invalid && TUK != TUK_Friend) + if (!Invalid && SearchDC->isRecord()) SetMemberAccessSpecifier(New, PrevDecl, AS); if (TUK == TUK_Definition) @@ -5026,13 +5149,11 @@ CreateNewDecl: if (PrevDecl) New->setAccess(PrevDecl->getAccess()); - // Friend tag decls are visible in fairly strange ways. - if (!CurContext->isDependentContext()) { - DeclContext *DC = New->getDeclContext()->getLookupContext(); - DC->makeDeclVisibleInContext(New, /* Recoverable = */ false); + DeclContext *DC = New->getDeclContext()->getLookupContext(); + DC->makeDeclVisibleInContext(New, /* Recoverable = */ false); + if (Name) // can be null along some error paths if (Scope *EnclosingScope = getScopeForDeclContext(S, DC)) PushOnScopeChains(New, EnclosingScope, /* AddToContext = */ false); - } } else if (Name) { S = getNonFieldDeclScope(S); PushOnScopeChains(New, S); @@ -5261,6 +5382,10 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, FieldDecl *NewFD = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, TSSL, AS, PrevDecl, &D); + + if (NewFD->isInvalidDecl()) + Record->setInvalidDecl(); + if (NewFD->isInvalidDecl() && PrevDecl) { // Don't introduce NewFD into scope; there's already something // with the same name in the same scope. @@ -5804,7 +5929,7 @@ void Sema::ActOnFields(Scope* S, } else if (ObjCCategoryDecl *CDecl = dyn_cast(EnclosingDecl)) { if (!LangOpts.ObjCNonFragileABI2 || !CDecl->IsClassExtension()) - Diag(LBrac, diag::err_misplaced_ivar); + Diag(LBrac, diag::err_misplaced_ivar) << CDecl->IsClassExtension(); else { // FIXME. Class extension does not have a LocEnd field. // CDecl->setLocEnd(RBrac); diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 73a34f8..cc24735 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -490,6 +490,9 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr, } static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) { + // NOTE: We don't add the attribute to a FunctionDecl because the noreturn + // trait will be part of the function's type. + // Don't apply as a decl attribute to ValueDecl. // FIXME: probably ought to diagnose this. if (isa(d)) @@ -521,7 +524,8 @@ static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - if (!isa(d) && !isa(d) && !isFunctionOrMethod(d)) { + if (!isa(d) && !isa(d) && !isFunctionOrMethod(d) && + !isa(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 2 /*variable and function*/; return; @@ -834,18 +838,24 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S) return; } - if (!isFunction(D)) { + if (!isFunction(D) && !isa(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 0 /*function*/; return; } - if (getFunctionType(D)->getResultType()->isVoidType()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_void_function) - << Attr.getName(); + if (isFunction(D) && getFunctionType(D)->getResultType()->isVoidType()) { + S.Diag(Attr.getLoc(), diag::warn_attribute_void_function_method) + << Attr.getName() << 0; return; } - + if (const ObjCMethodDecl *MD = dyn_cast(D)) + if (MD->getResultType()->isVoidType()) { + S.Diag(Attr.getLoc(), diag::warn_attribute_void_function_method) + << Attr.getName() << 1; + return; + } + D->addAttr(::new (S.Context) WarnUnusedResultAttr()); } @@ -1115,6 +1125,7 @@ enum FormatAttrKind { NSStringFormat, StrftimeFormat, SupportedFormat, + IgnoredFormat, InvalidFormat }; @@ -1136,6 +1147,10 @@ static FormatAttrKind getFormatAttrKind(llvm::StringRef Format) { Format == "zcmn_err") return SupportedFormat; + if (Format == "gcc_diag" || Format == "gcc_cdiag" || + Format == "gcc_cxxdiag" || Format == "gcc_tdiag") + return IgnoredFormat; + return InvalidFormat; } @@ -1171,6 +1186,10 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { // Check for supported formats. FormatAttrKind Kind = getFormatAttrKind(Format); + + if (Kind == IgnoredFormat) + return; + if (Kind == InvalidFormat) { S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) << "format" << Attr.getParameterName()->getName(); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 13a7ead..47df435 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1104,8 +1104,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, // member. Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest) << MemberOrBase << true << R.getLookupName() - << CodeModificationHint::CreateReplacement(R.getNameLoc(), - R.getLookupName().getAsString()); + << FixItHint::CreateReplacement(R.getNameLoc(), + R.getLookupName().getAsString()); Diag(Member->getLocation(), diag::note_previous_decl) << Member->getDeclName(); @@ -1123,8 +1123,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, // that base class. Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest) << MemberOrBase << false << R.getLookupName() - << CodeModificationHint::CreateReplacement(R.getNameLoc(), - R.getLookupName().getAsString()); + << FixItHint::CreateReplacement(R.getNameLoc(), + R.getLookupName().getAsString()); const CXXBaseSpecifier *BaseSpec = DirectBaseSpec? DirectBaseSpec : VirtualBaseSpec; @@ -1429,134 +1429,106 @@ bool Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, CXXBaseOrMemberInitializer **Initializers, unsigned NumInitializers, - bool IsImplicitConstructor, bool AnyErrors) { + if (Constructor->isDependentContext()) { + // Just store the initializers as written, they will be checked during + // instantiation. + if (NumInitializers > 0) { + Constructor->setNumBaseOrMemberInitializers(NumInitializers); + CXXBaseOrMemberInitializer **baseOrMemberInitializers = + new (Context) CXXBaseOrMemberInitializer*[NumInitializers]; + memcpy(baseOrMemberInitializers, Initializers, + NumInitializers * sizeof(CXXBaseOrMemberInitializer*)); + Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers); + } + + return false; + } + // We need to build the initializer AST according to order of construction // and not what user specified in the Initializers list. - CXXRecordDecl *ClassDecl = cast(Constructor->getDeclContext()); + CXXRecordDecl *ClassDecl = Constructor->getParent()->getDefinition(); + if (!ClassDecl) + return true; + llvm::SmallVector AllToInit; llvm::DenseMap AllBaseFields; - bool HasDependentBaseInit = false; bool HadError = false; for (unsigned i = 0; i < NumInitializers; i++) { CXXBaseOrMemberInitializer *Member = Initializers[i]; - if (Member->isBaseInitializer()) { - if (Member->getBaseClass()->isDependentType()) - HasDependentBaseInit = true; + + if (Member->isBaseInitializer()) AllBaseFields[Member->getBaseClass()->getAs()] = Member; - } else { + else AllBaseFields[Member->getMember()] = Member; - } } - if (HasDependentBaseInit) { - // FIXME. This does not preserve the ordering of the initializers. - // Try (with -Wreorder) - // template struct A {}; - // template struct B : A { - // B() : x1(10), A() {} - // int x1; - // }; - // B x; - // On seeing one dependent type, we should essentially exit this routine - // while preserving user-declared initializer list. When this routine is - // called during instantiatiation process, this routine will rebuild the - // ordered initializer list correctly. - - // If we have a dependent base initialization, we can't determine the - // association between initializers and bases; just dump the known - // initializers into the list, and don't try to deal with other bases. - for (unsigned i = 0; i < NumInitializers; i++) { - CXXBaseOrMemberInitializer *Member = Initializers[i]; - if (Member->isBaseInitializer()) - AllToInit.push_back(Member); - } - } else { - llvm::SmallVector BasesToDefaultInit; - - // Push virtual bases before others. - for (CXXRecordDecl::base_class_iterator VBase = - ClassDecl->vbases_begin(), - E = ClassDecl->vbases_end(); VBase != E; ++VBase) { - if (VBase->getType()->isDependentType()) - continue; - if (CXXBaseOrMemberInitializer *Value - = AllBaseFields.lookup(VBase->getType()->getAs())) { - AllToInit.push_back(Value); - } else if (!AnyErrors) { - InitializedEntity InitEntity - = InitializedEntity::InitializeBase(Context, VBase); - InitializationKind InitKind - = InitializationKind::CreateDefault(Constructor->getLocation()); - InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); - OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind, - MultiExprArg(*this, 0, 0)); - BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit)); - if (BaseInit.isInvalid()) { - HadError = true; - continue; - } + llvm::SmallVector BasesToDefaultInit; - // Don't attach synthesized base initializers in a dependent - // context; they'll be checked again at template instantiation - // time. - if (CurContext->isDependentContext()) - continue; - - CXXBaseOrMemberInitializer *CXXBaseInit = - new (Context) CXXBaseOrMemberInitializer(Context, - Context.getTrivialTypeSourceInfo(VBase->getType(), - SourceLocation()), - SourceLocation(), - BaseInit.takeAs(), - SourceLocation()); - AllToInit.push_back(CXXBaseInit); - } - } + // Push virtual bases before others. + for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(), + E = ClassDecl->vbases_end(); VBase != E; ++VBase) { - for (CXXRecordDecl::base_class_iterator Base = - ClassDecl->bases_begin(), - E = ClassDecl->bases_end(); Base != E; ++Base) { - // Virtuals are in the virtual base list and already constructed. - if (Base->isVirtual()) - continue; - // Skip dependent types. - if (Base->getType()->isDependentType()) + if (CXXBaseOrMemberInitializer *Value + = AllBaseFields.lookup(VBase->getType()->getAs())) { + AllToInit.push_back(Value); + } else if (!AnyErrors) { + InitializedEntity InitEntity + = InitializedEntity::InitializeBase(Context, VBase); + InitializationKind InitKind + = InitializationKind::CreateDefault(Constructor->getLocation()); + InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); + OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind, + MultiExprArg(*this, 0, 0)); + BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit)); + if (BaseInit.isInvalid()) { + HadError = true; continue; - if (CXXBaseOrMemberInitializer *Value - = AllBaseFields.lookup(Base->getType()->getAs())) { - AllToInit.push_back(Value); } - else if (!AnyErrors) { - InitializedEntity InitEntity - = InitializedEntity::InitializeBase(Context, Base); - InitializationKind InitKind - = InitializationKind::CreateDefault(Constructor->getLocation()); - InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); - OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind, - MultiExprArg(*this, 0, 0)); - BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit)); - if (BaseInit.isInvalid()) { - HadError = true; - continue; - } - - // Don't attach synthesized base initializers in a dependent - // context; they'll be regenerated at template instantiation - // time. - if (CurContext->isDependentContext()) - continue; - CXXBaseOrMemberInitializer *CXXBaseInit = - new (Context) CXXBaseOrMemberInitializer(Context, - Context.getTrivialTypeSourceInfo(Base->getType(), - SourceLocation()), - SourceLocation(), - BaseInit.takeAs(), - SourceLocation()); - AllToInit.push_back(CXXBaseInit); + CXXBaseOrMemberInitializer *CXXBaseInit = + new (Context) CXXBaseOrMemberInitializer(Context, + Context.getTrivialTypeSourceInfo(VBase->getType(), + SourceLocation()), + SourceLocation(), + BaseInit.takeAs(), + SourceLocation()); + AllToInit.push_back(CXXBaseInit); + } + } + + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), + E = ClassDecl->bases_end(); Base != E; ++Base) { + // Virtuals are in the virtual base list and already constructed. + if (Base->isVirtual()) + continue; + + if (CXXBaseOrMemberInitializer *Value + = AllBaseFields.lookup(Base->getType()->getAs())) { + AllToInit.push_back(Value); + } else if (!AnyErrors) { + InitializedEntity InitEntity + = InitializedEntity::InitializeBase(Context, Base); + InitializationKind InitKind + = InitializationKind::CreateDefault(Constructor->getLocation()); + InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); + OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind, + MultiExprArg(*this, 0, 0)); + BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit)); + if (BaseInit.isInvalid()) { + HadError = true; + continue; } + + CXXBaseOrMemberInitializer *CXXBaseInit = + new (Context) CXXBaseOrMemberInitializer(Context, + Context.getTrivialTypeSourceInfo(Base->getType(), + SourceLocation()), + SourceLocation(), + BaseInit.takeAs(), + SourceLocation()); + AllToInit.push_back(CXXBaseInit); } } @@ -1624,14 +1596,14 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, } else if (FT->isReferenceType()) { Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor) - << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl) + << (int)Constructor->isImplicit() << Context.getTagDeclType(ClassDecl) << 0 << (*Field)->getDeclName(); Diag((*Field)->getLocation(), diag::note_declared_at); HadError = true; } else if (FT.isConstQualified()) { Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor) - << (int)IsImplicitConstructor << Context.getTagDeclType(ClassDecl) + << (int)Constructor->isImplicit() << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getDeclName(); Diag((*Field)->getLocation(), diag::note_declared_at); HadError = true; @@ -1665,121 +1637,70 @@ static void *GetKeyForTopLevelField(FieldDecl *Field) { return static_cast(Field); } -static void *GetKeyForBase(QualType BaseType) { - if (const RecordType *RT = BaseType->getAs()) - return (void *)RT; - - assert(0 && "Unexpected base type!"); - return 0; +static void *GetKeyForBase(ASTContext &Context, QualType BaseType) { + return Context.getCanonicalType(BaseType).getTypePtr(); } -static void *GetKeyForMember(CXXBaseOrMemberInitializer *Member, +static void *GetKeyForMember(ASTContext &Context, + CXXBaseOrMemberInitializer *Member, bool MemberMaybeAnon = false) { + if (!Member->isMemberInitializer()) + return GetKeyForBase(Context, QualType(Member->getBaseClass(), 0)); + // For fields injected into the class via declaration of an anonymous union, // use its anonymous union class declaration as the unique key. - if (Member->isMemberInitializer()) { - FieldDecl *Field = Member->getMember(); - - // After SetBaseOrMemberInitializers call, Field is the anonymous union - // data member of the class. Data member used in the initializer list is - // in AnonUnionMember field. - if (MemberMaybeAnon && Field->isAnonymousStructOrUnion()) - Field = Member->getAnonUnionMember(); - if (Field->getDeclContext()->isRecord()) { - RecordDecl *RD = cast(Field->getDeclContext()); - if (RD->isAnonymousStructOrUnion()) - return static_cast(RD); - } - return static_cast(Field); - } - - return GetKeyForBase(QualType(Member->getBaseClass(), 0)); -} - -/// ActOnMemInitializers - Handle the member initializers for a constructor. -void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, - SourceLocation ColonLoc, - MemInitTy **MemInits, unsigned NumMemInits, - bool AnyErrors) { - if (!ConstructorDecl) - return; + FieldDecl *Field = Member->getMember(); - AdjustDeclIfTemplate(ConstructorDecl); - - CXXConstructorDecl *Constructor - = dyn_cast(ConstructorDecl.getAs()); - - if (!Constructor) { - Diag(ColonLoc, diag::err_only_constructors_take_base_inits); - return; - } - - if (!Constructor->isDependentContext()) { - llvm::DenseMapMembers; - bool err = false; - for (unsigned i = 0; i < NumMemInits; i++) { - CXXBaseOrMemberInitializer *Member = - static_cast(MemInits[i]); - void *KeyToMember = GetKeyForMember(Member); - CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember]; - if (!PrevMember) { - PrevMember = Member; - continue; - } - if (FieldDecl *Field = Member->getMember()) - Diag(Member->getSourceLocation(), - diag::error_multiple_mem_initialization) - << Field->getNameAsString() - << Member->getSourceRange(); - else { - Type *BaseClass = Member->getBaseClass(); - assert(BaseClass && "ActOnMemInitializers - neither field or base"); - Diag(Member->getSourceLocation(), - diag::error_multiple_base_initialization) - << QualType(BaseClass, 0) - << Member->getSourceRange(); - } - Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer) - << 0; - err = true; - } - - if (err) - return; - } + // After SetBaseOrMemberInitializers call, Field is the anonymous union + // data member of the class. Data member used in the initializer list is + // in AnonUnionMember field. + if (MemberMaybeAnon && Field->isAnonymousStructOrUnion()) + Field = Member->getAnonUnionMember(); + + // If the field is a member of an anonymous union, we use record decl of the + // union as the key. + RecordDecl *RD = Field->getParent(); + if (RD->isAnonymousStructOrUnion() && RD->isUnion()) + return static_cast(RD); - SetBaseOrMemberInitializers(Constructor, - reinterpret_cast(MemInits), - NumMemInits, false, AnyErrors); + return static_cast(Field); +} +static void +DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef, + const CXXConstructorDecl *Constructor, + CXXBaseOrMemberInitializer **MemInits, + unsigned NumMemInits) { if (Constructor->isDependentContext()) return; - if (Diags.getDiagnosticLevel(diag::warn_base_initialized) == + if (SemaRef.Diags.getDiagnosticLevel(diag::warn_base_initialized) == Diagnostic::Ignored && - Diags.getDiagnosticLevel(diag::warn_field_initialized) == + SemaRef.Diags.getDiagnosticLevel(diag::warn_field_initialized) == Diagnostic::Ignored) return; - + // Also issue warning if order of ctor-initializer list does not match order // of 1) base class declarations and 2) order of non-static data members. llvm::SmallVector AllBaseOrMembers; - CXXRecordDecl *ClassDecl - = cast(Constructor->getDeclContext()); + const CXXRecordDecl *ClassDecl = Constructor->getParent(); + // Push virtual bases before others. - for (CXXRecordDecl::base_class_iterator VBase = + for (CXXRecordDecl::base_class_const_iterator VBase = ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); VBase != E; ++VBase) - AllBaseOrMembers.push_back(GetKeyForBase(VBase->getType())); + AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context, + VBase->getType())); - for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), + for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(), E = ClassDecl->bases_end(); Base != E; ++Base) { // Virtuals are alread in the virtual base list and are constructed // first. if (Base->isVirtual()) continue; - AllBaseOrMembers.push_back(GetKeyForBase(Base->getType())); + AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context, + Base->getType())); } for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), @@ -1790,9 +1711,8 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, int curIndex = 0; CXXBaseOrMemberInitializer *PrevMember = 0; for (unsigned i = 0; i < NumMemInits; i++) { - CXXBaseOrMemberInitializer *Member = - static_cast(MemInits[i]); - void *MemberInCtorList = GetKeyForMember(Member, true); + CXXBaseOrMemberInitializer *Member = MemInits[i]; + void *MemberInCtorList = GetKeyForMember(SemaRef.Context, Member, true); for (; curIndex < Last; curIndex++) if (MemberInCtorList == AllBaseOrMembers[curIndex]) @@ -1804,23 +1724,23 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, if (PrevMember->isBaseInitializer()) { // Diagnostics is for an initialized base class. Type *BaseClass = PrevMember->getBaseClass(); - Diag(PrevMember->getSourceLocation(), - diag::warn_base_initialized) + SemaRef.Diag(PrevMember->getSourceLocation(), + diag::warn_base_initialized) << QualType(BaseClass, 0); } else { FieldDecl *Field = PrevMember->getMember(); - Diag(PrevMember->getSourceLocation(), - diag::warn_field_initialized) + SemaRef.Diag(PrevMember->getSourceLocation(), + diag::warn_field_initialized) << Field->getNameAsString(); } // Also the note! if (FieldDecl *Field = Member->getMember()) - Diag(Member->getSourceLocation(), - diag::note_fieldorbase_initialized_here) << 0 + SemaRef.Diag(Member->getSourceLocation(), + diag::note_fieldorbase_initialized_here) << 0 << Field->getNameAsString(); else { Type *BaseClass = Member->getBaseClass(); - Diag(Member->getSourceLocation(), + SemaRef.Diag(Member->getSourceLocation(), diag::note_fieldorbase_initialized_here) << 1 << QualType(BaseClass, 0); } @@ -1832,6 +1752,64 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, } } +/// ActOnMemInitializers - Handle the member initializers for a constructor. +void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, + SourceLocation ColonLoc, + MemInitTy **meminits, unsigned NumMemInits, + bool AnyErrors) { + if (!ConstructorDecl) + return; + + AdjustDeclIfTemplate(ConstructorDecl); + + CXXConstructorDecl *Constructor + = dyn_cast(ConstructorDecl.getAs()); + + if (!Constructor) { + Diag(ColonLoc, diag::err_only_constructors_take_base_inits); + return; + } + + CXXBaseOrMemberInitializer **MemInits = + reinterpret_cast(meminits); + + llvm::DenseMap Members; + bool HadError = false; + for (unsigned i = 0; i < NumMemInits; i++) { + CXXBaseOrMemberInitializer *Member = MemInits[i]; + + void *KeyToMember = GetKeyForMember(Context, Member); + CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember]; + if (!PrevMember) { + PrevMember = Member; + continue; + } + if (FieldDecl *Field = Member->getMember()) + Diag(Member->getSourceLocation(), + diag::error_multiple_mem_initialization) + << Field->getNameAsString() + << Member->getSourceRange(); + else { + Type *BaseClass = Member->getBaseClass(); + assert(BaseClass && "ActOnMemInitializers - neither field or base"); + Diag(Member->getSourceLocation(), + diag::error_multiple_base_initialization) + << QualType(BaseClass, 0) + << Member->getSourceRange(); + } + Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer) + << 0; + HadError = true; + } + + if (HadError) + return; + + DiagnoseBaseOrMemInitializerOrder(*this, Constructor, MemInits, NumMemInits); + + SetBaseOrMemberInitializers(Constructor, MemInits, NumMemInits, AnyErrors); +} + void Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, CXXRecordDecl *ClassDecl) { @@ -1861,7 +1839,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor(Context); CheckDestructorAccess(Field->getLocation(), Dtor, - PartialDiagnostic(diag::err_access_dtor_field) + PDiag(diag::err_access_dtor_field) << Field->getDeclName() << FieldType); @@ -1889,7 +1867,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, // FIXME: caret should be on the start of the class name CheckDestructorAccess(Base->getSourceRange().getBegin(), Dtor, - PartialDiagnostic(diag::err_access_dtor_base) + PDiag(diag::err_access_dtor_base) << Base->getType() << Base->getSourceRange()); @@ -1914,7 +1892,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context); CheckDestructorAccess(ClassDecl->getLocation(), Dtor, - PartialDiagnostic(diag::err_access_dtor_vbase) + PDiag(diag::err_access_dtor_vbase) << VBase->getType()); MarkDeclarationReferenced(Location, const_cast(Dtor)); @@ -1925,94 +1903,11 @@ void Sema::ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) { if (!CDtorDecl) return; - AdjustDeclIfTemplate(CDtorDecl); - if (CXXConstructorDecl *Constructor = dyn_cast(CDtorDecl.getAs())) - SetBaseOrMemberInitializers(Constructor, 0, 0, false, false); -} - -namespace { - /// PureVirtualMethodCollector - traverses a class and its superclasses - /// and determines if it has any pure virtual methods. - class PureVirtualMethodCollector { - ASTContext &Context; - - public: - typedef llvm::SmallVector MethodList; - - private: - MethodList Methods; - - void Collect(const CXXRecordDecl* RD, MethodList& Methods); - - public: - PureVirtualMethodCollector(ASTContext &Ctx, const CXXRecordDecl* RD) - : Context(Ctx) { - - MethodList List; - Collect(RD, List); - - // Copy the temporary list to methods, and make sure to ignore any - // null entries. - for (size_t i = 0, e = List.size(); i != e; ++i) { - if (List[i]) - Methods.push_back(List[i]); - } - } - - bool empty() const { return Methods.empty(); } - - MethodList::const_iterator methods_begin() { return Methods.begin(); } - MethodList::const_iterator methods_end() { return Methods.end(); } - }; - - void PureVirtualMethodCollector::Collect(const CXXRecordDecl* RD, - MethodList& Methods) { - // First, collect the pure virtual methods for the base classes. - for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(), - BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) { - if (const RecordType *RT = Base->getType()->getAs()) { - const CXXRecordDecl *BaseDecl = cast(RT->getDecl()); - if (BaseDecl && BaseDecl->isAbstract()) - Collect(BaseDecl, Methods); - } - } - - // Next, zero out any pure virtual methods that this class overrides. - typedef llvm::SmallPtrSet MethodSetTy; - - MethodSetTy OverriddenMethods; - size_t MethodsSize = Methods.size(); - - for (RecordDecl::decl_iterator i = RD->decls_begin(), e = RD->decls_end(); - i != e; ++i) { - // Traverse the record, looking for methods. - if (CXXMethodDecl *MD = dyn_cast(*i)) { - // If the method is pure virtual, add it to the methods vector. - if (MD->isPure()) - Methods.push_back(MD); - - // Record all the overridden methods in our set. - for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), - E = MD->end_overridden_methods(); I != E; ++I) { - // Keep track of the overridden methods. - OverriddenMethods.insert(*I); - } - } - } - - // Now go through the methods and zero out all the ones we know are - // overridden. - for (size_t i = 0, e = MethodsSize; i != e; ++i) { - if (OverriddenMethods.count(Methods[i])) - Methods[i] = 0; - } - - } + SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false); } - bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID, AbstractDiagSelID SelID, const CXXRecordDecl *CurrentRD) { @@ -2066,14 +1961,32 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, if (PureVirtualClassDiagSet && PureVirtualClassDiagSet->count(RD)) return true; - PureVirtualMethodCollector Collector(Context, RD); + CXXFinalOverriderMap FinalOverriders; + RD->getFinalOverriders(FinalOverriders); + + for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(), + MEnd = FinalOverriders.end(); + M != MEnd; + ++M) { + for (OverridingMethods::iterator SO = M->second.begin(), + SOEnd = M->second.end(); + SO != SOEnd; ++SO) { + // C++ [class.abstract]p4: + // A class is abstract if it contains or inherits at least one + // pure virtual function for which the final overrider is pure + // virtual. + + // + if (SO->second.size() != 1) + continue; - for (PureVirtualMethodCollector::MethodList::const_iterator I = - Collector.methods_begin(), E = Collector.methods_end(); I != E; ++I) { - const CXXMethodDecl *MD = *I; + if (!SO->second.front().Method->isPure()) + continue; - Diag(MD->getLocation(), diag::note_pure_virtual_function) << - MD->getDeclName(); + Diag(SO->second.front().Method->getLocation(), + diag::note_pure_virtual_function) + << SO->second.front().Method->getDeclName(); + } } if (!PureVirtualClassDiagSet) @@ -2162,22 +2075,79 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { for (UnresolvedSetIterator I = Convs->begin(), E = Convs->end(); I != E; ++I) Convs->setAccess(I, (*I)->getAccess()); - if (!Record->isAbstract()) { - // Collect all the pure virtual methods and see if this is an abstract - // class after all. - PureVirtualMethodCollector Collector(Context, Record); - if (!Collector.empty()) - Record->setAbstract(true); + // Determine whether we need to check for final overriders. We do + // this either when there are virtual base classes (in which case we + // may end up finding multiple final overriders for a given virtual + // function) or any of the base classes is abstract (in which case + // we might detect that this class is abstract). + bool CheckFinalOverriders = false; + if (Record->isPolymorphic() && !Record->isInvalidDecl() && + !Record->isDependentType()) { + if (Record->getNumVBases()) + CheckFinalOverriders = true; + else if (!Record->isAbstract()) { + for (CXXRecordDecl::base_class_const_iterator B = Record->bases_begin(), + BEnd = Record->bases_end(); + B != BEnd; ++B) { + CXXRecordDecl *BaseDecl + = cast(B->getType()->getAs()->getDecl()); + if (BaseDecl->isAbstract()) { + CheckFinalOverriders = true; + break; + } + } + } + } + + if (CheckFinalOverriders) { + CXXFinalOverriderMap FinalOverriders; + Record->getFinalOverriders(FinalOverriders); + + for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(), + MEnd = FinalOverriders.end(); + M != MEnd; ++M) { + for (OverridingMethods::iterator SO = M->second.begin(), + SOEnd = M->second.end(); + SO != SOEnd; ++SO) { + assert(SO->second.size() > 0 && + "All virtual functions have overridding virtual functions"); + if (SO->second.size() == 1) { + // C++ [class.abstract]p4: + // A class is abstract if it contains or inherits at least one + // pure virtual function for which the final overrider is pure + // virtual. + if (SO->second.front().Method->isPure()) + Record->setAbstract(true); + continue; + } + + // C++ [class.virtual]p2: + // In a derived class, if a virtual member function of a base + // class subobject has more than one final overrider the + // program is ill-formed. + Diag(Record->getLocation(), diag::err_multiple_final_overriders) + << (NamedDecl *)M->first << Record; + Diag(M->first->getLocation(), diag::note_overridden_virtual_function); + for (OverridingMethods::overriding_iterator OM = SO->second.begin(), + OMEnd = SO->second.end(); + OM != OMEnd; ++OM) + Diag(OM->Method->getLocation(), diag::note_final_overrider) + << (NamedDecl *)M->first << OM->Method->getParent(); + + Record->setInvalidDecl(); + } + } } - if (Record->isAbstract()) + if (Record->isAbstract() && !Record->isInvalidDecl()) (void)AbstractClassUsageDiagnoser(*this, Record); } void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, DeclPtrTy TagDecl, SourceLocation LBrac, - SourceLocation RBrac) { + SourceLocation RBrac, + AttributeList *AttrList) { if (!TagDecl) return; @@ -2185,7 +2155,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, ActOnFields(S, RLoc, TagDecl, (DeclPtrTy*)FieldCollector->getCurFields(), - FieldCollector->getCurNumFields(), LBrac, RBrac, 0); + FieldCollector->getCurNumFields(), LBrac, RBrac, AttrList); CheckCompletedCXXClass( dyn_cast_or_null(TagDecl.getAs())); @@ -2218,8 +2188,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { Context.getFunctionType(Context.VoidTy, 0, 0, false, 0, /*FIXME*/false, false, - 0, 0, false, - CC_Default), + 0, 0, + FunctionType::ExtInfo()), /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, @@ -2293,8 +2263,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { &ArgType, 1, false, 0, /*FIXME:*/false, - false, 0, 0, false, - CC_Default), + false, 0, 0, + FunctionType::ExtInfo()), /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, @@ -2382,8 +2352,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { Context.getFunctionType(RetType, &ArgType, 1, false, 0, /*FIXME:*/false, - false, 0, 0, false, - CC_Default), + false, 0, 0, + FunctionType::ExtInfo()), /*TInfo=*/0, /*isStatic=*/false, /*isInline=*/true); CopyAssignment->setAccess(AS_public); CopyAssignment->setImplicit(); @@ -2412,8 +2382,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { QualType Ty = Context.getFunctionType(Context.VoidTy, 0, 0, false, 0, /*FIXME:*/false, - false, 0, 0, false, - CC_Default); + false, 0, 0, FunctionType::ExtInfo()); DeclarationName Name = Context.DeclarationNames.getCXXDestructorName(ClassType); @@ -2586,8 +2555,7 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R, Proto->hasAnyExceptionSpec(), Proto->getNumExceptions(), Proto->exception_begin(), - Proto->getNoReturnAttr(), - Proto->getCallConv()); + Proto->getExtInfo()); } /// CheckConstructor - Checks a fully-formed constructor for @@ -2615,7 +2583,7 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) { SourceLocation ParamLoc = Constructor->getParamDecl(0)->getLocation(); Diag(ParamLoc, diag::err_constructor_byvalue_arg) - << CodeModificationHint::CreateInsertion(ParamLoc, " const &"); + << FixItHint::CreateInsertion(ParamLoc, " const &"); // FIXME: Rather that making the constructor invalid, we should endeavor // to fix the type. @@ -2746,7 +2714,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, // will put in a result type of "int" when none was specified. // FIXME: Exceptions! return Context.getFunctionType(Context.VoidTy, 0, 0, false, 0, - false, false, 0, 0, false, CC_Default); + false, false, 0, 0, FunctionType::ExtInfo()); } /// CheckConversionDeclarator - Called by ActOnDeclarator to check the @@ -2822,8 +2790,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, Proto->hasAnyExceptionSpec(), Proto->getNumExceptions(), Proto->exception_begin(), - Proto->getNoReturnAttr(), - Proto->getCallConv()); + Proto->getExtInfo()); // C++0x explicit conversion operators. if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x) @@ -2962,7 +2929,6 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, } else { // Anonymous namespaces. assert(Namespc->isAnonymousNamespace()); - CurContext->addDecl(Namespc); // Link the anonymous namespace into its parent. NamespaceDecl *PrevDecl; @@ -2984,6 +2950,8 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, PrevDecl->setNextNamespace(Namespc); } + CurContext->addDecl(Namespc); + // C++ [namespace.unnamed]p1. An unnamed-namespace-definition // behaves as if it were replaced by // namespace unique { /* empty body */ } @@ -3160,8 +3128,7 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, UsingLoc = Name.getSourceRange().getBegin(); Diag(UsingLoc, diag::warn_access_decl_deprecated) - << CodeModificationHint::CreateInsertion(SS.getRange().getBegin(), - "using "); + << FixItHint::CreateInsertion(SS.getRange().getBegin(), "using "); } NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS, @@ -3330,6 +3297,11 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S, CurContext->addDecl(Shadow); Shadow->setAccess(UD->getAccess()); + // Register it as a conversion if appropriate. + if (Shadow->getDeclName().getNameKind() + == DeclarationName::CXXConversionFunctionName) + cast(CurContext)->addConversionFunction(Shadow); + if (Orig->isInvalidDecl() || UD->isInvalidDecl()) Shadow->setInvalidDecl(); @@ -3364,6 +3336,10 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S, /// decl structures are (very reasonably) not designed for removal. /// (2) avoids this but is very fiddly and phase-dependent. void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) { + if (Shadow->getDeclName().getNameKind() == + DeclarationName::CXXConversionFunctionName) + cast(Shadow->getDeclContext())->removeConversion(Shadow); + // Remove it from the DeclContext... Shadow->getDeclContext()->removeDecl(Shadow); @@ -3377,7 +3353,7 @@ void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) { Shadow->getUsingDecl()->removeShadowDecl(Shadow); // TODO: complain somehow if Shadow was used. It shouldn't - // be possible for this to happen, because + // be possible for this to happen, because...? } /// Builds a using declaration. @@ -3738,8 +3714,10 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, if (NamespaceAliasDecl *AD = dyn_cast(PrevDecl)) { // We already have an alias with the same name that points to the same // namespace, so don't create a new one. + // FIXME: At some point, we'll want to create the (redundant) + // declaration to maintain better source information. if (!R.isAmbiguous() && !R.empty() && - AD->getNamespace() == getNamespaceDecl(R.getFoundDecl())) + AD->getNamespace()->Equals(getNamespaceDecl(R.getFoundDecl()))) return DeclPtrTy(); } @@ -3780,7 +3758,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, DeclContext *PreviousContext = CurContext; CurContext = Constructor; - if (SetBaseOrMemberInitializers(Constructor, 0, 0, true, false)) { + if (SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false)) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXDefaultConstructor << Context.getTagDeclType(ClassDecl); Constructor->setInvalidDecl(); @@ -3847,7 +3825,7 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, BaseClassDecl)) { CheckDirectMemberAccess(Base->getSourceRange().getBegin(), BaseAssignOpMethod, - PartialDiagnostic(diag::err_access_assign_base) + PDiag(diag::err_access_assign_base) << Base->getType()); MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod); @@ -3866,7 +3844,7 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, FieldClassDecl)) { CheckDirectMemberAccess(Field->getLocation(), FieldAssignOpMethod, - PartialDiagnostic(diag::err_access_assign_field) + PDiag(diag::err_access_assign_field) << Field->getDeclName() << Field->getType()); MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod); @@ -3948,7 +3926,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, BaseClassDecl->getCopyConstructor(Context, TypeQuals)) { CheckDirectMemberAccess(Base->getSourceRange().getBegin(), BaseCopyCtor, - PartialDiagnostic(diag::err_access_copy_base) + PDiag(diag::err_access_copy_base) << Base->getType()); MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor); @@ -3967,7 +3945,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, FieldClassDecl->getCopyConstructor(Context, TypeQuals)) { CheckDirectMemberAccess(Field->getLocation(), FieldCopyCtor, - PartialDiagnostic(diag::err_access_copy_field) + PDiag(diag::err_access_copy_field) << Field->getDeclName() << Field->getType()); MarkDeclarationReferenced(CurrentLocation, FieldCopyCtor); @@ -4062,7 +4040,7 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { CXXDestructorDecl *Destructor = ClassDecl->getDestructor(Context); MarkDeclarationReferenced(VD->getLocation(), Destructor); CheckDestructorAccess(VD->getLocation(), Destructor, - PartialDiagnostic(diag::err_access_dtor_var) + PDiag(diag::err_access_dtor_var) << VD->getDeclName() << VD->getType()); } @@ -4408,16 +4386,18 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // to resolve the overloaded function. If all goes well, T2 is the // type of the resulting function. if (Context.getCanonicalType(T2) == Context.OverloadTy) { + DeclAccessPair Found; FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType, - ICS != 0); + ICS != 0, Found); if (Fn) { // Since we're performing this reference-initialization for // real, update the initializer with the resulting function. if (!ICS) { if (DiagnoseUseOfDecl(Fn, DeclLoc)) - return true; + return true; - Init = FixOverloadedFunctionReference(Init, Fn); + CheckAddressOfMemberAccess(Init, Found); + Init = FixOverloadedFunctionReference(Init, Found, Fn); } T2 = Fn->getType(); @@ -5378,7 +5358,8 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, // friend templates because ActOnTag never produces a ClassTemplateDecl // for a TUK_Friend. Declarator TheDeclarator(DS, Declarator::MemberContext); - QualType T = GetTypeForDeclarator(TheDeclarator, S); + TypeSourceInfo *TSI; + QualType T = GetTypeForDeclarator(TheDeclarator, S, &TSI); if (TheDeclarator.isInvalidType()) return DeclPtrTy(); @@ -5396,7 +5377,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, // // FIXME: handle "template <> friend class A;", which // is possibly well-formed? Who even knows? - if (TempParams.size() && !isa(T)) { + if (TempParams.size() && !T->isElaboratedTypeSpecifier()) { Diag(Loc, diag::err_tagless_friend_type_template) << DS.getSourceRange(); return DeclPtrTy(); @@ -5408,7 +5389,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, // * The class-key of the elaborated-type-specifier is required. // This is one of the rare places in Clang where it's legitimate to // ask about the "spelling" of the type. - if (!getLangOptions().CPlusPlus0x && !isa(T)) { + if (!getLangOptions().CPlusPlus0x && !T->isElaboratedTypeSpecifier()) { // If we evaluated the type to a record type, suggest putting // a tag in front. if (const RecordType *RT = T->getAs()) { @@ -5420,8 +5401,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, << (unsigned) RD->getTagKind() << T << SourceRange(DS.getFriendSpecLoc()) - << CodeModificationHint::CreateInsertion(DS.getTypeSpecTypeLoc(), - InsertionText); + << FixItHint::CreateInsertion(DS.getTypeSpecTypeLoc(), InsertionText); return DeclPtrTy(); }else { Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend) @@ -5443,16 +5423,20 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, // deadline. It's also a very silly restriction that seriously // affects inner classes and which nobody else seems to implement; // thus we never diagnose it, not even in -pedantic. + // + // But note that we could warn about it: it's always useless to + // friend one of your own members (it's not, however, worthless to + // friend a member of an arbitrary specialization of your template). Decl *D; if (TempParams.size()) D = FriendTemplateDecl::Create(Context, CurContext, Loc, TempParams.size(), (TemplateParameterList**) TempParams.release(), - T.getTypePtr(), + TSI, DS.getFriendSpecLoc()); else - D = FriendDecl::Create(Context, CurContext, Loc, T.getTypePtr(), + D = FriendDecl::Create(Context, CurContext, Loc, TSI, DS.getFriendSpecLoc()); D->setAccess(AS_public); CurContext->addDecl(D); @@ -5889,7 +5873,7 @@ static bool needsVtable(CXXMethodDecl *MD, ASTContext &Context) { break; case TSK_ExplicitInstantiationDeclaration: - return true; //FIXME: This looks wrong. + return false; case TSK_ExplicitInstantiationDefinition: // This is method of a explicit instantiation; mark all of the virtual @@ -5945,7 +5929,8 @@ bool Sema::ProcessPendingClassesWithUnmarkedVirtualMembers() { return true; } -void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD) { +void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, + const CXXRecordDecl *RD) { for (CXXRecordDecl::method_iterator i = RD->method_begin(), e = RD->method_end(); i != e; ++i) { CXXMethodDecl *MD = *i; @@ -5955,4 +5940,19 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD) { if (MD->isVirtual() && !MD->isPure()) MarkDeclarationReferenced(Loc, MD); } + + // Only classes that have virtual bases need a VTT. + if (RD->getNumVBases() == 0) + return; + + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast(i->getType()->getAs()->getDecl()); + if (i->isVirtual()) + continue; + if (Base->getNumVBases() == 0) + continue; + MarkVirtualMembersReferenced(Loc, Base); + } } diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index b2f6717..9bc0846 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -559,8 +559,8 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation( << ClassName << R.getLookupName(); Diag(IDecl->getLocation(), diag::note_previous_decl) << R.getLookupName() - << CodeModificationHint::CreateReplacement(ClassLoc, - R.getLookupName().getAsString()); + << FixItHint::CreateReplacement(ClassLoc, + R.getLookupName().getAsString()); IDecl = 0; } else { Diag(ClassLoc, diag::warn_undef_interface) << ClassName; @@ -667,8 +667,6 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, Diag(ClsIvar->getLocation(), diag::note_previous_definition); continue; } - if (ImplIvar->getAccessControl() != ObjCIvarDecl::Private) - Diag(ImplIvar->getLocation(), diag::err_non_private_ivar_declaration); // Instance ivar to Implementation's DeclContext. ImplIvar->setLexicalDeclContext(ImpDecl); IDecl->makeDeclVisibleInContext(ImplIvar, false); @@ -721,12 +719,13 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, } void Sema::WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method, - bool &IncompleteImpl) { + bool &IncompleteImpl, unsigned DiagID) { if (!IncompleteImpl) { Diag(ImpLoc, diag::warn_incomplete_impl); IncompleteImpl = true; } - Diag(ImpLoc, diag::warn_undef_method_impl) << method->getDeclName(); + Diag(method->getLocation(), DiagID) + << method->getDeclName(); } void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl, @@ -770,7 +769,14 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, bool& IncompleteImpl, const llvm::DenseSet &InsMap, const llvm::DenseSet &ClsMap, - ObjCInterfaceDecl *IDecl) { + ObjCContainerDecl *CDecl) { + ObjCInterfaceDecl *IDecl; + if (ObjCCategoryDecl *C = dyn_cast(CDecl)) + IDecl = C->getClassInterface(); + else + IDecl = dyn_cast(CDecl); + assert (IDecl && "CheckProtocolMethodDefs - IDecl is null"); + ObjCInterfaceDecl *Super = IDecl->getSuperClass(); ObjCInterfaceDecl *NSIDecl = 0; if (getLangOptions().NeXTRuntime) { @@ -808,8 +814,14 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, // uses the protocol. ObjCMethodDecl *MethodInClass = IDecl->lookupInstanceMethod(method->getSelector()); - if (!MethodInClass || !MethodInClass->isSynthesized()) - WarnUndefinedMethod(ImpLoc, method, IncompleteImpl); + if (!MethodInClass || !MethodInClass->isSynthesized()) { + unsigned DIAG = diag::warn_unimplemented_protocol_method; + if (Diags.getDiagnosticLevel(DIAG) != Diagnostic::Ignored) { + WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG); + Diag(CDecl->getLocation(), diag::note_required_for_protocol_at) + << PDecl->getDeclName(); + } + } } } // check unimplemented class methods @@ -819,8 +831,14 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, ObjCMethodDecl *method = *I; if (method->getImplementationControl() != ObjCMethodDecl::Optional && !ClsMap.count(method->getSelector()) && - (!Super || !Super->lookupClassMethod(method->getSelector()))) - WarnUndefinedMethod(ImpLoc, method, IncompleteImpl); + (!Super || !Super->lookupClassMethod(method->getSelector()))) { + unsigned DIAG = diag::warn_unimplemented_protocol_method; + if (Diags.getDiagnosticLevel(DIAG) != Diagnostic::Ignored) { + WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG); + Diag(IDecl->getLocation(), diag::note_required_for_protocol_at) << + PDecl->getDeclName(); + } + } } // Check on this protocols's referenced protocols, recursively. for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), @@ -849,7 +867,8 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet &InsMap, if (!(*I)->isSynthesized() && !InsMap.count((*I)->getSelector())) { if (ImmediateClass) - WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl); + WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl, + diag::note_undef_method_impl); continue; } else { ObjCMethodDecl *ImpMethodDecl = @@ -873,7 +892,8 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet &InsMap, ClsMapSeen.insert((*I)->getSelector()); if (!ClsMap.count((*I)->getSelector())) { if (ImmediateClass) - WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl); + WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl, + diag::note_undef_method_impl); } else { ObjCMethodDecl *ImpMethodDecl = IMPDecl->getClassMethod((*I)->getSelector()); @@ -950,7 +970,7 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, for (ObjCCategoryDecl::protocol_iterator PI = C->protocol_begin(), E = C->protocol_end(); PI != E; ++PI) CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, - InsMap, ClsMap, C->getClassInterface()); + InsMap, ClsMap, CDecl); // Report unimplemented properties in the category as well. // When reporting on missing setter/getters, do not report when // setter/getter is implemented in category's primary class diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 4ce1ce9..53e9385 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -15,6 +15,8 @@ #include "clang/AST/CXXInheritance.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/TypeLoc.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/SmallPtrSet.h" @@ -94,19 +96,21 @@ bool Sema::CheckDistantExceptionSpec(QualType T) { } bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { + bool MissingExceptionSpecification = false; bool MissingEmptyExceptionSpecification = false; - if (!CheckEquivalentExceptionSpec(diag::err_mismatched_exception_spec, - diag::note_previous_declaration, + if (!CheckEquivalentExceptionSpec(PDiag(diag::err_mismatched_exception_spec), + PDiag(diag::note_previous_declaration), Old->getType()->getAs(), Old->getLocation(), New->getType()->getAs(), New->getLocation(), + &MissingExceptionSpecification, &MissingEmptyExceptionSpecification)) return false; // The failure was something other than an empty exception // specification; return an error. - if (!MissingEmptyExceptionSpecification) + if (!MissingExceptionSpecification && !MissingEmptyExceptionSpecification) return true; // The new function declaration is only missing an empty exception @@ -117,8 +121,10 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { // to many libc functions as an optimization. Unfortunately, that // optimization isn't permitted by the C++ standard, so we're forced // to work around it here. - if (isa(New->getType()) && - Context.getSourceManager().isInSystemHeader(Old->getLocation()) && + if (MissingEmptyExceptionSpecification && + isa(New->getType()) && + (Old->getLocation().isInvalid() || + Context.getSourceManager().isInSystemHeader(Old->getLocation())) && Old->isExternC()) { const FunctionProtoType *NewProto = cast(New->getType()); @@ -128,12 +134,91 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { NewProto->isVariadic(), NewProto->getTypeQuals(), true, false, 0, 0, - NewProto->getNoReturnAttr(), - NewProto->getCallConv()); + NewProto->getExtInfo()); New->setType(NewType); return false; } + if (MissingExceptionSpecification && isa(New->getType())) { + const FunctionProtoType *NewProto + = cast(New->getType()); + const FunctionProtoType *OldProto + = Old->getType()->getAs(); + + // Update the type of the function with the appropriate exception + // specification. + QualType NewType = Context.getFunctionType(NewProto->getResultType(), + NewProto->arg_type_begin(), + NewProto->getNumArgs(), + NewProto->isVariadic(), + NewProto->getTypeQuals(), + OldProto->hasExceptionSpec(), + OldProto->hasAnyExceptionSpec(), + OldProto->getNumExceptions(), + OldProto->exception_begin(), + NewProto->getExtInfo()); + New->setType(NewType); + + // If exceptions are disabled, suppress the warning about missing + // exception specifications for new and delete operators. + if (!getLangOptions().Exceptions) { + switch (New->getDeclName().getCXXOverloadedOperator()) { + case OO_New: + case OO_Array_New: + case OO_Delete: + case OO_Array_Delete: + if (New->getDeclContext()->isTranslationUnit()) + return false; + break; + + default: + break; + } + } + + // Warn about the lack of exception specification. + llvm::SmallString<128> ExceptionSpecString; + llvm::raw_svector_ostream OS(ExceptionSpecString); + OS << "throw("; + bool OnFirstException = true; + for (FunctionProtoType::exception_iterator E = OldProto->exception_begin(), + EEnd = OldProto->exception_end(); + E != EEnd; + ++E) { + if (OnFirstException) + OnFirstException = false; + else + OS << ", "; + + OS << E->getAsString(Context.PrintingPolicy); + } + OS << ")"; + OS.flush(); + + SourceLocation AfterParenLoc; + if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) { + TypeLoc TL = TSInfo->getTypeLoc(); + if (const FunctionTypeLoc *FTLoc = dyn_cast(&TL)) + AfterParenLoc = PP.getLocForEndOfToken(FTLoc->getRParenLoc()); + } + + if (AfterParenLoc.isInvalid()) + Diag(New->getLocation(), diag::warn_missing_exception_specification) + << New << OS.str(); + else { + // FIXME: This will get more complicated with C++0x + // late-specified return types. + Diag(New->getLocation(), diag::warn_missing_exception_specification) + << New << OS.str() + << FixItHint::CreateInsertion(AfterParenLoc, " " + OS.str().str()); + } + + if (!Old->getLocation().isInvalid()) + Diag(Old->getLocation(), diag::note_previous_declaration); + + return false; + } + Diag(New->getLocation(), diag::err_mismatched_exception_spec); Diag(Old->getLocation(), diag::note_previous_declaration); return true; @@ -146,8 +231,9 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { bool Sema::CheckEquivalentExceptionSpec( const FunctionProtoType *Old, SourceLocation OldLoc, const FunctionProtoType *New, SourceLocation NewLoc) { - return CheckEquivalentExceptionSpec(diag::err_mismatched_exception_spec, - diag::note_previous_declaration, + return CheckEquivalentExceptionSpec( + PDiag(diag::err_mismatched_exception_spec), + PDiag(diag::note_previous_declaration), Old, OldLoc, New, NewLoc); } @@ -155,11 +241,17 @@ bool Sema::CheckEquivalentExceptionSpec( /// exception specifications. Exception specifications are equivalent if /// they allow exactly the same set of exception types. It does not matter how /// that is achieved. See C++ [except.spec]p2. -bool Sema::CheckEquivalentExceptionSpec( - const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, - const FunctionProtoType *Old, SourceLocation OldLoc, - const FunctionProtoType *New, SourceLocation NewLoc, - bool *MissingEmptyExceptionSpecification) { +bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, + const PartialDiagnostic & NoteID, + const FunctionProtoType *Old, + SourceLocation OldLoc, + const FunctionProtoType *New, + SourceLocation NewLoc, + bool *MissingExceptionSpecification, + bool *MissingEmptyExceptionSpecification) { + if (MissingExceptionSpecification) + *MissingExceptionSpecification = false; + if (MissingEmptyExceptionSpecification) *MissingEmptyExceptionSpecification = false; @@ -168,13 +260,20 @@ bool Sema::CheckEquivalentExceptionSpec( if (OldAny && NewAny) return false; if (OldAny || NewAny) { - if (MissingEmptyExceptionSpecification && Old->hasExceptionSpec() && - !Old->hasAnyExceptionSpec() && Old->getNumExceptions() == 0 && + if (MissingExceptionSpecification && Old->hasExceptionSpec() && !New->hasExceptionSpec()) { - // The old type has a throw() exception specification and the - // new type has no exception specification, and the caller asked - // to handle this itself. - *MissingEmptyExceptionSpecification = true; + // The old type has an exception specification of some sort, but + // the new type does not. + *MissingExceptionSpecification = true; + + if (MissingEmptyExceptionSpecification && + !Old->hasAnyExceptionSpec() && Old->getNumExceptions() == 0) { + // The old type has a throw() exception specification and the + // new type has no exception specification, and the caller asked + // to handle this itself. + *MissingEmptyExceptionSpecification = true; + } + return true; } @@ -350,7 +449,8 @@ bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID, const FunctionProtoType *Source, SourceLocation SourceLoc) { if (CheckSpecForTypesEquivalent(*this, - PDiag(diag::err_deep_exception_specs_differ) << 0, 0, + PDiag(diag::err_deep_exception_specs_differ) << 0, + PDiag(), Target->getResultType(), TargetLoc, Source->getResultType(), SourceLoc)) return true; @@ -361,7 +461,8 @@ bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID, "Functions have different argument counts."); for (unsigned i = 0, E = Target->getNumArgs(); i != E; ++i) { if (CheckSpecForTypesEquivalent(*this, - PDiag(diag::err_deep_exception_specs_differ) << 1, 0, + PDiag(diag::err_deep_exception_specs_differ) << 1, + PDiag(), Target->getArgType(i), TargetLoc, Source->getArgType(i), SourceLoc)) return true; @@ -386,15 +487,16 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) // This means that the source of the conversion can only throw a subset of // the exceptions of the target, and any exception specs on arguments or // return types must be equivalent. - return CheckExceptionSpecSubset(diag::err_incompatible_exception_specs, - 0, ToFunc, From->getSourceRange().getBegin(), + return CheckExceptionSpecSubset(PDiag(diag::err_incompatible_exception_specs), + PDiag(), ToFunc, + From->getSourceRange().getBegin(), FromFunc, SourceLocation()); } bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, const CXXMethodDecl *Old) { - return CheckExceptionSpecSubset(diag::err_override_exception_spec, - diag::note_overridden_virtual_function, + return CheckExceptionSpecSubset(PDiag(diag::err_override_exception_spec), + PDiag(diag::note_overridden_virtual_function), Old->getType()->getAs(), Old->getLocation(), New->getType()->getAs(), diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index fe6f3b9..fbdf080 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -635,7 +635,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, MemberType = Context.getQualifiedType(MemberType, NewQuals); MarkDeclarationReferenced(Loc, *FI); - PerformObjectMemberConversion(Result, /*FIXME:Qualifier=*/0, *FI); + PerformObjectMemberConversion(Result, /*FIXME:Qualifier=*/0, *FI, *FI); // FIXME: Might this end up being a qualified name? Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, *FI, OpLoc, MemberType); @@ -949,8 +949,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, // Actually quite difficult! if (isInstance) Diag(R.getNameLoc(), diagnostic) << Name - << CodeModificationHint::CreateInsertion(R.getNameLoc(), - "this->"); + << FixItHint::CreateInsertion(R.getNameLoc(), "this->"); else Diag(R.getNameLoc(), diagnostic) << Name; @@ -969,14 +968,14 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, if (isa(*R.begin()) || isa(*R.begin())) { if (SS.isEmpty()) Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName() - << CodeModificationHint::CreateReplacement(R.getNameLoc(), - R.getLookupName().getAsString()); + << FixItHint::CreateReplacement(R.getNameLoc(), + R.getLookupName().getAsString()); else Diag(R.getNameLoc(), diag::err_no_member_suggest) << Name << computeDeclContext(SS, false) << R.getLookupName() << SS.getRange() - << CodeModificationHint::CreateReplacement(R.getNameLoc(), - R.getLookupName().getAsString()); + << FixItHint::CreateReplacement(R.getNameLoc(), + R.getLookupName().getAsString()); if (NamedDecl *ND = R.getAsSingle()) Diag(ND->getLocation(), diag::note_previous_decl) << ND->getDeclName(); @@ -1355,10 +1354,27 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, return Owned((Expr*) 0); } -/// \brief Cast member's object to its own class if necessary. +/// \brief Cast a base object to a member's actual type. +/// +/// Logically this happens in three phases: +/// +/// * First we cast from the base type to the naming class. +/// The naming class is the class into which we were looking +/// when we found the member; it's the qualifier type if a +/// qualifier was provided, and otherwise it's the base type. +/// +/// * Next we cast from the naming class to the declaring class. +/// If the member we found was brought into a class's scope by +/// a using declaration, this is that class; otherwise it's +/// the class declaring the member. +/// +/// * Finally we cast from the declaring class to the "true" +/// declaring class of the member. This conversion does not +/// obey access control. bool Sema::PerformObjectMemberConversion(Expr *&From, NestedNameSpecifier *Qualifier, + NamedDecl *FoundDecl, NamedDecl *Member) { CXXRecordDecl *RD = dyn_cast(Member->getDeclContext()); if (!RD) @@ -1406,6 +1422,9 @@ Sema::PerformObjectMemberConversion(Expr *&From, if (Context.hasSameUnqualifiedType(FromRecordType, DestRecordType)) return false; + SourceRange FromRange = From->getSourceRange(); + SourceLocation FromLoc = FromRange.getBegin(); + // C++ [class.member.lookup]p8: // [...] Ambiguities can often be resolved by qualifying a name with its // class name. @@ -1424,51 +1443,87 @@ Sema::PerformObjectMemberConversion(Expr *&From, // x = 17; // error: ambiguous base subobjects // Derived1::x = 17; // okay, pick the Base subobject of Derived1 // } - QualType IntermediateRecordType; - QualType IntermediateType; if (Qualifier) { - if (const RecordType *IntermediateRecord - = Qualifier->getAsType()->getAs()) { - IntermediateRecordType = QualType(IntermediateRecord, 0); - IntermediateType = IntermediateRecordType; + QualType QType = QualType(Qualifier->getAsType(), 0); + assert(!QType.isNull() && "lookup done with dependent qualifier?"); + assert(QType->isRecordType() && "lookup done with non-record type"); + + QualType QRecordType = QualType(QType->getAs(), 0); + + // In C++98, the qualifier type doesn't actually have to be a base + // type of the object type, in which case we just ignore it. + // Otherwise build the appropriate casts. + if (IsDerivedFrom(FromRecordType, QRecordType)) { + if (CheckDerivedToBaseConversion(FromRecordType, QRecordType, + FromLoc, FromRange)) + return true; + if (PointerConversions) - IntermediateType = Context.getPointerType(IntermediateType); + QType = Context.getPointerType(QType); + ImpCastExprToType(From, QType, CastExpr::CK_UncheckedDerivedToBase, + /*isLvalue*/ !PointerConversions); + + FromType = QType; + FromRecordType = QRecordType; + + // If the qualifier type was the same as the destination type, + // we're done. + if (Context.hasSameUnqualifiedType(FromRecordType, DestRecordType)) + return false; } } - if (!IntermediateType.isNull() && - IsDerivedFrom(FromRecordType, IntermediateRecordType) && - IsDerivedFrom(IntermediateRecordType, DestRecordType)) { - if (CheckDerivedToBaseConversion(FromRecordType, IntermediateRecordType, - From->getSourceRange().getBegin(), - From->getSourceRange()) || - CheckDerivedToBaseConversion(IntermediateRecordType, DestRecordType, - From->getSourceRange().getBegin(), - From->getSourceRange())) - return true; + bool IgnoreAccess = false; - ImpCastExprToType(From, IntermediateType, CastExpr::CK_DerivedToBase, - /*isLvalue=*/!PointerConversions); - ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase, - /*isLvalue=*/!PointerConversions); - return false; + // If we actually found the member through a using declaration, cast + // down to the using declaration's type. + // + // Pointer equality is fine here because only one declaration of a + // class ever has member declarations. + if (FoundDecl->getDeclContext() != Member->getDeclContext()) { + assert(isa(FoundDecl)); + QualType URecordType = Context.getTypeDeclType( + cast(FoundDecl->getDeclContext())); + + // We only need to do this if the naming-class to declaring-class + // conversion is non-trivial. + if (!Context.hasSameUnqualifiedType(FromRecordType, URecordType)) { + assert(IsDerivedFrom(FromRecordType, URecordType)); + if (CheckDerivedToBaseConversion(FromRecordType, URecordType, + FromLoc, FromRange)) + return true; + + QualType UType = URecordType; + if (PointerConversions) + UType = Context.getPointerType(UType); + ImpCastExprToType(From, UType, CastExpr::CK_UncheckedDerivedToBase, + /*isLvalue*/ !PointerConversions); + FromType = UType; + FromRecordType = URecordType; + } + + // We don't do access control for the conversion from the + // declaring class to the true declaring class. + IgnoreAccess = true; } if (CheckDerivedToBaseConversion(FromRecordType, DestRecordType, - From->getSourceRange().getBegin(), - From->getSourceRange())) + FromLoc, + FromRange, + IgnoreAccess)) return true; - ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase, - /*isLvalue=*/true); + ImpCastExprToType(From, DestType, CastExpr::CK_UncheckedDerivedToBase, + /*isLvalue=*/ !PointerConversions); return false; } /// \brief Build a MemberExpr AST node. static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, const CXXScopeSpec &SS, ValueDecl *Member, - SourceLocation Loc, QualType Ty, + NamedDecl *FoundDecl, SourceLocation Loc, + QualType Ty, const TemplateArgumentListInfo *TemplateArgs = 0) { NestedNameSpecifier *Qualifier = 0; SourceRange QualifierRange; @@ -1478,7 +1533,7 @@ static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, } return MemberExpr::Create(C, Base, isArrow, Qualifier, QualifierRange, - Member, Loc, TemplateArgs, Ty); + Member, FoundDecl, Loc, TemplateArgs, Ty); } /// Builds an implicit member access expression. The current context @@ -2520,7 +2575,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, SourceLocation OpLoc, const CXXScopeSpec &SS) { RecordDecl *RDecl = RTy->getDecl(); if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0), - PDiag(diag::err_typecheck_incomplete_tag) + SemaRef.PDiag(diag::err_typecheck_incomplete_tag) << BaseRange)) return true; @@ -2558,8 +2613,8 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, (isa(*R.begin()) || isa(*R.begin()))) { SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest) << Name << DC << R.getLookupName() << SS.getRange() - << CodeModificationHint::CreateReplacement(R.getNameLoc(), - R.getLookupName().getAsString()); + << FixItHint::CreateReplacement(R.getNameLoc(), + R.getLookupName().getAsString()); if (NamedDecl *ND = R.getAsSingle()) SemaRef.Diag(ND->getLocation(), diag::note_previous_decl) << ND->getDeclName(); @@ -2692,6 +2747,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, } assert(R.isSingleResult()); + NamedDecl *FoundDecl = *R.begin(); NamedDecl *MemberDecl = R.getFoundDecl(); // FIXME: diagnose the presence of template arguments now. @@ -2754,30 +2810,30 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, } MarkDeclarationReferenced(MemberLoc, FD); - if (PerformObjectMemberConversion(BaseExpr, Qualifier, FD)) + if (PerformObjectMemberConversion(BaseExpr, Qualifier, FoundDecl, FD)) return ExprError(); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - FD, MemberLoc, MemberType)); + FD, FoundDecl, MemberLoc, MemberType)); } if (VarDecl *Var = dyn_cast(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, Var); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - Var, MemberLoc, + Var, FoundDecl, MemberLoc, Var->getType().getNonReferenceType())); } if (FunctionDecl *MemberFn = dyn_cast(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, MemberDecl); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - MemberFn, MemberLoc, + MemberFn, FoundDecl, MemberLoc, MemberFn->getType())); } if (EnumConstantDecl *Enum = dyn_cast(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, MemberDecl); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - Enum, MemberLoc, Enum->getType())); + Enum, FoundDecl, MemberLoc, Enum->getType())); } Owned(BaseExpr); @@ -2836,7 +2892,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd()); Diag(Loc, diag::err_member_reference_needs_call) << QualType(Fun, 0) - << CodeModificationHint::CreateInsertion(Loc, "()"); + << FixItHint::CreateInsertion(Loc, "()"); OwningExprResult NewBase = ActOnCallExpr(0, ExprArg(*this, BaseExpr), Loc, @@ -2955,7 +3011,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // by now. Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) << BaseType << int(IsArrow) << BaseExpr->getSourceRange() - << CodeModificationHint::CreateReplacement(OpLoc, "."); + << FixItHint::CreateReplacement(OpLoc, "."); IsArrow = false; } else { Diag(MemberLoc, diag::err_typecheck_member_reference_arrow) @@ -2975,7 +3031,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, if (PT && PT->getPointeeType()->isRecordType()) { Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) << BaseType << int(IsArrow) << BaseExpr->getSourceRange() - << CodeModificationHint::CreateReplacement(OpLoc, "->"); + << FixItHint::CreateReplacement(OpLoc, "->"); BaseType = PT->getPointeeType(); IsArrow = true; } @@ -3014,8 +3070,8 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, Diag(R.getNameLoc(), diag::err_typecheck_member_reference_ivar_suggest) << IDecl->getDeclName() << MemberName << IV->getDeclName() - << CodeModificationHint::CreateReplacement(R.getNameLoc(), - IV->getNameAsString()); + << FixItHint::CreateReplacement(R.getNameLoc(), + IV->getNameAsString()); Diag(IV->getLocation(), diag::note_previous_decl) << IV->getDeclName(); } @@ -3189,8 +3245,8 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, Res.getAsSingle()) { Diag(R.getNameLoc(), diag::err_property_not_found_suggest) << MemberName << BaseType << Res.getLookupName() - << CodeModificationHint::CreateReplacement(R.getNameLoc(), - Res.getLookupName().getAsString()); + << FixItHint::CreateReplacement(R.getNameLoc(), + Res.getLookupName().getAsString()); ObjCPropertyDecl *Property = Res.getAsSingle(); Diag(Property->getLocation(), diag::note_previous_decl) << Property->getDeclName(); @@ -3519,7 +3575,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, if (NumArgs > 0) { // Pseudo-destructor calls should not have any arguments. Diag(Fn->getLocStart(), diag::err_pseudo_dtor_call_with_args) - << CodeModificationHint::CreateRemoval( + << FixItHint::CreateRemoval( SourceRange(Args[0]->getLocStart(), Args[NumArgs-1]->getLocEnd())); @@ -4594,13 +4650,15 @@ Sema::AssignConvertType Sema::CheckObjCPointerTypesForAssignment(QualType lhsType, QualType rhsType) { if (lhsType->isObjCBuiltinType()) { // Class is not compatible with ObjC object pointers. - if (lhsType->isObjCClassType() && !rhsType->isObjCBuiltinType()) + if (lhsType->isObjCClassType() && !rhsType->isObjCBuiltinType() && + !rhsType->isObjCQualifiedClassType()) return IncompatiblePointer; return Compatible; } if (rhsType->isObjCBuiltinType()) { // Class is not compatible with ObjC object pointers. - if (rhsType->isObjCClassType() && !lhsType->isObjCBuiltinType()) + if (rhsType->isObjCClassType() && !lhsType->isObjCBuiltinType() && + !lhsType->isObjCQualifiedClassType()) return IncompatiblePointer; return Compatible; } @@ -5367,12 +5425,10 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, PDiag(diag::warn_stringcompare) << isa(literalStringStripped) << literalString->getSourceRange() - << CodeModificationHint::CreateReplacement(SourceRange(Loc), ", ") - << CodeModificationHint::CreateInsertion(lex->getLocStart(), - "strcmp(") - << CodeModificationHint::CreateInsertion( - PP.getLocForEndOfToken(rex->getLocEnd()), - resultComparison)); + << FixItHint::CreateReplacement(SourceRange(Loc), ", ") + << FixItHint::CreateInsertion(lex->getLocStart(), "strcmp(") + << FixItHint::CreateInsertion(PP.getLocForEndOfToken(rex->getLocEnd()), + resultComparison)); } } @@ -5783,7 +5839,7 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { case Expr::MLV_IncompleteType: case Expr::MLV_IncompleteVoidType: return S.RequireCompleteType(Loc, E->getType(), - PDiag(diag::err_typecheck_incomplete_type_not_modifiable_lvalue) + S.PDiag(diag::err_typecheck_incomplete_type_not_modifiable_lvalue) << E->getSourceRange()); case Expr::MLV_DuplicateVectorComponents: Diag = diag::err_typecheck_duplicate_vector_components_not_mlvalue; @@ -6345,8 +6401,8 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, static void SuggestParentheses(Sema &Self, SourceLocation Loc, const PartialDiagnostic &PD, SourceRange ParenRange, - const PartialDiagnostic &SecondPD = PartialDiagnostic(0), - SourceRange SecondParenRange = SourceRange()) { + const PartialDiagnostic &SecondPD, + SourceRange SecondParenRange) { SourceLocation EndLoc = Self.PP.getLocForEndOfToken(ParenRange.getEnd()); if (!ParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { // We can't display the parentheses, so just dig the @@ -6356,8 +6412,8 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc, } Self.Diag(Loc, PD) - << CodeModificationHint::CreateInsertion(ParenRange.getBegin(), "(") - << CodeModificationHint::CreateInsertion(EndLoc, ")"); + << FixItHint::CreateInsertion(ParenRange.getBegin(), "(") + << FixItHint::CreateInsertion(EndLoc, ")"); if (!SecondPD.getDiagID()) return; @@ -6371,8 +6427,8 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc, } Self.Diag(Loc, SecondPD) - << CodeModificationHint::CreateInsertion(SecondParenRange.getBegin(), "(") - << CodeModificationHint::CreateInsertion(EndLoc, ")"); + << FixItHint::CreateInsertion(SecondParenRange.getBegin(), "(") + << FixItHint::CreateInsertion(EndLoc, ")"); } /// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison @@ -6401,20 +6457,20 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperator::Opcode Opc, if (BinOp::isComparisonOp(lhsopc)) SuggestParentheses(Self, OpLoc, - PDiag(diag::warn_precedence_bitwise_rel) + Self.PDiag(diag::warn_precedence_bitwise_rel) << SourceRange(lhs->getLocStart(), OpLoc) << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc), lhs->getSourceRange(), - PDiag(diag::note_precedence_bitwise_first) + Self.PDiag(diag::note_precedence_bitwise_first) << BinOp::getOpcodeStr(Opc), SourceRange(cast(lhs)->getRHS()->getLocStart(), rhs->getLocEnd())); else if (BinOp::isComparisonOp(rhsopc)) SuggestParentheses(Self, OpLoc, - PDiag(diag::warn_precedence_bitwise_rel) + Self.PDiag(diag::warn_precedence_bitwise_rel) << SourceRange(OpLoc, rhs->getLocEnd()) << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc), rhs->getSourceRange(), - PDiag(diag::note_precedence_bitwise_first) + Self.PDiag(diag::note_precedence_bitwise_first) << BinOp::getOpcodeStr(Opc), SourceRange(lhs->getLocEnd(), cast(rhs)->getLHS()->getLocStart())); } @@ -6750,7 +6806,8 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, Res = BuildAnonymousStructUnionMemberReference( OC.LocEnd, MemberDecl, Res, OC.LocEnd).takeAs(); } else { - PerformObjectMemberConversion(Res, /*Qualifier=*/0, MemberDecl); + PerformObjectMemberConversion(Res, /*Qualifier=*/0, + *R.begin(), MemberDecl); // MemberDecl->getType() doesn't get the right qualifiers, but it // doesn't matter here. Res = new (Context) MemberExpr(Res, false, MemberDecl, OC.LocEnd, @@ -6849,8 +6906,8 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { // The parameter list is optional, if there was none, assume (). if (!T->isFunctionType()) - T = Context.getFunctionType(T, 0, 0, false, 0, false, false, 0, 0, false, - CC_Default); + T = Context.getFunctionType(T, 0, 0, false, 0, false, false, 0, 0, + FunctionType::ExtInfo()); CurBlock->hasPrototype = true; CurBlock->isVariadic = false; @@ -6905,13 +6962,21 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { CurBlock->Params.size()); CurBlock->TheDecl->setIsVariadic(CurBlock->isVariadic); ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo); + + bool ShouldCheckShadow = + Diags.getDiagnosticLevel(diag::warn_decl_shadow) != Diagnostic::Ignored; + for (BlockDecl::param_iterator AI = CurBlock->TheDecl->param_begin(), E = CurBlock->TheDecl->param_end(); AI != E; ++AI) { (*AI)->setOwningFunction(CurBlock->TheDecl); // If this has an identifier, add it to the scope stack. - if ((*AI)->getIdentifier()) + if ((*AI)->getIdentifier()) { + if (ShouldCheckShadow) + CheckShadow(CurBlock->TheScope, *AI); + PushOnScopeChains(*AI, CurBlock->TheScope); + } } // Check for a valid sentinel attribute on this block. @@ -6967,11 +7032,11 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, QualType BlockTy; if (!BSI->hasPrototype) BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0, false, false, 0, 0, - NoReturn, CC_Default); + FunctionType::ExtInfo(NoReturn, 0, CC_Default)); else BlockTy = Context.getFunctionType(RetTy, ArgTypes.data(), ArgTypes.size(), BSI->isVariadic, 0, false, false, 0, 0, - NoReturn, CC_Default); + FunctionType::ExtInfo(NoReturn, 0, CC_Default)); // FIXME: Check that return/parameter types are complete/non-abstract DiagnoseUnusedParameters(BSI->Params.begin(), BSI->Params.end()); @@ -7004,8 +7069,9 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, } // Issue any analysis-based warnings. - sema::AnalysisBasedWarnings W(*this); - W.IssueWarnings(BSI->TheDecl, BlockTy); + const sema::AnalysisBasedWarnings::Policy &WP = + AnalysisWarnings.getDefaultPolicy(); + AnalysisWarnings.IssueWarnings(WP, BSI->TheDecl, BlockTy); Expr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy, BSI->hasBlockDeclRefExprs); @@ -7066,11 +7132,8 @@ Sema::OwningExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) { return Owned(new (Context) GNUNullExpr(Ty, TokenLoc)); } -static void -MakeObjCStringLiteralCodeModificationHint(Sema& SemaRef, - QualType DstType, - Expr *SrcExpr, - CodeModificationHint &Hint) { +static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType, + Expr *SrcExpr, FixItHint &Hint) { if (!SemaRef.getLangOptions().ObjC1) return; @@ -7091,7 +7154,7 @@ MakeObjCStringLiteralCodeModificationHint(Sema& SemaRef, if (!SL || SL->isWide()) return; - Hint = CodeModificationHint::CreateInsertion(SL->getLocStart(), "@"); + Hint = FixItHint::CreateInsertion(SL->getLocStart(), "@"); } bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, @@ -7101,7 +7164,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, // Decode the result (notice that AST's are still created for extensions). bool isInvalid = false; unsigned DiagKind; - CodeModificationHint Hint; + FixItHint Hint; switch (ConvTy) { default: assert(0 && "Unknown conversion type"); @@ -7113,7 +7176,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, DiagKind = diag::ext_typecheck_convert_int_pointer; break; case IncompatiblePointer: - MakeObjCStringLiteralCodeModificationHint(*this, DstType, SrcExpr, Hint); + MakeObjCStringLiteralFixItHint(*this, DstType, SrcExpr, Hint); DiagKind = diag::ext_typecheck_convert_incompatible_pointer; break; case IncompatiblePointerSign: @@ -7480,10 +7543,10 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) { Diag(Loc, diagnostic) << E->getSourceRange() - << CodeModificationHint::CreateInsertion(Open, "(") - << CodeModificationHint::CreateInsertion(Close, ")"); + << FixItHint::CreateInsertion(Open, "(") + << FixItHint::CreateInsertion(Close, ")"); Diag(Loc, diag::note_condition_assign_to_comparison) - << CodeModificationHint::CreateReplacement(Loc, "=="); + << FixItHint::CreateReplacement(Loc, "=="); } bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) { diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 366089f..501c877 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -948,7 +948,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, = Context.getFunctionType(Context.VoidTy, ArgTypes.data(), ArgTypes.size(), Proto->isVariadic(), - 0, false, false, 0, 0, false, CC_Default); + 0, false, false, 0, 0, + FunctionType::ExtInfo()); } for (LookupResult::iterator D = FoundDelete.begin(), @@ -1062,10 +1063,15 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, // Watch out for variadic allocator function. unsigned NumArgsInFnDecl = FnDecl->getNumParams(); for (unsigned i = 0; (i < NumArgs && i < NumArgsInFnDecl); ++i) { - if (PerformCopyInitialization(Args[i], - FnDecl->getParamDecl(i)->getType(), - AA_Passing)) + OwningExprResult Result + = PerformCopyInitialization(InitializedEntity::InitializeParameter( + FnDecl->getParamDecl(i)), + SourceLocation(), + Owned(Args[i]->Retain())); + if (Result.isInvalid()) return true; + + Args[i] = Result.takeAs(); } Operator = FnDecl; CheckAllocationAccess(StartLoc, Range, R.getNamingClass(), Best->FoundDecl); @@ -1204,7 +1210,8 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0, true, false, HasBadAllocExceptionSpec? 1 : 0, - &BadAllocType, false, CC_Default); + &BadAllocType, + FunctionType::ExtInfo()); FunctionDecl *Alloc = FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name, FnType, /*TInfo=*/0, FunctionDecl::None, false, true); @@ -1295,17 +1302,21 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, QualType Type = Ex->getType(); if (const RecordType *Record = Type->getAs()) { - llvm::SmallVector ObjectPtrConversions; + llvm::SmallVector ObjectPtrConversions; + CXXRecordDecl *RD = cast(Record->getDecl()); - const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions(); - + const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions(); for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { + NamedDecl *D = I.getDecl(); + if (isa(D)) + D = cast(D)->getTargetDecl(); + // Skip over templated conversion functions; they aren't considered. - if (isa(*I)) + if (isa(D)) continue; - CXXConversionDecl *Conv = cast(*I); + CXXConversionDecl *Conv = cast(D); QualType ConvType = Conv->getConversionType().getNonReferenceType(); if (const PointerType *ConvPtrType = ConvType->getAs()) @@ -1315,9 +1326,10 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, if (ObjectPtrConversions.size() == 1) { // We have a single conversion to a pointer-to-object type. Perform // that conversion. + // TODO: don't redo the conversion calculation. Operand.release(); - if (!PerformImplicitConversion(Ex, - ObjectPtrConversions.front()->getConversionType(), + if (!PerformImplicitConversion(Ex, + ObjectPtrConversions.front()->getConversionType(), AA_Converting)) { Operand = Owned(Ex); Type = Ex->getType(); @@ -1326,10 +1338,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, else if (ObjectPtrConversions.size() > 1) { Diag(StartLoc, diag::err_ambiguous_delete_operand) << Type << Ex->getSourceRange(); - for (unsigned i= 0; i < ObjectPtrConversions.size(); i++) { - CXXConversionDecl *Conv = ObjectPtrConversions[i]; - NoteOverloadCandidate(Conv); - } + for (unsigned i= 0; i < ObjectPtrConversions.size(); i++) + NoteOverloadCandidate(ObjectPtrConversions[i]); return ExprError(); } } @@ -1643,14 +1653,16 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, case ICK_Function_To_Pointer: if (Context.getCanonicalType(FromType) == Context.OverloadTy) { - FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, true); + DeclAccessPair Found; + FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, + true, Found); if (!Fn) return true; if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin())) return true; - From = FixOverloadedFunctionReference(From, Fn); + From = FixOverloadedFunctionReference(From, Found, Fn); FromType = From->getType(); // If there's already an address-of operator in the expression, we have @@ -1846,7 +1858,7 @@ QualType Sema::CheckPointerToMemberOperands( else { Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling << 1 << LType - << CodeModificationHint::CreateReplacement(SourceRange(Loc), ".*"); + << FixItHint::CreateReplacement(SourceRange(Loc), ".*"); return QualType(); } } @@ -1891,58 +1903,44 @@ QualType Sema::CheckPointerToMemberOperands( return Result; } -/// \brief Get the target type of a standard or user-defined conversion. -static QualType TargetType(const ImplicitConversionSequence &ICS) { - switch (ICS.getKind()) { - case ImplicitConversionSequence::StandardConversion: - return ICS.Standard.getToType(2); - case ImplicitConversionSequence::UserDefinedConversion: - return ICS.UserDefined.After.getToType(2); - case ImplicitConversionSequence::AmbiguousConversion: - return ICS.Ambiguous.getToType(); - - case ImplicitConversionSequence::EllipsisConversion: - case ImplicitConversionSequence::BadConversion: - llvm_unreachable("function not valid for ellipsis or bad conversions"); - } - return QualType(); // silence warnings -} - /// \brief Try to convert a type to another according to C++0x 5.16p3. /// /// This is part of the parameter validation for the ? operator. If either /// value operand is a class type, the two operands are attempted to be /// converted to each other. This function does the conversion in one direction. -/// It emits a diagnostic and returns true only if it finds an ambiguous -/// conversion. +/// It returns true if the program is ill-formed and has already been diagnosed +/// as such. static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, SourceLocation QuestionLoc, - ImplicitConversionSequence &ICS) { + bool &HaveConversion, + QualType &ToType) { + HaveConversion = false; + ToType = To->getType(); + + InitializationKind Kind = InitializationKind::CreateCopy(To->getLocStart(), + SourceLocation()); // C++0x 5.16p3 // The process for determining whether an operand expression E1 of type T1 // can be converted to match an operand expression E2 of type T2 is defined // as follows: // -- If E2 is an lvalue: - if (To->isLvalue(Self.Context) == Expr::LV_Valid) { + bool ToIsLvalue = (To->isLvalue(Self.Context) == Expr::LV_Valid); + if (ToIsLvalue) { // E1 can be converted to match E2 if E1 can be implicitly converted to // type "lvalue reference to T2", subject to the constraint that in the // conversion the reference must bind directly to E1. - if (!Self.CheckReferenceInit(From, - Self.Context.getLValueReferenceType(To->getType()), - To->getLocStart(), - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, - /*ForceRValue=*/false, - &ICS)) - { - assert((ICS.isStandard() || ICS.isUserDefined()) && - "expected a definite conversion"); - bool DirectBinding = - ICS.isStandard() ? ICS.Standard.DirectBinding - : ICS.UserDefined.After.DirectBinding; - if (DirectBinding) - return false; + QualType T = Self.Context.getLValueReferenceType(ToType); + InitializedEntity Entity = InitializedEntity::InitializeTemporary(T); + + InitializationSequence InitSeq(Self, Entity, Kind, &From, 1); + if (InitSeq.isDirectReferenceBinding()) { + ToType = T; + HaveConversion = true; + return false; } + + if (InitSeq.isAmbiguous()) + return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); } // -- If E2 is an rvalue, or if the conversion above cannot be done: @@ -1952,47 +1950,47 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, QualType TTy = To->getType(); const RecordType *FRec = FTy->getAs(); const RecordType *TRec = TTy->getAs(); - bool FDerivedFromT = FRec && TRec && Self.IsDerivedFrom(FTy, TTy); - if (FRec && TRec && (FRec == TRec || - FDerivedFromT || Self.IsDerivedFrom(TTy, FTy))) { + bool FDerivedFromT = FRec && TRec && FRec != TRec && + Self.IsDerivedFrom(FTy, TTy); + if (FRec && TRec && + (FRec == TRec || FDerivedFromT || Self.IsDerivedFrom(TTy, FTy))) { // E1 can be converted to match E2 if the class of T2 is the // same type as, or a base class of, the class of T1, and // [cv2 > cv1]. if (FRec == TRec || FDerivedFromT) { if (TTy.isAtLeastAsQualifiedAs(FTy)) { - // Could still fail if there's no copy constructor. - // FIXME: Is this a hard error then, or just a conversion failure? The - // standard doesn't say. - ICS = Self.TryCopyInitialization(From, TTy, - /*SuppressUserConversions=*/false, - /*ForceRValue=*/false, - /*InOverloadResolution=*/false); - } else { - ICS.setBad(BadConversionSequence::bad_qualifiers, From, TTy); - } - } else { - // Can't implicitly convert FTy to a derived class TTy. - // TODO: more specific error for this. - ICS.setBad(BadConversionSequence::no_conversion, From, TTy); + InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); + InitializationSequence InitSeq(Self, Entity, Kind, &From, 1); + if (InitSeq.getKind() != InitializationSequence::FailedSequence) { + HaveConversion = true; + return false; + } + + if (InitSeq.isAmbiguous()) + return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); + } } - } else { - // -- Otherwise: E1 can be converted to match E2 if E1 can be - // implicitly converted to the type that expression E2 would have - // if E2 were converted to an rvalue. - // First find the decayed type. - if (TTy->isFunctionType()) - TTy = Self.Context.getPointerType(TTy); - else if (TTy->isArrayType()) - TTy = Self.Context.getArrayDecayedType(TTy); - - // Now try the implicit conversion. - // FIXME: This doesn't detect ambiguities. - ICS = Self.TryImplicitConversion(From, TTy, - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, - /*ForceRValue=*/false, - /*InOverloadResolution=*/false); + + return false; } + + // -- Otherwise: E1 can be converted to match E2 if E1 can be + // implicitly converted to the type that expression E2 would have + // if E2 were converted to an rvalue (or the type it has, if E2 is + // an rvalue). + // + // This actually refers very narrowly to the lvalue-to-rvalue conversion, not + // to the array-to-pointer or function-to-pointer conversions. + if (!TTy->getAs()) + TTy = TTy.getUnqualifiedType(); + + InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); + InitializationSequence InitSeq(Self, Entity, Kind, &From, 1); + HaveConversion = InitSeq.getKind() != InitializationSequence::FailedSequence; + ToType = TTy; + if (InitSeq.isAmbiguous()) + return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); + return false; } @@ -2041,37 +2039,17 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, /// \brief Perform an "extended" implicit conversion as returned by /// TryClassUnification. -/// -/// TryClassUnification generates ICSs that include reference bindings. -/// PerformImplicitConversion is not suitable for this; it chokes if the -/// second part of a standard conversion is ICK_DerivedToBase. This function -/// handles the reference binding specially. -static bool ConvertForConditional(Sema &Self, Expr *&E, - const ImplicitConversionSequence &ICS) { - if (ICS.isStandard() && ICS.Standard.ReferenceBinding) { - assert(ICS.Standard.DirectBinding && - "TryClassUnification should never generate indirect ref bindings"); - // FIXME: CheckReferenceInit should be able to reuse the ICS instead of - // redoing all the work. - return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType( - TargetType(ICS)), - /*FIXME:*/E->getLocStart(), - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, - /*ForceRValue=*/false); - } - if (ICS.isUserDefined() && ICS.UserDefined.After.ReferenceBinding) { - assert(ICS.UserDefined.After.DirectBinding && - "TryClassUnification should never generate indirect ref bindings"); - return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType( - TargetType(ICS)), - /*FIXME:*/E->getLocStart(), - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, - /*ForceRValue=*/false); - } - if (Self.PerformImplicitConversion(E, TargetType(ICS), ICS, Sema::AA_Converting)) +static bool ConvertForConditional(Sema &Self, Expr *&E, QualType T) { + InitializedEntity Entity = InitializedEntity::InitializeTemporary(T); + InitializationKind Kind = InitializationKind::CreateCopy(E->getLocStart(), + SourceLocation()); + InitializationSequence InitSeq(Self, Entity, Kind, &E, 1); + Sema::OwningExprResult Result = InitSeq.Perform(Self, Entity, Kind, + Sema::MultiExprArg(Self, (void **)&E, 1)); + if (Result.isInvalid()) return true; + + E = Result.takeAs(); return false; } @@ -2139,17 +2117,17 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // Otherwise, if the second and third operand have different types, and // either has (cv) class type, and attempt is made to convert each of those // operands to the other. - if (Context.getCanonicalType(LTy) != Context.getCanonicalType(RTy) && + if (!Context.hasSameType(LTy, RTy) && (LTy->isRecordType() || RTy->isRecordType())) { ImplicitConversionSequence ICSLeftToRight, ICSRightToLeft; // These return true if a single direction is already ambiguous. - if (TryClassUnification(*this, LHS, RHS, QuestionLoc, ICSLeftToRight)) + QualType L2RType, R2LType; + bool HaveL2R, HaveR2L; + if (TryClassUnification(*this, LHS, RHS, QuestionLoc, HaveL2R, L2RType)) return QualType(); - if (TryClassUnification(*this, RHS, LHS, QuestionLoc, ICSRightToLeft)) + if (TryClassUnification(*this, RHS, LHS, QuestionLoc, HaveR2L, R2LType)) return QualType(); - - bool HaveL2R = !ICSLeftToRight.isBad(); - bool HaveR2L = !ICSRightToLeft.isBad(); + // If both can be converted, [...] the program is ill-formed. if (HaveL2R && HaveR2L) { Diag(QuestionLoc, diag::err_conditional_ambiguous) @@ -2161,11 +2139,11 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // the chosen operand and the converted operands are used in place of the // original operands for the remainder of this section. if (HaveL2R) { - if (ConvertForConditional(*this, LHS, ICSLeftToRight)) + if (ConvertForConditional(*this, LHS, L2RType)) return QualType(); LTy = LHS->getType(); } else if (HaveR2L) { - if (ConvertForConditional(*this, RHS, ICSRightToLeft)) + if (ConvertForConditional(*this, RHS, R2LType)) return QualType(); RTy = RHS->getType(); } @@ -2174,7 +2152,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // C++0x 5.16p4 // If the second and third operands are lvalues and have the same type, // the result is of that type [...] - bool Same = Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy); + bool Same = Context.hasSameType(LTy, RTy); if (Same && LHS->isLvalue(Context) == Expr::LV_Valid && RHS->isLvalue(Context) == Expr::LV_Valid) return LTy; @@ -2235,7 +2213,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, return Composite; } - // Similarly, attempt to find composite type of twp objective-c pointers. + // Similarly, attempt to find composite type of two objective-c pointers. Composite = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc); if (!Composite.isNull()) return Composite; @@ -2611,7 +2589,7 @@ Sema::OwningExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc, SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(NameLoc); Diag(E->getLocStart(), diag::err_dtor_expr_without_call) << isa(E) - << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()"); + << FixItHint::CreateInsertion(ExpectedLParenLoc, "()"); return ActOnCallExpr(/*Scope*/ 0, move(MemExpr), @@ -2645,7 +2623,7 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base, // The user wrote "p->" when she probably meant "p."; fix it. Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) << ObjectType << true - << CodeModificationHint::CreateReplacement(OpLoc, "."); + << FixItHint::CreateReplacement(OpLoc, "."); if (isSFINAEContext()) return ExprError(); @@ -2750,7 +2728,7 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, // The user wrote "p->" when she probably meant "p."; fix it. Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) << ObjectType << true - << CodeModificationHint::CreateReplacement(OpLoc, "."); + << FixItHint::CreateReplacement(OpLoc, "."); if (isSFINAEContext()) return ExprError(); @@ -2874,8 +2852,10 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, } CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, + NamedDecl *FoundDecl, CXXMethodDecl *Method) { - if (PerformObjectArgumentInitialization(Exp, /*Qualifier=*/0, Method)) + if (PerformObjectArgumentInitialization(Exp, /*Qualifier=*/0, + FoundDecl, Method)) assert(0 && "Calling BuildCXXMemberCallExpr with invalid call?"); MemberExpr *ME = @@ -2919,7 +2899,8 @@ Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc, assert(!From->getType()->isPointerType() && "Arg can't have pointer type!"); // Create an implicit call expr that calls it. - CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method); + // FIXME: pass the FoundDecl for the user-defined conversion here + CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method, Method); return MaybeBindToTemporary(CE); } } diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index c98ba43..d5a22ca 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -289,7 +289,10 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr( IdentifierInfo *receiverNamePtr = &receiverName; ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr); - + if (!IFace) { + Diag(receiverNameLoc, diag::err_expected_ident_or_lparen); + return ExprError(); + } // Search for a declared property first. Selector Sel = PP.getSelectorTable().getNullarySelector(&propertyName); diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index f86ae51..648e43b 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -504,13 +504,11 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, SemaRef.Diag(StructuredSubobjectInitList->getLocStart(), diag::warn_missing_braces) << StructuredSubobjectInitList->getSourceRange() - << CodeModificationHint::CreateInsertion( - StructuredSubobjectInitList->getLocStart(), - "{") - << CodeModificationHint::CreateInsertion( - SemaRef.PP.getLocForEndOfToken( + << FixItHint::CreateInsertion(StructuredSubobjectInitList->getLocStart(), + "{") + << FixItHint::CreateInsertion(SemaRef.PP.getLocForEndOfToken( StructuredSubobjectInitList->getLocEnd()), - "}"); + "}"); } } @@ -571,8 +569,8 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity, if (T->isScalarType() && !TopLevelObject) SemaRef.Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init) << IList->getSourceRange() - << CodeModificationHint::CreateRemoval(IList->getLocStart()) - << CodeModificationHint::CreateRemoval(IList->getLocEnd()); + << FixItHint::CreateRemoval(IList->getLocStart()) + << FixItHint::CreateRemoval(IList->getLocEnd()); } void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, @@ -1363,8 +1361,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown_suggest) << FieldName << CurrentObjectType << R.getLookupName() - << CodeModificationHint::CreateReplacement(D->getFieldLoc(), - R.getLookupName().getAsString()); + << FixItHint::CreateReplacement(D->getFieldLoc(), + R.getLookupName().getAsString()); SemaRef.Diag(ReplacementField->getLocation(), diag::note_previous_decl) << ReplacementField->getDeclName(); @@ -2001,14 +1999,48 @@ void InitializationSequence::Step::Destroy() { } } +bool InitializationSequence::isDirectReferenceBinding() const { + return getKind() == ReferenceBinding && Steps.back().Kind == SK_BindReference; +} + +bool InitializationSequence::isAmbiguous() const { + if (getKind() != FailedSequence) + return false; + + switch (getFailureKind()) { + case FK_TooManyInitsForReference: + case FK_ArrayNeedsInitList: + case FK_ArrayNeedsInitListOrStringLiteral: + case FK_AddressOfOverloadFailed: // FIXME: Could do better + case FK_NonConstLValueReferenceBindingToTemporary: + case FK_NonConstLValueReferenceBindingToUnrelated: + case FK_RValueReferenceBindingToLValue: + case FK_ReferenceInitDropsQualifiers: + case FK_ReferenceInitFailed: + case FK_ConversionFailed: + case FK_TooManyInitsForScalar: + case FK_ReferenceBindingToInitList: + case FK_InitListBadDestinationType: + case FK_DefaultInitOfConst: + return false; + + case FK_ReferenceInitOverloadFailed: + case FK_UserConversionOverloadFailed: + case FK_ConstructorOverloadFailed: + return FailedOverloadResult == OR_Ambiguous; + } + + return false; +} + void InitializationSequence::AddAddressOverloadResolutionStep( - FunctionDecl *Function) { + FunctionDecl *Function, + DeclAccessPair Found) { Step S; S.Kind = SK_ResolveAddressOfOverloadedFunction; S.Type = Function->getType(); - // Access is currently ignored for these. S.Function.Function = Function; - S.Function.FoundDecl = DeclAccessPair::make(Function, AS_none); + S.Function.FoundDecl = Found; Steps.push_back(S); } @@ -2341,15 +2373,17 @@ static void TryReferenceInitialization(Sema &S, // to resolve the overloaded function. If all goes well, T2 is the // type of the resulting function. if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) { + DeclAccessPair Found; FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(Initializer, T1, - false); + false, + Found); if (!Fn) { Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); return; } - Sequence.AddAddressOverloadResolutionStep(Fn); + Sequence.AddAddressOverloadResolutionStep(Fn, Found); cv2T2 = Fn->getType(); T2 = cv2T2.getUnqualifiedType(); } @@ -2802,7 +2836,7 @@ static void TryUserDefinedConversion(Sema &S, if (ConvTemplate) Conv = cast(ConvTemplate->getTemplatedDecl()); else - Conv = cast(*I); + Conv = cast(D); if (AllowExplicit || !Conv->isExplicit()) { if (ConvTemplate) @@ -3314,8 +3348,9 @@ InitializationSequence::Perform(Sema &S, case SK_ResolveAddressOfOverloadedFunction: // Overload resolution determined which function invoke; update the // initializer to reflect that choice. - // Access control was done in overload resolution. + S.CheckAddressOfMemberAccess(CurInitExpr, Step->Function.FoundDecl); CurInit = S.FixOverloadedFunctionReference(move(CurInit), + Step->Function.FoundDecl, Step->Function.Function); break; @@ -3382,6 +3417,7 @@ InitializationSequence::Perform(Sema &S, bool IsCopy = false; FunctionDecl *Fn = Step->Function.Function; DeclAccessPair FoundFn = Step->Function.FoundDecl; + bool IsLvalue = false; if (CXXConstructorDecl *Constructor = dyn_cast(Fn)) { // Build a call to the selected constructor. ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); @@ -3414,7 +3450,7 @@ InitializationSequence::Perform(Sema &S, } else { // Build a call to the conversion function. CXXConversionDecl *Conversion = cast(Fn); - + IsLvalue = Conversion->getResultType()->isLValueReferenceType(); S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, 0, FoundFn); @@ -3422,7 +3458,7 @@ InitializationSequence::Perform(Sema &S, // derived-to-base conversion? I believe the answer is "no", because // we don't want to turn off access control here for c-style casts. if (S.PerformObjectArgumentInitialization(CurInitExpr, /*Qualifier=*/0, - Conversion)) + FoundFn, Conversion)) return S.ExprError(); // Do a little dance to make sure that CurInit has the proper @@ -3430,7 +3466,8 @@ InitializationSequence::Perform(Sema &S, CurInit.release(); // Build the actual call to the conversion function. - CurInit = S.Owned(S.BuildCXXMemberCallExpr(CurInitExpr, Conversion)); + CurInit = S.Owned(S.BuildCXXMemberCallExpr(CurInitExpr, FoundFn, + Conversion)); if (CurInit.isInvalid() || !CurInit.get()) return S.ExprError(); @@ -3444,7 +3481,7 @@ InitializationSequence::Perform(Sema &S, CurInit = S.Owned(new (S.Context) ImplicitCastExpr(CurInitExpr->getType(), CastKind, CurInitExpr, - false)); + IsLvalue)); if (!IsCopy) CurInit = CopyIfRequiredForEntity(S, Entity, Kind, move(CurInit)); @@ -3614,11 +3651,14 @@ bool InitializationSequence::Diagnose(Sema &S, << (Failure == FK_ArrayNeedsInitListOrStringLiteral); break; - case FK_AddressOfOverloadFailed: + case FK_AddressOfOverloadFailed: { + DeclAccessPair Found; S.ResolveAddressOfOverloadedFunction(Args[0], DestType.getNonReferenceType(), - true); + true, + Found); break; + } case FK_ReferenceInitOverloadFailed: case FK_UserConversionOverloadFailed: diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h index 18a0938..7c6327f 100644 --- a/lib/Sema/SemaInit.h +++ b/lib/Sema/SemaInit.h @@ -599,12 +599,20 @@ public: step_iterator step_begin() const { return Steps.begin(); } step_iterator step_end() const { return Steps.end(); } + /// \brief Determine whether this initialization is a direct reference + /// binding (C++ [dcl.init.ref]). + bool isDirectReferenceBinding() const; + + /// \brief Determine whether this initialization failed due to an ambiguity. + bool isAmbiguous() const; + /// \brief Add a new step in the initialization that resolves the address /// of an overloaded function to a specific function declaration. /// /// \param Function the function to which the overloaded function reference /// resolves. - void AddAddressOverloadResolutionStep(FunctionDecl *Function); + void AddAddressOverloadResolutionStep(FunctionDecl *Function, + DeclAccessPair Found); /// \brief Add a new step in the initialization that performs a derived-to- /// base cast. diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 9ae520d..a29c4d4 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -304,6 +304,23 @@ void LookupResult::configure() { SemaRef.getLangOptions().CPlusPlus, isForRedeclaration()); IsAcceptableFn = getResultFilter(LookupKind); + + // If we're looking for one of the allocation or deallocation + // operators, make sure that the implicitly-declared new and delete + // operators can be found. + if (!isForRedeclaration()) { + switch (Name.getCXXOverloadedOperator()) { + case OO_New: + case OO_Delete: + case OO_Array_New: + case OO_Array_Delete: + SemaRef.DeclareGlobalNewDelete(); + break; + + default: + break; + } + } } // Necessary because CXXBasePaths is not complete in Sema.h @@ -539,13 +556,13 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { // Compute the type of the function that we would expect the conversion // function to have, if it were to match the name given. // FIXME: Calling convention! + FunctionType::ExtInfo ConvProtoInfo = ConvProto->getExtInfo(); QualType ExpectedType = R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(), 0, 0, ConvProto->isVariadic(), ConvProto->getTypeQuals(), false, false, 0, 0, - ConvProto->getNoReturnAttr(), - CC_Default); + ConvProtoInfo.withCallingConv(CC_Default)); // Perform template argument deduction against the type that we would // expect the function to have. diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 41ed6c6..f815068 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -44,9 +44,6 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, Diag(AtLoc, diag::error_reference_property); return DeclPtrTy(); } - // Validate the attributes on the @property. - CheckObjCPropertyAttributes(T, AtLoc, Attributes); - // Proceed with constructing the ObjCPropertDecls. ObjCContainerDecl *ClassDecl = cast(ClassCategory.getAs()); @@ -60,10 +57,13 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, isOverridingProperty, T, MethodImplKind); - return DeclPtrTy::make(CreatePropertyDecl(S, ClassDecl, AtLoc, FD, + DeclPtrTy Res = DeclPtrTy::make(CreatePropertyDecl(S, ClassDecl, AtLoc, FD, GetterSel, SetterSel, isAssign, isReadWrite, Attributes, T, MethodImplKind)); + // Validate the attributes on the @property. + CheckObjCPropertyAttributes(Res, AtLoc, Attributes); + return Res; } Sema::DeclPtrTy @@ -93,6 +93,11 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(), PropertyId, AtLoc, T); + if (Attributes & ObjCDeclSpec::DQ_PR_readonly) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly); + if (Attributes & ObjCDeclSpec::DQ_PR_readwrite) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite); + DC->addDecl(PDecl); // We need to look in the @interface to see if the @property was @@ -378,7 +383,9 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, if (PropType != IvarType) { if (CheckAssignmentConstraints(PropType, IvarType) != Compatible) { Diag(PropertyLoc, diag::error_property_ivar_type) - << property->getDeclName() << Ivar->getDeclName(); + << property->getDeclName() << PropType + << Ivar->getDeclName() << IvarType; + Diag(Ivar->getLocation(), diag::note_ivar_decl); // Note! I deliberately want it to fall thru so, we have a // a property implementation and to avoid future warnings. } @@ -391,7 +398,9 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, if (lhsType != rhsType && lhsType->isArithmeticType()) { Diag(PropertyLoc, diag::error_property_ivar_type) - << property->getDeclName() << Ivar->getDeclName(); + << property->getDeclName() << PropType + << Ivar->getDeclName() << IvarType; + Diag(Ivar->getLocation(), diag::note_ivar_decl); // Fall thru - see previous comment } // __weak is explicit. So it works on Canonical type. @@ -973,10 +982,13 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, AddInstanceMethodToGlobalPool(SetterMethod); } -void Sema::CheckObjCPropertyAttributes(QualType PropertyTy, +void Sema::CheckObjCPropertyAttributes(DeclPtrTy PropertyPtrTy, SourceLocation Loc, unsigned &Attributes) { // FIXME: Improve the reported location. + Decl *PDecl = PropertyPtrTy.getAs(); + ObjCPropertyDecl *PropertyDecl = dyn_cast_or_null(PDecl); + QualType PropertyTy = PropertyDecl->getType(); // readonly and readwrite/assign/retain/copy conflict. if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) && @@ -1001,7 +1013,8 @@ void Sema::CheckObjCPropertyAttributes(QualType PropertyTy, if ((Attributes & (ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) && !PropertyTy->isObjCObjectPointerType() && !PropertyTy->isBlockPointerType() && - !Context.isObjCNSObjectType(PropertyTy)) { + !Context.isObjCNSObjectType(PropertyTy) && + !PropertyDecl->getAttr()) { Diag(Loc, diag::err_objc_property_requires_object) << (Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain"); Attributes &= ~(ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 410bf9a..bc10a58 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -567,6 +567,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // array-to-pointer conversion, or function-to-pointer conversion // (C++ 4p1). + DeclAccessPair AccessPair; + // Lvalue-to-rvalue conversion (C++ 4.1): // An lvalue (3.10) of a non-function, non-array type T can be // converted to an rvalue. @@ -612,7 +614,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // function. (C++ 4.3p1). FromType = Context.getPointerType(FromType); } else if (FunctionDecl *Fn - = ResolveAddressOfOverloadedFunction(From, ToType, false)) { + = ResolveAddressOfOverloadedFunction(From, ToType, false, + AccessPair)) { // Address of overloaded function (C++ [over.over]). SCS.First = ICK_Function_To_Pointer; @@ -1579,10 +1582,10 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, CXXConversionDecl *Conv; FunctionTemplateDecl *ConvTemplate; - if ((ConvTemplate = dyn_cast(*I))) - Conv = dyn_cast(ConvTemplate->getTemplatedDecl()); + if ((ConvTemplate = dyn_cast(D))) + Conv = cast(ConvTemplate->getTemplatedDecl()); else - Conv = dyn_cast(*I); + Conv = cast(D); if (AllowExplicit || !Conv->isExplicit()) { if (ConvTemplate) @@ -2201,44 +2204,6 @@ Sema::TryCopyInitialization(Expr *From, QualType ToType, } } -/// PerformCopyInitialization - Copy-initialize an object of type @p ToType with -/// the expression @p From. Returns true (and emits a diagnostic) if there was -/// an error, returns false if the initialization succeeded. Elidable should -/// be true when the copy may be elided (C++ 12.8p15). Overload resolution works -/// differently in C++0x for this case. -bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType, - AssignmentAction Action, bool Elidable) { - if (!getLangOptions().CPlusPlus) { - // In C, argument passing is the same as performing an assignment. - QualType FromType = From->getType(); - - AssignConvertType ConvTy = - CheckSingleAssignmentConstraints(ToType, From); - if (ConvTy != Compatible && - CheckTransparentUnionArgumentConstraints(ToType, From) == Compatible) - ConvTy = Compatible; - - return DiagnoseAssignmentResult(ConvTy, From->getLocStart(), ToType, - FromType, From, Action); - } - - if (ToType->isReferenceType()) - return CheckReferenceInit(From, ToType, - /*FIXME:*/From->getLocStart(), - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, - /*ForceRValue=*/false); - - if (!PerformImplicitConversion(From, ToType, Action, - /*AllowExplicit=*/false, Elidable)) - return false; - if (!DiagnoseMultipleUserDefinedConversion(From, ToType)) - return Diag(From->getSourceRange().getBegin(), - diag::err_typecheck_convert_incompatible) - << ToType << From->getType() << Action << From->getSourceRange(); - return true; -} - /// TryObjectArgumentInitialization - Try to initialize the object /// parameter of the given member function (@c Method) from the /// expression @p From. @@ -2316,6 +2281,7 @@ Sema::TryObjectArgumentInitialization(QualType OrigFromType, bool Sema::PerformObjectArgumentInitialization(Expr *&From, NestedNameSpecifier *Qualifier, + NamedDecl *FoundDecl, CXXMethodDecl *Method) { QualType FromRecordType, DestType; QualType ImplicitParamRecordType = @@ -2340,7 +2306,7 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, << ImplicitParamRecordType << FromRecordType << From->getSourceRange(); if (ICS.Standard.Second == ICK_Derived_To_Base) - return PerformObjectMemberConversion(From, Qualifier, Method); + return PerformObjectMemberConversion(From, Qualifier, FoundDecl, Method); if (!Context.hasSameType(From->getType(), DestType)) ImpCastExprToType(From, DestType, CastExpr::CK_NoOp, @@ -3344,13 +3310,16 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, = ClassDecl->getVisibleConversionFunctions(); for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { + NamedDecl *D = I.getDecl(); + if (isa(D)) + D = cast(D)->getTargetDecl(); // Skip conversion function templates; they don't tell us anything // about which builtin types we can convert to. - if (isa(*I)) + if (isa(D)) continue; - CXXConversionDecl *Conv = cast(*I); + CXXConversionDecl *Conv = cast(D); if (AllowExplicitConversions || !Conv->isExplicit()) { AddTypesConvertedFrom(Conv->getConversionType(), Loc, false, false, VisibleQuals); @@ -3412,7 +3381,10 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { - if (CXXConversionDecl *Conv = dyn_cast(*I)) { + NamedDecl *D = I.getDecl(); + if (isa(D)) + D = cast(D)->getTargetDecl(); + if (CXXConversionDecl *Conv = dyn_cast(D)) { QualType CanTy = Context.getCanonicalType(Conv->getConversionType()); if (const ReferenceType *ResTypeRef = CanTy->getAs()) CanTy = ResTypeRef->getPointeeType(); @@ -4733,7 +4705,7 @@ void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc, if (!ICS.isAmbiguous()) continue; S.DiagnoseAmbiguousConversion(ICS, OpLoc, - PDiag(diag::note_ambiguous_type_conversion)); + S.PDiag(diag::note_ambiguous_type_conversion)); } } @@ -4980,7 +4952,8 @@ static bool CheckUnresolvedAccess(Sema &S, OverloadExpr *E, DeclAccessPair D) { /// routine will emit diagnostics if there is an error. FunctionDecl * Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, - bool Complain) { + bool Complain, + DeclAccessPair &FoundResult) { QualType FunctionType = ToType; bool IsMember = false; if (const PointerType *ToTypePtr = ToType->getAs()) @@ -5018,6 +4991,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // Look through all of the overloaded functions, searching for one // whose type matches exactly. llvm::SmallVector, 4> Matches; + llvm::SmallVector NonMatches; + bool FoundNonTemplateFunction = false; for (UnresolvedSetIterator I = OvlExpr->decls_begin(), E = OvlExpr->decls_end(); I != E; ++I) { @@ -5097,9 +5072,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, return 0; else if (Matches.size() == 1) { FunctionDecl *Result = Matches[0].second; + FoundResult = Matches[0].first; MarkDeclarationReferenced(From->getLocStart(), Result); if (Complain) - CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first); + CheckAddressOfMemberAccess(OvlExpr, Matches[0].first); return Result; } @@ -5131,10 +5107,9 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, << (unsigned) oc_function_template); assert(Result != MatchesCopy.end() && "no most-specialized template"); MarkDeclarationReferenced(From->getLocStart(), *Result); - if (Complain) { - DeclAccessPair FoundDecl = Matches[Result - MatchesCopy.begin()].first; - CheckUnresolvedAccess(*this, OvlExpr, FoundDecl); - } + FoundResult = Matches[Result - MatchesCopy.begin()].first; + if (Complain) + CheckUnresolvedAccess(*this, OvlExpr, FoundResult); return cast(*Result); } @@ -5153,6 +5128,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // selected function. if (Matches.size() == 1) { MarkDeclarationReferenced(From->getLocStart(), Matches[0].second); + FoundResult = Matches[0].first; if (Complain) CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first); return cast(Matches[0].second); @@ -5433,7 +5409,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE, case OR_Success: { FunctionDecl *FDecl = Best->Function; CheckUnresolvedLookupAccess(ULE, Best->FoundDecl); - Fn = FixOverloadedFunctionReference(Fn, FDecl); + Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl); return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc); } @@ -5560,7 +5536,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, if (CXXMethodDecl *Method = dyn_cast(FnDecl)) { CheckMemberOperatorAccess(OpLoc, Args[0], 0, Best->FoundDecl); - if (PerformObjectArgumentInitialization(Input, /*Qualifier=*/0, Method)) + if (PerformObjectArgumentInitialization(Input, /*Qualifier=*/0, + Best->FoundDecl, Method)) return ExprError(); } else { // Convert the arguments. @@ -5754,7 +5731,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, return ExprError(); if (PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0, - Method)) + Best->FoundDecl, Method)) return ExprError(); Args[1] = RHS = Arg1.takeAs(); @@ -5921,7 +5898,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // Convert the arguments. CXXMethodDecl *Method = cast(FnDecl); if (PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0, - Method)) + Best->FoundDecl, Method)) return ExprError(); // Convert the arguments. @@ -6026,10 +6003,12 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, MemberExpr *MemExpr; CXXMethodDecl *Method = 0; + NamedDecl *FoundDecl = 0; NestedNameSpecifier *Qualifier = 0; if (isa(NakedMemExpr)) { MemExpr = cast(NakedMemExpr); Method = cast(MemExpr->getMemberDecl()); + FoundDecl = MemExpr->getFoundDecl(); Qualifier = MemExpr->getQualifier(); } else { UnresolvedMemberExpr *UnresExpr = cast(NakedMemExpr); @@ -6079,6 +6058,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, switch (BestViableFunction(CandidateSet, UnresExpr->getLocStart(), Best)) { case OR_Success: Method = cast(Best->Function); + FoundDecl = Best->FoundDecl; CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl); break; @@ -6106,7 +6086,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, return ExprError(); } - MemExprE = FixOverloadedFunctionReference(MemExprE, Method); + MemExprE = FixOverloadedFunctionReference(MemExprE, FoundDecl, Method); // If overload resolution picked a static member, build a // non-member call based on that function. @@ -6131,9 +6111,12 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, return ExprError(); // Convert the object argument (for a non-static member function call). + // We only need to do this if there was actually an overload; otherwise + // it was done at lookup. Expr *ObjectArg = MemExpr->getBase(); if (!Method->isStatic() && - PerformObjectArgumentInitialization(ObjectArg, Qualifier, Method)) + PerformObjectArgumentInitialization(ObjectArg, Qualifier, + FoundDecl, Method)) return ExprError(); MemExpr->setBase(ObjectArg); @@ -6173,7 +6156,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call); if (RequireCompleteType(LParenLoc, Object->getType(), - PartialDiagnostic(diag::err_incomplete_object_call) + PDiag(diag::err_incomplete_object_call) << Object->getSourceRange())) return true; @@ -6293,7 +6276,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // Create an implicit member expr to refer to the conversion operator. // and then call it. - CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(Object, Conv); + CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(Object, Best->FoundDecl, + Conv); return ActOnCallExpr(S, ExprArg(*this, CE), LParenLoc, MultiExprArg(*this, (ExprTy**)Args, NumArgs), @@ -6353,7 +6337,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // Initialize the implicit object parameter. IsError |= PerformObjectArgumentInitialization(Object, /*Qualifier=*/0, - Method); + Best->FoundDecl, Method); TheCall->setArg(0, Object); @@ -6474,7 +6458,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { // Convert the object parameter. CXXMethodDecl *Method = cast(Best->Function); - if (PerformObjectArgumentInitialization(Base, /*Qualifier=*/0, Method)) + if (PerformObjectArgumentInitialization(Base, /*Qualifier=*/0, + Best->FoundDecl, Method)) return ExprError(); // No concerns about early exits now. @@ -6501,9 +6486,11 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { /// perhaps a '&' around it). We have resolved the overloaded function /// to the function declaration Fn, so patch up the expression E to /// refer (possibly indirectly) to Fn. Returns the new expr. -Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { +Expr *Sema::FixOverloadedFunctionReference(Expr *E, NamedDecl *Found, + FunctionDecl *Fn) { if (ParenExpr *PE = dyn_cast(E)) { - Expr *SubExpr = FixOverloadedFunctionReference(PE->getSubExpr(), Fn); + Expr *SubExpr = FixOverloadedFunctionReference(PE->getSubExpr(), + Found, Fn); if (SubExpr == PE->getSubExpr()) return PE->Retain(); @@ -6511,7 +6498,8 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { } if (ImplicitCastExpr *ICE = dyn_cast(E)) { - Expr *SubExpr = FixOverloadedFunctionReference(ICE->getSubExpr(), Fn); + Expr *SubExpr = FixOverloadedFunctionReference(ICE->getSubExpr(), + Found, Fn); assert(Context.hasSameType(ICE->getSubExpr()->getType(), SubExpr->getType()) && "Implicit cast type cannot be determined from overload"); @@ -6535,7 +6523,8 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { // Fix the sub expression, which really has to be an // UnresolvedLookupExpr holding an overloaded member function // or template. - Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn); + Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), + Found, Fn); if (SubExpr == UnOp->getSubExpr()) return UnOp->Retain(); @@ -6556,7 +6545,8 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { MemPtrType, UnOp->getOperatorLoc()); } } - Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn); + Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), + Found, Fn); if (SubExpr == UnOp->getSubExpr()) return UnOp->Retain(); @@ -6618,6 +6608,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { MemExpr->getQualifier(), MemExpr->getQualifierRange(), Fn, + Found, MemExpr->getMemberLoc(), TemplateArgs, Fn->getType()); @@ -6628,8 +6619,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { } Sema::OwningExprResult Sema::FixOverloadedFunctionReference(OwningExprResult E, + NamedDecl *Found, FunctionDecl *Fn) { - return Owned(FixOverloadedFunctionReference((Expr *)E.get(), Fn)); + return Owned(FixOverloadedFunctionReference((Expr *)E.get(), Found, Fn)); } } // end namespace clang diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index fd65c32..791de8c 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -119,7 +119,13 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { } } } - + else if (const ObjCMessageExpr *ME = dyn_cast(E)) { + const ObjCMethodDecl *MD = ME->getMethodDecl(); + if (MD && MD->getAttr()) { + Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result"; + return; + } + } Diag(Loc, DiagID) << R1 << R2; } @@ -427,48 +433,50 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc, // Make sure that the condition expression has a complete type, // otherwise we'll never find any conversions. if (S.RequireCompleteType(SwitchLoc, CondType, - PDiag(diag::err_switch_incomplete_class_type) + S.PDiag(diag::err_switch_incomplete_class_type) << CondExpr->getSourceRange())) return true; - llvm::SmallVector ViableConversions; - llvm::SmallVector ExplicitConversions; + UnresolvedSet<4> ViableConversions; + UnresolvedSet<4> ExplicitConversions; if (const RecordType *RecordTy = CondType->getAs()) { const UnresolvedSetImpl *Conversions = cast(RecordTy->getDecl()) ->getVisibleConversionFunctions(); for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { - if (CXXConversionDecl *Conversion = dyn_cast(*I)) + if (CXXConversionDecl *Conversion + = dyn_cast((*I)->getUnderlyingDecl())) if (Conversion->getConversionType().getNonReferenceType() ->isIntegralType()) { if (Conversion->isExplicit()) - ExplicitConversions.push_back(Conversion); + ExplicitConversions.addDecl(I.getDecl(), I.getAccess()); else - ViableConversions.push_back(Conversion); + ViableConversions.addDecl(I.getDecl(), I.getAccess()); } } switch (ViableConversions.size()) { case 0: if (ExplicitConversions.size() == 1) { + DeclAccessPair Found = ExplicitConversions[0]; + CXXConversionDecl *Conversion = + cast(Found->getUnderlyingDecl()); // The user probably meant to invoke the given explicit // conversion; use it. QualType ConvTy - = ExplicitConversions[0]->getConversionType() - .getNonReferenceType(); + = Conversion->getConversionType().getNonReferenceType(); std::string TypeStr; ConvTy.getAsStringInternal(TypeStr, S.Context.PrintingPolicy); S.Diag(SwitchLoc, diag::err_switch_explicit_conversion) << CondType << ConvTy << CondExpr->getSourceRange() - << CodeModificationHint::CreateInsertion(CondExpr->getLocStart(), - "static_cast<" + TypeStr + ">(") - << CodeModificationHint::CreateInsertion( + << FixItHint::CreateInsertion(CondExpr->getLocStart(), + "static_cast<" + TypeStr + ">(") + << FixItHint::CreateInsertion( S.PP.getLocForEndOfToken(CondExpr->getLocEnd()), ")"); - S.Diag(ExplicitConversions[0]->getLocation(), - diag::note_switch_conversion) + S.Diag(Conversion->getLocation(), diag::note_switch_conversion) << ConvTy->isEnumeralType() << ConvTy; // If we aren't in a SFINAE context, build a call to the @@ -476,25 +484,32 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc, if (S.isSFINAEContext()) return true; - CondExpr = S.BuildCXXMemberCallExpr(CondExpr, ExplicitConversions[0]); + S.CheckMemberOperatorAccess(CondExpr->getExprLoc(), + CondExpr, 0, Found); + CondExpr = S.BuildCXXMemberCallExpr(CondExpr, Found, Conversion); } // We'll complain below about a non-integral condition type. break; - case 1: + case 1: { // Apply this conversion. - CondExpr = S.BuildCXXMemberCallExpr(CondExpr, ViableConversions[0]); + DeclAccessPair Found = ViableConversions[0]; + S.CheckMemberOperatorAccess(CondExpr->getExprLoc(), + CondExpr, 0, Found); + CondExpr = S.BuildCXXMemberCallExpr(CondExpr, Found, + cast(Found->getUnderlyingDecl())); break; + } default: S.Diag(SwitchLoc, diag::err_switch_multiple_conversions) << CondType << CondExpr->getSourceRange(); for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) { - QualType ConvTy - = ViableConversions[I]->getConversionType().getNonReferenceType(); - S.Diag(ViableConversions[I]->getLocation(), - diag::note_switch_conversion) + CXXConversionDecl *Conv + = cast(ViableConversions[I]->getUnderlyingDecl()); + QualType ConvTy = Conv->getConversionType().getNonReferenceType(); + S.Diag(Conv->getLocation(), diag::note_switch_conversion) << ConvTy->isEnumeralType() << ConvTy; } return true; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 434d556..40ec4bcb 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -161,7 +161,7 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, NestedNameSpecifier *Qualifier = (NestedNameSpecifier*)SS->getScopeRep(); Diag(IILoc, diag::err_template_kw_missing) << Qualifier << II.getName() - << CodeModificationHint::CreateInsertion(IILoc, "template "); + << FixItHint::CreateInsertion(IILoc, "template "); SuggestedTemplate = TemplateTy::make(Context.getDependentTemplateName(Qualifier, &II)); SuggestedKind = TNK_Dependent_template_name; @@ -240,12 +240,12 @@ void Sema::LookupTemplateName(LookupResult &Found, if (LookupCtx) Diag(Found.getNameLoc(), diag::err_no_member_template_suggest) << Name << LookupCtx << Found.getLookupName() << SS.getRange() - << CodeModificationHint::CreateReplacement(Found.getNameLoc(), + << FixItHint::CreateReplacement(Found.getNameLoc(), Found.getLookupName().getAsString()); else Diag(Found.getNameLoc(), diag::err_no_template_suggest) << Name << Found.getLookupName() - << CodeModificationHint::CreateReplacement(Found.getNameLoc(), + << FixItHint::CreateReplacement(Found.getNameLoc(), Found.getLookupName().getAsString()); if (TemplateDecl *Template = Found.getAsSingle()) Diag(Template->getLocation(), diag::note_previous_decl) @@ -822,8 +822,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind, KWLoc, *Name)) { Diag(KWLoc, diag::err_use_with_wrong_tag) << Name - << CodeModificationHint::CreateReplacement(KWLoc, - PrevRecordDecl->getKindName()); + << FixItHint::CreateReplacement(KWLoc, PrevRecordDecl->getKindName()); Diag(PrevRecordDecl->getLocation(), diag::note_previous_use); Kind = PrevRecordDecl->getTagKind(); } @@ -1295,8 +1294,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, } else { Diag(SS.getRange().getBegin(), diag::err_template_spec_needs_header) << SS.getRange() - << CodeModificationHint::CreateInsertion(FirstTemplateLoc, - "template<> "); + << FixItHint::CreateInsertion(FirstTemplateLoc, "template<> "); IsExplicitSpecialization = true; } return 0; @@ -1499,8 +1497,7 @@ Sema::TypeResult Sema::ActOnTagTemplateIdType(TypeResult TypeResult, if (!isAcceptableTagRedeclaration(D, TagKind, TagLoc, *Id)) { Diag(TagLoc, diag::err_use_with_wrong_tag) << Type - << CodeModificationHint::CreateReplacement(SourceRange(TagLoc), - D->getKindName()); + << FixItHint::CreateReplacement(SourceRange(TagLoc), D->getKindName()); Diag(D->getLocation(), diag::note_previous_use); } } @@ -1897,7 +1894,8 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, - TemplateArgumentListBuilder &Converted) { + TemplateArgumentListBuilder &Converted, + CheckTemplateArgumentKind CTAK) { // Check template type parameters. if (TemplateTypeParmDecl *TTP = dyn_cast(Param)) return CheckTemplateTypeArgument(TTP, Arg, Converted); @@ -1937,7 +1935,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, case TemplateArgument::Expression: { Expr *E = Arg.getArgument().getAsExpr(); TemplateArgument Result; - if (CheckTemplateArgument(NTTP, NTTPType, E, Result)) + if (CheckTemplateArgument(NTTP, NTTPType, E, Result, CTAK)) return true; Converted.Append(Result); @@ -2268,18 +2266,20 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, /// \brief Checks whether the given template argument is the address /// of an object or function according to C++ [temp.arg.nontype]p1. -bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, - NamedDecl *&Entity) { +static bool +CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, + NonTypeTemplateParmDecl *Param, + QualType ParamType, + Expr *ArgIn, + TemplateArgument &Converted) { bool Invalid = false; + Expr *Arg = ArgIn; + QualType ArgType = Arg->getType(); // See through any implicit casts we added to fix the type. while (ImplicitCastExpr *Cast = dyn_cast(Arg)) Arg = Cast->getSubExpr(); - // C++0x allows nullptr, and there's no further checking to be done for that. - if (Arg->getType()->isNullPtrType()) - return false; - // C++ [temp.arg.nontype]p1: // // A template-argument for a non-type, non-template @@ -2296,8 +2296,8 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, // Ignore (and complain about) any excess parentheses. while (ParenExpr *Parens = dyn_cast(Arg)) { if (!Invalid) { - Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_extra_parens) + S.Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_extra_parens) << Arg->getSourceRange(); Invalid = true; } @@ -2305,77 +2305,227 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, Arg = Parens->getSubExpr(); } + bool AddressTaken = false; + SourceLocation AddrOpLoc; if (UnaryOperator *UnOp = dyn_cast(Arg)) { - if (UnOp->getOpcode() == UnaryOperator::AddrOf) + if (UnOp->getOpcode() == UnaryOperator::AddrOf) { DRE = dyn_cast(UnOp->getSubExpr()); + AddressTaken = true; + AddrOpLoc = UnOp->getOperatorLoc(); + } } else DRE = dyn_cast(Arg); - if (!DRE) - return Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_not_decl_ref) - << Arg->getSourceRange(); + if (!DRE) { + if (S.Context.hasSameUnqualifiedType(ArgType, S.Context.OverloadTy)) { + S.Diag(Arg->getLocStart(), + diag::err_template_arg_unresolved_overloaded_function) + << ParamType << Arg->getSourceRange(); + } else { + S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref) + << Arg->getSourceRange(); + } + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } // Stop checking the precise nature of the argument if it is value dependent, // it should be checked when instantiated. - if (Arg->isValueDependent()) + if (Arg->isValueDependent()) { + Converted = TemplateArgument(ArgIn->Retain()); return false; + } - if (!isa(DRE->getDecl())) - return Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_not_object_or_func_form) + if (!isa(DRE->getDecl())) { + S.Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_not_object_or_func_form) << Arg->getSourceRange(); + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + + NamedDecl *Entity = 0; // Cannot refer to non-static data members - if (FieldDecl *Field = dyn_cast(DRE->getDecl())) - return Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_field) + if (FieldDecl *Field = dyn_cast(DRE->getDecl())) { + S.Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_field) << Field << Arg->getSourceRange(); + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } // Cannot refer to non-static member functions if (CXXMethodDecl *Method = dyn_cast(DRE->getDecl())) - if (!Method->isStatic()) - return Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_method) + if (!Method->isStatic()) { + S.Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_method) << Method << Arg->getSourceRange(); + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } // Functions must have external linkage. if (FunctionDecl *Func = dyn_cast(DRE->getDecl())) { if (!isExternalLinkage(Func->getLinkage())) { - Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_function_not_extern) + S.Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_function_not_extern) << Func << Arg->getSourceRange(); - Diag(Func->getLocation(), diag::note_template_arg_internal_object) + S.Diag(Func->getLocation(), diag::note_template_arg_internal_object) << true; return true; } // Okay: we've named a function with external linkage. Entity = Func; - return Invalid; - } - if (VarDecl *Var = dyn_cast(DRE->getDecl())) { + // If the template parameter has pointer type, the function decays. + if (ParamType->isPointerType() && !AddressTaken) + ArgType = S.Context.getPointerType(Func->getType()); + else if (AddressTaken && ParamType->isReferenceType()) { + // If we originally had an address-of operator, but the + // parameter has reference type, complain and (if things look + // like they will work) drop the address-of operator. + if (!S.Context.hasSameUnqualifiedType(Func->getType(), + ParamType.getNonReferenceType())) { + S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer) + << ParamType; + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + + S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer) + << ParamType + << FixItHint::CreateRemoval(AddrOpLoc); + S.Diag(Param->getLocation(), diag::note_template_param_here); + + ArgType = Func->getType(); + } + } else if (VarDecl *Var = dyn_cast(DRE->getDecl())) { if (!isExternalLinkage(Var->getLinkage())) { - Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_object_not_extern) + S.Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_object_not_extern) << Var << Arg->getSourceRange(); - Diag(Var->getLocation(), diag::note_template_arg_internal_object) + S.Diag(Var->getLocation(), diag::note_template_arg_internal_object) << true; return true; } + // A value of reference type is not an object. + if (Var->getType()->isReferenceType()) { + S.Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_reference_var) + << Var->getType() << Arg->getSourceRange(); + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + // Okay: we've named an object with external linkage Entity = Var; - return Invalid; - } - // We found something else, but we don't know specifically what it is. - Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_not_object_or_func) + // If the template parameter has pointer type, we must have taken + // the address of this object. + if (ParamType->isReferenceType()) { + if (AddressTaken) { + // If we originally had an address-of operator, but the + // parameter has reference type, complain and (if things look + // like they will work) drop the address-of operator. + if (!S.Context.hasSameUnqualifiedType(Var->getType(), + ParamType.getNonReferenceType())) { + S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer) + << ParamType; + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + + S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer) + << ParamType + << FixItHint::CreateRemoval(AddrOpLoc); + S.Diag(Param->getLocation(), diag::note_template_param_here); + + ArgType = Var->getType(); + } + } else if (!AddressTaken && ParamType->isPointerType()) { + if (Var->getType()->isArrayType()) { + // Array-to-pointer decay. + ArgType = S.Context.getArrayDecayedType(Var->getType()); + } else { + // If the template parameter has pointer type but the address of + // this object was not taken, complain and (possibly) recover by + // taking the address of the entity. + ArgType = S.Context.getPointerType(Var->getType()); + if (!S.Context.hasSameUnqualifiedType(ArgType, ParamType)) { + S.Diag(Arg->getLocStart(), diag::err_template_arg_not_address_of) + << ParamType; + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + + S.Diag(Arg->getLocStart(), diag::err_template_arg_not_address_of) + << ParamType + << FixItHint::CreateInsertion(Arg->getLocStart(), "&"); + + S.Diag(Param->getLocation(), diag::note_template_param_here); + } + } + } else { + // We found something else, but we don't know specifically what it is. + S.Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_not_object_or_func) << Arg->getSourceRange(); - Diag(DRE->getDecl()->getLocation(), - diag::note_template_arg_refers_here); - return true; + S.Diag(DRE->getDecl()->getLocation(), diag::note_template_arg_refers_here); + return true; + } + + if (ParamType->isPointerType() && + !ParamType->getAs()->getPointeeType()->isFunctionType() && + S.IsQualificationConversion(ArgType, ParamType)) { + // For pointer-to-object types, qualification conversions are + // permitted. + } else { + if (const ReferenceType *ParamRef = ParamType->getAs()) { + if (!ParamRef->getPointeeType()->isFunctionType()) { + // C++ [temp.arg.nontype]p5b3: + // For a non-type template-parameter of type reference to + // object, no conversions apply. The type referred to by the + // reference may be more cv-qualified than the (otherwise + // identical) type of the template- argument. The + // template-parameter is bound directly to the + // template-argument, which shall be an lvalue. + + // FIXME: Other qualifiers? + unsigned ParamQuals = ParamRef->getPointeeType().getCVRQualifiers(); + unsigned ArgQuals = ArgType.getCVRQualifiers(); + + if ((ParamQuals | ArgQuals) != ParamQuals) { + S.Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_ref_bind_ignores_quals) + << ParamType << Arg->getType() + << Arg->getSourceRange(); + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + } + } + + // At this point, the template argument refers to an object or + // function with external linkage. We now need to check whether the + // argument and parameter types are compatible. + if (!S.Context.hasSameUnqualifiedType(ArgType, + ParamType.getNonReferenceType())) { + // We can't perform this conversion or binding. + if (ParamType->isReferenceType()) + S.Diag(Arg->getLocStart(), diag::err_template_arg_no_ref_bind) + << ParamType << Arg->getType() << Arg->getSourceRange(); + else + S.Diag(Arg->getLocStart(), diag::err_template_arg_not_convertible) + << Arg->getType() << ParamType << Arg->getSourceRange(); + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + } + + // Create the template argument. + Converted = TemplateArgument(Entity->getCanonicalDecl()); + return false; } /// \brief Checks whether the given template argument is a pointer to @@ -2388,10 +2538,6 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, while (ImplicitCastExpr *Cast = dyn_cast(Arg)) Arg = Cast->getSubExpr(); - // C++0x allows nullptr, and there's no further checking to be done for that. - if (Arg->getType()->isNullPtrType()) - return false; - // C++ [temp.arg.nontype]p1: // // A template-argument for a non-type, non-template @@ -2478,12 +2624,12 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, /// If no error was detected, Converted receives the converted template argument. bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *&Arg, - TemplateArgument &Converted) { + TemplateArgument &Converted, + CheckTemplateArgumentKind CTAK) { SourceLocation StartLoc = Arg->getSourceRange().getBegin(); // If either the parameter has a dependent type or the argument is // type-dependent, there's nothing we can check now. - // FIXME: Add template argument to Converted! if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent()) { // FIXME: Produce a cloned, canonical expression? Converted = TemplateArgument(Arg); @@ -2525,17 +2671,27 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return true; } - // FIXME: We need some way to more easily get the unqualified form - // of the types without going all the way to the - // canonical type. - if (Context.getCanonicalType(ParamType).getCVRQualifiers()) - ParamType = Context.getCanonicalType(ParamType).getUnqualifiedType(); - if (Context.getCanonicalType(ArgType).getCVRQualifiers()) - ArgType = Context.getCanonicalType(ArgType).getUnqualifiedType(); + // From here on out, all we care about are the unqualified forms + // of the parameter and argument types. + ParamType = ParamType.getUnqualifiedType(); + ArgType = ArgType.getUnqualifiedType(); // Try to convert the argument to the parameter's type. if (Context.hasSameType(ParamType, ArgType)) { // Okay: no conversion necessary + } else if (CTAK == CTAK_Deduced) { + // C++ [temp.deduct.type]p17: + // If, in the declaration of a function template with a non-type + // template-parameter, the non-type template- parameter is used + // in an expression in the function parameter-list and, if the + // corresponding template-argument is deduced, the + // template-argument type shall match the type of the + // template-parameter exactly, except that a template-argument + // deduced from an array bound may be of any integral type. + Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch) + << ArgType << ParamType; + Diag(Param->getLocation(), diag::note_template_param_here); + return true; } else if (IsIntegralPromotion(Arg, ArgType, ParamType) || !ParamType->isEnumeralType()) { // This is an integral promotion or conversion. @@ -2554,38 +2710,39 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, IntegerType = Context.getCanonicalType(Enum->getDecl()->getIntegerType()); if (!Arg->isValueDependent()) { - // Check that an unsigned parameter does not receive a negative - // value. + llvm::APSInt OldValue = Value; + + // Coerce the template argument's value to the value it will have + // based on the template parameter's type. + unsigned AllowedBits = Context.getTypeSize(IntegerType); + if (Value.getBitWidth() != AllowedBits) + Value.extOrTrunc(AllowedBits); + Value.setIsSigned(IntegerType->isSignedIntegerType()); + + // Complain if an unsigned parameter received a negative value. if (IntegerType->isUnsignedIntegerType() - && (Value.isSigned() && Value.isNegative())) { - Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_negative) - << Value.toString(10) << Param->getType() + && (OldValue.isSigned() && OldValue.isNegative())) { + Diag(Arg->getSourceRange().getBegin(), diag::warn_template_arg_negative) + << OldValue.toString(10) << Value.toString(10) << Param->getType() << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); - return true; } - // Check that we don't overflow the template parameter type. - unsigned AllowedBits = Context.getTypeSize(IntegerType); + // Complain if we overflowed the template parameter's type. unsigned RequiredBits; if (IntegerType->isUnsignedIntegerType()) - RequiredBits = Value.getActiveBits(); - else if (Value.isUnsigned()) - RequiredBits = Value.getActiveBits() + 1; + RequiredBits = OldValue.getActiveBits(); + else if (OldValue.isUnsigned()) + RequiredBits = OldValue.getActiveBits() + 1; else - RequiredBits = Value.getMinSignedBits(); + RequiredBits = OldValue.getMinSignedBits(); if (RequiredBits > AllowedBits) { Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_too_large) - << Value.toString(10) << Param->getType() + diag::warn_template_arg_too_large) + << OldValue.toString(10) << Value.toString(10) << Param->getType() << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); - return true; } - - if (Value.getBitWidth() != AllowedBits) - Value.extOrTrunc(AllowedBits); - Value.setIsSigned(IntegerType->isSignedIntegerType()); } // Add the value of this argument to the list of converted @@ -2604,6 +2761,18 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return false; } + DeclAccessPair FoundResult; // temporary for ResolveOverloadedFunction + + // C++0x [temp.arg.nontype]p5 bullets 2, 4 and 6 permit conversion + // from a template argument of type std::nullptr_t to a non-type + // template parameter of type pointer to object, pointer to + // function, or pointer-to-member, respectively. + if (ArgType->isNullPtrType() && + (ParamType->isPointerType() || ParamType->isMemberPointerType())) { + Converted = TemplateArgument((NamedDecl *)0); + return false; + } + // Handle pointer-to-function, reference-to-function, and // pointer-to-member-function all in (roughly) the same way. if (// -- For a non-type template-parameter of type pointer to @@ -2611,7 +2780,6 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // applied. If the template-argument represents a set of // overloaded functions (or a pointer to such), the matching // function is selected from the set (13.4). - // In C++0x, any std::nullptr_t value can be converted. (ParamType->isPointerType() && ParamType->getAs()->getPointeeType()->isFunctionType()) || // -- For a non-type template-parameter of type reference to @@ -2625,38 +2793,30 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // template-argument represents a set of overloaded member // functions, the matching member function is selected from // the set (13.4). - // Again, C++0x allows a std::nullptr_t value. (ParamType->isMemberPointerType() && ParamType->getAs()->getPointeeType() ->isFunctionType())) { - if (Context.hasSameUnqualifiedType(ArgType, - ParamType.getNonReferenceType())) { - // We don't have to do anything: the types already match. - } else if (ArgType->isNullPtrType() && (ParamType->isPointerType() || - ParamType->isMemberPointerType())) { - ArgType = ParamType; - if (ParamType->isMemberPointerType()) - ImpCastExprToType(Arg, ParamType, CastExpr::CK_NullToMemberPointer); - else - ImpCastExprToType(Arg, ParamType, CastExpr::CK_BitCast); - } else if (ArgType->isFunctionType() && ParamType->isPointerType()) { - ArgType = Context.getPointerType(ArgType); - ImpCastExprToType(Arg, ArgType, CastExpr::CK_FunctionToPointerDecay); - } else if (FunctionDecl *Fn - = ResolveAddressOfOverloadedFunction(Arg, ParamType, true)) { + + if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType, + true, + FoundResult)) { if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) return true; - Arg = FixOverloadedFunctionReference(Arg, Fn); + Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); ArgType = Arg->getType(); - if (ArgType->isFunctionType() && ParamType->isPointerType()) { - ArgType = Context.getPointerType(Arg->getType()); - ImpCastExprToType(Arg, ArgType, CastExpr::CK_FunctionToPointerDecay); - } } - if (!Context.hasSameUnqualifiedType(ArgType, - ParamType.getNonReferenceType())) { + if (!ParamType->isMemberPointerType()) + return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, + ParamType, + Arg, Converted); + + if (IsQualificationConversion(ArgType, ParamType.getNonReferenceType())) { + ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp, + Arg->isLvalue(Context) == Expr::LV_Valid); + } else if (!Context.hasSameUnqualifiedType(ArgType, + ParamType.getNonReferenceType())) { // We can't perform this conversion. Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_not_convertible) @@ -2665,21 +2825,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return true; } - if (ParamType->isMemberPointerType()) - return CheckTemplateArgumentPointerToMember(Arg, Converted); - - NamedDecl *Entity = 0; - if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) - return true; - - if (Arg->isValueDependent()) { - Converted = TemplateArgument(Arg); - } else { - if (Entity) - Entity = cast(Entity->getCanonicalDecl()); - Converted = TemplateArgument(Entity); - } - return false; + return CheckTemplateArgumentPointerToMember(Arg, Converted); } if (ParamType->isPointerType()) { @@ -2690,40 +2836,9 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, assert(ParamType->getAs()->getPointeeType()->isObjectType() && "Only object pointers allowed here"); - if (ArgType->isNullPtrType()) { - ArgType = ParamType; - ImpCastExprToType(Arg, ParamType, CastExpr::CK_BitCast); - } else if (ArgType->isArrayType()) { - ArgType = Context.getArrayDecayedType(ArgType); - ImpCastExprToType(Arg, ArgType, CastExpr::CK_ArrayToPointerDecay); - } - - if (IsQualificationConversion(ArgType, ParamType)) { - ArgType = ParamType; - ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp); - } - - if (!Context.hasSameUnqualifiedType(ArgType, ParamType)) { - // We can't perform this conversion. - Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_not_convertible) - << Arg->getType() << InstantiatedParamType << Arg->getSourceRange(); - Diag(Param->getLocation(), diag::note_template_param_here); - return true; - } - - NamedDecl *Entity = 0; - if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) - return true; - - if (Arg->isValueDependent()) { - Converted = TemplateArgument(Arg); - } else { - if (Entity) - Entity = cast(Entity->getCanonicalDecl()); - Converted = TemplateArgument(Entity); - } - return false; + return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, + ParamType, + Arg, Converted); } if (const ReferenceType *ParamRefType = ParamType->getAs()) { @@ -2736,53 +2851,31 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, assert(ParamRefType->getPointeeType()->isObjectType() && "Only object references allowed here"); - QualType ReferredType = ParamRefType->getPointeeType(); - if (!Context.hasSameUnqualifiedType(ReferredType, ArgType)) { - Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_no_ref_bind) - << InstantiatedParamType << Arg->getType() - << Arg->getSourceRange(); - Diag(Param->getLocation(), diag::note_template_param_here); - return true; - } - - unsigned ParamQuals - = Context.getCanonicalType(ReferredType).getCVRQualifiers(); - unsigned ArgQuals = Context.getCanonicalType(ArgType).getCVRQualifiers(); + if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, + ParamRefType->getPointeeType(), + true, + FoundResult)) { + if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) + return true; - if ((ParamQuals | ArgQuals) != ParamQuals) { - Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_ref_bind_ignores_quals) - << InstantiatedParamType << Arg->getType() - << Arg->getSourceRange(); - Diag(Param->getLocation(), diag::note_template_param_here); - return true; + Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); + ArgType = Arg->getType(); } - NamedDecl *Entity = 0; - if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) - return true; - - if (Arg->isValueDependent()) { - Converted = TemplateArgument(Arg); - } else { - Entity = cast(Entity->getCanonicalDecl()); - Converted = TemplateArgument(Entity); - } - return false; + return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, + ParamType, + Arg, Converted); } // -- For a non-type template-parameter of type pointer to data // member, qualification conversions (4.4) are applied. - // C++0x allows std::nullptr_t values. assert(ParamType->isMemberPointerType() && "Only pointers to members remain"); if (Context.hasSameUnqualifiedType(ParamType, ArgType)) { // Types match exactly: nothing more to do here. - } else if (ArgType->isNullPtrType()) { - ImpCastExprToType(Arg, ParamType, CastExpr::CK_NullToMemberPointer); } else if (IsQualificationConversion(ArgType, ParamType)) { - ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp); + ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp, + Arg->isLvalue(Context) == Expr::LV_Valid); } else { // We can't perform this conversion. Diag(Arg->getSourceRange().getBegin(), @@ -2837,6 +2930,109 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, Arg.getLocation()); } +/// \brief Given a non-type template argument that refers to a +/// declaration and the type of its corresponding non-type template +/// parameter, produce an expression that properly refers to that +/// declaration. +Sema::OwningExprResult +Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, + QualType ParamType, + SourceLocation Loc) { + assert(Arg.getKind() == TemplateArgument::Declaration && + "Only declaration template arguments permitted here"); + ValueDecl *VD = cast(Arg.getAsDecl()); + + if (VD->getDeclContext()->isRecord() && + (isa(VD) || isa(VD))) { + // If the value is a class member, we might have a pointer-to-member. + // Determine whether the non-type template template parameter is of + // pointer-to-member type. If so, we need to build an appropriate + // expression for a pointer-to-member, since a "normal" DeclRefExpr + // would refer to the member itself. + if (ParamType->isMemberPointerType()) { + QualType ClassType + = Context.getTypeDeclType(cast(VD->getDeclContext())); + NestedNameSpecifier *Qualifier + = NestedNameSpecifier::Create(Context, 0, false, ClassType.getTypePtr()); + CXXScopeSpec SS; + SS.setScopeRep(Qualifier); + OwningExprResult RefExpr = BuildDeclRefExpr(VD, + VD->getType().getNonReferenceType(), + Loc, + &SS); + if (RefExpr.isInvalid()) + return ExprError(); + + RefExpr = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(RefExpr)); + assert(!RefExpr.isInvalid() && + Context.hasSameType(((Expr*) RefExpr.get())->getType(), + ParamType)); + return move(RefExpr); + } + } + + QualType T = VD->getType().getNonReferenceType(); + if (ParamType->isPointerType()) { + // When the non-type template parameter is a pointer, take the + // address of the declaration. + OwningExprResult RefExpr = BuildDeclRefExpr(VD, T, Loc); + if (RefExpr.isInvalid()) + return ExprError(); + + if (T->isFunctionType() || T->isArrayType()) { + // Decay functions and arrays. + Expr *RefE = (Expr *)RefExpr.get(); + DefaultFunctionArrayConversion(RefE); + if (RefE != RefExpr.get()) { + RefExpr.release(); + RefExpr = Owned(RefE); + } + + return move(RefExpr); + } + + // Take the address of everything else + return CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(RefExpr)); + } + + // If the non-type template parameter has reference type, qualify the + // resulting declaration reference with the extra qualifiers on the + // type that the reference refers to. + if (const ReferenceType *TargetRef = ParamType->getAs()) + T = Context.getQualifiedType(T, TargetRef->getPointeeType().getQualifiers()); + + return BuildDeclRefExpr(VD, T, Loc); +} + +/// \brief Construct a new expression that refers to the given +/// integral template argument with the given source-location +/// information. +/// +/// This routine takes care of the mapping from an integral template +/// argument (which may have any integral type) to the appropriate +/// literal value. +Sema::OwningExprResult +Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, + SourceLocation Loc) { + assert(Arg.getKind() == TemplateArgument::Integral && + "Operation is only value for integral template arguments"); + QualType T = Arg.getIntegralType(); + if (T->isCharType() || T->isWideCharType()) + return Owned(new (Context) CharacterLiteral( + Arg.getAsIntegral()->getZExtValue(), + T->isWideCharType(), + T, + Loc)); + if (T->isBooleanType()) + return Owned(new (Context) CXXBoolLiteralExpr( + Arg.getAsIntegral()->getBoolValue(), + T, + Loc)); + + return Owned(new (Context) IntegerLiteral(*Arg.getAsIntegral(), T, Loc)); +} + + /// \brief Determine whether the given template parameter lists are /// equivalent. /// @@ -3341,7 +3537,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, } else if (TemplateParams) { if (TUK == TUK_Friend) Diag(KWLoc, diag::err_template_spec_friend) - << CodeModificationHint::CreateRemoval( + << FixItHint::CreateRemoval( SourceRange(TemplateParams->getTemplateLoc(), TemplateParams->getRAngleLoc())) << SourceRange(LAngleLoc, RAngleLoc); @@ -3349,7 +3545,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, isExplicitSpecialization = true; } else if (TUK != TUK_Friend) { Diag(KWLoc, diag::err_template_spec_needs_header) - << CodeModificationHint::CreateInsertion(KWLoc, "template<> "); + << FixItHint::CreateInsertion(KWLoc, "template<> "); isExplicitSpecialization = true; } @@ -3367,7 +3563,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, *ClassTemplate->getIdentifier())) { Diag(KWLoc, diag::err_use_with_wrong_tag) << ClassTemplate - << CodeModificationHint::CreateReplacement(KWLoc, + << FixItHint::CreateReplacement(KWLoc, ClassTemplate->getTemplatedDecl()->getKindName()); Diag(ClassTemplate->getTemplatedDecl()->getLocation(), diag::note_previous_use); @@ -3409,8 +3605,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // to the implicit argument list of the primary template. Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template) << (TUK == TUK_Definition) - << CodeModificationHint::CreateRemoval(SourceRange(LAngleLoc, - RAngleLoc)); + << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc)); return CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS, ClassTemplate->getIdentifier(), TemplateNameLoc, @@ -3644,7 +3839,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, if (TUK == TUK_Friend) { FriendDecl *Friend = FriendDecl::Create(Context, CurContext, TemplateNameLoc, - WrittenTy->getType().getTypePtr(), + WrittenTy, /*FIXME:*/KWLoc); Friend->setAccess(AS_public); CurContext->addDecl(Friend); @@ -3948,11 +4143,11 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, UnresolvedSetIterator Result = getMostSpecialized(Candidates.begin(), Candidates.end(), TPOC_Other, FD->getLocation(), - PartialDiagnostic(diag::err_function_template_spec_no_match) + PDiag(diag::err_function_template_spec_no_match) << FD->getDeclName(), - PartialDiagnostic(diag::err_function_template_spec_ambiguous) + PDiag(diag::err_function_template_spec_ambiguous) << FD->getDeclName() << (ExplicitTemplateArgs != 0), - PartialDiagnostic(diag::note_function_template_spec_matched)); + PDiag(diag::note_function_template_spec_matched)); if (Result == Candidates.end()) return true; @@ -3961,9 +4156,14 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // FIXME: Check if the prior specialization has a point of instantiation. // If so, we have run afoul of . + + // If this is a friend declaration, then we're not really declaring + // an explicit specialization. + bool isFriend = (FD->getFriendObjectKind() != Decl::FOK_None); // Check the scope of this explicit specialization. - if (CheckTemplateSpecializationScope(*this, + if (!isFriend && + CheckTemplateSpecializationScope(*this, Specialization->getPrimaryTemplate(), Specialization, FD->getLocation(), false)) @@ -3980,7 +4180,8 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, assert(SpecInfo && "Function template specialization info missing?"); bool SuppressNew = false; - if (CheckSpecializationInstantiationRedecl(FD->getLocation(), + if (!isFriend && + CheckSpecializationInstantiationRedecl(FD->getLocation(), TSK_ExplicitSpecialization, Specialization, SpecInfo->getTemplateSpecializationKind(), @@ -3990,7 +4191,8 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // Mark the prior declaration as an explicit specialization, so that later // clients know that this is an explicit specialization. - SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization); + if (!isFriend) + SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization); // Turn the given function declaration into a function template // specialization, with the template arguments from the previous @@ -3999,7 +4201,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, new (Context) TemplateArgumentList( *Specialization->getTemplateSpecializationArgs()), /*InsertPos=*/0, - TSK_ExplicitSpecialization); + SpecInfo->getTemplateSpecializationKind()); // The "previous declaration" for this function template specialization is // the prior function template specialization. @@ -4250,7 +4452,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, *ClassTemplate->getIdentifier())) { Diag(KWLoc, diag::err_use_with_wrong_tag) << ClassTemplate - << CodeModificationHint::CreateReplacement(KWLoc, + << FixItHint::CreateReplacement(KWLoc, ClassTemplate->getTemplatedDecl()->getKindName()); Diag(ClassTemplate->getTemplatedDecl()->getLocation(), diag::note_previous_use); @@ -4388,8 +4590,17 @@ Sema::ActOnExplicitInstantiation(Scope *S, // Instantiate the members of this class template specialization. Def = cast_or_null( Specialization->getDefinition()); - if (Def) + if (Def) { + TemplateSpecializationKind Old_TSK = Def->getTemplateSpecializationKind(); + + // Fix a TSK_ExplicitInstantiationDeclaration followed by a + // TSK_ExplicitInstantiationDefinition + if (Old_TSK == TSK_ExplicitInstantiationDeclaration && + TSK == TSK_ExplicitInstantiationDefinition) + Def->setTemplateSpecializationKind(TSK); + InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK); + } return DeclPtrTy::make(Specialization); } @@ -4559,7 +4770,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (D.getDeclSpec().isInlineSpecified() && getLangOptions().CPlusPlus0x) Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_explicit_instantiation_inline) - <(Result.getFoundDecl())) { @@ -4960,16 +5174,16 @@ namespace { /// \brief Transforms a typename type by determining whether the type now /// 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 TransformDependentNameType(TypeLocBuilder &TLB, DependentNameTypeLoc TL, QualType ObjectType); }; } QualType -CurrentInstantiationRebuilder::TransformTypenameType(TypeLocBuilder &TLB, - TypenameTypeLoc TL, +CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB, + DependentNameTypeLoc TL, QualType ObjectType) { - TypenameType *T = TL.getTypePtr(); + DependentNameType *T = TL.getTypePtr(); NestedNameSpecifier *NNS = TransformNestedNameSpecifier(T->getQualifier(), @@ -5001,15 +5215,17 @@ CurrentInstantiationRebuilder::TransformTypenameType(TypeLocBuilder &TLB, NewTemplateId == QualType(TemplateId, 0)) Result = QualType(T, 0); else - Result = getDerived().RebuildTypenameType(NNS, NewTemplateId); + Result = getDerived().RebuildDependentNameType(T->getKeyword(), + NNS, NewTemplateId); } else - Result = getDerived().RebuildTypenameType(NNS, T->getIdentifier(), - SourceRange(TL.getNameLoc())); + Result = getDerived().RebuildDependentNameType(T->getKeyword(), + NNS, T->getIdentifier(), + SourceRange(TL.getNameLoc())); if (Result.isNull()) return QualType(); - TypenameTypeLoc NewTL = TLB.push(Result); + DependentNameTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; } @@ -5034,7 +5250,7 @@ CurrentInstantiationRebuilder::TransformTypenameType(TypeLocBuilder &TLB, /// typename X::pointer X::data() { ... } /// \endcode /// -/// Here, the type "typename X::pointer" will be created as a TypenameType, +/// Here, the type "typename X::pointer" will be created as a DependentNameType, /// since we do not know that we can look into X when we parsed the type. /// This function will rebuild the type, performing the lookup of "pointer" /// in X and returning a QualifiedNameType whose canonical type is the same diff --git a/lib/Sema/SemaTemplate.h b/lib/Sema/SemaTemplate.h index 2bfb25a..ca59e27 100644 --- a/lib/Sema/SemaTemplate.h +++ b/lib/Sema/SemaTemplate.h @@ -99,6 +99,40 @@ namespace clang { /// template specialization to a function template. TPOC_Other }; + + /// \brief Captures a template argument whose value has been deduced + /// via c++ template argument deduction. + class DeducedTemplateArgument : public TemplateArgument { + /// \brief For a non-type template argument, whether the value was + /// deduced from an array bound. + bool DeducedFromArrayBound; + + public: + DeducedTemplateArgument() + : TemplateArgument(), DeducedFromArrayBound(false) { } + + DeducedTemplateArgument(const TemplateArgument &Arg, + bool DeducedFromArrayBound = false) + : TemplateArgument(Arg), DeducedFromArrayBound(DeducedFromArrayBound) { } + + /// \brief Construct an integral non-type template argument that + /// has been deduced, possible from an array bound. + DeducedTemplateArgument(const llvm::APSInt &Value, + QualType ValueType, + bool DeducedFromArrayBound) + : TemplateArgument(Value, ValueType), + DeducedFromArrayBound(DeducedFromArrayBound) { } + + /// \brief For a non-type template argument, determine whether the + /// template argument was deduced from an array bound. + bool wasDeducedFromArrayBound() const { return DeducedFromArrayBound; } + + /// \brief Specify whether the given non-type template argument + /// was deduced from an array bound. + void setDeducedFromArrayBound(bool Deduced) { + DeducedFromArrayBound = Deduced; + } + }; } #endif // LLVM_CLANG_SEMA_TEMPLATE_H diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 326519d..d61a767 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -48,13 +48,34 @@ namespace clang { using namespace clang; +/// \brief Compare two APSInts, extending and switching the sign as +/// necessary to compare their values regardless of underlying type. +static bool hasSameExtendedValue(llvm::APSInt X, llvm::APSInt Y) { + if (Y.getBitWidth() > X.getBitWidth()) + X.extend(Y.getBitWidth()); + else if (Y.getBitWidth() < X.getBitWidth()) + Y.extend(X.getBitWidth()); + + // If there is a signedness mismatch, correct it. + if (X.isSigned() != Y.isSigned()) { + // If the signed value is negative, then the values cannot be the same. + if ((Y.isSigned() && Y.isNegative()) || (X.isSigned() && X.isNegative())) + return false; + + Y.setIsSigned(true); + X.setIsSigned(true); + } + + return X == Y; +} + static Sema::TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, const TemplateArgument &Param, const TemplateArgument &Arg, Sema::TemplateDeductionInfo &Info, - llvm::SmallVectorImpl &Deduced); + llvm::SmallVectorImpl &Deduced); /// \brief If the given expression is of a form that permits the deduction /// of a non-type template parameter, return the declaration of that @@ -74,50 +95,38 @@ static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) { static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument(Sema &S, NonTypeTemplateParmDecl *NTTP, - llvm::APSInt Value, + llvm::APSInt Value, QualType ValueType, + bool DeducedFromArrayBound, Sema::TemplateDeductionInfo &Info, - llvm::SmallVectorImpl &Deduced) { + llvm::SmallVectorImpl &Deduced) { assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); if (Deduced[NTTP->getIndex()].isNull()) { - QualType T = NTTP->getType(); - - // FIXME: Make sure we didn't overflow our data type! - unsigned AllowedBits = S.Context.getTypeSize(T); - if (Value.getBitWidth() != AllowedBits) - Value.extOrTrunc(AllowedBits); - Value.setIsSigned(T->isSignedIntegerType()); - - Deduced[NTTP->getIndex()] = TemplateArgument(Value, T); + Deduced[NTTP->getIndex()] = DeducedTemplateArgument(Value, ValueType, + DeducedFromArrayBound); return Sema::TDK_Success; } - assert(Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Integral); - - // If the template argument was previously deduced to a negative value, - // then our deduction fails. - const llvm::APSInt *PrevValuePtr = Deduced[NTTP->getIndex()].getAsIntegral(); - if (PrevValuePtr->isNegative()) { + if (Deduced[NTTP->getIndex()].getKind() != TemplateArgument::Integral) { Info.Param = NTTP; Info.FirstArg = Deduced[NTTP->getIndex()]; - Info.SecondArg = TemplateArgument(Value, NTTP->getType()); - return Sema::TDK_Inconsistent; + Info.SecondArg = TemplateArgument(Value, ValueType); + return Sema::TDK_Inconsistent; } - llvm::APSInt PrevValue = *PrevValuePtr; - if (Value.getBitWidth() > PrevValue.getBitWidth()) - PrevValue.zext(Value.getBitWidth()); - else if (Value.getBitWidth() < PrevValue.getBitWidth()) - Value.zext(PrevValue.getBitWidth()); - - if (Value != PrevValue) { + // Extent the smaller of the two values. + llvm::APSInt PrevValue = *Deduced[NTTP->getIndex()].getAsIntegral(); + if (!hasSameExtendedValue(PrevValue, Value)) { Info.Param = NTTP; Info.FirstArg = Deduced[NTTP->getIndex()]; - Info.SecondArg = TemplateArgument(Value, NTTP->getType()); + Info.SecondArg = TemplateArgument(Value, ValueType); return Sema::TDK_Inconsistent; } + if (!DeducedFromArrayBound) + Deduced[NTTP->getIndex()].setDeducedFromArrayBound(false); + return Sema::TDK_Success; } @@ -130,15 +139,14 @@ DeduceNonTypeTemplateArgument(Sema &S, NonTypeTemplateParmDecl *NTTP, Expr *Value, Sema::TemplateDeductionInfo &Info, - llvm::SmallVectorImpl &Deduced) { + llvm::SmallVectorImpl &Deduced) { assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); assert((Value->isTypeDependent() || Value->isValueDependent()) && "Expression template argument must be type- or value-dependent."); if (Deduced[NTTP->getIndex()].isNull()) { - // FIXME: Clone the Value? - Deduced[NTTP->getIndex()] = TemplateArgument(Value); + Deduced[NTTP->getIndex()] = TemplateArgument(Value->Retain()); return Sema::TDK_Success; } @@ -173,7 +181,7 @@ DeduceNonTypeTemplateArgument(Sema &S, NonTypeTemplateParmDecl *NTTP, Decl *D, Sema::TemplateDeductionInfo &Info, - llvm::SmallVectorImpl &Deduced) { + llvm::SmallVectorImpl &Deduced) { assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); @@ -207,7 +215,7 @@ DeduceTemplateArguments(Sema &S, TemplateName Param, TemplateName Arg, Sema::TemplateDeductionInfo &Info, - llvm::SmallVectorImpl &Deduced) { + llvm::SmallVectorImpl &Deduced) { TemplateDecl *ParamDecl = Param.getAsTemplateDecl(); if (!ParamDecl) { // The parameter type is dependent and is not a template template parameter, @@ -271,7 +279,7 @@ DeduceTemplateArguments(Sema &S, const TemplateSpecializationType *Param, QualType Arg, Sema::TemplateDeductionInfo &Info, - llvm::SmallVectorImpl &Deduced) { + llvm::SmallVectorImpl &Deduced) { assert(Arg.isCanonical() && "Argument type must be canonical"); // Check whether the template argument is a dependent template-id. @@ -363,7 +371,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, QualType ParamIn, QualType ArgIn, Sema::TemplateDeductionInfo &Info, - llvm::SmallVectorImpl &Deduced, + llvm::SmallVectorImpl &Deduced, unsigned TDF) { // We only want to look at the canonical types, since typedefs and // sugar are not part of template argument deduction. @@ -569,7 +577,9 @@ DeduceTemplateArguments(Sema &S, if (const ConstantArrayType *ConstantArrayArg = dyn_cast(ArrayArg)) { llvm::APSInt Size(ConstantArrayArg->getSize()); - return DeduceNonTypeTemplateArgument(S, NTTP, Size, + return DeduceNonTypeTemplateArgument(S, NTTP, Size, + S.Context.getSizeType(), + /*ArrayBound=*/true, Info, Deduced); } if (const DependentSizedArrayType *DependentArrayArg @@ -763,7 +773,7 @@ DeduceTemplateArguments(Sema &S, case Type::TypeOfExpr: case Type::TypeOf: - case Type::Typename: + case Type::DependentName: // No template argument deduction for these types return Sema::TDK_Success; @@ -781,7 +791,7 @@ DeduceTemplateArguments(Sema &S, const TemplateArgument &Param, const TemplateArgument &Arg, Sema::TemplateDeductionInfo &Info, - llvm::SmallVectorImpl &Deduced) { + llvm::SmallVectorImpl &Deduced) { switch (Param.getKind()) { case TemplateArgument::Null: assert(false && "Null template argument in parameter list"); @@ -816,8 +826,7 @@ DeduceTemplateArguments(Sema &S, case TemplateArgument::Integral: if (Arg.getKind() == TemplateArgument::Integral) { - // FIXME: Zero extension + sign checking here? - if (*Param.getAsIntegral() == *Arg.getAsIntegral()) + if (hasSameExtendedValue(*Param.getAsIntegral(), *Arg.getAsIntegral())) return Sema::TDK_Success; Info.FirstArg = Param; @@ -840,9 +849,10 @@ DeduceTemplateArguments(Sema &S, if (NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(Param.getAsExpr())) { if (Arg.getKind() == TemplateArgument::Integral) - // FIXME: Sign problems here return DeduceNonTypeTemplateArgument(S, NTTP, *Arg.getAsIntegral(), + Arg.getIntegralType(), + /*ArrayBound=*/false, Info, Deduced); if (Arg.getKind() == TemplateArgument::Expression) return DeduceNonTypeTemplateArgument(S, NTTP, Arg.getAsExpr(), @@ -874,7 +884,7 @@ DeduceTemplateArguments(Sema &S, const TemplateArgumentList &ParamList, const TemplateArgumentList &ArgList, Sema::TemplateDeductionInfo &Info, - llvm::SmallVectorImpl &Deduced) { + llvm::SmallVectorImpl &Deduced) { assert(ParamList.size() == ArgList.size()); for (unsigned I = 0, N = ParamList.size(); I != N; ++I) { if (Sema::TemplateDeductionResult Result @@ -963,7 +973,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, // specialization can be deduced from the actual template argument // list (14.8.2). SFINAETrap Trap(*this); - llvm::SmallVector Deduced; + llvm::SmallVector Deduced; Deduced.resize(Partial->getTemplateParameters()->size()); if (TemplateDeductionResult Result = ::DeduceTemplateArguments(*this, @@ -987,13 +997,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, Decl *Param = const_cast( Partial->getTemplateParameters()->getParam(I)); - if (TemplateTypeParmDecl *TTP = dyn_cast(Param)) - Info.Param = TTP; - else if (NonTypeTemplateParmDecl *NTTP - = dyn_cast(Param)) - Info.Param = NTTP; - else - Info.Param = cast(Param); + Info.Param = makeTemplateParameter(Param); return TDK_Incomplete; } @@ -1010,6 +1014,9 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, // verify that the instantiated template arguments are both valid // and are equivalent to the template arguments originally provided // to the class template. + // FIXME: Do we have to correct the types of deduced non-type template + // arguments (in particular, integral non-type template arguments?). + Sema::LocalInstantiationScope InstScope(*this); ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate(); const TemplateArgumentLoc *PartialTemplateArgs = Partial->getTemplateArgsAsWritten(); @@ -1112,7 +1119,7 @@ Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( FunctionTemplateDecl *FunctionTemplate, const TemplateArgumentListInfo &ExplicitTemplateArgs, - llvm::SmallVectorImpl &Deduced, + llvm::SmallVectorImpl &Deduced, llvm::SmallVectorImpl &ParamTypes, QualType *FunctionType, TemplateDeductionInfo &Info) { @@ -1225,12 +1232,67 @@ Sema::SubstituteExplicitTemplateArguments( return TDK_Success; } +/// \brief Allocate a TemplateArgumentLoc where all locations have +/// been initialized to the given location. +/// +/// \param S The semantic analysis object. +/// +/// \param The template argument we are producing template argument +/// location information for. +/// +/// \param NTTPType For a declaration template argument, the type of +/// the non-type template parameter that corresponds to this template +/// argument. +/// +/// \param Loc The source location to use for the resulting template +/// argument. +static TemplateArgumentLoc +getTrivialTemplateArgumentLoc(Sema &S, + const TemplateArgument &Arg, + QualType NTTPType, + SourceLocation Loc) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + llvm_unreachable("Can't get a NULL template argument here"); + break; + + case TemplateArgument::Type: + return TemplateArgumentLoc(Arg, + S.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc)); + + case TemplateArgument::Declaration: { + Expr *E + = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc) + .takeAs(); + return TemplateArgumentLoc(TemplateArgument(E), E); + } + + case TemplateArgument::Integral: { + Expr *E + = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).takeAs(); + return TemplateArgumentLoc(TemplateArgument(E), E); + } + + case TemplateArgument::Template: + return TemplateArgumentLoc(Arg, SourceRange(), Loc); + + case TemplateArgument::Expression: + return TemplateArgumentLoc(Arg, Arg.getAsExpr()); + + case TemplateArgument::Pack: + llvm_unreachable("Template parameter packs are not yet supported"); + } + + return TemplateArgumentLoc(); +} + /// \brief Finish template argument deduction for a function template, /// checking the deduced template arguments for completeness and forming /// the function template specialization. Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, - llvm::SmallVectorImpl &Deduced, + llvm::SmallVectorImpl &Deduced, + unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, TemplateDeductionInfo &Info) { TemplateParameterList *TemplateParams @@ -1253,13 +1315,71 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, // explicitly specified, template argument deduction fails. TemplateArgumentListBuilder Builder(TemplateParams, Deduced.size()); for (unsigned I = 0, N = Deduced.size(); I != N; ++I) { + NamedDecl *Param = FunctionTemplate->getTemplateParameters()->getParam(I); if (!Deduced[I].isNull()) { - Builder.Append(Deduced[I]); + if (I < NumExplicitlySpecified || + Deduced[I].getKind() == TemplateArgument::Type) { + // We have already fully type-checked and converted this + // argument (because it was explicitly-specified) or no + // additional checking is necessary (because it's a template + // type parameter). Just record the presence of this + // parameter. + Builder.Append(Deduced[I]); + continue; + } + + // We have deduced this argument, so it still needs to be + // checked and converted. + + // First, for a non-type template parameter type that is + // initialized by a declaration, we need the type of the + // corresponding non-type template parameter. + QualType NTTPType; + if (NonTypeTemplateParmDecl *NTTP + = dyn_cast(Param)) { + if (Deduced[I].getKind() == TemplateArgument::Declaration) { + NTTPType = NTTP->getType(); + if (NTTPType->isDependentType()) { + TemplateArgumentList TemplateArgs(Context, Builder, + /*TakeArgs=*/false); + NTTPType = SubstType(NTTPType, + MultiLevelTemplateArgumentList(TemplateArgs), + NTTP->getLocation(), + NTTP->getDeclName()); + if (NTTPType.isNull()) { + Info.Param = makeTemplateParameter(Param); + return TDK_SubstitutionFailure; + } + } + } + } + + // Convert the deduced template argument into a template + // argument that we can check, almost as if the user had written + // the template argument explicitly. + TemplateArgumentLoc Arg = getTrivialTemplateArgumentLoc(*this, + Deduced[I], + NTTPType, + SourceLocation()); + + // Check the template argument, converting it as necessary. + if (CheckTemplateArgument(Param, Arg, + FunctionTemplate, + FunctionTemplate->getLocation(), + FunctionTemplate->getSourceRange().getEnd(), + Builder, + Deduced[I].wasDeducedFromArrayBound() + ? CTAK_DeducedFromArrayBound + : CTAK_Deduced)) { + Info.Param = makeTemplateParameter( + const_cast(TemplateParams->getParam(I))); + return TDK_SubstitutionFailure; + } + continue; } // Substitute into the default template argument, if available. - NamedDecl *Param = FunctionTemplate->getTemplateParameters()->getParam(I); TemplateArgumentLoc DefArg = SubstDefaultTemplateArgumentIfAvailable(FunctionTemplate, FunctionTemplate->getLocation(), @@ -1279,7 +1399,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, FunctionTemplate, FunctionTemplate->getLocation(), FunctionTemplate->getSourceRange().getEnd(), - Builder)) { + Builder, + CTAK_Deduced)) { Info.Param = makeTemplateParameter( const_cast(TemplateParams->getParam(I))); return TDK_SubstitutionFailure; @@ -1390,7 +1511,8 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, // Type deduction is done independently for each P/A pair, and // the deduced template argument values are then combined. // So we do not reject deductions which were made elsewhere. - llvm::SmallVector Deduced(TemplateParams->size()); + llvm::SmallVector + Deduced(TemplateParams->size()); Sema::TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc()); unsigned TDF = 0; @@ -1458,10 +1580,12 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // The types of the parameters from which we will perform template argument // deduction. + Sema::LocalInstantiationScope InstScope(*this); TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); - llvm::SmallVector Deduced; + llvm::SmallVector Deduced; llvm::SmallVector ParamTypes; + unsigned NumExplicitlySpecified = 0; if (ExplicitTemplateArgs) { TemplateDeductionResult Result = SubstituteExplicitTemplateArguments(FunctionTemplate, @@ -1472,6 +1596,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, Info); if (Result) return Result; + + NumExplicitlySpecified = Deduced.size(); } else { // Just fill in the parameter types from the function declaration. for (unsigned I = 0; I != CheckArgs; ++I) @@ -1574,6 +1700,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, } return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, + NumExplicitlySpecified, Specialization, Info); } @@ -1612,7 +1739,9 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, QualType FunctionType = Function->getType(); // Substitute any explicit template arguments. - llvm::SmallVector Deduced; + Sema::LocalInstantiationScope InstScope(*this); + llvm::SmallVector Deduced; + unsigned NumExplicitlySpecified = 0; llvm::SmallVector ParamTypes; if (ExplicitTemplateArgs) { if (TemplateDeductionResult Result @@ -1621,6 +1750,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, Deduced, ParamTypes, &FunctionType, Info)) return Result; + + NumExplicitlySpecified = Deduced.size(); } // Template argument deduction for function templates in a SFINAE context. @@ -1639,6 +1770,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, } return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, + NumExplicitlySpecified, Specialization, Info); } @@ -1707,7 +1839,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // A) as described in 14.8.2.4. TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); - llvm::SmallVector Deduced; + llvm::SmallVector Deduced; Deduced.resize(TemplateParams->size()); // C++0x [temp.deduct.conv]p4: @@ -1739,9 +1871,11 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // modulo the various allowed differences. // Finish template argument deduction. + Sema::LocalInstantiationScope InstScope(*this); FunctionDecl *Spec = 0; TemplateDeductionResult Result - = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, Spec, Info); + = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, 0, Spec, + Info); Specialization = cast_or_null(Spec); return Result; } @@ -1799,11 +1933,11 @@ enum DeductionQualifierComparison { /// but it may still fail, later, for other reasons. static Sema::TemplateDeductionResult DeduceTemplateArgumentsDuringPartialOrdering(Sema &S, - TemplateParameterList *TemplateParams, + TemplateParameterList *TemplateParams, QualType ParamIn, QualType ArgIn, Sema::TemplateDeductionInfo &Info, - llvm::SmallVectorImpl &Deduced, - llvm::SmallVectorImpl *QualifierComparisons) { + llvm::SmallVectorImpl &Deduced, + llvm::SmallVectorImpl *QualifierComparisons) { CanQualType Param = S.Context.getCanonicalType(ParamIn); CanQualType Arg = S.Context.getCanonicalType(ArgIn); @@ -1877,7 +2011,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, assert(Proto1 && Proto2 && "Function templates must have prototypes"); TemplateParameterList *TemplateParams = FT2->getTemplateParameters(); - llvm::SmallVector Deduced; + llvm::SmallVector Deduced; Deduced.resize(TemplateParams->size()); // C++0x [temp.deduct.partial]p3: @@ -2204,7 +2338,7 @@ Sema::getMoreSpecializedPartialSpecialization( // computation is slightly simpler than the general problem of function // template partial ordering, because class template partial specializations // are more constrained. We know that every template parameter is deduc - llvm::SmallVector Deduced; + llvm::SmallVector Deduced; Sema::TemplateDeductionInfo Info(Context, Loc); // Determine whether PS1 is at least as specialized as PS2 @@ -2421,10 +2555,10 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, OnlyDeduced, Depth, Used); break; - case Type::Typename: + case Type::DependentName: if (!OnlyDeduced) MarkUsedTemplateParameters(SemaRef, - cast(T)->getQualifier(), + cast(T)->getQualifier(), OnlyDeduced, Depth, Used); break; @@ -2525,8 +2659,9 @@ Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, /// \brief Marks all of the template parameters that will be deduced by a /// call to the given function template. -void Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, - llvm::SmallVectorImpl &Deduced) { +void +Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, + llvm::SmallVectorImpl &Deduced) { TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); Deduced.clear(); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 0d6acd0..d21862b 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -394,7 +394,11 @@ void Sema::PrintInstantiationStack() { = cast((Decl *)Active->Entity); Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), diag::note_explicit_template_arg_substitution_here) - << FnTmpl << Active->InstantiationRange; + << FnTmpl + << getTemplateArgumentBindingsText(FnTmpl->getTemplateParameters(), + Active->TemplateArgs, + Active->NumTemplateArgs) + << Active->InstantiationRange; break; } @@ -405,13 +409,21 @@ void Sema::PrintInstantiationStack() { Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), diag::note_partial_spec_deduct_instantiation_here) << Context.getTypeDeclType(PartialSpec) + << getTemplateArgumentBindingsText( + PartialSpec->getTemplateParameters(), + Active->TemplateArgs, + Active->NumTemplateArgs) << Active->InstantiationRange; } else { FunctionTemplateDecl *FnTmpl = cast((Decl *)Active->Entity); Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), diag::note_function_template_deduction_instantiation_here) - << FnTmpl << Active->InstantiationRange; + << FnTmpl + << getTemplateArgumentBindingsText(FnTmpl->getTemplateParameters(), + Active->TemplateArgs, + Active->NumTemplateArgs) + << Active->InstantiationRange; } break; @@ -677,8 +689,8 @@ TemplateInstantiator::RebuildElaboratedType(QualType T, if (!SemaRef.isAcceptableTagRedeclaration(TD, Tag, TagLocation, *Id)) { SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag) << Id - << CodeModificationHint::CreateReplacement(SourceRange(TagLocation), - TD->getKindName()); + << FixItHint::CreateReplacement(SourceRange(TagLocation), + TD->getKindName()); SemaRef.Diag(TD->getLocation(), diag::note_previous_use); } } @@ -745,101 +757,13 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, DeclarationName()); assert(!TargetType.isNull() && "type substitution failed for param type"); assert(!TargetType->isDependentType() && "param type still dependent"); - - if (VD->getDeclContext()->isRecord() && - (isa(VD) || isa(VD))) { - // If the value is a class member, we might have a pointer-to-member. - // Determine whether the non-type template template parameter is of - // pointer-to-member type. If so, we need to build an appropriate - // expression for a pointer-to-member, since a "normal" DeclRefExpr - // would refer to the member itself. - if (TargetType->isMemberPointerType()) { - QualType ClassType - = SemaRef.Context.getTypeDeclType( - cast(VD->getDeclContext())); - NestedNameSpecifier *Qualifier - = NestedNameSpecifier::Create(SemaRef.Context, 0, false, - ClassType.getTypePtr()); - CXXScopeSpec SS; - SS.setScopeRep(Qualifier); - OwningExprResult RefExpr - = SemaRef.BuildDeclRefExpr(VD, - VD->getType().getNonReferenceType(), - E->getLocation(), - &SS); - if (RefExpr.isInvalid()) - return SemaRef.ExprError(); - - RefExpr = SemaRef.CreateBuiltinUnaryOp(E->getLocation(), - UnaryOperator::AddrOf, - move(RefExpr)); - assert(!RefExpr.isInvalid() && - SemaRef.Context.hasSameType(((Expr*) RefExpr.get())->getType(), - TargetType)); - return move(RefExpr); - } - } - - QualType T = VD->getType().getNonReferenceType(); - - if (TargetType->isPointerType()) { - // C++03 [temp.arg.nontype]p5: - // - For a non-type template-parameter of type pointer to - // object, qualification conversions and the array-to-pointer - // conversion are applied. - // - For a non-type template-parameter of type pointer to - // function, only the function-to-pointer conversion is - // applied. - - OwningExprResult RefExpr - = SemaRef.BuildDeclRefExpr(VD, T, E->getLocation()); - if (RefExpr.isInvalid()) - return SemaRef.ExprError(); - - // Decay functions and arrays. - Expr *RefE = (Expr *)RefExpr.get(); - SemaRef.DefaultFunctionArrayConversion(RefE); - if (RefE != RefExpr.get()) { - RefExpr.release(); - RefExpr = SemaRef.Owned(RefE); - } - - // Qualification conversions. - RefExpr.release(); - SemaRef.ImpCastExprToType(RefE, TargetType.getUnqualifiedType(), - CastExpr::CK_NoOp); - return SemaRef.Owned(RefE); - } - - // If the non-type template parameter has reference type, qualify the - // resulting declaration reference with the extra qualifiers on the - // type that the reference refers to. - if (const ReferenceType *TargetRef = TargetType->getAs()) - T = SemaRef.Context.getQualifiedType(T, - TargetRef->getPointeeType().getQualifiers()); - - return SemaRef.BuildDeclRefExpr(VD, T, E->getLocation()); + return SemaRef.BuildExpressionFromDeclTemplateArgument(Arg, + TargetType, + E->getLocation()); } - 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())); + return SemaRef.BuildExpressionFromIntegralTemplateArgument(Arg, + E->getSourceRange().getBegin()); } @@ -873,8 +797,11 @@ TemplateInstantiator::TransformFunctionTypeParams(FunctionProtoTypeLoc TL, llvm::SmallVectorImpl &PTypes, llvm::SmallVectorImpl &PVars) { // Create a local instantiation scope for the parameters. - Sema::LocalInstantiationScope - Scope(SemaRef, SemaRef.CurrentInstantiationScope != 0); + // FIXME: When we implement the C++0x late-specified return type, + // we will need to move this scope out to the function type itself. + bool IsTemporaryScope = (SemaRef.CurrentInstantiationScope != 0); + Sema::LocalInstantiationScope Scope(SemaRef, IsTemporaryScope, + IsTemporaryScope); if (TreeTransform:: TransformFunctionTypeParams(TL, PTypes, PVars)) @@ -1159,6 +1086,12 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, DeclContext *PreviousContext = CurContext; CurContext = Instantiation; + // If this is an instantiation of a local class, merge this local + // instantiation scope with the enclosing scope. Otherwise, every + // instantiation of a class has its own local instantiation scope. + bool MergeWithParentScope = !Instantiation->isDefinedOutsideFunctionOrMethod(); + Sema::LocalInstantiationScope Scope(*this, MergeWithParentScope); + // Start the definition of this instantiation. Instantiation->startDefinition(); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index dbe041c..3375ccc 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -15,6 +15,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclVisitor.h" +#include "clang/AST/DependentDiagnostic.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/TypeLoc.h" @@ -285,17 +286,19 @@ static bool InstantiateInitializer(Sema &S, Expr *Init, } if (CXXConstructExpr *Construct = dyn_cast(Init)) { - if (InstantiateInitializationArguments(S, - Construct->getArgs(), - Construct->getNumArgs(), - TemplateArgs, - CommaLocs, NewArgs)) - return true; - - // FIXME: Fake locations! - LParenLoc = S.PP.getLocForEndOfToken(Init->getLocStart()); - RParenLoc = CommaLocs.empty()? LParenLoc : CommaLocs.back(); - return false; + if (!isa(Construct)) { + if (InstantiateInitializationArguments(S, + Construct->getArgs(), + Construct->getNumArgs(), + TemplateArgs, + CommaLocs, NewArgs)) + return true; + + // FIXME: Fake locations! + LParenLoc = S.PP.getLocForEndOfToken(Init->getLocStart()); + RParenLoc = CommaLocs.empty()? LParenLoc : CommaLocs.back(); + return false; + } } Sema::OwningExprResult Result = S.SubstExpr(Init, TemplateArgs); @@ -477,13 +480,17 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { // Handle friend type expressions by simply substituting template // parameters into the pattern type. - if (Type *Ty = D->getFriendType()) { - QualType T = SemaRef.SubstType(QualType(Ty,0), TemplateArgs, - D->getLocation(), DeclarationName()); - if (T.isNull()) return 0; + if (TypeSourceInfo *Ty = D->getFriendType()) { + TypeSourceInfo *InstTy = + SemaRef.SubstType(Ty, TemplateArgs, + D->getLocation(), DeclarationName()); + if (!InstTy) return 0; + + // This assertion is valid because the source type was necessarily + // an elaborated-type-specifier with a record tag. + assert(getLangOptions().CPlusPlus0x || InstTy->getType()->isRecordType()); - assert(getLangOptions().CPlusPlus0x || T->isRecordType()); - FU = T.getTypePtr(); + FU = InstTy; // Handle everything else by appropriate substitution. } else { @@ -496,22 +503,12 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { Decl *NewND; // Hack to make this work almost well pending a rewrite. - if (ND->getDeclContext()->isRecord()) { - if (!ND->getDeclContext()->isDependentContext()) { - NewND = SemaRef.FindInstantiatedDecl(D->getLocation(), ND, - TemplateArgs); - } else { - // FIXME: Hack to avoid crashing when incorrectly trying to instantiate - // templated friend declarations. This doesn't produce a correct AST; - // however this is sufficient for some AST analysis. The real solution - // must be put in place during the pending rewrite. See PR5848. - return 0; - } - } else if (D->wasSpecialization()) { + if (D->wasSpecialization()) { // Totally egregious hack to work around PR5866 return 0; - } else + } else { NewND = Visit(ND); + } if (!NewND) return 0; FU = cast(NewND); @@ -638,6 +635,8 @@ namespace { } Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { + bool isFriend = (D->getFriendObjectKind() != Decl::FOK_None); + // Create a local instantiation scope for this class template, which // will contain the instantiations of the template parameters. Sema::LocalInstantiationScope Scope(SemaRef); @@ -647,32 +646,106 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { return NULL; CXXRecordDecl *Pattern = D->getTemplatedDecl(); + + // Instantiate the qualifier. We have to do this first in case + // we're a friend declaration, because if we are then we need to put + // the new declaration in the appropriate context. + NestedNameSpecifier *Qualifier = Pattern->getQualifier(); + if (Qualifier) { + Qualifier = SemaRef.SubstNestedNameSpecifier(Qualifier, + Pattern->getQualifierRange(), + TemplateArgs); + if (!Qualifier) return 0; + } + + CXXRecordDecl *PrevDecl = 0; + ClassTemplateDecl *PrevClassTemplate = 0; + + // If this isn't a friend, then it's a member template, in which + // case we just want to build the instantiation in the + // specialization. If it is a friend, we want to build it in + // the appropriate context. + DeclContext *DC = Owner; + if (isFriend) { + if (Qualifier) { + CXXScopeSpec SS; + SS.setScopeRep(Qualifier); + SS.setRange(Pattern->getQualifierRange()); + DC = SemaRef.computeDeclContext(SS); + if (!DC) return 0; + } else { + DC = SemaRef.FindInstantiatedContext(Pattern->getLocation(), + Pattern->getDeclContext(), + TemplateArgs); + } + + // Look for a previous declaration of the template in the owning + // context. + LookupResult R(SemaRef, Pattern->getDeclName(), Pattern->getLocation(), + Sema::LookupOrdinaryName, Sema::ForRedeclaration); + SemaRef.LookupQualifiedName(R, DC); + + if (R.isSingleResult()) { + PrevClassTemplate = R.getAsSingle(); + if (PrevClassTemplate) + PrevDecl = PrevClassTemplate->getTemplatedDecl(); + } + + if (!PrevClassTemplate && Qualifier) { + SemaRef.Diag(Pattern->getLocation(), diag::err_not_tag_in_scope) + << D->getTemplatedDecl()->getTagKind() << Pattern->getDeclName() << DC + << Pattern->getQualifierRange(); + return 0; + } + + if (PrevClassTemplate) { + TemplateParameterList *PrevParams + = PrevClassTemplate->getTemplateParameters(); + + // Make sure the parameter lists match. + if (!SemaRef.TemplateParameterListsAreEqual(InstParams, PrevParams, + /*Complain=*/true, + Sema::TPL_TemplateMatch)) + return 0; + + // Do some additional validation, then merge default arguments + // from the existing declarations. + if (SemaRef.CheckTemplateParameterList(InstParams, PrevParams, + Sema::TPC_ClassTemplate)) + return 0; + } + } + CXXRecordDecl *RecordInst - = CXXRecordDecl::Create(SemaRef.Context, Pattern->getTagKind(), Owner, + = CXXRecordDecl::Create(SemaRef.Context, Pattern->getTagKind(), DC, Pattern->getLocation(), Pattern->getIdentifier(), - Pattern->getTagKeywordLoc(), /*PrevDecl=*/ NULL, + Pattern->getTagKeywordLoc(), PrevDecl, /*DelayTypeCreation=*/true); - // Substitute the nested name specifier, if any. - if (SubstQualifier(Pattern, RecordInst)) - return 0; + if (Qualifier) + RecordInst->setQualifierInfo(Qualifier, Pattern->getQualifierRange()); ClassTemplateDecl *Inst - = ClassTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(), - D->getIdentifier(), InstParams, RecordInst, 0); + = ClassTemplateDecl::Create(SemaRef.Context, DC, D->getLocation(), + D->getIdentifier(), InstParams, RecordInst, + PrevClassTemplate); RecordInst->setDescribedClassTemplate(Inst); - if (D->getFriendObjectKind()) - Inst->setObjectOfFriendDecl(true); - else + if (isFriend) { + Inst->setObjectOfFriendDecl(PrevClassTemplate != 0); + // TODO: do we want to track the instantiation progeny of this + // friend target decl? + } else { Inst->setAccess(D->getAccess()); - Inst->setInstantiatedFromMemberTemplate(D); + Inst->setInstantiatedFromMemberTemplate(D); + } // Trigger creation of the type for the instantiation. SemaRef.Context.getInjectedClassNameType(RecordInst, Inst->getInjectedClassNameSpecialization(SemaRef.Context)); // Finish handling of friends. - if (Inst->getFriendObjectKind()) { + if (isFriend) { + DC->makeDeclVisibleInContext(Inst, /*Recoverable*/ false); return Inst; } @@ -762,16 +835,18 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { assert(InstTemplate && "VisitFunctionDecl/CXXMethodDecl didn't create a template!"); + bool isFriend = (InstTemplate->getFriendObjectKind() != Decl::FOK_None); + // Link the instantiation back to the pattern *unless* this is a // non-definition friend declaration. if (!InstTemplate->getInstantiatedFromMemberTemplate() && - !(InstTemplate->getFriendObjectKind() && - !D->getTemplatedDecl()->isThisDeclarationADefinition())) + !(isFriend && !D->getTemplatedDecl()->isThisDeclarationADefinition())) InstTemplate->setInstantiatedFromMemberTemplate(D); - // Add non-friends into the owner. - if (!InstTemplate->getFriendObjectKind()) + // Make declarations visible in the appropriate context. + if (!isFriend) Owner->addDecl(InstTemplate); + return InstTemplate; } @@ -843,6 +918,12 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, return Info->Function; } + bool isFriend; + if (FunctionTemplate) + isFriend = (FunctionTemplate->getFriendObjectKind() != Decl::FOK_None); + else + isFriend = (D->getFriendObjectKind() != Decl::FOK_None); + bool MergeWithParentScope = (TemplateParams != 0) || !(isa(Owner) && cast(Owner)->isDefinedOutsideFunctionOrMethod()); @@ -855,14 +936,29 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, return 0; QualType T = TInfo->getType(); + NestedNameSpecifier *Qualifier = D->getQualifier(); + if (Qualifier) { + Qualifier = SemaRef.SubstNestedNameSpecifier(Qualifier, + D->getQualifierRange(), + TemplateArgs); + if (!Qualifier) return 0; + } + // If we're instantiating a local function declaration, put the result // in the owner; otherwise we need to find the instantiated context. DeclContext *DC; if (D->getDeclContext()->isFunctionOrMethod()) DC = Owner; - else + else if (isFriend && Qualifier) { + CXXScopeSpec SS; + SS.setScopeRep(Qualifier); + SS.setRange(D->getQualifierRange()); + DC = SemaRef.computeDeclContext(SS); + if (!DC) return 0; + } else { DC = SemaRef.FindInstantiatedContext(D->getLocation(), D->getDeclContext(), TemplateArgs); + } FunctionDecl *Function = FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(), @@ -870,11 +966,16 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, D->getStorageClass(), D->isInlineSpecified(), D->hasWrittenPrototype()); - // Substitute the nested name specifier, if any. - if (SubstQualifier(D, Function)) - return 0; + if (Qualifier) + Function->setQualifierInfo(Qualifier, D->getQualifierRange()); - Function->setLexicalDeclContext(Owner); + DeclContext *LexicalDC = Owner; + if (!isFriend && D->isOutOfLine()) { + assert(D->getDeclContext()->isFileContext()); + LexicalDC = D->getDeclContext(); + } + + Function->setLexicalDeclContext(LexicalDC); // Attach the parameters for (unsigned P = 0; P < Params.size(); ++P) @@ -896,17 +997,29 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, // which means substituting int for T, but leaving "f" as a friend function // template. // Build the function template itself. - FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, Owner, + FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, DC, Function->getLocation(), Function->getDeclName(), TemplateParams, Function); Function->setDescribedFunctionTemplate(FunctionTemplate); - FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext()); + + FunctionTemplate->setLexicalDeclContext(LexicalDC); + + if (isFriend && D->isThisDeclarationADefinition()) { + // TODO: should we remember this connection regardless of whether + // the friend declaration provided a body? + FunctionTemplate->setInstantiatedFromMemberTemplate( + D->getDescribedFunctionTemplate()); + } } else if (FunctionTemplate) { // Record this function template specialization. Function->setFunctionTemplateSpecialization(FunctionTemplate, &TemplateArgs.getInnermost(), InsertPos); + } else if (isFriend && D->isThisDeclarationADefinition()) { + // TODO: should we remember this connection regardless of whether + // the friend declaration provided a body? + Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); } if (InitFunctionInstantiation(Function, D)) @@ -938,9 +1051,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, // If the original function was part of a friend declaration, // inherit its namespace state and add it to the owner. - NamedDecl *FromFriendD - = TemplateParams? cast(D->getDescribedFunctionTemplate()) : D; - if (FromFriendD->getFriendObjectKind()) { + if (isFriend) { NamedDecl *ToFriendD = 0; NamedDecl *PrevDecl; if (TemplateParams) { @@ -951,11 +1062,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, PrevDecl = Function->getPreviousDeclaration(); } ToFriendD->setObjectOfFriendDecl(PrevDecl != NULL); - if (!Owner->isDependentContext() && !PrevDecl) - DC->makeDeclVisibleInContext(ToFriendD, /* Recoverable = */ false); - - if (!TemplateParams) - Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); + DC->makeDeclVisibleInContext(ToFriendD, /*Recoverable=*/ false); } return Function; @@ -985,6 +1092,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, return Info->Function; } + bool isFriend; + if (FunctionTemplate) + isFriend = (FunctionTemplate->getFriendObjectKind() != Decl::FOK_None); + else + isFriend = (D->getFriendObjectKind() != Decl::FOK_None); + bool MergeWithParentScope = (TemplateParams != 0) || !(isa(Owner) && cast(Owner)->isDefinedOutsideFunctionOrMethod()); @@ -997,8 +1110,31 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, return 0; QualType T = TInfo->getType(); + NestedNameSpecifier *Qualifier = D->getQualifier(); + if (Qualifier) { + Qualifier = SemaRef.SubstNestedNameSpecifier(Qualifier, + D->getQualifierRange(), + TemplateArgs); + if (!Qualifier) return 0; + } + + DeclContext *DC = Owner; + if (isFriend) { + if (Qualifier) { + CXXScopeSpec SS; + SS.setScopeRep(Qualifier); + SS.setRange(D->getQualifierRange()); + DC = SemaRef.computeDeclContext(SS); + } else { + DC = SemaRef.FindInstantiatedContext(D->getLocation(), + D->getDeclContext(), + TemplateArgs); + } + if (!DC) return 0; + } + // Build the instantiated method declaration. - CXXRecordDecl *Record = cast(Owner); + CXXRecordDecl *Record = cast(DC); CXXMethodDecl *Method = 0; DeclarationName Name = D->getDeclName(); @@ -1035,9 +1171,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, D->isStatic(), D->isInlineSpecified()); } - // Substitute the nested name specifier, if any. - if (SubstQualifier(D, Method)) - return 0; + if (Qualifier) + Method->setQualifierInfo(Qualifier, D->getQualifierRange()); if (TemplateParams) { // Our resulting instantiation is actually a function template, since we @@ -1057,7 +1192,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method->getLocation(), Method->getDeclName(), TemplateParams, Method); - if (D->isOutOfLine()) + if (isFriend) { + FunctionTemplate->setLexicalDeclContext(Owner); + FunctionTemplate->setObjectOfFriendDecl(true); + } else if (D->isOutOfLine()) FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext()); Method->setDescribedFunctionTemplate(FunctionTemplate); } else if (FunctionTemplate) { @@ -1065,7 +1203,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method->setFunctionTemplateSpecialization(FunctionTemplate, &TemplateArgs.getInnermost(), InsertPos); - } else { + } else if (!isFriend) { // Record that this is an instantiation of a member function. Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); } @@ -1073,7 +1211,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, // If we are instantiating a member function defined // out-of-line, the instantiation will have the same lexical // context (which will be a namespace scope) as the template. - if (D->isOutOfLine()) + if (isFriend) { + Method->setLexicalDeclContext(Owner); + Method->setObjectOfFriendDecl(true); + } else if (D->isOutOfLine()) Method->setLexicalDeclContext(D->getLexicalDeclContext()); // Attach the parameters @@ -1087,8 +1228,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, LookupResult Previous(SemaRef, Name, SourceLocation(), Sema::LookupOrdinaryName, Sema::ForRedeclaration); - if (!FunctionTemplate || TemplateParams) { - SemaRef.LookupQualifiedName(Previous, Owner); + if (!FunctionTemplate || TemplateParams || isFriend) { + SemaRef.LookupQualifiedName(Previous, Record); // In C++, the previous declaration we find might be a tag type // (class or enum). In this case, the new declaration will hide the @@ -1108,9 +1249,19 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method->setAccess(D->getAccess()); - if (!FunctionTemplate && (!Method->isInvalidDecl() || Previous.empty()) && - !Method->getFriendObjectKind()) - Owner->addDecl(Method); + if (FunctionTemplate) { + // If there's a function template, let our caller handle it. + } else if (Method->isInvalidDecl() && !Previous.empty()) { + // Don't hide a (potentially) valid declaration with an invalid one. + } else { + NamedDecl *DeclToAdd = (TemplateParams + ? cast(FunctionTemplate) + : Method); + if (isFriend) + Record->makeDeclVisibleInContext(DeclToAdd); + else + Owner->addDecl(DeclToAdd); + } return Method; } @@ -1694,8 +1845,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, Proto->hasAnyExceptionSpec(), Exceptions.size(), Exceptions.data(), - Proto->getNoReturnAttr(), - Proto->getCallConv())); + Proto->getExtInfo())); } return false; @@ -1839,6 +1989,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, ActOnFinishFunctionBody(DeclPtrTy::make(Function), move(Body), /*IsInstantiation=*/true); + PerformDependentDiagnostics(PatternDecl, TemplateArgs); + CurContext = PreviousContext; DeclGroupRef DG(Function); @@ -2475,3 +2627,17 @@ void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) { InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true); } } + +void Sema::PerformDependentDiagnostics(const DeclContext *Pattern, + const MultiLevelTemplateArgumentList &TemplateArgs) { + for (DeclContext::ddiag_iterator I = Pattern->ddiag_begin(), + E = Pattern->ddiag_end(); I != E; ++I) { + DependentDiagnostic *DD = *I; + + switch (DD->getKind()) { + case DependentDiagnostic::Access: + HandleDependentAccessCheck(*DD, TemplateArgs); + break; + } + } +} diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index a79853a..8278691 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -183,8 +183,7 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, if (DS.isEmpty()) { TheSema.Diag(DeclLoc, diag::ext_missing_declspec) << DS.getSourceRange() - << CodeModificationHint::CreateInsertion(DS.getSourceRange().getBegin(), - "int"); + << FixItHint::CreateInsertion(DS.getSourceRange().getBegin(), "int"); } } else if (!DS.hasTypeSpecifier()) { // C99 and C++ require a type specifier. For example, C99 6.7.2p2 says: @@ -680,8 +679,11 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, return QualType(); } if (ConstVal == 0) { - // GCC accepts zero sized static arrays. - Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size) + // GCC accepts zero sized static arrays. We allow them when + // we're not in a SFINAE context. + Diag(ArraySize->getLocStart(), + isSFINAEContext()? diag::err_typecheck_zero_array_size + : diag::ext_typecheck_zero_array_size) << ArraySize->getSourceRange(); } T = Context.getConstantArrayType(T, ConstVal, ASM, Quals); @@ -798,7 +800,8 @@ QualType Sema::BuildFunctionType(QualType T, return QualType(); return Context.getFunctionType(T, ParamTypes, NumParamTypes, Variadic, - Quals, false, false, 0, 0, false, CC_Default); + Quals, false, false, 0, 0, + FunctionType::ExtInfo()); } /// \brief Build a member pointer type \c T Class::*. @@ -1135,7 +1138,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, FTI.hasExceptionSpec, FTI.hasAnyExceptionSpec, Exceptions.size(), Exceptions.data(), - false, CC_Default); + FunctionType::ExtInfo()); } else if (FTI.isVariadic) { // We allow a zero-parameter variadic function in C if the // function is marked with the "overloadable" @@ -1152,7 +1155,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (!Overloadable) Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_arg); T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic, 0, - false, false, 0, 0, false, CC_Default); + false, false, 0, 0, + FunctionType::ExtInfo()); } else { // Simple void foo(), where the incoming T is the result type. T = Context.getFunctionNoProtoType(T); @@ -1228,7 +1232,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, FTI.hasExceptionSpec, FTI.hasAnyExceptionSpec, Exceptions.size(), Exceptions.data(), - false, CC_Default); + FunctionType::ExtInfo()); } // For GCC compatibility, we allow attributes that apply only to @@ -1257,7 +1261,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, NestedNameSpecifier *NNSPrefix = NNS->getPrefix(); switch (NNS->getKind()) { case NestedNameSpecifier::Identifier: - ClsType = Context.getTypenameType(NNSPrefix, NNS->getAsIdentifier()); + ClsType = Context.getDependentNameType(ETK_None, NNSPrefix, + NNS->getAsIdentifier()); break; case NestedNameSpecifier::Namespace: @@ -1326,7 +1331,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // Strip the cv-quals from the type. T = Context.getFunctionType(FnTy->getResultType(), FnTy->arg_type_begin(), FnTy->getNumArgs(), FnTy->isVariadic(), 0, - false, false, 0, 0, false, CC_Default); + false, false, 0, 0, FunctionType::ExtInfo()); } } @@ -1734,6 +1739,30 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { return false; } + if (Attr.getKind() == AttributeList::AT_regparm) { + // The warning is emitted elsewhere + if (Attr.getNumArgs() != 1) { + return false; + } + + // Delay if this is not a function or pointer to block. + if (!Type->isFunctionPointerType() + && !Type->isBlockPointerType() + && !Type->isFunctionType()) + return true; + + // Otherwise we can process right away. + Expr *NumParamsExpr = static_cast(Attr.getArg(0)); + llvm::APSInt NumParams(32); + + // The warning is emitted elsewhere + if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) + return false; + + Type = S.Context.getRegParmType(Type, NumParams.getZExtValue()); + return false; + } + // Otherwise, a calling convention. if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; @@ -1863,6 +1892,7 @@ void ProcessTypeAttributeList(Sema &S, QualType &Result, case AttributeList::AT_cdecl: case AttributeList::AT_fastcall: case AttributeList::AT_stdcall: + case AttributeList::AT_regparm: // Don't process these on the DeclSpec. if (IsDeclSpec || ProcessFnAttr(S, Result, *AL)) @@ -1942,6 +1972,16 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, if (diag == 0) return true; + const TagType *Tag = 0; + if (const RecordType *Record = T->getAs()) + Tag = Record; + else if (const EnumType *Enum = T->getAs()) + Tag = Enum; + + // Avoid diagnosing invalid decls as incomplete. + if (Tag && Tag->getDecl()->isInvalidDecl()) + return true; + // We have an incomplete type. Produce a diagnostic. Diag(Loc, PD) << T; @@ -1950,13 +1990,7 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, Diag(Note.first, Note.second); // If the type was a forward declaration of a class/struct/union - // type, produce - const TagType *Tag = 0; - if (const RecordType *Record = T->getAs()) - Tag = Record; - else if (const EnumType *Enum = T->getAs()) - Tag = Enum; - + // type, produce a note. if (Tag && !Tag->getDecl()->isInvalidDecl()) Diag(Tag->getDecl()->getLocation(), Tag->isBeingDefined() ? diag::note_type_being_defined @@ -1966,6 +2000,18 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, return true; } +bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, + const PartialDiagnostic &PD) { + return RequireCompleteType(Loc, T, PD, + std::make_pair(SourceLocation(), PDiag(0))); +} + +bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, + unsigned DiagID) { + return RequireCompleteType(Loc, T, PDiag(DiagID), + std::make_pair(SourceLocation(), PDiag(0))); +} + /// \brief Retrieve a version of the type 'T' that is qualified by the /// nested-name-specifier contained in SS. QualType Sema::getQualifiedNameType(const CXXScopeSpec &SS, QualType T) { @@ -1983,7 +2029,7 @@ QualType Sema::BuildTypeofExprType(Expr *E) { // function template specialization wherever deduction cannot occur. if (FunctionDecl *Specialization = ResolveSingleFunctionTemplateSpecialization(E)) { - E = FixOverloadedFunctionReference(E, Specialization); + E = FixOverloadedFunctionReference(E, Specialization, Specialization); if (!E) return QualType(); } else { @@ -2003,7 +2049,7 @@ QualType Sema::BuildDecltypeType(Expr *E) { // function template specialization wherever deduction cannot occur. if (FunctionDecl *Specialization = ResolveSingleFunctionTemplateSpecialization(E)) { - E = FixOverloadedFunctionReference(E, Specialization); + E = FixOverloadedFunctionReference(E, Specialization, Specialization); if (!E) return QualType(); } else { diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index d6f3352..f9ffd3f 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -537,18 +537,22 @@ public: /// \brief Build a new typename type that refers to a template-id. /// - /// By default, builds a new TypenameType type from the nested-name-specifier + /// By default, builds a new DependentNameType type from the + /// nested-name-specifier /// and the given type. Subclasses may override this routine to provide /// different behavior. - QualType RebuildTypenameType(NestedNameSpecifier *NNS, QualType T) { + QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, QualType T) { if (NNS->isDependent()) { + // If the name is still dependent, just build a new dependent name type. CXXScopeSpec SS; SS.setScopeRep(NNS); if (!SemaRef.computeDeclContext(SS)) - return SemaRef.Context.getTypenameType(NNS, + return SemaRef.Context.getDependentNameType(Keyword, NNS, cast(T)); } - + + // FIXME: Handle elaborated-type-specifiers separately. return SemaRef.Context.getQualifiedNameType(NNS, T); } @@ -557,10 +561,80 @@ public: /// By default, performs semantic analysis when building the typename type /// (or qualified name type). Subclasses may override this routine to provide /// different behavior. - QualType RebuildTypenameType(NestedNameSpecifier *NNS, - const IdentifierInfo *Id, - SourceRange SR) { - return SemaRef.CheckTypenameType(NNS, *Id, SR); + QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + const IdentifierInfo *Id, + SourceRange SR) { + CXXScopeSpec SS; + SS.setScopeRep(NNS); + + if (NNS->isDependent()) { + // If the name is still dependent, just build a new dependent name type. + if (!SemaRef.computeDeclContext(SS)) + return SemaRef.Context.getDependentNameType(Keyword, NNS, Id); + } + + TagDecl::TagKind Kind = TagDecl::TK_enum; + switch (Keyword) { + case ETK_None: + // FIXME: Note the lack of the "typename" specifier! + // Fall through + case ETK_Typename: + return SemaRef.CheckTypenameType(NNS, *Id, SR); + + case ETK_Class: Kind = TagDecl::TK_class; break; + case ETK_Struct: Kind = TagDecl::TK_struct; break; + case ETK_Union: Kind = TagDecl::TK_union; break; + case ETK_Enum: Kind = TagDecl::TK_enum; break; + } + + // We had a dependent elaborated-type-specifier that as been transformed + // into a non-dependent elaborated-type-specifier. Find the tag we're + // referring to. + LookupResult Result(SemaRef, Id, SR.getEnd(), Sema::LookupTagName); + DeclContext *DC = SemaRef.computeDeclContext(SS, false); + if (!DC) + return QualType(); + + TagDecl *Tag = 0; + SemaRef.LookupQualifiedName(Result, DC); + switch (Result.getResultKind()) { + case LookupResult::NotFound: + case LookupResult::NotFoundInCurrentInstantiation: + break; + + case LookupResult::Found: + Tag = Result.getAsSingle(); + break; + + case LookupResult::FoundOverloaded: + case LookupResult::FoundUnresolvedValue: + llvm_unreachable("Tag lookup cannot find non-tags"); + return QualType(); + + case LookupResult::Ambiguous: + // Let the LookupResult structure handle ambiguities. + return QualType(); + } + + if (!Tag) { + // FIXME: Would be nice to highlight just the source range. + SemaRef.Diag(SR.getEnd(), diag::err_not_tag_in_scope) + << Kind << Id << DC; + return QualType(); + } + + // FIXME: Terrible location information + if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, SR.getEnd(), *Id)) { + SemaRef.Diag(SR.getBegin(), diag::err_use_with_wrong_tag) << Id; + SemaRef.Diag(Tag->getLocation(), diag::note_previous_use); + return QualType(); + } + + // Build the elaborated-type-specifier type. + QualType T = SemaRef.Context.getTypeDeclType(Tag); + T = SemaRef.Context.getQualifiedNameType(NNS, T); + return SemaRef.Context.getElaboratedType(T, Kind); } /// \brief Build a new nested-name-specifier given the prefix and an @@ -977,6 +1051,7 @@ public: SourceRange QualifierRange, SourceLocation MemberLoc, ValueDecl *Member, + NamedDecl *FoundDecl, const TemplateArgumentListInfo *ExplicitTemplateArgs, NamedDecl *FirstQualifierInScope) { if (!Member->getDeclName()) { @@ -984,7 +1059,8 @@ public: assert(!Qualifier && "Can't have an unnamed field with a qualifier!"); Expr *BaseExpr = Base.takeAs(); - if (getSema().PerformObjectMemberConversion(BaseExpr, Qualifier, Member)) + if (getSema().PerformObjectMemberConversion(BaseExpr, Qualifier, + FoundDecl, Member)) return getSema().ExprError(); MemberExpr *ME = @@ -1002,9 +1078,11 @@ public: QualType BaseType = ((Expr*) Base.get())->getType(); + // FIXME: this involves duplicating earlier analysis in a lot of + // cases; we should avoid this when possible. LookupResult R(getSema(), Member->getDeclName(), MemberLoc, Sema::LookupMemberName); - R.addDecl(Member); + R.addDecl(FoundDecl); R.resolveKind(); return getSema().BuildMemberReferenceExpr(move(Base), BaseType, @@ -2992,10 +3070,10 @@ TreeTransform::TransformQualifiedNameType(TypeLocBuilder &TLB, } template -QualType TreeTransform::TransformTypenameType(TypeLocBuilder &TLB, - TypenameTypeLoc TL, +QualType TreeTransform::TransformDependentNameType(TypeLocBuilder &TLB, + DependentNameTypeLoc TL, QualType ObjectType) { - TypenameType *T = TL.getTypePtr(); + DependentNameType *T = TL.getTypePtr(); /* FIXME: preserve source information better than this */ SourceRange SR(TL.getNameLoc()); @@ -3019,14 +3097,16 @@ QualType TreeTransform::TransformTypenameType(TypeLocBuilder &TLB, NewTemplateId == QualType(TemplateId, 0)) return QualType(T, 0); - Result = getDerived().RebuildTypenameType(NNS, NewTemplateId); + Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS, + NewTemplateId); } else { - Result = getDerived().RebuildTypenameType(NNS, T->getIdentifier(), SR); + Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS, + T->getIdentifier(), SR); } if (Result.isNull()) return QualType(); - TypenameTypeLoc NewTL = TLB.push(Result); + DependentNameTypeLoc NewTL = TLB.push(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; @@ -3868,10 +3948,21 @@ TreeTransform::TransformMemberExpr(MemberExpr *E) { if (!Member) return SemaRef.ExprError(); + NamedDecl *FoundDecl = E->getFoundDecl(); + if (FoundDecl == E->getMemberDecl()) { + FoundDecl = Member; + } else { + FoundDecl = cast_or_null( + getDerived().TransformDecl(E->getMemberLoc(), FoundDecl)); + if (!FoundDecl) + return SemaRef.ExprError(); + } + if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase() && Qualifier == E->getQualifier() && Member == E->getMemberDecl() && + FoundDecl == E->getFoundDecl() && !E->hasExplicitTemplateArgumentList()) { // Mark it referenced in the new context regardless. @@ -3908,6 +3999,7 @@ TreeTransform::TransformMemberExpr(MemberExpr *E) { E->getQualifierRange(), E->getMemberLoc(), Member, + FoundDecl, (E->hasExplicitTemplateArgumentList() ? &TransArgs : 0), FirstQualifierInScope); @@ -5118,7 +5210,7 @@ TreeTransform::TransformCXXTemporaryObjectExpr( !ArgumentChanged) { // FIXME: Instantiation-specific SemaRef.MarkDeclarationReferenced(E->getTypeBeginLoc(), Constructor); - return SemaRef.Owned(E->Retain()); + return SemaRef.MaybeBindToTemporary(E->Retain()); } // FIXME: Bogus location information -- cgit v1.1