diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/JumpDiagnostics.cpp | 14 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 62 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 183 | ||||
-rw-r--r-- | lib/Sema/SemaCXXScopeSpec.cpp | 48 | ||||
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 465 | ||||
-rw-r--r-- | lib/Sema/SemaCodeComplete.cpp | 9 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 182 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 236 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 170 | ||||
-rw-r--r-- | lib/Sema/SemaDeclObjC.cpp | 98 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 188 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 787 | ||||
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 16 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 25 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 40 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 116 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.h | 68 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 29 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 58 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 21 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 23 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 238 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 31 | ||||
-rw-r--r-- | lib/Sema/TargetAttributesSema.cpp | 112 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 472 |
25 files changed, 2550 insertions, 1141 deletions
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp index 2b37e9d..7cf207f 100644 --- a/lib/Sema/JumpDiagnostics.cpp +++ b/lib/Sema/JumpDiagnostics.cpp @@ -77,7 +77,7 @@ JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) { /// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a /// diagnostic that should be emitted if control goes over it. If not, return 0. -static unsigned GetDiagForGotoScopeDecl(const Decl *D) { +static unsigned GetDiagForGotoScopeDecl(const Decl *D, bool isCPlusPlus) { if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { if (VD->getType()->isVariablyModifiedType()) return diag::note_protected_by_vla; @@ -85,6 +85,9 @@ static unsigned GetDiagForGotoScopeDecl(const Decl *D) { return diag::note_protected_by_cleanup; if (VD->hasAttr<BlocksAttr>()) return diag::note_protected_by___block; + if (isCPlusPlus && VD->hasLocalStorage() && VD->hasInit()) + return diag::note_protected_by_variable_init; + } else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { if (TD->getUnderlyingType()->isVariablyModifiedType()) return diag::note_protected_by_vla_typedef; @@ -116,18 +119,17 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { Stmt *SubStmt = *CI; if (SubStmt == 0) continue; - // FIXME: diagnose jumps past initialization: required in C++, warning in C. - // goto L; int X = 4; L: ; + bool isCPlusPlus = this->S.getLangOptions().CPlusPlus; // If this is a declstmt with a VLA definition, it defines a scope from here // to the end of the containing context. if (DeclStmt *DS = dyn_cast<DeclStmt>(SubStmt)) { - // The decl statement creates a scope if any of the decls in it are VLAs or - // have the cleanup attribute. + // The decl statement creates a scope if any of the decls in it are VLAs + // or have the cleanup attribute. for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end(); I != E; ++I) { // If this decl causes a new scope, push and switch to it. - if (unsigned Diag = GetDiagForGotoScopeDecl(*I)) { + if (unsigned Diag = GetDiagForGotoScopeDecl(*I, isCPlusPlus)) { Scopes.push_back(GotoScope(ParentScope, Diag, (*I)->getLocation())); ParentScope = Scopes.size()-1; } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 38c842e..3b4afef 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -26,7 +26,18 @@ #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" using namespace clang; - + +FunctionScopeInfo::~FunctionScopeInfo() { } + +void FunctionScopeInfo::Clear(unsigned NumErrors) { + NeedsScopeChecking = false; + LabelMap.clear(); + SwitchStack.clear(); + NumErrorsAtStartOfFunction = NumErrors; +} + +BlockScopeInfo::~BlockScopeInfo() { } + static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) { if (C.getLangOptions().CPlusPlus) return CXXRecordDecl::Create(C, TagDecl::TK_struct, @@ -116,7 +127,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0), - CurBlock(0), PackContext(0), ParsingDeclDepth(0), + PackContext(0), TopFunctionScope(0), ParsingDeclDepth(0), IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0), GlobalNewDeleteDeclared(false), CompleteTranslationUnit(CompleteTranslationUnit), @@ -138,6 +149,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, Sema::~Sema() { if (PackContext) FreePackedContext(); delete TheTargetAttributesSema; + while (!FunctionScopes.empty()) + PopFunctionOrBlockScope(); } /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast. @@ -342,6 +355,51 @@ Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) { return Builder; } + +/// \brief Enter a new function scope +void Sema::PushFunctionScope() { + if (FunctionScopes.empty()) { + // Use the "top" function scope rather than having to allocate memory for + // a new scope. + TopFunctionScope.Clear(getDiagnostics().getNumErrors()); + FunctionScopes.push_back(&TopFunctionScope); + return; + } + + FunctionScopes.push_back( + new FunctionScopeInfo(getDiagnostics().getNumErrors())); +} + +void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) { + FunctionScopes.push_back(new BlockScopeInfo(getDiagnostics().getNumErrors(), + BlockScope, Block)); +} + +void Sema::PopFunctionOrBlockScope() { + if (FunctionScopes.back() != &TopFunctionScope) + delete FunctionScopes.back(); + else + TopFunctionScope.Clear(getDiagnostics().getNumErrors()); + + FunctionScopes.pop_back(); +} + +/// \brief Determine whether any errors occurred within this function/method/ +/// block. +bool Sema::hasAnyErrorsInThisFunction() const { + unsigned NumErrors = TopFunctionScope.NumErrorsAtStartOfFunction; + if (!FunctionScopes.empty()) + NumErrors = FunctionScopes.back()->NumErrorsAtStartOfFunction; + return NumErrors != getDiagnostics().getNumErrors(); +} + +BlockScopeInfo *Sema::getCurBlock() { + if (FunctionScopes.empty()) + return 0; + + return dyn_cast<BlockScopeInfo>(FunctionScopes.back()); +} + void Sema::ActOnComment(SourceRange Comment) { Context.Comments.push_back(Comment); } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 3c7492a..efd04e8 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -95,6 +95,7 @@ namespace clang { class ObjCMethodDecl; class ObjCPropertyDecl; class ObjCContainerDecl; + class PseudoDestructorTypeStorage; class FunctionProtoType; class CXXBasePath; class CXXBasePaths; @@ -107,9 +108,47 @@ namespace clang { class TargetAttributesSema; class ADLResult; -/// BlockSemaInfo - When a block is being parsed, this contains information -/// about the block. It is pointed to from Sema::CurBlock. -struct BlockSemaInfo { +/// \brief Retains information about a function, method, or block that is +/// currently being parsed. +struct FunctionScopeInfo { + /// \brief Whether this scope information structure defined information for + /// a block. + bool IsBlockInfo; + + /// \brief Set true when a function, method contains a VLA or ObjC try block, + /// which introduce scopes that need to be checked for goto conditions. If a + /// function does not contain this, then it need not have the jump checker run on it. + bool NeedsScopeChecking; + + /// \brief The number of errors that had occurred before starting this + /// function or block. + unsigned NumErrorsAtStartOfFunction; + + /// LabelMap - This is a mapping from label identifiers to the LabelStmt for + /// it (which acts like the label decl in some ways). Forward referenced + /// labels have a LabelStmt created for them with a null location & SubStmt. + llvm::DenseMap<IdentifierInfo*, LabelStmt*> LabelMap; + + /// SwitchStack - This is the current set of active switch statements in the + /// block. + llvm::SmallVector<SwitchStmt*, 8> SwitchStack; + + FunctionScopeInfo(unsigned NumErrors) + : IsBlockInfo(false), NeedsScopeChecking(false), + NumErrorsAtStartOfFunction(NumErrors) { } + + virtual ~FunctionScopeInfo(); + + /// \brief Clear out the information in this function scope, making it + /// suitable for reuse. + void Clear(unsigned NumErrors); + + static bool classof(const FunctionScopeInfo *FSI) { return true; } +}; + + +/// \brief Retains information about a block that is currently being parsed. +struct BlockScopeInfo : FunctionScopeInfo { llvm::SmallVector<ParmVarDecl*, 8> Params; bool hasPrototype; bool isVariadic; @@ -125,22 +164,17 @@ struct BlockSemaInfo { /// return types, if any, in the block body. QualType ReturnType; - /// LabelMap - This is a mapping from label identifiers to the LabelStmt for - /// it (which acts like the label decl in some ways). Forward referenced - /// labels have a LabelStmt created for them with a null location & SubStmt. - llvm::DenseMap<IdentifierInfo*, LabelStmt*> LabelMap; - - /// SwitchStack - This is the current set of active switch statements in the - /// block. - llvm::SmallVector<SwitchStmt*, 8> SwitchStack; + BlockScopeInfo(unsigned NumErrors, Scope *BlockScope, BlockDecl *Block) + : FunctionScopeInfo(NumErrors), hasPrototype(false), isVariadic(false), + hasBlockDeclRefExprs(false), TheDecl(Block), TheScope(BlockScope) + { + IsBlockInfo = true; + } - /// SavedFunctionNeedsScopeChecking - This is the value of - /// CurFunctionNeedsScopeChecking at the point when the block started. - bool SavedFunctionNeedsScopeChecking; + virtual ~BlockScopeInfo(); - /// PrevBlockInfo - If this is nested inside another block, this points - /// to the outer block. - BlockSemaInfo *PrevBlockInfo; + static bool classof(const FunctionScopeInfo *FSI) { return FSI->IsBlockInfo; } + static bool classof(const BlockScopeInfo *BSI) { return true; } }; /// \brief Holds a QualType and a TypeSourceInfo* that came out of a declarator @@ -199,38 +233,25 @@ public: /// CurContext - This is the current declaration context of parsing. DeclContext *CurContext; - /// CurBlock - If inside of a block definition, this contains a pointer to - /// the active block object that represents it. - BlockSemaInfo *CurBlock; - /// PackContext - Manages the stack for #pragma pack. An alignment /// of 0 indicates default alignment. void *PackContext; // Really a "PragmaPackStack*" - /// FunctionLabelMap - This is a mapping from label identifiers to the - /// LabelStmt for it (which acts like the label decl in some ways). Forward - /// referenced labels have a LabelStmt created for them with a null location & - /// SubStmt. + /// \brief Stack containing information about each of the nested function, + /// block, and method scopes that are currently active. + llvm::SmallVector<FunctionScopeInfo *, 4> FunctionScopes; + + /// \brief Cached function scope object used for the top function scope + /// and when there is no function scope (in error cases). /// - /// Note that this should always be accessed through getLabelMap() in order - /// to handle blocks properly. - llvm::DenseMap<IdentifierInfo*, LabelStmt*> FunctionLabelMap; - - /// FunctionSwitchStack - This is the current set of active switch statements - /// in the top level function. Clients should always use getSwitchStack() to - /// handle the case when they are in a block. - llvm::SmallVector<SwitchStmt*, 8> FunctionSwitchStack; - + /// This should never be accessed directly; rather, it's address will be + /// pushed into \c FunctionScopes when we want to re-use it. + FunctionScopeInfo TopFunctionScope; + /// ExprTemporaries - This is the stack of temporaries that are created by /// the current full expression. llvm::SmallVector<CXXTemporary*, 8> ExprTemporaries; - /// CurFunctionNeedsScopeChecking - This is set to true when a function or - /// ObjC method body contains a VLA or an ObjC try block, which introduce - /// scopes that need to be checked for goto conditions. If a function does - /// not contain this, then it need not have the jump checker run on it. - bool CurFunctionNeedsScopeChecking; - /// ExtVectorDecls - This is a list all the extended vector types. This allows /// us to associate a raw vector type with one of the ext_vector type names. /// This is only necessary for issuing pretty diagnostics. @@ -606,18 +627,42 @@ public: virtual void ActOnEndOfTranslationUnit(); + void PushFunctionScope(); + void PushBlockScope(Scope *BlockScope, BlockDecl *Block); + void PopFunctionOrBlockScope(); + /// getLabelMap() - Return the current label map. If we're in a block, we /// return it. llvm::DenseMap<IdentifierInfo*, LabelStmt*> &getLabelMap() { - return CurBlock ? CurBlock->LabelMap : FunctionLabelMap; + if (FunctionScopes.empty()) + return TopFunctionScope.LabelMap; + + return FunctionScopes.back()->LabelMap; } /// getSwitchStack - This is returns the switch stack for the current block or /// function. llvm::SmallVector<SwitchStmt*,8> &getSwitchStack() { - return CurBlock ? CurBlock->SwitchStack : FunctionSwitchStack; + if (FunctionScopes.empty()) + return TopFunctionScope.SwitchStack; + + return FunctionScopes.back()->SwitchStack; } + /// \brief Determine whether the current function or block needs scope + /// checking. + bool &FunctionNeedsScopeChecking() { + if (FunctionScopes.empty()) + return TopFunctionScope.NeedsScopeChecking; + + return FunctionScopes.back()->NeedsScopeChecking; + } + + bool hasAnyErrorsInThisFunction() const; + + /// \brief Retrieve the current block, if any. + BlockScopeInfo *getCurBlock(); + /// WeakTopLevelDeclDecls - access to #pragma weak-generated Decls llvm::SmallVector<Decl*,2> &WeakTopLevelDecls() { return WeakTopLevelDecl; } @@ -1440,6 +1485,8 @@ public: void AtomicPropertySetterGetterRules(ObjCImplDecl* IMPDecl, ObjCContainerDecl* IDecl); + void DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, ObjCInterfaceDecl *SID); + /// MatchTwoMethodDeclarations - Checks if two methods' type match and returns /// true, or false, accordingly. bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, @@ -2056,6 +2103,12 @@ public: SourceLocation Loc, ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs); + virtual TypeTy *getDestructorName(SourceLocation TildeLoc, + IdentifierInfo &II, SourceLocation NameLoc, + Scope *S, const CXXScopeSpec &SS, + TypeTy *ObjectType, + bool EnteringContext); + /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. virtual OwningExprResult ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, @@ -2167,8 +2220,32 @@ public: ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, - TypeTy *&ObjectType); + TypeTy *&ObjectType, + bool &MayBePseudoDestructor); + OwningExprResult DiagnoseDtorReference(SourceLocation NameLoc, + ExprArg MemExpr); + + OwningExprResult BuildPseudoDestructorExpr(ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + TypeSourceInfo *ScopeType, + SourceLocation CCLoc, + SourceLocation TildeLoc, + PseudoDestructorTypeStorage DestroyedType, + bool HasTrailingLParen); + + virtual OwningExprResult ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + UnqualifiedId &FirstTypeName, + SourceLocation CCLoc, + SourceLocation TildeLoc, + UnqualifiedId &SecondTypeName, + bool HasTrailingLParen); + /// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is /// non-empty, will create a new CXXExprWithTemporaries expression. /// Otherwise, just returs the passed in expression. @@ -2195,7 +2272,11 @@ public: bool isAcceptableNestedNameSpecifier(NamedDecl *SD); NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS); - + virtual bool isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, + SourceLocation IdLoc, + IdentifierInfo &II, + TypeTy *ObjectType); + CXXScopeTy *BuildCXXNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, SourceLocation IdLoc, @@ -3376,7 +3457,8 @@ public: Decl *getInstantiationOf(const Decl *D) { Decl *Result = LocalDecls[D]; - assert(Result && "declaration was not instantiated in this scope!"); + assert((Result || D->isInvalidDecl()) && + "declaration was not instantiated in this scope!"); return Result; } @@ -3395,7 +3477,7 @@ public: void InstantiatedLocal(const Decl *D, Decl *Inst) { Decl *&Stored = LocalDecls[D]; - assert(!Stored && "Already instantiated this local"); + assert((!Stored || Stored == Inst) && "Already instantiated this local"); Stored = Inst; } }; @@ -3502,9 +3584,9 @@ public: const CXXConstructorDecl *Tmpl, const MultiLevelTemplateArgumentList &TemplateArgs); - NamedDecl *FindInstantiatedDecl(NamedDecl *D, + NamedDecl *FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs); - DeclContext *FindInstantiatedContext(DeclContext *DC, + DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC, const MultiLevelTemplateArgumentList &TemplateArgs); // Objective-C declarations. @@ -3910,7 +3992,8 @@ public: Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc); QualType CXXCheckConditionalOperands( // C++ 5.16 Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc); - QualType FindCompositePointerType(Expr *&E1, Expr *&E2); // C++ 5.9 + QualType FindCompositePointerType(Expr *&E1, Expr *&E2, + bool *NonStandardCompositeType = 0); QualType FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, SourceLocation questionLoc); @@ -4129,7 +4212,7 @@ private: CallExpr *TheCall); bool SemaBuiltinVAStart(CallExpr *TheCall); bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); - bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned LastArg=1); + bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs); bool SemaBuiltinStackAddress(CallExpr *TheCall); public: diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 52e9e9b..971b78c 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -327,6 +327,54 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) { return 0; } +bool Sema::isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, + SourceLocation IdLoc, + IdentifierInfo &II, + TypeTy *ObjectTypePtr) { + QualType ObjectType = GetTypeFromParser(ObjectTypePtr); + LookupResult Found(*this, &II, IdLoc, LookupNestedNameSpecifierName); + + // Determine where to perform name lookup + DeclContext *LookupCtx = 0; + bool isDependent = false; + if (!ObjectType.isNull()) { + // This nested-name-specifier occurs in a member access expression, e.g., + // x->B::f, and we are looking into the type of the object. + assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); + LookupCtx = computeDeclContext(ObjectType); + isDependent = ObjectType->isDependentType(); + } else if (SS.isSet()) { + // This nested-name-specifier occurs after another nested-name-specifier, + // so long into the context associated with the prior nested-name-specifier. + LookupCtx = computeDeclContext(SS, false); + isDependent = isDependentScopeSpecifier(SS); + Found.setContextRange(SS.getRange()); + } + + if (LookupCtx) { + // Perform "qualified" name lookup into the declaration context we + // computed, which is either the type of the base of a member access + // expression or the declaration context associated with a prior + // nested-name-specifier. + + // The declaration context must be complete. + if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS)) + return false; + + LookupQualifiedName(Found, LookupCtx); + } else if (isDependent) { + return false; + } else { + LookupName(Found, S); + } + Found.suppressDiagnostics(); + + if (NamedDecl *ND = Found.getAsSingle<NamedDecl>()) + return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND); + + return false; +} + /// \brief Build a new nested-name-specifier for "identifier::", as described /// by ActOnCXXNestedNameSpecifier. /// diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index b62cd19..30a6ab4 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -13,8 +13,9 @@ //===----------------------------------------------------------------------===// #include "Sema.h" -#include "clang/Analysis/CFG.h" #include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/Analyses/ReachableCode.h" #include "clang/Analysis/Analyses/PrintfFormatString.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" @@ -109,7 +110,8 @@ bool Sema::CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall) { } if (format_idx < TheCall->getNumArgs()) { Expr *Format = TheCall->getArg(format_idx)->IgnoreParenCasts(); - if (!Format->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) + if (!Format->isNullPointerConstant(Context, + Expr::NPC_ValueDependentIsNull)) return true; } } @@ -150,7 +152,7 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case Builtin::BI__builtin_isinf_sign: case Builtin::BI__builtin_isnan: case Builtin::BI__builtin_isnormal: - if (SemaBuiltinFPClassification(TheCall)) + if (SemaBuiltinFPClassification(TheCall, 1)) return ExprError(); break; case Builtin::BI__builtin_return_address: @@ -504,6 +506,7 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { } // Determine whether the current function is variadic or not. + BlockScopeInfo *CurBlock = getCurBlock(); bool isVariadic; if (CurBlock) isVariadic = CurBlock->isVariadic; @@ -590,19 +593,20 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) { /// SemaBuiltinSemaBuiltinFPClassification - Handle functions like /// __builtin_isnan and friends. This is declared to take (...), so we have -/// to check everything. -bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned LastArg) { - if (TheCall->getNumArgs() < LastArg) +/// to check everything. We expect the last argument to be a floating point +/// value. +bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { + if (TheCall->getNumArgs() < NumArgs) return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) << 0 /*function call*/; - if (TheCall->getNumArgs() > LastArg) - return Diag(TheCall->getArg(LastArg)->getLocStart(), + if (TheCall->getNumArgs() > NumArgs) + return Diag(TheCall->getArg(NumArgs)->getLocStart(), diag::err_typecheck_call_too_many_args) << 0 /*function call*/ - << SourceRange(TheCall->getArg(LastArg)->getLocStart(), + << SourceRange(TheCall->getArg(NumArgs)->getLocStart(), (*(TheCall->arg_end()-1))->getLocEnd()); - Expr *OrigArg = TheCall->getArg(LastArg-1); + Expr *OrigArg = TheCall->getArg(NumArgs-1); if (OrigArg->isTypeDependent()) return false; @@ -953,6 +957,7 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull, /// FormatGuard: Automatic Protection From printf Format String /// Vulnerabilities, Proceedings of the 10th USENIX Security Symposium, 2001. /// +/// TODO: /// Functionality implemented: /// /// We can statically check the following properties for string @@ -963,7 +968,7 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull, /// data arguments? /// /// (2) Does each format conversion correctly match the type of the -/// corresponding data argument? (TODO) +/// corresponding data argument? /// /// Moreover, for all printf functions we can: /// @@ -982,7 +987,6 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull, /// /// All of these checks can be done by parsing the format string. /// -/// For now, we ONLY do (1), (3), (5), (6), (7), and (8). void Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg) { @@ -1042,13 +1046,15 @@ class CheckPrintfHandler : public analyze_printf::FormatStringHandler { Sema &S; const StringLiteral *FExpr; const Expr *OrigFormatExpr; - unsigned NumConversions; const unsigned NumDataArgs; const bool IsObjCLiteral; const char *Beg; // Start of format string. const bool HasVAListArg; const CallExpr *TheCall; unsigned FormatIdx; + llvm::BitVector CoveredArgs; + bool usesPositionalArgs; + bool atFirstArg; public: CheckPrintfHandler(Sema &s, const StringLiteral *fexpr, const Expr *origFormatExpr, @@ -1056,21 +1062,31 @@ public: const char *beg, bool hasVAListArg, const CallExpr *theCall, unsigned formatIdx) : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), - NumConversions(0), NumDataArgs(numDataArgs), + NumDataArgs(numDataArgs), IsObjCLiteral(isObjCLiteral), Beg(beg), HasVAListArg(hasVAListArg), - TheCall(theCall), FormatIdx(formatIdx) {} + TheCall(theCall), FormatIdx(formatIdx), + usesPositionalArgs(false), atFirstArg(true) { + CoveredArgs.resize(numDataArgs); + CoveredArgs.reset(); + } void DoneProcessing(); void HandleIncompleteFormatSpecifier(const char *startSpecifier, unsigned specifierLen); - void + bool HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS, const char *startSpecifier, unsigned specifierLen); + virtual void HandleInvalidPosition(const char *startSpecifier, + unsigned specifierLen, + analyze_printf::PositionContext p); + + virtual void HandleZeroPosition(const char *startPos, unsigned posLen); + void HandleNullChar(const char *nullCharacter); bool HandleFormatSpecifier(const analyze_printf::FormatSpecifier &FS, @@ -1082,9 +1098,8 @@ private: unsigned specifierLen); SourceLocation getLocationOfByte(const char *x); - bool HandleAmount(const analyze_printf::OptionalAmount &Amt, - unsigned MissingArgDiag, unsigned BadTypeDiag, - const char *startSpecifier, unsigned specifierLen); + bool HandleAmount(const analyze_printf::OptionalAmount &Amt, unsigned k, + const char *startSpecifier, unsigned specifierLen); void HandleFlags(const analyze_printf::FormatSpecifier &FS, llvm::StringRef flag, llvm::StringRef cspec, const char *startSpecifier, unsigned specifierLen); @@ -1115,18 +1130,50 @@ HandleIncompleteFormatSpecifier(const char *startSpecifier, << getFormatSpecifierRange(startSpecifier, specifierLen); } -void CheckPrintfHandler:: +void +CheckPrintfHandler::HandleInvalidPosition(const char *startPos, unsigned posLen, + analyze_printf::PositionContext p) { + SourceLocation Loc = getLocationOfByte(startPos); + S.Diag(Loc, diag::warn_printf_invalid_positional_specifier) + << (unsigned) p << getFormatSpecifierRange(startPos, posLen); +} + +void CheckPrintfHandler::HandleZeroPosition(const char *startPos, + unsigned posLen) { + SourceLocation Loc = getLocationOfByte(startPos); + S.Diag(Loc, diag::warn_printf_zero_positional_specifier) + << getFormatSpecifierRange(startPos, posLen); +} + +bool CheckPrintfHandler:: HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS, const char *startSpecifier, unsigned specifierLen) { - ++NumConversions; + unsigned argIndex = FS.getArgIndex(); + bool keepGoing = true; + if (argIndex < NumDataArgs) { + // Consider the argument coverered, even though the specifier doesn't + // make sense. + CoveredArgs.set(argIndex); + } + else { + // If argIndex exceeds the number of data arguments we + // don't issue a warning because that is just a cascade of warnings (and + // they may have intended '%%' anyway). We don't want to continue processing + // the format string after this point, however, as we will like just get + // gibberish when trying to match arguments. + keepGoing = false; + } + const analyze_printf::ConversionSpecifier &CS = FS.getConversionSpecifier(); SourceLocation Loc = getLocationOfByte(CS.getStart()); S.Diag(Loc, diag::warn_printf_invalid_conversion) << llvm::StringRef(CS.getStart(), CS.getLength()) << getFormatSpecifierRange(startSpecifier, specifierLen); + + return keepGoing; } void CheckPrintfHandler::HandleNullChar(const char *nullCharacter) { @@ -1137,7 +1184,7 @@ void CheckPrintfHandler::HandleNullChar(const char *nullCharacter) { } const Expr *CheckPrintfHandler::getDataArg(unsigned i) const { - return TheCall->getArg(FormatIdx + i); + return TheCall->getArg(FormatIdx + i + 1); } @@ -1154,17 +1201,16 @@ void CheckPrintfHandler::HandleFlags(const analyze_printf::FormatSpecifier &FS, bool CheckPrintfHandler::HandleAmount(const analyze_printf::OptionalAmount &Amt, - unsigned MissingArgDiag, - unsigned BadTypeDiag, - const char *startSpecifier, + unsigned k, const char *startSpecifier, unsigned specifierLen) { if (Amt.hasDataArgument()) { - ++NumConversions; if (!HasVAListArg) { - if (NumConversions > NumDataArgs) { - S.Diag(getLocationOfByte(Amt.getStart()), MissingArgDiag) - << getFormatSpecifierRange(startSpecifier, specifierLen); + unsigned argIndex = Amt.getArgIndex(); + if (argIndex >= NumDataArgs) { + S.Diag(getLocationOfByte(Amt.getStart()), + diag::warn_printf_asterisk_missing_arg) + << k << getFormatSpecifierRange(startSpecifier, specifierLen); // Don't do any more checking. We will just emit // spurious errors. return false; @@ -1174,14 +1220,17 @@ CheckPrintfHandler::HandleAmount(const analyze_printf::OptionalAmount &Amt, // Although not in conformance with C99, we also allow the argument to be // an 'unsigned int' as that is a reasonably safe case. GCC also // doesn't emit a warning for that case. - const Expr *Arg = getDataArg(NumConversions); + CoveredArgs.set(argIndex); + const Expr *Arg = getDataArg(argIndex); QualType T = Arg->getType(); const analyze_printf::ArgTypeResult &ATR = Amt.getArgType(S.Context); assert(ATR.isValid()); if (!ATR.matchesType(S.Context, T)) { - S.Diag(getLocationOfByte(Amt.getStart()), BadTypeDiag) + S.Diag(getLocationOfByte(Amt.getStart()), + diag::warn_printf_asterisk_wrong_type) + << k << ATR.getRepresentativeType(S.Context) << T << getFormatSpecifierRange(startSpecifier, specifierLen) << Arg->getSourceRange(); @@ -1200,32 +1249,31 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier const char *startSpecifier, unsigned specifierLen) { - using namespace analyze_printf; + using namespace analyze_printf; const ConversionSpecifier &CS = FS.getConversionSpecifier(); - // First check if the field width, precision, and conversion specifier - // have matching data arguments. - if (!HandleAmount(FS.getFieldWidth(), - diag::warn_printf_asterisk_width_missing_arg, - diag::warn_printf_asterisk_width_wrong_type, - startSpecifier, specifierLen)) { + if (atFirstArg) { + atFirstArg = false; + usesPositionalArgs = FS.usesPositionalArg(); + } + else if (usesPositionalArgs != FS.usesPositionalArg()) { + // Cannot mix-and-match positional and non-positional arguments. + S.Diag(getLocationOfByte(CS.getStart()), + diag::warn_printf_mix_positional_nonpositional_args) + << getFormatSpecifierRange(startSpecifier, specifierLen); return false; } - if (!HandleAmount(FS.getPrecision(), - diag::warn_printf_asterisk_precision_missing_arg, - diag::warn_printf_asterisk_precision_wrong_type, - startSpecifier, specifierLen)) { + // First check if the field width, precision, and conversion specifier + // have matching data arguments. + if (!HandleAmount(FS.getFieldWidth(), /* field width */ 0, + startSpecifier, specifierLen)) { return false; } - // Check for using an Objective-C specific conversion specifier - // in a non-ObjC literal. - if (!IsObjCLiteral && CS.isObjCArg()) { - HandleInvalidConversionSpecifier(FS, startSpecifier, specifierLen); - - // Continue checking the other format specifiers. - return true; + if (!HandleAmount(FS.getPrecision(), /* precision */ 1, + startSpecifier, specifierLen)) { + return false; } if (!CS.consumesDataArgument()) { @@ -1234,7 +1282,20 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier return true; } - ++NumConversions; + // Consume the argument. + unsigned argIndex = FS.getArgIndex(); + if (argIndex < NumDataArgs) { + // The check to see if the argIndex is valid will come later. + // We set the bit here because we may exit early from this + // function if we encounter some other error. + CoveredArgs.set(argIndex); + } + + // Check for using an Objective-C specific conversion specifier + // in a non-ObjC literal. + if (!IsObjCLiteral && CS.isObjCArg()) { + return HandleInvalidConversionSpecifier(FS, startSpecifier, specifierLen); + } // Are we using '%n'? Issue a warning about this being // a possible security issue. @@ -1268,7 +1329,7 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier if (HasVAListArg) return true; - if (NumConversions > NumDataArgs) { + if (argIndex >= NumDataArgs) { S.Diag(getLocationOfByte(CS.getStart()), diag::warn_printf_insufficient_data_args) << getFormatSpecifierRange(startSpecifier, specifierLen); @@ -1278,7 +1339,7 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier // Now type check the data expression that matches the // format specifier. - const Expr *Ex = getDataArg(NumConversions); + const Expr *Ex = getDataArg(argIndex); const analyze_printf::ArgTypeResult &ATR = FS.getArgType(S.Context); if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType())) { // Check if we didn't match because of an implicit cast from a 'char' @@ -1302,10 +1363,17 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier void CheckPrintfHandler::DoneProcessing() { // Does the number of data arguments exceed the number of // format conversions in the format string? - if (!HasVAListArg && NumConversions < NumDataArgs) - S.Diag(getDataArg(NumConversions+1)->getLocStart(), - diag::warn_printf_too_many_data_args) - << getFormatStringRange(); + if (!HasVAListArg) { + // Find any arguments that weren't covered. + CoveredArgs.flip(); + signed notCoveredArg = CoveredArgs.find_first(); + if (notCoveredArg >= 0) { + assert((unsigned)notCoveredArg < NumDataArgs); + S.Diag(getDataArg((unsigned) notCoveredArg)->getLocStart(), + diag::warn_printf_data_arg_not_used) + << getFormatStringRange(); + } + } } void Sema::CheckPrintfString(const StringLiteral *FExpr, @@ -1680,13 +1748,13 @@ struct IntRange { } // Returns the supremum of two ranges: i.e. their conservative merge. - static IntRange join(const IntRange &L, const IntRange &R) { + static IntRange join(IntRange L, IntRange R) { return IntRange(std::max(L.Width, R.Width), L.NonNegative && R.NonNegative); } // Returns the infinum of two ranges: i.e. their aggressive merge. - static IntRange meet(const IntRange &L, const IntRange &R) { + static IntRange meet(IntRange L, IntRange R) { return IntRange(std::min(L.Width, R.Width), L.NonNegative || R.NonNegative); } @@ -1804,6 +1872,15 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { case BinaryOperator::NE: return IntRange::forBoolType(); + // The type of these compound assignments is the type of the LHS, + // so the RHS is not necessarily an integer. + case BinaryOperator::MulAssign: + case BinaryOperator::DivAssign: + case BinaryOperator::RemAssign: + case BinaryOperator::AddAssign: + case BinaryOperator::SubAssign: + return IntRange::forType(C, E->getType()); + // Operations with opaque sources are black-listed. case BinaryOperator::PtrMemD: case BinaryOperator::PtrMemI: @@ -1811,15 +1888,18 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { // Bitwise-and uses the *infinum* of the two source ranges. case BinaryOperator::And: + case BinaryOperator::AndAssign: return IntRange::meet(GetExprRange(C, BO->getLHS(), MaxWidth), GetExprRange(C, BO->getRHS(), MaxWidth)); // Left shift gets black-listed based on a judgement call. case BinaryOperator::Shl: + case BinaryOperator::ShlAssign: return IntRange::forType(C, E->getType()); // Right shift by a constant can narrow its left argument. - case BinaryOperator::Shr: { + case BinaryOperator::Shr: + case BinaryOperator::ShrAssign: { IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth); // If the shift amount is a positive constant, drop the width by @@ -2103,250 +2183,30 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) { return; } -// MarkLive - Mark all the blocks reachable from e as live. Returns the total -// number of blocks just marked live. -static unsigned MarkLive(CFGBlock *e, llvm::BitVector &live) { - unsigned count = 0; - std::queue<CFGBlock*> workq; - // Prep work queue - live.set(e->getBlockID()); - ++count; - workq.push(e); - // Solve - while (!workq.empty()) { - CFGBlock *item = workq.front(); - workq.pop(); - for (CFGBlock::succ_iterator I=item->succ_begin(), - E=item->succ_end(); - I != E; - ++I) { - if ((*I) && !live[(*I)->getBlockID()]) { - live.set((*I)->getBlockID()); - ++count; - workq.push(*I); - } - } - } - return count; -} -static SourceLocation GetUnreachableLoc(CFGBlock &b, SourceRange &R1, - SourceRange &R2) { - Stmt *S; - unsigned sn = 0; - R1 = R2 = SourceRange(); - - top: - if (sn < b.size()) - S = b[sn].getStmt(); - else if (b.getTerminator()) - S = b.getTerminator(); - else - return SourceLocation(); - - switch (S->getStmtClass()) { - case Expr::BinaryOperatorClass: { - BinaryOperator *BO = cast<BinaryOperator>(S); - if (BO->getOpcode() == BinaryOperator::Comma) { - if (sn+1 < b.size()) - return b[sn+1].getStmt()->getLocStart(); - CFGBlock *n = &b; - while (1) { - if (n->getTerminator()) - return n->getTerminator()->getLocStart(); - if (n->succ_size() != 1) - return SourceLocation(); - n = n[0].succ_begin()[0]; - if (n->pred_size() != 1) - return SourceLocation(); - if (!n->empty()) - return n[0][0].getStmt()->getLocStart(); - } - } - R1 = BO->getLHS()->getSourceRange(); - R2 = BO->getRHS()->getSourceRange(); - return BO->getOperatorLoc(); - } - case Expr::UnaryOperatorClass: { - const UnaryOperator *UO = cast<UnaryOperator>(S); - R1 = UO->getSubExpr()->getSourceRange(); - return UO->getOperatorLoc(); - } - case Expr::CompoundAssignOperatorClass: { - const CompoundAssignOperator *CAO = cast<CompoundAssignOperator>(S); - R1 = CAO->getLHS()->getSourceRange(); - R2 = CAO->getRHS()->getSourceRange(); - return CAO->getOperatorLoc(); - } - case Expr::ConditionalOperatorClass: { - const ConditionalOperator *CO = cast<ConditionalOperator>(S); - return CO->getQuestionLoc(); - } - case Expr::MemberExprClass: { - const MemberExpr *ME = cast<MemberExpr>(S); - R1 = ME->getSourceRange(); - return ME->getMemberLoc(); - } - case Expr::ArraySubscriptExprClass: { - const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(S); - R1 = ASE->getLHS()->getSourceRange(); - R2 = ASE->getRHS()->getSourceRange(); - return ASE->getRBracketLoc(); - } - case Expr::CStyleCastExprClass: { - const CStyleCastExpr *CSC = cast<CStyleCastExpr>(S); - R1 = CSC->getSubExpr()->getSourceRange(); - return CSC->getLParenLoc(); - } - case Expr::CXXFunctionalCastExprClass: { - const CXXFunctionalCastExpr *CE = cast <CXXFunctionalCastExpr>(S); - R1 = CE->getSubExpr()->getSourceRange(); - return CE->getTypeBeginLoc(); - } - case Expr::ImplicitCastExprClass: - ++sn; - goto top; - case Stmt::CXXTryStmtClass: { - return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc(); - } - default: ; - } - R1 = S->getSourceRange(); - return S->getLocStart(); -} - -static SourceLocation MarkLiveTop(CFGBlock *e, llvm::BitVector &live, - SourceManager &SM) { - std::queue<CFGBlock*> workq; - // Prep work queue - workq.push(e); - SourceRange R1, R2; - SourceLocation top = GetUnreachableLoc(*e, R1, R2); - bool FromMainFile = false; - bool FromSystemHeader = false; - bool TopValid = false; - if (top.isValid()) { - FromMainFile = SM.isFromMainFile(top); - FromSystemHeader = SM.isInSystemHeader(top); - TopValid = true; - } - // Solve - while (!workq.empty()) { - CFGBlock *item = workq.front(); - workq.pop(); - SourceLocation c = GetUnreachableLoc(*item, R1, R2); - if (c.isValid() - && (!TopValid - || (SM.isFromMainFile(c) && !FromMainFile) - || (FromSystemHeader && !SM.isInSystemHeader(c)) - || SM.isBeforeInTranslationUnit(c, top))) { - top = c; - FromMainFile = SM.isFromMainFile(top); - FromSystemHeader = SM.isInSystemHeader(top); - } - live.set(item->getBlockID()); - for (CFGBlock::succ_iterator I=item->succ_begin(), - E=item->succ_end(); - I != E; - ++I) { - if ((*I) && !live[(*I)->getBlockID()]) { - live.set((*I)->getBlockID()); - workq.push(*I); - } - } - } - return top; -} - -static int LineCmp(const void *p1, const void *p2) { - SourceLocation *Line1 = (SourceLocation *)p1; - SourceLocation *Line2 = (SourceLocation *)p2; - return !(*Line1 < *Line2); -} namespace { - struct ErrLoc { - SourceLocation Loc; - SourceRange R1; - SourceRange R2; - ErrLoc(SourceLocation l, SourceRange r1, SourceRange r2) - : Loc(l), R1(r1), R2(r2) { } - }; +class UnreachableCodeHandler : public reachable_code::Callback { + Sema &S; +public: + UnreachableCodeHandler(Sema *s) : S(*s) {} + + void HandleUnreachable(SourceLocation L, SourceRange R1, SourceRange R2) { + S.Diag(L, diag::warn_unreachable) << R1 << R2; + } +}; } /// CheckUnreachable - Check for unreachable code. void Sema::CheckUnreachable(AnalysisContext &AC) { - unsigned count; // We avoid checking when there are errors, as the CFG won't faithfully match // the user's code. - if (getDiagnostics().hasErrorOccurred()) - return; - if (Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored) - return; - - CFG *cfg = AC.getCFG(); - if (cfg == 0) + if (getDiagnostics().hasErrorOccurred() || + Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored) return; - llvm::BitVector live(cfg->getNumBlockIDs()); - // Mark all live things first. - count = MarkLive(&cfg->getEntry(), live); - - if (count == cfg->getNumBlockIDs()) - // If there are no dead blocks, we're done. - return; - - SourceRange R1, R2; - - llvm::SmallVector<ErrLoc, 24> lines; - bool AddEHEdges = AC.getAddEHEdges(); - // First, give warnings for blocks with no predecessors, as they - // can't be part of a loop. - for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { - CFGBlock &b = **I; - if (!live[b.getBlockID()]) { - if (b.pred_begin() == b.pred_end()) { - if (!AddEHEdges && b.getTerminator() - && isa<CXXTryStmt>(b.getTerminator())) { - // When not adding EH edges from calls, catch clauses - // can otherwise seem dead. Avoid noting them as dead. - count += MarkLive(&b, live); - continue; - } - SourceLocation c = GetUnreachableLoc(b, R1, R2); - if (!c.isValid()) { - // Blocks without a location can't produce a warning, so don't mark - // reachable blocks from here as live. - live.set(b.getBlockID()); - ++count; - continue; - } - lines.push_back(ErrLoc(c, R1, R2)); - // Avoid excessive errors by marking everything reachable from here - count += MarkLive(&b, live); - } - } - } - - if (count < cfg->getNumBlockIDs()) { - // And then give warnings for the tops of loops. - for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { - CFGBlock &b = **I; - if (!live[b.getBlockID()]) - // Avoid excessive errors by marking everything reachable from here - lines.push_back(ErrLoc(MarkLiveTop(&b, live, - Context.getSourceManager()), - SourceRange(), SourceRange())); - } - } - - llvm::array_pod_sort(lines.begin(), lines.end(), LineCmp); - for (llvm::SmallVector<ErrLoc, 24>::iterator I = lines.begin(), - E = lines.end(); - I != E; - ++I) - if (I->Loc.isValid()) - Diag(I->Loc, diag::warn_unreachable) << I->R1 << I->R2; + UnreachableCodeHandler UC(this); + reachable_code::FindUnreachableCode(AC, UC); } /// CheckFallThrough - Check that we don't fall off the end of a @@ -2368,7 +2228,8 @@ Sema::ControlFlowKind Sema::CheckFallThrough(AnalysisContext &AC) { // confuse us, so we mark all live things first. std::queue<CFGBlock*> workq; llvm::BitVector live(cfg->getNumBlockIDs()); - unsigned count = MarkLive(&cfg->getEntry(), live); + unsigned count = reachable_code::ScanReachableFromBlock(cfg->getEntry(), + live); bool AddEHEdges = AC.getAddEHEdges(); if (!AddEHEdges && count != cfg->getNumBlockIDs()) @@ -2382,7 +2243,7 @@ Sema::ControlFlowKind Sema::CheckFallThrough(AnalysisContext &AC) { if (b.getTerminator() && isa<CXXTryStmt>(b.getTerminator())) // When not adding EH edges from calls, catch clauses // can otherwise seem dead. Avoid noting them as dead. - count += MarkLive(&b, live); + count += reachable_code::ScanReachableFromBlock(b, live); continue; } } @@ -2489,22 +2350,20 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body, bool ReturnsVoid = false; bool HasNoReturn = false; + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { // For function templates, class templates and member function templates // we'll do the analysis at instantiation time. if (FD->isDependentContext()) return; - if (FD->getResultType()->isVoidType()) - ReturnsVoid = true; - if (FD->hasAttr<NoReturnAttr>() || - FD->getType()->getAs<FunctionType>()->getNoReturnAttr()) - HasNoReturn = true; + ReturnsVoid = FD->getResultType()->isVoidType(); + HasNoReturn = FD->hasAttr<NoReturnAttr>() || + FD->getType()->getAs<FunctionType>()->getNoReturnAttr(); + } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { - if (MD->getResultType()->isVoidType()) - ReturnsVoid = true; - if (MD->hasAttr<NoReturnAttr>()) - HasNoReturn = true; + ReturnsVoid = MD->getResultType()->isVoidType(); + HasNoReturn = MD->hasAttr<NoReturnAttr>(); } // Short circuit for compilation speed. diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index a862949..edf1bc5 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -1137,12 +1137,15 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, else if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(SemaRef.CurContext)) isVoid = Method->getResultType()->isVoidType(); - else if (SemaRef.CurBlock && !SemaRef.CurBlock->ReturnType.isNull()) - isVoid = SemaRef.CurBlock->ReturnType->isVoidType(); + else if (SemaRef.getCurBlock() && + !SemaRef.getCurBlock()->ReturnType.isNull()) + isVoid = SemaRef.getCurBlock()->ReturnType->isVoidType(); Pattern = new CodeCompletionString; Pattern->AddTypedTextChunk("return"); - if (!isVoid) + if (!isVoid) { + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddPlaceholderChunk("expression"); + } Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 1fc08ce..ec1939e 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -436,14 +436,15 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { if (AddToContext) CurContext->addDecl(D); - // Out-of-line function and variable definitions should not be pushed into - // scope. - if ((isa<FunctionTemplateDecl>(D) && - cast<FunctionTemplateDecl>(D)->getTemplatedDecl()->isOutOfLine()) || - (isa<FunctionDecl>(D) && - (cast<FunctionDecl>(D)->isFunctionTemplateSpecialization() || - cast<FunctionDecl>(D)->isOutOfLine())) || - (isa<VarDecl>(D) && cast<VarDecl>(D)->isOutOfLine())) + // Out-of-line definitions shouldn't be pushed into scope in C++. + // Out-of-line variable and function definitions shouldn't even in C. + if ((getLangOptions().CPlusPlus || isa<VarDecl>(D) || isa<FunctionDecl>(D)) && + D->isOutOfLine()) + return; + + // Template instantiations should also not be pushed into scope. + if (isa<FunctionDecl>(D) && + cast<FunctionDecl>(D)->isFunctionTemplateSpecialization()) return; // If this replaces anything in the current scope, @@ -552,7 +553,8 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { if (!D->getDeclName()) continue; // Diagnose unused variables in this scope. - if (ShouldDiagnoseUnusedDecl(D)) + if (ShouldDiagnoseUnusedDecl(D) && + S->getNumErrorsAtStart() == getDiagnostics().getNumErrors()) Diag(D->getLocation(), diag::warn_unused_variable) << D->getDeclName(); // Remove this name from our lexical scope. @@ -849,7 +851,7 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) { // is normally mapped to an error, but can be controlled with // -Wtypedef-redefinition. If either the original or the redefinition is // in a system header, don't emit this for compatibility with GCC. - if (PP.getDiagnostics().getSuppressSystemWarnings() && + if (getDiagnostics().getSuppressSystemWarnings() && (Context.getSourceManager().isInSystemHeader(Old->getLocation()) || Context.getSourceManager().isInSystemHeader(New->getLocation()))) return; @@ -908,6 +910,16 @@ static Sema::CXXSpecialMember getSpecialMember(ASTContext &Ctx, return Sema::CXXCopyAssignment; } +/// canREdefineFunction - checks if a function can be redefined. Currently, +/// only extern inline functions can be redefined, and even then only in +/// GNU89 mode. +static bool canRedefineFunction(const FunctionDecl *FD, + const LangOptions& LangOpts) { + return (LangOpts.GNUMode && !LangOpts.C99 && !LangOpts.CPlusPlus && + FD->isInlineSpecified() && + FD->getStorageClass() == FunctionDecl::Extern); +} + /// MergeFunctionDecl - We just parsed a function 'New' from /// declarator D which has the same name and scope as a previous /// declaration 'Old'. Figure out how to resolve this situation, @@ -956,9 +968,12 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { QualType OldQType = Context.getCanonicalType(Old->getType()); QualType NewQType = Context.getCanonicalType(New->getType()); + // Don't complain about this if we're in GNU89 mode and the old function + // is an extern inline function. if (!isa<CXXMethodDecl>(New) && !isa<CXXMethodDecl>(Old) && New->getStorageClass() == FunctionDecl::Static && - Old->getStorageClass() != FunctionDecl::Static) { + Old->getStorageClass() != FunctionDecl::Static && + !canRedefineFunction(Old, getLangOptions())) { Diag(New->getLocation(), diag::err_static_non_static) << New; Diag(Old->getLocation(), PrevDiag); @@ -1089,7 +1104,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { NewQType = Context.getFunctionType(NewFuncType->getResultType(), ParamTypes.data(), ParamTypes.size(), OldProto->isVariadic(), - OldProto->getTypeQuals()); + OldProto->getTypeQuals(), + false, false, 0, 0, + OldProto->getNoReturnAttr(), + OldProto->getCallConv()); New->setType(NewQType); New->setHasInheritedPrototype(); @@ -1168,7 +1186,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { New->setType(Context.getFunctionType(MergedReturn, &ArgTypes[0], ArgTypes.size(), - OldProto->isVariadic(), 0)); + OldProto->isVariadic(), 0, + false, false, 0, 0, + OldProto->getNoReturnAttr(), + OldProto->getCallConv())); return MergeCompatibleFunctionDecls(New, Old); } @@ -2159,7 +2180,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, // then it shall have block scope. QualType T = NewTD->getUnderlyingType(); if (T->isVariablyModifiedType()) { - CurFunctionNeedsScopeChecking = true; + FunctionNeedsScopeChecking() = true; if (S->getFnParent() == 0) { bool SizeIsNegative; @@ -2480,8 +2501,13 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, bool isVM = T->isVariablyModifiedType(); if (isVM || NewVD->hasAttr<CleanupAttr>() || - NewVD->hasAttr<BlocksAttr>()) - CurFunctionNeedsScopeChecking = true; + NewVD->hasAttr<BlocksAttr>() || + // FIXME: We need to diagnose jumps passed initialized variables in C++. + // However, this turns on the scope checker for everything with a variable + // which may impact compile time. See if we can find a better solution + // to this, perhaps only checking functions that contain gotos in C++? + (LangOpts.CPlusPlus && NewVD->hasLocalStorage())) + FunctionNeedsScopeChecking() = true; if ((isVM && NewVD->hasLinkage()) || (T->isVariableArrayType() && NewVD->hasGlobalStorage())) { @@ -3135,7 +3161,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // FIXME: Also include static functions declared but not defined. if (!NewFD->isInvalidDecl() && IsFunctionDefinition && !NewFD->isInlined() && NewFD->getLinkage() == InternalLinkage - && !NewFD->isUsed()) + && !NewFD->isUsed() && !NewFD->hasAttr<UnusedAttr>()) UnusedStaticFuncs.push_back(NewFD); return NewFD; @@ -3212,7 +3238,7 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // Turn this into a variadic function with no parameters. QualType R = Context.getFunctionType( NewFD->getType()->getAs<FunctionType>()->getResultType(), - 0, 0, true, 0); + 0, 0, true, 0, false, false, 0, 0, false, CC_Default); NewFD->setType(R); return NewFD->setInvalidDecl(); } @@ -3858,9 +3884,7 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { << Context.getTypeDeclType(OwnedDecl); } - // TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope. - // Can this happen for params? We already checked that they don't conflict - // among each other. Here they can only shadow globals, which is ok. + // Check for redeclaration of parameters, e.g. int foo(int x, int x); IdentifierInfo *II = D.getIdentifier(); if (II) { if (NamedDecl *PrevDecl = LookupSingleName(S, II, LookupOrdinaryName)) { @@ -3871,6 +3895,7 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { PrevDecl = 0; } else if (S->isDeclScope(DeclPtrTy::make(PrevDecl))) { Diag(D.getIdentifierLoc(), diag::err_param_redefinition) << II; + Diag(PrevDecl->getLocation(), diag::note_previous_declaration); // Recover by removing the name II = 0; @@ -4059,11 +4084,15 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { else FD = cast<FunctionDecl>(D.getAs<Decl>()); - CurFunctionNeedsScopeChecking = false; + // Enter a new function scope + PushFunctionScope(); // See if this is a redefinition. + // But don't complain if we're in GNU89 mode and the previous definition + // was an extern inline function. const FunctionDecl *Definition; - if (FD->getBody(Definition)) { + if (FD->getBody(Definition) && + !canRedefineFunction(Definition, getLangOptions())) { Diag(FD->getLocation(), diag::err_redefinition) << FD->getDeclName(); Diag(Definition->getLocation(), diag::note_previous_definition); } @@ -4120,7 +4149,11 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { << "dllimport"; FD->setInvalidDecl(); return DeclPtrTy::make(FD); - } else { + } + + // Visual C++ appears to not think this is an issue, so only issue + // a warning when Microsoft extensions are disabled. + if (!LangOpts.Microsoft) { // If a symbol previously declared dllimport is later defined, the // attribute is ignored in subsequent references, and a warning is // emitted. @@ -4184,11 +4217,9 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, // Verify and clean out per-function state. - assert(&getLabelMap() == &FunctionLabelMap && "Didn't pop block right?"); - // Check goto/label use. for (llvm::DenseMap<IdentifierInfo*, LabelStmt*>::iterator - I = FunctionLabelMap.begin(), E = FunctionLabelMap.end(); I != E; ++I) { + I = getLabelMap().begin(), E = getLabelMap().end(); I != E; ++I) { LabelStmt *L = I->second; // Verify that we have no forward references left. If so, there was a goto @@ -4224,32 +4255,41 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, Elements.push_back(L); Compound->setStmts(Context, &Elements[0], Elements.size()); } - FunctionLabelMap.clear(); - if (!Body) return D; - - CheckUnreachable(AC); + if (Body) { + CheckUnreachable(AC); + // C++ constructors that have function-try-blocks can't have return + // statements in the handlers of that block. (C++ [except.handle]p14) + // Verify this. + if (FD && isa<CXXConstructorDecl>(FD) && isa<CXXTryStmt>(Body)) + DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body)); + // Verify that that gotos and switch cases don't jump into scopes illegally. - if (CurFunctionNeedsScopeChecking) - DiagnoseInvalidJumps(Body); - - // C++ constructors that have function-try-blocks can't have return - // statements in the handlers of that block. (C++ [except.handle]p14) - // Verify this. - if (FD && isa<CXXConstructorDecl>(FD) && isa<CXXTryStmt>(Body)) - DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body)); + // Verify that that gotos and switch cases don't jump into scopes illegally. + if (FunctionNeedsScopeChecking() && !hasAnyErrorsInThisFunction()) + DiagnoseInvalidJumps(Body); - if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl)) - MarkBaseAndMemberDestructorsReferenced(Destructor); + if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl)) + MarkBaseAndMemberDestructorsReferenced(Destructor); + + // If any errors have occurred, clear out any temporaries that may have + // been leftover. This ensures that these temporaries won't be picked up for + // deletion in some later function. + if (PP.getDiagnostics().hasErrorOccurred()) + ExprTemporaries.clear(); + + assert(ExprTemporaries.empty() && "Leftover temporaries in function"); + } + + PopFunctionOrBlockScope(); // If any errors have occurred, clear out any temporaries that may have // been leftover. This ensures that these temporaries won't be picked up for // deletion in some later function. - if (PP.getDiagnostics().hasErrorOccurred()) + if (getDiagnostics().hasErrorOccurred()) ExprTemporaries.clear(); - assert(ExprTemporaries.empty() && "Leftover temporaries in function"); return D; } @@ -4501,8 +4541,9 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, bool isStdBadAlloc = false; bool Invalid = false; - RedeclarationKind Redecl = (TUK != TUK_Reference ? ForRedeclaration - : NotForRedeclaration); + RedeclarationKind Redecl = ForRedeclaration; + if (TUK == TUK_Friend || TUK == TUK_Reference) + Redecl = NotForRedeclaration; LookupResult Previous(*this, Name, NameLoc, LookupTagName, Redecl); @@ -4752,12 +4793,15 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // 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. - while (!SearchDC->isFileContext()) - SearchDC = SearchDC->getParent(); + SearchDC = SearchDC->getEnclosingNamespaceContext(); - // The entity of a decl scope is a DeclContext; see PushDeclContext. - while (S->getEntity() != SearchDC) + // 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: @@ -5625,7 +5669,6 @@ void Sema::ActOnFields(Scope* S, ObjCIvarDecl **ClsFields = reinterpret_cast<ObjCIvarDecl**>(RecFields.data()); if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(EnclosingDecl)) { - ID->setIVarList(ClsFields, RecFields.size(), Context); ID->setLocEnd(RBrac); // Add ivar's to class's DeclContext. for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { @@ -5634,21 +5677,8 @@ void Sema::ActOnFields(Scope* S, } // Must enforce the rule that ivars in the base classes may not be // duplicates. - if (ID->getSuperClass()) { - for (ObjCInterfaceDecl::ivar_iterator IVI = ID->ivar_begin(), - IVE = ID->ivar_end(); IVI != IVE; ++IVI) { - ObjCIvarDecl* Ivar = (*IVI); - - if (IdentifierInfo *II = Ivar->getIdentifier()) { - ObjCIvarDecl* prevIvar = - ID->getSuperClass()->lookupInstanceVariable(II); - if (prevIvar) { - Diag(Ivar->getLocation(), diag::err_duplicate_member) << II; - Diag(prevIvar->getLocation(), diag::note_previous_declaration); - } - } - } - } + if (ID->getSuperClass()) + DiagnoseDuplicateIvars(ID, ID->getSuperClass()); } else if (ObjCImplementationDecl *IMPDecl = dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) { assert(IMPDecl && "ActOnFields - missing ObjCImplementationDecl"); @@ -5657,6 +5687,19 @@ void Sema::ActOnFields(Scope* S, // Only it is in implementation's lexical context. ClsFields[I]->setLexicalDeclContext(IMPDecl); CheckImplementationIvars(IMPDecl, ClsFields, RecFields.size(), RBrac); + } else if (ObjCCategoryDecl *CDecl = + dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) { + if (!LangOpts.ObjCNonFragileABI2 || !CDecl->IsClassExtension()) + Diag(LBrac, diag::err_misplaced_ivar); + else { + // FIXME. Class extension does not have a LocEnd field. + // CDecl->setLocEnd(RBrac); + // Add ivar's to class extension's DeclContext. + for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { + ClsFields[i]->setLexicalDeclContext(CDecl); + CDecl->addDecl(ClsFields[i]); + } + } } } @@ -5714,12 +5757,13 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, llvm::APSInt EnumVal(IntWidth); QualType EltTy; if (Val) { - if (Enum->isDependentType()) + if (Enum->isDependentType() || Val->isTypeDependent()) EltTy = Context.DependentTy; else { // C99 6.7.2.2p2: Make sure we have an integer constant expression. SourceLocation ExpLoc; - if (VerifyIntegerConstantExpression(Val, &EnumVal)) { + if (!Val->isValueDependent() && + VerifyIntegerConstantExpression(Val, &EnumVal)) { Val = 0; } else { if (!getLangOptions().CPlusPlus) { @@ -5732,7 +5776,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, if (!isRepresentableIntegerValue(Context, EnumVal, Context.IntTy)) Diag(IdLoc, diag::ext_enum_value_not_int) << EnumVal.toString(10) << Val->getSourceRange() - << EnumVal.isNonNegative(); + << (EnumVal.isUnsigned() || EnumVal.isNonNegative()); else if (!Context.hasSameType(Val->getType(), Context.IntTy)) { // Force the type of the expression to 'int'. ImpCastExprToType(Val, Context.IntTy, CastExpr::CK_IntegralCast); @@ -5821,7 +5865,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, } } - if (!Enum->isDependentType()) { + if (!EltTy->isDependentType()) { // Make the enumerator value match the signedness and size of the // enumerator's type. EnumVal.zextOrTrunc(Context.getTypeSize(EltTy)); diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index cba1e9e..242d66f 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -225,19 +225,38 @@ static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); } -static void HandleIBOutletAttr(Decl *d, const AttributeList &Attr, Sema &S) { +static void HandleIBAction(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() > 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } - // The IBOutlet attribute only applies to instance variables of Objective-C - // classes. - if (isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d)) + // The IBAction attributes only apply to instance methods. + if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d)) + if (MD->isInstanceMethod()) { + d->addAttr(::new (S.Context) IBActionAttr()); + return; + } + + S.Diag(Attr.getLoc(), diag::err_attribute_ibaction) << Attr.getName(); +} + +static void HandleIBOutlet(Decl *d, const AttributeList &Attr, Sema &S) { + // check the attribute arguments. + if (Attr.getNumArgs() > 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return; + } + + // The IBOutlet attributes only apply to instance variables of + // Objective-C classes. + if (isa<ObjCIvarDecl>(d) || isa<ObjCPropertyDecl>(d)) { d->addAttr(::new (S.Context) IBOutletAttr()); - else - S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet); + return; + } + + S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet) << Attr.getName(); } static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -310,6 +329,86 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { d->addAttr(::new (S.Context) NonNullAttr(S.Context, start, size)); } +static bool isStaticVarOrStaticFunciton(Decl *D) { + if (VarDecl *VD = dyn_cast<VarDecl>(D)) + return VD->getStorageClass() == VarDecl::Static; + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + return FD->getStorageClass() == FunctionDecl::Static; + return false; +} + +static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) { + // Check the attribute arguments. + if (Attr.getNumArgs() > 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + + // gcc rejects + // class c { + // static int a __attribute__((weakref ("v2"))); + // static int b() __attribute__((weakref ("f3"))); + // }; + // and ignores the attributes of + // void f(void) { + // static int a __attribute__((weakref ("v2"))); + // } + // we reject them + if (const DeclContext *Ctx = d->getDeclContext()) { + Ctx = Ctx->getLookupContext(); + if (!isa<TranslationUnitDecl>(Ctx) && !isa<NamespaceDecl>(Ctx) ) { + S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_global_context) << + dyn_cast<NamedDecl>(d)->getNameAsString(); + return; + } + } + + // The GCC manual says + // + // At present, a declaration to which `weakref' is attached can only + // be `static'. + // + // It also says + // + // Without a TARGET, + // given as an argument to `weakref' or to `alias', `weakref' is + // equivalent to `weak'. + // + // gcc 4.4.1 will accept + // int a7 __attribute__((weakref)); + // as + // int a7 __attribute__((weak)); + // This looks like a bug in gcc. We reject that for now. We should revisit + // it if this behaviour is actually used. + + if (!isStaticVarOrStaticFunciton(d)) { + S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_static) << + dyn_cast<NamedDecl>(d)->getNameAsString(); + return; + } + + // GCC rejects + // static ((alias ("y"), weakref)). + // Should we? How to check that weakref is before or after alias? + + if (Attr.getNumArgs() == 1) { + Expr *Arg = static_cast<Expr*>(Attr.getArg(0)); + Arg = Arg->IgnoreParenCasts(); + StringLiteral *Str = dyn_cast<StringLiteral>(Arg); + + if (Str == 0 || Str->isWide()) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) + << "weakref" << 1; + return; + } + // GCC will accept anything as the argument of weakref. Should we + // check for an existing decl? + d->addAttr(::new (S.Context) AliasAttr(S.Context, Str->getString())); + } + + d->addAttr(::new (S.Context) WeakRefAttr()); +} + static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() != 1) { @@ -422,7 +521,7 @@ static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - if (!isa<VarDecl>(d) && !isFunctionOrMethod(d)) { + if (!isa<VarDecl>(d) && !isa<ObjCIvarDecl>(d) && !isFunctionOrMethod(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 2 /*variable and function*/; return; @@ -735,7 +834,7 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S) return; } - if (!isFunctionOrMethod(D)) { + if (!isFunction(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 0 /*function*/; return; @@ -758,13 +857,7 @@ static void HandleWeakAttr(Decl *D, const AttributeList &Attr, Sema &S) { } /* weak only applies to non-static declarations */ - bool isStatic = false; - if (VarDecl *VD = dyn_cast<VarDecl>(D)) { - isStatic = VD->getStorageClass() == VarDecl::Static; - } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - isStatic = FD->getStorageClass() == FunctionDecl::Static; - } - if (isStatic) { + if (isStaticVarOrStaticFunciton(D)) { S.Diag(Attr.getLoc(), diag::err_attribute_weak_static) << dyn_cast<NamedDecl>(D)->getNameAsString(); return; @@ -813,82 +906,6 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { D->addAttr(::new (S.Context) WeakImportAttr()); } -static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { - // check the attribute arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; - return; - } - - // Attribute can be applied only to functions or variables. - if (isa<VarDecl>(D)) { - D->addAttr(::new (S.Context) DLLImportAttr()); - return; - } - - FunctionDecl *FD = dyn_cast<FunctionDecl>(D); - if (!FD) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 2 /*variable and function*/; - return; - } - - // Currently, the dllimport attribute is ignored for inlined functions. - // Warning is emitted. - if (FD->isInlineSpecified()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport"; - return; - } - - // The attribute is also overridden by a subsequent declaration as dllexport. - // Warning is emitted. - for (AttributeList *nextAttr = Attr.getNext(); nextAttr; - nextAttr = nextAttr->getNext()) { - if (nextAttr->getKind() == AttributeList::AT_dllexport) { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport"; - return; - } - } - - if (D->getAttr<DLLExportAttr>()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport"; - return; - } - - D->addAttr(::new (S.Context) DLLImportAttr()); -} - -static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) { - // check the attribute arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; - return; - } - - // Attribute can be applied only to functions or variables. - if (isa<VarDecl>(D)) { - D->addAttr(::new (S.Context) DLLExportAttr()); - return; - } - - FunctionDecl *FD = dyn_cast<FunctionDecl>(D); - if (!FD) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 2 /*variable and function*/; - return; - } - - // Currently, the dllexport attribute is ignored for inlined functions, unless - // the -fkeep-inline-functions flag has been used. Warning is emitted; - if (FD->isInlineSpecified()) { - // FIXME: ... unless the -fkeep-inline-functions flag has been used. - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport"; - return; - } - - D->addAttr(::new (S.Context) DLLExportAttr()); -} - static void HandleReqdWorkGroupSize(Decl *D, const AttributeList &Attr, Sema &S) { // Attribute has 3 arguments. @@ -1777,6 +1794,12 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr, default: assert(0 && "invalid ownership attribute"); return; + case AttributeList::AT_cf_returns_not_retained: + d->addAttr(::new (S.Context) CFReturnsNotRetainedAttr()); + return; + case AttributeList::AT_ns_returns_not_retained: + d->addAttr(::new (S.Context) NSReturnsNotRetainedAttr()); + return; case AttributeList::AT_cf_returns_retained: d->addAttr(::new (S.Context) CFReturnsRetainedAttr()); return; @@ -1786,6 +1809,11 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr, }; } +static bool isKnownDeclSpecAttr(const AttributeList &Attr) { + return Attr.getKind() == AttributeList::AT_dllimport || + Attr.getKind() == AttributeList::AT_dllexport; +} + //===----------------------------------------------------------------------===// // Top Level Sema Entry Points //===----------------------------------------------------------------------===// @@ -1796,11 +1824,12 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr, /// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4). static void ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr, Sema &S) { - if (Attr.isDeclspecAttribute()) - // FIXME: Try to deal with __declspec attributes! + if (Attr.isDeclspecAttribute() && !isKnownDeclSpecAttr(Attr)) + // FIXME: Try to deal with other __declspec attributes! return; switch (Attr.getKind()) { - case AttributeList::AT_IBOutlet: HandleIBOutletAttr (D, Attr, S); break; + case AttributeList::AT_IBAction: HandleIBAction(D, Attr, S); break; + case AttributeList::AT_IBOutlet: HandleIBOutlet(D, Attr, S); break; case AttributeList::AT_address_space: case AttributeList::AT_objc_gc: case AttributeList::AT_vector_size: @@ -1820,8 +1849,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_constructor: HandleConstructorAttr (D, Attr, S); break; case AttributeList::AT_deprecated: HandleDeprecatedAttr (D, Attr, S); break; case AttributeList::AT_destructor: HandleDestructorAttr (D, Attr, S); break; - case AttributeList::AT_dllexport: HandleDLLExportAttr (D, Attr, S); break; - case AttributeList::AT_dllimport: HandleDLLImportAttr (D, Attr, S); break; case AttributeList::AT_ext_vector_type: HandleExtVectorTypeAttr(scope, D, Attr, S); break; @@ -1838,6 +1865,8 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_override: HandleOverrideAttr (D, Attr, S); break; // Checker-specific. + case AttributeList::AT_ns_returns_not_retained: + case AttributeList::AT_cf_returns_not_retained: case AttributeList::AT_ns_returns_retained: case AttributeList::AT_cf_returns_retained: HandleNSReturnsRetainedAttr(D, Attr, S); break; @@ -1854,6 +1883,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_warn_unused_result: HandleWarnUnusedResult(D,Attr,S); break; case AttributeList::AT_weak: HandleWeakAttr (D, Attr, S); break; + case AttributeList::AT_weakref: HandleWeakRefAttr (D, Attr, S); break; case AttributeList::AT_weak_import: HandleWeakImportAttr (D, Attr, S); break; case AttributeList::AT_transparent_union: HandleTransparentUnionAttr(D, Attr, S); @@ -1892,9 +1922,17 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, /// ProcessDeclAttributeList - Apply all the decl attributes in the specified /// attribute list to the specified decl, ignoring any type attributes. void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AttrList) { - while (AttrList) { - ProcessDeclAttribute(S, D, *AttrList, *this); - AttrList = AttrList->getNext(); + for (const AttributeList* l = AttrList; l; l = l->getNext()) { + ProcessDeclAttribute(S, D, *l, *this); + } + + // GCC accepts + // static int a9 __attribute__((weakref)); + // but that looks really pointless. We reject it. + if (D->hasAttr<WeakRefAttr>() && !D->hasAttr<AliasAttr>()) { + Diag(AttrList->getLoc(), diag::err_attribute_weakref_without_alias) << + dyn_cast<NamedDecl>(D)->getNameAsString(); + return; } } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 9defcca..574b225 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -586,7 +586,10 @@ Sema::ActOnBaseSpecifier(DeclPtrTy classdecl, SourceRange SpecifierRange, return true; AdjustDeclIfTemplate(classdecl); - CXXRecordDecl *Class = cast<CXXRecordDecl>(classdecl.getAs<Decl>()); + CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(classdecl.getAs<Decl>()); + if (!Class) + return true; + QualType BaseType = GetTypeFromParser(basetype); if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange, Virtual, Access, @@ -1635,8 +1638,22 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, new (Context) CXXBaseOrMemberInitializer*[NumInitializers]; Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers); - for (unsigned Idx = 0; Idx < NumInitializers; ++Idx) - baseOrMemberInitializers[Idx] = AllToInit[Idx]; + for (unsigned Idx = 0; Idx < NumInitializers; ++Idx) { + CXXBaseOrMemberInitializer *Member = AllToInit[Idx]; + baseOrMemberInitializers[Idx] = Member; + if (!Member->isBaseInitializer()) + continue; + const Type *BaseType = Member->getBaseClass(); + const RecordType *RT = BaseType->getAs<RecordType>(); + if (!RT) + continue; + CXXRecordDecl *BaseClassDecl = + cast<CXXRecordDecl>(RT->getDecl()); + if (BaseClassDecl->hasTrivialDestructor()) + continue; + CXXDestructorDecl *DD = BaseClassDecl->getDestructor(Context); + MarkDeclarationReferenced(Constructor->getLocation(), DD); + } } return HadError; @@ -2174,7 +2191,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { CXXConstructorDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name, Context.getFunctionType(Context.VoidTy, - 0, 0, false, 0), + 0, 0, false, 0, + /*FIXME*/false, false, + 0, 0, false, + CC_Default), /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, @@ -2246,7 +2266,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { ClassDecl->getLocation(), Name, Context.getFunctionType(Context.VoidTy, &ArgType, 1, - false, 0), + false, 0, + /*FIXME:*/false, + false, 0, 0, false, + CC_Default), /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, @@ -2332,7 +2355,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { CXXMethodDecl *CopyAssignment = CXXMethodDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name, Context.getFunctionType(RetType, &ArgType, 1, - false, 0), + false, 0, + /*FIXME:*/false, + false, 0, 0, false, + CC_Default), /*TInfo=*/0, /*isStatic=*/false, /*isInline=*/true); CopyAssignment->setAccess(AS_public); CopyAssignment->setImplicit(); @@ -2364,7 +2390,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { = CXXDestructorDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name, Context.getFunctionType(Context.VoidTy, - 0, 0, false, 0), + 0, 0, false, 0, + /*FIXME:*/false, + false, 0, 0, false, + CC_Default), /*isInline=*/true, /*isImplicitlyDeclared=*/true); Destructor->setAccess(AS_public); @@ -2523,7 +2552,13 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R, const FunctionProtoType *Proto = R->getAs<FunctionProtoType>(); return Context.getFunctionType(Context.VoidTy, Proto->arg_type_begin(), Proto->getNumArgs(), - Proto->isVariadic(), 0); + Proto->isVariadic(), 0, + Proto->hasExceptionSpec(), + Proto->hasAnyExceptionSpec(), + Proto->getNumExceptions(), + Proto->exception_begin(), + Proto->getNoReturnAttr(), + Proto->getCallConv()); } /// CheckConstructor - Checks a fully-formed constructor for @@ -2680,7 +2715,9 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, // "void" as the return type, since destructors don't have return // types. We *always* have to do this, because GetTypeForDeclarator // will put in a result type of "int" when none was specified. - return Context.getFunctionType(Context.VoidTy, 0, 0, false, 0); + // FIXME: Exceptions! + return Context.getFunctionType(Context.VoidTy, 0, 0, false, 0, + false, false, 0, 0, false, CC_Default); } /// CheckConversionDeclarator - Called by ActOnDeclarator to check the @@ -2749,8 +2786,15 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, // Rebuild the function type "R" without any parameters (in case any // of the errors above fired) and with the conversion type as the // return type. + const FunctionProtoType *Proto = R->getAs<FunctionProtoType>(); R = Context.getFunctionType(ConvType, 0, 0, false, - R->getAs<FunctionProtoType>()->getTypeQuals()); + Proto->getTypeQuals(), + Proto->hasExceptionSpec(), + Proto->hasAnyExceptionSpec(), + Proto->getNumExceptions(), + Proto->exception_begin(), + Proto->getNoReturnAttr(), + Proto->getCallConv()); // C++0x explicit conversion operators. if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x) @@ -3996,7 +4040,8 @@ bool Sema::InitializeVarWithConstructor(VarDecl *VD, void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Record->getDecl()); - if (!ClassDecl->hasTrivialDestructor()) { + if (!ClassDecl->isInvalidDecl() && !VD->isInvalidDecl() && + !ClassDecl->hasTrivialDestructor()) { CXXDestructorDecl *Destructor = ClassDecl->getDestructor(Context); MarkDeclarationReferenced(VD->getLocation(), Destructor); CheckDestructorAccess(VD->getLocation(), Record); @@ -4368,8 +4413,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // Most paths end in a failed conversion. if (ICS) { - ICS->setBad(); - ICS->Bad.init(BadConversionSequence::no_conversion, Init, DeclType); + ICS->setBad(BadConversionSequence::no_conversion, Init, DeclType); } // C++ [dcl.init.ref]p5: @@ -5761,55 +5805,74 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { return Dcl; } -void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc, - CXXMethodDecl *MD) { +static bool needsVtable(CXXMethodDecl *MD, ASTContext &Context) { // Ignore dependent types. if (MD->isDependentContext()) - return; - + return false; + + // Ignore declarations that are not definitions. + if (!MD->isThisDeclarationADefinition()) + return false; + CXXRecordDecl *RD = MD->getParent(); - + // Ignore classes without a vtable. if (!RD->isDynamicClass()) - return; + return false; - // Ignore declarations that are not definitions. - if (!MD->isThisDeclarationADefinition()) - return; - - if (isa<CXXConstructorDecl>(MD)) { - switch (MD->getParent()->getTemplateSpecializationKind()) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - // Classes that aren't instantiations of templates don't need their - // virtual methods marked until we see the definition of the key - // function. - return; - - case TSK_ImplicitInstantiation: - case TSK_ExplicitInstantiationDeclaration: - case TSK_ExplicitInstantiationDefinition: - // This is a constructor of a class template; mark all of the virtual - // members as referenced to ensure that they get instantiatied. - break; - } - } else if (!MD->isOutOfLine()) { - // Consider only out-of-line definitions of member functions. When we see - // an inline definition, it's too early to compute the key function. - return; - } else if (const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD)) { - // If this is not the key function, we don't need to mark virtual members. - if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl()) - return; - } else { - // The class has no key function, so we've already noted that we need to - // mark the virtual members of this class. - return; + switch (MD->getParent()->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + // Classes that aren't instantiations of templates don't need their + // virtual methods marked until we see the definition of the key + // function. + break; + + case TSK_ImplicitInstantiation: + // This is a constructor of a class template; mark all of the virtual + // members as referenced to ensure that they get instantiatied. + if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) + return true; + break; + + case TSK_ExplicitInstantiationDeclaration: + return true; //FIXME: This looks wrong. + + case TSK_ExplicitInstantiationDefinition: + // This is method of a explicit instantiation; mark all of the virtual + // members as referenced to ensure that they get instantiatied. + return true; } - + + // Consider only out-of-line definitions of member functions. When we see + // an inline definition, it's too early to compute the key function. + if (!MD->isOutOfLine()) + return false; + + const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD); + + // If there is no key function, we will need a copy of the vtable. + if (!KeyFunction) + return true; + + // If this is the key function, we need to mark virtual members. + if (KeyFunction->getCanonicalDecl() == MD->getCanonicalDecl()) + return true; + + return false; +} + +void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc, + CXXMethodDecl *MD) { + CXXRecordDecl *RD = MD->getParent(); + // We will need to mark all of the virtual members as referenced to build the // vtable. - ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(RD, Loc)); + // We actually call MarkVirtualMembersReferenced instead of adding to + // ClassesWithUnmarkedVirtualMembers because this marking is needed by + // codegen that will happend before we finish parsing the file. + if (needsVtable(MD, Context)) + MarkVirtualMembersReferenced(Loc, RD); } bool Sema::ProcessPendingClassesWithUnmarkedVirtualMembers() { @@ -5837,4 +5900,3 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, CXXRecordDecl *RD) { MarkDeclarationReferenced(Loc, MD); } } - diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 1e9b56a..149fe15 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -49,8 +49,6 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) { if (!MDecl) return; - CurFunctionNeedsScopeChecking = false; - // Allow the rest of sema to find private method decl implementations. if (MDecl->isInstanceMethod()) AddInstanceMethodToGlobalPool(MDecl); @@ -59,7 +57,8 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) { // Allow all of Sema to see that we are entering a method definition. PushDeclContext(FnBodyScope, MDecl); - + PushFunctionScope(); + // Create Decl objects for each parameter, entrring them in the scope for // binding to their use. @@ -599,26 +598,31 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, SourceLocation EndProtoLoc) { ObjCCategoryDecl *CDecl = 0; ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc); + + /// Check that class of this category is already completely declared. + if (!IDecl || IDecl->isForwardDecl()) { + // Create an invalid ObjCCategoryDecl to serve as context for + // the enclosing method declarations. We mark the decl invalid + // to make it clear that this isn't a valid AST. + CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, + ClassLoc, CategoryLoc, CategoryName); + CDecl->setInvalidDecl(); + Diag(ClassLoc, diag::err_undef_interface) << ClassName; + return DeclPtrTy::make(CDecl); + } + if (!CategoryName) { // Class extensions require a special treatment. Use an existing one. - for (CDecl = IDecl->getCategoryList(); CDecl; - CDecl = CDecl->getNextClassCategory()) - if (CDecl->IsClassExtension()) - break; + // Note that 'getClassExtension()' can return NULL. + CDecl = IDecl->getClassExtension(); } + if (!CDecl) { - CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, ClassLoc, - CategoryLoc, CategoryName); + CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, + ClassLoc, CategoryLoc, CategoryName); // FIXME: PushOnScopeChains? CurContext->addDecl(CDecl); - /// Check that class of this category is already completely declared. - if (!IDecl || IDecl->isForwardDecl()) { - CDecl->setInvalidDecl(); - Diag(ClassLoc, diag::err_undef_interface) << ClassName; - return DeclPtrTy::make(CDecl); - } - CDecl->setClassInterface(IDecl); // Insert first use of class extension to the list of class's categories. if (!CategoryName) @@ -821,8 +825,14 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, /// (legacy objective-c @implementation decl without an @interface decl). /// Add implementations's ivar to the synthesize class's ivar list. if (IDecl->isImplicitInterfaceDecl()) { - IDecl->setIVarList(ivars, numIvars, Context); IDecl->setLocEnd(RBrace); + // Add ivar's to class's DeclContext. + for (unsigned i = 0, e = numIvars; i != e; ++i) { + ivars[i]->setLexicalDeclContext(ImpDecl); + IDecl->makeDeclVisibleInContext(ivars[i], false); + ImpDecl->addDecl(ivars[i]); + } + return; } // If implementation has empty ivar list, just return. @@ -830,7 +840,26 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, return; assert(ivars && "missing @implementation ivars"); - + if (LangOpts.ObjCNonFragileABI2) { + if (ImpDecl->getSuperClass()) + Diag(ImpDecl->getLocation(), diag::warn_on_superclass_use); + for (unsigned i = 0; i < numIvars; i++) { + ObjCIvarDecl* ImplIvar = ivars[i]; + if (const ObjCIvarDecl *ClsIvar = + IDecl->getIvarDecl(ImplIvar->getIdentifier())) { + Diag(ImplIvar->getLocation(), diag::err_duplicate_ivar_declaration); + 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); + ImpDecl->addDecl(ImplIvar); + } + return; + } // Check interface's Ivar list against those in the implementation. // names and types must match. // @@ -1751,6 +1780,29 @@ void Sema::CompareMethodParamsInBaseAndSuper(Decl *ClassDecl, } } +/// DiagnoseDuplicateIvars - +/// Check for duplicate ivars in the entire class at the start of +/// @implementation. This becomes necesssary because class extension can +/// add ivars to a class in random order which will not be known until +/// class's @implementation is seen. +void Sema::DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, + ObjCInterfaceDecl *SID) { + for (ObjCInterfaceDecl::ivar_iterator IVI = ID->ivar_begin(), + IVE = ID->ivar_end(); IVI != IVE; ++IVI) { + ObjCIvarDecl* Ivar = (*IVI); + if (Ivar->isInvalidDecl()) + continue; + if (IdentifierInfo *II = Ivar->getIdentifier()) { + ObjCIvarDecl* prevIvar = SID->lookupInstanceVariable(II); + if (prevIvar) { + Diag(Ivar->getLocation(), diag::err_duplicate_member) << II; + Diag(prevIvar->getLocation(), diag::note_previous_declaration); + Ivar->setInvalidDecl(); + } + } + } +} + // Note: For class/category implemenations, allMethods/allProperties is // always null. void Sema::ActOnAtEnd(SourceRange AtEnd, @@ -1862,6 +1914,11 @@ void Sema::ActOnAtEnd(SourceRange AtEnd, if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) { ImplMethodsVsClassMethods(IC, IDecl); AtomicPropertySetterGetterRules(IC, IDecl); + if (LangOpts.ObjCNonFragileABI2) + while (IDecl->getSuperClass()) { + DiagnoseDuplicateIvars(IDecl, IDecl->getSuperClass()); + IDecl = IDecl->getSuperClass(); + } } } else if (ObjCCategoryImplDecl* CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) { @@ -1930,7 +1987,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( // Make sure we can establish a context for the method. if (!ClassDecl) { Diag(MethodLoc, diag::error_missing_method_context); - FunctionLabelMap.clear(); + getLabelMap().clear(); return DeclPtrTy(); } QualType resultDeclType; @@ -2440,8 +2497,7 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, PropertyIvar, PropType, /*Dinfo=*/0, ObjCIvarDecl::Public, (Expr *)0); - Ivar->setLexicalDeclContext(IDecl); - IDecl->addDecl(Ivar); + IDecl->makeDeclVisibleInContext(Ivar, false); property->setPropertyIvarDecl(Ivar); if (!getLangOptions().ObjCNonFragileABI) Diag(PropertyLoc, diag::error_missing_property_ivar_decl) << PropertyId; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 633884f..d9464ad 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -393,10 +393,10 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) { /// variables defined outside the block) or false if this is not needed (e.g. /// for values inside the block or for globals). /// -/// This also keeps the 'hasBlockDeclRefExprs' in the BlockSemaInfo records +/// This also keeps the 'hasBlockDeclRefExprs' in the BlockScopeInfo records /// up-to-date. /// -static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock, +static bool ShouldSnapshotBlockValueReference(Sema &S, BlockScopeInfo *CurBlock, ValueDecl *VD) { // If the value is defined inside the block, we couldn't snapshot it even if // we wanted to. @@ -421,8 +421,12 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock, // which case that outer block doesn't get "hasBlockDeclRefExprs") or it may // be defined outside all of the current blocks (in which case the blocks do // all get the bit). Walk the nesting chain. - for (BlockSemaInfo *NextBlock = CurBlock->PrevBlockInfo; NextBlock; - NextBlock = NextBlock->PrevBlockInfo) { + for (unsigned I = S.FunctionScopes.size() - 1; I; --I) { + BlockScopeInfo *NextBlock = dyn_cast<BlockScopeInfo>(S.FunctionScopes[I]); + + if (!NextBlock) + continue; + // If we found the defining block for the variable, don't mark the block as // having a reference outside it. if (NextBlock->TheDecl == VD->getDeclContext()) @@ -1597,7 +1601,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, // We do not do this for things like enum constants, global variables, etc, // as they do not get snapshotted. // - if (CurBlock && ShouldSnapshotBlockValueReference(CurBlock, VD)) { + if (getCurBlock() && + ShouldSnapshotBlockValueReference(*this, getCurBlock(), VD)) { if (VD->getType().getTypePtr()->isVariablyModifiedType()) { Diag(Loc, diag::err_ref_vm_type); Diag(D->getLocation(), diag::note_declared_at); @@ -1664,12 +1669,10 @@ Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, Sema::OwningExprResult Sema::ActOnCharacterConstant(const Token &Tok) { llvm::SmallString<16> CharBuffer; - CharBuffer.resize(Tok.getLength()); - const char *ThisTokBegin = &CharBuffer[0]; - unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin); + llvm::StringRef ThisTok = PP.getSpelling(Tok, CharBuffer); - CharLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength, - Tok.getLocation(), PP); + CharLiteralParser Literal(ThisTok.begin(), ThisTok.end(), Tok.getLocation(), + PP); if (Literal.hadError()) return ExprError(); @@ -1736,10 +1739,10 @@ Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) { unsigned diagnostic; llvm::SmallVector<char, 20> buffer; if (result & APFloat::opOverflow) { - diagnostic = diag::err_float_overflow; + diagnostic = diag::warn_float_overflow; APFloat::getLargest(Format).toString(buffer); } else { - diagnostic = diag::err_float_underflow; + diagnostic = diag::warn_float_underflow; APFloat::getSmallest(Format).toString(buffer); } @@ -2900,46 +2903,6 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, return Owned((Expr*) 0); } - // Handle pseudo-destructors (C++ [expr.pseudo]). Since anything referring - // into a record type was handled above, any destructor we see here is a - // pseudo-destructor. - if (MemberName.getNameKind() == DeclarationName::CXXDestructorName) { - // C++ [expr.pseudo]p2: - // The left hand side of the dot operator shall be of scalar type. The - // left hand side of the arrow operator shall be of pointer to scalar - // type. - if (!BaseType->isScalarType()) - return Owned(Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar) - << BaseType << BaseExpr->getSourceRange()); - - // [...] The type designated by the pseudo-destructor-name shall be the - // same as the object type. - if (!MemberName.getCXXNameType()->isDependentType() && - !Context.hasSameUnqualifiedType(BaseType, MemberName.getCXXNameType())) - return Owned(Diag(OpLoc, diag::err_pseudo_dtor_type_mismatch) - << BaseType << MemberName.getCXXNameType() - << BaseExpr->getSourceRange() << SourceRange(MemberLoc)); - - // [...] Furthermore, the two type-names in a pseudo-destructor-name of - // the form - // - // ::[opt] nested-name-specifier[opt] type-name :: ̃ type-name - // - // shall designate the same scalar type. - // - // FIXME: DPG can't see any way to trigger this particular clause, so it - // isn't checked here. - - // FIXME: We've lost the precise spelling of the type by going through - // DeclarationName. Can we do better? - return Owned(new (Context) CXXPseudoDestructorExpr(Context, BaseExpr, - IsArrow, OpLoc, - (NestedNameSpecifier *) SS.getScopeRep(), - SS.getRange(), - MemberName.getCXXNameType(), - MemberLoc)); - } - // Handle access to Objective-C instance variables, such as "Obj->ivar" and // (*Obj).ivar. if ((IsArrow && BaseType->isObjCObjectPointerType()) || @@ -3147,9 +3110,12 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, return LookupMemberExpr(Res, BaseExpr, IsArrow, OpLoc, SS, ObjCImpDecl); } - - return ExprError(Diag(MemberLoc, diag::err_property_not_found) - << MemberName << BaseType); + Diag(MemberLoc, diag::err_property_not_found) + << MemberName << BaseType; + if (Setter && !Getter) + Diag(Setter->getLocation(), diag::note_getter_unavailable) + << MemberName << BaseExpr->getSourceRange(); + return ExprError(); } // Handle the following exceptional case (*Obj).isa. @@ -3168,30 +3134,13 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, return Owned(new (Context) ExtVectorElementExpr(ret, BaseExpr, *Member, MemberLoc)); } - + Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union) << BaseType << BaseExpr->getSourceRange(); return ExprError(); } -static Sema::OwningExprResult DiagnoseDtorReference(Sema &SemaRef, - SourceLocation NameLoc, - Sema::ExprArg MemExpr) { - Expr *E = (Expr *) MemExpr.get(); - SourceLocation ExpectedLParenLoc = SemaRef.PP.getLocForEndOfToken(NameLoc); - SemaRef.Diag(E->getLocStart(), diag::err_dtor_expr_without_call) - << isa<CXXPseudoDestructorExpr>(E) - << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()"); - - return SemaRef.ActOnCallExpr(/*Scope*/ 0, - move(MemExpr), - /*LPLoc*/ ExpectedLParenLoc, - Sema::MultiExprArg(SemaRef, 0, 0), - /*CommaLocs*/ 0, - /*RPLoc*/ ExpectedLParenLoc); -} - /// The main callback when the parser finds something like /// expression . [nested-name-specifier] identifier /// expression -> [nested-name-specifier] identifier @@ -3262,7 +3211,7 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, // call now. if (!HasTrailingLParen && Id.getKind() == UnqualifiedId::IK_DestructorName) - return DiagnoseDtorReference(*this, NameLoc, move(Result)); + return DiagnoseDtorReference(NameLoc, move(Result)); return move(Result); } @@ -5378,11 +5327,18 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, // // C++ [expr.eq]p1 uses the same notion for (in)equality // comparisons of pointers. - QualType T = FindCompositePointerType(lex, rex); + bool NonStandardCompositeType = false; + QualType T = FindCompositePointerType(lex, rex, + isSFINAEContext()? 0 : &NonStandardCompositeType); if (T.isNull()) { Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); return QualType(); + } else if (NonStandardCompositeType) { + Diag(Loc, + diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard) + << lType << rType << T + << lex->getSourceRange() << rex->getSourceRange(); } ImpCastExprToType(lex, T, CastExpr::CK_BitCast); @@ -5444,11 +5400,18 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, // of one of the operands, with a cv-qualification signature (4.4) // that is the union of the cv-qualification signatures of the operand // types. - QualType T = FindCompositePointerType(lex, rex); + bool NonStandardCompositeType = false; + QualType T = FindCompositePointerType(lex, rex, + isSFINAEContext()? 0 : &NonStandardCompositeType); if (T.isNull()) { Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers) - << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + << lType << rType << lex->getSourceRange() << rex->getSourceRange(); return QualType(); + } else if (NonStandardCompositeType) { + Diag(Loc, + diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard) + << lType << rType << T + << lex->getSourceRange() << rex->getSourceRange(); } ImpCastExprToType(lex, T, CastExpr::CK_BitCast); @@ -5697,7 +5660,6 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { unsigned Diag = 0; bool NeedType = false; switch (IsLV) { // C99 6.5.16p2 - default: assert(0 && "Unknown result from isModifiableLvalue!"); case Expr::MLV_ConstQualified: Diag = diag::err_typecheck_assign_const; break; case Expr::MLV_ArrayType: Diag = diag::err_typecheck_array_not_modifiable_lvalue; @@ -5710,7 +5672,11 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { case Expr::MLV_LValueCast: Diag = diag::err_typecheck_lvalue_casts_not_supported; break; + case Expr::MLV_Valid: + llvm_unreachable("did not take early return for MLV_Valid"); case Expr::MLV_InvalidExpression: + case Expr::MLV_MemberFunction: + case Expr::MLV_ClassTemporary: Diag = diag::err_typecheck_expression_not_modifiable_lvalue; break; case Expr::MLV_IncompleteType: @@ -5995,6 +5961,12 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { return Context.getMemberPointerType(op->getType(), Context.getTypeDeclType(cast<RecordDecl>(dcl->getDeclContext())) .getTypePtr()); + } else if (lval == Expr::LV_ClassTemporary) { + Diag(OpLoc, isSFINAEContext()? diag::err_typecheck_addrof_class_temporary + : diag::ext_typecheck_addrof_class_temporary) + << op->getType() << op->getSourceRange(); + if (isSFINAEContext()) + return QualType(); } else if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) { // C99 6.5.3.2p1 // The operand must be either an l-value or a function designator @@ -6755,28 +6727,16 @@ Sema::OwningExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, /// ActOnBlockStart - This callback is invoked when a block literal is started. void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) { - // Analyze block parameters. - BlockSemaInfo *BSI = new BlockSemaInfo(); - - // Add BSI to CurBlock. - BSI->PrevBlockInfo = CurBlock; - CurBlock = BSI; - - BSI->ReturnType = QualType(); - BSI->TheScope = BlockScope; - BSI->hasBlockDeclRefExprs = false; - BSI->hasPrototype = false; - BSI->SavedFunctionNeedsScopeChecking = CurFunctionNeedsScopeChecking; - CurFunctionNeedsScopeChecking = false; - - BSI->TheDecl = BlockDecl::Create(Context, CurContext, CaretLoc); - CurContext->addDecl(BSI->TheDecl); - PushDeclContext(BlockScope, BSI->TheDecl); + BlockDecl *Block = BlockDecl::Create(Context, CurContext, CaretLoc); + PushBlockScope(BlockScope, Block); + CurContext->addDecl(Block); + PushDeclContext(BlockScope, Block); } void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { assert(ParamInfo.getIdentifier()==0 && "block-id should have no identifier!"); - + BlockScopeInfo *CurBlock = getCurBlock(); + if (ParamInfo.getNumTypeObjects() == 0 || ParamInfo.getTypeObject(0).Kind != DeclaratorChunk::Function) { ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo); @@ -6790,7 +6750,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, NULL, 0, 0, 0); + T = Context.getFunctionType(T, 0, 0, false, 0, false, false, 0, 0, false, + CC_Default); CurBlock->hasPrototype = true; CurBlock->isVariadic = false; @@ -6877,14 +6838,9 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { /// ActOnBlockError - If there is an error parsing a block, this callback /// is invoked to pop the information about the block from the action impl. void Sema::ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) { - // Ensure that CurBlock is deleted. - llvm::OwningPtr<BlockSemaInfo> CC(CurBlock); - - CurFunctionNeedsScopeChecking = CurBlock->SavedFunctionNeedsScopeChecking; - // Pop off CurBlock, handle nested blocks. PopDeclContext(); - CurBlock = CurBlock->PrevBlockInfo; + PopFunctionOrBlockScope(); // FIXME: Delete the ParmVarDecl objects as well??? } @@ -6896,14 +6852,10 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, if (!LangOpts.Blocks) Diag(CaretLoc, diag::err_blocks_disable); - // Ensure that CurBlock is deleted. - llvm::OwningPtr<BlockSemaInfo> BSI(CurBlock); + BlockScopeInfo *BSI = cast<BlockScopeInfo>(FunctionScopes.back()); PopDeclContext(); - // Pop off CurBlock, handle nested blocks. - CurBlock = CurBlock->PrevBlockInfo; - QualType RetTy = Context.VoidTy; if (!BSI->ReturnType.isNull()) RetTy = BSI->ReturnType; @@ -6916,20 +6868,19 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, QualType BlockTy; if (!BSI->hasPrototype) BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0, false, false, 0, 0, - NoReturn); + NoReturn, CC_Default); else BlockTy = Context.getFunctionType(RetTy, ArgTypes.data(), ArgTypes.size(), BSI->isVariadic, 0, false, false, 0, 0, - NoReturn); + NoReturn, CC_Default); // FIXME: Check that return/parameter types are complete/non-abstract DiagnoseUnusedParameters(BSI->Params.begin(), BSI->Params.end()); BlockTy = Context.getBlockPointerType(BlockTy); // If needed, diagnose invalid gotos and switches in the block. - if (CurFunctionNeedsScopeChecking) + if (FunctionNeedsScopeChecking() && !hasAnyErrorsInThisFunction()) DiagnoseInvalidJumps(static_cast<CompoundStmt*>(body.get())); - CurFunctionNeedsScopeChecking = BSI->SavedFunctionNeedsScopeChecking; BSI->TheDecl->setBody(body.takeAs<CompoundStmt>()); @@ -6948,15 +6899,18 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, Diag(L->getIdentLoc(), diag::err_undeclared_label_use) << L->getName(); Good = false; } - BSI->LabelMap.clear(); - if (!Good) + if (!Good) { + PopFunctionOrBlockScope(); return ExprError(); - + } + AnalysisContext AC(BSI->TheDecl); CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody(), AC); CheckUnreachable(AC); - return Owned(new (Context) BlockExpr(BSI->TheDecl, BlockTy, - BSI->hasBlockDeclRefExprs)); + Expr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy, + BSI->hasBlockDeclRefExprs); + PopFunctionOrBlockScope(); + return Owned(Result); } Sema::OwningExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc, diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 9eeda54..5f46019 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -17,13 +17,278 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/TypeLoc.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Parse/DeclSpec.h" +#include "clang/Parse/Template.h" #include "llvm/ADT/STLExtras.h" using namespace clang; +Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc, + IdentifierInfo &II, + SourceLocation NameLoc, + Scope *S, const CXXScopeSpec &SS, + TypeTy *ObjectTypePtr, + bool EnteringContext) { + // Determine where to perform name lookup. + + // FIXME: This area of the standard is very messy, and the current + // wording is rather unclear about which scopes we search for the + // destructor name; see core issues 399 and 555. Issue 399 in + // particular shows where the current description of destructor name + // lookup is completely out of line with existing practice, e.g., + // this appears to be ill-formed: + // + // namespace N { + // template <typename T> struct S { + // ~S(); + // }; + // } + // + // void f(N::S<int>* s) { + // s->N::S<int>::~S(); + // } + // + // See also PR6358 and PR6359. + QualType SearchType; + DeclContext *LookupCtx = 0; + bool isDependent = false; + bool LookInScope = false; + + // If we have an object type, it's because we are in a + // pseudo-destructor-expression or a member access expression, and + // we know what type we're looking for. + if (ObjectTypePtr) + SearchType = GetTypeFromParser(ObjectTypePtr); + + if (SS.isSet()) { + NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep(); + + bool AlreadySearched = false; + bool LookAtPrefix = true; + if (!getLangOptions().CPlusPlus0x) { + // C++ [basic.lookup.qual]p6: + // If a pseudo-destructor-name (5.2.4) contains a nested-name-specifier, + // the type-names are looked up as types in the scope designated by the + // nested-name-specifier. In a qualified-id of the form: + // + // ::[opt] nested-name-specifier ̃ class-name + // + // where the nested-name-specifier designates a namespace scope, and in + // a qualified-id of the form: + // + // ::opt nested-name-specifier class-name :: ̃ class-name + // + // the class-names are looked up as types in the scope designated by + // the nested-name-specifier. + // + // Here, we check the first case (completely) and determine whether the + // code below is permitted to look at the prefix of the + // nested-name-specifier (as we do in C++0x). + DeclContext *DC = computeDeclContext(SS, EnteringContext); + if (DC && DC->isFileContext()) { + AlreadySearched = true; + LookupCtx = DC; + isDependent = false; + } else if (DC && isa<CXXRecordDecl>(DC)) + LookAtPrefix = false; + } + + // C++0x [basic.lookup.qual]p6: + // If a pseudo-destructor-name (5.2.4) contains a + // nested-name-specifier, the type-names are looked up as types + // in the scope designated by the nested-name-specifier. Similarly, in + // a qualified-id of the form: + // + // :: [opt] nested-name-specifier[opt] class-name :: ~class-name + // + // the second class-name is looked up in the same scope as the first. + // + // To implement this, we look at the prefix of the + // nested-name-specifier we were given, and determine the lookup + // context from that. + // + // We also fold in the second case from the C++03 rules quoted further + // above. + NestedNameSpecifier *Prefix = 0; + if (AlreadySearched) { + // Nothing left to do. + } else if (LookAtPrefix && (Prefix = NNS->getPrefix())) { + CXXScopeSpec PrefixSS; + PrefixSS.setScopeRep(Prefix); + LookupCtx = computeDeclContext(PrefixSS, EnteringContext); + isDependent = isDependentScopeSpecifier(PrefixSS); + } else if (getLangOptions().CPlusPlus0x && + (LookupCtx = computeDeclContext(SS, EnteringContext))) { + if (!LookupCtx->isTranslationUnit()) + LookupCtx = LookupCtx->getParent(); + isDependent = LookupCtx && LookupCtx->isDependentContext(); + } else if (ObjectTypePtr) { + LookupCtx = computeDeclContext(SearchType); + isDependent = SearchType->isDependentType(); + } else { + LookupCtx = computeDeclContext(SS, EnteringContext); + isDependent = LookupCtx && LookupCtx->isDependentContext(); + } + + LookInScope = false; + } else if (ObjectTypePtr) { + // C++ [basic.lookup.classref]p3: + // If the unqualified-id is ~type-name, the type-name is looked up + // in the context of the entire postfix-expression. If the type T + // of the object expression is of a class type C, the type-name is + // also looked up in the scope of class C. At least one of the + // lookups shall find a name that refers to (possibly + // cv-qualified) T. + LookupCtx = computeDeclContext(SearchType); + isDependent = SearchType->isDependentType(); + assert((isDependent || !SearchType->isIncompleteType()) && + "Caller should have completed object type"); + + LookInScope = true; + } else { + // Perform lookup into the current scope (only). + LookInScope = true; + } + + LookupResult Found(*this, &II, NameLoc, LookupOrdinaryName); + for (unsigned Step = 0; Step != 2; ++Step) { + // Look for the name first in the computed lookup context (if we + // have one) and, if that fails to find a match, in the sope (if + // we're allowed to look there). + Found.clear(); + if (Step == 0 && LookupCtx) + LookupQualifiedName(Found, LookupCtx); + else if (Step == 1 && LookInScope && S) + LookupName(Found, S); + else + continue; + + // FIXME: Should we be suppressing ambiguities here? + if (Found.isAmbiguous()) + return 0; + + if (TypeDecl *Type = Found.getAsSingle<TypeDecl>()) { + QualType T = Context.getTypeDeclType(Type); + // If we found the injected-class-name of a class template, retrieve the + // type of that template. + // FIXME: We really shouldn't need to do this. + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Type)) + if (Record->isInjectedClassName()) + if (Record->getDescribedClassTemplate()) + T = Record->getDescribedClassTemplate() + ->getInjectedClassNameType(Context); + + if (SearchType.isNull() || SearchType->isDependentType() || + Context.hasSameUnqualifiedType(T, SearchType)) { + // We found our type! + + return T.getAsOpaquePtr(); + } + } + + // If the name that we found is a class template name, and it is + // the same name as the template name in the last part of the + // nested-name-specifier (if present) or the object type, then + // this is the destructor for that class. + // FIXME: This is a workaround until we get real drafting for core + // issue 399, for which there isn't even an obvious direction. + if (ClassTemplateDecl *Template = Found.getAsSingle<ClassTemplateDecl>()) { + QualType MemberOfType; + if (SS.isSet()) { + if (DeclContext *Ctx = computeDeclContext(SS, EnteringContext)) { + // Figure out the type of the context, if it has one. + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) + MemberOfType = Context.getTypeDeclType(Spec); + else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) { + if (Record->getDescribedClassTemplate()) + MemberOfType = Record->getDescribedClassTemplate() + ->getInjectedClassNameType(Context); + else + MemberOfType = Context.getTypeDeclType(Record); + } + } + } + if (MemberOfType.isNull()) + MemberOfType = SearchType; + + if (MemberOfType.isNull()) + continue; + + // We're referring into a class template specialization. If the + // class template we found is the same as the template being + // specialized, we found what we are looking for. + if (const RecordType *Record = MemberOfType->getAs<RecordType>()) { + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) { + if (Spec->getSpecializedTemplate()->getCanonicalDecl() == + Template->getCanonicalDecl()) + return MemberOfType.getAsOpaquePtr(); + } + + continue; + } + + // We're referring to an unresolved class template + // specialization. Determine whether we class template we found + // is the same as the template being specialized or, if we don't + // know which template is being specialized, that it at least + // has the same name. + if (const TemplateSpecializationType *SpecType + = MemberOfType->getAs<TemplateSpecializationType>()) { + TemplateName SpecName = SpecType->getTemplateName(); + + // The class template we found is the same template being + // specialized. + if (TemplateDecl *SpecTemplate = SpecName.getAsTemplateDecl()) { + if (SpecTemplate->getCanonicalDecl() == Template->getCanonicalDecl()) + return MemberOfType.getAsOpaquePtr(); + + continue; + } + + // The class template we found has the same name as the + // (dependent) template name being specialized. + if (DependentTemplateName *DepTemplate + = SpecName.getAsDependentTemplateName()) { + if (DepTemplate->isIdentifier() && + DepTemplate->getIdentifier() == Template->getIdentifier()) + return MemberOfType.getAsOpaquePtr(); + + continue; + } + } + } + } + + if (isDependent) { + // We didn't find our type, but that's okay: it's dependent + // anyway. + NestedNameSpecifier *NNS = 0; + SourceRange Range; + if (SS.isSet()) { + NNS = (NestedNameSpecifier *)SS.getScopeRep(); + Range = SourceRange(SS.getRange().getBegin(), NameLoc); + } else { + NNS = NestedNameSpecifier::Create(Context, &II); + Range = SourceRange(NameLoc); + } + + return CheckTypenameType(NNS, II, Range).getAsOpaquePtr(); + } + + if (ObjectTypePtr) + Diag(NameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) + << &II; + else + Diag(NameLoc, diag::err_destructor_class_name); + + return 0; +} + /// ActOnCXXTypeidOfType - Parse typeid( type-id ). Action::OwningExprResult Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, @@ -161,6 +426,18 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { : diag::err_throw_incomplete) << E->getSourceRange())) return true; + + // FIXME: This is just a hack to mark the copy constructor referenced. + // This should go away when the next FIXME is fixed. + const RecordType *RT = Ty->getAs<RecordType>(); + if (!RT) + return false; + + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + if (RD->hasTrivialCopyConstructor()) + return false; + CXXConstructorDecl *CopyCtor = RD->getCopyConstructor(Context, 0); + MarkDeclarationReferenced(ThrowLoc, CopyCtor); } // FIXME: Construct a temporary here. @@ -515,6 +792,12 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, ConsArgs = (Expr **)ConvertedConstructorArgs.take(); } + // Mark the new and delete operators as referenced. + if (OperatorNew) + MarkDeclarationReferenced(StartLoc, OperatorNew); + if (OperatorDelete) + MarkDeclarationReferenced(StartLoc, OperatorDelete); + // FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16) PlacementArgs.release(); @@ -554,6 +837,20 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, return false; } +/// \brief Determine whether the given function is a non-placement +/// deallocation function. +static bool isNonPlacementDeallocationFunction(FunctionDecl *FD) { + if (FD->isInvalidDecl()) + return false; + + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD)) + return Method->isUsualDeallocationFunction(); + + return ((FD->getOverloadedOperator() == OO_Delete || + FD->getOverloadedOperator() == OO_Array_Delete) && + FD->getNumParams() == 1); +} + /// FindAllocationFunctions - Finds the overloads of operator new and delete /// that are appropriate for the allocation. bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, @@ -570,7 +867,6 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // operator new. // 3) The first argument is always size_t. Append the arguments from the // placement form. - // FIXME: Also find the appropriate delete operator. llvm::SmallVector<Expr*, 8> AllocArgs(1 + NumPlaceArgs); // We don't care about the actual value of this argument. @@ -583,12 +879,20 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, AllocArgs[0] = &Size; std::copy(PlaceArgs, PlaceArgs + NumPlaceArgs, AllocArgs.begin() + 1); + // C++ [expr.new]p8: + // If the allocated type is a non-array type, the allocation + // function’s name is operator new and the deallocation function’s + // name is operator delete. If the allocated type is an array + // type, the allocation function’s name is operator new[] and the + // deallocation function’s name is operator delete[]. DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName( IsArray ? OO_Array_New : OO_New); + DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( + IsArray ? OO_Array_Delete : OO_Delete); + if (AllocType->isRecordType() && !UseGlobal) { CXXRecordDecl *Record = cast<CXXRecordDecl>(AllocType->getAs<RecordType>()->getDecl()); - // FIXME: We fail to find inherited overloads. if (FindAllocationOverload(StartLoc, Range, NewName, &AllocArgs[0], AllocArgs.size(), Record, /*AllowMissing=*/true, OperatorNew)) @@ -609,6 +913,110 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, if (NumPlaceArgs > 0) std::copy(&AllocArgs[1], AllocArgs.end(), PlaceArgs); + // C++ [expr.new]p19: + // + // If the new-expression begins with a unary :: operator, the + // deallocation function’s name is looked up in the global + // scope. Otherwise, if the allocated type is a class type T or an + // array thereof, the deallocation function’s name is looked up in + // the scope of T. If this lookup fails to find the name, or if + // the allocated type is not a class type or array thereof, the + // deallocation function’s name is looked up in the global scope. + LookupResult FoundDelete(*this, DeleteName, StartLoc, LookupOrdinaryName); + if (AllocType->isRecordType() && !UseGlobal) { + CXXRecordDecl *RD + = cast<CXXRecordDecl>(AllocType->getAs<RecordType>()->getDecl()); + LookupQualifiedName(FoundDelete, RD); + } + + if (FoundDelete.empty()) { + DeclareGlobalNewDelete(); + LookupQualifiedName(FoundDelete, Context.getTranslationUnitDecl()); + } + + FoundDelete.suppressDiagnostics(); + llvm::SmallVector<NamedDecl *, 4> Matches; + if (NumPlaceArgs > 1) { + // C++ [expr.new]p20: + // A declaration of a placement deallocation function matches the + // declaration of a placement allocation function if it has the + // same number of parameters and, after parameter transformations + // (8.3.5), all parameter types except the first are + // identical. [...] + // + // To perform this comparison, we compute the function type that + // the deallocation function should have, and use that type both + // for template argument deduction and for comparison purposes. + QualType ExpectedFunctionType; + { + const FunctionProtoType *Proto + = OperatorNew->getType()->getAs<FunctionProtoType>(); + llvm::SmallVector<QualType, 4> ArgTypes; + ArgTypes.push_back(Context.VoidPtrTy); + for (unsigned I = 1, N = Proto->getNumArgs(); I < N; ++I) + ArgTypes.push_back(Proto->getArgType(I)); + + ExpectedFunctionType + = Context.getFunctionType(Context.VoidTy, ArgTypes.data(), + ArgTypes.size(), + Proto->isVariadic(), + 0, false, false, 0, 0, false, CC_Default); + } + + for (LookupResult::iterator D = FoundDelete.begin(), + DEnd = FoundDelete.end(); + D != DEnd; ++D) { + FunctionDecl *Fn = 0; + if (FunctionTemplateDecl *FnTmpl + = dyn_cast<FunctionTemplateDecl>((*D)->getUnderlyingDecl())) { + // Perform template argument deduction to try to match the + // expected function type. + TemplateDeductionInfo Info(Context, StartLoc); + if (DeduceTemplateArguments(FnTmpl, 0, ExpectedFunctionType, Fn, Info)) + continue; + } else + Fn = cast<FunctionDecl>((*D)->getUnderlyingDecl()); + + if (Context.hasSameType(Fn->getType(), ExpectedFunctionType)) + Matches.push_back(Fn); + } + } else { + // C++ [expr.new]p20: + // [...] Any non-placement deallocation function matches a + // non-placement allocation function. [...] + for (LookupResult::iterator D = FoundDelete.begin(), + DEnd = FoundDelete.end(); + D != DEnd; ++D) { + if (FunctionDecl *Fn = dyn_cast<FunctionDecl>((*D)->getUnderlyingDecl())) + if (isNonPlacementDeallocationFunction(Fn)) + Matches.push_back(*D); + } + } + + // C++ [expr.new]p20: + // [...] If the lookup finds a single matching deallocation + // function, that function will be called; otherwise, no + // deallocation function will be called. + if (Matches.size() == 1) { + // FIXME: Drops access, using-declaration info! + OperatorDelete = cast<FunctionDecl>(Matches[0]->getUnderlyingDecl()); + + // C++0x [expr.new]p20: + // If the lookup finds the two-parameter form of a usual + // deallocation function (3.7.4.2) and that function, considered + // as a placement deallocation function, would have been + // selected as a match for the allocation function, the program + // is ill-formed. + if (NumPlaceArgs && getLangOptions().CPlusPlus0x && + isNonPlacementDeallocationFunction(OperatorDelete)) { + Diag(StartLoc, diag::err_placement_new_non_placement_delete) + << SourceRange(PlaceArgs[0]->getLocStart(), + PlaceArgs[NumPlaceArgs - 1]->getLocEnd()); + Diag(OperatorDelete->getLocation(), diag::note_previous_decl) + << DeleteName; + } + } + return false; } @@ -802,7 +1210,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0, true, false, HasBadAllocExceptionSpec? 1 : 0, - &BadAllocType); + &BadAllocType, false, CC_Default); FunctionDecl *Alloc = FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name, FnType, /*TInfo=*/0, FunctionDecl::None, false, true); @@ -1079,8 +1487,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, AssignmentAction Action, bool AllowExplicit, bool Elidable, ImplicitConversionSequence& ICS) { - ICS.setBad(); - ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType); + ICS.setBad(BadConversionSequence::no_conversion, From, ToType); if (Elidable && getLangOptions().CPlusPlus0x) { ICS = TryImplicitConversion(From, ToType, /*SuppressUserConversions=*/false, @@ -1379,6 +1786,11 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, ImpCastExprToType(From, ToType.getNonReferenceType(), CastExpr::CK_NoOp, ToType->isLValueReferenceType()); + + if (SCS.DeprecatedStringLiteralToCharPtr) + Diag(From->getLocStart(), diag::warn_deprecated_string_literal_conversion) + << ToType.getNonReferenceType(); + break; default: @@ -1494,6 +1906,7 @@ static QualType TargetType(const ImplicitConversionSequence &ICS) { 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"); @@ -1537,7 +1950,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, return false; } } - ICS.setBad(); + // -- If E2 is an rvalue, or if the conversion above cannot be done: // -- if E1 and E2 have class type, and the underlying class types are // the same or one is a base class of the other: @@ -1551,14 +1964,22 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, // 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) && 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); + 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); } } else { // -- Otherwise: E1 can be converted to match E2 if E1 can be @@ -1807,9 +2228,18 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // performed to bring them to a common type, whose cv-qualification // shall match the cv-qualification of either the second or the third // operand. The result is of the common type. - QualType Composite = FindCompositePointerType(LHS, RHS); - if (!Composite.isNull()) + bool NonStandardCompositeType = false; + QualType Composite = FindCompositePointerType(LHS, RHS, + isSFINAEContext()? 0 : &NonStandardCompositeType); + if (!Composite.isNull()) { + if (NonStandardCompositeType) + Diag(QuestionLoc, + diag::ext_typecheck_cond_incompatible_operands_nonstandard) + << LTy << RTy << Composite + << LHS->getSourceRange() << RHS->getSourceRange(); + return Composite; + } // Similarly, attempt to find composite type of twp objective-c pointers. Composite = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc); @@ -1828,7 +2258,16 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, /// and @p E2 according to C++0x 5.9p2. It converts both expressions to this /// type and returns it. /// It does not emit diagnostics. -QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { +/// +/// If \p NonStandardCompositeType is non-NULL, then we are permitted to find +/// a non-standard (but still sane) composite type to which both expressions +/// can be converted. When such a type is chosen, \c *NonStandardCompositeType +/// will be set true. +QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2, + bool *NonStandardCompositeType) { + if (NonStandardCompositeType) + *NonStandardCompositeType = false; + assert(getLangOptions().CPlusPlus && "This function assumes C++"); QualType T1 = E1->getType(), T2 = E2->getType(); @@ -1879,12 +2318,20 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { ContainingClassVector MemberOfClass; QualType Composite1 = Context.getCanonicalType(T1), Composite2 = Context.getCanonicalType(T2); + unsigned NeedConstBefore = 0; do { const PointerType *Ptr1, *Ptr2; if ((Ptr1 = Composite1->getAs<PointerType>()) && (Ptr2 = Composite2->getAs<PointerType>())) { Composite1 = Ptr1->getPointeeType(); Composite2 = Ptr2->getPointeeType(); + + // If we're allowed to create a non-standard composite type, keep track + // of where we need to fill in additional 'const' qualifiers. + if (NonStandardCompositeType && + Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) + NeedConstBefore = QualifierUnion.size(); + QualifierUnion.push_back( Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); MemberOfClass.push_back(std::make_pair((const Type *)0, (const Type *)0)); @@ -1896,6 +2343,13 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { (MemPtr2 = Composite2->getAs<MemberPointerType>())) { Composite1 = MemPtr1->getPointeeType(); Composite2 = MemPtr2->getPointeeType(); + + // If we're allowed to create a non-standard composite type, keep track + // of where we need to fill in additional 'const' qualifiers. + if (NonStandardCompositeType && + Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) + NeedConstBefore = QualifierUnion.size(); + QualifierUnion.push_back( Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(), @@ -1909,6 +2363,18 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { break; } while (true); + if (NeedConstBefore && NonStandardCompositeType) { + // Extension: Add 'const' to qualifiers that come before the first qualifier + // mismatch, so that our (non-standard!) composite type meets the + // requirements of C++ [conv.qual]p4 bullet 3. + for (unsigned I = 0; I != NeedConstBefore; ++I) { + if ((QualifierUnion[I] & Qualifiers::Const) == 0) { + QualifierUnion[I] = QualifierUnion[I] | Qualifiers::Const; + *NonStandardCompositeType = true; + } + } + } + // Rewrap the composites as pointers or member pointers with the union CVRs. ContainingClassVector::reverse_iterator MOC = MemberOfClass.rbegin(); @@ -1947,9 +2413,8 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { /*ForceRValue=*/false, /*InOverloadResolution=*/false); + bool ToC2Viable = false; ImplicitConversionSequence E1ToC2, E2ToC2; - E1ToC2.setBad(); - E2ToC2.setBad(); if (Context.getCanonicalType(Composite1) != Context.getCanonicalType(Composite2)) { E1ToC2 = TryImplicitConversion(E1, Composite2, @@ -1962,10 +2427,10 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { /*AllowExplicit=*/false, /*ForceRValue=*/false, /*InOverloadResolution=*/false); + ToC2Viable = !E1ToC2.isBad() && !E2ToC2.isBad(); } bool ToC1Viable = !E1ToC1.isBad() && !E2ToC1.isBad(); - bool ToC2Viable = !E1ToC2.isBad() && !E2ToC2.isBad(); if (ToC1Viable && !ToC2Viable) { if (!PerformImplicitConversion(E1, Composite1, E1ToC1, Sema::AA_Converting) && !PerformImplicitConversion(E2, Composite1, E2ToC1, Sema::AA_Converting)) @@ -1995,7 +2460,9 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) { QualType Ty = CE->getCallee()->getType(); if (const PointerType *PT = Ty->getAs<PointerType>()) Ty = PT->getPointeeType(); - + else if (const BlockPointerType *BPT = Ty->getAs<BlockPointerType>()) + Ty = BPT->getPointeeType(); + const FunctionType *FTy = Ty->getAs<FunctionType>(); if (FTy->getResultType()->isReferenceType()) return Owned(E); @@ -2060,7 +2527,8 @@ FullExpr Sema::CreateFullExpr(Expr *SubExpr) { Sema::OwningExprResult Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, - tok::TokenKind OpKind, TypeTy *&ObjectType) { + tok::TokenKind OpKind, TypeTy *&ObjectType, + bool &MayBePseudoDestructor) { // Since this might be a postfix expression, get rid of ParenListExprs. Base = MaybeConvertParenListExprToParenExpr(S, move(Base)); @@ -2068,6 +2536,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, assert(BaseExpr && "no record expansion"); QualType BaseType = BaseExpr->getType(); + MayBePseudoDestructor = false; if (BaseType->isDependentType()) { // If we have a pointer to a dependent type and are using the -> operator, // the object type is the type that the pointer points to. We might still @@ -2077,6 +2546,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, BaseType = Ptr->getPointeeType(); ObjectType = BaseType.getAsOpaquePtr(); + MayBePseudoDestructor = true; return move(Base); } @@ -2118,7 +2588,11 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, // [...] If the type of the object expression is of pointer to scalar // type, the unqualified-id is looked up in the context of the complete // postfix-expression. + // + // This also indicates that we should be parsing a + // pseudo-destructor-name. ObjectType = 0; + MayBePseudoDestructor = true; return move(Base); } @@ -2134,10 +2608,277 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, // type C (or of pointer to a class type C), the unqualified-id is looked // up in the scope of class C. [...] ObjectType = BaseType.getAsOpaquePtr(); - return move(Base); } +Sema::OwningExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc, + ExprArg MemExpr) { + Expr *E = (Expr *) MemExpr.get(); + SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(NameLoc); + Diag(E->getLocStart(), diag::err_dtor_expr_without_call) + << isa<CXXPseudoDestructorExpr>(E) + << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()"); + + return ActOnCallExpr(/*Scope*/ 0, + move(MemExpr), + /*LPLoc*/ ExpectedLParenLoc, + Sema::MultiExprArg(*this, 0, 0), + /*CommaLocs*/ 0, + /*RPLoc*/ ExpectedLParenLoc); +} + +Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + TypeSourceInfo *ScopeTypeInfo, + SourceLocation CCLoc, + SourceLocation TildeLoc, + PseudoDestructorTypeStorage Destructed, + bool HasTrailingLParen) { + TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo(); + + // C++ [expr.pseudo]p2: + // The left-hand side of the dot operator shall be of scalar type. The + // left-hand side of the arrow operator shall be of pointer to scalar type. + // This scalar type is the object type. + Expr *BaseE = (Expr *)Base.get(); + QualType ObjectType = BaseE->getType(); + if (OpKind == tok::arrow) { + if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) { + ObjectType = Ptr->getPointeeType(); + } else if (!BaseE->isTypeDependent()) { + // The user wrote "p->" when she probably meant "p."; fix it. + Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) + << ObjectType << true + << CodeModificationHint::CreateReplacement(OpLoc, "."); + if (isSFINAEContext()) + return ExprError(); + + OpKind = tok::period; + } + } + + if (!ObjectType->isDependentType() && !ObjectType->isScalarType()) { + Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar) + << ObjectType << BaseE->getSourceRange(); + return ExprError(); + } + + // C++ [expr.pseudo]p2: + // [...] The cv-unqualified versions of the object type and of the type + // designated by the pseudo-destructor-name shall be the same type. + if (DestructedTypeInfo) { + QualType DestructedType = DestructedTypeInfo->getType(); + SourceLocation DestructedTypeStart + = DestructedTypeInfo->getTypeLoc().getSourceRange().getBegin(); + if (!DestructedType->isDependentType() && !ObjectType->isDependentType() && + !Context.hasSameUnqualifiedType(DestructedType, ObjectType)) { + Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch) + << ObjectType << DestructedType << BaseE->getSourceRange() + << DestructedTypeInfo->getTypeLoc().getSourceRange(); + + // Recover by setting the destructed type to the object type. + DestructedType = ObjectType; + DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType, + DestructedTypeStart); + Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); + } + } + + // C++ [expr.pseudo]p2: + // [...] Furthermore, the two type-names in a pseudo-destructor-name of the + // form + // + // ::[opt] nested-name-specifier[opt] type-name :: ~ type-name + // + // shall designate the same scalar type. + if (ScopeTypeInfo) { + QualType ScopeType = ScopeTypeInfo->getType(); + if (!ScopeType->isDependentType() && !ObjectType->isDependentType() && + !Context.hasSameType(ScopeType, ObjectType)) { + + Diag(ScopeTypeInfo->getTypeLoc().getSourceRange().getBegin(), + diag::err_pseudo_dtor_type_mismatch) + << ObjectType << ScopeType << BaseE->getSourceRange() + << ScopeTypeInfo->getTypeLoc().getSourceRange(); + + ScopeType = QualType(); + ScopeTypeInfo = 0; + } + } + + OwningExprResult Result + = Owned(new (Context) CXXPseudoDestructorExpr(Context, + Base.takeAs<Expr>(), + OpKind == tok::arrow, + OpLoc, + (NestedNameSpecifier *) SS.getScopeRep(), + SS.getRange(), + ScopeTypeInfo, + CCLoc, + TildeLoc, + Destructed)); + + if (HasTrailingLParen) + return move(Result); + + return DiagnoseDtorReference(Destructed.getLocation(), move(Result)); +} + +Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + UnqualifiedId &FirstTypeName, + SourceLocation CCLoc, + SourceLocation TildeLoc, + UnqualifiedId &SecondTypeName, + bool HasTrailingLParen) { + assert((FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId || + FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) && + "Invalid first type name in pseudo-destructor"); + assert((SecondTypeName.getKind() == UnqualifiedId::IK_TemplateId || + SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) && + "Invalid second type name in pseudo-destructor"); + + Expr *BaseE = (Expr *)Base.get(); + + // C++ [expr.pseudo]p2: + // The left-hand side of the dot operator shall be of scalar type. The + // left-hand side of the arrow operator shall be of pointer to scalar type. + // This scalar type is the object type. + QualType ObjectType = BaseE->getType(); + if (OpKind == tok::arrow) { + if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) { + ObjectType = Ptr->getPointeeType(); + } else if (!ObjectType->isDependentType()) { + // The user wrote "p->" when she probably meant "p."; fix it. + Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) + << ObjectType << true + << CodeModificationHint::CreateReplacement(OpLoc, "."); + if (isSFINAEContext()) + return ExprError(); + + OpKind = tok::period; + } + } + + // Compute the object type that we should use for name lookup purposes. Only + // record types and dependent types matter. + void *ObjectTypePtrForLookup = 0; + if (!SS.isSet()) { + ObjectTypePtrForLookup = (void *)ObjectType->getAs<RecordType>(); + if (!ObjectTypePtrForLookup && ObjectType->isDependentType()) + ObjectTypePtrForLookup = Context.DependentTy.getAsOpaquePtr(); + } + + // Convert the name of the type being destructed (following the ~) into a + // type (with source-location information). + QualType DestructedType; + TypeSourceInfo *DestructedTypeInfo = 0; + PseudoDestructorTypeStorage Destructed; + if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) { + TypeTy *T = getTypeName(*SecondTypeName.Identifier, + SecondTypeName.StartLocation, + S, &SS, true, ObjectTypePtrForLookup); + if (!T && + ((SS.isSet() && !computeDeclContext(SS, false)) || + (!SS.isSet() && ObjectType->isDependentType()))) { + // The name of the type being destroyed is a dependent name, and we + // couldn't find anything useful in scope. Just store the identifier and + // it's location, and we'll perform (qualified) name lookup again at + // template instantiation time. + Destructed = PseudoDestructorTypeStorage(SecondTypeName.Identifier, + SecondTypeName.StartLocation); + } else if (!T) { + Diag(SecondTypeName.StartLocation, + diag::err_pseudo_dtor_destructor_non_type) + << SecondTypeName.Identifier << ObjectType; + if (isSFINAEContext()) + return ExprError(); + + // Recover by assuming we had the right type all along. + DestructedType = ObjectType; + } else + DestructedType = GetTypeFromParser(T, &DestructedTypeInfo); + } else { + // Resolve the template-id to a type. + TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId; + ASTTemplateArgsPtr TemplateArgsPtr(*this, + TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc); + if (T.isInvalid() || !T.get()) { + // Recover by assuming we had the right type all along. + DestructedType = ObjectType; + } else + DestructedType = GetTypeFromParser(T.get(), &DestructedTypeInfo); + } + + // If we've performed some kind of recovery, (re-)build the type source + // information. + if (!DestructedType.isNull()) { + if (!DestructedTypeInfo) + DestructedTypeInfo = Context.getTrivialTypeSourceInfo(DestructedType, + SecondTypeName.StartLocation); + Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); + } + + // Convert the name of the scope type (the type prior to '::') into a type. + TypeSourceInfo *ScopeTypeInfo = 0; + QualType ScopeType; + if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId || + FirstTypeName.Identifier) { + if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) { + TypeTy *T = getTypeName(*FirstTypeName.Identifier, + FirstTypeName.StartLocation, + S, &SS, false, ObjectTypePtrForLookup); + if (!T) { + Diag(FirstTypeName.StartLocation, + diag::err_pseudo_dtor_destructor_non_type) + << FirstTypeName.Identifier << ObjectType; + + if (isSFINAEContext()) + return ExprError(); + + // Just drop this type. It's unnecessary anyway. + ScopeType = QualType(); + } else + ScopeType = GetTypeFromParser(T, &ScopeTypeInfo); + } else { + // Resolve the template-id to a type. + TemplateIdAnnotation *TemplateId = FirstTypeName.TemplateId; + ASTTemplateArgsPtr TemplateArgsPtr(*this, + TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc); + if (T.isInvalid() || !T.get()) { + // Recover by dropping this type. + ScopeType = QualType(); + } else + ScopeType = GetTypeFromParser(T.get(), &ScopeTypeInfo); + } + } + + if (!ScopeType.isNull() && !ScopeTypeInfo) + ScopeTypeInfo = Context.getTrivialTypeSourceInfo(ScopeType, + FirstTypeName.StartLocation); + + + return BuildPseudoDestructorExpr(move(Base), OpLoc, OpKind, SS, + ScopeTypeInfo, CCLoc, TildeLoc, + Destructed, HasTrailingLParen); +} + CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, CXXMethodDecl *Method) { if (PerformObjectArgumentInitialization(Exp, Method)) diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 0c5d8ef..3a05241 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -426,14 +426,14 @@ Sema::ExprResult Sema::ActOnClassMessage( if (!ClassDecl) { NamedDecl *IDecl = LookupSingleName(TUScope, receiverName, LookupOrdinaryName); - if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(IDecl)) { - const ObjCInterfaceType *OCIT; - OCIT = OCTD->getUnderlyingType()->getAs<ObjCInterfaceType>(); - if (!OCIT) { - Diag(receiverLoc, diag::err_invalid_receiver_to_message); - return true; - } - ClassDecl = OCIT->getDecl(); + if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(IDecl)) + if (const ObjCInterfaceType *OCIT + = OCTD->getUnderlyingType()->getAs<ObjCInterfaceType>()) + ClassDecl = OCIT->getDecl(); + + if (!ClassDecl) { + Diag(receiverLoc, diag::err_invalid_receiver_to_message); + return true; } } assert(ClassDecl && "missing interface declaration"); diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 7b4a417..0f8107a 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2227,7 +2227,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, ToType, CandidateSet); else S.AddConversionCandidate(Conv, I.getAccess(), ActingDC, - Initializer, cv1T1, CandidateSet); + Initializer, ToType, CandidateSet); } } } @@ -3439,10 +3439,25 @@ InitializationSequence::Perform(Sema &S, return S.ExprError(); // Build the an expression that constructs a temporary. - CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), - Constructor, - move_arg(ConstructorArgs), - ConstructorInitRequiresZeroInit, + if (Entity.getKind() == InitializedEntity::EK_Temporary && + (Kind.getKind() == InitializationKind::IK_Direct || + Kind.getKind() == InitializationKind::IK_Value)) { + // An explicitly-constructed temporary, e.g., X(1, 2). + unsigned NumExprs = ConstructorArgs.size(); + Expr **Exprs = (Expr **)ConstructorArgs.take(); + S.MarkDeclarationReferenced(Kind.getLocation(), Constructor); + CurInit = S.Owned(new (S.Context) CXXTemporaryObjectExpr(S.Context, + Constructor, + Entity.getType(), + Kind.getLocation(), + Exprs, + NumExprs, + Kind.getParenRange().getEnd())); + } else + CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), + Constructor, + move_arg(ConstructorArgs), + ConstructorInitRequiresZeroInit, Entity.getKind() == InitializedEntity::EK_Base); if (CurInit.isInvalid()) return S.ExprError(); diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index c7569d6..744b806 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -544,7 +544,8 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { 0, 0, ConvProto->isVariadic(), ConvProto->getTypeQuals(), false, false, 0, 0, - ConvProto->getNoReturnAttr()); + ConvProto->getNoReturnAttr(), + CC_Default); // Perform template argument deduction against the type that we would // expect the function to have. @@ -644,14 +645,37 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { DeclContext *OuterCtx = findOuterContext(S); for (; Ctx && Ctx->getPrimaryContext() != OuterCtx; Ctx = Ctx->getLookupParent()) { - // We do not directly look into function or method contexts - // (since all local variables are found via the identifier - // changes) or in transparent contexts (since those entities - // will be found in the nearest enclosing non-transparent - // context). - if (Ctx->isFunctionOrMethod() || Ctx->isTransparentContext()) + // We do not directly look into transparent contexts, since + // those entities will be found in the nearest enclosing + // non-transparent context. + if (Ctx->isTransparentContext()) continue; - + + // We do not look directly into function or method contexts, + // since all of the local variables and parameters of the + // function/method are present within the Scope. + if (Ctx->isFunctionOrMethod()) { + // If we have an Objective-C instance method, look for ivars + // in the corresponding interface. + if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(Ctx)) { + if (Method->isInstanceMethod() && Name.getAsIdentifierInfo()) + if (ObjCInterfaceDecl *Class = Method->getClassInterface()) { + ObjCInterfaceDecl *ClassDeclared; + if (ObjCIvarDecl *Ivar = Class->lookupInstanceVariable( + Name.getAsIdentifierInfo(), + ClassDeclared)) { + if (R.isAcceptableDecl(Ivar)) { + R.addDecl(Ivar); + R.resolveKind(); + return true; + } + } + } + } + + continue; + } + // Perform qualified name lookup into this context. // FIXME: In some cases, we know that every name that could be found by // this qualified name lookup will also be on the identifier chain. For diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index b79b1cc..ed0d137 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -80,7 +80,7 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) { ICR_Conversion, ICR_Conversion, ICR_Conversion, - ICR_Conversion + ICR_Complex_Real_Conversion }; return Rank[(int)Kind]; } @@ -118,7 +118,7 @@ void StandardConversionSequence::setAsIdentityConversion() { First = ICK_Identity; Second = ICK_Identity; Third = ICK_Identity; - Deprecated = false; + DeprecatedStringLiteralToCharPtr = false; ReferenceBinding = false; DirectBinding = false; RRefBinding = false; @@ -453,8 +453,7 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, } if (!getLangOptions().CPlusPlus) { - ICS.setBad(); - ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType); + ICS.setBad(BadConversionSequence::no_conversion, From, ToType); return ICS; } @@ -500,8 +499,7 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, // 13.3.1.6 in all cases, only standard conversion sequences and // ellipsis conversion sequences are allowed. if (SuppressUserConversions && ICS.isUserDefined()) { - ICS.setBad(); - ICS.Bad.init(BadConversionSequence::suppressed_user, From, ToType); + ICS.setBad(BadConversionSequence::suppressed_user, From, ToType); } } else if (UserDefResult == OR_Ambiguous && !SuppressUserConversions) { ICS.setAmbiguous(); @@ -512,8 +510,7 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, if (Cand->Viable) ICS.Ambiguous.addConversion(Cand->Function); } else { - ICS.setBad(); - ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType); + ICS.setBad(BadConversionSequence::no_conversion, From, ToType); } return ICS; @@ -552,7 +549,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // Standard conversions (C++ [conv]) SCS.setAsIdentityConversion(); - SCS.Deprecated = false; + SCS.DeprecatedStringLiteralToCharPtr = false; SCS.IncompatibleObjC = false; SCS.setFromType(FromType); SCS.CopyConstructor = 0; @@ -595,7 +592,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, if (IsStringLiteralToNonConstPointerConversion(From, ToType)) { // This conversion is deprecated. (C++ D.4). - SCS.Deprecated = true; + SCS.DeprecatedStringLiteralToCharPtr = true; // For the purpose of ranking in overload resolution // (13.3.3.1.1), this conversion is considered an @@ -672,14 +669,19 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // Integral conversions (C++ 4.7). SCS.Second = ICK_Integral_Conversion; FromType = ToType.getUnqualifiedType(); - } else if (FromType->isFloatingType() && ToType->isFloatingType()) { - // Floating point conversions (C++ 4.8). - SCS.Second = ICK_Floating_Conversion; - FromType = ToType.getUnqualifiedType(); } else if (FromType->isComplexType() && ToType->isComplexType()) { // Complex conversions (C99 6.3.1.6) SCS.Second = ICK_Complex_Conversion; FromType = ToType.getUnqualifiedType(); + } else if ((FromType->isComplexType() && ToType->isArithmeticType()) || + (ToType->isComplexType() && FromType->isArithmeticType())) { + // Complex-real conversions (C99 6.3.1.7) + SCS.Second = ICK_Complex_Real; + FromType = ToType.getUnqualifiedType(); + } else if (FromType->isFloatingType() && ToType->isFloatingType()) { + // Floating point conversions (C++ 4.8). + SCS.Second = ICK_Floating_Conversion; + FromType = ToType.getUnqualifiedType(); } else if ((FromType->isFloatingType() && ToType->isIntegralType() && (!ToType->isBooleanType() && !ToType->isEnumeralType())) || @@ -688,11 +690,6 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // Floating-integral conversions (C++ 4.9). SCS.Second = ICK_Floating_Integral; FromType = ToType.getUnqualifiedType(); - } else if ((FromType->isComplexType() && ToType->isArithmeticType()) || - (ToType->isComplexType() && FromType->isArithmeticType())) { - // Complex-real conversions (C99 6.3.1.7) - SCS.Second = ICK_Complex_Real; - FromType = ToType.getUnqualifiedType(); } else if (IsPointerConversion(From, FromType, ToType, InOverloadResolution, FromType, IncompatibleObjC)) { // Pointer conversions (C++ 4.10). @@ -1094,6 +1091,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, // here. That is handled by CheckPointerConversion. if (getLangOptions().CPlusPlus && FromPointeeType->isRecordType() && ToPointeeType->isRecordType() && + !Context.hasSameUnqualifiedType(FromPointeeType, ToPointeeType) && !RequireCompleteType(From->getLocStart(), FromPointeeType, PDiag()) && IsDerivedFrom(FromPointeeType, ToPointeeType)) { ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, @@ -1995,7 +1993,7 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1, // the deprecated string literal array to pointer conversion. switch (Result) { case ImplicitConversionSequence::Better: - if (SCS1.Deprecated) + if (SCS1.DeprecatedStringLiteralToCharPtr) Result = ImplicitConversionSequence::Indistinguishable; break; @@ -2003,7 +2001,7 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1, break; case ImplicitConversionSequence::Worse: - if (SCS2.Deprecated) + if (SCS2.DeprecatedStringLiteralToCharPtr) Result = ImplicitConversionSequence::Indistinguishable; break; } @@ -2096,32 +2094,6 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, } } - // Compare based on reference bindings. - if (SCS1.ReferenceBinding && SCS2.ReferenceBinding && - SCS1.Second == ICK_Derived_To_Base) { - // -- binding of an expression of type C to a reference of type - // B& is better than binding an expression of type C to a - // reference of type A&, - if (Context.hasSameUnqualifiedType(FromType1, FromType2) && - !Context.hasSameUnqualifiedType(ToType1, ToType2)) { - if (IsDerivedFrom(ToType1, ToType2)) - return ImplicitConversionSequence::Better; - else if (IsDerivedFrom(ToType2, ToType1)) - return ImplicitConversionSequence::Worse; - } - - // -- binding of an expression of type B to a reference of type - // A& is better than binding an expression of type C to a - // reference of type A&, - if (!Context.hasSameUnqualifiedType(FromType1, FromType2) && - Context.hasSameUnqualifiedType(ToType1, ToType2)) { - if (IsDerivedFrom(FromType2, FromType1)) - return ImplicitConversionSequence::Better; - else if (IsDerivedFrom(FromType1, FromType2)) - return ImplicitConversionSequence::Worse; - } - } - // Ranking of member-pointer types. if (SCS1.Second == ICK_Pointer_Member && SCS2.Second == ICK_Pointer_Member && FromType1->isMemberPointerType() && FromType2->isMemberPointerType() && @@ -2158,9 +2130,13 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, } } - if (SCS1.CopyConstructor && SCS2.CopyConstructor && + if ((SCS1.ReferenceBinding || SCS1.CopyConstructor) && + (SCS2.ReferenceBinding || SCS2.CopyConstructor) && SCS1.Second == ICK_Derived_To_Base) { // -- conversion of C to B is better than conversion of C to A, + // -- binding of an expression of type C to a reference of type + // B& is better than binding an expression of type C to a + // reference of type A&, if (Context.hasSameUnqualifiedType(FromType1, FromType2) && !Context.hasSameUnqualifiedType(ToType1, ToType2)) { if (IsDerivedFrom(ToType1, ToType2)) @@ -2170,6 +2146,9 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, } // -- conversion of B to A is better than conversion of C to A. + // -- binding of an expression of type B to a reference of type + // A& is better than binding an expression of type C to a + // reference of type A&, if (!Context.hasSameUnqualifiedType(FromType1, FromType2) && Context.hasSameUnqualifiedType(ToType1, ToType2)) { if (IsDerivedFrom(FromType2, FromType1)) @@ -2195,7 +2174,7 @@ Sema::TryCopyInitialization(Expr *From, QualType ToType, bool InOverloadResolution) { if (ToType->isReferenceType()) { ImplicitConversionSequence ICS; - ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType); + ICS.setBad(BadConversionSequence::no_conversion, From, ToType); CheckReferenceInit(From, ToType, /*FIXME:*/From->getLocStart(), SuppressUserConversions, @@ -2267,8 +2246,6 @@ Sema::TryObjectArgumentInitialization(QualType OrigFromType, // Set up the conversion sequence as a "bad" conversion, to allow us // to exit early. ImplicitConversionSequence ICS; - ICS.Standard.setAsIdentityConversion(); - ICS.setBad(); // We need to have an object of class type. QualType FromType = OrigFromType; @@ -2292,25 +2269,29 @@ Sema::TryObjectArgumentInitialization(QualType OrigFromType, if (ImplicitParamType.getCVRQualifiers() != FromTypeCanon.getLocalCVRQualifiers() && !ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) { - ICS.Bad.init(BadConversionSequence::bad_qualifiers, - OrigFromType, ImplicitParamType); + ICS.setBad(BadConversionSequence::bad_qualifiers, + OrigFromType, ImplicitParamType); return ICS; } // Check that we have either the same type or a derived type. It // affects the conversion rank. QualType ClassTypeCanon = Context.getCanonicalType(ClassType); - if (ClassTypeCanon == FromTypeCanon.getLocalUnqualifiedType()) - ICS.Standard.Second = ICK_Identity; - else if (IsDerivedFrom(FromType, ClassType)) - ICS.Standard.Second = ICK_Derived_To_Base; + ImplicitConversionKind SecondKind; + if (ClassTypeCanon == FromTypeCanon.getLocalUnqualifiedType()) { + SecondKind = ICK_Identity; + } else if (IsDerivedFrom(FromType, ClassType)) + SecondKind = ICK_Derived_To_Base; else { - ICS.Bad.init(BadConversionSequence::unrelated_class, FromType, ImplicitParamType); + ICS.setBad(BadConversionSequence::unrelated_class, + FromType, ImplicitParamType); return ICS; } // Success. Mark this as a reference binding. ICS.setStandard(); + ICS.Standard.setAsIdentityConversion(); + ICS.Standard.Second = SecondKind; ICS.Standard.setFromType(FromType); ICS.Standard.setAllToTypes(ImplicitParamType); ICS.Standard.ReferenceBinding = true; @@ -2439,7 +2420,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, QualType ClassType = Context.getTypeDeclType(Constructor->getParent()); if (NumArgs == 1 && Constructor->isCopyConstructorLikeSpecialization() && - Context.hasSameUnqualifiedType(ClassType, Args[0]->getType())) + (Context.hasSameUnqualifiedType(ClassType, Args[0]->getType()) || + IsDerivedFrom(Args[0]->getType(), ClassType))) return; } @@ -4462,7 +4444,7 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { QualType ToTy = Conv.Bad.getToType(); if (FromTy == S.Context.OverloadTy) { - assert(FromExpr); + assert(FromExpr && "overload set argument came from implicit argument?"); Expr *E = FromExpr->IgnoreParens(); if (isa<UnaryOperator>(E)) E = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens(); @@ -4665,8 +4647,9 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, case ovl_fail_bad_final_conversion: return S.NoteOverloadCandidate(Fn); - case ovl_fail_bad_conversion: - for (unsigned I = 0, N = Cand->Conversions.size(); I != N; ++I) + case ovl_fail_bad_conversion: { + unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0); + for (unsigned N = Cand->Conversions.size(); I != N; ++I) if (Cand->Conversions[I].isBad()) return DiagnoseBadConversion(S, Cand, I); @@ -4675,6 +4658,7 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, // those conditions and diagnose them well. return S.NoteOverloadCandidate(Fn); } + } } void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) { @@ -4794,7 +4778,8 @@ struct CompareOverloadCandidatesForDisplay { assert(L->Conversions.size() == R->Conversions.size()); int leftBetter = 0; - for (unsigned I = 0, E = L->Conversions.size(); I != E; ++I) { + unsigned I = (L->IgnoreObjectArgument || R->IgnoreObjectArgument); + for (unsigned E = L->Conversions.size(); I != E; ++I) { switch (S.CompareImplicitConversionSequences(L->Conversions[I], R->Conversions[I])) { case ImplicitConversionSequence::Better: @@ -4840,7 +4825,7 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, if (Cand->FailureKind != ovl_fail_bad_conversion) return; // Skip forward to the first bad conversion. - unsigned ConvIdx = 0; + unsigned ConvIdx = (Cand->IgnoreObjectArgument ? 1 : 0); unsigned ConvCount = Cand->Conversions.size(); while (true) { assert(ConvIdx != ConvCount && "no bad conversion in candidate"); @@ -4852,6 +4837,9 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, if (ConvIdx == ConvCount) return; + assert(!Cand->Conversions[ConvIdx].isInitialized() && + "remaining conversion is initialized?"); + // FIXME: these should probably be preserved from the overload // operation somehow. bool SuppressUserConversions = false; diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index e6dfa74..58e416c 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -54,12 +54,12 @@ namespace clang { ICK_Floating_Conversion, ///< Floating point conversions (C++ 4.8) ICK_Complex_Conversion, ///< Complex conversions (C99 6.3.1.6) ICK_Floating_Integral, ///< Floating-integral conversions (C++ 4.9) - ICK_Complex_Real, ///< Complex-real conversions (C99 6.3.1.7) ICK_Pointer_Conversion, ///< Pointer conversions (C++ 4.10) ICK_Pointer_Member, ///< Pointer-to-member conversions (C++ 4.11) ICK_Boolean_Conversion, ///< Boolean conversions (C++ 4.12) ICK_Compatible_Conversion, ///< Conversions between compatible types in C99 ICK_Derived_To_Base, ///< Derived-to-base (C++ [over.best.ics]) + ICK_Complex_Real, ///< Complex-real conversions (C99 6.3.1.7) ICK_Num_Conversion_Kinds ///< The number of conversion kinds }; @@ -83,9 +83,10 @@ namespace clang { /// 13.3.3.1.1) and are listed such that better conversion ranks /// have smaller values. enum ImplicitConversionRank { - ICR_Exact_Match = 0, ///< Exact Match - ICR_Promotion, ///< Promotion - ICR_Conversion ///< Conversion + ICR_Exact_Match = 0, ///< Exact Match + ICR_Promotion, ///< Promotion + ICR_Conversion, ///< Conversion + ICR_Complex_Real_Conversion ///< Complex <-> Real conversion }; ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind); @@ -116,7 +117,7 @@ namespace clang { /// Deprecated - Whether this the deprecated conversion of a /// string literal to a pointer to non-const character data /// (C++ 4.2p2). - bool Deprecated : 1; + bool DeprecatedStringLiteralToCharPtr : 1; /// IncompatibleObjC - Whether this is an Objective-C conversion /// that we should warn about (if we actually use it). @@ -316,14 +317,22 @@ namespace clang { }; private: + enum { + Uninitialized = BadConversion + 1 + }; + /// ConversionKind - The kind of implicit conversion sequence. - Kind ConversionKind; + unsigned ConversionKind; void setKind(Kind K) { - if (isAmbiguous()) Ambiguous.destruct(); + destruct(); ConversionKind = K; } + void destruct() { + if (ConversionKind == AmbiguousConversion) Ambiguous.destruct(); + } + public: union { /// When ConversionKind == StandardConversion, provides the @@ -343,14 +352,15 @@ namespace clang { BadConversionSequence Bad; }; - ImplicitConversionSequence() : ConversionKind(BadConversion) {} + ImplicitConversionSequence() : ConversionKind(Uninitialized) {} ~ImplicitConversionSequence() { - if (isAmbiguous()) Ambiguous.destruct(); + destruct(); } ImplicitConversionSequence(const ImplicitConversionSequence &Other) : ConversionKind(Other.ConversionKind) { switch (ConversionKind) { + case Uninitialized: break; case StandardConversion: Standard = Other.Standard; break; case UserDefinedConversion: UserDefined = Other.UserDefined; break; case AmbiguousConversion: Ambiguous.copyFrom(Other.Ambiguous); break; @@ -361,26 +371,45 @@ namespace clang { ImplicitConversionSequence & operator=(const ImplicitConversionSequence &Other) { - if (isAmbiguous()) Ambiguous.destruct(); + destruct(); new (this) ImplicitConversionSequence(Other); return *this; } - Kind getKind() const { return ConversionKind; } - bool isBad() const { return ConversionKind == BadConversion; } - bool isStandard() const { return ConversionKind == StandardConversion; } - bool isEllipsis() const { return ConversionKind == EllipsisConversion; } - bool isAmbiguous() const { return ConversionKind == AmbiguousConversion; } - bool isUserDefined() const { - return ConversionKind == UserDefinedConversion; + Kind getKind() const { + assert(isInitialized() && "querying uninitialized conversion"); + return Kind(ConversionKind); + } + bool isBad() const { return getKind() == BadConversion; } + bool isStandard() const { return getKind() == StandardConversion; } + bool isEllipsis() const { return getKind() == EllipsisConversion; } + bool isAmbiguous() const { return getKind() == AmbiguousConversion; } + bool isUserDefined() const { return getKind() == UserDefinedConversion; } + + /// Determines whether this conversion sequence has been + /// initialized. Most operations should never need to query + /// uninitialized conversions and should assert as above. + bool isInitialized() const { return ConversionKind != Uninitialized; } + + /// Sets this sequence as a bad conversion for an explicit argument. + void setBad(BadConversionSequence::FailureKind Failure, + Expr *FromExpr, QualType ToType) { + setKind(BadConversion); + Bad.init(Failure, FromExpr, ToType); + } + + /// Sets this sequence as a bad conversion for an implicit argument. + void setBad(BadConversionSequence::FailureKind Failure, + QualType FromType, QualType ToType) { + setKind(BadConversion); + Bad.init(Failure, FromType, ToType); } - void setBad() { setKind(BadConversion); } void setStandard() { setKind(StandardConversion); } void setEllipsis() { setKind(EllipsisConversion); } void setUserDefined() { setKind(UserDefinedConversion); } void setAmbiguous() { - if (isAmbiguous()) return; + if (ConversionKind == AmbiguousConversion) return; ConversionKind = AmbiguousConversion; Ambiguous.construct(); } @@ -490,6 +519,7 @@ namespace clang { bool hasAmbiguousConversion() const { for (llvm::SmallVectorImpl<ImplicitConversionSequence>::const_iterator I = Conversions.begin(), E = Conversions.end(); I != E; ++I) { + if (!I->isInitialized()) return false; if (I->isAmbiguous()) return true; } return false; diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index fa42634..75d9f67 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -314,15 +314,13 @@ void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val, // Perform a conversion to the promoted condition type if needed. if (NewWidth > Val.getBitWidth()) { // If this is an extension, just do it. - llvm::APSInt OldVal(Val); Val.extend(NewWidth); - - // If the input was signed and negative and the output is unsigned, - // warn. - if (!NewSign && OldVal.isSigned() && OldVal.isNegative()) - Diag(Loc, DiagID) << OldVal.toString(10) << Val.toString(10); - Val.setIsSigned(NewSign); + + // If the input was signed and negative and the output is + // unsigned, don't bother to warn: this is implementation-defined + // behavior. + // FIXME: Introduce a second, default-ignored warning for this case? } else if (NewWidth < Val.getBitWidth()) { // If this is a truncation, check for overflow. llvm::APSInt ConvVal(Val); @@ -340,11 +338,11 @@ void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val, } else if (NewSign != Val.isSigned()) { // Convert the sign to match the sign of the condition. This can cause // overflow as well: unsigned(INTMIN) + // We don't diagnose this overflow, because it is implementation-defined + // behavior. + // FIXME: Introduce a second, default-ignored warning for this case? llvm::APSInt OldVal(Val); Val.setIsSigned(NewSign); - - if (Val.isNegative()) // Sign bit changes meaning. - Diag(Loc, DiagID) << OldVal.toString(10) << Val.toString(10); } } @@ -752,7 +750,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, // Check to see if switch is over an Enum and handles all of its // values - const EnumType* ET = dyn_cast<EnumType>(CondTypeBeforePromotion); + const EnumType* ET = CondTypeBeforePromotion->getAs<EnumType>(); // If switch has default case, then ignore it. if (!CaseListIsErroneous && !TheDefaultStmt && ET) { const EnumDecl *ED = ET->getDecl(); @@ -1038,6 +1036,7 @@ Action::OwningStmtResult Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // If this is the first return we've seen in the block, infer the type of // the block from it. + BlockScopeInfo *CurBlock = getCurBlock(); if (CurBlock->ReturnType.isNull()) { if (RetValExp) { // Don't call UsualUnaryConversions(), since we don't want to do @@ -1132,7 +1131,7 @@ static bool IsReturnCopyElidable(ASTContext &Ctx, QualType RetType, Action::OwningStmtResult Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { Expr *RetValExp = rex.takeAs<Expr>(); - if (CurBlock) + if (getCurBlock()) return ActOnBlockReturnStmt(ReturnLoc, RetValExp); QualType FnRetType; @@ -1502,7 +1501,7 @@ Sema::ActOnObjCAtFinallyStmt(SourceLocation AtLoc, StmtArg Body) { Action::OwningStmtResult Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, StmtArg Try, StmtArg Catch, StmtArg Finally) { - CurFunctionNeedsScopeChecking = true; + FunctionNeedsScopeChecking() = true; return Owned(new (Context) ObjCAtTryStmt(AtLoc, Try.takeAs<Stmt>(), Catch.takeAs<Stmt>(), Finally.takeAs<Stmt>())); @@ -1535,7 +1534,7 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr,Scope *CurScope) { Action::OwningStmtResult Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprArg SynchExpr, StmtArg SynchBody) { - CurFunctionNeedsScopeChecking = true; + FunctionNeedsScopeChecking() = true; // Make sure the expression type is an ObjC pointer or "void *". Expr *SyncExpr = static_cast<Expr*>(SynchExpr.get()); @@ -1645,7 +1644,7 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, StmtArg TryBlock, // Neither of these are explicitly forbidden, but every compiler detects them // and warns. - CurFunctionNeedsScopeChecking = true; + FunctionNeedsScopeChecking() = true; RawHandlers.release(); return Owned(CXXTryStmt::Create(Context, TryLoc, static_cast<Stmt*>(TryBlock.release()), diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 10e411f..0321958 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3242,6 +3242,23 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs( return false; } +/// \brief Retrieve the previous declaration of the given declaration. +static NamedDecl *getPreviousDecl(NamedDecl *ND) { + if (VarDecl *VD = dyn_cast<VarDecl>(ND)) + return VD->getPreviousDeclaration(); + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) + return FD->getPreviousDeclaration(); + if (TagDecl *TD = dyn_cast<TagDecl>(ND)) + return TD->getPreviousDeclaration(); + if (TypedefDecl *TD = dyn_cast<TypedefDecl>(ND)) + return TD->getPreviousDeclaration(); + if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND)) + return FTD->getPreviousDeclaration(); + if (ClassTemplateDecl *CTD = dyn_cast<ClassTemplateDecl>(ND)) + return CTD->getPreviousDeclaration(); + return 0; +} + Sema::DeclResult Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, @@ -3547,15 +3564,26 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // instantiation to take place, in every translation unit in which such a // use occurs; no diagnostic is required. if (PrevDecl && PrevDecl->getPointOfInstantiation().isValid()) { - SourceRange Range(TemplateNameLoc, RAngleLoc); - Diag(TemplateNameLoc, diag::err_specialization_after_instantiation) - << Context.getTypeDeclType(Specialization) << Range; + bool Okay = false; + for (NamedDecl *Prev = PrevDecl; Prev; Prev = getPreviousDecl(Prev)) { + // Is there any previous explicit specialization declaration? + if (getTemplateSpecializationKind(Prev) == TSK_ExplicitSpecialization) { + Okay = true; + break; + } + } - Diag(PrevDecl->getPointOfInstantiation(), - diag::note_instantiation_required_here) - << (PrevDecl->getTemplateSpecializationKind() + if (!Okay) { + SourceRange Range(TemplateNameLoc, RAngleLoc); + Diag(TemplateNameLoc, diag::err_specialization_after_instantiation) + << Context.getTypeDeclType(Specialization) << Range; + + Diag(PrevDecl->getPointOfInstantiation(), + diag::note_instantiation_required_here) + << (PrevDecl->getTemplateSpecializationKind() != TSK_ImplicitInstantiation); - return true; + return true; + } } // If this is not a friend, note that this is an explicit specialization. @@ -3728,6 +3756,12 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, // before the first use of that specialization that would cause an // implicit instantiation to take place, in every translation unit in // which such a use occurs; no diagnostic is required. + for (NamedDecl *Prev = PrevDecl; Prev; Prev = getPreviousDecl(Prev)) { + // Is there any previous explicit specialization declaration? + if (getTemplateSpecializationKind(Prev) == TSK_ExplicitSpecialization) + return false; + } + Diag(NewLoc, diag::err_specialization_after_instantiation) << PrevDecl; Diag(PrevPointOfInstantiation, diag::note_instantiation_required_here) @@ -3756,6 +3790,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, // of a template appears after a declaration of an explicit // specialization for that template, the explicit instantiation has no // effect. + SuppressNew = true; return false; case TSK_ExplicitInstantiationDefinition: @@ -4911,18 +4946,21 @@ 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 TransformTypenameType(TypeLocBuilder &TLB, TypenameTypeLoc TL, + QualType ObjectType); }; } QualType CurrentInstantiationRebuilder::TransformTypenameType(TypeLocBuilder &TLB, - TypenameTypeLoc TL) { + TypenameTypeLoc TL, + QualType ObjectType) { TypenameType *T = TL.getTypePtr(); NestedNameSpecifier *NNS = TransformNestedNameSpecifier(T->getQualifier(), - /*FIXME:*/SourceRange(getBaseLocation())); + /*FIXME:*/SourceRange(getBaseLocation()), + ObjectType); if (!NNS) return QualType(); diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index df4d4a8..7f16400 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -2419,6 +2419,27 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, OnlyDeduced, Depth, Used); break; + case Type::TypeOf: + if (!OnlyDeduced) + MarkUsedTemplateParameters(SemaRef, + cast<TypeOfType>(T)->getUnderlyingType(), + OnlyDeduced, Depth, Used); + break; + + case Type::TypeOfExpr: + if (!OnlyDeduced) + MarkUsedTemplateParameters(SemaRef, + cast<TypeOfExprType>(T)->getUnderlyingExpr(), + OnlyDeduced, Depth, Used); + break; + + case Type::Decltype: + if (!OnlyDeduced) + MarkUsedTemplateParameters(SemaRef, + cast<DecltypeType>(T)->getUnderlyingExpr(), + OnlyDeduced, Depth, Used); + break; + // None of these types have any template parameters in them. case Type::Builtin: case Type::VariableArray: diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 51e17fe..8f73337 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -540,11 +540,11 @@ namespace { /// \brief Transform the given declaration by instantiating a reference to /// this declaration. - Decl *TransformDecl(Decl *D); + Decl *TransformDecl(SourceLocation Loc, Decl *D); /// \brief Transform the definition of the given declaration by /// instantiating it. - Decl *TransformDefinition(Decl *D); + Decl *TransformDefinition(SourceLocation Loc, Decl *D); /// \bried Transform the first qualifier within a scope by instantiating the /// declaration. @@ -570,11 +570,12 @@ namespace { /// \brief Transforms a template type parameter type by performing /// substitution of the corresponding template type argument. QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, - TemplateTypeParmTypeLoc TL); + TemplateTypeParmTypeLoc TL, + QualType ObjectType); }; } -Decl *TemplateInstantiator::TransformDecl(Decl *D) { +Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) { if (!D) return 0; @@ -599,10 +600,10 @@ Decl *TemplateInstantiator::TransformDecl(Decl *D) { // template parameter. } - return SemaRef.FindInstantiatedDecl(cast<NamedDecl>(D), TemplateArgs); + return SemaRef.FindInstantiatedDecl(Loc, cast<NamedDecl>(D), TemplateArgs); } -Decl *TemplateInstantiator::TransformDefinition(Decl *D) { +Decl *TemplateInstantiator::TransformDefinition(SourceLocation Loc, Decl *D) { Decl *Inst = getSema().SubstDecl(D, getSema().CurContext, TemplateArgs); if (!Inst) return 0; @@ -622,7 +623,7 @@ TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D, if (TTP->getDepth() < TemplateArgs.getNumLevels()) { QualType T = TemplateArgs(TTP->getDepth(), TTP->getIndex()).getAsType(); if (T.isNull()) - return cast_or_null<NamedDecl>(TransformDecl(D)); + return cast_or_null<NamedDecl>(TransformDecl(Loc, D)); if (const TagType *Tag = T->getAs<TagType>()) return Tag->getDecl(); @@ -633,7 +634,7 @@ TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D, } } - return cast_or_null<NamedDecl>(TransformDecl(D)); + return cast_or_null<NamedDecl>(TransformDecl(Loc, D)); } VarDecl * @@ -723,7 +724,8 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, // Find the instantiation of the template argument. This is // required for nested templates. VD = cast_or_null<ValueDecl>( - getSema().FindInstantiatedDecl(VD, TemplateArgs)); + getSema().FindInstantiatedDecl(E->getLocation(), + VD, TemplateArgs)); if (!VD) return SemaRef.ExprError(); @@ -859,7 +861,8 @@ Sema::OwningExprResult TemplateInstantiator::TransformCXXDefaultArgExpr( QualType TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, - TemplateTypeParmTypeLoc TL) { + TemplateTypeParmTypeLoc TL, + QualType ObjectType) { TemplateTypeParmType *T = TL.getTypePtr(); if (T->getDepth() < TemplateArgs.getNumLevels()) { // Replace the template type parameter with its corresponding diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 0b0efcb..3a6b4cb 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -162,7 +162,8 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { Typedef->setInvalidDecl(); if (TypedefDecl *Prev = D->getPreviousDeclaration()) { - NamedDecl *InstPrev = SemaRef.FindInstantiatedDecl(Prev, TemplateArgs); + NamedDecl *InstPrev = SemaRef.FindInstantiatedDecl(D->getLocation(), Prev, + TemplateArgs); Typedef->setPreviousDeclaration(cast<TypedefDecl>(InstPrev)); } @@ -201,6 +202,72 @@ static bool InstantiateInitializationArguments(Sema &SemaRef, return false; } +/// \brief Instantiate an initializer, breaking it into separate +/// initialization arguments. +/// +/// \param S The semantic analysis object. +/// +/// \param Init The initializer to instantiate. +/// +/// \param TemplateArgs Template arguments to be substituted into the +/// initializer. +/// +/// \param NewArgs Will be filled in with the instantiation arguments. +/// +/// \returns true if an error occurred, false otherwise +static bool InstantiateInitializer(Sema &S, Expr *Init, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation &LParenLoc, + llvm::SmallVector<SourceLocation, 4> &CommaLocs, + ASTOwningVector<&ActionBase::DeleteExpr> &NewArgs, + SourceLocation &RParenLoc) { + NewArgs.clear(); + LParenLoc = SourceLocation(); + RParenLoc = SourceLocation(); + + if (!Init) + return false; + + if (CXXExprWithTemporaries *ExprTemp = dyn_cast<CXXExprWithTemporaries>(Init)) + Init = ExprTemp->getSubExpr(); + + while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(Init)) + Init = Binder->getSubExpr(); + + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Init)) + Init = ICE->getSubExprAsWritten(); + + if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) { + LParenLoc = ParenList->getLParenLoc(); + RParenLoc = ParenList->getRParenLoc(); + return InstantiateInitializationArguments(S, ParenList->getExprs(), + ParenList->getNumExprs(), + TemplateArgs, CommaLocs, + NewArgs); + } + + if (CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(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; + } + + Sema::OwningExprResult Result = S.SubstExpr(Init, TemplateArgs); + if (Result.isInvalid()) + return true; + + NewArgs.push_back(Result.takeAs<Expr>()); + return false; +} + Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // Do substitution on the type of the declaration TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(), @@ -232,7 +299,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { bool Redeclaration = false; // FIXME: having to fake up a LookupResult is dumb. LookupResult Previous(SemaRef, Var->getDeclName(), Var->getLocation(), - Sema::LookupOrdinaryName); + Sema::LookupOrdinaryName, Sema::ForRedeclaration); if (D->isStaticDataMember()) SemaRef.LookupQualifiedName(Previous, Owner, false); SemaRef.CheckVariableDeclaration(Var, Previous, Redeclaration); @@ -258,77 +325,33 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { else SemaRef.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated); - // Extract the initializer, skipping through any temporary-binding - // expressions and look at the subexpression as it was written. - Expr *DInit = D->getInit(); - if (CXXExprWithTemporaries *ExprTemp - = dyn_cast<CXXExprWithTemporaries>(DInit)) - DInit = ExprTemp->getSubExpr(); - while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(DInit)) - DInit = Binder->getSubExpr(); - if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(DInit)) - DInit = ICE->getSubExprAsWritten(); - - if (ParenListExpr *PLE = dyn_cast<ParenListExpr>(DInit)) { - // The initializer is a parenthesized list of expressions that is - // type-dependent. Instantiate each of the expressions; we'll be - // performing direct initialization with them. - llvm::SmallVector<SourceLocation, 4> CommaLocs; - ASTOwningVector<&ActionBase::DeleteExpr> InitArgs(SemaRef); - if (!InstantiateInitializationArguments(SemaRef, - PLE->getExprs(), - PLE->getNumExprs(), - TemplateArgs, - CommaLocs, InitArgs)) { + // Instantiate the initializer. + SourceLocation LParenLoc, RParenLoc; + llvm::SmallVector<SourceLocation, 4> CommaLocs; + ASTOwningVector<&ActionBase::DeleteExpr> InitArgs(SemaRef); + if (!InstantiateInitializer(SemaRef, D->getInit(), TemplateArgs, LParenLoc, + CommaLocs, InitArgs, RParenLoc)) { + // Attach the initializer to the declaration. + if (D->hasCXXDirectInitializer()) { // Add the direct initializer to the declaration. SemaRef.AddCXXDirectInitializerToDecl(Sema::DeclPtrTy::make(Var), - PLE->getLParenLoc(), + LParenLoc, move_arg(InitArgs), CommaLocs.data(), - PLE->getRParenLoc()); + RParenLoc); + } else if (InitArgs.size() == 1) { + Expr *Init = (Expr*)(InitArgs.take()[0]); + SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), + SemaRef.Owned(Init), + false); + } else { + assert(InitArgs.size() == 0); + SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false); } - } else if (CXXConstructExpr *Construct =dyn_cast<CXXConstructExpr>(DInit)) { - // The initializer resolved to a constructor. Instantiate the constructor - // arguments. - llvm::SmallVector<SourceLocation, 4> CommaLocs; - ASTOwningVector<&ActionBase::DeleteExpr> InitArgs(SemaRef); - - if (!InstantiateInitializationArguments(SemaRef, - Construct->getArgs(), - Construct->getNumArgs(), - TemplateArgs, - CommaLocs, InitArgs)) { - if (D->hasCXXDirectInitializer()) { - SourceLocation FakeLParenLoc = - SemaRef.PP.getLocForEndOfToken(D->getLocation()); - SourceLocation FakeRParenLoc = CommaLocs.empty()? FakeLParenLoc - : CommaLocs.back(); - SemaRef.AddCXXDirectInitializerToDecl(Sema::DeclPtrTy::make(Var), - FakeLParenLoc, - move_arg(InitArgs), - CommaLocs.data(), - FakeRParenLoc); - } else if (InitArgs.size() == 1) { - Expr *Init = (Expr*)(InitArgs.take()[0]); - SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), - SemaRef.Owned(Init), - false); - } else { - assert(InitArgs.size() == 0); - SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false); - } - } } else { - OwningExprResult Init - = SemaRef.SubstExpr(D->getInit(), TemplateArgs); - - // FIXME: Not happy about invalidating decls just because of a bad - // initializer, unless it affects the type. - if (Init.isInvalid()) - Var->setInvalidDecl(); - else - SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), move(Init), - D->hasCXXDirectInitializer()); + // FIXME: Not too happy about invalidating the declaration + // because of a bogus initializer. + Var->setInvalidDecl(); } SemaRef.PopExpressionEvaluationContext(); @@ -433,7 +456,8 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { // Hack to make this work almost well pending a rewrite. if (ND->getDeclContext()->isRecord()) { if (!ND->getDeclContext()->isDependentContext()) { - NewND = SemaRef.FindInstantiatedDecl(ND, TemplateArgs); + 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; @@ -489,6 +513,9 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { Owner->addDecl(Enum); Enum->startDefinition(); + if (D->getDeclContext()->isFunctionOrMethod()) + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum); + llvm::SmallVector<Sema::DeclPtrTy, 4> Enumerators; EnumConstantDecl *LastEnumConst = 0; @@ -528,6 +555,12 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { Enum->addDecl(EnumConst); Enumerators.push_back(Sema::DeclPtrTy::make(EnumConst)); LastEnumConst = EnumConst; + + if (D->getDeclContext()->isFunctionOrMethod()) { + // If the enumeration is within a function or method, record the enum + // constant as a local. + SemaRef.CurrentInstantiationScope->InstantiatedLocal(*EC, EnumConst); + } } } @@ -699,7 +732,8 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { if (D->isInjectedClassName()) PrevDecl = cast<CXXRecordDecl>(Owner); else if (D->getPreviousDeclaration()) { - NamedDecl *Prev = SemaRef.FindInstantiatedDecl(D->getPreviousDeclaration(), + NamedDecl *Prev = SemaRef.FindInstantiatedDecl(D->getLocation(), + D->getPreviousDeclaration(), TemplateArgs); if (!Prev) return 0; PrevDecl = cast<CXXRecordDecl>(Prev); @@ -772,7 +806,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, if (D->getDeclContext()->isFunctionOrMethod()) DC = Owner; else - DC = SemaRef.FindInstantiatedContext(D->getDeclContext(), TemplateArgs); + DC = SemaRef.FindInstantiatedContext(D->getLocation(), D->getDeclContext(), + TemplateArgs); FunctionDecl *Function = FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(), @@ -1228,7 +1263,8 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { I != E; ++I) { UsingShadowDecl *Shadow = *I; NamedDecl *InstTarget = - cast<NamedDecl>(SemaRef.FindInstantiatedDecl(Shadow->getTargetDecl(), + cast<NamedDecl>(SemaRef.FindInstantiatedDecl(Shadow->getLocation(), + Shadow->getTargetDecl(), TemplateArgs)); if (CheckRedeclaration && @@ -1304,6 +1340,9 @@ Decl * TemplateDeclInstantiator Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner, const MultiLevelTemplateArgumentList &TemplateArgs) { TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs); + if (D->isInvalidDecl()) + return 0; + return Instantiator.Visit(D); } @@ -1871,29 +1910,15 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, Inits != InitsEnd; ++Inits) { CXXBaseOrMemberInitializer *Init = *Inits; + SourceLocation LParenLoc, RParenLoc; ASTOwningVector<&ActionBase::DeleteExpr> NewArgs(*this); llvm::SmallVector<SourceLocation, 4> CommaLocs; - // Instantiate all the arguments. - Expr *InitE = Init->getInit(); - if (!InitE) { - // Nothing to instantiate; - } else if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(InitE)) { - if (InstantiateInitializationArguments(*this, ParenList->getExprs(), - ParenList->getNumExprs(), - TemplateArgs, CommaLocs, - NewArgs)) { - AnyErrors = true; - continue; - } - } else { - OwningExprResult InitArg = SubstExpr(InitE, TemplateArgs); - if (InitArg.isInvalid()) { - AnyErrors = true; - continue; - } - - NewArgs.push_back(InitArg.release()); + // Instantiate the initializer. + if (InstantiateInitializer(*this, Init->getInit(), TemplateArgs, + LParenLoc, CommaLocs, NewArgs, RParenLoc)) { + AnyErrors = true; + continue; } MemInitResult NewInit; @@ -1919,9 +1944,11 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, // Is this an anonymous union? if (FieldDecl *UnionInit = Init->getAnonUnionMember()) - Member = cast<FieldDecl>(FindInstantiatedDecl(UnionInit, TemplateArgs)); + Member = cast<FieldDecl>(FindInstantiatedDecl(Init->getMemberLocation(), + UnionInit, TemplateArgs)); else - Member = cast<FieldDecl>(FindInstantiatedDecl(Init->getMember(), + Member = cast<FieldDecl>(FindInstantiatedDecl(Init->getMemberLocation(), + Init->getMember(), TemplateArgs)); NewInit = BuildMemberInitializer(Member, (Expr **)NewArgs.data(), @@ -2151,10 +2178,10 @@ static NamedDecl *findInstantiationOf(ASTContext &Ctx, /// within the current instantiation. /// /// \returns NULL if there was an error -DeclContext *Sema::FindInstantiatedContext(DeclContext* DC, +DeclContext *Sema::FindInstantiatedContext(SourceLocation Loc, DeclContext* DC, const MultiLevelTemplateArgumentList &TemplateArgs) { if (NamedDecl *D = dyn_cast<NamedDecl>(DC)) { - Decl* ID = FindInstantiatedDecl(D, TemplateArgs); + Decl* ID = FindInstantiatedDecl(Loc, D, TemplateArgs); return cast_or_null<DeclContext>(ID); } else return DC; } @@ -2185,7 +2212,7 @@ DeclContext *Sema::FindInstantiatedContext(DeclContext* DC, /// X<T>::<Kind>::KnownValue) to its instantiation /// (X<int>::<Kind>::KnownValue). InstantiateCurrentDeclRef() performs /// this mapping from within the instantiation of X<int>. -NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D, +NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs) { DeclContext *ParentDC = D->getDeclContext(); if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) || @@ -2272,7 +2299,7 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D, if (!ParentDC->isDependentContext()) return D; - ParentDC = FindInstantiatedContext(ParentDC, TemplateArgs); + ParentDC = FindInstantiatedContext(Loc, ParentDC, TemplateArgs); if (!ParentDC) return 0; @@ -2280,6 +2307,20 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D, // We performed some kind of instantiation in the parent context, // so now we need to look into the instantiated parent context to // find the instantiation of the declaration D. + + // If our context is a class template specialization, we may need + // to instantiate it before performing lookup into that context. + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(ParentDC)) { + if (!Spec->isDependentContext()) { + QualType T = Context.getTypeDeclType(Spec); + if (const TagType *Tag = T->getAs<TagType>()) + if (!Tag->isBeingDefined() && + RequireCompleteType(Loc, T, diag::err_incomplete_type)) + return 0; + } + } + NamedDecl *Result = 0; if (D->getDeclName()) { DeclContext::lookup_result Found = ParentDC->lookup(D->getDeclName()); @@ -2299,7 +2340,8 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D, } // UsingShadowDecls can instantiate to nothing because of using hiding. - assert((Result || isa<UsingShadowDecl>(D)) + assert((Result || isa<UsingShadowDecl>(D) || D->isInvalidDecl() || + cast<Decl>(ParentDC)->isInvalidDecl()) && "Unable to find instantiation of declaration!"); D = Result; diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 7911e76..2fb5c84 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -72,6 +72,7 @@ typedef std::pair<const AttributeList*,QualType> DelayedAttribute; typedef llvm::SmallVectorImpl<DelayedAttribute> DelayedAttributeSet; static void ProcessTypeAttributeList(Sema &S, QualType &Type, + bool IsDeclSpec, const AttributeList *Attrs, DelayedAttributeSet &DelayedFnAttrs); static bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr); @@ -385,7 +386,7 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, // See if there are any attributes on the declspec that apply to the type (as // opposed to the decl). if (const AttributeList *AL = DS.getAttributes()) - ProcessTypeAttributeList(TheSema, Result, AL, Delayed); + ProcessTypeAttributeList(TheSema, Result, true, AL, Delayed); // Apply const/volatile/restrict qualifiers to T. if (unsigned TypeQuals = DS.getTypeQualifiers()) { @@ -797,7 +798,7 @@ QualType Sema::BuildFunctionType(QualType T, return QualType(); return Context.getFunctionType(T, ParamTypes, NumParamTypes, Variadic, - Quals); + Quals, false, false, 0, 0, false, CC_Default); } /// \brief Build a member pointer type \c T Class::*. @@ -1132,7 +1133,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic, FTI.TypeQuals, FTI.hasExceptionSpec, FTI.hasAnyExceptionSpec, - Exceptions.size(), Exceptions.data()); + Exceptions.size(), Exceptions.data(), + false, CC_Default); } else if (FTI.isVariadic) { // We allow a zero-parameter variadic function in C if the // function is marked with the "overloadable" @@ -1148,7 +1150,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); + T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic, 0, + false, false, 0, 0, false, CC_Default); } else { // Simple void foo(), where the incoming T is the result type. T = Context.getFunctionNoProtoType(T); @@ -1223,7 +1226,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, FTI.isVariadic, FTI.TypeQuals, FTI.hasExceptionSpec, FTI.hasAnyExceptionSpec, - Exceptions.size(), Exceptions.data()); + Exceptions.size(), Exceptions.data(), + false, CC_Default); } // For GCC compatibility, we allow attributes that apply only to @@ -1294,7 +1298,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // See if there are any attributes on this declarator chunk. if (const AttributeList *AL = DeclType.getAttrs()) - ProcessTypeAttributeList(*this, T, AL, FnAttrsFromPreviousChunk); + ProcessTypeAttributeList(*this, T, false, AL, FnAttrsFromPreviousChunk); } if (getLangOptions().CPlusPlus && T->isFunctionType()) { @@ -1320,7 +1324,8 @@ 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); + FnTy->getNumArgs(), FnTy->isVariadic(), 0, + false, false, 0, 0, false, CC_Default); } } @@ -1333,7 +1338,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // block-literal expressions, which are parsed wierdly. if (D.getContext() != Declarator::BlockLiteralContext) if (const AttributeList *Attrs = D.getAttributes()) - ProcessTypeAttributeList(*this, T, Attrs, FnAttrsFromPreviousChunk); + ProcessTypeAttributeList(*this, T, false, Attrs, + FnAttrsFromPreviousChunk); DiagnoseDelayedFnAttrs(*this, FnAttrsFromPreviousChunk); @@ -1751,7 +1757,8 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { } CallingConv CCOld = Fn->getCallConv(); - if (CC == CCOld) return false; + if (S.Context.getCanonicalCallConv(CC) == + S.Context.getCanonicalCallConv(CCOld)) return false; if (CCOld != CC_Default) { // Should we diagnose reapplications of the same convention? @@ -1829,7 +1836,7 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S } void ProcessTypeAttributeList(Sema &S, QualType &Result, - const AttributeList *AL, + bool IsDeclSpec, const AttributeList *AL, DelayedAttributeSet &FnAttrs) { // Scan through and apply attributes to this type where it makes sense. Some // attributes (such as __address_space__, __vector_size__, etc) apply to the @@ -1855,7 +1862,9 @@ void ProcessTypeAttributeList(Sema &S, QualType &Result, case AttributeList::AT_cdecl: case AttributeList::AT_fastcall: case AttributeList::AT_stdcall: - if (ProcessFnAttr(S, Result, *AL)) + // Don't process these on the DeclSpec. + if (IsDeclSpec || + ProcessFnAttr(S, Result, *AL)) FnAttrs.push_back(DelayedAttribute(AL, Result)); break; } diff --git a/lib/Sema/TargetAttributesSema.cpp b/lib/Sema/TargetAttributesSema.cpp index d45d010..87e7b9d 100644 --- a/lib/Sema/TargetAttributesSema.cpp +++ b/lib/Sema/TargetAttributesSema.cpp @@ -79,14 +79,17 @@ static void HandleX86ForceAlignArgPointerAttr(Decl *D, return; } - // If we try to apply it to a function pointer, warn. This is a special - // instance of the warn_attribute_ignored warning that can be turned - // off with -Wno-force-align-arg-pointer. - ValueDecl* VD = dyn_cast<ValueDecl>(D); - if (VD && VD->getType()->isFunctionPointerType()) { - S.Diag(Attr.getLoc(), diag::warn_faap_attribute_ignored); + // If we try to apply it to a function pointer, don't warn, but don't + // do anything, either. It doesn't matter anyway, because there's nothing + // special about calling a force_align_arg_pointer function. + ValueDecl *VD = dyn_cast<ValueDecl>(D); + if (VD && VD->getType()->isFunctionPointerType()) + return; + // Also don't warn on function pointer typedefs. + TypedefDecl *TD = dyn_cast<TypedefDecl>(D); + if (TD && (TD->getUnderlyingType()->isFunctionPointerType() || + TD->getUnderlyingType()->isFunctionType())) return; - } // Attribute can only be applied to function types. if (!isa<FunctionDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) @@ -97,13 +100,106 @@ static void HandleX86ForceAlignArgPointerAttr(Decl *D, D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr()); } +static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { + // check the attribute arguments. + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return; + } + + // Attribute can be applied only to functions or variables. + if (isa<VarDecl>(D)) { + D->addAttr(::new (S.Context) DLLImportAttr()); + return; + } + + FunctionDecl *FD = dyn_cast<FunctionDecl>(D); + if (!FD) { + // Apparently Visual C++ thinks it is okay to not emit a warning + // in this case, so only emit a warning when -fms-extensions is not + // specified. + if (!S.getLangOptions().Microsoft) + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 2 /*variable and function*/; + return; + } + + // Currently, the dllimport attribute is ignored for inlined functions. + // Warning is emitted. + if (FD->isInlineSpecified()) { + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport"; + return; + } + + // The attribute is also overridden by a subsequent declaration as dllexport. + // Warning is emitted. + for (AttributeList *nextAttr = Attr.getNext(); nextAttr; + nextAttr = nextAttr->getNext()) { + if (nextAttr->getKind() == AttributeList::AT_dllexport) { + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport"; + return; + } + } + + if (D->getAttr<DLLExportAttr>()) { + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport"; + return; + } + + D->addAttr(::new (S.Context) DLLImportAttr()); +} + +static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) { + // check the attribute arguments. + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return; + } + + // Attribute can be applied only to functions or variables. + if (isa<VarDecl>(D)) { + D->addAttr(::new (S.Context) DLLExportAttr()); + return; + } + + FunctionDecl *FD = dyn_cast<FunctionDecl>(D); + if (!FD) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 2 /*variable and function*/; + return; + } + + // Currently, the dllexport attribute is ignored for inlined functions, unless + // the -fkeep-inline-functions flag has been used. Warning is emitted; + if (FD->isInlineSpecified()) { + // FIXME: ... unless the -fkeep-inline-functions flag has been used. + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport"; + return; + } + + D->addAttr(::new (S.Context) DLLExportAttr()); +} + namespace { class X86AttributesSema : public TargetAttributesSema { public: X86AttributesSema() { } bool ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr, Sema &S) const { - if (Attr.getName()->getName() == "force_align_arg_pointer") { + const llvm::Triple &Triple(S.Context.Target.getTriple()); + if (Triple.getOS() == llvm::Triple::Win32 || + Triple.getOS() == llvm::Triple::MinGW32 || + Triple.getOS() == llvm::Triple::MinGW64) { + switch (Attr.getKind()) { + case AttributeList::AT_dllimport: HandleDLLImportAttr(D, Attr, S); + return true; + case AttributeList::AT_dllexport: HandleDLLExportAttr(D, Attr, S); + return true; + default: break; + } + } + if (Attr.getName()->getName() == "force_align_arg_pointer" || + Attr.getName()->getName() == "__force_align_arg_pointer__") { HandleX86ForceAlignArgPointerAttr(D, Attr, S); return true; } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index fc069f7..2f3c482 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -191,7 +191,7 @@ public: /// switched to storing TypeSourceInfos. /// /// \returns the transformed type. - QualType TransformType(QualType T); + QualType TransformType(QualType T, QualType ObjectType = QualType()); /// \brief Transforms the given type-with-location into a new /// type-with-location. @@ -201,13 +201,15 @@ public: /// may override this function (to take over all type /// transformations) or some set of the TransformXXXType functions /// to alter the transformation. - TypeSourceInfo *TransformType(TypeSourceInfo *DI); + TypeSourceInfo *TransformType(TypeSourceInfo *DI, + QualType ObjectType = QualType()); /// \brief Transform the given type-with-location into a new /// type, collecting location information in the given builder /// as necessary. /// - QualType TransformType(TypeLocBuilder &TLB, TypeLoc TL); + QualType TransformType(TypeLocBuilder &TLB, TypeLoc TL, + QualType ObjectType = QualType()); /// \brief Transform the given statement. /// @@ -235,13 +237,15 @@ public: /// /// By default, acts as the identity function on declarations. Subclasses /// may override this function to provide alternate behavior. - Decl *TransformDecl(Decl *D) { return D; } + Decl *TransformDecl(SourceLocation Loc, Decl *D) { return D; } /// \brief Transform the definition of the given declaration. /// /// By default, invokes TransformDecl() to transform the declaration. /// Subclasses may override this function to provide alternate behavior. - Decl *TransformDefinition(Decl *D) { return getDerived().TransformDecl(D); } + Decl *TransformDefinition(SourceLocation Loc, Decl *D) { + return getDerived().TransformDecl(Loc, D); + } /// \brief Transform the given declaration, which was the first part of a /// nested-name-specifier in a member access expression. @@ -253,7 +257,7 @@ public: /// By default, invokes TransformDecl() to transform the declaration. /// Subclasses may override this function to provide alternate behavior. NamedDecl *TransformFirstQualifierInScope(NamedDecl *D, SourceLocation Loc) { - return cast_or_null<NamedDecl>(getDerived().TransformDecl(D)); + return cast_or_null<NamedDecl>(getDerived().TransformDecl(Loc, D)); } /// \brief Transform the given nested-name-specifier. @@ -307,20 +311,17 @@ public: #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ - QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T); + QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T, \ + QualType ObjectType = QualType()); #include "clang/AST/TypeLocNodes.def" - QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL); + QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL, + QualType ObjectType); QualType TransformTemplateSpecializationType(const TemplateSpecializationType *T, QualType ObjectType); - QualType - TransformTemplateSpecializationType(TypeLocBuilder &TLB, - TemplateSpecializationTypeLoc TL, - QualType ObjectType); - OwningStmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr); #define STMT(Node, Parent) \ @@ -882,28 +883,12 @@ public: OwningExprResult RebuildCXXPseudoDestructorExpr(ExprArg Base, SourceLocation OperatorLoc, bool isArrow, - SourceLocation DestroyedTypeLoc, - QualType DestroyedType, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange) { - CXXScopeSpec SS; - if (Qualifier) { - SS.setRange(QualifierRange); - SS.setScopeRep(Qualifier); - } - - QualType BaseType = ((Expr*) Base.get())->getType(); - - DeclarationName Name - = SemaRef.Context.DeclarationNames.getCXXDestructorName( - SemaRef.Context.getCanonicalType(DestroyedType)); - - return getSema().BuildMemberReferenceExpr(move(Base), BaseType, - OperatorLoc, isArrow, - SS, /*FIXME: FirstQualifier*/ 0, - Name, DestroyedTypeLoc, - /*TemplateArgs*/ 0); - } + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + TypeSourceInfo *ScopeType, + SourceLocation CCLoc, + SourceLocation TildeLoc, + PseudoDestructorTypeStorage Destroyed); /// \brief Build a new unary operator expression. /// @@ -1762,7 +1747,8 @@ TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS, case NestedNameSpecifier::Namespace: { NamespaceDecl *NS = cast_or_null<NamespaceDecl>( - getDerived().TransformDecl(NNS->getAsNamespace())); + getDerived().TransformDecl(Range.getBegin(), + NNS->getAsNamespace())); if (!getDerived().AlwaysRebuild() && Prefix == NNS->getPrefix() && NS == NNS->getAsNamespace()) @@ -1779,7 +1765,8 @@ TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS, case NestedNameSpecifier::TypeSpecWithTemplate: case NestedNameSpecifier::TypeSpec: { TemporaryBase Rebase(*this, Range.getBegin(), DeclarationName()); - QualType T = getDerived().TransformType(QualType(NNS->getAsType(), 0)); + QualType T = getDerived().TransformType(QualType(NNS->getAsType(), 0), + ObjectType); if (T.isNull()) return 0; @@ -1820,14 +1807,8 @@ TreeTransform<Derived>::TransformDeclarationName(DeclarationName Name, case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: { TemporaryBase Rebase(*this, Loc, Name); - QualType T; - if (!ObjectType.isNull() && - isa<TemplateSpecializationType>(Name.getCXXNameType())) { - TemplateSpecializationType *SpecType - = cast<TemplateSpecializationType>(Name.getCXXNameType()); - T = TransformTemplateSpecializationType(SpecType, ObjectType); - } else - T = getDerived().TransformType(Name.getCXXNameType()); + QualType T = getDerived().TransformType(Name.getCXXNameType(), + ObjectType); if (T.isNull()) return DeclarationName(); @@ -1844,16 +1825,19 @@ template<typename Derived> TemplateName TreeTransform<Derived>::TransformTemplateName(TemplateName Name, QualType ObjectType) { + SourceLocation Loc = getDerived().getBaseLocation(); + if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) { NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(QTN->getQualifier(), - /*FIXME:*/SourceRange(getDerived().getBaseLocation())); + /*FIXME:*/SourceRange(getDerived().getBaseLocation()), + ObjectType); if (!NNS) return TemplateName(); if (TemplateDecl *Template = QTN->getTemplateDecl()) { TemplateDecl *TransTemplate - = cast_or_null<TemplateDecl>(getDerived().TransformDecl(Template)); + = cast_or_null<TemplateDecl>(getDerived().TransformDecl(Loc, Template)); if (!TransTemplate) return TemplateName(); @@ -1873,7 +1857,8 @@ TreeTransform<Derived>::TransformTemplateName(TemplateName Name, if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(DTN->getQualifier(), - /*FIXME:*/SourceRange(getDerived().getBaseLocation())); + /*FIXME:*/SourceRange(getDerived().getBaseLocation()), + ObjectType); if (!NNS && DTN->getQualifier()) return TemplateName(); @@ -1892,7 +1877,7 @@ TreeTransform<Derived>::TransformTemplateName(TemplateName Name, if (TemplateDecl *Template = Name.getAsTemplateDecl()) { TemplateDecl *TransTemplate - = cast_or_null<TemplateDecl>(getDerived().TransformDecl(Template)); + = cast_or_null<TemplateDecl>(getDerived().TransformDecl(Loc, Template)); if (!TransTemplate) return TemplateName(); @@ -1969,7 +1954,7 @@ bool TreeTransform<Derived>::TransformTemplateArgument( if (NamedDecl *ND = dyn_cast<NamedDecl>(Arg.getAsDecl())) Name = ND->getDeclName(); TemporaryBase Rebase(*this, Input.getLocation(), Name); - Decl *D = getDerived().TransformDecl(Arg.getAsDecl()); + Decl *D = getDerived().TransformDecl(Input.getLocation(), Arg.getAsDecl()); if (!D) return true; Expr *SourceExpr = Input.getSourceDeclExpression(); @@ -2055,7 +2040,8 @@ bool TreeTransform<Derived>::TransformTemplateArgument( //===----------------------------------------------------------------------===// template<typename Derived> -QualType TreeTransform<Derived>::TransformType(QualType T) { +QualType TreeTransform<Derived>::TransformType(QualType T, + QualType ObjectType) { if (getDerived().AlreadyTransformed(T)) return T; @@ -2064,7 +2050,7 @@ QualType TreeTransform<Derived>::TransformType(QualType T) { TypeSourceInfo *DI = getSema().Context.CreateTypeSourceInfo(T); DI->getTypeLoc().initialize(getDerived().getBaseLocation()); - TypeSourceInfo *NewDI = getDerived().TransformType(DI); + TypeSourceInfo *NewDI = getDerived().TransformType(DI, ObjectType); if (!NewDI) return QualType(); @@ -2073,7 +2059,8 @@ QualType TreeTransform<Derived>::TransformType(QualType T) { } template<typename Derived> -TypeSourceInfo *TreeTransform<Derived>::TransformType(TypeSourceInfo *DI) { +TypeSourceInfo *TreeTransform<Derived>::TransformType(TypeSourceInfo *DI, + QualType ObjectType) { if (getDerived().AlreadyTransformed(DI->getType())) return DI; @@ -2082,7 +2069,7 @@ TypeSourceInfo *TreeTransform<Derived>::TransformType(TypeSourceInfo *DI) { TypeLoc TL = DI->getTypeLoc(); TLB.reserve(TL.getFullDataSize()); - QualType Result = getDerived().TransformType(TLB, TL); + QualType Result = getDerived().TransformType(TLB, TL, ObjectType); if (Result.isNull()) return 0; @@ -2091,12 +2078,14 @@ TypeSourceInfo *TreeTransform<Derived>::TransformType(TypeSourceInfo *DI) { template<typename Derived> QualType -TreeTransform<Derived>::TransformType(TypeLocBuilder &TLB, TypeLoc T) { +TreeTransform<Derived>::TransformType(TypeLocBuilder &TLB, TypeLoc T, + QualType ObjectType) { switch (T.getTypeLocClass()) { #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ case TypeLoc::CLASS: \ - return getDerived().Transform##CLASS##Type(TLB, cast<CLASS##TypeLoc>(T)); + return getDerived().Transform##CLASS##Type(TLB, cast<CLASS##TypeLoc>(T), \ + ObjectType); #include "clang/AST/TypeLocNodes.def" } @@ -2112,10 +2101,12 @@ TreeTransform<Derived>::TransformType(TypeLocBuilder &TLB, TypeLoc T) { template<typename Derived> QualType TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB, - QualifiedTypeLoc T) { + QualifiedTypeLoc T, + QualType ObjectType) { Qualifiers Quals = T.getType().getLocalQualifiers(); - QualType Result = getDerived().TransformType(TLB, T.getUnqualifiedLoc()); + QualType Result = getDerived().TransformType(TLB, T.getUnqualifiedLoc(), + ObjectType); if (Result.isNull()) return QualType(); @@ -2166,7 +2157,8 @@ QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) { template<typename Derived> QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB, - BuiltinTypeLoc T) { + BuiltinTypeLoc T, + QualType ObjectType) { BuiltinTypeLoc NewT = TLB.push<BuiltinTypeLoc>(T.getType()); NewT.setBuiltinLoc(T.getBuiltinLoc()); if (T.needsExtraLocalData()) @@ -2176,21 +2168,24 @@ QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformComplexType(TypeLocBuilder &TLB, - ComplexTypeLoc T) { + ComplexTypeLoc T, + QualType ObjectType) { // FIXME: recurse? return TransformTypeSpecType(TLB, T); } template<typename Derived> QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB, - PointerTypeLoc TL) { + PointerTypeLoc TL, + QualType ObjectType) { TransformPointerLikeType(PointerType); } template<typename Derived> QualType TreeTransform<Derived>::TransformBlockPointerType(TypeLocBuilder &TLB, - BlockPointerTypeLoc TL) { + BlockPointerTypeLoc TL, + QualType ObjectType) { TransformPointerLikeType(BlockPointerType); } @@ -2201,7 +2196,8 @@ TreeTransform<Derived>::TransformBlockPointerType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformReferenceType(TypeLocBuilder &TLB, - ReferenceTypeLoc TL) { + ReferenceTypeLoc TL, + QualType ObjectType) { const ReferenceType *T = TL.getTypePtr(); // Note that this works with the pointee-as-written. @@ -2233,21 +2229,24 @@ TreeTransform<Derived>::TransformReferenceType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformLValueReferenceType(TypeLocBuilder &TLB, - LValueReferenceTypeLoc TL) { - return TransformReferenceType(TLB, TL); + LValueReferenceTypeLoc TL, + QualType ObjectType) { + return TransformReferenceType(TLB, TL, ObjectType); } template<typename Derived> QualType TreeTransform<Derived>::TransformRValueReferenceType(TypeLocBuilder &TLB, - RValueReferenceTypeLoc TL) { - return TransformReferenceType(TLB, TL); + RValueReferenceTypeLoc TL, + QualType ObjectType) { + return TransformReferenceType(TLB, TL, ObjectType); } template<typename Derived> QualType TreeTransform<Derived>::TransformMemberPointerType(TypeLocBuilder &TLB, - MemberPointerTypeLoc TL) { + MemberPointerTypeLoc TL, + QualType ObjectType) { MemberPointerType *T = TL.getTypePtr(); QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc()); @@ -2279,7 +2278,8 @@ TreeTransform<Derived>::TransformMemberPointerType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformConstantArrayType(TypeLocBuilder &TLB, - ConstantArrayTypeLoc TL) { + ConstantArrayTypeLoc TL, + QualType ObjectType) { ConstantArrayType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) @@ -2314,7 +2314,8 @@ TreeTransform<Derived>::TransformConstantArrayType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformIncompleteArrayType( TypeLocBuilder &TLB, - IncompleteArrayTypeLoc TL) { + IncompleteArrayTypeLoc TL, + QualType ObjectType) { IncompleteArrayType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) @@ -2342,7 +2343,8 @@ QualType TreeTransform<Derived>::TransformIncompleteArrayType( template<typename Derived> QualType TreeTransform<Derived>::TransformVariableArrayType(TypeLocBuilder &TLB, - VariableArrayTypeLoc TL) { + VariableArrayTypeLoc TL, + QualType ObjectType) { VariableArrayType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) @@ -2383,7 +2385,8 @@ TreeTransform<Derived>::TransformVariableArrayType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformDependentSizedArrayType(TypeLocBuilder &TLB, - DependentSizedArrayTypeLoc TL) { + DependentSizedArrayTypeLoc TL, + QualType ObjectType) { DependentSizedArrayType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) @@ -2426,7 +2429,8 @@ TreeTransform<Derived>::TransformDependentSizedArrayType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType( TypeLocBuilder &TLB, - DependentSizedExtVectorTypeLoc TL) { + DependentSizedExtVectorTypeLoc TL, + QualType ObjectType) { DependentSizedExtVectorType *T = TL.getTypePtr(); // FIXME: ext vector locs should be nested @@ -2468,7 +2472,8 @@ QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType( template<typename Derived> QualType TreeTransform<Derived>::TransformVectorType(TypeLocBuilder &TLB, - VectorTypeLoc TL) { + VectorTypeLoc TL, + QualType ObjectType) { VectorType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(T->getElementType()); if (ElementType.isNull()) @@ -2491,7 +2496,8 @@ QualType TreeTransform<Derived>::TransformVectorType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformExtVectorType(TypeLocBuilder &TLB, - ExtVectorTypeLoc TL) { + ExtVectorTypeLoc TL, + QualType ObjectType) { VectorType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(T->getElementType()); if (ElementType.isNull()) @@ -2516,7 +2522,8 @@ QualType TreeTransform<Derived>::TransformExtVectorType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, - FunctionProtoTypeLoc TL) { + FunctionProtoTypeLoc TL, + QualType ObjectType) { FunctionProtoType *T = TL.getTypePtr(); QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); if (ResultType.isNull()) @@ -2592,7 +2599,8 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformFunctionNoProtoType( TypeLocBuilder &TLB, - FunctionNoProtoTypeLoc TL) { + FunctionNoProtoTypeLoc TL, + QualType ObjectType) { FunctionNoProtoType *T = TL.getTypePtr(); QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); if (ResultType.isNull()) @@ -2612,9 +2620,10 @@ QualType TreeTransform<Derived>::TransformFunctionNoProtoType( template<typename Derived> QualType TreeTransform<Derived>::TransformUnresolvedUsingType(TypeLocBuilder &TLB, - UnresolvedUsingTypeLoc TL) { + UnresolvedUsingTypeLoc TL, + QualType ObjectType) { UnresolvedUsingType *T = TL.getTypePtr(); - Decl *D = getDerived().TransformDecl(T->getDecl()); + Decl *D = getDerived().TransformDecl(TL.getNameLoc(), T->getDecl()); if (!D) return QualType(); @@ -2635,10 +2644,12 @@ TreeTransform<Derived>::TransformUnresolvedUsingType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformTypedefType(TypeLocBuilder &TLB, - TypedefTypeLoc TL) { + TypedefTypeLoc TL, + QualType ObjectType) { TypedefType *T = TL.getTypePtr(); TypedefDecl *Typedef - = cast_or_null<TypedefDecl>(getDerived().TransformDecl(T->getDecl())); + = cast_or_null<TypedefDecl>(getDerived().TransformDecl(TL.getNameLoc(), + T->getDecl())); if (!Typedef) return QualType(); @@ -2658,7 +2669,8 @@ QualType TreeTransform<Derived>::TransformTypedefType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB, - TypeOfExprTypeLoc TL) { + TypeOfExprTypeLoc TL, + QualType ObjectType) { // typeof expressions are not potentially evaluated contexts EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); @@ -2685,7 +2697,8 @@ QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformTypeOfType(TypeLocBuilder &TLB, - TypeOfTypeLoc TL) { + TypeOfTypeLoc TL, + QualType ObjectType) { TypeSourceInfo* Old_Under_TI = TL.getUnderlyingTInfo(); TypeSourceInfo* New_Under_TI = getDerived().TransformType(Old_Under_TI); if (!New_Under_TI) @@ -2709,7 +2722,8 @@ QualType TreeTransform<Derived>::TransformTypeOfType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB, - DecltypeTypeLoc TL) { + DecltypeTypeLoc TL, + QualType ObjectType) { DecltypeType *T = TL.getTypePtr(); // decltype expressions are not potentially evaluated contexts @@ -2736,10 +2750,12 @@ QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformRecordType(TypeLocBuilder &TLB, - RecordTypeLoc TL) { + RecordTypeLoc TL, + QualType ObjectType) { RecordType *T = TL.getTypePtr(); RecordDecl *Record - = cast_or_null<RecordDecl>(getDerived().TransformDecl(T->getDecl())); + = cast_or_null<RecordDecl>(getDerived().TransformDecl(TL.getNameLoc(), + T->getDecl())); if (!Record) return QualType(); @@ -2759,10 +2775,12 @@ QualType TreeTransform<Derived>::TransformRecordType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformEnumType(TypeLocBuilder &TLB, - EnumTypeLoc TL) { + EnumTypeLoc TL, + QualType ObjectType) { EnumType *T = TL.getTypePtr(); EnumDecl *Enum - = cast_or_null<EnumDecl>(getDerived().TransformDecl(T->getDecl())); + = cast_or_null<EnumDecl>(getDerived().TransformDecl(TL.getNameLoc(), + T->getDecl())); if (!Enum) return QualType(); @@ -2782,7 +2800,8 @@ QualType TreeTransform<Derived>::TransformEnumType(TypeLocBuilder &TLB, template <typename Derived> QualType TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB, - ElaboratedTypeLoc TL) { + ElaboratedTypeLoc TL, + QualType ObjectType) { ElaboratedType *T = TL.getTypePtr(); // FIXME: this should be a nested type. @@ -2808,26 +2827,20 @@ QualType TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformTemplateTypeParmType( TypeLocBuilder &TLB, - TemplateTypeParmTypeLoc TL) { + TemplateTypeParmTypeLoc TL, + QualType ObjectType) { return TransformTypeSpecType(TLB, TL); } template<typename Derived> QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType( TypeLocBuilder &TLB, - SubstTemplateTypeParmTypeLoc TL) { + SubstTemplateTypeParmTypeLoc TL, + QualType ObjectType) { return TransformTypeSpecType(TLB, TL); } template<typename Derived> -inline QualType -TreeTransform<Derived>::TransformTemplateSpecializationType( - TypeLocBuilder &TLB, - TemplateSpecializationTypeLoc TL) { - return TransformTemplateSpecializationType(TLB, TL, QualType()); -} - -template<typename Derived> QualType TreeTransform<Derived>::TransformTemplateSpecializationType( const TemplateSpecializationType *TST, QualType ObjectType) { @@ -2901,11 +2914,13 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType( template<typename Derived> QualType TreeTransform<Derived>::TransformQualifiedNameType(TypeLocBuilder &TLB, - QualifiedNameTypeLoc TL) { + QualifiedNameTypeLoc TL, + QualType ObjectType) { QualifiedNameType *T = TL.getTypePtr(); NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(T->getQualifier(), - SourceRange()); + SourceRange(), + ObjectType); if (!NNS) return QualType(); @@ -2930,14 +2945,16 @@ TreeTransform<Derived>::TransformQualifiedNameType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformTypenameType(TypeLocBuilder &TLB, - TypenameTypeLoc TL) { + TypenameTypeLoc TL, + QualType ObjectType) { TypenameType *T = TL.getTypePtr(); /* FIXME: preserve source information better than this */ SourceRange SR(TL.getNameLoc()); NestedNameSpecifier *NNS - = getDerived().TransformNestedNameSpecifier(T->getQualifier(), SR); + = getDerived().TransformNestedNameSpecifier(T->getQualifier(), SR, + ObjectType); if (!NNS) return QualType(); @@ -2970,7 +2987,8 @@ QualType TreeTransform<Derived>::TransformTypenameType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformObjCInterfaceType(TypeLocBuilder &TLB, - ObjCInterfaceTypeLoc TL) { + ObjCInterfaceTypeLoc TL, + QualType ObjectType) { assert(false && "TransformObjCInterfaceType unimplemented"); return QualType(); } @@ -2978,7 +2996,8 @@ TreeTransform<Derived>::TransformObjCInterfaceType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB, - ObjCObjectPointerTypeLoc TL) { + ObjCObjectPointerTypeLoc TL, + QualType ObjectType) { assert(false && "TransformObjCObjectPointerType unimplemented"); return QualType(); } @@ -3098,7 +3117,9 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) { if (S->getConditionVariable()) { ConditionVar = cast_or_null<VarDecl>( - getDerived().TransformDefinition(S->getConditionVariable())); + getDerived().TransformDefinition( + S->getConditionVariable()->getLocation(), + S->getConditionVariable())); if (!ConditionVar) return SemaRef.StmtError(); } else { @@ -3141,7 +3162,9 @@ TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) { if (S->getConditionVariable()) { ConditionVar = cast_or_null<VarDecl>( - getDerived().TransformDefinition(S->getConditionVariable())); + getDerived().TransformDefinition( + S->getConditionVariable()->getLocation(), + S->getConditionVariable())); if (!ConditionVar) return SemaRef.StmtError(); } else { @@ -3178,7 +3201,9 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) { if (S->getConditionVariable()) { ConditionVar = cast_or_null<VarDecl>( - getDerived().TransformDefinition(S->getConditionVariable())); + getDerived().TransformDefinition( + S->getConditionVariable()->getLocation(), + S->getConditionVariable())); if (!ConditionVar) return SemaRef.StmtError(); } else { @@ -3242,7 +3267,9 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) { if (S->getConditionVariable()) { ConditionVar = cast_or_null<VarDecl>( - getDerived().TransformDefinition(S->getConditionVariable())); + getDerived().TransformDefinition( + S->getConditionVariable()->getLocation(), + S->getConditionVariable())); if (!ConditionVar) return SemaRef.StmtError(); } else { @@ -3330,7 +3357,8 @@ TreeTransform<Derived>::TransformDeclStmt(DeclStmt *S) { llvm::SmallVector<Decl *, 4> Decls; for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); D != DEnd; ++D) { - Decl *Transformed = getDerived().TransformDefinition(*D); + Decl *Transformed = getDerived().TransformDefinition((*D)->getLocation(), + *D); if (!Transformed) return SemaRef.StmtError(); @@ -3577,7 +3605,8 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) { } ValueDecl *ND - = cast_or_null<ValueDecl>(getDerived().TransformDecl(E->getDecl())); + = cast_or_null<ValueDecl>(getDerived().TransformDecl(E->getLocation(), + E->getDecl())); if (!ND) return SemaRef.ExprError(); @@ -3786,7 +3815,8 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) { } ValueDecl *Member - = cast_or_null<ValueDecl>(getDerived().TransformDecl(E->getMemberDecl())); + = cast_or_null<ValueDecl>(getDerived().TransformDecl(E->getMemberLoc(), + E->getMemberDecl())); if (!Member) return SemaRef.ExprError(); @@ -4510,7 +4540,8 @@ template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) { ParmVarDecl *Param - = cast_or_null<ParmVarDecl>(getDerived().TransformDecl(E->getParam())); + = cast_or_null<ParmVarDecl>(getDerived().TransformDecl(E->getLocStart(), + E->getParam())); if (!Param) return SemaRef.ExprError(); @@ -4577,11 +4608,51 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { ConstructorArgs.push_back(Arg.take()); } + // Transform constructor, new operator, and delete operator. + CXXConstructorDecl *Constructor = 0; + if (E->getConstructor()) { + Constructor = cast_or_null<CXXConstructorDecl>( + getDerived().TransformDecl(E->getLocStart(), + E->getConstructor())); + if (!Constructor) + return SemaRef.ExprError(); + } + + FunctionDecl *OperatorNew = 0; + if (E->getOperatorNew()) { + OperatorNew = cast_or_null<FunctionDecl>( + getDerived().TransformDecl(E->getLocStart(), + E->getOperatorNew())); + if (!OperatorNew) + return SemaRef.ExprError(); + } + + FunctionDecl *OperatorDelete = 0; + if (E->getOperatorDelete()) { + OperatorDelete = cast_or_null<FunctionDecl>( + getDerived().TransformDecl(E->getLocStart(), + E->getOperatorDelete())); + if (!OperatorDelete) + return SemaRef.ExprError(); + } + if (!getDerived().AlwaysRebuild() && AllocType == E->getAllocatedType() && ArraySize.get() == E->getArraySize() && - !ArgumentChanged) + Constructor == E->getConstructor() && + OperatorNew == E->getOperatorNew() && + OperatorDelete == E->getOperatorDelete() && + !ArgumentChanged) { + // Mark any declarations we need as referenced. + // FIXME: instantiation-specific. + if (Constructor) + SemaRef.MarkDeclarationReferenced(E->getLocStart(), Constructor); + if (OperatorNew) + SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorNew); + if (OperatorDelete) + SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorDelete); return SemaRef.Owned(E->Retain()); + } if (!ArraySize.get()) { // If no array size was specified, but the new expression was @@ -4630,9 +4701,25 @@ TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E) { if (Operand.isInvalid()) return SemaRef.ExprError(); + // Transform the delete operator, if known. + FunctionDecl *OperatorDelete = 0; + if (E->getOperatorDelete()) { + OperatorDelete = cast_or_null<FunctionDecl>( + getDerived().TransformDecl(E->getLocStart(), + E->getOperatorDelete())); + if (!OperatorDelete) + return SemaRef.ExprError(); + } + if (!getDerived().AlwaysRebuild() && - Operand.get() == E->getArgument()) + Operand.get() == E->getArgument() && + OperatorDelete == E->getOperatorDelete()) { + // Mark any declarations we need as referenced. + // FIXME: instantiation-specific. + if (OperatorDelete) + SemaRef.MarkDeclarationReferenced(E->getLocStart(), OperatorDelete); return SemaRef.Owned(E->Retain()); + } return getDerived().RebuildCXXDeleteExpr(E->getLocStart(), E->isGlobalDelete(), @@ -4648,33 +4735,75 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr( if (Base.isInvalid()) return SemaRef.ExprError(); + Sema::TypeTy *ObjectTypePtr = 0; + bool MayBePseudoDestructor = false; + Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), + E->getOperatorLoc(), + E->isArrow()? tok::arrow : tok::period, + ObjectTypePtr, + MayBePseudoDestructor); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr); NestedNameSpecifier *Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), - E->getQualifierRange()); + E->getQualifierRange(), + ObjectType); if (E->getQualifier() && !Qualifier) return SemaRef.ExprError(); - QualType DestroyedType; - { - TemporaryBase Rebase(*this, E->getDestroyedTypeLoc(), DeclarationName()); - DestroyedType = getDerived().TransformType(E->getDestroyedType()); - if (DestroyedType.isNull()) + PseudoDestructorTypeStorage Destroyed; + if (E->getDestroyedTypeInfo()) { + TypeSourceInfo *DestroyedTypeInfo + = getDerived().TransformType(E->getDestroyedTypeInfo(), ObjectType); + if (!DestroyedTypeInfo) return SemaRef.ExprError(); + Destroyed = DestroyedTypeInfo; + } else if (ObjectType->isDependentType()) { + // We aren't likely to be able to resolve the identifier down to a type + // now anyway, so just retain the identifier. + Destroyed = PseudoDestructorTypeStorage(E->getDestroyedTypeIdentifier(), + E->getDestroyedTypeLoc()); + } else { + // Look for a destructor known with the given name. + CXXScopeSpec SS; + if (Qualifier) { + SS.setScopeRep(Qualifier); + SS.setRange(E->getQualifierRange()); + } + + Sema::TypeTy *T = SemaRef.getDestructorName(E->getTildeLoc(), + *E->getDestroyedTypeIdentifier(), + E->getDestroyedTypeLoc(), + /*Scope=*/0, + SS, ObjectTypePtr, + false); + if (!T) + return SemaRef.ExprError(); + + Destroyed + = SemaRef.Context.getTrivialTypeSourceInfo(SemaRef.GetTypeFromParser(T), + E->getDestroyedTypeLoc()); } - if (!getDerived().AlwaysRebuild() && - Base.get() == E->getBase() && - Qualifier == E->getQualifier() && - DestroyedType == E->getDestroyedType()) - return SemaRef.Owned(E->Retain()); - + TypeSourceInfo *ScopeTypeInfo = 0; + if (E->getScopeTypeInfo()) { + ScopeTypeInfo = getDerived().TransformType(E->getScopeTypeInfo(), + ObjectType); + if (!ScopeTypeInfo) + return SemaRef.ExprError(); + } + return getDerived().RebuildCXXPseudoDestructorExpr(move(Base), E->getOperatorLoc(), E->isArrow(), - E->getDestroyedTypeLoc(), - DestroyedType, Qualifier, - E->getQualifierRange()); + E->getQualifierRange(), + ScopeTypeInfo, + E->getColonColonLoc(), + E->getTildeLoc(), + Destroyed); } template<typename Derived> @@ -4689,7 +4818,9 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr( // Transform all the decls. for (UnresolvedLookupExpr::decls_iterator I = Old->decls_begin(), E = Old->decls_end(); I != E; ++I) { - NamedDecl *InstD = static_cast<NamedDecl*>(getDerived().TransformDecl(*I)); + NamedDecl *InstD = static_cast<NamedDecl*>( + getDerived().TransformDecl(Old->getNameLoc(), + *I)); if (!InstD) { // Silently ignore these if a UsingShadowDecl instantiated to nothing. // This can happen because of dependent hiding. @@ -4828,7 +4959,8 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) { CXXConstructorDecl *Constructor = cast_or_null<CXXConstructorDecl>( - getDerived().TransformDecl(E->getConstructor())); + getDerived().TransformDecl(E->getLocStart(), + E->getConstructor())); if (!Constructor) return SemaRef.ExprError(); @@ -4853,8 +4985,12 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) { if (!getDerived().AlwaysRebuild() && T == E->getType() && Constructor == E->getConstructor() && - !ArgumentChanged) + !ArgumentChanged) { + // Mark the constructor as referenced. + // FIXME: Instantiation-specific + SemaRef.MarkDeclarationReferenced(E->getLocStart(), Constructor); return SemaRef.Owned(E->Retain()); + } return getDerived().RebuildCXXConstructExpr(T, /*FIXME:*/E->getLocStart(), Constructor, E->isElidable(), @@ -4904,7 +5040,8 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr( CXXConstructorDecl *Constructor = cast_or_null<CXXConstructorDecl>( - getDerived().TransformDecl(E->getConstructor())); + getDerived().TransformDecl(E->getLocStart(), + E->getConstructor())); if (!Constructor) return SemaRef.ExprError(); @@ -4914,6 +5051,11 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr( for (CXXTemporaryObjectExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end(); Arg != ArgEnd; ++Arg) { + if (getDerived().DropCallArgument(*Arg)) { + ArgumentChanged = true; + break; + } + OwningExprResult TransArg = getDerived().TransformExpr(*Arg); if (TransArg.isInvalid()) return SemaRef.ExprError(); @@ -4925,8 +5067,11 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr( if (!getDerived().AlwaysRebuild() && T == E->getType() && Constructor == E->getConstructor() && - !ArgumentChanged) + !ArgumentChanged) { + // FIXME: Instantiation-specific + SemaRef.MarkDeclarationReferenced(E->getTypeBeginLoc(), Constructor); return SemaRef.Owned(E->Retain()); + } // FIXME: Bogus location information SourceLocation CommaLoc; @@ -4999,10 +5144,12 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr( // Start the member reference and compute the object's type. Sema::TypeTy *ObjectTy = 0; + bool MayBePseudoDestructor = false; Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), E->getOperatorLoc(), E->isArrow()? tok::arrow : tok::period, - ObjectTy); + ObjectTy, + MayBePseudoDestructor); if (Base.isInvalid()) return SemaRef.ExprError(); @@ -5110,7 +5257,9 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) // Transform all the decls. for (UnresolvedMemberExpr::decls_iterator I = Old->decls_begin(), E = Old->decls_end(); I != E; ++I) { - NamedDecl *InstD = static_cast<NamedDecl*>(getDerived().TransformDecl(*I)); + NamedDecl *InstD = static_cast<NamedDecl*>( + getDerived().TransformDecl(Old->getMemberLoc(), + *I)); if (!InstD) { // Silently ignore these if a UsingShadowDecl instantiated to nothing. // This can happen because of dependent hiding. @@ -5208,7 +5357,8 @@ Sema::OwningExprResult TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E) { ObjCProtocolDecl *Protocol = cast_or_null<ObjCProtocolDecl>( - getDerived().TransformDecl(E->getProtocol())); + getDerived().TransformDecl(E->getLocStart(), + E->getProtocol())); if (!Protocol) return SemaRef.ExprError(); @@ -5704,6 +5854,52 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, return move(Result); } +template<typename Derived> +Sema::OwningExprResult +TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(ExprArg Base, + SourceLocation OperatorLoc, + bool isArrow, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + TypeSourceInfo *ScopeType, + SourceLocation CCLoc, + SourceLocation TildeLoc, + PseudoDestructorTypeStorage Destroyed) { + CXXScopeSpec SS; + if (Qualifier) { + SS.setRange(QualifierRange); + SS.setScopeRep(Qualifier); + } + + Expr *BaseE = (Expr *)Base.get(); + QualType BaseType = BaseE->getType(); + if (BaseE->isTypeDependent() || Destroyed.getIdentifier() || + (!isArrow && !BaseType->getAs<RecordType>()) || + (isArrow && BaseType->getAs<PointerType>() && + !BaseType->getAs<PointerType>()->getPointeeType() + ->template getAs<RecordType>())){ + // This pseudo-destructor expression is still a pseudo-destructor. + return SemaRef.BuildPseudoDestructorExpr(move(Base), OperatorLoc, + isArrow? tok::arrow : tok::period, + SS, ScopeType, CCLoc, TildeLoc, + Destroyed, + /*FIXME?*/true); + } + + TypeSourceInfo *DestroyedType = Destroyed.getTypeSourceInfo(); + DeclarationName Name + = SemaRef.Context.DeclarationNames.getCXXDestructorName( + SemaRef.Context.getCanonicalType(DestroyedType->getType())); + + // FIXME: the ScopeType should be tacked onto SS. + + return getSema().BuildMemberReferenceExpr(move(Base), BaseType, + OperatorLoc, isArrow, + SS, /*FIXME: FirstQualifier*/ 0, + Name, Destroyed.getLocation(), + /*TemplateArgs*/ 0); +} + } // end namespace clang #endif // LLVM_CLANG_SEMA_TREETRANSFORM_H |