diff options
author | ed <ed@FreeBSD.org> | 2009-06-02 17:58:47 +0000 |
---|---|---|
committer | ed <ed@FreeBSD.org> | 2009-06-02 17:58:47 +0000 |
commit | f27e5a09a0d815b8a4814152954ff87dadfdefc0 (patch) | |
tree | ce7d964cbb5e39695b71481698f10cb099c23d4a /lib/Sema | |
download | FreeBSD-src-f27e5a09a0d815b8a4814152954ff87dadfdefc0.zip FreeBSD-src-f27e5a09a0d815b8a4814152954ff87dadfdefc0.tar.gz |
Import Clang, at r72732.
Diffstat (limited to 'lib/Sema')
34 files changed, 43781 insertions, 0 deletions
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt new file mode 100644 index 0000000..321dac1 --- /dev/null +++ b/lib/Sema/CMakeLists.txt @@ -0,0 +1,33 @@ +set(LLVM_NO_RTTI 1) + +add_clang_library(clangSema + IdentifierResolver.cpp + JumpDiagnostics.cpp + ParseAST.cpp + Sema.cpp + SemaAccess.cpp + SemaAttr.cpp + SemaChecking.cpp + SemaCXXScopeSpec.cpp + SemaDeclAttr.cpp + SemaDecl.cpp + SemaDeclCXX.cpp + SemaDeclObjC.cpp + SemaExpr.cpp + SemaExprCXX.cpp + SemaExprObjC.cpp + SemaInherit.cpp + SemaInit.cpp + SemaLookup.cpp + SemaNamedCast.cpp + SemaOverload.cpp + SemaStmt.cpp + SemaTemplate.cpp + SemaTemplateInstantiate.cpp + SemaTemplateInstantiateDecl.cpp + SemaTemplateInstantiateExpr.cpp + SemaTemplateInstantiateStmt.cpp + SemaType.cpp + ) + +add_dependencies(clangSema ClangDiagnosticSema) diff --git a/lib/Sema/CXXFieldCollector.h b/lib/Sema/CXXFieldCollector.h new file mode 100644 index 0000000..69d1351 --- /dev/null +++ b/lib/Sema/CXXFieldCollector.h @@ -0,0 +1,76 @@ +//===- CXXFieldCollector.h - Utility class for C++ class semantic analysis ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides CXXFieldCollector that is used during parsing & semantic +// analysis of C++ classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_CXXFIELDCOLLECTOR_H +#define LLVM_CLANG_SEMA_CXXFIELDCOLLECTOR_H + +#include "llvm/ADT/SmallVector.h" + +namespace clang { + class FieldDecl; + +/// CXXFieldCollector - Used to keep track of CXXFieldDecls during parsing of +/// C++ classes. +class CXXFieldCollector { + /// Fields - Contains all FieldDecls collected during parsing of a C++ + /// class. When a nested class is entered, its fields are appended to the + /// fields of its parent class, when it is exited its fields are removed. + llvm::SmallVector<FieldDecl*, 32> Fields; + + /// FieldCount - Each entry represents the number of fields collected during + /// the parsing of a C++ class. When a nested class is entered, a new field + /// count is pushed, when it is exited, the field count is popped. + llvm::SmallVector<size_t, 4> FieldCount; + + // Example: + // + // class C { + // int x,y; + // class NC { + // int q; + // // At this point, Fields contains [x,y,q] decls and FieldCount contains + // // [2,1]. + // }; + // int z; + // // At this point, Fields contains [x,y,z] decls and FieldCount contains + // // [3]. + // }; + +public: + /// StartClass - Called by Sema::ActOnStartCXXClassDef. + void StartClass() { FieldCount.push_back(0); } + + /// Add - Called by Sema::ActOnCXXMemberDeclarator. + void Add(FieldDecl *D) { + Fields.push_back(D); + ++FieldCount.back(); + } + + /// getCurNumField - The number of fields added to the currently parsed class. + size_t getCurNumFields() const { return FieldCount.back(); } + + /// getCurFields - Pointer to array of fields added to the currently parsed + /// class. + FieldDecl **getCurFields() { return &*(Fields.end() - getCurNumFields()); } + + /// FinishClass - Called by Sema::ActOnFinishCXXClassDef. + void FinishClass() { + Fields.resize(Fields.size() - getCurNumFields()); + FieldCount.pop_back(); + } +}; + +} // end namespace clang + +#endif diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp new file mode 100644 index 0000000..ceab859 --- /dev/null +++ b/lib/Sema/IdentifierResolver.cpp @@ -0,0 +1,293 @@ +//===- IdentifierResolver.cpp - Lexical Scope Name lookup -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the IdentifierResolver class, which is used for lexical +// scoped lookup, based on declaration names. +// +//===----------------------------------------------------------------------===// + +#include "IdentifierResolver.h" +#include "clang/Basic/LangOptions.h" +#include <list> +#include <vector> + +using namespace clang; + +//===----------------------------------------------------------------------===// +// IdDeclInfoMap class +//===----------------------------------------------------------------------===// + +/// IdDeclInfoMap - Associates IdDeclInfos with declaration names. +/// Allocates 'pools' (vectors of IdDeclInfos) to avoid allocating each +/// individual IdDeclInfo to heap. +class IdentifierResolver::IdDeclInfoMap { + static const unsigned int VECTOR_SIZE = 512; + // Holds vectors of IdDeclInfos that serve as 'pools'. + // New vectors are added when the current one is full. + std::list< std::vector<IdDeclInfo> > IDIVecs; + unsigned int CurIndex; + +public: + IdDeclInfoMap() : CurIndex(VECTOR_SIZE) {} + + /// Returns the IdDeclInfo associated to the DeclarationName. + /// It creates a new IdDeclInfo if one was not created before for this id. + IdDeclInfo &operator[](DeclarationName Name); +}; + + +//===----------------------------------------------------------------------===// +// IdDeclInfo Implementation +//===----------------------------------------------------------------------===// + +/// AddShadowed - Add a decl by putting it directly above the 'Shadow' decl. +/// Later lookups will find the 'Shadow' decl first. The 'Shadow' decl must +/// be already added to the scope chain and must be in the same context as +/// the decl that we want to add. +void IdentifierResolver::IdDeclInfo::AddShadowed(NamedDecl *D, + NamedDecl *Shadow) { + for (DeclsTy::iterator I = Decls.end(); I != Decls.begin(); --I) { + if (Shadow == *(I-1)) { + Decls.insert(I-1, D); + return; + } + } + + assert(0 && "Shadow wasn't in scope chain!"); +} + +/// RemoveDecl - Remove the decl from the scope chain. +/// The decl must already be part of the decl chain. +void IdentifierResolver::IdDeclInfo::RemoveDecl(NamedDecl *D) { + for (DeclsTy::iterator I = Decls.end(); I != Decls.begin(); --I) { + if (D == *(I-1)) { + Decls.erase(I-1); + return; + } + } + + assert(0 && "Didn't find this decl on its identifier's chain!"); +} + +bool +IdentifierResolver::IdDeclInfo::ReplaceDecl(NamedDecl *Old, NamedDecl *New) { + for (DeclsTy::iterator I = Decls.end(); I != Decls.begin(); --I) { + if (Old == *(I-1)) { + *(I - 1) = New; + return true; + } + } + + return false; +} + + +//===----------------------------------------------------------------------===// +// IdentifierResolver Implementation +//===----------------------------------------------------------------------===// + +IdentifierResolver::IdentifierResolver(const LangOptions &langOpt) + : LangOpt(langOpt), IdDeclInfos(new IdDeclInfoMap) { +} +IdentifierResolver::~IdentifierResolver() { + delete IdDeclInfos; +} + +/// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true +/// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns +/// true if 'D' belongs to the given declaration context. +bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, + ASTContext &Context, Scope *S) const { + Ctx = Ctx->getLookupContext(); + + if (Ctx->isFunctionOrMethod()) { + // Ignore the scopes associated within transparent declaration contexts. + while (S->getEntity() && + ((DeclContext *)S->getEntity())->isTransparentContext()) + S = S->getParent(); + + if (S->isDeclScope(Action::DeclPtrTy::make(D))) + return true; + if (LangOpt.CPlusPlus) { + // C++ 3.3.2p3: + // The name declared in a catch exception-declaration is local to the + // handler and shall not be redeclared in the outermost block of the + // handler. + // C++ 3.3.2p4: + // Names declared in the for-init-statement, and in the condition of if, + // while, for, and switch statements are local to the if, while, for, or + // switch statement (including the controlled statement), and shall not be + // redeclared in a subsequent condition of that statement nor in the + // outermost block (or, for the if statement, any of the outermost blocks) + // of the controlled statement. + // + assert(S->getParent() && "No TUScope?"); + if (S->getParent()->getFlags() & Scope::ControlScope) + return S->getParent()->isDeclScope(Action::DeclPtrTy::make(D)); + } + return false; + } + + return D->getDeclContext()->getLookupContext() == Ctx->getPrimaryContext(); +} + +/// AddDecl - Link the decl to its shadowed decl chain. +void IdentifierResolver::AddDecl(NamedDecl *D) { + DeclarationName Name = D->getDeclName(); + void *Ptr = Name.getFETokenInfo<void>(); + + if (!Ptr) { + Name.setFETokenInfo(D); + return; + } + + IdDeclInfo *IDI; + + if (isDeclPtr(Ptr)) { + Name.setFETokenInfo(NULL); + IDI = &(*IdDeclInfos)[Name]; + NamedDecl *PrevD = static_cast<NamedDecl*>(Ptr); + IDI->AddDecl(PrevD); + } else + IDI = toIdDeclInfo(Ptr); + + IDI->AddDecl(D); +} + +/// AddShadowedDecl - Link the decl to its shadowed decl chain putting it +/// after the decl that the iterator points to, thus the 'Shadow' decl will be +/// encountered before the 'D' decl. +void IdentifierResolver::AddShadowedDecl(NamedDecl *D, NamedDecl *Shadow) { + assert(D->getDeclName() == Shadow->getDeclName() && "Different ids!"); + + DeclarationName Name = D->getDeclName(); + void *Ptr = Name.getFETokenInfo<void>(); + assert(Ptr && "No decl from Ptr ?"); + + IdDeclInfo *IDI; + + if (isDeclPtr(Ptr)) { + Name.setFETokenInfo(NULL); + IDI = &(*IdDeclInfos)[Name]; + NamedDecl *PrevD = static_cast<NamedDecl*>(Ptr); + assert(PrevD == Shadow && "Invalid shadow decl ?"); + IDI->AddDecl(D); + IDI->AddDecl(PrevD); + return; + } + + IDI = toIdDeclInfo(Ptr); + IDI->AddShadowed(D, Shadow); +} + +/// RemoveDecl - Unlink the decl from its shadowed decl chain. +/// The decl must already be part of the decl chain. +void IdentifierResolver::RemoveDecl(NamedDecl *D) { + assert(D && "null param passed"); + DeclarationName Name = D->getDeclName(); + void *Ptr = Name.getFETokenInfo<void>(); + + assert(Ptr && "Didn't find this decl on its identifier's chain!"); + + if (isDeclPtr(Ptr)) { + assert(D == Ptr && "Didn't find this decl on its identifier's chain!"); + Name.setFETokenInfo(NULL); + return; + } + + return toIdDeclInfo(Ptr)->RemoveDecl(D); +} + +bool IdentifierResolver::ReplaceDecl(NamedDecl *Old, NamedDecl *New) { + assert(Old->getDeclName() == New->getDeclName() && + "Cannot replace a decl with another decl of a different name"); + + DeclarationName Name = Old->getDeclName(); + void *Ptr = Name.getFETokenInfo<void>(); + + if (!Ptr) + return false; + + if (isDeclPtr(Ptr)) { + if (Ptr == Old) { + Name.setFETokenInfo(New); + return true; + } + return false; + } + + return toIdDeclInfo(Ptr)->ReplaceDecl(Old, New); +} + +/// begin - Returns an iterator for decls with name 'Name'. +IdentifierResolver::iterator +IdentifierResolver::begin(DeclarationName Name) { + void *Ptr = Name.getFETokenInfo<void>(); + if (!Ptr) return end(); + + if (isDeclPtr(Ptr)) + return iterator(static_cast<NamedDecl*>(Ptr)); + + IdDeclInfo *IDI = toIdDeclInfo(Ptr); + + IdDeclInfo::DeclsTy::iterator I = IDI->decls_end(); + if (I != IDI->decls_begin()) + return iterator(I-1); + // No decls found. + return end(); +} + +void IdentifierResolver::AddDeclToIdentifierChain(IdentifierInfo *II, + NamedDecl *D) { + void *Ptr = II->getFETokenInfo<void>(); + + if (!Ptr) { + II->setFETokenInfo(D); + return; + } + + IdDeclInfo *IDI; + + if (isDeclPtr(Ptr)) { + II->setFETokenInfo(NULL); + IDI = &(*IdDeclInfos)[II]; + NamedDecl *PrevD = static_cast<NamedDecl*>(Ptr); + IDI->AddDecl(PrevD); + } else + IDI = toIdDeclInfo(Ptr); + + IDI->AddDecl(D); +} + +//===----------------------------------------------------------------------===// +// IdDeclInfoMap Implementation +//===----------------------------------------------------------------------===// + +/// Returns the IdDeclInfo associated to the DeclarationName. +/// It creates a new IdDeclInfo if one was not created before for this id. +IdentifierResolver::IdDeclInfo & +IdentifierResolver::IdDeclInfoMap::operator[](DeclarationName Name) { + void *Ptr = Name.getFETokenInfo<void>(); + + if (Ptr) return *toIdDeclInfo(Ptr); + + if (CurIndex == VECTOR_SIZE) { + // Add a IdDeclInfo vector 'pool' + IDIVecs.push_back(std::vector<IdDeclInfo>()); + // Fill the vector + IDIVecs.back().resize(VECTOR_SIZE); + CurIndex = 0; + } + IdDeclInfo *IDI = &IDIVecs.back()[CurIndex]; + Name.setFETokenInfo(reinterpret_cast<void*>( + reinterpret_cast<uintptr_t>(IDI) | 0x1) + ); + ++CurIndex; + return *IDI; +} diff --git a/lib/Sema/IdentifierResolver.h b/lib/Sema/IdentifierResolver.h new file mode 100644 index 0000000..0b0e6b3 --- /dev/null +++ b/lib/Sema/IdentifierResolver.h @@ -0,0 +1,214 @@ +//===- IdentifierResolver.h - Lexical Scope Name lookup ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the IdentifierResolver class, which is used for lexical +// scoped lookup, based on declaration names. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_SEMA_IDENTIFIERRESOLVER_H +#define LLVM_CLANG_AST_SEMA_IDENTIFIERRESOLVER_H + +#include "clang/Basic/IdentifierTable.h" +#include "clang/Parse/Scope.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/DeclCXX.h" + +namespace clang { + +/// IdentifierResolver - Keeps track of shadowed decls on enclosing +/// scopes. It manages the shadowing chains of declaration names and +/// implements efficent decl lookup based on a declaration name. +class IdentifierResolver { + + /// IdDeclInfo - Keeps track of information about decls associated + /// to a particular declaration name. IdDeclInfos are lazily + /// constructed and assigned to a declaration name the first time a + /// decl with that declaration name is shadowed in some scope. + class IdDeclInfo { + public: + typedef llvm::SmallVector<NamedDecl*, 2> DeclsTy; + + inline DeclsTy::iterator decls_begin() { return Decls.begin(); } + inline DeclsTy::iterator decls_end() { return Decls.end(); } + + void AddDecl(NamedDecl *D) { Decls.push_back(D); } + + /// AddShadowed - Add a decl by putting it directly above the 'Shadow' decl. + /// Later lookups will find the 'Shadow' decl first. The 'Shadow' decl must + /// be already added to the scope chain and must be in the same context as + /// the decl that we want to add. + void AddShadowed(NamedDecl *D, NamedDecl *Shadow); + + /// RemoveDecl - Remove the decl from the scope chain. + /// The decl must already be part of the decl chain. + void RemoveDecl(NamedDecl *D); + + /// Replaces the Old declaration with the New declaration. If the + /// replacement is successful, returns true. If the old + /// declaration was not found, returns false. + bool ReplaceDecl(NamedDecl *Old, NamedDecl *New); + + private: + DeclsTy Decls; + }; + +public: + + /// iterator - Iterate over the decls of a specified declaration name. + /// It will walk or not the parent declaration contexts depending on how + /// it was instantiated. + class iterator { + public: + typedef NamedDecl * value_type; + typedef NamedDecl * reference; + typedef NamedDecl * pointer; + typedef std::input_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + /// Ptr - There are 3 forms that 'Ptr' represents: + /// 1) A single NamedDecl. (Ptr & 0x1 == 0) + /// 2) A IdDeclInfo::DeclsTy::iterator that traverses only the decls of the + /// same declaration context. (Ptr & 0x3 == 0x1) + /// 3) A IdDeclInfo::DeclsTy::iterator that traverses the decls of parent + /// declaration contexts too. (Ptr & 0x3 == 0x3) + uintptr_t Ptr; + typedef IdDeclInfo::DeclsTy::iterator BaseIter; + + /// A single NamedDecl. (Ptr & 0x1 == 0) + iterator(NamedDecl *D) { + Ptr = reinterpret_cast<uintptr_t>(D); + assert((Ptr & 0x1) == 0 && "Invalid Ptr!"); + } + /// A IdDeclInfo::DeclsTy::iterator that walks or not the parent declaration + /// contexts depending on 'LookInParentCtx'. + iterator(BaseIter I) { + Ptr = reinterpret_cast<uintptr_t>(I) | 0x1; + } + + bool isIterator() const { return (Ptr & 0x1); } + + BaseIter getIterator() const { + assert(isIterator() && "Ptr not an iterator!"); + return reinterpret_cast<BaseIter>(Ptr & ~0x3); + } + + friend class IdentifierResolver; + public: + iterator() : Ptr(0) {} + + NamedDecl *operator*() const { + if (isIterator()) + return *getIterator(); + else + return reinterpret_cast<NamedDecl*>(Ptr); + } + + bool operator==(const iterator &RHS) const { + return Ptr == RHS.Ptr; + } + bool operator!=(const iterator &RHS) const { + return Ptr != RHS.Ptr; + } + + // Preincrement. + iterator& operator++() { + if (!isIterator()) // common case. + Ptr = 0; + else { + NamedDecl *D = **this; + void *InfoPtr = D->getDeclName().getFETokenInfo<void>(); + assert(!isDeclPtr(InfoPtr) && "Decl with wrong id ?"); + IdDeclInfo *Info = toIdDeclInfo(InfoPtr); + + BaseIter I = getIterator(); + if (I != Info->decls_begin()) + *this = iterator(I-1); + else // No more decls. + *this = iterator(); + } + return *this; + } + + uintptr_t getAsOpaqueValue() const { return Ptr; } + + static iterator getFromOpaqueValue(uintptr_t P) { + iterator Result; + Result.Ptr = P; + return Result; + } + }; + + /// begin - Returns an iterator for decls with the name 'Name'. + static iterator begin(DeclarationName Name); + + /// end - Returns an iterator that has 'finished'. + static iterator end() { + return iterator(); + } + + /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true + /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns + /// true if 'D' belongs to the given declaration context. + bool isDeclInScope(Decl *D, DeclContext *Ctx, ASTContext &Context, + Scope *S = 0) const; + + /// AddDecl - Link the decl to its shadowed decl chain. + void AddDecl(NamedDecl *D); + + /// AddShadowedDecl - Link the decl to its shadowed decl chain putting it + /// after the decl that the iterator points to, thus the 'Shadow' decl will be + /// encountered before the 'D' decl. + void AddShadowedDecl(NamedDecl *D, NamedDecl *Shadow); + + /// RemoveDecl - Unlink the decl from its shadowed decl chain. + /// The decl must already be part of the decl chain. + void RemoveDecl(NamedDecl *D); + + /// Replace the decl Old with the new declaration New on its + /// identifier chain. Returns true if the old declaration was found + /// (and, therefore, replaced). + bool ReplaceDecl(NamedDecl *Old, NamedDecl *New); + + /// \brief Link the declaration into the chain of declarations for + /// the given identifier. + /// + /// This is a lower-level routine used by the PCH reader to link a + /// declaration into a specific IdentifierInfo before the + /// declaration actually has a name. + void AddDeclToIdentifierChain(IdentifierInfo *II, NamedDecl *D); + + explicit IdentifierResolver(const LangOptions &LangOpt); + ~IdentifierResolver(); + +private: + const LangOptions &LangOpt; + + class IdDeclInfoMap; + IdDeclInfoMap *IdDeclInfos; + + /// FETokenInfo contains a Decl pointer if lower bit == 0. + static inline bool isDeclPtr(void *Ptr) { + return (reinterpret_cast<uintptr_t>(Ptr) & 0x1) == 0; + } + + /// FETokenInfo contains a IdDeclInfo pointer if lower bit == 1. + static inline IdDeclInfo *toIdDeclInfo(void *Ptr) { + assert((reinterpret_cast<uintptr_t>(Ptr) & 0x1) == 1 + && "Ptr not a IdDeclInfo* !"); + return reinterpret_cast<IdDeclInfo*>( + reinterpret_cast<uintptr_t>(Ptr) & ~0x1 + ); + } +}; + +} // end namespace clang + +#endif diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp new file mode 100644 index 0000000..ae863f2 --- /dev/null +++ b/lib/Sema/JumpDiagnostics.cpp @@ -0,0 +1,327 @@ +//===--- JumpDiagnostics.cpp - Analyze Jump Targets for VLA issues --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the JumpScopeChecker class, which is used to diagnose +// jumps that enter a VLA scope in an invalid way. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/AST/Expr.h" +#include "clang/AST/StmtObjC.h" +#include "clang/AST/StmtCXX.h" +using namespace clang; + +namespace { + +/// JumpScopeChecker - This object is used by Sema to diagnose invalid jumps +/// into VLA and other protected scopes. For example, this rejects: +/// goto L; +/// int a[n]; +/// L: +/// +class JumpScopeChecker { + Sema &S; + + /// GotoScope - This is a record that we use to keep track of all of the + /// scopes that are introduced by VLAs and other things that scope jumps like + /// gotos. This scope tree has nothing to do with the source scope tree, + /// because you can have multiple VLA scopes per compound statement, and most + /// compound statements don't introduce any scopes. + struct GotoScope { + /// ParentScope - The index in ScopeMap of the parent scope. This is 0 for + /// the parent scope is the function body. + unsigned ParentScope; + + /// Diag - The diagnostic to emit if there is a jump into this scope. + unsigned Diag; + + /// Loc - Location to emit the diagnostic. + SourceLocation Loc; + + GotoScope(unsigned parentScope, unsigned diag, SourceLocation L) + : ParentScope(parentScope), Diag(diag), Loc(L) {} + }; + + llvm::SmallVector<GotoScope, 48> Scopes; + llvm::DenseMap<Stmt*, unsigned> LabelAndGotoScopes; + llvm::SmallVector<Stmt*, 16> Jumps; +public: + JumpScopeChecker(Stmt *Body, Sema &S); +private: + void BuildScopeInformation(Stmt *S, unsigned ParentScope); + void VerifyJumps(); + void CheckJump(Stmt *From, Stmt *To, + SourceLocation DiagLoc, unsigned JumpDiag); +}; +} // end anonymous namespace + + +JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s) : S(s) { + // Add a scope entry for function scope. + Scopes.push_back(GotoScope(~0U, ~0U, SourceLocation())); + + // Build information for the top level compound statement, so that we have a + // defined scope record for every "goto" and label. + BuildScopeInformation(Body, 0); + + // Check that all jumps we saw are kosher. + VerifyJumps(); +} + +/// 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) { + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (VD->getType()->isVariablyModifiedType()) + return diag::note_protected_by_vla; + if (VD->hasAttr<CleanupAttr>()) + return diag::note_protected_by_cleanup; + } else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { + if (TD->getUnderlyingType()->isVariablyModifiedType()) + return diag::note_protected_by_vla_typedef; + } + + return 0; +} + + +/// BuildScopeInformation - The statements from CI to CE are known to form a +/// coherent VLA scope with a specified parent node. Walk through the +/// statements, adding any labels or gotos to LabelAndGotoScopes and recursively +/// walking the AST as needed. +void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { + + // If we found a label, remember that it is in ParentScope scope. + if (isa<LabelStmt>(S) || isa<DefaultStmt>(S) || isa<CaseStmt>(S)) { + LabelAndGotoScopes[S] = ParentScope; + } else if (isa<GotoStmt>(S) || isa<SwitchStmt>(S) || + isa<IndirectGotoStmt>(S) || isa<AddrLabelExpr>(S)) { + // Remember both what scope a goto is in as well as the fact that we have + // it. This makes the second scan not have to walk the AST again. + LabelAndGotoScopes[S] = ParentScope; + Jumps.push_back(S); + } + + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E; + ++CI) { + Stmt *SubStmt = *CI; + if (SubStmt == 0) continue; + + // FIXME: diagnose jumps past initialization: required in C++, warning in C. + // goto L; int X = 4; L: ; + + // 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. + 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)) { + Scopes.push_back(GotoScope(ParentScope, Diag, (*I)->getLocation())); + ParentScope = Scopes.size()-1; + } + + // If the decl has an initializer, walk it with the potentially new + // scope we just installed. + if (VarDecl *VD = dyn_cast<VarDecl>(*I)) + if (Expr *Init = VD->getInit()) + BuildScopeInformation(Init, ParentScope); + } + continue; + } + + // Disallow jumps into any part of an @try statement by pushing a scope and + // walking all sub-stmts in that scope. + if (ObjCAtTryStmt *AT = dyn_cast<ObjCAtTryStmt>(SubStmt)) { + // Recursively walk the AST for the @try part. + Scopes.push_back(GotoScope(ParentScope,diag::note_protected_by_objc_try, + AT->getAtTryLoc())); + if (Stmt *TryPart = AT->getTryBody()) + BuildScopeInformation(TryPart, Scopes.size()-1); + + // Jump from the catch to the finally or try is not valid. + for (ObjCAtCatchStmt *AC = AT->getCatchStmts(); AC; + AC = AC->getNextCatchStmt()) { + Scopes.push_back(GotoScope(ParentScope, + diag::note_protected_by_objc_catch, + AC->getAtCatchLoc())); + // @catches are nested and it isn't + BuildScopeInformation(AC->getCatchBody(), Scopes.size()-1); + } + + // Jump from the finally to the try or catch is not valid. + if (ObjCAtFinallyStmt *AF = AT->getFinallyStmt()) { + Scopes.push_back(GotoScope(ParentScope, + diag::note_protected_by_objc_finally, + AF->getAtFinallyLoc())); + BuildScopeInformation(AF, Scopes.size()-1); + } + + continue; + } + + // Disallow jumps into the protected statement of an @synchronized, but + // allow jumps into the object expression it protects. + if (ObjCAtSynchronizedStmt *AS = dyn_cast<ObjCAtSynchronizedStmt>(SubStmt)){ + // Recursively walk the AST for the @synchronized object expr, it is + // evaluated in the normal scope. + BuildScopeInformation(AS->getSynchExpr(), ParentScope); + + // Recursively walk the AST for the @synchronized part, protected by a new + // scope. + Scopes.push_back(GotoScope(ParentScope, + diag::note_protected_by_objc_synchronized, + AS->getAtSynchronizedLoc())); + BuildScopeInformation(AS->getSynchBody(), Scopes.size()-1); + continue; + } + + // Disallow jumps into any part of a C++ try statement. This is pretty + // much the same as for Obj-C. + if (CXXTryStmt *TS = dyn_cast<CXXTryStmt>(SubStmt)) { + Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_cxx_try, + TS->getSourceRange().getBegin())); + if (Stmt *TryBlock = TS->getTryBlock()) + BuildScopeInformation(TryBlock, Scopes.size()-1); + + // Jump from the catch into the try is not allowed either. + for(unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) { + CXXCatchStmt *CS = TS->getHandler(I); + Scopes.push_back(GotoScope(ParentScope, + diag::note_protected_by_cxx_catch, + CS->getSourceRange().getBegin())); + BuildScopeInformation(CS->getHandlerBlock(), Scopes.size()-1); + } + + continue; + } + + // Recursively walk the AST. + BuildScopeInformation(SubStmt, ParentScope); + } +} + +/// VerifyJumps - Verify each element of the Jumps array to see if they are +/// valid, emitting diagnostics if not. +void JumpScopeChecker::VerifyJumps() { + while (!Jumps.empty()) { + Stmt *Jump = Jumps.pop_back_val(); + + // With a goto, + if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) { + CheckJump(GS, GS->getLabel(), GS->getGotoLoc(), + diag::err_goto_into_protected_scope); + continue; + } + + if (SwitchStmt *SS = dyn_cast<SwitchStmt>(Jump)) { + for (SwitchCase *SC = SS->getSwitchCaseList(); SC; + SC = SC->getNextSwitchCase()) { + assert(LabelAndGotoScopes.count(SC) && "Case not visited?"); + CheckJump(SS, SC, SC->getLocStart(), + diag::err_switch_into_protected_scope); + } + continue; + } + + unsigned DiagnosticScope; + + // We don't know where an indirect goto goes, require that it be at the + // top level of scoping. + if (IndirectGotoStmt *IG = dyn_cast<IndirectGotoStmt>(Jump)) { + assert(LabelAndGotoScopes.count(Jump) && + "Jump didn't get added to scopes?"); + unsigned GotoScope = LabelAndGotoScopes[IG]; + if (GotoScope == 0) continue; // indirect jump is ok. + S.Diag(IG->getGotoLoc(), diag::err_indirect_goto_in_protected_scope); + DiagnosticScope = GotoScope; + } else { + // We model &&Label as a jump for purposes of scope tracking. We actually + // don't care *where* the address of label is, but we require the *label + // itself* to be in scope 0. If it is nested inside of a VLA scope, then + // it is possible for an indirect goto to illegally enter the VLA scope by + // indirectly jumping to the label. + assert(isa<AddrLabelExpr>(Jump) && "Unknown jump type"); + LabelStmt *TheLabel = cast<AddrLabelExpr>(Jump)->getLabel(); + + assert(LabelAndGotoScopes.count(TheLabel) && + "Referenced label didn't get added to scopes?"); + unsigned LabelScope = LabelAndGotoScopes[TheLabel]; + if (LabelScope == 0) continue; // Addr of label is ok. + + S.Diag(Jump->getLocStart(), diag::err_addr_of_label_in_protected_scope); + DiagnosticScope = LabelScope; + } + + // Report all the things that would be skipped over by this &&label or + // indirect goto. + while (DiagnosticScope != 0) { + S.Diag(Scopes[DiagnosticScope].Loc, Scopes[DiagnosticScope].Diag); + DiagnosticScope = Scopes[DiagnosticScope].ParentScope; + } + } +} + +/// CheckJump - Validate that the specified jump statement is valid: that it is +/// jumping within or out of its current scope, not into a deeper one. +void JumpScopeChecker::CheckJump(Stmt *From, Stmt *To, + SourceLocation DiagLoc, unsigned JumpDiag) { + assert(LabelAndGotoScopes.count(From) && "Jump didn't get added to scopes?"); + unsigned FromScope = LabelAndGotoScopes[From]; + + assert(LabelAndGotoScopes.count(To) && "Jump didn't get added to scopes?"); + unsigned ToScope = LabelAndGotoScopes[To]; + + // Common case: exactly the same scope, which is fine. + if (FromScope == ToScope) return; + + // The only valid mismatch jump case happens when the jump is more deeply + // nested inside the jump target. Do a quick scan to see if the jump is valid + // because valid code is more common than invalid code. + unsigned TestScope = Scopes[FromScope].ParentScope; + while (TestScope != ~0U) { + // If we found the jump target, then we're jumping out of our current scope, + // which is perfectly fine. + if (TestScope == ToScope) return; + + // Otherwise, scan up the hierarchy. + TestScope = Scopes[TestScope].ParentScope; + } + + // If we get here, then we know we have invalid code. Diagnose the bad jump, + // and then emit a note at each VLA being jumped out of. + S.Diag(DiagLoc, JumpDiag); + + // Eliminate the common prefix of the jump and the target. Start by + // linearizing both scopes, reversing them as we go. + std::vector<unsigned> FromScopes, ToScopes; + for (TestScope = FromScope; TestScope != ~0U; + TestScope = Scopes[TestScope].ParentScope) + FromScopes.push_back(TestScope); + for (TestScope = ToScope; TestScope != ~0U; + TestScope = Scopes[TestScope].ParentScope) + ToScopes.push_back(TestScope); + + // Remove any common entries (such as the top-level function scope). + while (!FromScopes.empty() && FromScopes.back() == ToScopes.back()) { + FromScopes.pop_back(); + ToScopes.pop_back(); + } + + // Emit diagnostics for whatever is left in ToScopes. + for (unsigned i = 0, e = ToScopes.size(); i != e; ++i) + S.Diag(Scopes[ToScopes[i]].Loc, Scopes[ToScopes[i]].Diag); +} + +void Sema::DiagnoseInvalidJumps(Stmt *Body) { + JumpScopeChecker(Body, *this); +} diff --git a/lib/Sema/Makefile b/lib/Sema/Makefile new file mode 100644 index 0000000..0f4c796 --- /dev/null +++ b/lib/Sema/Makefile @@ -0,0 +1,23 @@ +##===- clang/lib/Sema/Makefile -----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This implements the semantic analyzer and AST builder library for the +# C-Language front-end. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +LIBRARYNAME := clangSema +BUILD_ARCHIVE = 1 +CXXFLAGS = -fno-rtti + +CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include + +include $(LEVEL)/Makefile.common + diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp new file mode 100644 index 0000000..e2ee88a --- /dev/null +++ b/lib/Sema/ParseAST.cpp @@ -0,0 +1,85 @@ +//===--- ParseAST.cpp - Provide the clang::ParseAST method ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the clang::ParseAST method. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/ParseAST.h" +#include "Sema.h" +#include "clang/Sema/SemaConsumer.h" +#include "clang/Sema/ExternalSemaSource.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ExternalASTSource.h" +#include "clang/AST/Stmt.h" +#include "clang/Parse/Parser.h" +#include "llvm/ADT/OwningPtr.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// Public interface to the file +//===----------------------------------------------------------------------===// + +/// ParseAST - Parse the entire file specified, notifying the ASTConsumer as +/// the file is parsed. This inserts the parsed decls into the translation unit +/// held by Ctx. +/// +void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, + ASTContext &Ctx, bool PrintStats, + bool CompleteTranslationUnit) { + // Collect global stats on Decls/Stmts (until we have a module streamer). + if (PrintStats) { + Decl::CollectingStats(true); + Stmt::CollectingStats(true); + } + + Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit); + Parser P(PP, S); + PP.EnterMainSourceFile(); + + // Initialize the parser. + P.Initialize(); + + Consumer->Initialize(Ctx); + + if (SemaConsumer *SC = dyn_cast<SemaConsumer>(Consumer)) + SC->InitializeSema(S); + + if (ExternalASTSource *External = Ctx.getExternalSource()) { + if (ExternalSemaSource *ExternalSema = + dyn_cast<ExternalSemaSource>(External)) + ExternalSema->InitializeSema(S); + + External->StartTranslationUnit(Consumer); + } + + Parser::DeclGroupPtrTy ADecl; + + while (!P.ParseTopLevelDecl(ADecl)) { // Not end of file. + // If we got a null return and something *was* parsed, ignore it. This + // is due to a top-level semicolon, an action override, or a parse error + // skipping something. + if (ADecl) + Consumer->HandleTopLevelDecl(ADecl.getAsVal<DeclGroupRef>()); + }; + + Consumer->HandleTranslationUnit(Ctx); + + if (PrintStats) { + fprintf(stderr, "\nSTATISTICS:\n"); + P.getActions().PrintStats(); + Ctx.PrintStats(); + Decl::PrintStats(); + Stmt::PrintStats(); + Consumer->PrintStats(); + + Decl::CollectingStats(false); + Stmt::CollectingStats(false); + } +} diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp new file mode 100644 index 0000000..1212d07 --- /dev/null +++ b/lib/Sema/Sema.cpp @@ -0,0 +1,333 @@ +//===--- Sema.cpp - AST Builder and Semantic Analysis Implementation ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the actions class which performs semantic analysis and +// builds an AST out of a parse stream. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Expr.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/TargetInfo.h" +using namespace clang; + +/// ConvertQualTypeToStringFn - This function is used to pretty print the +/// specified QualType as a string in diagnostics. +static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val, + const char *Modifier, unsigned ModLen, + const char *Argument, unsigned ArgLen, + llvm::SmallVectorImpl<char> &Output, + void *Cookie) { + ASTContext &Context = *static_cast<ASTContext*>(Cookie); + + std::string S; + if (Kind == Diagnostic::ak_qualtype) { + assert(ModLen == 0 && ArgLen == 0 && + "Invalid modifier for QualType argument"); + + QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val))); + + // FIXME: Playing with std::string is really slow. + S = Ty.getAsString(Context.PrintingPolicy); + + // If this is a sugared type (like a typedef, typeof, etc), then unwrap one + // level of the sugar so that the type is more obvious to the user. + QualType DesugaredTy = Ty->getDesugaredType(true); + DesugaredTy.setCVRQualifiers(DesugaredTy.getCVRQualifiers() | + Ty.getCVRQualifiers()); + + if (Ty != DesugaredTy && + // If the desugared type is a vector type, we don't want to expand it, + // it will turn into an attribute mess. People want their "vec4". + !isa<VectorType>(DesugaredTy) && + + // Don't desugar magic Objective-C types. + Ty.getUnqualifiedType() != Context.getObjCIdType() && + Ty.getUnqualifiedType() != Context.getObjCSelType() && + Ty.getUnqualifiedType() != Context.getObjCProtoType() && + Ty.getUnqualifiedType() != Context.getObjCClassType() && + + // Not va_list. + Ty.getUnqualifiedType() != Context.getBuiltinVaListType()) { + S = "'"+S+"' (aka '"; + S += DesugaredTy.getAsString(); + S += "')"; + Output.append(S.begin(), S.end()); + return; + } + + } else if (Kind == Diagnostic::ak_declarationname) { + + DeclarationName N = DeclarationName::getFromOpaqueInteger(Val); + S = N.getAsString(); + + if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0) + S = '+' + S; + else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12) && ArgLen==0) + S = '-' + S; + else + assert(ModLen == 0 && ArgLen == 0 && + "Invalid modifier for DeclarationName argument"); + } else { + assert(Kind == Diagnostic::ak_nameddecl); + if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0) + S = reinterpret_cast<NamedDecl*>(Val)->getQualifiedNameAsString(); + else { + assert(ModLen == 0 && ArgLen == 0 && + "Invalid modifier for NamedDecl* argument"); + S = reinterpret_cast<NamedDecl*>(Val)->getNameAsString(); + } + } + + Output.push_back('\''); + Output.append(S.begin(), S.end()); + Output.push_back('\''); +} + + +static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) { + if (C.getLangOptions().CPlusPlus) + return CXXRecordDecl::Create(C, TagDecl::TK_struct, + C.getTranslationUnitDecl(), + SourceLocation(), &C.Idents.get(Name)); + + return RecordDecl::Create(C, TagDecl::TK_struct, + C.getTranslationUnitDecl(), + SourceLocation(), &C.Idents.get(Name)); +} + +void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { + TUScope = S; + PushDeclContext(S, Context.getTranslationUnitDecl()); + + if (PP.getTargetInfo().getPointerWidth(0) >= 64) { + // Install [u]int128_t for 64-bit targets. + PushOnScopeChains(TypedefDecl::Create(Context, CurContext, + SourceLocation(), + &Context.Idents.get("__int128_t"), + Context.Int128Ty), TUScope); + PushOnScopeChains(TypedefDecl::Create(Context, CurContext, + SourceLocation(), + &Context.Idents.get("__uint128_t"), + Context.UnsignedInt128Ty), TUScope); + } + + + if (!PP.getLangOptions().ObjC1) return; + + if (Context.getObjCSelType().isNull()) { + // Synthesize "typedef struct objc_selector *SEL;" + RecordDecl *SelTag = CreateStructDecl(Context, "objc_selector"); + PushOnScopeChains(SelTag, TUScope); + + QualType SelT = Context.getPointerType(Context.getTagDeclType(SelTag)); + TypedefDecl *SelTypedef = TypedefDecl::Create(Context, CurContext, + SourceLocation(), + &Context.Idents.get("SEL"), + SelT); + PushOnScopeChains(SelTypedef, TUScope); + Context.setObjCSelType(Context.getTypeDeclType(SelTypedef)); + } + + if (Context.getObjCClassType().isNull()) { + RecordDecl *ClassTag = CreateStructDecl(Context, "objc_class"); + QualType ClassT = Context.getPointerType(Context.getTagDeclType(ClassTag)); + TypedefDecl *ClassTypedef = + TypedefDecl::Create(Context, CurContext, SourceLocation(), + &Context.Idents.get("Class"), ClassT); + PushOnScopeChains(ClassTag, TUScope); + PushOnScopeChains(ClassTypedef, TUScope); + Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef)); + } + + // Synthesize "@class Protocol; + if (Context.getObjCProtoType().isNull()) { + ObjCInterfaceDecl *ProtocolDecl = + ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(), + &Context.Idents.get("Protocol"), + SourceLocation(), true); + Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl)); + PushOnScopeChains(ProtocolDecl, TUScope); + } + + // Synthesize "typedef struct objc_object { Class isa; } *id;" + if (Context.getObjCIdType().isNull()) { + RecordDecl *ObjectTag = CreateStructDecl(Context, "objc_object"); + + QualType ObjT = Context.getPointerType(Context.getTagDeclType(ObjectTag)); + PushOnScopeChains(ObjectTag, TUScope); + TypedefDecl *IdTypedef = TypedefDecl::Create(Context, CurContext, + SourceLocation(), + &Context.Idents.get("id"), + ObjT); + PushOnScopeChains(IdTypedef, TUScope); + Context.setObjCIdType(Context.getTypeDeclType(IdTypedef)); + } +} + +Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, + bool CompleteTranslationUnit) + : LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), + Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), + ExternalSource(0), CurContext(0), PreDeclaratorDC(0), + CurBlock(0), PackContext(0), IdResolver(pp.getLangOptions()), + GlobalNewDeleteDeclared(false), + CompleteTranslationUnit(CompleteTranslationUnit), + CurrentInstantiationScope(0) { + + StdNamespace = 0; + TUScope = 0; + if (getLangOptions().CPlusPlus) + FieldCollector.reset(new CXXFieldCollector()); + + // Tell diagnostics how to render things from the AST library. + PP.getDiagnostics().SetArgToStringFn(ConvertArgToStringFn, &Context); +} + +/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast. +/// If there is already an implicit cast, merge into the existing one. +/// If isLvalue, the result of the cast is an lvalue. +void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, bool isLvalue) { + QualType ExprTy = Context.getCanonicalType(Expr->getType()); + QualType TypeTy = Context.getCanonicalType(Ty); + + if (ExprTy == TypeTy) + return; + + if (Expr->getType().getTypePtr()->isPointerType() && + Ty.getTypePtr()->isPointerType()) { + QualType ExprBaseType = + cast<PointerType>(ExprTy.getUnqualifiedType())->getPointeeType(); + QualType BaseType = + cast<PointerType>(TypeTy.getUnqualifiedType())->getPointeeType(); + if (ExprBaseType.getAddressSpace() != BaseType.getAddressSpace()) { + Diag(Expr->getExprLoc(), diag::err_implicit_pointer_address_space_cast) + << Expr->getSourceRange(); + } + } + + if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) { + ImpCast->setType(Ty); + ImpCast->setLvalueCast(isLvalue); + } else + Expr = new (Context) ImplicitCastExpr(Ty, Expr, isLvalue); +} + +void Sema::DeleteExpr(ExprTy *E) { + if (E) static_cast<Expr*>(E)->Destroy(Context); +} +void Sema::DeleteStmt(StmtTy *S) { + if (S) static_cast<Stmt*>(S)->Destroy(Context); +} + +/// ActOnEndOfTranslationUnit - This is called at the very end of the +/// translation unit when EOF is reached and all but the top-level scope is +/// popped. +void Sema::ActOnEndOfTranslationUnit() { + if (!CompleteTranslationUnit) + return; + + // C99 6.9.2p2: + // A declaration of an identifier for an object that has file + // scope without an initializer, and without a storage-class + // specifier or with the storage-class specifier static, + // constitutes a tentative definition. If a translation unit + // contains one or more tentative definitions for an identifier, + // and the translation unit contains no external definition for + // that identifier, then the behavior is exactly as if the + // translation unit contains a file scope declaration of that + // identifier, with the composite type as of the end of the + // translation unit, with an initializer equal to 0. + for (llvm::DenseMap<DeclarationName, VarDecl *>::iterator + D = TentativeDefinitions.begin(), + DEnd = TentativeDefinitions.end(); + D != DEnd; ++D) { + VarDecl *VD = D->second; + + if (VD->isInvalidDecl() || !VD->isTentativeDefinition(Context)) + continue; + + if (const IncompleteArrayType *ArrayT + = Context.getAsIncompleteArrayType(VD->getType())) { + if (RequireCompleteType(VD->getLocation(), + ArrayT->getElementType(), + diag::err_tentative_def_incomplete_type_arr)) + VD->setInvalidDecl(); + else { + // Set the length of the array to 1 (C99 6.9.2p5). + Diag(VD->getLocation(), diag::warn_tentative_incomplete_array); + llvm::APInt One(Context.getTypeSize(Context.getSizeType()), + true); + QualType T + = Context.getConstantArrayType(ArrayT->getElementType(), + One, ArrayType::Normal, 0); + VD->setType(T); + } + } else if (RequireCompleteType(VD->getLocation(), VD->getType(), + diag::err_tentative_def_incomplete_type)) + VD->setInvalidDecl(); + + // Notify the consumer that we've completed a tentative definition. + if (!VD->isInvalidDecl()) + Consumer.CompleteTentativeDefinition(VD); + + } +} + + +//===----------------------------------------------------------------------===// +// Helper functions. +//===----------------------------------------------------------------------===// + +/// getCurFunctionDecl - If inside of a function body, this returns a pointer +/// to the function decl for the function being parsed. If we're currently +/// in a 'block', this returns the containing context. +FunctionDecl *Sema::getCurFunctionDecl() { + DeclContext *DC = CurContext; + while (isa<BlockDecl>(DC)) + DC = DC->getParent(); + return dyn_cast<FunctionDecl>(DC); +} + +ObjCMethodDecl *Sema::getCurMethodDecl() { + DeclContext *DC = CurContext; + while (isa<BlockDecl>(DC)) + DC = DC->getParent(); + return dyn_cast<ObjCMethodDecl>(DC); +} + +NamedDecl *Sema::getCurFunctionOrMethodDecl() { + DeclContext *DC = CurContext; + while (isa<BlockDecl>(DC)) + DC = DC->getParent(); + if (isa<ObjCMethodDecl>(DC) || isa<FunctionDecl>(DC)) + return cast<NamedDecl>(DC); + return 0; +} + +Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { + this->Emit(); + + // If this is not a note, and we're in a template instantiation + // that is different from the last template instantiation where + // we emitted an error, print a template instantiation + // backtrace. + if (!SemaRef.Diags.isBuiltinNote(DiagID) && + !SemaRef.ActiveTemplateInstantiations.empty() && + SemaRef.ActiveTemplateInstantiations.back() + != SemaRef.LastTemplateInstantiationErrorContext) { + SemaRef.PrintInstantiationStack(); + SemaRef.LastTemplateInstantiationErrorContext + = SemaRef.ActiveTemplateInstantiations.back(); + } +} diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h new file mode 100644 index 0000000..c428d29 --- /dev/null +++ b/lib/Sema/Sema.h @@ -0,0 +1,2814 @@ +//===--- Sema.h - Semantic Analysis & AST Building --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Sema class, which performs semantic analysis and +// builds ASTs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_SEMA_H +#define LLVM_CLANG_AST_SEMA_H + +#include "IdentifierResolver.h" +#include "CXXFieldCollector.h" +#include "SemaOverload.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Parse/Action.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/OwningPtr.h" +#include <string> +#include <vector> + +namespace llvm { + class APSInt; +} + +namespace clang { + class ASTContext; + class ASTConsumer; + class Preprocessor; + class Decl; + class DeclContext; + class DeclSpec; + class ExternalSemaSource; + class NamedDecl; + class Stmt; + class Expr; + class InitListExpr; + class DesignatedInitExpr; + class CallExpr; + class DeclRefExpr; + class VarDecl; + class ParmVarDecl; + class TypedefDecl; + class FunctionDecl; + class QualType; + class LangOptions; + class Token; + class IntegerLiteral; + class StringLiteral; + class ArrayType; + class LabelStmt; + class SwitchStmt; + class CXXTryStmt; + class ExtVectorType; + class TypedefDecl; + class TemplateDecl; + class TemplateArgument; + class TemplateArgumentList; + class TemplateParameterList; + class TemplateTemplateParmDecl; + class ClassTemplatePartialSpecializationDecl; + class ClassTemplateDecl; + class ObjCInterfaceDecl; + class ObjCCompatibleAliasDecl; + class ObjCProtocolDecl; + class ObjCImplDecl; + class ObjCImplementationDecl; + class ObjCCategoryImplDecl; + class ObjCCategoryDecl; + class ObjCIvarDecl; + class ObjCMethodDecl; + class ObjCPropertyDecl; + class ObjCContainerDecl; + class BasePaths; + struct MemberLookupCriteria; + class CXXTemporary; + +/// BlockSemaInfo - When a block is being parsed, this contains information +/// about the block. It is pointed to from Sema::CurBlock. +struct BlockSemaInfo { + llvm::SmallVector<ParmVarDecl*, 8> Params; + bool hasPrototype; + bool isVariadic; + bool hasBlockDeclRefExprs; + + BlockDecl *TheDecl; + + /// TheScope - This is the scope for the block itself, which contains + /// arguments etc. + Scope *TheScope; + + /// ReturnType - This will get set to block result type, by looking at + /// return types, if any, in the block body. + Type *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; + + /// SavedFunctionNeedsScopeChecking - This is the value of + /// CurFunctionNeedsScopeChecking at the point when the block started. + bool SavedFunctionNeedsScopeChecking; + + /// PrevBlockInfo - If this is nested inside another block, this points + /// to the outer block. + BlockSemaInfo *PrevBlockInfo; +}; + +/// Sema - This implements semantic analysis and AST building for C. +class Sema : public Action { + Sema(const Sema&); // DO NOT IMPLEMENT + void operator=(const Sema&); // DO NOT IMPLEMENT +public: + const LangOptions &LangOpts; + Preprocessor &PP; + ASTContext &Context; + ASTConsumer &Consumer; + Diagnostic &Diags; + SourceManager &SourceMgr; + + /// \brief Source of additional semantic information. + ExternalSemaSource *ExternalSource; + + /// CurContext - This is the current declaration context of parsing. + DeclContext *CurContext; + + /// PreDeclaratorDC - Keeps the declaration context before switching to the + /// context of a declarator's nested-name-specifier. + DeclContext *PreDeclaratorDC; + + /// 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. + /// + /// 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; + + /// 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. + llvm::SmallVector<TypedefDecl*, 24> ExtVectorDecls; + + /// ObjCCategoryImpls - Maintain a list of category implementations so + /// we can check for duplicates and find local method declarations. + llvm::SmallVector<ObjCCategoryImplDecl*, 8> ObjCCategoryImpls; + + /// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes. + llvm::OwningPtr<CXXFieldCollector> FieldCollector; + + typedef llvm::SmallPtrSet<const CXXRecordDecl*, 8> RecordDeclSetTy; + + /// PureVirtualClassDiagSet - a set of class declarations which we have + /// emitted a list of pure virtual functions. Used to prevent emitting the + /// same list more than once. + llvm::OwningPtr<RecordDeclSetTy> PureVirtualClassDiagSet; + + /// \brief A mapping from external names to the most recent + /// locally-scoped external declaration with that name. + /// + /// This map contains external declarations introduced in local + /// scoped, e.g., + /// + /// \code + /// void f() { + /// void foo(int, int); + /// } + /// \endcode + /// + /// Here, the name "foo" will be associated with the declaration on + /// "foo" within f. This name is not visible outside of + /// "f". However, we still find it in two cases: + /// + /// - If we are declaring another external with the name "foo", we + /// can find "foo" as a previous declaration, so that the types + /// of this external declaration can be checked for + /// compatibility. + /// + /// - If we would implicitly declare "foo" (e.g., due to a call to + /// "foo" in C when no prototype or definition is visible), then + /// we find this declaration of "foo" and complain that it is + /// not visible. + llvm::DenseMap<DeclarationName, NamedDecl *> LocallyScopedExternalDecls; + + /// \brief The set of tentative declarations seen so far in this + /// translation unit for which no definition has been seen. + /// + /// The tentative declarations are indexed by the name of the + /// declaration, and only the most recent tentative declaration for + /// a given variable will be recorded here. + llvm::DenseMap<DeclarationName, VarDecl *> TentativeDefinitions; + + IdentifierResolver IdResolver; + + /// Translation Unit Scope - useful to Objective-C actions that need + /// to lookup file scope declarations in the "ordinary" C decl namespace. + /// For example, user-defined classes, built-in "id" type, etc. + Scope *TUScope; + + /// The C++ "std" namespace, where the standard library resides. Cached here + /// by GetStdNamespace + NamespaceDecl *StdNamespace; + + /// A flag to remember whether the implicit forms of operator new and delete + /// have been declared. + bool GlobalNewDeleteDeclared; + + /// \brief Whether the code handled by Sema should be considered a + /// complete translation unit or not. + /// + /// When true (which is generally the case), Sema will perform + /// end-of-translation-unit semantic tasks (such as creating + /// initializers for tentative definitions in C) once parsing has + /// completed. This flag will be false when building PCH files, + /// since a PCH file is by definition not a complete translation + /// unit. + bool CompleteTranslationUnit; + + typedef llvm::DenseMap<Selector, ObjCMethodList> MethodPool; + + /// Instance/Factory Method Pools - allows efficient lookup when typechecking + /// messages to "id". We need to maintain a list, since selectors can have + /// differing signatures across classes. In Cocoa, this happens to be + /// extremely uncommon (only 1% of selectors are "overloaded"). + MethodPool InstanceMethodPool; + MethodPool FactoryMethodPool; + + MethodPool::iterator ReadMethodPool(Selector Sel, bool isInstance); + + /// Private Helper predicate to check for 'self'. + bool isSelfExpr(Expr *RExpr); +public: + Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, + bool CompleteTranslationUnit = true); + ~Sema() { + if (PackContext) FreePackedContext(); + } + + const LangOptions &getLangOptions() const { return LangOpts; } + Diagnostic &getDiagnostics() const { return Diags; } + SourceManager &getSourceManager() const { return SourceMgr; } + + /// \brief Helper class that creates diagnostics with optional + /// template instantiation stacks. + /// + /// This class provides a wrapper around the basic DiagnosticBuilder + /// class that emits diagnostics. SemaDiagnosticBuilder is + /// responsible for emitting the diagnostic (as DiagnosticBuilder + /// does) and, if the diagnostic comes from inside a template + /// instantiation, printing the template instantiation stack as + /// well. + class SemaDiagnosticBuilder : public DiagnosticBuilder { + Sema &SemaRef; + unsigned DiagID; + + public: + SemaDiagnosticBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID) + : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) { } + + ~SemaDiagnosticBuilder(); + }; + + /// \brief Emit a diagnostic. + SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { + DiagnosticBuilder DB = Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID); + return SemaDiagnosticBuilder(DB, *this, DiagID); + } + + virtual void DeleteExpr(ExprTy *E); + virtual void DeleteStmt(StmtTy *S); + + OwningExprResult Owned(Expr* E) { return OwningExprResult(*this, E); } + OwningExprResult Owned(ExprResult R) { + if (R.isInvalid()) + return ExprError(); + return OwningExprResult(*this, R.get()); + } + OwningStmtResult Owned(Stmt* S) { return OwningStmtResult(*this, S); } + + virtual void ActOnEndOfTranslationUnit(); + + /// 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; + } + + /// getSwitchStack - This is returns the switch stack for the current block or + /// function. + llvm::SmallVector<SwitchStmt*,8> &getSwitchStack() { + return CurBlock ? CurBlock->SwitchStack : FunctionSwitchStack; + } + + //===--------------------------------------------------------------------===// + // Type Analysis / Processing: SemaType.cpp. + // + QualType adjustParameterType(QualType T); + QualType ConvertDeclSpecToType(const DeclSpec &DS, SourceLocation DeclLoc, + bool &IsInvalid); + void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL); + QualType BuildPointerType(QualType T, unsigned Quals, + SourceLocation Loc, DeclarationName Entity); + QualType BuildReferenceType(QualType T, bool LValueRef, unsigned Quals, + SourceLocation Loc, DeclarationName Entity); + QualType BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, + Expr *ArraySize, unsigned Quals, + SourceLocation Loc, DeclarationName Entity); + QualType BuildFunctionType(QualType T, + QualType *ParamTypes, unsigned NumParamTypes, + bool Variadic, unsigned Quals, + SourceLocation Loc, DeclarationName Entity); + QualType GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip = 0, + TagDecl **OwnedDecl = 0); + DeclarationName GetNameForDeclarator(Declarator &D); + bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range); + bool CheckDistantExceptionSpec(QualType T); + + QualType ObjCGetTypeForMethodDefinition(DeclPtrTy D); + + bool UnwrapSimilarPointerTypes(QualType& T1, QualType& T2); + + virtual TypeResult ActOnTypeName(Scope *S, Declarator &D); + + bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag, + SourceRange Range1 = SourceRange(), + SourceRange Range2 = SourceRange(), + QualType PrintType = QualType()); + + QualType getQualifiedNameType(const CXXScopeSpec &SS, QualType T); + + //===--------------------------------------------------------------------===// + // Symbol table / Decl tracking callbacks: SemaDecl.cpp. + // + + /// getDeclName - Return a pretty name for the specified decl if possible, or + /// an empty string if not. This is used for pretty crash reporting. + virtual std::string getDeclName(DeclPtrTy D); + + DeclGroupPtrTy ConvertDeclToDeclGroup(DeclPtrTy Ptr); + + virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc, + Scope *S, const CXXScopeSpec *SS); + virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S); + + virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D) { + return ActOnDeclarator(S, D, false); + } + DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D, bool IsFunctionDefinition); + void RegisterLocallyScopedExternCDecl(NamedDecl *ND, NamedDecl *PrevDecl, + Scope *S); + void DiagnoseFunctionSpecifiers(Declarator& D); + NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, + QualType R, Decl* PrevDecl, + bool &Redeclaration); + NamedDecl* ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, + QualType R, NamedDecl* PrevDecl, + bool &Redeclaration); + void CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl, + bool &Redeclaration); + NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, + QualType R, NamedDecl* PrevDecl, + bool IsFunctionDefinition, + bool &Redeclaration); + void CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, + bool &Redeclaration, + bool &OverloadableAttrRequired); + virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D); + virtual void ActOnParamDefaultArgument(DeclPtrTy param, + SourceLocation EqualLoc, + ExprArg defarg); + virtual void ActOnParamUnparsedDefaultArgument(DeclPtrTy param, + SourceLocation EqualLoc); + virtual void ActOnParamDefaultArgumentError(DeclPtrTy param); + virtual void AddInitializerToDecl(DeclPtrTy dcl, FullExprArg init); + void AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit); + void ActOnUninitializedDecl(DeclPtrTy dcl); + virtual void SetDeclDeleted(DeclPtrTy dcl, SourceLocation DelLoc); + virtual DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, + DeclPtrTy *Group, + unsigned NumDecls); + virtual void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, + SourceLocation LocAfterDecls); + virtual DeclPtrTy ActOnStartOfFunctionDef(Scope *S, Declarator &D); + virtual DeclPtrTy ActOnStartOfFunctionDef(Scope *S, DeclPtrTy D); + virtual void ActOnStartOfObjCMethodDef(Scope *S, DeclPtrTy D); + + virtual DeclPtrTy ActOnFinishFunctionBody(DeclPtrTy Decl, StmtArg Body); + DeclPtrTy ActOnFinishFunctionBody(DeclPtrTy Decl, StmtArg Body, + bool IsInstantiation); + void DiagnoseInvalidJumps(Stmt *Body); + virtual DeclPtrTy ActOnFileScopeAsmDecl(SourceLocation Loc, ExprArg expr); + + /// Scope actions. + virtual void ActOnPopScope(SourceLocation Loc, Scope *S); + virtual void ActOnTranslationUnitScope(SourceLocation Loc, Scope *S); + + /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with + /// no declarator (e.g. "struct foo;") is parsed. + virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS); + + bool InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, + RecordDecl *AnonRecord); + virtual DeclPtrTy BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, + RecordDecl *Record); + + bool isAcceptableTagRedeclaration(const TagDecl *Previous, + TagDecl::TagKind NewTag, + SourceLocation NewTagLoc, + const IdentifierInfo &Name); + + virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, + SourceLocation KWLoc, const CXXScopeSpec &SS, + IdentifierInfo *Name, SourceLocation NameLoc, + AttributeList *Attr, AccessSpecifier AS, + bool &OwnedDecl); + + virtual void ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, + IdentifierInfo *ClassName, + llvm::SmallVectorImpl<DeclPtrTy> &Decls); + virtual DeclPtrTy ActOnField(Scope *S, DeclPtrTy TagD, + SourceLocation DeclStart, + Declarator &D, ExprTy *BitfieldWidth); + + FieldDecl *HandleField(Scope *S, RecordDecl *TagD, SourceLocation DeclStart, + Declarator &D, Expr *BitfieldWidth, + AccessSpecifier AS); + + FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T, + RecordDecl *Record, SourceLocation Loc, + bool Mutable, Expr *BitfieldWidth, + AccessSpecifier AS, NamedDecl *PrevDecl, + Declarator *D = 0); + + virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart, + Declarator &D, ExprTy *BitfieldWidth, + tok::ObjCKeywordKind visibility); + + // This is used for both record definitions and ObjC interface declarations. + virtual void ActOnFields(Scope* S, + SourceLocation RecLoc, DeclPtrTy TagDecl, + DeclPtrTy *Fields, unsigned NumFields, + SourceLocation LBrac, SourceLocation RBrac, + AttributeList *AttrList); + + /// ActOnTagStartDefinition - Invoked when we have entered the + /// scope of a tag's definition (e.g., for an enumeration, class, + /// struct, or union). + virtual void ActOnTagStartDefinition(Scope *S, DeclPtrTy TagDecl); + + /// ActOnTagFinishDefinition - Invoked once we have finished parsing + /// the definition of a tag (enumeration, class, struct, or union). + virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl); + + EnumConstantDecl *CheckEnumConstant(EnumDecl *Enum, + EnumConstantDecl *LastEnumConst, + SourceLocation IdLoc, + IdentifierInfo *Id, + ExprArg val); + + virtual DeclPtrTy ActOnEnumConstant(Scope *S, DeclPtrTy EnumDecl, + DeclPtrTy LastEnumConstant, + SourceLocation IdLoc, IdentifierInfo *Id, + SourceLocation EqualLoc, ExprTy *Val); + virtual void ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, + SourceLocation RBraceLoc, DeclPtrTy EnumDecl, + DeclPtrTy *Elements, unsigned NumElements); + + DeclContext *getContainingDC(DeclContext *DC); + + /// Set the current declaration context until it gets popped. + void PushDeclContext(Scope *S, DeclContext *DC); + void PopDeclContext(); + + /// getCurFunctionDecl - If inside of a function body, this returns a pointer + /// to the function decl for the function being parsed. If we're currently + /// in a 'block', this returns the containing context. + FunctionDecl *getCurFunctionDecl(); + + /// getCurMethodDecl - If inside of a method body, this returns a pointer to + /// the method decl for the method being parsed. If we're currently + /// in a 'block', this returns the containing context. + ObjCMethodDecl *getCurMethodDecl(); + + /// getCurFunctionOrMethodDecl - Return the Decl for the current ObjC method + /// or C function we're in, otherwise return null. If we're currently + /// in a 'block', this returns the containing context. + NamedDecl *getCurFunctionOrMethodDecl(); + + /// Add this decl to the scope shadowed decl chains. + void PushOnScopeChains(NamedDecl *D, Scope *S); + + /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true + /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns + /// true if 'D' belongs to the given declaration context. + bool isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S = 0) { + return IdResolver.isDeclInScope(D, Ctx, Context, S); + } + + + /// Subroutines of ActOnDeclarator(). + TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T); + void MergeTypeDefDecl(TypedefDecl *New, Decl *Old); + bool MergeFunctionDecl(FunctionDecl *New, Decl *Old); + bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old); + void MergeVarDecl(VarDecl *New, Decl *Old); + bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old); + + /// C++ Overloading. + bool IsOverload(FunctionDecl *New, Decl* OldD, + OverloadedFunctionDecl::function_iterator &MatchedDecl); + ImplicitConversionSequence + TryImplicitConversion(Expr* From, QualType ToType, + bool SuppressUserConversions = false, + bool AllowExplicit = false, + bool ForceRValue = false); + bool IsStandardConversion(Expr *From, QualType ToType, + StandardConversionSequence& SCS); + bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType); + bool IsFloatingPointPromotion(QualType FromType, QualType ToType); + bool IsComplexPromotion(QualType FromType, QualType ToType); + bool IsPointerConversion(Expr *From, QualType FromType, QualType ToType, + QualType& ConvertedType, bool &IncompatibleObjC); + bool isObjCPointerConversion(QualType FromType, QualType ToType, + QualType& ConvertedType, bool &IncompatibleObjC); + bool CheckPointerConversion(Expr *From, QualType ToType); + bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType, + QualType &ConvertedType); + bool CheckMemberPointerConversion(Expr *From, QualType ToType); + bool IsQualificationConversion(QualType FromType, QualType ToType); + bool IsUserDefinedConversion(Expr *From, QualType ToType, + UserDefinedConversionSequence& User, + bool AllowConversionFunctions, + bool AllowExplicit, bool ForceRValue); + + ImplicitConversionSequence::CompareKind + CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1, + const ImplicitConversionSequence& ICS2); + + ImplicitConversionSequence::CompareKind + CompareStandardConversionSequences(const StandardConversionSequence& SCS1, + const StandardConversionSequence& SCS2); + + ImplicitConversionSequence::CompareKind + CompareQualificationConversions(const StandardConversionSequence& SCS1, + const StandardConversionSequence& SCS2); + + ImplicitConversionSequence::CompareKind + CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, + const StandardConversionSequence& SCS2); + + ImplicitConversionSequence + TryCopyInitialization(Expr* From, QualType ToType, + bool SuppressUserConversions = false, + bool ForceRValue = false); + bool PerformCopyInitialization(Expr *&From, QualType ToType, + const char *Flavor, bool Elidable = false); + + ImplicitConversionSequence + TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method); + bool PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method); + + ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From); + bool PerformContextuallyConvertToBool(Expr *&From); + + /// OverloadingResult - Capture the result of performing overload + /// resolution. + enum OverloadingResult { + OR_Success, ///< Overload resolution succeeded. + OR_No_Viable_Function, ///< No viable function found. + OR_Ambiguous, ///< Ambiguous candidates found. + OR_Deleted ///< Overload resoltuion refers to a deleted function. + }; + + typedef llvm::SmallPtrSet<FunctionDecl *, 16> FunctionSet; + typedef llvm::SmallPtrSet<NamespaceDecl *, 16> AssociatedNamespaceSet; + typedef llvm::SmallPtrSet<CXXRecordDecl *, 16> AssociatedClassSet; + + void AddOverloadCandidate(FunctionDecl *Function, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversions = false, + bool ForceRValue = false); + void AddFunctionCandidates(const FunctionSet &Functions, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversions = false); + void AddMethodCandidate(CXXMethodDecl *Method, + Expr *Object, Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversions = false, + bool ForceRValue = false); + void AddConversionCandidate(CXXConversionDecl *Conversion, + Expr *From, QualType ToType, + OverloadCandidateSet& CandidateSet); + void AddSurrogateCandidate(CXXConversionDecl *Conversion, + const FunctionProtoType *Proto, + Expr *Object, Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet); + void AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, + SourceLocation OpLoc, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet, + SourceRange OpRange = SourceRange()); + void AddMemberOperatorCandidates(OverloadedOperatorKind Op, + SourceLocation OpLoc, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet, + SourceRange OpRange = SourceRange()); + void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet, + bool IsAssignmentOperator = false, + unsigned NumContextualBoolArguments = 0); + void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet); + void AddArgumentDependentLookupCandidates(DeclarationName Name, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet); + bool isBetterOverloadCandidate(const OverloadCandidate& Cand1, + const OverloadCandidate& Cand2); + OverloadingResult BestViableFunction(OverloadCandidateSet& CandidateSet, + OverloadCandidateSet::iterator& Best); + void PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, + bool OnlyViable); + + FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, + bool Complain); + void FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn); + + FunctionDecl *ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee, + DeclarationName UnqualifiedName, + SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc, + bool &ArgumentDependentLookup); + + OwningExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc, + unsigned Opc, + FunctionSet &Functions, + ExprArg input); + + OwningExprResult CreateOverloadedBinOp(SourceLocation OpLoc, + unsigned Opc, + FunctionSet &Functions, + Expr *LHS, Expr *RHS); + + ExprResult + BuildCallToMemberFunction(Scope *S, Expr *MemExpr, + SourceLocation LParenLoc, Expr **Args, + unsigned NumArgs, SourceLocation *CommaLocs, + SourceLocation RParenLoc); + ExprResult + BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc); + + ExprResult BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, + SourceLocation MemberLoc, + IdentifierInfo &Member); + + /// Helpers for dealing with function parameters. + bool CheckParmsForFunctionDef(FunctionDecl *FD); + void CheckCXXDefaultArguments(FunctionDecl *FD); + void CheckExtraCXXDefaultArguments(Declarator &D); + + Scope *getNonFieldDeclScope(Scope *S); + + /// \name Name lookup + /// + /// These routines provide name lookup that is used during semantic + /// analysis to resolve the various kinds of names (identifiers, + /// overloaded operator names, constructor names, etc.) into zero or + /// more declarations within a particular scope. The major entry + /// points are LookupName, which performs unqualified name lookup, + /// and LookupQualifiedName, which performs qualified name lookup. + /// + /// All name lookup is performed based on some specific criteria, + /// which specify what names will be visible to name lookup and how + /// far name lookup should work. These criteria are important both + /// for capturing language semantics (certain lookups will ignore + /// certain names, for example) and for performance, since name + /// lookup is often a bottleneck in the compilation of C++. Name + /// lookup criteria is specified via the LookupCriteria enumeration. + /// + /// The results of name lookup can vary based on the kind of name + /// lookup performed, the current language, and the translation + /// unit. In C, for example, name lookup will either return nothing + /// (no entity found) or a single declaration. In C++, name lookup + /// can additionally refer to a set of overloaded functions or + /// result in an ambiguity. All of the possible results of name + /// lookup are captured by the LookupResult class, which provides + /// the ability to distinguish among them. + //@{ + + /// @brief Describes the kind of name lookup to perform. + enum LookupNameKind { + /// Ordinary name lookup, which finds ordinary names (functions, + /// variables, typedefs, etc.) in C and most kinds of names + /// (functions, variables, members, types, etc.) in C++. + LookupOrdinaryName = 0, + /// Tag name lookup, which finds the names of enums, classes, + /// structs, and unions. + LookupTagName, + /// Member name lookup, which finds the names of + /// class/struct/union members. + LookupMemberName, + // Look up of an operator name (e.g., operator+) for use with + // operator overloading. This lookup is similar to ordinary name + // lookup, but will ignore any declarations that are class + // members. + LookupOperatorName, + /// Look up of a name that precedes the '::' scope resolution + /// operator in C++. This lookup completely ignores operator, + /// function, and enumerator names (C++ [basic.lookup.qual]p1). + LookupNestedNameSpecifierName, + /// Look up a namespace name within a C++ using directive or + /// namespace alias definition, ignoring non-namespace names (C++ + /// [basic.lookup.udir]p1). + LookupNamespaceName, + /// Look up an ordinary name that is going to be redeclared as a + /// name with linkage. This lookup ignores any declarations that + /// are outside of the current scope unless they have linkage. See + /// C99 6.2.2p4-5 and C++ [basic.link]p6. + LookupRedeclarationWithLinkage, + /// Look up the name of an Objective-C protocol. + LookupObjCProtocolName, + /// Look up the name of an Objective-C implementation + LookupObjCImplementationName, + /// Look up the name of an Objective-C category implementation + LookupObjCCategoryImplName + }; + + /// @brief Represents the results of name lookup. + /// + /// An instance of the LookupResult class captures the results of a + /// single name lookup, which can return no result (nothing found), + /// a single declaration, a set of overloaded functions, or an + /// ambiguity. Use the getKind() method to determine which of these + /// results occurred for a given lookup. + /// + /// Any non-ambiguous lookup can be converted into a single + /// (possibly NULL) @c NamedDecl* via a conversion function or the + /// getAsDecl() method. This conversion permits the common-case + /// usage in C and Objective-C where name lookup will always return + /// a single declaration. + struct LookupResult { + /// The kind of entity that is actually stored within the + /// LookupResult object. + enum { + /// First is a single declaration (a NamedDecl*), which may be NULL. + SingleDecl, + + /// First is a single declaration (an OverloadedFunctionDecl*). + OverloadedDeclSingleDecl, + + /// [First, Last) is an iterator range represented as opaque + /// pointers used to reconstruct IdentifierResolver::iterators. + OverloadedDeclFromIdResolver, + + /// [First, Last) is an iterator range represented as opaque + /// pointers used to reconstruct DeclContext::lookup_iterators. + OverloadedDeclFromDeclContext, + + /// First is a pointer to a BasePaths structure, which is owned + /// by the LookupResult. Last is non-zero to indicate that the + /// ambiguity is caused by two names found in base class + /// subobjects of different types. + AmbiguousLookupStoresBasePaths, + + /// [First, Last) is an iterator range represented as opaque + /// pointers used to reconstruct new'ed Decl*[] array containing + /// found ambiguous decls. LookupResult is owner of this array. + AmbiguousLookupStoresDecls + } StoredKind; + + /// The first lookup result, whose contents depend on the kind of + /// lookup result. This may be a NamedDecl* (if StoredKind == + /// SingleDecl), OverloadedFunctionDecl* (if StoredKind == + /// OverloadedDeclSingleDecl), the opaque pointer from an + /// IdentifierResolver::iterator (if StoredKind == + /// OverloadedDeclFromIdResolver), a DeclContext::lookup_iterator + /// (if StoredKind == OverloadedDeclFromDeclContext), or a + /// BasePaths pointer (if StoredKind == AmbiguousLookupStoresBasePaths). + mutable uintptr_t First; + + /// The last lookup result, whose contents depend on the kind of + /// lookup result. This may be unused (if StoredKind == + /// SingleDecl), it may have the same type as First (for + /// overloaded function declarations), or is may be used as a + /// Boolean value (if StoredKind == AmbiguousLookupStoresBasePaths). + mutable uintptr_t Last; + + /// Context - The context in which we will build any + /// OverloadedFunctionDecl nodes needed by the conversion to + /// Decl*. + ASTContext *Context; + + /// @brief The kind of entity found by name lookup. + enum LookupKind { + /// @brief No entity found met the criteria. + NotFound = 0, + + /// @brief Name lookup found a single declaration that met the + /// criteria. getAsDecl will return this declaration. + Found, + + /// @brief Name lookup found a set of overloaded functions that + /// met the criteria. getAsDecl will turn this set of overloaded + /// functions into an OverloadedFunctionDecl. + FoundOverloaded, + + /// Name lookup results in an ambiguity because multiple + /// entities that meet the lookup criteria were found in + /// subobjects of different types. For example: + /// @code + /// struct A { void f(int); } + /// struct B { void f(double); } + /// struct C : A, B { }; + /// void test(C c) { + /// c.f(0); // error: A::f and B::f come from subobjects of different + /// // types. overload resolution is not performed. + /// } + /// @endcode + AmbiguousBaseSubobjectTypes, + + /// Name lookup results in an ambiguity because multiple + /// nonstatic entities that meet the lookup criteria were found + /// in different subobjects of the same type. For example: + /// @code + /// struct A { int x; }; + /// struct B : A { }; + /// struct C : A { }; + /// struct D : B, C { }; + /// int test(D d) { + /// return d.x; // error: 'x' is found in two A subobjects (of B and C) + /// } + /// @endcode + AmbiguousBaseSubobjects, + + /// Name lookup results in an ambiguity because multiple definitions + /// of entity that meet the lookup criteria were found in different + /// declaration contexts. + /// @code + /// namespace A { + /// int i; + /// namespace B { int i; } + /// int test() { + /// using namespace B; + /// return i; // error 'i' is found in namespace A and A::B + /// } + /// } + /// @endcode + AmbiguousReference + }; + + static LookupResult CreateLookupResult(ASTContext &Context, NamedDecl *D); + + static LookupResult CreateLookupResult(ASTContext &Context, + IdentifierResolver::iterator F, + IdentifierResolver::iterator L); + + static LookupResult CreateLookupResult(ASTContext &Context, + DeclContext::lookup_iterator F, + DeclContext::lookup_iterator L); + + static LookupResult CreateLookupResult(ASTContext &Context, BasePaths *Paths, + bool DifferentSubobjectTypes) { + LookupResult Result; + Result.StoredKind = AmbiguousLookupStoresBasePaths; + Result.First = reinterpret_cast<uintptr_t>(Paths); + Result.Last = DifferentSubobjectTypes? 1 : 0; + Result.Context = &Context; + return Result; + } + + template <typename Iterator> + static LookupResult CreateLookupResult(ASTContext &Context, + Iterator B, std::size_t Len) { + NamedDecl ** Array = new NamedDecl*[Len]; + for (std::size_t Idx = 0; Idx < Len; ++Idx, ++B) + Array[Idx] = *B; + LookupResult Result; + Result.StoredKind = AmbiguousLookupStoresDecls; + Result.First = reinterpret_cast<uintptr_t>(Array); + Result.Last = reinterpret_cast<uintptr_t>(Array + Len); + Result.Context = &Context; + return Result; + } + + LookupKind getKind() const; + + /// @brief Determine whether name look found something. + operator bool() const { return getKind() != NotFound; } + + /// @brief Determines whether the lookup resulted in an ambiguity. + bool isAmbiguous() const { + return StoredKind == AmbiguousLookupStoresBasePaths || + StoredKind == AmbiguousLookupStoresDecls; + } + + /// @brief Allows conversion of a lookup result into a + /// declaration, with the same behavior as getAsDecl. + operator NamedDecl*() const { return getAsDecl(); } + + NamedDecl* getAsDecl() const; + + BasePaths *getBasePaths() const; + + /// \brief Iterate over the results of name lookup. + /// + /// The @c iterator class provides iteration over the results of a + /// non-ambiguous name lookup. + class iterator { + /// The LookupResult structure we're iterating through. + LookupResult *Result; + + /// The current position of this iterator within the sequence of + /// results. This value will have the same representation as the + /// @c First field in the LookupResult structure. + mutable uintptr_t Current; + + public: + typedef NamedDecl * value_type; + typedef NamedDecl * reference; + typedef NamedDecl * pointer; + typedef std::ptrdiff_t difference_type; + typedef std::forward_iterator_tag iterator_category; + + iterator() : Result(0), Current(0) { } + + iterator(LookupResult *Res, uintptr_t Cur) : Result(Res), Current(Cur) { } + + reference operator*() const; + + pointer operator->() const { return **this; } + + iterator &operator++(); + + iterator operator++(int) { + iterator tmp(*this); + ++(*this); + return tmp; + } + + friend inline bool operator==(iterator const& x, iterator const& y) { + return x.Current == y.Current; + } + + friend inline bool operator!=(iterator const& x, iterator const& y) { + return x.Current != y.Current; + } + }; + friend class iterator; + + iterator begin(); + iterator end(); + + /// \brief Free the memory associated with this lookup. + void Destroy(); + }; + +private: + typedef llvm::SmallVector<LookupResult, 3> LookupResultsVecTy; + + std::pair<bool, LookupResult> CppLookupName(Scope *S, DeclarationName Name, + LookupNameKind NameKind, + bool RedeclarationOnly); + ObjCMethodDecl *FindMethodInNestedImplementations( + const ObjCInterfaceDecl *IFace, + const Selector &Sel); + +public: + /// Determines whether D is a suitable lookup result according to the + /// lookup criteria. + static bool isAcceptableLookupResult(NamedDecl *D, LookupNameKind NameKind, + unsigned IDNS) { + switch (NameKind) { + case Sema::LookupOrdinaryName: + case Sema::LookupTagName: + case Sema::LookupMemberName: + case Sema::LookupRedeclarationWithLinkage: // FIXME: check linkage, scoping + case Sema::LookupObjCProtocolName: + case Sema::LookupObjCImplementationName: + case Sema::LookupObjCCategoryImplName: + return D->isInIdentifierNamespace(IDNS); + + case Sema::LookupOperatorName: + return D->isInIdentifierNamespace(IDNS) && + !D->getDeclContext()->isRecord(); + + case Sema::LookupNestedNameSpecifierName: + return isa<TypedefDecl>(D) || D->isInIdentifierNamespace(Decl::IDNS_Tag); + + case Sema::LookupNamespaceName: + return isa<NamespaceDecl>(D) || isa<NamespaceAliasDecl>(D); + } + + assert(false && + "isAcceptableLookupResult always returns before this point"); + return false; + } + + LookupResult LookupName(Scope *S, DeclarationName Name, + LookupNameKind NameKind, + bool RedeclarationOnly = false, + bool AllowBuiltinCreation = true, + SourceLocation Loc = SourceLocation()); + LookupResult LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name, + LookupNameKind NameKind, + bool RedeclarationOnly = false); + LookupResult LookupParsedName(Scope *S, const CXXScopeSpec *SS, + DeclarationName Name, + LookupNameKind NameKind, + bool RedeclarationOnly = false, + bool AllowBuiltinCreation = true, + SourceLocation Loc = SourceLocation()); + + ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II); + ObjCImplementationDecl *LookupObjCImplementation(IdentifierInfo *II); + ObjCCategoryImplDecl *LookupObjCCategoryImpl(IdentifierInfo *II); + + void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, + QualType T1, QualType T2, + FunctionSet &Functions); + + void ArgumentDependentLookup(DeclarationName Name, + Expr **Args, unsigned NumArgs, + FunctionSet &Functions); + + void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs, + AssociatedNamespaceSet &AssociatedNamespaces, + AssociatedClassSet &AssociatedClasses); + + bool DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name, + SourceLocation NameLoc, + SourceRange LookupRange = SourceRange()); + //@} + + ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id); + NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, + Scope *S, bool ForRedeclaration, + SourceLocation Loc); + NamedDecl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II, + Scope *S); + void AddKnownFunctionAttributes(FunctionDecl *FD); + + // More parsing and symbol table subroutines. + + // Decl attributes - this routine is the top level dispatcher. + void ProcessDeclAttributes(Decl *D, const Declarator &PD); + void ProcessDeclAttributeList(Decl *D, const AttributeList *AttrList); + + void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method, + bool &IncompleteImpl); + void WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethod, + ObjCMethodDecl *IntfMethod); + bool QualifiedIdConformsQualifiedId(QualType LHS, QualType RHS); + + NamespaceDecl *GetStdNamespace(); + + bool isPropertyReadonly(ObjCPropertyDecl *PropertyDecl, + ObjCInterfaceDecl *IDecl); + + /// CheckProtocolMethodDefs - This routine checks unimplemented + /// methods declared in protocol, and those referenced by it. + /// \param IDecl - Used for checking for methods which may have been + /// inherited. + void CheckProtocolMethodDefs(SourceLocation ImpLoc, + ObjCProtocolDecl *PDecl, + bool& IncompleteImpl, + const llvm::DenseSet<Selector> &InsMap, + const llvm::DenseSet<Selector> &ClsMap, + ObjCInterfaceDecl *IDecl); + + /// CheckImplementationIvars - This routine checks if the instance variables + /// listed in the implelementation match those listed in the interface. + void CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, + ObjCIvarDecl **Fields, unsigned nIvars, + SourceLocation Loc); + + /// ImplMethodsVsClassMethods - This is main routine to warn if any method + /// remains unimplemented in the class or category @implementation. + void ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, + ObjCContainerDecl* IDecl, + bool IncompleteImpl = false); + + /// MatchTwoMethodDeclarations - Checks if two methods' type match and returns + /// true, or false, accordingly. + bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, + const ObjCMethodDecl *PrevMethod, + bool matchBasedOnSizeAndAlignment = false); + + /// MatchAllMethodDeclarations - Check methods declaraed in interface or + /// or protocol against those declared in their implementations. + void MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, + const llvm::DenseSet<Selector> &ClsMap, + llvm::DenseSet<Selector> &InsMapSeen, + llvm::DenseSet<Selector> &ClsMapSeen, + ObjCImplDecl* IMPDecl, + ObjCContainerDecl* IDecl, + bool &IncompleteImpl, + bool ImmediateClass); + + /// AddInstanceMethodToGlobalPool - All instance methods in a translation + /// unit are added to a global pool. This allows us to efficiently associate + /// a selector with a method declaraation for purposes of typechecking + /// messages sent to "id" (where the class of the object is unknown). + void AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method); + + /// LookupInstanceMethodInGlobalPool - Returns the method and warns if + /// there are multiple signatures. + ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R); + + /// LookupFactoryMethodInGlobalPool - Returns the method and warns if + /// there are multiple signatures. + ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R); + + /// AddFactoryMethodToGlobalPool - Same as above, but for factory methods. + void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method); + //===--------------------------------------------------------------------===// + // Statement Parsing Callbacks: SemaStmt.cpp. +public: + virtual OwningStmtResult ActOnExprStmt(FullExprArg Expr); + + virtual OwningStmtResult ActOnNullStmt(SourceLocation SemiLoc); + virtual OwningStmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R, + MultiStmtArg Elts, + bool isStmtExpr); + virtual OwningStmtResult ActOnDeclStmt(DeclGroupPtrTy Decl, + SourceLocation StartLoc, + SourceLocation EndLoc); + virtual OwningStmtResult ActOnCaseStmt(SourceLocation CaseLoc, ExprArg LHSVal, + SourceLocation DotDotDotLoc, ExprArg RHSVal, + SourceLocation ColonLoc); + virtual void ActOnCaseStmtBody(StmtTy *CaseStmt, StmtArg SubStmt); + + virtual OwningStmtResult ActOnDefaultStmt(SourceLocation DefaultLoc, + SourceLocation ColonLoc, + StmtArg SubStmt, Scope *CurScope); + virtual OwningStmtResult ActOnLabelStmt(SourceLocation IdentLoc, + IdentifierInfo *II, + SourceLocation ColonLoc, + StmtArg SubStmt); + virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc, + FullExprArg CondVal, StmtArg ThenVal, + SourceLocation ElseLoc, StmtArg ElseVal); + virtual OwningStmtResult ActOnStartOfSwitchStmt(ExprArg Cond); + virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, + StmtArg Switch, StmtArg Body); + virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc, + FullExprArg Cond, StmtArg Body); + virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body, + SourceLocation WhileLoc, ExprArg Cond); + + virtual OwningStmtResult ActOnForStmt(SourceLocation ForLoc, + SourceLocation LParenLoc, + StmtArg First, ExprArg Second, + ExprArg Third, SourceLocation RParenLoc, + StmtArg Body); + virtual OwningStmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc, + SourceLocation LParenLoc, + StmtArg First, ExprArg Second, + SourceLocation RParenLoc, StmtArg Body); + + virtual OwningStmtResult ActOnGotoStmt(SourceLocation GotoLoc, + SourceLocation LabelLoc, + IdentifierInfo *LabelII); + virtual OwningStmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc, + SourceLocation StarLoc, + ExprArg DestExp); + virtual OwningStmtResult ActOnContinueStmt(SourceLocation ContinueLoc, + Scope *CurScope); + virtual OwningStmtResult ActOnBreakStmt(SourceLocation GotoLoc, + Scope *CurScope); + + virtual OwningStmtResult ActOnReturnStmt(SourceLocation ReturnLoc, + FullExprArg RetValExp); + OwningStmtResult ActOnBlockReturnStmt(SourceLocation ReturnLoc, + Expr *RetValExp); + + virtual OwningStmtResult ActOnAsmStmt(SourceLocation AsmLoc, + bool IsSimple, + bool IsVolatile, + unsigned NumOutputs, + unsigned NumInputs, + std::string *Names, + MultiExprArg Constraints, + MultiExprArg Exprs, + ExprArg AsmString, + MultiExprArg Clobbers, + SourceLocation RParenLoc); + + virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc, + SourceLocation RParen, + DeclPtrTy Parm, StmtArg Body, + StmtArg CatchList); + + virtual OwningStmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc, + StmtArg Body); + + virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc, + StmtArg Try, + StmtArg Catch, StmtArg Finally); + + virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc, + ExprArg Throw, + Scope *CurScope); + virtual OwningStmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, + ExprArg SynchExpr, + StmtArg SynchBody); + + VarDecl *BuildExceptionDeclaration(Scope *S, QualType ExDeclType, + IdentifierInfo *Name, + SourceLocation Loc, + SourceRange Range); + virtual DeclPtrTy ActOnExceptionDeclarator(Scope *S, Declarator &D); + + virtual OwningStmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc, + DeclPtrTy ExDecl, + StmtArg HandlerBlock); + virtual OwningStmtResult ActOnCXXTryBlock(SourceLocation TryLoc, + StmtArg TryBlock, + MultiStmtArg Handlers); + void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock); + + //===--------------------------------------------------------------------===// + // Expression Parsing Callbacks: SemaExpr.cpp. + + bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc); + bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD, + ObjCMethodDecl *Getter, + SourceLocation Loc); + void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, + Expr **Args, unsigned NumArgs); + + // Primary Expressions. + virtual SourceRange getExprRange(ExprTy *E) const; + + virtual OwningExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc, + IdentifierInfo &II, + bool HasTrailingLParen, + const CXXScopeSpec *SS = 0, + bool isAddressOfOperand = false); + virtual OwningExprResult ActOnCXXOperatorFunctionIdExpr(Scope *S, + SourceLocation OperatorLoc, + OverloadedOperatorKind Op, + bool HasTrailingLParen, + const CXXScopeSpec &SS, + bool isAddressOfOperand); + virtual OwningExprResult ActOnCXXConversionFunctionExpr(Scope *S, + SourceLocation OperatorLoc, + TypeTy *Ty, + bool HasTrailingLParen, + const CXXScopeSpec &SS, + bool isAddressOfOperand); + DeclRefExpr *BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc, + bool TypeDependent, bool ValueDependent, + const CXXScopeSpec *SS = 0); + VarDecl *BuildAnonymousStructUnionMemberPath(FieldDecl *Field, + llvm::SmallVectorImpl<FieldDecl *> &Path); + OwningExprResult + BuildAnonymousStructUnionMemberReference(SourceLocation Loc, + FieldDecl *Field, + Expr *BaseObjectExpr = 0, + SourceLocation OpLoc = SourceLocation()); + OwningExprResult ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, + DeclarationName Name, + bool HasTrailingLParen, + const CXXScopeSpec *SS, + bool isAddressOfOperand = false); + + virtual OwningExprResult ActOnPredefinedExpr(SourceLocation Loc, + tok::TokenKind Kind); + virtual OwningExprResult ActOnNumericConstant(const Token &); + virtual OwningExprResult ActOnCharacterConstant(const Token &); + virtual OwningExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, + ExprArg Val); + + /// ActOnStringLiteral - The specified tokens were lexed as pasted string + /// fragments (e.g. "foo" "bar" L"baz"). + virtual OwningExprResult ActOnStringLiteral(const Token *Toks, + unsigned NumToks); + + // Binary/Unary Operators. 'Tok' is the token for the operator. + OwningExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc, + unsigned OpcIn, + ExprArg InputArg); + virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, + tok::TokenKind Op, ExprArg Input); + + OwningExprResult CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc, + bool isSizeOf, SourceRange R); + OwningExprResult CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc, + bool isSizeOf, SourceRange R); + virtual OwningExprResult + ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, + void *TyOrEx, const SourceRange &ArgRange); + + bool CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, const SourceRange &R); + bool CheckSizeOfAlignOfOperand(QualType type, SourceLocation OpLoc, + const SourceRange &R, bool isSizeof); + + virtual OwningExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, + tok::TokenKind Kind, + ExprArg Input); + + virtual OwningExprResult ActOnArraySubscriptExpr(Scope *S, ExprArg Base, + SourceLocation LLoc, + ExprArg Idx, + SourceLocation RLoc); + virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceLocation MemberLoc, + IdentifierInfo &Member, + DeclPtrTy ImplDecl); + bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, + FunctionDecl *FDecl, + const FunctionProtoType *Proto, + Expr **Args, unsigned NumArgs, + SourceLocation RParenLoc); + + /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. + /// This provides the location of the left/right parens and a list of comma + /// locations. + virtual OwningExprResult ActOnCallExpr(Scope *S, ExprArg Fn, + SourceLocation LParenLoc, + MultiExprArg Args, + SourceLocation *CommaLocs, + SourceLocation RParenLoc); + + virtual OwningExprResult ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty, + SourceLocation RParenLoc, ExprArg Op); + + virtual OwningExprResult ActOnCompoundLiteral(SourceLocation LParenLoc, + TypeTy *Ty, + SourceLocation RParenLoc, + ExprArg Op); + + virtual OwningExprResult ActOnInitList(SourceLocation LParenLoc, + MultiExprArg InitList, + SourceLocation RParenLoc); + + virtual OwningExprResult ActOnDesignatedInitializer(Designation &Desig, + SourceLocation Loc, + bool GNUSyntax, + OwningExprResult Init); + + virtual OwningExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc, + tok::TokenKind Kind, + ExprArg LHS, ExprArg RHS); + OwningExprResult CreateBuiltinBinOp(SourceLocation TokLoc, + unsigned Opc, Expr *lhs, Expr *rhs); + + /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null + /// in the case of a the GNU conditional expr extension. + virtual OwningExprResult ActOnConditionalOp(SourceLocation QuestionLoc, + SourceLocation ColonLoc, + ExprArg Cond, ExprArg LHS, + ExprArg RHS); + + /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". + virtual OwningExprResult ActOnAddrLabel(SourceLocation OpLoc, + SourceLocation LabLoc, + IdentifierInfo *LabelII); + + virtual OwningExprResult ActOnStmtExpr(SourceLocation LPLoc, StmtArg SubStmt, + SourceLocation RPLoc); // "({..})" + + /// __builtin_offsetof(type, a.b[123][456].c) + virtual OwningExprResult ActOnBuiltinOffsetOf(Scope *S, + SourceLocation BuiltinLoc, + SourceLocation TypeLoc, + TypeTy *Arg1, + OffsetOfComponent *CompPtr, + unsigned NumComponents, + SourceLocation RParenLoc); + + // __builtin_types_compatible_p(type1, type2) + virtual OwningExprResult ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc, + TypeTy *arg1, TypeTy *arg2, + SourceLocation RPLoc); + + // __builtin_choose_expr(constExpr, expr1, expr2) + virtual OwningExprResult ActOnChooseExpr(SourceLocation BuiltinLoc, + ExprArg cond, ExprArg expr1, + ExprArg expr2, SourceLocation RPLoc); + + // __builtin_va_arg(expr, type) + virtual OwningExprResult ActOnVAArg(SourceLocation BuiltinLoc, + ExprArg expr, TypeTy *type, + SourceLocation RPLoc); + + // __null + virtual OwningExprResult ActOnGNUNullExpr(SourceLocation TokenLoc); + + //===------------------------- "Block" Extension ------------------------===// + + /// ActOnBlockStart - This callback is invoked when a block literal is + /// started. + virtual void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope); + + /// ActOnBlockArguments - This callback allows processing of block arguments. + /// If there are no arguments, this is still invoked. + virtual void 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. + virtual void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope); + + /// ActOnBlockStmtExpr - This is called when the body of a block statement + /// literal was successfully completed. ^(int x){...} + virtual OwningExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc, + StmtArg Body, Scope *CurScope); + + //===---------------------------- C++ Features --------------------------===// + + // Act on C++ namespaces + virtual DeclPtrTy ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc, + IdentifierInfo *Ident, + SourceLocation LBrace); + virtual void ActOnFinishNamespaceDef(DeclPtrTy Dcl, SourceLocation RBrace); + + virtual DeclPtrTy ActOnUsingDirective(Scope *CurScope, + SourceLocation UsingLoc, + SourceLocation NamespcLoc, + const CXXScopeSpec &SS, + SourceLocation IdentLoc, + IdentifierInfo *NamespcName, + AttributeList *AttrList); + + void PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir); + + virtual DeclPtrTy ActOnNamespaceAliasDef(Scope *CurScope, + SourceLocation NamespaceLoc, + SourceLocation AliasLoc, + IdentifierInfo *Alias, + const CXXScopeSpec &SS, + SourceLocation IdentLoc, + IdentifierInfo *Ident); + + /// AddCXXDirectInitializerToDecl - This action is called immediately after + /// ActOnDeclarator, when a C++ direct initializer is present. + /// e.g: "int x(1);" + virtual void AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, + SourceLocation LParenLoc, + MultiExprArg Exprs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc); + + /// InitializeVarWithConstructor - Creates an CXXConstructExpr + /// and sets it as the initializer for the the passed in VarDecl. + void InitializeVarWithConstructor(VarDecl *VD, + CXXConstructorDecl *Constructor, + QualType DeclInitType, + Expr **Exprs, unsigned NumExprs); + + /// MaybeBindToTemporary - If the passed in expression has a record type with + /// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise + /// it simply returns the passed in expression. + OwningExprResult MaybeBindToTemporary(Expr *E); + + /// RemoveOutermostTemporaryBinding - Remove and destroy the outermost + /// CXXBindToTemporaryExpr if necessary. This is used when we want to not + /// destroy a temporary when a full expression has been evaluated. + /// For example: + /// + /// const T& t = T(10, T()); + /// + /// Here the outermost T needs to be destroyed when t goes out of scope, but + /// the innermost T needs to be destroyed when the expr has been evaluated. + Expr *RemoveOutermostTemporaryBinding(Expr *E); + + /// InitializationKind - Represents which kind of C++ initialization + /// [dcl.init] a routine is to perform. + enum InitializationKind { + IK_Direct, ///< Direct initialization + IK_Copy, ///< Copy initialization + IK_Default ///< Default initialization + }; + + CXXConstructorDecl * + PerformInitializationByConstructor(QualType ClassType, + Expr **Args, unsigned NumArgs, + SourceLocation Loc, SourceRange Range, + DeclarationName InitEntity, + InitializationKind Kind); + + /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. + virtual OwningExprResult ActOnCXXNamedCast(SourceLocation OpLoc, + tok::TokenKind Kind, + SourceLocation LAngleBracketLoc, + TypeTy *Ty, + SourceLocation RAngleBracketLoc, + SourceLocation LParenLoc, + ExprArg E, + SourceLocation RParenLoc); + + /// ActOnCXXTypeid - Parse typeid( something ). + virtual OwningExprResult ActOnCXXTypeid(SourceLocation OpLoc, + SourceLocation LParenLoc, bool isType, + void *TyOrExpr, + SourceLocation RParenLoc); + + //// ActOnCXXThis - Parse 'this' pointer. + virtual OwningExprResult ActOnCXXThis(SourceLocation ThisLoc); + + /// ActOnCXXBoolLiteral - Parse {true,false} literals. + virtual OwningExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, + tok::TokenKind Kind); + + /// ActOnCXXNullPtrLiteral - Parse 'nullptr'. + virtual OwningExprResult ActOnCXXNullPtrLiteral(SourceLocation Loc); + + //// ActOnCXXThrow - Parse throw expressions. + virtual OwningExprResult ActOnCXXThrow(SourceLocation OpLoc, + ExprArg expr); + bool CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E); + + /// ActOnCXXTypeConstructExpr - Parse construction of a specified type. + /// Can be interpreted either as function-style casting ("int(x)") + /// or class type construction ("ClassType(x,y,z)") + /// or creation of a value-initialized type ("int()"). + virtual OwningExprResult ActOnCXXTypeConstructExpr(SourceRange TypeRange, + TypeTy *TypeRep, + SourceLocation LParenLoc, + MultiExprArg Exprs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc); + + /// ActOnCXXNew - Parsed a C++ 'new' expression. + virtual OwningExprResult ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, + SourceLocation PlacementLParen, + MultiExprArg PlacementArgs, + SourceLocation PlacementRParen, + bool ParenTypeId, Declarator &D, + SourceLocation ConstructorLParen, + MultiExprArg ConstructorArgs, + SourceLocation ConstructorRParen); + OwningExprResult BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, + SourceLocation PlacementLParen, + MultiExprArg PlacementArgs, + SourceLocation PlacementRParen, + bool ParenTypeId, + QualType AllocType, + SourceLocation TypeLoc, + SourceRange TypeRange, + ExprArg ArraySize, + SourceLocation ConstructorLParen, + MultiExprArg ConstructorArgs, + SourceLocation ConstructorRParen); + + bool CheckAllocatedType(QualType AllocType, SourceLocation Loc, + SourceRange R); + bool FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, + bool UseGlobal, QualType AllocType, bool IsArray, + Expr **PlaceArgs, unsigned NumPlaceArgs, + FunctionDecl *&OperatorNew, + FunctionDecl *&OperatorDelete); + bool FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, + DeclarationName Name, Expr** Args, + unsigned NumArgs, DeclContext *Ctx, + bool AllowMissing, FunctionDecl *&Operator); + void DeclareGlobalNewDelete(); + void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return, + QualType Argument); + + /// ActOnCXXDelete - Parsed a C++ 'delete' expression + virtual OwningExprResult ActOnCXXDelete(SourceLocation StartLoc, + bool UseGlobal, bool ArrayForm, + ExprArg Operand); + + /// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a + /// C++ if/switch/while/for statement. + /// e.g: "if (int x = f()) {...}" + virtual OwningExprResult ActOnCXXConditionDeclarationExpr(Scope *S, + SourceLocation StartLoc, + Declarator &D, + SourceLocation EqualLoc, + ExprArg AssignExprVal); + + /// ActOnUnaryTypeTrait - Parsed one of the unary type trait support + /// pseudo-functions. + virtual OwningExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT, + SourceLocation KWLoc, + SourceLocation LParen, + TypeTy *Ty, + SourceLocation RParen); + + virtual OwningExprResult ActOnFinishFullExpr(ExprArg Expr); + + bool RequireCompleteDeclContext(const CXXScopeSpec &SS); + + DeclContext *computeDeclContext(const CXXScopeSpec &SS); + bool isDependentScopeSpecifier(const CXXScopeSpec &SS); + CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS); + bool isUnknownSpecialization(const CXXScopeSpec &SS); + + /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the + /// global scope ('::'). + virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S, + SourceLocation CCLoc); + + /// ActOnCXXNestedNameSpecifier - Called during parsing of a + /// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now + /// we want to resolve "bar::". 'SS' is empty or the previously parsed + /// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar', + /// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'. + /// Returns a CXXScopeTy* object representing the C++ scope. + virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S, + const CXXScopeSpec &SS, + SourceLocation IdLoc, + SourceLocation CCLoc, + IdentifierInfo &II); + + /// ActOnCXXNestedNameSpecifier - Called during parsing of a + /// nested-name-specifier that involves a template-id, e.g., + /// "foo::bar<int, float>::", and now we need to build a scope + /// specifier. \p SS is empty or the previously parsed nested-name + /// part ("foo::"), \p Type is the already-parsed class template + /// specialization (or other template-id that names a type), \p + /// TypeRange is the source range where the type is located, and \p + /// CCLoc is the location of the trailing '::'. + virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S, + const CXXScopeSpec &SS, + TypeTy *Type, + SourceRange TypeRange, + SourceLocation CCLoc); + + /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global + /// scope or nested-name-specifier) is parsed, part of a declarator-id. + /// After this method is called, according to [C++ 3.4.3p3], names should be + /// looked up in the declarator-id's scope, until the declarator is parsed and + /// ActOnCXXExitDeclaratorScope is called. + /// The 'SS' should be a non-empty valid CXXScopeSpec. + virtual void ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS); + + /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously + /// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same + /// CXXScopeSpec that was passed to ActOnCXXEnterDeclaratorScope as well. + /// Used to indicate that names should revert to being looked up in the + /// defining scope. + virtual void ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS); + + // ParseObjCStringLiteral - Parse Objective-C string literals. + virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, + ExprTy **Strings, + unsigned NumStrings); + virtual ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc, + SourceLocation EncodeLoc, + SourceLocation LParenLoc, + TypeTy *Ty, + SourceLocation RParenLoc); + + // ParseObjCSelectorExpression - Build selector expression for @selector + virtual ExprResult ParseObjCSelectorExpression(Selector Sel, + SourceLocation AtLoc, + SourceLocation SelLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc); + + // ParseObjCProtocolExpression - Build protocol expression for @protocol + virtual ExprResult ParseObjCProtocolExpression(IdentifierInfo * ProtocolName, + SourceLocation AtLoc, + SourceLocation ProtoLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc); + + //===--------------------------------------------------------------------===// + // C++ Declarations + // + virtual DeclPtrTy ActOnStartLinkageSpecification(Scope *S, + SourceLocation ExternLoc, + SourceLocation LangLoc, + const char *Lang, + unsigned StrSize, + SourceLocation LBraceLoc); + virtual DeclPtrTy ActOnFinishLinkageSpecification(Scope *S, + DeclPtrTy LinkageSpec, + SourceLocation RBraceLoc); + + + //===--------------------------------------------------------------------===// + // C++ Classes + // + virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S, + const CXXScopeSpec *SS); + + virtual DeclPtrTy ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, + Declarator &D, + ExprTy *BitfieldWidth, + ExprTy *Init, + bool Deleted = false); + + virtual MemInitResult ActOnMemInitializer(DeclPtrTy ConstructorD, + Scope *S, + IdentifierInfo *MemberOrBase, + SourceLocation IdLoc, + SourceLocation LParenLoc, + ExprTy **Args, unsigned NumArgs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc); + + void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl); + + virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl, + SourceLocation ColonLoc, + MemInitTy **MemInits, unsigned NumMemInits); + + virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, + DeclPtrTy TagDecl, + SourceLocation LBrac, + SourceLocation RBrac); + + virtual void ActOnReenterTemplateScope(Scope *S, DeclPtrTy Template); + virtual void ActOnStartDelayedCXXMethodDeclaration(Scope *S, + DeclPtrTy Method); + virtual void ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy Param); + virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, + DeclPtrTy Method); + + virtual DeclPtrTy ActOnStaticAssertDeclaration(SourceLocation AssertLoc, + ExprArg AssertExpr, + ExprArg AssertMessageExpr); + + virtual bool ActOnFriendDecl(Scope *S, SourceLocation FriendLoc, + DeclPtrTy Dcl); + + QualType CheckConstructorDeclarator(Declarator &D, QualType R, + FunctionDecl::StorageClass& SC); + void CheckConstructor(CXXConstructorDecl *Constructor); + QualType CheckDestructorDeclarator(Declarator &D, + FunctionDecl::StorageClass& SC); + void CheckConversionDeclarator(Declarator &D, QualType &R, + FunctionDecl::StorageClass& SC); + DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion); + + //===--------------------------------------------------------------------===// + // C++ Derived Classes + // + + /// ActOnBaseSpecifier - Parsed a base specifier + CXXBaseSpecifier *CheckBaseSpecifier(CXXRecordDecl *Class, + SourceRange SpecifierRange, + bool Virtual, AccessSpecifier Access, + QualType BaseType, + SourceLocation BaseLoc); + virtual BaseResult ActOnBaseSpecifier(DeclPtrTy classdecl, + SourceRange SpecifierRange, + bool Virtual, AccessSpecifier Access, + TypeTy *basetype, SourceLocation + BaseLoc); + + bool AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, + unsigned NumBases); + virtual void ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases, + unsigned NumBases); + + bool IsDerivedFrom(QualType Derived, QualType Base); + bool IsDerivedFrom(QualType Derived, QualType Base, BasePaths &Paths); + bool LookupInBases(CXXRecordDecl *Class, const MemberLookupCriteria& Criteria, + BasePaths &Paths); + bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, + SourceLocation Loc, SourceRange Range); + bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, + unsigned InaccessibleBaseID, + unsigned AmbigiousBaseConvID, + SourceLocation Loc, SourceRange Range, + DeclarationName Name); + + std::string getAmbiguousPathsDisplayString(BasePaths &Paths); + + /// CheckReturnTypeCovariance - Checks whether two types are covariant, + /// according to C++ [class.virtual]p5. + bool CheckOverridingFunctionReturnType(const CXXMethodDecl *New, + const CXXMethodDecl *Old); + + + //===--------------------------------------------------------------------===// + // C++ Access Control + // + + bool SetMemberAccessSpecifier(NamedDecl *MemberDecl, + NamedDecl *PrevMemberDecl, + AccessSpecifier LexicalAS); + + bool CheckBaseClassAccess(QualType Derived, QualType Base, + unsigned InaccessibleBaseID, + BasePaths& Paths, SourceLocation AccessLoc, + DeclarationName Name); + + + enum AbstractDiagSelID { + AbstractNone = -1, + AbstractReturnType, + AbstractParamType, + AbstractVariableType, + AbstractFieldType + }; + + bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID, + AbstractDiagSelID SelID = AbstractNone, + const CXXRecordDecl *CurrentRD = 0); + + //===--------------------------------------------------------------------===// + // C++ Overloaded Operators [C++ 13.5] + // + + bool CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl); + + //===--------------------------------------------------------------------===// + // C++ Templates [C++ 14] + // + virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S, + TemplateTy &Template, + const CXXScopeSpec *SS = 0); + bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); + TemplateDecl *AdjustDeclIfTemplate(DeclPtrTy &Decl); + + virtual DeclPtrTy ActOnTypeParameter(Scope *S, bool Typename, + SourceLocation KeyLoc, + IdentifierInfo *ParamName, + SourceLocation ParamNameLoc, + unsigned Depth, unsigned Position); + virtual void ActOnTypeParameterDefault(DeclPtrTy TypeParam, + SourceLocation EqualLoc, + SourceLocation DefaultLoc, + TypeTy *Default); + + QualType CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc); + virtual DeclPtrTy ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, + unsigned Depth, + unsigned Position); + virtual void ActOnNonTypeTemplateParameterDefault(DeclPtrTy TemplateParam, + SourceLocation EqualLoc, + ExprArg Default); + virtual DeclPtrTy ActOnTemplateTemplateParameter(Scope *S, + SourceLocation TmpLoc, + TemplateParamsTy *Params, + IdentifierInfo *ParamName, + SourceLocation ParamNameLoc, + unsigned Depth, + unsigned Position); + virtual void ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParam, + SourceLocation EqualLoc, + ExprArg Default); + + virtual TemplateParamsTy * + ActOnTemplateParameterList(unsigned Depth, + SourceLocation ExportLoc, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + DeclPtrTy *Params, unsigned NumParams, + SourceLocation RAngleLoc); + bool CheckTemplateParameterList(TemplateParameterList *NewParams, + TemplateParameterList *OldParams); + + virtual DeclResult + ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK, + SourceLocation KWLoc, const CXXScopeSpec &SS, + IdentifierInfo *Name, SourceLocation NameLoc, + AttributeList *Attr, + MultiTemplateParamsArg TemplateParameterLists, + AccessSpecifier AS); + + QualType CheckTemplateIdType(TemplateName Template, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceLocation RAngleLoc); + + virtual TypeResult + ActOnTemplateIdType(TemplateTy Template, SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc); + + virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc, + const IdentifierInfo &Name, + SourceLocation NameLoc, + const CXXScopeSpec &SS); + + bool CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate, + ClassTemplateSpecializationDecl *PrevDecl, + SourceLocation TemplateNameLoc, + SourceRange ScopeSpecifierRange, + bool ExplicitInstantiation); + + virtual DeclResult + ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, + SourceLocation KWLoc, + const CXXScopeSpec &SS, + TemplateTy Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc, + AttributeList *Attr, + MultiTemplateParamsArg TemplateParameterLists); + + virtual DeclResult + ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, + unsigned TagSpec, + SourceLocation KWLoc, + const CXXScopeSpec &SS, + TemplateTy Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc, + AttributeList *Attr); + + virtual DeclResult + ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, + unsigned TagSpec, + SourceLocation KWLoc, + const CXXScopeSpec &SS, + IdentifierInfo *Name, + SourceLocation NameLoc, + AttributeList *Attr); + + bool CheckTemplateArgumentList(TemplateDecl *Template, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceLocation RAngleLoc, + llvm::SmallVectorImpl<TemplateArgument> &Converted); + + bool CheckTemplateArgument(TemplateTypeParmDecl *Param, QualType Arg, + SourceLocation ArgLoc); + bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, + NamedDecl *&Entity); + bool CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member); + bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, + QualType InstantiatedParamType, Expr *&Arg, + llvm::SmallVectorImpl<TemplateArgument> *Converted = 0); + bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, DeclRefExpr *Arg); + bool TemplateParameterListsAreEqual(TemplateParameterList *New, + TemplateParameterList *Old, + bool Complain, + bool IsTemplateTemplateParm = false, + SourceLocation TemplateArgLoc + = SourceLocation()); + + bool CheckTemplateDeclScope(Scope *S, + MultiTemplateParamsArg &TemplateParameterLists); + + /// \brief Called when the parser has parsed a C++ typename + /// specifier, e.g., "typename T::type". + /// + /// \param TypenameLoc the location of the 'typename' keyword + /// \param SS the nested-name-specifier following the typename (e.g., 'T::'). + /// \param II the identifier we're retrieving (e.g., 'type' in the example). + /// \param IdLoc the location of the identifier. + virtual TypeResult + ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, + const IdentifierInfo &II, SourceLocation IdLoc); + + /// \brief Called when the parser has parsed a C++ typename + /// specifier that ends in a template-id, e.g., + /// "typename MetaFun::template apply<T1, T2>". + /// + /// \param TypenameLoc the location of the 'typename' keyword + /// \param SS the nested-name-specifier following the typename (e.g., 'T::'). + /// \param TemplateLoc the location of the 'template' keyword, if any. + /// \param Ty the type that the typename specifier refers to. + virtual TypeResult + ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, + SourceLocation TemplateLoc, TypeTy *Ty); + + QualType CheckTypenameType(NestedNameSpecifier *NNS, + const IdentifierInfo &II, + SourceRange Range); + + bool DeduceTemplateArguments(QualType Param, QualType Arg, + llvm::SmallVectorImpl<TemplateArgument> &Deduced); + bool DeduceTemplateArguments(const TemplateArgument &Param, + const TemplateArgument &Arg, + llvm::SmallVectorImpl<TemplateArgument> &Deduced); + bool DeduceTemplateArguments(const TemplateArgumentList &ParamList, + const TemplateArgumentList &ArgList, + llvm::SmallVectorImpl<TemplateArgument> &Deduced); + bool DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, + const TemplateArgumentList &TemplateArgs); + + //===--------------------------------------------------------------------===// + // C++ Template Instantiation + // + + const TemplateArgumentList &getTemplateInstantiationArgs(NamedDecl *D); + + /// \brief A template instantiation that is currently in progress. + struct ActiveTemplateInstantiation { + /// \brief The kind of template instantiation we are performing + enum { + /// We are instantiating a template declaration. The entity is + /// the declaration we're instantiating (e.g., a CXXRecordDecl). + TemplateInstantiation, + + /// We are instantiating a default argument for a template + /// parameter. The Entity is the template, and + /// TemplateArgs/NumTemplateArguments provides the template + /// arguments as specified. + DefaultTemplateArgumentInstantiation + } Kind; + + /// \brief The point of instantiation within the source code. + SourceLocation PointOfInstantiation; + + /// \brief The entity that is being instantiated. + uintptr_t Entity; + + // \brief If this the instantiation of a default template + // argument, the list of template arguments. + const TemplateArgument *TemplateArgs; + + /// \brief The number of template arguments in TemplateArgs. + unsigned NumTemplateArgs; + + /// \brief The source range that covers the construct that cause + /// the instantiation, e.g., the template-id that causes a class + /// template instantiation. + SourceRange InstantiationRange; + + friend bool operator==(const ActiveTemplateInstantiation &X, + const ActiveTemplateInstantiation &Y) { + if (X.Kind != Y.Kind) + return false; + + if (X.Entity != Y.Entity) + return false; + + switch (X.Kind) { + case TemplateInstantiation: + return true; + + case DefaultTemplateArgumentInstantiation: + return X.TemplateArgs == Y.TemplateArgs; + } + + return true; + } + + friend bool operator!=(const ActiveTemplateInstantiation &X, + const ActiveTemplateInstantiation &Y) { + return !(X == Y); + } + }; + + /// \brief List of active template instantiations. + /// + /// This vector is treated as a stack. As one template instantiation + /// requires another template instantiation, additional + /// instantiations are pushed onto the stack up to a + /// user-configurable limit LangOptions::InstantiationDepth. + llvm::SmallVector<ActiveTemplateInstantiation, 16> + ActiveTemplateInstantiations; + + /// \brief The last template from which a template instantiation + /// error or warning was produced. + /// + /// This value is used to suppress printing of redundant template + /// instantiation backtraces when there are multiple errors in the + /// same instantiation. FIXME: Does this belong in Sema? It's tough + /// to implement it anywhere else. + ActiveTemplateInstantiation LastTemplateInstantiationErrorContext; + + /// \brief A stack object to be created when performing template + /// instantiation. + /// + /// Construction of an object of type \c InstantiatingTemplate + /// pushes the current instantiation onto the stack of active + /// instantiations. If the size of this stack exceeds the maximum + /// number of recursive template instantiations, construction + /// produces an error and evaluates true. + /// + /// Destruction of this object will pop the named instantiation off + /// the stack. + struct InstantiatingTemplate { + /// \brief Note that we are instantiating a class template, + /// function template, or a member thereof. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + Decl *Entity, + SourceRange InstantiationRange = SourceRange()); + + /// \brief Note that we are instantiating a default argument in a + /// template-id. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + TemplateDecl *Template, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceRange InstantiationRange = SourceRange()); + + /// \brief Note that we have finished instantiating this template. + void Clear(); + + ~InstantiatingTemplate() { Clear(); } + + /// \brief Determines whether we have exceeded the maximum + /// recursive template instantiations. + operator bool() const { return Invalid; } + + private: + Sema &SemaRef; + bool Invalid; + + bool CheckInstantiationDepth(SourceLocation PointOfInstantiation, + SourceRange InstantiationRange); + + InstantiatingTemplate(const InstantiatingTemplate&); // not implemented + + InstantiatingTemplate& + operator=(const InstantiatingTemplate&); // not implemented + }; + + void PrintInstantiationStack(); + + /// \brief A stack-allocated class that identifies which local + /// variable declaration instantiations are present in this scope. + /// + /// A new instance of this class type will be created whenever we + /// instantiate a new function declaration, which will have its own + /// set of parameter declarations. + class LocalInstantiationScope { + /// \brief Reference to the semantic analysis that is performing + /// this template instantiation. + Sema &SemaRef; + + /// \brief A mapping from local declarations that occur + /// within a template to their instantiations. + /// + /// This mapping is used during instantiation to keep track of, + /// e.g., function parameter and variable declarations. For example, + /// given: + /// + /// \code + /// template<typename T> T add(T x, T y) { return x + y; } + /// \endcode + /// + /// when we instantiate add<int>, we will introduce a mapping from + /// the ParmVarDecl for 'x' that occurs in the template to the + /// instantiated ParmVarDecl for 'x'. + llvm::DenseMap<const Decl *, Decl *> LocalDecls; + + /// \brief The outer scope, in which contains local variable + /// definitions from some other instantiation (that is not + /// relevant to this particular scope). + LocalInstantiationScope *Outer; + + // This class is non-copyable + LocalInstantiationScope(const LocalInstantiationScope &); + LocalInstantiationScope &operator=(const LocalInstantiationScope &); + + public: + LocalInstantiationScope(Sema &SemaRef) + : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope) { + SemaRef.CurrentInstantiationScope = this; + } + + ~LocalInstantiationScope() { + SemaRef.CurrentInstantiationScope = Outer; + } + + Decl *getInstantiationOf(const Decl *D) { + Decl *Result = LocalDecls[D]; + assert(Result && "declaration was not instantiated in this scope!"); + return Result; + } + + VarDecl *getInstantiationOf(const VarDecl *Var) { + return cast<VarDecl>(getInstantiationOf(cast<Decl>(Var))); + } + + ParmVarDecl *getInstantiationOf(const ParmVarDecl *Var) { + return cast<ParmVarDecl>(getInstantiationOf(cast<Decl>(Var))); + } + + void InstantiatedLocal(const Decl *D, Decl *Inst) { + Decl *&Stored = LocalDecls[D]; + assert(!Stored && "Already instantiated this local"); + Stored = Inst; + } + }; + + /// \brief The current instantiation scope used to store local + /// variables. + LocalInstantiationScope *CurrentInstantiationScope; + + QualType InstantiateType(QualType T, const TemplateArgumentList &TemplateArgs, + SourceLocation Loc, DeclarationName Entity); + + OwningExprResult InstantiateExpr(Expr *E, + const TemplateArgumentList &TemplateArgs); + + OwningStmtResult InstantiateStmt(Stmt *S, + const TemplateArgumentList &TemplateArgs); + OwningStmtResult InstantiateCompoundStmt(CompoundStmt *S, + const TemplateArgumentList &TemplateArgs, + bool isStmtExpr); + + Decl *InstantiateDecl(Decl *D, DeclContext *Owner, + const TemplateArgumentList &TemplateArgs); + + bool + InstantiateBaseSpecifiers(CXXRecordDecl *Instantiation, + CXXRecordDecl *Pattern, + const TemplateArgumentList &TemplateArgs); + + bool + InstantiateClass(SourceLocation PointOfInstantiation, + CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, + const TemplateArgumentList &TemplateArgs, + bool ExplicitInstantiation); + + bool + InstantiateClassTemplateSpecialization( + ClassTemplateSpecializationDecl *ClassTemplateSpec, + bool ExplicitInstantiation); + + void InstantiateClassMembers(SourceLocation PointOfInstantiation, + CXXRecordDecl *Instantiation, + const TemplateArgumentList &TemplateArgs); + + void InstantiateClassTemplateSpecializationMembers( + SourceLocation PointOfInstantiation, + ClassTemplateSpecializationDecl *ClassTemplateSpec); + + NestedNameSpecifier * + InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS, + SourceRange Range, + const TemplateArgumentList &TemplateArgs); + + TemplateName + InstantiateTemplateName(TemplateName Name, SourceLocation Loc, + const TemplateArgumentList &TemplateArgs); + + void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, + FunctionDecl *Function); + void InstantiateVariableDefinition(VarDecl *Var); + + NamedDecl *InstantiateCurrentDeclRef(NamedDecl *D); + + // Simple function for cloning expressions. + template<typename T> + OwningExprResult Clone(T *E) { + assert(!E->isValueDependent() && !E->isTypeDependent() && + "expression is value or type dependent!"); + return Owned(E->Clone(Context)); + } + + // Objective-C declarations. + virtual DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *SuperName, + SourceLocation SuperLoc, + const DeclPtrTy *ProtoRefs, + unsigned NumProtoRefs, + SourceLocation EndProtoLoc, + AttributeList *AttrList); + + virtual DeclPtrTy ActOnCompatiblityAlias( + SourceLocation AtCompatibilityAliasLoc, + IdentifierInfo *AliasName, SourceLocation AliasLocation, + IdentifierInfo *ClassName, SourceLocation ClassLocation); + + void CheckForwardProtocolDeclarationForCircularDependency( + IdentifierInfo *PName, + SourceLocation &PLoc, SourceLocation PrevLoc, + const ObjCList<ObjCProtocolDecl> &PList); + + virtual DeclPtrTy ActOnStartProtocolInterface( + SourceLocation AtProtoInterfaceLoc, + IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, + const DeclPtrTy *ProtoRefNames, unsigned NumProtoRefs, + SourceLocation EndProtoLoc, + AttributeList *AttrList); + + virtual DeclPtrTy ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *CategoryName, + SourceLocation CategoryLoc, + const DeclPtrTy *ProtoRefs, + unsigned NumProtoRefs, + SourceLocation EndProtoLoc); + + virtual DeclPtrTy ActOnStartClassImplementation( + SourceLocation AtClassImplLoc, + IdentifierInfo *ClassName, SourceLocation ClassLoc, + IdentifierInfo *SuperClassname, + SourceLocation SuperClassLoc); + + virtual DeclPtrTy ActOnStartCategoryImplementation( + SourceLocation AtCatImplLoc, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *CatName, + SourceLocation CatLoc); + + virtual DeclPtrTy ActOnForwardClassDeclaration(SourceLocation Loc, + IdentifierInfo **IdentList, + unsigned NumElts); + + virtual DeclPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, + const IdentifierLocPair *IdentList, + unsigned NumElts, + AttributeList *attrList); + + virtual void FindProtocolDeclaration(bool WarnOnDeclarations, + const IdentifierLocPair *ProtocolId, + unsigned NumProtocols, + llvm::SmallVectorImpl<DeclPtrTy> &Protocols); + + /// Ensure attributes are consistent with type. + /// \param [in, out] Attributes The attributes to check; they will + /// be modified to be consistent with \arg PropertyTy. + void CheckObjCPropertyAttributes(QualType PropertyTy, + SourceLocation Loc, + unsigned &Attributes); + void ProcessPropertyDecl(ObjCPropertyDecl *property, ObjCContainerDecl *DC); + void DiagnosePropertyMismatch(ObjCPropertyDecl *Property, + ObjCPropertyDecl *SuperProperty, + const IdentifierInfo *Name); + void ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl); + + void MergeProtocolPropertiesIntoClass(Decl *CDecl, + DeclPtrTy MergeProtocols); + + void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT, + ObjCInterfaceDecl *ID); + + void MergeOneProtocolPropertiesIntoClass(Decl *CDecl, + ObjCProtocolDecl *PDecl); + + virtual void ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl, + DeclPtrTy *allMethods = 0, unsigned allNum = 0, + DeclPtrTy *allProperties = 0, unsigned pNum = 0, + DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0); + + virtual DeclPtrTy ActOnProperty(Scope *S, SourceLocation AtLoc, + FieldDeclarator &FD, ObjCDeclSpec &ODS, + Selector GetterSel, Selector SetterSel, + DeclPtrTy ClassCategory, + bool *OverridingProperty, + tok::ObjCKeywordKind MethodImplKind); + + virtual DeclPtrTy ActOnPropertyImplDecl(SourceLocation AtLoc, + SourceLocation PropertyLoc, + bool ImplKind,DeclPtrTy ClassImplDecl, + IdentifierInfo *PropertyId, + IdentifierInfo *PropertyIvar); + + virtual DeclPtrTy ActOnMethodDeclaration( + SourceLocation BeginLoc, // location of the + or -. + SourceLocation EndLoc, // location of the ; or {. + tok::TokenKind MethodType, + DeclPtrTy ClassDecl, ObjCDeclSpec &ReturnQT, TypeTy *ReturnType, + Selector Sel, + // optional arguments. The number of types/arguments is obtained + // from the Sel.getNumArgs(). + ObjCArgInfo *ArgInfo, + llvm::SmallVectorImpl<Declarator> &Cdecls, + AttributeList *AttrList, tok::ObjCKeywordKind MethodImplKind, + bool isVariadic = false); + + // Helper method for ActOnClassMethod/ActOnInstanceMethod. + // Will search "local" class/category implementations for a method decl. + // Will also search in class's root looking for instance method. + // Returns 0 if no method is found. + ObjCMethodDecl *LookupPrivateClassMethod(Selector Sel, + ObjCInterfaceDecl *CDecl); + ObjCMethodDecl *LookupPrivateInstanceMethod(Selector Sel, + ObjCInterfaceDecl *ClassDecl); + + virtual OwningExprResult ActOnClassPropertyRefExpr( + IdentifierInfo &receiverName, + IdentifierInfo &propertyName, + SourceLocation &receiverNameLoc, + SourceLocation &propertyNameLoc); + + // ActOnClassMessage - used for both unary and keyword messages. + // ArgExprs is optional - if it is present, the number of expressions + // is obtained from NumArgs. + virtual ExprResult ActOnClassMessage( + Scope *S, + IdentifierInfo *receivingClassName, Selector Sel, SourceLocation lbrac, + SourceLocation receiverLoc, SourceLocation selectorLoc,SourceLocation rbrac, + ExprTy **ArgExprs, unsigned NumArgs); + + // ActOnInstanceMessage - used for both unary and keyword messages. + // ArgExprs is optional - if it is present, the number of expressions + // is obtained from NumArgs. + virtual ExprResult ActOnInstanceMessage( + ExprTy *receiver, Selector Sel, + SourceLocation lbrac, SourceLocation receiverLoc, SourceLocation rbrac, + ExprTy **ArgExprs, unsigned NumArgs); + + /// ActOnPragmaPack - Called on well formed #pragma pack(...). + virtual void ActOnPragmaPack(PragmaPackKind Kind, + IdentifierInfo *Name, + ExprTy *Alignment, + SourceLocation PragmaLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc); + + /// ActOnPragmaUnused - Called on well-formed '#pragma unused'. + virtual void ActOnPragmaUnused(ExprTy **Exprs, unsigned NumExprs, + SourceLocation PragmaLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc); + + /// getPragmaPackAlignment() - Return the current alignment as specified by + /// the current #pragma pack directive, or 0 if none is currently active. + unsigned getPragmaPackAlignment() const; + + /// FreePackedContext - Deallocate and null out PackContext. + void FreePackedContext(); + + /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit + /// cast. If there is already an implicit cast, merge into the existing one. + /// If isLvalue, the result of the cast is an lvalue. + void ImpCastExprToType(Expr *&Expr, QualType Type, bool isLvalue = false); + + // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts + // functions and arrays to their respective pointers (C99 6.3.2.1). + Expr *UsualUnaryConversions(Expr *&expr); + + // DefaultFunctionArrayConversion - converts functions and arrays + // to their respective pointers (C99 6.3.2.1). + void DefaultFunctionArrayConversion(Expr *&expr); + + // DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that + // do not have a prototype. Integer promotions are performed on each + // argument, and arguments that have type float are promoted to double. + void DefaultArgumentPromotion(Expr *&Expr); + + // Used for emitting the right warning by DefaultVariadicArgumentPromotion + enum VariadicCallType { + VariadicFunction, + VariadicBlock, + VariadicMethod + }; + + // DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but + // will warn if the resulting type is not a POD type. + bool DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT); + + // UsualArithmeticConversions - performs the UsualUnaryConversions on it's + // operands and then handles various conversions that are common to binary + // operators (C99 6.3.1.8). If both operands aren't arithmetic, this + // routine returns the first non-arithmetic type found. The client is + // responsible for emitting appropriate error diagnostics. + QualType UsualArithmeticConversions(Expr *&lExpr, Expr *&rExpr, + bool isCompAssign = false); + + /// UsualArithmeticConversionsType - handles the various conversions + /// that are common to binary operators (C99 6.3.1.8, C++ [expr]p9) + /// and returns the result type of that conversion. + QualType UsualArithmeticConversionsType(QualType lhs, QualType rhs); + + + /// AssignConvertType - All of the 'assignment' semantic checks return this + /// enum to indicate whether the assignment was allowed. These checks are + /// done for simple assignments, as well as initialization, return from + /// function, argument passing, etc. The query is phrased in terms of a + /// source and destination type. + enum AssignConvertType { + /// Compatible - the types are compatible according to the standard. + Compatible, + + /// PointerToInt - The assignment converts a pointer to an int, which we + /// accept as an extension. + PointerToInt, + + /// IntToPointer - The assignment converts an int to a pointer, which we + /// accept as an extension. + IntToPointer, + + /// FunctionVoidPointer - The assignment is between a function pointer and + /// void*, which the standard doesn't allow, but we accept as an extension. + FunctionVoidPointer, + + /// IncompatiblePointer - The assignment is between two pointers types that + /// are not compatible, but we accept them as an extension. + IncompatiblePointer, + + /// IncompatiblePointer - The assignment is between two pointers types which + /// point to integers which have a different sign, but are otherwise identical. + /// This is a subset of the above, but broken out because it's by far the most + /// common case of incompatible pointers. + IncompatiblePointerSign, + + /// CompatiblePointerDiscardsQualifiers - The assignment discards + /// c/v/r qualifiers, which we accept as an extension. + CompatiblePointerDiscardsQualifiers, + + /// IncompatibleVectors - The assignment is between two vector types that + /// have the same size, which we accept as an extension. + IncompatibleVectors, + + /// IntToBlockPointer - The assignment converts an int to a block + /// pointer. We disallow this. + IntToBlockPointer, + + /// IncompatibleBlockPointer - The assignment is between two block + /// pointers types that are not compatible. + IncompatibleBlockPointer, + + /// IncompatibleObjCQualifiedId - The assignment is between a qualified + /// id type and something else (that is incompatible with it). For example, + /// "id <XXX>" = "Foo *", where "Foo *" doesn't implement the XXX protocol. + IncompatibleObjCQualifiedId, + + /// Incompatible - We reject this conversion outright, it is invalid to + /// represent it in the AST. + Incompatible + }; + + /// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the + /// assignment conversion type specified by ConvTy. This returns true if the + /// conversion was invalid or false if the conversion was accepted. + bool DiagnoseAssignmentResult(AssignConvertType ConvTy, + SourceLocation Loc, + QualType DstType, QualType SrcType, + Expr *SrcExpr, const char *Flavor); + + /// CheckAssignmentConstraints - Perform type checking for assignment, + /// argument passing, variable initialization, and function return values. + /// This routine is only used by the following two methods. C99 6.5.16. + AssignConvertType CheckAssignmentConstraints(QualType lhs, QualType rhs); + + // CheckSingleAssignmentConstraints - Currently used by + // CheckAssignmentOperands, and ActOnReturnStmt. Prior to type checking, + // this routine performs the default function/array converions. + AssignConvertType CheckSingleAssignmentConstraints(QualType lhs, + Expr *&rExpr); + + // \brief If the lhs type is a transparent union, check whether we + // can initialize the transparent union with the given expression. + AssignConvertType CheckTransparentUnionArgumentConstraints(QualType lhs, + Expr *&rExpr); + + // Helper function for CheckAssignmentConstraints (C99 6.5.16.1p1) + AssignConvertType CheckPointerTypesForAssignment(QualType lhsType, + QualType rhsType); + + // Helper function for CheckAssignmentConstraints involving two + // block pointer types. + AssignConvertType CheckBlockPointerTypesForAssignment(QualType lhsType, + QualType rhsType); + + bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType); + + bool PerformImplicitConversion(Expr *&From, QualType ToType, + const char *Flavor, + bool AllowExplicit = false, + bool Elidable = false); + bool PerformImplicitConversion(Expr *&From, QualType ToType, + const ImplicitConversionSequence& ICS, + const char *Flavor); + bool PerformImplicitConversion(Expr *&From, QualType ToType, + const StandardConversionSequence& SCS, + const char *Flavor); + + /// the following "Check" methods will return a valid/converted QualType + /// or a null QualType (indicating an error diagnostic was issued). + + /// type checking binary operators (subroutines of CreateBuiltinBinOp). + QualType InvalidOperands(SourceLocation l, Expr *&lex, Expr *&rex); + QualType CheckPointerToMemberOperands( // C++ 5.5 + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isIndirect); + QualType CheckMultiplyDivideOperands( // C99 6.5.5 + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); + QualType CheckRemainderOperands( // C99 6.5.5 + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); + QualType CheckAdditionOperands( // C99 6.5.6 + Expr *&lex, Expr *&rex, SourceLocation OpLoc, QualType* CompLHSTy = 0); + QualType CheckSubtractionOperands( // C99 6.5.6 + Expr *&lex, Expr *&rex, SourceLocation OpLoc, QualType* CompLHSTy = 0); + QualType CheckShiftOperands( // C99 6.5.7 + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); + QualType CheckCompareOperands( // C99 6.5.8/9 + Expr *&lex, Expr *&rex, SourceLocation OpLoc, unsigned Opc, bool isRelational); + QualType CheckBitwiseOperands( // C99 6.5.[10...12] + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); + QualType CheckLogicalOperands( // C99 6.5.[13,14] + Expr *&lex, Expr *&rex, SourceLocation OpLoc); + // CheckAssignmentOperands is used for both simple and compound assignment. + // For simple assignment, pass both expressions and a null converted type. + // For compound assignment, pass both expressions and the converted type. + QualType CheckAssignmentOperands( // C99 6.5.16.[1,2] + Expr *lex, Expr *&rex, SourceLocation OpLoc, QualType convertedType); + QualType CheckCommaOperands( // C99 6.5.17 + Expr *lex, Expr *&rex, SourceLocation OpLoc); + QualType CheckConditionalOperands( // C99 6.5.15 + 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 + + /// type checking for vector binary operators. + inline QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex); + inline QualType CheckVectorCompareOperands(Expr *&lex, Expr *&rx, + SourceLocation l, bool isRel); + + /// type checking unary operators (subroutines of ActOnUnaryOp). + /// C99 6.5.3.1, 6.5.3.2, 6.5.3.4 + QualType CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc, + bool isInc); + QualType CheckAddressOfOperand(Expr *op, SourceLocation OpLoc); + QualType CheckIndirectionOperand(Expr *op, SourceLocation OpLoc); + QualType CheckRealImagOperand(Expr *&Op, SourceLocation OpLoc, bool isReal); + + /// type checking primary expressions. + QualType CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, + IdentifierInfo &Comp, SourceLocation CmpLoc); + + /// type checking declaration initializers (C99 6.7.8) + + bool CheckInitializerTypes(Expr *&simpleInit_or_initList, QualType &declType, + SourceLocation InitLoc,DeclarationName InitEntity, + bool DirectInit); + bool CheckInitList(InitListExpr *&InitList, QualType &DeclType); + bool CheckForConstantInitializer(Expr *e, QualType t); + + bool CheckValueInitialization(QualType Type, SourceLocation Loc); + + // type checking C++ declaration initializers (C++ [dcl.init]). + + /// ReferenceCompareResult - Expresses the result of comparing two + /// types (cv1 T1 and cv2 T2) to determine their compatibility for the + /// purposes of initialization by reference (C++ [dcl.init.ref]p4). + enum ReferenceCompareResult { + /// Ref_Incompatible - The two types are incompatible, so direct + /// reference binding is not possible. + Ref_Incompatible = 0, + /// Ref_Related - The two types are reference-related, which means + /// that their unqualified forms (T1 and T2) are either the same + /// or T1 is a base class of T2. + Ref_Related, + /// Ref_Compatible_With_Added_Qualification - The two types are + /// reference-compatible with added qualification, meaning that + /// they are reference-compatible and the qualifiers on T1 (cv1) + /// are greater than the qualifiers on T2 (cv2). + Ref_Compatible_With_Added_Qualification, + /// Ref_Compatible - The two types are reference-compatible and + /// have equivalent qualifiers (cv1 == cv2). + Ref_Compatible + }; + + ReferenceCompareResult CompareReferenceRelationship(QualType T1, QualType T2, + bool& DerivedToBase); + + bool CheckReferenceInit(Expr *&simpleInit_or_initList, QualType declType, + ImplicitConversionSequence *ICS = 0, + bool SuppressUserConversions = false, + bool AllowExplicit = false, + bool ForceRValue = false); + + /// CheckCastTypes - Check type constraints for casting between types. + bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr); + + // CheckVectorCast - check type constraints for vectors. + // Since vectors are an extension, there are no C standard reference for this. + // We allow casting between vectors and integer datatypes of the same size. + // returns true if the cast is invalid + bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty); + + /// CheckMessageArgumentTypes - Check types in an Obj-C message send. + /// \param Method - May be null. + /// \param [out] ReturnType - The return type of the send. + /// \return true iff there were any incompatible types. + bool CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, Selector Sel, + ObjCMethodDecl *Method, bool isClassMessage, + SourceLocation lbrac, SourceLocation rbrac, + QualType &ReturnType); + + /// CheckCXXBooleanCondition - Returns true if conversion to bool is invalid. + bool CheckCXXBooleanCondition(Expr *&CondExpr); + + /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have + /// the specified width and sign. If an overflow occurs, detect it and emit + /// the specified diagnostic. + void ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &OldVal, + unsigned NewWidth, bool NewSign, + SourceLocation Loc, unsigned DiagID); + + bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS, + bool ForCompare); + + /// Checks that the Objective-C declaration is declared in the global scope. + /// Emits an error and marks the declaration as invalid if it's not declared + /// in the global scope. + bool CheckObjCDeclScope(Decl *D); + + void InitBuiltinVaListType(); + + /// VerifyIntegerConstantExpression - verifies that an expression is an ICE, + /// and reports the appropriate diagnostics. Returns false on success. + /// Can optionally return the value of the expression. + bool VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result = 0); + + /// VerifyBitField - verifies that a bit field expression is an ICE and has + /// the correct width, and that the field type is valid. + /// Returns false on success. + bool VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, + QualType FieldTy, const Expr *BitWidth); + + //===--------------------------------------------------------------------===// + // Extra semantic analysis beyond the C type system +private: + Action::OwningExprResult CheckFunctionCall(FunctionDecl *FDecl, + CallExpr *TheCall); + + Action::OwningExprResult CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall); + SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL, + unsigned ByteNo) const; + bool CheckObjCString(Expr *Arg); + bool SemaBuiltinVAStart(CallExpr *TheCall); + bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); + bool SemaBuiltinStackAddress(CallExpr *TheCall); + +public: + // Used by C++ template instantiation. + Action::OwningExprResult SemaBuiltinShuffleVector(CallExpr *TheCall); + +private: + bool SemaBuiltinPrefetch(CallExpr *TheCall); + bool SemaBuiltinObjectSize(CallExpr *TheCall); + bool SemaBuiltinLongjmp(CallExpr *TheCall); + bool SemaBuiltinAtomicOverloaded(CallExpr *TheCall); + bool SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall, + bool HasVAListArg, unsigned format_idx, + unsigned firstDataArg); + void CheckPrintfString(const StringLiteral *FExpr, const Expr *OrigFormatExpr, + const CallExpr *TheCall, bool HasVAListArg, + unsigned format_idx, unsigned firstDataArg); + void CheckNonNullArguments(const NonNullAttr *NonNull, + const CallExpr *TheCall); + void CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg, + unsigned format_idx, unsigned firstDataArg); + void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, + SourceLocation ReturnLoc); + void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex); +}; + + +//===--------------------------------------------------------------------===// +// Typed version of Parser::ExprArg (smart pointer for wrapping Expr pointers). +template <typename T> +class ExprOwningPtr : public Action::ExprArg { +public: + ExprOwningPtr(Sema *S, T *expr) : Action::ExprArg(*S, expr) {} + + void reset(T* p) { Action::ExprArg::operator=(p); } + T* get() const { return static_cast<T*>(Action::ExprArg::get()); } + T* take() { return static_cast<T*>(Action::ExprArg::take()); } + T* release() { return take(); } + + T& operator*() const { return *get(); } + T* operator->() const { return get(); } +}; + +} // end namespace clang + +#endif diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp new file mode 100644 index 0000000..bae69ac --- /dev/null +++ b/lib/Sema/SemaAccess.cpp @@ -0,0 +1,124 @@ +//===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides Sema routines for C++ access control semantics. +// +//===----------------------------------------------------------------------===// + +#include "SemaInherit.h" +#include "Sema.h" +#include "clang/AST/ASTContext.h" +using namespace clang; + +/// SetMemberAccessSpecifier - Set the access specifier of a member. +/// Returns true on error (when the previous member decl access specifier +/// is different from the new member decl access specifier). +bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, + NamedDecl *PrevMemberDecl, + AccessSpecifier LexicalAS) { + if (!PrevMemberDecl) { + // Use the lexical access specifier. + MemberDecl->setAccess(LexicalAS); + return false; + } + + // C++ [class.access.spec]p3: When a member is redeclared its access + // specifier must be same as its initial declaration. + if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) { + Diag(MemberDecl->getLocation(), + diag::err_class_redeclared_with_different_access) + << MemberDecl << LexicalAS; + Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration) + << PrevMemberDecl << PrevMemberDecl->getAccess(); + return true; + } + + MemberDecl->setAccess(PrevMemberDecl->getAccess()); + return false; +} + +/// CheckBaseClassAccess - Check that a derived class can access its base class +/// and report an error if it can't. [class.access.base] +bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base, + unsigned InaccessibleBaseID, + BasePaths& Paths, SourceLocation AccessLoc, + DeclarationName Name) { + Base = Context.getCanonicalType(Base).getUnqualifiedType(); + assert(!Paths.isAmbiguous(Base) && + "Can't check base class access if set of paths is ambiguous"); + assert(Paths.isRecordingPaths() && + "Can't check base class access without recorded paths"); + + if (!getLangOptions().AccessControl) + return false; + + const CXXBaseSpecifier *InacessibleBase = 0; + + const CXXRecordDecl* CurrentClassDecl = 0; + if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(getCurFunctionDecl())) + CurrentClassDecl = MD->getParent(); + + for (BasePaths::paths_iterator Path = Paths.begin(), PathsEnd = Paths.end(); + Path != PathsEnd; ++Path) { + + bool FoundInaccessibleBase = false; + + for (BasePath::const_iterator Element = Path->begin(), + ElementEnd = Path->end(); Element != ElementEnd; ++Element) { + const CXXBaseSpecifier *Base = Element->Base; + + switch (Base->getAccessSpecifier()) { + default: + assert(0 && "invalid access specifier"); + case AS_public: + // Nothing to do. + break; + case AS_private: + // FIXME: Check if the current function/class is a friend. + if (CurrentClassDecl != Element->Class) + FoundInaccessibleBase = true; + break; + case AS_protected: + // FIXME: Implement + break; + } + + if (FoundInaccessibleBase) { + InacessibleBase = Base; + break; + } + } + + if (!FoundInaccessibleBase) { + // We found a path to the base, our work here is done. + InacessibleBase = 0; + break; + } + } + + if (InacessibleBase) { + Diag(AccessLoc, InaccessibleBaseID) + << Derived << Base << Name; + + AccessSpecifier AS = InacessibleBase->getAccessSpecifierAsWritten(); + + // If there's no written access specifier, then the inheritance specifier + // is implicitly private. + if (AS == AS_none) + Diag(InacessibleBase->getSourceRange().getBegin(), + diag::note_inheritance_implicitly_private_here); + else + Diag(InacessibleBase->getSourceRange().getBegin(), + diag::note_inheritance_specifier_here) << AS; + + return true; + } + + return false; +} diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp new file mode 100644 index 0000000..1bf8444 --- /dev/null +++ b/lib/Sema/SemaAttr.cpp @@ -0,0 +1,211 @@ +//===--- SemaAttr.cpp - Semantic Analysis for Attributes ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for non-trivial attributes and +// pragmas. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/AST/Expr.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// Pragma Packed +//===----------------------------------------------------------------------===// + +namespace { + /// PragmaPackStack - Simple class to wrap the stack used by #pragma + /// pack. + class PragmaPackStack { + typedef std::vector< std::pair<unsigned, IdentifierInfo*> > stack_ty; + + /// Alignment - The current user specified alignment. + unsigned Alignment; + + /// Stack - Entries in the #pragma pack stack, consisting of saved + /// alignments and optional names. + stack_ty Stack; + + public: + PragmaPackStack() : Alignment(0) {} + + void setAlignment(unsigned A) { Alignment = A; } + unsigned getAlignment() { return Alignment; } + + /// push - Push the current alignment onto the stack, optionally + /// using the given \arg Name for the record, if non-zero. + void push(IdentifierInfo *Name) { + Stack.push_back(std::make_pair(Alignment, Name)); + } + + /// pop - Pop a record from the stack and restore the current + /// alignment to the previous value. If \arg Name is non-zero then + /// the first such named record is popped, otherwise the top record + /// is popped. Returns true if the pop succeeded. + bool pop(IdentifierInfo *Name); + }; +} // end anonymous namespace. + +bool PragmaPackStack::pop(IdentifierInfo *Name) { + if (Stack.empty()) + return false; + + // If name is empty just pop top. + if (!Name) { + Alignment = Stack.back().first; + Stack.pop_back(); + return true; + } + + // Otherwise, find the named record. + for (unsigned i = Stack.size(); i != 0; ) { + --i; + if (Stack[i].second == Name) { + // Found it, pop up to and including this record. + Alignment = Stack[i].first; + Stack.erase(Stack.begin() + i, Stack.end()); + return true; + } + } + + return false; +} + + +/// FreePackedContext - Deallocate and null out PackContext. +void Sema::FreePackedContext() { + delete static_cast<PragmaPackStack*>(PackContext); + PackContext = 0; +} + +/// getPragmaPackAlignment() - Return the current alignment as specified by +/// the current #pragma pack directive, or 0 if none is currently active. +unsigned Sema::getPragmaPackAlignment() const { + if (PackContext) + return static_cast<PragmaPackStack*>(PackContext)->getAlignment(); + return 0; +} + +void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, + ExprTy *alignment, SourceLocation PragmaLoc, + SourceLocation LParenLoc, SourceLocation RParenLoc) { + Expr *Alignment = static_cast<Expr *>(alignment); + + // If specified then alignment must be a "small" power of two. + unsigned AlignmentVal = 0; + if (Alignment) { + llvm::APSInt Val; + + // pack(0) is like pack(), which just works out since that is what + // we use 0 for in PackAttr. + if (!Alignment->isIntegerConstantExpr(Val, Context) || + !(Val == 0 || Val.isPowerOf2()) || + Val.getZExtValue() > 16) { + Diag(PragmaLoc, diag::warn_pragma_pack_invalid_alignment); + Alignment->Destroy(Context); + return; // Ignore + } + + AlignmentVal = (unsigned) Val.getZExtValue(); + } + + if (PackContext == 0) + PackContext = new PragmaPackStack(); + + PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext); + + switch (Kind) { + case Action::PPK_Default: // pack([n]) + Context->setAlignment(AlignmentVal); + break; + + case Action::PPK_Show: // pack(show) + // Show the current alignment, making sure to show the right value + // for the default. + AlignmentVal = Context->getAlignment(); + // FIXME: This should come from the target. + if (AlignmentVal == 0) + AlignmentVal = 8; + Diag(PragmaLoc, diag::warn_pragma_pack_show) << AlignmentVal; + break; + + case Action::PPK_Push: // pack(push [, id] [, [n]) + Context->push(Name); + // Set the new alignment if specified. + if (Alignment) + Context->setAlignment(AlignmentVal); + break; + + case Action::PPK_Pop: // pack(pop [, id] [, n]) + // MSDN, C/C++ Preprocessor Reference > Pragma Directives > pack: + // "#pragma pack(pop, identifier, n) is undefined" + if (Alignment && Name) + Diag(PragmaLoc, diag::warn_pragma_pack_pop_identifer_and_alignment); + + // Do the pop. + if (!Context->pop(Name)) { + // If a name was specified then failure indicates the name + // wasn't found. Otherwise failure indicates the stack was + // empty. + Diag(PragmaLoc, diag::warn_pragma_pack_pop_failed) + << (Name ? "no record matching name" : "stack empty"); + + // FIXME: Warn about popping named records as MSVC does. + } else { + // Pop succeeded, set the new alignment if specified. + if (Alignment) + Context->setAlignment(AlignmentVal); + } + break; + + default: + assert(0 && "Invalid #pragma pack kind."); + } +} + +void Sema::ActOnPragmaUnused(ExprTy **Exprs, unsigned NumExprs, + SourceLocation PragmaLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + + // Verify that all of the expressions are valid before + // modifying the attributes of any referenced decl. + Expr *ErrorExpr = 0; + + for (unsigned i = 0; i < NumExprs; ++i) { + Expr *Ex = (Expr*) Exprs[i]; + if (!isa<DeclRefExpr>(Ex)) { + ErrorExpr = Ex; + break; + } + + Decl *d = cast<DeclRefExpr>(Ex)->getDecl();; + + if (!isa<VarDecl>(d) || !cast<VarDecl>(d)->hasLocalStorage()) { + ErrorExpr = Ex; + break; + } + } + + // Delete the expressions if we encountered any error. + if (ErrorExpr) { + Diag(ErrorExpr->getLocStart(), diag::warn_pragma_unused_expected_localvar); + for (unsigned i = 0; i < NumExprs; ++i) + ((Expr*) Exprs[i])->Destroy(Context); + return; + } + + // Otherwise, add the 'unused' attribute to each referenced declaration. + for (unsigned i = 0; i < NumExprs; ++i) { + DeclRefExpr *DR = (DeclRefExpr*) Exprs[i]; + DR->getDecl()->addAttr(::new (Context) UnusedAttr()); + DR->Destroy(Context); + } +} diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp new file mode 100644 index 0000000..11ac0bd --- /dev/null +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -0,0 +1,312 @@ +//===--- SemaCXXScopeSpec.cpp - Semantic Analysis for C++ scope specifiers-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements C++ semantic analysis for scope specifiers. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/Parse/DeclSpec.h" +#include "llvm/ADT/STLExtras.h" +using namespace clang; + +/// \brief Compute the DeclContext that is associated with the given +/// scope specifier. +DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS) { + if (!SS.isSet() || SS.isInvalid()) + return 0; + + NestedNameSpecifier *NNS + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + if (NNS->isDependent()) { + // If this nested-name-specifier refers to the current + // instantiation, return its DeclContext. + if (CXXRecordDecl *Record = getCurrentInstantiationOf(NNS)) + return Record; + else + return 0; + } + + switch (NNS->getKind()) { + case NestedNameSpecifier::Identifier: + assert(false && "Dependent nested-name-specifier has no DeclContext"); + break; + + case NestedNameSpecifier::Namespace: + return NNS->getAsNamespace(); + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: { + const TagType *Tag = NNS->getAsType()->getAsTagType(); + assert(Tag && "Non-tag type in nested-name-specifier"); + return Tag->getDecl(); + } break; + + case NestedNameSpecifier::Global: + return Context.getTranslationUnitDecl(); + } + + // Required to silence a GCC warning. + return 0; +} + +bool Sema::isDependentScopeSpecifier(const CXXScopeSpec &SS) { + if (!SS.isSet() || SS.isInvalid()) + return false; + + NestedNameSpecifier *NNS + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + return NNS->isDependent(); +} + +// \brief Determine whether this C++ scope specifier refers to an +// unknown specialization, i.e., a dependent type that is not the +// current instantiation. +bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) { + if (!isDependentScopeSpecifier(SS)) + return false; + + NestedNameSpecifier *NNS + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + return getCurrentInstantiationOf(NNS) == 0; +} + +/// \brief If the given nested name specifier refers to the current +/// instantiation, return the declaration that corresponds to that +/// current instantiation (C++0x [temp.dep.type]p1). +/// +/// \param NNS a dependent nested name specifier. +CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) { + assert(getLangOptions().CPlusPlus && "Only callable in C++"); + assert(NNS->isDependent() && "Only dependent nested-name-specifier allowed"); + + QualType T = QualType(NNS->getAsType(), 0); + // If the nested name specifier does not refer to a type, then it + // does not refer to the current instantiation. + if (T.isNull()) + return 0; + + T = Context.getCanonicalType(T); + + for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getParent()) { + // If we've hit a namespace or the global scope, then the + // nested-name-specifier can't refer to the current instantiation. + if (Ctx->isFileContext()) + return 0; + + // Skip non-class contexts. + CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx); + if (!Record) + continue; + + // If this record type is not dependent, + if (!Record->isDependentType()) + return 0; + + // C++ [temp.dep.type]p1: + // + // In the definition of a class template, a nested class of a + // class template, a member of a class template, or a member of a + // nested class of a class template, a name refers to the current + // instantiation if it is + // -- the injected-class-name (9) of the class template or + // nested class, + // -- in the definition of a primary class template, the name + // of the class template followed by the template argument + // list of the primary template (as described below) + // enclosed in <>, + // -- in the definition of a nested class of a class template, + // the name of the nested class referenced as a member of + // the current instantiation, or + // -- in the definition of a partial specialization, the name + // of the class template followed by the template argument + // list of the partial specialization enclosed in <>. If + // the nth template parameter is a parameter pack, the nth + // template argument is a pack expansion (14.6.3) whose + // pattern is the name of the parameter pack. (FIXME) + // + // All of these options come down to having the + // nested-name-specifier type that is equivalent to the + // injected-class-name of one of the types that is currently in + // our context. + if (Context.getTypeDeclType(Record) == T) + return Record; + + if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) { + QualType InjectedClassName + = Template->getInjectedClassNameType(Context); + if (T == Context.getCanonicalType(InjectedClassName)) + return Template->getTemplatedDecl(); + } + } + + return 0; +} + +/// \brief Require that the context specified by SS be complete. +/// +/// If SS refers to a type, this routine checks whether the type is +/// complete enough (or can be made complete enough) for name lookup +/// into the DeclContext. A type that is not yet completed can be +/// considered "complete enough" if it is a class/struct/union/enum +/// that is currently being defined. Or, if we have a type that names +/// a class template specialization that is not a complete type, we +/// will attempt to instantiate that class template. +bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) { + if (!SS.isSet() || SS.isInvalid()) + return false; + + DeclContext *DC = computeDeclContext(SS); + if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) { + // If we're currently defining this type, then lookup into the + // type is okay: don't complain that it isn't complete yet. + const TagType *TagT = Context.getTypeDeclType(Tag)->getAsTagType(); + if (TagT->isBeingDefined()) + return false; + + // The type must be complete. + return RequireCompleteType(SS.getRange().getBegin(), + Context.getTypeDeclType(Tag), + diag::err_incomplete_nested_name_spec, + SS.getRange()); + } + + return false; +} + +/// ActOnCXXGlobalScopeSpecifier - Return the object that represents the +/// global scope ('::'). +Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S, + SourceLocation CCLoc) { + return NestedNameSpecifier::GlobalSpecifier(Context); +} + +/// ActOnCXXNestedNameSpecifier - Called during parsing of a +/// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now +/// we want to resolve "bar::". 'SS' is empty or the previously parsed +/// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar', +/// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'. +/// Returns a CXXScopeTy* object representing the C++ scope. +Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, + const CXXScopeSpec &SS, + SourceLocation IdLoc, + SourceLocation CCLoc, + IdentifierInfo &II) { + NestedNameSpecifier *Prefix + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + + // If the prefix already refers to an unknown specialization, there + // is no name lookup to perform. Just build the resulting + // nested-name-specifier. + if (Prefix && isUnknownSpecialization(SS)) + return NestedNameSpecifier::Create(Context, Prefix, &II); + + NamedDecl *SD = LookupParsedName(S, &SS, &II, LookupNestedNameSpecifierName); + + if (SD) { + if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD)) + return NestedNameSpecifier::Create(Context, Prefix, Namespace); + + if (TypeDecl *Type = dyn_cast<TypeDecl>(SD)) { + // Determine whether we have a class (or, in C++0x, an enum) or + // a typedef thereof. If so, build the nested-name-specifier. + QualType T = Context.getTypeDeclType(Type); + bool AcceptableType = false; + if (T->isDependentType()) + AcceptableType = true; + else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) { + if (TD->getUnderlyingType()->isRecordType() || + (getLangOptions().CPlusPlus0x && + TD->getUnderlyingType()->isEnumeralType())) + AcceptableType = true; + } else if (isa<RecordDecl>(Type) || + (getLangOptions().CPlusPlus0x && isa<EnumDecl>(Type))) + AcceptableType = true; + + if (AcceptableType) + return NestedNameSpecifier::Create(Context, Prefix, false, + T.getTypePtr()); + } + + if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD)) + return NestedNameSpecifier::Create(Context, Prefix, + Alias->getNamespace()); + + // Fall through to produce an error: we found something that isn't + // a class or a namespace. + } + + // If we didn't find anything during our lookup, try again with + // ordinary name lookup, which can help us produce better error + // messages. + if (!SD) + SD = LookupParsedName(S, &SS, &II, LookupOrdinaryName); + unsigned DiagID; + if (SD) + DiagID = diag::err_expected_class_or_namespace; + else if (SS.isSet()) + DiagID = diag::err_typecheck_no_member; + else + DiagID = diag::err_undeclared_var_use; + + if (SS.isSet()) + Diag(IdLoc, DiagID) << &II << SS.getRange(); + else + Diag(IdLoc, DiagID) << &II; + + return 0; +} + +Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, + const CXXScopeSpec &SS, + TypeTy *Ty, + SourceRange TypeRange, + SourceLocation CCLoc) { + NestedNameSpecifier *Prefix + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + QualType T = QualType::getFromOpaquePtr(Ty); + return NestedNameSpecifier::Create(Context, Prefix, /*FIXME:*/false, + T.getTypePtr()); +} + +/// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global +/// scope or nested-name-specifier) is parsed, part of a declarator-id. +/// After this method is called, according to [C++ 3.4.3p3], names should be +/// looked up in the declarator-id's scope, until the declarator is parsed and +/// ActOnCXXExitDeclaratorScope is called. +/// The 'SS' should be a non-empty valid CXXScopeSpec. +void Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { + assert(SS.isSet() && "Parser passed invalid CXXScopeSpec."); + assert(PreDeclaratorDC == 0 && "Previous declarator context not popped?"); + PreDeclaratorDC = static_cast<DeclContext*>(S->getEntity()); + CurContext = computeDeclContext(SS); + assert(CurContext && "No context?"); + S->setEntity(CurContext); +} + +/// ActOnCXXExitDeclaratorScope - Called when a declarator that previously +/// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same +/// CXXScopeSpec that was passed to ActOnCXXEnterDeclaratorScope as well. +/// Used to indicate that names should revert to being looked up in the +/// defining scope. +void Sema::ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { + assert(SS.isSet() && "Parser passed invalid CXXScopeSpec."); + assert(S->getEntity() == computeDeclContext(SS) && "Context imbalance!"); + S->setEntity(PreDeclaratorDC); + PreDeclaratorDC = 0; + + // Reset CurContext to the nearest enclosing context. + while (!S->getEntity() && S->getParent()) + S = S->getParent(); + CurContext = static_cast<DeclContext*>(S->getEntity()); + assert(CurContext && "No context?"); +} diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp new file mode 100644 index 0000000..4856e7f --- /dev/null +++ b/lib/Sema/SemaChecking.cpp @@ -0,0 +1,1449 @@ +//===--- SemaChecking.cpp - Extra Semantic Checking -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements extra semantic analysis beyond what is enforced +// by the C type system. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/Lex/LiteralSupport.h" +#include "clang/Lex/Preprocessor.h" +#include <limits> +using namespace clang; + +/// getLocationOfStringLiteralByte - Return a source location that points to the +/// specified byte of the specified string literal. +/// +/// Strings are amazingly complex. They can be formed from multiple tokens and +/// can have escape sequences in them in addition to the usual trigraph and +/// escaped newline business. This routine handles this complexity. +/// +SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL, + unsigned ByteNo) const { + assert(!SL->isWide() && "This doesn't work for wide strings yet"); + + // Loop over all of the tokens in this string until we find the one that + // contains the byte we're looking for. + unsigned TokNo = 0; + while (1) { + assert(TokNo < SL->getNumConcatenated() && "Invalid byte number!"); + SourceLocation StrTokLoc = SL->getStrTokenLoc(TokNo); + + // Get the spelling of the string so that we can get the data that makes up + // the string literal, not the identifier for the macro it is potentially + // expanded through. + SourceLocation StrTokSpellingLoc = SourceMgr.getSpellingLoc(StrTokLoc); + + // Re-lex the token to get its length and original spelling. + std::pair<FileID, unsigned> LocInfo = + SourceMgr.getDecomposedLoc(StrTokSpellingLoc); + std::pair<const char *,const char *> Buffer = + SourceMgr.getBufferData(LocInfo.first); + const char *StrData = Buffer.first+LocInfo.second; + + // Create a langops struct and enable trigraphs. This is sufficient for + // relexing tokens. + LangOptions LangOpts; + LangOpts.Trigraphs = true; + + // Create a lexer starting at the beginning of this token. + Lexer TheLexer(StrTokSpellingLoc, LangOpts, Buffer.first, StrData, + Buffer.second); + Token TheTok; + TheLexer.LexFromRawLexer(TheTok); + + // Use the StringLiteralParser to compute the length of the string in bytes. + StringLiteralParser SLP(&TheTok, 1, PP); + unsigned TokNumBytes = SLP.GetStringLength(); + + // If the byte is in this token, return the location of the byte. + if (ByteNo < TokNumBytes || + (ByteNo == TokNumBytes && TokNo == SL->getNumConcatenated())) { + unsigned Offset = + StringLiteralParser::getOffsetOfStringByte(TheTok, ByteNo, PP); + + // Now that we know the offset of the token in the spelling, use the + // preprocessor to get the offset in the original source. + return PP.AdvanceToTokenCharacter(StrTokLoc, Offset); + } + + // Move to the next string token. + ++TokNo; + ByteNo -= TokNumBytes; + } +} + + +/// CheckFunctionCall - Check a direct function call for various correctness +/// and safety properties not strictly enforced by the C type system. +Action::OwningExprResult +Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { + OwningExprResult TheCallResult(Owned(TheCall)); + // Get the IdentifierInfo* for the called function. + IdentifierInfo *FnInfo = FDecl->getIdentifier(); + + // None of the checks below are needed for functions that don't have + // simple names (e.g., C++ conversion functions). + if (!FnInfo) + return move(TheCallResult); + + switch (FDecl->getBuiltinID(Context)) { + case Builtin::BI__builtin___CFStringMakeConstantString: + assert(TheCall->getNumArgs() == 1 && + "Wrong # arguments to builtin CFStringMakeConstantString"); + if (CheckObjCString(TheCall->getArg(0))) + return ExprError(); + return move(TheCallResult); + case Builtin::BI__builtin_stdarg_start: + case Builtin::BI__builtin_va_start: + if (SemaBuiltinVAStart(TheCall)) + return ExprError(); + return move(TheCallResult); + case Builtin::BI__builtin_isgreater: + case Builtin::BI__builtin_isgreaterequal: + case Builtin::BI__builtin_isless: + case Builtin::BI__builtin_islessequal: + case Builtin::BI__builtin_islessgreater: + case Builtin::BI__builtin_isunordered: + if (SemaBuiltinUnorderedCompare(TheCall)) + return ExprError(); + return move(TheCallResult); + case Builtin::BI__builtin_return_address: + case Builtin::BI__builtin_frame_address: + if (SemaBuiltinStackAddress(TheCall)) + return ExprError(); + return move(TheCallResult); + case Builtin::BI__builtin_shufflevector: + return SemaBuiltinShuffleVector(TheCall); + // TheCall will be freed by the smart pointer here, but that's fine, since + // SemaBuiltinShuffleVector guts it, but then doesn't release it. + case Builtin::BI__builtin_prefetch: + if (SemaBuiltinPrefetch(TheCall)) + return ExprError(); + return move(TheCallResult); + case Builtin::BI__builtin_object_size: + if (SemaBuiltinObjectSize(TheCall)) + return ExprError(); + return move(TheCallResult); + case Builtin::BI__builtin_longjmp: + if (SemaBuiltinLongjmp(TheCall)) + return ExprError(); + return move(TheCallResult); + case Builtin::BI__sync_fetch_and_add: + case Builtin::BI__sync_fetch_and_sub: + case Builtin::BI__sync_fetch_and_or: + case Builtin::BI__sync_fetch_and_and: + case Builtin::BI__sync_fetch_and_xor: + case Builtin::BI__sync_fetch_and_nand: + case Builtin::BI__sync_add_and_fetch: + case Builtin::BI__sync_sub_and_fetch: + case Builtin::BI__sync_and_and_fetch: + case Builtin::BI__sync_or_and_fetch: + case Builtin::BI__sync_xor_and_fetch: + case Builtin::BI__sync_nand_and_fetch: + case Builtin::BI__sync_val_compare_and_swap: + case Builtin::BI__sync_bool_compare_and_swap: + case Builtin::BI__sync_lock_test_and_set: + case Builtin::BI__sync_lock_release: + if (SemaBuiltinAtomicOverloaded(TheCall)) + return ExprError(); + return move(TheCallResult); + } + + // FIXME: This mechanism should be abstracted to be less fragile and + // more efficient. For example, just map function ids to custom + // handlers. + + // Printf checking. + if (const FormatAttr *Format = FDecl->getAttr<FormatAttr>()) { + if (Format->getType() == "printf") { + bool HasVAListArg = Format->getFirstArg() == 0; + if (!HasVAListArg) { + if (const FunctionProtoType *Proto + = FDecl->getType()->getAsFunctionProtoType()) + HasVAListArg = !Proto->isVariadic(); + } + CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1, + HasVAListArg ? 0 : Format->getFirstArg() - 1); + } + } + for (const Attr *attr = FDecl->getAttrs(); attr; attr = attr->getNext()) { + if (const NonNullAttr *NonNull = dyn_cast<NonNullAttr>(attr)) + CheckNonNullArguments(NonNull, TheCall); + } + + return move(TheCallResult); +} + +Action::OwningExprResult +Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) { + + OwningExprResult TheCallResult(Owned(TheCall)); + // Printf checking. + const FormatAttr *Format = NDecl->getAttr<FormatAttr>(); + if (!Format) + return move(TheCallResult); + const VarDecl *V = dyn_cast<VarDecl>(NDecl); + if (!V) + return move(TheCallResult); + QualType Ty = V->getType(); + if (!Ty->isBlockPointerType()) + return move(TheCallResult); + if (Format->getType() == "printf") { + bool HasVAListArg = Format->getFirstArg() == 0; + if (!HasVAListArg) { + const FunctionType *FT = + Ty->getAsBlockPointerType()->getPointeeType()->getAsFunctionType(); + if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) + HasVAListArg = !Proto->isVariadic(); + } + CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1, + HasVAListArg ? 0 : Format->getFirstArg() - 1); + } + return move(TheCallResult); +} + +/// SemaBuiltinAtomicOverloaded - We have a call to a function like +/// __sync_fetch_and_add, which is an overloaded function based on the pointer +/// type of its first argument. The main ActOnCallExpr routines have already +/// promoted the types of arguments because all of these calls are prototyped as +/// void(...). +/// +/// This function goes through and does final semantic checking for these +/// builtins, +bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { + DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts()); + FunctionDecl *FDecl = cast<FunctionDecl>(DRE->getDecl()); + + // Ensure that we have at least one argument to do type inference from. + if (TheCall->getNumArgs() < 1) + return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) + << 0 << TheCall->getCallee()->getSourceRange(); + + // Inspect the first argument of the atomic builtin. This should always be + // a pointer type, whose element is an integral scalar or pointer type. + // Because it is a pointer type, we don't have to worry about any implicit + // casts here. + Expr *FirstArg = TheCall->getArg(0); + if (!FirstArg->getType()->isPointerType()) + return Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer) + << FirstArg->getType() << FirstArg->getSourceRange(); + + QualType ValType = FirstArg->getType()->getAsPointerType()->getPointeeType(); + if (!ValType->isIntegerType() && !ValType->isPointerType() && + !ValType->isBlockPointerType()) + return Diag(DRE->getLocStart(), + diag::err_atomic_builtin_must_be_pointer_intptr) + << FirstArg->getType() << FirstArg->getSourceRange(); + + // We need to figure out which concrete builtin this maps onto. For example, + // __sync_fetch_and_add with a 2 byte object turns into + // __sync_fetch_and_add_2. +#define BUILTIN_ROW(x) \ + { Builtin::BI##x##_1, Builtin::BI##x##_2, Builtin::BI##x##_4, \ + Builtin::BI##x##_8, Builtin::BI##x##_16 } + + static const unsigned BuiltinIndices[][5] = { + BUILTIN_ROW(__sync_fetch_and_add), + BUILTIN_ROW(__sync_fetch_and_sub), + BUILTIN_ROW(__sync_fetch_and_or), + BUILTIN_ROW(__sync_fetch_and_and), + BUILTIN_ROW(__sync_fetch_and_xor), + BUILTIN_ROW(__sync_fetch_and_nand), + + BUILTIN_ROW(__sync_add_and_fetch), + BUILTIN_ROW(__sync_sub_and_fetch), + BUILTIN_ROW(__sync_and_and_fetch), + BUILTIN_ROW(__sync_or_and_fetch), + BUILTIN_ROW(__sync_xor_and_fetch), + BUILTIN_ROW(__sync_nand_and_fetch), + + BUILTIN_ROW(__sync_val_compare_and_swap), + BUILTIN_ROW(__sync_bool_compare_and_swap), + BUILTIN_ROW(__sync_lock_test_and_set), + BUILTIN_ROW(__sync_lock_release) + }; +#undef BUILTIN_ROW + + // Determine the index of the size. + unsigned SizeIndex; + switch (Context.getTypeSize(ValType)/8) { + case 1: SizeIndex = 0; break; + case 2: SizeIndex = 1; break; + case 4: SizeIndex = 2; break; + case 8: SizeIndex = 3; break; + case 16: SizeIndex = 4; break; + default: + return Diag(DRE->getLocStart(), diag::err_atomic_builtin_pointer_size) + << FirstArg->getType() << FirstArg->getSourceRange(); + } + + // Each of these builtins has one pointer argument, followed by some number of + // values (0, 1 or 2) followed by a potentially empty varags list of stuff + // that we ignore. Find out which row of BuiltinIndices to read from as well + // as the number of fixed args. + unsigned BuiltinID = FDecl->getBuiltinID(Context); + unsigned BuiltinIndex, NumFixed = 1; + switch (BuiltinID) { + default: assert(0 && "Unknown overloaded atomic builtin!"); + case Builtin::BI__sync_fetch_and_add: BuiltinIndex = 0; break; + case Builtin::BI__sync_fetch_and_sub: BuiltinIndex = 1; break; + case Builtin::BI__sync_fetch_and_or: BuiltinIndex = 2; break; + case Builtin::BI__sync_fetch_and_and: BuiltinIndex = 3; break; + case Builtin::BI__sync_fetch_and_xor: BuiltinIndex = 4; break; + case Builtin::BI__sync_fetch_and_nand:BuiltinIndex = 5; break; + + case Builtin::BI__sync_add_and_fetch: BuiltinIndex = 6; break; + case Builtin::BI__sync_sub_and_fetch: BuiltinIndex = 7; break; + case Builtin::BI__sync_and_and_fetch: BuiltinIndex = 8; break; + case Builtin::BI__sync_or_and_fetch: BuiltinIndex = 9; break; + case Builtin::BI__sync_xor_and_fetch: BuiltinIndex =10; break; + case Builtin::BI__sync_nand_and_fetch:BuiltinIndex =11; break; + + case Builtin::BI__sync_val_compare_and_swap: + BuiltinIndex = 12; + NumFixed = 2; + break; + case Builtin::BI__sync_bool_compare_and_swap: + BuiltinIndex = 13; + NumFixed = 2; + break; + case Builtin::BI__sync_lock_test_and_set: BuiltinIndex = 14; break; + case Builtin::BI__sync_lock_release: + BuiltinIndex = 15; + NumFixed = 0; + break; + } + + // Now that we know how many fixed arguments we expect, first check that we + // have at least that many. + if (TheCall->getNumArgs() < 1+NumFixed) + return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) + << 0 << TheCall->getCallee()->getSourceRange(); + + + // Get the decl for the concrete builtin from this, we can tell what the + // concrete integer type we should convert to is. + unsigned NewBuiltinID = BuiltinIndices[BuiltinIndex][SizeIndex]; + const char *NewBuiltinName = Context.BuiltinInfo.GetName(NewBuiltinID); + IdentifierInfo *NewBuiltinII = PP.getIdentifierInfo(NewBuiltinName); + FunctionDecl *NewBuiltinDecl = + cast<FunctionDecl>(LazilyCreateBuiltin(NewBuiltinII, NewBuiltinID, + TUScope, false, DRE->getLocStart())); + const FunctionProtoType *BuiltinFT = + NewBuiltinDecl->getType()->getAsFunctionProtoType(); + ValType = BuiltinFT->getArgType(0)->getAsPointerType()->getPointeeType(); + + // If the first type needs to be converted (e.g. void** -> int*), do it now. + if (BuiltinFT->getArgType(0) != FirstArg->getType()) { + ImpCastExprToType(FirstArg, BuiltinFT->getArgType(0), false); + TheCall->setArg(0, FirstArg); + } + + // Next, walk the valid ones promoting to the right type. + for (unsigned i = 0; i != NumFixed; ++i) { + Expr *Arg = TheCall->getArg(i+1); + + // If the argument is an implicit cast, then there was a promotion due to + // "...", just remove it now. + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { + Arg = ICE->getSubExpr(); + ICE->setSubExpr(0); + ICE->Destroy(Context); + TheCall->setArg(i+1, Arg); + } + + // GCC does an implicit conversion to the pointer or integer ValType. This + // can fail in some cases (1i -> int**), check for this error case now. + if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg)) + return true; + + // Okay, we have something that *can* be converted to the right type. Check + // to see if there is a potentially weird extension going on here. This can + // happen when you do an atomic operation on something like an char* and + // pass in 42. The 42 gets converted to char. This is even more strange + // for things like 45.123 -> char, etc. + // FIXME: Do this check. + ImpCastExprToType(Arg, ValType, false); + TheCall->setArg(i+1, Arg); + } + + // Switch the DeclRefExpr to refer to the new decl. + DRE->setDecl(NewBuiltinDecl); + DRE->setType(NewBuiltinDecl->getType()); + + // Set the callee in the CallExpr. + // FIXME: This leaks the original parens and implicit casts. + Expr *PromotedCall = DRE; + UsualUnaryConversions(PromotedCall); + TheCall->setCallee(PromotedCall); + + + // Change the result type of the call to match the result type of the decl. + TheCall->setType(NewBuiltinDecl->getResultType()); + return false; +} + + +/// CheckObjCString - Checks that the argument to the builtin +/// CFString constructor is correct +/// FIXME: GCC currently emits the following warning: +/// "warning: input conversion stopped due to an input byte that does not +/// belong to the input codeset UTF-8" +/// Note: It might also make sense to do the UTF-16 conversion here (would +/// simplify the backend). +bool Sema::CheckObjCString(Expr *Arg) { + Arg = Arg->IgnoreParenCasts(); + StringLiteral *Literal = dyn_cast<StringLiteral>(Arg); + + if (!Literal || Literal->isWide()) { + Diag(Arg->getLocStart(), diag::err_cfstring_literal_not_string_constant) + << Arg->getSourceRange(); + return true; + } + + const char *Data = Literal->getStrData(); + unsigned Length = Literal->getByteLength(); + + for (unsigned i = 0; i < Length; ++i) { + if (!Data[i]) { + Diag(getLocationOfStringLiteralByte(Literal, i), + diag::warn_cfstring_literal_contains_nul_character) + << Arg->getSourceRange(); + break; + } + } + + return false; +} + +/// SemaBuiltinVAStart - Check the arguments to __builtin_va_start for validity. +/// Emit an error and return true on failure, return false on success. +bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { + Expr *Fn = TheCall->getCallee(); + if (TheCall->getNumArgs() > 2) { + Diag(TheCall->getArg(2)->getLocStart(), + diag::err_typecheck_call_too_many_args) + << 0 /*function call*/ << Fn->getSourceRange() + << SourceRange(TheCall->getArg(2)->getLocStart(), + (*(TheCall->arg_end()-1))->getLocEnd()); + return true; + } + + if (TheCall->getNumArgs() < 2) { + return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) + << 0 /*function call*/; + } + + // Determine whether the current function is variadic or not. + bool isVariadic; + if (CurBlock) + isVariadic = CurBlock->isVariadic; + else if (getCurFunctionDecl()) { + if (FunctionProtoType* FTP = + dyn_cast<FunctionProtoType>(getCurFunctionDecl()->getType())) + isVariadic = FTP->isVariadic(); + else + isVariadic = false; + } else { + isVariadic = getCurMethodDecl()->isVariadic(); + } + + if (!isVariadic) { + Diag(Fn->getLocStart(), diag::err_va_start_used_in_non_variadic_function); + return true; + } + + // Verify that the second argument to the builtin is the last argument of the + // current function or method. + bool SecondArgIsLastNamedArgument = false; + const Expr *Arg = TheCall->getArg(1)->IgnoreParenCasts(); + + if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Arg)) { + if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(DR->getDecl())) { + // FIXME: This isn't correct for methods (results in bogus warning). + // Get the last formal in the current function. + const ParmVarDecl *LastArg; + if (CurBlock) + LastArg = *(CurBlock->TheDecl->param_end()-1); + else if (FunctionDecl *FD = getCurFunctionDecl()) + LastArg = *(FD->param_end()-1); + else + LastArg = *(getCurMethodDecl()->param_end()-1); + SecondArgIsLastNamedArgument = PV == LastArg; + } + } + + if (!SecondArgIsLastNamedArgument) + Diag(TheCall->getArg(1)->getLocStart(), + diag::warn_second_parameter_of_va_start_not_last_named_argument); + return false; +} + +/// SemaBuiltinUnorderedCompare - Handle functions like __builtin_isgreater and +/// friends. This is declared to take (...), so we have to check everything. +bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) { + if (TheCall->getNumArgs() < 2) + return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) + << 0 /*function call*/; + if (TheCall->getNumArgs() > 2) + return Diag(TheCall->getArg(2)->getLocStart(), + diag::err_typecheck_call_too_many_args) + << 0 /*function call*/ + << SourceRange(TheCall->getArg(2)->getLocStart(), + (*(TheCall->arg_end()-1))->getLocEnd()); + + Expr *OrigArg0 = TheCall->getArg(0); + Expr *OrigArg1 = TheCall->getArg(1); + + // Do standard promotions between the two arguments, returning their common + // type. + QualType Res = UsualArithmeticConversions(OrigArg0, OrigArg1, false); + + // Make sure any conversions are pushed back into the call; this is + // type safe since unordered compare builtins are declared as "_Bool + // foo(...)". + TheCall->setArg(0, OrigArg0); + TheCall->setArg(1, OrigArg1); + + if (OrigArg0->isTypeDependent() || OrigArg1->isTypeDependent()) + return false; + + // If the common type isn't a real floating type, then the arguments were + // invalid for this operation. + if (!Res->isRealFloatingType()) + return Diag(OrigArg0->getLocStart(), + diag::err_typecheck_call_invalid_ordered_compare) + << OrigArg0->getType() << OrigArg1->getType() + << SourceRange(OrigArg0->getLocStart(), OrigArg1->getLocEnd()); + + return false; +} + +bool Sema::SemaBuiltinStackAddress(CallExpr *TheCall) { + // The signature for these builtins is exact; the only thing we need + // to check is that the argument is a constant. + SourceLocation Loc; + if (!TheCall->getArg(0)->isTypeDependent() && + !TheCall->getArg(0)->isValueDependent() && + !TheCall->getArg(0)->isIntegerConstantExpr(Context, &Loc)) + return Diag(Loc, diag::err_stack_const_level) << TheCall->getSourceRange(); + + return false; +} + +/// SemaBuiltinShuffleVector - Handle __builtin_shufflevector. +// This is declared to take (...), so we have to check everything. +Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { + if (TheCall->getNumArgs() < 3) + return ExprError(Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_few_args) + << 0 /*function call*/ << TheCall->getSourceRange()); + + unsigned numElements = std::numeric_limits<unsigned>::max(); + if (!TheCall->getArg(0)->isTypeDependent() && + !TheCall->getArg(1)->isTypeDependent()) { + QualType FAType = TheCall->getArg(0)->getType(); + QualType SAType = TheCall->getArg(1)->getType(); + + if (!FAType->isVectorType() || !SAType->isVectorType()) { + Diag(TheCall->getLocStart(), diag::err_shufflevector_non_vector) + << SourceRange(TheCall->getArg(0)->getLocStart(), + TheCall->getArg(1)->getLocEnd()); + return ExprError(); + } + + if (Context.getCanonicalType(FAType).getUnqualifiedType() != + Context.getCanonicalType(SAType).getUnqualifiedType()) { + Diag(TheCall->getLocStart(), diag::err_shufflevector_incompatible_vector) + << SourceRange(TheCall->getArg(0)->getLocStart(), + TheCall->getArg(1)->getLocEnd()); + return ExprError(); + } + + numElements = FAType->getAsVectorType()->getNumElements(); + if (TheCall->getNumArgs() != numElements+2) { + if (TheCall->getNumArgs() < numElements+2) + return ExprError(Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_few_args) + << 0 /*function call*/ << TheCall->getSourceRange()); + return ExprError(Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_many_args) + << 0 /*function call*/ << TheCall->getSourceRange()); + } + } + + for (unsigned i = 2; i < TheCall->getNumArgs(); i++) { + if (TheCall->getArg(i)->isTypeDependent() || + TheCall->getArg(i)->isValueDependent()) + continue; + + llvm::APSInt Result(32); + if (!TheCall->getArg(i)->isIntegerConstantExpr(Result, Context)) + return ExprError(Diag(TheCall->getLocStart(), + diag::err_shufflevector_nonconstant_argument) + << TheCall->getArg(i)->getSourceRange()); + + if (Result.getActiveBits() > 64 || Result.getZExtValue() >= numElements*2) + return ExprError(Diag(TheCall->getLocStart(), + diag::err_shufflevector_argument_too_large) + << TheCall->getArg(i)->getSourceRange()); + } + + llvm::SmallVector<Expr*, 32> exprs; + + for (unsigned i = 0, e = TheCall->getNumArgs(); i != e; i++) { + exprs.push_back(TheCall->getArg(i)); + TheCall->setArg(i, 0); + } + + return Owned(new (Context) ShuffleVectorExpr(exprs.begin(), exprs.size(), + exprs[0]->getType(), + TheCall->getCallee()->getLocStart(), + TheCall->getRParenLoc())); +} + +/// SemaBuiltinPrefetch - Handle __builtin_prefetch. +// This is declared to take (const void*, ...) and can take two +// optional constant int args. +bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) { + unsigned NumArgs = TheCall->getNumArgs(); + + if (NumArgs > 3) + return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_many_args) + << 0 /*function call*/ << TheCall->getSourceRange(); + + // Argument 0 is checked for us and the remaining arguments must be + // constant integers. + for (unsigned i = 1; i != NumArgs; ++i) { + Expr *Arg = TheCall->getArg(i); + if (Arg->isTypeDependent()) + continue; + + QualType RWType = Arg->getType(); + + const BuiltinType *BT = RWType->getAsBuiltinType(); + llvm::APSInt Result; + if (!BT || BT->getKind() != BuiltinType::Int) + return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_argument) + << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); + + if (Arg->isValueDependent()) + continue; + + if (!Arg->isIntegerConstantExpr(Result, Context)) + return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_argument) + << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); + + // FIXME: gcc issues a warning and rewrites these to 0. These + // seems especially odd for the third argument since the default + // is 3. + if (i == 1) { + if (Result.getSExtValue() < 0 || Result.getSExtValue() > 1) + return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range) + << "0" << "1" << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); + } else { + if (Result.getSExtValue() < 0 || Result.getSExtValue() > 3) + return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range) + << "0" << "3" << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); + } + } + + return false; +} + +/// SemaBuiltinObjectSize - Handle __builtin_object_size(void *ptr, +/// int type). This simply type checks that type is one of the defined +/// constants (0-3). +bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) { + Expr *Arg = TheCall->getArg(1); + if (Arg->isTypeDependent()) + return false; + + QualType ArgType = Arg->getType(); + const BuiltinType *BT = ArgType->getAsBuiltinType(); + llvm::APSInt Result(32); + if (!BT || BT->getKind() != BuiltinType::Int) + return Diag(TheCall->getLocStart(), diag::err_object_size_invalid_argument) + << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); + + if (Arg->isValueDependent()) + return false; + + if (!Arg->isIntegerConstantExpr(Result, Context)) { + return Diag(TheCall->getLocStart(), diag::err_object_size_invalid_argument) + << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); + } + + if (Result.getSExtValue() < 0 || Result.getSExtValue() > 3) { + return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range) + << "0" << "3" << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); + } + + return false; +} + +/// SemaBuiltinLongjmp - Handle __builtin_longjmp(void *env[5], int val). +/// This checks that val is a constant 1. +bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) { + Expr *Arg = TheCall->getArg(1); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + return false; + + llvm::APSInt Result(32); + if (!Arg->isIntegerConstantExpr(Result, Context) || Result != 1) + return Diag(TheCall->getLocStart(), diag::err_builtin_longjmp_invalid_val) + << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); + + return false; +} + +// Handle i > 1 ? "x" : "y", recursivelly +bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall, + bool HasVAListArg, + unsigned format_idx, unsigned firstDataArg) { + if (E->isTypeDependent() || E->isValueDependent()) + return false; + + switch (E->getStmtClass()) { + case Stmt::ConditionalOperatorClass: { + const ConditionalOperator *C = cast<ConditionalOperator>(E); + return SemaCheckStringLiteral(C->getLHS(), TheCall, + HasVAListArg, format_idx, firstDataArg) + && SemaCheckStringLiteral(C->getRHS(), TheCall, + HasVAListArg, format_idx, firstDataArg); + } + + case Stmt::ImplicitCastExprClass: { + const ImplicitCastExpr *Expr = cast<ImplicitCastExpr>(E); + return SemaCheckStringLiteral(Expr->getSubExpr(), TheCall, HasVAListArg, + format_idx, firstDataArg); + } + + case Stmt::ParenExprClass: { + const ParenExpr *Expr = cast<ParenExpr>(E); + return SemaCheckStringLiteral(Expr->getSubExpr(), TheCall, HasVAListArg, + format_idx, firstDataArg); + } + + case Stmt::DeclRefExprClass: { + const DeclRefExpr *DR = cast<DeclRefExpr>(E); + + // As an exception, do not flag errors for variables binding to + // const string literals. + if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { + bool isConstant = false; + QualType T = DR->getType(); + + if (const ArrayType *AT = Context.getAsArrayType(T)) { + isConstant = AT->getElementType().isConstant(Context); + } + else if (const PointerType *PT = T->getAsPointerType()) { + isConstant = T.isConstant(Context) && + PT->getPointeeType().isConstant(Context); + } + + if (isConstant) { + const VarDecl *Def = 0; + if (const Expr *Init = VD->getDefinition(Def)) + return SemaCheckStringLiteral(Init, TheCall, + HasVAListArg, format_idx, firstDataArg); + } + } + + return false; + } + + case Stmt::ObjCStringLiteralClass: + case Stmt::StringLiteralClass: { + const StringLiteral *StrE = NULL; + + if (const ObjCStringLiteral *ObjCFExpr = dyn_cast<ObjCStringLiteral>(E)) + StrE = ObjCFExpr->getString(); + else + StrE = cast<StringLiteral>(E); + + if (StrE) { + CheckPrintfString(StrE, E, TheCall, HasVAListArg, format_idx, + firstDataArg); + return true; + } + + return false; + } + + default: + return false; + } +} + +void +Sema::CheckNonNullArguments(const NonNullAttr *NonNull, const CallExpr *TheCall) +{ + for (NonNullAttr::iterator i = NonNull->begin(), e = NonNull->end(); + i != e; ++i) { + const Expr *ArgExpr = TheCall->getArg(*i); + if (ArgExpr->isNullPointerConstant(Context)) + Diag(TheCall->getCallee()->getLocStart(), diag::warn_null_arg) + << ArgExpr->getSourceRange(); + } +} + +/// CheckPrintfArguments - Check calls to printf (and similar functions) for +/// correct use of format strings. +/// +/// HasVAListArg - A predicate indicating whether the printf-like +/// function is passed an explicit va_arg argument (e.g., vprintf) +/// +/// format_idx - The index into Args for the format string. +/// +/// Improper format strings to functions in the printf family can be +/// the source of bizarre bugs and very serious security holes. A +/// good source of information is available in the following paper +/// (which includes additional references): +/// +/// FormatGuard: Automatic Protection From printf Format String +/// Vulnerabilities, Proceedings of the 10th USENIX Security Symposium, 2001. +/// +/// Functionality implemented: +/// +/// We can statically check the following properties for string +/// literal format strings for non v.*printf functions (where the +/// arguments are passed directly): +// +/// (1) Are the number of format conversions equal to the number of +/// data arguments? +/// +/// (2) Does each format conversion correctly match the type of the +/// corresponding data argument? (TODO) +/// +/// Moreover, for all printf functions we can: +/// +/// (3) Check for a missing format string (when not caught by type checking). +/// +/// (4) Check for no-operation flags; e.g. using "#" with format +/// conversion 'c' (TODO) +/// +/// (5) Check the use of '%n', a major source of security holes. +/// +/// (6) Check for malformed format conversions that don't specify anything. +/// +/// (7) Check for empty format strings. e.g: printf(""); +/// +/// (8) Check that the format string is a wide literal. +/// +/// (9) Also check the arguments of functions with the __format__ attribute. +/// (TODO). +/// +/// All of these checks can be done by parsing the format string. +/// +/// For now, we ONLY do (1), (3), (5), (6), (7), and (8). +void +Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg, + unsigned format_idx, unsigned firstDataArg) { + const Expr *Fn = TheCall->getCallee(); + + // CHECK: printf-like function is called with no format string. + if (format_idx >= TheCall->getNumArgs()) { + Diag(TheCall->getRParenLoc(), diag::warn_printf_missing_format_string) + << Fn->getSourceRange(); + return; + } + + const Expr *OrigFormatExpr = TheCall->getArg(format_idx)->IgnoreParenCasts(); + + // CHECK: format string is not a string literal. + // + // Dynamically generated format strings are difficult to + // automatically vet at compile time. Requiring that format strings + // are string literals: (1) permits the checking of format strings by + // the compiler and thereby (2) can practically remove the source of + // many format string exploits. + + // Format string can be either ObjC string (e.g. @"%d") or + // C string (e.g. "%d") + // ObjC string uses the same format specifiers as C string, so we can use + // the same format string checking logic for both ObjC and C strings. + if (SemaCheckStringLiteral(OrigFormatExpr, TheCall, HasVAListArg, format_idx, + firstDataArg)) + return; // Literal format string found, check done! + + // For vprintf* functions (i.e., HasVAListArg==true), we add a + // special check to see if the format string is a function parameter + // of the function calling the printf function. If the function + // has an attribute indicating it is a printf-like function, then we + // should suppress warnings concerning non-literals being used in a call + // to a vprintf function. For example: + // + // void + // logmessage(char const *fmt __attribute__ (format (printf, 1, 2)), ...) { + // va_list ap; + // va_start(ap, fmt); + // vprintf(fmt, ap); // Do NOT emit a warning about "fmt". + // ... + // + // + // FIXME: We don't have full attribute support yet, so just check to see + // if the argument is a DeclRefExpr that references a parameter. We'll + // add proper support for checking the attribute later. + if (HasVAListArg) + if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(OrigFormatExpr)) + if (isa<ParmVarDecl>(DR->getDecl())) + return; + + // If there are no arguments specified, warn with -Wformat-security, otherwise + // warn only with -Wformat-nonliteral. + if (TheCall->getNumArgs() == format_idx+1) + Diag(TheCall->getArg(format_idx)->getLocStart(), + diag::warn_printf_nonliteral_noargs) + << OrigFormatExpr->getSourceRange(); + else + Diag(TheCall->getArg(format_idx)->getLocStart(), + diag::warn_printf_nonliteral) + << OrigFormatExpr->getSourceRange(); +} + +void Sema::CheckPrintfString(const StringLiteral *FExpr, + const Expr *OrigFormatExpr, + const CallExpr *TheCall, bool HasVAListArg, + unsigned format_idx, unsigned firstDataArg) { + + const ObjCStringLiteral *ObjCFExpr = + dyn_cast<ObjCStringLiteral>(OrigFormatExpr); + + // CHECK: is the format string a wide literal? + if (FExpr->isWide()) { + Diag(FExpr->getLocStart(), + diag::warn_printf_format_string_is_wide_literal) + << OrigFormatExpr->getSourceRange(); + return; + } + + // Str - The format string. NOTE: this is NOT null-terminated! + const char *Str = FExpr->getStrData(); + + // CHECK: empty format string? + unsigned StrLen = FExpr->getByteLength(); + + if (StrLen == 0) { + Diag(FExpr->getLocStart(), diag::warn_printf_empty_format_string) + << OrigFormatExpr->getSourceRange(); + return; + } + + // We process the format string using a binary state machine. The + // current state is stored in CurrentState. + enum { + state_OrdChr, + state_Conversion + } CurrentState = state_OrdChr; + + // numConversions - The number of conversions seen so far. This is + // incremented as we traverse the format string. + unsigned numConversions = 0; + + // numDataArgs - The number of data arguments after the format + // string. This can only be determined for non vprintf-like + // functions. For those functions, this value is 1 (the sole + // va_arg argument). + unsigned numDataArgs = TheCall->getNumArgs()-firstDataArg; + + // Inspect the format string. + unsigned StrIdx = 0; + + // LastConversionIdx - Index within the format string where we last saw + // a '%' character that starts a new format conversion. + unsigned LastConversionIdx = 0; + + for (; StrIdx < StrLen; ++StrIdx) { + + // Is the number of detected conversion conversions greater than + // the number of matching data arguments? If so, stop. + if (!HasVAListArg && numConversions > numDataArgs) break; + + // Handle "\0" + if (Str[StrIdx] == '\0') { + // The string returned by getStrData() is not null-terminated, + // so the presence of a null character is likely an error. + Diag(getLocationOfStringLiteralByte(FExpr, StrIdx), + diag::warn_printf_format_string_contains_null_char) + << OrigFormatExpr->getSourceRange(); + return; + } + + // Ordinary characters (not processing a format conversion). + if (CurrentState == state_OrdChr) { + if (Str[StrIdx] == '%') { + CurrentState = state_Conversion; + LastConversionIdx = StrIdx; + } + continue; + } + + // Seen '%'. Now processing a format conversion. + switch (Str[StrIdx]) { + // Handle dynamic precision or width specifier. + case '*': { + ++numConversions; + + if (!HasVAListArg) { + if (numConversions > numDataArgs) { + SourceLocation Loc = getLocationOfStringLiteralByte(FExpr, StrIdx); + + if (Str[StrIdx-1] == '.') + Diag(Loc, diag::warn_printf_asterisk_precision_missing_arg) + << OrigFormatExpr->getSourceRange(); + else + Diag(Loc, diag::warn_printf_asterisk_width_missing_arg) + << OrigFormatExpr->getSourceRange(); + + // Don't do any more checking. We'll just emit spurious errors. + return; + } + + // Perform type checking on width/precision specifier. + const Expr *E = TheCall->getArg(format_idx+numConversions); + if (const BuiltinType *BT = E->getType()->getAsBuiltinType()) + if (BT->getKind() == BuiltinType::Int) + break; + + SourceLocation Loc = getLocationOfStringLiteralByte(FExpr, StrIdx); + + if (Str[StrIdx-1] == '.') + Diag(Loc, diag::warn_printf_asterisk_precision_wrong_type) + << E->getType() << E->getSourceRange(); + else + Diag(Loc, diag::warn_printf_asterisk_width_wrong_type) + << E->getType() << E->getSourceRange(); + + break; + } + } + + // Characters which can terminate a format conversion + // (e.g. "%d"). Characters that specify length modifiers or + // other flags are handled by the default case below. + // + // FIXME: additional checks will go into the following cases. + case 'i': + case 'd': + case 'o': + case 'u': + case 'x': + case 'X': + case 'D': + case 'O': + case 'U': + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + case 'a': + case 'A': + case 'c': + case 'C': + case 'S': + case 's': + case 'p': + ++numConversions; + CurrentState = state_OrdChr; + break; + + case 'm': + // FIXME: Warn in situations where this isn't supported! + CurrentState = state_OrdChr; + break; + + // CHECK: Are we using "%n"? Issue a warning. + case 'n': { + ++numConversions; + CurrentState = state_OrdChr; + SourceLocation Loc = getLocationOfStringLiteralByte(FExpr, + LastConversionIdx); + + Diag(Loc, diag::warn_printf_write_back)<<OrigFormatExpr->getSourceRange(); + break; + } + + // Handle "%@" + case '@': + // %@ is allowed in ObjC format strings only. + if(ObjCFExpr != NULL) + CurrentState = state_OrdChr; + else { + // Issue a warning: invalid format conversion. + SourceLocation Loc = + getLocationOfStringLiteralByte(FExpr, LastConversionIdx); + + Diag(Loc, diag::warn_printf_invalid_conversion) + << std::string(Str+LastConversionIdx, + Str+std::min(LastConversionIdx+2, StrLen)) + << OrigFormatExpr->getSourceRange(); + } + ++numConversions; + break; + + // Handle "%%" + case '%': + // Sanity check: Was the first "%" character the previous one? + // If not, we will assume that we have a malformed format + // conversion, and that the current "%" character is the start + // of a new conversion. + if (StrIdx - LastConversionIdx == 1) + CurrentState = state_OrdChr; + else { + // Issue a warning: invalid format conversion. + SourceLocation Loc = + getLocationOfStringLiteralByte(FExpr, LastConversionIdx); + + Diag(Loc, diag::warn_printf_invalid_conversion) + << std::string(Str+LastConversionIdx, Str+StrIdx) + << OrigFormatExpr->getSourceRange(); + + // This conversion is broken. Advance to the next format + // conversion. + LastConversionIdx = StrIdx; + ++numConversions; + } + break; + + default: + // This case catches all other characters: flags, widths, etc. + // We should eventually process those as well. + break; + } + } + + if (CurrentState == state_Conversion) { + // Issue a warning: invalid format conversion. + SourceLocation Loc = + getLocationOfStringLiteralByte(FExpr, LastConversionIdx); + + Diag(Loc, diag::warn_printf_invalid_conversion) + << std::string(Str+LastConversionIdx, + Str+std::min(LastConversionIdx+2, StrLen)) + << OrigFormatExpr->getSourceRange(); + return; + } + + if (!HasVAListArg) { + // CHECK: Does the number of format conversions exceed the number + // of data arguments? + if (numConversions > numDataArgs) { + SourceLocation Loc = + getLocationOfStringLiteralByte(FExpr, LastConversionIdx); + + Diag(Loc, diag::warn_printf_insufficient_data_args) + << OrigFormatExpr->getSourceRange(); + } + // CHECK: Does the number of data arguments exceed the number of + // format conversions in the format string? + else if (numConversions < numDataArgs) + Diag(TheCall->getArg(format_idx+numConversions+1)->getLocStart(), + diag::warn_printf_too_many_data_args) + << OrigFormatExpr->getSourceRange(); + } +} + +//===--- CHECK: Return Address of Stack Variable --------------------------===// + +static DeclRefExpr* EvalVal(Expr *E); +static DeclRefExpr* EvalAddr(Expr* E); + +/// CheckReturnStackAddr - Check if a return statement returns the address +/// of a stack variable. +void +Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, + SourceLocation ReturnLoc) { + + // Perform checking for returned stack addresses. + if (lhsType->isPointerType() || lhsType->isBlockPointerType()) { + if (DeclRefExpr *DR = EvalAddr(RetValExp)) + Diag(DR->getLocStart(), diag::warn_ret_stack_addr) + << DR->getDecl()->getDeclName() << RetValExp->getSourceRange(); + + // Skip over implicit cast expressions when checking for block expressions. + if (ImplicitCastExpr *IcExpr = + dyn_cast_or_null<ImplicitCastExpr>(RetValExp)) + RetValExp = IcExpr->getSubExpr(); + + if (BlockExpr *C = dyn_cast_or_null<BlockExpr>(RetValExp)) + if (C->hasBlockDeclRefExprs()) + Diag(C->getLocStart(), diag::err_ret_local_block) + << C->getSourceRange(); + } + // Perform checking for stack values returned by reference. + else if (lhsType->isReferenceType()) { + // Check for a reference to the stack + if (DeclRefExpr *DR = EvalVal(RetValExp)) + Diag(DR->getLocStart(), diag::warn_ret_stack_ref) + << DR->getDecl()->getDeclName() << RetValExp->getSourceRange(); + } +} + +/// EvalAddr - EvalAddr and EvalVal are mutually recursive functions that +/// check if the expression in a return statement evaluates to an address +/// to a location on the stack. The recursion is used to traverse the +/// AST of the return expression, with recursion backtracking when we +/// encounter a subexpression that (1) clearly does not lead to the address +/// of a stack variable or (2) is something we cannot determine leads to +/// the address of a stack variable based on such local checking. +/// +/// EvalAddr processes expressions that are pointers that are used as +/// references (and not L-values). EvalVal handles all other values. +/// At the base case of the recursion is a check for a DeclRefExpr* in +/// the refers to a stack variable. +/// +/// This implementation handles: +/// +/// * pointer-to-pointer casts +/// * implicit conversions from array references to pointers +/// * taking the address of fields +/// * arbitrary interplay between "&" and "*" operators +/// * pointer arithmetic from an address of a stack variable +/// * taking the address of an array element where the array is on the stack +static DeclRefExpr* EvalAddr(Expr *E) { + // We should only be called for evaluating pointer expressions. + assert((E->getType()->isPointerType() || + E->getType()->isBlockPointerType() || + E->getType()->isObjCQualifiedIdType()) && + "EvalAddr only works on pointers"); + + // Our "symbolic interpreter" is just a dispatch off the currently + // viewed AST node. We then recursively traverse the AST by calling + // EvalAddr and EvalVal appropriately. + switch (E->getStmtClass()) { + case Stmt::ParenExprClass: + // Ignore parentheses. + return EvalAddr(cast<ParenExpr>(E)->getSubExpr()); + + case Stmt::UnaryOperatorClass: { + // The only unary operator that make sense to handle here + // is AddrOf. All others don't make sense as pointers. + UnaryOperator *U = cast<UnaryOperator>(E); + + if (U->getOpcode() == UnaryOperator::AddrOf) + return EvalVal(U->getSubExpr()); + else + return NULL; + } + + case Stmt::BinaryOperatorClass: { + // Handle pointer arithmetic. All other binary operators are not valid + // in this context. + BinaryOperator *B = cast<BinaryOperator>(E); + BinaryOperator::Opcode op = B->getOpcode(); + + if (op != BinaryOperator::Add && op != BinaryOperator::Sub) + return NULL; + + Expr *Base = B->getLHS(); + + // Determine which argument is the real pointer base. It could be + // the RHS argument instead of the LHS. + if (!Base->getType()->isPointerType()) Base = B->getRHS(); + + assert (Base->getType()->isPointerType()); + return EvalAddr(Base); + } + + // For conditional operators we need to see if either the LHS or RHS are + // valid DeclRefExpr*s. If one of them is valid, we return it. + case Stmt::ConditionalOperatorClass: { + ConditionalOperator *C = cast<ConditionalOperator>(E); + + // Handle the GNU extension for missing LHS. + if (Expr *lhsExpr = C->getLHS()) + if (DeclRefExpr* LHS = EvalAddr(lhsExpr)) + return LHS; + + return EvalAddr(C->getRHS()); + } + + // For casts, we need to handle conversions from arrays to + // pointer values, and pointer-to-pointer conversions. + case Stmt::ImplicitCastExprClass: + case Stmt::CStyleCastExprClass: + case Stmt::CXXFunctionalCastExprClass: { + Expr* SubExpr = cast<CastExpr>(E)->getSubExpr(); + QualType T = SubExpr->getType(); + + if (SubExpr->getType()->isPointerType() || + SubExpr->getType()->isBlockPointerType() || + SubExpr->getType()->isObjCQualifiedIdType()) + return EvalAddr(SubExpr); + else if (T->isArrayType()) + return EvalVal(SubExpr); + else + return 0; + } + + // C++ casts. For dynamic casts, static casts, and const casts, we + // are always converting from a pointer-to-pointer, so we just blow + // through the cast. In the case the dynamic cast doesn't fail (and + // return NULL), we take the conservative route and report cases + // where we return the address of a stack variable. For Reinterpre + // FIXME: The comment about is wrong; we're not always converting + // from pointer to pointer. I'm guessing that this code should also + // handle references to objects. + case Stmt::CXXStaticCastExprClass: + case Stmt::CXXDynamicCastExprClass: + case Stmt::CXXConstCastExprClass: + case Stmt::CXXReinterpretCastExprClass: { + Expr *S = cast<CXXNamedCastExpr>(E)->getSubExpr(); + if (S->getType()->isPointerType() || S->getType()->isBlockPointerType()) + return EvalAddr(S); + else + return NULL; + } + + // Everything else: we simply don't reason about them. + default: + return NULL; + } +} + + +/// EvalVal - This function is complements EvalAddr in the mutual recursion. +/// See the comments for EvalAddr for more details. +static DeclRefExpr* EvalVal(Expr *E) { + + // We should only be called for evaluating non-pointer expressions, or + // expressions with a pointer type that are not used as references but instead + // are l-values (e.g., DeclRefExpr with a pointer type). + + // Our "symbolic interpreter" is just a dispatch off the currently + // viewed AST node. We then recursively traverse the AST by calling + // EvalAddr and EvalVal appropriately. + switch (E->getStmtClass()) { + case Stmt::DeclRefExprClass: + case Stmt::QualifiedDeclRefExprClass: { + // DeclRefExpr: the base case. When we hit a DeclRefExpr we are looking + // at code that refers to a variable's name. We check if it has local + // storage within the function, and if so, return the expression. + DeclRefExpr *DR = cast<DeclRefExpr>(E); + + if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) + if(V->hasLocalStorage() && !V->getType()->isReferenceType()) return DR; + + return NULL; + } + + case Stmt::ParenExprClass: + // Ignore parentheses. + return EvalVal(cast<ParenExpr>(E)->getSubExpr()); + + case Stmt::UnaryOperatorClass: { + // The only unary operator that make sense to handle here + // is Deref. All others don't resolve to a "name." This includes + // handling all sorts of rvalues passed to a unary operator. + UnaryOperator *U = cast<UnaryOperator>(E); + + if (U->getOpcode() == UnaryOperator::Deref) + return EvalAddr(U->getSubExpr()); + + return NULL; + } + + case Stmt::ArraySubscriptExprClass: { + // Array subscripts are potential references to data on the stack. We + // retrieve the DeclRefExpr* for the array variable if it indeed + // has local storage. + return EvalAddr(cast<ArraySubscriptExpr>(E)->getBase()); + } + + case Stmt::ConditionalOperatorClass: { + // For conditional operators we need to see if either the LHS or RHS are + // non-NULL DeclRefExpr's. If one is non-NULL, we return it. + ConditionalOperator *C = cast<ConditionalOperator>(E); + + // Handle the GNU extension for missing LHS. + if (Expr *lhsExpr = C->getLHS()) + if (DeclRefExpr *LHS = EvalVal(lhsExpr)) + return LHS; + + return EvalVal(C->getRHS()); + } + + // Accesses to members are potential references to data on the stack. + case Stmt::MemberExprClass: { + MemberExpr *M = cast<MemberExpr>(E); + + // Check for indirect access. We only want direct field accesses. + if (!M->isArrow()) + return EvalVal(M->getBase()); + else + return NULL; + } + + // Everything else: we simply don't reason about them. + default: + return NULL; + } +} + +//===--- CHECK: Floating-Point comparisons (-Wfloat-equal) ---------------===// + +/// Check for comparisons of floating point operands using != and ==. +/// Issue a warning if these are no self-comparisons, as they are not likely +/// to do what the programmer intended. +void Sema::CheckFloatComparison(SourceLocation loc, Expr* lex, Expr *rex) { + bool EmitWarning = true; + + Expr* LeftExprSansParen = lex->IgnoreParens(); + Expr* RightExprSansParen = rex->IgnoreParens(); + + // Special case: check for x == x (which is OK). + // Do not emit warnings for such cases. + if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(LeftExprSansParen)) + if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RightExprSansParen)) + if (DRL->getDecl() == DRR->getDecl()) + EmitWarning = false; + + + // Special case: check for comparisons against literals that can be exactly + // represented by APFloat. In such cases, do not emit a warning. This + // is a heuristic: often comparison against such literals are used to + // detect if a value in a variable has not changed. This clearly can + // lead to false negatives. + if (EmitWarning) { + if (FloatingLiteral* FLL = dyn_cast<FloatingLiteral>(LeftExprSansParen)) { + if (FLL->isExact()) + EmitWarning = false; + } + else + if (FloatingLiteral* FLR = dyn_cast<FloatingLiteral>(RightExprSansParen)){ + if (FLR->isExact()) + EmitWarning = false; + } + } + + // Check for comparisons with builtin types. + if (EmitWarning) + if (CallExpr* CL = dyn_cast<CallExpr>(LeftExprSansParen)) + if (CL->isBuiltinCall(Context)) + EmitWarning = false; + + if (EmitWarning) + if (CallExpr* CR = dyn_cast<CallExpr>(RightExprSansParen)) + if (CR->isBuiltinCall(Context)) + EmitWarning = false; + + // Emit the diagnostic. + if (EmitWarning) + Diag(loc, diag::warn_floatingpoint_eq) + << lex->getSourceRange() << rex->getSourceRange(); +} diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp new file mode 100644 index 0000000..959154c --- /dev/null +++ b/lib/Sema/SemaDecl.cpp @@ -0,0 +1,4415 @@ +//===--- SemaDecl.cpp - Semantic Analysis for Declarations ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for declarations. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "SemaInherit.h" +#include "clang/AST/APValue.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtCXX.h" +#include "clang/Parse/DeclSpec.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/SourceManager.h" +// FIXME: layering (ideally, Sema shouldn't be dependent on Lex API's) +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/HeaderSearch.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/STLExtras.h" +#include <algorithm> +#include <functional> +using namespace clang; + +/// getDeclName - Return a pretty name for the specified decl if possible, or +/// an empty string if not. This is used for pretty crash reporting. +std::string Sema::getDeclName(DeclPtrTy d) { + Decl *D = d.getAs<Decl>(); + if (NamedDecl *DN = dyn_cast_or_null<NamedDecl>(D)) + return DN->getQualifiedNameAsString(); + return ""; +} + +Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(DeclPtrTy Ptr) { + return DeclGroupPtrTy::make(DeclGroupRef(Ptr.getAs<Decl>())); +} + +/// \brief If the identifier refers to a type name within this scope, +/// return the declaration of that type. +/// +/// This routine performs ordinary name lookup of the identifier II +/// within the given scope, with optional C++ scope specifier SS, to +/// determine whether the name refers to a type. If so, returns an +/// opaque pointer (actually a QualType) corresponding to that +/// type. Otherwise, returns NULL. +/// +/// If name lookup results in an ambiguity, this routine will complain +/// and then return NULL. +Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, + Scope *S, const CXXScopeSpec *SS) { + // C++ [temp.res]p3: + // A qualified-id that refers to a type and in which the + // nested-name-specifier depends on a template-parameter (14.6.2) + // shall be prefixed by the keyword typename to indicate that the + // qualified-id denotes a type, forming an + // elaborated-type-specifier (7.1.5.3). + // + // We therefore do not perform any name lookup if the result would + // refer to a member of an unknown specialization. + if (SS && isUnknownSpecialization(*SS)) + return 0; + + LookupResult Result + = LookupParsedName(S, SS, &II, LookupOrdinaryName, false, false); + + NamedDecl *IIDecl = 0; + switch (Result.getKind()) { + case LookupResult::NotFound: + case LookupResult::FoundOverloaded: + return 0; + + case LookupResult::AmbiguousBaseSubobjectTypes: + case LookupResult::AmbiguousBaseSubobjects: + case LookupResult::AmbiguousReference: { + // Look to see if we have a type anywhere in the list of results. + for (LookupResult::iterator Res = Result.begin(), ResEnd = Result.end(); + Res != ResEnd; ++Res) { + if (isa<TypeDecl>(*Res) || isa<ObjCInterfaceDecl>(*Res)) { + if (!IIDecl || + (*Res)->getLocation().getRawEncoding() < + IIDecl->getLocation().getRawEncoding()) + IIDecl = *Res; + } + } + + if (!IIDecl) { + // None of the entities we found is a type, so there is no way + // to even assume that the result is a type. In this case, don't + // complain about the ambiguity. The parser will either try to + // perform this lookup again (e.g., as an object name), which + // will produce the ambiguity, or will complain that it expected + // a type name. + Result.Destroy(); + return 0; + } + + // We found a type within the ambiguous lookup; diagnose the + // ambiguity and then return that type. This might be the right + // answer, or it might not be, but it suppresses any attempt to + // perform the name lookup again. + DiagnoseAmbiguousLookup(Result, DeclarationName(&II), NameLoc); + break; + } + + case LookupResult::Found: + IIDecl = Result.getAsDecl(); + break; + } + + if (IIDecl) { + QualType T; + + if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) { + // Check whether we can use this type + (void)DiagnoseUseOfDecl(IIDecl, NameLoc); + + if (getLangOptions().CPlusPlus) { + // C++ [temp.local]p2: + // Within the scope of a class template specialization or + // partial specialization, when the injected-class-name is + // not followed by a <, it is equivalent to the + // injected-class-name followed by the template-argument s + // of the class template specialization or partial + // specialization enclosed in <>. + if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD)) + if (RD->isInjectedClassName()) + if (ClassTemplateDecl *Template = RD->getDescribedClassTemplate()) + T = Template->getInjectedClassNameType(Context); + } + + if (T.isNull()) + T = Context.getTypeDeclType(TD); + } else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) { + // Check whether we can use this interface. + (void)DiagnoseUseOfDecl(IIDecl, NameLoc); + + T = Context.getObjCInterfaceType(IDecl); + } else + return 0; + + if (SS) + T = getQualifiedNameType(*SS, T); + + return T.getAsOpaquePtr(); + } + + return 0; +} + +/// isTagName() - This method is called *for error recovery purposes only* +/// to determine if the specified name is a valid tag name ("struct foo"). If +/// so, this returns the TST for the tag corresponding to it (TST_enum, +/// TST_union, TST_struct, TST_class). This is used to diagnose cases in C +/// where the user forgot to specify the tag. +DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { + // Do a tag name lookup in this scope. + LookupResult R = LookupName(S, &II, LookupTagName, false, false); + if (R.getKind() == LookupResult::Found) + if (const TagDecl *TD = dyn_cast<TagDecl>(R.getAsDecl())) { + switch (TD->getTagKind()) { + case TagDecl::TK_struct: return DeclSpec::TST_struct; + case TagDecl::TK_union: return DeclSpec::TST_union; + case TagDecl::TK_class: return DeclSpec::TST_class; + case TagDecl::TK_enum: return DeclSpec::TST_enum; + } + } + + return DeclSpec::TST_unspecified; +} + + + +DeclContext *Sema::getContainingDC(DeclContext *DC) { + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) { + // A C++ out-of-line method will return to the file declaration context. + if (MD->isOutOfLineDefinition()) + return MD->getLexicalDeclContext(); + + // A C++ inline method is parsed *after* the topmost class it was declared + // in is fully parsed (it's "complete"). + // The parsing of a C++ inline method happens at the declaration context of + // the topmost (non-nested) class it is lexically declared in. + assert(isa<CXXRecordDecl>(MD->getParent()) && "C++ method not in Record."); + DC = MD->getParent(); + while (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC->getLexicalParent())) + DC = RD; + + // Return the declaration context of the topmost class the inline method is + // declared in. + return DC; + } + + if (isa<ObjCMethodDecl>(DC)) + return Context.getTranslationUnitDecl(); + + return DC->getLexicalParent(); +} + +void Sema::PushDeclContext(Scope *S, DeclContext *DC) { + assert(getContainingDC(DC) == CurContext && + "The next DeclContext should be lexically contained in the current one."); + CurContext = DC; + S->setEntity(DC); +} + +void Sema::PopDeclContext() { + assert(CurContext && "DeclContext imbalance!"); + + CurContext = getContainingDC(CurContext); +} + +/// \brief Determine whether we allow overloading of the function +/// PrevDecl with another declaration. +/// +/// This routine determines whether overloading is possible, not +/// whether some new function is actually an overload. It will return +/// true in C++ (where we can always provide overloads) or, as an +/// extension, in C when the previous function is already an +/// overloaded function declaration or has the "overloadable" +/// attribute. +static bool AllowOverloadingOfFunction(Decl *PrevDecl, ASTContext &Context) { + if (Context.getLangOptions().CPlusPlus) + return true; + + if (isa<OverloadedFunctionDecl>(PrevDecl)) + return true; + + return PrevDecl->getAttr<OverloadableAttr>() != 0; +} + +/// Add this decl to the scope shadowed decl chains. +void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) { + // Move up the scope chain until we find the nearest enclosing + // non-transparent context. The declaration will be introduced into this + // scope. + while (S->getEntity() && + ((DeclContext *)S->getEntity())->isTransparentContext()) + S = S->getParent(); + + S->AddDecl(DeclPtrTy::make(D)); + + // Add scoped declarations into their context, so that they can be + // found later. Declarations without a context won't be inserted + // into any context. + CurContext->addDecl(Context, D); + + // C++ [basic.scope]p4: + // -- exactly one declaration shall declare a class name or + // enumeration name that is not a typedef name and the other + // declarations shall all refer to the same object or + // enumerator, or all refer to functions and function templates; + // in this case the class name or enumeration name is hidden. + if (TagDecl *TD = dyn_cast<TagDecl>(D)) { + // We are pushing the name of a tag (enum or class). + if (CurContext->getLookupContext() + == TD->getDeclContext()->getLookupContext()) { + // We're pushing the tag into the current context, which might + // require some reshuffling in the identifier resolver. + IdentifierResolver::iterator + I = IdResolver.begin(TD->getDeclName()), + IEnd = IdResolver.end(); + if (I != IEnd && isDeclInScope(*I, CurContext, S)) { + NamedDecl *PrevDecl = *I; + for (; I != IEnd && isDeclInScope(*I, CurContext, S); + PrevDecl = *I, ++I) { + if (TD->declarationReplaces(*I)) { + // This is a redeclaration. Remove it from the chain and + // break out, so that we'll add in the shadowed + // declaration. + S->RemoveDecl(DeclPtrTy::make(*I)); + if (PrevDecl == *I) { + IdResolver.RemoveDecl(*I); + IdResolver.AddDecl(TD); + return; + } else { + IdResolver.RemoveDecl(*I); + break; + } + } + } + + // There is already a declaration with the same name in the same + // scope, which is not a tag declaration. It must be found + // before we find the new declaration, so insert the new + // declaration at the end of the chain. + IdResolver.AddShadowedDecl(TD, PrevDecl); + + return; + } + } + } else if (isa<FunctionDecl>(D) && + AllowOverloadingOfFunction(D, Context)) { + // We are pushing the name of a function, which might be an + // overloaded name. + FunctionDecl *FD = cast<FunctionDecl>(D); + IdentifierResolver::iterator Redecl + = std::find_if(IdResolver.begin(FD->getDeclName()), + IdResolver.end(), + std::bind1st(std::mem_fun(&NamedDecl::declarationReplaces), + FD)); + if (Redecl != IdResolver.end() && + S->isDeclScope(DeclPtrTy::make(*Redecl))) { + // There is already a declaration of a function on our + // IdResolver chain. Replace it with this declaration. + S->RemoveDecl(DeclPtrTy::make(*Redecl)); + IdResolver.RemoveDecl(*Redecl); + } + } else if (isa<ObjCInterfaceDecl>(D)) { + // We're pushing an Objective-C interface into the current + // context. If there is already an alias declaration, remove it first. + for (IdentifierResolver::iterator + I = IdResolver.begin(D->getDeclName()), IEnd = IdResolver.end(); + I != IEnd; ++I) { + if (isa<ObjCCompatibleAliasDecl>(*I)) { + S->RemoveDecl(DeclPtrTy::make(*I)); + IdResolver.RemoveDecl(*I); + break; + } + } + } + + IdResolver.AddDecl(D); +} + +void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { + if (S->decl_empty()) return; + assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) && + "Scope shouldn't contain decls!"); + + for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end(); + I != E; ++I) { + Decl *TmpD = (*I).getAs<Decl>(); + assert(TmpD && "This decl didn't get pushed??"); + + assert(isa<NamedDecl>(TmpD) && "Decl isn't NamedDecl?"); + NamedDecl *D = cast<NamedDecl>(TmpD); + + if (!D->getDeclName()) continue; + + // Remove this name from our lexical scope. + IdResolver.RemoveDecl(D); + } +} + +/// getObjCInterfaceDecl - Look up a for a class declaration in the scope. +/// return 0 if one not found. +ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) { + // The third "scope" argument is 0 since we aren't enabling lazy built-in + // creation from this context. + NamedDecl *IDecl = LookupName(TUScope, Id, LookupOrdinaryName); + + return dyn_cast_or_null<ObjCInterfaceDecl>(IDecl); +} + +/// getNonFieldDeclScope - Retrieves the innermost scope, starting +/// from S, where a non-field would be declared. This routine copes +/// with the difference between C and C++ scoping rules in structs and +/// unions. For example, the following code is well-formed in C but +/// ill-formed in C++: +/// @code +/// struct S6 { +/// enum { BAR } e; +/// }; +/// +/// void test_S6() { +/// struct S6 a; +/// a.e = BAR; +/// } +/// @endcode +/// For the declaration of BAR, this routine will return a different +/// scope. The scope S will be the scope of the unnamed enumeration +/// within S6. In C++, this routine will return the scope associated +/// with S6, because the enumeration's scope is a transparent +/// context but structures can contain non-field names. In C, this +/// routine will return the translation unit scope, since the +/// enumeration's scope is a transparent context and structures cannot +/// contain non-field names. +Scope *Sema::getNonFieldDeclScope(Scope *S) { + while (((S->getFlags() & Scope::DeclScope) == 0) || + (S->getEntity() && + ((DeclContext *)S->getEntity())->isTransparentContext()) || + (S->isClassScope() && !getLangOptions().CPlusPlus)) + S = S->getParent(); + return S; +} + +void Sema::InitBuiltinVaListType() { + if (!Context.getBuiltinVaListType().isNull()) + return; + + IdentifierInfo *VaIdent = &Context.Idents.get("__builtin_va_list"); + NamedDecl *VaDecl = LookupName(TUScope, VaIdent, LookupOrdinaryName); + TypedefDecl *VaTypedef = cast<TypedefDecl>(VaDecl); + Context.setBuiltinVaListType(Context.getTypedefType(VaTypedef)); +} + +/// LazilyCreateBuiltin - The specified Builtin-ID was first used at +/// file scope. lazily create a decl for it. ForRedeclaration is true +/// if we're creating this built-in in anticipation of redeclaring the +/// built-in. +NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, + Scope *S, bool ForRedeclaration, + SourceLocation Loc) { + Builtin::ID BID = (Builtin::ID)bid; + + if (Context.BuiltinInfo.hasVAListUse(BID)) + InitBuiltinVaListType(); + + Builtin::Context::GetBuiltinTypeError Error; + QualType R = Context.BuiltinInfo.GetBuiltinType(BID, Context, Error); + switch (Error) { + case Builtin::Context::GE_None: + // Okay + break; + + case Builtin::Context::GE_Missing_FILE: + if (ForRedeclaration) + Diag(Loc, diag::err_implicit_decl_requires_stdio) + << Context.BuiltinInfo.GetName(BID); + return 0; + } + + if (!ForRedeclaration && Context.BuiltinInfo.isPredefinedLibFunction(BID)) { + Diag(Loc, diag::ext_implicit_lib_function_decl) + << Context.BuiltinInfo.GetName(BID) + << R; + if (Context.BuiltinInfo.getHeaderName(BID) && + Diags.getDiagnosticLevel(diag::ext_implicit_lib_function_decl) + != Diagnostic::Ignored) + Diag(Loc, diag::note_please_include_header) + << Context.BuiltinInfo.getHeaderName(BID) + << Context.BuiltinInfo.GetName(BID); + } + + FunctionDecl *New = FunctionDecl::Create(Context, + Context.getTranslationUnitDecl(), + Loc, II, R, + FunctionDecl::Extern, false, + /*hasPrototype=*/true); + New->setImplicit(); + + // Create Decl objects for each parameter, adding them to the + // FunctionDecl. + if (FunctionProtoType *FT = dyn_cast<FunctionProtoType>(R)) { + llvm::SmallVector<ParmVarDecl*, 16> Params; + for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) + Params.push_back(ParmVarDecl::Create(Context, New, SourceLocation(), 0, + FT->getArgType(i), VarDecl::None, 0)); + New->setParams(Context, Params.data(), Params.size()); + } + + AddKnownFunctionAttributes(New); + + // TUScope is the translation-unit scope to insert this function into. + // FIXME: This is hideous. We need to teach PushOnScopeChains to + // relate Scopes to DeclContexts, and probably eliminate CurContext + // entirely, but we're not there yet. + DeclContext *SavedContext = CurContext; + CurContext = Context.getTranslationUnitDecl(); + PushOnScopeChains(New, TUScope); + CurContext = SavedContext; + return New; +} + +/// GetStdNamespace - This method gets the C++ "std" namespace. This is where +/// everything from the standard library is defined. +NamespaceDecl *Sema::GetStdNamespace() { + if (!StdNamespace) { + IdentifierInfo *StdIdent = &PP.getIdentifierTable().get("std"); + DeclContext *Global = Context.getTranslationUnitDecl(); + Decl *Std = LookupQualifiedName(Global, StdIdent, LookupNamespaceName); + StdNamespace = dyn_cast_or_null<NamespaceDecl>(Std); + } + return StdNamespace; +} + +/// MergeTypeDefDecl - We just parsed a typedef 'New' which has the +/// same name and scope as a previous declaration 'Old'. Figure out +/// how to resolve this situation, merging decls or emitting +/// diagnostics as appropriate. If there was an error, set New to be invalid. +/// +void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { + // If either decl is known invalid already, set the new one to be invalid and + // don't bother doing any merging checks. + if (New->isInvalidDecl() || OldD->isInvalidDecl()) + return New->setInvalidDecl(); + + bool objc_types = false; + + // Allow multiple definitions for ObjC built-in typedefs. + // FIXME: Verify the underlying types are equivalent! + if (getLangOptions().ObjC1) { + const IdentifierInfo *TypeID = New->getIdentifier(); + switch (TypeID->getLength()) { + default: break; + case 2: + if (!TypeID->isStr("id")) + break; + Context.setObjCIdType(Context.getTypeDeclType(New)); + objc_types = true; + break; + case 5: + if (!TypeID->isStr("Class")) + break; + Context.setObjCClassType(Context.getTypeDeclType(New)); + return; + case 3: + if (!TypeID->isStr("SEL")) + break; + Context.setObjCSelType(Context.getTypeDeclType(New)); + return; + case 8: + if (!TypeID->isStr("Protocol")) + break; + Context.setObjCProtoType(New->getUnderlyingType()); + return; + } + // Fall through - the typedef name was not a builtin type. + } + // Verify the old decl was also a type. + TypeDecl *Old = dyn_cast<TypeDecl>(OldD); + if (!Old) { + Diag(New->getLocation(), diag::err_redefinition_different_kind) + << New->getDeclName(); + if (OldD->getLocation().isValid()) + Diag(OldD->getLocation(), diag::note_previous_definition); + return New->setInvalidDecl(); + } + + // Determine the "old" type we'll use for checking and diagnostics. + QualType OldType; + if (TypedefDecl *OldTypedef = dyn_cast<TypedefDecl>(Old)) + OldType = OldTypedef->getUnderlyingType(); + else + OldType = Context.getTypeDeclType(Old); + + // If the typedef types are not identical, reject them in all languages and + // with any extensions enabled. + + if (OldType != New->getUnderlyingType() && + Context.getCanonicalType(OldType) != + Context.getCanonicalType(New->getUnderlyingType())) { + Diag(New->getLocation(), diag::err_redefinition_different_typedef) + << New->getUnderlyingType() << OldType; + if (Old->getLocation().isValid()) + Diag(Old->getLocation(), diag::note_previous_definition); + return New->setInvalidDecl(); + } + + if (objc_types || getLangOptions().Microsoft) + return; + + // C++ [dcl.typedef]p2: + // In a given non-class scope, a typedef specifier can be used to + // redefine the name of any type declared in that scope to refer + // to the type to which it already refers. + if (getLangOptions().CPlusPlus) { + if (!isa<CXXRecordDecl>(CurContext)) + return; + Diag(New->getLocation(), diag::err_redefinition) + << New->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + return New->setInvalidDecl(); + } + + // If we have a redefinition of a typedef in C, emit a warning. This warning + // is normally mapped to an error, but can be controlled with + // -Wtypedef-redefinition. If either the original was in a system header, + // don't emit this for compatibility with GCC. + if (PP.getDiagnostics().getSuppressSystemWarnings() && + Context.getSourceManager().isInSystemHeader(Old->getLocation())) + return; + + Diag(New->getLocation(), diag::warn_redefinition_of_typedef) + << New->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + return; +} + +/// DeclhasAttr - returns true if decl Declaration already has the target +/// attribute. +static bool DeclHasAttr(const Decl *decl, const Attr *target) { + for (const Attr *attr = decl->getAttrs(); attr; attr = attr->getNext()) + if (attr->getKind() == target->getKind()) + return true; + + return false; +} + +/// MergeAttributes - append attributes from the Old decl to the New one. +static void MergeAttributes(Decl *New, Decl *Old, ASTContext &C) { + for (const Attr *attr = Old->getAttrs(); attr; attr = attr->getNext()) { + if (!DeclHasAttr(New, attr) && attr->isMerged()) { + Attr *NewAttr = attr->clone(C); + NewAttr->setInherited(true); + New->addAttr(NewAttr); + } + } +} + +/// Used in MergeFunctionDecl to keep track of function parameters in +/// C. +struct GNUCompatibleParamWarning { + ParmVarDecl *OldParm; + ParmVarDecl *NewParm; + QualType PromotedType; +}; + +/// 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, +/// merging decls or emitting diagnostics as appropriate. +/// +/// In C++, New and Old must be declarations that are not +/// overloaded. Use IsOverload to determine whether New and Old are +/// overloaded, and to select the Old declaration that New should be +/// merged with. +/// +/// Returns true if there was an error, false otherwise. +bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { + assert(!isa<OverloadedFunctionDecl>(OldD) && + "Cannot merge with an overloaded function declaration"); + + // Verify the old decl was also a function. + FunctionDecl *Old = dyn_cast<FunctionDecl>(OldD); + if (!Old) { + Diag(New->getLocation(), diag::err_redefinition_different_kind) + << New->getDeclName(); + Diag(OldD->getLocation(), diag::note_previous_definition); + return true; + } + + // Determine whether the previous declaration was a definition, + // implicit declaration, or a declaration. + diag::kind PrevDiag; + if (Old->isThisDeclarationADefinition()) + PrevDiag = diag::note_previous_definition; + else if (Old->isImplicit()) + PrevDiag = diag::note_previous_implicit_declaration; + else + PrevDiag = diag::note_previous_declaration; + + QualType OldQType = Context.getCanonicalType(Old->getType()); + QualType NewQType = Context.getCanonicalType(New->getType()); + + if (!isa<CXXMethodDecl>(New) && !isa<CXXMethodDecl>(Old) && + New->getStorageClass() == FunctionDecl::Static && + Old->getStorageClass() != FunctionDecl::Static) { + Diag(New->getLocation(), diag::err_static_non_static) + << New; + Diag(Old->getLocation(), PrevDiag); + return true; + } + + if (getLangOptions().CPlusPlus) { + // (C++98 13.1p2): + // Certain function declarations cannot be overloaded: + // -- Function declarations that differ only in the return type + // cannot be overloaded. + QualType OldReturnType + = cast<FunctionType>(OldQType.getTypePtr())->getResultType(); + QualType NewReturnType + = cast<FunctionType>(NewQType.getTypePtr())->getResultType(); + if (OldReturnType != NewReturnType) { + Diag(New->getLocation(), diag::err_ovl_diff_return_type); + Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); + return true; + } + + const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old); + const CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New); + if (OldMethod && NewMethod && + OldMethod->getLexicalDeclContext() == + NewMethod->getLexicalDeclContext()) { + // -- Member function declarations with the same name and the + // same parameter types cannot be overloaded if any of them + // is a static member function declaration. + if (OldMethod->isStatic() || NewMethod->isStatic()) { + Diag(New->getLocation(), diag::err_ovl_static_nonstatic_member); + Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); + return true; + } + + // C++ [class.mem]p1: + // [...] A member shall not be declared twice in the + // member-specification, except that a nested class or member + // class template can be declared and then later defined. + unsigned NewDiag; + if (isa<CXXConstructorDecl>(OldMethod)) + NewDiag = diag::err_constructor_redeclared; + else if (isa<CXXDestructorDecl>(NewMethod)) + NewDiag = diag::err_destructor_redeclared; + else if (isa<CXXConversionDecl>(NewMethod)) + NewDiag = diag::err_conv_function_redeclared; + else + NewDiag = diag::err_member_redeclared; + + Diag(New->getLocation(), NewDiag); + Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); + } + + // (C++98 8.3.5p3): + // All declarations for a function shall agree exactly in both the + // return type and the parameter-type-list. + if (OldQType == NewQType) + return MergeCompatibleFunctionDecls(New, Old); + + // Fall through for conflicting redeclarations and redefinitions. + } + + // C: Function types need to be compatible, not identical. This handles + // duplicate function decls like "void f(int); void f(enum X);" properly. + if (!getLangOptions().CPlusPlus && + Context.typesAreCompatible(OldQType, NewQType)) { + const FunctionType *OldFuncType = OldQType->getAsFunctionType(); + const FunctionType *NewFuncType = NewQType->getAsFunctionType(); + const FunctionProtoType *OldProto = 0; + if (isa<FunctionNoProtoType>(NewFuncType) && + (OldProto = dyn_cast<FunctionProtoType>(OldFuncType))) { + // The old declaration provided a function prototype, but the + // new declaration does not. Merge in the prototype. + assert(!OldProto->hasExceptionSpec() && "Exception spec in C"); + llvm::SmallVector<QualType, 16> ParamTypes(OldProto->arg_type_begin(), + OldProto->arg_type_end()); + NewQType = Context.getFunctionType(NewFuncType->getResultType(), + ParamTypes.data(), ParamTypes.size(), + OldProto->isVariadic(), + OldProto->getTypeQuals()); + New->setType(NewQType); + New->setHasInheritedPrototype(); + + // Synthesize a parameter for each argument type. + llvm::SmallVector<ParmVarDecl*, 16> Params; + for (FunctionProtoType::arg_type_iterator + ParamType = OldProto->arg_type_begin(), + ParamEnd = OldProto->arg_type_end(); + ParamType != ParamEnd; ++ParamType) { + ParmVarDecl *Param = ParmVarDecl::Create(Context, New, + SourceLocation(), 0, + *ParamType, VarDecl::None, + 0); + Param->setImplicit(); + Params.push_back(Param); + } + + New->setParams(Context, Params.data(), Params.size()); + } + + return MergeCompatibleFunctionDecls(New, Old); + } + + // GNU C permits a K&R definition to follow a prototype declaration + // if the declared types of the parameters in the K&R definition + // match the types in the prototype declaration, even when the + // promoted types of the parameters from the K&R definition differ + // from the types in the prototype. GCC then keeps the types from + // the prototype. + // + // If a variadic prototype is followed by a non-variadic K&R definition, + // the K&R definition becomes variadic. This is sort of an edge case, but + // it's legal per the standard depending on how you read C99 6.7.5.3p15 and + // C99 6.9.1p8. + if (!getLangOptions().CPlusPlus && + Old->hasPrototype() && !New->hasPrototype() && + New->getType()->getAsFunctionProtoType() && + Old->getNumParams() == New->getNumParams()) { + llvm::SmallVector<QualType, 16> ArgTypes; + llvm::SmallVector<GNUCompatibleParamWarning, 16> Warnings; + const FunctionProtoType *OldProto + = Old->getType()->getAsFunctionProtoType(); + const FunctionProtoType *NewProto + = New->getType()->getAsFunctionProtoType(); + + // Determine whether this is the GNU C extension. + QualType MergedReturn = Context.mergeTypes(OldProto->getResultType(), + NewProto->getResultType()); + bool LooseCompatible = !MergedReturn.isNull(); + for (unsigned Idx = 0, End = Old->getNumParams(); + LooseCompatible && Idx != End; ++Idx) { + ParmVarDecl *OldParm = Old->getParamDecl(Idx); + ParmVarDecl *NewParm = New->getParamDecl(Idx); + if (Context.typesAreCompatible(OldParm->getType(), + NewProto->getArgType(Idx))) { + ArgTypes.push_back(NewParm->getType()); + } else if (Context.typesAreCompatible(OldParm->getType(), + NewParm->getType())) { + GNUCompatibleParamWarning Warn + = { OldParm, NewParm, NewProto->getArgType(Idx) }; + Warnings.push_back(Warn); + ArgTypes.push_back(NewParm->getType()); + } else + LooseCompatible = false; + } + + if (LooseCompatible) { + for (unsigned Warn = 0; Warn < Warnings.size(); ++Warn) { + Diag(Warnings[Warn].NewParm->getLocation(), + diag::ext_param_promoted_not_compatible_with_prototype) + << Warnings[Warn].PromotedType + << Warnings[Warn].OldParm->getType(); + Diag(Warnings[Warn].OldParm->getLocation(), + diag::note_previous_declaration); + } + + New->setType(Context.getFunctionType(MergedReturn, &ArgTypes[0], + ArgTypes.size(), + OldProto->isVariadic(), 0)); + return MergeCompatibleFunctionDecls(New, Old); + } + + // Fall through to diagnose conflicting types. + } + + // A function that has already been declared has been redeclared or defined + // with a different type- show appropriate diagnostic + if (unsigned BuiltinID = Old->getBuiltinID(Context)) { + // The user has declared a builtin function with an incompatible + // signature. + if (Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) { + // The function the user is redeclaring is a library-defined + // function like 'malloc' or 'printf'. Warn about the + // redeclaration, then pretend that we don't know about this + // library built-in. + Diag(New->getLocation(), diag::warn_redecl_library_builtin) << New; + Diag(Old->getLocation(), diag::note_previous_builtin_declaration) + << Old << Old->getType(); + New->getIdentifier()->setBuiltinID(Builtin::NotBuiltin); + Old->setInvalidDecl(); + return false; + } + + PrevDiag = diag::note_previous_builtin_declaration; + } + + Diag(New->getLocation(), diag::err_conflicting_types) << New->getDeclName(); + Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); + return true; +} + +/// \brief Completes the merge of two function declarations that are +/// known to be compatible. +/// +/// This routine handles the merging of attributes and other +/// properties of function declarations form the old declaration to +/// the new declaration, once we know that New is in fact a +/// redeclaration of Old. +/// +/// \returns false +bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) { + // Merge the attributes + MergeAttributes(New, Old, Context); + + // Merge the storage class. + if (Old->getStorageClass() != FunctionDecl::Extern) + New->setStorageClass(Old->getStorageClass()); + + // Merge "inline" + if (Old->isInline()) + New->setInline(true); + + // If this function declaration by itself qualifies as a C99 inline + // definition (C99 6.7.4p6), but the previous definition did not, + // then the function is not a C99 inline definition. + if (New->isC99InlineDefinition() && !Old->isC99InlineDefinition()) + New->setC99InlineDefinition(false); + else if (Old->isC99InlineDefinition() && !New->isC99InlineDefinition()) { + // Mark all preceding definitions as not being C99 inline definitions. + for (const FunctionDecl *Prev = Old; Prev; + Prev = Prev->getPreviousDeclaration()) + const_cast<FunctionDecl *>(Prev)->setC99InlineDefinition(false); + } + + // Merge "pure" flag. + if (Old->isPure()) + New->setPure(); + + // Merge the "deleted" flag. + if (Old->isDeleted()) + New->setDeleted(); + + if (getLangOptions().CPlusPlus) + return MergeCXXFunctionDecl(New, Old); + + return false; +} + +/// MergeVarDecl - We just parsed a variable 'New' which has the same name +/// and scope as a previous declaration 'Old'. Figure out how to resolve this +/// situation, merging decls or emitting diagnostics as appropriate. +/// +/// Tentative definition rules (C99 6.9.2p2) are checked by +/// FinalizeDeclaratorGroup. Unfortunately, we can't analyze tentative +/// definitions here, since the initializer hasn't been attached. +/// +void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) { + // If either decl is invalid, make sure the new one is marked invalid and + // don't do any other checking. + if (New->isInvalidDecl() || OldD->isInvalidDecl()) + return New->setInvalidDecl(); + + // Verify the old decl was also a variable. + VarDecl *Old = dyn_cast<VarDecl>(OldD); + if (!Old) { + Diag(New->getLocation(), diag::err_redefinition_different_kind) + << New->getDeclName(); + Diag(OldD->getLocation(), diag::note_previous_definition); + return New->setInvalidDecl(); + } + + MergeAttributes(New, Old, Context); + + // Merge the types + QualType MergedT; + if (getLangOptions().CPlusPlus) { + if (Context.hasSameType(New->getType(), Old->getType())) + MergedT = New->getType(); + } else { + MergedT = Context.mergeTypes(New->getType(), Old->getType()); + } + if (MergedT.isNull()) { + Diag(New->getLocation(), diag::err_redefinition_different_type) + << New->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + return New->setInvalidDecl(); + } + New->setType(MergedT); + + // C99 6.2.2p4: Check if we have a static decl followed by a non-static. + if (New->getStorageClass() == VarDecl::Static && + (Old->getStorageClass() == VarDecl::None || Old->hasExternalStorage())) { + Diag(New->getLocation(), diag::err_static_non_static) << New->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + return New->setInvalidDecl(); + } + // C99 6.2.2p4: + // For an identifier declared with the storage-class specifier + // extern in a scope in which a prior declaration of that + // identifier is visible,23) if the prior declaration specifies + // internal or external linkage, the linkage of the identifier at + // the later declaration is the same as the linkage specified at + // the prior declaration. If no prior declaration is visible, or + // if the prior declaration specifies no linkage, then the + // identifier has external linkage. + if (New->hasExternalStorage() && Old->hasLinkage()) + /* Okay */; + else if (New->getStorageClass() != VarDecl::Static && + Old->getStorageClass() == VarDecl::Static) { + Diag(New->getLocation(), diag::err_non_static_static) << New->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + return New->setInvalidDecl(); + } + + // Variables with external linkage are analyzed in FinalizeDeclaratorGroup. + + // FIXME: The test for external storage here seems wrong? We still + // need to check for mismatches. + if (!New->hasExternalStorage() && !New->isFileVarDecl() && + // Don't complain about out-of-line definitions of static members. + !(Old->getLexicalDeclContext()->isRecord() && + !New->getLexicalDeclContext()->isRecord())) { + Diag(New->getLocation(), diag::err_redefinition) << New->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + return New->setInvalidDecl(); + } + + if (New->isThreadSpecified() && !Old->isThreadSpecified()) { + Diag(New->getLocation(), diag::err_thread_non_thread) << New->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + } else if (!New->isThreadSpecified() && Old->isThreadSpecified()) { + Diag(New->getLocation(), diag::err_non_thread_thread) << New->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + } + + // Keep a chain of previous declarations. + New->setPreviousDeclaration(Old); +} + +/// CheckParmsForFunctionDef - Check that the parameters of the given +/// function are appropriate for the definition of a function. This +/// takes care of any checks that cannot be performed on the +/// declaration itself, e.g., that the types of each of the function +/// parameters are complete. +bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) { + bool HasInvalidParm = false; + for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) { + ParmVarDecl *Param = FD->getParamDecl(p); + + // C99 6.7.5.3p4: the parameters in a parameter type list in a + // function declarator that is part of a function definition of + // that function shall not have incomplete type. + // + // This is also C++ [dcl.fct]p6. + if (!Param->isInvalidDecl() && + RequireCompleteType(Param->getLocation(), Param->getType(), + diag::err_typecheck_decl_incomplete_type)) { + Param->setInvalidDecl(); + HasInvalidParm = true; + } + + // C99 6.9.1p5: If the declarator includes a parameter type list, the + // declaration of each parameter shall include an identifier. + if (Param->getIdentifier() == 0 && + !Param->isImplicit() && + !getLangOptions().CPlusPlus) + Diag(Param->getLocation(), diag::err_parameter_name_omitted); + } + + return HasInvalidParm; +} + +/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with +/// no declarator (e.g. "struct foo;") is parsed. +Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { + // FIXME: Error on auto/register at file scope + // FIXME: Error on inline/virtual/explicit + // FIXME: Error on invalid restrict + // FIXME: Warn on useless __thread + // FIXME: Warn on useless const/volatile + // FIXME: Warn on useless static/extern/typedef/private_extern/mutable + // FIXME: Warn on useless attributes + TagDecl *Tag = 0; + if (DS.getTypeSpecType() == DeclSpec::TST_class || + DS.getTypeSpecType() == DeclSpec::TST_struct || + DS.getTypeSpecType() == DeclSpec::TST_union || + DS.getTypeSpecType() == DeclSpec::TST_enum) { + if (!DS.getTypeRep()) // We probably had an error + return DeclPtrTy(); + + Tag = dyn_cast<TagDecl>(static_cast<Decl *>(DS.getTypeRep())); + } + + if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) { + if (!Record->getDeclName() && Record->isDefinition() && + DS.getStorageClassSpec() != DeclSpec::SCS_typedef) { + if (getLangOptions().CPlusPlus || + Record->getDeclContext()->isRecord()) + return BuildAnonymousStructOrUnion(S, DS, Record); + + Diag(DS.getSourceRange().getBegin(), diag::err_no_declarators) + << DS.getSourceRange(); + } + + // Microsoft allows unnamed struct/union fields. Don't complain + // about them. + // FIXME: Should we support Microsoft's extensions in this area? + if (Record->getDeclName() && getLangOptions().Microsoft) + return DeclPtrTy::make(Tag); + } + + if (!DS.isMissingDeclaratorOk() && + DS.getTypeSpecType() != DeclSpec::TST_error) { + // Warn about typedefs of enums without names, since this is an + // extension in both Microsoft an GNU. + if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef && + Tag && isa<EnumDecl>(Tag)) { + Diag(DS.getSourceRange().getBegin(), diag::ext_typedef_without_a_name) + << DS.getSourceRange(); + return DeclPtrTy::make(Tag); + } + + Diag(DS.getSourceRange().getBegin(), diag::err_no_declarators) + << DS.getSourceRange(); + return DeclPtrTy(); + } + + return DeclPtrTy::make(Tag); +} + +/// InjectAnonymousStructOrUnionMembers - Inject the members of the +/// anonymous struct or union AnonRecord into the owning context Owner +/// and scope S. This routine will be invoked just after we realize +/// that an unnamed union or struct is actually an anonymous union or +/// struct, e.g., +/// +/// @code +/// union { +/// int i; +/// float f; +/// }; // InjectAnonymousStructOrUnionMembers called here to inject i and +/// // f into the surrounding scope.x +/// @endcode +/// +/// This routine is recursive, injecting the names of nested anonymous +/// structs/unions into the owning context and scope as well. +bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, + RecordDecl *AnonRecord) { + bool Invalid = false; + for (RecordDecl::field_iterator F = AnonRecord->field_begin(Context), + FEnd = AnonRecord->field_end(Context); + F != FEnd; ++F) { + if ((*F)->getDeclName()) { + NamedDecl *PrevDecl = LookupQualifiedName(Owner, (*F)->getDeclName(), + LookupOrdinaryName, true); + if (PrevDecl && !isa<TagDecl>(PrevDecl)) { + // C++ [class.union]p2: + // The names of the members of an anonymous union shall be + // distinct from the names of any other entity in the + // scope in which the anonymous union is declared. + unsigned diagKind + = AnonRecord->isUnion()? diag::err_anonymous_union_member_redecl + : diag::err_anonymous_struct_member_redecl; + Diag((*F)->getLocation(), diagKind) + << (*F)->getDeclName(); + Diag(PrevDecl->getLocation(), diag::note_previous_declaration); + Invalid = true; + } else { + // C++ [class.union]p2: + // For the purpose of name lookup, after the anonymous union + // definition, the members of the anonymous union are + // considered to have been defined in the scope in which the + // anonymous union is declared. + Owner->makeDeclVisibleInContext(Context, *F); + S->AddDecl(DeclPtrTy::make(*F)); + IdResolver.AddDecl(*F); + } + } else if (const RecordType *InnerRecordType + = (*F)->getType()->getAsRecordType()) { + RecordDecl *InnerRecord = InnerRecordType->getDecl(); + if (InnerRecord->isAnonymousStructOrUnion()) + Invalid = Invalid || + InjectAnonymousStructOrUnionMembers(S, Owner, InnerRecord); + } + } + + return Invalid; +} + +/// ActOnAnonymousStructOrUnion - Handle the declaration of an +/// anonymous structure or union. Anonymous unions are a C++ feature +/// (C++ [class.union]) and a GNU C extension; anonymous structures +/// are a GNU C and GNU C++ extension. +Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, + RecordDecl *Record) { + DeclContext *Owner = Record->getDeclContext(); + + // Diagnose whether this anonymous struct/union is an extension. + if (Record->isUnion() && !getLangOptions().CPlusPlus) + Diag(Record->getLocation(), diag::ext_anonymous_union); + else if (!Record->isUnion()) + Diag(Record->getLocation(), diag::ext_anonymous_struct); + + // C and C++ require different kinds of checks for anonymous + // structs/unions. + bool Invalid = false; + if (getLangOptions().CPlusPlus) { + const char* PrevSpec = 0; + // C++ [class.union]p3: + // Anonymous unions declared in a named namespace or in the + // global namespace shall be declared static. + if (DS.getStorageClassSpec() != DeclSpec::SCS_static && + (isa<TranslationUnitDecl>(Owner) || + (isa<NamespaceDecl>(Owner) && + cast<NamespaceDecl>(Owner)->getDeclName()))) { + Diag(Record->getLocation(), diag::err_anonymous_union_not_static); + Invalid = true; + + // Recover by adding 'static'. + DS.SetStorageClassSpec(DeclSpec::SCS_static, SourceLocation(), PrevSpec); + } + // C++ [class.union]p3: + // A storage class is not allowed in a declaration of an + // anonymous union in a class scope. + else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified && + isa<RecordDecl>(Owner)) { + Diag(DS.getStorageClassSpecLoc(), + diag::err_anonymous_union_with_storage_spec); + Invalid = true; + + // Recover by removing the storage specifier. + DS.SetStorageClassSpec(DeclSpec::SCS_unspecified, SourceLocation(), + PrevSpec); + } + + // C++ [class.union]p2: + // The member-specification of an anonymous union shall only + // define non-static data members. [Note: nested types and + // functions cannot be declared within an anonymous union. ] + for (DeclContext::decl_iterator Mem = Record->decls_begin(Context), + MemEnd = Record->decls_end(Context); + Mem != MemEnd; ++Mem) { + if (FieldDecl *FD = dyn_cast<FieldDecl>(*Mem)) { + // C++ [class.union]p3: + // An anonymous union shall not have private or protected + // members (clause 11). + if (FD->getAccess() == AS_protected || FD->getAccess() == AS_private) { + Diag(FD->getLocation(), diag::err_anonymous_record_nonpublic_member) + << (int)Record->isUnion() << (int)(FD->getAccess() == AS_protected); + Invalid = true; + } + } else if ((*Mem)->isImplicit()) { + // Any implicit members are fine. + } else if (isa<TagDecl>(*Mem) && (*Mem)->getDeclContext() != Record) { + // This is a type that showed up in an + // elaborated-type-specifier inside the anonymous struct or + // union, but which actually declares a type outside of the + // anonymous struct or union. It's okay. + } else if (RecordDecl *MemRecord = dyn_cast<RecordDecl>(*Mem)) { + if (!MemRecord->isAnonymousStructOrUnion() && + MemRecord->getDeclName()) { + // This is a nested type declaration. + Diag(MemRecord->getLocation(), diag::err_anonymous_record_with_type) + << (int)Record->isUnion(); + Invalid = true; + } + } else { + // We have something that isn't a non-static data + // member. Complain about it. + unsigned DK = diag::err_anonymous_record_bad_member; + if (isa<TypeDecl>(*Mem)) + DK = diag::err_anonymous_record_with_type; + else if (isa<FunctionDecl>(*Mem)) + DK = diag::err_anonymous_record_with_function; + else if (isa<VarDecl>(*Mem)) + DK = diag::err_anonymous_record_with_static; + Diag((*Mem)->getLocation(), DK) + << (int)Record->isUnion(); + Invalid = true; + } + } + } + + if (!Record->isUnion() && !Owner->isRecord()) { + Diag(Record->getLocation(), diag::err_anonymous_struct_not_member) + << (int)getLangOptions().CPlusPlus; + Invalid = true; + } + + // Create a declaration for this anonymous struct/union. + NamedDecl *Anon = 0; + if (RecordDecl *OwningClass = dyn_cast<RecordDecl>(Owner)) { + Anon = FieldDecl::Create(Context, OwningClass, Record->getLocation(), + /*IdentifierInfo=*/0, + Context.getTypeDeclType(Record), + /*BitWidth=*/0, /*Mutable=*/false); + Anon->setAccess(AS_public); + if (getLangOptions().CPlusPlus) + FieldCollector->Add(cast<FieldDecl>(Anon)); + } else { + VarDecl::StorageClass SC; + switch (DS.getStorageClassSpec()) { + default: assert(0 && "Unknown storage class!"); + case DeclSpec::SCS_unspecified: SC = VarDecl::None; break; + case DeclSpec::SCS_extern: SC = VarDecl::Extern; break; + case DeclSpec::SCS_static: SC = VarDecl::Static; break; + case DeclSpec::SCS_auto: SC = VarDecl::Auto; break; + case DeclSpec::SCS_register: SC = VarDecl::Register; break; + case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break; + case DeclSpec::SCS_mutable: + // mutable can only appear on non-static class members, so it's always + // an error here + Diag(Record->getLocation(), diag::err_mutable_nonmember); + Invalid = true; + SC = VarDecl::None; + break; + } + + Anon = VarDecl::Create(Context, Owner, Record->getLocation(), + /*IdentifierInfo=*/0, + Context.getTypeDeclType(Record), + SC, DS.getSourceRange().getBegin()); + } + Anon->setImplicit(); + + // Add the anonymous struct/union object to the current + // context. We'll be referencing this object when we refer to one of + // its members. + Owner->addDecl(Context, Anon); + + // Inject the members of the anonymous struct/union into the owning + // context and into the identifier resolver chain for name lookup + // purposes. + if (InjectAnonymousStructOrUnionMembers(S, Owner, Record)) + Invalid = true; + + // Mark this as an anonymous struct/union type. Note that we do not + // do this until after we have already checked and injected the + // members of this anonymous struct/union type, because otherwise + // the members could be injected twice: once by DeclContext when it + // builds its lookup table, and once by + // InjectAnonymousStructOrUnionMembers. + Record->setAnonymousStructOrUnion(true); + + if (Invalid) + Anon->setInvalidDecl(); + + return DeclPtrTy::make(Anon); +} + + +/// GetNameForDeclarator - Determine the full declaration name for the +/// given Declarator. +DeclarationName Sema::GetNameForDeclarator(Declarator &D) { + switch (D.getKind()) { + case Declarator::DK_Abstract: + assert(D.getIdentifier() == 0 && "abstract declarators have no name"); + return DeclarationName(); + + case Declarator::DK_Normal: + assert (D.getIdentifier() != 0 && "normal declarators have an identifier"); + return DeclarationName(D.getIdentifier()); + + case Declarator::DK_Constructor: { + QualType Ty = QualType::getFromOpaquePtr(D.getDeclaratorIdType()); + Ty = Context.getCanonicalType(Ty); + return Context.DeclarationNames.getCXXConstructorName(Ty); + } + + case Declarator::DK_Destructor: { + QualType Ty = QualType::getFromOpaquePtr(D.getDeclaratorIdType()); + Ty = Context.getCanonicalType(Ty); + return Context.DeclarationNames.getCXXDestructorName(Ty); + } + + case Declarator::DK_Conversion: { + // FIXME: We'd like to keep the non-canonical type for diagnostics! + QualType Ty = QualType::getFromOpaquePtr(D.getDeclaratorIdType()); + Ty = Context.getCanonicalType(Ty); + return Context.DeclarationNames.getCXXConversionFunctionName(Ty); + } + + case Declarator::DK_Operator: + assert(D.getIdentifier() == 0 && "operator names have no identifier"); + return Context.DeclarationNames.getCXXOperatorName( + D.getOverloadedOperator()); + } + + assert(false && "Unknown name kind"); + return DeclarationName(); +} + +/// isNearlyMatchingFunction - Determine whether the C++ functions +/// Declaration and Definition are "nearly" matching. This heuristic +/// is used to improve diagnostics in the case where an out-of-line +/// function definition doesn't match any declaration within +/// the class or namespace. +static bool isNearlyMatchingFunction(ASTContext &Context, + FunctionDecl *Declaration, + FunctionDecl *Definition) { + if (Declaration->param_size() != Definition->param_size()) + return false; + for (unsigned Idx = 0; Idx < Declaration->param_size(); ++Idx) { + QualType DeclParamTy = Declaration->getParamDecl(Idx)->getType(); + QualType DefParamTy = Definition->getParamDecl(Idx)->getType(); + + DeclParamTy = Context.getCanonicalType(DeclParamTy.getNonReferenceType()); + DefParamTy = Context.getCanonicalType(DefParamTy.getNonReferenceType()); + if (DeclParamTy.getUnqualifiedType() != DefParamTy.getUnqualifiedType()) + return false; + } + + return true; +} + +Sema::DeclPtrTy +Sema::ActOnDeclarator(Scope *S, Declarator &D, bool IsFunctionDefinition) { + DeclarationName Name = GetNameForDeclarator(D); + + // All of these full declarators require an identifier. If it doesn't have + // one, the ParsedFreeStandingDeclSpec action should be used. + if (!Name) { + if (!D.isInvalidType()) // Reject this if we think it is valid. + Diag(D.getDeclSpec().getSourceRange().getBegin(), + diag::err_declarator_need_ident) + << D.getDeclSpec().getSourceRange() << D.getSourceRange(); + return DeclPtrTy(); + } + + // The scope passed in may not be a decl scope. Zip up the scope tree until + // we find one that is. + while ((S->getFlags() & Scope::DeclScope) == 0 || + (S->getFlags() & Scope::TemplateParamScope) != 0) + S = S->getParent(); + + DeclContext *DC; + NamedDecl *PrevDecl; + NamedDecl *New; + + QualType R = GetTypeForDeclarator(D, S); + + // See if this is a redefinition of a variable in the same scope. + if (D.getCXXScopeSpec().isInvalid()) { + DC = CurContext; + PrevDecl = 0; + D.setInvalidType(); + } else if (!D.getCXXScopeSpec().isSet()) { + LookupNameKind NameKind = LookupOrdinaryName; + + // If the declaration we're planning to build will be a function + // or object with linkage, then look for another declaration with + // linkage (C99 6.2.2p4-5 and C++ [basic.link]p6). + if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) + /* Do nothing*/; + else if (R->isFunctionType()) { + if (CurContext->isFunctionOrMethod()) + NameKind = LookupRedeclarationWithLinkage; + } else if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern) + NameKind = LookupRedeclarationWithLinkage; + + DC = CurContext; + PrevDecl = LookupName(S, Name, NameKind, true, + D.getDeclSpec().getStorageClassSpec() != + DeclSpec::SCS_static, + D.getIdentifierLoc()); + } else { // Something like "int foo::x;" + DC = computeDeclContext(D.getCXXScopeSpec()); + // FIXME: RequireCompleteDeclContext(D.getCXXScopeSpec()); ? + PrevDecl = LookupQualifiedName(DC, Name, LookupOrdinaryName, true); + + // C++ 7.3.1.2p2: + // Members (including explicit specializations of templates) of a named + // namespace can also be defined outside that namespace by explicit + // qualification of the name being defined, provided that the entity being + // defined was already declared in the namespace and the definition appears + // after the point of declaration in a namespace that encloses the + // declarations namespace. + // + // Note that we only check the context at this point. We don't yet + // have enough information to make sure that PrevDecl is actually + // the declaration we want to match. For example, given: + // + // class X { + // void f(); + // void f(float); + // }; + // + // void X::f(int) { } // ill-formed + // + // In this case, PrevDecl will point to the overload set + // containing the two f's declared in X, but neither of them + // matches. + + // First check whether we named the global scope. + if (isa<TranslationUnitDecl>(DC)) { + Diag(D.getIdentifierLoc(), diag::err_invalid_declarator_global_scope) + << Name << D.getCXXScopeSpec().getRange(); + } else if (!CurContext->Encloses(DC)) { + // The qualifying scope doesn't enclose the original declaration. + // Emit diagnostic based on current scope. + SourceLocation L = D.getIdentifierLoc(); + SourceRange R = D.getCXXScopeSpec().getRange(); + if (isa<FunctionDecl>(CurContext)) + Diag(L, diag::err_invalid_declarator_in_function) << Name << R; + else + Diag(L, diag::err_invalid_declarator_scope) + << Name << cast<NamedDecl>(DC) << R; + D.setInvalidType(); + } + } + + if (PrevDecl && PrevDecl->isTemplateParameter()) { + // Maybe we will complain about the shadowed template parameter. + if (!D.isInvalidType()) + if (DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl)) + D.setInvalidType(); + + // Just pretend that we didn't see the previous declaration. + PrevDecl = 0; + } + + // In C++, the previous declaration we find might be a tag type + // (class or enum). In this case, the new declaration will hide the + // tag type. Note that this does does not apply if we're declaring a + // typedef (C++ [dcl.typedef]p4). + if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag && + D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef) + PrevDecl = 0; + + bool Redeclaration = false; + if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) { + New = ActOnTypedefDeclarator(S, D, DC, R, PrevDecl, Redeclaration); + } else if (R->isFunctionType()) { + New = ActOnFunctionDeclarator(S, D, DC, R, PrevDecl, + IsFunctionDefinition, Redeclaration); + } else { + New = ActOnVariableDeclarator(S, D, DC, R, PrevDecl, Redeclaration); + } + + if (New == 0) + return DeclPtrTy(); + + // If this has an identifier and is not an invalid redeclaration, + // add it to the scope stack. + if (Name && !(Redeclaration && New->isInvalidDecl())) + PushOnScopeChains(New, S); + + return DeclPtrTy::make(New); +} + +/// TryToFixInvalidVariablyModifiedType - Helper method to turn variable array +/// types into constant array types in certain situations which would otherwise +/// be errors (for GCC compatibility). +static QualType TryToFixInvalidVariablyModifiedType(QualType T, + ASTContext &Context, + bool &SizeIsNegative) { + // This method tries to turn a variable array into a constant + // array even when the size isn't an ICE. This is necessary + // for compatibility with code that depends on gcc's buggy + // constant expression folding, like struct {char x[(int)(char*)2];} + SizeIsNegative = false; + + if (const PointerType* PTy = dyn_cast<PointerType>(T)) { + QualType Pointee = PTy->getPointeeType(); + QualType FixedType = + TryToFixInvalidVariablyModifiedType(Pointee, Context, SizeIsNegative); + if (FixedType.isNull()) return FixedType; + FixedType = Context.getPointerType(FixedType); + FixedType.setCVRQualifiers(T.getCVRQualifiers()); + return FixedType; + } + + const VariableArrayType* VLATy = dyn_cast<VariableArrayType>(T); + if (!VLATy) + return QualType(); + // FIXME: We should probably handle this case + if (VLATy->getElementType()->isVariablyModifiedType()) + return QualType(); + + Expr::EvalResult EvalResult; + if (!VLATy->getSizeExpr() || + !VLATy->getSizeExpr()->Evaluate(EvalResult, Context) || + !EvalResult.Val.isInt()) + return QualType(); + + llvm::APSInt &Res = EvalResult.Val.getInt(); + if (Res >= llvm::APSInt(Res.getBitWidth(), Res.isUnsigned())) + return Context.getConstantArrayType(VLATy->getElementType(), + Res, ArrayType::Normal, 0); + + SizeIsNegative = true; + return QualType(); +} + +/// \brief Register the given locally-scoped external C declaration so +/// that it can be found later for redeclarations +void +Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, NamedDecl *PrevDecl, + Scope *S) { + assert(ND->getLexicalDeclContext()->isFunctionOrMethod() && + "Decl is not a locally-scoped decl!"); + // Note that we have a locally-scoped external with this name. + LocallyScopedExternalDecls[ND->getDeclName()] = ND; + + if (!PrevDecl) + return; + + // If there was a previous declaration of this variable, it may be + // in our identifier chain. Update the identifier chain with the new + // declaration. + if (S && IdResolver.ReplaceDecl(PrevDecl, ND)) { + // The previous declaration was found on the identifer resolver + // chain, so remove it from its scope. + while (S && !S->isDeclScope(DeclPtrTy::make(PrevDecl))) + S = S->getParent(); + + if (S) + S->RemoveDecl(DeclPtrTy::make(PrevDecl)); + } +} + +/// \brief Diagnose function specifiers on a declaration of an identifier that +/// does not identify a function. +void Sema::DiagnoseFunctionSpecifiers(Declarator& D) { + // FIXME: We should probably indicate the identifier in question to avoid + // confusion for constructs like "inline int a(), b;" + if (D.getDeclSpec().isInlineSpecified()) + Diag(D.getDeclSpec().getInlineSpecLoc(), + diag::err_inline_non_function); + + if (D.getDeclSpec().isVirtualSpecified()) + Diag(D.getDeclSpec().getVirtualSpecLoc(), + diag::err_virtual_non_function); + + if (D.getDeclSpec().isExplicitSpecified()) + Diag(D.getDeclSpec().getExplicitSpecLoc(), + diag::err_explicit_non_function); +} + +NamedDecl* +Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, + QualType R, Decl* PrevDecl, bool &Redeclaration) { + // Typedef declarators cannot be qualified (C++ [dcl.meaning]p1). + if (D.getCXXScopeSpec().isSet()) { + Diag(D.getIdentifierLoc(), diag::err_qualified_typedef_declarator) + << D.getCXXScopeSpec().getRange(); + D.setInvalidType(); + // Pretend we didn't see the scope specifier. + DC = 0; + } + + if (getLangOptions().CPlusPlus) { + // Check that there are no default arguments (C++ only). + CheckExtraCXXDefaultArguments(D); + } + + DiagnoseFunctionSpecifiers(D); + + if (D.getDeclSpec().isThreadSpecified()) + Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + + TypedefDecl *NewTD = ParseTypedefDecl(S, D, R); + if (!NewTD) return 0; + + if (D.isInvalidType()) + NewTD->setInvalidDecl(); + + // Handle attributes prior to checking for duplicates in MergeVarDecl + ProcessDeclAttributes(NewTD, D); + // Merge the decl with the existing one if appropriate. If the decl is + // in an outer scope, it isn't the same thing. + if (PrevDecl && isDeclInScope(PrevDecl, DC, S)) { + Redeclaration = true; + MergeTypeDefDecl(NewTD, PrevDecl); + } + + // C99 6.7.7p2: If a typedef name specifies a variably modified type + // then it shall have block scope. + QualType T = NewTD->getUnderlyingType(); + if (T->isVariablyModifiedType()) { + CurFunctionNeedsScopeChecking = true; + + if (S->getFnParent() == 0) { + bool SizeIsNegative; + QualType FixedTy = + TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative); + if (!FixedTy.isNull()) { + Diag(D.getIdentifierLoc(), diag::warn_illegal_constant_array_size); + NewTD->setUnderlyingType(FixedTy); + } else { + if (SizeIsNegative) + Diag(D.getIdentifierLoc(), diag::err_typecheck_negative_array_size); + else if (T->isVariableArrayType()) + Diag(D.getIdentifierLoc(), diag::err_vla_decl_in_file_scope); + else + Diag(D.getIdentifierLoc(), diag::err_vm_decl_in_file_scope); + NewTD->setInvalidDecl(); + } + } + } + return NewTD; +} + +/// \brief Determines whether the given declaration is an out-of-scope +/// previous declaration. +/// +/// This routine should be invoked when name lookup has found a +/// previous declaration (PrevDecl) that is not in the scope where a +/// new declaration by the same name is being introduced. If the new +/// declaration occurs in a local scope, previous declarations with +/// linkage may still be considered previous declarations (C99 +/// 6.2.2p4-5, C++ [basic.link]p6). +/// +/// \param PrevDecl the previous declaration found by name +/// lookup +/// +/// \param DC the context in which the new declaration is being +/// declared. +/// +/// \returns true if PrevDecl is an out-of-scope previous declaration +/// for a new delcaration with the same name. +static bool +isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC, + ASTContext &Context) { + if (!PrevDecl) + return 0; + + // FIXME: PrevDecl could be an OverloadedFunctionDecl, in which + // case we need to check each of the overloaded functions. + if (!PrevDecl->hasLinkage()) + return false; + + if (Context.getLangOptions().CPlusPlus) { + // C++ [basic.link]p6: + // If there is a visible declaration of an entity with linkage + // having the same name and type, ignoring entities declared + // outside the innermost enclosing namespace scope, the block + // scope declaration declares that same entity and receives the + // linkage of the previous declaration. + DeclContext *OuterContext = DC->getLookupContext(); + if (!OuterContext->isFunctionOrMethod()) + // This rule only applies to block-scope declarations. + return false; + else { + DeclContext *PrevOuterContext = PrevDecl->getDeclContext(); + if (PrevOuterContext->isRecord()) + // We found a member function: ignore it. + return false; + else { + // Find the innermost enclosing namespace for the new and + // previous declarations. + while (!OuterContext->isFileContext()) + OuterContext = OuterContext->getParent(); + while (!PrevOuterContext->isFileContext()) + PrevOuterContext = PrevOuterContext->getParent(); + + // The previous declaration is in a different namespace, so it + // isn't the same function. + if (OuterContext->getPrimaryContext() != + PrevOuterContext->getPrimaryContext()) + return false; + } + } + } + + return true; +} + +NamedDecl* +Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, + QualType R,NamedDecl* PrevDecl, + bool &Redeclaration) { + DeclarationName Name = GetNameForDeclarator(D); + + // Check that there are no default arguments (C++ only). + if (getLangOptions().CPlusPlus) + CheckExtraCXXDefaultArguments(D); + + VarDecl *NewVD; + VarDecl::StorageClass SC; + switch (D.getDeclSpec().getStorageClassSpec()) { + default: assert(0 && "Unknown storage class!"); + case DeclSpec::SCS_unspecified: SC = VarDecl::None; break; + case DeclSpec::SCS_extern: SC = VarDecl::Extern; break; + case DeclSpec::SCS_static: SC = VarDecl::Static; break; + case DeclSpec::SCS_auto: SC = VarDecl::Auto; break; + case DeclSpec::SCS_register: SC = VarDecl::Register; break; + case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break; + case DeclSpec::SCS_mutable: + // mutable can only appear on non-static class members, so it's always + // an error here + Diag(D.getIdentifierLoc(), diag::err_mutable_nonmember); + D.setInvalidType(); + SC = VarDecl::None; + break; + } + + IdentifierInfo *II = Name.getAsIdentifierInfo(); + if (!II) { + Diag(D.getIdentifierLoc(), diag::err_bad_variable_name) + << Name.getAsString(); + return 0; + } + + DiagnoseFunctionSpecifiers(D); + + if (!DC->isRecord() && S->getFnParent() == 0) { + // C99 6.9p2: The storage-class specifiers auto and register shall not + // appear in the declaration specifiers in an external declaration. + if (SC == VarDecl::Auto || SC == VarDecl::Register) { + + // If this is a register variable with an asm label specified, then this + // is a GNU extension. + if (SC == VarDecl::Register && D.getAsmLabel()) + Diag(D.getIdentifierLoc(), diag::err_unsupported_global_register); + else + Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_fscope); + D.setInvalidType(); + } + } + if (DC->isRecord() && !CurContext->isRecord()) { + // This is an out-of-line definition of a static data member. + if (SC == VarDecl::Static) { + Diag(D.getDeclSpec().getStorageClassSpecLoc(), + diag::err_static_out_of_line) + << CodeModificationHint::CreateRemoval( + SourceRange(D.getDeclSpec().getStorageClassSpecLoc())); + } else if (SC == VarDecl::None) + SC = VarDecl::Static; + } + + // The variable can not + NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), + II, R, SC, + // FIXME: Move to DeclGroup... + D.getDeclSpec().getSourceRange().getBegin()); + + if (D.isInvalidType()) + NewVD->setInvalidDecl(); + + if (D.getDeclSpec().isThreadSpecified()) { + if (NewVD->hasLocalStorage()) + Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_non_global); + else if (!Context.Target.isTLSSupported()) + Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_unsupported); + else + NewVD->setThreadSpecified(true); + } + + // Set the lexical context. If the declarator has a C++ scope specifier, the + // lexical context will be different from the semantic context. + NewVD->setLexicalDeclContext(CurContext); + + // Handle attributes prior to checking for duplicates in MergeVarDecl + ProcessDeclAttributes(NewVD, D); + + // Handle GNU asm-label extension (encoded as an attribute). + if (Expr *E = (Expr*) D.getAsmLabel()) { + // The parser guarantees this is a string. + StringLiteral *SE = cast<StringLiteral>(E); + NewVD->addAttr(::new (Context) AsmLabelAttr(std::string(SE->getStrData(), + SE->getByteLength()))); + } + + // If name lookup finds a previous declaration that is not in the + // same scope as the new declaration, this may still be an + // acceptable redeclaration. + if (PrevDecl && !isDeclInScope(PrevDecl, DC, S) && + !(NewVD->hasLinkage() && + isOutOfScopePreviousDeclaration(PrevDecl, DC, Context))) + PrevDecl = 0; + + // Merge the decl with the existing one if appropriate. + if (PrevDecl) { + if (isa<FieldDecl>(PrevDecl) && D.getCXXScopeSpec().isSet()) { + // The user tried to define a non-static data member + // out-of-line (C++ [dcl.meaning]p1). + Diag(NewVD->getLocation(), diag::err_nonstatic_member_out_of_line) + << D.getCXXScopeSpec().getRange(); + PrevDecl = 0; + NewVD->setInvalidDecl(); + } + } else if (D.getCXXScopeSpec().isSet()) { + // No previous declaration in the qualifying scope. + Diag(D.getIdentifierLoc(), diag::err_typecheck_no_member) + << Name << D.getCXXScopeSpec().getRange(); + NewVD->setInvalidDecl(); + } + + CheckVariableDeclaration(NewVD, PrevDecl, Redeclaration); + + // If this is a locally-scoped extern C variable, update the map of + // such variables. + if (CurContext->isFunctionOrMethod() && NewVD->isExternC(Context) && + !NewVD->isInvalidDecl()) + RegisterLocallyScopedExternCDecl(NewVD, PrevDecl, S); + + return NewVD; +} + +/// \brief Perform semantic checking on a newly-created variable +/// declaration. +/// +/// This routine performs all of the type-checking required for a +/// variable declaration once it has been built. It is used both to +/// check variables after they have been parsed and their declarators +/// have been translated into a declaration, and to check variables +/// that have been instantiated from a template. +/// +/// Sets NewVD->isInvalidDecl() if an error was encountered. +void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl, + bool &Redeclaration) { + // If the decl is already known invalid, don't check it. + if (NewVD->isInvalidDecl()) + return; + + QualType T = NewVD->getType(); + + if (T->isObjCInterfaceType()) { + Diag(NewVD->getLocation(), diag::err_statically_allocated_object); + return NewVD->setInvalidDecl(); + } + + // The variable can not have an abstract class type. + if (RequireNonAbstractType(NewVD->getLocation(), T, + diag::err_abstract_type_in_decl, + AbstractVariableType)) + return NewVD->setInvalidDecl(); + + // Emit an error if an address space was applied to decl with local storage. + // This includes arrays of objects with address space qualifiers, but not + // automatic variables that point to other address spaces. + // ISO/IEC TR 18037 S5.1.2 + if (NewVD->hasLocalStorage() && (T.getAddressSpace() != 0)) { + Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl); + return NewVD->setInvalidDecl(); + } + + if (NewVD->hasLocalStorage() && T.isObjCGCWeak() + && !NewVD->hasAttr<BlocksAttr>()) + Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local); + + bool isVM = T->isVariablyModifiedType(); + if (isVM || NewVD->hasAttr<CleanupAttr>()) + CurFunctionNeedsScopeChecking = true; + + if ((isVM && NewVD->hasLinkage()) || + (T->isVariableArrayType() && NewVD->hasGlobalStorage())) { + bool SizeIsNegative; + QualType FixedTy = + TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative); + + if (FixedTy.isNull() && T->isVariableArrayType()) { + const VariableArrayType *VAT = Context.getAsVariableArrayType(T); + // FIXME: This won't give the correct result for + // int a[10][n]; + SourceRange SizeRange = VAT->getSizeExpr()->getSourceRange(); + + if (NewVD->isFileVarDecl()) + Diag(NewVD->getLocation(), diag::err_vla_decl_in_file_scope) + << SizeRange; + else if (NewVD->getStorageClass() == VarDecl::Static) + Diag(NewVD->getLocation(), diag::err_vla_decl_has_static_storage) + << SizeRange; + else + Diag(NewVD->getLocation(), diag::err_vla_decl_has_extern_linkage) + << SizeRange; + return NewVD->setInvalidDecl(); + } + + if (FixedTy.isNull()) { + if (NewVD->isFileVarDecl()) + Diag(NewVD->getLocation(), diag::err_vm_decl_in_file_scope); + else + Diag(NewVD->getLocation(), diag::err_vm_decl_has_extern_linkage); + return NewVD->setInvalidDecl(); + } + + Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size); + NewVD->setType(FixedTy); + } + + if (!PrevDecl && NewVD->isExternC(Context)) { + // Since we did not find anything by this name and we're declaring + // an extern "C" variable, look for a non-visible extern "C" + // declaration with the same name. + llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos + = LocallyScopedExternalDecls.find(NewVD->getDeclName()); + if (Pos != LocallyScopedExternalDecls.end()) + PrevDecl = Pos->second; + } + + if (T->isVoidType() && !NewVD->hasExternalStorage()) { + Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type) + << T; + return NewVD->setInvalidDecl(); + } + + if (!NewVD->hasLocalStorage() && NewVD->hasAttr<BlocksAttr>()) { + Diag(NewVD->getLocation(), diag::err_block_on_nonlocal); + return NewVD->setInvalidDecl(); + } + + if (isVM && NewVD->hasAttr<BlocksAttr>()) { + Diag(NewVD->getLocation(), diag::err_block_on_vm); + return NewVD->setInvalidDecl(); + } + + if (PrevDecl) { + Redeclaration = true; + MergeVarDecl(NewVD, PrevDecl); + } +} + +NamedDecl* +Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, + QualType R, NamedDecl* PrevDecl, + bool IsFunctionDefinition, bool &Redeclaration) { + assert(R.getTypePtr()->isFunctionType()); + + DeclarationName Name = GetNameForDeclarator(D); + FunctionDecl::StorageClass SC = FunctionDecl::None; + switch (D.getDeclSpec().getStorageClassSpec()) { + default: assert(0 && "Unknown storage class!"); + case DeclSpec::SCS_auto: + case DeclSpec::SCS_register: + case DeclSpec::SCS_mutable: + Diag(D.getDeclSpec().getStorageClassSpecLoc(), + diag::err_typecheck_sclass_func); + D.setInvalidType(); + break; + case DeclSpec::SCS_unspecified: SC = FunctionDecl::None; break; + case DeclSpec::SCS_extern: SC = FunctionDecl::Extern; break; + case DeclSpec::SCS_static: { + if (CurContext->getLookupContext()->isFunctionOrMethod()) { + // C99 6.7.1p5: + // The declaration of an identifier for a function that has + // block scope shall have no explicit storage-class specifier + // other than extern + // See also (C++ [dcl.stc]p4). + Diag(D.getDeclSpec().getStorageClassSpecLoc(), + diag::err_static_block_func); + SC = FunctionDecl::None; + } else + SC = FunctionDecl::Static; + break; + } + case DeclSpec::SCS_private_extern: SC = FunctionDecl::PrivateExtern;break; + } + + if (D.getDeclSpec().isThreadSpecified()) + Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + + bool isInline = D.getDeclSpec().isInlineSpecified(); + bool isVirtual = D.getDeclSpec().isVirtualSpecified(); + bool isExplicit = D.getDeclSpec().isExplicitSpecified(); + + // Check that the return type is not an abstract class type. + // For record types, this is done by the AbstractClassUsageDiagnoser once + // the class has been completely parsed. + if (!DC->isRecord() && + RequireNonAbstractType(D.getIdentifierLoc(), + R->getAsFunctionType()->getResultType(), + diag::err_abstract_type_in_decl, + AbstractReturnType)) + D.setInvalidType(); + + // Do not allow returning a objc interface by-value. + if (R->getAsFunctionType()->getResultType()->isObjCInterfaceType()) { + Diag(D.getIdentifierLoc(), + diag::err_object_cannot_be_passed_returned_by_value) << 0 + << R->getAsFunctionType()->getResultType(); + D.setInvalidType(); + } + + bool isVirtualOkay = false; + FunctionDecl *NewFD; + if (D.getKind() == Declarator::DK_Constructor) { + // This is a C++ constructor declaration. + assert(DC->isRecord() && + "Constructors can only be declared in a member context"); + + R = CheckConstructorDeclarator(D, R, SC); + + // Create the new declaration + NewFD = CXXConstructorDecl::Create(Context, + cast<CXXRecordDecl>(DC), + D.getIdentifierLoc(), Name, R, + isExplicit, isInline, + /*isImplicitlyDeclared=*/false); + } else if (D.getKind() == Declarator::DK_Destructor) { + // This is a C++ destructor declaration. + if (DC->isRecord()) { + R = CheckDestructorDeclarator(D, SC); + + NewFD = CXXDestructorDecl::Create(Context, + cast<CXXRecordDecl>(DC), + D.getIdentifierLoc(), Name, R, + isInline, + /*isImplicitlyDeclared=*/false); + + isVirtualOkay = true; + } else { + Diag(D.getIdentifierLoc(), diag::err_destructor_not_member); + + // Create a FunctionDecl to satisfy the function definition parsing + // code path. + NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(), + Name, R, SC, isInline, + /*hasPrototype=*/true, + // FIXME: Move to DeclGroup... + D.getDeclSpec().getSourceRange().getBegin()); + D.setInvalidType(); + } + } else if (D.getKind() == Declarator::DK_Conversion) { + if (!DC->isRecord()) { + Diag(D.getIdentifierLoc(), + diag::err_conv_function_not_member); + return 0; + } + + CheckConversionDeclarator(D, R, SC); + NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC), + D.getIdentifierLoc(), Name, R, + isInline, isExplicit); + + isVirtualOkay = true; + } else if (DC->isRecord()) { + // If the of the function is the same as the name of the record, then this + // must be an invalid constructor that has a return type. + // (The parser checks for a return type and makes the declarator a + // constructor if it has no return type). + // must have an invalid constructor that has a return type + if (Name.getAsIdentifierInfo() == cast<CXXRecordDecl>(DC)->getIdentifier()){ + Diag(D.getIdentifierLoc(), diag::err_constructor_return_type) + << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) + << SourceRange(D.getIdentifierLoc()); + return 0; + } + + // This is a C++ method declaration. + NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC), + D.getIdentifierLoc(), Name, R, + (SC == FunctionDecl::Static), isInline); + + isVirtualOkay = (SC != FunctionDecl::Static); + } else { + // Determine whether the function was written with a + // prototype. This true when: + // - we're in C++ (where every function has a prototype), + // - there is a prototype in the declarator, or + // - the type R of the function is some kind of typedef or other reference + // to a type name (which eventually refers to a function type). + bool HasPrototype = + getLangOptions().CPlusPlus || + (D.getNumTypeObjects() && D.getTypeObject(0).Fun.hasPrototype) || + (!isa<FunctionType>(R.getTypePtr()) && R->isFunctionProtoType()); + + NewFD = FunctionDecl::Create(Context, DC, + D.getIdentifierLoc(), + Name, R, SC, isInline, HasPrototype, + // FIXME: Move to DeclGroup... + D.getDeclSpec().getSourceRange().getBegin()); + } + + if (D.isInvalidType()) + NewFD->setInvalidDecl(); + + // Set the lexical context. If the declarator has a C++ + // scope specifier, the lexical context will be different + // from the semantic context. + NewFD->setLexicalDeclContext(CurContext); + + // C++ [dcl.fct.spec]p5: + // The virtual specifier shall only be used in declarations of + // nonstatic class member functions that appear within a + // member-specification of a class declaration; see 10.3. + // + if (isVirtual && !NewFD->isInvalidDecl()) { + if (!isVirtualOkay) { + Diag(D.getDeclSpec().getVirtualSpecLoc(), + diag::err_virtual_non_function); + } else if (!CurContext->isRecord()) { + // 'virtual' was specified outside of the class. + Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_out_of_class) + << CodeModificationHint::CreateRemoval( + SourceRange(D.getDeclSpec().getVirtualSpecLoc())); + } else { + // Okay: Add virtual to the method. + cast<CXXMethodDecl>(NewFD)->setVirtualAsWritten(true); + CXXRecordDecl *CurClass = cast<CXXRecordDecl>(DC); + CurClass->setAggregate(false); + CurClass->setPOD(false); + CurClass->setPolymorphic(true); + CurClass->setHasTrivialConstructor(false); + } + } + + if (CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD)) { + // Look for virtual methods in base classes that this method might override. + + BasePaths Paths; + if (LookupInBases(cast<CXXRecordDecl>(DC), + MemberLookupCriteria(NewMD), Paths)) { + for (BasePaths::decl_iterator I = Paths.found_decls_begin(), + E = Paths.found_decls_end(); I != E; ++I) { + if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) { + if (!CheckOverridingFunctionReturnType(NewMD, OldMD)) + NewMD->addOverriddenMethod(OldMD); + } + } + } + } + + if (SC == FunctionDecl::Static && isa<CXXMethodDecl>(NewFD) && + !CurContext->isRecord()) { + // C++ [class.static]p1: + // A data or function member of a class may be declared static + // in a class definition, in which case it is a static member of + // the class. + + // Complain about the 'static' specifier if it's on an out-of-line + // member function definition. + Diag(D.getDeclSpec().getStorageClassSpecLoc(), + diag::err_static_out_of_line) + << CodeModificationHint::CreateRemoval( + SourceRange(D.getDeclSpec().getStorageClassSpecLoc())); + } + + // Handle GNU asm-label extension (encoded as an attribute). + if (Expr *E = (Expr*) D.getAsmLabel()) { + // The parser guarantees this is a string. + StringLiteral *SE = cast<StringLiteral>(E); + NewFD->addAttr(::new (Context) AsmLabelAttr(std::string(SE->getStrData(), + SE->getByteLength()))); + } + + // Copy the parameter declarations from the declarator D to the function + // declaration NewFD, if they are available. First scavenge them into Params. + llvm::SmallVector<ParmVarDecl*, 16> Params; + if (D.getNumTypeObjects() > 0) { + DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + + // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs + // function that takes no arguments, not a function that takes a + // single void argument. + // We let through "const void" here because Sema::GetTypeForDeclarator + // already checks for that case. + if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 && + FTI.ArgInfo[0].Param && + FTI.ArgInfo[0].Param.getAs<ParmVarDecl>()->getType()->isVoidType()) { + // Empty arg list, don't push any params. + ParmVarDecl *Param = FTI.ArgInfo[0].Param.getAs<ParmVarDecl>(); + + // In C++, the empty parameter-type-list must be spelled "void"; a + // typedef of void is not permitted. + if (getLangOptions().CPlusPlus && + Param->getType().getUnqualifiedType() != Context.VoidTy) + Diag(Param->getLocation(), diag::err_param_typedef_of_void); + // FIXME: Leaks decl? + } else if (FTI.NumArgs > 0 && FTI.ArgInfo[0].Param != 0) { + for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) + Params.push_back(FTI.ArgInfo[i].Param.getAs<ParmVarDecl>()); + } + + } else if (const FunctionProtoType *FT = R->getAsFunctionProtoType()) { + // When we're declaring a function with a typedef, typeof, etc as in the + // following example, we'll need to synthesize (unnamed) + // parameters for use in the declaration. + // + // @code + // typedef void fn(int); + // fn f; + // @endcode + + // Synthesize a parameter for each argument type. + for (FunctionProtoType::arg_type_iterator AI = FT->arg_type_begin(), + AE = FT->arg_type_end(); AI != AE; ++AI) { + ParmVarDecl *Param = ParmVarDecl::Create(Context, DC, + SourceLocation(), 0, + *AI, VarDecl::None, 0); + Param->setImplicit(); + Params.push_back(Param); + } + } else { + assert(R->isFunctionNoProtoType() && NewFD->getNumParams() == 0 && + "Should not need args for typedef of non-prototype fn"); + } + // Finally, we know we have the right number of parameters, install them. + NewFD->setParams(Context, Params.data(), Params.size()); + + + + // If name lookup finds a previous declaration that is not in the + // same scope as the new declaration, this may still be an + // acceptable redeclaration. + if (PrevDecl && !isDeclInScope(PrevDecl, DC, S) && + !(NewFD->hasLinkage() && + isOutOfScopePreviousDeclaration(PrevDecl, DC, Context))) + PrevDecl = 0; + + // Perform semantic checking on the function declaration. + bool OverloadableAttrRequired = false; // FIXME: HACK! + CheckFunctionDeclaration(NewFD, PrevDecl, Redeclaration, + /*FIXME:*/OverloadableAttrRequired); + + if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) { + // An out-of-line member function declaration must also be a + // definition (C++ [dcl.meaning]p1). + if (!IsFunctionDefinition) { + Diag(NewFD->getLocation(), diag::err_out_of_line_declaration) + << D.getCXXScopeSpec().getRange(); + NewFD->setInvalidDecl(); + } else if (!Redeclaration) { + // The user tried to provide an out-of-line definition for a + // function that is a member of a class or namespace, but there + // was no such member function declared (C++ [class.mfct]p2, + // C++ [namespace.memdef]p2). For example: + // + // class X { + // void f() const; + // }; + // + // void X::f() { } // ill-formed + // + // Complain about this problem, and attempt to suggest close + // matches (e.g., those that differ only in cv-qualifiers and + // whether the parameter types are references). + Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match) + << cast<NamedDecl>(DC) << D.getCXXScopeSpec().getRange(); + NewFD->setInvalidDecl(); + + LookupResult Prev = LookupQualifiedName(DC, Name, LookupOrdinaryName, + true); + assert(!Prev.isAmbiguous() && + "Cannot have an ambiguity in previous-declaration lookup"); + for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end(); + Func != FuncEnd; ++Func) { + if (isa<FunctionDecl>(*Func) && + isNearlyMatchingFunction(Context, cast<FunctionDecl>(*Func), NewFD)) + Diag((*Func)->getLocation(), diag::note_member_def_close_match); + } + + PrevDecl = 0; + } + } + + // Handle attributes. We need to have merged decls when handling attributes + // (for example to check for conflicts, etc). + // FIXME: This needs to happen before we merge declarations. Then, + // let attribute merging cope with attribute conflicts. + ProcessDeclAttributes(NewFD, D); + AddKnownFunctionAttributes(NewFD); + + if (OverloadableAttrRequired && !NewFD->getAttr<OverloadableAttr>()) { + // If a function name is overloadable in C, then every function + // with that name must be marked "overloadable". + Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing) + << Redeclaration << NewFD; + if (PrevDecl) + Diag(PrevDecl->getLocation(), + diag::note_attribute_overloadable_prev_overload); + NewFD->addAttr(::new (Context) OverloadableAttr()); + } + + // If this is a locally-scoped extern C function, update the + // map of such names. + if (CurContext->isFunctionOrMethod() && NewFD->isExternC(Context) + && !NewFD->isInvalidDecl()) + RegisterLocallyScopedExternCDecl(NewFD, PrevDecl, S); + + return NewFD; +} + +/// \brief Perform semantic checking of a new function declaration. +/// +/// Performs semantic analysis of the new function declaration +/// NewFD. This routine performs all semantic checking that does not +/// require the actual declarator involved in the declaration, and is +/// used both for the declaration of functions as they are parsed +/// (called via ActOnDeclarator) and for the declaration of functions +/// that have been instantiated via C++ template instantiation (called +/// via InstantiateDecl). +/// +/// This sets NewFD->isInvalidDecl() to true if there was an error. +void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, + bool &Redeclaration, + bool &OverloadableAttrRequired) { + // If NewFD is already known erroneous, don't do any of this checking. + if (NewFD->isInvalidDecl()) + return; + + if (NewFD->getResultType()->isVariablyModifiedType()) { + // Functions returning a variably modified type violate C99 6.7.5.2p2 + // because all functions have linkage. + Diag(NewFD->getLocation(), diag::err_vm_func_decl); + return NewFD->setInvalidDecl(); + } + + // Semantic checking for this function declaration (in isolation). + if (getLangOptions().CPlusPlus) { + // C++-specific checks. + if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) { + CheckConstructor(Constructor); + } else if (isa<CXXDestructorDecl>(NewFD)) { + CXXRecordDecl *Record = cast<CXXRecordDecl>(NewFD->getParent()); + Record->setUserDeclaredDestructor(true); + // C++ [class]p4: A POD-struct is an aggregate class that has [...] no + // user-defined destructor. + Record->setPOD(false); + + // C++ [class.dtor]p3: A destructor is trivial if it is an implicitly- + // declared destructor. + Record->setHasTrivialDestructor(false); + } else if (CXXConversionDecl *Conversion + = dyn_cast<CXXConversionDecl>(NewFD)) + ActOnConversionDeclarator(Conversion); + + // Extra checking for C++ overloaded operators (C++ [over.oper]). + if (NewFD->isOverloadedOperator() && + CheckOverloadedOperatorDeclaration(NewFD)) + return NewFD->setInvalidDecl(); + } + + // C99 6.7.4p6: + // [... ] For a function with external linkage, the following + // restrictions apply: [...] If all of the file scope declarations + // for a function in a translation unit include the inline + // function specifier without extern, then the definition in that + // translation unit is an inline definition. An inline definition + // does not provide an external definition for the function, and + // does not forbid an external definition in another translation + // unit. + // + // Here we determine whether this function, in isolation, would be a + // C99 inline definition. MergeCompatibleFunctionDecls looks at + // previous declarations. + if (NewFD->isInline() && getLangOptions().C99 && + NewFD->getStorageClass() == FunctionDecl::None && + NewFD->getDeclContext()->getLookupContext()->isTranslationUnit()) + NewFD->setC99InlineDefinition(true); + + // Check for a previous declaration of this name. + if (!PrevDecl && NewFD->isExternC(Context)) { + // Since we did not find anything by this name and we're declaring + // an extern "C" function, look for a non-visible extern "C" + // declaration with the same name. + llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos + = LocallyScopedExternalDecls.find(NewFD->getDeclName()); + if (Pos != LocallyScopedExternalDecls.end()) + PrevDecl = Pos->second; + } + + // Merge or overload the declaration with an existing declaration of + // the same name, if appropriate. + if (PrevDecl) { + // Determine whether NewFD is an overload of PrevDecl or + // a declaration that requires merging. If it's an overload, + // there's no more work to do here; we'll just add the new + // function to the scope. + OverloadedFunctionDecl::function_iterator MatchedDecl; + + if (!getLangOptions().CPlusPlus && + AllowOverloadingOfFunction(PrevDecl, Context)) { + OverloadableAttrRequired = true; + + // Functions marked "overloadable" must have a prototype (that + // we can't get through declaration merging). + if (!NewFD->getType()->getAsFunctionProtoType()) { + Diag(NewFD->getLocation(), diag::err_attribute_overloadable_no_prototype) + << NewFD; + Redeclaration = true; + + // Turn this into a variadic function with no parameters. + QualType R = Context.getFunctionType( + NewFD->getType()->getAsFunctionType()->getResultType(), + 0, 0, true, 0); + NewFD->setType(R); + return NewFD->setInvalidDecl(); + } + } + + if (PrevDecl && + (!AllowOverloadingOfFunction(PrevDecl, Context) || + !IsOverload(NewFD, PrevDecl, MatchedDecl))) { + Redeclaration = true; + Decl *OldDecl = PrevDecl; + + // If PrevDecl was an overloaded function, extract the + // FunctionDecl that matched. + if (isa<OverloadedFunctionDecl>(PrevDecl)) + OldDecl = *MatchedDecl; + + // NewFD and OldDecl represent declarations that need to be + // merged. + if (MergeFunctionDecl(NewFD, OldDecl)) + return NewFD->setInvalidDecl(); + + NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl)); + } + } + + // In C++, check default arguments now that we have merged decls. Unless + // the lexical context is the class, because in this case this is done + // during delayed parsing anyway. + if (getLangOptions().CPlusPlus && !CurContext->isRecord()) + CheckCXXDefaultArguments(NewFD); +} + +bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) { + // FIXME: Need strict checking. In C89, we need to check for + // any assignment, increment, decrement, function-calls, or + // commas outside of a sizeof. In C99, it's the same list, + // except that the aforementioned are allowed in unevaluated + // expressions. Everything else falls under the + // "may accept other forms of constant expressions" exception. + // (We never end up here for C++, so the constant expression + // rules there don't matter.) + if (Init->isConstantInitializer(Context)) + return false; + Diag(Init->getExprLoc(), diag::err_init_element_not_constant) + << Init->getSourceRange(); + return true; +} + +void Sema::AddInitializerToDecl(DeclPtrTy dcl, FullExprArg init) { + AddInitializerToDecl(dcl, init.release(), /*DirectInit=*/false); +} + +/// AddInitializerToDecl - Adds the initializer Init to the +/// declaration dcl. If DirectInit is true, this is C++ direct +/// initialization rather than copy initialization. +void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { + Decl *RealDecl = dcl.getAs<Decl>(); + // If there is no declaration, there was an error parsing it. Just ignore + // the initializer. + if (RealDecl == 0) + return; + + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) { + // With declarators parsed the way they are, the parser cannot + // distinguish between a normal initializer and a pure-specifier. + // Thus this grotesque test. + IntegerLiteral *IL; + Expr *Init = static_cast<Expr *>(init.get()); + if ((IL = dyn_cast<IntegerLiteral>(Init)) && IL->getValue() == 0 && + Context.getCanonicalType(IL->getType()) == Context.IntTy) { + if (Method->isVirtualAsWritten()) { + Method->setPure(); + + // A class is abstract if at least one function is pure virtual. + cast<CXXRecordDecl>(CurContext)->setAbstract(true); + } else if (!Method->isInvalidDecl()) { + Diag(Method->getLocation(), diag::err_non_virtual_pure) + << Method->getDeclName() << Init->getSourceRange(); + Method->setInvalidDecl(); + } + } else { + Diag(Method->getLocation(), diag::err_member_function_initialization) + << Method->getDeclName() << Init->getSourceRange(); + Method->setInvalidDecl(); + } + return; + } + + VarDecl *VDecl = dyn_cast<VarDecl>(RealDecl); + if (!VDecl) { + if (getLangOptions().CPlusPlus && + RealDecl->getLexicalDeclContext()->isRecord() && + isa<NamedDecl>(RealDecl)) + Diag(RealDecl->getLocation(), diag::err_member_initialization) + << cast<NamedDecl>(RealDecl)->getDeclName(); + else + Diag(RealDecl->getLocation(), diag::err_illegal_initializer); + RealDecl->setInvalidDecl(); + return; + } + + if (!VDecl->getType()->isArrayType() && + RequireCompleteType(VDecl->getLocation(), VDecl->getType(), + diag::err_typecheck_decl_incomplete_type)) { + RealDecl->setInvalidDecl(); + return; + } + + const VarDecl *Def = 0; + if (VDecl->getDefinition(Def)) { + Diag(VDecl->getLocation(), diag::err_redefinition) + << VDecl->getDeclName(); + Diag(Def->getLocation(), diag::note_previous_definition); + VDecl->setInvalidDecl(); + return; + } + + // Take ownership of the expression, now that we're sure we have somewhere + // to put it. + Expr *Init = init.takeAs<Expr>(); + assert(Init && "missing initializer"); + + // Get the decls type and save a reference for later, since + // CheckInitializerTypes may change it. + QualType DclT = VDecl->getType(), SavT = DclT; + if (VDecl->isBlockVarDecl()) { + if (VDecl->hasExternalStorage()) { // C99 6.7.8p5 + Diag(VDecl->getLocation(), diag::err_block_extern_cant_init); + VDecl->setInvalidDecl(); + } else if (!VDecl->isInvalidDecl()) { + if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(), + VDecl->getDeclName(), DirectInit)) + VDecl->setInvalidDecl(); + + // C++ 3.6.2p2, allow dynamic initialization of static initializers. + // Don't check invalid declarations to avoid emitting useless diagnostics. + if (!getLangOptions().CPlusPlus && !VDecl->isInvalidDecl()) { + if (VDecl->getStorageClass() == VarDecl::Static) // C99 6.7.8p4. + CheckForConstantInitializer(Init, DclT); + } + } + } else if (VDecl->isStaticDataMember() && + VDecl->getLexicalDeclContext()->isRecord()) { + // This is an in-class initialization for a static data member, e.g., + // + // struct S { + // static const int value = 17; + // }; + + // Attach the initializer + VDecl->setInit(Context, Init); + + // C++ [class.mem]p4: + // A member-declarator can contain a constant-initializer only + // if it declares a static member (9.4) of const integral or + // const enumeration type, see 9.4.2. + QualType T = VDecl->getType(); + if (!T->isDependentType() && + (!Context.getCanonicalType(T).isConstQualified() || + !T->isIntegralType())) { + Diag(VDecl->getLocation(), diag::err_member_initialization) + << VDecl->getDeclName() << Init->getSourceRange(); + VDecl->setInvalidDecl(); + } else { + // C++ [class.static.data]p4: + // If a static data member is of const integral or const + // enumeration type, its declaration in the class definition + // can specify a constant-initializer which shall be an + // integral constant expression (5.19). + if (!Init->isTypeDependent() && + !Init->getType()->isIntegralType()) { + // We have a non-dependent, non-integral or enumeration type. + Diag(Init->getSourceRange().getBegin(), + diag::err_in_class_initializer_non_integral_type) + << Init->getType() << Init->getSourceRange(); + VDecl->setInvalidDecl(); + } else if (!Init->isTypeDependent() && !Init->isValueDependent()) { + // Check whether the expression is a constant expression. + llvm::APSInt Value; + SourceLocation Loc; + if (!Init->isIntegerConstantExpr(Value, Context, &Loc)) { + Diag(Loc, diag::err_in_class_initializer_non_constant) + << Init->getSourceRange(); + VDecl->setInvalidDecl(); + } else if (!VDecl->getType()->isDependentType()) + ImpCastExprToType(Init, VDecl->getType()); + } + } + } else if (VDecl->isFileVarDecl()) { + if (VDecl->getStorageClass() == VarDecl::Extern) + Diag(VDecl->getLocation(), diag::warn_extern_init); + if (!VDecl->isInvalidDecl()) + if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(), + VDecl->getDeclName(), DirectInit)) + VDecl->setInvalidDecl(); + + // C++ 3.6.2p2, allow dynamic initialization of static initializers. + // Don't check invalid declarations to avoid emitting useless diagnostics. + if (!getLangOptions().CPlusPlus && !VDecl->isInvalidDecl()) { + // C99 6.7.8p4. All file scoped initializers need to be constant. + CheckForConstantInitializer(Init, DclT); + } + } + // If the type changed, it means we had an incomplete type that was + // completed by the initializer. For example: + // int ary[] = { 1, 3, 5 }; + // "ary" transitions from a VariableArrayType to a ConstantArrayType. + if (!VDecl->isInvalidDecl() && (DclT != SavT)) { + VDecl->setType(DclT); + Init->setType(DclT); + } + + // Attach the initializer to the decl. + VDecl->setInit(Context, Init); + + // If the previous declaration of VDecl was a tentative definition, + // remove it from the set of tentative definitions. + if (VDecl->getPreviousDeclaration() && + VDecl->getPreviousDeclaration()->isTentativeDefinition(Context)) { + llvm::DenseMap<DeclarationName, VarDecl *>::iterator Pos + = TentativeDefinitions.find(VDecl->getDeclName()); + assert(Pos != TentativeDefinitions.end() && + "Unrecorded tentative definition?"); + TentativeDefinitions.erase(Pos); + } + + return; +} + +void Sema::ActOnUninitializedDecl(DeclPtrTy dcl) { + Decl *RealDecl = dcl.getAs<Decl>(); + + // If there is no declaration, there was an error parsing it. Just ignore it. + if (RealDecl == 0) + return; + + if (VarDecl *Var = dyn_cast<VarDecl>(RealDecl)) { + QualType Type = Var->getType(); + + // Record tentative definitions. + if (Var->isTentativeDefinition(Context)) + TentativeDefinitions[Var->getDeclName()] = Var; + + // C++ [dcl.init.ref]p3: + // The initializer can be omitted for a reference only in a + // parameter declaration (8.3.5), in the declaration of a + // function return type, in the declaration of a class member + // within its class declaration (9.2), and where the extern + // specifier is explicitly used. + if (Type->isReferenceType() && !Var->hasExternalStorage()) { + Diag(Var->getLocation(), diag::err_reference_var_requires_init) + << Var->getDeclName() + << SourceRange(Var->getLocation(), Var->getLocation()); + Var->setInvalidDecl(); + return; + } + + // C++ [dcl.init]p9: + // + // If no initializer is specified for an object, and the object + // is of (possibly cv-qualified) non-POD class type (or array + // thereof), the object shall be default-initialized; if the + // object is of const-qualified type, the underlying class type + // shall have a user-declared default constructor. + if (getLangOptions().CPlusPlus) { + QualType InitType = Type; + if (const ArrayType *Array = Context.getAsArrayType(Type)) + InitType = Array->getElementType(); + if ((!Var->hasExternalStorage() && !Var->isExternC(Context)) && + InitType->isRecordType() && !InitType->isDependentType()) { + CXXRecordDecl *RD = + cast<CXXRecordDecl>(InitType->getAsRecordType()->getDecl()); + CXXConstructorDecl *Constructor = 0; + if (!RequireCompleteType(Var->getLocation(), InitType, + diag::err_invalid_incomplete_type_use)) + Constructor + = PerformInitializationByConstructor(InitType, 0, 0, + Var->getLocation(), + SourceRange(Var->getLocation(), + Var->getLocation()), + Var->getDeclName(), + IK_Default); + if (!Constructor) + Var->setInvalidDecl(); + else if (!RD->hasTrivialConstructor()) + InitializeVarWithConstructor(Var, Constructor, InitType, 0, 0); + } + } + +#if 0 + // FIXME: Temporarily disabled because we are not properly parsing + // linkage specifications on declarations, e.g., + // + // extern "C" const CGPoint CGPointerZero; + // + // C++ [dcl.init]p9: + // + // If no initializer is specified for an object, and the + // object is of (possibly cv-qualified) non-POD class type (or + // array thereof), the object shall be default-initialized; if + // the object is of const-qualified type, the underlying class + // type shall have a user-declared default + // constructor. Otherwise, if no initializer is specified for + // an object, the object and its subobjects, if any, have an + // indeterminate initial value; if the object or any of its + // subobjects are of const-qualified type, the program is + // ill-formed. + // + // This isn't technically an error in C, so we don't diagnose it. + // + // FIXME: Actually perform the POD/user-defined default + // constructor check. + if (getLangOptions().CPlusPlus && + Context.getCanonicalType(Type).isConstQualified() && + !Var->hasExternalStorage()) + Diag(Var->getLocation(), diag::err_const_var_requires_init) + << Var->getName() + << SourceRange(Var->getLocation(), Var->getLocation()); +#endif + } +} + +Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, + DeclPtrTy *Group, + unsigned NumDecls) { + llvm::SmallVector<Decl*, 8> Decls; + + if (DS.isTypeSpecOwned()) + Decls.push_back((Decl*)DS.getTypeRep()); + + for (unsigned i = 0; i != NumDecls; ++i) + if (Decl *D = Group[i].getAs<Decl>()) + Decls.push_back(D); + + // Perform semantic analysis that depends on having fully processed both + // the declarator and initializer. + for (unsigned i = 0, e = Decls.size(); i != e; ++i) { + VarDecl *IDecl = dyn_cast<VarDecl>(Decls[i]); + if (!IDecl) + continue; + QualType T = IDecl->getType(); + + // Block scope. C99 6.7p7: If an identifier for an object is declared with + // no linkage (C99 6.2.2p6), the type for the object shall be complete... + if (IDecl->isBlockVarDecl() && !IDecl->hasExternalStorage()) { + if (!IDecl->isInvalidDecl() && + RequireCompleteType(IDecl->getLocation(), T, + diag::err_typecheck_decl_incomplete_type)) + IDecl->setInvalidDecl(); + } + // File scope. C99 6.9.2p2: A declaration of an identifier for and + // object that has file scope without an initializer, and without a + // storage-class specifier or with the storage-class specifier "static", + // constitutes a tentative definition. Note: A tentative definition with + // external linkage is valid (C99 6.2.2p5). + if (IDecl->isTentativeDefinition(Context)) { + QualType CheckType = T; + unsigned DiagID = diag::err_typecheck_decl_incomplete_type; + + const IncompleteArrayType *ArrayT = Context.getAsIncompleteArrayType(T); + if (ArrayT) { + CheckType = ArrayT->getElementType(); + DiagID = diag::err_illegal_decl_array_incomplete_type; + } + + if (IDecl->isInvalidDecl()) { + // Do nothing with invalid declarations + } else if ((ArrayT || IDecl->getStorageClass() == VarDecl::Static) && + RequireCompleteType(IDecl->getLocation(), CheckType, DiagID)) { + // C99 6.9.2p3: If the declaration of an identifier for an object is + // a tentative definition and has internal linkage (C99 6.2.2p3), the + // declared type shall not be an incomplete type. + IDecl->setInvalidDecl(); + } + } + } + return DeclGroupPtrTy::make(DeclGroupRef::Create(Context, + Decls.data(), Decls.size())); +} + + +/// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator() +/// to introduce parameters into function prototype scope. +Sema::DeclPtrTy +Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { + const DeclSpec &DS = D.getDeclSpec(); + + // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'. + VarDecl::StorageClass StorageClass = VarDecl::None; + if (DS.getStorageClassSpec() == DeclSpec::SCS_register) { + StorageClass = VarDecl::Register; + } else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) { + Diag(DS.getStorageClassSpecLoc(), + diag::err_invalid_storage_class_in_func_decl); + D.getMutableDeclSpec().ClearStorageClassSpecs(); + } + + if (D.getDeclSpec().isThreadSpecified()) + Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + + DiagnoseFunctionSpecifiers(D); + + // Check that there are no default arguments inside the type of this + // parameter (C++ only). + if (getLangOptions().CPlusPlus) + CheckExtraCXXDefaultArguments(D); + + TagDecl *OwnedDecl = 0; + QualType parmDeclType = GetTypeForDeclarator(D, S, /*Skip=*/0, &OwnedDecl); + + if (getLangOptions().CPlusPlus && OwnedDecl && OwnedDecl->isDefinition()) { + // C++ [dcl.fct]p6: + // Types shall not be defined in return or parameter types. + Diag(OwnedDecl->getLocation(), diag::err_type_defined_in_param_type) + << 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. + IdentifierInfo *II = D.getIdentifier(); + if (II) { + if (NamedDecl *PrevDecl = LookupName(S, II, LookupOrdinaryName)) { + if (PrevDecl->isTemplateParameter()) { + // Maybe we will complain about the shadowed template parameter. + DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); + // Just pretend that we didn't see the previous declaration. + PrevDecl = 0; + } else if (S->isDeclScope(DeclPtrTy::make(PrevDecl))) { + Diag(D.getIdentifierLoc(), diag::err_param_redefinition) << II; + + // Recover by removing the name + II = 0; + D.SetIdentifier(0, D.getIdentifierLoc()); + } + } + } + + // Parameters can not be abstract class types. + // For record types, this is done by the AbstractClassUsageDiagnoser once + // the class has been completely parsed. + if (!CurContext->isRecord() && + RequireNonAbstractType(D.getIdentifierLoc(), parmDeclType, + diag::err_abstract_type_in_decl, + AbstractParamType)) + D.setInvalidType(true); + + QualType T = adjustParameterType(parmDeclType); + + ParmVarDecl *New; + if (T == parmDeclType) // parameter type did not need adjustment + New = ParmVarDecl::Create(Context, CurContext, + D.getIdentifierLoc(), II, + parmDeclType, StorageClass, + 0); + else // keep track of both the adjusted and unadjusted types + New = OriginalParmVarDecl::Create(Context, CurContext, + D.getIdentifierLoc(), II, T, + parmDeclType, StorageClass, 0); + + if (D.isInvalidType()) + New->setInvalidDecl(); + + // Parameter declarators cannot be interface types. All ObjC objects are + // passed by reference. + if (T->isObjCInterfaceType()) { + Diag(D.getIdentifierLoc(), + diag::err_object_cannot_be_passed_returned_by_value) << 1 << T; + New->setInvalidDecl(); + } + + // Parameter declarators cannot be qualified (C++ [dcl.meaning]p1). + if (D.getCXXScopeSpec().isSet()) { + Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator) + << D.getCXXScopeSpec().getRange(); + New->setInvalidDecl(); + } + + // Add the parameter declaration into this scope. + S->AddDecl(DeclPtrTy::make(New)); + if (II) + IdResolver.AddDecl(New); + + ProcessDeclAttributes(New, D); + + if (New->hasAttr<BlocksAttr>()) { + Diag(New->getLocation(), diag::err_block_on_nonlocal); + } + return DeclPtrTy::make(New); +} + +void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, + SourceLocation LocAfterDecls) { + assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function && + "Not a function declarator!"); + DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + + // Verify 6.9.1p6: 'every identifier in the identifier list shall be declared' + // for a K&R function. + if (!FTI.hasPrototype) { + for (int i = FTI.NumArgs; i != 0; /* decrement in loop */) { + --i; + if (FTI.ArgInfo[i].Param == 0) { + std::string Code = " int "; + Code += FTI.ArgInfo[i].Ident->getName(); + Code += ";\n"; + Diag(FTI.ArgInfo[i].IdentLoc, diag::ext_param_not_declared) + << FTI.ArgInfo[i].Ident + << CodeModificationHint::CreateInsertion(LocAfterDecls, Code); + + // Implicitly declare the argument as type 'int' for lack of a better + // type. + DeclSpec DS; + const char* PrevSpec; // unused + DS.SetTypeSpecType(DeclSpec::TST_int, FTI.ArgInfo[i].IdentLoc, + PrevSpec); + Declarator ParamD(DS, Declarator::KNRTypeListContext); + ParamD.SetIdentifier(FTI.ArgInfo[i].Ident, FTI.ArgInfo[i].IdentLoc); + FTI.ArgInfo[i].Param = ActOnParamDeclarator(S, ParamD); + } + } + } +} + +Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, + Declarator &D) { + assert(getCurFunctionDecl() == 0 && "Function parsing confused"); + assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function && + "Not a function declarator!"); + DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + + if (FTI.hasPrototype) { + // FIXME: Diagnose arguments without names in C. + } + + Scope *ParentScope = FnBodyScope->getParent(); + + DeclPtrTy DP = ActOnDeclarator(ParentScope, D, /*IsFunctionDefinition=*/true); + return ActOnStartOfFunctionDef(FnBodyScope, DP); +} + +Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { + FunctionDecl *FD = cast<FunctionDecl>(D.getAs<Decl>()); + + CurFunctionNeedsScopeChecking = false; + + // See if this is a redefinition. + const FunctionDecl *Definition; + if (FD->getBody(Context, Definition)) { + Diag(FD->getLocation(), diag::err_redefinition) << FD->getDeclName(); + Diag(Definition->getLocation(), diag::note_previous_definition); + } + + // Builtin functions cannot be defined. + if (unsigned BuiltinID = FD->getBuiltinID(Context)) { + if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) { + Diag(FD->getLocation(), diag::err_builtin_definition) << FD; + FD->setInvalidDecl(); + } + } + + // The return type of a function definition must be complete + // (C99 6.9.1p3, C++ [dcl.fct]p6). + QualType ResultType = FD->getResultType(); + if (!ResultType->isDependentType() && !ResultType->isVoidType() && + !FD->isInvalidDecl() && + RequireCompleteType(FD->getLocation(), ResultType, + diag::err_func_def_incomplete_result)) + FD->setInvalidDecl(); + + // GNU warning -Wmissing-prototypes: + // Warn if a global function is defined without a previous + // prototype declaration. This warning is issued even if the + // definition itself provides a prototype. The aim is to detect + // global functions that fail to be declared in header files. + if (!FD->isInvalidDecl() && FD->isGlobal() && !isa<CXXMethodDecl>(FD) && + !FD->isMain()) { + bool MissingPrototype = true; + for (const FunctionDecl *Prev = FD->getPreviousDeclaration(); + Prev; Prev = Prev->getPreviousDeclaration()) { + // Ignore any declarations that occur in function or method + // scope, because they aren't visible from the header. + if (Prev->getDeclContext()->isFunctionOrMethod()) + continue; + + MissingPrototype = !Prev->getType()->isFunctionProtoType(); + break; + } + + if (MissingPrototype) + Diag(FD->getLocation(), diag::warn_missing_prototype) << FD; + } + + if (FnBodyScope) + PushDeclContext(FnBodyScope, FD); + + // Check the validity of our function parameters + CheckParmsForFunctionDef(FD); + + // Introduce our parameters into the function scope + for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) { + ParmVarDecl *Param = FD->getParamDecl(p); + Param->setOwningFunction(FD); + + // If this has an identifier, add it to the scope stack. + if (Param->getIdentifier() && FnBodyScope) + PushOnScopeChains(Param, FnBodyScope); + } + + // Checking attributes of current function definition + // dllimport attribute. + if (FD->getAttr<DLLImportAttr>() && (!FD->getAttr<DLLExportAttr>())) { + // dllimport attribute cannot be applied to definition. + if (!(FD->getAttr<DLLImportAttr>())->isInherited()) { + Diag(FD->getLocation(), + diag::err_attribute_can_be_applied_only_to_symbol_declaration) + << "dllimport"; + FD->setInvalidDecl(); + return DeclPtrTy::make(FD); + } else { + // If a symbol previously declared dllimport is later defined, the + // attribute is ignored in subsequent references, and a warning is + // emitted. + Diag(FD->getLocation(), + diag::warn_redeclaration_without_attribute_prev_attribute_ignored) + << FD->getNameAsCString() << "dllimport"; + } + } + return DeclPtrTy::make(FD); +} + +Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg) { + return ActOnFinishFunctionBody(D, move(BodyArg), false); +} + +Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, + bool IsInstantiation) { + Decl *dcl = D.getAs<Decl>(); + Stmt *Body = BodyArg.takeAs<Stmt>(); + if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(dcl)) { + FD->setBody(Body); + assert(FD == getCurFunctionDecl() && "Function parsing confused"); + } else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) { + assert(MD == getCurMethodDecl() && "Method parsing confused"); + MD->setBody(Body); + } else { + Body->Destroy(Context); + return DeclPtrTy(); + } + if (!IsInstantiation) + PopDeclContext(); + + // 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) { + LabelStmt *L = I->second; + + // Verify that we have no forward references left. If so, there was a goto + // or address of a label taken, but no definition of it. Label fwd + // definitions are indicated with a null substmt. + if (L->getSubStmt() != 0) + continue; + + // Emit error. + Diag(L->getIdentLoc(), diag::err_undeclared_label_use) << L->getName(); + + // At this point, we have gotos that use the bogus label. Stitch it into + // the function body so that they aren't leaked and that the AST is well + // formed. + if (Body == 0) { + // The whole function wasn't parsed correctly, just delete this. + L->Destroy(Context); + continue; + } + + // Otherwise, the body is valid: we want to stitch the label decl into the + // function somewhere so that it is properly owned and so that the goto + // has a valid target. Do this by creating a new compound stmt with the + // label in it. + + // Give the label a sub-statement. + L->setSubStmt(new (Context) NullStmt(L->getIdentLoc())); + + CompoundStmt *Compound = isa<CXXTryStmt>(Body) ? + cast<CXXTryStmt>(Body)->getTryBlock() : + cast<CompoundStmt>(Body); + std::vector<Stmt*> Elements(Compound->body_begin(), Compound->body_end()); + Elements.push_back(L); + Compound->setStmts(Context, &Elements[0], Elements.size()); + } + FunctionLabelMap.clear(); + + if (!Body) return D; + + // 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 (isa<CXXConstructorDecl>(dcl) && isa<CXXTryStmt>(Body)) + DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body)); + + return D; +} + +/// ImplicitlyDefineFunction - An undeclared identifier was used in a function +/// call, forming a call to an implicitly defined function (per C99 6.5.1p2). +NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, + IdentifierInfo &II, Scope *S) { + // Before we produce a declaration for an implicitly defined + // function, see whether there was a locally-scoped declaration of + // this name as a function or variable. If so, use that + // (non-visible) declaration, and complain about it. + llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos + = LocallyScopedExternalDecls.find(&II); + if (Pos != LocallyScopedExternalDecls.end()) { + Diag(Loc, diag::warn_use_out_of_scope_declaration) << Pos->second; + Diag(Pos->second->getLocation(), diag::note_previous_declaration); + return Pos->second; + } + + // Extension in C99. Legal in C90, but warn about it. + if (getLangOptions().C99) + Diag(Loc, diag::ext_implicit_function_decl) << &II; + else + Diag(Loc, diag::warn_implicit_function_decl) << &II; + + // FIXME: handle stuff like: + // void foo() { extern float X(); } + // void bar() { X(); } <-- implicit decl for X in another scope. + + // Set a Declarator for the implicit definition: int foo(); + const char *Dummy; + DeclSpec DS; + bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy); + Error = Error; // Silence warning. + assert(!Error && "Error setting up implicit decl!"); + Declarator D(DS, Declarator::BlockContext); + D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, SourceLocation(), 0, + 0, 0, false, SourceLocation(), + false, 0,0,0, Loc, D), + SourceLocation()); + D.SetIdentifier(&II, Loc); + + // Insert this function into translation-unit scope. + + DeclContext *PrevDC = CurContext; + CurContext = Context.getTranslationUnitDecl(); + + FunctionDecl *FD = + dyn_cast<FunctionDecl>(ActOnDeclarator(TUScope, D, DeclPtrTy()).getAs<Decl>()); + FD->setImplicit(); + + CurContext = PrevDC; + + AddKnownFunctionAttributes(FD); + + return FD; +} + +/// \brief Adds any function attributes that we know a priori based on +/// the declaration of this function. +/// +/// These attributes can apply both to implicitly-declared builtins +/// (like __builtin___printf_chk) or to library-declared functions +/// like NSLog or printf. +void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { + if (FD->isInvalidDecl()) + return; + + // If this is a built-in function, map its builtin attributes to + // actual attributes. + if (unsigned BuiltinID = FD->getBuiltinID(Context)) { + // Handle printf-formatting attributes. + unsigned FormatIdx; + bool HasVAListArg; + if (Context.BuiltinInfo.isPrintfLike(BuiltinID, FormatIdx, HasVAListArg)) { + if (!FD->getAttr<FormatAttr>()) + FD->addAttr(::new (Context) FormatAttr("printf", FormatIdx + 1, + FormatIdx + 2)); + } + + // Mark const if we don't care about errno and that is the only + // thing preventing the function from being const. This allows + // IRgen to use LLVM intrinsics for such functions. + if (!getLangOptions().MathErrno && + Context.BuiltinInfo.isConstWithoutErrno(BuiltinID)) { + if (!FD->getAttr<ConstAttr>()) + FD->addAttr(::new (Context) ConstAttr()); + } + } + + IdentifierInfo *Name = FD->getIdentifier(); + if (!Name) + return; + if ((!getLangOptions().CPlusPlus && + FD->getDeclContext()->isTranslationUnit()) || + (isa<LinkageSpecDecl>(FD->getDeclContext()) && + cast<LinkageSpecDecl>(FD->getDeclContext())->getLanguage() == + LinkageSpecDecl::lang_c)) { + // Okay: this could be a libc/libm/Objective-C function we know + // about. + } else + return; + + if (Name->isStr("NSLog") || Name->isStr("NSLogv")) { + if (const FormatAttr *Format = FD->getAttr<FormatAttr>()) { + // FIXME: We known better than our headers. + const_cast<FormatAttr *>(Format)->setType("printf"); + } else + FD->addAttr(::new (Context) FormatAttr("printf", 1, 2)); + } else if (Name->isStr("asprintf") || Name->isStr("vasprintf")) { + if (!FD->getAttr<FormatAttr>()) + FD->addAttr(::new (Context) FormatAttr("printf", 2, 3)); + } +} + +TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T) { + assert(D.getIdentifier() && "Wrong callback for declspec without declarator"); + assert(!T.isNull() && "GetTypeForDeclarator() returned null type"); + + // Scope manipulation handled by caller. + TypedefDecl *NewTD = TypedefDecl::Create(Context, CurContext, + D.getIdentifierLoc(), + D.getIdentifier(), + T); + + if (TagType *TT = dyn_cast<TagType>(T)) { + TagDecl *TD = TT->getDecl(); + + // If the TagDecl that the TypedefDecl points to is an anonymous decl + // keep track of the TypedefDecl. + if (!TD->getIdentifier() && !TD->getTypedefForAnonDecl()) + TD->setTypedefForAnonDecl(NewTD); + } + + if (D.isInvalidType()) + NewTD->setInvalidDecl(); + return NewTD; +} + + +/// \brief Determine whether a tag with a given kind is acceptable +/// as a redeclaration of the given tag declaration. +/// +/// \returns true if the new tag kind is acceptable, false otherwise. +bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, + TagDecl::TagKind NewTag, + SourceLocation NewTagLoc, + const IdentifierInfo &Name) { + // C++ [dcl.type.elab]p3: + // The class-key or enum keyword present in the + // elaborated-type-specifier shall agree in kind with the + // declaration to which the name in theelaborated-type-specifier + // refers. This rule also applies to the form of + // elaborated-type-specifier that declares a class-name or + // friend class since it can be construed as referring to the + // definition of the class. Thus, in any + // elaborated-type-specifier, the enum keyword shall be used to + // refer to an enumeration (7.2), the union class-keyshall be + // used to refer to a union (clause 9), and either the class or + // struct class-key shall be used to refer to a class (clause 9) + // declared using the class or struct class-key. + TagDecl::TagKind OldTag = Previous->getTagKind(); + if (OldTag == NewTag) + return true; + + if ((OldTag == TagDecl::TK_struct || OldTag == TagDecl::TK_class) && + (NewTag == TagDecl::TK_struct || NewTag == TagDecl::TK_class)) { + // Warn about the struct/class tag mismatch. + bool isTemplate = false; + if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Previous)) + isTemplate = Record->getDescribedClassTemplate(); + + Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) + << (NewTag == TagDecl::TK_class) + << isTemplate << &Name + << CodeModificationHint::CreateReplacement(SourceRange(NewTagLoc), + OldTag == TagDecl::TK_class? "class" : "struct"); + Diag(Previous->getLocation(), diag::note_previous_use); + return true; + } + return false; +} + +/// ActOnTag - This is invoked when we see 'struct foo' or 'struct {'. In the +/// former case, Name will be non-null. In the later case, Name will be null. +/// TagSpec indicates what kind of tag this is. TK indicates whether this is a +/// reference/declaration/definition of a tag. +Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, + SourceLocation KWLoc, const CXXScopeSpec &SS, + IdentifierInfo *Name, SourceLocation NameLoc, + AttributeList *Attr, AccessSpecifier AS, + bool &OwnedDecl) { + // If this is not a definition, it must have a name. + assert((Name != 0 || TK == TK_Definition) && + "Nameless record must be a definition!"); + + OwnedDecl = false; + TagDecl::TagKind Kind; + switch (TagSpec) { + default: assert(0 && "Unknown tag type!"); + case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break; + case DeclSpec::TST_union: Kind = TagDecl::TK_union; break; + case DeclSpec::TST_class: Kind = TagDecl::TK_class; break; + case DeclSpec::TST_enum: Kind = TagDecl::TK_enum; break; + } + + DeclContext *SearchDC = CurContext; + DeclContext *DC = CurContext; + NamedDecl *PrevDecl = 0; + + bool Invalid = false; + + if (Name && SS.isNotEmpty()) { + // We have a nested-name tag ('struct foo::bar'). + + // Check for invalid 'foo::'. + if (SS.isInvalid()) { + Name = 0; + goto CreateNewDecl; + } + + if (RequireCompleteDeclContext(SS)) + return DeclPtrTy::make((Decl *)0); + + DC = computeDeclContext(SS); + SearchDC = DC; + // Look-up name inside 'foo::'. + PrevDecl + = dyn_cast_or_null<TagDecl>( + LookupQualifiedName(DC, Name, LookupTagName, true).getAsDecl()); + + // A tag 'foo::bar' must already exist. + if (PrevDecl == 0) { + Diag(NameLoc, diag::err_not_tag_in_scope) << Name << SS.getRange(); + Name = 0; + Invalid = true; + goto CreateNewDecl; + } + } else if (Name) { + // If this is a named struct, check to see if there was a previous forward + // declaration or definition. + // FIXME: We're looking into outer scopes here, even when we + // shouldn't be. Doing so can result in ambiguities that we + // shouldn't be diagnosing. + LookupResult R = LookupName(S, Name, LookupTagName, + /*RedeclarationOnly=*/(TK != TK_Reference)); + if (R.isAmbiguous()) { + DiagnoseAmbiguousLookup(R, Name, NameLoc); + // FIXME: This is not best way to recover from case like: + // + // struct S s; + // + // causes needless "incomplete type" error later. + Name = 0; + PrevDecl = 0; + Invalid = true; + } + else + PrevDecl = R; + + if (!getLangOptions().CPlusPlus && TK != TK_Reference) { + // FIXME: This makes sure that we ignore the contexts associated + // with C structs, unions, and enums when looking for a matching + // tag declaration or definition. See the similar lookup tweak + // in Sema::LookupName; is there a better way to deal with this? + while (isa<RecordDecl>(SearchDC) || isa<EnumDecl>(SearchDC)) + SearchDC = SearchDC->getParent(); + } + } + + if (PrevDecl && PrevDecl->isTemplateParameter()) { + // Maybe we will complain about the shadowed template parameter. + DiagnoseTemplateParameterShadow(NameLoc, PrevDecl); + // Just pretend that we didn't see the previous declaration. + PrevDecl = 0; + } + + if (PrevDecl) { + // Check whether the previous declaration is usable. + (void)DiagnoseUseOfDecl(PrevDecl, NameLoc); + + if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) { + // If this is a use of a previous tag, or if the tag is already declared + // in the same scope (so that the definition/declaration completes or + // rementions the tag), reuse the decl. + if (TK == TK_Reference || isDeclInScope(PrevDecl, SearchDC, S)) { + // Make sure that this wasn't declared as an enum and now used as a + // struct or something similar. + if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, KWLoc, *Name)) { + bool SafeToContinue + = (PrevTagDecl->getTagKind() != TagDecl::TK_enum && + Kind != TagDecl::TK_enum); + if (SafeToContinue) + Diag(KWLoc, diag::err_use_with_wrong_tag) + << Name + << CodeModificationHint::CreateReplacement(SourceRange(KWLoc), + PrevTagDecl->getKindName()); + else + Diag(KWLoc, diag::err_use_with_wrong_tag) << Name; + Diag(PrevDecl->getLocation(), diag::note_previous_use); + + if (SafeToContinue) + Kind = PrevTagDecl->getTagKind(); + else { + // Recover by making this an anonymous redefinition. + Name = 0; + PrevDecl = 0; + Invalid = true; + } + } + + if (!Invalid) { + // If this is a use, just return the declaration we found. + + // FIXME: In the future, return a variant or some other clue + // for the consumer of this Decl to know it doesn't own it. + // For our current ASTs this shouldn't be a problem, but will + // need to be changed with DeclGroups. + if (TK == TK_Reference) + return DeclPtrTy::make(PrevDecl); + + // Diagnose attempts to redefine a tag. + if (TK == TK_Definition) { + if (TagDecl *Def = PrevTagDecl->getDefinition(Context)) { + Diag(NameLoc, diag::err_redefinition) << Name; + Diag(Def->getLocation(), diag::note_previous_definition); + // If this is a redefinition, recover by making this + // struct be anonymous, which will make any later + // references get the previous definition. + Name = 0; + PrevDecl = 0; + Invalid = true; + } else { + // If the type is currently being defined, complain + // about a nested redefinition. + TagType *Tag = cast<TagType>(Context.getTagDeclType(PrevTagDecl)); + if (Tag->isBeingDefined()) { + Diag(NameLoc, diag::err_nested_redefinition) << Name; + Diag(PrevTagDecl->getLocation(), + diag::note_previous_definition); + Name = 0; + PrevDecl = 0; + Invalid = true; + } + } + + // Okay, this is definition of a previously declared or referenced + // tag PrevDecl. We're going to create a new Decl for it. + } + } + // If we get here we have (another) forward declaration or we + // have a definition. Just create a new decl. + } else { + // If we get here, this is a definition of a new tag type in a nested + // scope, e.g. "struct foo; void bar() { struct foo; }", just create a + // new decl/type. We set PrevDecl to NULL so that the entities + // have distinct types. + PrevDecl = 0; + } + // If we get here, we're going to create a new Decl. If PrevDecl + // is non-NULL, it's a definition of the tag declared by + // PrevDecl. If it's NULL, we have a new definition. + } else { + // PrevDecl is a namespace, template, or anything else + // that lives in the IDNS_Tag identifier namespace. + if (isDeclInScope(PrevDecl, SearchDC, S)) { + // The tag name clashes with a namespace name, issue an error and + // recover by making this tag be anonymous. + Diag(NameLoc, diag::err_redefinition_different_kind) << Name; + Diag(PrevDecl->getLocation(), diag::note_previous_definition); + Name = 0; + PrevDecl = 0; + Invalid = true; + } else { + // The existing declaration isn't relevant to us; we're in a + // new scope, so clear out the previous declaration. + PrevDecl = 0; + } + } + } else if (TK == TK_Reference && SS.isEmpty() && Name && + (Kind != TagDecl::TK_enum || !getLangOptions().CPlusPlus)) { + // C++ [basic.scope.pdecl]p5: + // -- for an elaborated-type-specifier of the form + // + // class-key identifier + // + // if the elaborated-type-specifier is used in the + // decl-specifier-seq or parameter-declaration-clause of a + // function defined in namespace scope, the identifier is + // declared as a class-name in the namespace that contains + // the declaration; otherwise, except as a friend + // declaration, the identifier is declared in the smallest + // non-class, non-function-prototype scope that contains the + // declaration. + // + // C99 6.7.2.3p8 has a similar (but not identical!) provision for + // C structs and unions. + // + // GNU C also supports this behavior as part of its incomplete + // enum types extension, while GNU C++ does not. + // + // Find the context where we'll be declaring the tag. + // FIXME: We would like to maintain the current DeclContext as the + // lexical context, + while (SearchDC->isRecord()) + SearchDC = SearchDC->getParent(); + + // Find the scope where we'll be declaring the tag. + while (S->isClassScope() || + (getLangOptions().CPlusPlus && S->isFunctionPrototypeScope()) || + ((S->getFlags() & Scope::DeclScope) == 0) || + (S->getEntity() && + ((DeclContext *)S->getEntity())->isTransparentContext())) + S = S->getParent(); + } + +CreateNewDecl: + + // If there is an identifier, use the location of the identifier as the + // location of the decl, otherwise use the location of the struct/union + // keyword. + SourceLocation Loc = NameLoc.isValid() ? NameLoc : KWLoc; + + // Otherwise, create a new declaration. If there is a previous + // declaration of the same entity, the two will be linked via + // PrevDecl. + TagDecl *New; + + if (Kind == TagDecl::TK_enum) { + // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.: + // enum X { A, B, C } D; D should chain to X. + New = EnumDecl::Create(Context, SearchDC, Loc, Name, + cast_or_null<EnumDecl>(PrevDecl)); + // If this is an undefined enum, warn. + if (TK != TK_Definition && !Invalid) { + unsigned DK = getLangOptions().CPlusPlus? diag::err_forward_ref_enum + : diag::ext_forward_ref_enum; + Diag(Loc, DK); + } + } else { + // struct/union/class + + // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.: + // struct X { int A; } D; D should chain to X. + if (getLangOptions().CPlusPlus) + // FIXME: Look for a way to use RecordDecl for simple structs. + New = CXXRecordDecl::Create(Context, Kind, SearchDC, Loc, Name, + cast_or_null<CXXRecordDecl>(PrevDecl)); + else + New = RecordDecl::Create(Context, Kind, SearchDC, Loc, Name, + cast_or_null<RecordDecl>(PrevDecl)); + } + + if (Kind != TagDecl::TK_enum) { + // Handle #pragma pack: if the #pragma pack stack has non-default + // alignment, make up a packed attribute for this decl. These + // attributes are checked when the ASTContext lays out the + // structure. + // + // It is important for implementing the correct semantics that this + // happen here (in act on tag decl). The #pragma pack stack is + // maintained as a result of parser callbacks which can occur at + // many points during the parsing of a struct declaration (because + // the #pragma tokens are effectively skipped over during the + // parsing of the struct). + if (unsigned Alignment = getPragmaPackAlignment()) + New->addAttr(::new (Context) PackedAttr(Alignment * 8)); + } + + if (getLangOptions().CPlusPlus && SS.isEmpty() && Name && !Invalid) { + // C++ [dcl.typedef]p3: + // [...] Similarly, in a given scope, a class or enumeration + // shall not be declared with the same name as a typedef-name + // that is declared in that scope and refers to a type other + // than the class or enumeration itself. + LookupResult Lookup = LookupName(S, Name, LookupOrdinaryName, true); + TypedefDecl *PrevTypedef = 0; + if (Lookup.getKind() == LookupResult::Found) + PrevTypedef = dyn_cast<TypedefDecl>(Lookup.getAsDecl()); + + if (PrevTypedef && isDeclInScope(PrevTypedef, SearchDC, S) && + Context.getCanonicalType(Context.getTypeDeclType(PrevTypedef)) != + Context.getCanonicalType(Context.getTypeDeclType(New))) { + Diag(Loc, diag::err_tag_definition_of_typedef) + << Context.getTypeDeclType(New) + << PrevTypedef->getUnderlyingType(); + Diag(PrevTypedef->getLocation(), diag::note_previous_definition); + Invalid = true; + } + } + + if (Invalid) + New->setInvalidDecl(); + + if (Attr) + ProcessDeclAttributeList(New, Attr); + + // If we're declaring or defining a tag in function prototype scope + // in C, note that this type can only be used within the function. + if (Name && S->isFunctionPrototypeScope() && !getLangOptions().CPlusPlus) + Diag(Loc, diag::warn_decl_in_param_list) << Context.getTagDeclType(New); + + // Set the lexical context. If the tag has a C++ scope specifier, the + // lexical context will be different from the semantic context. + New->setLexicalDeclContext(CurContext); + + // Set the access specifier. + if (!Invalid) + SetMemberAccessSpecifier(New, PrevDecl, AS); + + if (TK == TK_Definition) + New->startDefinition(); + + // If this has an identifier, add it to the scope stack. + if (Name) { + S = getNonFieldDeclScope(S); + PushOnScopeChains(New, S); + } else { + CurContext->addDecl(Context, New); + } + + OwnedDecl = true; + return DeclPtrTy::make(New); +} + +void Sema::ActOnTagStartDefinition(Scope *S, DeclPtrTy TagD) { + AdjustDeclIfTemplate(TagD); + TagDecl *Tag = cast<TagDecl>(TagD.getAs<Decl>()); + + // Enter the tag context. + PushDeclContext(S, Tag); + + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Tag)) { + FieldCollector->StartClass(); + + if (Record->getIdentifier()) { + // C++ [class]p2: + // [...] The class-name is also inserted into the scope of the + // class itself; this is known as the injected-class-name. For + // purposes of access checking, the injected-class-name is treated + // as if it were a public member name. + CXXRecordDecl *InjectedClassName + = CXXRecordDecl::Create(Context, Record->getTagKind(), + CurContext, Record->getLocation(), + Record->getIdentifier(), Record); + InjectedClassName->setImplicit(); + InjectedClassName->setAccess(AS_public); + if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) + InjectedClassName->setDescribedClassTemplate(Template); + PushOnScopeChains(InjectedClassName, S); + assert(InjectedClassName->isInjectedClassName() && + "Broken injected-class-name"); + } + } +} + +void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD) { + AdjustDeclIfTemplate(TagD); + TagDecl *Tag = cast<TagDecl>(TagD.getAs<Decl>()); + + if (isa<CXXRecordDecl>(Tag)) + FieldCollector->FinishClass(); + + // Exit this scope of this tag's definition. + PopDeclContext(); + + // Notify the consumer that we've defined a tag. + Consumer.HandleTagDeclDefinition(Tag); +} + +// Note that FieldName may be null for anonymous bitfields. +bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, + QualType FieldTy, const Expr *BitWidth) { + + // C99 6.7.2.1p4 - verify the field type. + // C++ 9.6p3: A bit-field shall have integral or enumeration type. + if (!FieldTy->isDependentType() && !FieldTy->isIntegralType()) { + // Handle incomplete types with specific error. + if (RequireCompleteType(FieldLoc, FieldTy, diag::err_field_incomplete)) + return true; + if (FieldName) + return Diag(FieldLoc, diag::err_not_integral_type_bitfield) + << FieldName << FieldTy << BitWidth->getSourceRange(); + return Diag(FieldLoc, diag::err_not_integral_type_anon_bitfield) + << FieldTy << BitWidth->getSourceRange(); + } + + // If the bit-width is type- or value-dependent, don't try to check + // it now. + if (BitWidth->isValueDependent() || BitWidth->isTypeDependent()) + return false; + + llvm::APSInt Value; + if (VerifyIntegerConstantExpression(BitWidth, &Value)) + return true; + + // Zero-width bitfield is ok for anonymous field. + if (Value == 0 && FieldName) + return Diag(FieldLoc, diag::err_bitfield_has_zero_width) << FieldName; + + if (Value.isSigned() && Value.isNegative()) { + if (FieldName) + return Diag(FieldLoc, diag::err_bitfield_has_negative_width) + << FieldName << Value.toString(10); + return Diag(FieldLoc, diag::err_anon_bitfield_has_negative_width) + << Value.toString(10); + } + + if (!FieldTy->isDependentType()) { + uint64_t TypeSize = Context.getTypeSize(FieldTy); + if (Value.getZExtValue() > TypeSize) { + if (FieldName) + return Diag(FieldLoc, diag::err_bitfield_width_exceeds_type_size) + << FieldName << (unsigned)TypeSize; + return Diag(FieldLoc, diag::err_anon_bitfield_width_exceeds_type_size) + << (unsigned)TypeSize; + } + } + + return false; +} + +/// ActOnField - Each field of a struct/union/class is passed into this in order +/// to create a FieldDecl object for it. +Sema::DeclPtrTy Sema::ActOnField(Scope *S, DeclPtrTy TagD, + SourceLocation DeclStart, + Declarator &D, ExprTy *BitfieldWidth) { + FieldDecl *Res = HandleField(S, cast_or_null<RecordDecl>(TagD.getAs<Decl>()), + DeclStart, D, static_cast<Expr*>(BitfieldWidth), + AS_public); + return DeclPtrTy::make(Res); +} + +/// HandleField - Analyze a field of a C struct or a C++ data member. +/// +FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, + SourceLocation DeclStart, + Declarator &D, Expr *BitWidth, + AccessSpecifier AS) { + IdentifierInfo *II = D.getIdentifier(); + SourceLocation Loc = DeclStart; + if (II) Loc = D.getIdentifierLoc(); + + QualType T = GetTypeForDeclarator(D, S); + if (getLangOptions().CPlusPlus) + CheckExtraCXXDefaultArguments(D); + + DiagnoseFunctionSpecifiers(D); + + if (D.getDeclSpec().isThreadSpecified()) + Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + + NamedDecl *PrevDecl = LookupName(S, II, LookupMemberName, true); + if (PrevDecl && !isDeclInScope(PrevDecl, Record, S)) + PrevDecl = 0; + + FieldDecl *NewFD + = CheckFieldDecl(II, T, Record, Loc, + D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable, + BitWidth, AS, PrevDecl, &D); + if (NewFD->isInvalidDecl() && PrevDecl) { + // Don't introduce NewFD into scope; there's already something + // with the same name in the same scope. + } else if (II) { + PushOnScopeChains(NewFD, S); + } else + Record->addDecl(Context, NewFD); + + return NewFD; +} + +/// \brief Build a new FieldDecl and check its well-formedness. +/// +/// This routine builds a new FieldDecl given the fields name, type, +/// record, etc. \p PrevDecl should refer to any previous declaration +/// with the same name and in the same scope as the field to be +/// created. +/// +/// \returns a new FieldDecl. +/// +/// \todo The Declarator argument is a hack. It will be removed once +FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, + RecordDecl *Record, SourceLocation Loc, + bool Mutable, Expr *BitWidth, + AccessSpecifier AS, NamedDecl *PrevDecl, + Declarator *D) { + IdentifierInfo *II = Name.getAsIdentifierInfo(); + bool InvalidDecl = false; + if (D) InvalidDecl = D->isInvalidType(); + + // If we receive a broken type, recover by assuming 'int' and + // marking this declaration as invalid. + if (T.isNull()) { + InvalidDecl = true; + T = Context.IntTy; + } + + // C99 6.7.2.1p8: A member of a structure or union may have any type other + // than a variably modified type. + if (T->isVariablyModifiedType()) { + bool SizeIsNegative; + QualType FixedTy = TryToFixInvalidVariablyModifiedType(T, Context, + SizeIsNegative); + if (!FixedTy.isNull()) { + Diag(Loc, diag::warn_illegal_constant_array_size); + T = FixedTy; + } else { + if (SizeIsNegative) + Diag(Loc, diag::err_typecheck_negative_array_size); + else + Diag(Loc, diag::err_typecheck_field_variable_size); + T = Context.IntTy; + InvalidDecl = true; + } + } + + // Fields can not have abstract class types + if (RequireNonAbstractType(Loc, T, diag::err_abstract_type_in_decl, + AbstractFieldType)) + InvalidDecl = true; + + // If this is declared as a bit-field, check the bit-field. + if (BitWidth && VerifyBitField(Loc, II, T, BitWidth)) { + InvalidDecl = true; + DeleteExpr(BitWidth); + BitWidth = 0; + } + + FieldDecl *NewFD = FieldDecl::Create(Context, Record, Loc, II, T, BitWidth, + Mutable); + if (InvalidDecl) + NewFD->setInvalidDecl(); + + if (PrevDecl && !isa<TagDecl>(PrevDecl)) { + Diag(Loc, diag::err_duplicate_member) << II; + Diag(PrevDecl->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + } + + if (getLangOptions().CPlusPlus && !T->isPODType()) + cast<CXXRecordDecl>(Record)->setPOD(false); + + // FIXME: We need to pass in the attributes given an AST + // representation, not a parser representation. + if (D) + ProcessDeclAttributes(NewFD, *D); + + if (T.isObjCGCWeak()) + Diag(Loc, diag::warn_attribute_weak_on_field); + + NewFD->setAccess(AS); + + // C++ [dcl.init.aggr]p1: + // An aggregate is an array or a class (clause 9) with [...] no + // private or protected non-static data members (clause 11). + // A POD must be an aggregate. + if (getLangOptions().CPlusPlus && + (AS == AS_private || AS == AS_protected)) { + CXXRecordDecl *CXXRecord = cast<CXXRecordDecl>(Record); + CXXRecord->setAggregate(false); + CXXRecord->setPOD(false); + } + + return NewFD; +} + +/// TranslateIvarVisibility - Translate visibility from a token ID to an +/// AST enum value. +static ObjCIvarDecl::AccessControl +TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) { + switch (ivarVisibility) { + default: assert(0 && "Unknown visitibility kind"); + case tok::objc_private: return ObjCIvarDecl::Private; + case tok::objc_public: return ObjCIvarDecl::Public; + case tok::objc_protected: return ObjCIvarDecl::Protected; + case tok::objc_package: return ObjCIvarDecl::Package; + } +} + +/// ActOnIvar - Each ivar field of an objective-c class is passed into this +/// in order to create an IvarDecl object for it. +Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, + SourceLocation DeclStart, + Declarator &D, ExprTy *BitfieldWidth, + tok::ObjCKeywordKind Visibility) { + + IdentifierInfo *II = D.getIdentifier(); + Expr *BitWidth = (Expr*)BitfieldWidth; + SourceLocation Loc = DeclStart; + if (II) Loc = D.getIdentifierLoc(); + + // FIXME: Unnamed fields can be handled in various different ways, for + // example, unnamed unions inject all members into the struct namespace! + + QualType T = GetTypeForDeclarator(D, S); + + if (BitWidth) { + // 6.7.2.1p3, 6.7.2.1p4 + if (VerifyBitField(Loc, II, T, BitWidth)) { + D.setInvalidType(); + DeleteExpr(BitWidth); + BitWidth = 0; + } + } else { + // Not a bitfield. + + // validate II. + + } + + // C99 6.7.2.1p8: A member of a structure or union may have any type other + // than a variably modified type. + if (T->isVariablyModifiedType()) { + Diag(Loc, diag::err_typecheck_ivar_variable_size); + D.setInvalidType(); + } + + // Get the visibility (access control) for this ivar. + ObjCIvarDecl::AccessControl ac = + Visibility != tok::objc_not_keyword ? TranslateIvarVisibility(Visibility) + : ObjCIvarDecl::None; + + // Construct the decl. + ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context, CurContext, Loc, II, T,ac, + (Expr *)BitfieldWidth); + + if (II) { + NamedDecl *PrevDecl = LookupName(S, II, LookupMemberName, true); + if (PrevDecl && isDeclInScope(PrevDecl, CurContext, S) + && !isa<TagDecl>(PrevDecl)) { + Diag(Loc, diag::err_duplicate_member) << II; + Diag(PrevDecl->getLocation(), diag::note_previous_declaration); + NewID->setInvalidDecl(); + } + } + + // Process attributes attached to the ivar. + ProcessDeclAttributes(NewID, D); + + if (D.isInvalidType()) + NewID->setInvalidDecl(); + + if (II) { + // FIXME: When interfaces are DeclContexts, we'll need to add + // these to the interface. + S->AddDecl(DeclPtrTy::make(NewID)); + IdResolver.AddDecl(NewID); + } + + return DeclPtrTy::make(NewID); +} + +void Sema::ActOnFields(Scope* S, + SourceLocation RecLoc, DeclPtrTy RecDecl, + DeclPtrTy *Fields, unsigned NumFields, + SourceLocation LBrac, SourceLocation RBrac, + AttributeList *Attr) { + Decl *EnclosingDecl = RecDecl.getAs<Decl>(); + assert(EnclosingDecl && "missing record or interface decl"); + + // If the decl this is being inserted into is invalid, then it may be a + // redeclaration or some other bogus case. Don't try to add fields to it. + if (EnclosingDecl->isInvalidDecl()) { + // FIXME: Deallocate fields? + return; + } + + + // Verify that all the fields are okay. + unsigned NumNamedMembers = 0; + llvm::SmallVector<FieldDecl*, 32> RecFields; + + RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl); + for (unsigned i = 0; i != NumFields; ++i) { + FieldDecl *FD = cast<FieldDecl>(Fields[i].getAs<Decl>()); + + // Get the type for the field. + Type *FDTy = FD->getType().getTypePtr(); + + if (!FD->isAnonymousStructOrUnion()) { + // Remember all fields written by the user. + RecFields.push_back(FD); + } + + // If the field is already invalid for some reason, don't emit more + // diagnostics about it. + if (FD->isInvalidDecl()) + continue; + + // C99 6.7.2.1p2: + // A structure or union shall not contain a member with + // incomplete or function type (hence, a structure shall not + // contain an instance of itself, but may contain a pointer to + // an instance of itself), except that the last member of a + // structure with more than one named member may have incomplete + // array type; such a structure (and any union containing, + // possibly recursively, a member that is such a structure) + // shall not be a member of a structure or an element of an + // array. + if (FDTy->isFunctionType()) { + // Field declared as a function. + Diag(FD->getLocation(), diag::err_field_declared_as_function) + << FD->getDeclName(); + FD->setInvalidDecl(); + EnclosingDecl->setInvalidDecl(); + continue; + } else if (FDTy->isIncompleteArrayType() && i == NumFields - 1 && + Record && Record->isStruct()) { + // Flexible array member. + if (NumNamedMembers < 1) { + Diag(FD->getLocation(), diag::err_flexible_array_empty_struct) + << FD->getDeclName(); + FD->setInvalidDecl(); + EnclosingDecl->setInvalidDecl(); + continue; + } + // Okay, we have a legal flexible array member at the end of the struct. + if (Record) + Record->setHasFlexibleArrayMember(true); + } else if (!FDTy->isDependentType() && + RequireCompleteType(FD->getLocation(), FD->getType(), + diag::err_field_incomplete)) { + // Incomplete type + FD->setInvalidDecl(); + EnclosingDecl->setInvalidDecl(); + continue; + } else if (const RecordType *FDTTy = FDTy->getAsRecordType()) { + if (FDTTy->getDecl()->hasFlexibleArrayMember()) { + // If this is a member of a union, then entire union becomes "flexible". + if (Record && Record->isUnion()) { + Record->setHasFlexibleArrayMember(true); + } else { + // If this is a struct/class and this is not the last element, reject + // it. Note that GCC supports variable sized arrays in the middle of + // structures. + if (i != NumFields-1) + Diag(FD->getLocation(), diag::ext_variable_sized_type_in_struct) + << FD->getDeclName() << FD->getType(); + else { + // We support flexible arrays at the end of structs in + // other structs as an extension. + Diag(FD->getLocation(), diag::ext_flexible_array_in_struct) + << FD->getDeclName(); + if (Record) + Record->setHasFlexibleArrayMember(true); + } + } + } + } else if (FDTy->isObjCInterfaceType()) { + /// A field cannot be an Objective-c object + Diag(FD->getLocation(), diag::err_statically_allocated_object); + FD->setInvalidDecl(); + EnclosingDecl->setInvalidDecl(); + continue; + } + // Keep track of the number of named members. + if (FD->getIdentifier()) + ++NumNamedMembers; + } + + // Okay, we successfully defined 'Record'. + if (Record) { + Record->completeDefinition(Context); + } else { + ObjCIvarDecl **ClsFields = + reinterpret_cast<ObjCIvarDecl**>(RecFields.data()); + if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(EnclosingDecl)) { + ID->setIVarList(ClsFields, RecFields.size(), Context); + ID->setLocEnd(RBrac); + + // 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(Context, II); + if (prevIvar) { + Diag(Ivar->getLocation(), diag::err_duplicate_member) << II; + Diag(prevIvar->getLocation(), diag::note_previous_declaration); + } + } + } + } + } else if (ObjCImplementationDecl *IMPDecl = + dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) { + assert(IMPDecl && "ActOnFields - missing ObjCImplementationDecl"); + for (unsigned I = 0, N = RecFields.size(); I != N; ++I) { + // FIXME: Set the DeclContext correctly when we build the + // declarations. + ClsFields[I]->setLexicalDeclContext(IMPDecl); + IMPDecl->addDecl(Context, ClsFields[I]); + } + CheckImplementationIvars(IMPDecl, ClsFields, RecFields.size(), RBrac); + } + } + + if (Attr) + ProcessDeclAttributeList(Record, Attr); +} + +EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, + EnumConstantDecl *LastEnumConst, + SourceLocation IdLoc, + IdentifierInfo *Id, + ExprArg val) { + Expr *Val = (Expr *)val.get(); + + llvm::APSInt EnumVal(32); + QualType EltTy; + if (Val && !Val->isTypeDependent()) { + // Make sure to promote the operand type to int. + UsualUnaryConversions(Val); + if (Val != val.get()) { + val.release(); + val = Val; + } + + // C99 6.7.2.2p2: Make sure we have an integer constant expression. + SourceLocation ExpLoc; + if (!Val->isValueDependent() && + VerifyIntegerConstantExpression(Val, &EnumVal)) { + Val = 0; + } else { + EltTy = Val->getType(); + } + } + + if (!Val) { + if (LastEnumConst) { + // Assign the last value + 1. + EnumVal = LastEnumConst->getInitVal(); + ++EnumVal; + + // Check for overflow on increment. + if (EnumVal < LastEnumConst->getInitVal()) + Diag(IdLoc, diag::warn_enum_value_overflow); + + EltTy = LastEnumConst->getType(); + } else { + // First value, set to zero. + EltTy = Context.IntTy; + EnumVal.zextOrTrunc(static_cast<uint32_t>(Context.getTypeSize(EltTy))); + } + } + + val.release(); + return EnumConstantDecl::Create(Context, Enum, IdLoc, Id, EltTy, + Val, EnumVal); +} + + +Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl, + DeclPtrTy lastEnumConst, + SourceLocation IdLoc, + IdentifierInfo *Id, + SourceLocation EqualLoc, ExprTy *val) { + EnumDecl *TheEnumDecl = cast<EnumDecl>(theEnumDecl.getAs<Decl>()); + EnumConstantDecl *LastEnumConst = + cast_or_null<EnumConstantDecl>(lastEnumConst.getAs<Decl>()); + Expr *Val = static_cast<Expr*>(val); + + // The scope passed in may not be a decl scope. Zip up the scope tree until + // we find one that is. + S = getNonFieldDeclScope(S); + + // Verify that there isn't already something declared with this name in this + // scope. + NamedDecl *PrevDecl = LookupName(S, Id, LookupOrdinaryName); + if (PrevDecl && PrevDecl->isTemplateParameter()) { + // Maybe we will complain about the shadowed template parameter. + DiagnoseTemplateParameterShadow(IdLoc, PrevDecl); + // Just pretend that we didn't see the previous declaration. + PrevDecl = 0; + } + + if (PrevDecl) { + // When in C++, we may get a TagDecl with the same name; in this case the + // enum constant will 'hide' the tag. + assert((getLangOptions().CPlusPlus || !isa<TagDecl>(PrevDecl)) && + "Received TagDecl when not in C++!"); + if (!isa<TagDecl>(PrevDecl) && isDeclInScope(PrevDecl, CurContext, S)) { + if (isa<EnumConstantDecl>(PrevDecl)) + Diag(IdLoc, diag::err_redefinition_of_enumerator) << Id; + else + Diag(IdLoc, diag::err_redefinition) << Id; + Diag(PrevDecl->getLocation(), diag::note_previous_definition); + if (Val) Val->Destroy(Context); + return DeclPtrTy(); + } + } + + EnumConstantDecl *New = CheckEnumConstant(TheEnumDecl, LastEnumConst, + IdLoc, Id, Owned(Val)); + + // Register this decl in the current scope stack. + if (New) + PushOnScopeChains(New, S); + + return DeclPtrTy::make(New); +} + +void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, + SourceLocation RBraceLoc, DeclPtrTy EnumDeclX, + DeclPtrTy *Elements, unsigned NumElements) { + EnumDecl *Enum = cast<EnumDecl>(EnumDeclX.getAs<Decl>()); + QualType EnumType = Context.getTypeDeclType(Enum); + + // TODO: If the result value doesn't fit in an int, it must be a long or long + // long value. ISO C does not support this, but GCC does as an extension, + // emit a warning. + unsigned IntWidth = Context.Target.getIntWidth(); + + // Verify that all the values are okay, compute the size of the values, and + // reverse the list. + unsigned NumNegativeBits = 0; + unsigned NumPositiveBits = 0; + + // Keep track of whether all elements have type int. + bool AllElementsInt = true; + + for (unsigned i = 0; i != NumElements; ++i) { + EnumConstantDecl *ECD = + cast_or_null<EnumConstantDecl>(Elements[i].getAs<Decl>()); + if (!ECD) continue; // Already issued a diagnostic. + + // If the enum value doesn't fit in an int, emit an extension warning. + const llvm::APSInt &InitVal = ECD->getInitVal(); + assert(InitVal.getBitWidth() >= IntWidth && + "Should have promoted value to int"); + if (InitVal.getBitWidth() > IntWidth) { + llvm::APSInt V(InitVal); + V.trunc(IntWidth); + V.extend(InitVal.getBitWidth()); + if (V != InitVal) + Diag(ECD->getLocation(), diag::ext_enum_value_not_int) + << InitVal.toString(10); + } + + // Keep track of the size of positive and negative values. + if (InitVal.isUnsigned() || InitVal.isNonNegative()) + NumPositiveBits = std::max(NumPositiveBits, + (unsigned)InitVal.getActiveBits()); + else + NumNegativeBits = std::max(NumNegativeBits, + (unsigned)InitVal.getMinSignedBits()); + + // Keep track of whether every enum element has type int (very commmon). + if (AllElementsInt) + AllElementsInt = ECD->getType() == Context.IntTy; + } + + // Figure out the type that should be used for this enum. + // FIXME: Support attribute(packed) on enums and -fshort-enums. + QualType BestType; + unsigned BestWidth; + + if (NumNegativeBits) { + // If there is a negative value, figure out the smallest integer type (of + // int/long/longlong) that fits. + if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) { + BestType = Context.IntTy; + BestWidth = IntWidth; + } else { + BestWidth = Context.Target.getLongWidth(); + + if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth) + BestType = Context.LongTy; + else { + BestWidth = Context.Target.getLongLongWidth(); + + if (NumNegativeBits > BestWidth || NumPositiveBits >= BestWidth) + Diag(Enum->getLocation(), diag::warn_enum_too_large); + BestType = Context.LongLongTy; + } + } + } else { + // If there is no negative value, figure out which of uint, ulong, ulonglong + // fits. + if (NumPositiveBits <= IntWidth) { + BestType = Context.UnsignedIntTy; + BestWidth = IntWidth; + } else if (NumPositiveBits <= + (BestWidth = Context.Target.getLongWidth())) { + BestType = Context.UnsignedLongTy; + } else { + BestWidth = Context.Target.getLongLongWidth(); + assert(NumPositiveBits <= BestWidth && + "How could an initializer get larger than ULL?"); + BestType = Context.UnsignedLongLongTy; + } + } + + // Loop over all of the enumerator constants, changing their types to match + // the type of the enum if needed. + for (unsigned i = 0; i != NumElements; ++i) { + EnumConstantDecl *ECD = + cast_or_null<EnumConstantDecl>(Elements[i].getAs<Decl>()); + if (!ECD) continue; // Already issued a diagnostic. + + // Standard C says the enumerators have int type, but we allow, as an + // extension, the enumerators to be larger than int size. If each + // enumerator value fits in an int, type it as an int, otherwise type it the + // same as the enumerator decl itself. This means that in "enum { X = 1U }" + // that X has type 'int', not 'unsigned'. + if (ECD->getType() == Context.IntTy) { + // Make sure the init value is signed. + llvm::APSInt IV = ECD->getInitVal(); + IV.setIsSigned(true); + ECD->setInitVal(IV); + + if (getLangOptions().CPlusPlus) + // C++ [dcl.enum]p4: Following the closing brace of an + // enum-specifier, each enumerator has the type of its + // enumeration. + ECD->setType(EnumType); + continue; // Already int type. + } + + // Determine whether the value fits into an int. + llvm::APSInt InitVal = ECD->getInitVal(); + bool FitsInInt; + if (InitVal.isUnsigned() || !InitVal.isNegative()) + FitsInInt = InitVal.getActiveBits() < IntWidth; + else + FitsInInt = InitVal.getMinSignedBits() <= IntWidth; + + // If it fits into an integer type, force it. Otherwise force it to match + // the enum decl type. + QualType NewTy; + unsigned NewWidth; + bool NewSign; + if (FitsInInt) { + NewTy = Context.IntTy; + NewWidth = IntWidth; + NewSign = true; + } else if (ECD->getType() == BestType) { + // Already the right type! + if (getLangOptions().CPlusPlus) + // C++ [dcl.enum]p4: Following the closing brace of an + // enum-specifier, each enumerator has the type of its + // enumeration. + ECD->setType(EnumType); + continue; + } else { + NewTy = BestType; + NewWidth = BestWidth; + NewSign = BestType->isSignedIntegerType(); + } + + // Adjust the APSInt value. + InitVal.extOrTrunc(NewWidth); + InitVal.setIsSigned(NewSign); + ECD->setInitVal(InitVal); + + // Adjust the Expr initializer and type. + if (ECD->getInitExpr()) + ECD->setInitExpr(new (Context) ImplicitCastExpr(NewTy, ECD->getInitExpr(), + /*isLvalue=*/false)); + if (getLangOptions().CPlusPlus) + // C++ [dcl.enum]p4: Following the closing brace of an + // enum-specifier, each enumerator has the type of its + // enumeration. + ECD->setType(EnumType); + else + ECD->setType(NewTy); + } + + Enum->completeDefinition(Context, BestType); +} + +Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc, + ExprArg expr) { + StringLiteral *AsmString = cast<StringLiteral>(expr.takeAs<Expr>()); + + FileScopeAsmDecl *New = FileScopeAsmDecl::Create(Context, CurContext, + Loc, AsmString); + CurContext->addDecl(Context, New); + return DeclPtrTy::make(New); +} diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp new file mode 100644 index 0000000..99b4d77 --- /dev/null +++ b/lib/Sema/SemaDeclAttr.cpp @@ -0,0 +1,1803 @@ +//===--- SemaDeclAttr.cpp - Declaration Attribute Handling ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements decl-related attribute processing. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Expr.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Parse/DeclSpec.h" +#include <llvm/ADT/StringExtras.h> +using namespace clang; + +//===----------------------------------------------------------------------===// +// Helper functions +//===----------------------------------------------------------------------===// + +static const FunctionType *getFunctionType(Decl *d, bool blocksToo = true) { + QualType Ty; + if (ValueDecl *decl = dyn_cast<ValueDecl>(d)) + Ty = decl->getType(); + else if (FieldDecl *decl = dyn_cast<FieldDecl>(d)) + Ty = decl->getType(); + else if (TypedefDecl* decl = dyn_cast<TypedefDecl>(d)) + Ty = decl->getUnderlyingType(); + else + return 0; + + if (Ty->isFunctionPointerType()) + Ty = Ty->getAsPointerType()->getPointeeType(); + else if (blocksToo && Ty->isBlockPointerType()) + Ty = Ty->getAsBlockPointerType()->getPointeeType(); + + return Ty->getAsFunctionType(); +} + +// FIXME: We should provide an abstraction around a method or function +// to provide the following bits of information. + +/// isFunctionOrMethod - Return true if the given decl has function +/// type (function or function-typed variable) or an Objective-C +/// method. +static bool isFunctionOrMethod(Decl *d) { + return getFunctionType(d, false) || isa<ObjCMethodDecl>(d); +} + +/// isFunctionOrMethodOrBlock - Return true if the given decl has function +/// type (function or function-typed variable) or an Objective-C +/// method or a block. +static bool isFunctionOrMethodOrBlock(Decl *d) { + if (isFunctionOrMethod(d)) + return true; + // check for block is more involved. + if (const VarDecl *V = dyn_cast<VarDecl>(d)) { + QualType Ty = V->getType(); + return Ty->isBlockPointerType(); + } + return isa<BlockDecl>(d); +} + +/// hasFunctionProto - Return true if the given decl has a argument +/// information. This decl should have already passed +/// isFunctionOrMethod or isFunctionOrMethodOrBlock. +static bool hasFunctionProto(Decl *d) { + if (const FunctionType *FnTy = getFunctionType(d)) + return isa<FunctionProtoType>(FnTy); + else { + assert(isa<ObjCMethodDecl>(d) || isa<BlockDecl>(d)); + return true; + } +} + +/// getFunctionOrMethodNumArgs - Return number of function or method +/// arguments. It is an error to call this on a K&R function (use +/// hasFunctionProto first). +static unsigned getFunctionOrMethodNumArgs(Decl *d) { + if (const FunctionType *FnTy = getFunctionType(d)) + return cast<FunctionProtoType>(FnTy)->getNumArgs(); + if (const BlockDecl *BD = dyn_cast<BlockDecl>(d)) + return BD->getNumParams(); + return cast<ObjCMethodDecl>(d)->param_size(); +} + +static QualType getFunctionOrMethodArgType(Decl *d, unsigned Idx) { + if (const FunctionType *FnTy = getFunctionType(d)) + return cast<FunctionProtoType>(FnTy)->getArgType(Idx); + if (const BlockDecl *BD = dyn_cast<BlockDecl>(d)) + return BD->getParamDecl(Idx)->getType(); + + return cast<ObjCMethodDecl>(d)->param_begin()[Idx]->getType(); +} + +static QualType getFunctionOrMethodResultType(Decl *d) { + if (const FunctionType *FnTy = getFunctionType(d)) + return cast<FunctionProtoType>(FnTy)->getResultType(); + return cast<ObjCMethodDecl>(d)->getResultType(); +} + +static bool isFunctionOrMethodVariadic(Decl *d) { + if (const FunctionType *FnTy = getFunctionType(d)) { + const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy); + return proto->isVariadic(); + } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(d)) + return BD->IsVariadic(); + else { + return cast<ObjCMethodDecl>(d)->isVariadic(); + } +} + +static inline bool isNSStringType(QualType T, ASTContext &Ctx) { + const PointerType *PT = T->getAsPointerType(); + if (!PT) + return false; + + const ObjCInterfaceType *ClsT =PT->getPointeeType()->getAsObjCInterfaceType(); + if (!ClsT) + return false; + + IdentifierInfo* ClsName = ClsT->getDecl()->getIdentifier(); + + // FIXME: Should we walk the chain of classes? + return ClsName == &Ctx.Idents.get("NSString") || + ClsName == &Ctx.Idents.get("NSMutableString"); +} + +static inline bool isCFStringType(QualType T, ASTContext &Ctx) { + const PointerType *PT = T->getAsPointerType(); + if (!PT) + return false; + + const RecordType *RT = PT->getPointeeType()->getAsRecordType(); + if (!RT) + return false; + + const RecordDecl *RD = RT->getDecl(); + if (RD->getTagKind() != TagDecl::TK_struct) + return false; + + return RD->getIdentifier() == &Ctx.Idents.get("__CFString"); +} + +//===----------------------------------------------------------------------===// +// Attribute Implementations +//===----------------------------------------------------------------------===// + +// FIXME: All this manual attribute parsing code is gross. At the +// least add some helper functions to check most argument patterns (# +// and types of args). + +static void HandleExtVectorTypeAttr(Decl *d, const AttributeList &Attr, + Sema &S) { + TypedefDecl *tDecl = dyn_cast<TypedefDecl>(d); + if (tDecl == 0) { + S.Diag(Attr.getLoc(), diag::err_typecheck_ext_vector_not_typedef); + return; + } + + QualType curType = tDecl->getUnderlyingType(); + // check the attribute arguments. + if (Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0)); + llvm::APSInt vecSize(32); + if (!sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) + << "ext_vector_type" << sizeExpr->getSourceRange(); + return; + } + // unlike gcc's vector_size attribute, we do not allow vectors to be defined + // in conjunction with complex types (pointers, arrays, functions, etc.). + if (!curType->isIntegerType() && !curType->isRealFloatingType()) { + S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << curType; + return; + } + // unlike gcc's vector_size attribute, the size is specified as the + // number of elements, not the number of bytes. + unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue()); + + if (vectorSize == 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_zero_size) + << sizeExpr->getSourceRange(); + return; + } + // Instantiate/Install the vector type, the number of elements is > 0. + tDecl->setUnderlyingType(S.Context.getExtVectorType(curType, vectorSize)); + // Remember this typedef decl, we will need it later for diagnostics. + S.ExtVectorDecls.push_back(tDecl); +} + + +/// HandleVectorSizeAttribute - this attribute is only applicable to +/// integral and float scalars, although arrays, pointers, and function +/// return values are allowed in conjunction with this construct. Aggregates +/// with this attribute are invalid, even if they are of the same size as a +/// corresponding scalar. +/// The raw attribute should contain precisely 1 argument, the vector size +/// for the variable, measured in bytes. If curType and rawAttr are well +/// formed, this routine will return a new vector type. +static void HandleVectorSizeAttr(Decl *D, const AttributeList &Attr, Sema &S) { + QualType CurType; + if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) + CurType = VD->getType(); + else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) + CurType = TD->getUnderlyingType(); + else { + S.Diag(D->getLocation(), diag::err_attr_wrong_decl) + << "vector_size" << SourceRange(Attr.getLoc(), Attr.getLoc()); + return; + } + + // Check the attribute arugments. + if (Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0)); + llvm::APSInt vecSize(32); + if (!sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) + << "vector_size" << sizeExpr->getSourceRange(); + return; + } + // navigate to the base type - we need to provide for vector pointers, + // vector arrays, and functions returning vectors. + if (CurType->isPointerType() || CurType->isArrayType() || + CurType->isFunctionType()) { + S.Diag(Attr.getLoc(), diag::err_unsupported_vector_size) << CurType; + return; + /* FIXME: rebuild the type from the inside out, vectorizing the inner type. + do { + if (PointerType *PT = dyn_cast<PointerType>(canonType)) + canonType = PT->getPointeeType().getTypePtr(); + else if (ArrayType *AT = dyn_cast<ArrayType>(canonType)) + canonType = AT->getElementType().getTypePtr(); + else if (FunctionType *FT = dyn_cast<FunctionType>(canonType)) + canonType = FT->getResultType().getTypePtr(); + } while (canonType->isPointerType() || canonType->isArrayType() || + canonType->isFunctionType()); + */ + } + // the base type must be integer or float, and can't already be a vector. + if (CurType->isVectorType() || + (!CurType->isIntegerType() && !CurType->isRealFloatingType())) { + S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << CurType; + return; + } + unsigned typeSize = static_cast<unsigned>(S.Context.getTypeSize(CurType)); + // vecSize is specified in bytes - convert to bits. + unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue() * 8); + + // the vector size needs to be an integral multiple of the type size. + if (vectorSize % typeSize) { + S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size) + << sizeExpr->getSourceRange(); + return; + } + if (vectorSize == 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_zero_size) + << sizeExpr->getSourceRange(); + return; + } + + // Success! Instantiate the vector type, the number of elements is > 0, and + // not required to be a power of 2, unlike GCC. + CurType = S.Context.getVectorType(CurType, vectorSize/typeSize); + + if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) + VD->setType(CurType); + else + cast<TypedefDecl>(D)->setUnderlyingType(CurType); +} + +static void HandlePackedAttr(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; + } + + if (TagDecl *TD = dyn_cast<TagDecl>(d)) + TD->addAttr(::new (S.Context) PackedAttr(1)); + else if (FieldDecl *FD = dyn_cast<FieldDecl>(d)) { + // If the alignment is less than or equal to 8 bits, the packed attribute + // has no effect. + if (!FD->getType()->isIncompleteType() && + S.Context.getTypeAlign(FD->getType()) <= 8) + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type) + << Attr.getName() << FD->getType(); + else + FD->addAttr(::new (S.Context) PackedAttr(1)); + } else + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); +} + +static void HandleIBOutletAttr(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)) + d->addAttr(::new (S.Context) IBOutletAttr()); + else + S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet); +} + +static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { + // GCC ignores the nonnull attribute on K&R style function + // prototypes, so we ignore it as well + if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 0 /*function*/; + return; + } + + unsigned NumArgs = getFunctionOrMethodNumArgs(d); + + // The nonnull attribute only applies to pointers. + llvm::SmallVector<unsigned, 10> NonNullArgs; + + for (AttributeList::arg_iterator I=Attr.arg_begin(), + E=Attr.arg_end(); I!=E; ++I) { + + + // The argument must be an integer constant expression. + Expr *Ex = static_cast<Expr *>(*I); + llvm::APSInt ArgNum(32); + if (!Ex->isIntegerConstantExpr(ArgNum, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) + << "nonnull" << Ex->getSourceRange(); + return; + } + + unsigned x = (unsigned) ArgNum.getZExtValue(); + + if (x < 1 || x > NumArgs) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) + << "nonnull" << I.getArgNum() << Ex->getSourceRange(); + return; + } + + --x; + + // Is the function argument a pointer type? + QualType T = getFunctionOrMethodArgType(d, x); + if (!T->isPointerType() && !T->isBlockPointerType()) { + // FIXME: Should also highlight argument in decl. + S.Diag(Attr.getLoc(), diag::err_nonnull_pointers_only) + << "nonnull" << Ex->getSourceRange(); + continue; + } + + NonNullArgs.push_back(x); + } + + // If no arguments were specified to __attribute__((nonnull)) then all + // pointer arguments have a nonnull attribute. + if (NonNullArgs.empty()) { + for (unsigned I = 0, E = getFunctionOrMethodNumArgs(d); I != E; ++I) { + QualType T = getFunctionOrMethodArgType(d, I); + if (T->isPointerType() || T->isBlockPointerType()) + NonNullArgs.push_back(I); + } + + if (NonNullArgs.empty()) { + S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_no_pointers); + return; + } + } + + unsigned* start = &NonNullArgs[0]; + unsigned size = NonNullArgs.size(); + std::sort(start, start + size); + d->addAttr(::new (S.Context) NonNullAttr(start, size)); +} + +static void HandleAliasAttr(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; + } + + 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) + << "alias" << 1; + return; + } + + const char *Alias = Str->getStrData(); + unsigned AliasLen = Str->getByteLength(); + + // FIXME: check if target symbol exists in current file + + d->addAttr(::new (S.Context) AliasAttr(std::string(Alias, AliasLen))); +} + +static void HandleAlwaysInlineAttr(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; + } + + if (!isa<FunctionDecl>(d)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 0 /*function*/; + return; + } + + d->addAttr(::new (S.Context) AlwaysInlineAttr()); +} + +static bool HandleCommonNoReturnAttr(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 false; + } + + if (!isFunctionOrMethod(d) && !isa<BlockDecl>(d)) { + ValueDecl *VD = dyn_cast<ValueDecl>(d); + if (VD == 0 || !VD->getType()->isBlockPointerType()) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 0 /*function*/; + return false; + } + } + + return true; +} + +static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) { + if (HandleCommonNoReturnAttr(d, Attr, S)) + d->addAttr(::new (S.Context) NoReturnAttr()); +} + +static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr, + Sema &S) { + if (HandleCommonNoReturnAttr(d, Attr, S)) + d->addAttr(::new (S.Context) AnalyzerNoReturnAttr()); +} + +static void HandleUnusedAttr(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; + } + + if (!isa<VarDecl>(d) && !isFunctionOrMethod(d)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 2 /*variable and function*/; + return; + } + + d->addAttr(::new (S.Context) UnusedAttr()); +} + +static void HandleUsedAttr(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; + } + + if (const VarDecl *VD = dyn_cast<VarDecl>(d)) { + if (VD->hasLocalStorage() || VD->hasExternalStorage()) { + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "used"; + return; + } + } else if (!isFunctionOrMethod(d)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 2 /*variable and function*/; + return; + } + + d->addAttr(::new (S.Context) UsedAttr()); +} + +static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { + // check the attribute arguments. + if (Attr.getNumArgs() != 0 && Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) + << "0 or 1"; + return; + } + + int priority = 65535; // FIXME: Do not hardcode such constants. + if (Attr.getNumArgs() > 0) { + Expr *E = static_cast<Expr *>(Attr.getArg(0)); + llvm::APSInt Idx(32); + if (!E->isIntegerConstantExpr(Idx, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) + << "constructor" << 1 << E->getSourceRange(); + return; + } + priority = Idx.getZExtValue(); + } + + if (!isa<FunctionDecl>(d)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 0 /*function*/; + return; + } + + d->addAttr(::new (S.Context) ConstructorAttr(priority)); +} + +static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { + // check the attribute arguments. + if (Attr.getNumArgs() != 0 && Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) + << "0 or 1"; + return; + } + + int priority = 65535; // FIXME: Do not hardcode such constants. + if (Attr.getNumArgs() > 0) { + Expr *E = static_cast<Expr *>(Attr.getArg(0)); + llvm::APSInt Idx(32); + if (!E->isIntegerConstantExpr(Idx, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) + << "destructor" << 1 << E->getSourceRange(); + return; + } + priority = Idx.getZExtValue(); + } + + if (!isa<FunctionDecl>(d)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 0 /*function*/; + return; + } + + d->addAttr(::new (S.Context) DestructorAttr(priority)); +} + +static void HandleDeprecatedAttr(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; + } + + d->addAttr(::new (S.Context) DeprecatedAttr()); +} + +static void HandleUnavailableAttr(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; + } + + d->addAttr(::new (S.Context) UnavailableAttr()); +} + +static void HandleVisibilityAttr(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; + } + + 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) + << "visibility" << 1; + return; + } + + const char *TypeStr = Str->getStrData(); + unsigned TypeLen = Str->getByteLength(); + VisibilityAttr::VisibilityTypes type; + + if (TypeLen == 7 && !memcmp(TypeStr, "default", 7)) + type = VisibilityAttr::DefaultVisibility; + else if (TypeLen == 6 && !memcmp(TypeStr, "hidden", 6)) + type = VisibilityAttr::HiddenVisibility; + else if (TypeLen == 8 && !memcmp(TypeStr, "internal", 8)) + type = VisibilityAttr::HiddenVisibility; // FIXME + else if (TypeLen == 9 && !memcmp(TypeStr, "protected", 9)) + type = VisibilityAttr::ProtectedVisibility; + else { + S.Diag(Attr.getLoc(), diag::warn_attribute_unknown_visibility) << TypeStr; + return; + } + + d->addAttr(::new (S.Context) VisibilityAttr(type)); +} + +static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr, + Sema &S) { + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return; + } + + ObjCInterfaceDecl *OCI = dyn_cast<ObjCInterfaceDecl>(D); + if (OCI == 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_requires_objc_interface); + return; + } + + D->addAttr(::new (S.Context) ObjCExceptionAttr()); +} + +static void HandleObjCNSObject(Decl *D, const AttributeList &Attr, Sema &S) { + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { + QualType T = TD->getUnderlyingType(); + if (!T->isPointerType() || + !T->getAsPointerType()->getPointeeType()->isRecordType()) { + S.Diag(TD->getLocation(), diag::err_nsobject_attribute); + return; + } + } + D->addAttr(::new (S.Context) ObjCNSObjectAttr()); +} + +static void +HandleOverloadableAttr(Decl *D, const AttributeList &Attr, Sema &S) { + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + + if (!isa<FunctionDecl>(D)) { + S.Diag(Attr.getLoc(), diag::err_attribute_overloadable_not_function); + return; + } + + D->addAttr(::new (S.Context) OverloadableAttr()); +} + +static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) { + if (!Attr.getParameterName()) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) + << "blocks" << 1; + return; + } + + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + + BlocksAttr::BlocksAttrTypes type; + if (Attr.getParameterName()->isStr("byref")) + type = BlocksAttr::ByRef; + else { + S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) + << "blocks" << Attr.getParameterName(); + return; + } + + d->addAttr(::new (S.Context) BlocksAttr(type)); +} + +static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) { + // check the attribute arguments. + if (Attr.getNumArgs() > 2) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) + << "0, 1 or 2"; + return; + } + + int sentinel = 0; + if (Attr.getNumArgs() > 0) { + Expr *E = static_cast<Expr *>(Attr.getArg(0)); + llvm::APSInt Idx(32); + if (!E->isIntegerConstantExpr(Idx, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) + << "sentinel" << 1 << E->getSourceRange(); + return; + } + sentinel = Idx.getZExtValue(); + + if (sentinel < 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_less_than_zero) + << E->getSourceRange(); + return; + } + } + + int nullPos = 0; + if (Attr.getNumArgs() > 1) { + Expr *E = static_cast<Expr *>(Attr.getArg(1)); + llvm::APSInt Idx(32); + if (!E->isIntegerConstantExpr(Idx, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) + << "sentinel" << 2 << E->getSourceRange(); + return; + } + nullPos = Idx.getZExtValue(); + + if (nullPos > 1 || nullPos < 0) { + // FIXME: This error message could be improved, it would be nice + // to say what the bounds actually are. + S.Diag(Attr.getLoc(), diag::err_attribute_sentinel_not_zero_or_one) + << E->getSourceRange(); + return; + } + } + + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) { + const FunctionType *FT = FD->getType()->getAsFunctionType(); + assert(FT && "FunctionDecl has non-function type?"); + + if (isa<FunctionNoProtoType>(FT)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_named_arguments); + return; + } + + if (!cast<FunctionProtoType>(FT)->isVariadic()) { + S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0; + return; + } + } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d)) { + if (!MD->isVariadic()) { + S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0; + return; + } + } else if (isa<BlockDecl>(d)) { + // Note! BlockDecl is typeless. Variadic diagnostics + // will be issued by the caller. + ; + } else if (const VarDecl *V = dyn_cast<VarDecl>(d)) { + QualType Ty = V->getType(); + if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) { + const FunctionType *FT = Ty->isFunctionPointerType() ? getFunctionType(d) + : Ty->getAsBlockPointerType()->getPointeeType()->getAsFunctionType(); + if (!cast<FunctionProtoType>(FT)->isVariadic()) { + int m = Ty->isFunctionPointerType() ? 0 : 1; + S.Diag(Attr.getLoc(), diag::warn_attribute_sentinel_not_variadic) << m; + return; + } + } + else { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 6 /*function, method or block */; + return; + } + } else { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 6 /*function, method or block */; + return; + } + d->addAttr(::new (S.Context) SentinelAttr(sentinel, nullPos)); +} + +static void HandleWarnUnusedResult(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; + } + + // TODO: could also be applied to methods? + FunctionDecl *Fn = dyn_cast<FunctionDecl>(D); + if (!Fn) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 0 /*function*/; + return; + } + + Fn->addAttr(::new (S.Context) WarnUnusedResultAttr()); +} + +static void HandleWeakAttr(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; + } + + // TODO: could also be applied to methods? + if (!isa<FunctionDecl>(D) && !isa<VarDecl>(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 2 /*variable and function*/; + return; + } + + D->addAttr(::new (S.Context) WeakAttr()); +} + +static void HandleWeakImportAttr(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; + } + + // weak_import only applies to variable & function declarations. + bool isDef = false; + if (VarDecl *VD = dyn_cast<VarDecl>(D)) { + isDef = (!VD->hasExternalStorage() || VD->getInit()); + } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + isDef = FD->getBody(S.Context); + } else if (isa<ObjCPropertyDecl>(D) || isa<ObjCMethodDecl>(D)) { + // We ignore weak import on properties and methods + return; + } else { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 2 /*variable and function*/; + return; + } + + // Merge should handle any subsequent violations. + if (isDef) { + S.Diag(Attr.getLoc(), + diag::warn_attribute_weak_import_invalid_on_definition) + << "weak_import" << 2 /*variable and function*/; + return; + } + + 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->isInline()) { + 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->isInline()) { + // 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 HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) { + // Attribute has no arguments. + if (Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + + // Make sure that there is a string literal as the sections's single + // argument. + StringLiteral *SE = + dyn_cast<StringLiteral>(static_cast<Expr *>(Attr.getArg(0))); + if (!SE) { + // FIXME + S.Diag(Attr.getLoc(), diag::err_attribute_annotate_no_string); + return; + } + D->addAttr(::new (S.Context) SectionAttr(std::string(SE->getStrData(), + SE->getByteLength()))); +} + +static void HandleStdCallAttr(Decl *d, const AttributeList &Attr, Sema &S) { + // Attribute has no arguments. + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return; + } + + // Attribute can be applied only to functions. + if (!isa<FunctionDecl>(d)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 0 /*function*/; + return; + } + + // stdcall and fastcall attributes are mutually incompatible. + if (d->getAttr<FastCallAttr>()) { + S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) + << "stdcall" << "fastcall"; + return; + } + + d->addAttr(::new (S.Context) StdCallAttr()); +} + +static void HandleFastCallAttr(Decl *d, const AttributeList &Attr, Sema &S) { + // Attribute has no arguments. + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return; + } + + if (!isa<FunctionDecl>(d)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 0 /*function*/; + return; + } + + // stdcall and fastcall attributes are mutually incompatible. + if (d->getAttr<StdCallAttr>()) { + S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) + << "fastcall" << "stdcall"; + return; + } + + d->addAttr(::new (S.Context) FastCallAttr()); +} + +static void HandleNothrowAttr(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; + } + + d->addAttr(::new (S.Context) NoThrowAttr()); +} + +static void HandleConstAttr(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; + } + + d->addAttr(::new (S.Context) ConstAttr()); +} + +static void HandlePureAttr(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; + } + + d->addAttr(::new (S.Context) PureAttr()); +} + +static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) { + // Match gcc which ignores cleanup attrs when compiling C++. + if (S.getLangOptions().CPlusPlus) + return; + + if (!Attr.getParameterName()) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + + VarDecl *VD = dyn_cast<VarDecl>(d); + + if (!VD || !VD->hasLocalStorage()) { + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "cleanup"; + return; + } + + // Look up the function + NamedDecl *CleanupDecl = S.LookupName(S.TUScope, Attr.getParameterName(), + Sema::LookupOrdinaryName); + if (!CleanupDecl) { + S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_arg_not_found) << + Attr.getParameterName(); + return; + } + + FunctionDecl *FD = dyn_cast<FunctionDecl>(CleanupDecl); + if (!FD) { + S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_arg_not_function) << + Attr.getParameterName(); + return; + } + + if (FD->getNumParams() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_func_must_take_one_arg) << + Attr.getParameterName(); + return; + } + + // We're currently more strict than GCC about what function types we accept. + // If this ever proves to be a problem it should be easy to fix. + QualType Ty = S.Context.getPointerType(VD->getType()); + QualType ParamTy = FD->getParamDecl(0)->getType(); + if (S.CheckAssignmentConstraints(ParamTy, Ty) != Sema::Compatible) { + S.Diag(Attr.getLoc(), + diag::err_attribute_cleanup_func_arg_incompatible_type) << + Attr.getParameterName() << ParamTy << Ty; + return; + } + + d->addAttr(::new (S.Context) CleanupAttr(FD)); +} + +/// Handle __attribute__((format_arg((idx)))) attribute +/// based on http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html +static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) { + if (Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 0 /*function*/; + return; + } + // FIXME: in C++ the implicit 'this' function parameter also counts. + // this is needed in order to be compatible with GCC + // the index must start with 1. + unsigned NumArgs = getFunctionOrMethodNumArgs(d); + unsigned FirstIdx = 1; + // checks for the 2nd argument + Expr *IdxExpr = static_cast<Expr *>(Attr.getArg(0)); + llvm::APSInt Idx(32); + if (!IdxExpr->isIntegerConstantExpr(Idx, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) + << "format" << 2 << IdxExpr->getSourceRange(); + return; + } + + if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) + << "format" << 2 << IdxExpr->getSourceRange(); + return; + } + + unsigned ArgIdx = Idx.getZExtValue() - 1; + + // make sure the format string is really a string + QualType Ty = getFunctionOrMethodArgType(d, ArgIdx); + + bool not_nsstring_type = !isNSStringType(Ty, S.Context); + if (not_nsstring_type && + !isCFStringType(Ty, S.Context) && + (!Ty->isPointerType() || + !Ty->getAsPointerType()->getPointeeType()->isCharType())) { + // FIXME: Should highlight the actual expression that has the wrong type. + S.Diag(Attr.getLoc(), diag::err_format_attribute_not) + << (not_nsstring_type ? "a string type" : "an NSString") + << IdxExpr->getSourceRange(); + return; + } + Ty = getFunctionOrMethodResultType(d); + if (!isNSStringType(Ty, S.Context) && + !isCFStringType(Ty, S.Context) && + (!Ty->isPointerType() || + !Ty->getAsPointerType()->getPointeeType()->isCharType())) { + // FIXME: Should highlight the actual expression that has the wrong type. + S.Diag(Attr.getLoc(), diag::err_format_attribute_result_not) + << (not_nsstring_type ? "string type" : "NSString") + << IdxExpr->getSourceRange(); + return; + } + + d->addAttr(::new (S.Context) FormatArgAttr(Idx.getZExtValue())); +} + +/// Handle __attribute__((format(type,idx,firstarg))) attributes +/// based on http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html +static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { + + if (!Attr.getParameterName()) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) + << "format" << 1; + return; + } + + if (Attr.getNumArgs() != 2) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 3; + return; + } + + if (!isFunctionOrMethodOrBlock(d) || !hasFunctionProto(d)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 0 /*function*/; + return; + } + + // FIXME: in C++ the implicit 'this' function parameter also counts. + // this is needed in order to be compatible with GCC + // the index must start in 1 and the limit is numargs+1 + unsigned NumArgs = getFunctionOrMethodNumArgs(d); + unsigned FirstIdx = 1; + + const char *Format = Attr.getParameterName()->getName(); + unsigned FormatLen = Attr.getParameterName()->getLength(); + + // Normalize the argument, __foo__ becomes foo. + if (FormatLen > 4 && Format[0] == '_' && Format[1] == '_' && + Format[FormatLen - 2] == '_' && Format[FormatLen - 1] == '_') { + Format += 2; + FormatLen -= 4; + } + + bool Supported = false; + bool is_NSString = false; + bool is_strftime = false; + bool is_CFString = false; + + switch (FormatLen) { + default: break; + case 5: Supported = !memcmp(Format, "scanf", 5); break; + case 6: Supported = !memcmp(Format, "printf", 6); break; + case 7: Supported = !memcmp(Format, "strfmon", 7); break; + case 8: + Supported = (is_strftime = !memcmp(Format, "strftime", 8)) || + (is_NSString = !memcmp(Format, "NSString", 8)) || + (is_CFString = !memcmp(Format, "CFString", 8)); + break; + } + + if (!Supported) { + S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) + << "format" << Attr.getParameterName()->getName(); + return; + } + + // checks for the 2nd argument + Expr *IdxExpr = static_cast<Expr *>(Attr.getArg(0)); + llvm::APSInt Idx(32); + if (!IdxExpr->isIntegerConstantExpr(Idx, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) + << "format" << 2 << IdxExpr->getSourceRange(); + return; + } + + if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) + << "format" << 2 << IdxExpr->getSourceRange(); + return; + } + + // FIXME: Do we need to bounds check? + unsigned ArgIdx = Idx.getZExtValue() - 1; + + // make sure the format string is really a string + QualType Ty = getFunctionOrMethodArgType(d, ArgIdx); + + if (is_CFString) { + if (!isCFStringType(Ty, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_format_attribute_not) + << "a CFString" << IdxExpr->getSourceRange(); + return; + } + } else if (is_NSString) { + // FIXME: do we need to check if the type is NSString*? What are the + // semantics? + if (!isNSStringType(Ty, S.Context)) { + // FIXME: Should highlight the actual expression that has the wrong type. + S.Diag(Attr.getLoc(), diag::err_format_attribute_not) + << "an NSString" << IdxExpr->getSourceRange(); + return; + } + } else if (!Ty->isPointerType() || + !Ty->getAsPointerType()->getPointeeType()->isCharType()) { + // FIXME: Should highlight the actual expression that has the wrong type. + S.Diag(Attr.getLoc(), diag::err_format_attribute_not) + << "a string type" << IdxExpr->getSourceRange(); + return; + } + + // check the 3rd argument + Expr *FirstArgExpr = static_cast<Expr *>(Attr.getArg(1)); + llvm::APSInt FirstArg(32); + if (!FirstArgExpr->isIntegerConstantExpr(FirstArg, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_int) + << "format" << 3 << FirstArgExpr->getSourceRange(); + return; + } + + // check if the function is variadic if the 3rd argument non-zero + if (FirstArg != 0) { + if (isFunctionOrMethodVariadic(d)) { + ++NumArgs; // +1 for ... + } else { + S.Diag(d->getLocation(), diag::err_format_attribute_requires_variadic); + return; + } + } + + // strftime requires FirstArg to be 0 because it doesn't read from any + // variable the input is just the current time + the format string. + if (is_strftime) { + if (FirstArg != 0) { + S.Diag(Attr.getLoc(), diag::err_format_strftime_third_parameter) + << FirstArgExpr->getSourceRange(); + return; + } + // if 0 it disables parameter checking (to use with e.g. va_list) + } else if (FirstArg != 0 && FirstArg != NumArgs) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) + << "format" << 3 << FirstArgExpr->getSourceRange(); + return; + } + + d->addAttr(::new (S.Context) FormatAttr(std::string(Format, FormatLen), + Idx.getZExtValue(), FirstArg.getZExtValue())); +} + +static void HandleTransparentUnionAttr(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; + } + + // Try to find the underlying union declaration. + RecordDecl *RD = 0; + TypedefDecl *TD = dyn_cast<TypedefDecl>(d); + if (TD && TD->getUnderlyingType()->isUnionType()) + RD = TD->getUnderlyingType()->getAsUnionType()->getDecl(); + else + RD = dyn_cast<RecordDecl>(d); + + if (!RD || !RD->isUnion()) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 1 /*union*/; + return; + } + + if (!RD->isDefinition()) { + S.Diag(Attr.getLoc(), + diag::warn_transparent_union_attribute_not_definition); + return; + } + + RecordDecl::field_iterator Field = RD->field_begin(S.Context), + FieldEnd = RD->field_end(S.Context); + if (Field == FieldEnd) { + S.Diag(Attr.getLoc(), diag::warn_transparent_union_attribute_zero_fields); + return; + } + + FieldDecl *FirstField = *Field; + QualType FirstType = FirstField->getType(); + if (FirstType->isFloatingType() || FirstType->isVectorType()) { + S.Diag(FirstField->getLocation(), + diag::warn_transparent_union_attribute_floating); + return; + } + + uint64_t FirstSize = S.Context.getTypeSize(FirstType); + uint64_t FirstAlign = S.Context.getTypeAlign(FirstType); + for (; Field != FieldEnd; ++Field) { + QualType FieldType = Field->getType(); + if (S.Context.getTypeSize(FieldType) != FirstSize || + S.Context.getTypeAlign(FieldType) != FirstAlign) { + // Warn if we drop the attribute. + bool isSize = S.Context.getTypeSize(FieldType) != FirstSize; + unsigned FieldBits = isSize? S.Context.getTypeSize(FieldType) + : S.Context.getTypeAlign(FieldType); + S.Diag(Field->getLocation(), + diag::warn_transparent_union_attribute_field_size_align) + << isSize << Field->getDeclName() << FieldBits; + unsigned FirstBits = isSize? FirstSize : FirstAlign; + S.Diag(FirstField->getLocation(), + diag::note_transparent_union_first_field_size_align) + << isSize << FirstBits; + return; + } + } + + RD->addAttr(::new (S.Context) TransparentUnionAttr()); +} + +static void HandleAnnotateAttr(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; + } + Expr *argExpr = static_cast<Expr *>(Attr.getArg(0)); + StringLiteral *SE = dyn_cast<StringLiteral>(argExpr); + + // Make sure that there is a string literal as the annotation's single + // argument. + if (!SE) { + S.Diag(Attr.getLoc(), diag::err_attribute_annotate_no_string); + return; + } + d->addAttr(::new (S.Context) AnnotateAttr(std::string(SE->getStrData(), + SE->getByteLength()))); +} + +static void HandleAlignedAttr(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; + } + + unsigned Align = 0; + if (Attr.getNumArgs() == 0) { + // FIXME: This should be the target specific maximum alignment. + // (For now we just use 128 bits which is the maximum on X86). + Align = 128; + d->addAttr(::new (S.Context) AlignedAttr(Align)); + return; + } + + Expr *alignmentExpr = static_cast<Expr *>(Attr.getArg(0)); + llvm::APSInt Alignment(32); + if (!alignmentExpr->isIntegerConstantExpr(Alignment, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) + << "aligned" << alignmentExpr->getSourceRange(); + return; + } + if (!llvm::isPowerOf2_64(Alignment.getZExtValue())) { + S.Diag(Attr.getLoc(), diag::err_attribute_aligned_not_power_of_two) + << alignmentExpr->getSourceRange(); + return; + } + + d->addAttr(::new (S.Context) AlignedAttr(Alignment.getZExtValue() * 8)); +} + +/// HandleModeAttr - This attribute modifies the width of a decl with +/// primitive type. +/// +/// Despite what would be logical, the mode attribute is a decl attribute, +/// not a type attribute: 'int ** __attribute((mode(HI))) *G;' tries to make +/// 'G' be HImode, not an intermediate pointer. +/// +static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) { + // This attribute isn't documented, but glibc uses it. It changes + // the width of an int or unsigned int to the specified size. + + // Check that there aren't any arguments + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return; + } + + IdentifierInfo *Name = Attr.getParameterName(); + if (!Name) { + S.Diag(Attr.getLoc(), diag::err_attribute_missing_parameter_name); + return; + } + const char *Str = Name->getName(); + unsigned Len = Name->getLength(); + + // Normalize the attribute name, __foo__ becomes foo. + if (Len > 4 && Str[0] == '_' && Str[1] == '_' && + Str[Len - 2] == '_' && Str[Len - 1] == '_') { + Str += 2; + Len -= 4; + } + + unsigned DestWidth = 0; + bool IntegerMode = true; + bool ComplexMode = false; + switch (Len) { + case 2: + switch (Str[0]) { + case 'Q': DestWidth = 8; break; + case 'H': DestWidth = 16; break; + case 'S': DestWidth = 32; break; + case 'D': DestWidth = 64; break; + case 'X': DestWidth = 96; break; + case 'T': DestWidth = 128; break; + } + if (Str[1] == 'F') { + IntegerMode = false; + } else if (Str[1] == 'C') { + IntegerMode = false; + ComplexMode = true; + } else if (Str[1] != 'I') { + DestWidth = 0; + } + break; + case 4: + // FIXME: glibc uses 'word' to define register_t; this is narrower than a + // pointer on PIC16 and other embedded platforms. + if (!memcmp(Str, "word", 4)) + DestWidth = S.Context.Target.getPointerWidth(0); + if (!memcmp(Str, "byte", 4)) + DestWidth = S.Context.Target.getCharWidth(); + break; + case 7: + if (!memcmp(Str, "pointer", 7)) + DestWidth = S.Context.Target.getPointerWidth(0); + break; + } + + QualType OldTy; + if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) + OldTy = TD->getUnderlyingType(); + else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) + OldTy = VD->getType(); + else { + S.Diag(D->getLocation(), diag::err_attr_wrong_decl) + << "mode" << SourceRange(Attr.getLoc(), Attr.getLoc()); + return; + } + + if (!OldTy->getAsBuiltinType() && !OldTy->isComplexType()) + S.Diag(Attr.getLoc(), diag::err_mode_not_primitive); + else if (IntegerMode) { + if (!OldTy->isIntegralType()) + S.Diag(Attr.getLoc(), diag::err_mode_wrong_type); + } else if (ComplexMode) { + if (!OldTy->isComplexType()) + S.Diag(Attr.getLoc(), diag::err_mode_wrong_type); + } else { + if (!OldTy->isFloatingType()) + S.Diag(Attr.getLoc(), diag::err_mode_wrong_type); + } + + // FIXME: Sync this with InitializePredefinedMacros; we need to match int8_t + // and friends, at least with glibc. + // FIXME: Make sure 32/64-bit integers don't get defined to types of the wrong + // width on unusual platforms. + // FIXME: Make sure floating-point mappings are accurate + // FIXME: Support XF and TF types + QualType NewTy; + switch (DestWidth) { + case 0: + S.Diag(Attr.getLoc(), diag::err_unknown_machine_mode) << Name; + return; + default: + S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name; + return; + case 8: + if (!IntegerMode) { + S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name; + return; + } + if (OldTy->isSignedIntegerType()) + NewTy = S.Context.SignedCharTy; + else + NewTy = S.Context.UnsignedCharTy; + break; + case 16: + if (!IntegerMode) { + S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name; + return; + } + if (OldTy->isSignedIntegerType()) + NewTy = S.Context.ShortTy; + else + NewTy = S.Context.UnsignedShortTy; + break; + case 32: + if (!IntegerMode) + NewTy = S.Context.FloatTy; + else if (OldTy->isSignedIntegerType()) + NewTy = S.Context.IntTy; + else + NewTy = S.Context.UnsignedIntTy; + break; + case 64: + if (!IntegerMode) + NewTy = S.Context.DoubleTy; + else if (OldTy->isSignedIntegerType()) + NewTy = S.Context.LongLongTy; + else + NewTy = S.Context.UnsignedLongLongTy; + break; + case 96: + NewTy = S.Context.LongDoubleTy; + break; + case 128: + if (!IntegerMode) { + S.Diag(Attr.getLoc(), diag::err_unsupported_machine_mode) << Name; + return; + } + NewTy = S.Context.getFixedWidthIntType(128, OldTy->isSignedIntegerType()); + break; + } + + if (ComplexMode) { + NewTy = S.Context.getComplexType(NewTy); + } + + // Install the new type. + if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) + TD->setUnderlyingType(NewTy); + else + cast<ValueDecl>(D)->setType(NewTy); +} + +static void HandleNodebugAttr(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; + } + + if (!isFunctionOrMethod(d)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 0 /*function*/; + return; + } + + d->addAttr(::new (S.Context) NodebugAttr()); +} + +static void HandleNoinlineAttr(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; + } + + if (!isa<FunctionDecl>(d)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 0 /*function*/; + return; + } + + d->addAttr(::new (S.Context) NoinlineAttr()); +} + +static void HandleGNUInlineAttr(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; + } + + FunctionDecl *Fn = dyn_cast<FunctionDecl>(d); + if (Fn == 0) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 0 /*function*/; + return; + } + + if (!Fn->isInline()) { + S.Diag(Attr.getLoc(), diag::warn_gnu_inline_attribute_requires_inline); + return; + } + + d->addAttr(::new (S.Context) GNUInlineAttr()); +} + +static void HandleRegparmAttr(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; + } + + if (!isFunctionOrMethod(d)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 0 /*function*/; + return; + } + + Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0)); + llvm::APSInt NumParams(32); + if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) + << "regparm" << NumParamsExpr->getSourceRange(); + return; + } + + if (S.Context.Target.getRegParmMax() == 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_regparm_wrong_platform) + << NumParamsExpr->getSourceRange(); + return; + } + + if (NumParams.getLimitedValue(255) > S.Context.Target.getRegParmMax()) { + S.Diag(Attr.getLoc(), diag::err_attribute_regparm_invalid_number) + << S.Context.Target.getRegParmMax() << NumParamsExpr->getSourceRange(); + return; + } + + d->addAttr(::new (S.Context) RegparmAttr(NumParams.getZExtValue())); +} + +//===----------------------------------------------------------------------===// +// Checker-specific attribute handlers. +//===----------------------------------------------------------------------===// + +static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr, + Sema &S) { + + QualType RetTy; + + if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d)) + RetTy = MD->getResultType(); + else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d)) + RetTy = FD->getResultType(); + else { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 3 /* function or method */; + return; + } + + if (!(S.Context.isObjCNSObjectType(RetTy) || RetTy->getAsPointerType())) { + S.Diag(Attr.getLoc(), diag::warn_ns_attribute_wrong_return_type) + << Attr.getName(); + return; + } + + switch (Attr.getKind()) { + default: + assert(0 && "invalid ownership attribute"); + return; + case AttributeList::AT_cf_returns_retained: + d->addAttr(::new (S.Context) CFReturnsRetainedAttr()); + return; + case AttributeList::AT_ns_returns_retained: + d->addAttr(::new (S.Context) NSReturnsRetainedAttr()); + return; + }; +} + +//===----------------------------------------------------------------------===// +// Top Level Sema Entry Points +//===----------------------------------------------------------------------===// + +/// ProcessDeclAttribute - Apply the specific attribute to the specified decl if +/// the attribute applies to decls. If the attribute is a type attribute, just +/// silently ignore it. +static void ProcessDeclAttribute(Decl *D, const AttributeList &Attr, Sema &S) { + switch (Attr.getKind()) { + case AttributeList::AT_IBOutlet: HandleIBOutletAttr (D, Attr, S); break; + case AttributeList::AT_address_space: + case AttributeList::AT_objc_gc: + // Ignore these, these are type attributes, handled by ProcessTypeAttributes. + break; + case AttributeList::AT_alias: HandleAliasAttr (D, Attr, S); break; + case AttributeList::AT_aligned: HandleAlignedAttr (D, Attr, S); break; + case AttributeList::AT_always_inline: + HandleAlwaysInlineAttr (D, Attr, S); break; + case AttributeList::AT_analyzer_noreturn: + HandleAnalyzerNoReturnAttr (D, Attr, S); break; + case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break; + 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(D, Attr, S); + break; + case AttributeList::AT_fastcall: HandleFastCallAttr (D, Attr, S); break; + case AttributeList::AT_format: HandleFormatAttr (D, Attr, S); break; + case AttributeList::AT_format_arg: HandleFormatArgAttr (D, Attr, S); break; + case AttributeList::AT_gnu_inline: HandleGNUInlineAttr(D, Attr, S); break; + case AttributeList::AT_mode: HandleModeAttr (D, Attr, S); break; + case AttributeList::AT_nonnull: HandleNonNullAttr (D, Attr, S); break; + case AttributeList::AT_noreturn: HandleNoReturnAttr (D, Attr, S); break; + case AttributeList::AT_nothrow: HandleNothrowAttr (D, Attr, S); break; + + // Checker-specific. + case AttributeList::AT_ns_returns_retained: + case AttributeList::AT_cf_returns_retained: + HandleNSReturnsRetainedAttr(D, Attr, S); break; + + case AttributeList::AT_packed: HandlePackedAttr (D, Attr, S); break; + case AttributeList::AT_section: HandleSectionAttr (D, Attr, S); break; + case AttributeList::AT_stdcall: HandleStdCallAttr (D, Attr, S); break; + case AttributeList::AT_unavailable: HandleUnavailableAttr(D, Attr, S); break; + case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break; + case AttributeList::AT_used: HandleUsedAttr (D, Attr, S); break; + case AttributeList::AT_vector_size: HandleVectorSizeAttr(D, Attr, S); break; + case AttributeList::AT_visibility: HandleVisibilityAttr(D, Attr, S); break; + case AttributeList::AT_warn_unused_result: HandleWarnUnusedResult(D,Attr,S); + break; + case AttributeList::AT_weak: HandleWeakAttr (D, Attr, S); break; + case AttributeList::AT_weak_import: HandleWeakImportAttr(D, Attr, S); break; + case AttributeList::AT_transparent_union: + HandleTransparentUnionAttr(D, Attr, S); + break; + case AttributeList::AT_objc_exception: + HandleObjCExceptionAttr(D, Attr, S); + break; + case AttributeList::AT_overloadable:HandleOverloadableAttr(D, Attr, S); break; + case AttributeList::AT_nsobject: HandleObjCNSObject (D, Attr, S); break; + case AttributeList::AT_blocks: HandleBlocksAttr (D, Attr, S); break; + case AttributeList::AT_sentinel: HandleSentinelAttr (D, Attr, S); break; + case AttributeList::AT_const: HandleConstAttr (D, Attr, S); break; + case AttributeList::AT_pure: HandlePureAttr (D, Attr, S); break; + case AttributeList::AT_cleanup: HandleCleanupAttr (D, Attr, S); break; + case AttributeList::AT_nodebug: HandleNodebugAttr (D, Attr, S); break; + case AttributeList::AT_noinline: HandleNoinlineAttr (D, Attr, S); break; + case AttributeList::AT_regparm: HandleRegparmAttr (D, Attr, S); break; + case AttributeList::IgnoredAttribute: + case AttributeList::AT_no_instrument_function: // Interacts with -pg. + // Just ignore + break; + default: + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); + break; + } +} + +/// ProcessDeclAttributeList - Apply all the decl attributes in the specified +/// attribute list to the specified decl, ignoring any type attributes. +void Sema::ProcessDeclAttributeList(Decl *D, const AttributeList *AttrList) { + while (AttrList) { + ProcessDeclAttribute(D, *AttrList, *this); + AttrList = AttrList->getNext(); + } +} + +/// ProcessDeclAttributes - Given a declarator (PD) with attributes indicated in +/// it, apply them to D. This is a bit tricky because PD can have attributes +/// specified in many different places, and we need to find and apply them all. +void Sema::ProcessDeclAttributes(Decl *D, const Declarator &PD) { + // Apply decl attributes from the DeclSpec if present. + if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes()) + ProcessDeclAttributeList(D, Attrs); + + // Walk the declarator structure, applying decl attributes that were in a type + // position to the decl itself. This handles cases like: + // int *__attr__(x)** D; + // when X is a decl attribute. + for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i) + if (const AttributeList *Attrs = PD.getTypeObject(i).getAttrs()) + ProcessDeclAttributeList(D, Attrs); + + // Finally, apply any attributes on the decl itself. + if (const AttributeList *Attrs = PD.getAttributes()) + ProcessDeclAttributeList(D, Attrs); +} diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp new file mode 100644 index 0000000..f13179f --- /dev/null +++ b/lib/Sema/SemaDeclCXX.cpp @@ -0,0 +1,2823 @@ +//===------ SemaDeclCXX.cpp - Semantic Analysis for C++ Declarations ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for C++ declarations. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "SemaInherit.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/TypeOrdering.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Parse/DeclSpec.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Compiler.h" +#include <algorithm> // for std::equal +#include <map> + +using namespace clang; + +//===----------------------------------------------------------------------===// +// CheckDefaultArgumentVisitor +//===----------------------------------------------------------------------===// + +namespace { + /// CheckDefaultArgumentVisitor - C++ [dcl.fct.default] Traverses + /// the default argument of a parameter to determine whether it + /// contains any ill-formed subexpressions. For example, this will + /// diagnose the use of local variables or parameters within the + /// default argument expression. + class VISIBILITY_HIDDEN CheckDefaultArgumentVisitor + : public StmtVisitor<CheckDefaultArgumentVisitor, bool> { + Expr *DefaultArg; + Sema *S; + + public: + CheckDefaultArgumentVisitor(Expr *defarg, Sema *s) + : DefaultArg(defarg), S(s) {} + + bool VisitExpr(Expr *Node); + bool VisitDeclRefExpr(DeclRefExpr *DRE); + bool VisitCXXThisExpr(CXXThisExpr *ThisE); + }; + + /// VisitExpr - Visit all of the children of this expression. + bool CheckDefaultArgumentVisitor::VisitExpr(Expr *Node) { + bool IsInvalid = false; + for (Stmt::child_iterator I = Node->child_begin(), + E = Node->child_end(); I != E; ++I) + IsInvalid |= Visit(*I); + return IsInvalid; + } + + /// VisitDeclRefExpr - Visit a reference to a declaration, to + /// determine whether this declaration can be used in the default + /// argument expression. + bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(DeclRefExpr *DRE) { + NamedDecl *Decl = DRE->getDecl(); + if (ParmVarDecl *Param = dyn_cast<ParmVarDecl>(Decl)) { + // C++ [dcl.fct.default]p9 + // Default arguments are evaluated each time the function is + // called. The order of evaluation of function arguments is + // unspecified. Consequently, parameters of a function shall not + // be used in default argument expressions, even if they are not + // evaluated. Parameters of a function declared before a default + // argument expression are in scope and can hide namespace and + // class member names. + return S->Diag(DRE->getSourceRange().getBegin(), + diag::err_param_default_argument_references_param) + << Param->getDeclName() << DefaultArg->getSourceRange(); + } else if (VarDecl *VDecl = dyn_cast<VarDecl>(Decl)) { + // C++ [dcl.fct.default]p7 + // Local variables shall not be used in default argument + // expressions. + if (VDecl->isBlockVarDecl()) + return S->Diag(DRE->getSourceRange().getBegin(), + diag::err_param_default_argument_references_local) + << VDecl->getDeclName() << DefaultArg->getSourceRange(); + } + + return false; + } + + /// VisitCXXThisExpr - Visit a C++ "this" expression. + bool CheckDefaultArgumentVisitor::VisitCXXThisExpr(CXXThisExpr *ThisE) { + // C++ [dcl.fct.default]p8: + // The keyword this shall not be used in a default argument of a + // member function. + return S->Diag(ThisE->getSourceRange().getBegin(), + diag::err_param_default_argument_references_this) + << ThisE->getSourceRange(); + } +} + +/// ActOnParamDefaultArgument - Check whether the default argument +/// provided for a function parameter is well-formed. If so, attach it +/// to the parameter declaration. +void +Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc, + ExprArg defarg) { + ParmVarDecl *Param = cast<ParmVarDecl>(param.getAs<Decl>()); + ExprOwningPtr<Expr> DefaultArg(this, defarg.takeAs<Expr>()); + QualType ParamType = Param->getType(); + + // Default arguments are only permitted in C++ + if (!getLangOptions().CPlusPlus) { + Diag(EqualLoc, diag::err_param_default_argument) + << DefaultArg->getSourceRange(); + Param->setInvalidDecl(); + return; + } + + // C++ [dcl.fct.default]p5 + // A default argument expression is implicitly converted (clause + // 4) to the parameter type. The default argument expression has + // the same semantic constraints as the initializer expression in + // a declaration of a variable of the parameter type, using the + // copy-initialization semantics (8.5). + Expr *DefaultArgPtr = DefaultArg.get(); + bool DefaultInitFailed = CheckInitializerTypes(DefaultArgPtr, ParamType, + EqualLoc, + Param->getDeclName(), + /*DirectInit=*/false); + if (DefaultArgPtr != DefaultArg.get()) { + DefaultArg.take(); + DefaultArg.reset(DefaultArgPtr); + } + if (DefaultInitFailed) { + return; + } + + // Check that the default argument is well-formed + CheckDefaultArgumentVisitor DefaultArgChecker(DefaultArg.get(), this); + if (DefaultArgChecker.Visit(DefaultArg.get())) { + Param->setInvalidDecl(); + return; + } + + // Okay: add the default argument to the parameter + Param->setDefaultArg(DefaultArg.take()); +} + +/// ActOnParamUnparsedDefaultArgument - We've seen a default +/// argument for a function parameter, but we can't parse it yet +/// because we're inside a class definition. Note that this default +/// argument will be parsed later. +void Sema::ActOnParamUnparsedDefaultArgument(DeclPtrTy param, + SourceLocation EqualLoc) { + ParmVarDecl *Param = cast<ParmVarDecl>(param.getAs<Decl>()); + if (Param) + Param->setUnparsedDefaultArg(); +} + +/// ActOnParamDefaultArgumentError - Parsing or semantic analysis of +/// the default argument for the parameter param failed. +void Sema::ActOnParamDefaultArgumentError(DeclPtrTy param) { + cast<ParmVarDecl>(param.getAs<Decl>())->setInvalidDecl(); +} + +/// CheckExtraCXXDefaultArguments - Check for any extra default +/// arguments in the declarator, which is not a function declaration +/// or definition and therefore is not permitted to have default +/// arguments. This routine should be invoked for every declarator +/// that is not a function declaration or definition. +void Sema::CheckExtraCXXDefaultArguments(Declarator &D) { + // C++ [dcl.fct.default]p3 + // A default argument expression shall be specified only in the + // parameter-declaration-clause of a function declaration or in a + // template-parameter (14.1). It shall not be specified for a + // parameter pack. If it is specified in a + // parameter-declaration-clause, it shall not occur within a + // declarator or abstract-declarator of a parameter-declaration. + for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { + DeclaratorChunk &chunk = D.getTypeObject(i); + if (chunk.Kind == DeclaratorChunk::Function) { + for (unsigned argIdx = 0, e = chunk.Fun.NumArgs; argIdx != e; ++argIdx) { + ParmVarDecl *Param = + cast<ParmVarDecl>(chunk.Fun.ArgInfo[argIdx].Param.getAs<Decl>()); + if (Param->hasUnparsedDefaultArg()) { + CachedTokens *Toks = chunk.Fun.ArgInfo[argIdx].DefaultArgTokens; + Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc) + << SourceRange((*Toks)[1].getLocation(), Toks->back().getLocation()); + delete Toks; + chunk.Fun.ArgInfo[argIdx].DefaultArgTokens = 0; + } else if (Param->getDefaultArg()) { + Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc) + << Param->getDefaultArg()->getSourceRange(); + Param->setDefaultArg(0); + } + } + } + } +} + +// MergeCXXFunctionDecl - Merge two declarations of the same C++ +// function, once we already know that they have the same +// type. Subroutine of MergeFunctionDecl. Returns true if there was an +// error, false otherwise. +bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { + bool Invalid = false; + + // C++ [dcl.fct.default]p4: + // + // For non-template functions, default arguments can be added in + // later declarations of a function in the same + // scope. Declarations in different scopes have completely + // distinct sets of default arguments. That is, declarations in + // inner scopes do not acquire default arguments from + // declarations in outer scopes, and vice versa. In a given + // function declaration, all parameters subsequent to a + // parameter with a default argument shall have default + // arguments supplied in this or previous declarations. A + // default argument shall not be redefined by a later + // declaration (not even to the same value). + for (unsigned p = 0, NumParams = Old->getNumParams(); p < NumParams; ++p) { + ParmVarDecl *OldParam = Old->getParamDecl(p); + ParmVarDecl *NewParam = New->getParamDecl(p); + + if(OldParam->getDefaultArg() && NewParam->getDefaultArg()) { + Diag(NewParam->getLocation(), + diag::err_param_default_argument_redefinition) + << NewParam->getDefaultArg()->getSourceRange(); + Diag(OldParam->getLocation(), diag::note_previous_definition); + Invalid = true; + } else if (OldParam->getDefaultArg()) { + // Merge the old default argument into the new parameter + NewParam->setDefaultArg(OldParam->getDefaultArg()); + } + } + + return Invalid; +} + +/// CheckCXXDefaultArguments - Verify that the default arguments for a +/// function declaration are well-formed according to C++ +/// [dcl.fct.default]. +void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { + unsigned NumParams = FD->getNumParams(); + unsigned p; + + // Find first parameter with a default argument + for (p = 0; p < NumParams; ++p) { + ParmVarDecl *Param = FD->getParamDecl(p); + if (Param->getDefaultArg()) + break; + } + + // C++ [dcl.fct.default]p4: + // In a given function declaration, all parameters + // subsequent to a parameter with a default argument shall + // have default arguments supplied in this or previous + // declarations. A default argument shall not be redefined + // by a later declaration (not even to the same value). + unsigned LastMissingDefaultArg = 0; + for(; p < NumParams; ++p) { + ParmVarDecl *Param = FD->getParamDecl(p); + if (!Param->getDefaultArg()) { + if (Param->isInvalidDecl()) + /* We already complained about this parameter. */; + else if (Param->getIdentifier()) + Diag(Param->getLocation(), + diag::err_param_default_argument_missing_name) + << Param->getIdentifier(); + else + Diag(Param->getLocation(), + diag::err_param_default_argument_missing); + + LastMissingDefaultArg = p; + } + } + + if (LastMissingDefaultArg > 0) { + // Some default arguments were missing. Clear out all of the + // default arguments up to (and including) the last missing + // default argument, so that we leave the function parameters + // in a semantically valid state. + for (p = 0; p <= LastMissingDefaultArg; ++p) { + ParmVarDecl *Param = FD->getParamDecl(p); + if (Param->getDefaultArg()) { + if (!Param->hasUnparsedDefaultArg()) + Param->getDefaultArg()->Destroy(Context); + Param->setDefaultArg(0); + } + } + } +} + +/// isCurrentClassName - Determine whether the identifier II is the +/// name of the class type currently being defined. In the case of +/// nested classes, this will only return true if II is the name of +/// the innermost class. +bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *, + const CXXScopeSpec *SS) { + CXXRecordDecl *CurDecl; + if (SS && SS->isSet() && !SS->isInvalid()) { + DeclContext *DC = computeDeclContext(*SS); + CurDecl = dyn_cast_or_null<CXXRecordDecl>(DC); + } else + CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext); + + if (CurDecl) + return &II == CurDecl->getIdentifier(); + else + return false; +} + +/// \brief Check the validity of a C++ base class specifier. +/// +/// \returns a new CXXBaseSpecifier if well-formed, emits diagnostics +/// and returns NULL otherwise. +CXXBaseSpecifier * +Sema::CheckBaseSpecifier(CXXRecordDecl *Class, + SourceRange SpecifierRange, + bool Virtual, AccessSpecifier Access, + QualType BaseType, + SourceLocation BaseLoc) { + // C++ [class.union]p1: + // A union shall not have base classes. + if (Class->isUnion()) { + Diag(Class->getLocation(), diag::err_base_clause_on_union) + << SpecifierRange; + return 0; + } + + if (BaseType->isDependentType()) + return new CXXBaseSpecifier(SpecifierRange, Virtual, + Class->getTagKind() == RecordDecl::TK_class, + Access, BaseType); + + // Base specifiers must be record types. + if (!BaseType->isRecordType()) { + Diag(BaseLoc, diag::err_base_must_be_class) << SpecifierRange; + return 0; + } + + // C++ [class.union]p1: + // A union shall not be used as a base class. + if (BaseType->isUnionType()) { + Diag(BaseLoc, diag::err_union_as_base_class) << SpecifierRange; + return 0; + } + + // C++ [class.derived]p2: + // The class-name in a base-specifier shall not be an incompletely + // defined class. + if (RequireCompleteType(BaseLoc, BaseType, diag::err_incomplete_base_class, + SpecifierRange)) + return 0; + + // If the base class is polymorphic, the new one is, too. + RecordDecl *BaseDecl = BaseType->getAsRecordType()->getDecl(); + assert(BaseDecl && "Record type has no declaration"); + BaseDecl = BaseDecl->getDefinition(Context); + assert(BaseDecl && "Base type is not incomplete, but has no definition"); + if (cast<CXXRecordDecl>(BaseDecl)->isPolymorphic()) + Class->setPolymorphic(true); + + // C++ [dcl.init.aggr]p1: + // An aggregate is [...] a class with [...] no base classes [...]. + Class->setAggregate(false); + Class->setPOD(false); + + if (Virtual) { + // C++ [class.ctor]p5: + // A constructor is trivial if its class has no virtual base classes. + Class->setHasTrivialConstructor(false); + } else { + // C++ [class.ctor]p5: + // A constructor is trivial if all the direct base classes of its + // class have trivial constructors. + Class->setHasTrivialConstructor(cast<CXXRecordDecl>(BaseDecl)-> + hasTrivialConstructor()); + } + + // C++ [class.ctor]p3: + // A destructor is trivial if all the direct base classes of its class + // have trivial destructors. + Class->setHasTrivialDestructor(cast<CXXRecordDecl>(BaseDecl)-> + hasTrivialDestructor()); + + // Create the base specifier. + // FIXME: Allocate via ASTContext? + return new CXXBaseSpecifier(SpecifierRange, Virtual, + Class->getTagKind() == RecordDecl::TK_class, + Access, BaseType); +} + +/// ActOnBaseSpecifier - Parsed a base specifier. A base specifier is +/// one entry in the base class list of a class specifier, for +/// example: +/// class foo : public bar, virtual private baz { +/// 'public bar' and 'virtual private baz' are each base-specifiers. +Sema::BaseResult +Sema::ActOnBaseSpecifier(DeclPtrTy classdecl, SourceRange SpecifierRange, + bool Virtual, AccessSpecifier Access, + TypeTy *basetype, SourceLocation BaseLoc) { + AdjustDeclIfTemplate(classdecl); + CXXRecordDecl *Class = cast<CXXRecordDecl>(classdecl.getAs<Decl>()); + QualType BaseType = QualType::getFromOpaquePtr(basetype); + if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange, + Virtual, Access, + BaseType, BaseLoc)) + return BaseSpec; + + return true; +} + +/// \brief Performs the actual work of attaching the given base class +/// specifiers to a C++ class. +bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, + unsigned NumBases) { + if (NumBases == 0) + return false; + + // Used to keep track of which base types we have already seen, so + // that we can properly diagnose redundant direct base types. Note + // that the key is always the unqualified canonical type of the base + // class. + std::map<QualType, CXXBaseSpecifier*, QualTypeOrdering> KnownBaseTypes; + + // Copy non-redundant base specifiers into permanent storage. + unsigned NumGoodBases = 0; + bool Invalid = false; + for (unsigned idx = 0; idx < NumBases; ++idx) { + QualType NewBaseType + = Context.getCanonicalType(Bases[idx]->getType()); + NewBaseType = NewBaseType.getUnqualifiedType(); + + if (KnownBaseTypes[NewBaseType]) { + // C++ [class.mi]p3: + // A class shall not be specified as a direct base class of a + // derived class more than once. + Diag(Bases[idx]->getSourceRange().getBegin(), + diag::err_duplicate_base_class) + << KnownBaseTypes[NewBaseType]->getType() + << Bases[idx]->getSourceRange(); + + // Delete the duplicate base class specifier; we're going to + // overwrite its pointer later. + delete Bases[idx]; + + Invalid = true; + } else { + // Okay, add this new base class. + KnownBaseTypes[NewBaseType] = Bases[idx]; + Bases[NumGoodBases++] = Bases[idx]; + } + } + + // Attach the remaining base class specifiers to the derived class. + Class->setBases(Bases, NumGoodBases); + + // Delete the remaining (good) base class specifiers, since their + // data has been copied into the CXXRecordDecl. + for (unsigned idx = 0; idx < NumGoodBases; ++idx) + delete Bases[idx]; + + return Invalid; +} + +/// ActOnBaseSpecifiers - Attach the given base specifiers to the +/// class, after checking whether there are any duplicate base +/// classes. +void Sema::ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases, + unsigned NumBases) { + if (!ClassDecl || !Bases || !NumBases) + return; + + AdjustDeclIfTemplate(ClassDecl); + AttachBaseSpecifiers(cast<CXXRecordDecl>(ClassDecl.getAs<Decl>()), + (CXXBaseSpecifier**)(Bases), NumBases); +} + +//===----------------------------------------------------------------------===// +// C++ class member Handling +//===----------------------------------------------------------------------===// + +/// ActOnCXXMemberDeclarator - This is invoked when a C++ class member +/// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the +/// bitfield width if there is one and 'InitExpr' specifies the initializer if +/// any. +Sema::DeclPtrTy +Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, + ExprTy *BW, ExprTy *InitExpr, bool Deleted) { + const DeclSpec &DS = D.getDeclSpec(); + DeclarationName Name = GetNameForDeclarator(D); + Expr *BitWidth = static_cast<Expr*>(BW); + Expr *Init = static_cast<Expr*>(InitExpr); + SourceLocation Loc = D.getIdentifierLoc(); + + bool isFunc = D.isFunctionDeclarator(); + + // C++ 9.2p6: A member shall not be declared to have automatic storage + // duration (auto, register) or with the extern storage-class-specifier. + // C++ 7.1.1p8: The mutable specifier can be applied only to names of class + // data members and cannot be applied to names declared const or static, + // and cannot be applied to reference members. + switch (DS.getStorageClassSpec()) { + case DeclSpec::SCS_unspecified: + case DeclSpec::SCS_typedef: + case DeclSpec::SCS_static: + // FALL THROUGH. + break; + case DeclSpec::SCS_mutable: + if (isFunc) { + if (DS.getStorageClassSpecLoc().isValid()) + Diag(DS.getStorageClassSpecLoc(), diag::err_mutable_function); + else + Diag(DS.getThreadSpecLoc(), diag::err_mutable_function); + + // FIXME: It would be nicer if the keyword was ignored only for this + // declarator. Otherwise we could get follow-up errors. + D.getMutableDeclSpec().ClearStorageClassSpecs(); + } else { + QualType T = GetTypeForDeclarator(D, S); + diag::kind err = static_cast<diag::kind>(0); + if (T->isReferenceType()) + err = diag::err_mutable_reference; + else if (T.isConstQualified()) + err = diag::err_mutable_const; + if (err != 0) { + if (DS.getStorageClassSpecLoc().isValid()) + Diag(DS.getStorageClassSpecLoc(), err); + else + Diag(DS.getThreadSpecLoc(), err); + // FIXME: It would be nicer if the keyword was ignored only for this + // declarator. Otherwise we could get follow-up errors. + D.getMutableDeclSpec().ClearStorageClassSpecs(); + } + } + break; + default: + if (DS.getStorageClassSpecLoc().isValid()) + Diag(DS.getStorageClassSpecLoc(), + diag::err_storageclass_invalid_for_member); + else + Diag(DS.getThreadSpecLoc(), diag::err_storageclass_invalid_for_member); + D.getMutableDeclSpec().ClearStorageClassSpecs(); + } + + if (!isFunc && + D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_typename && + D.getNumTypeObjects() == 0) { + // Check also for this case: + // + // typedef int f(); + // f a; + // + QualType TDType = QualType::getFromOpaquePtr(DS.getTypeRep()); + isFunc = TDType->isFunctionType(); + } + + bool isInstField = ((DS.getStorageClassSpec() == DeclSpec::SCS_unspecified || + DS.getStorageClassSpec() == DeclSpec::SCS_mutable) && + !isFunc); + + Decl *Member; + if (isInstField) { + Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth, + AS); + assert(Member && "HandleField never returns null"); + } else { + Member = ActOnDeclarator(S, D).getAs<Decl>(); + if (!Member) { + if (BitWidth) DeleteExpr(BitWidth); + return DeclPtrTy(); + } + + // Non-instance-fields can't have a bitfield. + if (BitWidth) { + if (Member->isInvalidDecl()) { + // don't emit another diagnostic. + } else if (isa<VarDecl>(Member)) { + // C++ 9.6p3: A bit-field shall not be a static member. + // "static member 'A' cannot be a bit-field" + Diag(Loc, diag::err_static_not_bitfield) + << Name << BitWidth->getSourceRange(); + } else if (isa<TypedefDecl>(Member)) { + // "typedef member 'x' cannot be a bit-field" + Diag(Loc, diag::err_typedef_not_bitfield) + << Name << BitWidth->getSourceRange(); + } else { + // A function typedef ("typedef int f(); f a;"). + // C++ 9.6p3: A bit-field shall have integral or enumeration type. + Diag(Loc, diag::err_not_integral_type_bitfield) + << Name << cast<ValueDecl>(Member)->getType() + << BitWidth->getSourceRange(); + } + + DeleteExpr(BitWidth); + BitWidth = 0; + Member->setInvalidDecl(); + } + + Member->setAccess(AS); + } + + assert((Name || isInstField) && "No identifier for non-field ?"); + + if (Init) + AddInitializerToDecl(DeclPtrTy::make(Member), ExprArg(*this, Init), false); + if (Deleted) // FIXME: Source location is not very good. + SetDeclDeleted(DeclPtrTy::make(Member), D.getSourceRange().getBegin()); + + if (isInstField) { + FieldCollector->Add(cast<FieldDecl>(Member)); + return DeclPtrTy(); + } + return DeclPtrTy::make(Member); +} + +/// ActOnMemInitializer - Handle a C++ member initializer. +Sema::MemInitResult +Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, + Scope *S, + IdentifierInfo *MemberOrBase, + SourceLocation IdLoc, + SourceLocation LParenLoc, + ExprTy **Args, unsigned NumArgs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc) { + CXXConstructorDecl *Constructor + = dyn_cast<CXXConstructorDecl>(ConstructorD.getAs<Decl>()); + if (!Constructor) { + // The user wrote a constructor initializer on a function that is + // not a C++ constructor. Ignore the error for now, because we may + // have more member initializers coming; we'll diagnose it just + // once in ActOnMemInitializers. + return true; + } + + CXXRecordDecl *ClassDecl = Constructor->getParent(); + + // C++ [class.base.init]p2: + // Names in a mem-initializer-id are looked up in the scope of the + // constructor’s class and, if not found in that scope, are looked + // up in the scope containing the constructor’s + // definition. [Note: if the constructor’s class contains a member + // with the same name as a direct or virtual base class of the + // class, a mem-initializer-id naming the member or base class and + // composed of a single identifier refers to the class member. A + // mem-initializer-id for the hidden base class may be specified + // using a qualified name. ] + // Look for a member, first. + FieldDecl *Member = 0; + DeclContext::lookup_result Result + = ClassDecl->lookup(Context, MemberOrBase); + if (Result.first != Result.second) + Member = dyn_cast<FieldDecl>(*Result.first); + + // FIXME: Handle members of an anonymous union. + + if (Member) { + // FIXME: Perform direct initialization of the member. + return new CXXBaseOrMemberInitializer(Member, (Expr **)Args, NumArgs); + } + + // It didn't name a member, so see if it names a class. + TypeTy *BaseTy = getTypeName(*MemberOrBase, IdLoc, S, 0/*SS*/); + if (!BaseTy) + return Diag(IdLoc, diag::err_mem_init_not_member_or_class) + << MemberOrBase << SourceRange(IdLoc, RParenLoc); + + QualType BaseType = QualType::getFromOpaquePtr(BaseTy); + if (!BaseType->isRecordType()) + return Diag(IdLoc, diag::err_base_init_does_not_name_class) + << BaseType << SourceRange(IdLoc, RParenLoc); + + // C++ [class.base.init]p2: + // [...] Unless the mem-initializer-id names a nonstatic data + // member of the constructor’s class or a direct or virtual base + // of that class, the mem-initializer is ill-formed. A + // mem-initializer-list can initialize a base class using any + // name that denotes that base class type. + + // First, check for a direct base class. + const CXXBaseSpecifier *DirectBaseSpec = 0; + for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); + Base != ClassDecl->bases_end(); ++Base) { + if (Context.getCanonicalType(BaseType).getUnqualifiedType() == + Context.getCanonicalType(Base->getType()).getUnqualifiedType()) { + // We found a direct base of this type. That's what we're + // initializing. + DirectBaseSpec = &*Base; + break; + } + } + + // Check for a virtual base class. + // FIXME: We might be able to short-circuit this if we know in advance that + // there are no virtual bases. + const CXXBaseSpecifier *VirtualBaseSpec = 0; + if (!DirectBaseSpec || !DirectBaseSpec->isVirtual()) { + // We haven't found a base yet; search the class hierarchy for a + // virtual base class. + BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/false); + if (IsDerivedFrom(Context.getTypeDeclType(ClassDecl), BaseType, Paths)) { + for (BasePaths::paths_iterator Path = Paths.begin(); + Path != Paths.end(); ++Path) { + if (Path->back().Base->isVirtual()) { + VirtualBaseSpec = Path->back().Base; + break; + } + } + } + } + + // C++ [base.class.init]p2: + // If a mem-initializer-id is ambiguous because it designates both + // a direct non-virtual base class and an inherited virtual base + // class, the mem-initializer is ill-formed. + if (DirectBaseSpec && VirtualBaseSpec) + return Diag(IdLoc, diag::err_base_init_direct_and_virtual) + << MemberOrBase << SourceRange(IdLoc, RParenLoc); + + return new CXXBaseOrMemberInitializer(BaseType, (Expr **)Args, NumArgs); +} + +void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, + SourceLocation ColonLoc, + MemInitTy **MemInits, unsigned NumMemInits) { + CXXConstructorDecl *Constructor = + dyn_cast<CXXConstructorDecl>(ConstructorDecl.getAs<Decl>()); + + if (!Constructor) { + Diag(ColonLoc, diag::err_only_constructors_take_base_inits); + return; + } +} + +namespace { + /// PureVirtualMethodCollector - traverses a class and its superclasses + /// and determines if it has any pure virtual methods. + class VISIBILITY_HIDDEN PureVirtualMethodCollector { + ASTContext &Context; + + public: + typedef llvm::SmallVector<const CXXMethodDecl*, 8> MethodList; + + private: + MethodList Methods; + + void Collect(const CXXRecordDecl* RD, MethodList& Methods); + + public: + PureVirtualMethodCollector(ASTContext &Ctx, const CXXRecordDecl* RD) + : Context(Ctx) { + + MethodList List; + Collect(RD, List); + + // Copy the temporary list to methods, and make sure to ignore any + // null entries. + for (size_t i = 0, e = List.size(); i != e; ++i) { + if (List[i]) + Methods.push_back(List[i]); + } + } + + bool empty() const { return Methods.empty(); } + + MethodList::const_iterator methods_begin() { return Methods.begin(); } + MethodList::const_iterator methods_end() { return Methods.end(); } + }; + + void PureVirtualMethodCollector::Collect(const CXXRecordDecl* RD, + MethodList& Methods) { + // First, collect the pure virtual methods for the base classes. + for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(), + BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) { + if (const RecordType *RT = Base->getType()->getAsRecordType()) { + const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(RT->getDecl()); + if (BaseDecl && BaseDecl->isAbstract()) + Collect(BaseDecl, Methods); + } + } + + // Next, zero out any pure virtual methods that this class overrides. + typedef llvm::SmallPtrSet<const CXXMethodDecl*, 4> MethodSetTy; + + MethodSetTy OverriddenMethods; + size_t MethodsSize = Methods.size(); + + for (RecordDecl::decl_iterator i = RD->decls_begin(Context), + e = RD->decls_end(Context); + i != e; ++i) { + // Traverse the record, looking for methods. + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*i)) { + // If the method is pre virtual, add it to the methods vector. + if (MD->isPure()) { + Methods.push_back(MD); + continue; + } + + // Otherwise, record all the overridden methods in our set. + for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), + E = MD->end_overridden_methods(); I != E; ++I) { + // Keep track of the overridden methods. + OverriddenMethods.insert(*I); + } + } + } + + // Now go through the methods and zero out all the ones we know are + // overridden. + for (size_t i = 0, e = MethodsSize; i != e; ++i) { + if (OverriddenMethods.count(Methods[i])) + Methods[i] = 0; + } + + } +} + +bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, + unsigned DiagID, AbstractDiagSelID SelID, + const CXXRecordDecl *CurrentRD) { + + if (!getLangOptions().CPlusPlus) + return false; + + if (const ArrayType *AT = Context.getAsArrayType(T)) + return RequireNonAbstractType(Loc, AT->getElementType(), DiagID, SelID, + CurrentRD); + + if (const PointerType *PT = T->getAsPointerType()) { + // Find the innermost pointer type. + while (const PointerType *T = PT->getPointeeType()->getAsPointerType()) + PT = T; + + if (const ArrayType *AT = Context.getAsArrayType(PT->getPointeeType())) + return RequireNonAbstractType(Loc, AT->getElementType(), DiagID, SelID, + CurrentRD); + } + + const RecordType *RT = T->getAsRecordType(); + if (!RT) + return false; + + const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); + if (!RD) + return false; + + if (CurrentRD && CurrentRD != RD) + return false; + + if (!RD->isAbstract()) + return false; + + Diag(Loc, DiagID) << RD->getDeclName() << SelID; + + // Check if we've already emitted the list of pure virtual functions for this + // class. + if (PureVirtualClassDiagSet && PureVirtualClassDiagSet->count(RD)) + return true; + + PureVirtualMethodCollector Collector(Context, RD); + + for (PureVirtualMethodCollector::MethodList::const_iterator I = + Collector.methods_begin(), E = Collector.methods_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + Diag(MD->getLocation(), diag::note_pure_virtual_function) << + MD->getDeclName(); + } + + if (!PureVirtualClassDiagSet) + PureVirtualClassDiagSet.reset(new RecordDeclSetTy); + PureVirtualClassDiagSet->insert(RD); + + return true; +} + +namespace { + class VISIBILITY_HIDDEN AbstractClassUsageDiagnoser + : public DeclVisitor<AbstractClassUsageDiagnoser, bool> { + Sema &SemaRef; + CXXRecordDecl *AbstractClass; + + bool VisitDeclContext(const DeclContext *DC) { + bool Invalid = false; + + for (CXXRecordDecl::decl_iterator I = DC->decls_begin(SemaRef.Context), + E = DC->decls_end(SemaRef.Context); I != E; ++I) + Invalid |= Visit(*I); + + return Invalid; + } + + public: + AbstractClassUsageDiagnoser(Sema& SemaRef, CXXRecordDecl *ac) + : SemaRef(SemaRef), AbstractClass(ac) { + Visit(SemaRef.Context.getTranslationUnitDecl()); + } + + bool VisitFunctionDecl(const FunctionDecl *FD) { + if (FD->isThisDeclarationADefinition()) { + // No need to do the check if we're in a definition, because it requires + // that the return/param types are complete. + // because that requires + return VisitDeclContext(FD); + } + + // Check the return type. + QualType RTy = FD->getType()->getAsFunctionType()->getResultType(); + bool Invalid = + SemaRef.RequireNonAbstractType(FD->getLocation(), RTy, + diag::err_abstract_type_in_decl, + Sema::AbstractReturnType, + AbstractClass); + + for (FunctionDecl::param_const_iterator I = FD->param_begin(), + E = FD->param_end(); I != E; ++I) { + const ParmVarDecl *VD = *I; + Invalid |= + SemaRef.RequireNonAbstractType(VD->getLocation(), + VD->getOriginalType(), + diag::err_abstract_type_in_decl, + Sema::AbstractParamType, + AbstractClass); + } + + return Invalid; + } + + bool VisitDecl(const Decl* D) { + if (const DeclContext *DC = dyn_cast<DeclContext>(D)) + return VisitDeclContext(DC); + + return false; + } + }; +} + +void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, + DeclPtrTy TagDecl, + SourceLocation LBrac, + SourceLocation RBrac) { + AdjustDeclIfTemplate(TagDecl); + ActOnFields(S, RLoc, TagDecl, + (DeclPtrTy*)FieldCollector->getCurFields(), + FieldCollector->getCurNumFields(), LBrac, RBrac, 0); + + CXXRecordDecl *RD = cast<CXXRecordDecl>(TagDecl.getAs<Decl>()); + if (!RD->isAbstract()) { + // Collect all the pure virtual methods and see if this is an abstract + // class after all. + PureVirtualMethodCollector Collector(Context, RD); + if (!Collector.empty()) + RD->setAbstract(true); + } + + if (RD->isAbstract()) + AbstractClassUsageDiagnoser(*this, RD); + + if (RD->hasTrivialConstructor() || RD->hasTrivialDestructor()) { + for (RecordDecl::field_iterator i = RD->field_begin(Context), + e = RD->field_end(Context); i != e; ++i) { + // All the nonstatic data members must have trivial constructors. + QualType FTy = i->getType(); + while (const ArrayType *AT = Context.getAsArrayType(FTy)) + FTy = AT->getElementType(); + + if (const RecordType *RT = FTy->getAsRecordType()) { + CXXRecordDecl *FieldRD = cast<CXXRecordDecl>(RT->getDecl()); + + if (!FieldRD->hasTrivialConstructor()) + RD->setHasTrivialConstructor(false); + if (!FieldRD->hasTrivialDestructor()) + RD->setHasTrivialDestructor(false); + + // If RD has neither a trivial constructor nor a trivial destructor + // we don't need to continue checking. + if (!RD->hasTrivialConstructor() && !RD->hasTrivialDestructor()) + break; + } + } + } + + if (!RD->isDependentType()) + AddImplicitlyDeclaredMembersToClass(RD); +} + +/// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared +/// special functions, such as the default constructor, copy +/// constructor, or destructor, to the given C++ class (C++ +/// [special]p1). This routine can only be executed just before the +/// definition of the class is complete. +void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { + QualType ClassType = Context.getTypeDeclType(ClassDecl); + ClassType = Context.getCanonicalType(ClassType); + + // FIXME: Implicit declarations have exception specifications, which are + // the union of the specifications of the implicitly called functions. + + if (!ClassDecl->hasUserDeclaredConstructor()) { + // C++ [class.ctor]p5: + // A default constructor for a class X is a constructor of class X + // that can be called without an argument. If there is no + // user-declared constructor for class X, a default constructor is + // implicitly declared. An implicitly-declared default constructor + // is an inline public member of its class. + DeclarationName Name + = Context.DeclarationNames.getCXXConstructorName(ClassType); + CXXConstructorDecl *DefaultCon = + CXXConstructorDecl::Create(Context, ClassDecl, + ClassDecl->getLocation(), Name, + Context.getFunctionType(Context.VoidTy, + 0, 0, false, 0), + /*isExplicit=*/false, + /*isInline=*/true, + /*isImplicitlyDeclared=*/true); + DefaultCon->setAccess(AS_public); + DefaultCon->setImplicit(); + ClassDecl->addDecl(Context, DefaultCon); + + // Notify the class that we've added a constructor. + ClassDecl->addedConstructor(Context, DefaultCon); + } + + if (!ClassDecl->hasUserDeclaredCopyConstructor()) { + // C++ [class.copy]p4: + // If the class definition does not explicitly declare a copy + // constructor, one is declared implicitly. + + // C++ [class.copy]p5: + // The implicitly-declared copy constructor for a class X will + // have the form + // + // X::X(const X&) + // + // if + bool HasConstCopyConstructor = true; + + // -- each direct or virtual base class B of X has a copy + // constructor whose first parameter is of type const B& or + // const volatile B&, and + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(); + HasConstCopyConstructor && Base != ClassDecl->bases_end(); ++Base) { + const CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl()); + HasConstCopyConstructor + = BaseClassDecl->hasConstCopyConstructor(Context); + } + + // -- for all the nonstatic data members of X that are of a + // class type M (or array thereof), each such class type + // has a copy constructor whose first parameter is of type + // const M& or const volatile M&. + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(Context); + HasConstCopyConstructor && Field != ClassDecl->field_end(Context); + ++Field) { + QualType FieldType = (*Field)->getType(); + if (const ArrayType *Array = Context.getAsArrayType(FieldType)) + FieldType = Array->getElementType(); + if (const RecordType *FieldClassType = FieldType->getAsRecordType()) { + const CXXRecordDecl *FieldClassDecl + = cast<CXXRecordDecl>(FieldClassType->getDecl()); + HasConstCopyConstructor + = FieldClassDecl->hasConstCopyConstructor(Context); + } + } + + // Otherwise, the implicitly declared copy constructor will have + // the form + // + // X::X(X&) + QualType ArgType = ClassType; + if (HasConstCopyConstructor) + ArgType = ArgType.withConst(); + ArgType = Context.getLValueReferenceType(ArgType); + + // An implicitly-declared copy constructor is an inline public + // member of its class. + DeclarationName Name + = Context.DeclarationNames.getCXXConstructorName(ClassType); + CXXConstructorDecl *CopyConstructor + = CXXConstructorDecl::Create(Context, ClassDecl, + ClassDecl->getLocation(), Name, + Context.getFunctionType(Context.VoidTy, + &ArgType, 1, + false, 0), + /*isExplicit=*/false, + /*isInline=*/true, + /*isImplicitlyDeclared=*/true); + CopyConstructor->setAccess(AS_public); + CopyConstructor->setImplicit(); + + // Add the parameter to the constructor. + ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor, + ClassDecl->getLocation(), + /*IdentifierInfo=*/0, + ArgType, VarDecl::None, 0); + CopyConstructor->setParams(Context, &FromParam, 1); + + ClassDecl->addedConstructor(Context, CopyConstructor); + ClassDecl->addDecl(Context, CopyConstructor); + } + + if (!ClassDecl->hasUserDeclaredCopyAssignment()) { + // Note: The following rules are largely analoguous to the copy + // constructor rules. Note that virtual bases are not taken into account + // for determining the argument type of the operator. Note also that + // operators taking an object instead of a reference are allowed. + // + // C++ [class.copy]p10: + // If the class definition does not explicitly declare a copy + // assignment operator, one is declared implicitly. + // The implicitly-defined copy assignment operator for a class X + // will have the form + // + // X& X::operator=(const X&) + // + // if + bool HasConstCopyAssignment = true; + + // -- each direct base class B of X has a copy assignment operator + // whose parameter is of type const B&, const volatile B& or B, + // and + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(); + HasConstCopyAssignment && Base != ClassDecl->bases_end(); ++Base) { + const CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base->getType()->getAsRecordType()->getDecl()); + HasConstCopyAssignment = BaseClassDecl->hasConstCopyAssignment(Context); + } + + // -- for all the nonstatic data members of X that are of a class + // type M (or array thereof), each such class type has a copy + // assignment operator whose parameter is of type const M&, + // const volatile M& or M. + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(Context); + HasConstCopyAssignment && Field != ClassDecl->field_end(Context); + ++Field) { + QualType FieldType = (*Field)->getType(); + if (const ArrayType *Array = Context.getAsArrayType(FieldType)) + FieldType = Array->getElementType(); + if (const RecordType *FieldClassType = FieldType->getAsRecordType()) { + const CXXRecordDecl *FieldClassDecl + = cast<CXXRecordDecl>(FieldClassType->getDecl()); + HasConstCopyAssignment + = FieldClassDecl->hasConstCopyAssignment(Context); + } + } + + // Otherwise, the implicitly declared copy assignment operator will + // have the form + // + // X& X::operator=(X&) + QualType ArgType = ClassType; + QualType RetType = Context.getLValueReferenceType(ArgType); + if (HasConstCopyAssignment) + ArgType = ArgType.withConst(); + ArgType = Context.getLValueReferenceType(ArgType); + + // An implicitly-declared copy assignment operator is an inline public + // member of its class. + DeclarationName Name = + Context.DeclarationNames.getCXXOperatorName(OO_Equal); + CXXMethodDecl *CopyAssignment = + CXXMethodDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name, + Context.getFunctionType(RetType, &ArgType, 1, + false, 0), + /*isStatic=*/false, /*isInline=*/true); + CopyAssignment->setAccess(AS_public); + CopyAssignment->setImplicit(); + + // Add the parameter to the operator. + ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment, + ClassDecl->getLocation(), + /*IdentifierInfo=*/0, + ArgType, VarDecl::None, 0); + CopyAssignment->setParams(Context, &FromParam, 1); + + // Don't call addedAssignmentOperator. There is no way to distinguish an + // implicit from an explicit assignment operator. + ClassDecl->addDecl(Context, CopyAssignment); + } + + if (!ClassDecl->hasUserDeclaredDestructor()) { + // C++ [class.dtor]p2: + // If a class has no user-declared destructor, a destructor is + // declared implicitly. An implicitly-declared destructor is an + // inline public member of its class. + DeclarationName Name + = Context.DeclarationNames.getCXXDestructorName(ClassType); + CXXDestructorDecl *Destructor + = CXXDestructorDecl::Create(Context, ClassDecl, + ClassDecl->getLocation(), Name, + Context.getFunctionType(Context.VoidTy, + 0, 0, false, 0), + /*isInline=*/true, + /*isImplicitlyDeclared=*/true); + Destructor->setAccess(AS_public); + Destructor->setImplicit(); + ClassDecl->addDecl(Context, Destructor); + } +} + +void Sema::ActOnReenterTemplateScope(Scope *S, DeclPtrTy TemplateD) { + TemplateDecl *Template = TemplateD.getAs<TemplateDecl>(); + if (!Template) + return; + + TemplateParameterList *Params = Template->getTemplateParameters(); + for (TemplateParameterList::iterator Param = Params->begin(), + ParamEnd = Params->end(); + Param != ParamEnd; ++Param) { + NamedDecl *Named = cast<NamedDecl>(*Param); + if (Named->getDeclName()) { + S->AddDecl(DeclPtrTy::make(Named)); + IdResolver.AddDecl(Named); + } + } +} + +/// ActOnStartDelayedCXXMethodDeclaration - We have completed +/// parsing a top-level (non-nested) C++ class, and we are now +/// parsing those parts of the given Method declaration that could +/// not be parsed earlier (C++ [class.mem]p2), such as default +/// arguments. This action should enter the scope of the given +/// Method declaration as if we had just parsed the qualified method +/// name. However, it should not bring the parameters into scope; +/// that will be performed by ActOnDelayedCXXMethodParameter. +void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) { + CXXScopeSpec SS; + FunctionDecl *Method = cast<FunctionDecl>(MethodD.getAs<Decl>()); + QualType ClassTy + = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext())); + SS.setScopeRep( + NestedNameSpecifier::Create(Context, 0, false, ClassTy.getTypePtr())); + ActOnCXXEnterDeclaratorScope(S, SS); +} + +/// ActOnDelayedCXXMethodParameter - We've already started a delayed +/// C++ method declaration. We're (re-)introducing the given +/// function parameter into scope for use in parsing later parts of +/// the method declaration. For example, we could see an +/// ActOnParamDefaultArgument event for this parameter. +void Sema::ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy ParamD) { + ParmVarDecl *Param = cast<ParmVarDecl>(ParamD.getAs<Decl>()); + + // If this parameter has an unparsed default argument, clear it out + // to make way for the parsed default argument. + if (Param->hasUnparsedDefaultArg()) + Param->setDefaultArg(0); + + S->AddDecl(DeclPtrTy::make(Param)); + if (Param->getDeclName()) + IdResolver.AddDecl(Param); +} + +/// ActOnFinishDelayedCXXMethodDeclaration - We have finished +/// processing the delayed method declaration for Method. The method +/// declaration is now considered finished. There may be a separate +/// ActOnStartOfFunctionDef action later (not necessarily +/// immediately!) for this method, if it was also defined inside the +/// class body. +void Sema::ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) { + FunctionDecl *Method = cast<FunctionDecl>(MethodD.getAs<Decl>()); + CXXScopeSpec SS; + QualType ClassTy + = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext())); + SS.setScopeRep( + NestedNameSpecifier::Create(Context, 0, false, ClassTy.getTypePtr())); + ActOnCXXExitDeclaratorScope(S, SS); + + // Now that we have our default arguments, check the constructor + // again. It could produce additional diagnostics or affect whether + // the class has implicitly-declared destructors, among other + // things. + if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Method)) + CheckConstructor(Constructor); + + // Check the default arguments, which we may have added. + if (!Method->isInvalidDecl()) + CheckCXXDefaultArguments(Method); +} + +/// CheckConstructorDeclarator - Called by ActOnDeclarator to check +/// the well-formedness of the constructor declarator @p D with type @p +/// R. If there are any errors in the declarator, this routine will +/// emit diagnostics and set the invalid bit to true. In any case, the type +/// will be updated to reflect a well-formed type for the constructor and +/// returned. +QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R, + FunctionDecl::StorageClass &SC) { + bool isVirtual = D.getDeclSpec().isVirtualSpecified(); + + // C++ [class.ctor]p3: + // A constructor shall not be virtual (10.3) or static (9.4). A + // constructor can be invoked for a const, volatile or const + // volatile object. A constructor shall not be declared const, + // volatile, or const volatile (9.3.2). + if (isVirtual) { + if (!D.isInvalidType()) + Diag(D.getIdentifierLoc(), diag::err_constructor_cannot_be) + << "virtual" << SourceRange(D.getDeclSpec().getVirtualSpecLoc()) + << SourceRange(D.getIdentifierLoc()); + D.setInvalidType(); + } + if (SC == FunctionDecl::Static) { + if (!D.isInvalidType()) + Diag(D.getIdentifierLoc(), diag::err_constructor_cannot_be) + << "static" << SourceRange(D.getDeclSpec().getStorageClassSpecLoc()) + << SourceRange(D.getIdentifierLoc()); + D.setInvalidType(); + SC = FunctionDecl::None; + } + + DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + if (FTI.TypeQuals != 0) { + if (FTI.TypeQuals & QualType::Const) + Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor) + << "const" << SourceRange(D.getIdentifierLoc()); + if (FTI.TypeQuals & QualType::Volatile) + Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor) + << "volatile" << SourceRange(D.getIdentifierLoc()); + if (FTI.TypeQuals & QualType::Restrict) + Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_constructor) + << "restrict" << SourceRange(D.getIdentifierLoc()); + } + + // Rebuild the function type "R" without any type qualifiers (in + // case any of the errors above fired) and with "void" as the + // return type, since constructors 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. + const FunctionProtoType *Proto = R->getAsFunctionProtoType(); + return Context.getFunctionType(Context.VoidTy, Proto->arg_type_begin(), + Proto->getNumArgs(), + Proto->isVariadic(), 0); +} + +/// CheckConstructor - Checks a fully-formed constructor for +/// well-formedness, issuing any diagnostics required. Returns true if +/// the constructor declarator is invalid. +void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { + CXXRecordDecl *ClassDecl + = dyn_cast<CXXRecordDecl>(Constructor->getDeclContext()); + if (!ClassDecl) + return Constructor->setInvalidDecl(); + + // C++ [class.copy]p3: + // A declaration of a constructor for a class X is ill-formed if + // its first parameter is of type (optionally cv-qualified) X and + // either there are no other parameters or else all other + // parameters have default arguments. + if (!Constructor->isInvalidDecl() && + ((Constructor->getNumParams() == 1) || + (Constructor->getNumParams() > 1 && + Constructor->getParamDecl(1)->getDefaultArg() != 0))) { + QualType ParamType = Constructor->getParamDecl(0)->getType(); + QualType ClassTy = Context.getTagDeclType(ClassDecl); + if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) { + SourceLocation ParamLoc = Constructor->getParamDecl(0)->getLocation(); + Diag(ParamLoc, diag::err_constructor_byvalue_arg) + << CodeModificationHint::CreateInsertion(ParamLoc, " const &"); + Constructor->setInvalidDecl(); + } + } + + // Notify the class that we've added a constructor. + ClassDecl->addedConstructor(Context, Constructor); +} + +static inline bool +FTIHasSingleVoidArgument(DeclaratorChunk::FunctionTypeInfo &FTI) { + return (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 && + FTI.ArgInfo[0].Param && + FTI.ArgInfo[0].Param.getAs<ParmVarDecl>()->getType()->isVoidType()); +} + +/// CheckDestructorDeclarator - Called by ActOnDeclarator to check +/// the well-formednes of the destructor declarator @p D with type @p +/// R. If there are any errors in the declarator, this routine will +/// emit diagnostics and set the declarator to invalid. Even if this happens, +/// will be updated to reflect a well-formed type for the destructor and +/// returned. +QualType Sema::CheckDestructorDeclarator(Declarator &D, + FunctionDecl::StorageClass& SC) { + // C++ [class.dtor]p1: + // [...] A typedef-name that names a class is a class-name + // (7.1.3); however, a typedef-name that names a class shall not + // be used as the identifier in the declarator for a destructor + // declaration. + QualType DeclaratorType = QualType::getFromOpaquePtr(D.getDeclaratorIdType()); + if (isa<TypedefType>(DeclaratorType)) { + Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name) + << DeclaratorType; + D.setInvalidType(); + } + + // C++ [class.dtor]p2: + // A destructor is used to destroy objects of its class type. A + // destructor takes no parameters, and no return type can be + // specified for it (not even void). The address of a destructor + // shall not be taken. A destructor shall not be static. A + // destructor can be invoked for a const, volatile or const + // volatile object. A destructor shall not be declared const, + // volatile or const volatile (9.3.2). + if (SC == FunctionDecl::Static) { + if (!D.isInvalidType()) + Diag(D.getIdentifierLoc(), diag::err_destructor_cannot_be) + << "static" << SourceRange(D.getDeclSpec().getStorageClassSpecLoc()) + << SourceRange(D.getIdentifierLoc()); + SC = FunctionDecl::None; + D.setInvalidType(); + } + if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) { + // Destructors don't have return types, but the parser will + // happily parse something like: + // + // class X { + // float ~X(); + // }; + // + // The return type will be eliminated later. + Diag(D.getIdentifierLoc(), diag::err_destructor_return_type) + << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) + << SourceRange(D.getIdentifierLoc()); + } + + DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + if (FTI.TypeQuals != 0 && !D.isInvalidType()) { + if (FTI.TypeQuals & QualType::Const) + Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor) + << "const" << SourceRange(D.getIdentifierLoc()); + if (FTI.TypeQuals & QualType::Volatile) + Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor) + << "volatile" << SourceRange(D.getIdentifierLoc()); + if (FTI.TypeQuals & QualType::Restrict) + Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_destructor) + << "restrict" << SourceRange(D.getIdentifierLoc()); + D.setInvalidType(); + } + + // Make sure we don't have any parameters. + if (FTI.NumArgs > 0 && !FTIHasSingleVoidArgument(FTI)) { + Diag(D.getIdentifierLoc(), diag::err_destructor_with_params); + + // Delete the parameters. + FTI.freeArgs(); + D.setInvalidType(); + } + + // Make sure the destructor isn't variadic. + if (FTI.isVariadic) { + Diag(D.getIdentifierLoc(), diag::err_destructor_variadic); + D.setInvalidType(); + } + + // Rebuild the function type "R" without any type qualifiers or + // parameters (in case any of the errors above fired) and with + // "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); +} + +/// CheckConversionDeclarator - Called by ActOnDeclarator to check the +/// well-formednes of the conversion function declarator @p D with +/// type @p R. If there are any errors in the declarator, this routine +/// will emit diagnostics and return true. Otherwise, it will return +/// false. Either way, the type @p R will be updated to reflect a +/// well-formed type for the conversion operator. +void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, + FunctionDecl::StorageClass& SC) { + // C++ [class.conv.fct]p1: + // Neither parameter types nor return type can be specified. The + // type of a conversion function (8.3.5) is “function taking no + // parameter returning conversion-type-id.” + if (SC == FunctionDecl::Static) { + if (!D.isInvalidType()) + Diag(D.getIdentifierLoc(), diag::err_conv_function_not_member) + << "static" << SourceRange(D.getDeclSpec().getStorageClassSpecLoc()) + << SourceRange(D.getIdentifierLoc()); + D.setInvalidType(); + SC = FunctionDecl::None; + } + if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) { + // Conversion functions don't have return types, but the parser will + // happily parse something like: + // + // class X { + // float operator bool(); + // }; + // + // The return type will be changed later anyway. + Diag(D.getIdentifierLoc(), diag::err_conv_function_return_type) + << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) + << SourceRange(D.getIdentifierLoc()); + } + + // Make sure we don't have any parameters. + if (R->getAsFunctionProtoType()->getNumArgs() > 0) { + Diag(D.getIdentifierLoc(), diag::err_conv_function_with_params); + + // Delete the parameters. + D.getTypeObject(0).Fun.freeArgs(); + D.setInvalidType(); + } + + // Make sure the conversion function isn't variadic. + if (R->getAsFunctionProtoType()->isVariadic() && !D.isInvalidType()) { + Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic); + D.setInvalidType(); + } + + // C++ [class.conv.fct]p4: + // The conversion-type-id shall not represent a function type nor + // an array type. + QualType ConvType = QualType::getFromOpaquePtr(D.getDeclaratorIdType()); + if (ConvType->isArrayType()) { + Diag(D.getIdentifierLoc(), diag::err_conv_function_to_array); + ConvType = Context.getPointerType(ConvType); + D.setInvalidType(); + } else if (ConvType->isFunctionType()) { + Diag(D.getIdentifierLoc(), diag::err_conv_function_to_function); + ConvType = Context.getPointerType(ConvType); + D.setInvalidType(); + } + + // 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. + R = Context.getFunctionType(ConvType, 0, 0, false, + R->getAsFunctionProtoType()->getTypeQuals()); + + // C++0x explicit conversion operators. + if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x) + Diag(D.getDeclSpec().getExplicitSpecLoc(), + diag::warn_explicit_conversion_functions) + << SourceRange(D.getDeclSpec().getExplicitSpecLoc()); +} + +/// ActOnConversionDeclarator - Called by ActOnDeclarator to complete +/// the declaration of the given C++ conversion function. This routine +/// is responsible for recording the conversion function in the C++ +/// class, if possible. +Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { + assert(Conversion && "Expected to receive a conversion function declaration"); + + // Set the lexical context of this conversion function + Conversion->setLexicalDeclContext(CurContext); + + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Conversion->getDeclContext()); + + // Make sure we aren't redeclaring the conversion function. + QualType ConvType = Context.getCanonicalType(Conversion->getConversionType()); + + // C++ [class.conv.fct]p1: + // [...] A conversion function is never used to convert a + // (possibly cv-qualified) object to the (possibly cv-qualified) + // same object type (or a reference to it), to a (possibly + // cv-qualified) base class of that type (or a reference to it), + // or to (possibly cv-qualified) void. + // FIXME: Suppress this warning if the conversion function ends up being a + // virtual function that overrides a virtual function in a base class. + QualType ClassType + = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); + if (const ReferenceType *ConvTypeRef = ConvType->getAsReferenceType()) + ConvType = ConvTypeRef->getPointeeType(); + if (ConvType->isRecordType()) { + ConvType = Context.getCanonicalType(ConvType).getUnqualifiedType(); + if (ConvType == ClassType) + Diag(Conversion->getLocation(), diag::warn_conv_to_self_not_used) + << ClassType; + else if (IsDerivedFrom(ClassType, ConvType)) + Diag(Conversion->getLocation(), diag::warn_conv_to_base_not_used) + << ClassType << ConvType; + } else if (ConvType->isVoidType()) { + Diag(Conversion->getLocation(), diag::warn_conv_to_void_not_used) + << ClassType << ConvType; + } + + if (Conversion->getPreviousDeclaration()) { + OverloadedFunctionDecl *Conversions = ClassDecl->getConversionFunctions(); + for (OverloadedFunctionDecl::function_iterator + Conv = Conversions->function_begin(), + ConvEnd = Conversions->function_end(); + Conv != ConvEnd; ++Conv) { + if (*Conv == Conversion->getPreviousDeclaration()) { + *Conv = Conversion; + return DeclPtrTy::make(Conversion); + } + } + assert(Conversion->isInvalidDecl() && "Conversion should not get here."); + } else + ClassDecl->addConversionFunction(Context, Conversion); + + return DeclPtrTy::make(Conversion); +} + +//===----------------------------------------------------------------------===// +// Namespace Handling +//===----------------------------------------------------------------------===// + +/// ActOnStartNamespaceDef - This is called at the start of a namespace +/// definition. +Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, + SourceLocation IdentLoc, + IdentifierInfo *II, + SourceLocation LBrace) { + NamespaceDecl *Namespc = + NamespaceDecl::Create(Context, CurContext, IdentLoc, II); + Namespc->setLBracLoc(LBrace); + + Scope *DeclRegionScope = NamespcScope->getParent(); + + if (II) { + // C++ [namespace.def]p2: + // The identifier in an original-namespace-definition shall not have been + // previously defined in the declarative region in which the + // original-namespace-definition appears. The identifier in an + // original-namespace-definition is the name of the namespace. Subsequently + // in that declarative region, it is treated as an original-namespace-name. + + NamedDecl *PrevDecl = LookupName(DeclRegionScope, II, LookupOrdinaryName, + true); + + if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl)) { + // This is an extended namespace definition. + // Attach this namespace decl to the chain of extended namespace + // definitions. + OrigNS->setNextNamespace(Namespc); + Namespc->setOriginalNamespace(OrigNS->getOriginalNamespace()); + + // Remove the previous declaration from the scope. + if (DeclRegionScope->isDeclScope(DeclPtrTy::make(OrigNS))) { + IdResolver.RemoveDecl(OrigNS); + DeclRegionScope->RemoveDecl(DeclPtrTy::make(OrigNS)); + } + } else if (PrevDecl) { + // This is an invalid name redefinition. + Diag(Namespc->getLocation(), diag::err_redefinition_different_kind) + << Namespc->getDeclName(); + Diag(PrevDecl->getLocation(), diag::note_previous_definition); + Namespc->setInvalidDecl(); + // Continue on to push Namespc as current DeclContext and return it. + } + + PushOnScopeChains(Namespc, DeclRegionScope); + } else { + // FIXME: Handle anonymous namespaces + } + + // Although we could have an invalid decl (i.e. the namespace name is a + // redefinition), push it as current DeclContext and try to continue parsing. + // FIXME: We should be able to push Namespc here, so that the each DeclContext + // for the namespace has the declarations that showed up in that particular + // namespace definition. + PushDeclContext(NamespcScope, Namespc); + return DeclPtrTy::make(Namespc); +} + +/// ActOnFinishNamespaceDef - This callback is called after a namespace is +/// exited. Decl is the DeclTy returned by ActOnStartNamespaceDef. +void Sema::ActOnFinishNamespaceDef(DeclPtrTy D, SourceLocation RBrace) { + Decl *Dcl = D.getAs<Decl>(); + NamespaceDecl *Namespc = dyn_cast_or_null<NamespaceDecl>(Dcl); + assert(Namespc && "Invalid parameter, expected NamespaceDecl"); + Namespc->setRBracLoc(RBrace); + PopDeclContext(); +} + +Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S, + SourceLocation UsingLoc, + SourceLocation NamespcLoc, + const CXXScopeSpec &SS, + SourceLocation IdentLoc, + IdentifierInfo *NamespcName, + AttributeList *AttrList) { + assert(!SS.isInvalid() && "Invalid CXXScopeSpec."); + assert(NamespcName && "Invalid NamespcName."); + assert(IdentLoc.isValid() && "Invalid NamespceName location."); + assert(S->getFlags() & Scope::DeclScope && "Invalid Scope."); + + UsingDirectiveDecl *UDir = 0; + + // Lookup namespace name. + LookupResult R = LookupParsedName(S, &SS, NamespcName, + LookupNamespaceName, false); + if (R.isAmbiguous()) { + DiagnoseAmbiguousLookup(R, NamespcName, IdentLoc); + return DeclPtrTy(); + } + if (NamedDecl *NS = R) { + assert(isa<NamespaceDecl>(NS) && "expected namespace decl"); + // C++ [namespace.udir]p1: + // A using-directive specifies that the names in the nominated + // namespace can be used in the scope in which the + // using-directive appears after the using-directive. During + // unqualified name lookup (3.4.1), the names appear as if they + // were declared in the nearest enclosing namespace which + // contains both the using-directive and the nominated + // namespace. [Note: in this context, “contains” means “contains + // directly or indirectly”. ] + + // Find enclosing context containing both using-directive and + // nominated namespace. + DeclContext *CommonAncestor = cast<DeclContext>(NS); + while (CommonAncestor && !CommonAncestor->Encloses(CurContext)) + CommonAncestor = CommonAncestor->getParent(); + + UDir = UsingDirectiveDecl::Create(Context, + CurContext, UsingLoc, + NamespcLoc, + SS.getRange(), + (NestedNameSpecifier *)SS.getScopeRep(), + IdentLoc, + cast<NamespaceDecl>(NS), + CommonAncestor); + PushUsingDirective(S, UDir); + } else { + Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange(); + } + + // FIXME: We ignore attributes for now. + delete AttrList; + return DeclPtrTy::make(UDir); +} + +void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) { + // If scope has associated entity, then using directive is at namespace + // or translation unit scope. We add UsingDirectiveDecls, into + // it's lookup structure. + if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) + Ctx->addDecl(Context, UDir); + else + // Otherwise it is block-sope. using-directives will affect lookup + // only to the end of scope. + S->PushUsingDirective(DeclPtrTy::make(UDir)); +} + +/// getNamespaceDecl - Returns the namespace a decl represents. If the decl +/// is a namespace alias, returns the namespace it points to. +static inline NamespaceDecl *getNamespaceDecl(NamedDecl *D) { + if (NamespaceAliasDecl *AD = dyn_cast_or_null<NamespaceAliasDecl>(D)) + return AD->getNamespace(); + return dyn_cast_or_null<NamespaceDecl>(D); +} + +Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, + SourceLocation NamespaceLoc, + SourceLocation AliasLoc, + IdentifierInfo *Alias, + const CXXScopeSpec &SS, + SourceLocation IdentLoc, + IdentifierInfo *Ident) { + + // Lookup the namespace name. + LookupResult R = LookupParsedName(S, &SS, Ident, LookupNamespaceName, false); + + // Check if we have a previous declaration with the same name. + if (NamedDecl *PrevDecl = LookupName(S, Alias, LookupOrdinaryName, true)) { + if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) { + // We already have an alias with the same name that points to the same + // namespace, so don't create a new one. + if (!R.isAmbiguous() && AD->getNamespace() == getNamespaceDecl(R)) + return DeclPtrTy(); + } + + unsigned DiagID = isa<NamespaceDecl>(PrevDecl) ? diag::err_redefinition : + diag::err_redefinition_different_kind; + Diag(AliasLoc, DiagID) << Alias; + Diag(PrevDecl->getLocation(), diag::note_previous_definition); + return DeclPtrTy(); + } + + if (R.isAmbiguous()) { + DiagnoseAmbiguousLookup(R, Ident, IdentLoc); + return DeclPtrTy(); + } + + if (!R) { + Diag(NamespaceLoc, diag::err_expected_namespace_name) << SS.getRange(); + return DeclPtrTy(); + } + + NamespaceAliasDecl *AliasDecl = + NamespaceAliasDecl::Create(Context, CurContext, NamespaceLoc, AliasLoc, + Alias, SS.getRange(), + (NestedNameSpecifier *)SS.getScopeRep(), + IdentLoc, R); + + CurContext->addDecl(Context, AliasDecl); + return DeclPtrTy::make(AliasDecl); +} + +void Sema::InitializeVarWithConstructor(VarDecl *VD, + CXXConstructorDecl *Constructor, + QualType DeclInitType, + Expr **Exprs, unsigned NumExprs) { + Expr *Temp = CXXConstructExpr::Create(Context, DeclInitType, Constructor, + false, Exprs, NumExprs); + VD->setInit(Context, Temp); +} + +/// AddCXXDirectInitializerToDecl - This action is called immediately after +/// ActOnDeclarator, when a C++ direct initializer is present. +/// e.g: "int x(1);" +void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, + SourceLocation LParenLoc, + MultiExprArg Exprs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc) { + unsigned NumExprs = Exprs.size(); + assert(NumExprs != 0 && Exprs.get() && "missing expressions"); + Decl *RealDecl = Dcl.getAs<Decl>(); + + // If there is no declaration, there was an error parsing it. Just ignore + // the initializer. + if (RealDecl == 0) + return; + + VarDecl *VDecl = dyn_cast<VarDecl>(RealDecl); + if (!VDecl) { + Diag(RealDecl->getLocation(), diag::err_illegal_initializer); + RealDecl->setInvalidDecl(); + return; + } + + // FIXME: Need to handle dependent types and expressions here. + + // We will treat direct-initialization as a copy-initialization: + // int x(1); -as-> int x = 1; + // ClassType x(a,b,c); -as-> ClassType x = ClassType(a,b,c); + // + // Clients that want to distinguish between the two forms, can check for + // direct initializer using VarDecl::hasCXXDirectInitializer(). + // A major benefit is that clients that don't particularly care about which + // exactly form was it (like the CodeGen) can handle both cases without + // special case code. + + // C++ 8.5p11: + // The form of initialization (using parentheses or '=') is generally + // insignificant, but does matter when the entity being initialized has a + // class type. + QualType DeclInitType = VDecl->getType(); + if (const ArrayType *Array = Context.getAsArrayType(DeclInitType)) + DeclInitType = Array->getElementType(); + + // FIXME: This isn't the right place to complete the type. + if (RequireCompleteType(VDecl->getLocation(), VDecl->getType(), + diag::err_typecheck_decl_incomplete_type)) { + VDecl->setInvalidDecl(); + return; + } + + if (VDecl->getType()->isRecordType()) { + CXXConstructorDecl *Constructor + = PerformInitializationByConstructor(DeclInitType, + (Expr **)Exprs.get(), NumExprs, + VDecl->getLocation(), + SourceRange(VDecl->getLocation(), + RParenLoc), + VDecl->getDeclName(), + IK_Direct); + if (!Constructor) + RealDecl->setInvalidDecl(); + else { + VDecl->setCXXDirectInitializer(true); + InitializeVarWithConstructor(VDecl, Constructor, DeclInitType, + (Expr**)Exprs.release(), NumExprs); + } + return; + } + + if (NumExprs > 1) { + Diag(CommaLocs[0], diag::err_builtin_direct_init_more_than_one_arg) + << SourceRange(VDecl->getLocation(), RParenLoc); + RealDecl->setInvalidDecl(); + return; + } + + // Let clients know that initialization was done with a direct initializer. + VDecl->setCXXDirectInitializer(true); + + assert(NumExprs == 1 && "Expected 1 expression"); + // Set the init expression, handles conversions. + AddInitializerToDecl(Dcl, ExprArg(*this, Exprs.release()[0]), + /*DirectInit=*/true); +} + +/// PerformInitializationByConstructor - Perform initialization by +/// constructor (C++ [dcl.init]p14), which may occur as part of +/// direct-initialization or copy-initialization. We are initializing +/// an object of type @p ClassType with the given arguments @p +/// Args. @p Loc is the location in the source code where the +/// initializer occurs (e.g., a declaration, member initializer, +/// functional cast, etc.) while @p Range covers the whole +/// initialization. @p InitEntity is the entity being initialized, +/// which may by the name of a declaration or a type. @p Kind is the +/// kind of initialization we're performing, which affects whether +/// explicit constructors will be considered. When successful, returns +/// the constructor that will be used to perform the initialization; +/// when the initialization fails, emits a diagnostic and returns +/// null. +CXXConstructorDecl * +Sema::PerformInitializationByConstructor(QualType ClassType, + Expr **Args, unsigned NumArgs, + SourceLocation Loc, SourceRange Range, + DeclarationName InitEntity, + InitializationKind Kind) { + const RecordType *ClassRec = ClassType->getAsRecordType(); + assert(ClassRec && "Can only initialize a class type here"); + + // C++ [dcl.init]p14: + // + // If the initialization is direct-initialization, or if it is + // copy-initialization where the cv-unqualified version of the + // source type is the same class as, or a derived class of, the + // class of the destination, constructors are considered. The + // applicable constructors are enumerated (13.3.1.3), and the + // best one is chosen through overload resolution (13.3). The + // constructor so selected is called to initialize the object, + // with the initializer expression(s) as its argument(s). If no + // constructor applies, or the overload resolution is ambiguous, + // the initialization is ill-formed. + const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(ClassRec->getDecl()); + OverloadCandidateSet CandidateSet; + + // Add constructors to the overload set. + DeclarationName ConstructorName + = Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(ClassType.getUnqualifiedType())); + DeclContext::lookup_const_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = ClassDecl->lookup(Context, ConstructorName); + Con != ConEnd; ++Con) { + CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); + if ((Kind == IK_Direct) || + (Kind == IK_Copy && Constructor->isConvertingConstructor()) || + (Kind == IK_Default && Constructor->isDefaultConstructor())) + AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet); + } + + // FIXME: When we decide not to synthesize the implicitly-declared + // constructors, we'll need to make them appear here. + + OverloadCandidateSet::iterator Best; + switch (BestViableFunction(CandidateSet, Best)) { + case OR_Success: + // We found a constructor. Return it. + return cast<CXXConstructorDecl>(Best->Function); + + case OR_No_Viable_Function: + if (InitEntity) + Diag(Loc, diag::err_ovl_no_viable_function_in_init) + << InitEntity << Range; + else + Diag(Loc, diag::err_ovl_no_viable_function_in_init) + << ClassType << Range; + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + return 0; + + case OR_Ambiguous: + if (InitEntity) + Diag(Loc, diag::err_ovl_ambiguous_init) << InitEntity << Range; + else + Diag(Loc, diag::err_ovl_ambiguous_init) << ClassType << Range; + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + return 0; + + case OR_Deleted: + if (InitEntity) + Diag(Loc, diag::err_ovl_deleted_init) + << Best->Function->isDeleted() + << InitEntity << Range; + else + Diag(Loc, diag::err_ovl_deleted_init) + << Best->Function->isDeleted() + << InitEntity << Range; + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + return 0; + } + + return 0; +} + +/// CompareReferenceRelationship - Compare the two types T1 and T2 to +/// determine whether they are reference-related, +/// reference-compatible, reference-compatible with added +/// qualification, or incompatible, for use in C++ initialization by +/// reference (C++ [dcl.ref.init]p4). Neither type can be a reference +/// type, and the first type (T1) is the pointee type of the reference +/// type being initialized. +Sema::ReferenceCompareResult +Sema::CompareReferenceRelationship(QualType T1, QualType T2, + bool& DerivedToBase) { + assert(!T1->isReferenceType() && + "T1 must be the pointee type of the reference type"); + assert(!T2->isReferenceType() && "T2 cannot be a reference type"); + + T1 = Context.getCanonicalType(T1); + T2 = Context.getCanonicalType(T2); + QualType UnqualT1 = T1.getUnqualifiedType(); + QualType UnqualT2 = T2.getUnqualifiedType(); + + // C++ [dcl.init.ref]p4: + // Given types “cv1 T1” and “cv2 T2,” “cv1 T1” is + // reference-related to “cv2 T2” if T1 is the same type as T2, or + // T1 is a base class of T2. + if (UnqualT1 == UnqualT2) + DerivedToBase = false; + else if (IsDerivedFrom(UnqualT2, UnqualT1)) + DerivedToBase = true; + else + return Ref_Incompatible; + + // At this point, we know that T1 and T2 are reference-related (at + // least). + + // C++ [dcl.init.ref]p4: + // "cv1 T1” is reference-compatible with “cv2 T2” if T1 is + // reference-related to T2 and cv1 is the same cv-qualification + // as, or greater cv-qualification than, cv2. For purposes of + // overload resolution, cases for which cv1 is greater + // cv-qualification than cv2 are identified as + // reference-compatible with added qualification (see 13.3.3.2). + if (T1.getCVRQualifiers() == T2.getCVRQualifiers()) + return Ref_Compatible; + else if (T1.isMoreQualifiedThan(T2)) + return Ref_Compatible_With_Added_Qualification; + else + return Ref_Related; +} + +/// CheckReferenceInit - Check the initialization of a reference +/// variable with the given initializer (C++ [dcl.init.ref]). Init is +/// the initializer (either a simple initializer or an initializer +/// list), and DeclType is the type of the declaration. When ICS is +/// non-null, this routine will compute the implicit conversion +/// sequence according to C++ [over.ics.ref] and will not produce any +/// diagnostics; when ICS is null, it will emit diagnostics when any +/// errors are found. Either way, a return value of true indicates +/// that there was a failure, a return value of false indicates that +/// the reference initialization succeeded. +/// +/// When @p SuppressUserConversions, user-defined conversions are +/// suppressed. +/// When @p AllowExplicit, we also permit explicit user-defined +/// conversion functions. +/// When @p ForceRValue, we unconditionally treat the initializer as an rvalue. +bool +Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, + ImplicitConversionSequence *ICS, + bool SuppressUserConversions, + bool AllowExplicit, bool ForceRValue) { + assert(DeclType->isReferenceType() && "Reference init needs a reference"); + + QualType T1 = DeclType->getAsReferenceType()->getPointeeType(); + QualType T2 = Init->getType(); + + // If the initializer is the address of an overloaded function, try + // to resolve the overloaded function. If all goes well, T2 is the + // type of the resulting function. + if (Context.getCanonicalType(T2) == Context.OverloadTy) { + FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType, + ICS != 0); + if (Fn) { + // Since we're performing this reference-initialization for + // real, update the initializer with the resulting function. + if (!ICS) { + if (DiagnoseUseOfDecl(Fn, Init->getSourceRange().getBegin())) + return true; + + FixOverloadedFunctionReference(Init, Fn); + } + + T2 = Fn->getType(); + } + } + + // Compute some basic properties of the types and the initializer. + bool isRValRef = DeclType->isRValueReferenceType(); + bool DerivedToBase = false; + Expr::isLvalueResult InitLvalue = ForceRValue ? Expr::LV_InvalidExpression : + Init->isLvalue(Context); + ReferenceCompareResult RefRelationship + = CompareReferenceRelationship(T1, T2, DerivedToBase); + + // Most paths end in a failed conversion. + if (ICS) + ICS->ConversionKind = ImplicitConversionSequence::BadConversion; + + // C++ [dcl.init.ref]p5: + // A reference to type “cv1 T1” is initialized by an expression + // of type “cv2 T2” as follows: + + // -- If the initializer expression + + // Rvalue references cannot bind to lvalues (N2812). + // There is absolutely no situation where they can. In particular, note that + // this is ill-formed, even if B has a user-defined conversion to A&&: + // B b; + // A&& r = b; + if (isRValRef && InitLvalue == Expr::LV_Valid) { + if (!ICS) + Diag(Init->getSourceRange().getBegin(), diag::err_lvalue_to_rvalue_ref) + << Init->getSourceRange(); + return true; + } + + bool BindsDirectly = false; + // -- is an lvalue (but is not a bit-field), and “cv1 T1” is + // reference-compatible with “cv2 T2,” or + // + // Note that the bit-field check is skipped if we are just computing + // the implicit conversion sequence (C++ [over.best.ics]p2). + if (InitLvalue == Expr::LV_Valid && (ICS || !Init->getBitField()) && + RefRelationship >= Ref_Compatible_With_Added_Qualification) { + BindsDirectly = true; + + if (ICS) { + // C++ [over.ics.ref]p1: + // When a parameter of reference type binds directly (8.5.3) + // to an argument expression, the implicit conversion sequence + // is the identity conversion, unless the argument expression + // has a type that is a derived class of the parameter type, + // in which case the implicit conversion sequence is a + // derived-to-base Conversion (13.3.3.1). + ICS->ConversionKind = ImplicitConversionSequence::StandardConversion; + ICS->Standard.First = ICK_Identity; + ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; + ICS->Standard.Third = ICK_Identity; + ICS->Standard.FromTypePtr = T2.getAsOpaquePtr(); + ICS->Standard.ToTypePtr = T1.getAsOpaquePtr(); + ICS->Standard.ReferenceBinding = true; + ICS->Standard.DirectBinding = true; + ICS->Standard.RRefBinding = false; + ICS->Standard.CopyConstructor = 0; + + // Nothing more to do: the inaccessibility/ambiguity check for + // derived-to-base conversions is suppressed when we're + // computing the implicit conversion sequence (C++ + // [over.best.ics]p2). + return false; + } else { + // Perform the conversion. + // FIXME: Binding to a subobject of the lvalue is going to require more + // AST annotation than this. + ImpCastExprToType(Init, T1, /*isLvalue=*/true); + } + } + + // -- has a class type (i.e., T2 is a class type) and can be + // implicitly converted to an lvalue of type “cv3 T3,” + // where “cv1 T1” is reference-compatible with “cv3 T3” + // 92) (this conversion is selected by enumerating the + // applicable conversion functions (13.3.1.6) and choosing + // the best one through overload resolution (13.3)), + if (!isRValRef && !SuppressUserConversions && T2->isRecordType()) { + // FIXME: Look for conversions in base classes! + CXXRecordDecl *T2RecordDecl + = dyn_cast<CXXRecordDecl>(T2->getAsRecordType()->getDecl()); + + OverloadCandidateSet CandidateSet; + OverloadedFunctionDecl *Conversions + = T2RecordDecl->getConversionFunctions(); + for (OverloadedFunctionDecl::function_iterator Func + = Conversions->function_begin(); + Func != Conversions->function_end(); ++Func) { + CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func); + + // If the conversion function doesn't return a reference type, + // it can't be considered for this conversion. + if (Conv->getConversionType()->isLValueReferenceType() && + (AllowExplicit || !Conv->isExplicit())) + AddConversionCandidate(Conv, Init, DeclType, CandidateSet); + } + + OverloadCandidateSet::iterator Best; + switch (BestViableFunction(CandidateSet, Best)) { + case OR_Success: + // This is a direct binding. + BindsDirectly = true; + + if (ICS) { + // C++ [over.ics.ref]p1: + // + // [...] If the parameter binds directly to the result of + // applying a conversion function to the argument + // expression, the implicit conversion sequence is a + // user-defined conversion sequence (13.3.3.1.2), with the + // second standard conversion sequence either an identity + // conversion or, if the conversion function returns an + // entity of a type that is a derived class of the parameter + // type, a derived-to-base Conversion. + ICS->ConversionKind = ImplicitConversionSequence::UserDefinedConversion; + ICS->UserDefined.Before = Best->Conversions[0].Standard; + ICS->UserDefined.After = Best->FinalConversion; + ICS->UserDefined.ConversionFunction = Best->Function; + assert(ICS->UserDefined.After.ReferenceBinding && + ICS->UserDefined.After.DirectBinding && + "Expected a direct reference binding!"); + return false; + } else { + // Perform the conversion. + // FIXME: Binding to a subobject of the lvalue is going to require more + // AST annotation than this. + ImpCastExprToType(Init, T1, /*isLvalue=*/true); + } + break; + + case OR_Ambiguous: + assert(false && "Ambiguous reference binding conversions not implemented."); + return true; + + case OR_No_Viable_Function: + case OR_Deleted: + // There was no suitable conversion, or we found a deleted + // conversion; continue with other checks. + break; + } + } + + if (BindsDirectly) { + // C++ [dcl.init.ref]p4: + // [...] In all cases where the reference-related or + // reference-compatible relationship of two types is used to + // establish the validity of a reference binding, and T1 is a + // base class of T2, a program that necessitates such a binding + // is ill-formed if T1 is an inaccessible (clause 11) or + // ambiguous (10.2) base class of T2. + // + // Note that we only check this condition when we're allowed to + // complain about errors, because we should not be checking for + // ambiguity (or inaccessibility) unless the reference binding + // actually happens. + if (DerivedToBase) + return CheckDerivedToBaseConversion(T2, T1, + Init->getSourceRange().getBegin(), + Init->getSourceRange()); + else + return false; + } + + // -- Otherwise, the reference shall be to a non-volatile const + // type (i.e., cv1 shall be const), or the reference shall be an + // rvalue reference and the initializer expression shall be an rvalue. + if (!isRValRef && T1.getCVRQualifiers() != QualType::Const) { + if (!ICS) + Diag(Init->getSourceRange().getBegin(), + diag::err_not_reference_to_const_init) + << T1 << (InitLvalue != Expr::LV_Valid? "temporary" : "value") + << T2 << Init->getSourceRange(); + return true; + } + + // -- If the initializer expression is an rvalue, with T2 a + // class type, and “cv1 T1” is reference-compatible with + // “cv2 T2,” the reference is bound in one of the + // following ways (the choice is implementation-defined): + // + // -- The reference is bound to the object represented by + // the rvalue (see 3.10) or to a sub-object within that + // object. + // + // -- A temporary of type “cv1 T2” [sic] is created, and + // a constructor is called to copy the entire rvalue + // object into the temporary. The reference is bound to + // the temporary or to a sub-object within the + // temporary. + // + // The constructor that would be used to make the copy + // shall be callable whether or not the copy is actually + // done. + // + // Note that C++0x [dcl.init.ref]p5 takes away this implementation + // freedom, so we will always take the first option and never build + // a temporary in this case. FIXME: We will, however, have to check + // for the presence of a copy constructor in C++98/03 mode. + if (InitLvalue != Expr::LV_Valid && T2->isRecordType() && + RefRelationship >= Ref_Compatible_With_Added_Qualification) { + if (ICS) { + ICS->ConversionKind = ImplicitConversionSequence::StandardConversion; + ICS->Standard.First = ICK_Identity; + ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; + ICS->Standard.Third = ICK_Identity; + ICS->Standard.FromTypePtr = T2.getAsOpaquePtr(); + ICS->Standard.ToTypePtr = T1.getAsOpaquePtr(); + ICS->Standard.ReferenceBinding = true; + ICS->Standard.DirectBinding = false; + ICS->Standard.RRefBinding = isRValRef; + ICS->Standard.CopyConstructor = 0; + } else { + // FIXME: Binding to a subobject of the rvalue is going to require more + // AST annotation than this. + ImpCastExprToType(Init, T1, /*isLvalue=*/false); + } + return false; + } + + // -- Otherwise, a temporary of type “cv1 T1” is created and + // initialized from the initializer expression using the + // rules for a non-reference copy initialization (8.5). The + // reference is then bound to the temporary. If T1 is + // reference-related to T2, cv1 must be the same + // cv-qualification as, or greater cv-qualification than, + // cv2; otherwise, the program is ill-formed. + if (RefRelationship == Ref_Related) { + // If cv1 == cv2 or cv1 is a greater cv-qualified than cv2, then + // we would be reference-compatible or reference-compatible with + // added qualification. But that wasn't the case, so the reference + // initialization fails. + if (!ICS) + Diag(Init->getSourceRange().getBegin(), + diag::err_reference_init_drops_quals) + << T1 << (InitLvalue != Expr::LV_Valid? "temporary" : "value") + << T2 << Init->getSourceRange(); + return true; + } + + // If at least one of the types is a class type, the types are not + // related, and we aren't allowed any user conversions, the + // reference binding fails. This case is important for breaking + // recursion, since TryImplicitConversion below will attempt to + // create a temporary through the use of a copy constructor. + if (SuppressUserConversions && RefRelationship == Ref_Incompatible && + (T1->isRecordType() || T2->isRecordType())) { + if (!ICS) + Diag(Init->getSourceRange().getBegin(), + diag::err_typecheck_convert_incompatible) + << DeclType << Init->getType() << "initializing" << Init->getSourceRange(); + return true; + } + + // Actually try to convert the initializer to T1. + if (ICS) { + // C++ [over.ics.ref]p2: + // + // When a parameter of reference type is not bound directly to + // an argument expression, the conversion sequence is the one + // required to convert the argument expression to the + // underlying type of the reference according to + // 13.3.3.1. Conceptually, this conversion sequence corresponds + // to copy-initializing a temporary of the underlying type with + // the argument expression. Any difference in top-level + // cv-qualification is subsumed by the initialization itself + // and does not constitute a conversion. + *ICS = TryImplicitConversion(Init, T1, SuppressUserConversions); + // Of course, that's still a reference binding. + if (ICS->ConversionKind == ImplicitConversionSequence::StandardConversion) { + ICS->Standard.ReferenceBinding = true; + ICS->Standard.RRefBinding = isRValRef; + } else if(ICS->ConversionKind == + ImplicitConversionSequence::UserDefinedConversion) { + ICS->UserDefined.After.ReferenceBinding = true; + ICS->UserDefined.After.RRefBinding = isRValRef; + } + return ICS->ConversionKind == ImplicitConversionSequence::BadConversion; + } else { + return PerformImplicitConversion(Init, T1, "initializing"); + } +} + +/// CheckOverloadedOperatorDeclaration - Check whether the declaration +/// of this overloaded operator is well-formed. If so, returns false; +/// otherwise, emits appropriate diagnostics and returns true. +bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { + assert(FnDecl && FnDecl->isOverloadedOperator() && + "Expected an overloaded operator declaration"); + + OverloadedOperatorKind Op = FnDecl->getOverloadedOperator(); + + // C++ [over.oper]p5: + // The allocation and deallocation functions, operator new, + // operator new[], operator delete and operator delete[], are + // described completely in 3.7.3. The attributes and restrictions + // found in the rest of this subclause do not apply to them unless + // explicitly stated in 3.7.3. + // FIXME: Write a separate routine for checking this. For now, just allow it. + if (Op == OO_New || Op == OO_Array_New || + Op == OO_Delete || Op == OO_Array_Delete) + return false; + + // C++ [over.oper]p6: + // An operator function shall either be a non-static member + // function or be a non-member function and have at least one + // parameter whose type is a class, a reference to a class, an + // enumeration, or a reference to an enumeration. + if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(FnDecl)) { + if (MethodDecl->isStatic()) + return Diag(FnDecl->getLocation(), + diag::err_operator_overload_static) << FnDecl->getDeclName(); + } else { + bool ClassOrEnumParam = false; + for (FunctionDecl::param_iterator Param = FnDecl->param_begin(), + ParamEnd = FnDecl->param_end(); + Param != ParamEnd; ++Param) { + QualType ParamType = (*Param)->getType().getNonReferenceType(); + if (ParamType->isRecordType() || ParamType->isEnumeralType()) { + ClassOrEnumParam = true; + break; + } + } + + if (!ClassOrEnumParam) + return Diag(FnDecl->getLocation(), + diag::err_operator_overload_needs_class_or_enum) + << FnDecl->getDeclName(); + } + + // C++ [over.oper]p8: + // An operator function cannot have default arguments (8.3.6), + // except where explicitly stated below. + // + // Only the function-call operator allows default arguments + // (C++ [over.call]p1). + if (Op != OO_Call) { + for (FunctionDecl::param_iterator Param = FnDecl->param_begin(); + Param != FnDecl->param_end(); ++Param) { + if ((*Param)->hasUnparsedDefaultArg()) + return Diag((*Param)->getLocation(), + diag::err_operator_overload_default_arg) + << FnDecl->getDeclName(); + else if (Expr *DefArg = (*Param)->getDefaultArg()) + return Diag((*Param)->getLocation(), + diag::err_operator_overload_default_arg) + << FnDecl->getDeclName() << DefArg->getSourceRange(); + } + } + + static const bool OperatorUses[NUM_OVERLOADED_OPERATORS][3] = { + { false, false, false } +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + , { Unary, Binary, MemberOnly } +#include "clang/Basic/OperatorKinds.def" + }; + + bool CanBeUnaryOperator = OperatorUses[Op][0]; + bool CanBeBinaryOperator = OperatorUses[Op][1]; + bool MustBeMemberOperator = OperatorUses[Op][2]; + + // C++ [over.oper]p8: + // [...] Operator functions cannot have more or fewer parameters + // than the number required for the corresponding operator, as + // described in the rest of this subclause. + unsigned NumParams = FnDecl->getNumParams() + + (isa<CXXMethodDecl>(FnDecl)? 1 : 0); + if (Op != OO_Call && + ((NumParams == 1 && !CanBeUnaryOperator) || + (NumParams == 2 && !CanBeBinaryOperator) || + (NumParams < 1) || (NumParams > 2))) { + // We have the wrong number of parameters. + unsigned ErrorKind; + if (CanBeUnaryOperator && CanBeBinaryOperator) { + ErrorKind = 2; // 2 -> unary or binary. + } else if (CanBeUnaryOperator) { + ErrorKind = 0; // 0 -> unary + } else { + assert(CanBeBinaryOperator && + "All non-call overloaded operators are unary or binary!"); + ErrorKind = 1; // 1 -> binary + } + + return Diag(FnDecl->getLocation(), diag::err_operator_overload_must_be) + << FnDecl->getDeclName() << NumParams << ErrorKind; + } + + // Overloaded operators other than operator() cannot be variadic. + if (Op != OO_Call && + FnDecl->getType()->getAsFunctionProtoType()->isVariadic()) { + return Diag(FnDecl->getLocation(), diag::err_operator_overload_variadic) + << FnDecl->getDeclName(); + } + + // Some operators must be non-static member functions. + if (MustBeMemberOperator && !isa<CXXMethodDecl>(FnDecl)) { + return Diag(FnDecl->getLocation(), + diag::err_operator_overload_must_be_member) + << FnDecl->getDeclName(); + } + + // C++ [over.inc]p1: + // The user-defined function called operator++ implements the + // prefix and postfix ++ operator. If this function is a member + // function with no parameters, or a non-member function with one + // parameter of class or enumeration type, it defines the prefix + // increment operator ++ for objects of that type. If the function + // is a member function with one parameter (which shall be of type + // int) or a non-member function with two parameters (the second + // of which shall be of type int), it defines the postfix + // increment operator ++ for objects of that type. + if ((Op == OO_PlusPlus || Op == OO_MinusMinus) && NumParams == 2) { + ParmVarDecl *LastParam = FnDecl->getParamDecl(FnDecl->getNumParams() - 1); + bool ParamIsInt = false; + if (const BuiltinType *BT = LastParam->getType()->getAsBuiltinType()) + ParamIsInt = BT->getKind() == BuiltinType::Int; + + if (!ParamIsInt) + return Diag(LastParam->getLocation(), + diag::err_operator_overload_post_incdec_must_be_int) + << LastParam->getType() << (Op == OO_MinusMinus); + } + + // Notify the class if it got an assignment operator. + if (Op == OO_Equal) { + // Would have returned earlier otherwise. + assert(isa<CXXMethodDecl>(FnDecl) && + "Overloaded = not member, but not filtered."); + CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl); + Method->getParent()->addedAssignmentOperator(Context, Method); + } + + return false; +} + +/// ActOnStartLinkageSpecification - Parsed the beginning of a C++ +/// linkage specification, including the language and (if present) +/// the '{'. ExternLoc is the location of the 'extern', LangLoc is +/// the location of the language string literal, which is provided +/// by Lang/StrSize. LBraceLoc, if valid, provides the location of +/// the '{' brace. Otherwise, this linkage specification does not +/// have any braces. +Sema::DeclPtrTy Sema::ActOnStartLinkageSpecification(Scope *S, + SourceLocation ExternLoc, + SourceLocation LangLoc, + const char *Lang, + unsigned StrSize, + SourceLocation LBraceLoc) { + LinkageSpecDecl::LanguageIDs Language; + if (strncmp(Lang, "\"C\"", StrSize) == 0) + Language = LinkageSpecDecl::lang_c; + else if (strncmp(Lang, "\"C++\"", StrSize) == 0) + Language = LinkageSpecDecl::lang_cxx; + else { + Diag(LangLoc, diag::err_bad_language); + return DeclPtrTy(); + } + + // FIXME: Add all the various semantics of linkage specifications + + LinkageSpecDecl *D = LinkageSpecDecl::Create(Context, CurContext, + LangLoc, Language, + LBraceLoc.isValid()); + CurContext->addDecl(Context, D); + PushDeclContext(S, D); + return DeclPtrTy::make(D); +} + +/// ActOnFinishLinkageSpecification - Completely the definition of +/// the C++ linkage specification LinkageSpec. If RBraceLoc is +/// valid, it's the position of the closing '}' brace in a linkage +/// specification that uses braces. +Sema::DeclPtrTy Sema::ActOnFinishLinkageSpecification(Scope *S, + DeclPtrTy LinkageSpec, + SourceLocation RBraceLoc) { + if (LinkageSpec) + PopDeclContext(); + return LinkageSpec; +} + +/// \brief Perform semantic analysis for the variable declaration that +/// occurs within a C++ catch clause, returning the newly-created +/// variable. +VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, + IdentifierInfo *Name, + SourceLocation Loc, + SourceRange Range) { + bool Invalid = false; + + // Arrays and functions decay. + if (ExDeclType->isArrayType()) + ExDeclType = Context.getArrayDecayedType(ExDeclType); + else if (ExDeclType->isFunctionType()) + ExDeclType = Context.getPointerType(ExDeclType); + + // C++ 15.3p1: The exception-declaration shall not denote an incomplete type. + // The exception-declaration shall not denote a pointer or reference to an + // incomplete type, other than [cv] void*. + // N2844 forbids rvalue references. + if(!ExDeclType->isDependentType() && ExDeclType->isRValueReferenceType()) { + Diag(Loc, diag::err_catch_rvalue_ref) << Range; + Invalid = true; + } + + QualType BaseType = ExDeclType; + int Mode = 0; // 0 for direct type, 1 for pointer, 2 for reference + unsigned DK = diag::err_catch_incomplete; + if (const PointerType *Ptr = BaseType->getAsPointerType()) { + BaseType = Ptr->getPointeeType(); + Mode = 1; + DK = diag::err_catch_incomplete_ptr; + } else if(const ReferenceType *Ref = BaseType->getAsReferenceType()) { + // For the purpose of error recovery, we treat rvalue refs like lvalue refs. + BaseType = Ref->getPointeeType(); + Mode = 2; + DK = diag::err_catch_incomplete_ref; + } + if (!Invalid && (Mode == 0 || !BaseType->isVoidType()) && + !BaseType->isDependentType() && RequireCompleteType(Loc, BaseType, DK)) + Invalid = true; + + if (!Invalid && !ExDeclType->isDependentType() && + RequireNonAbstractType(Loc, ExDeclType, + diag::err_abstract_type_in_decl, + AbstractVariableType)) + Invalid = true; + + // FIXME: Need to test for ability to copy-construct and destroy the + // exception variable. + + // FIXME: Need to check for abstract classes. + + VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc, + Name, ExDeclType, VarDecl::None, + Range.getBegin()); + + if (Invalid) + ExDecl->setInvalidDecl(); + + return ExDecl; +} + +/// ActOnExceptionDeclarator - Parsed the exception-declarator in a C++ catch +/// handler. +Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { + QualType ExDeclType = GetTypeForDeclarator(D, S); + + bool Invalid = D.isInvalidType(); + IdentifierInfo *II = D.getIdentifier(); + if (NamedDecl *PrevDecl = LookupName(S, II, LookupOrdinaryName)) { + // The scope should be freshly made just for us. There is just no way + // it contains any previous declaration. + assert(!S->isDeclScope(DeclPtrTy::make(PrevDecl))); + if (PrevDecl->isTemplateParameter()) { + // Maybe we will complain about the shadowed template parameter. + DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); + } + } + + if (D.getCXXScopeSpec().isSet() && !Invalid) { + Diag(D.getIdentifierLoc(), diag::err_qualified_catch_declarator) + << D.getCXXScopeSpec().getRange(); + Invalid = true; + } + + VarDecl *ExDecl = BuildExceptionDeclaration(S, ExDeclType, + D.getIdentifier(), + D.getIdentifierLoc(), + D.getDeclSpec().getSourceRange()); + + if (Invalid) + ExDecl->setInvalidDecl(); + + // Add the exception declaration into this scope. + if (II) + PushOnScopeChains(ExDecl, S); + else + CurContext->addDecl(Context, ExDecl); + + ProcessDeclAttributes(ExDecl, D); + return DeclPtrTy::make(ExDecl); +} + +Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc, + ExprArg assertexpr, + ExprArg assertmessageexpr) { + Expr *AssertExpr = (Expr *)assertexpr.get(); + StringLiteral *AssertMessage = + cast<StringLiteral>((Expr *)assertmessageexpr.get()); + + if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent()) { + llvm::APSInt Value(32); + if (!AssertExpr->isIntegerConstantExpr(Value, Context)) { + Diag(AssertLoc, diag::err_static_assert_expression_is_not_constant) << + AssertExpr->getSourceRange(); + return DeclPtrTy(); + } + + if (Value == 0) { + std::string str(AssertMessage->getStrData(), + AssertMessage->getByteLength()); + Diag(AssertLoc, diag::err_static_assert_failed) + << str << AssertExpr->getSourceRange(); + } + } + + assertexpr.release(); + assertmessageexpr.release(); + Decl *Decl = StaticAssertDecl::Create(Context, CurContext, AssertLoc, + AssertExpr, AssertMessage); + + CurContext->addDecl(Context, Decl); + return DeclPtrTy::make(Decl); +} + +bool Sema::ActOnFriendDecl(Scope *S, SourceLocation FriendLoc, DeclPtrTy Dcl) { + if (!(S->getFlags() & Scope::ClassScope)) { + Diag(FriendLoc, diag::err_friend_decl_outside_class); + return true; + } + + return false; +} + +void Sema::SetDeclDeleted(DeclPtrTy dcl, SourceLocation DelLoc) { + Decl *Dcl = dcl.getAs<Decl>(); + FunctionDecl *Fn = dyn_cast<FunctionDecl>(Dcl); + if (!Fn) { + Diag(DelLoc, diag::err_deleted_non_function); + return; + } + if (const FunctionDecl *Prev = Fn->getPreviousDeclaration()) { + Diag(DelLoc, diag::err_deleted_decl_not_first); + Diag(Prev->getLocation(), diag::note_previous_declaration); + // If the declaration wasn't the first, we delete the function anyway for + // recovery. + } + Fn->setDeleted(); +} + +static void SearchForReturnInStmt(Sema &Self, Stmt *S) { + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E; + ++CI) { + Stmt *SubStmt = *CI; + if (!SubStmt) + continue; + if (isa<ReturnStmt>(SubStmt)) + Self.Diag(SubStmt->getSourceRange().getBegin(), + diag::err_return_in_constructor_handler); + if (!isa<Expr>(SubStmt)) + SearchForReturnInStmt(Self, SubStmt); + } +} + +void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) { + for (unsigned I = 0, E = TryBlock->getNumHandlers(); I != E; ++I) { + CXXCatchStmt *Handler = TryBlock->getHandler(I); + SearchForReturnInStmt(*this, Handler); + } +} + +bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, + const CXXMethodDecl *Old) { + QualType NewTy = New->getType()->getAsFunctionType()->getResultType(); + QualType OldTy = Old->getType()->getAsFunctionType()->getResultType(); + + QualType CNewTy = Context.getCanonicalType(NewTy); + QualType COldTy = Context.getCanonicalType(OldTy); + + if (CNewTy == COldTy && + CNewTy.getCVRQualifiers() == COldTy.getCVRQualifiers()) + return false; + + // Check if the return types are covariant + QualType NewClassTy, OldClassTy; + + /// Both types must be pointers or references to classes. + if (PointerType *NewPT = dyn_cast<PointerType>(NewTy)) { + if (PointerType *OldPT = dyn_cast<PointerType>(OldTy)) { + NewClassTy = NewPT->getPointeeType(); + OldClassTy = OldPT->getPointeeType(); + } + } else if (ReferenceType *NewRT = dyn_cast<ReferenceType>(NewTy)) { + if (ReferenceType *OldRT = dyn_cast<ReferenceType>(OldTy)) { + NewClassTy = NewRT->getPointeeType(); + OldClassTy = OldRT->getPointeeType(); + } + } + + // The return types aren't either both pointers or references to a class type. + if (NewClassTy.isNull()) { + Diag(New->getLocation(), + diag::err_different_return_type_for_overriding_virtual_function) + << New->getDeclName() << NewTy << OldTy; + Diag(Old->getLocation(), diag::note_overridden_virtual_function); + + return true; + } + + if (NewClassTy.getUnqualifiedType() != OldClassTy.getUnqualifiedType()) { + // Check if the new class derives from the old class. + if (!IsDerivedFrom(NewClassTy, OldClassTy)) { + Diag(New->getLocation(), + diag::err_covariant_return_not_derived) + << New->getDeclName() << NewTy << OldTy; + Diag(Old->getLocation(), diag::note_overridden_virtual_function); + return true; + } + + // Check if we the conversion from derived to base is valid. + if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy, + diag::err_covariant_return_inaccessible_base, + diag::err_covariant_return_ambiguous_derived_to_base_conv, + // FIXME: Should this point to the return type? + New->getLocation(), SourceRange(), New->getDeclName())) { + Diag(Old->getLocation(), diag::note_overridden_virtual_function); + return true; + } + } + + // The qualifiers of the return types must be the same. + if (CNewTy.getCVRQualifiers() != COldTy.getCVRQualifiers()) { + Diag(New->getLocation(), + diag::err_covariant_return_type_different_qualifications) + << New->getDeclName() << NewTy << OldTy; + Diag(Old->getLocation(), diag::note_overridden_virtual_function); + return true; + }; + + + // The new class type must have the same or less qualifiers as the old type. + if (NewClassTy.isMoreQualifiedThan(OldClassTy)) { + Diag(New->getLocation(), + diag::err_covariant_return_type_class_type_more_qualified) + << New->getDeclName() << NewTy << OldTy; + Diag(Old->getLocation(), diag::note_overridden_virtual_function); + return true; + }; + + return false; +} diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp new file mode 100644 index 0000000..8f58034 --- /dev/null +++ b/lib/Sema/SemaDeclObjC.cpp @@ -0,0 +1,2166 @@ +//===--- SemaDeclObjC.cpp - Semantic Analysis for ObjC Declarations -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for Objective C declarations. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/Sema/ExternalSemaSource.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Parse/DeclSpec.h" +using namespace clang; + +bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property, + ObjCMethodDecl *GetterMethod, + SourceLocation Loc) { + if (GetterMethod && + GetterMethod->getResultType() != property->getType()) { + AssignConvertType result = Incompatible; + if (Context.isObjCObjectPointerType(property->getType())) + result = CheckAssignmentConstraints(GetterMethod->getResultType(), property->getType()); + if (result != Compatible) { + Diag(Loc, diag::warn_accessor_property_type_mismatch) + << property->getDeclName() + << GetterMethod->getSelector(); + Diag(GetterMethod->getLocation(), diag::note_declared_at); + return true; + } + } + return false; +} + +/// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible +/// and user declared, in the method definition's AST. +void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) { + assert(getCurMethodDecl() == 0 && "Method parsing confused"); + ObjCMethodDecl *MDecl = dyn_cast_or_null<ObjCMethodDecl>(D.getAs<Decl>()); + + // If we don't have a valid method decl, simply return. + if (!MDecl) + return; + + CurFunctionNeedsScopeChecking = false; + + // Allow the rest of sema to find private method decl implementations. + if (MDecl->isInstanceMethod()) + AddInstanceMethodToGlobalPool(MDecl); + else + AddFactoryMethodToGlobalPool(MDecl); + + // Allow all of Sema to see that we are entering a method definition. + PushDeclContext(FnBodyScope, MDecl); + + // Create Decl objects for each parameter, entrring them in the scope for + // binding to their use. + + // Insert the invisible arguments, self and _cmd! + MDecl->createImplicitParams(Context, MDecl->getClassInterface()); + + PushOnScopeChains(MDecl->getSelfDecl(), FnBodyScope); + PushOnScopeChains(MDecl->getCmdDecl(), FnBodyScope); + + // Introduce all of the other parameters into this scope. + for (ObjCMethodDecl::param_iterator PI = MDecl->param_begin(), + E = MDecl->param_end(); PI != E; ++PI) + if ((*PI)->getIdentifier()) + PushOnScopeChains(*PI, FnBodyScope); +} + +Sema::DeclPtrTy Sema:: +ActOnStartClassInterface(SourceLocation AtInterfaceLoc, + IdentifierInfo *ClassName, SourceLocation ClassLoc, + IdentifierInfo *SuperName, SourceLocation SuperLoc, + const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, + SourceLocation EndProtoLoc, AttributeList *AttrList) { + assert(ClassName && "Missing class identifier"); + + // Check for another declaration kind with the same name. + NamedDecl *PrevDecl = LookupName(TUScope, ClassName, LookupOrdinaryName); + if (PrevDecl && PrevDecl->isTemplateParameter()) { + // Maybe we will complain about the shadowed template parameter. + DiagnoseTemplateParameterShadow(ClassLoc, PrevDecl); + // Just pretend that we didn't see the previous declaration. + PrevDecl = 0; + } + + if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) { + Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName; + Diag(PrevDecl->getLocation(), diag::note_previous_definition); + } + + ObjCInterfaceDecl* IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); + if (IDecl) { + // Class already seen. Is it a forward declaration? + if (!IDecl->isForwardDecl()) { + IDecl->setInvalidDecl(); + Diag(AtInterfaceLoc, diag::err_duplicate_class_def)<<IDecl->getDeclName(); + Diag(IDecl->getLocation(), diag::note_previous_definition); + + // Return the previous class interface. + // FIXME: don't leak the objects passed in! + return DeclPtrTy::make(IDecl); + } else { + IDecl->setLocation(AtInterfaceLoc); + IDecl->setForwardDecl(false); + } + } else { + IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc, + ClassName, ClassLoc); + if (AttrList) + ProcessDeclAttributeList(IDecl, AttrList); + + PushOnScopeChains(IDecl, TUScope); + } + + if (SuperName) { + // Check if a different kind of symbol declared in this scope. + PrevDecl = LookupName(TUScope, SuperName, LookupOrdinaryName); + + ObjCInterfaceDecl *SuperClassDecl = + dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); + + // Diagnose classes that inherit from deprecated classes. + if (SuperClassDecl) + (void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc); + + if (PrevDecl && SuperClassDecl == 0) { + // The previous declaration was not a class decl. Check if we have a + // typedef. If we do, get the underlying class type. + if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(PrevDecl)) { + QualType T = TDecl->getUnderlyingType(); + if (T->isObjCInterfaceType()) { + if (NamedDecl *IDecl = T->getAsObjCInterfaceType()->getDecl()) + SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl); + } + } + + // This handles the following case: + // + // typedef int SuperClass; + // @interface MyClass : SuperClass {} @end + // + if (!SuperClassDecl) { + Diag(SuperLoc, diag::err_redefinition_different_kind) << SuperName; + Diag(PrevDecl->getLocation(), diag::note_previous_definition); + } + } + + if (!dyn_cast_or_null<TypedefDecl>(PrevDecl)) { + if (!SuperClassDecl) + Diag(SuperLoc, diag::err_undef_superclass) + << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); + else if (SuperClassDecl->isForwardDecl()) + Diag(SuperLoc, diag::err_undef_superclass) + << SuperClassDecl->getDeclName() << ClassName + << SourceRange(AtInterfaceLoc, ClassLoc); + } + IDecl->setSuperClass(SuperClassDecl); + IDecl->setSuperClassLoc(SuperLoc); + IDecl->setLocEnd(SuperLoc); + } else { // we have a root class. + IDecl->setLocEnd(ClassLoc); + } + + /// Check then save referenced protocols. + if (NumProtoRefs) { + IDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, + Context); + IDecl->setLocEnd(EndProtoLoc); + } + + CheckObjCDeclScope(IDecl); + return DeclPtrTy::make(IDecl); +} + +/// ActOnCompatiblityAlias - this action is called after complete parsing of +/// @compatibility_alias declaration. It sets up the alias relationships. +Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc, + IdentifierInfo *AliasName, + SourceLocation AliasLocation, + IdentifierInfo *ClassName, + SourceLocation ClassLocation) { + // Look for previous declaration of alias name + NamedDecl *ADecl = LookupName(TUScope, AliasName, LookupOrdinaryName); + if (ADecl) { + if (isa<ObjCCompatibleAliasDecl>(ADecl)) + Diag(AliasLocation, diag::warn_previous_alias_decl); + else + Diag(AliasLocation, diag::err_conflicting_aliasing_type) << AliasName; + Diag(ADecl->getLocation(), diag::note_previous_declaration); + return DeclPtrTy(); + } + // Check for class declaration + NamedDecl *CDeclU = LookupName(TUScope, ClassName, LookupOrdinaryName); + if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(CDeclU)) { + QualType T = TDecl->getUnderlyingType(); + if (T->isObjCInterfaceType()) { + if (NamedDecl *IDecl = T->getAsObjCInterfaceType()->getDecl()) { + ClassName = IDecl->getIdentifier(); + CDeclU = LookupName(TUScope, ClassName, LookupOrdinaryName); + } + } + } + ObjCInterfaceDecl *CDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDeclU); + if (CDecl == 0) { + Diag(ClassLocation, diag::warn_undef_interface) << ClassName; + if (CDeclU) + Diag(CDeclU->getLocation(), diag::note_previous_declaration); + return DeclPtrTy(); + } + + // Everything checked out, instantiate a new alias declaration AST. + ObjCCompatibleAliasDecl *AliasDecl = + ObjCCompatibleAliasDecl::Create(Context, CurContext, AtLoc, AliasName, CDecl); + + if (!CheckObjCDeclScope(AliasDecl)) + PushOnScopeChains(AliasDecl, TUScope); + + return DeclPtrTy::make(AliasDecl); +} + +void Sema::CheckForwardProtocolDeclarationForCircularDependency( + IdentifierInfo *PName, + SourceLocation &Ploc, SourceLocation PrevLoc, + const ObjCList<ObjCProtocolDecl> &PList) +{ + for (ObjCList<ObjCProtocolDecl>::iterator I = PList.begin(), + E = PList.end(); I != E; ++I) { + + if (ObjCProtocolDecl *PDecl = LookupProtocol((*I)->getIdentifier())) { + if (PDecl->getIdentifier() == PName) { + Diag(Ploc, diag::err_protocol_has_circular_dependency); + Diag(PrevLoc, diag::note_previous_definition); + } + CheckForwardProtocolDeclarationForCircularDependency(PName, Ploc, + PDecl->getLocation(), PDecl->getReferencedProtocols()); + } + } +} + +Sema::DeclPtrTy +Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, + IdentifierInfo *ProtocolName, + SourceLocation ProtocolLoc, + const DeclPtrTy *ProtoRefs, + unsigned NumProtoRefs, + SourceLocation EndProtoLoc, + AttributeList *AttrList) { + // FIXME: Deal with AttrList. + assert(ProtocolName && "Missing protocol identifier"); + ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolName); + if (PDecl) { + // Protocol already seen. Better be a forward protocol declaration + if (!PDecl->isForwardDecl()) { + Diag(ProtocolLoc, diag::warn_duplicate_protocol_def) << ProtocolName; + Diag(PDecl->getLocation(), diag::note_previous_definition); + // Just return the protocol we already had. + // FIXME: don't leak the objects passed in! + return DeclPtrTy::make(PDecl); + } + ObjCList<ObjCProtocolDecl> PList; + PList.set((ObjCProtocolDecl *const*)ProtoRefs, NumProtoRefs, Context); + CheckForwardProtocolDeclarationForCircularDependency( + ProtocolName, ProtocolLoc, PDecl->getLocation(), PList); + PList.Destroy(Context); + + // Make sure the cached decl gets a valid start location. + PDecl->setLocation(AtProtoInterfaceLoc); + PDecl->setForwardDecl(false); + } else { + PDecl = ObjCProtocolDecl::Create(Context, CurContext, + AtProtoInterfaceLoc,ProtocolName); + PushOnScopeChains(PDecl, TUScope); + PDecl->setForwardDecl(false); + } + if (AttrList) + ProcessDeclAttributeList(PDecl, AttrList); + if (NumProtoRefs) { + /// Check then save referenced protocols. + PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,Context); + PDecl->setLocEnd(EndProtoLoc); + } + + CheckObjCDeclScope(PDecl); + return DeclPtrTy::make(PDecl); +} + +/// FindProtocolDeclaration - This routine looks up protocols and +/// issues an error if they are not declared. It returns list of +/// protocol declarations in its 'Protocols' argument. +void +Sema::FindProtocolDeclaration(bool WarnOnDeclarations, + const IdentifierLocPair *ProtocolId, + unsigned NumProtocols, + llvm::SmallVectorImpl<DeclPtrTy> &Protocols) { + for (unsigned i = 0; i != NumProtocols; ++i) { + ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first); + if (!PDecl) { + Diag(ProtocolId[i].second, diag::err_undeclared_protocol) + << ProtocolId[i].first; + continue; + } + + (void)DiagnoseUseOfDecl(PDecl, ProtocolId[i].second); + + // If this is a forward declaration and we are supposed to warn in this + // case, do it. + if (WarnOnDeclarations && PDecl->isForwardDecl()) + Diag(ProtocolId[i].second, diag::warn_undef_protocolref) + << ProtocolId[i].first; + Protocols.push_back(DeclPtrTy::make(PDecl)); + } +} + +/// DiagnosePropertyMismatch - Compares two properties for their +/// attributes and types and warns on a variety of inconsistencies. +/// +void +Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property, + ObjCPropertyDecl *SuperProperty, + const IdentifierInfo *inheritedName) { + ObjCPropertyDecl::PropertyAttributeKind CAttr = + Property->getPropertyAttributes(); + ObjCPropertyDecl::PropertyAttributeKind SAttr = + SuperProperty->getPropertyAttributes(); + if ((CAttr & ObjCPropertyDecl::OBJC_PR_readonly) + && (SAttr & ObjCPropertyDecl::OBJC_PR_readwrite)) + Diag(Property->getLocation(), diag::warn_readonly_property) + << Property->getDeclName() << inheritedName; + if ((CAttr & ObjCPropertyDecl::OBJC_PR_copy) + != (SAttr & ObjCPropertyDecl::OBJC_PR_copy)) + Diag(Property->getLocation(), diag::warn_property_attribute) + << Property->getDeclName() << "copy" << inheritedName; + else if ((CAttr & ObjCPropertyDecl::OBJC_PR_retain) + != (SAttr & ObjCPropertyDecl::OBJC_PR_retain)) + Diag(Property->getLocation(), diag::warn_property_attribute) + << Property->getDeclName() << "retain" << inheritedName; + + if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic) + != (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)) + Diag(Property->getLocation(), diag::warn_property_attribute) + << Property->getDeclName() << "atomic" << inheritedName; + if (Property->getSetterName() != SuperProperty->getSetterName()) + Diag(Property->getLocation(), diag::warn_property_attribute) + << Property->getDeclName() << "setter" << inheritedName; + if (Property->getGetterName() != SuperProperty->getGetterName()) + Diag(Property->getLocation(), diag::warn_property_attribute) + << Property->getDeclName() << "getter" << inheritedName; + + QualType LHSType = + Context.getCanonicalType(SuperProperty->getType()); + QualType RHSType = + Context.getCanonicalType(Property->getType()); + + if (!Context.typesAreCompatible(LHSType, RHSType)) { + // FIXME: Incorporate this test with typesAreCompatible. + if (LHSType->isObjCQualifiedIdType() && RHSType->isObjCQualifiedIdType()) + if (ObjCQualifiedIdTypesAreCompatible(LHSType, RHSType, false)) + return; + Diag(Property->getLocation(), diag::warn_property_types_are_incompatible) + << Property->getType() << SuperProperty->getType() << inheritedName; + } +} + +/// ComparePropertiesInBaseAndSuper - This routine compares property +/// declarations in base and its super class, if any, and issues +/// diagnostics in a variety of inconsistant situations. +/// +void Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) { + ObjCInterfaceDecl *SDecl = IDecl->getSuperClass(); + if (!SDecl) + return; + // FIXME: O(N^2) + for (ObjCInterfaceDecl::prop_iterator S = SDecl->prop_begin(Context), + E = SDecl->prop_end(Context); S != E; ++S) { + ObjCPropertyDecl *SuperPDecl = (*S); + // Does property in super class has declaration in current class? + for (ObjCInterfaceDecl::prop_iterator I = IDecl->prop_begin(Context), + E = IDecl->prop_end(Context); I != E; ++I) { + ObjCPropertyDecl *PDecl = (*I); + if (SuperPDecl->getIdentifier() == PDecl->getIdentifier()) + DiagnosePropertyMismatch(PDecl, SuperPDecl, + SDecl->getIdentifier()); + } + } +} + +/// MergeOneProtocolPropertiesIntoClass - This routine goes thru the list +/// of properties declared in a protocol and adds them to the list +/// of properties for current class/category if it is not there already. +void +Sema::MergeOneProtocolPropertiesIntoClass(Decl *CDecl, + ObjCProtocolDecl *PDecl) { + ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl); + if (!IDecl) { + // Category + ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl); + assert (CatDecl && "MergeOneProtocolPropertiesIntoClass"); + for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(Context), + E = PDecl->prop_end(Context); P != E; ++P) { + ObjCPropertyDecl *Pr = (*P); + ObjCCategoryDecl::prop_iterator CP, CE; + // Is this property already in category's list of properties? + for (CP = CatDecl->prop_begin(Context), CE = CatDecl->prop_end(Context); + CP != CE; ++CP) + if ((*CP)->getIdentifier() == Pr->getIdentifier()) + break; + if (CP != CE) + // Property protocol already exist in class. Diagnose any mismatch. + DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier()); + } + return; + } + for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(Context), + E = PDecl->prop_end(Context); P != E; ++P) { + ObjCPropertyDecl *Pr = (*P); + ObjCInterfaceDecl::prop_iterator CP, CE; + // Is this property already in class's list of properties? + for (CP = IDecl->prop_begin(Context), CE = IDecl->prop_end(Context); + CP != CE; ++CP) + if ((*CP)->getIdentifier() == Pr->getIdentifier()) + break; + if (CP != CE) + // Property protocol already exist in class. Diagnose any mismatch. + DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier()); + } +} + +/// MergeProtocolPropertiesIntoClass - This routine merges properties +/// declared in 'MergeItsProtocols' objects (which can be a class or an +/// inherited protocol into the list of properties for class/category 'CDecl' +/// +void Sema::MergeProtocolPropertiesIntoClass(Decl *CDecl, + DeclPtrTy MergeItsProtocols) { + Decl *ClassDecl = MergeItsProtocols.getAs<Decl>(); + ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl); + + if (!IDecl) { + // Category + ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl); + assert (CatDecl && "MergeProtocolPropertiesIntoClass"); + if (ObjCCategoryDecl *MDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) { + for (ObjCCategoryDecl::protocol_iterator P = MDecl->protocol_begin(), + E = MDecl->protocol_end(); P != E; ++P) + // Merge properties of category (*P) into IDECL's + MergeOneProtocolPropertiesIntoClass(CatDecl, *P); + + // Go thru the list of protocols for this category and recursively merge + // their properties into this class as well. + for (ObjCCategoryDecl::protocol_iterator P = CatDecl->protocol_begin(), + E = CatDecl->protocol_end(); P != E; ++P) + MergeProtocolPropertiesIntoClass(CatDecl, DeclPtrTy::make(*P)); + } else { + ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl); + for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(), + E = MD->protocol_end(); P != E; ++P) + MergeOneProtocolPropertiesIntoClass(CatDecl, *P); + } + return; + } + + if (ObjCInterfaceDecl *MDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) { + for (ObjCInterfaceDecl::protocol_iterator P = MDecl->protocol_begin(), + E = MDecl->protocol_end(); P != E; ++P) + // Merge properties of class (*P) into IDECL's + MergeOneProtocolPropertiesIntoClass(IDecl, *P); + + // Go thru the list of protocols for this class and recursively merge + // their properties into this class as well. + for (ObjCInterfaceDecl::protocol_iterator P = IDecl->protocol_begin(), + E = IDecl->protocol_end(); P != E; ++P) + MergeProtocolPropertiesIntoClass(IDecl, DeclPtrTy::make(*P)); + } else { + ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl); + for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(), + E = MD->protocol_end(); P != E; ++P) + MergeOneProtocolPropertiesIntoClass(IDecl, *P); + } +} + +/// DiagnoseClassExtensionDupMethods - Check for duplicate declaration of +/// a class method in its extension. +/// +void Sema::DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT, + ObjCInterfaceDecl *ID) { + if (!ID) + return; // Possibly due to previous error + + llvm::DenseMap<Selector, const ObjCMethodDecl*> MethodMap; + for (ObjCInterfaceDecl::method_iterator i = ID->meth_begin(Context), + e = ID->meth_end(Context); i != e; ++i) { + ObjCMethodDecl *MD = *i; + MethodMap[MD->getSelector()] = MD; + } + + if (MethodMap.empty()) + return; + for (ObjCCategoryDecl::method_iterator i = CAT->meth_begin(Context), + e = CAT->meth_end(Context); i != e; ++i) { + ObjCMethodDecl *Method = *i; + const ObjCMethodDecl *&PrevMethod = MethodMap[Method->getSelector()]; + if (PrevMethod && !MatchTwoMethodDeclarations(Method, PrevMethod)) { + Diag(Method->getLocation(), diag::err_duplicate_method_decl) + << Method->getDeclName(); + Diag(PrevMethod->getLocation(), diag::note_previous_declaration); + } + } +} + +/// ActOnForwardProtocolDeclaration - Handle @protocol foo; +Action::DeclPtrTy +Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, + const IdentifierLocPair *IdentList, + unsigned NumElts, + AttributeList *attrList) { + llvm::SmallVector<ObjCProtocolDecl*, 32> Protocols; + + for (unsigned i = 0; i != NumElts; ++i) { + IdentifierInfo *Ident = IdentList[i].first; + ObjCProtocolDecl *PDecl = LookupProtocol(Ident); + if (PDecl == 0) { // Not already seen? + PDecl = ObjCProtocolDecl::Create(Context, CurContext, + IdentList[i].second, Ident); + PushOnScopeChains(PDecl, TUScope); + } + if (attrList) + ProcessDeclAttributeList(PDecl, attrList); + Protocols.push_back(PDecl); + } + + ObjCForwardProtocolDecl *PDecl = + ObjCForwardProtocolDecl::Create(Context, CurContext, AtProtocolLoc, + &Protocols[0], Protocols.size()); + CurContext->addDecl(Context, PDecl); + CheckObjCDeclScope(PDecl); + return DeclPtrTy::make(PDecl); +} + +Sema::DeclPtrTy Sema:: +ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, + IdentifierInfo *ClassName, SourceLocation ClassLoc, + IdentifierInfo *CategoryName, + SourceLocation CategoryLoc, + const DeclPtrTy *ProtoRefs, + unsigned NumProtoRefs, + SourceLocation EndProtoLoc) { + ObjCCategoryDecl *CDecl = + ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, CategoryName); + // FIXME: PushOnScopeChains? + CurContext->addDecl(Context, CDecl); + + ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName); + /// 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); + + // If the interface is deprecated, warn about it. + (void)DiagnoseUseOfDecl(IDecl, ClassLoc); + + /// Check for duplicate interface declaration for this category + ObjCCategoryDecl *CDeclChain; + for (CDeclChain = IDecl->getCategoryList(); CDeclChain; + CDeclChain = CDeclChain->getNextClassCategory()) { + if (CategoryName && CDeclChain->getIdentifier() == CategoryName) { + Diag(CategoryLoc, diag::warn_dup_category_def) + << ClassName << CategoryName; + Diag(CDeclChain->getLocation(), diag::note_previous_definition); + break; + } + } + if (!CDeclChain) + CDecl->insertNextClassCategory(); + + if (NumProtoRefs) { + CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,Context); + CDecl->setLocEnd(EndProtoLoc); + } + + CheckObjCDeclScope(CDecl); + return DeclPtrTy::make(CDecl); +} + +/// ActOnStartCategoryImplementation - Perform semantic checks on the +/// category implementation declaration and build an ObjCCategoryImplDecl +/// object. +Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation( + SourceLocation AtCatImplLoc, + IdentifierInfo *ClassName, SourceLocation ClassLoc, + IdentifierInfo *CatName, SourceLocation CatLoc) { + ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName); + ObjCCategoryImplDecl *CDecl = + ObjCCategoryImplDecl::Create(Context, CurContext, AtCatImplLoc, CatName, + IDecl); + /// Check that class of this category is already completely declared. + if (!IDecl || IDecl->isForwardDecl()) + Diag(ClassLoc, diag::err_undef_interface) << ClassName; + + // FIXME: PushOnScopeChains? + CurContext->addDecl(Context, CDecl); + + /// TODO: Check that CatName, category name, is not used in another + // implementation. + ObjCCategoryImpls.push_back(CDecl); + + CheckObjCDeclScope(CDecl); + return DeclPtrTy::make(CDecl); +} + +Sema::DeclPtrTy Sema::ActOnStartClassImplementation( + SourceLocation AtClassImplLoc, + IdentifierInfo *ClassName, SourceLocation ClassLoc, + IdentifierInfo *SuperClassname, + SourceLocation SuperClassLoc) { + ObjCInterfaceDecl* IDecl = 0; + // Check for another declaration kind with the same name. + NamedDecl *PrevDecl = LookupName(TUScope, ClassName, LookupOrdinaryName); + if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) { + Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName; + Diag(PrevDecl->getLocation(), diag::note_previous_definition); + } else { + // Is there an interface declaration of this class; if not, warn! + IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); + if (!IDecl || IDecl->isForwardDecl()) { + Diag(ClassLoc, diag::warn_undef_interface) << ClassName; + IDecl = 0; + } + } + + // Check that super class name is valid class name + ObjCInterfaceDecl* SDecl = 0; + if (SuperClassname) { + // Check if a different kind of symbol declared in this scope. + PrevDecl = LookupName(TUScope, SuperClassname, LookupOrdinaryName); + if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) { + Diag(SuperClassLoc, diag::err_redefinition_different_kind) + << SuperClassname; + Diag(PrevDecl->getLocation(), diag::note_previous_definition); + } else { + SDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); + if (!SDecl) + Diag(SuperClassLoc, diag::err_undef_superclass) + << SuperClassname << ClassName; + else if (IDecl && IDecl->getSuperClass() != SDecl) { + // This implementation and its interface do not have the same + // super class. + Diag(SuperClassLoc, diag::err_conflicting_super_class) + << SDecl->getDeclName(); + Diag(SDecl->getLocation(), diag::note_previous_definition); + } + } + } + + if (!IDecl) { + // Legacy case of @implementation with no corresponding @interface. + // Build, chain & install the interface decl into the identifier. + + // FIXME: Do we support attributes on the @implementation? If so we should + // copy them over. + IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassImplLoc, + ClassName, ClassLoc, false, true); + IDecl->setSuperClass(SDecl); + IDecl->setLocEnd(ClassLoc); + + PushOnScopeChains(IDecl, TUScope); + } else { + // Mark the interface as being completed, even if it was just as + // @class ....; + // declaration; the user cannot reopen it. + IDecl->setForwardDecl(false); + } + + ObjCImplementationDecl* IMPDecl = + ObjCImplementationDecl::Create(Context, CurContext, AtClassImplLoc, + IDecl, SDecl); + + if (CheckObjCDeclScope(IMPDecl)) + return DeclPtrTy::make(IMPDecl); + + // Check that there is no duplicate implementation of this class. + if (LookupObjCImplementation(ClassName)) + // FIXME: Don't leak everything! + Diag(ClassLoc, diag::err_dup_implementation_class) << ClassName; + else // add it to the list. + PushOnScopeChains(IMPDecl, TUScope); + return DeclPtrTy::make(IMPDecl); +} + +void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, + ObjCIvarDecl **ivars, unsigned numIvars, + SourceLocation RBrace) { + assert(ImpDecl && "missing implementation decl"); + ObjCInterfaceDecl* IDecl = ImpDecl->getClassInterface(); + if (!IDecl) + return; + /// Check case of non-existing @interface decl. + /// (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); + return; + } + // If implementation has empty ivar list, just return. + if (numIvars == 0) + return; + + assert(ivars && "missing @implementation ivars"); + + // Check interface's Ivar list against those in the implementation. + // names and types must match. + // + unsigned j = 0; + ObjCInterfaceDecl::ivar_iterator + IVI = IDecl->ivar_begin(), IVE = IDecl->ivar_end(); + for (; numIvars > 0 && IVI != IVE; ++IVI) { + ObjCIvarDecl* ImplIvar = ivars[j++]; + ObjCIvarDecl* ClsIvar = *IVI; + assert (ImplIvar && "missing implementation ivar"); + assert (ClsIvar && "missing class ivar"); + + // First, make sure the types match. + if (Context.getCanonicalType(ImplIvar->getType()) != + Context.getCanonicalType(ClsIvar->getType())) { + Diag(ImplIvar->getLocation(), diag::err_conflicting_ivar_type) + << ImplIvar->getIdentifier() + << ImplIvar->getType() << ClsIvar->getType(); + Diag(ClsIvar->getLocation(), diag::note_previous_definition); + } else if (ImplIvar->isBitField() && ClsIvar->isBitField()) { + Expr *ImplBitWidth = ImplIvar->getBitWidth(); + Expr *ClsBitWidth = ClsIvar->getBitWidth(); + if (ImplBitWidth->EvaluateAsInt(Context).getZExtValue() != + ClsBitWidth->EvaluateAsInt(Context).getZExtValue()) { + Diag(ImplBitWidth->getLocStart(), diag::err_conflicting_ivar_bitwidth) + << ImplIvar->getIdentifier(); + Diag(ClsBitWidth->getLocStart(), diag::note_previous_definition); + } + } + // Make sure the names are identical. + if (ImplIvar->getIdentifier() != ClsIvar->getIdentifier()) { + Diag(ImplIvar->getLocation(), diag::err_conflicting_ivar_name) + << ImplIvar->getIdentifier() << ClsIvar->getIdentifier(); + Diag(ClsIvar->getLocation(), diag::note_previous_definition); + } + --numIvars; + } + + if (numIvars > 0) + Diag(ivars[j]->getLocation(), diag::err_inconsistant_ivar_count); + else if (IVI != IVE) + Diag((*IVI)->getLocation(), diag::err_inconsistant_ivar_count); +} + +void Sema::WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method, + bool &IncompleteImpl) { + if (!IncompleteImpl) { + Diag(ImpLoc, diag::warn_incomplete_impl); + IncompleteImpl = true; + } + Diag(ImpLoc, diag::warn_undef_method_impl) << method->getDeclName(); +} + +void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl, + ObjCMethodDecl *IntfMethodDecl) { + if (!Context.typesAreCompatible(IntfMethodDecl->getResultType(), + ImpMethodDecl->getResultType()) && + !QualifiedIdConformsQualifiedId(IntfMethodDecl->getResultType(), + ImpMethodDecl->getResultType())) { + Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_ret_types) + << ImpMethodDecl->getDeclName() << IntfMethodDecl->getResultType() + << ImpMethodDecl->getResultType(); + Diag(IntfMethodDecl->getLocation(), diag::note_previous_definition); + } + + for (ObjCMethodDecl::param_iterator IM = ImpMethodDecl->param_begin(), + IF = IntfMethodDecl->param_begin(), EM = ImpMethodDecl->param_end(); + IM != EM; ++IM, ++IF) { + if (Context.typesAreCompatible((*IF)->getType(), (*IM)->getType()) || + QualifiedIdConformsQualifiedId((*IF)->getType(), (*IM)->getType())) + continue; + + Diag((*IM)->getLocation(), diag::warn_conflicting_param_types) + << ImpMethodDecl->getDeclName() << (*IF)->getType() + << (*IM)->getType(); + Diag((*IF)->getLocation(), diag::note_previous_definition); + } +} + +/// isPropertyReadonly - Return true if property is readonly, by searching +/// for the property in the class and in its categories and implementations +/// +bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl, + ObjCInterfaceDecl *IDecl) { + // by far the most common case. + if (!PDecl->isReadOnly()) + return false; + // Even if property is ready only, if interface has a user defined setter, + // it is not considered read only. + if (IDecl->getInstanceMethod(Context, PDecl->getSetterName())) + return false; + + // Main class has the property as 'readonly'. Must search + // through the category list to see if the property's + // attribute has been over-ridden to 'readwrite'. + for (ObjCCategoryDecl *Category = IDecl->getCategoryList(); + Category; Category = Category->getNextClassCategory()) { + // Even if property is ready only, if a category has a user defined setter, + // it is not considered read only. + if (Category->getInstanceMethod(Context, PDecl->getSetterName())) + return false; + ObjCPropertyDecl *P = + Category->FindPropertyDeclaration(Context, PDecl->getIdentifier()); + if (P && !P->isReadOnly()) + return false; + } + + // Also, check for definition of a setter method in the implementation if + // all else failed. + if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(CurContext)) { + if (ObjCImplementationDecl *IMD = + dyn_cast<ObjCImplementationDecl>(OMD->getDeclContext())) { + if (IMD->getInstanceMethod(Context, PDecl->getSetterName())) + return false; + } + else if (ObjCCategoryImplDecl *CIMD = + dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) { + if (CIMD->getInstanceMethod(Context, PDecl->getSetterName())) + return false; + } + } + // Lastly, look through the implementation (if one is in scope). + if (ObjCImplementationDecl *ImpDecl + = LookupObjCImplementation(IDecl->getIdentifier())) + if (ImpDecl->getInstanceMethod(Context, PDecl->getSetterName())) + return false; + // If all fails, look at the super class. + if (ObjCInterfaceDecl *SIDecl = IDecl->getSuperClass()) + return isPropertyReadonly(PDecl, SIDecl); + return true; +} + +/// FIXME: Type hierarchies in Objective-C can be deep. We could most likely +/// improve the efficiency of selector lookups and type checking by associating +/// with each protocol / interface / category the flattened instance tables. If +/// we used an immutable set to keep the table then it wouldn't add significant +/// memory cost and it would be handy for lookups. + +/// CheckProtocolMethodDefs - This routine checks unimplemented methods +/// Declared in protocol, and those referenced by it. +void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, + ObjCProtocolDecl *PDecl, + bool& IncompleteImpl, + const llvm::DenseSet<Selector> &InsMap, + const llvm::DenseSet<Selector> &ClsMap, + ObjCInterfaceDecl *IDecl) { + ObjCInterfaceDecl *Super = IDecl->getSuperClass(); + ObjCInterfaceDecl *NSIDecl = 0; + if (getLangOptions().NeXTRuntime) { + // check to see if class implements forwardInvocation method and objects + // of this class are derived from 'NSProxy' so that to forward requests + // from one object to another. + // Under such conditions, which means that every method possible is + // implemented in the class, we should not issue "Method definition not + // found" warnings. + // FIXME: Use a general GetUnarySelector method for this. + IdentifierInfo* II = &Context.Idents.get("forwardInvocation"); + Selector fISelector = Context.Selectors.getSelector(1, &II); + if (InsMap.count(fISelector)) + // Is IDecl derived from 'NSProxy'? If so, no instance methods + // need be implemented in the implementation. + NSIDecl = IDecl->lookupInheritedClass(&Context.Idents.get("NSProxy")); + } + + // If a method lookup fails locally we still need to look and see if + // the method was implemented by a base class or an inherited + // protocol. This lookup is slow, but occurs rarely in correct code + // and otherwise would terminate in a warning. + + // check unimplemented instance methods. + if (!NSIDecl) + for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(Context), + E = PDecl->instmeth_end(Context); I != E; ++I) { + ObjCMethodDecl *method = *I; + if (method->getImplementationControl() != ObjCMethodDecl::Optional && + !method->isSynthesized() && !InsMap.count(method->getSelector()) && + (!Super || + !Super->lookupInstanceMethod(Context, method->getSelector()))) { + // Ugly, but necessary. Method declared in protcol might have + // have been synthesized due to a property declared in the class which + // uses the protocol. + ObjCMethodDecl *MethodInClass = + IDecl->lookupInstanceMethod(Context, method->getSelector()); + if (!MethodInClass || !MethodInClass->isSynthesized()) + WarnUndefinedMethod(ImpLoc, method, IncompleteImpl); + } + } + // check unimplemented class methods + for (ObjCProtocolDecl::classmeth_iterator + I = PDecl->classmeth_begin(Context), + E = PDecl->classmeth_end(Context); + I != E; ++I) { + ObjCMethodDecl *method = *I; + if (method->getImplementationControl() != ObjCMethodDecl::Optional && + !ClsMap.count(method->getSelector()) && + (!Super || !Super->lookupClassMethod(Context, method->getSelector()))) + WarnUndefinedMethod(ImpLoc, method, IncompleteImpl); + } + // Check on this protocols's referenced protocols, recursively. + for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), + E = PDecl->protocol_end(); PI != E; ++PI) + CheckProtocolMethodDefs(ImpLoc, *PI, IncompleteImpl, InsMap, ClsMap, IDecl); +} + +/// MatchAllMethodDeclarations - Check methods declaraed in interface or +/// or protocol against those declared in their implementations. +/// +void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, + const llvm::DenseSet<Selector> &ClsMap, + llvm::DenseSet<Selector> &InsMapSeen, + llvm::DenseSet<Selector> &ClsMapSeen, + ObjCImplDecl* IMPDecl, + ObjCContainerDecl* CDecl, + bool &IncompleteImpl, + bool ImmediateClass) +{ + // Check and see if instance methods in class interface have been + // implemented in the implementation class. If so, their types match. + for (ObjCInterfaceDecl::instmeth_iterator I = CDecl->instmeth_begin(Context), + E = CDecl->instmeth_end(Context); I != E; ++I) { + if (InsMapSeen.count((*I)->getSelector())) + continue; + InsMapSeen.insert((*I)->getSelector()); + if (!(*I)->isSynthesized() && + !InsMap.count((*I)->getSelector())) { + if (ImmediateClass) + WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl); + continue; + } + else { + ObjCMethodDecl *ImpMethodDecl = + IMPDecl->getInstanceMethod(Context, (*I)->getSelector()); + ObjCMethodDecl *IntfMethodDecl = + CDecl->getInstanceMethod(Context, (*I)->getSelector()); + assert(IntfMethodDecl && + "IntfMethodDecl is null in ImplMethodsVsClassMethods"); + // ImpMethodDecl may be null as in a @dynamic property. + if (ImpMethodDecl) + WarnConflictingTypedMethods(ImpMethodDecl, IntfMethodDecl); + } + } + + // Check and see if class methods in class interface have been + // implemented in the implementation class. If so, their types match. + for (ObjCInterfaceDecl::classmeth_iterator + I = CDecl->classmeth_begin(Context), + E = CDecl->classmeth_end(Context); + I != E; ++I) { + if (ClsMapSeen.count((*I)->getSelector())) + continue; + ClsMapSeen.insert((*I)->getSelector()); + if (!ClsMap.count((*I)->getSelector())) { + if (ImmediateClass) + WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl); + } + else { + ObjCMethodDecl *ImpMethodDecl = + IMPDecl->getClassMethod(Context, (*I)->getSelector()); + ObjCMethodDecl *IntfMethodDecl = + CDecl->getClassMethod(Context, (*I)->getSelector()); + WarnConflictingTypedMethods(ImpMethodDecl, IntfMethodDecl); + } + } + if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl> (CDecl)) { + // Check for any implementation of a methods declared in protocol. + for (ObjCInterfaceDecl::protocol_iterator PI = I->protocol_begin(), + E = I->protocol_end(); PI != E; ++PI) + MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, + IMPDecl, + (*PI), IncompleteImpl, false); + if (I->getSuperClass()) + MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, + IMPDecl, + I->getSuperClass(), IncompleteImpl, false); + } +} + +void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, + ObjCContainerDecl* CDecl, + bool IncompleteImpl) { + llvm::DenseSet<Selector> InsMap; + // Check and see if instance methods in class interface have been + // implemented in the implementation class. + for (ObjCImplementationDecl::instmeth_iterator + I = IMPDecl->instmeth_begin(Context), + E = IMPDecl->instmeth_end(Context); I != E; ++I) + InsMap.insert((*I)->getSelector()); + + // Check and see if properties declared in the interface have either 1) + // an implementation or 2) there is a @synthesize/@dynamic implementation + // of the property in the @implementation. + if (isa<ObjCInterfaceDecl>(CDecl)) + for (ObjCContainerDecl::prop_iterator P = CDecl->prop_begin(Context), + E = CDecl->prop_end(Context); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + if (Prop->isInvalidDecl()) + continue; + ObjCPropertyImplDecl *PI = 0; + // Is there a matching propery synthesize/dynamic? + for (ObjCImplDecl::propimpl_iterator + I = IMPDecl->propimpl_begin(Context), + EI = IMPDecl->propimpl_end(Context); I != EI; ++I) + if ((*I)->getPropertyDecl() == Prop) { + PI = (*I); + break; + } + if (PI) + continue; + if (!InsMap.count(Prop->getGetterName())) { + Diag(Prop->getLocation(), + diag::warn_setter_getter_impl_required) + << Prop->getDeclName() << Prop->getGetterName(); + Diag(IMPDecl->getLocation(), + diag::note_property_impl_required); + } + + if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) { + Diag(Prop->getLocation(), + diag::warn_setter_getter_impl_required) + << Prop->getDeclName() << Prop->getSetterName(); + Diag(IMPDecl->getLocation(), + diag::note_property_impl_required); + } + } + + llvm::DenseSet<Selector> ClsMap; + for (ObjCImplementationDecl::classmeth_iterator + I = IMPDecl->classmeth_begin(Context), + E = IMPDecl->classmeth_end(Context); I != E; ++I) + ClsMap.insert((*I)->getSelector()); + + // Check for type conflict of methods declared in a class/protocol and + // its implementation; if any. + llvm::DenseSet<Selector> InsMapSeen, ClsMapSeen; + MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, + IMPDecl, CDecl, + IncompleteImpl, true); + + // Check the protocol list for unimplemented methods in the @implementation + // class. + // Check and see if class methods in class interface have been + // implemented in the implementation class. + + if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl> (CDecl)) { + for (ObjCInterfaceDecl::protocol_iterator PI = I->protocol_begin(), + E = I->protocol_end(); PI != E; ++PI) + CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, + InsMap, ClsMap, I); + // Check class extensions (unnamed categories) + for (ObjCCategoryDecl *Categories = I->getCategoryList(); + Categories; Categories = Categories->getNextClassCategory()) { + if (!Categories->getIdentifier()) { + ImplMethodsVsClassMethods(IMPDecl, Categories, IncompleteImpl); + break; + } + } + } else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) { + for (ObjCCategoryDecl::protocol_iterator PI = C->protocol_begin(), + E = C->protocol_end(); PI != E; ++PI) + CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, + InsMap, ClsMap, C->getClassInterface()); + } else + assert(false && "invalid ObjCContainerDecl type."); +} + +/// ActOnForwardClassDeclaration - +Action::DeclPtrTy +Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, + IdentifierInfo **IdentList, + unsigned NumElts) { + llvm::SmallVector<ObjCInterfaceDecl*, 32> Interfaces; + + for (unsigned i = 0; i != NumElts; ++i) { + // Check for another declaration kind with the same name. + NamedDecl *PrevDecl = LookupName(TUScope, IdentList[i], LookupOrdinaryName); + if (PrevDecl && PrevDecl->isTemplateParameter()) { + // Maybe we will complain about the shadowed template parameter. + DiagnoseTemplateParameterShadow(AtClassLoc, PrevDecl); + // Just pretend that we didn't see the previous declaration. + PrevDecl = 0; + } + + if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) { + // GCC apparently allows the following idiom: + // + // typedef NSObject < XCElementTogglerP > XCElementToggler; + // @class XCElementToggler; + // + // FIXME: Make an extension? + TypedefDecl *TDD = dyn_cast<TypedefDecl>(PrevDecl); + if (!TDD || !isa<ObjCInterfaceType>(TDD->getUnderlyingType())) { + Diag(AtClassLoc, diag::err_redefinition_different_kind) << IdentList[i]; + Diag(PrevDecl->getLocation(), diag::note_previous_definition); + } + else if (TDD) { + // a forward class declaration matching a typedef name of a class + // refers to the underlying class. + if (ObjCInterfaceType * OI = + dyn_cast<ObjCInterfaceType>(TDD->getUnderlyingType())) + PrevDecl = OI->getDecl(); + } + } + ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); + if (!IDecl) { // Not already seen? Make a forward decl. + IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc, + IdentList[i], SourceLocation(), true); + PushOnScopeChains(IDecl, TUScope); + } + + Interfaces.push_back(IDecl); + } + + ObjCClassDecl *CDecl = ObjCClassDecl::Create(Context, CurContext, AtClassLoc, + &Interfaces[0], + Interfaces.size()); + CurContext->addDecl(Context, CDecl); + CheckObjCDeclScope(CDecl); + return DeclPtrTy::make(CDecl); +} + + +/// MatchTwoMethodDeclarations - Checks that two methods have matching type and +/// returns true, or false, accordingly. +/// TODO: Handle protocol list; such as id<p1,p2> in type comparisons +bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, + const ObjCMethodDecl *PrevMethod, + bool matchBasedOnSizeAndAlignment) { + QualType T1 = Context.getCanonicalType(Method->getResultType()); + QualType T2 = Context.getCanonicalType(PrevMethod->getResultType()); + + if (T1 != T2) { + // The result types are different. + if (!matchBasedOnSizeAndAlignment) + return false; + // Incomplete types don't have a size and alignment. + if (T1->isIncompleteType() || T2->isIncompleteType()) + return false; + // Check is based on size and alignment. + if (Context.getTypeInfo(T1) != Context.getTypeInfo(T2)) + return false; + } + + ObjCMethodDecl::param_iterator ParamI = Method->param_begin(), + E = Method->param_end(); + ObjCMethodDecl::param_iterator PrevI = PrevMethod->param_begin(); + + for (; ParamI != E; ++ParamI, ++PrevI) { + assert(PrevI != PrevMethod->param_end() && "Param mismatch"); + T1 = Context.getCanonicalType((*ParamI)->getType()); + T2 = Context.getCanonicalType((*PrevI)->getType()); + if (T1 != T2) { + // The result types are different. + if (!matchBasedOnSizeAndAlignment) + return false; + // Incomplete types don't have a size and alignment. + if (T1->isIncompleteType() || T2->isIncompleteType()) + return false; + // Check is based on size and alignment. + if (Context.getTypeInfo(T1) != Context.getTypeInfo(T2)) + return false; + } + } + return true; +} + +/// \brief Read the contents of the instance and factory method pools +/// for a given selector from external storage. +/// +/// This routine should only be called once, when neither the instance +/// nor the factory method pool has an entry for this selector. +Sema::MethodPool::iterator Sema::ReadMethodPool(Selector Sel, + bool isInstance) { + assert(ExternalSource && "We need an external AST source"); + assert(InstanceMethodPool.find(Sel) == InstanceMethodPool.end() && + "Selector data already loaded into the instance method pool"); + assert(FactoryMethodPool.find(Sel) == FactoryMethodPool.end() && + "Selector data already loaded into the factory method pool"); + + // Read the method list from the external source. + std::pair<ObjCMethodList, ObjCMethodList> Methods + = ExternalSource->ReadMethodPool(Sel); + + if (isInstance) { + if (Methods.second.Method) + FactoryMethodPool[Sel] = Methods.second; + return InstanceMethodPool.insert(std::make_pair(Sel, Methods.first)).first; + } + + if (Methods.first.Method) + InstanceMethodPool[Sel] = Methods.first; + + return FactoryMethodPool.insert(std::make_pair(Sel, Methods.second)).first; +} + +void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method) { + llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos + = InstanceMethodPool.find(Method->getSelector()); + if (Pos == InstanceMethodPool.end()) { + if (ExternalSource && !FactoryMethodPool.count(Method->getSelector())) + Pos = ReadMethodPool(Method->getSelector(), /*isInstance=*/true); + else + Pos = InstanceMethodPool.insert(std::make_pair(Method->getSelector(), + ObjCMethodList())).first; + } + + ObjCMethodList &Entry = Pos->second; + if (Entry.Method == 0) { + // Haven't seen a method with this selector name yet - add it. + Entry.Method = Method; + Entry.Next = 0; + return; + } + + // We've seen a method with this name, see if we have already seen this type + // signature. + for (ObjCMethodList *List = &Entry; List; List = List->Next) + if (MatchTwoMethodDeclarations(Method, List->Method)) + return; + + // We have a new signature for an existing method - add it. + // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". + Entry.Next = new ObjCMethodList(Method, Entry.Next); +} + +// FIXME: Finish implementing -Wno-strict-selector-match. +ObjCMethodDecl *Sema::LookupInstanceMethodInGlobalPool(Selector Sel, + SourceRange R) { + llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos + = InstanceMethodPool.find(Sel); + if (Pos == InstanceMethodPool.end()) { + if (ExternalSource && !FactoryMethodPool.count(Sel)) + Pos = ReadMethodPool(Sel, /*isInstance=*/true); + else + return 0; + } + + ObjCMethodList &MethList = Pos->second; + bool issueWarning = false; + + if (MethList.Method && MethList.Next) { + for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) + // This checks if the methods differ by size & alignment. + if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, true)) + issueWarning = true; + } + if (issueWarning && (MethList.Method && MethList.Next)) { + Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R; + Diag(MethList.Method->getLocStart(), diag::note_using_decl) + << MethList.Method->getSourceRange(); + for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) + Diag(Next->Method->getLocStart(), diag::note_also_found_decl) + << Next->Method->getSourceRange(); + } + return MethList.Method; +} + +void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) { + llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos + = FactoryMethodPool.find(Method->getSelector()); + if (Pos == FactoryMethodPool.end()) { + if (ExternalSource && !InstanceMethodPool.count(Method->getSelector())) + Pos = ReadMethodPool(Method->getSelector(), /*isInstance=*/false); + else + Pos = FactoryMethodPool.insert(std::make_pair(Method->getSelector(), + ObjCMethodList())).first; + } + + ObjCMethodList &FirstMethod = Pos->second; + if (!FirstMethod.Method) { + // Haven't seen a method with this selector name yet - add it. + FirstMethod.Method = Method; + FirstMethod.Next = 0; + } else { + // We've seen a method with this name, now check the type signature(s). + bool match = MatchTwoMethodDeclarations(Method, FirstMethod.Method); + + for (ObjCMethodList *Next = FirstMethod.Next; !match && Next; + Next = Next->Next) + match = MatchTwoMethodDeclarations(Method, Next->Method); + + if (!match) { + // We have a new signature for an existing method - add it. + // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". + struct ObjCMethodList *OMI = new ObjCMethodList(Method, FirstMethod.Next); + FirstMethod.Next = OMI; + } + } +} + +ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel, + SourceRange R) { + llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos + = FactoryMethodPool.find(Sel); + if (Pos == FactoryMethodPool.end()) { + if (ExternalSource && !InstanceMethodPool.count(Sel)) + Pos = ReadMethodPool(Sel, /*isInstance=*/false); + else + return 0; + } + + ObjCMethodList &MethList = Pos->second; + bool issueWarning = false; + + if (MethList.Method && MethList.Next) { + for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) + // This checks if the methods differ by size & alignment. + if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, true)) + issueWarning = true; + } + if (issueWarning && (MethList.Method && MethList.Next)) { + Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R; + Diag(MethList.Method->getLocStart(), diag::note_using_decl) + << MethList.Method->getSourceRange(); + for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) + Diag(Next->Method->getLocStart(), diag::note_also_found_decl) + << Next->Method->getSourceRange(); + } + return MethList.Method; +} + +/// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods +/// have the property type and issue diagnostics if they don't. +/// Also synthesize a getter/setter method if none exist (and update the +/// appropriate lookup tables. FIXME: Should reconsider if adding synthesized +/// methods is the "right" thing to do. +void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, + ObjCContainerDecl *CD) { + ObjCMethodDecl *GetterMethod, *SetterMethod; + + GetterMethod = CD->getInstanceMethod(Context, property->getGetterName()); + SetterMethod = CD->getInstanceMethod(Context, property->getSetterName()); + DiagnosePropertyAccessorMismatch(property, GetterMethod, + property->getLocation()); + + if (SetterMethod) { + if (Context.getCanonicalType(SetterMethod->getResultType()) + != Context.VoidTy) + Diag(SetterMethod->getLocation(), diag::err_setter_type_void); + if (SetterMethod->param_size() != 1 || + ((*SetterMethod->param_begin())->getType() != property->getType())) { + Diag(property->getLocation(), + diag::warn_accessor_property_type_mismatch) + << property->getDeclName() + << SetterMethod->getSelector(); + Diag(SetterMethod->getLocation(), diag::note_declared_at); + } + } + + // Synthesize getter/setter methods if none exist. + // Find the default getter and if one not found, add one. + // FIXME: The synthesized property we set here is misleading. We almost always + // synthesize these methods unless the user explicitly provided prototypes + // (which is odd, but allowed). Sema should be typechecking that the + // declarations jive in that situation (which it is not currently). + if (!GetterMethod) { + // No instance method of same name as property getter name was found. + // Declare a getter method and add it to the list of methods + // for this class. + GetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(), + property->getLocation(), property->getGetterName(), + property->getType(), CD, true, false, true, + (property->getPropertyImplementation() == + ObjCPropertyDecl::Optional) ? + ObjCMethodDecl::Optional : + ObjCMethodDecl::Required); + CD->addDecl(Context, GetterMethod); + } else + // A user declared getter will be synthesize when @synthesize of + // the property with the same name is seen in the @implementation + GetterMethod->setSynthesized(true); + property->setGetterMethodDecl(GetterMethod); + + // Skip setter if property is read-only. + if (!property->isReadOnly()) { + // Find the default setter and if one not found, add one. + if (!SetterMethod) { + // No instance method of same name as property setter name was found. + // Declare a setter method and add it to the list of methods + // for this class. + SetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(), + property->getLocation(), + property->getSetterName(), + Context.VoidTy, CD, true, false, true, + (property->getPropertyImplementation() == + ObjCPropertyDecl::Optional) ? + ObjCMethodDecl::Optional : + ObjCMethodDecl::Required); + // Invent the arguments for the setter. We don't bother making a + // nice name for the argument. + ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod, + property->getLocation(), + property->getIdentifier(), + property->getType(), + VarDecl::None, + 0); + SetterMethod->setMethodParams(Context, &Argument, 1); + CD->addDecl(Context, SetterMethod); + } else + // A user declared setter will be synthesize when @synthesize of + // the property with the same name is seen in the @implementation + SetterMethod->setSynthesized(true); + property->setSetterMethodDecl(SetterMethod); + } + // Add any synthesized methods to the global pool. This allows us to + // handle the following, which is supported by GCC (and part of the design). + // + // @interface Foo + // @property double bar; + // @end + // + // void thisIsUnfortunate() { + // id foo; + // double bar = [foo bar]; + // } + // + if (GetterMethod) + AddInstanceMethodToGlobalPool(GetterMethod); + if (SetterMethod) + AddInstanceMethodToGlobalPool(SetterMethod); +} + +// Note: For class/category implemenations, allMethods/allProperties is +// always null. +void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclPtrTy classDecl, + DeclPtrTy *allMethods, unsigned allNum, + DeclPtrTy *allProperties, unsigned pNum, + DeclGroupPtrTy *allTUVars, unsigned tuvNum) { + Decl *ClassDecl = classDecl.getAs<Decl>(); + + // FIXME: If we don't have a ClassDecl, we have an error. We should consider + // always passing in a decl. If the decl has an error, isInvalidDecl() + // should be true. + if (!ClassDecl) + return; + + bool isInterfaceDeclKind = + isa<ObjCInterfaceDecl>(ClassDecl) || isa<ObjCCategoryDecl>(ClassDecl) + || isa<ObjCProtocolDecl>(ClassDecl); + bool checkIdenticalMethods = isa<ObjCImplementationDecl>(ClassDecl); + + DeclContext *DC = dyn_cast<DeclContext>(ClassDecl); + + // FIXME: Remove these and use the ObjCContainerDecl/DeclContext. + llvm::DenseMap<Selector, const ObjCMethodDecl*> InsMap; + llvm::DenseMap<Selector, const ObjCMethodDecl*> ClsMap; + + for (unsigned i = 0; i < allNum; i++ ) { + ObjCMethodDecl *Method = + cast_or_null<ObjCMethodDecl>(allMethods[i].getAs<Decl>()); + + if (!Method) continue; // Already issued a diagnostic. + if (Method->isInstanceMethod()) { + /// Check for instance method of the same name with incompatible types + const ObjCMethodDecl *&PrevMethod = InsMap[Method->getSelector()]; + bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod) + : false; + if ((isInterfaceDeclKind && PrevMethod && !match) + || (checkIdenticalMethods && match)) { + Diag(Method->getLocation(), diag::err_duplicate_method_decl) + << Method->getDeclName(); + Diag(PrevMethod->getLocation(), diag::note_previous_declaration); + } else { + DC->addDecl(Context, Method); + InsMap[Method->getSelector()] = Method; + /// The following allows us to typecheck messages to "id". + AddInstanceMethodToGlobalPool(Method); + } + } + else { + /// Check for class method of the same name with incompatible types + const ObjCMethodDecl *&PrevMethod = ClsMap[Method->getSelector()]; + bool match = PrevMethod ? MatchTwoMethodDeclarations(Method, PrevMethod) + : false; + if ((isInterfaceDeclKind && PrevMethod && !match) + || (checkIdenticalMethods && match)) { + Diag(Method->getLocation(), diag::err_duplicate_method_decl) + << Method->getDeclName(); + Diag(PrevMethod->getLocation(), diag::note_previous_declaration); + } else { + DC->addDecl(Context, Method); + ClsMap[Method->getSelector()] = Method; + /// The following allows us to typecheck messages to "Class". + AddFactoryMethodToGlobalPool(Method); + } + } + } + if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) { + // Compares properties declared in this class to those of its + // super class. + ComparePropertiesInBaseAndSuper(I); + MergeProtocolPropertiesIntoClass(I, DeclPtrTy::make(I)); + } else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(ClassDecl)) { + // Categories are used to extend the class by declaring new methods. + // By the same token, they are also used to add new properties. No + // need to compare the added property to those in the class. + + // Merge protocol properties into category + MergeProtocolPropertiesIntoClass(C, DeclPtrTy::make(C)); + if (C->getIdentifier() == 0) + DiagnoseClassExtensionDupMethods(C, C->getClassInterface()); + } + if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(ClassDecl)) { + // ProcessPropertyDecl is responsible for diagnosing conflicts with any + // user-defined setter/getter. It also synthesizes setter/getter methods + // and adds them to the DeclContext and global method pools. + for (ObjCContainerDecl::prop_iterator I = CDecl->prop_begin(Context), + E = CDecl->prop_end(Context); + I != E; ++I) + ProcessPropertyDecl(*I, CDecl); + CDecl->setAtEndLoc(AtEndLoc); + } + if (ObjCImplementationDecl *IC=dyn_cast<ObjCImplementationDecl>(ClassDecl)) { + IC->setLocEnd(AtEndLoc); + if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) + ImplMethodsVsClassMethods(IC, IDecl); + } else if (ObjCCategoryImplDecl* CatImplClass = + dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) { + CatImplClass->setLocEnd(AtEndLoc); + + // Find category interface decl and then check that all methods declared + // in this interface are implemented in the category @implementation. + if (ObjCInterfaceDecl* IDecl = CatImplClass->getClassInterface()) { + for (ObjCCategoryDecl *Categories = IDecl->getCategoryList(); + Categories; Categories = Categories->getNextClassCategory()) { + if (Categories->getIdentifier() == CatImplClass->getIdentifier()) { + ImplMethodsVsClassMethods(CatImplClass, Categories); + break; + } + } + } + } + if (isInterfaceDeclKind) { + // Reject invalid vardecls. + for (unsigned i = 0; i != tuvNum; i++) { + DeclGroupRef DG = allTUVars[i].getAsVal<DeclGroupRef>(); + for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) + if (VarDecl *VDecl = dyn_cast<VarDecl>(*I)) { + if (!VDecl->hasExternalStorage()) + Diag(VDecl->getLocation(), diag::err_objc_var_decl_inclass); + } + } + } +} + + +/// CvtQTToAstBitMask - utility routine to produce an AST bitmask for +/// objective-c's type qualifier from the parser version of the same info. +static Decl::ObjCDeclQualifier +CvtQTToAstBitMask(ObjCDeclSpec::ObjCDeclQualifier PQTVal) { + Decl::ObjCDeclQualifier ret = Decl::OBJC_TQ_None; + if (PQTVal & ObjCDeclSpec::DQ_In) + ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_In); + if (PQTVal & ObjCDeclSpec::DQ_Inout) + ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Inout); + if (PQTVal & ObjCDeclSpec::DQ_Out) + ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Out); + if (PQTVal & ObjCDeclSpec::DQ_Bycopy) + ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Bycopy); + if (PQTVal & ObjCDeclSpec::DQ_Byref) + ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Byref); + if (PQTVal & ObjCDeclSpec::DQ_Oneway) + ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Oneway); + + return ret; +} + +Sema::DeclPtrTy Sema::ActOnMethodDeclaration( + SourceLocation MethodLoc, SourceLocation EndLoc, + tok::TokenKind MethodType, DeclPtrTy classDecl, + ObjCDeclSpec &ReturnQT, TypeTy *ReturnType, + Selector Sel, + // optional arguments. The number of types/arguments is obtained + // from the Sel.getNumArgs(). + ObjCArgInfo *ArgInfo, + llvm::SmallVectorImpl<Declarator> &Cdecls, + AttributeList *AttrList, tok::ObjCKeywordKind MethodDeclKind, + bool isVariadic) { + Decl *ClassDecl = classDecl.getAs<Decl>(); + + // Make sure we can establish a context for the method. + if (!ClassDecl) { + Diag(MethodLoc, diag::error_missing_method_context); + return DeclPtrTy(); + } + QualType resultDeclType; + + if (ReturnType) { + resultDeclType = QualType::getFromOpaquePtr(ReturnType); + + // Methods cannot return interface types. All ObjC objects are + // passed by reference. + if (resultDeclType->isObjCInterfaceType()) { + Diag(MethodLoc, diag::err_object_cannot_be_passed_returned_by_value) + << 0 << resultDeclType; + return DeclPtrTy(); + } + } else // get the type for "id". + resultDeclType = Context.getObjCIdType(); + + ObjCMethodDecl* ObjCMethod = + ObjCMethodDecl::Create(Context, MethodLoc, EndLoc, Sel, resultDeclType, + cast<DeclContext>(ClassDecl), + MethodType == tok::minus, isVariadic, + false, + MethodDeclKind == tok::objc_optional ? + ObjCMethodDecl::Optional : + ObjCMethodDecl::Required); + + llvm::SmallVector<ParmVarDecl*, 16> Params; + + for (unsigned i = 0, e = Sel.getNumArgs(); i != e; ++i) { + QualType ArgType, UnpromotedArgType; + + if (ArgInfo[i].Type == 0) { + UnpromotedArgType = ArgType = Context.getObjCIdType(); + } else { + UnpromotedArgType = ArgType = QualType::getFromOpaquePtr(ArgInfo[i].Type); + // Perform the default array/function conversions (C99 6.7.5.3p[7,8]). + ArgType = adjustParameterType(ArgType); + } + + ParmVarDecl* Param; + if (ArgType == UnpromotedArgType) + Param = ParmVarDecl::Create(Context, ObjCMethod, ArgInfo[i].NameLoc, + ArgInfo[i].Name, ArgType, + VarDecl::None, 0); + else + Param = OriginalParmVarDecl::Create(Context, ObjCMethod, + ArgInfo[i].NameLoc, + ArgInfo[i].Name, ArgType, + UnpromotedArgType, + VarDecl::None, 0); + + if (ArgType->isObjCInterfaceType()) { + Diag(ArgInfo[i].NameLoc, + diag::err_object_cannot_be_passed_returned_by_value) + << 1 << ArgType; + Param->setInvalidDecl(); + } + + Param->setObjCDeclQualifier( + CvtQTToAstBitMask(ArgInfo[i].DeclSpec.getObjCDeclQualifier())); + + // Apply the attributes to the parameter. + ProcessDeclAttributeList(Param, ArgInfo[i].ArgAttrs); + + Params.push_back(Param); + } + + ObjCMethod->setMethodParams(Context, Params.data(), Sel.getNumArgs()); + ObjCMethod->setObjCDeclQualifier( + CvtQTToAstBitMask(ReturnQT.getObjCDeclQualifier())); + const ObjCMethodDecl *PrevMethod = 0; + + if (AttrList) + ProcessDeclAttributeList(ObjCMethod, AttrList); + + // For implementations (which can be very "coarse grain"), we add the + // method now. This allows the AST to implement lookup methods that work + // incrementally (without waiting until we parse the @end). It also allows + // us to flag multiple declaration errors as they occur. + if (ObjCImplementationDecl *ImpDecl = + dyn_cast<ObjCImplementationDecl>(ClassDecl)) { + if (MethodType == tok::minus) { + PrevMethod = ImpDecl->getInstanceMethod(Context, Sel); + ImpDecl->addInstanceMethod(Context, ObjCMethod); + } else { + PrevMethod = ImpDecl->getClassMethod(Context, Sel); + ImpDecl->addClassMethod(Context, ObjCMethod); + } + if (AttrList) + Diag(EndLoc, diag::warn_attribute_method_def); + } + else if (ObjCCategoryImplDecl *CatImpDecl = + dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) { + if (MethodType == tok::minus) { + PrevMethod = CatImpDecl->getInstanceMethod(Context, Sel); + CatImpDecl->addInstanceMethod(Context, ObjCMethod); + } else { + PrevMethod = CatImpDecl->getClassMethod(Context, Sel); + CatImpDecl->addClassMethod(Context, ObjCMethod); + } + if (AttrList) + Diag(EndLoc, diag::warn_attribute_method_def); + } + if (PrevMethod) { + // You can never have two method definitions with the same name. + Diag(ObjCMethod->getLocation(), diag::err_duplicate_method_decl) + << ObjCMethod->getDeclName(); + Diag(PrevMethod->getLocation(), diag::note_previous_declaration); + } + return DeclPtrTy::make(ObjCMethod); +} + +void Sema::CheckObjCPropertyAttributes(QualType PropertyTy, + SourceLocation Loc, + unsigned &Attributes) { + // FIXME: Improve the reported location. + + // readonly and readwrite/assign/retain/copy conflict. + if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) && + (Attributes & (ObjCDeclSpec::DQ_PR_readwrite | + ObjCDeclSpec::DQ_PR_assign | + ObjCDeclSpec::DQ_PR_copy | + ObjCDeclSpec::DQ_PR_retain))) { + const char * which = (Attributes & ObjCDeclSpec::DQ_PR_readwrite) ? + "readwrite" : + (Attributes & ObjCDeclSpec::DQ_PR_assign) ? + "assign" : + (Attributes & ObjCDeclSpec::DQ_PR_copy) ? + "copy" : "retain"; + + Diag(Loc, (Attributes & (ObjCDeclSpec::DQ_PR_readwrite)) ? + diag::err_objc_property_attr_mutually_exclusive : + diag::warn_objc_property_attr_mutually_exclusive) + << "readonly" << which; + } + + // Check for copy or retain on non-object types. + if ((Attributes & (ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) && + !Context.isObjCObjectPointerType(PropertyTy)) { + Diag(Loc, diag::err_objc_property_requires_object) + << (Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain"); + Attributes &= ~(ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain); + } + + // Check for more than one of { assign, copy, retain }. + if (Attributes & ObjCDeclSpec::DQ_PR_assign) { + if (Attributes & ObjCDeclSpec::DQ_PR_copy) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "assign" << "copy"; + Attributes &= ~ObjCDeclSpec::DQ_PR_copy; + } + if (Attributes & ObjCDeclSpec::DQ_PR_retain) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "assign" << "retain"; + Attributes &= ~ObjCDeclSpec::DQ_PR_retain; + } + } else if (Attributes & ObjCDeclSpec::DQ_PR_copy) { + if (Attributes & ObjCDeclSpec::DQ_PR_retain) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "copy" << "retain"; + Attributes &= ~ObjCDeclSpec::DQ_PR_retain; + } + } + + // Warn if user supplied no assignment attribute, property is + // readwrite, and this is an object type. + if (!(Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_copy | + ObjCDeclSpec::DQ_PR_retain)) && + !(Attributes & ObjCDeclSpec::DQ_PR_readonly) && + Context.isObjCObjectPointerType(PropertyTy)) { + // Skip this warning in gc-only mode. + if (getLangOptions().getGCMode() != LangOptions::GCOnly) + Diag(Loc, diag::warn_objc_property_no_assignment_attribute); + + // If non-gc code warn that this is likely inappropriate. + if (getLangOptions().getGCMode() == LangOptions::NonGC) + Diag(Loc, diag::warn_objc_property_default_assign_on_object); + + // FIXME: Implement warning dependent on NSCopying being + // implemented. See also: + // <rdar://5168496&4855821&5607453&5096644&4947311&5698469&4947014&5168496> + // (please trim this list while you are at it). + } + + if (!(Attributes & ObjCDeclSpec::DQ_PR_copy) + && getLangOptions().getGCMode() == LangOptions::GCOnly + && PropertyTy->isBlockPointerType()) + Diag(Loc, diag::warn_objc_property_copy_missing_on_block); +} + +Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, + FieldDeclarator &FD, + ObjCDeclSpec &ODS, + Selector GetterSel, + Selector SetterSel, + DeclPtrTy ClassCategory, + bool *isOverridingProperty, + tok::ObjCKeywordKind MethodImplKind) { + unsigned Attributes = ODS.getPropertyAttributes(); + bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) || + // default is readwrite! + !(Attributes & ObjCDeclSpec::DQ_PR_readonly)); + // property is defaulted to 'assign' if it is readwrite and is + // not retain or copy + bool isAssign = ((Attributes & ObjCDeclSpec::DQ_PR_assign) || + (isReadWrite && + !(Attributes & ObjCDeclSpec::DQ_PR_retain) && + !(Attributes & ObjCDeclSpec::DQ_PR_copy))); + QualType T = GetTypeForDeclarator(FD.D, S); + Decl *ClassDecl = ClassCategory.getAs<Decl>(); + ObjCInterfaceDecl *CCPrimary = 0; // continuation class's primary class + // May modify Attributes. + CheckObjCPropertyAttributes(T, AtLoc, Attributes); + if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) + if (!CDecl->getIdentifier()) { + // This is a continuation class. property requires special + // handling. + if ((CCPrimary = CDecl->getClassInterface())) { + // Find the property in continuation class's primary class only. + ObjCPropertyDecl *PIDecl = 0; + IdentifierInfo *PropertyId = FD.D.getIdentifier(); + for (ObjCInterfaceDecl::prop_iterator + I = CCPrimary->prop_begin(Context), + E = CCPrimary->prop_end(Context); + I != E; ++I) + if ((*I)->getIdentifier() == PropertyId) { + PIDecl = *I; + break; + } + + if (PIDecl) { + // property 'PIDecl's readonly attribute will be over-ridden + // with continuation class's readwrite property attribute! + unsigned PIkind = PIDecl->getPropertyAttributes(); + if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) { + if ((Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) != + (PIkind & ObjCPropertyDecl::OBJC_PR_nonatomic)) + Diag(AtLoc, diag::warn_property_attr_mismatch); + PIDecl->makeitReadWriteAttribute(); + if (Attributes & ObjCDeclSpec::DQ_PR_retain) + PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); + if (Attributes & ObjCDeclSpec::DQ_PR_copy) + PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); + PIDecl->setSetterName(SetterSel); + } + else + Diag(AtLoc, diag::err_use_continuation_class) + << CCPrimary->getDeclName(); + *isOverridingProperty = true; + // Make sure setter decl is synthesized, and added to primary + // class's list. + ProcessPropertyDecl(PIDecl, CCPrimary); + return DeclPtrTy(); + } + // No matching property found in the primary class. Just fall thru + // and add property to continuation class's primary class. + ClassDecl = CCPrimary; + } else { + Diag(CDecl->getLocation(), diag::err_continuation_class); + *isOverridingProperty = true; + return DeclPtrTy(); + } + } + + DeclContext *DC = dyn_cast<DeclContext>(ClassDecl); + assert(DC && "ClassDecl is not a DeclContext"); + ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, + FD.D.getIdentifierLoc(), + FD.D.getIdentifier(), T); + DC->addDecl(Context, PDecl); + + if (T->isArrayType() || T->isFunctionType()) { + Diag(AtLoc, diag::err_property_type) << T; + PDecl->setInvalidDecl(); + } + + ProcessDeclAttributes(PDecl, FD.D); + + // Regardless of setter/getter attribute, we save the default getter/setter + // selector names in anticipation of declaration of setter/getter methods. + PDecl->setGetterName(GetterSel); + PDecl->setSetterName(SetterSel); + + if (Attributes & ObjCDeclSpec::DQ_PR_readonly) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly); + + if (Attributes & ObjCDeclSpec::DQ_PR_getter) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_getter); + + if (Attributes & ObjCDeclSpec::DQ_PR_setter) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_setter); + + if (isReadWrite) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite); + + if (Attributes & ObjCDeclSpec::DQ_PR_retain) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); + + if (Attributes & ObjCDeclSpec::DQ_PR_copy) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); + + if (isAssign) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign); + + if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic); + + if (MethodImplKind == tok::objc_required) + PDecl->setPropertyImplementation(ObjCPropertyDecl::Required); + else if (MethodImplKind == tok::objc_optional) + PDecl->setPropertyImplementation(ObjCPropertyDecl::Optional); + // A case of continuation class adding a new property in the class. This + // is not what it was meant for. However, gcc supports it and so should we. + // Make sure setter/getters are declared here. + if (CCPrimary) + ProcessPropertyDecl(PDecl, CCPrimary); + + return DeclPtrTy::make(PDecl); +} + +/// ActOnPropertyImplDecl - This routine performs semantic checks and +/// builds the AST node for a property implementation declaration; declared +/// as @synthesize or @dynamic. +/// +Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, + SourceLocation PropertyLoc, + bool Synthesize, + DeclPtrTy ClassCatImpDecl, + IdentifierInfo *PropertyId, + IdentifierInfo *PropertyIvar) { + Decl *ClassImpDecl = ClassCatImpDecl.getAs<Decl>(); + // Make sure we have a context for the property implementation declaration. + if (!ClassImpDecl) { + Diag(AtLoc, diag::error_missing_property_context); + return DeclPtrTy(); + } + ObjCPropertyDecl *property = 0; + ObjCInterfaceDecl* IDecl = 0; + // Find the class or category class where this property must have + // a declaration. + ObjCImplementationDecl *IC = 0; + ObjCCategoryImplDecl* CatImplClass = 0; + if ((IC = dyn_cast<ObjCImplementationDecl>(ClassImpDecl))) { + IDecl = IC->getClassInterface(); + // We always synthesize an interface for an implementation + // without an interface decl. So, IDecl is always non-zero. + assert(IDecl && + "ActOnPropertyImplDecl - @implementation without @interface"); + + // Look for this property declaration in the @implementation's @interface + property = IDecl->FindPropertyDeclaration(Context, PropertyId); + if (!property) { + Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName(); + return DeclPtrTy(); + } + } + else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) { + if (Synthesize) { + Diag(AtLoc, diag::error_synthesize_category_decl); + return DeclPtrTy(); + } + IDecl = CatImplClass->getClassInterface(); + if (!IDecl) { + Diag(AtLoc, diag::error_missing_property_interface); + return DeclPtrTy(); + } + ObjCCategoryDecl *Category = + IDecl->FindCategoryDeclaration(CatImplClass->getIdentifier()); + + // If category for this implementation not found, it is an error which + // has already been reported eralier. + if (!Category) + return DeclPtrTy(); + // Look for this property declaration in @implementation's category + property = Category->FindPropertyDeclaration(Context, PropertyId); + if (!property) { + Diag(PropertyLoc, diag::error_bad_category_property_decl) + << Category->getDeclName(); + return DeclPtrTy(); + } + } else { + Diag(AtLoc, diag::error_bad_property_context); + return DeclPtrTy(); + } + ObjCIvarDecl *Ivar = 0; + // Check that we have a valid, previously declared ivar for @synthesize + if (Synthesize) { + // @synthesize + if (!PropertyIvar) + PropertyIvar = PropertyId; + QualType PropType = Context.getCanonicalType(property->getType()); + // Check that this is a previously declared 'ivar' in 'IDecl' interface + ObjCInterfaceDecl *ClassDeclared; + Ivar = IDecl->lookupInstanceVariable(Context, PropertyIvar, ClassDeclared); + if (!Ivar) { + Ivar = ObjCIvarDecl::Create(Context, CurContext, PropertyLoc, + PropertyIvar, PropType, + ObjCIvarDecl::Public, + (Expr *)0); + property->setPropertyIvarDecl(Ivar); + if (!getLangOptions().ObjCNonFragileABI) + Diag(PropertyLoc, diag::error_missing_property_ivar_decl) << PropertyId; + // Note! I deliberately want it to fall thru so, we have a + // a property implementation and to avoid future warnings. + } + else if (getLangOptions().ObjCNonFragileABI && + ClassDeclared != IDecl) { + Diag(PropertyLoc, diag::error_ivar_in_superclass_use) + << property->getDeclName() << Ivar->getDeclName() + << ClassDeclared->getDeclName(); + Diag(Ivar->getLocation(), diag::note_previous_access_declaration) + << Ivar << Ivar->getNameAsCString(); + // Note! I deliberately want it to fall thru so more errors are caught. + } + QualType IvarType = Context.getCanonicalType(Ivar->getType()); + + // Check that type of property and its ivar are type compatible. + if (PropType != IvarType) { + if (CheckAssignmentConstraints(PropType, IvarType) != Compatible) { + Diag(PropertyLoc, diag::error_property_ivar_type) + << property->getDeclName() << Ivar->getDeclName(); + // Note! I deliberately want it to fall thru so, we have a + // a property implementation and to avoid future warnings. + } + + // FIXME! Rules for properties are somewhat different that those + // for assignments. Use a new routine to consolidate all cases; + // specifically for property redeclarations as well as for ivars. + QualType lhsType =Context.getCanonicalType(PropType).getUnqualifiedType(); + QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType(); + if (lhsType != rhsType && + lhsType->isArithmeticType()) { + Diag(PropertyLoc, diag::error_property_ivar_type) + << property->getDeclName() << Ivar->getDeclName(); + // Fall thru - see previous comment + } + // __weak is explicit. So it works on Canonical type. + if (PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() && + getLangOptions().getGCMode() != LangOptions::NonGC) { + Diag(PropertyLoc, diag::error_weak_property) + << property->getDeclName() << Ivar->getDeclName(); + // Fall thru - see previous comment + } + if ((Context.isObjCObjectPointerType(property->getType()) || + PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() && + getLangOptions().getGCMode() != LangOptions::NonGC) { + Diag(PropertyLoc, diag::error_strong_property) + << property->getDeclName() << Ivar->getDeclName(); + // Fall thru - see previous comment + } + } + } else if (PropertyIvar) + // @dynamic + Diag(PropertyLoc, diag::error_dynamic_property_ivar_decl); + assert (property && "ActOnPropertyImplDecl - property declaration missing"); + ObjCPropertyImplDecl *PIDecl = + ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc, + property, + (Synthesize ? + ObjCPropertyImplDecl::Synthesize + : ObjCPropertyImplDecl::Dynamic), + Ivar); + if (IC) { + if (Synthesize) + if (ObjCPropertyImplDecl *PPIDecl = + IC->FindPropertyImplIvarDecl(Context, PropertyIvar)) { + Diag(PropertyLoc, diag::error_duplicate_ivar_use) + << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier() + << PropertyIvar; + Diag(PPIDecl->getLocation(), diag::note_previous_use); + } + + if (ObjCPropertyImplDecl *PPIDecl + = IC->FindPropertyImplDecl(Context, PropertyId)) { + Diag(PropertyLoc, diag::error_property_implemented) << PropertyId; + Diag(PPIDecl->getLocation(), diag::note_previous_declaration); + return DeclPtrTy(); + } + IC->addPropertyImplementation(Context, PIDecl); + } + else { + if (Synthesize) + if (ObjCPropertyImplDecl *PPIDecl = + CatImplClass->FindPropertyImplIvarDecl(Context, PropertyIvar)) { + Diag(PropertyLoc, diag::error_duplicate_ivar_use) + << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier() + << PropertyIvar; + Diag(PPIDecl->getLocation(), diag::note_previous_use); + } + + if (ObjCPropertyImplDecl *PPIDecl = + CatImplClass->FindPropertyImplDecl(Context, PropertyId)) { + Diag(PropertyLoc, diag::error_property_implemented) << PropertyId; + Diag(PPIDecl->getLocation(), diag::note_previous_declaration); + return DeclPtrTy(); + } + CatImplClass->addPropertyImplementation(Context, PIDecl); + } + + return DeclPtrTy::make(PIDecl); +} + +bool Sema::CheckObjCDeclScope(Decl *D) { + if (isa<TranslationUnitDecl>(CurContext->getLookupContext())) + return false; + + Diag(D->getLocation(), diag::err_objc_decls_may_only_appear_in_global_scope); + D->setInvalidDecl(); + + return true; +} + +/// Collect the instance variables declared in an Objective-C object. Used in +/// the creation of structures from objects using the @defs directive. +/// FIXME: This should be consolidated with CollectObjCIvars as it is also +/// part of the AST generation logic of @defs. +static void CollectIvars(ObjCInterfaceDecl *Class, RecordDecl *Record, + ASTContext& Ctx, + llvm::SmallVectorImpl<Sema::DeclPtrTy> &ivars) { + if (Class->getSuperClass()) + CollectIvars(Class->getSuperClass(), Record, Ctx, ivars); + + // For each ivar, create a fresh ObjCAtDefsFieldDecl. + for (ObjCInterfaceDecl::ivar_iterator I = Class->ivar_begin(), + E = Class->ivar_end(); I != E; ++I) { + ObjCIvarDecl* ID = *I; + Decl *FD = ObjCAtDefsFieldDecl::Create(Ctx, Record, ID->getLocation(), + ID->getIdentifier(), ID->getType(), + ID->getBitWidth()); + ivars.push_back(Sema::DeclPtrTy::make(FD)); + } +} + +/// Called whenever @defs(ClassName) is encountered in the source. Inserts the +/// instance variables of ClassName into Decls. +void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, + IdentifierInfo *ClassName, + llvm::SmallVectorImpl<DeclPtrTy> &Decls) { + // Check that ClassName is a valid class + ObjCInterfaceDecl *Class = getObjCInterfaceDecl(ClassName); + if (!Class) { + Diag(DeclStart, diag::err_undef_interface) << ClassName; + return; + } + if (LangOpts.ObjCNonFragileABI) { + Diag(DeclStart, diag::err_atdef_nonfragile_interface); + return; + } + + // Collect the instance variables + CollectIvars(Class, dyn_cast<RecordDecl>(TagD.getAs<Decl>()), Context, Decls); + + // Introduce all of these fields into the appropriate scope. + for (llvm::SmallVectorImpl<DeclPtrTy>::iterator D = Decls.begin(); + D != Decls.end(); ++D) { + FieldDecl *FD = cast<FieldDecl>(D->getAs<Decl>()); + if (getLangOptions().CPlusPlus) + PushOnScopeChains(cast<FieldDecl>(FD), S); + else if (RecordDecl *Record = dyn_cast<RecordDecl>(TagD.getAs<Decl>())) + Record->addDecl(Context, FD); + } +} + diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp new file mode 100644 index 0000000..ee5132a --- /dev/null +++ b/lib/Sema/SemaExpr.cpp @@ -0,0 +1,5395 @@ +//===--- SemaExpr.cpp - Semantic Analysis for Expressions -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for expressions. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/LiteralSupport.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Parse/DeclSpec.h" +#include "clang/Parse/Designator.h" +#include "clang/Parse/Scope.h" +using namespace clang; + +/// \brief Determine whether the use of this declaration is valid, and +/// emit any corresponding diagnostics. +/// +/// This routine diagnoses various problems with referencing +/// declarations that can occur when using a declaration. For example, +/// it might warn if a deprecated or unavailable declaration is being +/// used, or produce an error (and return true) if a C++0x deleted +/// function is being used. +/// +/// \returns true if there was an error (this declaration cannot be +/// referenced), false otherwise. +bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) { + // See if the decl is deprecated. + if (D->getAttr<DeprecatedAttr>()) { + // Implementing deprecated stuff requires referencing deprecated + // stuff. Don't warn if we are implementing a deprecated + // construct. + bool isSilenced = false; + + if (NamedDecl *ND = getCurFunctionOrMethodDecl()) { + // If this reference happens *in* a deprecated function or method, don't + // warn. + isSilenced = ND->getAttr<DeprecatedAttr>(); + + // If this is an Objective-C method implementation, check to see if the + // method was deprecated on the declaration, not the definition. + if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ND)) { + // The semantic decl context of a ObjCMethodDecl is the + // ObjCImplementationDecl. + if (ObjCImplementationDecl *Impl + = dyn_cast<ObjCImplementationDecl>(MD->getParent())) { + + MD = Impl->getClassInterface()->getMethod(Context, + MD->getSelector(), + MD->isInstanceMethod()); + isSilenced |= MD && MD->getAttr<DeprecatedAttr>(); + } + } + } + + if (!isSilenced) + Diag(Loc, diag::warn_deprecated) << D->getDeclName(); + } + + // See if this is a deleted function. + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->isDeleted()) { + Diag(Loc, diag::err_deleted_function_use); + Diag(D->getLocation(), diag::note_unavailable_here) << true; + return true; + } + } + + // See if the decl is unavailable + if (D->getAttr<UnavailableAttr>()) { + Diag(Loc, diag::warn_unavailable) << D->getDeclName(); + Diag(D->getLocation(), diag::note_unavailable_here) << 0; + } + + return false; +} + +/// DiagnoseSentinelCalls - This routine checks on method dispatch calls +/// (and other functions in future), which have been declared with sentinel +/// attribute. It warns if call does not have the sentinel argument. +/// +void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, + Expr **Args, unsigned NumArgs) +{ + const SentinelAttr *attr = D->getAttr<SentinelAttr>(); + if (!attr) + return; + int sentinelPos = attr->getSentinel(); + int nullPos = attr->getNullPos(); + + // FIXME. ObjCMethodDecl and FunctionDecl need be derived from the same common + // base class. Then we won't be needing two versions of the same code. + unsigned int i = 0; + bool warnNotEnoughArgs = false; + int isMethod = 0; + if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + // skip over named parameters. + ObjCMethodDecl::param_iterator P, E = MD->param_end(); + for (P = MD->param_begin(); (P != E && i < NumArgs); ++P) { + if (nullPos) + --nullPos; + else + ++i; + } + warnNotEnoughArgs = (P != E || i >= NumArgs); + isMethod = 1; + } + else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // skip over named parameters. + ObjCMethodDecl::param_iterator P, E = FD->param_end(); + for (P = FD->param_begin(); (P != E && i < NumArgs); ++P) { + if (nullPos) + --nullPos; + else + ++i; + } + warnNotEnoughArgs = (P != E || i >= NumArgs); + } + else if (VarDecl *V = dyn_cast<VarDecl>(D)) { + // block or function pointer call. + QualType Ty = V->getType(); + if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) { + const FunctionType *FT = Ty->isFunctionPointerType() + ? Ty->getAsPointerType()->getPointeeType()->getAsFunctionType() + : Ty->getAsBlockPointerType()->getPointeeType()->getAsFunctionType(); + if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) { + unsigned NumArgsInProto = Proto->getNumArgs(); + unsigned k; + for (k = 0; (k != NumArgsInProto && i < NumArgs); k++) { + if (nullPos) + --nullPos; + else + ++i; + } + warnNotEnoughArgs = (k != NumArgsInProto || i >= NumArgs); + } + if (Ty->isBlockPointerType()) + isMethod = 2; + } + else + return; + } + else + return; + + if (warnNotEnoughArgs) { + Diag(Loc, diag::warn_not_enough_argument) << D->getDeclName(); + Diag(D->getLocation(), diag::note_sentinel_here) << isMethod; + return; + } + int sentinel = i; + while (sentinelPos > 0 && i < NumArgs-1) { + --sentinelPos; + ++i; + } + if (sentinelPos > 0) { + Diag(Loc, diag::warn_not_enough_argument) << D->getDeclName(); + Diag(D->getLocation(), diag::note_sentinel_here) << isMethod; + return; + } + while (i < NumArgs-1) { + ++i; + ++sentinel; + } + Expr *sentinelExpr = Args[sentinel]; + if (sentinelExpr && (!sentinelExpr->getType()->isPointerType() || + !sentinelExpr->isNullPointerConstant(Context))) { + Diag(Loc, diag::warn_missing_sentinel) << isMethod; + Diag(D->getLocation(), diag::note_sentinel_here) << isMethod; + } + return; +} + +SourceRange Sema::getExprRange(ExprTy *E) const { + Expr *Ex = (Expr *)E; + return Ex? Ex->getSourceRange() : SourceRange(); +} + +//===----------------------------------------------------------------------===// +// Standard Promotions and Conversions +//===----------------------------------------------------------------------===// + +/// DefaultFunctionArrayConversion (C99 6.3.2.1p3, C99 6.3.2.1p4). +void Sema::DefaultFunctionArrayConversion(Expr *&E) { + QualType Ty = E->getType(); + assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type"); + + if (Ty->isFunctionType()) + ImpCastExprToType(E, Context.getPointerType(Ty)); + else if (Ty->isArrayType()) { + // In C90 mode, arrays only promote to pointers if the array expression is + // an lvalue. The relevant legalese is C90 6.2.2.1p3: "an lvalue that has + // type 'array of type' is converted to an expression that has type 'pointer + // to type'...". In C99 this was changed to: C99 6.3.2.1p3: "an expression + // that has type 'array of type' ...". The relevant change is "an lvalue" + // (C90) to "an expression" (C99). + // + // C++ 4.2p1: + // An lvalue or rvalue of type "array of N T" or "array of unknown bound of + // T" can be converted to an rvalue of type "pointer to T". + // + if (getLangOptions().C99 || getLangOptions().CPlusPlus || + E->isLvalue(Context) == Expr::LV_Valid) + ImpCastExprToType(E, Context.getArrayDecayedType(Ty)); + } +} + +/// \brief Whether this is a promotable bitfield reference according +/// to C99 6.3.1.1p2, bullet 2. +/// +/// \returns the type this bit-field will promote to, or NULL if no +/// promotion occurs. +static QualType isPromotableBitField(Expr *E, ASTContext &Context) { + FieldDecl *Field = E->getBitField(); + if (!Field) + return QualType(); + + const BuiltinType *BT = Field->getType()->getAsBuiltinType(); + if (!BT) + return QualType(); + + if (BT->getKind() != BuiltinType::Bool && + BT->getKind() != BuiltinType::Int && + BT->getKind() != BuiltinType::UInt) + return QualType(); + + llvm::APSInt BitWidthAP; + if (!Field->getBitWidth()->isIntegerConstantExpr(BitWidthAP, Context)) + return QualType(); + + uint64_t BitWidth = BitWidthAP.getZExtValue(); + uint64_t IntSize = Context.getTypeSize(Context.IntTy); + if (BitWidth < IntSize || + (Field->getType()->isSignedIntegerType() && BitWidth == IntSize)) + return Context.IntTy; + + if (BitWidth == IntSize && Field->getType()->isUnsignedIntegerType()) + return Context.UnsignedIntTy; + + return QualType(); +} + +/// UsualUnaryConversions - Performs various conversions that are common to most +/// operators (C99 6.3). The conversions of array and function types are +/// sometimes surpressed. For example, the array->pointer conversion doesn't +/// apply if the array is an argument to the sizeof or address (&) operators. +/// In these instances, this routine should *not* be called. +Expr *Sema::UsualUnaryConversions(Expr *&Expr) { + QualType Ty = Expr->getType(); + assert(!Ty.isNull() && "UsualUnaryConversions - missing type"); + + // C99 6.3.1.1p2: + // + // The following may be used in an expression wherever an int or + // unsigned int may be used: + // - an object or expression with an integer type whose integer + // conversion rank is less than or equal to the rank of int + // and unsigned int. + // - A bit-field of type _Bool, int, signed int, or unsigned int. + // + // If an int can represent all values of the original type, the + // value is converted to an int; otherwise, it is converted to an + // unsigned int. These are called the integer promotions. All + // other types are unchanged by the integer promotions. + if (Ty->isPromotableIntegerType()) { + ImpCastExprToType(Expr, Context.IntTy); + return Expr; + } else { + QualType T = isPromotableBitField(Expr, Context); + if (!T.isNull()) { + ImpCastExprToType(Expr, T); + return Expr; + } + } + + DefaultFunctionArrayConversion(Expr); + return Expr; +} + +/// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that +/// do not have a prototype. Arguments that have type float are promoted to +/// double. All other argument types are converted by UsualUnaryConversions(). +void Sema::DefaultArgumentPromotion(Expr *&Expr) { + QualType Ty = Expr->getType(); + assert(!Ty.isNull() && "DefaultArgumentPromotion - missing type"); + + // If this is a 'float' (CVR qualified or typedef) promote to double. + if (const BuiltinType *BT = Ty->getAsBuiltinType()) + if (BT->getKind() == BuiltinType::Float) + return ImpCastExprToType(Expr, Context.DoubleTy); + + UsualUnaryConversions(Expr); +} + +/// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but +/// will warn if the resulting type is not a POD type, and rejects ObjC +/// interfaces passed by value. This returns true if the argument type is +/// completely illegal. +bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) { + DefaultArgumentPromotion(Expr); + + if (Expr->getType()->isObjCInterfaceType()) { + Diag(Expr->getLocStart(), + diag::err_cannot_pass_objc_interface_to_vararg) + << Expr->getType() << CT; + return true; + } + + if (!Expr->getType()->isPODType()) + Diag(Expr->getLocStart(), diag::warn_cannot_pass_non_pod_arg_to_vararg) + << Expr->getType() << CT; + + return false; +} + + +/// UsualArithmeticConversions - Performs various conversions that are common to +/// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this +/// routine returns the first non-arithmetic type found. The client is +/// responsible for emitting appropriate error diagnostics. +/// FIXME: verify the conversion rules for "complex int" are consistent with +/// GCC. +QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, + bool isCompAssign) { + if (!isCompAssign) + UsualUnaryConversions(lhsExpr); + + UsualUnaryConversions(rhsExpr); + + // For conversion purposes, we ignore any qualifiers. + // For example, "const float" and "float" are equivalent. + QualType lhs = + Context.getCanonicalType(lhsExpr->getType()).getUnqualifiedType(); + QualType rhs = + Context.getCanonicalType(rhsExpr->getType()).getUnqualifiedType(); + + // If both types are identical, no conversion is needed. + if (lhs == rhs) + return lhs; + + // If either side is a non-arithmetic type (e.g. a pointer), we are done. + // The caller can deal with this (e.g. pointer + int). + if (!lhs->isArithmeticType() || !rhs->isArithmeticType()) + return lhs; + + // Perform bitfield promotions. + QualType LHSBitfieldPromoteTy = isPromotableBitField(lhsExpr, Context); + if (!LHSBitfieldPromoteTy.isNull()) + lhs = LHSBitfieldPromoteTy; + QualType RHSBitfieldPromoteTy = isPromotableBitField(rhsExpr, Context); + if (!RHSBitfieldPromoteTy.isNull()) + rhs = RHSBitfieldPromoteTy; + + QualType destType = UsualArithmeticConversionsType(lhs, rhs); + if (!isCompAssign) + ImpCastExprToType(lhsExpr, destType); + ImpCastExprToType(rhsExpr, destType); + return destType; +} + +QualType Sema::UsualArithmeticConversionsType(QualType lhs, QualType rhs) { + // Perform the usual unary conversions. We do this early so that + // integral promotions to "int" can allow us to exit early, in the + // lhs == rhs check. Also, for conversion purposes, we ignore any + // qualifiers. For example, "const float" and "float" are + // equivalent. + if (lhs->isPromotableIntegerType()) + lhs = Context.IntTy; + else + lhs = lhs.getUnqualifiedType(); + if (rhs->isPromotableIntegerType()) + rhs = Context.IntTy; + else + rhs = rhs.getUnqualifiedType(); + + // If both types are identical, no conversion is needed. + if (lhs == rhs) + return lhs; + + // If either side is a non-arithmetic type (e.g. a pointer), we are done. + // The caller can deal with this (e.g. pointer + int). + if (!lhs->isArithmeticType() || !rhs->isArithmeticType()) + return lhs; + + // At this point, we have two different arithmetic types. + + // Handle complex types first (C99 6.3.1.8p1). + if (lhs->isComplexType() || rhs->isComplexType()) { + // if we have an integer operand, the result is the complex type. + if (rhs->isIntegerType() || rhs->isComplexIntegerType()) { + // convert the rhs to the lhs complex type. + return lhs; + } + if (lhs->isIntegerType() || lhs->isComplexIntegerType()) { + // convert the lhs to the rhs complex type. + return rhs; + } + // This handles complex/complex, complex/float, or float/complex. + // When both operands are complex, the shorter operand is converted to the + // type of the longer, and that is the type of the result. This corresponds + // to what is done when combining two real floating-point operands. + // The fun begins when size promotion occur across type domains. + // From H&S 6.3.4: When one operand is complex and the other is a real + // floating-point type, the less precise type is converted, within it's + // real or complex domain, to the precision of the other type. For example, + // when combining a "long double" with a "double _Complex", the + // "double _Complex" is promoted to "long double _Complex". + int result = Context.getFloatingTypeOrder(lhs, rhs); + + if (result > 0) { // The left side is bigger, convert rhs. + rhs = Context.getFloatingTypeOfSizeWithinDomain(lhs, rhs); + } else if (result < 0) { // The right side is bigger, convert lhs. + lhs = Context.getFloatingTypeOfSizeWithinDomain(rhs, lhs); + } + // At this point, lhs and rhs have the same rank/size. Now, make sure the + // domains match. This is a requirement for our implementation, C99 + // does not require this promotion. + if (lhs != rhs) { // Domains don't match, we have complex/float mix. + if (lhs->isRealFloatingType()) { // handle "double, _Complex double". + return rhs; + } else { // handle "_Complex double, double". + return lhs; + } + } + return lhs; // The domain/size match exactly. + } + // Now handle "real" floating types (i.e. float, double, long double). + if (lhs->isRealFloatingType() || rhs->isRealFloatingType()) { + // if we have an integer operand, the result is the real floating type. + if (rhs->isIntegerType()) { + // convert rhs to the lhs floating point type. + return lhs; + } + if (rhs->isComplexIntegerType()) { + // convert rhs to the complex floating point type. + return Context.getComplexType(lhs); + } + if (lhs->isIntegerType()) { + // convert lhs to the rhs floating point type. + return rhs; + } + if (lhs->isComplexIntegerType()) { + // convert lhs to the complex floating point type. + return Context.getComplexType(rhs); + } + // We have two real floating types, float/complex combos were handled above. + // Convert the smaller operand to the bigger result. + int result = Context.getFloatingTypeOrder(lhs, rhs); + if (result > 0) // convert the rhs + return lhs; + assert(result < 0 && "illegal float comparison"); + return rhs; // convert the lhs + } + if (lhs->isComplexIntegerType() || rhs->isComplexIntegerType()) { + // Handle GCC complex int extension. + const ComplexType *lhsComplexInt = lhs->getAsComplexIntegerType(); + const ComplexType *rhsComplexInt = rhs->getAsComplexIntegerType(); + + if (lhsComplexInt && rhsComplexInt) { + if (Context.getIntegerTypeOrder(lhsComplexInt->getElementType(), + rhsComplexInt->getElementType()) >= 0) + return lhs; // convert the rhs + return rhs; + } else if (lhsComplexInt && rhs->isIntegerType()) { + // convert the rhs to the lhs complex type. + return lhs; + } else if (rhsComplexInt && lhs->isIntegerType()) { + // convert the lhs to the rhs complex type. + return rhs; + } + } + // Finally, we have two differing integer types. + // The rules for this case are in C99 6.3.1.8 + int compare = Context.getIntegerTypeOrder(lhs, rhs); + bool lhsSigned = lhs->isSignedIntegerType(), + rhsSigned = rhs->isSignedIntegerType(); + QualType destType; + if (lhsSigned == rhsSigned) { + // Same signedness; use the higher-ranked type + destType = compare >= 0 ? lhs : rhs; + } else if (compare != (lhsSigned ? 1 : -1)) { + // The unsigned type has greater than or equal rank to the + // signed type, so use the unsigned type + destType = lhsSigned ? rhs : lhs; + } else if (Context.getIntWidth(lhs) != Context.getIntWidth(rhs)) { + // The two types are different widths; if we are here, that + // means the signed type is larger than the unsigned type, so + // use the signed type. + destType = lhsSigned ? lhs : rhs; + } else { + // The signed type is higher-ranked than the unsigned type, + // but isn't actually any bigger (like unsigned int and long + // on most 32-bit systems). Use the unsigned type corresponding + // to the signed type. + destType = Context.getCorrespondingUnsignedType(lhsSigned ? lhs : rhs); + } + return destType; +} + +//===----------------------------------------------------------------------===// +// Semantic Analysis for various Expression Types +//===----------------------------------------------------------------------===// + + +/// ActOnStringLiteral - The specified tokens were lexed as pasted string +/// fragments (e.g. "foo" "bar" L"baz"). The result string has to handle string +/// concatenation ([C99 5.1.1.2, translation phase #6]), so it may come from +/// multiple tokens. However, the common case is that StringToks points to one +/// string. +/// +Action::OwningExprResult +Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) { + assert(NumStringToks && "Must have at least one string!"); + + StringLiteralParser Literal(StringToks, NumStringToks, PP); + if (Literal.hadError) + return ExprError(); + + llvm::SmallVector<SourceLocation, 4> StringTokLocs; + for (unsigned i = 0; i != NumStringToks; ++i) + StringTokLocs.push_back(StringToks[i].getLocation()); + + QualType StrTy = Context.CharTy; + if (Literal.AnyWide) StrTy = Context.getWCharType(); + if (Literal.Pascal) StrTy = Context.UnsignedCharTy; + + // A C++ string literal has a const-qualified element type (C++ 2.13.4p1). + if (getLangOptions().CPlusPlus) + StrTy.addConst(); + + // Get an array type for the string, according to C99 6.4.5. This includes + // the nul terminator character as well as the string length for pascal + // strings. + StrTy = Context.getConstantArrayType(StrTy, + llvm::APInt(32, Literal.GetNumStringChars()+1), + ArrayType::Normal, 0); + + // Pass &StringTokLocs[0], StringTokLocs.size() to factory! + return Owned(StringLiteral::Create(Context, Literal.GetString(), + Literal.GetStringLength(), + Literal.AnyWide, StrTy, + &StringTokLocs[0], + StringTokLocs.size())); +} + +/// ShouldSnapshotBlockValueReference - Return true if a reference inside of +/// CurBlock to VD should cause it to be snapshotted (as we do for auto +/// 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 +/// up-to-date. +/// +static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock, + ValueDecl *VD) { + // If the value is defined inside the block, we couldn't snapshot it even if + // we wanted to. + if (CurBlock->TheDecl == VD->getDeclContext()) + return false; + + // If this is an enum constant or function, it is constant, don't snapshot. + if (isa<EnumConstantDecl>(VD) || isa<FunctionDecl>(VD)) + return false; + + // If this is a reference to an extern, static, or global variable, no need to + // snapshot it. + // FIXME: What about 'const' variables in C++? + if (const VarDecl *Var = dyn_cast<VarDecl>(VD)) + if (!Var->hasLocalStorage()) + return false; + + // Blocks that have these can't be constant. + CurBlock->hasBlockDeclRefExprs = true; + + // If we have nested blocks, the decl may be declared in an outer block (in + // 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) { + // 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()) + break; + + // Otherwise, the DeclRef from the inner block causes the outer one to need + // a snapshot as well. + NextBlock->hasBlockDeclRefExprs = true; + } + + return true; +} + + + +/// ActOnIdentifierExpr - The parser read an identifier in expression context, +/// validate it per-C99 6.5.1. HasTrailingLParen indicates whether this +/// identifier is used in a function call context. +/// SS is only used for a C++ qualified-id (foo::bar) to indicate the +/// class or namespace that the identifier must be a member of. +Sema::OwningExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc, + IdentifierInfo &II, + bool HasTrailingLParen, + const CXXScopeSpec *SS, + bool isAddressOfOperand) { + return ActOnDeclarationNameExpr(S, Loc, &II, HasTrailingLParen, SS, + isAddressOfOperand); +} + +/// BuildDeclRefExpr - Build either a DeclRefExpr or a +/// QualifiedDeclRefExpr based on whether or not SS is a +/// nested-name-specifier. +DeclRefExpr * +Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc, + bool TypeDependent, bool ValueDependent, + const CXXScopeSpec *SS) { + if (SS && !SS->isEmpty()) { + return new (Context) QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent, + ValueDependent, SS->getRange(), + static_cast<NestedNameSpecifier *>(SS->getScopeRep())); + } else + return new (Context) DeclRefExpr(D, Ty, Loc, TypeDependent, ValueDependent); +} + +/// getObjectForAnonymousRecordDecl - Retrieve the (unnamed) field or +/// variable corresponding to the anonymous union or struct whose type +/// is Record. +static Decl *getObjectForAnonymousRecordDecl(ASTContext &Context, + RecordDecl *Record) { + assert(Record->isAnonymousStructOrUnion() && + "Record must be an anonymous struct or union!"); + + // FIXME: Once Decls are directly linked together, this will be an O(1) + // operation rather than a slow walk through DeclContext's vector (which + // itself will be eliminated). DeclGroups might make this even better. + DeclContext *Ctx = Record->getDeclContext(); + for (DeclContext::decl_iterator D = Ctx->decls_begin(Context), + DEnd = Ctx->decls_end(Context); + D != DEnd; ++D) { + if (*D == Record) { + // The object for the anonymous struct/union directly + // follows its type in the list of declarations. + ++D; + assert(D != DEnd && "Missing object for anonymous record"); + assert(!cast<NamedDecl>(*D)->getDeclName() && "Decl should be unnamed"); + return *D; + } + } + + assert(false && "Missing object for anonymous record"); + return 0; +} + +/// \brief Given a field that represents a member of an anonymous +/// struct/union, build the path from that field's context to the +/// actual member. +/// +/// Construct the sequence of field member references we'll have to +/// perform to get to the field in the anonymous union/struct. The +/// list of members is built from the field outward, so traverse it +/// backwards to go from an object in the current context to the field +/// we found. +/// +/// \returns The variable from which the field access should begin, +/// for an anonymous struct/union that is not a member of another +/// class. Otherwise, returns NULL. +VarDecl *Sema::BuildAnonymousStructUnionMemberPath(FieldDecl *Field, + llvm::SmallVectorImpl<FieldDecl *> &Path) { + assert(Field->getDeclContext()->isRecord() && + cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion() + && "Field must be stored inside an anonymous struct or union"); + + Path.push_back(Field); + VarDecl *BaseObject = 0; + DeclContext *Ctx = Field->getDeclContext(); + do { + RecordDecl *Record = cast<RecordDecl>(Ctx); + Decl *AnonObject = getObjectForAnonymousRecordDecl(Context, Record); + if (FieldDecl *AnonField = dyn_cast<FieldDecl>(AnonObject)) + Path.push_back(AnonField); + else { + BaseObject = cast<VarDecl>(AnonObject); + break; + } + Ctx = Ctx->getParent(); + } while (Ctx->isRecord() && + cast<RecordDecl>(Ctx)->isAnonymousStructOrUnion()); + + return BaseObject; +} + +Sema::OwningExprResult +Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, + FieldDecl *Field, + Expr *BaseObjectExpr, + SourceLocation OpLoc) { + llvm::SmallVector<FieldDecl *, 4> AnonFields; + VarDecl *BaseObject = BuildAnonymousStructUnionMemberPath(Field, + AnonFields); + + // Build the expression that refers to the base object, from + // which we will build a sequence of member references to each + // of the anonymous union objects and, eventually, the field we + // found via name lookup. + bool BaseObjectIsPointer = false; + unsigned ExtraQuals = 0; + if (BaseObject) { + // BaseObject is an anonymous struct/union variable (and is, + // therefore, not part of another non-anonymous record). + if (BaseObjectExpr) BaseObjectExpr->Destroy(Context); + BaseObjectExpr = new (Context) DeclRefExpr(BaseObject,BaseObject->getType(), + SourceLocation()); + ExtraQuals + = Context.getCanonicalType(BaseObject->getType()).getCVRQualifiers(); + } else if (BaseObjectExpr) { + // The caller provided the base object expression. Determine + // whether its a pointer and whether it adds any qualifiers to the + // anonymous struct/union fields we're looking into. + QualType ObjectType = BaseObjectExpr->getType(); + if (const PointerType *ObjectPtr = ObjectType->getAsPointerType()) { + BaseObjectIsPointer = true; + ObjectType = ObjectPtr->getPointeeType(); + } + ExtraQuals = Context.getCanonicalType(ObjectType).getCVRQualifiers(); + } else { + // We've found a member of an anonymous struct/union that is + // inside a non-anonymous struct/union, so in a well-formed + // program our base object expression is "this". + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) { + if (!MD->isStatic()) { + QualType AnonFieldType + = Context.getTagDeclType( + cast<RecordDecl>(AnonFields.back()->getDeclContext())); + QualType ThisType = Context.getTagDeclType(MD->getParent()); + if ((Context.getCanonicalType(AnonFieldType) + == Context.getCanonicalType(ThisType)) || + IsDerivedFrom(ThisType, AnonFieldType)) { + // Our base object expression is "this". + BaseObjectExpr = new (Context) CXXThisExpr(SourceLocation(), + MD->getThisType(Context)); + BaseObjectIsPointer = true; + } + } else { + return ExprError(Diag(Loc,diag::err_invalid_member_use_in_static_method) + << Field->getDeclName()); + } + ExtraQuals = MD->getTypeQualifiers(); + } + + if (!BaseObjectExpr) + return ExprError(Diag(Loc, diag::err_invalid_non_static_member_use) + << Field->getDeclName()); + } + + // Build the implicit member references to the field of the + // anonymous struct/union. + Expr *Result = BaseObjectExpr; + for (llvm::SmallVector<FieldDecl *, 4>::reverse_iterator + FI = AnonFields.rbegin(), FIEnd = AnonFields.rend(); + FI != FIEnd; ++FI) { + QualType MemberType = (*FI)->getType(); + if (!(*FI)->isMutable()) { + unsigned combinedQualifiers + = MemberType.getCVRQualifiers() | ExtraQuals; + MemberType = MemberType.getQualifiedType(combinedQualifiers); + } + Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, *FI, + OpLoc, MemberType); + BaseObjectIsPointer = false; + ExtraQuals = Context.getCanonicalType(MemberType).getCVRQualifiers(); + } + + return Owned(Result); +} + +/// ActOnDeclarationNameExpr - The parser has read some kind of name +/// (e.g., a C++ id-expression (C++ [expr.prim]p1)). This routine +/// performs lookup on that name and returns an expression that refers +/// to that name. This routine isn't directly called from the parser, +/// because the parser doesn't know about DeclarationName. Rather, +/// this routine is called by ActOnIdentifierExpr, +/// ActOnOperatorFunctionIdExpr, and ActOnConversionFunctionExpr, +/// which form the DeclarationName from the corresponding syntactic +/// forms. +/// +/// HasTrailingLParen indicates whether this identifier is used in a +/// function call context. LookupCtx is only used for a C++ +/// qualified-id (foo::bar) to indicate the class or namespace that +/// the identifier must be a member of. +/// +/// isAddressOfOperand means that this expression is the direct operand +/// of an address-of operator. This matters because this is the only +/// situation where a qualified name referencing a non-static member may +/// appear outside a member function of this class. +Sema::OwningExprResult +Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, + DeclarationName Name, bool HasTrailingLParen, + const CXXScopeSpec *SS, + bool isAddressOfOperand) { + // Could be enum-constant, value decl, instance variable, etc. + if (SS && SS->isInvalid()) + return ExprError(); + + // C++ [temp.dep.expr]p3: + // An id-expression is type-dependent if it contains: + // -- a nested-name-specifier that contains a class-name that + // names a dependent type. + // FIXME: Member of the current instantiation. + if (SS && isDependentScopeSpecifier(*SS)) { + return Owned(new (Context) UnresolvedDeclRefExpr(Name, Context.DependentTy, + Loc, SS->getRange(), + static_cast<NestedNameSpecifier *>(SS->getScopeRep()))); + } + + LookupResult Lookup = LookupParsedName(S, SS, Name, LookupOrdinaryName, + false, true, Loc); + + if (Lookup.isAmbiguous()) { + DiagnoseAmbiguousLookup(Lookup, Name, Loc, + SS && SS->isSet() ? SS->getRange() + : SourceRange()); + return ExprError(); + } + + NamedDecl *D = Lookup.getAsDecl(); + + // If this reference is in an Objective-C method, then ivar lookup happens as + // well. + IdentifierInfo *II = Name.getAsIdentifierInfo(); + if (II && getCurMethodDecl()) { + // There are two cases to handle here. 1) scoped lookup could have failed, + // in which case we should look for an ivar. 2) scoped lookup could have + // found a decl, but that decl is outside the current instance method (i.e. + // a global variable). In these two cases, we do a lookup for an ivar with + // this name, if the lookup sucedes, we replace it our current decl. + if (D == 0 || D->isDefinedOutsideFunctionOrMethod()) { + ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface(); + ObjCInterfaceDecl *ClassDeclared; + if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(Context, II, + ClassDeclared)) { + // Check if referencing a field with __attribute__((deprecated)). + if (DiagnoseUseOfDecl(IV, Loc)) + return ExprError(); + + // If we're referencing an invalid decl, just return this as a silent + // error node. The error diagnostic was already emitted on the decl. + if (IV->isInvalidDecl()) + return ExprError(); + + bool IsClsMethod = getCurMethodDecl()->isClassMethod(); + // If a class method attemps to use a free standing ivar, this is + // an error. + if (IsClsMethod && D && !D->isDefinedOutsideFunctionOrMethod()) + return ExprError(Diag(Loc, diag::error_ivar_use_in_class_method) + << IV->getDeclName()); + // If a class method uses a global variable, even if an ivar with + // same name exists, use the global. + if (!IsClsMethod) { + if (IV->getAccessControl() == ObjCIvarDecl::Private && + ClassDeclared != IFace) + Diag(Loc, diag::error_private_ivar_access) << IV->getDeclName(); + // FIXME: This should use a new expr for a direct reference, don't + // turn this into Self->ivar, just return a BareIVarExpr or something. + IdentifierInfo &II = Context.Idents.get("self"); + OwningExprResult SelfExpr = ActOnIdentifierExpr(S, Loc, II, false); + return Owned(new (Context) + ObjCIvarRefExpr(IV, IV->getType(), Loc, + SelfExpr.takeAs<Expr>(), true, true)); + } + } + } + else if (getCurMethodDecl()->isInstanceMethod()) { + // We should warn if a local variable hides an ivar. + ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface(); + ObjCInterfaceDecl *ClassDeclared; + if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(Context, II, + ClassDeclared)) { + if (IV->getAccessControl() != ObjCIvarDecl::Private || + IFace == ClassDeclared) + Diag(Loc, diag::warn_ivar_use_hidden) << IV->getDeclName(); + } + } + // Needed to implement property "super.method" notation. + if (D == 0 && II->isStr("super")) { + QualType T; + + if (getCurMethodDecl()->isInstanceMethod()) + T = Context.getPointerType(Context.getObjCInterfaceType( + getCurMethodDecl()->getClassInterface())); + else + T = Context.getObjCClassType(); + return Owned(new (Context) ObjCSuperExpr(Loc, T)); + } + } + + // Determine whether this name might be a candidate for + // argument-dependent lookup. + bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) && + HasTrailingLParen; + + if (ADL && D == 0) { + // We've seen something of the form + // + // identifier( + // + // and we did not find any entity by the name + // "identifier". However, this identifier is still subject to + // argument-dependent lookup, so keep track of the name. + return Owned(new (Context) UnresolvedFunctionNameExpr(Name, + Context.OverloadTy, + Loc)); + } + + if (D == 0) { + // Otherwise, this could be an implicitly declared function reference (legal + // in C90, extension in C99). + if (HasTrailingLParen && II && + !getLangOptions().CPlusPlus) // Not in C++. + D = ImplicitlyDefineFunction(Loc, *II, S); + else { + // If this name wasn't predeclared and if this is not a function call, + // diagnose the problem. + if (SS && !SS->isEmpty()) + return ExprError(Diag(Loc, diag::err_typecheck_no_member) + << Name << SS->getRange()); + else if (Name.getNameKind() == DeclarationName::CXXOperatorName || + Name.getNameKind() == DeclarationName::CXXConversionFunctionName) + return ExprError(Diag(Loc, diag::err_undeclared_use) + << Name.getAsString()); + else + return ExprError(Diag(Loc, diag::err_undeclared_var_use) << Name); + } + } + + // If this is an expression of the form &Class::member, don't build an + // implicit member ref, because we want a pointer to the member in general, + // not any specific instance's member. + if (isAddressOfOperand && SS && !SS->isEmpty() && !HasTrailingLParen) { + DeclContext *DC = computeDeclContext(*SS); + if (D && isa<CXXRecordDecl>(DC)) { + QualType DType; + if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { + DType = FD->getType().getNonReferenceType(); + } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { + DType = Method->getType(); + } else if (isa<OverloadedFunctionDecl>(D)) { + DType = Context.OverloadTy; + } + // Could be an inner type. That's diagnosed below, so ignore it here. + if (!DType.isNull()) { + // The pointer is type- and value-dependent if it points into something + // dependent. + bool Dependent = DC->isDependentContext(); + return Owned(BuildDeclRefExpr(D, DType, Loc, Dependent, Dependent, SS)); + } + } + } + + // We may have found a field within an anonymous union or struct + // (C++ [class.union]). + if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) + if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion()) + return BuildAnonymousStructUnionMemberReference(Loc, FD); + + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) { + if (!MD->isStatic()) { + // C++ [class.mfct.nonstatic]p2: + // [...] if name lookup (3.4.1) resolves the name in the + // id-expression to a nonstatic nontype member of class X or of + // a base class of X, the id-expression is transformed into a + // class member access expression (5.2.5) using (*this) (9.3.2) + // as the postfix-expression to the left of the '.' operator. + DeclContext *Ctx = 0; + QualType MemberType; + if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { + Ctx = FD->getDeclContext(); + MemberType = FD->getType(); + + if (const ReferenceType *RefType = MemberType->getAsReferenceType()) + MemberType = RefType->getPointeeType(); + else if (!FD->isMutable()) { + unsigned combinedQualifiers + = MemberType.getCVRQualifiers() | MD->getTypeQualifiers(); + MemberType = MemberType.getQualifiedType(combinedQualifiers); + } + } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { + if (!Method->isStatic()) { + Ctx = Method->getParent(); + MemberType = Method->getType(); + } + } else if (OverloadedFunctionDecl *Ovl + = dyn_cast<OverloadedFunctionDecl>(D)) { + for (OverloadedFunctionDecl::function_iterator + Func = Ovl->function_begin(), + FuncEnd = Ovl->function_end(); + Func != FuncEnd; ++Func) { + if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(*Func)) + if (!DMethod->isStatic()) { + Ctx = Ovl->getDeclContext(); + MemberType = Context.OverloadTy; + break; + } + } + } + + if (Ctx && Ctx->isRecord()) { + QualType CtxType = Context.getTagDeclType(cast<CXXRecordDecl>(Ctx)); + QualType ThisType = Context.getTagDeclType(MD->getParent()); + if ((Context.getCanonicalType(CtxType) + == Context.getCanonicalType(ThisType)) || + IsDerivedFrom(ThisType, CtxType)) { + // Build the implicit member access expression. + Expr *This = new (Context) CXXThisExpr(SourceLocation(), + MD->getThisType(Context)); + return Owned(new (Context) MemberExpr(This, true, D, + Loc, MemberType)); + } + } + } + } + + if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) { + if (MD->isStatic()) + // "invalid use of member 'x' in static member function" + return ExprError(Diag(Loc,diag::err_invalid_member_use_in_static_method) + << FD->getDeclName()); + } + + // Any other ways we could have found the field in a well-formed + // program would have been turned into implicit member expressions + // above. + return ExprError(Diag(Loc, diag::err_invalid_non_static_member_use) + << FD->getDeclName()); + } + + if (isa<TypedefDecl>(D)) + return ExprError(Diag(Loc, diag::err_unexpected_typedef) << Name); + if (isa<ObjCInterfaceDecl>(D)) + return ExprError(Diag(Loc, diag::err_unexpected_interface) << Name); + if (isa<NamespaceDecl>(D)) + return ExprError(Diag(Loc, diag::err_unexpected_namespace) << Name); + + // Make the DeclRefExpr or BlockDeclRefExpr for the decl. + if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D)) + return Owned(BuildDeclRefExpr(Ovl, Context.OverloadTy, Loc, + false, false, SS)); + else if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) + return Owned(BuildDeclRefExpr(Template, Context.OverloadTy, Loc, + false, false, SS)); + ValueDecl *VD = cast<ValueDecl>(D); + + // Check whether this declaration can be used. Note that we suppress + // this check when we're going to perform argument-dependent lookup + // on this function name, because this might not be the function + // that overload resolution actually selects. + if (!(ADL && isa<FunctionDecl>(VD)) && DiagnoseUseOfDecl(VD, Loc)) + return ExprError(); + + if (VarDecl *Var = dyn_cast<VarDecl>(VD)) { + // Warn about constructs like: + // if (void *X = foo()) { ... } else { X }. + // In the else block, the pointer is always false. + + // FIXME: In a template instantiation, we don't have scope + // information to check this property. + if (Var->isDeclaredInCondition() && Var->getType()->isScalarType()) { + Scope *CheckS = S; + while (CheckS) { + if (CheckS->isWithinElse() && + CheckS->getControlParent()->isDeclScope(DeclPtrTy::make(Var))) { + if (Var->getType()->isBooleanType()) + ExprError(Diag(Loc, diag::warn_value_always_false) + << Var->getDeclName()); + else + ExprError(Diag(Loc, diag::warn_value_always_zero) + << Var->getDeclName()); + break; + } + + // Move up one more control parent to check again. + CheckS = CheckS->getControlParent(); + if (CheckS) + CheckS = CheckS->getParent(); + } + } + } else if (FunctionDecl *Func = dyn_cast<FunctionDecl>(VD)) { + if (!getLangOptions().CPlusPlus && !Func->hasPrototype()) { + // C99 DR 316 says that, if a function type comes from a + // function definition (without a prototype), that type is only + // used for checking compatibility. Therefore, when referencing + // the function, we pretend that we don't have the full function + // type. + QualType T = Func->getType(); + QualType NoProtoType = T; + if (const FunctionProtoType *Proto = T->getAsFunctionProtoType()) + NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType()); + return Owned(BuildDeclRefExpr(VD, NoProtoType, Loc, false, false, SS)); + } + } + + // Only create DeclRefExpr's for valid Decl's. + if (VD->isInvalidDecl()) + return ExprError(); + + // If the identifier reference is inside a block, and it refers to a value + // that is outside the block, create a BlockDeclRefExpr instead of a + // DeclRefExpr. This ensures the value is treated as a copy-in snapshot when + // the block is formed. + // + // We do not do this for things like enum constants, global variables, etc, + // as they do not get snapshotted. + // + if (CurBlock && ShouldSnapshotBlockValueReference(CurBlock, VD)) { + QualType ExprTy = VD->getType().getNonReferenceType(); + // The BlocksAttr indicates the variable is bound by-reference. + if (VD->getAttr<BlocksAttr>()) + return Owned(new (Context) BlockDeclRefExpr(VD, ExprTy, Loc, true)); + + // Variable will be bound by-copy, make it const within the closure. + ExprTy.addConst(); + return Owned(new (Context) BlockDeclRefExpr(VD, ExprTy, Loc, false)); + } + // If this reference is not in a block or if the referenced variable is + // within the block, create a normal DeclRefExpr. + + bool TypeDependent = false; + bool ValueDependent = false; + if (getLangOptions().CPlusPlus) { + // C++ [temp.dep.expr]p3: + // An id-expression is type-dependent if it contains: + // - an identifier that was declared with a dependent type, + if (VD->getType()->isDependentType()) + TypeDependent = true; + // - FIXME: a template-id that is dependent, + // - a conversion-function-id that specifies a dependent type, + else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName && + Name.getCXXNameType()->isDependentType()) + TypeDependent = true; + // - a nested-name-specifier that contains a class-name that + // names a dependent type. + else if (SS && !SS->isEmpty()) { + for (DeclContext *DC = computeDeclContext(*SS); + DC; DC = DC->getParent()) { + // FIXME: could stop early at namespace scope. + if (DC->isRecord()) { + CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); + if (Context.getTypeDeclType(Record)->isDependentType()) { + TypeDependent = true; + break; + } + } + } + } + + // C++ [temp.dep.constexpr]p2: + // + // An identifier is value-dependent if it is: + // - a name declared with a dependent type, + if (TypeDependent) + ValueDependent = true; + // - the name of a non-type template parameter, + else if (isa<NonTypeTemplateParmDecl>(VD)) + ValueDependent = true; + // - a constant with integral or enumeration type and is + // initialized with an expression that is value-dependent + // (FIXME!). + } + + return Owned(BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), Loc, + TypeDependent, ValueDependent, SS)); +} + +Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, + tok::TokenKind Kind) { + PredefinedExpr::IdentType IT; + + switch (Kind) { + default: assert(0 && "Unknown simple primary expr!"); + case tok::kw___func__: IT = PredefinedExpr::Func; break; // [C99 6.4.2.2] + case tok::kw___FUNCTION__: IT = PredefinedExpr::Function; break; + case tok::kw___PRETTY_FUNCTION__: IT = PredefinedExpr::PrettyFunction; break; + } + + // Pre-defined identifiers are of type char[x], where x is the length of the + // string. + unsigned Length; + if (FunctionDecl *FD = getCurFunctionDecl()) + Length = FD->getIdentifier()->getLength(); + else if (ObjCMethodDecl *MD = getCurMethodDecl()) + Length = MD->getSynthesizedMethodSize(); + else { + Diag(Loc, diag::ext_predef_outside_function); + // __PRETTY_FUNCTION__ -> "top level", the others produce an empty string. + Length = IT == PredefinedExpr::PrettyFunction ? strlen("top level") : 0; + } + + + llvm::APInt LengthI(32, Length + 1); + QualType ResTy = Context.CharTy.getQualifiedType(QualType::Const); + ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0); + return Owned(new (Context) PredefinedExpr(Loc, ResTy, IT)); +} + +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); + + CharLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength, + Tok.getLocation(), PP); + if (Literal.hadError()) + return ExprError(); + + QualType type = getLangOptions().CPlusPlus ? Context.CharTy : Context.IntTy; + + return Owned(new (Context) CharacterLiteral(Literal.getValue(), + Literal.isWide(), + type, Tok.getLocation())); +} + +Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) { + // Fast path for a single digit (which is quite common). A single digit + // cannot have a trigraph, escaped newline, radix prefix, or type suffix. + if (Tok.getLength() == 1) { + const char Val = PP.getSpellingOfSingleCharacterNumericConstant(Tok); + unsigned IntSize = Context.Target.getIntWidth(); + return Owned(new (Context) IntegerLiteral(llvm::APInt(IntSize, Val-'0'), + Context.IntTy, Tok.getLocation())); + } + + llvm::SmallString<512> IntegerBuffer; + // Add padding so that NumericLiteralParser can overread by one character. + IntegerBuffer.resize(Tok.getLength()+1); + const char *ThisTokBegin = &IntegerBuffer[0]; + + // Get the spelling of the token, which eliminates trigraphs, etc. + unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin); + + NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength, + Tok.getLocation(), PP); + if (Literal.hadError) + return ExprError(); + + Expr *Res; + + if (Literal.isFloatingLiteral()) { + QualType Ty; + if (Literal.isFloat) + Ty = Context.FloatTy; + else if (!Literal.isLong) + Ty = Context.DoubleTy; + else + Ty = Context.LongDoubleTy; + + const llvm::fltSemantics &Format = Context.getFloatTypeSemantics(Ty); + + // isExact will be set by GetFloatValue(). + bool isExact = false; + Res = new (Context) FloatingLiteral(Literal.GetFloatValue(Format, &isExact), + &isExact, Ty, Tok.getLocation()); + + } else if (!Literal.isIntegerLiteral()) { + return ExprError(); + } else { + QualType Ty; + + // long long is a C99 feature. + if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x && + Literal.isLongLong) + Diag(Tok.getLocation(), diag::ext_longlong); + + // Get the value in the widest-possible width. + llvm::APInt ResultVal(Context.Target.getIntMaxTWidth(), 0); + + if (Literal.GetIntegerValue(ResultVal)) { + // If this value didn't fit into uintmax_t, warn and force to ull. + Diag(Tok.getLocation(), diag::warn_integer_too_large); + Ty = Context.UnsignedLongLongTy; + assert(Context.getTypeSize(Ty) == ResultVal.getBitWidth() && + "long long is not intmax_t?"); + } else { + // If this value fits into a ULL, try to figure out what else it fits into + // according to the rules of C99 6.4.4.1p5. + + // Octal, Hexadecimal, and integers with a U suffix are allowed to + // be an unsigned int. + bool AllowUnsigned = Literal.isUnsigned || Literal.getRadix() != 10; + + // Check from smallest to largest, picking the smallest type we can. + unsigned Width = 0; + if (!Literal.isLong && !Literal.isLongLong) { + // Are int/unsigned possibilities? + unsigned IntSize = Context.Target.getIntWidth(); + + // Does it fit in a unsigned int? + if (ResultVal.isIntN(IntSize)) { + // Does it fit in a signed int? + if (!Literal.isUnsigned && ResultVal[IntSize-1] == 0) + Ty = Context.IntTy; + else if (AllowUnsigned) + Ty = Context.UnsignedIntTy; + Width = IntSize; + } + } + + // Are long/unsigned long possibilities? + if (Ty.isNull() && !Literal.isLongLong) { + unsigned LongSize = Context.Target.getLongWidth(); + + // Does it fit in a unsigned long? + if (ResultVal.isIntN(LongSize)) { + // Does it fit in a signed long? + if (!Literal.isUnsigned && ResultVal[LongSize-1] == 0) + Ty = Context.LongTy; + else if (AllowUnsigned) + Ty = Context.UnsignedLongTy; + Width = LongSize; + } + } + + // Finally, check long long if needed. + if (Ty.isNull()) { + unsigned LongLongSize = Context.Target.getLongLongWidth(); + + // Does it fit in a unsigned long long? + if (ResultVal.isIntN(LongLongSize)) { + // Does it fit in a signed long long? + if (!Literal.isUnsigned && ResultVal[LongLongSize-1] == 0) + Ty = Context.LongLongTy; + else if (AllowUnsigned) + Ty = Context.UnsignedLongLongTy; + Width = LongLongSize; + } + } + + // If we still couldn't decide a type, we probably have something that + // does not fit in a signed long long, but has no U suffix. + if (Ty.isNull()) { + Diag(Tok.getLocation(), diag::warn_integer_too_large_for_signed); + Ty = Context.UnsignedLongLongTy; + Width = Context.Target.getLongLongWidth(); + } + + if (ResultVal.getBitWidth() != Width) + ResultVal.trunc(Width); + } + Res = new (Context) IntegerLiteral(ResultVal, Ty, Tok.getLocation()); + } + + // If this is an imaginary literal, create the ImaginaryLiteral wrapper. + if (Literal.isImaginary) + Res = new (Context) ImaginaryLiteral(Res, + Context.getComplexType(Res->getType())); + + return Owned(Res); +} + +Action::OwningExprResult Sema::ActOnParenExpr(SourceLocation L, + SourceLocation R, ExprArg Val) { + Expr *E = Val.takeAs<Expr>(); + assert((E != 0) && "ActOnParenExpr() missing expr"); + return Owned(new (Context) ParenExpr(L, R, E)); +} + +/// The UsualUnaryConversions() function is *not* called by this routine. +/// See C99 6.3.2.1p[2-4] for more details. +bool Sema::CheckSizeOfAlignOfOperand(QualType exprType, + SourceLocation OpLoc, + const SourceRange &ExprRange, + bool isSizeof) { + if (exprType->isDependentType()) + return false; + + // C99 6.5.3.4p1: + if (isa<FunctionType>(exprType)) { + // alignof(function) is allowed as an extension. + if (isSizeof) + Diag(OpLoc, diag::ext_sizeof_function_type) << ExprRange; + return false; + } + + // Allow sizeof(void)/alignof(void) as an extension. + if (exprType->isVoidType()) { + Diag(OpLoc, diag::ext_sizeof_void_type) + << (isSizeof ? "sizeof" : "__alignof") << ExprRange; + return false; + } + + if (RequireCompleteType(OpLoc, exprType, + isSizeof ? diag::err_sizeof_incomplete_type : + diag::err_alignof_incomplete_type, + ExprRange)) + return true; + + // Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode. + if (LangOpts.ObjCNonFragileABI && exprType->isObjCInterfaceType()) { + Diag(OpLoc, diag::err_sizeof_nonfragile_interface) + << exprType << isSizeof << ExprRange; + return true; + } + + return false; +} + +bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, + const SourceRange &ExprRange) { + E = E->IgnoreParens(); + + // alignof decl is always ok. + if (isa<DeclRefExpr>(E)) + return false; + + // Cannot know anything else if the expression is dependent. + if (E->isTypeDependent()) + return false; + + if (E->getBitField()) { + Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 1 << ExprRange; + return true; + } + + // Alignment of a field access is always okay, so long as it isn't a + // bit-field. + if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) + if (dyn_cast<FieldDecl>(ME->getMemberDecl())) + return false; + + return CheckSizeOfAlignOfOperand(E->getType(), OpLoc, ExprRange, false); +} + +/// \brief Build a sizeof or alignof expression given a type operand. +Action::OwningExprResult +Sema::CreateSizeOfAlignOfExpr(QualType T, SourceLocation OpLoc, + bool isSizeOf, SourceRange R) { + if (T.isNull()) + return ExprError(); + + if (!T->isDependentType() && + CheckSizeOfAlignOfOperand(T, OpLoc, R, isSizeOf)) + return ExprError(); + + // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t. + return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, T, + Context.getSizeType(), OpLoc, + R.getEnd())); +} + +/// \brief Build a sizeof or alignof expression given an expression +/// operand. +Action::OwningExprResult +Sema::CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc, + bool isSizeOf, SourceRange R) { + // Verify that the operand is valid. + bool isInvalid = false; + if (E->isTypeDependent()) { + // Delay type-checking for type-dependent expressions. + } else if (!isSizeOf) { + isInvalid = CheckAlignOfExpr(E, OpLoc, R); + } else if (E->getBitField()) { // C99 6.5.3.4p1. + Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 0; + isInvalid = true; + } else { + isInvalid = CheckSizeOfAlignOfOperand(E->getType(), OpLoc, R, true); + } + + if (isInvalid) + return ExprError(); + + // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t. + return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, E, + Context.getSizeType(), OpLoc, + R.getEnd())); +} + +/// ActOnSizeOfAlignOfExpr - Handle @c sizeof(type) and @c sizeof @c expr and +/// the same for @c alignof and @c __alignof +/// Note that the ArgRange is invalid if isType is false. +Action::OwningExprResult +Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, + void *TyOrEx, const SourceRange &ArgRange) { + // If error parsing type, ignore. + if (TyOrEx == 0) return ExprError(); + + if (isType) { + QualType ArgTy = QualType::getFromOpaquePtr(TyOrEx); + return CreateSizeOfAlignOfExpr(ArgTy, OpLoc, isSizeof, ArgRange); + } + + // Get the end location. + Expr *ArgEx = (Expr *)TyOrEx; + Action::OwningExprResult Result + = CreateSizeOfAlignOfExpr(ArgEx, OpLoc, isSizeof, ArgEx->getSourceRange()); + + if (Result.isInvalid()) + DeleteExpr(ArgEx); + + return move(Result); +} + +QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc, bool isReal) { + if (V->isTypeDependent()) + return Context.DependentTy; + + // These operators return the element type of a complex type. + if (const ComplexType *CT = V->getType()->getAsComplexType()) + return CT->getElementType(); + + // Otherwise they pass through real integer and floating point types here. + if (V->getType()->isArithmeticType()) + return V->getType(); + + // Reject anything else. + Diag(Loc, diag::err_realimag_invalid_type) << V->getType() + << (isReal ? "__real" : "__imag"); + return QualType(); +} + + + +Action::OwningExprResult +Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, + tok::TokenKind Kind, ExprArg Input) { + Expr *Arg = (Expr *)Input.get(); + + UnaryOperator::Opcode Opc; + switch (Kind) { + default: assert(0 && "Unknown unary op!"); + case tok::plusplus: Opc = UnaryOperator::PostInc; break; + case tok::minusminus: Opc = UnaryOperator::PostDec; break; + } + + if (getLangOptions().CPlusPlus && + (Arg->getType()->isRecordType() || Arg->getType()->isEnumeralType())) { + // Which overloaded operator? + OverloadedOperatorKind OverOp = + (Opc == UnaryOperator::PostInc)? OO_PlusPlus : OO_MinusMinus; + + // C++ [over.inc]p1: + // + // [...] If the function is a member function with one + // parameter (which shall be of type int) or a non-member + // function with two parameters (the second of which shall be + // of type int), it defines the postfix increment operator ++ + // for objects of that type. When the postfix increment is + // called as a result of using the ++ operator, the int + // argument will have value zero. + Expr *Args[2] = { + Arg, + new (Context) IntegerLiteral(llvm::APInt(Context.Target.getIntWidth(), 0, + /*isSigned=*/true), Context.IntTy, SourceLocation()) + }; + + // Build the candidate set for overloading + OverloadCandidateSet CandidateSet; + AddOperatorCandidates(OverOp, S, OpLoc, Args, 2, CandidateSet); + + // Perform overload resolution. + OverloadCandidateSet::iterator Best; + switch (BestViableFunction(CandidateSet, Best)) { + case OR_Success: { + // We found a built-in operator or an overloaded operator. + FunctionDecl *FnDecl = Best->Function; + + if (FnDecl) { + // We matched an overloaded operator. Build a call to that + // operator. + + // Convert the arguments. + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { + if (PerformObjectArgumentInitialization(Arg, Method)) + return ExprError(); + } else { + // Convert the arguments. + if (PerformCopyInitialization(Arg, + FnDecl->getParamDecl(0)->getType(), + "passing")) + return ExprError(); + } + + // Determine the result type + QualType ResultTy + = FnDecl->getType()->getAsFunctionType()->getResultType(); + ResultTy = ResultTy.getNonReferenceType(); + + // Build the actual expression node. + Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(), + SourceLocation()); + UsualUnaryConversions(FnExpr); + + Input.release(); + Args[0] = Arg; + return Owned(new (Context) CXXOperatorCallExpr(Context, OverOp, FnExpr, + Args, 2, ResultTy, + OpLoc)); + } else { + // We matched a built-in operator. Convert the arguments, then + // break out so that we will build the appropriate built-in + // operator node. + if (PerformCopyInitialization(Arg, Best->BuiltinTypes.ParamTypes[0], + "passing")) + return ExprError(); + + break; + } + } + + case OR_No_Viable_Function: + // No viable function; fall through to handling this as a + // built-in operator, which will produce an error message for us. + break; + + case OR_Ambiguous: + Diag(OpLoc, diag::err_ovl_ambiguous_oper) + << UnaryOperator::getOpcodeStr(Opc) + << Arg->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + return ExprError(); + + case OR_Deleted: + Diag(OpLoc, diag::err_ovl_deleted_oper) + << Best->Function->isDeleted() + << UnaryOperator::getOpcodeStr(Opc) + << Arg->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + return ExprError(); + } + + // Either we found no viable overloaded operator or we matched a + // built-in operator. In either case, fall through to trying to + // build a built-in operation. + } + + QualType result = CheckIncrementDecrementOperand(Arg, OpLoc, + Opc == UnaryOperator::PostInc); + if (result.isNull()) + return ExprError(); + Input.release(); + return Owned(new (Context) UnaryOperator(Arg, Opc, result, OpLoc)); +} + +Action::OwningExprResult +Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, + ExprArg Idx, SourceLocation RLoc) { + Expr *LHSExp = static_cast<Expr*>(Base.get()), + *RHSExp = static_cast<Expr*>(Idx.get()); + + if (getLangOptions().CPlusPlus && + (LHSExp->isTypeDependent() || RHSExp->isTypeDependent())) { + Base.release(); + Idx.release(); + return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp, + Context.DependentTy, RLoc)); + } + + if (getLangOptions().CPlusPlus && + (LHSExp->getType()->isRecordType() || + LHSExp->getType()->isEnumeralType() || + RHSExp->getType()->isRecordType() || + RHSExp->getType()->isEnumeralType())) { + // Add the appropriate overloaded operators (C++ [over.match.oper]) + // to the candidate set. + OverloadCandidateSet CandidateSet; + Expr *Args[2] = { LHSExp, RHSExp }; + AddOperatorCandidates(OO_Subscript, S, LLoc, Args, 2, CandidateSet, + SourceRange(LLoc, RLoc)); + + // Perform overload resolution. + OverloadCandidateSet::iterator Best; + switch (BestViableFunction(CandidateSet, Best)) { + case OR_Success: { + // We found a built-in operator or an overloaded operator. + FunctionDecl *FnDecl = Best->Function; + + if (FnDecl) { + // We matched an overloaded operator. Build a call to that + // operator. + + // Convert the arguments. + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { + if (PerformObjectArgumentInitialization(LHSExp, Method) || + PerformCopyInitialization(RHSExp, + FnDecl->getParamDecl(0)->getType(), + "passing")) + return ExprError(); + } else { + // Convert the arguments. + if (PerformCopyInitialization(LHSExp, + FnDecl->getParamDecl(0)->getType(), + "passing") || + PerformCopyInitialization(RHSExp, + FnDecl->getParamDecl(1)->getType(), + "passing")) + return ExprError(); + } + + // Determine the result type + QualType ResultTy + = FnDecl->getType()->getAsFunctionType()->getResultType(); + ResultTy = ResultTy.getNonReferenceType(); + + // Build the actual expression node. + Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(), + SourceLocation()); + UsualUnaryConversions(FnExpr); + + Base.release(); + Idx.release(); + Args[0] = LHSExp; + Args[1] = RHSExp; + return Owned(new (Context) CXXOperatorCallExpr(Context, OO_Subscript, + FnExpr, Args, 2, + ResultTy, LLoc)); + } else { + // We matched a built-in operator. Convert the arguments, then + // break out so that we will build the appropriate built-in + // operator node. + if (PerformCopyInitialization(LHSExp, Best->BuiltinTypes.ParamTypes[0], + "passing") || + PerformCopyInitialization(RHSExp, Best->BuiltinTypes.ParamTypes[1], + "passing")) + return ExprError(); + + break; + } + } + + case OR_No_Viable_Function: + // No viable function; fall through to handling this as a + // built-in operator, which will produce an error message for us. + break; + + case OR_Ambiguous: + Diag(LLoc, diag::err_ovl_ambiguous_oper) + << "[]" + << LHSExp->getSourceRange() << RHSExp->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + return ExprError(); + + case OR_Deleted: + Diag(LLoc, diag::err_ovl_deleted_oper) + << Best->Function->isDeleted() + << "[]" + << LHSExp->getSourceRange() << RHSExp->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + return ExprError(); + } + + // Either we found no viable overloaded operator or we matched a + // built-in operator. In either case, fall through to trying to + // build a built-in operation. + } + + // Perform default conversions. + DefaultFunctionArrayConversion(LHSExp); + DefaultFunctionArrayConversion(RHSExp); + + QualType LHSTy = LHSExp->getType(), RHSTy = RHSExp->getType(); + + // C99 6.5.2.1p2: the expression e1[e2] is by definition precisely equivalent + // to the expression *((e1)+(e2)). This means the array "Base" may actually be + // in the subscript position. As a result, we need to derive the array base + // and index from the expression types. + Expr *BaseExpr, *IndexExpr; + QualType ResultType; + if (LHSTy->isDependentType() || RHSTy->isDependentType()) { + BaseExpr = LHSExp; + IndexExpr = RHSExp; + ResultType = Context.DependentTy; + } else if (const PointerType *PTy = LHSTy->getAsPointerType()) { + BaseExpr = LHSExp; + IndexExpr = RHSExp; + ResultType = PTy->getPointeeType(); + } else if (const PointerType *PTy = RHSTy->getAsPointerType()) { + // Handle the uncommon case of "123[Ptr]". + BaseExpr = RHSExp; + IndexExpr = LHSExp; + ResultType = PTy->getPointeeType(); + } else if (const VectorType *VTy = LHSTy->getAsVectorType()) { + BaseExpr = LHSExp; // vectors: V[123] + IndexExpr = RHSExp; + + // FIXME: need to deal with const... + ResultType = VTy->getElementType(); + } else if (LHSTy->isArrayType()) { + // If we see an array that wasn't promoted by + // DefaultFunctionArrayConversion, it must be an array that + // wasn't promoted because of the C90 rule that doesn't + // allow promoting non-lvalue arrays. Warn, then + // force the promotion here. + Diag(LHSExp->getLocStart(), diag::ext_subscript_non_lvalue) << + LHSExp->getSourceRange(); + ImpCastExprToType(LHSExp, Context.getArrayDecayedType(LHSTy)); + LHSTy = LHSExp->getType(); + + BaseExpr = LHSExp; + IndexExpr = RHSExp; + ResultType = LHSTy->getAsPointerType()->getPointeeType(); + } else if (RHSTy->isArrayType()) { + // Same as previous, except for 123[f().a] case + Diag(RHSExp->getLocStart(), diag::ext_subscript_non_lvalue) << + RHSExp->getSourceRange(); + ImpCastExprToType(RHSExp, Context.getArrayDecayedType(RHSTy)); + RHSTy = RHSExp->getType(); + + BaseExpr = RHSExp; + IndexExpr = LHSExp; + ResultType = RHSTy->getAsPointerType()->getPointeeType(); + } else { + return ExprError(Diag(LLoc, diag::err_typecheck_subscript_value) + << LHSExp->getSourceRange() << RHSExp->getSourceRange()); + } + // C99 6.5.2.1p1 + if (!IndexExpr->getType()->isIntegerType() && !IndexExpr->isTypeDependent()) + return ExprError(Diag(LLoc, diag::err_typecheck_subscript_not_integer) + << IndexExpr->getSourceRange()); + + // C99 6.5.2.1p1: "shall have type "pointer to *object* type". Similarly, + // C++ [expr.sub]p1: The type "T" shall be a completely-defined object + // type. Note that Functions are not objects, and that (in C99 parlance) + // incomplete types are not object types. + if (ResultType->isFunctionType()) { + Diag(BaseExpr->getLocStart(), diag::err_subscript_function_type) + << ResultType << BaseExpr->getSourceRange(); + return ExprError(); + } + + if (!ResultType->isDependentType() && + RequireCompleteType(LLoc, ResultType, diag::err_subscript_incomplete_type, + BaseExpr->getSourceRange())) + return ExprError(); + + // Diagnose bad cases where we step over interface counts. + if (ResultType->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) { + Diag(LLoc, diag::err_subscript_nonfragile_interface) + << ResultType << BaseExpr->getSourceRange(); + return ExprError(); + } + + Base.release(); + Idx.release(); + return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp, + ResultType, RLoc)); +} + +QualType Sema:: +CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, + IdentifierInfo &CompName, SourceLocation CompLoc) { + const ExtVectorType *vecType = baseType->getAsExtVectorType(); + + // The vector accessor can't exceed the number of elements. + const char *compStr = CompName.getName(); + + // This flag determines whether or not the component is one of the four + // special names that indicate a subset of exactly half the elements are + // to be selected. + bool HalvingSwizzle = false; + + // This flag determines whether or not CompName has an 's' char prefix, + // indicating that it is a string of hex values to be used as vector indices. + bool HexSwizzle = *compStr == 's'; + + // Check that we've found one of the special components, or that the component + // names must come from the same set. + if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") || + !strcmp(compStr, "even") || !strcmp(compStr, "odd")) { + HalvingSwizzle = true; + } else if (vecType->getPointAccessorIdx(*compStr) != -1) { + do + compStr++; + while (*compStr && vecType->getPointAccessorIdx(*compStr) != -1); + } else if (HexSwizzle || vecType->getNumericAccessorIdx(*compStr) != -1) { + do + compStr++; + while (*compStr && vecType->getNumericAccessorIdx(*compStr) != -1); + } + + if (!HalvingSwizzle && *compStr) { + // We didn't get to the end of the string. This means the component names + // didn't come from the same set *or* we encountered an illegal name. + Diag(OpLoc, diag::err_ext_vector_component_name_illegal) + << std::string(compStr,compStr+1) << SourceRange(CompLoc); + return QualType(); + } + + // Ensure no component accessor exceeds the width of the vector type it + // operates on. + if (!HalvingSwizzle) { + compStr = CompName.getName(); + + if (HexSwizzle) + compStr++; + + while (*compStr) { + if (!vecType->isAccessorWithinNumElements(*compStr++)) { + Diag(OpLoc, diag::err_ext_vector_component_exceeds_length) + << baseType << SourceRange(CompLoc); + return QualType(); + } + } + } + + // If this is a halving swizzle, verify that the base type has an even + // number of elements. + if (HalvingSwizzle && (vecType->getNumElements() & 1U)) { + Diag(OpLoc, diag::err_ext_vector_component_requires_even) + << baseType << SourceRange(CompLoc); + return QualType(); + } + + // The component accessor looks fine - now we need to compute the actual type. + // The vector type is implied by the component accessor. For example, + // vec4.b is a float, vec4.xy is a vec2, vec4.rgb is a vec3, etc. + // vec4.s0 is a float, vec4.s23 is a vec3, etc. + // vec4.hi, vec4.lo, vec4.e, and vec4.o all return vec2. + unsigned CompSize = HalvingSwizzle ? vecType->getNumElements() / 2 + : CompName.getLength(); + if (HexSwizzle) + CompSize--; + + if (CompSize == 1) + return vecType->getElementType(); + + QualType VT = Context.getExtVectorType(vecType->getElementType(), CompSize); + // Now look up the TypeDefDecl from the vector type. Without this, + // diagostics look bad. We want extended vector types to appear built-in. + for (unsigned i = 0, E = ExtVectorDecls.size(); i != E; ++i) { + if (ExtVectorDecls[i]->getUnderlyingType() == VT) + return Context.getTypedefType(ExtVectorDecls[i]); + } + return VT; // should never get here (a typedef type should always be found). +} + +static Decl *FindGetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDecl, + IdentifierInfo &Member, + const Selector &Sel, + ASTContext &Context) { + + if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Context, &Member)) + return PD; + if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(Context, Sel)) + return OMD; + + for (ObjCProtocolDecl::protocol_iterator I = PDecl->protocol_begin(), + E = PDecl->protocol_end(); I != E; ++I) { + if (Decl *D = FindGetterNameDeclFromProtocolList(*I, Member, Sel, + Context)) + return D; + } + return 0; +} + +static Decl *FindGetterNameDecl(const ObjCQualifiedIdType *QIdTy, + IdentifierInfo &Member, + const Selector &Sel, + ASTContext &Context) { + // Check protocols on qualified interfaces. + Decl *GDecl = 0; + for (ObjCQualifiedIdType::qual_iterator I = QIdTy->qual_begin(), + E = QIdTy->qual_end(); I != E; ++I) { + if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Context, &Member)) { + GDecl = PD; + break; + } + // Also must look for a getter name which uses property syntax. + if (ObjCMethodDecl *OMD = (*I)->getInstanceMethod(Context, Sel)) { + GDecl = OMD; + break; + } + } + if (!GDecl) { + for (ObjCQualifiedIdType::qual_iterator I = QIdTy->qual_begin(), + E = QIdTy->qual_end(); I != E; ++I) { + // Search in the protocol-qualifier list of current protocol. + GDecl = FindGetterNameDeclFromProtocolList(*I, Member, Sel, Context); + if (GDecl) + return GDecl; + } + } + return GDecl; +} + +/// FindMethodInNestedImplementations - Look up a method in current and +/// all base class implementations. +/// +ObjCMethodDecl *Sema::FindMethodInNestedImplementations( + const ObjCInterfaceDecl *IFace, + const Selector &Sel) { + ObjCMethodDecl *Method = 0; + if (ObjCImplementationDecl *ImpDecl + = LookupObjCImplementation(IFace->getIdentifier())) + Method = ImpDecl->getInstanceMethod(Context, Sel); + + if (!Method && IFace->getSuperClass()) + return FindMethodInNestedImplementations(IFace->getSuperClass(), Sel); + return Method; +} + +Action::OwningExprResult +Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, + tok::TokenKind OpKind, SourceLocation MemberLoc, + IdentifierInfo &Member, + DeclPtrTy ObjCImpDecl) { + Expr *BaseExpr = Base.takeAs<Expr>(); + assert(BaseExpr && "no record expression"); + + // Perform default conversions. + DefaultFunctionArrayConversion(BaseExpr); + + QualType BaseType = BaseExpr->getType(); + assert(!BaseType.isNull() && "no type for member expression"); + + // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr + // must have pointer type, and the accessed type is the pointee. + if (OpKind == tok::arrow) { + if (BaseType->isDependentType()) + return Owned(new (Context) CXXUnresolvedMemberExpr(Context, + BaseExpr, true, + OpLoc, + DeclarationName(&Member), + MemberLoc)); + else if (const PointerType *PT = BaseType->getAsPointerType()) + BaseType = PT->getPointeeType(); + else if (getLangOptions().CPlusPlus && BaseType->isRecordType()) + return Owned(BuildOverloadedArrowExpr(S, BaseExpr, OpLoc, + MemberLoc, Member)); + else + return ExprError(Diag(MemberLoc, + diag::err_typecheck_member_reference_arrow) + << BaseType << BaseExpr->getSourceRange()); + } else { + if (BaseType->isDependentType()) { + // Require that the base type isn't a pointer type + // (so we'll report an error for) + // T* t; + // t.f; + // + // In Obj-C++, however, the above expression is valid, since it could be + // accessing the 'f' property if T is an Obj-C interface. The extra check + // allows this, while still reporting an error if T is a struct pointer. + const PointerType *PT = BaseType->getAsPointerType(); + + if (!PT || (getLangOptions().ObjC1 && + !PT->getPointeeType()->isRecordType())) + return Owned(new (Context) CXXUnresolvedMemberExpr(Context, + BaseExpr, false, + OpLoc, + DeclarationName(&Member), + MemberLoc)); + } + } + + // Handle field access to simple records. This also handles access to fields + // of the ObjC 'id' struct. + if (const RecordType *RTy = BaseType->getAsRecordType()) { + RecordDecl *RDecl = RTy->getDecl(); + if (RequireCompleteType(OpLoc, BaseType, + diag::err_typecheck_incomplete_tag, + BaseExpr->getSourceRange())) + return ExprError(); + + // The record definition is complete, now make sure the member is valid. + // FIXME: Qualified name lookup for C++ is a bit more complicated than this. + LookupResult Result + = LookupQualifiedName(RDecl, DeclarationName(&Member), + LookupMemberName, false); + + if (!Result) + return ExprError(Diag(MemberLoc, diag::err_typecheck_no_member) + << &Member << BaseExpr->getSourceRange()); + if (Result.isAmbiguous()) { + DiagnoseAmbiguousLookup(Result, DeclarationName(&Member), + MemberLoc, BaseExpr->getSourceRange()); + return ExprError(); + } + + NamedDecl *MemberDecl = Result; + + // If the decl being referenced had an error, return an error for this + // sub-expr without emitting another error, in order to avoid cascading + // error cases. + if (MemberDecl->isInvalidDecl()) + return ExprError(); + + // Check the use of this field + if (DiagnoseUseOfDecl(MemberDecl, MemberLoc)) + return ExprError(); + + if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) { + // We may have found a field within an anonymous union or struct + // (C++ [class.union]). + if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion()) + return BuildAnonymousStructUnionMemberReference(MemberLoc, FD, + BaseExpr, OpLoc); + + // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref] + // FIXME: Handle address space modifiers + QualType MemberType = FD->getType(); + if (const ReferenceType *Ref = MemberType->getAsReferenceType()) + MemberType = Ref->getPointeeType(); + else { + unsigned combinedQualifiers = + MemberType.getCVRQualifiers() | BaseType.getCVRQualifiers(); + if (FD->isMutable()) + combinedQualifiers &= ~QualType::Const; + MemberType = MemberType.getQualifiedType(combinedQualifiers); + } + + return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, FD, + MemberLoc, MemberType)); + } + + if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) + return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, + Var, MemberLoc, + Var->getType().getNonReferenceType())); + if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl)) + return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, + MemberFn, MemberLoc, + MemberFn->getType())); + if (OverloadedFunctionDecl *Ovl + = dyn_cast<OverloadedFunctionDecl>(MemberDecl)) + return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, Ovl, + MemberLoc, Context.OverloadTy)); + if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) + return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, + Enum, MemberLoc, Enum->getType())); + if (isa<TypeDecl>(MemberDecl)) + return ExprError(Diag(MemberLoc,diag::err_typecheck_member_reference_type) + << DeclarationName(&Member) << int(OpKind == tok::arrow)); + + // We found a declaration kind that we didn't expect. This is a + // generic error message that tells the user that she can't refer + // to this member with '.' or '->'. + return ExprError(Diag(MemberLoc, + diag::err_typecheck_member_reference_unknown) + << DeclarationName(&Member) << int(OpKind == tok::arrow)); + } + + // Handle access to Objective-C instance variables, such as "Obj->ivar" and + // (*Obj).ivar. + if (const ObjCInterfaceType *IFTy = BaseType->getAsObjCInterfaceType()) { + ObjCInterfaceDecl *ClassDeclared; + if (ObjCIvarDecl *IV = IFTy->getDecl()->lookupInstanceVariable(Context, + &Member, + ClassDeclared)) { + // If the decl being referenced had an error, return an error for this + // sub-expr without emitting another error, in order to avoid cascading + // error cases. + if (IV->isInvalidDecl()) + return ExprError(); + + // Check whether we can reference this field. + if (DiagnoseUseOfDecl(IV, MemberLoc)) + return ExprError(); + if (IV->getAccessControl() != ObjCIvarDecl::Public && + IV->getAccessControl() != ObjCIvarDecl::Package) { + ObjCInterfaceDecl *ClassOfMethodDecl = 0; + if (ObjCMethodDecl *MD = getCurMethodDecl()) + ClassOfMethodDecl = MD->getClassInterface(); + else if (ObjCImpDecl && getCurFunctionDecl()) { + // Case of a c-function declared inside an objc implementation. + // FIXME: For a c-style function nested inside an objc implementation + // class, there is no implementation context available, so we pass + // down the context as argument to this routine. Ideally, this context + // need be passed down in the AST node and somehow calculated from the + // AST for a function decl. + Decl *ImplDecl = ObjCImpDecl.getAs<Decl>(); + if (ObjCImplementationDecl *IMPD = + dyn_cast<ObjCImplementationDecl>(ImplDecl)) + ClassOfMethodDecl = IMPD->getClassInterface(); + else if (ObjCCategoryImplDecl* CatImplClass = + dyn_cast<ObjCCategoryImplDecl>(ImplDecl)) + ClassOfMethodDecl = CatImplClass->getClassInterface(); + } + + if (IV->getAccessControl() == ObjCIvarDecl::Private) { + if (ClassDeclared != IFTy->getDecl() || + ClassOfMethodDecl != ClassDeclared) + Diag(MemberLoc, diag::error_private_ivar_access) << IV->getDeclName(); + } + // @protected + else if (!IFTy->getDecl()->isSuperClassOf(ClassOfMethodDecl)) + Diag(MemberLoc, diag::error_protected_ivar_access) << IV->getDeclName(); + } + + return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(), + MemberLoc, BaseExpr, + OpKind == tok::arrow)); + } + return ExprError(Diag(MemberLoc, diag::err_typecheck_member_reference_ivar) + << IFTy->getDecl()->getDeclName() << &Member + << BaseExpr->getSourceRange()); + } + + // Handle Objective-C property access, which is "Obj.property" where Obj is a + // pointer to a (potentially qualified) interface type. + const PointerType *PTy; + const ObjCInterfaceType *IFTy; + if (OpKind == tok::period && (PTy = BaseType->getAsPointerType()) && + (IFTy = PTy->getPointeeType()->getAsObjCInterfaceType())) { + ObjCInterfaceDecl *IFace = IFTy->getDecl(); + + // Search for a declared property first. + if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Context, + &Member)) { + // Check whether we can reference this property. + if (DiagnoseUseOfDecl(PD, MemberLoc)) + return ExprError(); + QualType ResTy = PD->getType(); + Selector Sel = PP.getSelectorTable().getNullarySelector(&Member); + ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Context, Sel); + if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc)) + ResTy = Getter->getResultType(); + return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy, + MemberLoc, BaseExpr)); + } + + // Check protocols on qualified interfaces. + for (ObjCInterfaceType::qual_iterator I = IFTy->qual_begin(), + E = IFTy->qual_end(); I != E; ++I) + if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Context, + &Member)) { + // Check whether we can reference this property. + if (DiagnoseUseOfDecl(PD, MemberLoc)) + return ExprError(); + + return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), + MemberLoc, BaseExpr)); + } + + // If that failed, look for an "implicit" property by seeing if the nullary + // selector is implemented. + + // FIXME: The logic for looking up nullary and unary selectors should be + // shared with the code in ActOnInstanceMessage. + + Selector Sel = PP.getSelectorTable().getNullarySelector(&Member); + ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Context, Sel); + + // If this reference is in an @implementation, check for 'private' methods. + if (!Getter) + Getter = FindMethodInNestedImplementations(IFace, Sel); + + // Look through local category implementations associated with the class. + if (!Getter) { + for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Getter; i++) { + if (ObjCCategoryImpls[i]->getClassInterface() == IFace) + Getter = ObjCCategoryImpls[i]->getInstanceMethod(Context, Sel); + } + } + if (Getter) { + // Check if we can reference this property. + if (DiagnoseUseOfDecl(Getter, MemberLoc)) + return ExprError(); + } + // If we found a getter then this may be a valid dot-reference, we + // will look for the matching setter, in case it is needed. + Selector SetterSel = + SelectorTable::constructSetterName(PP.getIdentifierTable(), + PP.getSelectorTable(), &Member); + ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(Context, SetterSel); + if (!Setter) { + // If this reference is in an @implementation, also check for 'private' + // methods. + Setter = FindMethodInNestedImplementations(IFace, SetterSel); + } + // Look through local category implementations associated with the class. + if (!Setter) { + for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Setter; i++) { + if (ObjCCategoryImpls[i]->getClassInterface() == IFace) + Setter = ObjCCategoryImpls[i]->getInstanceMethod(Context, SetterSel); + } + } + + if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) + return ExprError(); + + if (Getter || Setter) { + QualType PType; + + if (Getter) + PType = Getter->getResultType(); + else { + for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(), + E = Setter->param_end(); PI != E; ++PI) + PType = (*PI)->getType(); + } + // FIXME: we must check that the setter has property type. + return Owned(new (Context) ObjCKVCRefExpr(Getter, PType, + Setter, MemberLoc, BaseExpr)); + } + return ExprError(Diag(MemberLoc, diag::err_property_not_found) + << &Member << BaseType); + } + // Handle properties on qualified "id" protocols. + const ObjCQualifiedIdType *QIdTy; + if (OpKind == tok::period && (QIdTy = BaseType->getAsObjCQualifiedIdType())) { + // Check protocols on qualified interfaces. + Selector Sel = PP.getSelectorTable().getNullarySelector(&Member); + if (Decl *PMDecl = FindGetterNameDecl(QIdTy, Member, Sel, Context)) { + if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(PMDecl)) { + // Check the use of this declaration + if (DiagnoseUseOfDecl(PD, MemberLoc)) + return ExprError(); + + return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), + MemberLoc, BaseExpr)); + } + if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) { + // Check the use of this method. + if (DiagnoseUseOfDecl(OMD, MemberLoc)) + return ExprError(); + + return Owned(new (Context) ObjCMessageExpr(BaseExpr, Sel, + OMD->getResultType(), + OMD, OpLoc, MemberLoc, + NULL, 0)); + } + } + + return ExprError(Diag(MemberLoc, diag::err_property_not_found) + << &Member << BaseType); + } + // Handle properties on ObjC 'Class' types. + if (OpKind == tok::period && (BaseType == Context.getObjCClassType())) { + // Also must look for a getter name which uses property syntax. + Selector Sel = PP.getSelectorTable().getNullarySelector(&Member); + if (ObjCMethodDecl *MD = getCurMethodDecl()) { + ObjCInterfaceDecl *IFace = MD->getClassInterface(); + ObjCMethodDecl *Getter; + // FIXME: need to also look locally in the implementation. + if ((Getter = IFace->lookupClassMethod(Context, Sel))) { + // Check the use of this method. + if (DiagnoseUseOfDecl(Getter, MemberLoc)) + return ExprError(); + } + // If we found a getter then this may be a valid dot-reference, we + // will look for the matching setter, in case it is needed. + Selector SetterSel = + SelectorTable::constructSetterName(PP.getIdentifierTable(), + PP.getSelectorTable(), &Member); + ObjCMethodDecl *Setter = IFace->lookupClassMethod(Context, SetterSel); + if (!Setter) { + // If this reference is in an @implementation, also check for 'private' + // methods. + Setter = FindMethodInNestedImplementations(IFace, SetterSel); + } + // Look through local category implementations associated with the class. + if (!Setter) { + for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Setter; i++) { + if (ObjCCategoryImpls[i]->getClassInterface() == IFace) + Setter = ObjCCategoryImpls[i]->getClassMethod(Context, SetterSel); + } + } + + if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) + return ExprError(); + + if (Getter || Setter) { + QualType PType; + + if (Getter) + PType = Getter->getResultType(); + else { + for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(), + E = Setter->param_end(); PI != E; ++PI) + PType = (*PI)->getType(); + } + // FIXME: we must check that the setter has property type. + return Owned(new (Context) ObjCKVCRefExpr(Getter, PType, + Setter, MemberLoc, BaseExpr)); + } + return ExprError(Diag(MemberLoc, diag::err_property_not_found) + << &Member << BaseType); + } + } + + // Handle 'field access' to vectors, such as 'V.xx'. + if (BaseType->isExtVectorType()) { + QualType ret = CheckExtVectorComponent(BaseType, OpLoc, Member, MemberLoc); + if (ret.isNull()) + return ExprError(); + return Owned(new (Context) ExtVectorElementExpr(ret, BaseExpr, Member, + MemberLoc)); + } + + Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union) + << BaseType << BaseExpr->getSourceRange(); + + // If the user is trying to apply -> or . to a function or function + // pointer, it's probably because they forgot parentheses to call + // the function. Suggest the addition of those parentheses. + if (BaseType == Context.OverloadTy || + BaseType->isFunctionType() || + (BaseType->isPointerType() && + BaseType->getAsPointerType()->isFunctionType())) { + SourceLocation Loc = PP.getLocForEndOfToken(BaseExpr->getLocEnd()); + Diag(Loc, diag::note_member_reference_needs_call) + << CodeModificationHint::CreateInsertion(Loc, "()"); + } + + return ExprError(); +} + +/// ConvertArgumentsForCall - Converts the arguments specified in +/// Args/NumArgs to the parameter types of the function FDecl with +/// function prototype Proto. Call is the call expression itself, and +/// Fn is the function expression. For a C++ member function, this +/// routine does not attempt to convert the object argument. Returns +/// true if the call is ill-formed. +bool +Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, + FunctionDecl *FDecl, + const FunctionProtoType *Proto, + Expr **Args, unsigned NumArgs, + SourceLocation RParenLoc) { + // C99 6.5.2.2p7 - the arguments are implicitly converted, as if by + // assignment, to the types of the corresponding parameter, ... + unsigned NumArgsInProto = Proto->getNumArgs(); + unsigned NumArgsToCheck = NumArgs; + bool Invalid = false; + + // If too few arguments are available (and we don't have default + // arguments for the remaining parameters), don't make the call. + if (NumArgs < NumArgsInProto) { + if (!FDecl || NumArgs < FDecl->getMinRequiredArguments()) + return Diag(RParenLoc, diag::err_typecheck_call_too_few_args) + << Fn->getType()->isBlockPointerType() << Fn->getSourceRange(); + // Use default arguments for missing arguments + NumArgsToCheck = NumArgsInProto; + Call->setNumArgs(Context, NumArgsInProto); + } + + // If too many are passed and not variadic, error on the extras and drop + // them. + if (NumArgs > NumArgsInProto) { + if (!Proto->isVariadic()) { + Diag(Args[NumArgsInProto]->getLocStart(), + diag::err_typecheck_call_too_many_args) + << Fn->getType()->isBlockPointerType() << Fn->getSourceRange() + << SourceRange(Args[NumArgsInProto]->getLocStart(), + Args[NumArgs-1]->getLocEnd()); + // This deletes the extra arguments. + Call->setNumArgs(Context, NumArgsInProto); + Invalid = true; + } + NumArgsToCheck = NumArgsInProto; + } + + // Continue to check argument types (even if we have too few/many args). + for (unsigned i = 0; i != NumArgsToCheck; i++) { + QualType ProtoArgType = Proto->getArgType(i); + + Expr *Arg; + if (i < NumArgs) { + Arg = Args[i]; + + if (RequireCompleteType(Arg->getSourceRange().getBegin(), + ProtoArgType, + diag::err_call_incomplete_argument, + Arg->getSourceRange())) + return true; + + // Pass the argument. + if (PerformCopyInitialization(Arg, ProtoArgType, "passing")) + return true; + } else + // We already type-checked the argument, so we know it works. + Arg = new (Context) CXXDefaultArgExpr(FDecl->getParamDecl(i)); + QualType ArgType = Arg->getType(); + + Call->setArg(i, Arg); + } + + // If this is a variadic call, handle args passed through "...". + if (Proto->isVariadic()) { + VariadicCallType CallType = VariadicFunction; + if (Fn->getType()->isBlockPointerType()) + CallType = VariadicBlock; // Block + else if (isa<MemberExpr>(Fn)) + CallType = VariadicMethod; + + // Promote the arguments (C99 6.5.2.2p7). + for (unsigned i = NumArgsInProto; i != NumArgs; i++) { + Expr *Arg = Args[i]; + Invalid |= DefaultVariadicArgumentPromotion(Arg, CallType); + Call->setArg(i, Arg); + } + } + + return Invalid; +} + +/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. +/// This provides the location of the left/right parens and a list of comma +/// locations. +Action::OwningExprResult +Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, + MultiExprArg args, + SourceLocation *CommaLocs, SourceLocation RParenLoc) { + unsigned NumArgs = args.size(); + Expr *Fn = fn.takeAs<Expr>(); + Expr **Args = reinterpret_cast<Expr**>(args.release()); + assert(Fn && "no function call expression"); + FunctionDecl *FDecl = NULL; + NamedDecl *NDecl = NULL; + DeclarationName UnqualifiedName; + + if (getLangOptions().CPlusPlus) { + // Determine whether this is a dependent call inside a C++ template, + // in which case we won't do any semantic analysis now. + // FIXME: Will need to cache the results of name lookup (including ADL) in + // Fn. + bool Dependent = false; + if (Fn->isTypeDependent()) + Dependent = true; + else if (Expr::hasAnyTypeDependentArguments(Args, NumArgs)) + Dependent = true; + + if (Dependent) + return Owned(new (Context) CallExpr(Context, Fn, Args, NumArgs, + Context.DependentTy, RParenLoc)); + + // Determine whether this is a call to an object (C++ [over.call.object]). + if (Fn->getType()->isRecordType()) + return Owned(BuildCallToObjectOfClassType(S, Fn, LParenLoc, Args, NumArgs, + CommaLocs, RParenLoc)); + + // Determine whether this is a call to a member function. + if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(Fn->IgnoreParens())) + if (isa<OverloadedFunctionDecl>(MemExpr->getMemberDecl()) || + isa<CXXMethodDecl>(MemExpr->getMemberDecl())) + return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, + CommaLocs, RParenLoc)); + } + + // If we're directly calling a function, get the appropriate declaration. + DeclRefExpr *DRExpr = NULL; + Expr *FnExpr = Fn; + bool ADL = true; + while (true) { + if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(FnExpr)) + FnExpr = IcExpr->getSubExpr(); + else if (ParenExpr *PExpr = dyn_cast<ParenExpr>(FnExpr)) { + // Parentheses around a function disable ADL + // (C++0x [basic.lookup.argdep]p1). + ADL = false; + FnExpr = PExpr->getSubExpr(); + } else if (isa<UnaryOperator>(FnExpr) && + cast<UnaryOperator>(FnExpr)->getOpcode() + == UnaryOperator::AddrOf) { + FnExpr = cast<UnaryOperator>(FnExpr)->getSubExpr(); + } else if ((DRExpr = dyn_cast<DeclRefExpr>(FnExpr))) { + // Qualified names disable ADL (C++0x [basic.lookup.argdep]p1). + ADL &= !isa<QualifiedDeclRefExpr>(DRExpr); + break; + } else if (UnresolvedFunctionNameExpr *DepName + = dyn_cast<UnresolvedFunctionNameExpr>(FnExpr)) { + UnqualifiedName = DepName->getName(); + break; + } else { + // Any kind of name that does not refer to a declaration (or + // set of declarations) disables ADL (C++0x [basic.lookup.argdep]p3). + ADL = false; + break; + } + } + + OverloadedFunctionDecl *Ovl = 0; + if (DRExpr) { + FDecl = dyn_cast<FunctionDecl>(DRExpr->getDecl()); + Ovl = dyn_cast<OverloadedFunctionDecl>(DRExpr->getDecl()); + NDecl = dyn_cast<NamedDecl>(DRExpr->getDecl()); + } + + if (Ovl || (getLangOptions().CPlusPlus && (FDecl || UnqualifiedName))) { + // We don't perform ADL for implicit declarations of builtins. + if (FDecl && FDecl->getBuiltinID(Context) && FDecl->isImplicit()) + ADL = false; + + // We don't perform ADL in C. + if (!getLangOptions().CPlusPlus) + ADL = false; + + if (Ovl || ADL) { + FDecl = ResolveOverloadedCallFn(Fn, DRExpr? DRExpr->getDecl() : 0, + UnqualifiedName, LParenLoc, Args, + NumArgs, CommaLocs, RParenLoc, ADL); + if (!FDecl) + return ExprError(); + + // Update Fn to refer to the actual function selected. + Expr *NewFn = 0; + if (QualifiedDeclRefExpr *QDRExpr + = dyn_cast_or_null<QualifiedDeclRefExpr>(DRExpr)) + NewFn = new (Context) QualifiedDeclRefExpr(FDecl, FDecl->getType(), + QDRExpr->getLocation(), + false, false, + QDRExpr->getQualifierRange(), + QDRExpr->getQualifier()); + else + NewFn = new (Context) DeclRefExpr(FDecl, FDecl->getType(), + Fn->getSourceRange().getBegin()); + Fn->Destroy(Context); + Fn = NewFn; + } + } + + // Promote the function operand. + UsualUnaryConversions(Fn); + + // Make the call expr early, before semantic checks. This guarantees cleanup + // of arguments and function on error. + ExprOwningPtr<CallExpr> TheCall(this, new (Context) CallExpr(Context, Fn, + Args, NumArgs, + Context.BoolTy, + RParenLoc)); + + const FunctionType *FuncT; + if (!Fn->getType()->isBlockPointerType()) { + // C99 6.5.2.2p1 - "The expression that denotes the called function shall + // have type pointer to function". + const PointerType *PT = Fn->getType()->getAsPointerType(); + if (PT == 0) + return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function) + << Fn->getType() << Fn->getSourceRange()); + FuncT = PT->getPointeeType()->getAsFunctionType(); + } else { // This is a block call. + FuncT = Fn->getType()->getAsBlockPointerType()->getPointeeType()-> + getAsFunctionType(); + } + if (FuncT == 0) + return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function) + << Fn->getType() << Fn->getSourceRange()); + + // Check for a valid return type + if (!FuncT->getResultType()->isVoidType() && + RequireCompleteType(Fn->getSourceRange().getBegin(), + FuncT->getResultType(), + diag::err_call_incomplete_return, + TheCall->getSourceRange())) + return ExprError(); + + // We know the result type of the call, set it. + TheCall->setType(FuncT->getResultType().getNonReferenceType()); + + if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FuncT)) { + if (ConvertArgumentsForCall(&*TheCall, Fn, FDecl, Proto, Args, NumArgs, + RParenLoc)) + return ExprError(); + } else { + assert(isa<FunctionNoProtoType>(FuncT) && "Unknown FunctionType!"); + + if (FDecl) { + // Check if we have too few/too many template arguments, based + // on our knowledge of the function definition. + const FunctionDecl *Def = 0; + if (FDecl->getBody(Context, Def) && NumArgs != Def->param_size()) { + const FunctionProtoType *Proto = + Def->getType()->getAsFunctionProtoType(); + if (!Proto || !(Proto->isVariadic() && NumArgs >= Def->param_size())) { + Diag(RParenLoc, diag::warn_call_wrong_number_of_arguments) + << (NumArgs > Def->param_size()) << FDecl << Fn->getSourceRange(); + } + } + } + + // Promote the arguments (C99 6.5.2.2p6). + for (unsigned i = 0; i != NumArgs; i++) { + Expr *Arg = Args[i]; + DefaultArgumentPromotion(Arg); + if (RequireCompleteType(Arg->getSourceRange().getBegin(), + Arg->getType(), + diag::err_call_incomplete_argument, + Arg->getSourceRange())) + return ExprError(); + TheCall->setArg(i, Arg); + } + } + + if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(FDecl)) + if (!Method->isStatic()) + return ExprError(Diag(LParenLoc, diag::err_member_call_without_object) + << Fn->getSourceRange()); + + // Check for sentinels + if (NDecl) + DiagnoseSentinelCalls(NDecl, LParenLoc, Args, NumArgs); + // Do special checking on direct calls to functions. + if (FDecl) + return CheckFunctionCall(FDecl, TheCall.take()); + if (NDecl) + return CheckBlockCall(NDecl, TheCall.take()); + + return Owned(TheCall.take()); +} + +Action::OwningExprResult +Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, + SourceLocation RParenLoc, ExprArg InitExpr) { + assert((Ty != 0) && "ActOnCompoundLiteral(): missing type"); + QualType literalType = QualType::getFromOpaquePtr(Ty); + // FIXME: put back this assert when initializers are worked out. + //assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression"); + Expr *literalExpr = static_cast<Expr*>(InitExpr.get()); + + if (literalType->isArrayType()) { + if (literalType->isVariableArrayType()) + return ExprError(Diag(LParenLoc, diag::err_variable_object_no_init) + << SourceRange(LParenLoc, literalExpr->getSourceRange().getEnd())); + } else if (!literalType->isDependentType() && + RequireCompleteType(LParenLoc, literalType, + diag::err_typecheck_decl_incomplete_type, + SourceRange(LParenLoc, literalExpr->getSourceRange().getEnd()))) + return ExprError(); + + if (CheckInitializerTypes(literalExpr, literalType, LParenLoc, + DeclarationName(), /*FIXME:DirectInit=*/false)) + return ExprError(); + + bool isFileScope = getCurFunctionOrMethodDecl() == 0; + if (isFileScope) { // 6.5.2.5p3 + if (CheckForConstantInitializer(literalExpr, literalType)) + return ExprError(); + } + InitExpr.release(); + return Owned(new (Context) CompoundLiteralExpr(LParenLoc, literalType, + literalExpr, isFileScope)); +} + +Action::OwningExprResult +Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist, + SourceLocation RBraceLoc) { + unsigned NumInit = initlist.size(); + Expr **InitList = reinterpret_cast<Expr**>(initlist.release()); + + // Semantic analysis for initializers is done by ActOnDeclarator() and + // CheckInitializer() - it requires knowledge of the object being intialized. + + InitListExpr *E = new (Context) InitListExpr(LBraceLoc, InitList, NumInit, + RBraceLoc); + E->setType(Context.VoidTy); // FIXME: just a place holder for now. + return Owned(E); +} + +/// CheckCastTypes - Check type constraints for casting between types. +bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr) { + UsualUnaryConversions(castExpr); + + // C99 6.5.4p2: the cast type needs to be void or scalar and the expression + // type needs to be scalar. + if (castType->isVoidType()) { + // Cast to void allows any expr type. + } else if (castType->isDependentType() || castExpr->isTypeDependent()) { + // We can't check any more until template instantiation time. + } else if (!castType->isScalarType() && !castType->isVectorType()) { + if (Context.getCanonicalType(castType).getUnqualifiedType() == + Context.getCanonicalType(castExpr->getType().getUnqualifiedType()) && + (castType->isStructureType() || castType->isUnionType())) { + // GCC struct/union extension: allow cast to self. + // FIXME: Check that the cast destination type is complete. + Diag(TyR.getBegin(), diag::ext_typecheck_cast_nonscalar) + << castType << castExpr->getSourceRange(); + } else if (castType->isUnionType()) { + // GCC cast to union extension + RecordDecl *RD = castType->getAsRecordType()->getDecl(); + RecordDecl::field_iterator Field, FieldEnd; + for (Field = RD->field_begin(Context), FieldEnd = RD->field_end(Context); + Field != FieldEnd; ++Field) { + if (Context.getCanonicalType(Field->getType()).getUnqualifiedType() == + Context.getCanonicalType(castExpr->getType()).getUnqualifiedType()) { + Diag(TyR.getBegin(), diag::ext_typecheck_cast_to_union) + << castExpr->getSourceRange(); + break; + } + } + if (Field == FieldEnd) + return Diag(TyR.getBegin(), diag::err_typecheck_cast_to_union_no_type) + << castExpr->getType() << castExpr->getSourceRange(); + } else { + // Reject any other conversions to non-scalar types. + return Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar) + << castType << castExpr->getSourceRange(); + } + } else if (!castExpr->getType()->isScalarType() && + !castExpr->getType()->isVectorType()) { + return Diag(castExpr->getLocStart(), + diag::err_typecheck_expect_scalar_operand) + << castExpr->getType() << castExpr->getSourceRange(); + } else if (castExpr->getType()->isVectorType()) { + if (CheckVectorCast(TyR, castExpr->getType(), castType)) + return true; + } else if (castType->isVectorType()) { + if (CheckVectorCast(TyR, castType, castExpr->getType())) + return true; + } else if (getLangOptions().ObjC1 && isa<ObjCSuperExpr>(castExpr)) { + return Diag(castExpr->getLocStart(), diag::err_illegal_super_cast) << TyR; + } else if (!castType->isArithmeticType()) { + QualType castExprType = castExpr->getType(); + if (!castExprType->isIntegralType() && castExprType->isArithmeticType()) + return Diag(castExpr->getLocStart(), + diag::err_cast_pointer_from_non_pointer_int) + << castExprType << castExpr->getSourceRange(); + } else if (!castExpr->getType()->isArithmeticType()) { + if (!castType->isIntegralType() && castType->isArithmeticType()) + return Diag(castExpr->getLocStart(), + diag::err_cast_pointer_to_non_pointer_int) + << castType << castExpr->getSourceRange(); + } + if (isa<ObjCSelectorExpr>(castExpr)) + return Diag(castExpr->getLocStart(), diag::err_cast_selector_expr); + return false; +} + +bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty) { + assert(VectorTy->isVectorType() && "Not a vector type!"); + + if (Ty->isVectorType() || Ty->isIntegerType()) { + if (Context.getTypeSize(VectorTy) != Context.getTypeSize(Ty)) + return Diag(R.getBegin(), + Ty->isVectorType() ? + diag::err_invalid_conversion_between_vectors : + diag::err_invalid_conversion_between_vector_and_integer) + << VectorTy << Ty << R; + } else + return Diag(R.getBegin(), + diag::err_invalid_conversion_between_vector_and_scalar) + << VectorTy << Ty << R; + + return false; +} + +Action::OwningExprResult +Sema::ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty, + SourceLocation RParenLoc, ExprArg Op) { + assert((Ty != 0) && (Op.get() != 0) && + "ActOnCastExpr(): missing type or expr"); + + Expr *castExpr = Op.takeAs<Expr>(); + QualType castType = QualType::getFromOpaquePtr(Ty); + + if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), castType, castExpr)) + return ExprError(); + return Owned(new (Context) CStyleCastExpr(castType, castExpr, castType, + LParenLoc, RParenLoc)); +} + +/// Note that lhs is not null here, even if this is the gnu "x ?: y" extension. +/// In that case, lhs = cond. +/// C99 6.5.15 +QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, + SourceLocation QuestionLoc) { + // C++ is sufficiently different to merit its own checker. + if (getLangOptions().CPlusPlus) + return CXXCheckConditionalOperands(Cond, LHS, RHS, QuestionLoc); + + UsualUnaryConversions(Cond); + UsualUnaryConversions(LHS); + UsualUnaryConversions(RHS); + QualType CondTy = Cond->getType(); + QualType LHSTy = LHS->getType(); + QualType RHSTy = RHS->getType(); + + // first, check the condition. + if (!CondTy->isScalarType()) { // C99 6.5.15p2 + Diag(Cond->getLocStart(), diag::err_typecheck_cond_expect_scalar) + << CondTy; + return QualType(); + } + + // Now check the two expressions. + + // If both operands have arithmetic type, do the usual arithmetic conversions + // to find a common type: C99 6.5.15p3,5. + if (LHSTy->isArithmeticType() && RHSTy->isArithmeticType()) { + UsualArithmeticConversions(LHS, RHS); + return LHS->getType(); + } + + // If both operands are the same structure or union type, the result is that + // type. + if (const RecordType *LHSRT = LHSTy->getAsRecordType()) { // C99 6.5.15p3 + if (const RecordType *RHSRT = RHSTy->getAsRecordType()) + if (LHSRT->getDecl() == RHSRT->getDecl()) + // "If both the operands have structure or union type, the result has + // that type." This implies that CV qualifiers are dropped. + return LHSTy.getUnqualifiedType(); + // FIXME: Type of conditional expression must be complete in C mode. + } + + // C99 6.5.15p5: "If both operands have void type, the result has void type." + // The following || allows only one side to be void (a GCC-ism). + if (LHSTy->isVoidType() || RHSTy->isVoidType()) { + if (!LHSTy->isVoidType()) + Diag(RHS->getLocStart(), diag::ext_typecheck_cond_one_void) + << RHS->getSourceRange(); + if (!RHSTy->isVoidType()) + Diag(LHS->getLocStart(), diag::ext_typecheck_cond_one_void) + << LHS->getSourceRange(); + ImpCastExprToType(LHS, Context.VoidTy); + ImpCastExprToType(RHS, Context.VoidTy); + return Context.VoidTy; + } + // C99 6.5.15p6 - "if one operand is a null pointer constant, the result has + // the type of the other operand." + if ((LHSTy->isPointerType() || LHSTy->isBlockPointerType() || + Context.isObjCObjectPointerType(LHSTy)) && + RHS->isNullPointerConstant(Context)) { + ImpCastExprToType(RHS, LHSTy); // promote the null to a pointer. + return LHSTy; + } + if ((RHSTy->isPointerType() || RHSTy->isBlockPointerType() || + Context.isObjCObjectPointerType(RHSTy)) && + LHS->isNullPointerConstant(Context)) { + ImpCastExprToType(LHS, RHSTy); // promote the null to a pointer. + return RHSTy; + } + + const PointerType *LHSPT = LHSTy->getAsPointerType(); + const PointerType *RHSPT = RHSTy->getAsPointerType(); + const BlockPointerType *LHSBPT = LHSTy->getAsBlockPointerType(); + const BlockPointerType *RHSBPT = RHSTy->getAsBlockPointerType(); + + // Handle the case where both operands are pointers before we handle null + // pointer constants in case both operands are null pointer constants. + if ((LHSPT || LHSBPT) && (RHSPT || RHSBPT)) { // C99 6.5.15p3,6 + // get the "pointed to" types + QualType lhptee = (LHSPT ? LHSPT->getPointeeType() + : LHSBPT->getPointeeType()); + QualType rhptee = (RHSPT ? RHSPT->getPointeeType() + : RHSBPT->getPointeeType()); + + // ignore qualifiers on void (C99 6.5.15p3, clause 6) + if (lhptee->isVoidType() + && (RHSBPT || rhptee->isIncompleteOrObjectType())) { + // Figure out necessary qualifiers (C99 6.5.15p6) + QualType destPointee=lhptee.getQualifiedType(rhptee.getCVRQualifiers()); + QualType destType = Context.getPointerType(destPointee); + ImpCastExprToType(LHS, destType); // add qualifiers if necessary + ImpCastExprToType(RHS, destType); // promote to void* + return destType; + } + if (rhptee->isVoidType() + && (LHSBPT || lhptee->isIncompleteOrObjectType())) { + QualType destPointee=rhptee.getQualifiedType(lhptee.getCVRQualifiers()); + QualType destType = Context.getPointerType(destPointee); + ImpCastExprToType(LHS, destType); // add qualifiers if necessary + ImpCastExprToType(RHS, destType); // promote to void* + return destType; + } + + bool sameKind = (LHSPT && RHSPT) || (LHSBPT && RHSBPT); + if (sameKind + && Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) { + // Two identical pointer types are always compatible. + return LHSTy; + } + + QualType compositeType = LHSTy; + + // If either type is an Objective-C object type then check + // compatibility according to Objective-C. + if (Context.isObjCObjectPointerType(LHSTy) || + Context.isObjCObjectPointerType(RHSTy)) { + // If both operands are interfaces and either operand can be + // assigned to the other, use that type as the composite + // type. This allows + // xxx ? (A*) a : (B*) b + // where B is a subclass of A. + // + // Additionally, as for assignment, if either type is 'id' + // allow silent coercion. Finally, if the types are + // incompatible then make sure to use 'id' as the composite + // type so the result is acceptable for sending messages to. + + // FIXME: Consider unifying with 'areComparableObjCPointerTypes'. + // It could return the composite type. + const ObjCInterfaceType* LHSIface = lhptee->getAsObjCInterfaceType(); + const ObjCInterfaceType* RHSIface = rhptee->getAsObjCInterfaceType(); + if (LHSIface && RHSIface && + Context.canAssignObjCInterfaces(LHSIface, RHSIface)) { + compositeType = LHSTy; + } else if (LHSIface && RHSIface && + Context.canAssignObjCInterfaces(RHSIface, LHSIface)) { + compositeType = RHSTy; + } else if (Context.isObjCIdStructType(lhptee) || + Context.isObjCIdStructType(rhptee)) { + compositeType = Context.getObjCIdType(); + } else if (LHSBPT || RHSBPT) { + if (!sameKind + || !Context.typesAreBlockCompatible(lhptee.getUnqualifiedType(), + rhptee.getUnqualifiedType())) + Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) + << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); + return QualType(); + } else { + Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands) + << LHSTy << RHSTy + << LHS->getSourceRange() << RHS->getSourceRange(); + QualType incompatTy = Context.getObjCIdType(); + ImpCastExprToType(LHS, incompatTy); + ImpCastExprToType(RHS, incompatTy); + return incompatTy; + } + } else if (!sameKind + || !Context.typesAreCompatible(lhptee.getUnqualifiedType(), + rhptee.getUnqualifiedType())) { + Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers) + << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); + // In this situation, we assume void* type. No especially good + // reason, but this is what gcc does, and we do have to pick + // to get a consistent AST. + QualType incompatTy = Context.getPointerType(Context.VoidTy); + ImpCastExprToType(LHS, incompatTy); + ImpCastExprToType(RHS, incompatTy); + return incompatTy; + } + // The pointer types are compatible. + // C99 6.5.15p6: If both operands are pointers to compatible types *or* to + // differently qualified versions of compatible types, the result type is + // a pointer to an appropriately qualified version of the *composite* + // type. + // FIXME: Need to calculate the composite type. + // FIXME: Need to add qualifiers + ImpCastExprToType(LHS, compositeType); + ImpCastExprToType(RHS, compositeType); + return compositeType; + } + + // GCC compatibility: soften pointer/integer mismatch. + if (RHSTy->isPointerType() && LHSTy->isIntegerType()) { + Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch) + << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); + ImpCastExprToType(LHS, RHSTy); // promote the integer to a pointer. + return RHSTy; + } + if (LHSTy->isPointerType() && RHSTy->isIntegerType()) { + Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch) + << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); + ImpCastExprToType(RHS, LHSTy); // promote the integer to a pointer. + return LHSTy; + } + + // Need to handle "id<xx>" explicitly. Unlike "id", whose canonical type + // evaluates to "struct objc_object *" (and is handled above when comparing + // id with statically typed objects). + if (LHSTy->isObjCQualifiedIdType() || RHSTy->isObjCQualifiedIdType()) { + // GCC allows qualified id and any Objective-C type to devolve to + // id. Currently localizing to here until clear this should be + // part of ObjCQualifiedIdTypesAreCompatible. + if (ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true) || + (LHSTy->isObjCQualifiedIdType() && + Context.isObjCObjectPointerType(RHSTy)) || + (RHSTy->isObjCQualifiedIdType() && + Context.isObjCObjectPointerType(LHSTy))) { + // FIXME: This is not the correct composite type. This only happens to + // work because id can more or less be used anywhere, however this may + // change the type of method sends. + + // FIXME: gcc adds some type-checking of the arguments and emits + // (confusing) incompatible comparison warnings in some + // cases. Investigate. + QualType compositeType = Context.getObjCIdType(); + ImpCastExprToType(LHS, compositeType); + ImpCastExprToType(RHS, compositeType); + return compositeType; + } + } + + // Otherwise, the operands are not compatible. + Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) + << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); + return QualType(); +} + +/// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null +/// in the case of a the GNU conditional expr extension. +Action::OwningExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, + SourceLocation ColonLoc, + ExprArg Cond, ExprArg LHS, + ExprArg RHS) { + Expr *CondExpr = (Expr *) Cond.get(); + Expr *LHSExpr = (Expr *) LHS.get(), *RHSExpr = (Expr *) RHS.get(); + + // If this is the gnu "x ?: y" extension, analyze the types as though the LHS + // was the condition. + bool isLHSNull = LHSExpr == 0; + if (isLHSNull) + LHSExpr = CondExpr; + + QualType result = CheckConditionalOperands(CondExpr, LHSExpr, + RHSExpr, QuestionLoc); + if (result.isNull()) + return ExprError(); + + Cond.release(); + LHS.release(); + RHS.release(); + return Owned(new (Context) ConditionalOperator(CondExpr, + isLHSNull ? 0 : LHSExpr, + RHSExpr, result)); +} + + +// CheckPointerTypesForAssignment - This is a very tricky routine (despite +// being closely modeled after the C99 spec:-). The odd characteristic of this +// routine is it effectively iqnores the qualifiers on the top level pointee. +// This circumvents the usual type rules specified in 6.2.7p1 & 6.7.5.[1-3]. +// FIXME: add a couple examples in this comment. +Sema::AssignConvertType +Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { + QualType lhptee, rhptee; + + // get the "pointed to" type (ignoring qualifiers at the top level) + lhptee = lhsType->getAsPointerType()->getPointeeType(); + rhptee = rhsType->getAsPointerType()->getPointeeType(); + + // make sure we operate on the canonical type + lhptee = Context.getCanonicalType(lhptee); + rhptee = Context.getCanonicalType(rhptee); + + AssignConvertType ConvTy = Compatible; + + // C99 6.5.16.1p1: This following citation is common to constraints + // 3 & 4 (below). ...and the type *pointed to* by the left has all the + // qualifiers of the type *pointed to* by the right; + // FIXME: Handle ExtQualType + if (!lhptee.isAtLeastAsQualifiedAs(rhptee)) + ConvTy = CompatiblePointerDiscardsQualifiers; + + // C99 6.5.16.1p1 (constraint 4): If one operand is a pointer to an object or + // incomplete type and the other is a pointer to a qualified or unqualified + // version of void... + if (lhptee->isVoidType()) { + if (rhptee->isIncompleteOrObjectType()) + return ConvTy; + + // As an extension, we allow cast to/from void* to function pointer. + assert(rhptee->isFunctionType()); + return FunctionVoidPointer; + } + + if (rhptee->isVoidType()) { + if (lhptee->isIncompleteOrObjectType()) + return ConvTy; + + // As an extension, we allow cast to/from void* to function pointer. + assert(lhptee->isFunctionType()); + return FunctionVoidPointer; + } + // C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or + // unqualified versions of compatible types, ... + lhptee = lhptee.getUnqualifiedType(); + rhptee = rhptee.getUnqualifiedType(); + if (!Context.typesAreCompatible(lhptee, rhptee)) { + // Check if the pointee types are compatible ignoring the sign. + // We explicitly check for char so that we catch "char" vs + // "unsigned char" on systems where "char" is unsigned. + if (lhptee->isCharType()) { + lhptee = Context.UnsignedCharTy; + } else if (lhptee->isSignedIntegerType()) { + lhptee = Context.getCorrespondingUnsignedType(lhptee); + } + if (rhptee->isCharType()) { + rhptee = Context.UnsignedCharTy; + } else if (rhptee->isSignedIntegerType()) { + rhptee = Context.getCorrespondingUnsignedType(rhptee); + } + if (lhptee == rhptee) { + // Types are compatible ignoring the sign. Qualifier incompatibility + // takes priority over sign incompatibility because the sign + // warning can be disabled. + if (ConvTy != Compatible) + return ConvTy; + return IncompatiblePointerSign; + } + // General pointer incompatibility takes priority over qualifiers. + return IncompatiblePointer; + } + return ConvTy; +} + +/// CheckBlockPointerTypesForAssignment - This routine determines whether two +/// block pointer types are compatible or whether a block and normal pointer +/// are compatible. It is more restrict than comparing two function pointer +// types. +Sema::AssignConvertType +Sema::CheckBlockPointerTypesForAssignment(QualType lhsType, + QualType rhsType) { + QualType lhptee, rhptee; + + // get the "pointed to" type (ignoring qualifiers at the top level) + lhptee = lhsType->getAsBlockPointerType()->getPointeeType(); + rhptee = rhsType->getAsBlockPointerType()->getPointeeType(); + + // make sure we operate on the canonical type + lhptee = Context.getCanonicalType(lhptee); + rhptee = Context.getCanonicalType(rhptee); + + AssignConvertType ConvTy = Compatible; + + // For blocks we enforce that qualifiers are identical. + if (lhptee.getCVRQualifiers() != rhptee.getCVRQualifiers()) + ConvTy = CompatiblePointerDiscardsQualifiers; + + if (!Context.typesAreBlockCompatible(lhptee, rhptee)) + return IncompatibleBlockPointer; + return ConvTy; +} + +/// CheckAssignmentConstraints (C99 6.5.16) - This routine currently +/// has code to accommodate several GCC extensions when type checking +/// pointers. Here are some objectionable examples that GCC considers warnings: +/// +/// int a, *pint; +/// short *pshort; +/// struct foo *pfoo; +/// +/// pint = pshort; // warning: assignment from incompatible pointer type +/// a = pint; // warning: assignment makes integer from pointer without a cast +/// pint = a; // warning: assignment makes pointer from integer without a cast +/// pint = pfoo; // warning: assignment from incompatible pointer type +/// +/// As a result, the code for dealing with pointers is more complex than the +/// C99 spec dictates. +/// +Sema::AssignConvertType +Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { + // Get canonical types. We're not formatting these types, just comparing + // them. + lhsType = Context.getCanonicalType(lhsType).getUnqualifiedType(); + rhsType = Context.getCanonicalType(rhsType).getUnqualifiedType(); + + if (lhsType == rhsType) + return Compatible; // Common case: fast path an exact match. + + // If the left-hand side is a reference type, then we are in a + // (rare!) case where we've allowed the use of references in C, + // e.g., as a parameter type in a built-in function. In this case, + // just make sure that the type referenced is compatible with the + // right-hand side type. The caller is responsible for adjusting + // lhsType so that the resulting expression does not have reference + // type. + if (const ReferenceType *lhsTypeRef = lhsType->getAsReferenceType()) { + if (Context.typesAreCompatible(lhsTypeRef->getPointeeType(), rhsType)) + return Compatible; + return Incompatible; + } + + if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType()) { + if (ObjCQualifiedIdTypesAreCompatible(lhsType, rhsType, false)) + return Compatible; + // Relax integer conversions like we do for pointers below. + if (rhsType->isIntegerType()) + return IntToPointer; + if (lhsType->isIntegerType()) + return PointerToInt; + return IncompatibleObjCQualifiedId; + } + + if (lhsType->isVectorType() || rhsType->isVectorType()) { + // For ExtVector, allow vector splats; float -> <n x float> + if (const ExtVectorType *LV = lhsType->getAsExtVectorType()) + if (LV->getElementType() == rhsType) + return Compatible; + + // If we are allowing lax vector conversions, and LHS and RHS are both + // vectors, the total size only needs to be the same. This is a bitcast; + // no bits are changed but the result type is different. + if (getLangOptions().LaxVectorConversions && + lhsType->isVectorType() && rhsType->isVectorType()) { + if (Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType)) + return IncompatibleVectors; + } + return Incompatible; + } + + if (lhsType->isArithmeticType() && rhsType->isArithmeticType()) + return Compatible; + + if (isa<PointerType>(lhsType)) { + if (rhsType->isIntegerType()) + return IntToPointer; + + if (isa<PointerType>(rhsType)) + return CheckPointerTypesForAssignment(lhsType, rhsType); + + if (rhsType->getAsBlockPointerType()) { + if (lhsType->getAsPointerType()->getPointeeType()->isVoidType()) + return Compatible; + + // Treat block pointers as objects. + if (getLangOptions().ObjC1 && + lhsType == Context.getCanonicalType(Context.getObjCIdType())) + return Compatible; + } + return Incompatible; + } + + if (isa<BlockPointerType>(lhsType)) { + if (rhsType->isIntegerType()) + return IntToBlockPointer; + + // Treat block pointers as objects. + if (getLangOptions().ObjC1 && + rhsType == Context.getCanonicalType(Context.getObjCIdType())) + return Compatible; + + if (rhsType->isBlockPointerType()) + return CheckBlockPointerTypesForAssignment(lhsType, rhsType); + + if (const PointerType *RHSPT = rhsType->getAsPointerType()) { + if (RHSPT->getPointeeType()->isVoidType()) + return Compatible; + } + return Incompatible; + } + + if (isa<PointerType>(rhsType)) { + // C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer. + if (lhsType == Context.BoolTy) + return Compatible; + + if (lhsType->isIntegerType()) + return PointerToInt; + + if (isa<PointerType>(lhsType)) + return CheckPointerTypesForAssignment(lhsType, rhsType); + + if (isa<BlockPointerType>(lhsType) && + rhsType->getAsPointerType()->getPointeeType()->isVoidType()) + return Compatible; + return Incompatible; + } + + if (isa<TagType>(lhsType) && isa<TagType>(rhsType)) { + if (Context.typesAreCompatible(lhsType, rhsType)) + return Compatible; + } + return Incompatible; +} + +/// \brief Constructs a transparent union from an expression that is +/// used to initialize the transparent union. +static void ConstructTransparentUnion(ASTContext &C, Expr *&E, + QualType UnionType, FieldDecl *Field) { + // Build an initializer list that designates the appropriate member + // of the transparent union. + InitListExpr *Initializer = new (C) InitListExpr(SourceLocation(), + &E, 1, + SourceLocation()); + Initializer->setType(UnionType); + Initializer->setInitializedFieldInUnion(Field); + + // Build a compound literal constructing a value of the transparent + // union type from this initializer list. + E = new (C) CompoundLiteralExpr(SourceLocation(), UnionType, Initializer, + false); +} + +Sema::AssignConvertType +Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) { + QualType FromType = rExpr->getType(); + + // If the ArgType is a Union type, we want to handle a potential + // transparent_union GCC extension. + const RecordType *UT = ArgType->getAsUnionType(); + if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>()) + return Incompatible; + + // The field to initialize within the transparent union. + RecordDecl *UD = UT->getDecl(); + FieldDecl *InitField = 0; + // It's compatible if the expression matches any of the fields. + for (RecordDecl::field_iterator it = UD->field_begin(Context), + itend = UD->field_end(Context); + it != itend; ++it) { + if (it->getType()->isPointerType()) { + // If the transparent union contains a pointer type, we allow: + // 1) void pointer + // 2) null pointer constant + if (FromType->isPointerType()) + if (FromType->getAsPointerType()->getPointeeType()->isVoidType()) { + ImpCastExprToType(rExpr, it->getType()); + InitField = *it; + break; + } + + if (rExpr->isNullPointerConstant(Context)) { + ImpCastExprToType(rExpr, it->getType()); + InitField = *it; + break; + } + } + + if (CheckAssignmentConstraints(it->getType(), rExpr->getType()) + == Compatible) { + InitField = *it; + break; + } + } + + if (!InitField) + return Incompatible; + + ConstructTransparentUnion(Context, rExpr, ArgType, InitField); + return Compatible; +} + +Sema::AssignConvertType +Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { + if (getLangOptions().CPlusPlus) { + if (!lhsType->isRecordType()) { + // C++ 5.17p3: If the left operand is not of class type, the + // expression is implicitly converted (C++ 4) to the + // cv-unqualified type of the left operand. + if (PerformImplicitConversion(rExpr, lhsType.getUnqualifiedType(), + "assigning")) + return Incompatible; + return Compatible; + } + + // FIXME: Currently, we fall through and treat C++ classes like C + // structures. + } + + // C99 6.5.16.1p1: the left operand is a pointer and the right is + // a null pointer constant. + if ((lhsType->isPointerType() || + lhsType->isObjCQualifiedIdType() || + lhsType->isBlockPointerType()) + && rExpr->isNullPointerConstant(Context)) { + ImpCastExprToType(rExpr, lhsType); + return Compatible; + } + + // This check seems unnatural, however it is necessary to ensure the proper + // conversion of functions/arrays. If the conversion were done for all + // DeclExpr's (created by ActOnIdentifierExpr), it would mess up the unary + // expressions that surpress this implicit conversion (&, sizeof). + // + // Suppress this for references: C++ 8.5.3p5. + if (!lhsType->isReferenceType()) + DefaultFunctionArrayConversion(rExpr); + + Sema::AssignConvertType result = + CheckAssignmentConstraints(lhsType, rExpr->getType()); + + // C99 6.5.16.1p2: The value of the right operand is converted to the + // type of the assignment expression. + // CheckAssignmentConstraints allows the left-hand side to be a reference, + // so that we can use references in built-in functions even in C. + // The getNonReferenceType() call makes sure that the resulting expression + // does not have reference type. + if (result != Incompatible && rExpr->getType() != lhsType) + ImpCastExprToType(rExpr, lhsType.getNonReferenceType()); + return result; +} + +QualType Sema::InvalidOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) { + Diag(Loc, diag::err_typecheck_invalid_operands) + << lex->getType() << rex->getType() + << lex->getSourceRange() << rex->getSourceRange(); + return QualType(); +} + +inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, + Expr *&rex) { + // For conversion purposes, we ignore any qualifiers. + // For example, "const float" and "float" are equivalent. + QualType lhsType = + Context.getCanonicalType(lex->getType()).getUnqualifiedType(); + QualType rhsType = + Context.getCanonicalType(rex->getType()).getUnqualifiedType(); + + // If the vector types are identical, return. + if (lhsType == rhsType) + return lhsType; + + // Handle the case of a vector & extvector type of the same size and element + // type. It would be nice if we only had one vector type someday. + if (getLangOptions().LaxVectorConversions) { + // FIXME: Should we warn here? + if (const VectorType *LV = lhsType->getAsVectorType()) { + if (const VectorType *RV = rhsType->getAsVectorType()) + if (LV->getElementType() == RV->getElementType() && + LV->getNumElements() == RV->getNumElements()) { + return lhsType->isExtVectorType() ? lhsType : rhsType; + } + } + } + + // If the lhs is an extended vector and the rhs is a scalar of the same type + // or a literal, promote the rhs to the vector type. + if (const ExtVectorType *V = lhsType->getAsExtVectorType()) { + QualType eltType = V->getElementType(); + + if ((eltType->getAsBuiltinType() == rhsType->getAsBuiltinType()) || + (eltType->isIntegerType() && isa<IntegerLiteral>(rex)) || + (eltType->isFloatingType() && isa<FloatingLiteral>(rex))) { + ImpCastExprToType(rex, lhsType); + return lhsType; + } + } + + // If the rhs is an extended vector and the lhs is a scalar of the same type, + // promote the lhs to the vector type. + if (const ExtVectorType *V = rhsType->getAsExtVectorType()) { + QualType eltType = V->getElementType(); + + if ((eltType->getAsBuiltinType() == lhsType->getAsBuiltinType()) || + (eltType->isIntegerType() && isa<IntegerLiteral>(lex)) || + (eltType->isFloatingType() && isa<FloatingLiteral>(lex))) { + ImpCastExprToType(lex, rhsType); + return rhsType; + } + } + + // You cannot convert between vector values of different size. + Diag(Loc, diag::err_typecheck_vector_not_convertable) + << lex->getType() << rex->getType() + << lex->getSourceRange() << rex->getSourceRange(); + return QualType(); +} + +inline QualType Sema::CheckMultiplyDivideOperands( + Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) +{ + if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) + return CheckVectorOperands(Loc, lex, rex); + + QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); + + if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) + return compType; + return InvalidOperands(Loc, lex, rex); +} + +inline QualType Sema::CheckRemainderOperands( + Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) +{ + if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) { + if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType()) + return CheckVectorOperands(Loc, lex, rex); + return InvalidOperands(Loc, lex, rex); + } + + QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); + + if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType()) + return compType; + return InvalidOperands(Loc, lex, rex); +} + +inline QualType Sema::CheckAdditionOperands( // C99 6.5.6 + Expr *&lex, Expr *&rex, SourceLocation Loc, QualType* CompLHSTy) +{ + if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) { + QualType compType = CheckVectorOperands(Loc, lex, rex); + if (CompLHSTy) *CompLHSTy = compType; + return compType; + } + + QualType compType = UsualArithmeticConversions(lex, rex, CompLHSTy); + + // handle the common case first (both operands are arithmetic). + if (lex->getType()->isArithmeticType() && + rex->getType()->isArithmeticType()) { + if (CompLHSTy) *CompLHSTy = compType; + return compType; + } + + // Put any potential pointer into PExp + Expr* PExp = lex, *IExp = rex; + if (IExp->getType()->isPointerType()) + std::swap(PExp, IExp); + + if (const PointerType *PTy = PExp->getType()->getAsPointerType()) { + if (IExp->getType()->isIntegerType()) { + QualType PointeeTy = PTy->getPointeeType(); + // Check for arithmetic on pointers to incomplete types. + if (PointeeTy->isVoidType()) { + if (getLangOptions().CPlusPlus) { + Diag(Loc, diag::err_typecheck_pointer_arith_void_type) + << lex->getSourceRange() << rex->getSourceRange(); + return QualType(); + } + + // GNU extension: arithmetic on pointer to void + Diag(Loc, diag::ext_gnu_void_ptr) + << lex->getSourceRange() << rex->getSourceRange(); + } else if (PointeeTy->isFunctionType()) { + if (getLangOptions().CPlusPlus) { + Diag(Loc, diag::err_typecheck_pointer_arith_function_type) + << lex->getType() << lex->getSourceRange(); + return QualType(); + } + + // GNU extension: arithmetic on pointer to function + Diag(Loc, diag::ext_gnu_ptr_func_arith) + << lex->getType() << lex->getSourceRange(); + } else if (!PTy->isDependentType() && + RequireCompleteType(Loc, PointeeTy, + diag::err_typecheck_arithmetic_incomplete_type, + PExp->getSourceRange(), SourceRange(), + PExp->getType())) + return QualType(); + + // Diagnose bad cases where we step over interface counts. + if (PointeeTy->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) { + Diag(Loc, diag::err_arithmetic_nonfragile_interface) + << PointeeTy << PExp->getSourceRange(); + return QualType(); + } + + if (CompLHSTy) { + QualType LHSTy = lex->getType(); + if (LHSTy->isPromotableIntegerType()) + LHSTy = Context.IntTy; + else { + QualType T = isPromotableBitField(lex, Context); + if (!T.isNull()) + LHSTy = T; + } + + *CompLHSTy = LHSTy; + } + return PExp->getType(); + } + } + + return InvalidOperands(Loc, lex, rex); +} + +// C99 6.5.6 +QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, + SourceLocation Loc, QualType* CompLHSTy) { + if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) { + QualType compType = CheckVectorOperands(Loc, lex, rex); + if (CompLHSTy) *CompLHSTy = compType; + return compType; + } + + QualType compType = UsualArithmeticConversions(lex, rex, CompLHSTy); + + // Enforce type constraints: C99 6.5.6p3. + + // Handle the common case first (both operands are arithmetic). + if (lex->getType()->isArithmeticType() + && rex->getType()->isArithmeticType()) { + if (CompLHSTy) *CompLHSTy = compType; + return compType; + } + + // Either ptr - int or ptr - ptr. + if (const PointerType *LHSPTy = lex->getType()->getAsPointerType()) { + QualType lpointee = LHSPTy->getPointeeType(); + + // The LHS must be an completely-defined object type. + + bool ComplainAboutVoid = false; + Expr *ComplainAboutFunc = 0; + if (lpointee->isVoidType()) { + if (getLangOptions().CPlusPlus) { + Diag(Loc, diag::err_typecheck_pointer_arith_void_type) + << lex->getSourceRange() << rex->getSourceRange(); + return QualType(); + } + + // GNU C extension: arithmetic on pointer to void + ComplainAboutVoid = true; + } else if (lpointee->isFunctionType()) { + if (getLangOptions().CPlusPlus) { + Diag(Loc, diag::err_typecheck_pointer_arith_function_type) + << lex->getType() << lex->getSourceRange(); + return QualType(); + } + + // GNU C extension: arithmetic on pointer to function + ComplainAboutFunc = lex; + } else if (!lpointee->isDependentType() && + RequireCompleteType(Loc, lpointee, + diag::err_typecheck_sub_ptr_object, + lex->getSourceRange(), + SourceRange(), + lex->getType())) + return QualType(); + + // Diagnose bad cases where we step over interface counts. + if (lpointee->isObjCInterfaceType() && LangOpts.ObjCNonFragileABI) { + Diag(Loc, diag::err_arithmetic_nonfragile_interface) + << lpointee << lex->getSourceRange(); + return QualType(); + } + + // The result type of a pointer-int computation is the pointer type. + if (rex->getType()->isIntegerType()) { + if (ComplainAboutVoid) + Diag(Loc, diag::ext_gnu_void_ptr) + << lex->getSourceRange() << rex->getSourceRange(); + if (ComplainAboutFunc) + Diag(Loc, diag::ext_gnu_ptr_func_arith) + << ComplainAboutFunc->getType() + << ComplainAboutFunc->getSourceRange(); + + if (CompLHSTy) *CompLHSTy = lex->getType(); + return lex->getType(); + } + + // Handle pointer-pointer subtractions. + if (const PointerType *RHSPTy = rex->getType()->getAsPointerType()) { + QualType rpointee = RHSPTy->getPointeeType(); + + // RHS must be a completely-type object type. + // Handle the GNU void* extension. + if (rpointee->isVoidType()) { + if (getLangOptions().CPlusPlus) { + Diag(Loc, diag::err_typecheck_pointer_arith_void_type) + << lex->getSourceRange() << rex->getSourceRange(); + return QualType(); + } + + ComplainAboutVoid = true; + } else if (rpointee->isFunctionType()) { + if (getLangOptions().CPlusPlus) { + Diag(Loc, diag::err_typecheck_pointer_arith_function_type) + << rex->getType() << rex->getSourceRange(); + return QualType(); + } + + // GNU extension: arithmetic on pointer to function + if (!ComplainAboutFunc) + ComplainAboutFunc = rex; + } else if (!rpointee->isDependentType() && + RequireCompleteType(Loc, rpointee, + diag::err_typecheck_sub_ptr_object, + rex->getSourceRange(), + SourceRange(), + rex->getType())) + return QualType(); + + if (getLangOptions().CPlusPlus) { + // Pointee types must be the same: C++ [expr.add] + if (!Context.hasSameUnqualifiedType(lpointee, rpointee)) { + Diag(Loc, diag::err_typecheck_sub_ptr_compatible) + << lex->getType() << rex->getType() + << lex->getSourceRange() << rex->getSourceRange(); + return QualType(); + } + } else { + // Pointee types must be compatible C99 6.5.6p3 + if (!Context.typesAreCompatible( + Context.getCanonicalType(lpointee).getUnqualifiedType(), + Context.getCanonicalType(rpointee).getUnqualifiedType())) { + Diag(Loc, diag::err_typecheck_sub_ptr_compatible) + << lex->getType() << rex->getType() + << lex->getSourceRange() << rex->getSourceRange(); + return QualType(); + } + } + + if (ComplainAboutVoid) + Diag(Loc, diag::ext_gnu_void_ptr) + << lex->getSourceRange() << rex->getSourceRange(); + if (ComplainAboutFunc) + Diag(Loc, diag::ext_gnu_ptr_func_arith) + << ComplainAboutFunc->getType() + << ComplainAboutFunc->getSourceRange(); + + if (CompLHSTy) *CompLHSTy = lex->getType(); + return Context.getPointerDiffType(); + } + } + + return InvalidOperands(Loc, lex, rex); +} + +// C99 6.5.7 +QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, + bool isCompAssign) { + // C99 6.5.7p2: Each of the operands shall have integer type. + if (!lex->getType()->isIntegerType() || !rex->getType()->isIntegerType()) + return InvalidOperands(Loc, lex, rex); + + // Shifts don't perform usual arithmetic conversions, they just do integer + // promotions on each operand. C99 6.5.7p3 + QualType LHSTy; + if (lex->getType()->isPromotableIntegerType()) + LHSTy = Context.IntTy; + else { + LHSTy = isPromotableBitField(lex, Context); + if (LHSTy.isNull()) + LHSTy = lex->getType(); + } + if (!isCompAssign) + ImpCastExprToType(lex, LHSTy); + + UsualUnaryConversions(rex); + + // "The type of the result is that of the promoted left operand." + return LHSTy; +} + +// C99 6.5.8, C++ [expr.rel] +QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, + unsigned OpaqueOpc, bool isRelational) { + BinaryOperator::Opcode Opc = (BinaryOperator::Opcode)OpaqueOpc; + + if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) + return CheckVectorCompareOperands(lex, rex, Loc, isRelational); + + // C99 6.5.8p3 / C99 6.5.9p4 + if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) + UsualArithmeticConversions(lex, rex); + else { + UsualUnaryConversions(lex); + UsualUnaryConversions(rex); + } + QualType lType = lex->getType(); + QualType rType = rex->getType(); + + if (!lType->isFloatingType() + && !(lType->isBlockPointerType() && isRelational)) { + // For non-floating point types, check for self-comparisons of the form + // x == x, x != x, x < x, etc. These always evaluate to a constant, and + // often indicate logic errors in the program. + // NOTE: Don't warn about comparisons of enum constants. These can arise + // from macro expansions, and are usually quite deliberate. + Expr *LHSStripped = lex->IgnoreParens(); + Expr *RHSStripped = rex->IgnoreParens(); + if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(LHSStripped)) + if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RHSStripped)) + if (DRL->getDecl() == DRR->getDecl() && + !isa<EnumConstantDecl>(DRL->getDecl())) + Diag(Loc, diag::warn_selfcomparison); + + if (isa<CastExpr>(LHSStripped)) + LHSStripped = LHSStripped->IgnoreParenCasts(); + if (isa<CastExpr>(RHSStripped)) + RHSStripped = RHSStripped->IgnoreParenCasts(); + + // Warn about comparisons against a string constant (unless the other + // operand is null), the user probably wants strcmp. + Expr *literalString = 0; + Expr *literalStringStripped = 0; + if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) && + !RHSStripped->isNullPointerConstant(Context)) { + literalString = lex; + literalStringStripped = LHSStripped; + } + else if ((isa<StringLiteral>(RHSStripped) || + isa<ObjCEncodeExpr>(RHSStripped)) && + !LHSStripped->isNullPointerConstant(Context)) { + literalString = rex; + literalStringStripped = RHSStripped; + } + + if (literalString) { + std::string resultComparison; + switch (Opc) { + case BinaryOperator::LT: resultComparison = ") < 0"; break; + case BinaryOperator::GT: resultComparison = ") > 0"; break; + case BinaryOperator::LE: resultComparison = ") <= 0"; break; + case BinaryOperator::GE: resultComparison = ") >= 0"; break; + case BinaryOperator::EQ: resultComparison = ") == 0"; break; + case BinaryOperator::NE: resultComparison = ") != 0"; break; + default: assert(false && "Invalid comparison operator"); + } + Diag(Loc, diag::warn_stringcompare) + << isa<ObjCEncodeExpr>(literalStringStripped) + << literalString->getSourceRange() + << CodeModificationHint::CreateReplacement(SourceRange(Loc), ", ") + << CodeModificationHint::CreateInsertion(lex->getLocStart(), + "strcmp(") + << CodeModificationHint::CreateInsertion( + PP.getLocForEndOfToken(rex->getLocEnd()), + resultComparison); + } + } + + // The result of comparisons is 'bool' in C++, 'int' in C. + QualType ResultTy = getLangOptions().CPlusPlus? Context.BoolTy :Context.IntTy; + + if (isRelational) { + if (lType->isRealType() && rType->isRealType()) + return ResultTy; + } else { + // Check for comparisons of floating point operands using != and ==. + if (lType->isFloatingType()) { + assert(rType->isFloatingType()); + CheckFloatComparison(Loc,lex,rex); + } + + if (lType->isArithmeticType() && rType->isArithmeticType()) + return ResultTy; + } + + bool LHSIsNull = lex->isNullPointerConstant(Context); + bool RHSIsNull = rex->isNullPointerConstant(Context); + + // All of the following pointer related warnings are GCC extensions, except + // when handling null pointer constants. One day, we can consider making them + // errors (when -pedantic-errors is enabled). + if (lType->isPointerType() && rType->isPointerType()) { // C99 6.5.8p2 + QualType LCanPointeeTy = + Context.getCanonicalType(lType->getAsPointerType()->getPointeeType()); + QualType RCanPointeeTy = + Context.getCanonicalType(rType->getAsPointerType()->getPointeeType()); + + // Simple check: if the pointee types are identical, we're done. + if (LCanPointeeTy == RCanPointeeTy) + return ResultTy; + + if (getLangOptions().CPlusPlus) { + // C++ [expr.rel]p2: + // [...] Pointer conversions (4.10) and qualification + // conversions (4.4) are performed on pointer operands (or on + // a pointer operand and a null pointer constant) to bring + // them to their composite pointer type. [...] + // + // C++ [expr.eq]p2 uses the same notion for (in)equality + // comparisons of pointers. + QualType T = FindCompositePointerType(lex, rex); + if (T.isNull()) { + Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers) + << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + return QualType(); + } + + ImpCastExprToType(lex, T); + ImpCastExprToType(rex, T); + return ResultTy; + } + + if (!LHSIsNull && !RHSIsNull && // C99 6.5.9p2 + !LCanPointeeTy->isVoidType() && !RCanPointeeTy->isVoidType() && + !Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(), + RCanPointeeTy.getUnqualifiedType()) && + !Context.areComparableObjCPointerTypes(lType, rType)) { + Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) + << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + } + ImpCastExprToType(rex, lType); // promote the pointer to pointer + return ResultTy; + } + // C++ allows comparison of pointers with null pointer constants. + if (getLangOptions().CPlusPlus) { + if (lType->isPointerType() && RHSIsNull) { + ImpCastExprToType(rex, lType); + return ResultTy; + } + if (rType->isPointerType() && LHSIsNull) { + ImpCastExprToType(lex, rType); + return ResultTy; + } + // And comparison of nullptr_t with itself. + if (lType->isNullPtrType() && rType->isNullPtrType()) + return ResultTy; + } + // Handle block pointer types. + if (!isRelational && lType->isBlockPointerType() && rType->isBlockPointerType()) { + QualType lpointee = lType->getAsBlockPointerType()->getPointeeType(); + QualType rpointee = rType->getAsBlockPointerType()->getPointeeType(); + + if (!LHSIsNull && !RHSIsNull && + !Context.typesAreBlockCompatible(lpointee, rpointee)) { + Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks) + << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + } + ImpCastExprToType(rex, lType); // promote the pointer to pointer + return ResultTy; + } + // Allow block pointers to be compared with null pointer constants. + if (!isRelational + && ((lType->isBlockPointerType() && rType->isPointerType()) + || (lType->isPointerType() && rType->isBlockPointerType()))) { + if (!LHSIsNull && !RHSIsNull) { + if (!((rType->isPointerType() && rType->getAsPointerType() + ->getPointeeType()->isVoidType()) + || (lType->isPointerType() && lType->getAsPointerType() + ->getPointeeType()->isVoidType()))) + Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks) + << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + } + ImpCastExprToType(rex, lType); // promote the pointer to pointer + return ResultTy; + } + + if ((lType->isObjCQualifiedIdType() || rType->isObjCQualifiedIdType())) { + if (lType->isPointerType() || rType->isPointerType()) { + const PointerType *LPT = lType->getAsPointerType(); + const PointerType *RPT = rType->getAsPointerType(); + bool LPtrToVoid = LPT ? + Context.getCanonicalType(LPT->getPointeeType())->isVoidType() : false; + bool RPtrToVoid = RPT ? + Context.getCanonicalType(RPT->getPointeeType())->isVoidType() : false; + + if (!LPtrToVoid && !RPtrToVoid && + !Context.typesAreCompatible(lType, rType)) { + Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) + << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + ImpCastExprToType(rex, lType); + return ResultTy; + } + ImpCastExprToType(rex, lType); + return ResultTy; + } + if (ObjCQualifiedIdTypesAreCompatible(lType, rType, true)) { + ImpCastExprToType(rex, lType); + return ResultTy; + } else { + if ((lType->isObjCQualifiedIdType() && rType->isObjCQualifiedIdType())) { + Diag(Loc, diag::warn_incompatible_qualified_id_operands) + << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + ImpCastExprToType(rex, lType); + return ResultTy; + } + } + } + if ((lType->isPointerType() || lType->isObjCQualifiedIdType()) && + rType->isIntegerType()) { + if (!RHSIsNull) + Diag(Loc, diag::ext_typecheck_comparison_of_pointer_integer) + << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + ImpCastExprToType(rex, lType); // promote the integer to pointer + return ResultTy; + } + if (lType->isIntegerType() && + (rType->isPointerType() || rType->isObjCQualifiedIdType())) { + if (!LHSIsNull) + Diag(Loc, diag::ext_typecheck_comparison_of_pointer_integer) + << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + ImpCastExprToType(lex, rType); // promote the integer to pointer + return ResultTy; + } + // Handle block pointers. + if (!isRelational && RHSIsNull + && lType->isBlockPointerType() && rType->isIntegerType()) { + ImpCastExprToType(rex, lType); // promote the integer to pointer + return ResultTy; + } + if (!isRelational && LHSIsNull + && lType->isIntegerType() && rType->isBlockPointerType()) { + ImpCastExprToType(lex, rType); // promote the integer to pointer + return ResultTy; + } + return InvalidOperands(Loc, lex, rex); +} + +/// CheckVectorCompareOperands - vector comparisons are a clang extension that +/// operates on extended vector types. Instead of producing an IntTy result, +/// like a scalar comparison, a vector comparison produces a vector of integer +/// types. +QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex, + SourceLocation Loc, + bool isRelational) { + // Check to make sure we're operating on vectors of the same type and width, + // Allowing one side to be a scalar of element type. + QualType vType = CheckVectorOperands(Loc, lex, rex); + if (vType.isNull()) + return vType; + + QualType lType = lex->getType(); + QualType rType = rex->getType(); + + // For non-floating point types, check for self-comparisons of the form + // x == x, x != x, x < x, etc. These always evaluate to a constant, and + // often indicate logic errors in the program. + if (!lType->isFloatingType()) { + if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(lex->IgnoreParens())) + if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(rex->IgnoreParens())) + if (DRL->getDecl() == DRR->getDecl()) + Diag(Loc, diag::warn_selfcomparison); + } + + // Check for comparisons of floating point operands using != and ==. + if (!isRelational && lType->isFloatingType()) { + assert (rType->isFloatingType()); + CheckFloatComparison(Loc,lex,rex); + } + + // FIXME: Vector compare support in the LLVM backend is not fully reliable, + // just reject all vector comparisons for now. + if (1) { + Diag(Loc, diag::err_typecheck_vector_comparison) + << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + return QualType(); + } + + // Return the type for the comparison, which is the same as vector type for + // integer vectors, or an integer type of identical size and number of + // elements for floating point vectors. + if (lType->isIntegerType()) + return lType; + + const VectorType *VTy = lType->getAsVectorType(); + unsigned TypeSize = Context.getTypeSize(VTy->getElementType()); + if (TypeSize == Context.getTypeSize(Context.IntTy)) + return Context.getExtVectorType(Context.IntTy, VTy->getNumElements()); + if (TypeSize == Context.getTypeSize(Context.LongTy)) + return Context.getExtVectorType(Context.LongTy, VTy->getNumElements()); + + assert(TypeSize == Context.getTypeSize(Context.LongLongTy) && + "Unhandled vector element size in vector compare"); + return Context.getExtVectorType(Context.LongLongTy, VTy->getNumElements()); +} + +inline QualType Sema::CheckBitwiseOperands( + Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) +{ + if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) + return CheckVectorOperands(Loc, lex, rex); + + QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); + + if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType()) + return compType; + return InvalidOperands(Loc, lex, rex); +} + +inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] + Expr *&lex, Expr *&rex, SourceLocation Loc) +{ + UsualUnaryConversions(lex); + UsualUnaryConversions(rex); + + if (lex->getType()->isScalarType() && rex->getType()->isScalarType()) + return Context.IntTy; + return InvalidOperands(Loc, lex, rex); +} + +/// IsReadonlyProperty - Verify that otherwise a valid l-value expression +/// is a read-only property; return true if so. A readonly property expression +/// depends on various declarations and thus must be treated specially. +/// +static bool IsReadonlyProperty(Expr *E, Sema &S) +{ + if (E->getStmtClass() == Expr::ObjCPropertyRefExprClass) { + const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E); + if (ObjCPropertyDecl *PDecl = PropExpr->getProperty()) { + QualType BaseType = PropExpr->getBase()->getType(); + if (const PointerType *PTy = BaseType->getAsPointerType()) + if (const ObjCInterfaceType *IFTy = + PTy->getPointeeType()->getAsObjCInterfaceType()) + if (ObjCInterfaceDecl *IFace = IFTy->getDecl()) + if (S.isPropertyReadonly(PDecl, IFace)) + return true; + } + } + return false; +} + +/// CheckForModifiableLvalue - Verify that E is a modifiable lvalue. If not, +/// emit an error and return true. If so, return false. +static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { + SourceLocation OrigLoc = Loc; + Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(S.Context, + &Loc); + if (IsLV == Expr::MLV_Valid && IsReadonlyProperty(E, S)) + IsLV = Expr::MLV_ReadonlyProperty; + if (IsLV == Expr::MLV_Valid) + return false; + + 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; + NeedType = true; + break; + case Expr::MLV_NotObjectType: + Diag = diag::err_typecheck_non_object_not_modifiable_lvalue; + NeedType = true; + break; + case Expr::MLV_LValueCast: + Diag = diag::err_typecheck_lvalue_casts_not_supported; + break; + case Expr::MLV_InvalidExpression: + Diag = diag::err_typecheck_expression_not_modifiable_lvalue; + break; + case Expr::MLV_IncompleteType: + case Expr::MLV_IncompleteVoidType: + return S.RequireCompleteType(Loc, E->getType(), + diag::err_typecheck_incomplete_type_not_modifiable_lvalue, + E->getSourceRange()); + case Expr::MLV_DuplicateVectorComponents: + Diag = diag::err_typecheck_duplicate_vector_components_not_mlvalue; + break; + case Expr::MLV_NotBlockQualified: + Diag = diag::err_block_decl_ref_not_modifiable_lvalue; + break; + case Expr::MLV_ReadonlyProperty: + Diag = diag::error_readonly_property_assignment; + break; + case Expr::MLV_NoSetterProperty: + Diag = diag::error_nosetter_property_assignment; + break; + } + + SourceRange Assign; + if (Loc != OrigLoc) + Assign = SourceRange(OrigLoc, OrigLoc); + if (NeedType) + S.Diag(Loc, Diag) << E->getType() << E->getSourceRange() << Assign; + else + S.Diag(Loc, Diag) << E->getSourceRange() << Assign; + return true; +} + + + +// C99 6.5.16.1 +QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS, + SourceLocation Loc, + QualType CompoundType) { + // Verify that LHS is a modifiable lvalue, and emit error if not. + if (CheckForModifiableLvalue(LHS, Loc, *this)) + return QualType(); + + QualType LHSType = LHS->getType(); + QualType RHSType = CompoundType.isNull() ? RHS->getType() : CompoundType; + + AssignConvertType ConvTy; + if (CompoundType.isNull()) { + // Simple assignment "x = y". + ConvTy = CheckSingleAssignmentConstraints(LHSType, RHS); + // Special case of NSObject attributes on c-style pointer types. + if (ConvTy == IncompatiblePointer && + ((Context.isObjCNSObjectType(LHSType) && + Context.isObjCObjectPointerType(RHSType)) || + (Context.isObjCNSObjectType(RHSType) && + Context.isObjCObjectPointerType(LHSType)))) + ConvTy = Compatible; + + // If the RHS is a unary plus or minus, check to see if they = and + are + // right next to each other. If so, the user may have typo'd "x =+ 4" + // instead of "x += 4". + Expr *RHSCheck = RHS; + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(RHSCheck)) + RHSCheck = ICE->getSubExpr(); + if (UnaryOperator *UO = dyn_cast<UnaryOperator>(RHSCheck)) { + if ((UO->getOpcode() == UnaryOperator::Plus || + UO->getOpcode() == UnaryOperator::Minus) && + Loc.isFileID() && UO->getOperatorLoc().isFileID() && + // Only if the two operators are exactly adjacent. + Loc.getFileLocWithOffset(1) == UO->getOperatorLoc() && + // And there is a space or other character before the subexpr of the + // unary +/-. We don't want to warn on "x=-1". + Loc.getFileLocWithOffset(2) != UO->getSubExpr()->getLocStart() && + UO->getSubExpr()->getLocStart().isFileID()) { + Diag(Loc, diag::warn_not_compound_assign) + << (UO->getOpcode() == UnaryOperator::Plus ? "+" : "-") + << SourceRange(UO->getOperatorLoc(), UO->getOperatorLoc()); + } + } + } else { + // Compound assignment "x += y" + ConvTy = CheckAssignmentConstraints(LHSType, RHSType); + } + + if (DiagnoseAssignmentResult(ConvTy, Loc, LHSType, RHSType, + RHS, "assigning")) + return QualType(); + + // C99 6.5.16p3: The type of an assignment expression is the type of the + // left operand unless the left operand has qualified type, in which case + // it is the unqualified version of the type of the left operand. + // C99 6.5.16.1p2: In simple assignment, the value of the right operand + // is converted to the type of the assignment expression (above). + // C++ 5.17p1: the type of the assignment expression is that of its left + // operand. + return LHSType.getUnqualifiedType(); +} + +// C99 6.5.17 +QualType Sema::CheckCommaOperands(Expr *LHS, Expr *&RHS, SourceLocation Loc) { + // Comma performs lvalue conversion (C99 6.3.2.1), but not unary conversions. + DefaultFunctionArrayConversion(RHS); + + // FIXME: Check that RHS type is complete in C mode (it's legal for it to be + // incomplete in C++). + + return RHS->getType(); +} + +/// CheckIncrementDecrementOperand - unlike most "Check" methods, this routine +/// doesn't need to call UsualUnaryConversions or UsualArithmeticConversions. +QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, + bool isInc) { + if (Op->isTypeDependent()) + return Context.DependentTy; + + QualType ResType = Op->getType(); + assert(!ResType.isNull() && "no type for increment/decrement expression"); + + if (getLangOptions().CPlusPlus && ResType->isBooleanType()) { + // Decrement of bool is not allowed. + if (!isInc) { + Diag(OpLoc, diag::err_decrement_bool) << Op->getSourceRange(); + return QualType(); + } + // Increment of bool sets it to true, but is deprecated. + Diag(OpLoc, diag::warn_increment_bool) << Op->getSourceRange(); + } else if (ResType->isRealType()) { + // OK! + } else if (const PointerType *PT = ResType->getAsPointerType()) { + // C99 6.5.2.4p2, 6.5.6p2 + if (PT->getPointeeType()->isVoidType()) { + if (getLangOptions().CPlusPlus) { + Diag(OpLoc, diag::err_typecheck_pointer_arith_void_type) + << Op->getSourceRange(); + return QualType(); + } + + // Pointer to void is a GNU extension in C. + Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange(); + } else if (PT->getPointeeType()->isFunctionType()) { + if (getLangOptions().CPlusPlus) { + Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type) + << Op->getType() << Op->getSourceRange(); + return QualType(); + } + + Diag(OpLoc, diag::ext_gnu_ptr_func_arith) + << ResType << Op->getSourceRange(); + } else if (RequireCompleteType(OpLoc, PT->getPointeeType(), + diag::err_typecheck_arithmetic_incomplete_type, + Op->getSourceRange(), SourceRange(), + ResType)) + return QualType(); + } else if (ResType->isComplexType()) { + // C99 does not support ++/-- on complex types, we allow as an extension. + Diag(OpLoc, diag::ext_integer_increment_complex) + << ResType << Op->getSourceRange(); + } else { + Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement) + << ResType << Op->getSourceRange(); + return QualType(); + } + // At this point, we know we have a real, complex or pointer type. + // Now make sure the operand is a modifiable lvalue. + if (CheckForModifiableLvalue(Op, OpLoc, *this)) + return QualType(); + return ResType; +} + +/// getPrimaryDecl - Helper function for CheckAddressOfOperand(). +/// This routine allows us to typecheck complex/recursive expressions +/// where the declaration is needed for type checking. We only need to +/// handle cases when the expression references a function designator +/// or is an lvalue. Here are some examples: +/// - &(x) => x +/// - &*****f => f for f a function designator. +/// - &s.xx => s +/// - &s.zz[1].yy -> s, if zz is an array +/// - *(x + 1) -> x, if x is an array +/// - &"123"[2] -> 0 +/// - & __real__ x -> x +static NamedDecl *getPrimaryDecl(Expr *E) { + switch (E->getStmtClass()) { + case Stmt::DeclRefExprClass: + case Stmt::QualifiedDeclRefExprClass: + return cast<DeclRefExpr>(E)->getDecl(); + case Stmt::MemberExprClass: + // If this is an arrow operator, the address is an offset from + // the base's value, so the object the base refers to is + // irrelevant. + if (cast<MemberExpr>(E)->isArrow()) + return 0; + // Otherwise, the expression refers to a part of the base + return getPrimaryDecl(cast<MemberExpr>(E)->getBase()); + case Stmt::ArraySubscriptExprClass: { + // FIXME: This code shouldn't be necessary! We should catch the implicit + // promotion of register arrays earlier. + Expr* Base = cast<ArraySubscriptExpr>(E)->getBase(); + if (ImplicitCastExpr* ICE = dyn_cast<ImplicitCastExpr>(Base)) { + if (ICE->getSubExpr()->getType()->isArrayType()) + return getPrimaryDecl(ICE->getSubExpr()); + } + return 0; + } + case Stmt::UnaryOperatorClass: { + UnaryOperator *UO = cast<UnaryOperator>(E); + + switch(UO->getOpcode()) { + case UnaryOperator::Real: + case UnaryOperator::Imag: + case UnaryOperator::Extension: + return getPrimaryDecl(UO->getSubExpr()); + default: + return 0; + } + } + case Stmt::ParenExprClass: + return getPrimaryDecl(cast<ParenExpr>(E)->getSubExpr()); + case Stmt::ImplicitCastExprClass: + // If the result of an implicit cast is an l-value, we care about + // the sub-expression; otherwise, the result here doesn't matter. + return getPrimaryDecl(cast<ImplicitCastExpr>(E)->getSubExpr()); + default: + return 0; + } +} + +/// CheckAddressOfOperand - The operand of & must be either a function +/// designator or an lvalue designating an object. If it is an lvalue, the +/// object cannot be declared with storage class register or be a bit field. +/// Note: The usual conversions are *not* applied to the operand of the & +/// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue. +/// In C++, the operand might be an overloaded function name, in which case +/// we allow the '&' but retain the overloaded-function type. +QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { + // Make sure to ignore parentheses in subsequent checks + op = op->IgnoreParens(); + + if (op->isTypeDependent()) + return Context.DependentTy; + + if (getLangOptions().C99) { + // Implement C99-only parts of addressof rules. + if (UnaryOperator* uOp = dyn_cast<UnaryOperator>(op)) { + if (uOp->getOpcode() == UnaryOperator::Deref) + // Per C99 6.5.3.2, the address of a deref always returns a valid result + // (assuming the deref expression is valid). + return uOp->getSubExpr()->getType(); + } + // Technically, there should be a check for array subscript + // expressions here, but the result of one is always an lvalue anyway. + } + NamedDecl *dcl = getPrimaryDecl(op); + Expr::isLvalueResult lval = op->isLvalue(Context); + + if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) { + // C99 6.5.3.2p1 + // The operand must be either an l-value or a function designator + if (!op->getType()->isFunctionType()) { + // FIXME: emit more specific diag... + Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof) + << op->getSourceRange(); + return QualType(); + } + } else if (op->getBitField()) { // C99 6.5.3.2p1 + // The operand cannot be a bit-field + Diag(OpLoc, diag::err_typecheck_address_of) + << "bit-field" << op->getSourceRange(); + return QualType(); + } else if (isa<ExtVectorElementExpr>(op) || (isa<ArraySubscriptExpr>(op) && + cast<ArraySubscriptExpr>(op)->getBase()->getType()->isVectorType())){ + // The operand cannot be an element of a vector + Diag(OpLoc, diag::err_typecheck_address_of) + << "vector element" << op->getSourceRange(); + return QualType(); + } else if (dcl) { // C99 6.5.3.2p1 + // We have an lvalue with a decl. Make sure the decl is not declared + // with the register storage-class specifier. + if (const VarDecl *vd = dyn_cast<VarDecl>(dcl)) { + if (vd->getStorageClass() == VarDecl::Register) { + Diag(OpLoc, diag::err_typecheck_address_of) + << "register variable" << op->getSourceRange(); + return QualType(); + } + } else if (isa<OverloadedFunctionDecl>(dcl)) { + return Context.OverloadTy; + } else if (isa<FieldDecl>(dcl)) { + // Okay: we can take the address of a field. + // Could be a pointer to member, though, if there is an explicit + // scope qualifier for the class. + if (isa<QualifiedDeclRefExpr>(op)) { + DeclContext *Ctx = dcl->getDeclContext(); + if (Ctx && Ctx->isRecord()) + return Context.getMemberPointerType(op->getType(), + Context.getTypeDeclType(cast<RecordDecl>(Ctx)).getTypePtr()); + } + } else if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(dcl)) { + // Okay: we can take the address of a function. + // As above. + if (isa<QualifiedDeclRefExpr>(op) && MD->isInstance()) + return Context.getMemberPointerType(op->getType(), + Context.getTypeDeclType(MD->getParent()).getTypePtr()); + } else if (!isa<FunctionDecl>(dcl)) + assert(0 && "Unknown/unexpected decl type"); + } + + if (lval == Expr::LV_IncompleteVoidType) { + // Taking the address of a void variable is technically illegal, but we + // allow it in cases which are otherwise valid. + // Example: "extern void x; void* y = &x;". + Diag(OpLoc, diag::ext_typecheck_addrof_void) << op->getSourceRange(); + } + + // If the operand has type "type", the result has type "pointer to type". + return Context.getPointerType(op->getType()); +} + +QualType Sema::CheckIndirectionOperand(Expr *Op, SourceLocation OpLoc) { + if (Op->isTypeDependent()) + return Context.DependentTy; + + UsualUnaryConversions(Op); + QualType Ty = Op->getType(); + + // Note that per both C89 and C99, this is always legal, even if ptype is an + // incomplete type or void. It would be possible to warn about dereferencing + // a void pointer, but it's completely well-defined, and such a warning is + // unlikely to catch any mistakes. + if (const PointerType *PT = Ty->getAsPointerType()) + return PT->getPointeeType(); + + Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer) + << Ty << Op->getSourceRange(); + return QualType(); +} + +static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode( + tok::TokenKind Kind) { + BinaryOperator::Opcode Opc; + switch (Kind) { + default: assert(0 && "Unknown binop!"); + case tok::periodstar: Opc = BinaryOperator::PtrMemD; break; + case tok::arrowstar: Opc = BinaryOperator::PtrMemI; break; + case tok::star: Opc = BinaryOperator::Mul; break; + case tok::slash: Opc = BinaryOperator::Div; break; + case tok::percent: Opc = BinaryOperator::Rem; break; + case tok::plus: Opc = BinaryOperator::Add; break; + case tok::minus: Opc = BinaryOperator::Sub; break; + case tok::lessless: Opc = BinaryOperator::Shl; break; + case tok::greatergreater: Opc = BinaryOperator::Shr; break; + case tok::lessequal: Opc = BinaryOperator::LE; break; + case tok::less: Opc = BinaryOperator::LT; break; + case tok::greaterequal: Opc = BinaryOperator::GE; break; + case tok::greater: Opc = BinaryOperator::GT; break; + case tok::exclaimequal: Opc = BinaryOperator::NE; break; + case tok::equalequal: Opc = BinaryOperator::EQ; break; + case tok::amp: Opc = BinaryOperator::And; break; + case tok::caret: Opc = BinaryOperator::Xor; break; + case tok::pipe: Opc = BinaryOperator::Or; break; + case tok::ampamp: Opc = BinaryOperator::LAnd; break; + case tok::pipepipe: Opc = BinaryOperator::LOr; break; + case tok::equal: Opc = BinaryOperator::Assign; break; + case tok::starequal: Opc = BinaryOperator::MulAssign; break; + case tok::slashequal: Opc = BinaryOperator::DivAssign; break; + case tok::percentequal: Opc = BinaryOperator::RemAssign; break; + case tok::plusequal: Opc = BinaryOperator::AddAssign; break; + case tok::minusequal: Opc = BinaryOperator::SubAssign; break; + case tok::lesslessequal: Opc = BinaryOperator::ShlAssign; break; + case tok::greatergreaterequal: Opc = BinaryOperator::ShrAssign; break; + case tok::ampequal: Opc = BinaryOperator::AndAssign; break; + case tok::caretequal: Opc = BinaryOperator::XorAssign; break; + case tok::pipeequal: Opc = BinaryOperator::OrAssign; break; + case tok::comma: Opc = BinaryOperator::Comma; break; + } + return Opc; +} + +static inline UnaryOperator::Opcode ConvertTokenKindToUnaryOpcode( + tok::TokenKind Kind) { + UnaryOperator::Opcode Opc; + switch (Kind) { + default: assert(0 && "Unknown unary op!"); + case tok::plusplus: Opc = UnaryOperator::PreInc; break; + case tok::minusminus: Opc = UnaryOperator::PreDec; break; + case tok::amp: Opc = UnaryOperator::AddrOf; break; + case tok::star: Opc = UnaryOperator::Deref; break; + case tok::plus: Opc = UnaryOperator::Plus; break; + case tok::minus: Opc = UnaryOperator::Minus; break; + case tok::tilde: Opc = UnaryOperator::Not; break; + case tok::exclaim: Opc = UnaryOperator::LNot; break; + case tok::kw___real: Opc = UnaryOperator::Real; break; + case tok::kw___imag: Opc = UnaryOperator::Imag; break; + case tok::kw___extension__: Opc = UnaryOperator::Extension; break; + } + return Opc; +} + +/// CreateBuiltinBinOp - Creates a new built-in binary operation with +/// operator @p Opc at location @c TokLoc. This routine only supports +/// built-in operations; ActOnBinOp handles overloaded operators. +Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, + unsigned Op, + Expr *lhs, Expr *rhs) { + QualType ResultTy; // Result type of the binary operator. + BinaryOperator::Opcode Opc = (BinaryOperator::Opcode)Op; + // The following two variables are used for compound assignment operators + QualType CompLHSTy; // Type of LHS after promotions for computation + QualType CompResultTy; // Type of computation result + + switch (Opc) { + case BinaryOperator::Assign: + ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, QualType()); + break; + case BinaryOperator::PtrMemD: + case BinaryOperator::PtrMemI: + ResultTy = CheckPointerToMemberOperands(lhs, rhs, OpLoc, + Opc == BinaryOperator::PtrMemI); + break; + case BinaryOperator::Mul: + case BinaryOperator::Div: + ResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc); + break; + case BinaryOperator::Rem: + ResultTy = CheckRemainderOperands(lhs, rhs, OpLoc); + break; + case BinaryOperator::Add: + ResultTy = CheckAdditionOperands(lhs, rhs, OpLoc); + break; + case BinaryOperator::Sub: + ResultTy = CheckSubtractionOperands(lhs, rhs, OpLoc); + break; + case BinaryOperator::Shl: + case BinaryOperator::Shr: + ResultTy = CheckShiftOperands(lhs, rhs, OpLoc); + break; + case BinaryOperator::LE: + case BinaryOperator::LT: + case BinaryOperator::GE: + case BinaryOperator::GT: + ResultTy = CheckCompareOperands(lhs, rhs, OpLoc, Opc, true); + break; + case BinaryOperator::EQ: + case BinaryOperator::NE: + ResultTy = CheckCompareOperands(lhs, rhs, OpLoc, Opc, false); + break; + case BinaryOperator::And: + case BinaryOperator::Xor: + case BinaryOperator::Or: + ResultTy = CheckBitwiseOperands(lhs, rhs, OpLoc); + break; + case BinaryOperator::LAnd: + case BinaryOperator::LOr: + ResultTy = CheckLogicalOperands(lhs, rhs, OpLoc); + break; + case BinaryOperator::MulAssign: + case BinaryOperator::DivAssign: + CompResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true); + CompLHSTy = CompResultTy; + if (!CompResultTy.isNull()) + ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); + break; + case BinaryOperator::RemAssign: + CompResultTy = CheckRemainderOperands(lhs, rhs, OpLoc, true); + CompLHSTy = CompResultTy; + if (!CompResultTy.isNull()) + ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); + break; + case BinaryOperator::AddAssign: + CompResultTy = CheckAdditionOperands(lhs, rhs, OpLoc, &CompLHSTy); + if (!CompResultTy.isNull()) + ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); + break; + case BinaryOperator::SubAssign: + CompResultTy = CheckSubtractionOperands(lhs, rhs, OpLoc, &CompLHSTy); + if (!CompResultTy.isNull()) + ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); + break; + case BinaryOperator::ShlAssign: + case BinaryOperator::ShrAssign: + CompResultTy = CheckShiftOperands(lhs, rhs, OpLoc, true); + CompLHSTy = CompResultTy; + if (!CompResultTy.isNull()) + ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); + break; + case BinaryOperator::AndAssign: + case BinaryOperator::XorAssign: + case BinaryOperator::OrAssign: + CompResultTy = CheckBitwiseOperands(lhs, rhs, OpLoc, true); + CompLHSTy = CompResultTy; + if (!CompResultTy.isNull()) + ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); + break; + case BinaryOperator::Comma: + ResultTy = CheckCommaOperands(lhs, rhs, OpLoc); + break; + } + if (ResultTy.isNull()) + return ExprError(); + if (CompResultTy.isNull()) + return Owned(new (Context) BinaryOperator(lhs, rhs, Opc, ResultTy, OpLoc)); + else + return Owned(new (Context) CompoundAssignOperator(lhs, rhs, Opc, ResultTy, + CompLHSTy, CompResultTy, + OpLoc)); +} + +// Binary Operators. 'Tok' is the token for the operator. +Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, + tok::TokenKind Kind, + ExprArg LHS, ExprArg RHS) { + BinaryOperator::Opcode Opc = ConvertTokenKindToBinaryOpcode(Kind); + Expr *lhs = LHS.takeAs<Expr>(), *rhs = RHS.takeAs<Expr>(); + + assert((lhs != 0) && "ActOnBinOp(): missing left expression"); + assert((rhs != 0) && "ActOnBinOp(): missing right expression"); + + if (getLangOptions().CPlusPlus && + (lhs->getType()->isOverloadableType() || + rhs->getType()->isOverloadableType())) { + // Find all of the overloaded operators visible from this + // point. We perform both an operator-name lookup from the local + // scope and an argument-dependent lookup based on the types of + // the arguments. + FunctionSet Functions; + OverloadedOperatorKind OverOp = BinaryOperator::getOverloadedOperator(Opc); + if (OverOp != OO_None) { + LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(), + Functions); + Expr *Args[2] = { lhs, rhs }; + DeclarationName OpName + = Context.DeclarationNames.getCXXOperatorName(OverOp); + ArgumentDependentLookup(OpName, Args, 2, Functions); + } + + // Build the (potentially-overloaded, potentially-dependent) + // binary operation. + return CreateOverloadedBinOp(TokLoc, Opc, Functions, lhs, rhs); + } + + // Build a built-in binary operation. + return CreateBuiltinBinOp(TokLoc, Opc, lhs, rhs); +} + +Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, + unsigned OpcIn, + ExprArg InputArg) { + UnaryOperator::Opcode Opc = static_cast<UnaryOperator::Opcode>(OpcIn); + + // FIXME: Input is modified below, but InputArg is not updated appropriately. + Expr *Input = (Expr *)InputArg.get(); + QualType resultType; + switch (Opc) { + case UnaryOperator::PostInc: + case UnaryOperator::PostDec: + case UnaryOperator::OffsetOf: + assert(false && "Invalid unary operator"); + break; + + case UnaryOperator::PreInc: + case UnaryOperator::PreDec: + resultType = CheckIncrementDecrementOperand(Input, OpLoc, + Opc == UnaryOperator::PreInc); + break; + case UnaryOperator::AddrOf: + resultType = CheckAddressOfOperand(Input, OpLoc); + break; + case UnaryOperator::Deref: + DefaultFunctionArrayConversion(Input); + resultType = CheckIndirectionOperand(Input, OpLoc); + break; + case UnaryOperator::Plus: + case UnaryOperator::Minus: + UsualUnaryConversions(Input); + resultType = Input->getType(); + if (resultType->isDependentType()) + break; + if (resultType->isArithmeticType()) // C99 6.5.3.3p1 + break; + else if (getLangOptions().CPlusPlus && // C++ [expr.unary.op]p6-7 + resultType->isEnumeralType()) + break; + else if (getLangOptions().CPlusPlus && // C++ [expr.unary.op]p6 + Opc == UnaryOperator::Plus && + resultType->isPointerType()) + break; + + return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) + << resultType << Input->getSourceRange()); + case UnaryOperator::Not: // bitwise complement + UsualUnaryConversions(Input); + resultType = Input->getType(); + if (resultType->isDependentType()) + break; + // C99 6.5.3.3p1. We allow complex int and float as a GCC extension. + if (resultType->isComplexType() || resultType->isComplexIntegerType()) + // C99 does not support '~' for complex conjugation. + Diag(OpLoc, diag::ext_integer_complement_complex) + << resultType << Input->getSourceRange(); + else if (!resultType->isIntegerType()) + return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) + << resultType << Input->getSourceRange()); + break; + case UnaryOperator::LNot: // logical negation + // Unlike +/-/~, integer promotions aren't done here (C99 6.5.3.3p5). + DefaultFunctionArrayConversion(Input); + resultType = Input->getType(); + if (resultType->isDependentType()) + break; + if (!resultType->isScalarType()) // C99 6.5.3.3p1 + return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) + << resultType << Input->getSourceRange()); + // LNot always has type int. C99 6.5.3.3p5. + // In C++, it's bool. C++ 5.3.1p8 + resultType = getLangOptions().CPlusPlus ? Context.BoolTy : Context.IntTy; + break; + case UnaryOperator::Real: + case UnaryOperator::Imag: + resultType = CheckRealImagOperand(Input, OpLoc, Opc == UnaryOperator::Real); + break; + case UnaryOperator::Extension: + resultType = Input->getType(); + break; + } + if (resultType.isNull()) + return ExprError(); + + InputArg.release(); + return Owned(new (Context) UnaryOperator(Input, Opc, resultType, OpLoc)); +} + +// Unary Operators. 'Tok' is the token for the operator. +Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, + tok::TokenKind Op, ExprArg input) { + Expr *Input = (Expr*)input.get(); + UnaryOperator::Opcode Opc = ConvertTokenKindToUnaryOpcode(Op); + + if (getLangOptions().CPlusPlus && Input->getType()->isOverloadableType()) { + // Find all of the overloaded operators visible from this + // point. We perform both an operator-name lookup from the local + // scope and an argument-dependent lookup based on the types of + // the arguments. + FunctionSet Functions; + OverloadedOperatorKind OverOp = UnaryOperator::getOverloadedOperator(Opc); + if (OverOp != OO_None) { + LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(), + Functions); + DeclarationName OpName + = Context.DeclarationNames.getCXXOperatorName(OverOp); + ArgumentDependentLookup(OpName, &Input, 1, Functions); + } + + return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(input)); + } + + return CreateBuiltinUnaryOp(OpLoc, Opc, move(input)); +} + +/// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". +Sema::OwningExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, + SourceLocation LabLoc, + IdentifierInfo *LabelII) { + // Look up the record for this label identifier. + LabelStmt *&LabelDecl = getLabelMap()[LabelII]; + + // If we haven't seen this label yet, create a forward reference. It + // will be validated and/or cleaned up in ActOnFinishFunctionBody. + if (LabelDecl == 0) + LabelDecl = new (Context) LabelStmt(LabLoc, LabelII, 0); + + // Create the AST node. The address of a label always has type 'void*'. + return Owned(new (Context) AddrLabelExpr(OpLoc, LabLoc, LabelDecl, + Context.getPointerType(Context.VoidTy))); +} + +Sema::OwningExprResult +Sema::ActOnStmtExpr(SourceLocation LPLoc, StmtArg substmt, + SourceLocation RPLoc) { // "({..})" + Stmt *SubStmt = static_cast<Stmt*>(substmt.get()); + assert(SubStmt && isa<CompoundStmt>(SubStmt) && "Invalid action invocation!"); + CompoundStmt *Compound = cast<CompoundStmt>(SubStmt); + + bool isFileScope = getCurFunctionOrMethodDecl() == 0; + if (isFileScope) + return ExprError(Diag(LPLoc, diag::err_stmtexpr_file_scope)); + + // FIXME: there are a variety of strange constraints to enforce here, for + // example, it is not possible to goto into a stmt expression apparently. + // More semantic analysis is needed. + + // If there are sub stmts in the compound stmt, take the type of the last one + // as the type of the stmtexpr. + QualType Ty = Context.VoidTy; + + if (!Compound->body_empty()) { + Stmt *LastStmt = Compound->body_back(); + // If LastStmt is a label, skip down through into the body. + while (LabelStmt *Label = dyn_cast<LabelStmt>(LastStmt)) + LastStmt = Label->getSubStmt(); + + if (Expr *LastExpr = dyn_cast<Expr>(LastStmt)) + Ty = LastExpr->getType(); + } + + // FIXME: Check that expression type is complete/non-abstract; statement + // expressions are not lvalues. + + substmt.release(); + return Owned(new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc)); +} + +Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, + SourceLocation BuiltinLoc, + SourceLocation TypeLoc, + TypeTy *argty, + OffsetOfComponent *CompPtr, + unsigned NumComponents, + SourceLocation RPLoc) { + // FIXME: This function leaks all expressions in the offset components on + // error. + QualType ArgTy = QualType::getFromOpaquePtr(argty); + assert(!ArgTy.isNull() && "Missing type argument!"); + + bool Dependent = ArgTy->isDependentType(); + + // We must have at least one component that refers to the type, and the first + // one is known to be a field designator. Verify that the ArgTy represents + // a struct/union/class. + if (!Dependent && !ArgTy->isRecordType()) + return ExprError(Diag(TypeLoc, diag::err_offsetof_record_type) << ArgTy); + + // FIXME: Type must be complete per C99 7.17p3 because a declaring a variable + // with an incomplete type would be illegal. + + // Otherwise, create a null pointer as the base, and iteratively process + // the offsetof designators. + QualType ArgTyPtr = Context.getPointerType(ArgTy); + Expr* Res = new (Context) ImplicitValueInitExpr(ArgTyPtr); + Res = new (Context) UnaryOperator(Res, UnaryOperator::Deref, + ArgTy, SourceLocation()); + + // offsetof with non-identifier designators (e.g. "offsetof(x, a.b[c])") are a + // GCC extension, diagnose them. + // FIXME: This diagnostic isn't actually visible because the location is in + // a system header! + if (NumComponents != 1) + Diag(BuiltinLoc, diag::ext_offsetof_extended_field_designator) + << SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd); + + if (!Dependent) { + bool DidWarnAboutNonPOD = false; + + // FIXME: Dependent case loses a lot of information here. And probably + // leaks like a sieve. + for (unsigned i = 0; i != NumComponents; ++i) { + const OffsetOfComponent &OC = CompPtr[i]; + if (OC.isBrackets) { + // Offset of an array sub-field. TODO: Should we allow vector elements? + const ArrayType *AT = Context.getAsArrayType(Res->getType()); + if (!AT) { + Res->Destroy(Context); + return ExprError(Diag(OC.LocEnd, diag::err_offsetof_array_type) + << Res->getType()); + } + + // FIXME: C++: Verify that operator[] isn't overloaded. + + // Promote the array so it looks more like a normal array subscript + // expression. + DefaultFunctionArrayConversion(Res); + + // C99 6.5.2.1p1 + Expr *Idx = static_cast<Expr*>(OC.U.E); + // FIXME: Leaks Res + if (!Idx->isTypeDependent() && !Idx->getType()->isIntegerType()) + return ExprError(Diag(Idx->getLocStart(), + diag::err_typecheck_subscript_not_integer) + << Idx->getSourceRange()); + + Res = new (Context) ArraySubscriptExpr(Res, Idx, AT->getElementType(), + OC.LocEnd); + continue; + } + + const RecordType *RC = Res->getType()->getAsRecordType(); + if (!RC) { + Res->Destroy(Context); + return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type) + << Res->getType()); + } + + // Get the decl corresponding to this. + RecordDecl *RD = RC->getDecl(); + if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) { + if (!CRD->isPOD() && !DidWarnAboutNonPOD) { + ExprError(Diag(BuiltinLoc, diag::warn_offsetof_non_pod_type) + << SourceRange(CompPtr[0].LocStart, OC.LocEnd) + << Res->getType()); + DidWarnAboutNonPOD = true; + } + } + + FieldDecl *MemberDecl + = dyn_cast_or_null<FieldDecl>(LookupQualifiedName(RD, OC.U.IdentInfo, + LookupMemberName) + .getAsDecl()); + // FIXME: Leaks Res + if (!MemberDecl) + return ExprError(Diag(BuiltinLoc, diag::err_typecheck_no_member) + << OC.U.IdentInfo << SourceRange(OC.LocStart, OC.LocEnd)); + + // FIXME: C++: Verify that MemberDecl isn't a static field. + // FIXME: Verify that MemberDecl isn't a bitfield. + if (cast<RecordDecl>(MemberDecl->getDeclContext())->isAnonymousStructOrUnion()) { + Res = BuildAnonymousStructUnionMemberReference( + SourceLocation(), MemberDecl, Res, SourceLocation()).takeAs<Expr>(); + } else { + // MemberDecl->getType() doesn't get the right qualifiers, but it + // doesn't matter here. + Res = new (Context) MemberExpr(Res, false, MemberDecl, OC.LocEnd, + MemberDecl->getType().getNonReferenceType()); + } + } + } + + return Owned(new (Context) UnaryOperator(Res, UnaryOperator::OffsetOf, + Context.getSizeType(), BuiltinLoc)); +} + + +Sema::OwningExprResult Sema::ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc, + TypeTy *arg1,TypeTy *arg2, + SourceLocation RPLoc) { + QualType argT1 = QualType::getFromOpaquePtr(arg1); + QualType argT2 = QualType::getFromOpaquePtr(arg2); + + assert((!argT1.isNull() && !argT2.isNull()) && "Missing type argument(s)"); + + if (getLangOptions().CPlusPlus) { + Diag(BuiltinLoc, diag::err_types_compatible_p_in_cplusplus) + << SourceRange(BuiltinLoc, RPLoc); + return ExprError(); + } + + return Owned(new (Context) TypesCompatibleExpr(Context.IntTy, BuiltinLoc, + argT1, argT2, RPLoc)); +} + +Sema::OwningExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, + ExprArg cond, + ExprArg expr1, ExprArg expr2, + SourceLocation RPLoc) { + Expr *CondExpr = static_cast<Expr*>(cond.get()); + Expr *LHSExpr = static_cast<Expr*>(expr1.get()); + Expr *RHSExpr = static_cast<Expr*>(expr2.get()); + + assert((CondExpr && LHSExpr && RHSExpr) && "Missing type argument(s)"); + + QualType resType; + if (CondExpr->isTypeDependent() || CondExpr->isValueDependent()) { + resType = Context.DependentTy; + } else { + // The conditional expression is required to be a constant expression. + llvm::APSInt condEval(32); + SourceLocation ExpLoc; + if (!CondExpr->isIntegerConstantExpr(condEval, Context, &ExpLoc)) + return ExprError(Diag(ExpLoc, + diag::err_typecheck_choose_expr_requires_constant) + << CondExpr->getSourceRange()); + + // If the condition is > zero, then the AST type is the same as the LSHExpr. + resType = condEval.getZExtValue() ? LHSExpr->getType() : RHSExpr->getType(); + } + + cond.release(); expr1.release(); expr2.release(); + return Owned(new (Context) ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr, + resType, RPLoc)); +} + +//===----------------------------------------------------------------------===// +// Clang Extensions. +//===----------------------------------------------------------------------===// + +/// 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 = 0; + BSI->TheScope = BlockScope; + BSI->hasBlockDeclRefExprs = false; + BSI->SavedFunctionNeedsScopeChecking = CurFunctionNeedsScopeChecking; + CurFunctionNeedsScopeChecking = false; + + BSI->TheDecl = BlockDecl::Create(Context, CurContext, CaretLoc); + PushDeclContext(BlockScope, BSI->TheDecl); +} + +void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { + assert(ParamInfo.getIdentifier()==0 && "block-id should have no identifier!"); + + if (ParamInfo.getNumTypeObjects() == 0 + || ParamInfo.getTypeObject(0).Kind != DeclaratorChunk::Function) { + ProcessDeclAttributes(CurBlock->TheDecl, ParamInfo); + QualType T = GetTypeForDeclarator(ParamInfo, CurScope); + + if (T->isArrayType()) { + Diag(ParamInfo.getSourceRange().getBegin(), + diag::err_block_returns_array); + return; + } + + // The parameter list is optional, if there was none, assume (). + if (!T->isFunctionType()) + T = Context.getFunctionType(T, NULL, 0, 0, 0); + + CurBlock->hasPrototype = true; + CurBlock->isVariadic = false; + // Check for a valid sentinel attribute on this block. + if (CurBlock->TheDecl->getAttr<SentinelAttr>()) { + Diag(ParamInfo.getAttributes()->getLoc(), + diag::warn_attribute_sentinel_not_variadic) << 1; + // FIXME: remove the attribute. + } + QualType RetTy = T.getTypePtr()->getAsFunctionType()->getResultType(); + + // Do not allow returning a objc interface by-value. + if (RetTy->isObjCInterfaceType()) { + Diag(ParamInfo.getSourceRange().getBegin(), + diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy; + return; + } + return; + } + + // Analyze arguments to block. + assert(ParamInfo.getTypeObject(0).Kind == DeclaratorChunk::Function && + "Not a function declarator!"); + DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getTypeObject(0).Fun; + + CurBlock->hasPrototype = FTI.hasPrototype; + CurBlock->isVariadic = true; + + // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs function that takes + // no arguments, not a function that takes a single void argument. + if (FTI.hasPrototype && + FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 && + (!FTI.ArgInfo[0].Param.getAs<ParmVarDecl>()->getType().getCVRQualifiers()&& + FTI.ArgInfo[0].Param.getAs<ParmVarDecl>()->getType()->isVoidType())) { + // empty arg list, don't push any params. + CurBlock->isVariadic = false; + } else if (FTI.hasPrototype) { + for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) + CurBlock->Params.push_back(FTI.ArgInfo[i].Param.getAs<ParmVarDecl>()); + CurBlock->isVariadic = FTI.isVariadic; + } + CurBlock->TheDecl->setParams(Context, CurBlock->Params.data(), + CurBlock->Params.size()); + CurBlock->TheDecl->setIsVariadic(CurBlock->isVariadic); + ProcessDeclAttributes(CurBlock->TheDecl, ParamInfo); + for (BlockDecl::param_iterator AI = CurBlock->TheDecl->param_begin(), + E = CurBlock->TheDecl->param_end(); AI != E; ++AI) + // If this has an identifier, add it to the scope stack. + if ((*AI)->getIdentifier()) + PushOnScopeChains(*AI, CurBlock->TheScope); + + // Check for a valid sentinel attribute on this block. + if (!CurBlock->isVariadic && CurBlock->TheDecl->getAttr<SentinelAttr>()) { + Diag(ParamInfo.getAttributes()->getLoc(), + diag::warn_attribute_sentinel_not_variadic) << 1; + // FIXME: remove the attribute. + } + + // Analyze the return type. + QualType T = GetTypeForDeclarator(ParamInfo, CurScope); + QualType RetTy = T->getAsFunctionType()->getResultType(); + + // Do not allow returning a objc interface by-value. + if (RetTy->isObjCInterfaceType()) { + Diag(ParamInfo.getSourceRange().getBegin(), + diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy; + } else if (!RetTy->isDependentType()) + CurBlock->ReturnType = RetTy.getTypePtr(); +} + +/// 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; + // FIXME: Delete the ParmVarDecl objects as well??? +} + +/// ActOnBlockStmtExpr - This is called when the body of a block statement +/// literal was successfully completed. ^(int x){...} +Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, + StmtArg body, Scope *CurScope) { + // If blocks are disabled, emit an error. + if (!LangOpts.Blocks) + Diag(CaretLoc, diag::err_blocks_disable); + + // Ensure that CurBlock is deleted. + llvm::OwningPtr<BlockSemaInfo> BSI(CurBlock); + + PopDeclContext(); + + // Pop off CurBlock, handle nested blocks. + CurBlock = CurBlock->PrevBlockInfo; + + QualType RetTy = Context.VoidTy; + if (BSI->ReturnType) + RetTy = QualType(BSI->ReturnType, 0); + + llvm::SmallVector<QualType, 8> ArgTypes; + for (unsigned i = 0, e = BSI->Params.size(); i != e; ++i) + ArgTypes.push_back(BSI->Params[i]->getType()); + + QualType BlockTy; + if (!BSI->hasPrototype) + BlockTy = Context.getFunctionNoProtoType(RetTy); + else + BlockTy = Context.getFunctionType(RetTy, ArgTypes.data(), ArgTypes.size(), + BSI->isVariadic, 0); + + // FIXME: Check that return/parameter types are complete/non-abstract + + BlockTy = Context.getBlockPointerType(BlockTy); + + // If needed, diagnose invalid gotos and switches in the block. + if (CurFunctionNeedsScopeChecking) + DiagnoseInvalidJumps(static_cast<CompoundStmt*>(body.get())); + CurFunctionNeedsScopeChecking = BSI->SavedFunctionNeedsScopeChecking; + + BSI->TheDecl->setBody(body.takeAs<CompoundStmt>()); + return Owned(new (Context) BlockExpr(BSI->TheDecl, BlockTy, + BSI->hasBlockDeclRefExprs)); +} + +Sema::OwningExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc, + ExprArg expr, TypeTy *type, + SourceLocation RPLoc) { + QualType T = QualType::getFromOpaquePtr(type); + Expr *E = static_cast<Expr*>(expr.get()); + Expr *OrigExpr = E; + + InitBuiltinVaListType(); + + // Get the va_list type + QualType VaListType = Context.getBuiltinVaListType(); + if (VaListType->isArrayType()) { + // Deal with implicit array decay; for example, on x86-64, + // va_list is an array, but it's supposed to decay to + // a pointer for va_arg. + VaListType = Context.getArrayDecayedType(VaListType); + // Make sure the input expression also decays appropriately. + UsualUnaryConversions(E); + } else { + // Otherwise, the va_list argument must be an l-value because + // it is modified by va_arg. + if (!E->isTypeDependent() && + CheckForModifiableLvalue(E, BuiltinLoc, *this)) + return ExprError(); + } + + if (!E->isTypeDependent() && + !Context.hasSameType(VaListType, E->getType())) { + return ExprError(Diag(E->getLocStart(), + diag::err_first_argument_to_va_arg_not_of_type_va_list) + << OrigExpr->getType() << E->getSourceRange()); + } + + // FIXME: Check that type is complete/non-abstract + // FIXME: Warn if a non-POD type is passed in. + + expr.release(); + return Owned(new (Context) VAArgExpr(BuiltinLoc, E, T.getNonReferenceType(), + RPLoc)); +} + +Sema::OwningExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) { + // The type of __null will be int or long, depending on the size of + // pointers on the target. + QualType Ty; + if (Context.Target.getPointerWidth(0) == Context.Target.getIntWidth()) + Ty = Context.IntTy; + else + Ty = Context.LongTy; + + return Owned(new (Context) GNUNullExpr(Ty, TokenLoc)); +} + +bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, + SourceLocation Loc, + QualType DstType, QualType SrcType, + Expr *SrcExpr, const char *Flavor) { + // Decode the result (notice that AST's are still created for extensions). + bool isInvalid = false; + unsigned DiagKind; + switch (ConvTy) { + default: assert(0 && "Unknown conversion type"); + case Compatible: return false; + case PointerToInt: + DiagKind = diag::ext_typecheck_convert_pointer_int; + break; + case IntToPointer: + DiagKind = diag::ext_typecheck_convert_int_pointer; + break; + case IncompatiblePointer: + DiagKind = diag::ext_typecheck_convert_incompatible_pointer; + break; + case IncompatiblePointerSign: + DiagKind = diag::ext_typecheck_convert_incompatible_pointer_sign; + break; + case FunctionVoidPointer: + DiagKind = diag::ext_typecheck_convert_pointer_void_func; + break; + case CompatiblePointerDiscardsQualifiers: + // If the qualifiers lost were because we were applying the + // (deprecated) C++ conversion from a string literal to a char* + // (or wchar_t*), then there was no error (C++ 4.2p2). FIXME: + // Ideally, this check would be performed in + // CheckPointerTypesForAssignment. However, that would require a + // bit of refactoring (so that the second argument is an + // expression, rather than a type), which should be done as part + // of a larger effort to fix CheckPointerTypesForAssignment for + // C++ semantics. + if (getLangOptions().CPlusPlus && + IsStringLiteralToNonConstPointerConversion(SrcExpr, DstType)) + return false; + DiagKind = diag::ext_typecheck_convert_discards_qualifiers; + break; + case IntToBlockPointer: + DiagKind = diag::err_int_to_block_pointer; + break; + case IncompatibleBlockPointer: + DiagKind = diag::err_typecheck_convert_incompatible_block_pointer; + break; + case IncompatibleObjCQualifiedId: + // FIXME: Diagnose the problem in ObjCQualifiedIdTypesAreCompatible, since + // it can give a more specific diagnostic. + DiagKind = diag::warn_incompatible_qualified_id; + break; + case IncompatibleVectors: + DiagKind = diag::warn_incompatible_vectors; + break; + case Incompatible: + DiagKind = diag::err_typecheck_convert_incompatible; + isInvalid = true; + break; + } + + Diag(Loc, DiagKind) << DstType << SrcType << Flavor + << SrcExpr->getSourceRange(); + return isInvalid; +} + +bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){ + llvm::APSInt ICEResult; + if (E->isIntegerConstantExpr(ICEResult, Context)) { + if (Result) + *Result = ICEResult; + return false; + } + + Expr::EvalResult EvalResult; + + if (!E->Evaluate(EvalResult, Context) || !EvalResult.Val.isInt() || + EvalResult.HasSideEffects) { + Diag(E->getExprLoc(), diag::err_expr_not_ice) << E->getSourceRange(); + + if (EvalResult.Diag) { + // We only show the note if it's not the usual "invalid subexpression" + // or if it's actually in a subexpression. + if (EvalResult.Diag != diag::note_invalid_subexpr_in_ice || + E->IgnoreParens() != EvalResult.DiagExpr->IgnoreParens()) + Diag(EvalResult.DiagLoc, EvalResult.Diag); + } + + return true; + } + + Diag(E->getExprLoc(), diag::ext_expr_not_ice) << + E->getSourceRange(); + + if (EvalResult.Diag && + Diags.getDiagnosticLevel(diag::ext_expr_not_ice) != Diagnostic::Ignored) + Diag(EvalResult.DiagLoc, EvalResult.Diag); + + if (Result) + *Result = EvalResult.Val.getInt(); + return false; +} diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp new file mode 100644 index 0000000..65018da --- /dev/null +++ b/lib/Sema/SemaExprCXX.cpp @@ -0,0 +1,1603 @@ +//===--- SemaExprCXX.cpp - Semantic Analysis for Expressions --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for C++ expressions. +// +//===----------------------------------------------------------------------===// + +#include "SemaInherit.h" +#include "Sema.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ASTContext.h" +#include "clang/Parse/DeclSpec.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/STLExtras.h" +using namespace clang; + +/// ActOnCXXConversionFunctionExpr - Parse a C++ conversion function +/// name (e.g., operator void const *) as an expression. This is +/// very similar to ActOnIdentifierExpr, except that instead of +/// providing an identifier the parser provides the type of the +/// conversion function. +Sema::OwningExprResult +Sema::ActOnCXXConversionFunctionExpr(Scope *S, SourceLocation OperatorLoc, + TypeTy *Ty, bool HasTrailingLParen, + const CXXScopeSpec &SS, + bool isAddressOfOperand) { + QualType ConvType = QualType::getFromOpaquePtr(Ty); + QualType ConvTypeCanon = Context.getCanonicalType(ConvType); + DeclarationName ConvName + = Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon); + return ActOnDeclarationNameExpr(S, OperatorLoc, ConvName, HasTrailingLParen, + &SS, isAddressOfOperand); +} + +/// ActOnCXXOperatorFunctionIdExpr - Parse a C++ overloaded operator +/// name (e.g., @c operator+ ) as an expression. This is very +/// similar to ActOnIdentifierExpr, except that instead of providing +/// an identifier the parser provides the kind of overloaded +/// operator that was parsed. +Sema::OwningExprResult +Sema::ActOnCXXOperatorFunctionIdExpr(Scope *S, SourceLocation OperatorLoc, + OverloadedOperatorKind Op, + bool HasTrailingLParen, + const CXXScopeSpec &SS, + bool isAddressOfOperand) { + DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(Op); + return ActOnDeclarationNameExpr(S, OperatorLoc, Name, HasTrailingLParen, &SS, + isAddressOfOperand); +} + +/// ActOnCXXTypeidOfType - Parse typeid( type-id ). +Action::OwningExprResult +Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, + bool isType, void *TyOrExpr, SourceLocation RParenLoc) { + NamespaceDecl *StdNs = GetStdNamespace(); + if (!StdNs) + return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); + + IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info"); + Decl *TypeInfoDecl = LookupQualifiedName(StdNs, TypeInfoII, LookupTagName); + RecordDecl *TypeInfoRecordDecl = dyn_cast_or_null<RecordDecl>(TypeInfoDecl); + if (!TypeInfoRecordDecl) + return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); + + QualType TypeInfoType = Context.getTypeDeclType(TypeInfoRecordDecl); + + return Owned(new (Context) CXXTypeidExpr(isType, TyOrExpr, + TypeInfoType.withConst(), + SourceRange(OpLoc, RParenLoc))); +} + +/// ActOnCXXBoolLiteral - Parse {true,false} literals. +Action::OwningExprResult +Sema::ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) { + assert((Kind == tok::kw_true || Kind == tok::kw_false) && + "Unknown C++ Boolean value!"); + return Owned(new (Context) CXXBoolLiteralExpr(Kind == tok::kw_true, + Context.BoolTy, OpLoc)); +} + +/// ActOnCXXNullPtrLiteral - Parse 'nullptr'. +Action::OwningExprResult +Sema::ActOnCXXNullPtrLiteral(SourceLocation Loc) { + return Owned(new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc)); +} + +/// ActOnCXXThrow - Parse throw expressions. +Action::OwningExprResult +Sema::ActOnCXXThrow(SourceLocation OpLoc, ExprArg E) { + Expr *Ex = E.takeAs<Expr>(); + if (Ex && !Ex->isTypeDependent() && CheckCXXThrowOperand(OpLoc, Ex)) + return ExprError(); + return Owned(new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc)); +} + +/// CheckCXXThrowOperand - Validate the operand of a throw. +bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { + // C++ [except.throw]p3: + // [...] adjusting the type from "array of T" or "function returning T" + // to "pointer to T" or "pointer to function returning T", [...] + DefaultFunctionArrayConversion(E); + + // If the type of the exception would be an incomplete type or a pointer + // to an incomplete type other than (cv) void the program is ill-formed. + QualType Ty = E->getType(); + int isPointer = 0; + if (const PointerType* Ptr = Ty->getAsPointerType()) { + Ty = Ptr->getPointeeType(); + isPointer = 1; + } + if (!isPointer || !Ty->isVoidType()) { + if (RequireCompleteType(ThrowLoc, Ty, + isPointer ? diag::err_throw_incomplete_ptr + : diag::err_throw_incomplete, + E->getSourceRange(), SourceRange(), QualType())) + return true; + } + + // FIXME: Construct a temporary here. + return false; +} + +Action::OwningExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) { + /// C++ 9.3.2: In the body of a non-static member function, the keyword this + /// is a non-lvalue expression whose value is the address of the object for + /// which the function is called. + + if (!isa<FunctionDecl>(CurContext)) + return ExprError(Diag(ThisLoc, diag::err_invalid_this_use)); + + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) + if (MD->isInstance()) + return Owned(new (Context) CXXThisExpr(ThisLoc, + MD->getThisType(Context))); + + return ExprError(Diag(ThisLoc, diag::err_invalid_this_use)); +} + +/// ActOnCXXTypeConstructExpr - Parse construction of a specified type. +/// Can be interpreted either as function-style casting ("int(x)") +/// or class type construction ("ClassType(x,y,z)") +/// or creation of a value-initialized type ("int()"). +Action::OwningExprResult +Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, + SourceLocation LParenLoc, + MultiExprArg exprs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc) { + assert(TypeRep && "Missing type!"); + QualType Ty = QualType::getFromOpaquePtr(TypeRep); + unsigned NumExprs = exprs.size(); + Expr **Exprs = (Expr**)exprs.get(); + SourceLocation TyBeginLoc = TypeRange.getBegin(); + SourceRange FullRange = SourceRange(TyBeginLoc, RParenLoc); + + if (Ty->isDependentType() || + CallExpr::hasAnyTypeDependentArguments(Exprs, NumExprs)) { + exprs.release(); + + return Owned(CXXUnresolvedConstructExpr::Create(Context, + TypeRange.getBegin(), Ty, + LParenLoc, + Exprs, NumExprs, + RParenLoc)); + } + + + // C++ [expr.type.conv]p1: + // If the expression list is a single expression, the type conversion + // expression is equivalent (in definedness, and if defined in meaning) to the + // corresponding cast expression. + // + if (NumExprs == 1) { + if (CheckCastTypes(TypeRange, Ty, Exprs[0])) + return ExprError(); + exprs.release(); + return Owned(new (Context) CXXFunctionalCastExpr(Ty.getNonReferenceType(), + Ty, TyBeginLoc, Exprs[0], + RParenLoc)); + } + + if (const RecordType *RT = Ty->getAsRecordType()) { + CXXRecordDecl *Record = cast<CXXRecordDecl>(RT->getDecl()); + + // FIXME: We should always create a CXXTemporaryObjectExpr here unless + // both the ctor and dtor are trivial. + if (NumExprs > 1 || Record->hasUserDeclaredConstructor()) { + CXXConstructorDecl *Constructor + = PerformInitializationByConstructor(Ty, Exprs, NumExprs, + TypeRange.getBegin(), + SourceRange(TypeRange.getBegin(), + RParenLoc), + DeclarationName(), + IK_Direct); + + if (!Constructor) + return ExprError(); + + exprs.release(); + Expr *E = new (Context) CXXTemporaryObjectExpr(Context, Constructor, + Ty, TyBeginLoc, Exprs, + NumExprs, RParenLoc); + return MaybeBindToTemporary(E); + } + + // Fall through to value-initialize an object of class type that + // doesn't have a user-declared default constructor. + } + + // C++ [expr.type.conv]p1: + // If the expression list specifies more than a single value, the type shall + // be a class with a suitably declared constructor. + // + if (NumExprs > 1) + return ExprError(Diag(CommaLocs[0], + diag::err_builtin_func_cast_more_than_one_arg) + << FullRange); + + assert(NumExprs == 0 && "Expected 0 expressions"); + + // C++ [expr.type.conv]p2: + // The expression T(), where T is a simple-type-specifier for a non-array + // complete object type or the (possibly cv-qualified) void type, creates an + // rvalue of the specified type, which is value-initialized. + // + if (Ty->isArrayType()) + return ExprError(Diag(TyBeginLoc, + diag::err_value_init_for_array_type) << FullRange); + if (!Ty->isDependentType() && !Ty->isVoidType() && + RequireCompleteType(TyBeginLoc, Ty, + diag::err_invalid_incomplete_type_use, FullRange)) + return ExprError(); + + if (RequireNonAbstractType(TyBeginLoc, Ty, + diag::err_allocation_of_abstract_type)) + return ExprError(); + + exprs.release(); + return Owned(new (Context) CXXZeroInitValueExpr(Ty, TyBeginLoc, RParenLoc)); +} + + +/// ActOnCXXNew - Parsed a C++ 'new' expression (C++ 5.3.4), as in e.g.: +/// @code new (memory) int[size][4] @endcode +/// or +/// @code ::new Foo(23, "hello") @endcode +/// For the interpretation of this heap of arguments, consult the base version. +Action::OwningExprResult +Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, + SourceLocation PlacementLParen, MultiExprArg PlacementArgs, + SourceLocation PlacementRParen, bool ParenTypeId, + Declarator &D, SourceLocation ConstructorLParen, + MultiExprArg ConstructorArgs, + SourceLocation ConstructorRParen) +{ + Expr *ArraySize = 0; + unsigned Skip = 0; + // If the specified type is an array, unwrap it and save the expression. + if (D.getNumTypeObjects() > 0 && + D.getTypeObject(0).Kind == DeclaratorChunk::Array) { + DeclaratorChunk &Chunk = D.getTypeObject(0); + if (Chunk.Arr.hasStatic) + return ExprError(Diag(Chunk.Loc, diag::err_static_illegal_in_new) + << D.getSourceRange()); + if (!Chunk.Arr.NumElts) + return ExprError(Diag(Chunk.Loc, diag::err_array_new_needs_size) + << D.getSourceRange()); + ArraySize = static_cast<Expr*>(Chunk.Arr.NumElts); + Skip = 1; + } + + QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, Skip); + if (D.isInvalidType()) + return ExprError(); + + // Every dimension shall be of constant size. + unsigned i = 1; + QualType ElementType = AllocType; + while (const ArrayType *Array = Context.getAsArrayType(ElementType)) { + if (!Array->isConstantArrayType()) { + Diag(D.getTypeObject(i).Loc, diag::err_new_array_nonconst) + << static_cast<Expr*>(D.getTypeObject(i).Arr.NumElts)->getSourceRange(); + return ExprError(); + } + ElementType = Array->getElementType(); + ++i; + } + + return BuildCXXNew(StartLoc, UseGlobal, + PlacementLParen, + move(PlacementArgs), + PlacementRParen, + ParenTypeId, + AllocType, + D.getSourceRange().getBegin(), + D.getSourceRange(), + Owned(ArraySize), + ConstructorLParen, + move(ConstructorArgs), + ConstructorRParen); +} + +Sema::OwningExprResult +Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, + SourceLocation PlacementLParen, + MultiExprArg PlacementArgs, + SourceLocation PlacementRParen, + bool ParenTypeId, + QualType AllocType, + SourceLocation TypeLoc, + SourceRange TypeRange, + ExprArg ArraySizeE, + SourceLocation ConstructorLParen, + MultiExprArg ConstructorArgs, + SourceLocation ConstructorRParen) { + if (CheckAllocatedType(AllocType, TypeLoc, TypeRange)) + return ExprError(); + + QualType ResultType = Context.getPointerType(AllocType); + + // That every array dimension except the first is constant was already + // checked by the type check above. + + // C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral + // or enumeration type with a non-negative value." + Expr *ArraySize = (Expr *)ArraySizeE.get(); + if (ArraySize && !ArraySize->isTypeDependent()) { + QualType SizeType = ArraySize->getType(); + if (!SizeType->isIntegralType() && !SizeType->isEnumeralType()) + return ExprError(Diag(ArraySize->getSourceRange().getBegin(), + diag::err_array_size_not_integral) + << SizeType << ArraySize->getSourceRange()); + // Let's see if this is a constant < 0. If so, we reject it out of hand. + // We don't care about special rules, so we tell the machinery it's not + // evaluated - it gives us a result in more cases. + if (!ArraySize->isValueDependent()) { + llvm::APSInt Value; + if (ArraySize->isIntegerConstantExpr(Value, Context, 0, false)) { + if (Value < llvm::APSInt( + llvm::APInt::getNullValue(Value.getBitWidth()), false)) + return ExprError(Diag(ArraySize->getSourceRange().getBegin(), + diag::err_typecheck_negative_array_size) + << ArraySize->getSourceRange()); + } + } + } + + FunctionDecl *OperatorNew = 0; + FunctionDecl *OperatorDelete = 0; + Expr **PlaceArgs = (Expr**)PlacementArgs.get(); + unsigned NumPlaceArgs = PlacementArgs.size(); + if (!AllocType->isDependentType() && + !Expr::hasAnyTypeDependentArguments(PlaceArgs, NumPlaceArgs) && + FindAllocationFunctions(StartLoc, + SourceRange(PlacementLParen, PlacementRParen), + UseGlobal, AllocType, ArraySize, PlaceArgs, + NumPlaceArgs, OperatorNew, OperatorDelete)) + return ExprError(); + + bool Init = ConstructorLParen.isValid(); + // --- Choosing a constructor --- + // C++ 5.3.4p15 + // 1) If T is a POD and there's no initializer (ConstructorLParen is invalid) + // the object is not initialized. If the object, or any part of it, is + // const-qualified, it's an error. + // 2) If T is a POD and there's an empty initializer, the object is value- + // initialized. + // 3) If T is a POD and there's one initializer argument, the object is copy- + // constructed. + // 4) If T is a POD and there's more initializer arguments, it's an error. + // 5) If T is not a POD, the initializer arguments are used as constructor + // arguments. + // + // Or by the C++0x formulation: + // 1) If there's no initializer, the object is default-initialized according + // to C++0x rules. + // 2) Otherwise, the object is direct-initialized. + CXXConstructorDecl *Constructor = 0; + Expr **ConsArgs = (Expr**)ConstructorArgs.get(); + const RecordType *RT; + unsigned NumConsArgs = ConstructorArgs.size(); + if (AllocType->isDependentType()) { + // Skip all the checks. + } + else if ((RT = AllocType->getAsRecordType()) && + !AllocType->isAggregateType()) { + Constructor = PerformInitializationByConstructor( + AllocType, ConsArgs, NumConsArgs, + TypeLoc, + SourceRange(TypeLoc, ConstructorRParen), + RT->getDecl()->getDeclName(), + NumConsArgs != 0 ? IK_Direct : IK_Default); + if (!Constructor) + return ExprError(); + } else { + if (!Init) { + // FIXME: Check that no subpart is const. + if (AllocType.isConstQualified()) + return ExprError(Diag(StartLoc, diag::err_new_uninitialized_const) + << TypeRange); + } else if (NumConsArgs == 0) { + // Object is value-initialized. Do nothing. + } else if (NumConsArgs == 1) { + // Object is direct-initialized. + // FIXME: What DeclarationName do we pass in here? + if (CheckInitializerTypes(ConsArgs[0], AllocType, StartLoc, + DeclarationName() /*AllocType.getAsString()*/, + /*DirectInit=*/true)) + return ExprError(); + } else { + return ExprError(Diag(StartLoc, + diag::err_builtin_direct_init_more_than_one_arg) + << SourceRange(ConstructorLParen, ConstructorRParen)); + } + } + + // FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16) + + PlacementArgs.release(); + ConstructorArgs.release(); + ArraySizeE.release(); + return Owned(new (Context) CXXNewExpr(UseGlobal, OperatorNew, PlaceArgs, + NumPlaceArgs, ParenTypeId, ArraySize, Constructor, Init, + ConsArgs, NumConsArgs, OperatorDelete, ResultType, + StartLoc, Init ? ConstructorRParen : SourceLocation())); +} + +/// CheckAllocatedType - Checks that a type is suitable as the allocated type +/// in a new-expression. +/// dimension off and stores the size expression in ArraySize. +bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, + SourceRange R) +{ + // C++ 5.3.4p1: "[The] type shall be a complete object type, but not an + // abstract class type or array thereof. + if (AllocType->isFunctionType()) + return Diag(Loc, diag::err_bad_new_type) + << AllocType << 0 << R; + else if (AllocType->isReferenceType()) + return Diag(Loc, diag::err_bad_new_type) + << AllocType << 1 << R; + else if (!AllocType->isDependentType() && + RequireCompleteType(Loc, AllocType, + diag::err_new_incomplete_type, + R)) + return true; + else if (RequireNonAbstractType(Loc, AllocType, + diag::err_allocation_of_abstract_type)) + return true; + + return false; +} + +/// FindAllocationFunctions - Finds the overloads of operator new and delete +/// that are appropriate for the allocation. +bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, + bool UseGlobal, QualType AllocType, + bool IsArray, Expr **PlaceArgs, + unsigned NumPlaceArgs, + FunctionDecl *&OperatorNew, + FunctionDecl *&OperatorDelete) +{ + // --- Choosing an allocation function --- + // C++ 5.3.4p8 - 14 & 18 + // 1) If UseGlobal is true, only look in the global scope. Else, also look + // in the scope of the allocated class. + // 2) If an array size is given, look for operator new[], else look for + // 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. + // FIXME: Should the Sema create the expression and embed it in the syntax + // tree? Or should the consumer just recalculate the value? + AllocArgs[0] = new (Context) IntegerLiteral(llvm::APInt::getNullValue( + Context.Target.getPointerWidth(0)), + Context.getSizeType(), + SourceLocation()); + std::copy(PlaceArgs, PlaceArgs + NumPlaceArgs, AllocArgs.begin() + 1); + + DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName( + IsArray ? OO_Array_New : OO_New); + if (AllocType->isRecordType() && !UseGlobal) { + CXXRecordDecl *Record + = cast<CXXRecordDecl>(AllocType->getAsRecordType()->getDecl()); + // FIXME: We fail to find inherited overloads. + if (FindAllocationOverload(StartLoc, Range, NewName, &AllocArgs[0], + AllocArgs.size(), Record, /*AllowMissing=*/true, + OperatorNew)) + return true; + } + if (!OperatorNew) { + // Didn't find a member overload. Look for a global one. + DeclareGlobalNewDelete(); + DeclContext *TUDecl = Context.getTranslationUnitDecl(); + if (FindAllocationOverload(StartLoc, Range, NewName, &AllocArgs[0], + AllocArgs.size(), TUDecl, /*AllowMissing=*/false, + OperatorNew)) + return true; + } + + // FindAllocationOverload can change the passed in arguments, so we need to + // copy them back. + if (NumPlaceArgs > 0) + std::copy(&AllocArgs[1], AllocArgs.end(), PlaceArgs); + + // FIXME: This is leaked on error. But so much is currently in Sema that it's + // easier to clean it in one go. + AllocArgs[0]->Destroy(Context); + return false; +} + +/// FindAllocationOverload - Find an fitting overload for the allocation +/// function in the specified scope. +bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, + DeclarationName Name, Expr** Args, + unsigned NumArgs, DeclContext *Ctx, + bool AllowMissing, FunctionDecl *&Operator) +{ + DeclContext::lookup_iterator Alloc, AllocEnd; + llvm::tie(Alloc, AllocEnd) = Ctx->lookup(Context, Name); + if (Alloc == AllocEnd) { + if (AllowMissing) + return false; + return Diag(StartLoc, diag::err_ovl_no_viable_function_in_call) + << Name << Range; + } + + OverloadCandidateSet Candidates; + for (; Alloc != AllocEnd; ++Alloc) { + // Even member operator new/delete are implicitly treated as + // static, so don't use AddMemberCandidate. + if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(*Alloc)) + AddOverloadCandidate(Fn, Args, NumArgs, Candidates, + /*SuppressUserConversions=*/false); + } + + // Do the resolution. + OverloadCandidateSet::iterator Best; + switch(BestViableFunction(Candidates, Best)) { + case OR_Success: { + // Got one! + FunctionDecl *FnDecl = Best->Function; + // The first argument is size_t, and the first parameter must be size_t, + // too. This is checked on declaration and can be assumed. (It can't be + // asserted on, though, since invalid decls are left in there.) + for (unsigned i = 1; i < NumArgs; ++i) { + // FIXME: Passing word to diagnostic. + if (PerformCopyInitialization(Args[i], + FnDecl->getParamDecl(i)->getType(), + "passing")) + return true; + } + Operator = FnDecl; + return false; + } + + case OR_No_Viable_Function: + Diag(StartLoc, diag::err_ovl_no_viable_function_in_call) + << Name << Range; + PrintOverloadCandidates(Candidates, /*OnlyViable=*/false); + return true; + + case OR_Ambiguous: + Diag(StartLoc, diag::err_ovl_ambiguous_call) + << Name << Range; + PrintOverloadCandidates(Candidates, /*OnlyViable=*/true); + return true; + + case OR_Deleted: + Diag(StartLoc, diag::err_ovl_deleted_call) + << Best->Function->isDeleted() + << Name << Range; + PrintOverloadCandidates(Candidates, /*OnlyViable=*/true); + return true; + } + assert(false && "Unreachable, bad result from BestViableFunction"); + return true; +} + + +/// DeclareGlobalNewDelete - Declare the global forms of operator new and +/// delete. These are: +/// @code +/// void* operator new(std::size_t) throw(std::bad_alloc); +/// void* operator new[](std::size_t) throw(std::bad_alloc); +/// void operator delete(void *) throw(); +/// void operator delete[](void *) throw(); +/// @endcode +/// Note that the placement and nothrow forms of new are *not* implicitly +/// declared. Their use requires including \<new\>. +void Sema::DeclareGlobalNewDelete() +{ + if (GlobalNewDeleteDeclared) + return; + GlobalNewDeleteDeclared = true; + + QualType VoidPtr = Context.getPointerType(Context.VoidTy); + QualType SizeT = Context.getSizeType(); + + // FIXME: Exception specifications are not added. + DeclareGlobalAllocationFunction( + Context.DeclarationNames.getCXXOperatorName(OO_New), + VoidPtr, SizeT); + DeclareGlobalAllocationFunction( + Context.DeclarationNames.getCXXOperatorName(OO_Array_New), + VoidPtr, SizeT); + DeclareGlobalAllocationFunction( + Context.DeclarationNames.getCXXOperatorName(OO_Delete), + Context.VoidTy, VoidPtr); + DeclareGlobalAllocationFunction( + Context.DeclarationNames.getCXXOperatorName(OO_Array_Delete), + Context.VoidTy, VoidPtr); +} + +/// DeclareGlobalAllocationFunction - Declares a single implicit global +/// allocation function if it doesn't already exist. +void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, + QualType Return, QualType Argument) +{ + DeclContext *GlobalCtx = Context.getTranslationUnitDecl(); + + // Check if this function is already declared. + { + DeclContext::lookup_iterator Alloc, AllocEnd; + for (llvm::tie(Alloc, AllocEnd) = GlobalCtx->lookup(Context, Name); + Alloc != AllocEnd; ++Alloc) { + // FIXME: Do we need to check for default arguments here? + FunctionDecl *Func = cast<FunctionDecl>(*Alloc); + if (Func->getNumParams() == 1 && + Context.getCanonicalType(Func->getParamDecl(0)->getType())==Argument) + return; + } + } + + QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0); + FunctionDecl *Alloc = + FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name, + FnType, FunctionDecl::None, false, true, + SourceLocation()); + Alloc->setImplicit(); + ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(), + 0, Argument, VarDecl::None, 0); + Alloc->setParams(Context, &Param, 1); + + // FIXME: Also add this declaration to the IdentifierResolver, but + // make sure it is at the end of the chain to coincide with the + // global scope. + ((DeclContext *)TUScope->getEntity())->addDecl(Context, Alloc); +} + +/// ActOnCXXDelete - Parsed a C++ 'delete' expression (C++ 5.3.5), as in: +/// @code ::delete ptr; @endcode +/// or +/// @code delete [] ptr; @endcode +Action::OwningExprResult +Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, + bool ArrayForm, ExprArg Operand) +{ + // C++ 5.3.5p1: "The operand shall have a pointer type, or a class type + // having a single conversion function to a pointer type. The result has + // type void." + // DR599 amends "pointer type" to "pointer to object type" in both cases. + + Expr *Ex = (Expr *)Operand.get(); + if (!Ex->isTypeDependent()) { + QualType Type = Ex->getType(); + + if (Type->isRecordType()) { + // FIXME: Find that one conversion function and amend the type. + } + + if (!Type->isPointerType()) + return ExprError(Diag(StartLoc, diag::err_delete_operand) + << Type << Ex->getSourceRange()); + + QualType Pointee = Type->getAsPointerType()->getPointeeType(); + if (Pointee->isFunctionType() || Pointee->isVoidType()) + return ExprError(Diag(StartLoc, diag::err_delete_operand) + << Type << Ex->getSourceRange()); + else if (!Pointee->isDependentType() && + RequireCompleteType(StartLoc, Pointee, + diag::warn_delete_incomplete, + Ex->getSourceRange())) + return ExprError(); + + // FIXME: Look up the correct operator delete overload and pass a pointer + // along. + // FIXME: Check access and ambiguity of operator delete and destructor. + } + + Operand.release(); + return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm, + 0, Ex, StartLoc)); +} + + +/// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a +/// C++ if/switch/while/for statement. +/// e.g: "if (int x = f()) {...}" +Action::OwningExprResult +Sema::ActOnCXXConditionDeclarationExpr(Scope *S, SourceLocation StartLoc, + Declarator &D, + SourceLocation EqualLoc, + ExprArg AssignExprVal) { + assert(AssignExprVal.get() && "Null assignment expression"); + + // C++ 6.4p2: + // The declarator shall not specify a function or an array. + // The type-specifier-seq shall not contain typedef and shall not declare a + // new class or enumeration. + + assert(D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && + "Parser allowed 'typedef' as storage class of condition decl."); + + QualType Ty = GetTypeForDeclarator(D, S); + + if (Ty->isFunctionType()) { // The declarator shall not specify a function... + // We exit without creating a CXXConditionDeclExpr because a FunctionDecl + // would be created and CXXConditionDeclExpr wants a VarDecl. + return ExprError(Diag(StartLoc, diag::err_invalid_use_of_function_type) + << SourceRange(StartLoc, EqualLoc)); + } else if (Ty->isArrayType()) { // ...or an array. + Diag(StartLoc, diag::err_invalid_use_of_array_type) + << SourceRange(StartLoc, EqualLoc); + } else if (const RecordType *RT = Ty->getAsRecordType()) { + RecordDecl *RD = RT->getDecl(); + // The type-specifier-seq shall not declare a new class... + if (RD->isDefinition() && + (RD->getIdentifier() == 0 || S->isDeclScope(DeclPtrTy::make(RD)))) + Diag(RD->getLocation(), diag::err_type_defined_in_condition); + } else if (const EnumType *ET = Ty->getAsEnumType()) { + EnumDecl *ED = ET->getDecl(); + // ...or enumeration. + if (ED->isDefinition() && + (ED->getIdentifier() == 0 || S->isDeclScope(DeclPtrTy::make(ED)))) + Diag(ED->getLocation(), diag::err_type_defined_in_condition); + } + + DeclPtrTy Dcl = ActOnDeclarator(S, D, DeclPtrTy()); + if (!Dcl) + return ExprError(); + AddInitializerToDecl(Dcl, move(AssignExprVal), /*DirectInit=*/false); + + // Mark this variable as one that is declared within a conditional. + // We know that the decl had to be a VarDecl because that is the only type of + // decl that can be assigned and the grammar requires an '='. + VarDecl *VD = cast<VarDecl>(Dcl.getAs<Decl>()); + VD->setDeclaredInCondition(true); + return Owned(new (Context) CXXConditionDeclExpr(StartLoc, EqualLoc, VD)); +} + +/// CheckCXXBooleanCondition - Returns true if a conversion to bool is invalid. +bool Sema::CheckCXXBooleanCondition(Expr *&CondExpr) { + // C++ 6.4p4: + // The value of a condition that is an initialized declaration in a statement + // other than a switch statement is the value of the declared variable + // implicitly converted to type bool. If that conversion is ill-formed, the + // program is ill-formed. + // The value of a condition that is an expression is the value of the + // expression, implicitly converted to bool. + // + return PerformContextuallyConvertToBool(CondExpr); +} + +/// Helper function to determine whether this is the (deprecated) C++ +/// conversion from a string literal to a pointer to non-const char or +/// non-const wchar_t (for narrow and wide string literals, +/// respectively). +bool +Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) { + // Look inside the implicit cast, if it exists. + if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(From)) + From = Cast->getSubExpr(); + + // A string literal (2.13.4) that is not a wide string literal can + // be converted to an rvalue of type "pointer to char"; a wide + // string literal can be converted to an rvalue of type "pointer + // to wchar_t" (C++ 4.2p2). + if (StringLiteral *StrLit = dyn_cast<StringLiteral>(From)) + if (const PointerType *ToPtrType = ToType->getAsPointerType()) + if (const BuiltinType *ToPointeeType + = ToPtrType->getPointeeType()->getAsBuiltinType()) { + // This conversion is considered only when there is an + // explicit appropriate pointer target type (C++ 4.2p2). + if (ToPtrType->getPointeeType().getCVRQualifiers() == 0 && + ((StrLit->isWide() && ToPointeeType->isWideCharType()) || + (!StrLit->isWide() && + (ToPointeeType->getKind() == BuiltinType::Char_U || + ToPointeeType->getKind() == BuiltinType::Char_S)))) + return true; + } + + return false; +} + +/// PerformImplicitConversion - Perform an implicit conversion of the +/// expression From to the type ToType. Returns true if there was an +/// error, false otherwise. The expression From is replaced with the +/// converted expression. Flavor is the kind of conversion we're +/// performing, used in the error message. If @p AllowExplicit, +/// explicit user-defined conversions are permitted. @p Elidable should be true +/// when called for copies which may be elided (C++ 12.8p15). C++0x overload +/// resolution works differently in that case. +bool +Sema::PerformImplicitConversion(Expr *&From, QualType ToType, + const char *Flavor, bool AllowExplicit, + bool Elidable) +{ + ImplicitConversionSequence ICS; + ICS.ConversionKind = ImplicitConversionSequence::BadConversion; + if (Elidable && getLangOptions().CPlusPlus0x) { + ICS = TryImplicitConversion(From, ToType, /*SuppressUserConversions*/false, + AllowExplicit, /*ForceRValue*/true); + } + if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) { + ICS = TryImplicitConversion(From, ToType, false, AllowExplicit); + } + return PerformImplicitConversion(From, ToType, ICS, Flavor); +} + +/// PerformImplicitConversion - Perform an implicit conversion of the +/// expression From to the type ToType using the pre-computed implicit +/// conversion sequence ICS. Returns true if there was an error, false +/// otherwise. The expression From is replaced with the converted +/// expression. Flavor is the kind of conversion we're performing, +/// used in the error message. +bool +Sema::PerformImplicitConversion(Expr *&From, QualType ToType, + const ImplicitConversionSequence &ICS, + const char* Flavor) { + switch (ICS.ConversionKind) { + case ImplicitConversionSequence::StandardConversion: + if (PerformImplicitConversion(From, ToType, ICS.Standard, Flavor)) + return true; + break; + + case ImplicitConversionSequence::UserDefinedConversion: + // FIXME: This is, of course, wrong. We'll need to actually call the + // constructor or conversion operator, and then cope with the standard + // conversions. + ImpCastExprToType(From, ToType.getNonReferenceType(), + ToType->isLValueReferenceType()); + return false; + + case ImplicitConversionSequence::EllipsisConversion: + assert(false && "Cannot perform an ellipsis conversion"); + return false; + + case ImplicitConversionSequence::BadConversion: + return true; + } + + // Everything went well. + return false; +} + +/// PerformImplicitConversion - Perform an implicit conversion of the +/// expression From to the type ToType by following the standard +/// conversion sequence SCS. Returns true if there was an error, false +/// otherwise. The expression From is replaced with the converted +/// expression. Flavor is the context in which we're performing this +/// conversion, for use in error messages. +bool +Sema::PerformImplicitConversion(Expr *&From, QualType ToType, + const StandardConversionSequence& SCS, + const char *Flavor) { + // Overall FIXME: we are recomputing too many types here and doing far too + // much extra work. What this means is that we need to keep track of more + // information that is computed when we try the implicit conversion initially, + // so that we don't need to recompute anything here. + QualType FromType = From->getType(); + + if (SCS.CopyConstructor) { + // FIXME: When can ToType be a reference type? + assert(!ToType->isReferenceType()); + + // FIXME: Keep track of whether the copy constructor is elidable or not. + From = CXXConstructExpr::Create(Context, ToType, + SCS.CopyConstructor, false, &From, 1); + return false; + } + + // Perform the first implicit conversion. + switch (SCS.First) { + case ICK_Identity: + case ICK_Lvalue_To_Rvalue: + // Nothing to do. + break; + + case ICK_Array_To_Pointer: + FromType = Context.getArrayDecayedType(FromType); + ImpCastExprToType(From, FromType); + break; + + case ICK_Function_To_Pointer: + if (Context.getCanonicalType(FromType) == Context.OverloadTy) { + FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, true); + if (!Fn) + return true; + + if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin())) + return true; + + FixOverloadedFunctionReference(From, Fn); + FromType = From->getType(); + } + FromType = Context.getPointerType(FromType); + ImpCastExprToType(From, FromType); + break; + + default: + assert(false && "Improper first standard conversion"); + break; + } + + // Perform the second implicit conversion + switch (SCS.Second) { + case ICK_Identity: + // Nothing to do. + break; + + case ICK_Integral_Promotion: + case ICK_Floating_Promotion: + case ICK_Complex_Promotion: + case ICK_Integral_Conversion: + case ICK_Floating_Conversion: + case ICK_Complex_Conversion: + case ICK_Floating_Integral: + case ICK_Complex_Real: + case ICK_Compatible_Conversion: + // FIXME: Go deeper to get the unqualified type! + FromType = ToType.getUnqualifiedType(); + ImpCastExprToType(From, FromType); + break; + + case ICK_Pointer_Conversion: + if (SCS.IncompatibleObjC) { + // Diagnose incompatible Objective-C conversions + Diag(From->getSourceRange().getBegin(), + diag::ext_typecheck_convert_incompatible_pointer) + << From->getType() << ToType << Flavor + << From->getSourceRange(); + } + + if (CheckPointerConversion(From, ToType)) + return true; + ImpCastExprToType(From, ToType); + break; + + case ICK_Pointer_Member: + if (CheckMemberPointerConversion(From, ToType)) + return true; + ImpCastExprToType(From, ToType); + break; + + case ICK_Boolean_Conversion: + FromType = Context.BoolTy; + ImpCastExprToType(From, FromType); + break; + + default: + assert(false && "Improper second standard conversion"); + break; + } + + switch (SCS.Third) { + case ICK_Identity: + // Nothing to do. + break; + + case ICK_Qualification: + // FIXME: Not sure about lvalue vs rvalue here in the presence of rvalue + // references. + ImpCastExprToType(From, ToType.getNonReferenceType(), + ToType->isLValueReferenceType()); + break; + + default: + assert(false && "Improper second standard conversion"); + break; + } + + return false; +} + +Sema::OwningExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait OTT, + SourceLocation KWLoc, + SourceLocation LParen, + TypeTy *Ty, + SourceLocation RParen) { + // FIXME: Some of the type traits have requirements. Interestingly, only the + // __is_base_of requirement is explicitly stated to be diagnosed. Indeed, G++ + // accepts __is_pod(Incomplete) without complaints, and claims that the type + // is indeed a POD. + + // There is no point in eagerly computing the value. The traits are designed + // to be used from type trait templates, so Ty will be a template parameter + // 99% of the time. + return Owned(new (Context) UnaryTypeTraitExpr(KWLoc, OTT, + QualType::getFromOpaquePtr(Ty), + RParen, Context.BoolTy)); +} + +QualType Sema::CheckPointerToMemberOperands( + Expr *&lex, Expr *&rex, SourceLocation Loc, bool isIndirect) +{ + const char *OpSpelling = isIndirect ? "->*" : ".*"; + // C++ 5.5p2 + // The binary operator .* [p3: ->*] binds its second operand, which shall + // be of type "pointer to member of T" (where T is a completely-defined + // class type) [...] + QualType RType = rex->getType(); + const MemberPointerType *MemPtr = RType->getAsMemberPointerType(); + if (!MemPtr) { + Diag(Loc, diag::err_bad_memptr_rhs) + << OpSpelling << RType << rex->getSourceRange(); + return QualType(); + } + + QualType Class(MemPtr->getClass(), 0); + + // C++ 5.5p2 + // [...] to its first operand, which shall be of class T or of a class of + // which T is an unambiguous and accessible base class. [p3: a pointer to + // such a class] + QualType LType = lex->getType(); + if (isIndirect) { + if (const PointerType *Ptr = LType->getAsPointerType()) + LType = Ptr->getPointeeType().getNonReferenceType(); + else { + Diag(Loc, diag::err_bad_memptr_lhs) + << OpSpelling << 1 << LType << lex->getSourceRange(); + return QualType(); + } + } + + if (Context.getCanonicalType(Class).getUnqualifiedType() != + Context.getCanonicalType(LType).getUnqualifiedType()) { + BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, + /*DetectVirtual=*/false); + // FIXME: Would it be useful to print full ambiguity paths, or is that + // overkill? + if (!IsDerivedFrom(LType, Class, Paths) || + Paths.isAmbiguous(Context.getCanonicalType(Class))) { + Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling + << (int)isIndirect << lex->getType() << lex->getSourceRange(); + return QualType(); + } + } + + // C++ 5.5p2 + // The result is an object or a function of the type specified by the + // second operand. + // The cv qualifiers are the union of those in the pointer and the left side, + // in accordance with 5.5p5 and 5.2.5. + // FIXME: This returns a dereferenced member function pointer as a normal + // function type. However, the only operation valid on such functions is + // calling them. There's also a GCC extension to get a function pointer to the + // thing, which is another complication, because this type - unlike the type + // that is the result of this expression - takes the class as the first + // argument. + // We probably need a "MemberFunctionClosureType" or something like that. + QualType Result = MemPtr->getPointeeType(); + if (LType.isConstQualified()) + Result.addConst(); + if (LType.isVolatileQualified()) + Result.addVolatile(); + return Result; +} + +/// \brief Get the target type of a standard or user-defined conversion. +static QualType TargetType(const ImplicitConversionSequence &ICS) { + assert((ICS.ConversionKind == + ImplicitConversionSequence::StandardConversion || + ICS.ConversionKind == + ImplicitConversionSequence::UserDefinedConversion) && + "function only valid for standard or user-defined conversions"); + if (ICS.ConversionKind == ImplicitConversionSequence::StandardConversion) + return QualType::getFromOpaquePtr(ICS.Standard.ToTypePtr); + return QualType::getFromOpaquePtr(ICS.UserDefined.After.ToTypePtr); +} + +/// \brief Try to convert a type to another according to C++0x 5.16p3. +/// +/// This is part of the parameter validation for the ? operator. If either +/// value operand is a class type, the two operands are attempted to be +/// converted to each other. This function does the conversion in one direction. +/// It emits a diagnostic and returns true only if it finds an ambiguous +/// conversion. +static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, + SourceLocation QuestionLoc, + ImplicitConversionSequence &ICS) +{ + // C++0x 5.16p3 + // The process for determining whether an operand expression E1 of type T1 + // can be converted to match an operand expression E2 of type T2 is defined + // as follows: + // -- If E2 is an lvalue: + if (To->isLvalue(Self.Context) == Expr::LV_Valid) { + // E1 can be converted to match E2 if E1 can be implicitly converted to + // type "lvalue reference to T2", subject to the constraint that in the + // conversion the reference must bind directly to E1. + if (!Self.CheckReferenceInit(From, + Self.Context.getLValueReferenceType(To->getType()), + &ICS)) + { + assert((ICS.ConversionKind == + ImplicitConversionSequence::StandardConversion || + ICS.ConversionKind == + ImplicitConversionSequence::UserDefinedConversion) && + "expected a definite conversion"); + bool DirectBinding = + ICS.ConversionKind == ImplicitConversionSequence::StandardConversion ? + ICS.Standard.DirectBinding : ICS.UserDefined.After.DirectBinding; + if (DirectBinding) + return false; + } + } + ICS.ConversionKind = ImplicitConversionSequence::BadConversion; + // -- 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: + QualType FTy = From->getType(); + QualType TTy = To->getType(); + const RecordType *FRec = FTy->getAsRecordType(); + const RecordType *TRec = TTy->getAsRecordType(); + bool FDerivedFromT = FRec && TRec && Self.IsDerivedFrom(FTy, TTy); + if (FRec && TRec && (FRec == TRec || + FDerivedFromT || Self.IsDerivedFrom(TTy, FTy))) { + // E1 can be converted to match E2 if the class of T2 is the + // same type as, or a base class of, the class of T1, and + // [cv2 > cv1]. + if ((FRec == TRec || FDerivedFromT) && 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); + } + } else { + // -- Otherwise: E1 can be converted to match E2 if E1 can be + // implicitly converted to the type that expression E2 would have + // if E2 were converted to an rvalue. + // First find the decayed type. + if (TTy->isFunctionType()) + TTy = Self.Context.getPointerType(TTy); + else if(TTy->isArrayType()) + TTy = Self.Context.getArrayDecayedType(TTy); + + // Now try the implicit conversion. + // FIXME: This doesn't detect ambiguities. + ICS = Self.TryImplicitConversion(From, TTy); + } + return false; +} + +/// \brief Try to find a common type for two according to C++0x 5.16p5. +/// +/// This is part of the parameter validation for the ? operator. If either +/// value operand is a class type, overload resolution is used to find a +/// conversion to a common type. +static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, + SourceLocation Loc) { + Expr *Args[2] = { LHS, RHS }; + OverloadCandidateSet CandidateSet; + Self.AddBuiltinOperatorCandidates(OO_Conditional, Args, 2, CandidateSet); + + OverloadCandidateSet::iterator Best; + switch (Self.BestViableFunction(CandidateSet, Best)) { + case Sema::OR_Success: + // We found a match. Perform the conversions on the arguments and move on. + if (Self.PerformImplicitConversion(LHS, Best->BuiltinTypes.ParamTypes[0], + Best->Conversions[0], "converting") || + Self.PerformImplicitConversion(RHS, Best->BuiltinTypes.ParamTypes[1], + Best->Conversions[1], "converting")) + break; + return false; + + case Sema::OR_No_Viable_Function: + Self.Diag(Loc, diag::err_typecheck_cond_incompatible_operands) + << LHS->getType() << RHS->getType() + << LHS->getSourceRange() << RHS->getSourceRange(); + return true; + + case Sema::OR_Ambiguous: + Self.Diag(Loc, diag::err_conditional_ambiguous_ovl) + << LHS->getType() << RHS->getType() + << LHS->getSourceRange() << RHS->getSourceRange(); + // FIXME: Print the possible common types by printing the return types of + // the viable candidates. + break; + + case Sema::OR_Deleted: + assert(false && "Conditional operator has only built-in overloads"); + break; + } + return true; +} + +/// \brief Perform an "extended" implicit conversion as returned by +/// TryClassUnification. +/// +/// TryClassUnification generates ICSs that include reference bindings. +/// PerformImplicitConversion is not suitable for this; it chokes if the +/// second part of a standard conversion is ICK_DerivedToBase. This function +/// handles the reference binding specially. +static bool ConvertForConditional(Sema &Self, Expr *&E, + const ImplicitConversionSequence &ICS) +{ + if (ICS.ConversionKind == ImplicitConversionSequence::StandardConversion && + ICS.Standard.ReferenceBinding) { + assert(ICS.Standard.DirectBinding && + "TryClassUnification should never generate indirect ref bindings"); + // FIXME: CheckReferenceInit should be able to reuse the ICS instead of + // redoing all the work. + return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType( + TargetType(ICS))); + } + if (ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion && + ICS.UserDefined.After.ReferenceBinding) { + assert(ICS.UserDefined.After.DirectBinding && + "TryClassUnification should never generate indirect ref bindings"); + return Self.CheckReferenceInit(E, Self.Context.getLValueReferenceType( + TargetType(ICS))); + } + if (Self.PerformImplicitConversion(E, TargetType(ICS), ICS, "converting")) + return true; + return false; +} + +/// \brief Check the operands of ?: under C++ semantics. +/// +/// See C++ [expr.cond]. Note that LHS is never null, even for the GNU x ?: y +/// extension. In this case, LHS == Cond. (But they're not aliases.) +QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, + SourceLocation QuestionLoc) { + // FIXME: Handle C99's complex types, vector types, block pointers and Obj-C++ + // interface pointers. + + // C++0x 5.16p1 + // The first expression is contextually converted to bool. + if (!Cond->isTypeDependent()) { + if (CheckCXXBooleanCondition(Cond)) + return QualType(); + } + + // Either of the arguments dependent? + if (LHS->isTypeDependent() || RHS->isTypeDependent()) + return Context.DependentTy; + + // C++0x 5.16p2 + // If either the second or the third operand has type (cv) void, ... + QualType LTy = LHS->getType(); + QualType RTy = RHS->getType(); + bool LVoid = LTy->isVoidType(); + bool RVoid = RTy->isVoidType(); + if (LVoid || RVoid) { + // ... then the [l2r] conversions are performed on the second and third + // operands ... + DefaultFunctionArrayConversion(LHS); + DefaultFunctionArrayConversion(RHS); + LTy = LHS->getType(); + RTy = RHS->getType(); + + // ... and one of the following shall hold: + // -- The second or the third operand (but not both) is a throw- + // expression; the result is of the type of the other and is an rvalue. + bool LThrow = isa<CXXThrowExpr>(LHS); + bool RThrow = isa<CXXThrowExpr>(RHS); + if (LThrow && !RThrow) + return RTy; + if (RThrow && !LThrow) + return LTy; + + // -- Both the second and third operands have type void; the result is of + // type void and is an rvalue. + if (LVoid && RVoid) + return Context.VoidTy; + + // Neither holds, error. + Diag(QuestionLoc, diag::err_conditional_void_nonvoid) + << (LVoid ? RTy : LTy) << (LVoid ? 0 : 1) + << LHS->getSourceRange() << RHS->getSourceRange(); + return QualType(); + } + + // Neither is void. + + // C++0x 5.16p3 + // Otherwise, if the second and third operand have different types, and + // either has (cv) class type, and attempt is made to convert each of those + // operands to the other. + if (Context.getCanonicalType(LTy) != Context.getCanonicalType(RTy) && + (LTy->isRecordType() || RTy->isRecordType())) { + ImplicitConversionSequence ICSLeftToRight, ICSRightToLeft; + // These return true if a single direction is already ambiguous. + if (TryClassUnification(*this, LHS, RHS, QuestionLoc, ICSLeftToRight)) + return QualType(); + if (TryClassUnification(*this, RHS, LHS, QuestionLoc, ICSRightToLeft)) + return QualType(); + + bool HaveL2R = ICSLeftToRight.ConversionKind != + ImplicitConversionSequence::BadConversion; + bool HaveR2L = ICSRightToLeft.ConversionKind != + ImplicitConversionSequence::BadConversion; + // If both can be converted, [...] the program is ill-formed. + if (HaveL2R && HaveR2L) { + Diag(QuestionLoc, diag::err_conditional_ambiguous) + << LTy << RTy << LHS->getSourceRange() << RHS->getSourceRange(); + return QualType(); + } + + // If exactly one conversion is possible, that conversion is applied to + // the chosen operand and the converted operands are used in place of the + // original operands for the remainder of this section. + if (HaveL2R) { + if (ConvertForConditional(*this, LHS, ICSLeftToRight)) + return QualType(); + LTy = LHS->getType(); + } else if (HaveR2L) { + if (ConvertForConditional(*this, RHS, ICSRightToLeft)) + return QualType(); + RTy = RHS->getType(); + } + } + + // C++0x 5.16p4 + // If the second and third operands are lvalues and have the same type, + // the result is of that type [...] + bool Same = Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy); + if (Same && LHS->isLvalue(Context) == Expr::LV_Valid && + RHS->isLvalue(Context) == Expr::LV_Valid) + return LTy; + + // C++0x 5.16p5 + // Otherwise, the result is an rvalue. If the second and third operands + // do not have the same type, and either has (cv) class type, ... + if (!Same && (LTy->isRecordType() || RTy->isRecordType())) { + // ... overload resolution is used to determine the conversions (if any) + // to be applied to the operands. If the overload resolution fails, the + // program is ill-formed. + if (FindConditionalOverload(*this, LHS, RHS, QuestionLoc)) + return QualType(); + } + + // C++0x 5.16p6 + // LValue-to-rvalue, array-to-pointer, and function-to-pointer standard + // conversions are performed on the second and third operands. + DefaultFunctionArrayConversion(LHS); + DefaultFunctionArrayConversion(RHS); + LTy = LHS->getType(); + RTy = RHS->getType(); + + // After those conversions, one of the following shall hold: + // -- The second and third operands have the same type; the result + // is of that type. + if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy)) + return LTy; + + // -- The second and third operands have arithmetic or enumeration type; + // the usual arithmetic conversions are performed to bring them to a + // common type, and the result is of that type. + if (LTy->isArithmeticType() && RTy->isArithmeticType()) { + UsualArithmeticConversions(LHS, RHS); + return LHS->getType(); + } + + // -- The second and third operands have pointer type, or one has pointer + // type and the other is a null pointer constant; pointer conversions + // and qualification conversions are performed to bring them to their + // composite pointer type. The result is of the composite pointer type. + QualType Composite = FindCompositePointerType(LHS, RHS); + if (!Composite.isNull()) + return Composite; + + // Fourth bullet is same for pointers-to-member. However, the possible + // conversions are far more limited: we have null-to-pointer, upcast of + // containing class, and second-level cv-ness. + // cv-ness is not a union, but must match one of the two operands. (Which, + // frankly, is stupid.) + const MemberPointerType *LMemPtr = LTy->getAsMemberPointerType(); + const MemberPointerType *RMemPtr = RTy->getAsMemberPointerType(); + if (LMemPtr && RHS->isNullPointerConstant(Context)) { + ImpCastExprToType(RHS, LTy); + return LTy; + } + if (RMemPtr && LHS->isNullPointerConstant(Context)) { + ImpCastExprToType(LHS, RTy); + return RTy; + } + if (LMemPtr && RMemPtr) { + QualType LPointee = LMemPtr->getPointeeType(); + QualType RPointee = RMemPtr->getPointeeType(); + // First, we check that the unqualified pointee type is the same. If it's + // not, there's no conversion that will unify the two pointers. + if (Context.getCanonicalType(LPointee).getUnqualifiedType() == + Context.getCanonicalType(RPointee).getUnqualifiedType()) { + // Second, we take the greater of the two cv qualifications. If neither + // is greater than the other, the conversion is not possible. + unsigned Q = LPointee.getCVRQualifiers() | RPointee.getCVRQualifiers(); + if (Q == LPointee.getCVRQualifiers() || Q == RPointee.getCVRQualifiers()){ + // Third, we check if either of the container classes is derived from + // the other. + QualType LContainer(LMemPtr->getClass(), 0); + QualType RContainer(RMemPtr->getClass(), 0); + QualType MoreDerived; + if (Context.getCanonicalType(LContainer) == + Context.getCanonicalType(RContainer)) + MoreDerived = LContainer; + else if (IsDerivedFrom(LContainer, RContainer)) + MoreDerived = LContainer; + else if (IsDerivedFrom(RContainer, LContainer)) + MoreDerived = RContainer; + + if (!MoreDerived.isNull()) { + // The type 'Q Pointee (MoreDerived::*)' is the common type. + // We don't use ImpCastExprToType here because this could still fail + // for ambiguous or inaccessible conversions. + QualType Common = Context.getMemberPointerType( + LPointee.getQualifiedType(Q), MoreDerived.getTypePtr()); + if (PerformImplicitConversion(LHS, Common, "converting")) + return QualType(); + if (PerformImplicitConversion(RHS, Common, "converting")) + return QualType(); + return Common; + } + } + } + } + + Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) + << LHS->getType() << RHS->getType() + << LHS->getSourceRange() << RHS->getSourceRange(); + return QualType(); +} + +/// \brief Find a merged pointer type and convert the two expressions to it. +/// +/// This finds the composite pointer type for @p E1 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) { + assert(getLangOptions().CPlusPlus && "This function assumes C++"); + QualType T1 = E1->getType(), T2 = E2->getType(); + if(!T1->isPointerType() && !T2->isPointerType()) + return QualType(); + + // C++0x 5.9p2 + // Pointer conversions and qualification conversions are performed on + // pointer operands to bring them to their composite pointer type. If + // one operand is a null pointer constant, the composite pointer type is + // the type of the other operand. + if (E1->isNullPointerConstant(Context)) { + ImpCastExprToType(E1, T2); + return T2; + } + if (E2->isNullPointerConstant(Context)) { + ImpCastExprToType(E2, T1); + return T1; + } + // Now both have to be pointers. + if(!T1->isPointerType() || !T2->isPointerType()) + return QualType(); + + // Otherwise, of one of the operands has type "pointer to cv1 void," then + // the other has type "pointer to cv2 T" and the composite pointer type is + // "pointer to cv12 void," where cv12 is the union of cv1 and cv2. + // Otherwise, the composite pointer type is a pointer type similar to the + // type of one of the operands, with a cv-qualification signature that is + // the union of the cv-qualification signatures of the operand types. + // In practice, the first part here is redundant; it's subsumed by the second. + // What we do here is, we build the two possible composite types, and try the + // conversions in both directions. If only one works, or if the two composite + // types are the same, we have succeeded. + llvm::SmallVector<unsigned, 4> QualifierUnion; + QualType Composite1 = T1, Composite2 = T2; + const PointerType *Ptr1, *Ptr2; + while ((Ptr1 = Composite1->getAsPointerType()) && + (Ptr2 = Composite2->getAsPointerType())) { + Composite1 = Ptr1->getPointeeType(); + Composite2 = Ptr2->getPointeeType(); + QualifierUnion.push_back( + Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); + } + // Rewrap the composites as pointers with the union CVRs. + for (llvm::SmallVector<unsigned, 4>::iterator I = QualifierUnion.begin(), + E = QualifierUnion.end(); I != E; ++I) { + Composite1 = Context.getPointerType(Composite1.getQualifiedType(*I)); + Composite2 = Context.getPointerType(Composite2.getQualifiedType(*I)); + } + + ImplicitConversionSequence E1ToC1 = TryImplicitConversion(E1, Composite1); + ImplicitConversionSequence E2ToC1 = TryImplicitConversion(E2, Composite1); + ImplicitConversionSequence E1ToC2, E2ToC2; + E1ToC2.ConversionKind = ImplicitConversionSequence::BadConversion; + E2ToC2.ConversionKind = ImplicitConversionSequence::BadConversion; + if (Context.getCanonicalType(Composite1) != + Context.getCanonicalType(Composite2)) { + E1ToC2 = TryImplicitConversion(E1, Composite2); + E2ToC2 = TryImplicitConversion(E2, Composite2); + } + + bool ToC1Viable = E1ToC1.ConversionKind != + ImplicitConversionSequence::BadConversion + && E2ToC1.ConversionKind != + ImplicitConversionSequence::BadConversion; + bool ToC2Viable = E1ToC2.ConversionKind != + ImplicitConversionSequence::BadConversion + && E2ToC2.ConversionKind != + ImplicitConversionSequence::BadConversion; + if (ToC1Viable && !ToC2Viable) { + if (!PerformImplicitConversion(E1, Composite1, E1ToC1, "converting") && + !PerformImplicitConversion(E2, Composite1, E2ToC1, "converting")) + return Composite1; + } + if (ToC2Viable && !ToC1Viable) { + if (!PerformImplicitConversion(E1, Composite2, E1ToC2, "converting") && + !PerformImplicitConversion(E2, Composite2, E2ToC2, "converting")) + return Composite2; + } + return QualType(); +} + +Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) { + const RecordType *RT = E->getType()->getAsRecordType(); + if (!RT) + return Owned(E); + + CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + if (RD->hasTrivialDestructor()) + return Owned(E); + + CXXTemporary *Temp = CXXTemporary::Create(Context, + RD->getDestructor(Context)); + ExprTemporaries.push_back(Temp); + + // FIXME: Add the temporary to the temporaries vector. + return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E)); +} + +// FIXME: This doesn't handle casts yet. +Expr *Sema::RemoveOutermostTemporaryBinding(Expr *E) { + const RecordType *RT = E->getType()->getAsRecordType(); + if (!RT) + return E; + + CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + if (RD->hasTrivialDestructor()) + return E; + + /// The expr passed in must be a CXXExprWithTemporaries. + CXXExprWithTemporaries *TempExpr = dyn_cast<CXXExprWithTemporaries>(E); + if (!TempExpr) + return E; + + Expr *SubExpr = TempExpr->getSubExpr(); + if (CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(SubExpr)) { + assert(BE->getTemporary() == + TempExpr->getTemporary(TempExpr->getNumTemporaries() - 1) && + "Found temporary is not last in list!"); + + Expr *BindSubExpr = BE->getSubExpr(); + BE->setSubExpr(0); + + if (TempExpr->getNumTemporaries() == 1) { + // There's just one temporary left, so we don't need the TempExpr node. + TempExpr->Destroy(Context); + return BindSubExpr; + } else { + TempExpr->removeLastTemporary(); + TempExpr->setSubExpr(BindSubExpr); + BE->Destroy(Context); + } + + return E; + } + + // FIXME: We might need to handle other expressions here. + return E; +} + +Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) { + Expr *FullExpr = Arg.takeAs<Expr>(); + + if (FullExpr && !ExprTemporaries.empty()) { + // Create a cleanup expr. + FullExpr = CXXExprWithTemporaries::Create(Context, FullExpr, + &ExprTemporaries[0], + ExprTemporaries.size()); + ExprTemporaries.clear(); + } + + return Owned(FullExpr); +} diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp new file mode 100644 index 0000000..eabc87d --- /dev/null +++ b/lib/Sema/SemaExprObjC.cpp @@ -0,0 +1,860 @@ +//===--- SemaExprObjC.cpp - Semantic Analysis for ObjC Expressions --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for Objective-C expressions. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/ExprObjC.h" +#include "llvm/ADT/SmallString.h" +#include "clang/Lex/Preprocessor.h" + +using namespace clang; + +Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, + ExprTy **strings, + unsigned NumStrings) { + StringLiteral **Strings = reinterpret_cast<StringLiteral**>(strings); + + // Most ObjC strings are formed out of a single piece. However, we *can* + // have strings formed out of multiple @ strings with multiple pptokens in + // each one, e.g. @"foo" "bar" @"baz" "qux" which need to be turned into one + // StringLiteral for ObjCStringLiteral to hold onto. + StringLiteral *S = Strings[0]; + + // If we have a multi-part string, merge it all together. + if (NumStrings != 1) { + // Concatenate objc strings. + llvm::SmallString<128> StrBuf; + llvm::SmallVector<SourceLocation, 8> StrLocs; + + for (unsigned i = 0; i != NumStrings; ++i) { + S = Strings[i]; + + // ObjC strings can't be wide. + if (S->isWide()) { + Diag(S->getLocStart(), diag::err_cfstring_literal_not_string_constant) + << S->getSourceRange(); + return true; + } + + // Get the string data. + StrBuf.append(S->getStrData(), S->getStrData()+S->getByteLength()); + + // Get the locations of the string tokens. + StrLocs.append(S->tokloc_begin(), S->tokloc_end()); + + // Free the temporary string. + S->Destroy(Context); + } + + // Create the aggregate string with the appropriate content and location + // information. + S = StringLiteral::Create(Context, &StrBuf[0], StrBuf.size(), false, + Context.getPointerType(Context.CharTy), + &StrLocs[0], StrLocs.size()); + } + + // Verify that this composite string is acceptable for ObjC strings. + if (CheckObjCString(S)) + return true; + + // Initialize the constant string interface lazily. This assumes + // the NSString interface is seen in this translation unit. Note: We + // don't use NSConstantString, since the runtime team considers this + // interface private (even though it appears in the header files). + QualType Ty = Context.getObjCConstantStringInterface(); + if (!Ty.isNull()) { + Ty = Context.getPointerType(Ty); + } else { + IdentifierInfo *NSIdent = &Context.Idents.get("NSString"); + NamedDecl *IF = LookupName(TUScope, NSIdent, LookupOrdinaryName); + if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) { + Context.setObjCConstantStringInterface(StrIF); + Ty = Context.getObjCConstantStringInterface(); + Ty = Context.getPointerType(Ty); + } else { + // If there is no NSString interface defined then treat constant + // strings as untyped objects and let the runtime figure it out later. + Ty = Context.getObjCIdType(); + } + } + + return new (Context) ObjCStringLiteral(S, Ty, AtLocs[0]); +} + +Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc, + SourceLocation EncodeLoc, + SourceLocation LParenLoc, + TypeTy *ty, + SourceLocation RParenLoc) { + QualType EncodedType = QualType::getFromOpaquePtr(ty); + + std::string Str; + Context.getObjCEncodingForType(EncodedType, Str); + + // The type of @encode is the same as the type of the corresponding string, + // which is an array type. + QualType StrTy = Context.CharTy; + // A C++ string literal has a const-qualified element type (C++ 2.13.4p1). + if (getLangOptions().CPlusPlus) + StrTy.addConst(); + StrTy = Context.getConstantArrayType(StrTy, llvm::APInt(32, Str.size()+1), + ArrayType::Normal, 0); + + return new (Context) ObjCEncodeExpr(StrTy, EncodedType, AtLoc, RParenLoc); +} + +Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, + SourceLocation AtLoc, + SourceLocation SelLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + QualType Ty = Context.getObjCSelType(); + return new (Context) ObjCSelectorExpr(Ty, Sel, AtLoc, RParenLoc); +} + +Sema::ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, + SourceLocation AtLoc, + SourceLocation ProtoLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + ObjCProtocolDecl* PDecl = LookupProtocol(ProtocolId); + if (!PDecl) { + Diag(ProtoLoc, diag::err_undeclared_protocol) << ProtocolId; + return true; + } + + QualType Ty = Context.getObjCProtoType(); + if (Ty.isNull()) + return true; + Ty = Context.getPointerType(Ty); + return new (Context) ObjCProtocolExpr(Ty, PDecl, AtLoc, RParenLoc); +} + +bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, + Selector Sel, ObjCMethodDecl *Method, + bool isClassMessage, + SourceLocation lbrac, SourceLocation rbrac, + QualType &ReturnType) { + if (!Method) { + // Apply default argument promotion as for (C99 6.5.2.2p6). + for (unsigned i = 0; i != NumArgs; i++) + DefaultArgumentPromotion(Args[i]); + + unsigned DiagID = isClassMessage ? diag::warn_class_method_not_found : + diag::warn_inst_method_not_found; + Diag(lbrac, DiagID) + << Sel << isClassMessage << SourceRange(lbrac, rbrac); + ReturnType = Context.getObjCIdType(); + return false; + } + + ReturnType = Method->getResultType(); + + unsigned NumNamedArgs = Sel.getNumArgs(); + assert(NumArgs >= NumNamedArgs && "Too few arguments for selector!"); + + bool IsError = false; + for (unsigned i = 0; i < NumNamedArgs; i++) { + Expr *argExpr = Args[i]; + assert(argExpr && "CheckMessageArgumentTypes(): missing expression"); + + QualType lhsType = Method->param_begin()[i]->getType(); + QualType rhsType = argExpr->getType(); + + // If necessary, apply function/array conversion. C99 6.7.5.3p[7,8]. + if (lhsType->isArrayType()) + lhsType = Context.getArrayDecayedType(lhsType); + else if (lhsType->isFunctionType()) + lhsType = Context.getPointerType(lhsType); + + AssignConvertType Result = + CheckSingleAssignmentConstraints(lhsType, argExpr); + if (Args[i] != argExpr) // The expression was converted. + Args[i] = argExpr; // Make sure we store the converted expression. + + IsError |= + DiagnoseAssignmentResult(Result, argExpr->getLocStart(), lhsType, rhsType, + argExpr, "sending"); + } + + // Promote additional arguments to variadic methods. + if (Method->isVariadic()) { + for (unsigned i = NumNamedArgs; i < NumArgs; ++i) + IsError |= DefaultVariadicArgumentPromotion(Args[i], VariadicMethod); + } else { + // Check for extra arguments to non-variadic methods. + if (NumArgs != NumNamedArgs) { + Diag(Args[NumNamedArgs]->getLocStart(), + diag::err_typecheck_call_too_many_args) + << 2 /*method*/ << Method->getSourceRange() + << SourceRange(Args[NumNamedArgs]->getLocStart(), + Args[NumArgs-1]->getLocEnd()); + } + } + + return IsError; +} + +bool Sema::isSelfExpr(Expr *RExpr) { + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RExpr)) + if (DRE->getDecl()->getIdentifier() == &Context.Idents.get("self")) + return true; + return false; +} + +// Helper method for ActOnClassMethod/ActOnInstanceMethod. +// Will search "local" class/category implementations for a method decl. +// If failed, then we search in class's root for an instance method. +// Returns 0 if no method is found. +ObjCMethodDecl *Sema::LookupPrivateClassMethod(Selector Sel, + ObjCInterfaceDecl *ClassDecl) { + ObjCMethodDecl *Method = 0; + // lookup in class and all superclasses + while (ClassDecl && !Method) { + if (ObjCImplementationDecl *ImpDecl + = LookupObjCImplementation(ClassDecl->getIdentifier())) + Method = ImpDecl->getClassMethod(Context, Sel); + + // Look through local category implementations associated with the class. + if (!Method) { + for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Method; i++) { + if (ObjCCategoryImpls[i]->getClassInterface() == ClassDecl) + Method = ObjCCategoryImpls[i]->getClassMethod(Context, Sel); + } + } + + // Before we give up, check if the selector is an instance method. + // But only in the root. This matches gcc's behaviour and what the + // runtime expects. + if (!Method && !ClassDecl->getSuperClass()) { + Method = ClassDecl->lookupInstanceMethod(Context, Sel); + // Look through local category implementations associated + // with the root class. + if (!Method) + Method = LookupPrivateInstanceMethod(Sel, ClassDecl); + } + + ClassDecl = ClassDecl->getSuperClass(); + } + return Method; +} + +ObjCMethodDecl *Sema::LookupPrivateInstanceMethod(Selector Sel, + ObjCInterfaceDecl *ClassDecl) { + ObjCMethodDecl *Method = 0; + while (ClassDecl && !Method) { + // If we have implementations in scope, check "private" methods. + if (ObjCImplementationDecl *ImpDecl + = LookupObjCImplementation(ClassDecl->getIdentifier())) + Method = ImpDecl->getInstanceMethod(Context, Sel); + + // Look through local category implementations associated with the class. + if (!Method) { + for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Method; i++) { + if (ObjCCategoryImpls[i]->getClassInterface() == ClassDecl) + Method = ObjCCategoryImpls[i]->getInstanceMethod(Context, Sel); + } + } + ClassDecl = ClassDecl->getSuperClass(); + } + return Method; +} + +Action::OwningExprResult Sema::ActOnClassPropertyRefExpr( + IdentifierInfo &receiverName, + IdentifierInfo &propertyName, + SourceLocation &receiverNameLoc, + SourceLocation &propertyNameLoc) { + + ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(&receiverName); + + // Search for a declared property first. + + Selector Sel = PP.getSelectorTable().getNullarySelector(&propertyName); + ObjCMethodDecl *Getter = IFace->lookupClassMethod(Context, Sel); + + // If this reference is in an @implementation, check for 'private' methods. + if (!Getter) + if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) + if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) + if (ObjCImplementationDecl *ImpDecl + = LookupObjCImplementation(ClassDecl->getIdentifier())) + Getter = ImpDecl->getClassMethod(Context, Sel); + + if (Getter) { + // FIXME: refactor/share with ActOnMemberReference(). + // Check if we can reference this property. + if (DiagnoseUseOfDecl(Getter, propertyNameLoc)) + return ExprError(); + } + + // Look for the matching setter, in case it is needed. + Selector SetterSel = + SelectorTable::constructSetterName(PP.getIdentifierTable(), + PP.getSelectorTable(), &propertyName); + + ObjCMethodDecl *Setter = IFace->lookupClassMethod(Context, SetterSel); + if (!Setter) { + // If this reference is in an @implementation, also check for 'private' + // methods. + if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) + if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) + if (ObjCImplementationDecl *ImpDecl + = LookupObjCImplementation(ClassDecl->getIdentifier())) + Setter = ImpDecl->getClassMethod(Context, SetterSel); + } + // Look through local category implementations associated with the class. + if (!Setter) { + for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Setter; i++) { + if (ObjCCategoryImpls[i]->getClassInterface() == IFace) + Setter = ObjCCategoryImpls[i]->getClassMethod(Context, SetterSel); + } + } + + if (Setter && DiagnoseUseOfDecl(Setter, propertyNameLoc)) + return ExprError(); + + if (Getter || Setter) { + QualType PType; + + if (Getter) + PType = Getter->getResultType(); + else { + for (ObjCMethodDecl::param_iterator PI = Setter->param_begin(), + E = Setter->param_end(); PI != E; ++PI) + PType = (*PI)->getType(); + } + return Owned(new (Context) ObjCKVCRefExpr(Getter, PType, Setter, + propertyNameLoc, IFace, receiverNameLoc)); + } + return ExprError(Diag(propertyNameLoc, diag::err_property_not_found) + << &propertyName << Context.getObjCInterfaceType(IFace)); +} + + +// ActOnClassMessage - used for both unary and keyword messages. +// ArgExprs is optional - if it is present, the number of expressions +// is obtained from Sel.getNumArgs(). +Sema::ExprResult Sema::ActOnClassMessage( + Scope *S, + IdentifierInfo *receiverName, Selector Sel, + SourceLocation lbrac, SourceLocation receiverLoc, + SourceLocation selectorLoc, SourceLocation rbrac, + ExprTy **Args, unsigned NumArgs) +{ + assert(receiverName && "missing receiver class name"); + + Expr **ArgExprs = reinterpret_cast<Expr **>(Args); + ObjCInterfaceDecl* ClassDecl = 0; + bool isSuper = false; + + if (receiverName->isStr("super")) { + if (getCurMethodDecl()) { + isSuper = true; + ObjCInterfaceDecl *OID = getCurMethodDecl()->getClassInterface(); + if (!OID) + return Diag(lbrac, diag::error_no_super_class_message) + << getCurMethodDecl()->getDeclName(); + ClassDecl = OID->getSuperClass(); + if (!ClassDecl) + return Diag(lbrac, diag::error_no_super_class) << OID->getDeclName(); + if (getCurMethodDecl()->isInstanceMethod()) { + QualType superTy = Context.getObjCInterfaceType(ClassDecl); + superTy = Context.getPointerType(superTy); + ExprResult ReceiverExpr = new (Context) ObjCSuperExpr(SourceLocation(), + superTy); + // We are really in an instance method, redirect. + return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac, + selectorLoc, rbrac, Args, NumArgs); + } + // We are sending a message to 'super' within a class method. Do nothing, + // the receiver will pass through as 'super' (how convenient:-). + } else { + // 'super' has been used outside a method context. If a variable named + // 'super' has been declared, redirect. If not, produce a diagnostic. + NamedDecl *SuperDecl = LookupName(S, receiverName, LookupOrdinaryName); + ValueDecl *VD = dyn_cast_or_null<ValueDecl>(SuperDecl); + if (VD) { + ExprResult ReceiverExpr = new (Context) DeclRefExpr(VD, VD->getType(), + receiverLoc); + // We are really in an instance method, redirect. + return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac, + selectorLoc, rbrac, Args, NumArgs); + } + return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName; + } + } else + ClassDecl = getObjCInterfaceDecl(receiverName); + + // The following code allows for the following GCC-ism: + // + // typedef XCElementDisplayRect XCElementGraphicsRect; + // + // @implementation XCRASlice + // - whatever { // Note that XCElementGraphicsRect is a typedef name. + // _sGraphicsDelegate =[[XCElementGraphicsRect alloc] init]; + // } + // + // If necessary, the following lookup could move to getObjCInterfaceDecl(). + if (!ClassDecl) { + NamedDecl *IDecl = LookupName(TUScope, receiverName, LookupOrdinaryName); + if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(IDecl)) { + const ObjCInterfaceType *OCIT; + OCIT = OCTD->getUnderlyingType()->getAsObjCInterfaceType(); + if (!OCIT) { + Diag(receiverLoc, diag::err_invalid_receiver_to_message); + return true; + } + ClassDecl = OCIT->getDecl(); + } + } + assert(ClassDecl && "missing interface declaration"); + ObjCMethodDecl *Method = 0; + QualType returnType; + if (ClassDecl->isForwardDecl()) { + // A forward class used in messaging is tread as a 'Class' + Diag(lbrac, diag::warn_receiver_forward_class) << ClassDecl->getDeclName(); + Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac,rbrac)); + if (Method) + Diag(Method->getLocation(), diag::note_method_sent_forward_class) + << Method->getDeclName(); + } + if (!Method) + Method = ClassDecl->lookupClassMethod(Context, Sel); + + // If we have an implementation in scope, check "private" methods. + if (!Method) + Method = LookupPrivateClassMethod(Sel, ClassDecl); + + if (Method && DiagnoseUseOfDecl(Method, receiverLoc)) + return true; + + if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, true, + lbrac, rbrac, returnType)) + return true; + + returnType = returnType.getNonReferenceType(); + + // If we have the ObjCInterfaceDecl* for the class that is receiving the + // message, use that to construct the ObjCMessageExpr. Otherwise pass on the + // IdentifierInfo* for the class. + // FIXME: need to do a better job handling 'super' usage within a class. For + // now, we simply pass the "super" identifier through (which isn't consistent + // with instance methods. + if (isSuper) + return new (Context) ObjCMessageExpr(receiverName, Sel, returnType, Method, + lbrac, rbrac, ArgExprs, NumArgs); + else + return new (Context) ObjCMessageExpr(ClassDecl, Sel, returnType, Method, + lbrac, rbrac, ArgExprs, NumArgs); +} + +// ActOnInstanceMessage - used for both unary and keyword messages. +// ArgExprs is optional - if it is present, the number of expressions +// is obtained from Sel.getNumArgs(). +Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, + SourceLocation lbrac, + SourceLocation receiverLoc, + SourceLocation rbrac, + ExprTy **Args, unsigned NumArgs) { + assert(receiver && "missing receiver expression"); + + Expr **ArgExprs = reinterpret_cast<Expr **>(Args); + Expr *RExpr = static_cast<Expr *>(receiver); + + // If necessary, apply function/array conversion to the receiver. + // C99 6.7.5.3p[7,8]. + DefaultFunctionArrayConversion(RExpr); + + QualType returnType; + QualType ReceiverCType = + Context.getCanonicalType(RExpr->getType()).getUnqualifiedType(); + + // Handle messages to 'super'. + if (isa<ObjCSuperExpr>(RExpr)) { + ObjCMethodDecl *Method = 0; + if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { + // If we have an interface in scope, check 'super' methods. + if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) + if (ObjCInterfaceDecl *SuperDecl = ClassDecl->getSuperClass()) { + Method = SuperDecl->lookupInstanceMethod(Context, Sel); + + if (!Method) + // If we have implementations in scope, check "private" methods. + Method = LookupPrivateInstanceMethod(Sel, SuperDecl); + } + } + + if (Method && DiagnoseUseOfDecl(Method, receiverLoc)) + return true; + + if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, + lbrac, rbrac, returnType)) + return true; + + returnType = returnType.getNonReferenceType(); + return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, + rbrac, ArgExprs, NumArgs); + } + + // Handle messages to id. + if (ReceiverCType == Context.getCanonicalType(Context.getObjCIdType()) || + ReceiverCType->isBlockPointerType() || + Context.isObjCNSObjectType(RExpr->getType())) { + ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool( + Sel, SourceRange(lbrac,rbrac)); + if (!Method) + Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac, rbrac)); + if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, + lbrac, rbrac, returnType)) + return true; + returnType = returnType.getNonReferenceType(); + return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, + rbrac, ArgExprs, NumArgs); + } + + // Handle messages to Class. + if (ReceiverCType == Context.getCanonicalType(Context.getObjCClassType())) { + ObjCMethodDecl *Method = 0; + + if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { + if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) { + // First check the public methods in the class interface. + Method = ClassDecl->lookupClassMethod(Context, Sel); + + if (!Method) + Method = LookupPrivateClassMethod(Sel, ClassDecl); + } + if (Method && DiagnoseUseOfDecl(Method, receiverLoc)) + return true; + } + if (!Method) { + // If not messaging 'self', look for any factory method named 'Sel'. + if (!isSelfExpr(RExpr)) { + Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac,rbrac)); + if (!Method) { + // If no class (factory) method was found, check if an _instance_ + // method of the same name exists in the root class only. + Method = LookupInstanceMethodInGlobalPool( + Sel, SourceRange(lbrac,rbrac)); + if (Method) + if (const ObjCInterfaceDecl *ID = + dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) { + if (ID->getSuperClass()) + Diag(lbrac, diag::warn_root_inst_method_not_found) + << Sel << SourceRange(lbrac, rbrac); + } + } + } + } + if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, + lbrac, rbrac, returnType)) + return true; + returnType = returnType.getNonReferenceType(); + return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, + rbrac, ArgExprs, NumArgs); + } + + ObjCMethodDecl *Method = 0; + ObjCInterfaceDecl* ClassDecl = 0; + + // We allow sending a message to a qualified ID ("id<foo>"), which is ok as + // long as one of the protocols implements the selector (if not, warn). + if (ObjCQualifiedIdType *QIdTy = dyn_cast<ObjCQualifiedIdType>(ReceiverCType)) { + // Search protocols for instance methods. + for (ObjCQualifiedIdType::qual_iterator I = QIdTy->qual_begin(), + E = QIdTy->qual_end(); I != E; ++I) { + ObjCProtocolDecl *PDecl = *I; + if (PDecl && (Method = PDecl->lookupInstanceMethod(Context, Sel))) + break; + // Since we aren't supporting "Class<foo>", look for a class method. + if (PDecl && (Method = PDecl->lookupClassMethod(Context, Sel))) + break; + } + } else if (const ObjCInterfaceType *OCIType = + ReceiverCType->getAsPointerToObjCInterfaceType()) { + // We allow sending a message to a pointer to an interface (an object). + + ClassDecl = OCIType->getDecl(); + // FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be + // faster than the following method (which can do *many* linear searches). + // The idea is to add class info to InstanceMethodPool. + Method = ClassDecl->lookupInstanceMethod(Context, Sel); + + if (!Method) { + // Search protocol qualifiers. + for (ObjCQualifiedInterfaceType::qual_iterator QI = OCIType->qual_begin(), + E = OCIType->qual_end(); QI != E; ++QI) { + if ((Method = (*QI)->lookupInstanceMethod(Context, Sel))) + break; + } + } + if (!Method) { + // If we have implementations in scope, check "private" methods. + Method = LookupPrivateInstanceMethod(Sel, ClassDecl); + + if (!Method && !isSelfExpr(RExpr)) { + // If we still haven't found a method, look in the global pool. This + // behavior isn't very desirable, however we need it for GCC + // compatibility. FIXME: should we deviate?? + if (OCIType->qual_empty()) { + Method = LookupInstanceMethodInGlobalPool( + Sel, SourceRange(lbrac,rbrac)); + if (Method && !OCIType->getDecl()->isForwardDecl()) + Diag(lbrac, diag::warn_maynot_respond) + << OCIType->getDecl()->getIdentifier()->getName() << Sel; + } + } + } + if (Method && DiagnoseUseOfDecl(Method, receiverLoc)) + return true; + } else if (!Context.getObjCIdType().isNull() && + (ReceiverCType->isPointerType() || + (ReceiverCType->isIntegerType() && + ReceiverCType->isScalarType()))) { + // Implicitly convert integers and pointers to 'id' but emit a warning. + Diag(lbrac, diag::warn_bad_receiver_type) + << RExpr->getType() << RExpr->getSourceRange(); + ImpCastExprToType(RExpr, Context.getObjCIdType()); + } else { + // Reject other random receiver types (e.g. structs). + Diag(lbrac, diag::err_bad_receiver_type) + << RExpr->getType() << RExpr->getSourceRange(); + return true; + } + + if (Method) + DiagnoseSentinelCalls(Method, receiverLoc, ArgExprs, NumArgs); + if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, + lbrac, rbrac, returnType)) + return true; + returnType = returnType.getNonReferenceType(); + return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, + rbrac, ArgExprs, NumArgs); +} + +//===----------------------------------------------------------------------===// +// ObjCQualifiedIdTypesAreCompatible - Compatibility testing for qualified id's. +//===----------------------------------------------------------------------===// + +/// ProtocolCompatibleWithProtocol - return 'true' if 'lProto' is in the +/// inheritance hierarchy of 'rProto'. +static bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, + ObjCProtocolDecl *rProto) { + if (lProto == rProto) + return true; + for (ObjCProtocolDecl::protocol_iterator PI = rProto->protocol_begin(), + E = rProto->protocol_end(); PI != E; ++PI) + if (ProtocolCompatibleWithProtocol(lProto, *PI)) + return true; + return false; +} + +/// ClassImplementsProtocol - Checks that 'lProto' protocol +/// has been implemented in IDecl class, its super class or categories (if +/// lookupCategory is true). +static bool ClassImplementsProtocol(ObjCProtocolDecl *lProto, + ObjCInterfaceDecl *IDecl, + bool lookupCategory, + bool RHSIsQualifiedID = false) { + + // 1st, look up the class. + const ObjCList<ObjCProtocolDecl> &Protocols = + IDecl->getReferencedProtocols(); + + for (ObjCList<ObjCProtocolDecl>::iterator PI = Protocols.begin(), + E = Protocols.end(); PI != E; ++PI) { + if (ProtocolCompatibleWithProtocol(lProto, *PI)) + return true; + // This is dubious and is added to be compatible with gcc. In gcc, it is + // also allowed assigning a protocol-qualified 'id' type to a LHS object + // when protocol in qualified LHS is in list of protocols in the rhs 'id' + // object. This IMO, should be a bug. + // FIXME: Treat this as an extension, and flag this as an error when GCC + // extensions are not enabled. + if (RHSIsQualifiedID && ProtocolCompatibleWithProtocol(*PI, lProto)) + return true; + } + + // 2nd, look up the category. + if (lookupCategory) + for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl; + CDecl = CDecl->getNextClassCategory()) { + for (ObjCCategoryDecl::protocol_iterator PI = CDecl->protocol_begin(), + E = CDecl->protocol_end(); PI != E; ++PI) + if (ProtocolCompatibleWithProtocol(lProto, *PI)) + return true; + } + + // 3rd, look up the super class(s) + if (IDecl->getSuperClass()) + return + ClassImplementsProtocol(lProto, IDecl->getSuperClass(), lookupCategory, + RHSIsQualifiedID); + + return false; +} + +/// QualifiedIdConformsQualifiedId - compare id<p,...> with id<p1,...> +/// return true if lhs's protocols conform to rhs's protocol; false +/// otherwise. +bool Sema::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) { + if (lhs->isObjCQualifiedIdType() && rhs->isObjCQualifiedIdType()) + return ObjCQualifiedIdTypesAreCompatible(lhs, rhs, false); + return false; +} + +/// ObjCQualifiedIdTypesAreCompatible - We know that one of lhs/rhs is an +/// ObjCQualifiedIDType. +/// FIXME: Move to ASTContext::typesAreCompatible() and friends. +bool Sema::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs, + bool compare) { + // Allow id<P..> and an 'id' or void* type in all cases. + if (const PointerType *PT = lhs->getAsPointerType()) { + QualType PointeeTy = PT->getPointeeType(); + if (PointeeTy->isVoidType() || + Context.isObjCIdStructType(PointeeTy) || + Context.isObjCClassStructType(PointeeTy)) + return true; + } else if (const PointerType *PT = rhs->getAsPointerType()) { + QualType PointeeTy = PT->getPointeeType(); + if (PointeeTy->isVoidType() || + Context.isObjCIdStructType(PointeeTy) || + Context.isObjCClassStructType(PointeeTy)) + return true; + } + + if (const ObjCQualifiedIdType *lhsQID = lhs->getAsObjCQualifiedIdType()) { + const ObjCQualifiedIdType *rhsQID = rhs->getAsObjCQualifiedIdType(); + const ObjCQualifiedInterfaceType *rhsQI = 0; + QualType rtype; + + if (!rhsQID) { + // Not comparing two ObjCQualifiedIdType's? + if (!rhs->isPointerType()) return false; + + rtype = rhs->getAsPointerType()->getPointeeType(); + rhsQI = rtype->getAsObjCQualifiedInterfaceType(); + if (rhsQI == 0) { + // If the RHS is a unqualified interface pointer "NSString*", + // make sure we check the class hierarchy. + if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) { + ObjCInterfaceDecl *rhsID = IT->getDecl(); + for (ObjCQualifiedIdType::qual_iterator I = lhsQID->qual_begin(), + E = lhsQID->qual_end(); I != E; ++I) { + // when comparing an id<P> on lhs with a static type on rhs, + // see if static class implements all of id's protocols, directly or + // through its super class and categories. + if (!ClassImplementsProtocol(*I, rhsID, true)) + return false; + } + return true; + } + } + } + + ObjCQualifiedIdType::qual_iterator RHSProtoI, RHSProtoE; + if (rhsQI) { // We have a qualified interface (e.g. "NSObject<Proto> *"). + RHSProtoI = rhsQI->qual_begin(); + RHSProtoE = rhsQI->qual_end(); + } else if (rhsQID) { // We have a qualified id (e.g. "id<Proto> *"). + RHSProtoI = rhsQID->qual_begin(); + RHSProtoE = rhsQID->qual_end(); + } else { + return false; + } + + for (ObjCQualifiedIdType::qual_iterator I = lhsQID->qual_begin(), + E = lhsQID->qual_end(); I != E; ++I) { + ObjCProtocolDecl *lhsProto = *I; + bool match = false; + + // when comparing an id<P> on lhs with a static type on rhs, + // see if static class implements all of id's protocols, directly or + // through its super class and categories. + for (; RHSProtoI != RHSProtoE; ++RHSProtoI) { + ObjCProtocolDecl *rhsProto = *RHSProtoI; + if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || + (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) { + match = true; + break; + } + } + if (rhsQI) { + // If the RHS is a qualified interface pointer "NSString<P>*", + // make sure we check the class hierarchy. + if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) { + ObjCInterfaceDecl *rhsID = IT->getDecl(); + for (ObjCQualifiedIdType::qual_iterator I = lhsQID->qual_begin(), + E = lhsQID->qual_end(); I != E; ++I) { + // when comparing an id<P> on lhs with a static type on rhs, + // see if static class implements all of id's protocols, directly or + // through its super class and categories. + if (ClassImplementsProtocol(*I, rhsID, true)) { + match = true; + break; + } + } + } + } + if (!match) + return false; + } + + return true; + } + + const ObjCQualifiedIdType *rhsQID = rhs->getAsObjCQualifiedIdType(); + assert(rhsQID && "One of the LHS/RHS should be id<x>"); + + if (!lhs->isPointerType()) + return false; + + QualType ltype = lhs->getAsPointerType()->getPointeeType(); + if (const ObjCQualifiedInterfaceType *lhsQI = + ltype->getAsObjCQualifiedInterfaceType()) { + ObjCQualifiedIdType::qual_iterator LHSProtoI = lhsQI->qual_begin(); + ObjCQualifiedIdType::qual_iterator LHSProtoE = lhsQI->qual_end(); + for (; LHSProtoI != LHSProtoE; ++LHSProtoI) { + bool match = false; + ObjCProtocolDecl *lhsProto = *LHSProtoI; + for (ObjCQualifiedIdType::qual_iterator I = rhsQID->qual_begin(), + E = rhsQID->qual_end(); I != E; ++I) { + ObjCProtocolDecl *rhsProto = *I; + if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || + (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) { + match = true; + break; + } + } + if (!match) + return false; + } + return true; + } + + if (const ObjCInterfaceType *IT = ltype->getAsObjCInterfaceType()) { + // for static type vs. qualified 'id' type, check that class implements + // all of 'id's protocols. + ObjCInterfaceDecl *lhsID = IT->getDecl(); + for (ObjCQualifiedIdType::qual_iterator I = rhsQID->qual_begin(), + E = rhsQID->qual_end(); I != E; ++I) { + if (!ClassImplementsProtocol(*I, lhsID, compare, true)) + return false; + } + return true; + } + return false; +} + diff --git a/lib/Sema/SemaInherit.cpp b/lib/Sema/SemaInherit.cpp new file mode 100644 index 0000000..1b968f0 --- /dev/null +++ b/lib/Sema/SemaInherit.cpp @@ -0,0 +1,344 @@ +//===---- SemaInherit.cpp - C++ Inheritance ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides Sema routines for C++ inheritance semantics, +// including searching the inheritance hierarchy. +// +//===----------------------------------------------------------------------===// + +#include "SemaInherit.h" +#include "Sema.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeOrdering.h" +#include <algorithm> +#include <memory> +#include <set> +#include <string> + +using namespace clang; + +/// \brief Computes the set of declarations referenced by these base +/// paths. +void BasePaths::ComputeDeclsFound() { + assert(NumDeclsFound == 0 && !DeclsFound && + "Already computed the set of declarations"); + + std::set<NamedDecl *> Decls; + for (BasePaths::paths_iterator Path = begin(), PathEnd = end(); + Path != PathEnd; ++Path) + Decls.insert(*Path->Decls.first); + + NumDeclsFound = Decls.size(); + DeclsFound = new NamedDecl * [NumDeclsFound]; + std::copy(Decls.begin(), Decls.end(), DeclsFound); +} + +BasePaths::decl_iterator BasePaths::found_decls_begin() { + if (NumDeclsFound == 0) + ComputeDeclsFound(); + return DeclsFound; +} + +BasePaths::decl_iterator BasePaths::found_decls_end() { + if (NumDeclsFound == 0) + ComputeDeclsFound(); + return DeclsFound + NumDeclsFound; +} + +/// isAmbiguous - Determines whether the set of paths provided is +/// ambiguous, i.e., there are two or more paths that refer to +/// different base class subobjects of the same type. BaseType must be +/// an unqualified, canonical class type. +bool BasePaths::isAmbiguous(QualType BaseType) { + assert(BaseType->isCanonical() && "Base type must be the canonical type"); + assert(BaseType.getCVRQualifiers() == 0 && "Base type must be unqualified"); + std::pair<bool, unsigned>& Subobjects = ClassSubobjects[BaseType]; + return Subobjects.second + (Subobjects.first? 1 : 0) > 1; +} + +/// clear - Clear out all prior path information. +void BasePaths::clear() { + Paths.clear(); + ClassSubobjects.clear(); + ScratchPath.clear(); + DetectedVirtual = 0; +} + +/// @brief Swaps the contents of this BasePaths structure with the +/// contents of Other. +void BasePaths::swap(BasePaths &Other) { + std::swap(Origin, Other.Origin); + Paths.swap(Other.Paths); + ClassSubobjects.swap(Other.ClassSubobjects); + std::swap(FindAmbiguities, Other.FindAmbiguities); + std::swap(RecordPaths, Other.RecordPaths); + std::swap(DetectVirtual, Other.DetectVirtual); + std::swap(DetectedVirtual, Other.DetectedVirtual); +} + +/// IsDerivedFrom - Determine whether the type Derived is derived from +/// the type Base, ignoring qualifiers on Base and Derived. This +/// routine does not assess whether an actual conversion from a +/// Derived* to a Base* is legal, because it does not account for +/// ambiguous conversions or conversions to private/protected bases. +bool Sema::IsDerivedFrom(QualType Derived, QualType Base) { + BasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false, + /*DetectVirtual=*/false); + return IsDerivedFrom(Derived, Base, Paths); +} + +/// IsDerivedFrom - Determine whether the type Derived is derived from +/// the type Base, ignoring qualifiers on Base and Derived. This +/// routine does not assess whether an actual conversion from a +/// Derived* to a Base* is legal, because it does not account for +/// ambiguous conversions or conversions to private/protected +/// bases. This routine will use Paths to determine if there are +/// ambiguous paths (if @c Paths.isFindingAmbiguities()) and record +/// information about all of the paths (if @c Paths.isRecordingPaths()). +bool Sema::IsDerivedFrom(QualType Derived, QualType Base, BasePaths &Paths) { + Derived = Context.getCanonicalType(Derived).getUnqualifiedType(); + Base = Context.getCanonicalType(Base).getUnqualifiedType(); + + if (!Derived->isRecordType() || !Base->isRecordType()) + return false; + + if (Derived == Base) + return false; + + Paths.setOrigin(Derived); + return LookupInBases(cast<CXXRecordDecl>(Derived->getAsRecordType()->getDecl()), + MemberLookupCriteria(Base), Paths); +} + +/// LookupInBases - Look for something that meets the specified +/// Criteria within the base classes of Class (or any of its base +/// classes, transitively). This routine populates BasePaths with the +/// list of paths that one can take to find the entity that meets the +/// search criteria, and returns true if any such entity is found. The +/// various options passed to the BasePath constructor will affect the +/// behavior of this lookup, e.g., whether it finds ambiguities, +/// records paths, or attempts to detect the use of virtual base +/// classes. +bool Sema::LookupInBases(CXXRecordDecl *Class, + const MemberLookupCriteria& Criteria, + BasePaths &Paths) { + bool FoundPath = false; + + for (CXXRecordDecl::base_class_const_iterator BaseSpec = Class->bases_begin(), + BaseSpecEnd = Class->bases_end(); + BaseSpec != BaseSpecEnd; ++BaseSpec) { + // Find the record of the base class subobjects for this type. + QualType BaseType = Context.getCanonicalType(BaseSpec->getType()); + BaseType = BaseType.getUnqualifiedType(); + + // Determine whether we need to visit this base class at all, + // updating the count of subobjects appropriately. + std::pair<bool, unsigned>& Subobjects = Paths.ClassSubobjects[BaseType]; + bool VisitBase = true; + bool SetVirtual = false; + if (BaseSpec->isVirtual()) { + VisitBase = !Subobjects.first; + Subobjects.first = true; + if (Paths.isDetectingVirtual() && Paths.DetectedVirtual == 0) { + // If this is the first virtual we find, remember it. If it turns out + // there is no base path here, we'll reset it later. + Paths.DetectedVirtual = BaseType->getAsRecordType(); + SetVirtual = true; + } + } else + ++Subobjects.second; + + if (Paths.isRecordingPaths()) { + // Add this base specifier to the current path. + BasePathElement Element; + Element.Base = &*BaseSpec; + Element.Class = Class; + if (BaseSpec->isVirtual()) + Element.SubobjectNumber = 0; + else + Element.SubobjectNumber = Subobjects.second; + Paths.ScratchPath.push_back(Element); + } + + CXXRecordDecl *BaseRecord + = cast<CXXRecordDecl>(BaseSpec->getType()->getAsRecordType()->getDecl()); + + // Either look at the base class type or look into the base class + // type to see if we've found a member that meets the search + // criteria. + bool FoundPathToThisBase = false; + switch (Criteria.Kind) { + case MemberLookupCriteria::LK_Base: + FoundPathToThisBase + = (Context.getCanonicalType(BaseSpec->getType()) == Criteria.Base); + break; + case MemberLookupCriteria::LK_NamedMember: + Paths.ScratchPath.Decls = BaseRecord->lookup(Context, Criteria.Name); + while (Paths.ScratchPath.Decls.first != Paths.ScratchPath.Decls.second) { + if (isAcceptableLookupResult(*Paths.ScratchPath.Decls.first, + Criteria.NameKind, Criteria.IDNS)) { + FoundPathToThisBase = true; + break; + } + ++Paths.ScratchPath.Decls.first; + } + break; + case MemberLookupCriteria::LK_OverriddenMember: + Paths.ScratchPath.Decls = + BaseRecord->lookup(Context, Criteria.Method->getDeclName()); + while (Paths.ScratchPath.Decls.first != Paths.ScratchPath.Decls.second) { + if (CXXMethodDecl *MD = + dyn_cast<CXXMethodDecl>(*Paths.ScratchPath.Decls.first)) { + OverloadedFunctionDecl::function_iterator MatchedDecl; + if (MD->isVirtual() && + !IsOverload(Criteria.Method, MD, MatchedDecl)) { + FoundPathToThisBase = true; + break; + } + } + + ++Paths.ScratchPath.Decls.first; + } + break; + } + + if (FoundPathToThisBase) { + // We've found a path that terminates that this base. + FoundPath = true; + if (Paths.isRecordingPaths()) { + // We have a path. Make a copy of it before moving on. + Paths.Paths.push_back(Paths.ScratchPath); + } else if (!Paths.isFindingAmbiguities()) { + // We found a path and we don't care about ambiguities; + // return immediately. + return FoundPath; + } + } + // C++ [class.member.lookup]p2: + // A member name f in one sub-object B hides a member name f in + // a sub-object A if A is a base class sub-object of B. Any + // declarations that are so hidden are eliminated from + // consideration. + else if (VisitBase && LookupInBases(BaseRecord, Criteria, Paths)) { + // There is a path to a base class that meets the criteria. If we're not + // collecting paths or finding ambiguities, we're done. + FoundPath = true; + if (!Paths.isFindingAmbiguities()) + return FoundPath; + } + + // Pop this base specifier off the current path (if we're + // collecting paths). + if (Paths.isRecordingPaths()) + Paths.ScratchPath.pop_back(); + // If we set a virtual earlier, and this isn't a path, forget it again. + if (SetVirtual && !FoundPath) { + Paths.DetectedVirtual = 0; + } + } + + return FoundPath; +} + +/// CheckDerivedToBaseConversion - Check whether the Derived-to-Base +/// conversion (where Derived and Base are class types) is +/// well-formed, meaning that the conversion is unambiguous (and +/// that all of the base classes are accessible). Returns true +/// and emits a diagnostic if the code is ill-formed, returns false +/// otherwise. Loc is the location where this routine should point to +/// if there is an error, and Range is the source range to highlight +/// if there is an error. +bool +Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, + unsigned InaccessibleBaseID, + unsigned AmbigiousBaseConvID, + SourceLocation Loc, SourceRange Range, + DeclarationName Name) { + // First, determine whether the path from Derived to Base is + // ambiguous. This is slightly more expensive than checking whether + // the Derived to Base conversion exists, because here we need to + // explore multiple paths to determine if there is an ambiguity. + BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/false); + bool DerivationOkay = IsDerivedFrom(Derived, Base, Paths); + assert(DerivationOkay && + "Can only be used with a derived-to-base conversion"); + (void)DerivationOkay; + + if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) { + // Check that the base class can be accessed. + return CheckBaseClassAccess(Derived, Base, InaccessibleBaseID, Paths, Loc, + Name); + } + + // We know that the derived-to-base conversion is ambiguous, and + // we're going to produce a diagnostic. Perform the derived-to-base + // search just one more time to compute all of the possible paths so + // that we can print them out. This is more expensive than any of + // the previous derived-to-base checks we've done, but at this point + // performance isn't as much of an issue. + Paths.clear(); + Paths.setRecordingPaths(true); + bool StillOkay = IsDerivedFrom(Derived, Base, Paths); + assert(StillOkay && "Can only be used with a derived-to-base conversion"); + (void)StillOkay; + + // Build up a textual representation of the ambiguous paths, e.g., + // D -> B -> A, that will be used to illustrate the ambiguous + // conversions in the diagnostic. We only print one of the paths + // to each base class subobject. + std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths); + + Diag(Loc, AmbigiousBaseConvID) + << Derived << Base << PathDisplayStr << Range << Name; + return true; +} + +bool +Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, + SourceLocation Loc, SourceRange Range) { + return CheckDerivedToBaseConversion(Derived, Base, + diag::err_conv_to_inaccessible_base, + diag::err_ambiguous_derived_to_base_conv, + Loc, Range, DeclarationName()); +} + + +/// @brief Builds a string representing ambiguous paths from a +/// specific derived class to different subobjects of the same base +/// class. +/// +/// This function builds a string that can be used in error messages +/// to show the different paths that one can take through the +/// inheritance hierarchy to go from the derived class to different +/// subobjects of a base class. The result looks something like this: +/// @code +/// struct D -> struct B -> struct A +/// struct D -> struct C -> struct A +/// @endcode +std::string Sema::getAmbiguousPathsDisplayString(BasePaths &Paths) { + std::string PathDisplayStr; + std::set<unsigned> DisplayedPaths; + for (BasePaths::paths_iterator Path = Paths.begin(); + Path != Paths.end(); ++Path) { + if (DisplayedPaths.insert(Path->back().SubobjectNumber).second) { + // We haven't displayed a path to this particular base + // class subobject yet. + PathDisplayStr += "\n "; + PathDisplayStr += Paths.getOrigin().getAsString(); + for (BasePath::const_iterator Element = Path->begin(); + Element != Path->end(); ++Element) + PathDisplayStr += " -> " + Element->Base->getType().getAsString(); + } + } + + return PathDisplayStr; +} diff --git a/lib/Sema/SemaInherit.h b/lib/Sema/SemaInherit.h new file mode 100644 index 0000000..b1e791a --- /dev/null +++ b/lib/Sema/SemaInherit.h @@ -0,0 +1,248 @@ +//===------ SemaInherit.h - C++ Inheritance ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides Sema data structures that help analyse C++ +// inheritance semantics, including searching the inheritance +// hierarchy. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_INHERIT_H +#define LLVM_CLANG_SEMA_INHERIT_H + +#include "Sema.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeOrdering.h" +#include "llvm/ADT/SmallVector.h" +#include <list> +#include <map> + +namespace clang { + class CXXBaseSpecifier; + + /// BasePathElement - An element in a path from a derived class to a + /// base class. Each step in the path references the link from a + /// derived class to one of its direct base classes, along with a + /// base "number" that identifies which base subobject of the + /// original derived class we are referencing. + struct BasePathElement { + /// Base - The base specifier that states the link from a derived + /// class to a base class, which will be followed by this base + /// path element. + const CXXBaseSpecifier *Base; + + /// Class - The record decl of the class that the base is a base of. + const CXXRecordDecl *Class; + + /// SubobjectNumber - Identifies which base class subobject (of type + /// @c Base->getType()) this base path element refers to. This + /// value is only valid if @c !Base->isVirtual(), because there + /// is no base numbering for the zero or one virtual bases of a + /// given type. + int SubobjectNumber; + }; + + /// BasePath - Represents a path from a specific derived class + /// (which is not represented as part of the path) to a particular + /// (direct or indirect) base class subobject that contains some + /// number of declarations with the same name. Individual elements + /// in the path are described by the BasePathElement structure, + /// which captures both the link from a derived class to one of its + /// direct bases and identification describing which base class + /// subobject is being used. + struct BasePath : public llvm::SmallVector<BasePathElement, 4> { + /// Decls - The set of declarations found inside this base class + /// subobject. + DeclContext::lookup_result Decls; + }; + + /// BasePaths - Represents the set of paths from a derived class to + /// one of its (direct or indirect) bases. For example, given the + /// following class hierachy: + /// + /// @code + /// class A { }; + /// class B : public A { }; + /// class C : public A { }; + /// class D : public B, public C{ }; + /// @endcode + /// + /// There are two potential BasePaths to represent paths from D to a + /// base subobject of type A. One path is (D,0) -> (B,0) -> (A,0) + /// and another is (D,0)->(C,0)->(A,1). These two paths actually + /// refer to two different base class subobjects of the same type, + /// so the BasePaths object refers to an ambiguous path. On the + /// other hand, consider the following class hierarchy: + /// + /// @code + /// class A { }; + /// class B : public virtual A { }; + /// class C : public virtual A { }; + /// class D : public B, public C{ }; + /// @endcode + /// + /// Here, there are two potential BasePaths again, (D, 0) -> (B, 0) + /// -> (A,v) and (D, 0) -> (C, 0) -> (A, v), but since both of them + /// refer to the same base class subobject of type A (the virtual + /// one), there is no ambiguity. + class BasePaths { + /// Origin - The type from which this search originated. + QualType Origin; + + /// Paths - The actual set of paths that can be taken from the + /// derived class to the same base class. + std::list<BasePath> Paths; + + /// ClassSubobjects - Records the class subobjects for each class + /// type that we've seen. The first element in the pair says + /// whether we found a path to a virtual base for that class type, + /// while the element contains the number of non-virtual base + /// class subobjects for that class type. The key of the map is + /// the cv-unqualified canonical type of the base class subobject. + std::map<QualType, std::pair<bool, unsigned>, QualTypeOrdering> + ClassSubobjects; + + /// FindAmbiguities - Whether Sema::IsDerivedFrom should try find + /// ambiguous paths while it is looking for a path from a derived + /// type to a base type. + bool FindAmbiguities; + + /// RecordPaths - Whether Sema::IsDerivedFrom should record paths + /// while it is determining whether there are paths from a derived + /// type to a base type. + bool RecordPaths; + + /// DetectVirtual - Whether Sema::IsDerivedFrom should abort the search + /// if it finds a path that goes across a virtual base. The virtual class + /// is also recorded. + bool DetectVirtual; + + /// ScratchPath - A BasePath that is used by Sema::IsDerivedFrom + /// to help build the set of paths. + BasePath ScratchPath; + + /// DetectedVirtual - The base class that is virtual. + const RecordType *DetectedVirtual; + + /// \brief Array of the declarations that have been found. This + /// array is constructed only if needed, e.g., to iterate over the + /// results within LookupResult. + NamedDecl **DeclsFound; + unsigned NumDeclsFound; + + friend class Sema; + + void ComputeDeclsFound(); + + public: + typedef std::list<BasePath>::const_iterator paths_iterator; + typedef NamedDecl **decl_iterator; + + /// BasePaths - Construct a new BasePaths structure to record the + /// paths for a derived-to-base search. + explicit BasePaths(bool FindAmbiguities = true, + bool RecordPaths = true, + bool DetectVirtual = true) + : FindAmbiguities(FindAmbiguities), RecordPaths(RecordPaths), + DetectVirtual(DetectVirtual), DetectedVirtual(0), DeclsFound(0), + NumDeclsFound(0) + {} + + ~BasePaths() { delete [] DeclsFound; } + + paths_iterator begin() const { return Paths.begin(); } + paths_iterator end() const { return Paths.end(); } + + BasePath& front() { return Paths.front(); } + const BasePath& front() const { return Paths.front(); } + + decl_iterator found_decls_begin(); + decl_iterator found_decls_end(); + + bool isAmbiguous(QualType BaseType); + + /// isFindingAmbiguities - Whether we are finding multiple paths + /// to detect ambiguities. + bool isFindingAmbiguities() const { return FindAmbiguities; } + + /// isRecordingPaths - Whether we are recording paths. + bool isRecordingPaths() const { return RecordPaths; } + + /// setRecordingPaths - Specify whether we should be recording + /// paths or not. + void setRecordingPaths(bool RP) { RecordPaths = RP; } + + /// isDetectingVirtual - Whether we are detecting virtual bases. + bool isDetectingVirtual() const { return DetectVirtual; } + + /// getDetectedVirtual - The virtual base discovered on the path. + const RecordType* getDetectedVirtual() const { + return DetectedVirtual; + } + + /// @brief Retrieve the type from which this base-paths search + /// began + QualType getOrigin() const { return Origin; } + void setOrigin(QualType Type) { Origin = Type; } + + void clear(); + + void swap(BasePaths &Other); + }; + + /// MemberLookupCriteria - Criteria for performing lookup of a + /// member of a C++ class. Objects of this type are used to direct + /// Sema::LookupCXXClassMember. + struct MemberLookupCriteria { + /// LookupKind - the kind of lookup we're doing. + enum LookupKind { + LK_Base, + LK_NamedMember, + LK_OverriddenMember + }; + + /// MemberLookupCriteria - Constructs member lookup criteria to + /// search for a base class of type Base. + explicit MemberLookupCriteria(QualType Base) + : Kind(LK_Base), Base(Base) { } + + /// MemberLookupCriteria - Constructs member lookup criteria to + /// search for a class member with the given Name. + explicit MemberLookupCriteria(DeclarationName Name, + Sema::LookupNameKind NameKind, + unsigned IDNS) + : Kind(LK_NamedMember), Name(Name), NameKind(NameKind), IDNS(IDNS) { } + + explicit MemberLookupCriteria(CXXMethodDecl *MD) + : Kind(LK_OverriddenMember), Method(MD) { } + + /// Kind - The kind of lookup we're doing. + /// LK_Base if we are looking for a base class (whose + /// type is Base). LK_NamedMember if we are looking for a named member of + /// the class (with the name Name). + LookupKind Kind; + + /// Base - The type of the base class we're searching for, if + /// LookupBase is true. + QualType Base; + + /// Name - The name of the member we're searching for, if + /// LookupBase is false. + DeclarationName Name; + + Sema::LookupNameKind NameKind; + unsigned IDNS; + + CXXMethodDecl *Method; + }; +} + +#endif diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp new file mode 100644 index 0000000..4e0eb1d --- /dev/null +++ b/lib/Sema/SemaInit.cpp @@ -0,0 +1,1784 @@ +//===--- SemaInit.cpp - Semantic Analysis for Initializers ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for initializers. The main entry +// point is Sema::CheckInitList(), but all of the work is performed +// within the InitListChecker class. +// +// This file also implements Sema::CheckInitializerTypes. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/Parse/Designator.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include <map> +using namespace clang; + +//===----------------------------------------------------------------------===// +// Sema Initialization Checking +//===----------------------------------------------------------------------===// + +static Expr *IsStringInit(Expr *Init, QualType DeclType, ASTContext &Context) { + const ArrayType *AT = Context.getAsArrayType(DeclType); + if (!AT) return 0; + + if (!isa<ConstantArrayType>(AT) && !isa<IncompleteArrayType>(AT)) + return 0; + + // See if this is a string literal or @encode. + Init = Init->IgnoreParens(); + + // Handle @encode, which is a narrow string. + if (isa<ObjCEncodeExpr>(Init) && AT->getElementType()->isCharType()) + return Init; + + // Otherwise we can only handle string literals. + StringLiteral *SL = dyn_cast<StringLiteral>(Init); + if (SL == 0) return 0; + + QualType ElemTy = Context.getCanonicalType(AT->getElementType()); + // char array can be initialized with a narrow string. + // Only allow char x[] = "foo"; not char x[] = L"foo"; + if (!SL->isWide()) + return ElemTy->isCharType() ? Init : 0; + + // wchar_t array can be initialized with a wide string: C99 6.7.8p15 (with + // correction from DR343): "An array with element type compatible with a + // qualified or unqualified version of wchar_t may be initialized by a wide + // string literal, optionally enclosed in braces." + if (Context.typesAreCompatible(Context.getWCharType(), + ElemTy.getUnqualifiedType())) + return Init; + + return 0; +} + +static bool CheckSingleInitializer(Expr *&Init, QualType DeclType, + bool DirectInit, Sema &S) { + // Get the type before calling CheckSingleAssignmentConstraints(), since + // it can promote the expression. + QualType InitType = Init->getType(); + + if (S.getLangOptions().CPlusPlus) { + // FIXME: I dislike this error message. A lot. + if (S.PerformImplicitConversion(Init, DeclType, "initializing", DirectInit)) + return S.Diag(Init->getSourceRange().getBegin(), + diag::err_typecheck_convert_incompatible) + << DeclType << Init->getType() << "initializing" + << Init->getSourceRange(); + return false; + } + + Sema::AssignConvertType ConvTy = + S.CheckSingleAssignmentConstraints(DeclType, Init); + return S.DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType, + InitType, Init, "initializing"); +} + +static void CheckStringInit(Expr *Str, QualType &DeclT, Sema &S) { + // Get the length of the string as parsed. + uint64_t StrLength = + cast<ConstantArrayType>(Str->getType())->getSize().getZExtValue(); + + + const ArrayType *AT = S.Context.getAsArrayType(DeclT); + if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT)) { + // C99 6.7.8p14. We have an array of character type with unknown size + // being initialized to a string literal. + llvm::APSInt ConstVal(32); + ConstVal = StrLength; + // Return a new array type (C99 6.7.8p22). + DeclT = S.Context.getConstantArrayType(IAT->getElementType(), ConstVal, + ArrayType::Normal, 0); + return; + } + + const ConstantArrayType *CAT = cast<ConstantArrayType>(AT); + + // C99 6.7.8p14. We have an array of character type with known size. However, + // the size may be smaller or larger than the string we are initializing. + // FIXME: Avoid truncation for 64-bit length strings. + if (StrLength-1 > CAT->getSize().getZExtValue()) + S.Diag(Str->getSourceRange().getBegin(), + diag::warn_initializer_string_for_char_array_too_long) + << Str->getSourceRange(); + + // Set the type to the actual size that we are initializing. If we have + // something like: + // char x[1] = "foo"; + // then this will set the string literal's type to char[1]. + Str->setType(DeclT); +} + +bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType, + SourceLocation InitLoc, + DeclarationName InitEntity, bool DirectInit) { + if (DeclType->isDependentType() || + Init->isTypeDependent() || Init->isValueDependent()) + return false; + + // C++ [dcl.init.ref]p1: + // A variable declared to be a T& or T&&, that is "reference to type T" + // (8.3.2), shall be initialized by an object, or function, of + // type T or by an object that can be converted into a T. + if (DeclType->isReferenceType()) + return CheckReferenceInit(Init, DeclType, 0, false, DirectInit); + + // C99 6.7.8p3: The type of the entity to be initialized shall be an array + // of unknown size ("[]") or an object type that is not a variable array type. + if (const VariableArrayType *VAT = Context.getAsVariableArrayType(DeclType)) + return Diag(InitLoc, diag::err_variable_object_no_init) + << VAT->getSizeExpr()->getSourceRange(); + + InitListExpr *InitList = dyn_cast<InitListExpr>(Init); + if (!InitList) { + // FIXME: Handle wide strings + if (Expr *Str = IsStringInit(Init, DeclType, Context)) { + CheckStringInit(Str, DeclType, *this); + return false; + } + + // C++ [dcl.init]p14: + // -- If the destination type is a (possibly cv-qualified) class + // type: + if (getLangOptions().CPlusPlus && DeclType->isRecordType()) { + QualType DeclTypeC = Context.getCanonicalType(DeclType); + QualType InitTypeC = Context.getCanonicalType(Init->getType()); + + // -- If the initialization is direct-initialization, or if it is + // copy-initialization where the cv-unqualified version of the + // source type is the same class as, or a derived class of, the + // class of the destination, constructors are considered. + if ((DeclTypeC.getUnqualifiedType() == InitTypeC.getUnqualifiedType()) || + IsDerivedFrom(InitTypeC, DeclTypeC)) { + const CXXRecordDecl *RD = + cast<CXXRecordDecl>(DeclType->getAsRecordType()->getDecl()); + + // No need to make a CXXConstructExpr if both the ctor and dtor are + // trivial. + if (RD->hasTrivialConstructor() && RD->hasTrivialDestructor()) + return false; + + CXXConstructorDecl *Constructor + = PerformInitializationByConstructor(DeclType, &Init, 1, + InitLoc, Init->getSourceRange(), + InitEntity, + DirectInit? IK_Direct : IK_Copy); + if (!Constructor) + return true; + + Init = CXXConstructExpr::Create(Context, DeclType, Constructor, false, + &Init, 1); + return false; + } + + // -- Otherwise (i.e., for the remaining copy-initialization + // cases), user-defined conversion sequences that can + // convert from the source type to the destination type or + // (when a conversion function is used) to a derived class + // thereof are enumerated as described in 13.3.1.4, and the + // best one is chosen through overload resolution + // (13.3). If the conversion cannot be done or is + // ambiguous, the initialization is ill-formed. The + // function selected is called with the initializer + // expression as its argument; if the function is a + // constructor, the call initializes a temporary of the + // destination type. + // FIXME: We're pretending to do copy elision here; return to this when we + // have ASTs for such things. + if (!PerformImplicitConversion(Init, DeclType, "initializing")) + return false; + + if (InitEntity) + return Diag(InitLoc, diag::err_cannot_initialize_decl) + << InitEntity << (int)(Init->isLvalue(Context) == Expr::LV_Valid) + << Init->getType() << Init->getSourceRange(); + else + return Diag(InitLoc, diag::err_cannot_initialize_decl_noname) + << DeclType << (int)(Init->isLvalue(Context) == Expr::LV_Valid) + << Init->getType() << Init->getSourceRange(); + } + + // C99 6.7.8p16. + if (DeclType->isArrayType()) + return Diag(Init->getLocStart(), diag::err_array_init_list_required) + << Init->getSourceRange(); + + return CheckSingleInitializer(Init, DeclType, DirectInit, *this); + } + + bool hadError = CheckInitList(InitList, DeclType); + Init = InitList; + return hadError; +} + +//===----------------------------------------------------------------------===// +// Semantic checking for initializer lists. +//===----------------------------------------------------------------------===// + +/// @brief Semantic checking for initializer lists. +/// +/// The InitListChecker class contains a set of routines that each +/// handle the initialization of a certain kind of entity, e.g., +/// arrays, vectors, struct/union types, scalars, etc. The +/// InitListChecker itself performs a recursive walk of the subobject +/// structure of the type to be initialized, while stepping through +/// the initializer list one element at a time. The IList and Index +/// parameters to each of the Check* routines contain the active +/// (syntactic) initializer list and the index into that initializer +/// list that represents the current initializer. Each routine is +/// responsible for moving that Index forward as it consumes elements. +/// +/// Each Check* routine also has a StructuredList/StructuredIndex +/// arguments, which contains the current the "structured" (semantic) +/// initializer list and the index into that initializer list where we +/// are copying initializers as we map them over to the semantic +/// list. Once we have completed our recursive walk of the subobject +/// structure, we will have constructed a full semantic initializer +/// list. +/// +/// C99 designators cause changes in the initializer list traversal, +/// because they make the initialization "jump" into a specific +/// subobject and then continue the initialization from that +/// point. CheckDesignatedInitializer() recursively steps into the +/// designated subobject and manages backing out the recursion to +/// initialize the subobjects after the one designated. +namespace { +class InitListChecker { + Sema &SemaRef; + bool hadError; + std::map<InitListExpr *, InitListExpr *> SyntacticToSemantic; + InitListExpr *FullyStructuredList; + + void CheckImplicitInitList(InitListExpr *ParentIList, QualType T, + unsigned &Index, InitListExpr *StructuredList, + unsigned &StructuredIndex, + bool TopLevelObject = false); + void CheckExplicitInitList(InitListExpr *IList, QualType &T, + unsigned &Index, InitListExpr *StructuredList, + unsigned &StructuredIndex, + bool TopLevelObject = false); + void CheckListElementTypes(InitListExpr *IList, QualType &DeclType, + bool SubobjectIsDesignatorContext, + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex, + bool TopLevelObject = false); + void CheckSubElementType(InitListExpr *IList, QualType ElemType, + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex); + void CheckScalarType(InitListExpr *IList, QualType DeclType, + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex); + void CheckReferenceType(InitListExpr *IList, QualType DeclType, + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex); + void CheckVectorType(InitListExpr *IList, QualType DeclType, unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex); + void CheckStructUnionTypes(InitListExpr *IList, QualType DeclType, + RecordDecl::field_iterator Field, + bool SubobjectIsDesignatorContext, unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex, + bool TopLevelObject = false); + void CheckArrayType(InitListExpr *IList, QualType &DeclType, + llvm::APSInt elementIndex, + bool SubobjectIsDesignatorContext, unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex); + bool CheckDesignatedInitializer(InitListExpr *IList, DesignatedInitExpr *DIE, + unsigned DesigIdx, + QualType &CurrentObjectType, + RecordDecl::field_iterator *NextField, + llvm::APSInt *NextElementIndex, + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex, + bool FinishSubobjectInit, + bool TopLevelObject); + InitListExpr *getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, + QualType CurrentObjectType, + InitListExpr *StructuredList, + unsigned StructuredIndex, + SourceRange InitRange); + void UpdateStructuredListElement(InitListExpr *StructuredList, + unsigned &StructuredIndex, + Expr *expr); + int numArrayElements(QualType DeclType); + int numStructUnionElements(QualType DeclType); + + void FillInValueInitializations(InitListExpr *ILE); +public: + InitListChecker(Sema &S, InitListExpr *IL, QualType &T); + bool HadError() { return hadError; } + + // @brief Retrieves the fully-structured initializer list used for + // semantic analysis and code generation. + InitListExpr *getFullyStructuredList() const { return FullyStructuredList; } +}; +} // end anonymous namespace + +/// Recursively replaces NULL values within the given initializer list +/// with expressions that perform value-initialization of the +/// appropriate type. +void InitListChecker::FillInValueInitializations(InitListExpr *ILE) { + assert((ILE->getType() != SemaRef.Context.VoidTy) && + "Should not have void type"); + SourceLocation Loc = ILE->getSourceRange().getBegin(); + if (ILE->getSyntacticForm()) + Loc = ILE->getSyntacticForm()->getSourceRange().getBegin(); + + if (const RecordType *RType = ILE->getType()->getAsRecordType()) { + unsigned Init = 0, NumInits = ILE->getNumInits(); + for (RecordDecl::field_iterator + Field = RType->getDecl()->field_begin(SemaRef.Context), + FieldEnd = RType->getDecl()->field_end(SemaRef.Context); + Field != FieldEnd; ++Field) { + if (Field->isUnnamedBitfield()) + continue; + + if (Init >= NumInits || !ILE->getInit(Init)) { + if (Field->getType()->isReferenceType()) { + // C++ [dcl.init.aggr]p9: + // If an incomplete or empty initializer-list leaves a + // member of reference type uninitialized, the program is + // ill-formed. + SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized) + << Field->getType() + << ILE->getSyntacticForm()->getSourceRange(); + SemaRef.Diag(Field->getLocation(), + diag::note_uninit_reference_member); + hadError = true; + return; + } else if (SemaRef.CheckValueInitialization(Field->getType(), Loc)) { + hadError = true; + return; + } + + // FIXME: If value-initialization involves calling a constructor, should + // we make that call explicit in the representation (even when it means + // extending the initializer list)? + if (Init < NumInits && !hadError) + ILE->setInit(Init, + new (SemaRef.Context) ImplicitValueInitExpr(Field->getType())); + } else if (InitListExpr *InnerILE + = dyn_cast<InitListExpr>(ILE->getInit(Init))) + FillInValueInitializations(InnerILE); + ++Init; + + // Only look at the first initialization of a union. + if (RType->getDecl()->isUnion()) + break; + } + + return; + } + + QualType ElementType; + + unsigned NumInits = ILE->getNumInits(); + unsigned NumElements = NumInits; + if (const ArrayType *AType = SemaRef.Context.getAsArrayType(ILE->getType())) { + ElementType = AType->getElementType(); + if (const ConstantArrayType *CAType = dyn_cast<ConstantArrayType>(AType)) + NumElements = CAType->getSize().getZExtValue(); + } else if (const VectorType *VType = ILE->getType()->getAsVectorType()) { + ElementType = VType->getElementType(); + NumElements = VType->getNumElements(); + } else + ElementType = ILE->getType(); + + for (unsigned Init = 0; Init != NumElements; ++Init) { + if (Init >= NumInits || !ILE->getInit(Init)) { + if (SemaRef.CheckValueInitialization(ElementType, Loc)) { + hadError = true; + return; + } + + // FIXME: If value-initialization involves calling a constructor, should + // we make that call explicit in the representation (even when it means + // extending the initializer list)? + if (Init < NumInits && !hadError) + ILE->setInit(Init, + new (SemaRef.Context) ImplicitValueInitExpr(ElementType)); + } + else if (InitListExpr *InnerILE =dyn_cast<InitListExpr>(ILE->getInit(Init))) + FillInValueInitializations(InnerILE); + } +} + + +InitListChecker::InitListChecker(Sema &S, InitListExpr *IL, QualType &T) + : SemaRef(S) { + hadError = false; + + unsigned newIndex = 0; + unsigned newStructuredIndex = 0; + FullyStructuredList + = getStructuredSubobjectInit(IL, newIndex, T, 0, 0, IL->getSourceRange()); + CheckExplicitInitList(IL, T, newIndex, FullyStructuredList, newStructuredIndex, + /*TopLevelObject=*/true); + + if (!hadError) + FillInValueInitializations(FullyStructuredList); +} + +int InitListChecker::numArrayElements(QualType DeclType) { + // FIXME: use a proper constant + int maxElements = 0x7FFFFFFF; + if (const ConstantArrayType *CAT = + SemaRef.Context.getAsConstantArrayType(DeclType)) { + maxElements = static_cast<int>(CAT->getSize().getZExtValue()); + } + return maxElements; +} + +int InitListChecker::numStructUnionElements(QualType DeclType) { + RecordDecl *structDecl = DeclType->getAsRecordType()->getDecl(); + int InitializableMembers = 0; + for (RecordDecl::field_iterator + Field = structDecl->field_begin(SemaRef.Context), + FieldEnd = structDecl->field_end(SemaRef.Context); + Field != FieldEnd; ++Field) { + if ((*Field)->getIdentifier() || !(*Field)->isBitField()) + ++InitializableMembers; + } + if (structDecl->isUnion()) + return std::min(InitializableMembers, 1); + return InitializableMembers - structDecl->hasFlexibleArrayMember(); +} + +void InitListChecker::CheckImplicitInitList(InitListExpr *ParentIList, + QualType T, unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex, + bool TopLevelObject) { + int maxElements = 0; + + if (T->isArrayType()) + maxElements = numArrayElements(T); + else if (T->isStructureType() || T->isUnionType()) + maxElements = numStructUnionElements(T); + else if (T->isVectorType()) + maxElements = T->getAsVectorType()->getNumElements(); + else + assert(0 && "CheckImplicitInitList(): Illegal type"); + + if (maxElements == 0) { + SemaRef.Diag(ParentIList->getInit(Index)->getLocStart(), + diag::err_implicit_empty_initializer); + ++Index; + hadError = true; + return; + } + + // Build a structured initializer list corresponding to this subobject. + InitListExpr *StructuredSubobjectInitList + = getStructuredSubobjectInit(ParentIList, Index, T, StructuredList, + StructuredIndex, + SourceRange(ParentIList->getInit(Index)->getSourceRange().getBegin(), + ParentIList->getSourceRange().getEnd())); + unsigned StructuredSubobjectInitIndex = 0; + + // Check the element types and build the structural subobject. + unsigned StartIndex = Index; + CheckListElementTypes(ParentIList, T, false, Index, + StructuredSubobjectInitList, + StructuredSubobjectInitIndex, + TopLevelObject); + unsigned EndIndex = (Index == StartIndex? StartIndex : Index - 1); + StructuredSubobjectInitList->setType(T); + + // Update the structured sub-object initializer so that it's ending + // range corresponds with the end of the last initializer it used. + if (EndIndex < ParentIList->getNumInits()) { + SourceLocation EndLoc + = ParentIList->getInit(EndIndex)->getSourceRange().getEnd(); + StructuredSubobjectInitList->setRBraceLoc(EndLoc); + } +} + +void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T, + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex, + bool TopLevelObject) { + assert(IList->isExplicit() && "Illegal Implicit InitListExpr"); + SyntacticToSemantic[IList] = StructuredList; + StructuredList->setSyntacticForm(IList); + CheckListElementTypes(IList, T, true, Index, StructuredList, + StructuredIndex, TopLevelObject); + IList->setType(T); + StructuredList->setType(T); + if (hadError) + return; + + if (Index < IList->getNumInits()) { + // We have leftover initializers + if (StructuredIndex == 1 && + IsStringInit(StructuredList->getInit(0), T, SemaRef.Context)) { + unsigned DK = diag::warn_excess_initializers_in_char_array_initializer; + if (SemaRef.getLangOptions().CPlusPlus) { + DK = diag::err_excess_initializers_in_char_array_initializer; + hadError = true; + } + // Special-case + SemaRef.Diag(IList->getInit(Index)->getLocStart(), DK) + << IList->getInit(Index)->getSourceRange(); + } else if (!T->isIncompleteType()) { + // Don't complain for incomplete types, since we'll get an error + // elsewhere + QualType CurrentObjectType = StructuredList->getType(); + int initKind = + CurrentObjectType->isArrayType()? 0 : + CurrentObjectType->isVectorType()? 1 : + CurrentObjectType->isScalarType()? 2 : + CurrentObjectType->isUnionType()? 3 : + 4; + + unsigned DK = diag::warn_excess_initializers; + if (SemaRef.getLangOptions().CPlusPlus) { + DK = diag::err_excess_initializers; + hadError = true; + } + + SemaRef.Diag(IList->getInit(Index)->getLocStart(), DK) + << initKind << IList->getInit(Index)->getSourceRange(); + } + } + + if (T->isScalarType() && !TopLevelObject) + SemaRef.Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init) + << IList->getSourceRange() + << CodeModificationHint::CreateRemoval(SourceRange(IList->getLocStart())) + << CodeModificationHint::CreateRemoval(SourceRange(IList->getLocEnd())); +} + +void InitListChecker::CheckListElementTypes(InitListExpr *IList, + QualType &DeclType, + bool SubobjectIsDesignatorContext, + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex, + bool TopLevelObject) { + if (DeclType->isScalarType()) { + CheckScalarType(IList, DeclType, Index, StructuredList, StructuredIndex); + } else if (DeclType->isVectorType()) { + CheckVectorType(IList, DeclType, Index, StructuredList, StructuredIndex); + } else if (DeclType->isAggregateType()) { + if (DeclType->isRecordType()) { + RecordDecl *RD = DeclType->getAsRecordType()->getDecl(); + CheckStructUnionTypes(IList, DeclType, RD->field_begin(SemaRef.Context), + SubobjectIsDesignatorContext, Index, + StructuredList, StructuredIndex, + TopLevelObject); + } else if (DeclType->isArrayType()) { + llvm::APSInt Zero( + SemaRef.Context.getTypeSize(SemaRef.Context.getSizeType()), + false); + CheckArrayType(IList, DeclType, Zero, SubobjectIsDesignatorContext, Index, + StructuredList, StructuredIndex); + } + else + assert(0 && "Aggregate that isn't a structure or array?!"); + } else if (DeclType->isVoidType() || DeclType->isFunctionType()) { + // This type is invalid, issue a diagnostic. + ++Index; + SemaRef.Diag(IList->getLocStart(), diag::err_illegal_initializer_type) + << DeclType; + hadError = true; + } else if (DeclType->isRecordType()) { + // C++ [dcl.init]p14: + // [...] If the class is an aggregate (8.5.1), and the initializer + // is a brace-enclosed list, see 8.5.1. + // + // Note: 8.5.1 is handled below; here, we diagnose the case where + // we have an initializer list and a destination type that is not + // an aggregate. + // FIXME: In C++0x, this is yet another form of initialization. + SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list) + << DeclType << IList->getSourceRange(); + hadError = true; + } else if (DeclType->isReferenceType()) { + CheckReferenceType(IList, DeclType, Index, StructuredList, StructuredIndex); + } else { + // In C, all types are either scalars or aggregates, but + // additional handling is needed here for C++ (and possibly others?). + assert(0 && "Unsupported initializer type"); + } +} + +void InitListChecker::CheckSubElementType(InitListExpr *IList, + QualType ElemType, + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex) { + Expr *expr = IList->getInit(Index); + if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) { + unsigned newIndex = 0; + unsigned newStructuredIndex = 0; + InitListExpr *newStructuredList + = getStructuredSubobjectInit(IList, Index, ElemType, + StructuredList, StructuredIndex, + SubInitList->getSourceRange()); + CheckExplicitInitList(SubInitList, ElemType, newIndex, + newStructuredList, newStructuredIndex); + ++StructuredIndex; + ++Index; + } else if (Expr *Str = IsStringInit(expr, ElemType, SemaRef.Context)) { + CheckStringInit(Str, ElemType, SemaRef); + UpdateStructuredListElement(StructuredList, StructuredIndex, Str); + ++Index; + } else if (ElemType->isScalarType()) { + CheckScalarType(IList, ElemType, Index, StructuredList, StructuredIndex); + } else if (ElemType->isReferenceType()) { + CheckReferenceType(IList, ElemType, Index, StructuredList, StructuredIndex); + } else { + if (SemaRef.getLangOptions().CPlusPlus) { + // C++ [dcl.init.aggr]p12: + // All implicit type conversions (clause 4) are considered when + // initializing the aggregate member with an ini- tializer from + // an initializer-list. If the initializer can initialize a + // member, the member is initialized. [...] + ImplicitConversionSequence ICS + = SemaRef.TryCopyInitialization(expr, ElemType); + if (ICS.ConversionKind != ImplicitConversionSequence::BadConversion) { + if (SemaRef.PerformImplicitConversion(expr, ElemType, ICS, + "initializing")) + hadError = true; + UpdateStructuredListElement(StructuredList, StructuredIndex, expr); + ++Index; + return; + } + + // Fall through for subaggregate initialization + } else { + // C99 6.7.8p13: + // + // The initializer for a structure or union object that has + // automatic storage duration shall be either an initializer + // list as described below, or a single expression that has + // compatible structure or union type. In the latter case, the + // initial value of the object, including unnamed members, is + // that of the expression. + if (ElemType->isRecordType() && + SemaRef.Context.hasSameUnqualifiedType(expr->getType(), ElemType)) { + UpdateStructuredListElement(StructuredList, StructuredIndex, expr); + ++Index; + return; + } + + // Fall through for subaggregate initialization + } + + // C++ [dcl.init.aggr]p12: + // + // [...] Otherwise, if the member is itself a non-empty + // subaggregate, brace elision is assumed and the initializer is + // considered for the initialization of the first member of + // the subaggregate. + if (ElemType->isAggregateType() || ElemType->isVectorType()) { + CheckImplicitInitList(IList, ElemType, Index, StructuredList, + StructuredIndex); + ++StructuredIndex; + } else { + // We cannot initialize this element, so let + // PerformCopyInitialization produce the appropriate diagnostic. + SemaRef.PerformCopyInitialization(expr, ElemType, "initializing"); + hadError = true; + ++Index; + ++StructuredIndex; + } + } +} + +void InitListChecker::CheckScalarType(InitListExpr *IList, QualType DeclType, + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex) { + if (Index < IList->getNumInits()) { + Expr *expr = IList->getInit(Index); + if (isa<InitListExpr>(expr)) { + SemaRef.Diag(IList->getLocStart(), + diag::err_many_braces_around_scalar_init) + << IList->getSourceRange(); + hadError = true; + ++Index; + ++StructuredIndex; + return; + } else if (isa<DesignatedInitExpr>(expr)) { + SemaRef.Diag(expr->getSourceRange().getBegin(), + diag::err_designator_for_scalar_init) + << DeclType << expr->getSourceRange(); + hadError = true; + ++Index; + ++StructuredIndex; + return; + } + + Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer. + if (CheckSingleInitializer(expr, DeclType, false, SemaRef)) + hadError = true; // types weren't compatible. + else if (savExpr != expr) { + // The type was promoted, update initializer list. + IList->setInit(Index, expr); + } + if (hadError) + ++StructuredIndex; + else + UpdateStructuredListElement(StructuredList, StructuredIndex, expr); + ++Index; + } else { + SemaRef.Diag(IList->getLocStart(), diag::err_empty_scalar_initializer) + << IList->getSourceRange(); + hadError = true; + ++Index; + ++StructuredIndex; + return; + } +} + +void InitListChecker::CheckReferenceType(InitListExpr *IList, QualType DeclType, + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex) { + if (Index < IList->getNumInits()) { + Expr *expr = IList->getInit(Index); + if (isa<InitListExpr>(expr)) { + SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list) + << DeclType << IList->getSourceRange(); + hadError = true; + ++Index; + ++StructuredIndex; + return; + } + + Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer. + if (SemaRef.CheckReferenceInit(expr, DeclType)) + hadError = true; + else if (savExpr != expr) { + // The type was promoted, update initializer list. + IList->setInit(Index, expr); + } + if (hadError) + ++StructuredIndex; + else + UpdateStructuredListElement(StructuredList, StructuredIndex, expr); + ++Index; + } else { + // FIXME: It would be wonderful if we could point at the actual member. In + // general, it would be useful to pass location information down the stack, + // so that we know the location (or decl) of the "current object" being + // initialized. + SemaRef.Diag(IList->getLocStart(), + diag::err_init_reference_member_uninitialized) + << DeclType + << IList->getSourceRange(); + hadError = true; + ++Index; + ++StructuredIndex; + return; + } +} + +void InitListChecker::CheckVectorType(InitListExpr *IList, QualType DeclType, + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex) { + if (Index < IList->getNumInits()) { + const VectorType *VT = DeclType->getAsVectorType(); + int maxElements = VT->getNumElements(); + QualType elementType = VT->getElementType(); + + for (int i = 0; i < maxElements; ++i) { + // Don't attempt to go past the end of the init list + if (Index >= IList->getNumInits()) + break; + CheckSubElementType(IList, elementType, Index, + StructuredList, StructuredIndex); + } + } +} + +void InitListChecker::CheckArrayType(InitListExpr *IList, QualType &DeclType, + llvm::APSInt elementIndex, + bool SubobjectIsDesignatorContext, + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex) { + // Check for the special-case of initializing an array with a string. + if (Index < IList->getNumInits()) { + if (Expr *Str = IsStringInit(IList->getInit(Index), DeclType, + SemaRef.Context)) { + CheckStringInit(Str, DeclType, SemaRef); + // We place the string literal directly into the resulting + // initializer list. This is the only place where the structure + // of the structured initializer list doesn't match exactly, + // because doing so would involve allocating one character + // constant for each string. + UpdateStructuredListElement(StructuredList, StructuredIndex, Str); + StructuredList->resizeInits(SemaRef.Context, StructuredIndex); + ++Index; + return; + } + } + if (const VariableArrayType *VAT = + SemaRef.Context.getAsVariableArrayType(DeclType)) { + // Check for VLAs; in standard C it would be possible to check this + // earlier, but I don't know where clang accepts VLAs (gcc accepts + // them in all sorts of strange places). + SemaRef.Diag(VAT->getSizeExpr()->getLocStart(), + diag::err_variable_object_no_init) + << VAT->getSizeExpr()->getSourceRange(); + hadError = true; + ++Index; + ++StructuredIndex; + return; + } + + // We might know the maximum number of elements in advance. + llvm::APSInt maxElements(elementIndex.getBitWidth(), + elementIndex.isUnsigned()); + bool maxElementsKnown = false; + if (const ConstantArrayType *CAT = + SemaRef.Context.getAsConstantArrayType(DeclType)) { + maxElements = CAT->getSize(); + elementIndex.extOrTrunc(maxElements.getBitWidth()); + elementIndex.setIsUnsigned(maxElements.isUnsigned()); + maxElementsKnown = true; + } + + QualType elementType = SemaRef.Context.getAsArrayType(DeclType) + ->getElementType(); + while (Index < IList->getNumInits()) { + Expr *Init = IList->getInit(Index); + if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Init)) { + // If we're not the subobject that matches up with the '{' for + // the designator, we shouldn't be handling the + // designator. Return immediately. + if (!SubobjectIsDesignatorContext) + return; + + // Handle this designated initializer. elementIndex will be + // updated to be the next array element we'll initialize. + if (CheckDesignatedInitializer(IList, DIE, 0, + DeclType, 0, &elementIndex, Index, + StructuredList, StructuredIndex, true, + false)) { + hadError = true; + continue; + } + + if (elementIndex.getBitWidth() > maxElements.getBitWidth()) + maxElements.extend(elementIndex.getBitWidth()); + else if (elementIndex.getBitWidth() < maxElements.getBitWidth()) + elementIndex.extend(maxElements.getBitWidth()); + elementIndex.setIsUnsigned(maxElements.isUnsigned()); + + // If the array is of incomplete type, keep track of the number of + // elements in the initializer. + if (!maxElementsKnown && elementIndex > maxElements) + maxElements = elementIndex; + + continue; + } + + // If we know the maximum number of elements, and we've already + // hit it, stop consuming elements in the initializer list. + if (maxElementsKnown && elementIndex == maxElements) + break; + + // Check this element. + CheckSubElementType(IList, elementType, Index, + StructuredList, StructuredIndex); + ++elementIndex; + + // If the array is of incomplete type, keep track of the number of + // elements in the initializer. + if (!maxElementsKnown && elementIndex > maxElements) + maxElements = elementIndex; + } + if (!hadError && DeclType->isIncompleteArrayType()) { + // If this is an incomplete array type, the actual type needs to + // be calculated here. + llvm::APSInt Zero(maxElements.getBitWidth(), maxElements.isUnsigned()); + if (maxElements == Zero) { + // Sizing an array implicitly to zero is not allowed by ISO C, + // but is supported by GNU. + SemaRef.Diag(IList->getLocStart(), + diag::ext_typecheck_zero_array_size); + } + + DeclType = SemaRef.Context.getConstantArrayType(elementType, maxElements, + ArrayType::Normal, 0); + } +} + +void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, + QualType DeclType, + RecordDecl::field_iterator Field, + bool SubobjectIsDesignatorContext, + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex, + bool TopLevelObject) { + RecordDecl* structDecl = DeclType->getAsRecordType()->getDecl(); + + // If the record is invalid, some of it's members are invalid. To avoid + // confusion, we forgo checking the intializer for the entire record. + if (structDecl->isInvalidDecl()) { + hadError = true; + return; + } + + if (DeclType->isUnionType() && IList->getNumInits() == 0) { + // Value-initialize the first named member of the union. + RecordDecl *RD = DeclType->getAsRecordType()->getDecl(); + for (RecordDecl::field_iterator FieldEnd = RD->field_end(SemaRef.Context); + Field != FieldEnd; ++Field) { + if (Field->getDeclName()) { + StructuredList->setInitializedFieldInUnion(*Field); + break; + } + } + return; + } + + // If structDecl is a forward declaration, this loop won't do + // anything except look at designated initializers; That's okay, + // because an error should get printed out elsewhere. It might be + // worthwhile to skip over the rest of the initializer, though. + RecordDecl *RD = DeclType->getAsRecordType()->getDecl(); + RecordDecl::field_iterator FieldEnd = RD->field_end(SemaRef.Context); + bool InitializedSomething = false; + while (Index < IList->getNumInits()) { + Expr *Init = IList->getInit(Index); + + if (DesignatedInitExpr *DIE = dyn_cast<DesignatedInitExpr>(Init)) { + // If we're not the subobject that matches up with the '{' for + // the designator, we shouldn't be handling the + // designator. Return immediately. + if (!SubobjectIsDesignatorContext) + return; + + // Handle this designated initializer. Field will be updated to + // the next field that we'll be initializing. + if (CheckDesignatedInitializer(IList, DIE, 0, + DeclType, &Field, 0, Index, + StructuredList, StructuredIndex, + true, TopLevelObject)) + hadError = true; + + InitializedSomething = true; + continue; + } + + if (Field == FieldEnd) { + // We've run out of fields. We're done. + break; + } + + // We've already initialized a member of a union. We're done. + if (InitializedSomething && DeclType->isUnionType()) + break; + + // If we've hit the flexible array member at the end, we're done. + if (Field->getType()->isIncompleteArrayType()) + break; + + if (Field->isUnnamedBitfield()) { + // Don't initialize unnamed bitfields, e.g. "int : 20;" + ++Field; + continue; + } + + CheckSubElementType(IList, Field->getType(), Index, + StructuredList, StructuredIndex); + InitializedSomething = true; + + if (DeclType->isUnionType()) { + // Initialize the first field within the union. + StructuredList->setInitializedFieldInUnion(*Field); + } + + ++Field; + } + + if (Field == FieldEnd || !Field->getType()->isIncompleteArrayType() || + Index >= IList->getNumInits()) + return; + + // Handle GNU flexible array initializers. + if (!TopLevelObject && + (!isa<InitListExpr>(IList->getInit(Index)) || + cast<InitListExpr>(IList->getInit(Index))->getNumInits() > 0)) { + SemaRef.Diag(IList->getInit(Index)->getSourceRange().getBegin(), + diag::err_flexible_array_init_nonempty) + << IList->getInit(Index)->getSourceRange().getBegin(); + SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) + << *Field; + hadError = true; + ++Index; + return; + } else { + SemaRef.Diag(IList->getInit(Index)->getSourceRange().getBegin(), + diag::ext_flexible_array_init) + << IList->getInit(Index)->getSourceRange().getBegin(); + SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) + << *Field; + } + + if (isa<InitListExpr>(IList->getInit(Index))) + CheckSubElementType(IList, Field->getType(), Index, StructuredList, + StructuredIndex); + else + CheckImplicitInitList(IList, Field->getType(), Index, StructuredList, + StructuredIndex); +} + +/// \brief Expand a field designator that refers to a member of an +/// anonymous struct or union into a series of field designators that +/// refers to the field within the appropriate subobject. +/// +/// Field/FieldIndex will be updated to point to the (new) +/// currently-designated field. +static void ExpandAnonymousFieldDesignator(Sema &SemaRef, + DesignatedInitExpr *DIE, + unsigned DesigIdx, + FieldDecl *Field, + RecordDecl::field_iterator &FieldIter, + unsigned &FieldIndex) { + typedef DesignatedInitExpr::Designator Designator; + + // Build the path from the current object to the member of the + // anonymous struct/union (backwards). + llvm::SmallVector<FieldDecl *, 4> Path; + SemaRef.BuildAnonymousStructUnionMemberPath(Field, Path); + + // Build the replacement designators. + llvm::SmallVector<Designator, 4> Replacements; + for (llvm::SmallVector<FieldDecl *, 4>::reverse_iterator + FI = Path.rbegin(), FIEnd = Path.rend(); + FI != FIEnd; ++FI) { + if (FI + 1 == FIEnd) + Replacements.push_back(Designator((IdentifierInfo *)0, + DIE->getDesignator(DesigIdx)->getDotLoc(), + DIE->getDesignator(DesigIdx)->getFieldLoc())); + else + Replacements.push_back(Designator((IdentifierInfo *)0, SourceLocation(), + SourceLocation())); + Replacements.back().setField(*FI); + } + + // Expand the current designator into the set of replacement + // designators, so we have a full subobject path down to where the + // member of the anonymous struct/union is actually stored. + DIE->ExpandDesignator(DesigIdx, &Replacements[0], + &Replacements[0] + Replacements.size()); + + // Update FieldIter/FieldIndex; + RecordDecl *Record = cast<RecordDecl>(Path.back()->getDeclContext()); + FieldIter = Record->field_begin(SemaRef.Context); + FieldIndex = 0; + for (RecordDecl::field_iterator FEnd = Record->field_end(SemaRef.Context); + FieldIter != FEnd; ++FieldIter) { + if (FieldIter->isUnnamedBitfield()) + continue; + + if (*FieldIter == Path.back()) + return; + + ++FieldIndex; + } + + assert(false && "Unable to find anonymous struct/union field"); +} + +/// @brief Check the well-formedness of a C99 designated initializer. +/// +/// Determines whether the designated initializer @p DIE, which +/// resides at the given @p Index within the initializer list @p +/// IList, is well-formed for a current object of type @p DeclType +/// (C99 6.7.8). The actual subobject that this designator refers to +/// within the current subobject is returned in either +/// @p NextField or @p NextElementIndex (whichever is appropriate). +/// +/// @param IList The initializer list in which this designated +/// initializer occurs. +/// +/// @param DIE The designated initializer expression. +/// +/// @param DesigIdx The index of the current designator. +/// +/// @param DeclType The type of the "current object" (C99 6.7.8p17), +/// into which the designation in @p DIE should refer. +/// +/// @param NextField If non-NULL and the first designator in @p DIE is +/// a field, this will be set to the field declaration corresponding +/// to the field named by the designator. +/// +/// @param NextElementIndex If non-NULL and the first designator in @p +/// DIE is an array designator or GNU array-range designator, this +/// will be set to the last index initialized by this designator. +/// +/// @param Index Index into @p IList where the designated initializer +/// @p DIE occurs. +/// +/// @param StructuredList The initializer list expression that +/// describes all of the subobject initializers in the order they'll +/// actually be initialized. +/// +/// @returns true if there was an error, false otherwise. +bool +InitListChecker::CheckDesignatedInitializer(InitListExpr *IList, + DesignatedInitExpr *DIE, + unsigned DesigIdx, + QualType &CurrentObjectType, + RecordDecl::field_iterator *NextField, + llvm::APSInt *NextElementIndex, + unsigned &Index, + InitListExpr *StructuredList, + unsigned &StructuredIndex, + bool FinishSubobjectInit, + bool TopLevelObject) { + if (DesigIdx == DIE->size()) { + // Check the actual initialization for the designated object type. + bool prevHadError = hadError; + + // Temporarily remove the designator expression from the + // initializer list that the child calls see, so that we don't try + // to re-process the designator. + unsigned OldIndex = Index; + IList->setInit(OldIndex, DIE->getInit()); + + CheckSubElementType(IList, CurrentObjectType, Index, + StructuredList, StructuredIndex); + + // Restore the designated initializer expression in the syntactic + // form of the initializer list. + if (IList->getInit(OldIndex) != DIE->getInit()) + DIE->setInit(IList->getInit(OldIndex)); + IList->setInit(OldIndex, DIE); + + return hadError && !prevHadError; + } + + bool IsFirstDesignator = (DesigIdx == 0); + assert((IsFirstDesignator || StructuredList) && + "Need a non-designated initializer list to start from"); + + DesignatedInitExpr::Designator *D = DIE->getDesignator(DesigIdx); + // Determine the structural initializer list that corresponds to the + // current subobject. + StructuredList = IsFirstDesignator? SyntacticToSemantic[IList] + : getStructuredSubobjectInit(IList, Index, CurrentObjectType, + StructuredList, StructuredIndex, + SourceRange(D->getStartLocation(), + DIE->getSourceRange().getEnd())); + assert(StructuredList && "Expected a structured initializer list"); + + if (D->isFieldDesignator()) { + // C99 6.7.8p7: + // + // If a designator has the form + // + // . identifier + // + // then the current object (defined below) shall have + // structure or union type and the identifier shall be the + // name of a member of that type. + const RecordType *RT = CurrentObjectType->getAsRecordType(); + if (!RT) { + SourceLocation Loc = D->getDotLoc(); + if (Loc.isInvalid()) + Loc = D->getFieldLoc(); + SemaRef.Diag(Loc, diag::err_field_designator_non_aggr) + << SemaRef.getLangOptions().CPlusPlus << CurrentObjectType; + ++Index; + return true; + } + + // Note: we perform a linear search of the fields here, despite + // the fact that we have a faster lookup method, because we always + // need to compute the field's index. + FieldDecl *KnownField = D->getField(); + IdentifierInfo *FieldName = D->getFieldName(); + unsigned FieldIndex = 0; + RecordDecl::field_iterator + Field = RT->getDecl()->field_begin(SemaRef.Context), + FieldEnd = RT->getDecl()->field_end(SemaRef.Context); + for (; Field != FieldEnd; ++Field) { + if (Field->isUnnamedBitfield()) + continue; + + if (KnownField == *Field || Field->getIdentifier() == FieldName) + break; + + ++FieldIndex; + } + + if (Field == FieldEnd) { + // There was no normal field in the struct with the designated + // name. Perform another lookup for this name, which may find + // something that we can't designate (e.g., a member function), + // may find nothing, or may find a member of an anonymous + // struct/union. + DeclContext::lookup_result Lookup + = RT->getDecl()->lookup(SemaRef.Context, FieldName); + if (Lookup.first == Lookup.second) { + // Name lookup didn't find anything. + SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown) + << FieldName << CurrentObjectType; + ++Index; + return true; + } else if (!KnownField && isa<FieldDecl>(*Lookup.first) && + cast<RecordDecl>((*Lookup.first)->getDeclContext()) + ->isAnonymousStructOrUnion()) { + // Handle an field designator that refers to a member of an + // anonymous struct or union. + ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, + cast<FieldDecl>(*Lookup.first), + Field, FieldIndex); + D = DIE->getDesignator(DesigIdx); + } else { + // Name lookup found something, but it wasn't a field. + SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield) + << FieldName; + SemaRef.Diag((*Lookup.first)->getLocation(), + diag::note_field_designator_found); + ++Index; + return true; + } + } else if (!KnownField && + cast<RecordDecl>((*Field)->getDeclContext()) + ->isAnonymousStructOrUnion()) { + ExpandAnonymousFieldDesignator(SemaRef, DIE, DesigIdx, *Field, + Field, FieldIndex); + D = DIE->getDesignator(DesigIdx); + } + + // All of the fields of a union are located at the same place in + // the initializer list. + if (RT->getDecl()->isUnion()) { + FieldIndex = 0; + StructuredList->setInitializedFieldInUnion(*Field); + } + + // Update the designator with the field declaration. + D->setField(*Field); + + // Make sure that our non-designated initializer list has space + // for a subobject corresponding to this field. + if (FieldIndex >= StructuredList->getNumInits()) + StructuredList->resizeInits(SemaRef.Context, FieldIndex + 1); + + // This designator names a flexible array member. + if (Field->getType()->isIncompleteArrayType()) { + bool Invalid = false; + if ((DesigIdx + 1) != DIE->size()) { + // We can't designate an object within the flexible array + // member (because GCC doesn't allow it). + DesignatedInitExpr::Designator *NextD + = DIE->getDesignator(DesigIdx + 1); + SemaRef.Diag(NextD->getStartLocation(), + diag::err_designator_into_flexible_array_member) + << SourceRange(NextD->getStartLocation(), + DIE->getSourceRange().getEnd()); + SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) + << *Field; + Invalid = true; + } + + if (!hadError && !isa<InitListExpr>(DIE->getInit())) { + // The initializer is not an initializer list. + SemaRef.Diag(DIE->getInit()->getSourceRange().getBegin(), + diag::err_flexible_array_init_needs_braces) + << DIE->getInit()->getSourceRange(); + SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) + << *Field; + Invalid = true; + } + + // Handle GNU flexible array initializers. + if (!Invalid && !TopLevelObject && + cast<InitListExpr>(DIE->getInit())->getNumInits() > 0) { + SemaRef.Diag(DIE->getSourceRange().getBegin(), + diag::err_flexible_array_init_nonempty) + << DIE->getSourceRange().getBegin(); + SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member) + << *Field; + Invalid = true; + } + + if (Invalid) { + ++Index; + return true; + } + + // Initialize the array. + bool prevHadError = hadError; + unsigned newStructuredIndex = FieldIndex; + unsigned OldIndex = Index; + IList->setInit(Index, DIE->getInit()); + CheckSubElementType(IList, Field->getType(), Index, + StructuredList, newStructuredIndex); + IList->setInit(OldIndex, DIE); + if (hadError && !prevHadError) { + ++Field; + ++FieldIndex; + if (NextField) + *NextField = Field; + StructuredIndex = FieldIndex; + return true; + } + } else { + // Recurse to check later designated subobjects. + QualType FieldType = (*Field)->getType(); + unsigned newStructuredIndex = FieldIndex; + if (CheckDesignatedInitializer(IList, DIE, DesigIdx + 1, FieldType, 0, 0, + Index, StructuredList, newStructuredIndex, + true, false)) + return true; + } + + // Find the position of the next field to be initialized in this + // subobject. + ++Field; + ++FieldIndex; + + // If this the first designator, our caller will continue checking + // the rest of this struct/class/union subobject. + if (IsFirstDesignator) { + if (NextField) + *NextField = Field; + StructuredIndex = FieldIndex; + return false; + } + + if (!FinishSubobjectInit) + return false; + + // We've already initialized something in the union; we're done. + if (RT->getDecl()->isUnion()) + return hadError; + + // Check the remaining fields within this class/struct/union subobject. + bool prevHadError = hadError; + CheckStructUnionTypes(IList, CurrentObjectType, Field, false, Index, + StructuredList, FieldIndex); + return hadError && !prevHadError; + } + + // C99 6.7.8p6: + // + // If a designator has the form + // + // [ constant-expression ] + // + // then the current object (defined below) shall have array + // type and the expression shall be an integer constant + // expression. If the array is of unknown size, any + // nonnegative value is valid. + // + // Additionally, cope with the GNU extension that permits + // designators of the form + // + // [ constant-expression ... constant-expression ] + const ArrayType *AT = SemaRef.Context.getAsArrayType(CurrentObjectType); + if (!AT) { + SemaRef.Diag(D->getLBracketLoc(), diag::err_array_designator_non_array) + << CurrentObjectType; + ++Index; + return true; + } + + Expr *IndexExpr = 0; + llvm::APSInt DesignatedStartIndex, DesignatedEndIndex; + if (D->isArrayDesignator()) { + IndexExpr = DIE->getArrayIndex(*D); + DesignatedStartIndex = IndexExpr->EvaluateAsInt(SemaRef.Context); + DesignatedEndIndex = DesignatedStartIndex; + } else { + assert(D->isArrayRangeDesignator() && "Need array-range designator"); + + + DesignatedStartIndex = + DIE->getArrayRangeStart(*D)->EvaluateAsInt(SemaRef.Context); + DesignatedEndIndex = + DIE->getArrayRangeEnd(*D)->EvaluateAsInt(SemaRef.Context); + IndexExpr = DIE->getArrayRangeEnd(*D); + + if (DesignatedStartIndex.getZExtValue() !=DesignatedEndIndex.getZExtValue()) + FullyStructuredList->sawArrayRangeDesignator(); + } + + if (isa<ConstantArrayType>(AT)) { + llvm::APSInt MaxElements(cast<ConstantArrayType>(AT)->getSize(), false); + DesignatedStartIndex.extOrTrunc(MaxElements.getBitWidth()); + DesignatedStartIndex.setIsUnsigned(MaxElements.isUnsigned()); + DesignatedEndIndex.extOrTrunc(MaxElements.getBitWidth()); + DesignatedEndIndex.setIsUnsigned(MaxElements.isUnsigned()); + if (DesignatedEndIndex >= MaxElements) { + SemaRef.Diag(IndexExpr->getSourceRange().getBegin(), + diag::err_array_designator_too_large) + << DesignatedEndIndex.toString(10) << MaxElements.toString(10) + << IndexExpr->getSourceRange(); + ++Index; + return true; + } + } else { + // Make sure the bit-widths and signedness match. + if (DesignatedStartIndex.getBitWidth() > DesignatedEndIndex.getBitWidth()) + DesignatedEndIndex.extend(DesignatedStartIndex.getBitWidth()); + else if (DesignatedStartIndex.getBitWidth() < + DesignatedEndIndex.getBitWidth()) + DesignatedStartIndex.extend(DesignatedEndIndex.getBitWidth()); + DesignatedStartIndex.setIsUnsigned(true); + DesignatedEndIndex.setIsUnsigned(true); + } + + // Make sure that our non-designated initializer list has space + // for a subobject corresponding to this array element. + if (DesignatedEndIndex.getZExtValue() >= StructuredList->getNumInits()) + StructuredList->resizeInits(SemaRef.Context, + DesignatedEndIndex.getZExtValue() + 1); + + // Repeatedly perform subobject initializations in the range + // [DesignatedStartIndex, DesignatedEndIndex]. + + // Move to the next designator + unsigned ElementIndex = DesignatedStartIndex.getZExtValue(); + unsigned OldIndex = Index; + while (DesignatedStartIndex <= DesignatedEndIndex) { + // Recurse to check later designated subobjects. + QualType ElementType = AT->getElementType(); + Index = OldIndex; + if (CheckDesignatedInitializer(IList, DIE, DesigIdx + 1, ElementType, 0, 0, + Index, StructuredList, ElementIndex, + (DesignatedStartIndex == DesignatedEndIndex), + false)) + return true; + + // Move to the next index in the array that we'll be initializing. + ++DesignatedStartIndex; + ElementIndex = DesignatedStartIndex.getZExtValue(); + } + + // If this the first designator, our caller will continue checking + // the rest of this array subobject. + if (IsFirstDesignator) { + if (NextElementIndex) + *NextElementIndex = DesignatedStartIndex; + StructuredIndex = ElementIndex; + return false; + } + + if (!FinishSubobjectInit) + return false; + + // Check the remaining elements within this array subobject. + bool prevHadError = hadError; + CheckArrayType(IList, CurrentObjectType, DesignatedStartIndex, false, Index, + StructuredList, ElementIndex); + return hadError && !prevHadError; +} + +// Get the structured initializer list for a subobject of type +// @p CurrentObjectType. +InitListExpr * +InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, + QualType CurrentObjectType, + InitListExpr *StructuredList, + unsigned StructuredIndex, + SourceRange InitRange) { + Expr *ExistingInit = 0; + if (!StructuredList) + ExistingInit = SyntacticToSemantic[IList]; + else if (StructuredIndex < StructuredList->getNumInits()) + ExistingInit = StructuredList->getInit(StructuredIndex); + + if (InitListExpr *Result = dyn_cast_or_null<InitListExpr>(ExistingInit)) + return Result; + + if (ExistingInit) { + // We are creating an initializer list that initializes the + // subobjects of the current object, but there was already an + // initialization that completely initialized the current + // subobject, e.g., by a compound literal: + // + // struct X { int a, b; }; + // struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 }; + // + // Here, xs[0].a == 0 and xs[0].b == 3, since the second, + // designated initializer re-initializes the whole + // subobject [0], overwriting previous initializers. + SemaRef.Diag(InitRange.getBegin(), + diag::warn_subobject_initializer_overrides) + << InitRange; + SemaRef.Diag(ExistingInit->getSourceRange().getBegin(), + diag::note_previous_initializer) + << /*FIXME:has side effects=*/0 + << ExistingInit->getSourceRange(); + } + + InitListExpr *Result + = new (SemaRef.Context) InitListExpr(InitRange.getBegin(), 0, 0, + InitRange.getEnd()); + + Result->setType(CurrentObjectType); + + // Pre-allocate storage for the structured initializer list. + unsigned NumElements = 0; + unsigned NumInits = 0; + if (!StructuredList) + NumInits = IList->getNumInits(); + else if (Index < IList->getNumInits()) { + if (InitListExpr *SubList = dyn_cast<InitListExpr>(IList->getInit(Index))) + NumInits = SubList->getNumInits(); + } + + if (const ArrayType *AType + = SemaRef.Context.getAsArrayType(CurrentObjectType)) { + if (const ConstantArrayType *CAType = dyn_cast<ConstantArrayType>(AType)) { + NumElements = CAType->getSize().getZExtValue(); + // Simple heuristic so that we don't allocate a very large + // initializer with many empty entries at the end. + if (NumInits && NumElements > NumInits) + NumElements = 0; + } + } else if (const VectorType *VType = CurrentObjectType->getAsVectorType()) + NumElements = VType->getNumElements(); + else if (const RecordType *RType = CurrentObjectType->getAsRecordType()) { + RecordDecl *RDecl = RType->getDecl(); + if (RDecl->isUnion()) + NumElements = 1; + else + NumElements = std::distance(RDecl->field_begin(SemaRef.Context), + RDecl->field_end(SemaRef.Context)); + } + + if (NumElements < NumInits) + NumElements = IList->getNumInits(); + + Result->reserveInits(NumElements); + + // Link this new initializer list into the structured initializer + // lists. + if (StructuredList) + StructuredList->updateInit(StructuredIndex, Result); + else { + Result->setSyntacticForm(IList); + SyntacticToSemantic[IList] = Result; + } + + return Result; +} + +/// Update the initializer at index @p StructuredIndex within the +/// structured initializer list to the value @p expr. +void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList, + unsigned &StructuredIndex, + Expr *expr) { + // No structured initializer list to update + if (!StructuredList) + return; + + if (Expr *PrevInit = StructuredList->updateInit(StructuredIndex, expr)) { + // This initializer overwrites a previous initializer. Warn. + SemaRef.Diag(expr->getSourceRange().getBegin(), + diag::warn_initializer_overrides) + << expr->getSourceRange(); + SemaRef.Diag(PrevInit->getSourceRange().getBegin(), + diag::note_previous_initializer) + << /*FIXME:has side effects=*/0 + << PrevInit->getSourceRange(); + } + + ++StructuredIndex; +} + +/// Check that the given Index expression is a valid array designator +/// value. This is essentailly just a wrapper around +/// VerifyIntegerConstantExpression that also checks for negative values +/// and produces a reasonable diagnostic if there is a +/// failure. Returns true if there was an error, false otherwise. If +/// everything went okay, Value will receive the value of the constant +/// expression. +static bool +CheckArrayDesignatorExpr(Sema &S, Expr *Index, llvm::APSInt &Value) { + SourceLocation Loc = Index->getSourceRange().getBegin(); + + // Make sure this is an integer constant expression. + if (S.VerifyIntegerConstantExpression(Index, &Value)) + return true; + + if (Value.isSigned() && Value.isNegative()) + return S.Diag(Loc, diag::err_array_designator_negative) + << Value.toString(10) << Index->getSourceRange(); + + Value.setIsUnsigned(true); + return false; +} + +Sema::OwningExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, + SourceLocation Loc, + bool GNUSyntax, + OwningExprResult Init) { + typedef DesignatedInitExpr::Designator ASTDesignator; + + bool Invalid = false; + llvm::SmallVector<ASTDesignator, 32> Designators; + llvm::SmallVector<Expr *, 32> InitExpressions; + + // Build designators and check array designator expressions. + for (unsigned Idx = 0; Idx < Desig.getNumDesignators(); ++Idx) { + const Designator &D = Desig.getDesignator(Idx); + switch (D.getKind()) { + case Designator::FieldDesignator: + Designators.push_back(ASTDesignator(D.getField(), D.getDotLoc(), + D.getFieldLoc())); + break; + + case Designator::ArrayDesignator: { + Expr *Index = static_cast<Expr *>(D.getArrayIndex()); + llvm::APSInt IndexValue; + if (!Index->isTypeDependent() && + !Index->isValueDependent() && + CheckArrayDesignatorExpr(*this, Index, IndexValue)) + Invalid = true; + else { + Designators.push_back(ASTDesignator(InitExpressions.size(), + D.getLBracketLoc(), + D.getRBracketLoc())); + InitExpressions.push_back(Index); + } + break; + } + + case Designator::ArrayRangeDesignator: { + Expr *StartIndex = static_cast<Expr *>(D.getArrayRangeStart()); + Expr *EndIndex = static_cast<Expr *>(D.getArrayRangeEnd()); + llvm::APSInt StartValue; + llvm::APSInt EndValue; + bool StartDependent = StartIndex->isTypeDependent() || + StartIndex->isValueDependent(); + bool EndDependent = EndIndex->isTypeDependent() || + EndIndex->isValueDependent(); + if ((!StartDependent && + CheckArrayDesignatorExpr(*this, StartIndex, StartValue)) || + (!EndDependent && + CheckArrayDesignatorExpr(*this, EndIndex, EndValue))) + Invalid = true; + else { + // Make sure we're comparing values with the same bit width. + if (StartDependent || EndDependent) { + // Nothing to compute. + } else if (StartValue.getBitWidth() > EndValue.getBitWidth()) + EndValue.extend(StartValue.getBitWidth()); + else if (StartValue.getBitWidth() < EndValue.getBitWidth()) + StartValue.extend(EndValue.getBitWidth()); + + if (!StartDependent && !EndDependent && EndValue < StartValue) { + Diag(D.getEllipsisLoc(), diag::err_array_designator_empty_range) + << StartValue.toString(10) << EndValue.toString(10) + << StartIndex->getSourceRange() << EndIndex->getSourceRange(); + Invalid = true; + } else { + Designators.push_back(ASTDesignator(InitExpressions.size(), + D.getLBracketLoc(), + D.getEllipsisLoc(), + D.getRBracketLoc())); + InitExpressions.push_back(StartIndex); + InitExpressions.push_back(EndIndex); + } + } + break; + } + } + } + + if (Invalid || Init.isInvalid()) + return ExprError(); + + // Clear out the expressions within the designation. + Desig.ClearExprs(*this); + + DesignatedInitExpr *DIE + = DesignatedInitExpr::Create(Context, + Designators.data(), Designators.size(), + InitExpressions.data(), InitExpressions.size(), + Loc, GNUSyntax, Init.takeAs<Expr>()); + return Owned(DIE); +} + +bool Sema::CheckInitList(InitListExpr *&InitList, QualType &DeclType) { + InitListChecker CheckInitList(*this, InitList, DeclType); + if (!CheckInitList.HadError()) + InitList = CheckInitList.getFullyStructuredList(); + + return CheckInitList.HadError(); +} + +/// \brief Diagnose any semantic errors with value-initialization of +/// the given type. +/// +/// Value-initialization effectively zero-initializes any types +/// without user-declared constructors, and calls the default +/// constructor for a for any type that has a user-declared +/// constructor (C++ [dcl.init]p5). Value-initialization can fail when +/// a type with a user-declared constructor does not have an +/// accessible, non-deleted default constructor. In C, everything can +/// be value-initialized, which corresponds to C's notion of +/// initializing objects with static storage duration when no +/// initializer is provided for that object. +/// +/// \returns true if there was an error, false otherwise. +bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) { + // C++ [dcl.init]p5: + // + // To value-initialize an object of type T means: + + // -- if T is an array type, then each element is value-initialized; + if (const ArrayType *AT = Context.getAsArrayType(Type)) + return CheckValueInitialization(AT->getElementType(), Loc); + + if (const RecordType *RT = Type->getAsRecordType()) { + if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { + // -- if T is a class type (clause 9) with a user-declared + // constructor (12.1), then the default constructor for T is + // called (and the initialization is ill-formed if T has no + // accessible default constructor); + if (ClassDecl->hasUserDeclaredConstructor()) + // FIXME: Eventually, we'll need to put the constructor decl into the + // AST. + return PerformInitializationByConstructor(Type, 0, 0, Loc, + SourceRange(Loc), + DeclarationName(), + IK_Direct); + } + } + + if (Type->isReferenceType()) { + // C++ [dcl.init]p5: + // [...] A program that calls for default-initialization or + // value-initialization of an entity of reference type is + // ill-formed. [...] + // FIXME: Once we have code that goes through this path, add an actual + // diagnostic :) + } + + return false; +} diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp new file mode 100644 index 0000000..6212449 --- /dev/null +++ b/lib/Sema/SemaLookup.cpp @@ -0,0 +1,1626 @@ +//===--------------------- SemaLookup.cpp - Name Lookup ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements name lookup for C, C++, Objective-C, and +// Objective-C++. +// +//===----------------------------------------------------------------------===// +#include "Sema.h" +#include "SemaInherit.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/Parse/DeclSpec.h" +#include "clang/Basic/LangOptions.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include <set> +#include <vector> +#include <iterator> +#include <utility> +#include <algorithm> + +using namespace clang; + +typedef llvm::SmallVector<UsingDirectiveDecl*, 4> UsingDirectivesTy; +typedef llvm::DenseSet<NamespaceDecl*> NamespaceSet; +typedef llvm::SmallVector<Sema::LookupResult, 3> LookupResultsTy; + +/// UsingDirAncestorCompare - Implements strict weak ordering of +/// UsingDirectives. It orders them by address of its common ancestor. +struct UsingDirAncestorCompare { + + /// @brief Compares UsingDirectiveDecl common ancestor with DeclContext. + bool operator () (UsingDirectiveDecl *U, const DeclContext *Ctx) const { + return U->getCommonAncestor() < Ctx; + } + + /// @brief Compares UsingDirectiveDecl common ancestor with DeclContext. + bool operator () (const DeclContext *Ctx, UsingDirectiveDecl *U) const { + return Ctx < U->getCommonAncestor(); + } + + /// @brief Compares UsingDirectiveDecl common ancestors. + bool operator () (UsingDirectiveDecl *U1, UsingDirectiveDecl *U2) const { + return U1->getCommonAncestor() < U2->getCommonAncestor(); + } +}; + +/// AddNamespaceUsingDirectives - Adds all UsingDirectiveDecl's to heap UDirs +/// (ordered by common ancestors), found in namespace NS, +/// including all found (recursively) in their nominated namespaces. +void AddNamespaceUsingDirectives(ASTContext &Context, + DeclContext *NS, + UsingDirectivesTy &UDirs, + NamespaceSet &Visited) { + DeclContext::udir_iterator I, End; + + for (llvm::tie(I, End) = NS->getUsingDirectives(Context); I !=End; ++I) { + UDirs.push_back(*I); + std::push_heap(UDirs.begin(), UDirs.end(), UsingDirAncestorCompare()); + NamespaceDecl *Nominated = (*I)->getNominatedNamespace(); + if (Visited.insert(Nominated).second) + AddNamespaceUsingDirectives(Context, Nominated, UDirs, /*ref*/ Visited); + } +} + +/// AddScopeUsingDirectives - Adds all UsingDirectiveDecl's found in Scope S, +/// including all found in the namespaces they nominate. +static void AddScopeUsingDirectives(ASTContext &Context, Scope *S, + UsingDirectivesTy &UDirs) { + NamespaceSet VisitedNS; + + if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) { + + if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(Ctx)) + VisitedNS.insert(NS); + + AddNamespaceUsingDirectives(Context, Ctx, UDirs, /*ref*/ VisitedNS); + + } else { + Scope::udir_iterator I = S->using_directives_begin(), + End = S->using_directives_end(); + + for (; I != End; ++I) { + UsingDirectiveDecl *UD = I->getAs<UsingDirectiveDecl>(); + UDirs.push_back(UD); + std::push_heap(UDirs.begin(), UDirs.end(), UsingDirAncestorCompare()); + + NamespaceDecl *Nominated = UD->getNominatedNamespace(); + if (!VisitedNS.count(Nominated)) { + VisitedNS.insert(Nominated); + AddNamespaceUsingDirectives(Context, Nominated, UDirs, + /*ref*/ VisitedNS); + } + } + } +} + +/// MaybeConstructOverloadSet - Name lookup has determined that the +/// elements in [I, IEnd) have the name that we are looking for, and +/// *I is a match for the namespace. This routine returns an +/// appropriate Decl for name lookup, which may either be *I or an +/// OverloadedFunctionDecl that represents the overloaded functions in +/// [I, IEnd). +/// +/// The existance of this routine is temporary; users of LookupResult +/// should be able to handle multiple results, to deal with cases of +/// ambiguity and overloaded functions without needing to create a +/// Decl node. +template<typename DeclIterator> +static NamedDecl * +MaybeConstructOverloadSet(ASTContext &Context, + DeclIterator I, DeclIterator IEnd) { + assert(I != IEnd && "Iterator range cannot be empty"); + assert(!isa<OverloadedFunctionDecl>(*I) && + "Cannot have an overloaded function"); + + if (isa<FunctionDecl>(*I)) { + // If we found a function, there might be more functions. If + // so, collect them into an overload set. + DeclIterator Last = I; + OverloadedFunctionDecl *Ovl = 0; + for (++Last; Last != IEnd && isa<FunctionDecl>(*Last); ++Last) { + if (!Ovl) { + // FIXME: We leak this overload set. Eventually, we want to stop + // building the declarations for these overload sets, so there will be + // nothing to leak. + Ovl = OverloadedFunctionDecl::Create(Context, (*I)->getDeclContext(), + (*I)->getDeclName()); + Ovl->addOverload(cast<FunctionDecl>(*I)); + } + Ovl->addOverload(cast<FunctionDecl>(*Last)); + } + + // If we had more than one function, we built an overload + // set. Return it. + if (Ovl) + return Ovl; + } + + return *I; +} + +/// Merges together multiple LookupResults dealing with duplicated Decl's. +static Sema::LookupResult +MergeLookupResults(ASTContext &Context, LookupResultsTy &Results) { + typedef Sema::LookupResult LResult; + typedef llvm::SmallPtrSet<NamedDecl*, 4> DeclsSetTy; + + // Remove duplicated Decl pointing at same Decl, by storing them in + // associative collection. This might be case for code like: + // + // namespace A { int i; } + // namespace B { using namespace A; } + // namespace C { using namespace A; } + // + // void foo() { + // using namespace B; + // using namespace C; + // ++i; // finds A::i, from both namespace B and C at global scope + // } + // + // C++ [namespace.qual].p3: + // The same declaration found more than once is not an ambiguity + // (because it is still a unique declaration). + DeclsSetTy FoundDecls; + + // Counter of tag names, and functions for resolving ambiguity + // and name hiding. + std::size_t TagNames = 0, Functions = 0, OrdinaryNonFunc = 0; + + LookupResultsTy::iterator I = Results.begin(), End = Results.end(); + + // No name lookup results, return early. + if (I == End) return LResult::CreateLookupResult(Context, 0); + + // Keep track of the tag declaration we found. We only use this if + // we find a single tag declaration. + TagDecl *TagFound = 0; + + for (; I != End; ++I) { + switch (I->getKind()) { + case LResult::NotFound: + assert(false && + "Should be always successful name lookup result here."); + break; + + case LResult::AmbiguousReference: + case LResult::AmbiguousBaseSubobjectTypes: + case LResult::AmbiguousBaseSubobjects: + assert(false && "Shouldn't get ambiguous lookup here."); + break; + + case LResult::Found: { + NamedDecl *ND = I->getAsDecl(); + if (TagDecl *TD = dyn_cast<TagDecl>(ND)) { + TagFound = Context.getCanonicalDecl(TD); + TagNames += FoundDecls.insert(TagFound)? 1 : 0; + } else if (isa<FunctionDecl>(ND)) + Functions += FoundDecls.insert(ND)? 1 : 0; + else + FoundDecls.insert(ND); + break; + } + + case LResult::FoundOverloaded: + for (LResult::iterator FI = I->begin(), FEnd = I->end(); FI != FEnd; ++FI) + Functions += FoundDecls.insert(*FI)? 1 : 0; + break; + } + } + OrdinaryNonFunc = FoundDecls.size() - TagNames - Functions; + bool Ambiguous = false, NameHidesTags = false; + + if (FoundDecls.size() == 1) { + // 1) Exactly one result. + } else if (TagNames > 1) { + // 2) Multiple tag names (even though they may be hidden by an + // object name). + Ambiguous = true; + } else if (FoundDecls.size() - TagNames == 1) { + // 3) Ordinary name hides (optional) tag. + NameHidesTags = TagFound; + } else if (Functions) { + // C++ [basic.lookup].p1: + // ... Name lookup may associate more than one declaration with + // a name if it finds the name to be a function name; the declarations + // are said to form a set of overloaded functions (13.1). + // Overload resolution (13.3) takes place after name lookup has succeeded. + // + if (!OrdinaryNonFunc) { + // 4) Functions hide tag names. + NameHidesTags = TagFound; + } else { + // 5) Functions + ordinary names. + Ambiguous = true; + } + } else { + // 6) Multiple non-tag names + Ambiguous = true; + } + + if (Ambiguous) + return LResult::CreateLookupResult(Context, + FoundDecls.begin(), FoundDecls.size()); + if (NameHidesTags) { + // There's only one tag, TagFound. Remove it. + assert(TagFound && FoundDecls.count(TagFound) && "No tag name found?"); + FoundDecls.erase(TagFound); + } + + // Return successful name lookup result. + return LResult::CreateLookupResult(Context, + MaybeConstructOverloadSet(Context, + FoundDecls.begin(), + FoundDecls.end())); +} + +// Retrieve the set of identifier namespaces that correspond to a +// specific kind of name lookup. +inline unsigned +getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind, + bool CPlusPlus) { + unsigned IDNS = 0; + switch (NameKind) { + case Sema::LookupOrdinaryName: + case Sema::LookupOperatorName: + case Sema::LookupRedeclarationWithLinkage: + IDNS = Decl::IDNS_Ordinary; + if (CPlusPlus) + IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member; + break; + + case Sema::LookupTagName: + IDNS = Decl::IDNS_Tag; + break; + + case Sema::LookupMemberName: + IDNS = Decl::IDNS_Member; + if (CPlusPlus) + IDNS |= Decl::IDNS_Tag | Decl::IDNS_Ordinary; + break; + + case Sema::LookupNestedNameSpecifierName: + case Sema::LookupNamespaceName: + IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member; + break; + + case Sema::LookupObjCProtocolName: + IDNS = Decl::IDNS_ObjCProtocol; + break; + + case Sema::LookupObjCImplementationName: + IDNS = Decl::IDNS_ObjCImplementation; + break; + + case Sema::LookupObjCCategoryImplName: + IDNS = Decl::IDNS_ObjCCategoryImpl; + break; + } + return IDNS; +} + +Sema::LookupResult +Sema::LookupResult::CreateLookupResult(ASTContext &Context, NamedDecl *D) { + if (ObjCCompatibleAliasDecl *Alias + = dyn_cast_or_null<ObjCCompatibleAliasDecl>(D)) + D = Alias->getClassInterface(); + + LookupResult Result; + Result.StoredKind = (D && isa<OverloadedFunctionDecl>(D))? + OverloadedDeclSingleDecl : SingleDecl; + Result.First = reinterpret_cast<uintptr_t>(D); + Result.Last = 0; + Result.Context = &Context; + return Result; +} + +/// @brief Moves the name-lookup results from Other to this LookupResult. +Sema::LookupResult +Sema::LookupResult::CreateLookupResult(ASTContext &Context, + IdentifierResolver::iterator F, + IdentifierResolver::iterator L) { + LookupResult Result; + Result.Context = &Context; + + if (F != L && isa<FunctionDecl>(*F)) { + IdentifierResolver::iterator Next = F; + ++Next; + if (Next != L && isa<FunctionDecl>(*Next)) { + Result.StoredKind = OverloadedDeclFromIdResolver; + Result.First = F.getAsOpaqueValue(); + Result.Last = L.getAsOpaqueValue(); + return Result; + } + } + + Decl *D = *F; + if (ObjCCompatibleAliasDecl *Alias + = dyn_cast_or_null<ObjCCompatibleAliasDecl>(D)) + D = Alias->getClassInterface(); + + Result.StoredKind = SingleDecl; + Result.First = reinterpret_cast<uintptr_t>(D); + Result.Last = 0; + return Result; +} + +Sema::LookupResult +Sema::LookupResult::CreateLookupResult(ASTContext &Context, + DeclContext::lookup_iterator F, + DeclContext::lookup_iterator L) { + LookupResult Result; + Result.Context = &Context; + + if (F != L && isa<FunctionDecl>(*F)) { + DeclContext::lookup_iterator Next = F; + ++Next; + if (Next != L && isa<FunctionDecl>(*Next)) { + Result.StoredKind = OverloadedDeclFromDeclContext; + Result.First = reinterpret_cast<uintptr_t>(F); + Result.Last = reinterpret_cast<uintptr_t>(L); + return Result; + } + } + + Decl *D = *F; + if (ObjCCompatibleAliasDecl *Alias + = dyn_cast_or_null<ObjCCompatibleAliasDecl>(D)) + D = Alias->getClassInterface(); + + Result.StoredKind = SingleDecl; + Result.First = reinterpret_cast<uintptr_t>(D); + Result.Last = 0; + return Result; +} + +/// @brief Determine the result of name lookup. +Sema::LookupResult::LookupKind Sema::LookupResult::getKind() const { + switch (StoredKind) { + case SingleDecl: + return (reinterpret_cast<Decl *>(First) != 0)? Found : NotFound; + + case OverloadedDeclSingleDecl: + case OverloadedDeclFromIdResolver: + case OverloadedDeclFromDeclContext: + return FoundOverloaded; + + case AmbiguousLookupStoresBasePaths: + return Last? AmbiguousBaseSubobjectTypes : AmbiguousBaseSubobjects; + + case AmbiguousLookupStoresDecls: + return AmbiguousReference; + } + + // We can't ever get here. + return NotFound; +} + +/// @brief Converts the result of name lookup into a single (possible +/// NULL) pointer to a declaration. +/// +/// The resulting declaration will either be the declaration we found +/// (if only a single declaration was found), an +/// OverloadedFunctionDecl (if an overloaded function was found), or +/// NULL (if no declaration was found). This conversion must not be +/// used anywhere where name lookup could result in an ambiguity. +/// +/// The OverloadedFunctionDecl conversion is meant as a stop-gap +/// solution, since it causes the OverloadedFunctionDecl to be +/// leaked. FIXME: Eventually, there will be a better way to iterate +/// over the set of overloaded functions returned by name lookup. +NamedDecl *Sema::LookupResult::getAsDecl() const { + switch (StoredKind) { + case SingleDecl: + return reinterpret_cast<NamedDecl *>(First); + + case OverloadedDeclFromIdResolver: + return MaybeConstructOverloadSet(*Context, + IdentifierResolver::iterator::getFromOpaqueValue(First), + IdentifierResolver::iterator::getFromOpaqueValue(Last)); + + case OverloadedDeclFromDeclContext: + return MaybeConstructOverloadSet(*Context, + reinterpret_cast<DeclContext::lookup_iterator>(First), + reinterpret_cast<DeclContext::lookup_iterator>(Last)); + + case OverloadedDeclSingleDecl: + return reinterpret_cast<OverloadedFunctionDecl*>(First); + + case AmbiguousLookupStoresDecls: + case AmbiguousLookupStoresBasePaths: + assert(false && + "Name lookup returned an ambiguity that could not be handled"); + break; + } + + return 0; +} + +/// @brief Retrieves the BasePaths structure describing an ambiguous +/// name lookup, or null. +BasePaths *Sema::LookupResult::getBasePaths() const { + if (StoredKind == AmbiguousLookupStoresBasePaths) + return reinterpret_cast<BasePaths *>(First); + return 0; +} + +Sema::LookupResult::iterator::reference +Sema::LookupResult::iterator::operator*() const { + switch (Result->StoredKind) { + case SingleDecl: + return reinterpret_cast<NamedDecl*>(Current); + + case OverloadedDeclSingleDecl: + return *reinterpret_cast<NamedDecl**>(Current); + + case OverloadedDeclFromIdResolver: + return *IdentifierResolver::iterator::getFromOpaqueValue(Current); + + case AmbiguousLookupStoresBasePaths: + if (Result->Last) + return *reinterpret_cast<NamedDecl**>(Current); + + // Fall through to handle the DeclContext::lookup_iterator we're + // storing. + + case OverloadedDeclFromDeclContext: + case AmbiguousLookupStoresDecls: + return *reinterpret_cast<DeclContext::lookup_iterator>(Current); + } + + return 0; +} + +Sema::LookupResult::iterator& Sema::LookupResult::iterator::operator++() { + switch (Result->StoredKind) { + case SingleDecl: + Current = reinterpret_cast<uintptr_t>((NamedDecl*)0); + break; + + case OverloadedDeclSingleDecl: { + NamedDecl ** I = reinterpret_cast<NamedDecl**>(Current); + ++I; + Current = reinterpret_cast<uintptr_t>(I); + break; + } + + case OverloadedDeclFromIdResolver: { + IdentifierResolver::iterator I + = IdentifierResolver::iterator::getFromOpaqueValue(Current); + ++I; + Current = I.getAsOpaqueValue(); + break; + } + + case AmbiguousLookupStoresBasePaths: + if (Result->Last) { + NamedDecl ** I = reinterpret_cast<NamedDecl**>(Current); + ++I; + Current = reinterpret_cast<uintptr_t>(I); + break; + } + // Fall through to handle the DeclContext::lookup_iterator we're + // storing. + + case OverloadedDeclFromDeclContext: + case AmbiguousLookupStoresDecls: { + DeclContext::lookup_iterator I + = reinterpret_cast<DeclContext::lookup_iterator>(Current); + ++I; + Current = reinterpret_cast<uintptr_t>(I); + break; + } + } + + return *this; +} + +Sema::LookupResult::iterator Sema::LookupResult::begin() { + switch (StoredKind) { + case SingleDecl: + case OverloadedDeclFromIdResolver: + case OverloadedDeclFromDeclContext: + case AmbiguousLookupStoresDecls: + return iterator(this, First); + + case OverloadedDeclSingleDecl: { + OverloadedFunctionDecl * Ovl = + reinterpret_cast<OverloadedFunctionDecl*>(First); + return iterator(this, + reinterpret_cast<uintptr_t>(&(*Ovl->function_begin()))); + } + + case AmbiguousLookupStoresBasePaths: + if (Last) + return iterator(this, + reinterpret_cast<uintptr_t>(getBasePaths()->found_decls_begin())); + else + return iterator(this, + reinterpret_cast<uintptr_t>(getBasePaths()->front().Decls.first)); + } + + // Required to suppress GCC warning. + return iterator(); +} + +Sema::LookupResult::iterator Sema::LookupResult::end() { + switch (StoredKind) { + case SingleDecl: + case OverloadedDeclFromIdResolver: + case OverloadedDeclFromDeclContext: + case AmbiguousLookupStoresDecls: + return iterator(this, Last); + + case OverloadedDeclSingleDecl: { + OverloadedFunctionDecl * Ovl = + reinterpret_cast<OverloadedFunctionDecl*>(First); + return iterator(this, + reinterpret_cast<uintptr_t>(&(*Ovl->function_end()))); + } + + case AmbiguousLookupStoresBasePaths: + if (Last) + return iterator(this, + reinterpret_cast<uintptr_t>(getBasePaths()->found_decls_end())); + else + return iterator(this, reinterpret_cast<uintptr_t>( + getBasePaths()->front().Decls.second)); + } + + // Required to suppress GCC warning. + return iterator(); +} + +void Sema::LookupResult::Destroy() { + if (BasePaths *Paths = getBasePaths()) + delete Paths; + else if (getKind() == AmbiguousReference) + delete[] reinterpret_cast<NamedDecl **>(First); +} + +static void +CppNamespaceLookup(ASTContext &Context, DeclContext *NS, + DeclarationName Name, Sema::LookupNameKind NameKind, + unsigned IDNS, LookupResultsTy &Results, + UsingDirectivesTy *UDirs = 0) { + + assert(NS && NS->isFileContext() && "CppNamespaceLookup() requires namespace!"); + + // Perform qualified name lookup into the LookupCtx. + DeclContext::lookup_iterator I, E; + for (llvm::tie(I, E) = NS->lookup(Context, Name); I != E; ++I) + if (Sema::isAcceptableLookupResult(*I, NameKind, IDNS)) { + Results.push_back(Sema::LookupResult::CreateLookupResult(Context, I, E)); + break; + } + + if (UDirs) { + // For each UsingDirectiveDecl, which common ancestor is equal + // to NS, we preform qualified name lookup into namespace nominated by it. + UsingDirectivesTy::const_iterator UI, UEnd; + llvm::tie(UI, UEnd) = + std::equal_range(UDirs->begin(), UDirs->end(), NS, + UsingDirAncestorCompare()); + + for (; UI != UEnd; ++UI) + CppNamespaceLookup(Context, (*UI)->getNominatedNamespace(), + Name, NameKind, IDNS, Results); + } +} + +static bool isNamespaceOrTranslationUnitScope(Scope *S) { + if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) + return Ctx->isFileContext(); + return false; +} + +std::pair<bool, Sema::LookupResult> +Sema::CppLookupName(Scope *S, DeclarationName Name, + LookupNameKind NameKind, bool RedeclarationOnly) { + assert(getLangOptions().CPlusPlus && + "Can perform only C++ lookup"); + unsigned IDNS + = getIdentifierNamespacesFromLookupNameKind(NameKind, /*CPlusPlus*/ true); + Scope *Initial = S; + DeclContext *OutOfLineCtx = 0; + IdentifierResolver::iterator + I = IdResolver.begin(Name), + IEnd = IdResolver.end(); + + // First we lookup local scope. + // We don't consider using-directives, as per 7.3.4.p1 [namespace.udir] + // ...During unqualified name lookup (3.4.1), the names appear as if + // they were declared in the nearest enclosing namespace which contains + // both the using-directive and the nominated namespace. + // [Note: in this context, “contains” means “contains directly or + // indirectly”. + // + // For example: + // namespace A { int i; } + // void foo() { + // int i; + // { + // using namespace A; + // ++i; // finds local 'i', A::i appears at global scope + // } + // } + // + for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) { + // Check whether the IdResolver has anything in this scope. + for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) { + if (isAcceptableLookupResult(*I, NameKind, IDNS)) { + // We found something. Look for anything else in our scope + // with this same name and in an acceptable identifier + // namespace, so that we can construct an overload set if we + // need to. + IdentifierResolver::iterator LastI = I; + for (++LastI; LastI != IEnd; ++LastI) { + if (!S->isDeclScope(DeclPtrTy::make(*LastI))) + break; + } + LookupResult Result = + LookupResult::CreateLookupResult(Context, I, LastI); + return std::make_pair(true, Result); + } + } + if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) { + LookupResult R; + // Perform member lookup into struct. + // 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 + // example, inside a class without any base classes, we never need to + // perform qualified lookup because all of the members are on top of the + // identifier chain. + if (isa<RecordDecl>(Ctx)) { + R = LookupQualifiedName(Ctx, Name, NameKind, RedeclarationOnly); + if (R || RedeclarationOnly) + return std::make_pair(true, R); + } + if (Ctx->getParent() != Ctx->getLexicalParent() + || isa<CXXMethodDecl>(Ctx)) { + // It is out of line defined C++ method or struct, we continue + // doing name lookup in parent context. Once we will find namespace + // or translation-unit we save it for possible checking + // using-directives later. + for (OutOfLineCtx = Ctx; OutOfLineCtx && !OutOfLineCtx->isFileContext(); + OutOfLineCtx = OutOfLineCtx->getParent()) { + R = LookupQualifiedName(OutOfLineCtx, Name, NameKind, RedeclarationOnly); + if (R || RedeclarationOnly) + return std::make_pair(true, R); + } + } + } + } + + // Collect UsingDirectiveDecls in all scopes, and recursively all + // nominated namespaces by those using-directives. + // UsingDirectives are pushed to heap, in common ancestor pointer value order. + // FIXME: Cache this sorted list in Scope structure, and DeclContext, so we + // don't build it for each lookup! + UsingDirectivesTy UDirs; + for (Scope *SC = Initial; SC; SC = SC->getParent()) + if (SC->getFlags() & Scope::DeclScope) + AddScopeUsingDirectives(Context, SC, UDirs); + + // Sort heapified UsingDirectiveDecls. + std::sort_heap(UDirs.begin(), UDirs.end(), UsingDirAncestorCompare()); + + // Lookup namespace scope, and global scope. + // Unqualified name lookup in C++ requires looking into scopes + // that aren't strictly lexical, and therefore we walk through the + // context as well as walking through the scopes. + + LookupResultsTy LookupResults; + assert((!OutOfLineCtx || OutOfLineCtx->isFileContext()) && + "We should have been looking only at file context here already."); + bool LookedInCtx = false; + LookupResult Result; + while (OutOfLineCtx && + OutOfLineCtx != S->getEntity() && + OutOfLineCtx->isNamespace()) { + LookedInCtx = true; + + // Look into context considering using-directives. + CppNamespaceLookup(Context, OutOfLineCtx, Name, NameKind, IDNS, + LookupResults, &UDirs); + + if ((Result = MergeLookupResults(Context, LookupResults)) || + (RedeclarationOnly && !OutOfLineCtx->isTransparentContext())) + return std::make_pair(true, Result); + + OutOfLineCtx = OutOfLineCtx->getParent(); + } + + for (; S; S = S->getParent()) { + DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity()); + assert(Ctx && Ctx->isFileContext() && + "We should have been looking only at file context here already."); + + // Check whether the IdResolver has anything in this scope. + for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) { + if (isAcceptableLookupResult(*I, NameKind, IDNS)) { + // We found something. Look for anything else in our scope + // with this same name and in an acceptable identifier + // namespace, so that we can construct an overload set if we + // need to. + IdentifierResolver::iterator LastI = I; + for (++LastI; LastI != IEnd; ++LastI) { + if (!S->isDeclScope(DeclPtrTy::make(*LastI))) + break; + } + + // We store name lookup result, and continue trying to look into + // associated context, and maybe namespaces nominated by + // using-directives. + LookupResults.push_back( + LookupResult::CreateLookupResult(Context, I, LastI)); + break; + } + } + + LookedInCtx = true; + // Look into context considering using-directives. + CppNamespaceLookup(Context, Ctx, Name, NameKind, IDNS, + LookupResults, &UDirs); + + if ((Result = MergeLookupResults(Context, LookupResults)) || + (RedeclarationOnly && !Ctx->isTransparentContext())) + return std::make_pair(true, Result); + } + + if (!(LookedInCtx || LookupResults.empty())) { + // We didn't Performed lookup in Scope entity, so we return + // result form IdentifierResolver. + assert((LookupResults.size() == 1) && "Wrong size!"); + return std::make_pair(true, LookupResults.front()); + } + return std::make_pair(false, LookupResult()); +} + +/// @brief Perform unqualified name lookup starting from a given +/// scope. +/// +/// Unqualified name lookup (C++ [basic.lookup.unqual], C99 6.2.1) is +/// used to find names within the current scope. For example, 'x' in +/// @code +/// int x; +/// int f() { +/// return x; // unqualified name look finds 'x' in the global scope +/// } +/// @endcode +/// +/// Different lookup criteria can find different names. For example, a +/// particular scope can have both a struct and a function of the same +/// name, and each can be found by certain lookup criteria. For more +/// information about lookup criteria, see the documentation for the +/// class LookupCriteria. +/// +/// @param S The scope from which unqualified name lookup will +/// begin. If the lookup criteria permits, name lookup may also search +/// in the parent scopes. +/// +/// @param Name The name of the entity that we are searching for. +/// +/// @param Loc If provided, the source location where we're performing +/// name lookup. At present, this is only used to produce diagnostics when +/// C library functions (like "malloc") are implicitly declared. +/// +/// @returns The result of name lookup, which includes zero or more +/// declarations and possibly additional information used to diagnose +/// ambiguities. +Sema::LookupResult +Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind, + bool RedeclarationOnly, bool AllowBuiltinCreation, + SourceLocation Loc) { + if (!Name) return LookupResult::CreateLookupResult(Context, 0); + + if (!getLangOptions().CPlusPlus) { + // Unqualified name lookup in C/Objective-C is purely lexical, so + // search in the declarations attached to the name. + unsigned IDNS = 0; + switch (NameKind) { + case Sema::LookupOrdinaryName: + IDNS = Decl::IDNS_Ordinary; + break; + + case Sema::LookupTagName: + IDNS = Decl::IDNS_Tag; + break; + + case Sema::LookupMemberName: + IDNS = Decl::IDNS_Member; + break; + + case Sema::LookupOperatorName: + case Sema::LookupNestedNameSpecifierName: + case Sema::LookupNamespaceName: + assert(false && "C does not perform these kinds of name lookup"); + break; + + case Sema::LookupRedeclarationWithLinkage: + // Find the nearest non-transparent declaration scope. + while (!(S->getFlags() & Scope::DeclScope) || + (S->getEntity() && + static_cast<DeclContext *>(S->getEntity()) + ->isTransparentContext())) + S = S->getParent(); + IDNS = Decl::IDNS_Ordinary; + break; + + case Sema::LookupObjCProtocolName: + IDNS = Decl::IDNS_ObjCProtocol; + break; + + case Sema::LookupObjCImplementationName: + IDNS = Decl::IDNS_ObjCImplementation; + break; + + case Sema::LookupObjCCategoryImplName: + IDNS = Decl::IDNS_ObjCCategoryImpl; + break; + } + + // Scan up the scope chain looking for a decl that matches this + // identifier that is in the appropriate namespace. This search + // should not take long, as shadowing of names is uncommon, and + // deep shadowing is extremely uncommon. + bool LeftStartingScope = false; + + for (IdentifierResolver::iterator I = IdResolver.begin(Name), + IEnd = IdResolver.end(); + I != IEnd; ++I) + if ((*I)->isInIdentifierNamespace(IDNS)) { + if (NameKind == LookupRedeclarationWithLinkage) { + // Determine whether this (or a previous) declaration is + // out-of-scope. + if (!LeftStartingScope && !S->isDeclScope(DeclPtrTy::make(*I))) + LeftStartingScope = true; + + // If we found something outside of our starting scope that + // does not have linkage, skip it. + if (LeftStartingScope && !((*I)->hasLinkage())) + continue; + } + + if ((*I)->getAttr<OverloadableAttr>()) { + // If this declaration has the "overloadable" attribute, we + // might have a set of overloaded functions. + + // Figure out what scope the identifier is in. + while (!(S->getFlags() & Scope::DeclScope) || + !S->isDeclScope(DeclPtrTy::make(*I))) + S = S->getParent(); + + // Find the last declaration in this scope (with the same + // name, naturally). + IdentifierResolver::iterator LastI = I; + for (++LastI; LastI != IEnd; ++LastI) { + if (!S->isDeclScope(DeclPtrTy::make(*LastI))) + break; + } + + return LookupResult::CreateLookupResult(Context, I, LastI); + } + + // We have a single lookup result. + return LookupResult::CreateLookupResult(Context, *I); + } + } else { + // Perform C++ unqualified name lookup. + std::pair<bool, LookupResult> MaybeResult = + CppLookupName(S, Name, NameKind, RedeclarationOnly); + if (MaybeResult.first) + return MaybeResult.second; + } + + // If we didn't find a use of this identifier, and if the identifier + // corresponds to a compiler builtin, create the decl object for the builtin + // now, injecting it into translation unit scope, and return it. + if (NameKind == LookupOrdinaryName || + NameKind == LookupRedeclarationWithLinkage) { + IdentifierInfo *II = Name.getAsIdentifierInfo(); + if (II && AllowBuiltinCreation) { + // If this is a builtin on this (or all) targets, create the decl. + if (unsigned BuiltinID = II->getBuiltinID()) { + // In C++, we don't have any predefined library functions like + // 'malloc'. Instead, we'll just error. + if (getLangOptions().CPlusPlus && + Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) + return LookupResult::CreateLookupResult(Context, 0); + + return LookupResult::CreateLookupResult(Context, + LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID, + S, RedeclarationOnly, Loc)); + } + } + } + return LookupResult::CreateLookupResult(Context, 0); +} + +/// @brief Perform qualified name lookup into a given context. +/// +/// Qualified name lookup (C++ [basic.lookup.qual]) is used to find +/// names when the context of those names is explicit specified, e.g., +/// "std::vector" or "x->member". +/// +/// Different lookup criteria can find different names. For example, a +/// particular scope can have both a struct and a function of the same +/// name, and each can be found by certain lookup criteria. For more +/// information about lookup criteria, see the documentation for the +/// class LookupCriteria. +/// +/// @param LookupCtx The context in which qualified name lookup will +/// search. If the lookup criteria permits, name lookup may also search +/// in the parent contexts or (for C++ classes) base classes. +/// +/// @param Name The name of the entity that we are searching for. +/// +/// @param Criteria The criteria that this routine will use to +/// determine which names are visible and which names will be +/// found. Note that name lookup will find a name that is visible by +/// the given criteria, but the entity itself may not be semantically +/// correct or even the kind of entity expected based on the +/// lookup. For example, searching for a nested-name-specifier name +/// might result in an EnumDecl, which is visible but is not permitted +/// as a nested-name-specifier in C++03. +/// +/// @returns The result of name lookup, which includes zero or more +/// declarations and possibly additional information used to diagnose +/// ambiguities. +Sema::LookupResult +Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name, + LookupNameKind NameKind, bool RedeclarationOnly) { + assert(LookupCtx && "Sema::LookupQualifiedName requires a lookup context"); + + if (!Name) return LookupResult::CreateLookupResult(Context, 0); + + // If we're performing qualified name lookup (e.g., lookup into a + // struct), find fields as part of ordinary name lookup. + unsigned IDNS + = getIdentifierNamespacesFromLookupNameKind(NameKind, + getLangOptions().CPlusPlus); + if (NameKind == LookupOrdinaryName) + IDNS |= Decl::IDNS_Member; + + // Perform qualified name lookup into the LookupCtx. + DeclContext::lookup_iterator I, E; + for (llvm::tie(I, E) = LookupCtx->lookup(Context, Name); I != E; ++I) + if (isAcceptableLookupResult(*I, NameKind, IDNS)) + return LookupResult::CreateLookupResult(Context, I, E); + + // If this isn't a C++ class or we aren't allowed to look into base + // classes, we're done. + if (RedeclarationOnly || !isa<CXXRecordDecl>(LookupCtx)) + return LookupResult::CreateLookupResult(Context, 0); + + // Perform lookup into our base classes. + BasePaths Paths; + Paths.setOrigin(Context.getTypeDeclType(cast<RecordDecl>(LookupCtx))); + + // Look for this member in our base classes + if (!LookupInBases(cast<CXXRecordDecl>(LookupCtx), + MemberLookupCriteria(Name, NameKind, IDNS), Paths)) + return LookupResult::CreateLookupResult(Context, 0); + + // C++ [class.member.lookup]p2: + // [...] If the resulting set of declarations are not all from + // sub-objects of the same type, or the set has a nonstatic member + // and includes members from distinct sub-objects, there is an + // ambiguity and the program is ill-formed. Otherwise that set is + // the result of the lookup. + // FIXME: support using declarations! + QualType SubobjectType; + int SubobjectNumber = 0; + for (BasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end(); + Path != PathEnd; ++Path) { + const BasePathElement &PathElement = Path->back(); + + // Determine whether we're looking at a distinct sub-object or not. + if (SubobjectType.isNull()) { + // This is the first subobject we've looked at. Record it's type. + SubobjectType = Context.getCanonicalType(PathElement.Base->getType()); + SubobjectNumber = PathElement.SubobjectNumber; + } else if (SubobjectType + != Context.getCanonicalType(PathElement.Base->getType())) { + // We found members of the given name in two subobjects of + // different types. This lookup is ambiguous. + BasePaths *PathsOnHeap = new BasePaths; + PathsOnHeap->swap(Paths); + return LookupResult::CreateLookupResult(Context, PathsOnHeap, true); + } else if (SubobjectNumber != PathElement.SubobjectNumber) { + // We have a different subobject of the same type. + + // C++ [class.member.lookup]p5: + // A static member, a nested type or an enumerator defined in + // a base class T can unambiguously be found even if an object + // has more than one base class subobject of type T. + Decl *FirstDecl = *Path->Decls.first; + if (isa<VarDecl>(FirstDecl) || + isa<TypeDecl>(FirstDecl) || + isa<EnumConstantDecl>(FirstDecl)) + continue; + + if (isa<CXXMethodDecl>(FirstDecl)) { + // Determine whether all of the methods are static. + bool AllMethodsAreStatic = true; + for (DeclContext::lookup_iterator Func = Path->Decls.first; + Func != Path->Decls.second; ++Func) { + if (!isa<CXXMethodDecl>(*Func)) { + assert(isa<TagDecl>(*Func) && "Non-function must be a tag decl"); + break; + } + + if (!cast<CXXMethodDecl>(*Func)->isStatic()) { + AllMethodsAreStatic = false; + break; + } + } + + if (AllMethodsAreStatic) + continue; + } + + // We have found a nonstatic member name in multiple, distinct + // subobjects. Name lookup is ambiguous. + BasePaths *PathsOnHeap = new BasePaths; + PathsOnHeap->swap(Paths); + return LookupResult::CreateLookupResult(Context, PathsOnHeap, false); + } + } + + // Lookup in a base class succeeded; return these results. + + // If we found a function declaration, return an overload set. + if (isa<FunctionDecl>(*Paths.front().Decls.first)) + return LookupResult::CreateLookupResult(Context, + Paths.front().Decls.first, Paths.front().Decls.second); + + // We found a non-function declaration; return a single declaration. + return LookupResult::CreateLookupResult(Context, *Paths.front().Decls.first); +} + +/// @brief Performs name lookup for a name that was parsed in the +/// source code, and may contain a C++ scope specifier. +/// +/// This routine is a convenience routine meant to be called from +/// contexts that receive a name and an optional C++ scope specifier +/// (e.g., "N::M::x"). It will then perform either qualified or +/// unqualified name lookup (with LookupQualifiedName or LookupName, +/// respectively) on the given name and return those results. +/// +/// @param S The scope from which unqualified name lookup will +/// begin. +/// +/// @param SS An optional C++ scope-specified, e.g., "::N::M". +/// +/// @param Name The name of the entity that name lookup will +/// search for. +/// +/// @param Loc If provided, the source location where we're performing +/// name lookup. At present, this is only used to produce diagnostics when +/// C library functions (like "malloc") are implicitly declared. +/// +/// @returns The result of qualified or unqualified name lookup. +Sema::LookupResult +Sema::LookupParsedName(Scope *S, const CXXScopeSpec *SS, + DeclarationName Name, LookupNameKind NameKind, + bool RedeclarationOnly, bool AllowBuiltinCreation, + SourceLocation Loc) { + if (SS && (SS->isSet() || SS->isInvalid())) { + // If the scope specifier is invalid, don't even look for + // anything. + if (SS->isInvalid()) + return LookupResult::CreateLookupResult(Context, 0); + + assert(!isUnknownSpecialization(*SS) && "Can't lookup dependent types"); + + if (isDependentScopeSpecifier(*SS)) { + // Determine whether we are looking into the current + // instantiation. + NestedNameSpecifier *NNS + = static_cast<NestedNameSpecifier *>(SS->getScopeRep()); + CXXRecordDecl *Current = getCurrentInstantiationOf(NNS); + assert(Current && "Bad dependent scope specifier"); + + // We nested name specifier refers to the current instantiation, + // so now we will look for a member of the current instantiation + // (C++0x [temp.dep.type]). + unsigned IDNS = getIdentifierNamespacesFromLookupNameKind(NameKind, true); + DeclContext::lookup_iterator I, E; + for (llvm::tie(I, E) = Current->lookup(Context, Name); I != E; ++I) + if (isAcceptableLookupResult(*I, NameKind, IDNS)) + return LookupResult::CreateLookupResult(Context, I, E); + } + + if (RequireCompleteDeclContext(*SS)) + return LookupResult::CreateLookupResult(Context, 0); + + return LookupQualifiedName(computeDeclContext(*SS), + Name, NameKind, RedeclarationOnly); + } + + return LookupName(S, Name, NameKind, RedeclarationOnly, + AllowBuiltinCreation, Loc); +} + + +/// @brief Produce a diagnostic describing the ambiguity that resulted +/// from name lookup. +/// +/// @param Result The ambiguous name lookup result. +/// +/// @param Name The name of the entity that name lookup was +/// searching for. +/// +/// @param NameLoc The location of the name within the source code. +/// +/// @param LookupRange A source range that provides more +/// source-location information concerning the lookup itself. For +/// example, this range might highlight a nested-name-specifier that +/// precedes the name. +/// +/// @returns true +bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name, + SourceLocation NameLoc, + SourceRange LookupRange) { + assert(Result.isAmbiguous() && "Lookup result must be ambiguous"); + + if (BasePaths *Paths = Result.getBasePaths()) { + if (Result.getKind() == LookupResult::AmbiguousBaseSubobjects) { + QualType SubobjectType = Paths->front().back().Base->getType(); + Diag(NameLoc, diag::err_ambiguous_member_multiple_subobjects) + << Name << SubobjectType << getAmbiguousPathsDisplayString(*Paths) + << LookupRange; + + DeclContext::lookup_iterator Found = Paths->front().Decls.first; + while (isa<CXXMethodDecl>(*Found) && + cast<CXXMethodDecl>(*Found)->isStatic()) + ++Found; + + Diag((*Found)->getLocation(), diag::note_ambiguous_member_found); + + Result.Destroy(); + return true; + } + + assert(Result.getKind() == LookupResult::AmbiguousBaseSubobjectTypes && + "Unhandled form of name lookup ambiguity"); + + Diag(NameLoc, diag::err_ambiguous_member_multiple_subobject_types) + << Name << LookupRange; + + std::set<Decl *> DeclsPrinted; + for (BasePaths::paths_iterator Path = Paths->begin(), PathEnd = Paths->end(); + Path != PathEnd; ++Path) { + Decl *D = *Path->Decls.first; + if (DeclsPrinted.insert(D).second) + Diag(D->getLocation(), diag::note_ambiguous_member_found); + } + + Result.Destroy(); + return true; + } else if (Result.getKind() == LookupResult::AmbiguousReference) { + Diag(NameLoc, diag::err_ambiguous_reference) << Name << LookupRange; + + NamedDecl **DI = reinterpret_cast<NamedDecl **>(Result.First), + **DEnd = reinterpret_cast<NamedDecl **>(Result.Last); + + for (; DI != DEnd; ++DI) + Diag((*DI)->getLocation(), diag::note_ambiguous_candidate) << *DI; + + Result.Destroy(); + return true; + } + + assert(false && "Unhandled form of name lookup ambiguity"); + + // We can't reach here. + return true; +} + +// \brief Add the associated classes and namespaces for +// argument-dependent lookup with an argument of class type +// (C++ [basic.lookup.koenig]p2). +static void +addAssociatedClassesAndNamespaces(CXXRecordDecl *Class, + ASTContext &Context, + Sema::AssociatedNamespaceSet &AssociatedNamespaces, + Sema::AssociatedClassSet &AssociatedClasses) { + // C++ [basic.lookup.koenig]p2: + // [...] + // -- If T is a class type (including unions), its associated + // classes are: the class itself; the class of which it is a + // member, if any; and its direct and indirect base + // classes. Its associated namespaces are the namespaces in + // which its associated classes are defined. + + // Add the class of which it is a member, if any. + DeclContext *Ctx = Class->getDeclContext(); + if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx)) + AssociatedClasses.insert(EnclosingClass); + + // Add the associated namespace for this class. + while (Ctx->isRecord()) + Ctx = Ctx->getParent(); + if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx)) + AssociatedNamespaces.insert(EnclosingNamespace); + + // Add the class itself. If we've already seen this class, we don't + // need to visit base classes. + if (!AssociatedClasses.insert(Class)) + return; + + // FIXME: Handle class template specializations + + // Add direct and indirect base classes along with their associated + // namespaces. + llvm::SmallVector<CXXRecordDecl *, 32> Bases; + Bases.push_back(Class); + while (!Bases.empty()) { + // Pop this class off the stack. + Class = Bases.back(); + Bases.pop_back(); + + // Visit the base classes. + for (CXXRecordDecl::base_class_iterator Base = Class->bases_begin(), + BaseEnd = Class->bases_end(); + Base != BaseEnd; ++Base) { + const RecordType *BaseType = Base->getType()->getAsRecordType(); + CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(BaseType->getDecl()); + if (AssociatedClasses.insert(BaseDecl)) { + // Find the associated namespace for this base class. + DeclContext *BaseCtx = BaseDecl->getDeclContext(); + while (BaseCtx->isRecord()) + BaseCtx = BaseCtx->getParent(); + if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(BaseCtx)) + AssociatedNamespaces.insert(EnclosingNamespace); + + // Make sure we visit the bases of this base class. + if (BaseDecl->bases_begin() != BaseDecl->bases_end()) + Bases.push_back(BaseDecl); + } + } + } +} + +// \brief Add the associated classes and namespaces for +// argument-dependent lookup with an argument of type T +// (C++ [basic.lookup.koenig]p2). +static void +addAssociatedClassesAndNamespaces(QualType T, + ASTContext &Context, + Sema::AssociatedNamespaceSet &AssociatedNamespaces, + Sema::AssociatedClassSet &AssociatedClasses) { + // C++ [basic.lookup.koenig]p2: + // + // For each argument type T in the function call, there is a set + // of zero or more associated namespaces and a set of zero or more + // associated classes to be considered. The sets of namespaces and + // classes is determined entirely by the types of the function + // arguments (and the namespace of any template template + // argument). Typedef names and using-declarations used to specify + // the types do not contribute to this set. The sets of namespaces + // and classes are determined in the following way: + T = Context.getCanonicalType(T).getUnqualifiedType(); + + // -- If T is a pointer to U or an array of U, its associated + // namespaces and classes are those associated with U. + // + // We handle this by unwrapping pointer and array types immediately, + // to avoid unnecessary recursion. + while (true) { + if (const PointerType *Ptr = T->getAsPointerType()) + T = Ptr->getPointeeType(); + else if (const ArrayType *Ptr = Context.getAsArrayType(T)) + T = Ptr->getElementType(); + else + break; + } + + // -- If T is a fundamental type, its associated sets of + // namespaces and classes are both empty. + if (T->getAsBuiltinType()) + return; + + // -- If T is a class type (including unions), its associated + // classes are: the class itself; the class of which it is a + // member, if any; and its direct and indirect base + // classes. Its associated namespaces are the namespaces in + // which its associated classes are defined. + if (const RecordType *ClassType = T->getAsRecordType()) + if (CXXRecordDecl *ClassDecl + = dyn_cast<CXXRecordDecl>(ClassType->getDecl())) { + addAssociatedClassesAndNamespaces(ClassDecl, Context, + AssociatedNamespaces, + AssociatedClasses); + return; + } + + // -- If T is an enumeration type, its associated namespace is + // the namespace in which it is defined. If it is class + // member, its associated class is the member’s class; else + // it has no associated class. + if (const EnumType *EnumT = T->getAsEnumType()) { + EnumDecl *Enum = EnumT->getDecl(); + + DeclContext *Ctx = Enum->getDeclContext(); + if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx)) + AssociatedClasses.insert(EnclosingClass); + + // Add the associated namespace for this class. + while (Ctx->isRecord()) + Ctx = Ctx->getParent(); + if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx)) + AssociatedNamespaces.insert(EnclosingNamespace); + + return; + } + + // -- If T is a function type, its associated namespaces and + // classes are those associated with the function parameter + // types and those associated with the return type. + if (const FunctionType *FunctionType = T->getAsFunctionType()) { + // Return type + addAssociatedClassesAndNamespaces(FunctionType->getResultType(), + Context, + AssociatedNamespaces, AssociatedClasses); + + const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FunctionType); + if (!Proto) + return; + + // Argument types + for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(), + ArgEnd = Proto->arg_type_end(); + Arg != ArgEnd; ++Arg) + addAssociatedClassesAndNamespaces(*Arg, Context, + AssociatedNamespaces, AssociatedClasses); + + return; + } + + // -- If T is a pointer to a member function of a class X, its + // associated namespaces and classes are those associated + // with the function parameter types and return type, + // together with those associated with X. + // + // -- If T is a pointer to a data member of class X, its + // associated namespaces and classes are those associated + // with the member type together with those associated with + // X. + if (const MemberPointerType *MemberPtr = T->getAsMemberPointerType()) { + // Handle the type that the pointer to member points to. + addAssociatedClassesAndNamespaces(MemberPtr->getPointeeType(), + Context, + AssociatedNamespaces, AssociatedClasses); + + // Handle the class type into which this points. + if (const RecordType *Class = MemberPtr->getClass()->getAsRecordType()) + addAssociatedClassesAndNamespaces(cast<CXXRecordDecl>(Class->getDecl()), + Context, + AssociatedNamespaces, AssociatedClasses); + + return; + } + + // FIXME: What about block pointers? + // FIXME: What about Objective-C message sends? +} + +/// \brief Find the associated classes and namespaces for +/// argument-dependent lookup for a call with the given set of +/// arguments. +/// +/// This routine computes the sets of associated classes and associated +/// namespaces searched by argument-dependent lookup +/// (C++ [basic.lookup.argdep]) for a given set of arguments. +void +Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs, + AssociatedNamespaceSet &AssociatedNamespaces, + AssociatedClassSet &AssociatedClasses) { + AssociatedNamespaces.clear(); + AssociatedClasses.clear(); + + // C++ [basic.lookup.koenig]p2: + // For each argument type T in the function call, there is a set + // of zero or more associated namespaces and a set of zero or more + // associated classes to be considered. The sets of namespaces and + // classes is determined entirely by the types of the function + // arguments (and the namespace of any template template + // argument). + for (unsigned ArgIdx = 0; ArgIdx != NumArgs; ++ArgIdx) { + Expr *Arg = Args[ArgIdx]; + + if (Arg->getType() != Context.OverloadTy) { + addAssociatedClassesAndNamespaces(Arg->getType(), Context, + AssociatedNamespaces, AssociatedClasses); + continue; + } + + // [...] In addition, if the argument is the name or address of a + // set of overloaded functions and/or function templates, its + // associated classes and namespaces are the union of those + // associated with each of the members of the set: the namespace + // in which the function or function template is defined and the + // classes and namespaces associated with its (non-dependent) + // parameter types and return type. + DeclRefExpr *DRE = 0; + if (UnaryOperator *unaryOp = dyn_cast<UnaryOperator>(Arg)) { + if (unaryOp->getOpcode() == UnaryOperator::AddrOf) + DRE = dyn_cast<DeclRefExpr>(unaryOp->getSubExpr()); + } else + DRE = dyn_cast<DeclRefExpr>(Arg); + if (!DRE) + continue; + + OverloadedFunctionDecl *Ovl + = dyn_cast<OverloadedFunctionDecl>(DRE->getDecl()); + if (!Ovl) + continue; + + for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(), + FuncEnd = Ovl->function_end(); + Func != FuncEnd; ++Func) { + FunctionDecl *FDecl = cast<FunctionDecl>(*Func); + + // Add the namespace in which this function was defined. Note + // that, if this is a member function, we do *not* consider the + // enclosing namespace of its class. + DeclContext *Ctx = FDecl->getDeclContext(); + if (NamespaceDecl *EnclosingNamespace = dyn_cast<NamespaceDecl>(Ctx)) + AssociatedNamespaces.insert(EnclosingNamespace); + + // Add the classes and namespaces associated with the parameter + // types and return type of this function. + addAssociatedClassesAndNamespaces(FDecl->getType(), Context, + AssociatedNamespaces, AssociatedClasses); + } + } +} + +/// IsAcceptableNonMemberOperatorCandidate - Determine whether Fn is +/// an acceptable non-member overloaded operator for a call whose +/// arguments have types T1 (and, if non-empty, T2). This routine +/// implements the check in C++ [over.match.oper]p3b2 concerning +/// enumeration types. +static bool +IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn, + QualType T1, QualType T2, + ASTContext &Context) { + if (T1->isDependentType() || (!T2.isNull() && T2->isDependentType())) + return true; + + if (T1->isRecordType() || (!T2.isNull() && T2->isRecordType())) + return true; + + const FunctionProtoType *Proto = Fn->getType()->getAsFunctionProtoType(); + if (Proto->getNumArgs() < 1) + return false; + + if (T1->isEnumeralType()) { + QualType ArgType = Proto->getArgType(0).getNonReferenceType(); + if (Context.getCanonicalType(T1).getUnqualifiedType() + == Context.getCanonicalType(ArgType).getUnqualifiedType()) + return true; + } + + if (Proto->getNumArgs() < 2) + return false; + + if (!T2.isNull() && T2->isEnumeralType()) { + QualType ArgType = Proto->getArgType(1).getNonReferenceType(); + if (Context.getCanonicalType(T2).getUnqualifiedType() + == Context.getCanonicalType(ArgType).getUnqualifiedType()) + return true; + } + + return false; +} + +/// \brief Find the protocol with the given name, if any. +ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II) { + Decl *D = LookupName(TUScope, II, LookupObjCProtocolName).getAsDecl(); + return cast_or_null<ObjCProtocolDecl>(D); +} + +/// \brief Find the Objective-C implementation with the given name, if +/// any. +ObjCImplementationDecl *Sema::LookupObjCImplementation(IdentifierInfo *II) { + Decl *D = LookupName(TUScope, II, LookupObjCImplementationName).getAsDecl(); + return cast_or_null<ObjCImplementationDecl>(D); +} + +/// \brief Find the Objective-C category implementation with the given +/// name, if any. +ObjCCategoryImplDecl *Sema::LookupObjCCategoryImpl(IdentifierInfo *II) { + Decl *D = LookupName(TUScope, II, LookupObjCCategoryImplName).getAsDecl(); + return cast_or_null<ObjCCategoryImplDecl>(D); +} + +void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, + QualType T1, QualType T2, + FunctionSet &Functions) { + // C++ [over.match.oper]p3: + // -- The set of non-member candidates is the result of the + // unqualified lookup of operator@ in the context of the + // expression according to the usual rules for name lookup in + // unqualified function calls (3.4.2) except that all member + // functions are ignored. However, if no operand has a class + // type, only those non-member functions in the lookup set + // that have a first parameter of type T1 or “reference to + // (possibly cv-qualified) T1”, when T1 is an enumeration + // type, or (if there is a right operand) a second parameter + // of type T2 or “reference to (possibly cv-qualified) T2”, + // when T2 is an enumeration type, are candidate functions. + DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); + LookupResult Operators = LookupName(S, OpName, LookupOperatorName); + + assert(!Operators.isAmbiguous() && "Operator lookup cannot be ambiguous"); + + if (!Operators) + return; + + for (LookupResult::iterator Op = Operators.begin(), OpEnd = Operators.end(); + Op != OpEnd; ++Op) { + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Op)) + if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context)) + Functions.insert(FD); // FIXME: canonical FD + } +} + +void Sema::ArgumentDependentLookup(DeclarationName Name, + Expr **Args, unsigned NumArgs, + FunctionSet &Functions) { + // Find all of the associated namespaces and classes based on the + // arguments we have. + AssociatedNamespaceSet AssociatedNamespaces; + AssociatedClassSet AssociatedClasses; + FindAssociatedClassesAndNamespaces(Args, NumArgs, + AssociatedNamespaces, AssociatedClasses); + + // C++ [basic.lookup.argdep]p3: + // Let X be the lookup set produced by unqualified lookup (3.4.1) + // and let Y be the lookup set produced by argument dependent + // lookup (defined as follows). If X contains [...] then Y is + // empty. Otherwise Y is the set of declarations found in the + // namespaces associated with the argument types as described + // below. The set of declarations found by the lookup of the name + // is the union of X and Y. + // + // Here, we compute Y and add its members to the overloaded + // candidate set. + for (AssociatedNamespaceSet::iterator NS = AssociatedNamespaces.begin(), + NSEnd = AssociatedNamespaces.end(); + NS != NSEnd; ++NS) { + // When considering an associated namespace, the lookup is the + // same as the lookup performed when the associated namespace is + // used as a qualifier (3.4.3.2) except that: + // + // -- Any using-directives in the associated namespace are + // ignored. + // + // -- FIXME: Any namespace-scope friend functions declared in + // associated classes are visible within their respective + // namespaces even if they are not visible during an ordinary + // lookup (11.4). + DeclContext::lookup_iterator I, E; + for (llvm::tie(I, E) = (*NS)->lookup(Context, Name); I != E; ++I) { + FunctionDecl *Func = dyn_cast<FunctionDecl>(*I); + if (!Func) + break; + + Functions.insert(Func); + } + } +} diff --git a/lib/Sema/SemaNamedCast.cpp b/lib/Sema/SemaNamedCast.cpp new file mode 100644 index 0000000..daf6800 --- /dev/null +++ b/lib/Sema/SemaNamedCast.cpp @@ -0,0 +1,932 @@ +//===--- SemaNamedCast.cpp - Semantic Analysis for Named Casts ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for C++ named casts. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "SemaInherit.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ASTContext.h" +#include "llvm/ADT/SmallVector.h" +#include <set> +using namespace clang; + +enum TryStaticCastResult { + TSC_NotApplicable, ///< The cast method is not applicable. + TSC_Success, ///< The cast method is appropriate and successful. + TSC_Failed ///< The cast method is appropriate, but failed. A + ///< diagnostic has been emitted. +}; + +static void CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType, + const SourceRange &OpRange, + const SourceRange &DestRange); +static void CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, + const SourceRange &OpRange, + const SourceRange &DestRange); +static void CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, + const SourceRange &OpRange); +static void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, + const SourceRange &OpRange, + const SourceRange &DestRange); + +static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType); +static TryStaticCastResult TryLValueToRValueCast( + Sema &Self, Expr *SrcExpr, QualType DestType, const SourceRange &OpRange); +static TryStaticCastResult TryStaticReferenceDowncast( + Sema &Self, Expr *SrcExpr, QualType DestType, const SourceRange &OpRange); +static TryStaticCastResult TryStaticPointerDowncast( + Sema &Self, QualType SrcType, QualType DestType, const SourceRange &OpRange); +static TryStaticCastResult TryStaticMemberPointerUpcast( + Sema &Self, QualType SrcType, QualType DestType, const SourceRange &OpRange); +static TryStaticCastResult TryStaticDowncast(Sema &Self, QualType SrcType, + QualType DestType, + const SourceRange &OpRange, + QualType OrigSrcType, + QualType OrigDestType); +static TryStaticCastResult TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, + QualType DestType, + const SourceRange &OpRange); + +/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. +Action::OwningExprResult +Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, + SourceLocation LAngleBracketLoc, TypeTy *Ty, + SourceLocation RAngleBracketLoc, + SourceLocation LParenLoc, ExprArg E, + SourceLocation RParenLoc) { + Expr *Ex = E.takeAs<Expr>(); + QualType DestType = QualType::getFromOpaquePtr(Ty); + SourceRange OpRange(OpLoc, RParenLoc); + SourceRange DestRange(LAngleBracketLoc, RAngleBracketLoc); + + // If the type is dependent, we won't do the semantic analysis now. + // FIXME: should we check this in a more fine-grained manner? + bool TypeDependent = DestType->isDependentType() || Ex->isTypeDependent(); + + switch (Kind) { + default: assert(0 && "Unknown C++ cast!"); + + case tok::kw_const_cast: + if (!TypeDependent) + CheckConstCast(*this, Ex, DestType, OpRange, DestRange); + return Owned(new (Context) CXXConstCastExpr(DestType.getNonReferenceType(), + Ex, DestType, OpLoc)); + + case tok::kw_dynamic_cast: + if (!TypeDependent) + CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange); + return Owned(new (Context)CXXDynamicCastExpr(DestType.getNonReferenceType(), + Ex, DestType, OpLoc)); + + case tok::kw_reinterpret_cast: + if (!TypeDependent) + CheckReinterpretCast(*this, Ex, DestType, OpRange, DestRange); + return Owned(new (Context) CXXReinterpretCastExpr( + DestType.getNonReferenceType(), + Ex, DestType, OpLoc)); + + case tok::kw_static_cast: + if (!TypeDependent) + CheckStaticCast(*this, Ex, DestType, OpRange); + return Owned(new (Context) CXXStaticCastExpr(DestType.getNonReferenceType(), + Ex, DestType, OpLoc)); + } + + return ExprError(); +} + +/// CheckConstCast - Check that a const_cast\<DestType\>(SrcExpr) is valid. +/// Refer to C++ 5.2.11 for details. const_cast is typically used in code +/// like this: +/// const char *str = "literal"; +/// legacy_function(const_cast\<char*\>(str)); +void +CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType, + const SourceRange &OpRange, const SourceRange &DestRange) +{ + QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType(); + + DestType = Self.Context.getCanonicalType(DestType); + QualType SrcType = SrcExpr->getType(); + if (const LValueReferenceType *DestTypeTmp = + DestType->getAsLValueReferenceType()) { + if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) { + // Cannot cast non-lvalue to lvalue reference type. + Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue) + << "const_cast" << OrigDestType << SrcExpr->getSourceRange(); + return; + } + + // C++ 5.2.11p4: An lvalue of type T1 can be [cast] to an lvalue of type T2 + // [...] if a pointer to T1 can be [cast] to the type pointer to T2. + DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType()); + SrcType = Self.Context.getPointerType(SrcType); + } else { + // C++ 5.2.11p1: Otherwise, the result is an rvalue and the + // lvalue-to-rvalue, array-to-pointer, and function-to-pointer standard + // conversions are performed on the expression. + Self.DefaultFunctionArrayConversion(SrcExpr); + SrcType = SrcExpr->getType(); + } + + // C++ 5.2.11p5: For a const_cast involving pointers to data members [...] + // the rules for const_cast are the same as those used for pointers. + + if (!DestType->isPointerType() && !DestType->isMemberPointerType()) { + // Cannot cast to non-pointer, non-reference type. Note that, if DestType + // was a reference type, we converted it to a pointer above. + // The status of rvalue references isn't entirely clear, but it looks like + // conversion to them is simply invalid. + // C++ 5.2.11p3: For two pointer types [...] + Self.Diag(OpRange.getBegin(), diag::err_bad_const_cast_dest) + << OrigDestType << DestRange; + return; + } + if (DestType->isFunctionPointerType() || + DestType->isMemberFunctionPointerType()) { + // Cannot cast direct function pointers. + // C++ 5.2.11p2: [...] where T is any object type or the void type [...] + // T is the ultimate pointee of source and target type. + Self.Diag(OpRange.getBegin(), diag::err_bad_const_cast_dest) + << OrigDestType << DestRange; + return; + } + SrcType = Self.Context.getCanonicalType(SrcType); + + // Unwrap the pointers. Ignore qualifiers. Terminate early if the types are + // completely equal. + // FIXME: const_cast should probably not be able to convert between pointers + // to different address spaces. + // C++ 5.2.11p3 describes the core semantics of const_cast. All cv specifiers + // in multi-level pointers may change, but the level count must be the same, + // as must be the final pointee type. + while (SrcType != DestType && + Self.UnwrapSimilarPointerTypes(SrcType, DestType)) { + SrcType = SrcType.getUnqualifiedType(); + DestType = DestType.getUnqualifiedType(); + } + + // Doug Gregor said to disallow this until users complain. +#if 0 + // If we end up with constant arrays of equal size, unwrap those too. A cast + // from const int [N] to int (&)[N] is invalid by my reading of the + // standard, but g++ accepts it even with -ansi -pedantic. + // No more than one level, though, so don't embed this in the unwrap loop + // above. + const ConstantArrayType *SrcTypeArr, *DestTypeArr; + if ((SrcTypeArr = Self.Context.getAsConstantArrayType(SrcType)) && + (DestTypeArr = Self.Context.getAsConstantArrayType(DestType))) + { + if (SrcTypeArr->getSize() != DestTypeArr->getSize()) { + // Different array sizes. + Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic) + << "const_cast" << OrigDestType << OrigSrcType << OpRange; + return; + } + SrcType = SrcTypeArr->getElementType().getUnqualifiedType(); + DestType = DestTypeArr->getElementType().getUnqualifiedType(); + } +#endif + + // Since we're dealing in canonical types, the remainder must be the same. + if (SrcType != DestType) { + // Cast between unrelated types. + Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic) + << "const_cast" << OrigDestType << OrigSrcType << OpRange; + return; + } +} + +/// CheckReinterpretCast - Check that a reinterpret_cast\<DestType\>(SrcExpr) is +/// valid. +/// Refer to C++ 5.2.10 for details. reinterpret_cast is typically used in code +/// like this: +/// char *bytes = reinterpret_cast\<char*\>(int_ptr); +void +CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, + const SourceRange &OpRange, const SourceRange &DestRange) +{ + QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType(); + + DestType = Self.Context.getCanonicalType(DestType); + QualType SrcType = SrcExpr->getType(); + if (const LValueReferenceType *DestTypeTmp = + DestType->getAsLValueReferenceType()) { + if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) { + // Cannot cast non-lvalue to reference type. + Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue) + << "reinterpret_cast" << OrigDestType << SrcExpr->getSourceRange(); + return; + } + + // C++ 5.2.10p10: [...] a reference cast reinterpret_cast<T&>(x) has the + // same effect as the conversion *reinterpret_cast<T*>(&x) with the + // built-in & and * operators. + // This code does this transformation for the checked types. + DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType()); + SrcType = Self.Context.getPointerType(SrcType); + } else if (const RValueReferenceType *DestTypeTmp = + DestType->getAsRValueReferenceType()) { + // Both the reference conversion and the rvalue rules apply. + Self.DefaultFunctionArrayConversion(SrcExpr); + SrcType = SrcExpr->getType(); + + DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType()); + SrcType = Self.Context.getPointerType(SrcType); + } else { + // C++ 5.2.10p1: [...] the lvalue-to-rvalue, array-to-pointer, and + // function-to-pointer standard conversions are performed on the + // expression v. + Self.DefaultFunctionArrayConversion(SrcExpr); + SrcType = SrcExpr->getType(); + } + + // Canonicalize source for comparison. + SrcType = Self.Context.getCanonicalType(SrcType); + + const MemberPointerType *DestMemPtr = DestType->getAsMemberPointerType(), + *SrcMemPtr = SrcType->getAsMemberPointerType(); + if (DestMemPtr && SrcMemPtr) { + // C++ 5.2.10p9: An rvalue of type "pointer to member of X of type T1" + // can be explicitly converted to an rvalue of type "pointer to member + // of Y of type T2" if T1 and T2 are both function types or both object + // types. + if (DestMemPtr->getPointeeType()->isFunctionType() != + SrcMemPtr->getPointeeType()->isFunctionType()) { + Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic) + << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange; + return; + } + + // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away + // constness. + if (CastsAwayConstness(Self, SrcType, DestType)) { + Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away) + << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange; + return; + } + + // A valid member pointer cast. + return; + } + + // See below for the enumeral issue. + if (SrcType->isNullPtrType() && DestType->isIntegralType() && + !DestType->isEnumeralType()) { + // C++0x 5.2.10p4: A pointer can be explicitly converted to any integral + // type large enough to hold it. A value of std::nullptr_t can be + // converted to an integral type; the conversion has the same meaning + // and validity as a conversion of (void*)0 to the integral type. + if (Self.Context.getTypeSize(SrcType) > + Self.Context.getTypeSize(DestType)) { + Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_small_int) + << OrigDestType << DestRange; + } + return; + } + + bool destIsPtr = DestType->isPointerType(); + bool srcIsPtr = SrcType->isPointerType(); + if (!destIsPtr && !srcIsPtr) { + // Except for std::nullptr_t->integer and lvalue->reference, which are + // handled above, at least one of the two arguments must be a pointer. + Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic) + << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange; + return; + } + + if (SrcType == DestType) { + // C++ 5.2.10p2 has a note that mentions that, subject to all other + // restrictions, a cast to the same type is allowed. The intent is not + // entirely clear here, since all other paragraphs explicitly forbid casts + // to the same type. However, the behavior of compilers is pretty consistent + // on this point: allow same-type conversion if the involved types are + // pointers, disallow otherwise. + return; + } + + // Note: Clang treats enumeration types as integral types. If this is ever + // changed for C++, the additional check here will be redundant. + if (DestType->isIntegralType() && !DestType->isEnumeralType()) { + assert(srcIsPtr && "One type must be a pointer"); + // C++ 5.2.10p4: A pointer can be explicitly converted to any integral + // type large enough to hold it. + if (Self.Context.getTypeSize(SrcType) > + Self.Context.getTypeSize(DestType)) { + Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_small_int) + << OrigDestType << DestRange; + } + return; + } + + if (SrcType->isIntegralType() || SrcType->isEnumeralType()) { + assert(destIsPtr && "One type must be a pointer"); + // C++ 5.2.10p5: A value of integral or enumeration type can be explicitly + // converted to a pointer. + return; + } + + if (!destIsPtr || !srcIsPtr) { + // With the valid non-pointer conversions out of the way, we can be even + // more stringent. + Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic) + << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange; + return; + } + + // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away constness. + if (CastsAwayConstness(Self, SrcType, DestType)) { + Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away) + << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange; + return; + } + + // Not casting away constness, so the only remaining check is for compatible + // pointer categories. + + if (SrcType->isFunctionPointerType()) { + if (DestType->isFunctionPointerType()) { + // C++ 5.2.10p6: A pointer to a function can be explicitly converted to + // a pointer to a function of a different type. + return; + } + + // C++0x 5.2.10p8: Converting a pointer to a function into a pointer to + // an object type or vice versa is conditionally-supported. + // Compilers support it in C++03 too, though, because it's necessary for + // casting the return value of dlsym() and GetProcAddress(). + // FIXME: Conditionally-supported behavior should be configurable in the + // TargetInfo or similar. + if (!Self.getLangOptions().CPlusPlus0x) { + Self.Diag(OpRange.getBegin(), diag::ext_reinterpret_cast_fn_obj) + << OpRange; + } + return; + } + + if (DestType->isFunctionPointerType()) { + // See above. + if (!Self.getLangOptions().CPlusPlus0x) { + Self.Diag(OpRange.getBegin(), diag::ext_reinterpret_cast_fn_obj) + << OpRange; + } + return; + } + + // C++ 5.2.10p7: A pointer to an object can be explicitly converted to + // a pointer to an object of different type. + // Void pointers are not specified, but supported by every compiler out there. + // So we finish by allowing everything that remains - it's got to be two + // object pointers. +} + +/// CastsAwayConstness - Check if the pointer conversion from SrcType to +/// DestType casts away constness as defined in C++ 5.2.11p8ff. This is used by +/// the cast checkers. Both arguments must denote pointer (possibly to member) +/// types. +bool +CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) +{ + // Casting away constness is defined in C++ 5.2.11p8 with reference to + // C++ 4.4. We piggyback on Sema::IsQualificationConversion for this, since + // the rules are non-trivial. So first we construct Tcv *...cv* as described + // in C++ 5.2.11p8. + assert((SrcType->isPointerType() || SrcType->isMemberPointerType()) && + "Source type is not pointer or pointer to member."); + assert((DestType->isPointerType() || DestType->isMemberPointerType()) && + "Destination type is not pointer or pointer to member."); + + QualType UnwrappedSrcType = SrcType, UnwrappedDestType = DestType; + llvm::SmallVector<unsigned, 8> cv1, cv2; + + // Find the qualifications. + while (Self.UnwrapSimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) { + cv1.push_back(UnwrappedSrcType.getCVRQualifiers()); + cv2.push_back(UnwrappedDestType.getCVRQualifiers()); + } + assert(cv1.size() > 0 && "Must have at least one pointer level."); + + // Construct void pointers with those qualifiers (in reverse order of + // unwrapping, of course). + QualType SrcConstruct = Self.Context.VoidTy; + QualType DestConstruct = Self.Context.VoidTy; + for (llvm::SmallVector<unsigned, 8>::reverse_iterator i1 = cv1.rbegin(), + i2 = cv2.rbegin(); + i1 != cv1.rend(); ++i1, ++i2) + { + SrcConstruct = Self.Context.getPointerType( + SrcConstruct.getQualifiedType(*i1)); + DestConstruct = Self.Context.getPointerType( + DestConstruct.getQualifiedType(*i2)); + } + + // Test if they're compatible. + return SrcConstruct != DestConstruct && + !Self.IsQualificationConversion(SrcConstruct, DestConstruct); +} + +/// CheckStaticCast - Check that a static_cast\<DestType\>(SrcExpr) is valid. +/// Refer to C++ 5.2.9 for details. Static casts are mostly used for making +/// implicit conversions explicit and getting rid of data loss warnings. +void +CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, + const SourceRange &OpRange) +{ + // The order the tests is not entirely arbitrary. There is one conversion + // that can be handled in two different ways. Given: + // struct A {}; + // struct B : public A { + // B(); B(const A&); + // }; + // const A &a = B(); + // the cast static_cast<const B&>(a) could be seen as either a static + // reference downcast, or an explicit invocation of the user-defined + // conversion using B's conversion constructor. + // DR 427 specifies that the downcast is to be applied here. + + // FIXME: With N2812, casts to rvalue refs will change. + + // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". + if (DestType->isVoidType()) { + return; + } + + // C++ 5.2.9p5, reference downcast. + // See the function for details. + // DR 427 specifies that this is to be applied before paragraph 2. + if (TryStaticReferenceDowncast(Self, SrcExpr, DestType, OpRange) + > TSC_NotApplicable) { + return; + } + + // N2844 5.2.9p3: An lvalue of type "cv1 T1" can be cast to type "rvalue + // reference to cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1". + if (TryLValueToRValueCast(Self, SrcExpr, DestType, OpRange) > + TSC_NotApplicable) { + return; + } + + // C++ 5.2.9p2: An expression e can be explicitly converted to a type T + // [...] if the declaration "T t(e);" is well-formed, [...]. + if (TryStaticImplicitCast(Self, SrcExpr, DestType, OpRange) > + TSC_NotApplicable) { + return; + } + + // C++ 5.2.9p6: May apply the reverse of any standard conversion, except + // lvalue-to-rvalue, array-to-pointer, function-to-pointer, and boolean + // conversions, subject to further restrictions. + // Also, C++ 5.2.9p1 forbids casting away constness, which makes reversal + // of qualification conversions impossible. + + // The lvalue-to-rvalue, array-to-pointer and function-to-pointer conversions + // are applied to the expression. + QualType OrigSrcType = SrcExpr->getType(); + Self.DefaultFunctionArrayConversion(SrcExpr); + + QualType SrcType = Self.Context.getCanonicalType(SrcExpr->getType()); + + // Reverse integral promotion/conversion. All such conversions are themselves + // again integral promotions or conversions and are thus already handled by + // p2 (TryDirectInitialization above). + // (Note: any data loss warnings should be suppressed.) + // The exception is the reverse of enum->integer, i.e. integer->enum (and + // enum->enum). See also C++ 5.2.9p7. + // The same goes for reverse floating point promotion/conversion and + // floating-integral conversions. Again, only floating->enum is relevant. + if (DestType->isEnumeralType()) { + if (SrcType->isComplexType() || SrcType->isVectorType()) { + // Fall through - these cannot be converted. + } else if (SrcType->isArithmeticType() || SrcType->isEnumeralType()) { + return; + } + } + + // Reverse pointer upcast. C++ 4.10p3 specifies pointer upcast. + // C++ 5.2.9p8 additionally disallows a cast path through virtual inheritance. + if (TryStaticPointerDowncast(Self, SrcType, DestType, OpRange) + > TSC_NotApplicable) { + return; + } + + // Reverse member pointer conversion. C++ 4.11 specifies member pointer + // conversion. C++ 5.2.9p9 has additional information. + // DR54's access restrictions apply here also. + if (TryStaticMemberPointerUpcast(Self, SrcType, DestType, OpRange) + > TSC_NotApplicable) { + return; + } + + // Reverse pointer conversion to void*. C++ 4.10.p2 specifies conversion to + // void*. C++ 5.2.9p10 specifies additional restrictions, which really is + // just the usual constness stuff. + if (const PointerType *SrcPointer = SrcType->getAsPointerType()) { + QualType SrcPointee = SrcPointer->getPointeeType(); + if (SrcPointee->isVoidType()) { + if (const PointerType *DestPointer = DestType->getAsPointerType()) { + QualType DestPointee = DestPointer->getPointeeType(); + if (DestPointee->isIncompleteOrObjectType()) { + // This is definitely the intended conversion, but it might fail due + // to a const violation. + if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) { + Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away) + << "static_cast" << DestType << OrigSrcType << OpRange; + } + return; + } + } + } + } + + // We tried everything. Everything! Nothing works! :-( + // FIXME: Error reporting could be a lot better. Should store the reason why + // every substep failed and, at the end, select the most specific and report + // that. + Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic) + << "static_cast" << DestType << OrigSrcType + << OpRange; +} + +/// Tests whether a conversion according to N2844 is valid. +TryStaticCastResult +TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, + const SourceRange &OpRange) +{ + // N2844 5.2.9p3: An lvalue of type "cv1 T1" can be cast to type "rvalue + // reference to cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1". + const RValueReferenceType *R = DestType->getAsRValueReferenceType(); + if (!R) + return TSC_NotApplicable; + + if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) + return TSC_NotApplicable; + + // Because we try the reference downcast before this function, from now on + // this is the only cast possibility, so we issue an error if we fail now. + bool DerivedToBase; + if (Self.CompareReferenceRelationship(SrcExpr->getType(), R->getPointeeType(), + DerivedToBase) < + Sema::Ref_Compatible_With_Added_Qualification) { + Self.Diag(OpRange.getBegin(), diag::err_bad_lvalue_to_rvalue_cast) + << SrcExpr->getType() << R->getPointeeType() << OpRange; + return TSC_Failed; + } + + // FIXME: Similar to CheckReferenceInit, we actually need more AST annotation + // than nothing. + return TSC_Success; +} + +/// Tests whether a conversion according to C++ 5.2.9p5 is valid. +TryStaticCastResult +TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType, + const SourceRange &OpRange) +{ + // C++ 5.2.9p5: An lvalue of type "cv1 B", where B is a class type, can be + // cast to type "reference to cv2 D", where D is a class derived from B, + // if a valid standard conversion from "pointer to D" to "pointer to B" + // exists, cv2 >= cv1, and B is not a virtual base class of D. + // In addition, DR54 clarifies that the base must be accessible in the + // current context. Although the wording of DR54 only applies to the pointer + // variant of this rule, the intent is clearly for it to apply to the this + // conversion as well. + + if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) { + return TSC_NotApplicable; + } + + const ReferenceType *DestReference = DestType->getAsReferenceType(); + if (!DestReference) { + return TSC_NotApplicable; + } + QualType DestPointee = DestReference->getPointeeType(); + + return TryStaticDowncast(Self, SrcExpr->getType(), DestPointee, OpRange, + SrcExpr->getType(), DestType); +} + +/// Tests whether a conversion according to C++ 5.2.9p8 is valid. +TryStaticCastResult +TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType, + const SourceRange &OpRange) +{ + // C++ 5.2.9p8: An rvalue of type "pointer to cv1 B", where B is a class + // type, can be converted to an rvalue of type "pointer to cv2 D", where D + // is a class derived from B, if a valid standard conversion from "pointer + // to D" to "pointer to B" exists, cv2 >= cv1, and B is not a virtual base + // class of D. + // In addition, DR54 clarifies that the base must be accessible in the + // current context. + + const PointerType *SrcPointer = SrcType->getAsPointerType(); + if (!SrcPointer) { + return TSC_NotApplicable; + } + + const PointerType *DestPointer = DestType->getAsPointerType(); + if (!DestPointer) { + return TSC_NotApplicable; + } + + return TryStaticDowncast(Self, SrcPointer->getPointeeType(), + DestPointer->getPointeeType(), + OpRange, SrcType, DestType); +} + +/// TryStaticDowncast - Common functionality of TryStaticReferenceDowncast and +/// TryStaticPointerDowncast. Tests whether a static downcast from SrcType to +/// DestType, both of which must be canonical, is possible and allowed. +TryStaticCastResult +TryStaticDowncast(Sema &Self, QualType SrcType, QualType DestType, + const SourceRange &OpRange, QualType OrigSrcType, + QualType OrigDestType) +{ + // Downcast can only happen in class hierarchies, so we need classes. + if (!DestType->isRecordType() || !SrcType->isRecordType()) { + return TSC_NotApplicable; + } + + BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, + /*DetectVirtual=*/true); + if (!Self.IsDerivedFrom(DestType, SrcType, Paths)) { + return TSC_NotApplicable; + } + + // Target type does derive from source type. Now we're serious. If an error + // appears now, it's not ignored. + // This may not be entirely in line with the standard. Take for example: + // struct A {}; + // struct B : virtual A { + // B(A&); + // }; + // + // void f() + // { + // (void)static_cast<const B&>(*((A*)0)); + // } + // As far as the standard is concerned, p5 does not apply (A is virtual), so + // p2 should be used instead - "const B& t(*((A*)0));" is perfectly valid. + // However, both GCC and Comeau reject this example, and accepting it would + // mean more complex code if we're to preserve the nice error message. + // FIXME: Being 100% compliant here would be nice to have. + + // Must preserve cv, as always. + if (!DestType.isAtLeastAsQualifiedAs(SrcType)) { + Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away) + << "static_cast" << OrigDestType << OrigSrcType << OpRange; + return TSC_Failed; + } + + if (Paths.isAmbiguous(SrcType.getUnqualifiedType())) { + // This code is analoguous to that in CheckDerivedToBaseConversion, except + // that it builds the paths in reverse order. + // To sum up: record all paths to the base and build a nice string from + // them. Use it to spice up the error message. + Paths.clear(); + Paths.setRecordingPaths(true); + Self.IsDerivedFrom(DestType, SrcType, Paths); + std::string PathDisplayStr; + std::set<unsigned> DisplayedPaths; + for (BasePaths::paths_iterator Path = Paths.begin(); + Path != Paths.end(); ++Path) { + if (DisplayedPaths.insert(Path->back().SubobjectNumber).second) { + // We haven't displayed a path to this particular base + // class subobject yet. + PathDisplayStr += "\n "; + for (BasePath::const_reverse_iterator Element = Path->rbegin(); + Element != Path->rend(); ++Element) + PathDisplayStr += Element->Base->getType().getAsString() + " -> "; + PathDisplayStr += DestType.getAsString(); + } + } + + Self.Diag(OpRange.getBegin(), diag::err_ambiguous_base_to_derived_cast) + << SrcType.getUnqualifiedType() << DestType.getUnqualifiedType() + << PathDisplayStr << OpRange; + return TSC_Failed; + } + + if (Paths.getDetectedVirtual() != 0) { + QualType VirtualBase(Paths.getDetectedVirtual(), 0); + Self.Diag(OpRange.getBegin(), diag::err_static_downcast_via_virtual) + << OrigSrcType << OrigDestType << VirtualBase << OpRange; + return TSC_Failed; + } + + // FIXME: Test accessibility. + + return TSC_Success; +} + +/// TryStaticMemberPointerUpcast - Tests whether a conversion according to +/// C++ 5.2.9p9 is valid: +/// +/// An rvalue of type "pointer to member of D of type cv1 T" can be +/// converted to an rvalue of type "pointer to member of B of type cv2 T", +/// where B is a base class of D [...]. +/// +TryStaticCastResult +TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType, + const SourceRange &OpRange) +{ + const MemberPointerType *SrcMemPtr = SrcType->getAsMemberPointerType(); + if (!SrcMemPtr) + return TSC_NotApplicable; + const MemberPointerType *DestMemPtr = DestType->getAsMemberPointerType(); + if (!DestMemPtr) + return TSC_NotApplicable; + + // T == T, modulo cv + if (Self.Context.getCanonicalType( + SrcMemPtr->getPointeeType().getUnqualifiedType()) != + Self.Context.getCanonicalType(DestMemPtr->getPointeeType(). + getUnqualifiedType())) + return TSC_NotApplicable; + + // B base of D + QualType SrcClass(SrcMemPtr->getClass(), 0); + QualType DestClass(DestMemPtr->getClass(), 0); + BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, + /*DetectVirtual=*/true); + if (!Self.IsDerivedFrom(SrcClass, DestClass, Paths)) { + return TSC_NotApplicable; + } + + // B is a base of D. But is it an allowed base? If not, it's a hard error. + if (Paths.isAmbiguous(DestClass)) { + Paths.clear(); + Paths.setRecordingPaths(true); + bool StillOkay = Self.IsDerivedFrom(SrcClass, DestClass, Paths); + assert(StillOkay); + StillOkay = StillOkay; + std::string PathDisplayStr = Self.getAmbiguousPathsDisplayString(Paths); + Self.Diag(OpRange.getBegin(), diag::err_ambiguous_memptr_conv) + << 1 << SrcClass << DestClass << PathDisplayStr << OpRange; + return TSC_Failed; + } + + if (const RecordType *VBase = Paths.getDetectedVirtual()) { + Self.Diag(OpRange.getBegin(), diag::err_memptr_conv_via_virtual) + << SrcClass << DestClass << QualType(VBase, 0) << OpRange; + return TSC_Failed; + } + + // FIXME: Test accessibility. + + return TSC_Success; +} + +/// TryStaticImplicitCast - Tests whether a conversion according to C++ 5.2.9p2 +/// is valid: +/// +/// An expression e can be explicitly converted to a type T using a +/// @c static_cast if the declaration "T t(e);" is well-formed [...]. +TryStaticCastResult +TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, QualType DestType, + const SourceRange &OpRange) +{ + if (DestType->isReferenceType()) { + // At this point of CheckStaticCast, if the destination is a reference, + // this has to work. There is no other way that works. + return Self.CheckReferenceInit(SrcExpr, DestType) ? + TSC_Failed : TSC_Success; + } + if (DestType->isRecordType()) { + // FIXME: Use an implementation of C++ [over.match.ctor] for this. + return TSC_NotApplicable; + } + + // FIXME: To get a proper error from invalid conversions here, we need to + // reimplement more of this. + ImplicitConversionSequence ICS = Self.TryImplicitConversion( + SrcExpr, DestType); + return ICS.ConversionKind == ImplicitConversionSequence::BadConversion ? + TSC_NotApplicable : TSC_Success; +} + +/// CheckDynamicCast - Check that a dynamic_cast\<DestType\>(SrcExpr) is valid. +/// Refer to C++ 5.2.7 for details. Dynamic casts are used mostly for runtime- +/// checked downcasts in class hierarchies. +void +CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, + const SourceRange &OpRange, + const SourceRange &DestRange) +{ + QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType(); + DestType = Self.Context.getCanonicalType(DestType); + + // C++ 5.2.7p1: T shall be a pointer or reference to a complete class type, + // or "pointer to cv void". + + QualType DestPointee; + const PointerType *DestPointer = DestType->getAsPointerType(); + const ReferenceType *DestReference = DestType->getAsReferenceType(); + if (DestPointer) { + DestPointee = DestPointer->getPointeeType(); + } else if (DestReference) { + DestPointee = DestReference->getPointeeType(); + } else { + Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ref_or_ptr) + << OrigDestType << DestRange; + return; + } + + const RecordType *DestRecord = DestPointee->getAsRecordType(); + if (DestPointee->isVoidType()) { + assert(DestPointer && "Reference to void is not possible"); + } else if (DestRecord) { + if (Self.RequireCompleteType(OpRange.getBegin(), DestPointee, + diag::err_bad_dynamic_cast_incomplete, + DestRange)) + return; + } else { + Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class) + << DestPointee.getUnqualifiedType() << DestRange; + return; + } + + // C++0x 5.2.7p2: If T is a pointer type, v shall be an rvalue of a pointer to + // complete class type, [...]. If T is an lvalue reference type, v shall be + // an lvalue of a complete class type, [...]. If T is an rvalue reference + // type, v shall be an expression having a complete effective class type, + // [...] + + QualType SrcType = Self.Context.getCanonicalType(OrigSrcType); + QualType SrcPointee; + if (DestPointer) { + if (const PointerType *SrcPointer = SrcType->getAsPointerType()) { + SrcPointee = SrcPointer->getPointeeType(); + } else { + Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ptr) + << OrigSrcType << SrcExpr->getSourceRange(); + return; + } + } else if (DestReference->isLValueReferenceType()) { + if (SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) { + Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue) + << "dynamic_cast" << OrigDestType << OpRange; + } + SrcPointee = SrcType; + } else { + SrcPointee = SrcType; + } + + const RecordType *SrcRecord = SrcPointee->getAsRecordType(); + if (SrcRecord) { + if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee, + diag::err_bad_dynamic_cast_incomplete, + SrcExpr->getSourceRange())) + return; + } else { + Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class) + << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange(); + return; + } + + assert((DestPointer || DestReference) && + "Bad destination non-ptr/ref slipped through."); + assert((DestRecord || DestPointee->isVoidType()) && + "Bad destination pointee slipped through."); + assert(SrcRecord && "Bad source pointee slipped through."); + + // C++ 5.2.7p1: The dynamic_cast operator shall not cast away constness. + if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) { + Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away) + << "dynamic_cast" << OrigDestType << OrigSrcType << OpRange; + return; + } + + // C++ 5.2.7p3: If the type of v is the same as the required result type, + // [except for cv]. + if (DestRecord == SrcRecord) { + return; + } + + // C++ 5.2.7p5 + // Upcasts are resolved statically. + if (DestRecord && Self.IsDerivedFrom(SrcPointee, DestPointee)) { + Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee, + OpRange.getBegin(), OpRange); + // Diagnostic already emitted on error. + return; + } + + // C++ 5.2.7p6: Otherwise, v shall be [polymorphic]. + const RecordDecl *SrcDecl = SrcRecord->getDecl()->getDefinition(Self.Context); + assert(SrcDecl && "Definition missing"); + if (!cast<CXXRecordDecl>(SrcDecl)->isPolymorphic()) { + Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic) + << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange(); + } + + // Done. Everything else is run-time checks. +} diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp new file mode 100644 index 0000000..98ee13a --- /dev/null +++ b/lib/Sema/SemaOverload.cpp @@ -0,0 +1,4485 @@ +//===--- SemaOverload.cpp - C++ Overloading ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides Sema routines for C++ overloading. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "SemaInherit.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/TypeOrdering.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Compiler.h" +#include <algorithm> + +namespace clang { + +/// GetConversionCategory - Retrieve the implicit conversion +/// category corresponding to the given implicit conversion kind. +ImplicitConversionCategory +GetConversionCategory(ImplicitConversionKind Kind) { + static const ImplicitConversionCategory + Category[(int)ICK_Num_Conversion_Kinds] = { + ICC_Identity, + ICC_Lvalue_Transformation, + ICC_Lvalue_Transformation, + ICC_Lvalue_Transformation, + ICC_Qualification_Adjustment, + ICC_Promotion, + ICC_Promotion, + ICC_Promotion, + ICC_Conversion, + ICC_Conversion, + ICC_Conversion, + ICC_Conversion, + ICC_Conversion, + ICC_Conversion, + ICC_Conversion, + ICC_Conversion, + ICC_Conversion, + ICC_Conversion + }; + return Category[(int)Kind]; +} + +/// GetConversionRank - Retrieve the implicit conversion rank +/// corresponding to the given implicit conversion kind. +ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) { + static const ImplicitConversionRank + Rank[(int)ICK_Num_Conversion_Kinds] = { + ICR_Exact_Match, + ICR_Exact_Match, + ICR_Exact_Match, + ICR_Exact_Match, + ICR_Exact_Match, + ICR_Promotion, + ICR_Promotion, + ICR_Promotion, + ICR_Conversion, + ICR_Conversion, + ICR_Conversion, + ICR_Conversion, + ICR_Conversion, + ICR_Conversion, + ICR_Conversion, + ICR_Conversion, + ICR_Conversion, + ICR_Conversion + }; + return Rank[(int)Kind]; +} + +/// GetImplicitConversionName - Return the name of this kind of +/// implicit conversion. +const char* GetImplicitConversionName(ImplicitConversionKind Kind) { + static const char* Name[(int)ICK_Num_Conversion_Kinds] = { + "No conversion", + "Lvalue-to-rvalue", + "Array-to-pointer", + "Function-to-pointer", + "Qualification", + "Integral promotion", + "Floating point promotion", + "Complex promotion", + "Integral conversion", + "Floating conversion", + "Complex conversion", + "Floating-integral conversion", + "Complex-real conversion", + "Pointer conversion", + "Pointer-to-member conversion", + "Boolean conversion", + "Compatible-types conversion", + "Derived-to-base conversion" + }; + return Name[Kind]; +} + +/// StandardConversionSequence - Set the standard conversion +/// sequence to the identity conversion. +void StandardConversionSequence::setAsIdentityConversion() { + First = ICK_Identity; + Second = ICK_Identity; + Third = ICK_Identity; + Deprecated = false; + ReferenceBinding = false; + DirectBinding = false; + RRefBinding = false; + CopyConstructor = 0; +} + +/// getRank - Retrieve the rank of this standard conversion sequence +/// (C++ 13.3.3.1.1p3). The rank is the largest rank of each of the +/// implicit conversions. +ImplicitConversionRank StandardConversionSequence::getRank() const { + ImplicitConversionRank Rank = ICR_Exact_Match; + if (GetConversionRank(First) > Rank) + Rank = GetConversionRank(First); + if (GetConversionRank(Second) > Rank) + Rank = GetConversionRank(Second); + if (GetConversionRank(Third) > Rank) + Rank = GetConversionRank(Third); + return Rank; +} + +/// isPointerConversionToBool - Determines whether this conversion is +/// a conversion of a pointer or pointer-to-member to bool. This is +/// used as part of the ranking of standard conversion sequences +/// (C++ 13.3.3.2p4). +bool StandardConversionSequence::isPointerConversionToBool() const +{ + QualType FromType = QualType::getFromOpaquePtr(FromTypePtr); + QualType ToType = QualType::getFromOpaquePtr(ToTypePtr); + + // Note that FromType has not necessarily been transformed by the + // array-to-pointer or function-to-pointer implicit conversions, so + // check for their presence as well as checking whether FromType is + // a pointer. + if (ToType->isBooleanType() && + (FromType->isPointerType() || FromType->isBlockPointerType() || + First == ICK_Array_To_Pointer || First == ICK_Function_To_Pointer)) + return true; + + return false; +} + +/// isPointerConversionToVoidPointer - Determines whether this +/// conversion is a conversion of a pointer to a void pointer. This is +/// used as part of the ranking of standard conversion sequences (C++ +/// 13.3.3.2p4). +bool +StandardConversionSequence:: +isPointerConversionToVoidPointer(ASTContext& Context) const +{ + QualType FromType = QualType::getFromOpaquePtr(FromTypePtr); + QualType ToType = QualType::getFromOpaquePtr(ToTypePtr); + + // Note that FromType has not necessarily been transformed by the + // array-to-pointer implicit conversion, so check for its presence + // and redo the conversion to get a pointer. + if (First == ICK_Array_To_Pointer) + FromType = Context.getArrayDecayedType(FromType); + + if (Second == ICK_Pointer_Conversion) + if (const PointerType* ToPtrType = ToType->getAsPointerType()) + return ToPtrType->getPointeeType()->isVoidType(); + + return false; +} + +/// DebugPrint - Print this standard conversion sequence to standard +/// error. Useful for debugging overloading issues. +void StandardConversionSequence::DebugPrint() const { + bool PrintedSomething = false; + if (First != ICK_Identity) { + fprintf(stderr, "%s", GetImplicitConversionName(First)); + PrintedSomething = true; + } + + if (Second != ICK_Identity) { + if (PrintedSomething) { + fprintf(stderr, " -> "); + } + fprintf(stderr, "%s", GetImplicitConversionName(Second)); + + if (CopyConstructor) { + fprintf(stderr, " (by copy constructor)"); + } else if (DirectBinding) { + fprintf(stderr, " (direct reference binding)"); + } else if (ReferenceBinding) { + fprintf(stderr, " (reference binding)"); + } + PrintedSomething = true; + } + + if (Third != ICK_Identity) { + if (PrintedSomething) { + fprintf(stderr, " -> "); + } + fprintf(stderr, "%s", GetImplicitConversionName(Third)); + PrintedSomething = true; + } + + if (!PrintedSomething) { + fprintf(stderr, "No conversions required"); + } +} + +/// DebugPrint - Print this user-defined conversion sequence to standard +/// error. Useful for debugging overloading issues. +void UserDefinedConversionSequence::DebugPrint() const { + if (Before.First || Before.Second || Before.Third) { + Before.DebugPrint(); + fprintf(stderr, " -> "); + } + fprintf(stderr, "'%s'", ConversionFunction->getNameAsString().c_str()); + if (After.First || After.Second || After.Third) { + fprintf(stderr, " -> "); + After.DebugPrint(); + } +} + +/// DebugPrint - Print this implicit conversion sequence to standard +/// error. Useful for debugging overloading issues. +void ImplicitConversionSequence::DebugPrint() const { + switch (ConversionKind) { + case StandardConversion: + fprintf(stderr, "Standard conversion: "); + Standard.DebugPrint(); + break; + case UserDefinedConversion: + fprintf(stderr, "User-defined conversion: "); + UserDefined.DebugPrint(); + break; + case EllipsisConversion: + fprintf(stderr, "Ellipsis conversion"); + break; + case BadConversion: + fprintf(stderr, "Bad conversion"); + break; + } + + fprintf(stderr, "\n"); +} + +// IsOverload - Determine whether the given New declaration is an +// overload of the Old declaration. This routine returns false if New +// and Old cannot be overloaded, e.g., if they are functions with the +// same signature (C++ 1.3.10) or if the Old declaration isn't a +// function (or overload set). When it does return false and Old is an +// OverloadedFunctionDecl, MatchedDecl will be set to point to the +// FunctionDecl that New cannot be overloaded with. +// +// Example: Given the following input: +// +// void f(int, float); // #1 +// void f(int, int); // #2 +// int f(int, int); // #3 +// +// When we process #1, there is no previous declaration of "f", +// so IsOverload will not be used. +// +// When we process #2, Old is a FunctionDecl for #1. By comparing the +// parameter types, we see that #1 and #2 are overloaded (since they +// have different signatures), so this routine returns false; +// MatchedDecl is unchanged. +// +// When we process #3, Old is an OverloadedFunctionDecl containing #1 +// and #2. We compare the signatures of #3 to #1 (they're overloaded, +// so we do nothing) and then #3 to #2. Since the signatures of #3 and +// #2 are identical (return types of functions are not part of the +// signature), IsOverload returns false and MatchedDecl will be set to +// point to the FunctionDecl for #2. +bool +Sema::IsOverload(FunctionDecl *New, Decl* OldD, + OverloadedFunctionDecl::function_iterator& MatchedDecl) +{ + if (OverloadedFunctionDecl* Ovl = dyn_cast<OverloadedFunctionDecl>(OldD)) { + // Is this new function an overload of every function in the + // overload set? + OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(), + FuncEnd = Ovl->function_end(); + for (; Func != FuncEnd; ++Func) { + if (!IsOverload(New, *Func, MatchedDecl)) { + MatchedDecl = Func; + return false; + } + } + + // This function overloads every function in the overload set. + return true; + } else if (FunctionDecl* Old = dyn_cast<FunctionDecl>(OldD)) { + // Is the function New an overload of the function Old? + QualType OldQType = Context.getCanonicalType(Old->getType()); + QualType NewQType = Context.getCanonicalType(New->getType()); + + // Compare the signatures (C++ 1.3.10) of the two functions to + // determine whether they are overloads. If we find any mismatch + // in the signature, they are overloads. + + // If either of these functions is a K&R-style function (no + // prototype), then we consider them to have matching signatures. + if (isa<FunctionNoProtoType>(OldQType.getTypePtr()) || + isa<FunctionNoProtoType>(NewQType.getTypePtr())) + return false; + + FunctionProtoType* OldType = cast<FunctionProtoType>(OldQType.getTypePtr()); + FunctionProtoType* NewType = cast<FunctionProtoType>(NewQType.getTypePtr()); + + // The signature of a function includes the types of its + // parameters (C++ 1.3.10), which includes the presence or absence + // of the ellipsis; see C++ DR 357). + if (OldQType != NewQType && + (OldType->getNumArgs() != NewType->getNumArgs() || + OldType->isVariadic() != NewType->isVariadic() || + !std::equal(OldType->arg_type_begin(), OldType->arg_type_end(), + NewType->arg_type_begin()))) + return true; + + // If the function is a class member, its signature includes the + // cv-qualifiers (if any) on the function itself. + // + // As part of this, also check whether one of the member functions + // is static, in which case they are not overloads (C++ + // 13.1p2). While not part of the definition of the signature, + // this check is important to determine whether these functions + // can be overloaded. + CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old); + CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New); + if (OldMethod && NewMethod && + !OldMethod->isStatic() && !NewMethod->isStatic() && + OldMethod->getTypeQualifiers() != NewMethod->getTypeQualifiers()) + return true; + + // The signatures match; this is not an overload. + return false; + } else { + // (C++ 13p1): + // Only function declarations can be overloaded; object and type + // declarations cannot be overloaded. + return false; + } +} + +/// TryImplicitConversion - Attempt to perform an implicit conversion +/// from the given expression (Expr) to the given type (ToType). This +/// function returns an implicit conversion sequence that can be used +/// to perform the initialization. Given +/// +/// void f(float f); +/// void g(int i) { f(i); } +/// +/// this routine would produce an implicit conversion sequence to +/// describe the initialization of f from i, which will be a standard +/// conversion sequence containing an lvalue-to-rvalue conversion (C++ +/// 4.1) followed by a floating-integral conversion (C++ 4.9). +// +/// Note that this routine only determines how the conversion can be +/// performed; it does not actually perform the conversion. As such, +/// it will not produce any diagnostics if no conversion is available, +/// but will instead return an implicit conversion sequence of kind +/// "BadConversion". +/// +/// If @p SuppressUserConversions, then user-defined conversions are +/// not permitted. +/// If @p AllowExplicit, then explicit user-defined conversions are +/// permitted. +/// If @p ForceRValue, then overloading is performed as if From was an rvalue, +/// no matter its actual lvalueness. +ImplicitConversionSequence +Sema::TryImplicitConversion(Expr* From, QualType ToType, + bool SuppressUserConversions, + bool AllowExplicit, bool ForceRValue) +{ + ImplicitConversionSequence ICS; + if (IsStandardConversion(From, ToType, ICS.Standard)) + ICS.ConversionKind = ImplicitConversionSequence::StandardConversion; + else if (getLangOptions().CPlusPlus && + IsUserDefinedConversion(From, ToType, ICS.UserDefined, + !SuppressUserConversions, AllowExplicit, + ForceRValue)) { + ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion; + // C++ [over.ics.user]p4: + // A conversion of an expression of class type to the same class + // type is given Exact Match rank, and a conversion of an + // expression of class type to a base class of that type is + // given Conversion rank, in spite of the fact that a copy + // constructor (i.e., a user-defined conversion function) is + // called for those cases. + if (CXXConstructorDecl *Constructor + = dyn_cast<CXXConstructorDecl>(ICS.UserDefined.ConversionFunction)) { + QualType FromCanon + = Context.getCanonicalType(From->getType().getUnqualifiedType()); + QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType(); + if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) { + // Turn this into a "standard" conversion sequence, so that it + // gets ranked with standard conversion sequences. + ICS.ConversionKind = ImplicitConversionSequence::StandardConversion; + ICS.Standard.setAsIdentityConversion(); + ICS.Standard.FromTypePtr = From->getType().getAsOpaquePtr(); + ICS.Standard.ToTypePtr = ToType.getAsOpaquePtr(); + ICS.Standard.CopyConstructor = Constructor; + if (ToCanon != FromCanon) + ICS.Standard.Second = ICK_Derived_To_Base; + } + } + + // C++ [over.best.ics]p4: + // However, when considering the argument of a user-defined + // conversion function that is a candidate by 13.3.1.3 when + // invoked for the copying of the temporary in the second step + // of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or + // 13.3.1.6 in all cases, only standard conversion sequences and + // ellipsis conversion sequences are allowed. + if (SuppressUserConversions && + ICS.ConversionKind == ImplicitConversionSequence::UserDefinedConversion) + ICS.ConversionKind = ImplicitConversionSequence::BadConversion; + } else + ICS.ConversionKind = ImplicitConversionSequence::BadConversion; + + return ICS; +} + +/// IsStandardConversion - Determines whether there is a standard +/// conversion sequence (C++ [conv], C++ [over.ics.scs]) from the +/// expression From to the type ToType. Standard conversion sequences +/// only consider non-class types; for conversions that involve class +/// types, use TryImplicitConversion. If a conversion exists, SCS will +/// contain the standard conversion sequence required to perform this +/// conversion and this routine will return true. Otherwise, this +/// routine will return false and the value of SCS is unspecified. +bool +Sema::IsStandardConversion(Expr* From, QualType ToType, + StandardConversionSequence &SCS) +{ + QualType FromType = From->getType(); + + // Standard conversions (C++ [conv]) + SCS.setAsIdentityConversion(); + SCS.Deprecated = false; + SCS.IncompatibleObjC = false; + SCS.FromTypePtr = FromType.getAsOpaquePtr(); + SCS.CopyConstructor = 0; + + // There are no standard conversions for class types in C++, so + // abort early. When overloading in C, however, we do permit + if (FromType->isRecordType() || ToType->isRecordType()) { + if (getLangOptions().CPlusPlus) + return false; + + // When we're overloading in C, we allow, as standard conversions, + } + + // The first conversion can be an lvalue-to-rvalue conversion, + // array-to-pointer conversion, or function-to-pointer conversion + // (C++ 4p1). + + // Lvalue-to-rvalue conversion (C++ 4.1): + // An lvalue (3.10) of a non-function, non-array type T can be + // converted to an rvalue. + Expr::isLvalueResult argIsLvalue = From->isLvalue(Context); + if (argIsLvalue == Expr::LV_Valid && + !FromType->isFunctionType() && !FromType->isArrayType() && + Context.getCanonicalType(FromType) != Context.OverloadTy) { + SCS.First = ICK_Lvalue_To_Rvalue; + + // If T is a non-class type, the type of the rvalue is the + // cv-unqualified version of T. Otherwise, the type of the rvalue + // is T (C++ 4.1p1). C++ can't get here with class types; in C, we + // just strip the qualifiers because they don't matter. + + // FIXME: Doesn't see through to qualifiers behind a typedef! + FromType = FromType.getUnqualifiedType(); + } + // Array-to-pointer conversion (C++ 4.2) + else if (FromType->isArrayType()) { + SCS.First = ICK_Array_To_Pointer; + + // An lvalue or rvalue of type "array of N T" or "array of unknown + // bound of T" can be converted to an rvalue of type "pointer to + // T" (C++ 4.2p1). + FromType = Context.getArrayDecayedType(FromType); + + if (IsStringLiteralToNonConstPointerConversion(From, ToType)) { + // This conversion is deprecated. (C++ D.4). + SCS.Deprecated = true; + + // For the purpose of ranking in overload resolution + // (13.3.3.1.1), this conversion is considered an + // array-to-pointer conversion followed by a qualification + // conversion (4.4). (C++ 4.2p2) + SCS.Second = ICK_Identity; + SCS.Third = ICK_Qualification; + SCS.ToTypePtr = ToType.getAsOpaquePtr(); + return true; + } + } + // Function-to-pointer conversion (C++ 4.3). + else if (FromType->isFunctionType() && argIsLvalue == Expr::LV_Valid) { + SCS.First = ICK_Function_To_Pointer; + + // An lvalue of function type T can be converted to an rvalue of + // type "pointer to T." The result is a pointer to the + // function. (C++ 4.3p1). + FromType = Context.getPointerType(FromType); + } + // Address of overloaded function (C++ [over.over]). + else if (FunctionDecl *Fn + = ResolveAddressOfOverloadedFunction(From, ToType, false)) { + SCS.First = ICK_Function_To_Pointer; + + // We were able to resolve the address of the overloaded function, + // so we can convert to the type of that function. + FromType = Fn->getType(); + if (ToType->isLValueReferenceType()) + FromType = Context.getLValueReferenceType(FromType); + else if (ToType->isRValueReferenceType()) + FromType = Context.getRValueReferenceType(FromType); + else if (ToType->isMemberPointerType()) { + // Resolve address only succeeds if both sides are member pointers, + // but it doesn't have to be the same class. See DR 247. + // Note that this means that the type of &Derived::fn can be + // Ret (Base::*)(Args) if the fn overload actually found is from the + // base class, even if it was brought into the derived class via a + // using declaration. The standard isn't clear on this issue at all. + CXXMethodDecl *M = cast<CXXMethodDecl>(Fn); + FromType = Context.getMemberPointerType(FromType, + Context.getTypeDeclType(M->getParent()).getTypePtr()); + } else + FromType = Context.getPointerType(FromType); + } + // We don't require any conversions for the first step. + else { + SCS.First = ICK_Identity; + } + + // The second conversion can be an integral promotion, floating + // point promotion, integral conversion, floating point conversion, + // floating-integral conversion, pointer conversion, + // pointer-to-member conversion, or boolean conversion (C++ 4p1). + // For overloading in C, this can also be a "compatible-type" + // conversion. + bool IncompatibleObjC = false; + if (Context.hasSameUnqualifiedType(FromType, ToType)) { + // The unqualified versions of the types are the same: there's no + // conversion to do. + SCS.Second = ICK_Identity; + } + // Integral promotion (C++ 4.5). + else if (IsIntegralPromotion(From, FromType, ToType)) { + SCS.Second = ICK_Integral_Promotion; + FromType = ToType.getUnqualifiedType(); + } + // Floating point promotion (C++ 4.6). + else if (IsFloatingPointPromotion(FromType, ToType)) { + SCS.Second = ICK_Floating_Promotion; + FromType = ToType.getUnqualifiedType(); + } + // Complex promotion (Clang extension) + else if (IsComplexPromotion(FromType, ToType)) { + SCS.Second = ICK_Complex_Promotion; + FromType = ToType.getUnqualifiedType(); + } + // Integral conversions (C++ 4.7). + // FIXME: isIntegralType shouldn't be true for enums in C++. + else if ((FromType->isIntegralType() || FromType->isEnumeralType()) && + (ToType->isIntegralType() && !ToType->isEnumeralType())) { + SCS.Second = ICK_Integral_Conversion; + FromType = ToType.getUnqualifiedType(); + } + // Floating point conversions (C++ 4.8). + else if (FromType->isFloatingType() && ToType->isFloatingType()) { + SCS.Second = ICK_Floating_Conversion; + FromType = ToType.getUnqualifiedType(); + } + // Complex conversions (C99 6.3.1.6) + else if (FromType->isComplexType() && ToType->isComplexType()) { + SCS.Second = ICK_Complex_Conversion; + FromType = ToType.getUnqualifiedType(); + } + // Floating-integral conversions (C++ 4.9). + // FIXME: isIntegralType shouldn't be true for enums in C++. + else if ((FromType->isFloatingType() && + ToType->isIntegralType() && !ToType->isBooleanType() && + !ToType->isEnumeralType()) || + ((FromType->isIntegralType() || FromType->isEnumeralType()) && + ToType->isFloatingType())) { + SCS.Second = ICK_Floating_Integral; + FromType = ToType.getUnqualifiedType(); + } + // Complex-real conversions (C99 6.3.1.7) + else if ((FromType->isComplexType() && ToType->isArithmeticType()) || + (ToType->isComplexType() && FromType->isArithmeticType())) { + SCS.Second = ICK_Complex_Real; + FromType = ToType.getUnqualifiedType(); + } + // Pointer conversions (C++ 4.10). + else if (IsPointerConversion(From, FromType, ToType, FromType, + IncompatibleObjC)) { + SCS.Second = ICK_Pointer_Conversion; + SCS.IncompatibleObjC = IncompatibleObjC; + } + // Pointer to member conversions (4.11). + else if (IsMemberPointerConversion(From, FromType, ToType, FromType)) { + SCS.Second = ICK_Pointer_Member; + } + // Boolean conversions (C++ 4.12). + else if (ToType->isBooleanType() && + (FromType->isArithmeticType() || + FromType->isEnumeralType() || + FromType->isPointerType() || + FromType->isBlockPointerType() || + FromType->isMemberPointerType() || + FromType->isNullPtrType())) { + SCS.Second = ICK_Boolean_Conversion; + FromType = Context.BoolTy; + } + // Compatible conversions (Clang extension for C function overloading) + else if (!getLangOptions().CPlusPlus && + Context.typesAreCompatible(ToType, FromType)) { + SCS.Second = ICK_Compatible_Conversion; + } else { + // No second conversion required. + SCS.Second = ICK_Identity; + } + + QualType CanonFrom; + QualType CanonTo; + // The third conversion can be a qualification conversion (C++ 4p1). + if (IsQualificationConversion(FromType, ToType)) { + SCS.Third = ICK_Qualification; + FromType = ToType; + CanonFrom = Context.getCanonicalType(FromType); + CanonTo = Context.getCanonicalType(ToType); + } else { + // No conversion required + SCS.Third = ICK_Identity; + + // C++ [over.best.ics]p6: + // [...] Any difference in top-level cv-qualification is + // subsumed by the initialization itself and does not constitute + // a conversion. [...] + CanonFrom = Context.getCanonicalType(FromType); + CanonTo = Context.getCanonicalType(ToType); + if (CanonFrom.getUnqualifiedType() == CanonTo.getUnqualifiedType() && + CanonFrom.getCVRQualifiers() != CanonTo.getCVRQualifiers()) { + FromType = ToType; + CanonFrom = CanonTo; + } + } + + // If we have not converted the argument type to the parameter type, + // this is a bad conversion sequence. + if (CanonFrom != CanonTo) + return false; + + SCS.ToTypePtr = FromType.getAsOpaquePtr(); + return true; +} + +/// IsIntegralPromotion - Determines whether the conversion from the +/// expression From (whose potentially-adjusted type is FromType) to +/// ToType is an integral promotion (C++ 4.5). If so, returns true and +/// sets PromotedType to the promoted type. +bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) +{ + const BuiltinType *To = ToType->getAsBuiltinType(); + // All integers are built-in. + if (!To) { + return false; + } + + // An rvalue of type char, signed char, unsigned char, short int, or + // unsigned short int can be converted to an rvalue of type int if + // int can represent all the values of the source type; otherwise, + // the source rvalue can be converted to an rvalue of type unsigned + // int (C++ 4.5p1). + if (FromType->isPromotableIntegerType() && !FromType->isBooleanType()) { + if (// We can promote any signed, promotable integer type to an int + (FromType->isSignedIntegerType() || + // We can promote any unsigned integer type whose size is + // less than int to an int. + (!FromType->isSignedIntegerType() && + Context.getTypeSize(FromType) < Context.getTypeSize(ToType)))) { + return To->getKind() == BuiltinType::Int; + } + + return To->getKind() == BuiltinType::UInt; + } + + // An rvalue of type wchar_t (3.9.1) or an enumeration type (7.2) + // can be converted to an rvalue of the first of the following types + // that can represent all the values of its underlying type: int, + // unsigned int, long, or unsigned long (C++ 4.5p2). + if ((FromType->isEnumeralType() || FromType->isWideCharType()) + && ToType->isIntegerType()) { + // Determine whether the type we're converting from is signed or + // unsigned. + bool FromIsSigned; + uint64_t FromSize = Context.getTypeSize(FromType); + if (const EnumType *FromEnumType = FromType->getAsEnumType()) { + QualType UnderlyingType = FromEnumType->getDecl()->getIntegerType(); + FromIsSigned = UnderlyingType->isSignedIntegerType(); + } else { + // FIXME: Is wchar_t signed or unsigned? We assume it's signed for now. + FromIsSigned = true; + } + + // The types we'll try to promote to, in the appropriate + // order. Try each of these types. + QualType PromoteTypes[6] = { + Context.IntTy, Context.UnsignedIntTy, + Context.LongTy, Context.UnsignedLongTy , + Context.LongLongTy, Context.UnsignedLongLongTy + }; + for (int Idx = 0; Idx < 6; ++Idx) { + uint64_t ToSize = Context.getTypeSize(PromoteTypes[Idx]); + if (FromSize < ToSize || + (FromSize == ToSize && + FromIsSigned == PromoteTypes[Idx]->isSignedIntegerType())) { + // We found the type that we can promote to. If this is the + // type we wanted, we have a promotion. Otherwise, no + // promotion. + return Context.getCanonicalType(ToType).getUnqualifiedType() + == Context.getCanonicalType(PromoteTypes[Idx]).getUnqualifiedType(); + } + } + } + + // An rvalue for an integral bit-field (9.6) can be converted to an + // rvalue of type int if int can represent all the values of the + // bit-field; otherwise, it can be converted to unsigned int if + // unsigned int can represent all the values of the bit-field. If + // the bit-field is larger yet, no integral promotion applies to + // it. If the bit-field has an enumerated type, it is treated as any + // other value of that type for promotion purposes (C++ 4.5p3). + // FIXME: We should delay checking of bit-fields until we actually perform the + // conversion. + using llvm::APSInt; + if (From) + if (FieldDecl *MemberDecl = From->getBitField()) { + APSInt BitWidth; + if (FromType->isIntegralType() && !FromType->isEnumeralType() && + MemberDecl->getBitWidth()->isIntegerConstantExpr(BitWidth, Context)) { + APSInt ToSize(BitWidth.getBitWidth(), BitWidth.isUnsigned()); + ToSize = Context.getTypeSize(ToType); + + // Are we promoting to an int from a bitfield that fits in an int? + if (BitWidth < ToSize || + (FromType->isSignedIntegerType() && BitWidth <= ToSize)) { + return To->getKind() == BuiltinType::Int; + } + + // Are we promoting to an unsigned int from an unsigned bitfield + // that fits into an unsigned int? + if (FromType->isUnsignedIntegerType() && BitWidth <= ToSize) { + return To->getKind() == BuiltinType::UInt; + } + + return false; + } + } + + // An rvalue of type bool can be converted to an rvalue of type int, + // with false becoming zero and true becoming one (C++ 4.5p4). + if (FromType->isBooleanType() && To->getKind() == BuiltinType::Int) { + return true; + } + + return false; +} + +/// IsFloatingPointPromotion - Determines whether the conversion from +/// FromType to ToType is a floating point promotion (C++ 4.6). If so, +/// returns true and sets PromotedType to the promoted type. +bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) +{ + /// An rvalue of type float can be converted to an rvalue of type + /// double. (C++ 4.6p1). + if (const BuiltinType *FromBuiltin = FromType->getAsBuiltinType()) + if (const BuiltinType *ToBuiltin = ToType->getAsBuiltinType()) { + if (FromBuiltin->getKind() == BuiltinType::Float && + ToBuiltin->getKind() == BuiltinType::Double) + return true; + + // C99 6.3.1.5p1: + // When a float is promoted to double or long double, or a + // double is promoted to long double [...]. + if (!getLangOptions().CPlusPlus && + (FromBuiltin->getKind() == BuiltinType::Float || + FromBuiltin->getKind() == BuiltinType::Double) && + (ToBuiltin->getKind() == BuiltinType::LongDouble)) + return true; + } + + return false; +} + +/// \brief Determine if a conversion is a complex promotion. +/// +/// A complex promotion is defined as a complex -> complex conversion +/// where the conversion between the underlying real types is a +/// floating-point or integral promotion. +bool Sema::IsComplexPromotion(QualType FromType, QualType ToType) { + const ComplexType *FromComplex = FromType->getAsComplexType(); + if (!FromComplex) + return false; + + const ComplexType *ToComplex = ToType->getAsComplexType(); + if (!ToComplex) + return false; + + return IsFloatingPointPromotion(FromComplex->getElementType(), + ToComplex->getElementType()) || + IsIntegralPromotion(0, FromComplex->getElementType(), + ToComplex->getElementType()); +} + +/// BuildSimilarlyQualifiedPointerType - In a pointer conversion from +/// the pointer type FromPtr to a pointer to type ToPointee, with the +/// same type qualifiers as FromPtr has on its pointee type. ToType, +/// if non-empty, will be a pointer to ToType that may or may not have +/// the right set of qualifiers on its pointee. +static QualType +BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr, + QualType ToPointee, QualType ToType, + ASTContext &Context) { + QualType CanonFromPointee = Context.getCanonicalType(FromPtr->getPointeeType()); + QualType CanonToPointee = Context.getCanonicalType(ToPointee); + unsigned Quals = CanonFromPointee.getCVRQualifiers(); + + // Exact qualifier match -> return the pointer type we're converting to. + if (CanonToPointee.getCVRQualifiers() == Quals) { + // ToType is exactly what we need. Return it. + if (ToType.getTypePtr()) + return ToType; + + // Build a pointer to ToPointee. It has the right qualifiers + // already. + return Context.getPointerType(ToPointee); + } + + // Just build a canonical type that has the right qualifiers. + return Context.getPointerType(CanonToPointee.getQualifiedType(Quals)); +} + +/// IsPointerConversion - Determines whether the conversion of the +/// expression From, which has the (possibly adjusted) type FromType, +/// can be converted to the type ToType via a pointer conversion (C++ +/// 4.10). If so, returns true and places the converted type (that +/// might differ from ToType in its cv-qualifiers at some level) into +/// ConvertedType. +/// +/// This routine also supports conversions to and from block pointers +/// and conversions with Objective-C's 'id', 'id<protocols...>', and +/// pointers to interfaces. FIXME: Once we've determined the +/// appropriate overloading rules for Objective-C, we may want to +/// split the Objective-C checks into a different routine; however, +/// GCC seems to consider all of these conversions to be pointer +/// conversions, so for now they live here. IncompatibleObjC will be +/// set if the conversion is an allowed Objective-C conversion that +/// should result in a warning. +bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, + QualType& ConvertedType, + bool &IncompatibleObjC) +{ + IncompatibleObjC = false; + if (isObjCPointerConversion(FromType, ToType, ConvertedType, IncompatibleObjC)) + return true; + + // Conversion from a null pointer constant to any Objective-C pointer type. + if (Context.isObjCObjectPointerType(ToType) && + From->isNullPointerConstant(Context)) { + ConvertedType = ToType; + return true; + } + + // Blocks: Block pointers can be converted to void*. + if (FromType->isBlockPointerType() && ToType->isPointerType() && + ToType->getAsPointerType()->getPointeeType()->isVoidType()) { + ConvertedType = ToType; + return true; + } + // Blocks: A null pointer constant can be converted to a block + // pointer type. + if (ToType->isBlockPointerType() && From->isNullPointerConstant(Context)) { + ConvertedType = ToType; + return true; + } + + // If the left-hand-side is nullptr_t, the right side can be a null + // pointer constant. + if (ToType->isNullPtrType() && From->isNullPointerConstant(Context)) { + ConvertedType = ToType; + return true; + } + + const PointerType* ToTypePtr = ToType->getAsPointerType(); + if (!ToTypePtr) + return false; + + // A null pointer constant can be converted to a pointer type (C++ 4.10p1). + if (From->isNullPointerConstant(Context)) { + ConvertedType = ToType; + return true; + } + + // Beyond this point, both types need to be pointers. + const PointerType *FromTypePtr = FromType->getAsPointerType(); + if (!FromTypePtr) + return false; + + QualType FromPointeeType = FromTypePtr->getPointeeType(); + QualType ToPointeeType = ToTypePtr->getPointeeType(); + + // An rvalue of type "pointer to cv T," where T is an object type, + // can be converted to an rvalue of type "pointer to cv void" (C++ + // 4.10p2). + if (FromPointeeType->isObjectType() && ToPointeeType->isVoidType()) { + ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, + ToPointeeType, + ToType, Context); + return true; + } + + // When we're overloading in C, we allow a special kind of pointer + // conversion for compatible-but-not-identical pointee types. + if (!getLangOptions().CPlusPlus && + Context.typesAreCompatible(FromPointeeType, ToPointeeType)) { + ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, + ToPointeeType, + ToType, Context); + return true; + } + + // C++ [conv.ptr]p3: + // + // An rvalue of type "pointer to cv D," where D is a class type, + // can be converted to an rvalue of type "pointer to cv B," where + // B is a base class (clause 10) of D. If B is an inaccessible + // (clause 11) or ambiguous (10.2) base class of D, a program that + // necessitates this conversion is ill-formed. The result of the + // conversion is a pointer to the base class sub-object of the + // derived class object. The null pointer value is converted to + // the null pointer value of the destination type. + // + // Note that we do not check for ambiguity or inaccessibility + // here. That is handled by CheckPointerConversion. + if (getLangOptions().CPlusPlus && + FromPointeeType->isRecordType() && ToPointeeType->isRecordType() && + IsDerivedFrom(FromPointeeType, ToPointeeType)) { + ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, + ToPointeeType, + ToType, Context); + return true; + } + + return false; +} + +/// isObjCPointerConversion - Determines whether this is an +/// Objective-C pointer conversion. Subroutine of IsPointerConversion, +/// with the same arguments and return values. +bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, + QualType& ConvertedType, + bool &IncompatibleObjC) { + if (!getLangOptions().ObjC1) + return false; + + // Conversions with Objective-C's id<...>. + if ((FromType->isObjCQualifiedIdType() || ToType->isObjCQualifiedIdType()) && + ObjCQualifiedIdTypesAreCompatible(ToType, FromType, /*compare=*/false)) { + ConvertedType = ToType; + return true; + } + + // Beyond this point, both types need to be pointers or block pointers. + QualType ToPointeeType; + const PointerType* ToTypePtr = ToType->getAsPointerType(); + if (ToTypePtr) + ToPointeeType = ToTypePtr->getPointeeType(); + else if (const BlockPointerType *ToBlockPtr = ToType->getAsBlockPointerType()) + ToPointeeType = ToBlockPtr->getPointeeType(); + else + return false; + + QualType FromPointeeType; + const PointerType *FromTypePtr = FromType->getAsPointerType(); + if (FromTypePtr) + FromPointeeType = FromTypePtr->getPointeeType(); + else if (const BlockPointerType *FromBlockPtr + = FromType->getAsBlockPointerType()) + FromPointeeType = FromBlockPtr->getPointeeType(); + else + return false; + + // Objective C++: We're able to convert from a pointer to an + // interface to a pointer to a different interface. + const ObjCInterfaceType* FromIface = FromPointeeType->getAsObjCInterfaceType(); + const ObjCInterfaceType* ToIface = ToPointeeType->getAsObjCInterfaceType(); + if (FromIface && ToIface && + Context.canAssignObjCInterfaces(ToIface, FromIface)) { + ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, + ToPointeeType, + ToType, Context); + return true; + } + + if (FromIface && ToIface && + Context.canAssignObjCInterfaces(FromIface, ToIface)) { + // Okay: this is some kind of implicit downcast of Objective-C + // interfaces, which is permitted. However, we're going to + // complain about it. + IncompatibleObjC = true; + ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, + ToPointeeType, + ToType, Context); + return true; + } + + // Objective C++: We're able to convert between "id" and a pointer + // to any interface (in both directions). + if ((FromIface && Context.isObjCIdStructType(ToPointeeType)) + || (ToIface && Context.isObjCIdStructType(FromPointeeType))) { + ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, + ToPointeeType, + ToType, Context); + return true; + } + + // Objective C++: Allow conversions between the Objective-C "id" and + // "Class", in either direction. + if ((Context.isObjCIdStructType(FromPointeeType) && + Context.isObjCClassStructType(ToPointeeType)) || + (Context.isObjCClassStructType(FromPointeeType) && + Context.isObjCIdStructType(ToPointeeType))) { + ConvertedType = ToType; + return true; + } + + // If we have pointers to pointers, recursively check whether this + // is an Objective-C conversion. + if (FromPointeeType->isPointerType() && ToPointeeType->isPointerType() && + isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType, + IncompatibleObjC)) { + // We always complain about this conversion. + IncompatibleObjC = true; + ConvertedType = ToType; + return true; + } + + // If we have pointers to functions or blocks, check whether the only + // differences in the argument and result types are in Objective-C + // pointer conversions. If so, we permit the conversion (but + // complain about it). + const FunctionProtoType *FromFunctionType + = FromPointeeType->getAsFunctionProtoType(); + const FunctionProtoType *ToFunctionType + = ToPointeeType->getAsFunctionProtoType(); + if (FromFunctionType && ToFunctionType) { + // If the function types are exactly the same, this isn't an + // Objective-C pointer conversion. + if (Context.getCanonicalType(FromPointeeType) + == Context.getCanonicalType(ToPointeeType)) + return false; + + // Perform the quick checks that will tell us whether these + // function types are obviously different. + if (FromFunctionType->getNumArgs() != ToFunctionType->getNumArgs() || + FromFunctionType->isVariadic() != ToFunctionType->isVariadic() || + FromFunctionType->getTypeQuals() != ToFunctionType->getTypeQuals()) + return false; + + bool HasObjCConversion = false; + if (Context.getCanonicalType(FromFunctionType->getResultType()) + == Context.getCanonicalType(ToFunctionType->getResultType())) { + // Okay, the types match exactly. Nothing to do. + } else if (isObjCPointerConversion(FromFunctionType->getResultType(), + ToFunctionType->getResultType(), + ConvertedType, IncompatibleObjC)) { + // Okay, we have an Objective-C pointer conversion. + HasObjCConversion = true; + } else { + // Function types are too different. Abort. + return false; + } + + // Check argument types. + for (unsigned ArgIdx = 0, NumArgs = FromFunctionType->getNumArgs(); + ArgIdx != NumArgs; ++ArgIdx) { + QualType FromArgType = FromFunctionType->getArgType(ArgIdx); + QualType ToArgType = ToFunctionType->getArgType(ArgIdx); + if (Context.getCanonicalType(FromArgType) + == Context.getCanonicalType(ToArgType)) { + // Okay, the types match exactly. Nothing to do. + } else if (isObjCPointerConversion(FromArgType, ToArgType, + ConvertedType, IncompatibleObjC)) { + // Okay, we have an Objective-C pointer conversion. + HasObjCConversion = true; + } else { + // Argument types are too different. Abort. + return false; + } + } + + if (HasObjCConversion) { + // We had an Objective-C conversion. Allow this pointer + // conversion, but complain about it. + ConvertedType = ToType; + IncompatibleObjC = true; + return true; + } + } + + return false; +} + +/// CheckPointerConversion - Check the pointer conversion from the +/// expression From to the type ToType. This routine checks for +/// ambiguous (FIXME: or inaccessible) derived-to-base pointer +/// conversions for which IsPointerConversion has already returned +/// true. It returns true and produces a diagnostic if there was an +/// error, or returns false otherwise. +bool Sema::CheckPointerConversion(Expr *From, QualType ToType) { + QualType FromType = From->getType(); + + if (const PointerType *FromPtrType = FromType->getAsPointerType()) + if (const PointerType *ToPtrType = ToType->getAsPointerType()) { + QualType FromPointeeType = FromPtrType->getPointeeType(), + ToPointeeType = ToPtrType->getPointeeType(); + + // Objective-C++ conversions are always okay. + // FIXME: We should have a different class of conversions for the + // Objective-C++ implicit conversions. + if (Context.isObjCIdStructType(FromPointeeType) || + Context.isObjCIdStructType(ToPointeeType) || + Context.isObjCClassStructType(FromPointeeType) || + Context.isObjCClassStructType(ToPointeeType)) + return false; + + if (FromPointeeType->isRecordType() && + ToPointeeType->isRecordType()) { + // We must have a derived-to-base conversion. Check an + // ambiguous or inaccessible conversion. + return CheckDerivedToBaseConversion(FromPointeeType, ToPointeeType, + From->getExprLoc(), + From->getSourceRange()); + } + } + + return false; +} + +/// IsMemberPointerConversion - Determines whether the conversion of the +/// expression From, which has the (possibly adjusted) type FromType, can be +/// converted to the type ToType via a member pointer conversion (C++ 4.11). +/// If so, returns true and places the converted type (that might differ from +/// ToType in its cv-qualifiers at some level) into ConvertedType. +bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType, + QualType ToType, QualType &ConvertedType) +{ + const MemberPointerType *ToTypePtr = ToType->getAsMemberPointerType(); + if (!ToTypePtr) + return false; + + // A null pointer constant can be converted to a member pointer (C++ 4.11p1) + if (From->isNullPointerConstant(Context)) { + ConvertedType = ToType; + return true; + } + + // Otherwise, both types have to be member pointers. + const MemberPointerType *FromTypePtr = FromType->getAsMemberPointerType(); + if (!FromTypePtr) + return false; + + // A pointer to member of B can be converted to a pointer to member of D, + // where D is derived from B (C++ 4.11p2). + QualType FromClass(FromTypePtr->getClass(), 0); + QualType ToClass(ToTypePtr->getClass(), 0); + // FIXME: What happens when these are dependent? Is this function even called? + + if (IsDerivedFrom(ToClass, FromClass)) { + ConvertedType = Context.getMemberPointerType(FromTypePtr->getPointeeType(), + ToClass.getTypePtr()); + return true; + } + + return false; +} + +/// CheckMemberPointerConversion - Check the member pointer conversion from the +/// expression From to the type ToType. This routine checks for ambiguous or +/// virtual (FIXME: or inaccessible) base-to-derived member pointer conversions +/// for which IsMemberPointerConversion has already returned true. It returns +/// true and produces a diagnostic if there was an error, or returns false +/// otherwise. +bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType) { + QualType FromType = From->getType(); + const MemberPointerType *FromPtrType = FromType->getAsMemberPointerType(); + if (!FromPtrType) + return false; + + const MemberPointerType *ToPtrType = ToType->getAsMemberPointerType(); + assert(ToPtrType && "No member pointer cast has a target type " + "that is not a member pointer."); + + QualType FromClass = QualType(FromPtrType->getClass(), 0); + QualType ToClass = QualType(ToPtrType->getClass(), 0); + + // FIXME: What about dependent types? + assert(FromClass->isRecordType() && "Pointer into non-class."); + assert(ToClass->isRecordType() && "Pointer into non-class."); + + BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, + /*DetectVirtual=*/true); + bool DerivationOkay = IsDerivedFrom(ToClass, FromClass, Paths); + assert(DerivationOkay && + "Should not have been called if derivation isn't OK."); + (void)DerivationOkay; + + if (Paths.isAmbiguous(Context.getCanonicalType(FromClass). + getUnqualifiedType())) { + // Derivation is ambiguous. Redo the check to find the exact paths. + Paths.clear(); + Paths.setRecordingPaths(true); + bool StillOkay = IsDerivedFrom(ToClass, FromClass, Paths); + assert(StillOkay && "Derivation changed due to quantum fluctuation."); + (void)StillOkay; + + std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths); + Diag(From->getExprLoc(), diag::err_ambiguous_memptr_conv) + << 0 << FromClass << ToClass << PathDisplayStr << From->getSourceRange(); + return true; + } + + if (const RecordType *VBase = Paths.getDetectedVirtual()) { + Diag(From->getExprLoc(), diag::err_memptr_conv_via_virtual) + << FromClass << ToClass << QualType(VBase, 0) + << From->getSourceRange(); + return true; + } + + return false; +} + +/// IsQualificationConversion - Determines whether the conversion from +/// an rvalue of type FromType to ToType is a qualification conversion +/// (C++ 4.4). +bool +Sema::IsQualificationConversion(QualType FromType, QualType ToType) +{ + FromType = Context.getCanonicalType(FromType); + ToType = Context.getCanonicalType(ToType); + + // If FromType and ToType are the same type, this is not a + // qualification conversion. + if (FromType == ToType) + return false; + + // (C++ 4.4p4): + // A conversion can add cv-qualifiers at levels other than the first + // in multi-level pointers, subject to the following rules: [...] + bool PreviousToQualsIncludeConst = true; + bool UnwrappedAnyPointer = false; + while (UnwrapSimilarPointerTypes(FromType, ToType)) { + // Within each iteration of the loop, we check the qualifiers to + // determine if this still looks like a qualification + // conversion. Then, if all is well, we unwrap one more level of + // pointers or pointers-to-members and do it all again + // until there are no more pointers or pointers-to-members left to + // unwrap. + UnwrappedAnyPointer = true; + + // -- for every j > 0, if const is in cv 1,j then const is in cv + // 2,j, and similarly for volatile. + if (!ToType.isAtLeastAsQualifiedAs(FromType)) + return false; + + // -- if the cv 1,j and cv 2,j are different, then const is in + // every cv for 0 < k < j. + if (FromType.getCVRQualifiers() != ToType.getCVRQualifiers() + && !PreviousToQualsIncludeConst) + return false; + + // Keep track of whether all prior cv-qualifiers in the "to" type + // include const. + PreviousToQualsIncludeConst + = PreviousToQualsIncludeConst && ToType.isConstQualified(); + } + + // We are left with FromType and ToType being the pointee types + // after unwrapping the original FromType and ToType the same number + // of types. If we unwrapped any pointers, and if FromType and + // ToType have the same unqualified type (since we checked + // qualifiers above), then this is a qualification conversion. + return UnwrappedAnyPointer && + FromType.getUnqualifiedType() == ToType.getUnqualifiedType(); +} + +/// Determines whether there is a user-defined conversion sequence +/// (C++ [over.ics.user]) that converts expression From to the type +/// ToType. If such a conversion exists, User will contain the +/// user-defined conversion sequence that performs such a conversion +/// and this routine will return true. Otherwise, this routine returns +/// false and User is unspecified. +/// +/// \param AllowConversionFunctions true if the conversion should +/// consider conversion functions at all. If false, only constructors +/// will be considered. +/// +/// \param AllowExplicit true if the conversion should consider C++0x +/// "explicit" conversion functions as well as non-explicit conversion +/// functions (C++0x [class.conv.fct]p2). +/// +/// \param ForceRValue true if the expression should be treated as an rvalue +/// for overload resolution. +bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType, + UserDefinedConversionSequence& User, + bool AllowConversionFunctions, + bool AllowExplicit, bool ForceRValue) +{ + OverloadCandidateSet CandidateSet; + if (const RecordType *ToRecordType = ToType->getAsRecordType()) { + if (CXXRecordDecl *ToRecordDecl + = dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) { + // C++ [over.match.ctor]p1: + // When objects of class type are direct-initialized (8.5), or + // copy-initialized from an expression of the same or a + // derived class type (8.5), overload resolution selects the + // constructor. [...] For copy-initialization, the candidate + // functions are all the converting constructors (12.3.1) of + // that class. The argument list is the expression-list within + // the parentheses of the initializer. + DeclarationName ConstructorName + = Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(ToType).getUnqualifiedType()); + DeclContext::lookup_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) + = ToRecordDecl->lookup(Context, ConstructorName); + Con != ConEnd; ++Con) { + CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); + if (Constructor->isConvertingConstructor()) + AddOverloadCandidate(Constructor, &From, 1, CandidateSet, + /*SuppressUserConversions=*/true, ForceRValue); + } + } + } + + if (!AllowConversionFunctions) { + // Don't allow any conversion functions to enter the overload set. + } else if (const RecordType *FromRecordType + = From->getType()->getAsRecordType()) { + if (CXXRecordDecl *FromRecordDecl + = dyn_cast<CXXRecordDecl>(FromRecordType->getDecl())) { + // Add all of the conversion functions as candidates. + // FIXME: Look for conversions in base classes! + OverloadedFunctionDecl *Conversions + = FromRecordDecl->getConversionFunctions(); + for (OverloadedFunctionDecl::function_iterator Func + = Conversions->function_begin(); + Func != Conversions->function_end(); ++Func) { + CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func); + if (AllowExplicit || !Conv->isExplicit()) + AddConversionCandidate(Conv, From, ToType, CandidateSet); + } + } + } + + OverloadCandidateSet::iterator Best; + switch (BestViableFunction(CandidateSet, Best)) { + case OR_Success: + // Record the standard conversion we used and the conversion function. + if (CXXConstructorDecl *Constructor + = dyn_cast<CXXConstructorDecl>(Best->Function)) { + // C++ [over.ics.user]p1: + // If the user-defined conversion is specified by a + // constructor (12.3.1), the initial standard conversion + // sequence converts the source type to the type required by + // the argument of the constructor. + // + // FIXME: What about ellipsis conversions? + QualType ThisType = Constructor->getThisType(Context); + User.Before = Best->Conversions[0].Standard; + User.ConversionFunction = Constructor; + User.After.setAsIdentityConversion(); + User.After.FromTypePtr + = ThisType->getAsPointerType()->getPointeeType().getAsOpaquePtr(); + User.After.ToTypePtr = ToType.getAsOpaquePtr(); + return true; + } else if (CXXConversionDecl *Conversion + = dyn_cast<CXXConversionDecl>(Best->Function)) { + // C++ [over.ics.user]p1: + // + // [...] If the user-defined conversion is specified by a + // conversion function (12.3.2), the initial standard + // conversion sequence converts the source type to the + // implicit object parameter of the conversion function. + User.Before = Best->Conversions[0].Standard; + User.ConversionFunction = Conversion; + + // C++ [over.ics.user]p2: + // The second standard conversion sequence converts the + // result of the user-defined conversion to the target type + // for the sequence. Since an implicit conversion sequence + // is an initialization, the special rules for + // initialization by user-defined conversion apply when + // selecting the best user-defined conversion for a + // user-defined conversion sequence (see 13.3.3 and + // 13.3.3.1). + User.After = Best->FinalConversion; + return true; + } else { + assert(false && "Not a constructor or conversion function?"); + return false; + } + + case OR_No_Viable_Function: + case OR_Deleted: + // No conversion here! We're done. + return false; + + case OR_Ambiguous: + // FIXME: See C++ [over.best.ics]p10 for the handling of + // ambiguous conversion sequences. + return false; + } + + return false; +} + +/// CompareImplicitConversionSequences - Compare two implicit +/// conversion sequences to determine whether one is better than the +/// other or if they are indistinguishable (C++ 13.3.3.2). +ImplicitConversionSequence::CompareKind +Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1, + const ImplicitConversionSequence& ICS2) +{ + // (C++ 13.3.3.2p2): When comparing the basic forms of implicit + // conversion sequences (as defined in 13.3.3.1) + // -- a standard conversion sequence (13.3.3.1.1) is a better + // conversion sequence than a user-defined conversion sequence or + // an ellipsis conversion sequence, and + // -- a user-defined conversion sequence (13.3.3.1.2) is a better + // conversion sequence than an ellipsis conversion sequence + // (13.3.3.1.3). + // + if (ICS1.ConversionKind < ICS2.ConversionKind) + return ImplicitConversionSequence::Better; + else if (ICS2.ConversionKind < ICS1.ConversionKind) + return ImplicitConversionSequence::Worse; + + // Two implicit conversion sequences of the same form are + // indistinguishable conversion sequences unless one of the + // following rules apply: (C++ 13.3.3.2p3): + if (ICS1.ConversionKind == ImplicitConversionSequence::StandardConversion) + return CompareStandardConversionSequences(ICS1.Standard, ICS2.Standard); + else if (ICS1.ConversionKind == + ImplicitConversionSequence::UserDefinedConversion) { + // User-defined conversion sequence U1 is a better conversion + // sequence than another user-defined conversion sequence U2 if + // they contain the same user-defined conversion function or + // constructor and if the second standard conversion sequence of + // U1 is better than the second standard conversion sequence of + // U2 (C++ 13.3.3.2p3). + if (ICS1.UserDefined.ConversionFunction == + ICS2.UserDefined.ConversionFunction) + return CompareStandardConversionSequences(ICS1.UserDefined.After, + ICS2.UserDefined.After); + } + + return ImplicitConversionSequence::Indistinguishable; +} + +/// CompareStandardConversionSequences - Compare two standard +/// conversion sequences to determine whether one is better than the +/// other or if they are indistinguishable (C++ 13.3.3.2p3). +ImplicitConversionSequence::CompareKind +Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, + const StandardConversionSequence& SCS2) +{ + // Standard conversion sequence S1 is a better conversion sequence + // than standard conversion sequence S2 if (C++ 13.3.3.2p3): + + // -- S1 is a proper subsequence of S2 (comparing the conversion + // sequences in the canonical form defined by 13.3.3.1.1, + // excluding any Lvalue Transformation; the identity conversion + // sequence is considered to be a subsequence of any + // non-identity conversion sequence) or, if not that, + if (SCS1.Second == SCS2.Second && SCS1.Third == SCS2.Third) + // Neither is a proper subsequence of the other. Do nothing. + ; + else if ((SCS1.Second == ICK_Identity && SCS1.Third == SCS2.Third) || + (SCS1.Third == ICK_Identity && SCS1.Second == SCS2.Second) || + (SCS1.Second == ICK_Identity && + SCS1.Third == ICK_Identity)) + // SCS1 is a proper subsequence of SCS2. + return ImplicitConversionSequence::Better; + else if ((SCS2.Second == ICK_Identity && SCS2.Third == SCS1.Third) || + (SCS2.Third == ICK_Identity && SCS2.Second == SCS1.Second) || + (SCS2.Second == ICK_Identity && + SCS2.Third == ICK_Identity)) + // SCS2 is a proper subsequence of SCS1. + return ImplicitConversionSequence::Worse; + + // -- the rank of S1 is better than the rank of S2 (by the rules + // defined below), or, if not that, + ImplicitConversionRank Rank1 = SCS1.getRank(); + ImplicitConversionRank Rank2 = SCS2.getRank(); + if (Rank1 < Rank2) + return ImplicitConversionSequence::Better; + else if (Rank2 < Rank1) + return ImplicitConversionSequence::Worse; + + // (C++ 13.3.3.2p4): Two conversion sequences with the same rank + // are indistinguishable unless one of the following rules + // applies: + + // A conversion that is not a conversion of a pointer, or + // pointer to member, to bool is better than another conversion + // that is such a conversion. + if (SCS1.isPointerConversionToBool() != SCS2.isPointerConversionToBool()) + return SCS2.isPointerConversionToBool() + ? ImplicitConversionSequence::Better + : ImplicitConversionSequence::Worse; + + // C++ [over.ics.rank]p4b2: + // + // If class B is derived directly or indirectly from class A, + // conversion of B* to A* is better than conversion of B* to + // void*, and conversion of A* to void* is better than conversion + // of B* to void*. + bool SCS1ConvertsToVoid + = SCS1.isPointerConversionToVoidPointer(Context); + bool SCS2ConvertsToVoid + = SCS2.isPointerConversionToVoidPointer(Context); + if (SCS1ConvertsToVoid != SCS2ConvertsToVoid) { + // Exactly one of the conversion sequences is a conversion to + // a void pointer; it's the worse conversion. + return SCS2ConvertsToVoid ? ImplicitConversionSequence::Better + : ImplicitConversionSequence::Worse; + } else if (!SCS1ConvertsToVoid && !SCS2ConvertsToVoid) { + // Neither conversion sequence converts to a void pointer; compare + // their derived-to-base conversions. + if (ImplicitConversionSequence::CompareKind DerivedCK + = CompareDerivedToBaseConversions(SCS1, SCS2)) + return DerivedCK; + } else if (SCS1ConvertsToVoid && SCS2ConvertsToVoid) { + // Both conversion sequences are conversions to void + // pointers. Compare the source types to determine if there's an + // inheritance relationship in their sources. + QualType FromType1 = QualType::getFromOpaquePtr(SCS1.FromTypePtr); + QualType FromType2 = QualType::getFromOpaquePtr(SCS2.FromTypePtr); + + // Adjust the types we're converting from via the array-to-pointer + // conversion, if we need to. + if (SCS1.First == ICK_Array_To_Pointer) + FromType1 = Context.getArrayDecayedType(FromType1); + if (SCS2.First == ICK_Array_To_Pointer) + FromType2 = Context.getArrayDecayedType(FromType2); + + QualType FromPointee1 + = FromType1->getAsPointerType()->getPointeeType().getUnqualifiedType(); + QualType FromPointee2 + = FromType2->getAsPointerType()->getPointeeType().getUnqualifiedType(); + + if (IsDerivedFrom(FromPointee2, FromPointee1)) + return ImplicitConversionSequence::Better; + else if (IsDerivedFrom(FromPointee1, FromPointee2)) + return ImplicitConversionSequence::Worse; + + // Objective-C++: If one interface is more specific than the + // other, it is the better one. + const ObjCInterfaceType* FromIface1 = FromPointee1->getAsObjCInterfaceType(); + const ObjCInterfaceType* FromIface2 = FromPointee2->getAsObjCInterfaceType(); + if (FromIface1 && FromIface1) { + if (Context.canAssignObjCInterfaces(FromIface2, FromIface1)) + return ImplicitConversionSequence::Better; + else if (Context.canAssignObjCInterfaces(FromIface1, FromIface2)) + return ImplicitConversionSequence::Worse; + } + } + + // Compare based on qualification conversions (C++ 13.3.3.2p3, + // bullet 3). + if (ImplicitConversionSequence::CompareKind QualCK + = CompareQualificationConversions(SCS1, SCS2)) + return QualCK; + + if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) { + // C++0x [over.ics.rank]p3b4: + // -- S1 and S2 are reference bindings (8.5.3) and neither refers to an + // implicit object parameter of a non-static member function declared + // without a ref-qualifier, and S1 binds an rvalue reference to an + // rvalue and S2 binds an lvalue reference. + // FIXME: We don't know if we're dealing with the implicit object parameter, + // or if the member function in this case has a ref qualifier. + // (Of course, we don't have ref qualifiers yet.) + if (SCS1.RRefBinding != SCS2.RRefBinding) + return SCS1.RRefBinding ? ImplicitConversionSequence::Better + : ImplicitConversionSequence::Worse; + + // C++ [over.ics.rank]p3b4: + // -- S1 and S2 are reference bindings (8.5.3), and the types to + // which the references refer are the same type except for + // top-level cv-qualifiers, and the type to which the reference + // initialized by S2 refers is more cv-qualified than the type + // to which the reference initialized by S1 refers. + QualType T1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr); + QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr); + T1 = Context.getCanonicalType(T1); + T2 = Context.getCanonicalType(T2); + if (T1.getUnqualifiedType() == T2.getUnqualifiedType()) { + if (T2.isMoreQualifiedThan(T1)) + return ImplicitConversionSequence::Better; + else if (T1.isMoreQualifiedThan(T2)) + return ImplicitConversionSequence::Worse; + } + } + + return ImplicitConversionSequence::Indistinguishable; +} + +/// CompareQualificationConversions - Compares two standard conversion +/// sequences to determine whether they can be ranked based on their +/// qualification conversions (C++ 13.3.3.2p3 bullet 3). +ImplicitConversionSequence::CompareKind +Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1, + const StandardConversionSequence& SCS2) +{ + // C++ 13.3.3.2p3: + // -- S1 and S2 differ only in their qualification conversion and + // yield similar types T1 and T2 (C++ 4.4), respectively, and the + // cv-qualification signature of type T1 is a proper subset of + // the cv-qualification signature of type T2, and S1 is not the + // deprecated string literal array-to-pointer conversion (4.2). + if (SCS1.First != SCS2.First || SCS1.Second != SCS2.Second || + SCS1.Third != SCS2.Third || SCS1.Third != ICK_Qualification) + return ImplicitConversionSequence::Indistinguishable; + + // FIXME: the example in the standard doesn't use a qualification + // conversion (!) + QualType T1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr); + QualType T2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr); + T1 = Context.getCanonicalType(T1); + T2 = Context.getCanonicalType(T2); + + // If the types are the same, we won't learn anything by unwrapped + // them. + if (T1.getUnqualifiedType() == T2.getUnqualifiedType()) + return ImplicitConversionSequence::Indistinguishable; + + ImplicitConversionSequence::CompareKind Result + = ImplicitConversionSequence::Indistinguishable; + while (UnwrapSimilarPointerTypes(T1, T2)) { + // Within each iteration of the loop, we check the qualifiers to + // determine if this still looks like a qualification + // conversion. Then, if all is well, we unwrap one more level of + // pointers or pointers-to-members and do it all again + // until there are no more pointers or pointers-to-members left + // to unwrap. This essentially mimics what + // IsQualificationConversion does, but here we're checking for a + // strict subset of qualifiers. + if (T1.getCVRQualifiers() == T2.getCVRQualifiers()) + // The qualifiers are the same, so this doesn't tell us anything + // about how the sequences rank. + ; + else if (T2.isMoreQualifiedThan(T1)) { + // T1 has fewer qualifiers, so it could be the better sequence. + if (Result == ImplicitConversionSequence::Worse) + // Neither has qualifiers that are a subset of the other's + // qualifiers. + return ImplicitConversionSequence::Indistinguishable; + + Result = ImplicitConversionSequence::Better; + } else if (T1.isMoreQualifiedThan(T2)) { + // T2 has fewer qualifiers, so it could be the better sequence. + if (Result == ImplicitConversionSequence::Better) + // Neither has qualifiers that are a subset of the other's + // qualifiers. + return ImplicitConversionSequence::Indistinguishable; + + Result = ImplicitConversionSequence::Worse; + } else { + // Qualifiers are disjoint. + return ImplicitConversionSequence::Indistinguishable; + } + + // If the types after this point are equivalent, we're done. + if (T1.getUnqualifiedType() == T2.getUnqualifiedType()) + break; + } + + // Check that the winning standard conversion sequence isn't using + // the deprecated string literal array to pointer conversion. + switch (Result) { + case ImplicitConversionSequence::Better: + if (SCS1.Deprecated) + Result = ImplicitConversionSequence::Indistinguishable; + break; + + case ImplicitConversionSequence::Indistinguishable: + break; + + case ImplicitConversionSequence::Worse: + if (SCS2.Deprecated) + Result = ImplicitConversionSequence::Indistinguishable; + break; + } + + return Result; +} + +/// CompareDerivedToBaseConversions - Compares two standard conversion +/// sequences to determine whether they can be ranked based on their +/// various kinds of derived-to-base conversions (C++ +/// [over.ics.rank]p4b3). As part of these checks, we also look at +/// conversions between Objective-C interface types. +ImplicitConversionSequence::CompareKind +Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, + const StandardConversionSequence& SCS2) { + QualType FromType1 = QualType::getFromOpaquePtr(SCS1.FromTypePtr); + QualType ToType1 = QualType::getFromOpaquePtr(SCS1.ToTypePtr); + QualType FromType2 = QualType::getFromOpaquePtr(SCS2.FromTypePtr); + QualType ToType2 = QualType::getFromOpaquePtr(SCS2.ToTypePtr); + + // Adjust the types we're converting from via the array-to-pointer + // conversion, if we need to. + if (SCS1.First == ICK_Array_To_Pointer) + FromType1 = Context.getArrayDecayedType(FromType1); + if (SCS2.First == ICK_Array_To_Pointer) + FromType2 = Context.getArrayDecayedType(FromType2); + + // Canonicalize all of the types. + FromType1 = Context.getCanonicalType(FromType1); + ToType1 = Context.getCanonicalType(ToType1); + FromType2 = Context.getCanonicalType(FromType2); + ToType2 = Context.getCanonicalType(ToType2); + + // C++ [over.ics.rank]p4b3: + // + // If class B is derived directly or indirectly from class A and + // class C is derived directly or indirectly from B, + // + // For Objective-C, we let A, B, and C also be Objective-C + // interfaces. + + // Compare based on pointer conversions. + if (SCS1.Second == ICK_Pointer_Conversion && + SCS2.Second == ICK_Pointer_Conversion && + /*FIXME: Remove if Objective-C id conversions get their own rank*/ + FromType1->isPointerType() && FromType2->isPointerType() && + ToType1->isPointerType() && ToType2->isPointerType()) { + QualType FromPointee1 + = FromType1->getAsPointerType()->getPointeeType().getUnqualifiedType(); + QualType ToPointee1 + = ToType1->getAsPointerType()->getPointeeType().getUnqualifiedType(); + QualType FromPointee2 + = FromType2->getAsPointerType()->getPointeeType().getUnqualifiedType(); + QualType ToPointee2 + = ToType2->getAsPointerType()->getPointeeType().getUnqualifiedType(); + + const ObjCInterfaceType* FromIface1 = FromPointee1->getAsObjCInterfaceType(); + const ObjCInterfaceType* FromIface2 = FromPointee2->getAsObjCInterfaceType(); + const ObjCInterfaceType* ToIface1 = ToPointee1->getAsObjCInterfaceType(); + const ObjCInterfaceType* ToIface2 = ToPointee2->getAsObjCInterfaceType(); + + // -- conversion of C* to B* is better than conversion of C* to A*, + if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) { + if (IsDerivedFrom(ToPointee1, ToPointee2)) + return ImplicitConversionSequence::Better; + else if (IsDerivedFrom(ToPointee2, ToPointee1)) + return ImplicitConversionSequence::Worse; + + if (ToIface1 && ToIface2) { + if (Context.canAssignObjCInterfaces(ToIface2, ToIface1)) + return ImplicitConversionSequence::Better; + else if (Context.canAssignObjCInterfaces(ToIface1, ToIface2)) + return ImplicitConversionSequence::Worse; + } + } + + // -- conversion of B* to A* is better than conversion of C* to A*, + if (FromPointee1 != FromPointee2 && ToPointee1 == ToPointee2) { + if (IsDerivedFrom(FromPointee2, FromPointee1)) + return ImplicitConversionSequence::Better; + else if (IsDerivedFrom(FromPointee1, FromPointee2)) + return ImplicitConversionSequence::Worse; + + if (FromIface1 && FromIface2) { + if (Context.canAssignObjCInterfaces(FromIface1, FromIface2)) + return ImplicitConversionSequence::Better; + else if (Context.canAssignObjCInterfaces(FromIface2, FromIface1)) + return ImplicitConversionSequence::Worse; + } + } + } + + // 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 (FromType1.getUnqualifiedType() == FromType2.getUnqualifiedType() && + ToType1.getUnqualifiedType() != ToType2.getUnqualifiedType()) { + 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 (FromType1.getUnqualifiedType() != FromType2.getUnqualifiedType() && + ToType1.getUnqualifiedType() == ToType2.getUnqualifiedType()) { + if (IsDerivedFrom(FromType2, FromType1)) + return ImplicitConversionSequence::Better; + else if (IsDerivedFrom(FromType1, FromType2)) + return ImplicitConversionSequence::Worse; + } + } + + + // FIXME: conversion of A::* to B::* is better than conversion of + // A::* to C::*, + + // FIXME: conversion of B::* to C::* is better than conversion of + // A::* to C::*, and + + if (SCS1.CopyConstructor && SCS2.CopyConstructor && + SCS1.Second == ICK_Derived_To_Base) { + // -- conversion of C to B is better than conversion of C to A, + if (FromType1.getUnqualifiedType() == FromType2.getUnqualifiedType() && + ToType1.getUnqualifiedType() != ToType2.getUnqualifiedType()) { + if (IsDerivedFrom(ToType1, ToType2)) + return ImplicitConversionSequence::Better; + else if (IsDerivedFrom(ToType2, ToType1)) + return ImplicitConversionSequence::Worse; + } + + // -- conversion of B to A is better than conversion of C to A. + if (FromType1.getUnqualifiedType() != FromType2.getUnqualifiedType() && + ToType1.getUnqualifiedType() == ToType2.getUnqualifiedType()) { + if (IsDerivedFrom(FromType2, FromType1)) + return ImplicitConversionSequence::Better; + else if (IsDerivedFrom(FromType1, FromType2)) + return ImplicitConversionSequence::Worse; + } + } + + return ImplicitConversionSequence::Indistinguishable; +} + +/// TryCopyInitialization - Try to copy-initialize a value of type +/// ToType from the expression From. Return the implicit conversion +/// sequence required to pass this argument, which may be a bad +/// conversion sequence (meaning that the argument cannot be passed to +/// a parameter of this type). If @p SuppressUserConversions, then we +/// do not permit any user-defined conversion sequences. If @p ForceRValue, +/// then we treat @p From as an rvalue, even if it is an lvalue. +ImplicitConversionSequence +Sema::TryCopyInitialization(Expr *From, QualType ToType, + bool SuppressUserConversions, bool ForceRValue) { + if (ToType->isReferenceType()) { + ImplicitConversionSequence ICS; + CheckReferenceInit(From, ToType, &ICS, SuppressUserConversions, + /*AllowExplicit=*/false, ForceRValue); + return ICS; + } else { + return TryImplicitConversion(From, ToType, SuppressUserConversions, + ForceRValue); + } +} + +/// PerformCopyInitialization - Copy-initialize an object of type @p ToType with +/// the expression @p From. Returns true (and emits a diagnostic) if there was +/// an error, returns false if the initialization succeeded. Elidable should +/// be true when the copy may be elided (C++ 12.8p15). Overload resolution works +/// differently in C++0x for this case. +bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType, + const char* Flavor, bool Elidable) { + if (!getLangOptions().CPlusPlus) { + // In C, argument passing is the same as performing an assignment. + QualType FromType = From->getType(); + + AssignConvertType ConvTy = + CheckSingleAssignmentConstraints(ToType, From); + if (ConvTy != Compatible && + CheckTransparentUnionArgumentConstraints(ToType, From) == Compatible) + ConvTy = Compatible; + + return DiagnoseAssignmentResult(ConvTy, From->getLocStart(), ToType, + FromType, From, Flavor); + } + + if (ToType->isReferenceType()) + return CheckReferenceInit(From, ToType); + + if (!PerformImplicitConversion(From, ToType, Flavor, + /*AllowExplicit=*/false, Elidable)) + return false; + + return Diag(From->getSourceRange().getBegin(), + diag::err_typecheck_convert_incompatible) + << ToType << From->getType() << Flavor << From->getSourceRange(); +} + +/// TryObjectArgumentInitialization - Try to initialize the object +/// parameter of the given member function (@c Method) from the +/// expression @p From. +ImplicitConversionSequence +Sema::TryObjectArgumentInitialization(Expr *From, CXXMethodDecl *Method) { + QualType ClassType = Context.getTypeDeclType(Method->getParent()); + unsigned MethodQuals = Method->getTypeQualifiers(); + QualType ImplicitParamType = ClassType.getQualifiedType(MethodQuals); + + // Set up the conversion sequence as a "bad" conversion, to allow us + // to exit early. + ImplicitConversionSequence ICS; + ICS.Standard.setAsIdentityConversion(); + ICS.ConversionKind = ImplicitConversionSequence::BadConversion; + + // We need to have an object of class type. + QualType FromType = From->getType(); + if (const PointerType *PT = FromType->getAsPointerType()) + FromType = PT->getPointeeType(); + + assert(FromType->isRecordType()); + + // The implicit object parmeter is has the type "reference to cv X", + // where X is the class of which the function is a member + // (C++ [over.match.funcs]p4). However, when finding an implicit + // conversion sequence for the argument, we are not allowed to + // create temporaries or perform user-defined conversions + // (C++ [over.match.funcs]p5). We perform a simplified version of + // reference binding here, that allows class rvalues to bind to + // non-constant references. + + // First check the qualifiers. We don't care about lvalue-vs-rvalue + // with the implicit object parameter (C++ [over.match.funcs]p5). + QualType FromTypeCanon = Context.getCanonicalType(FromType); + if (ImplicitParamType.getCVRQualifiers() != FromType.getCVRQualifiers() && + !ImplicitParamType.isAtLeastAsQualifiedAs(FromType)) + 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.getUnqualifiedType()) + ICS.Standard.Second = ICK_Identity; + else if (IsDerivedFrom(FromType, ClassType)) + ICS.Standard.Second = ICK_Derived_To_Base; + else + return ICS; + + // Success. Mark this as a reference binding. + ICS.ConversionKind = ImplicitConversionSequence::StandardConversion; + ICS.Standard.FromTypePtr = FromType.getAsOpaquePtr(); + ICS.Standard.ToTypePtr = ImplicitParamType.getAsOpaquePtr(); + ICS.Standard.ReferenceBinding = true; + ICS.Standard.DirectBinding = true; + ICS.Standard.RRefBinding = false; + return ICS; +} + +/// PerformObjectArgumentInitialization - Perform initialization of +/// the implicit object parameter for the given Method with the given +/// expression. +bool +Sema::PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method) { + QualType FromRecordType, DestType; + QualType ImplicitParamRecordType = + Method->getThisType(Context)->getAsPointerType()->getPointeeType(); + + if (const PointerType *PT = From->getType()->getAsPointerType()) { + FromRecordType = PT->getPointeeType(); + DestType = Method->getThisType(Context); + } else { + FromRecordType = From->getType(); + DestType = ImplicitParamRecordType; + } + + ImplicitConversionSequence ICS + = TryObjectArgumentInitialization(From, Method); + if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) + return Diag(From->getSourceRange().getBegin(), + diag::err_implicit_object_parameter_init) + << ImplicitParamRecordType << FromRecordType << From->getSourceRange(); + + if (ICS.Standard.Second == ICK_Derived_To_Base && + CheckDerivedToBaseConversion(FromRecordType, + ImplicitParamRecordType, + From->getSourceRange().getBegin(), + From->getSourceRange())) + return true; + + ImpCastExprToType(From, DestType, /*isLvalue=*/true); + return false; +} + +/// TryContextuallyConvertToBool - Attempt to contextually convert the +/// expression From to bool (C++0x [conv]p3). +ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) { + return TryImplicitConversion(From, Context.BoolTy, false, true); +} + +/// PerformContextuallyConvertToBool - Perform a contextual conversion +/// of the expression From to bool (C++0x [conv]p3). +bool Sema::PerformContextuallyConvertToBool(Expr *&From) { + ImplicitConversionSequence ICS = TryContextuallyConvertToBool(From); + if (!PerformImplicitConversion(From, Context.BoolTy, ICS, "converting")) + return false; + + return Diag(From->getSourceRange().getBegin(), + diag::err_typecheck_bool_condition) + << From->getType() << From->getSourceRange(); +} + +/// AddOverloadCandidate - Adds the given function to the set of +/// candidate functions, using the given function call arguments. If +/// @p SuppressUserConversions, then don't allow user-defined +/// conversions via constructors or conversion operators. +/// If @p ForceRValue, treat all arguments as rvalues. This is a slightly +/// hacky way to implement the overloading rules for elidable copy +/// initialization in C++0x (C++0x 12.8p15). +void +Sema::AddOverloadCandidate(FunctionDecl *Function, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversions, + bool ForceRValue) +{ + const FunctionProtoType* Proto + = dyn_cast<FunctionProtoType>(Function->getType()->getAsFunctionType()); + assert(Proto && "Functions without a prototype cannot be overloaded"); + assert(!isa<CXXConversionDecl>(Function) && + "Use AddConversionCandidate for conversion functions"); + + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) { + if (!isa<CXXConstructorDecl>(Method)) { + // If we get here, it's because we're calling a member function + // that is named without a member access expression (e.g., + // "this->f") that was either written explicitly or created + // implicitly. This can happen with a qualified call to a member + // function, e.g., X::f(). We use a NULL object as the implied + // object argument (C++ [over.call.func]p3). + AddMethodCandidate(Method, 0, Args, NumArgs, CandidateSet, + SuppressUserConversions, ForceRValue); + return; + } + // We treat a constructor like a non-member function, since its object + // argument doesn't participate in overload resolution. + } + + + // Add this candidate + CandidateSet.push_back(OverloadCandidate()); + OverloadCandidate& Candidate = CandidateSet.back(); + Candidate.Function = Function; + Candidate.Viable = true; + Candidate.IsSurrogate = false; + Candidate.IgnoreObjectArgument = false; + + unsigned NumArgsInProto = Proto->getNumArgs(); + + // (C++ 13.3.2p2): A candidate function having fewer than m + // parameters is viable only if it has an ellipsis in its parameter + // list (8.3.5). + if (NumArgs > NumArgsInProto && !Proto->isVariadic()) { + Candidate.Viable = false; + return; + } + + // (C++ 13.3.2p2): A candidate function having more than m parameters + // is viable only if the (m+1)st parameter has a default argument + // (8.3.6). For the purposes of overload resolution, the + // parameter list is truncated on the right, so that there are + // exactly m parameters. + unsigned MinRequiredArgs = Function->getMinRequiredArguments(); + if (NumArgs < MinRequiredArgs) { + // Not enough arguments. + Candidate.Viable = false; + return; + } + + // Determine the implicit conversion sequences for each of the + // arguments. + Candidate.Conversions.resize(NumArgs); + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + if (ArgIdx < NumArgsInProto) { + // (C++ 13.3.2p3): for F to be a viable function, there shall + // exist for each argument an implicit conversion sequence + // (13.3.3.1) that converts that argument to the corresponding + // parameter of F. + QualType ParamType = Proto->getArgType(ArgIdx); + Candidate.Conversions[ArgIdx] + = TryCopyInitialization(Args[ArgIdx], ParamType, + SuppressUserConversions, ForceRValue); + if (Candidate.Conversions[ArgIdx].ConversionKind + == ImplicitConversionSequence::BadConversion) { + Candidate.Viable = false; + break; + } + } else { + // (C++ 13.3.2p2): For the purposes of overload resolution, any + // argument for which there is no corresponding parameter is + // considered to ""match the ellipsis" (C+ 13.3.3.1.3). + Candidate.Conversions[ArgIdx].ConversionKind + = ImplicitConversionSequence::EllipsisConversion; + } + } +} + +/// \brief Add all of the function declarations in the given function set to +/// the overload canddiate set. +void Sema::AddFunctionCandidates(const FunctionSet &Functions, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversions) { + for (FunctionSet::const_iterator F = Functions.begin(), + FEnd = Functions.end(); + F != FEnd; ++F) + AddOverloadCandidate(*F, Args, NumArgs, CandidateSet, + SuppressUserConversions); +} + +/// AddMethodCandidate - Adds the given C++ member function to the set +/// of candidate functions, using the given function call arguments +/// and the object argument (@c Object). For example, in a call +/// @c o.f(a1,a2), @c Object will contain @c o and @c Args will contain +/// both @c a1 and @c a2. If @p SuppressUserConversions, then don't +/// allow user-defined conversions via constructors or conversion +/// operators. If @p ForceRValue, treat all arguments as rvalues. This is +/// a slightly hacky way to implement the overloading rules for elidable copy +/// initialization in C++0x (C++0x 12.8p15). +void +Sema::AddMethodCandidate(CXXMethodDecl *Method, Expr *Object, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversions, bool ForceRValue) +{ + const FunctionProtoType* Proto + = dyn_cast<FunctionProtoType>(Method->getType()->getAsFunctionType()); + assert(Proto && "Methods without a prototype cannot be overloaded"); + assert(!isa<CXXConversionDecl>(Method) && + "Use AddConversionCandidate for conversion functions"); + assert(!isa<CXXConstructorDecl>(Method) && + "Use AddOverloadCandidate for constructors"); + + // Add this candidate + CandidateSet.push_back(OverloadCandidate()); + OverloadCandidate& Candidate = CandidateSet.back(); + Candidate.Function = Method; + Candidate.IsSurrogate = false; + Candidate.IgnoreObjectArgument = false; + + unsigned NumArgsInProto = Proto->getNumArgs(); + + // (C++ 13.3.2p2): A candidate function having fewer than m + // parameters is viable only if it has an ellipsis in its parameter + // list (8.3.5). + if (NumArgs > NumArgsInProto && !Proto->isVariadic()) { + Candidate.Viable = false; + return; + } + + // (C++ 13.3.2p2): A candidate function having more than m parameters + // is viable only if the (m+1)st parameter has a default argument + // (8.3.6). For the purposes of overload resolution, the + // parameter list is truncated on the right, so that there are + // exactly m parameters. + unsigned MinRequiredArgs = Method->getMinRequiredArguments(); + if (NumArgs < MinRequiredArgs) { + // Not enough arguments. + Candidate.Viable = false; + return; + } + + Candidate.Viable = true; + Candidate.Conversions.resize(NumArgs + 1); + + if (Method->isStatic() || !Object) + // The implicit object argument is ignored. + Candidate.IgnoreObjectArgument = true; + else { + // Determine the implicit conversion sequence for the object + // parameter. + Candidate.Conversions[0] = TryObjectArgumentInitialization(Object, Method); + if (Candidate.Conversions[0].ConversionKind + == ImplicitConversionSequence::BadConversion) { + Candidate.Viable = false; + return; + } + } + + // Determine the implicit conversion sequences for each of the + // arguments. + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + if (ArgIdx < NumArgsInProto) { + // (C++ 13.3.2p3): for F to be a viable function, there shall + // exist for each argument an implicit conversion sequence + // (13.3.3.1) that converts that argument to the corresponding + // parameter of F. + QualType ParamType = Proto->getArgType(ArgIdx); + Candidate.Conversions[ArgIdx + 1] + = TryCopyInitialization(Args[ArgIdx], ParamType, + SuppressUserConversions, ForceRValue); + if (Candidate.Conversions[ArgIdx + 1].ConversionKind + == ImplicitConversionSequence::BadConversion) { + Candidate.Viable = false; + break; + } + } else { + // (C++ 13.3.2p2): For the purposes of overload resolution, any + // argument for which there is no corresponding parameter is + // considered to ""match the ellipsis" (C+ 13.3.3.1.3). + Candidate.Conversions[ArgIdx + 1].ConversionKind + = ImplicitConversionSequence::EllipsisConversion; + } + } +} + +/// AddConversionCandidate - Add a C++ conversion function as a +/// candidate in the candidate set (C++ [over.match.conv], +/// C++ [over.match.copy]). From is the expression we're converting from, +/// and ToType is the type that we're eventually trying to convert to +/// (which may or may not be the same type as the type that the +/// conversion function produces). +void +Sema::AddConversionCandidate(CXXConversionDecl *Conversion, + Expr *From, QualType ToType, + OverloadCandidateSet& CandidateSet) { + // Add this candidate + CandidateSet.push_back(OverloadCandidate()); + OverloadCandidate& Candidate = CandidateSet.back(); + Candidate.Function = Conversion; + Candidate.IsSurrogate = false; + Candidate.IgnoreObjectArgument = false; + Candidate.FinalConversion.setAsIdentityConversion(); + Candidate.FinalConversion.FromTypePtr + = Conversion->getConversionType().getAsOpaquePtr(); + Candidate.FinalConversion.ToTypePtr = ToType.getAsOpaquePtr(); + + // Determine the implicit conversion sequence for the implicit + // object parameter. + Candidate.Viable = true; + Candidate.Conversions.resize(1); + Candidate.Conversions[0] = TryObjectArgumentInitialization(From, Conversion); + + if (Candidate.Conversions[0].ConversionKind + == ImplicitConversionSequence::BadConversion) { + Candidate.Viable = false; + return; + } + + // To determine what the conversion from the result of calling the + // conversion function to the type we're eventually trying to + // convert to (ToType), we need to synthesize a call to the + // conversion function and attempt copy initialization from it. This + // makes sure that we get the right semantics with respect to + // lvalues/rvalues and the type. Fortunately, we can allocate this + // call on the stack and we don't need its arguments to be + // well-formed. + DeclRefExpr ConversionRef(Conversion, Conversion->getType(), + SourceLocation()); + ImplicitCastExpr ConversionFn(Context.getPointerType(Conversion->getType()), + &ConversionRef, false); + + // Note that it is safe to allocate CallExpr on the stack here because + // there are 0 arguments (i.e., nothing is allocated using ASTContext's + // allocator). + CallExpr Call(Context, &ConversionFn, 0, 0, + Conversion->getConversionType().getNonReferenceType(), + SourceLocation()); + ImplicitConversionSequence ICS = TryCopyInitialization(&Call, ToType, true); + switch (ICS.ConversionKind) { + case ImplicitConversionSequence::StandardConversion: + Candidate.FinalConversion = ICS.Standard; + break; + + case ImplicitConversionSequence::BadConversion: + Candidate.Viable = false; + break; + + default: + assert(false && + "Can only end up with a standard conversion sequence or failure"); + } +} + +/// AddSurrogateCandidate - Adds a "surrogate" candidate function that +/// converts the given @c Object to a function pointer via the +/// conversion function @c Conversion, and then attempts to call it +/// with the given arguments (C++ [over.call.object]p2-4). Proto is +/// the type of function that we'll eventually be calling. +void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, + const FunctionProtoType *Proto, + Expr *Object, Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet) { + CandidateSet.push_back(OverloadCandidate()); + OverloadCandidate& Candidate = CandidateSet.back(); + Candidate.Function = 0; + Candidate.Surrogate = Conversion; + Candidate.Viable = true; + Candidate.IsSurrogate = true; + Candidate.IgnoreObjectArgument = false; + Candidate.Conversions.resize(NumArgs + 1); + + // Determine the implicit conversion sequence for the implicit + // object parameter. + ImplicitConversionSequence ObjectInit + = TryObjectArgumentInitialization(Object, Conversion); + if (ObjectInit.ConversionKind == ImplicitConversionSequence::BadConversion) { + Candidate.Viable = false; + return; + } + + // The first conversion is actually a user-defined conversion whose + // first conversion is ObjectInit's standard conversion (which is + // effectively a reference binding). Record it as such. + Candidate.Conversions[0].ConversionKind + = ImplicitConversionSequence::UserDefinedConversion; + Candidate.Conversions[0].UserDefined.Before = ObjectInit.Standard; + Candidate.Conversions[0].UserDefined.ConversionFunction = Conversion; + Candidate.Conversions[0].UserDefined.After + = Candidate.Conversions[0].UserDefined.Before; + Candidate.Conversions[0].UserDefined.After.setAsIdentityConversion(); + + // Find the + unsigned NumArgsInProto = Proto->getNumArgs(); + + // (C++ 13.3.2p2): A candidate function having fewer than m + // parameters is viable only if it has an ellipsis in its parameter + // list (8.3.5). + if (NumArgs > NumArgsInProto && !Proto->isVariadic()) { + Candidate.Viable = false; + return; + } + + // Function types don't have any default arguments, so just check if + // we have enough arguments. + if (NumArgs < NumArgsInProto) { + // Not enough arguments. + Candidate.Viable = false; + return; + } + + // Determine the implicit conversion sequences for each of the + // arguments. + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + if (ArgIdx < NumArgsInProto) { + // (C++ 13.3.2p3): for F to be a viable function, there shall + // exist for each argument an implicit conversion sequence + // (13.3.3.1) that converts that argument to the corresponding + // parameter of F. + QualType ParamType = Proto->getArgType(ArgIdx); + Candidate.Conversions[ArgIdx + 1] + = TryCopyInitialization(Args[ArgIdx], ParamType, + /*SuppressUserConversions=*/false); + if (Candidate.Conversions[ArgIdx + 1].ConversionKind + == ImplicitConversionSequence::BadConversion) { + Candidate.Viable = false; + break; + } + } else { + // (C++ 13.3.2p2): For the purposes of overload resolution, any + // argument for which there is no corresponding parameter is + // considered to ""match the ellipsis" (C+ 13.3.3.1.3). + Candidate.Conversions[ArgIdx + 1].ConversionKind + = ImplicitConversionSequence::EllipsisConversion; + } + } +} + +// FIXME: This will eventually be removed, once we've migrated all of the +// operator overloading logic over to the scheme used by binary operators, which +// works for template instantiation. +void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, + SourceLocation OpLoc, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet, + SourceRange OpRange) { + + FunctionSet Functions; + + QualType T1 = Args[0]->getType(); + QualType T2; + if (NumArgs > 1) + T2 = Args[1]->getType(); + + DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); + if (S) + LookupOverloadedOperatorName(Op, S, T1, T2, Functions); + ArgumentDependentLookup(OpName, Args, NumArgs, Functions); + AddFunctionCandidates(Functions, Args, NumArgs, CandidateSet); + AddMemberOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet, OpRange); + AddBuiltinOperatorCandidates(Op, Args, NumArgs, CandidateSet); +} + +/// \brief Add overload candidates for overloaded operators that are +/// member functions. +/// +/// Add the overloaded operator candidates that are member functions +/// for the operator Op that was used in an operator expression such +/// as "x Op y". , Args/NumArgs provides the operator arguments, and +/// CandidateSet will store the added overload candidates. (C++ +/// [over.match.oper]). +void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, + SourceLocation OpLoc, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet, + SourceRange OpRange) { + DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); + + // C++ [over.match.oper]p3: + // For a unary operator @ with an operand of a type whose + // cv-unqualified version is T1, and for a binary operator @ with + // a left operand of a type whose cv-unqualified version is T1 and + // a right operand of a type whose cv-unqualified version is T2, + // three sets of candidate functions, designated member + // candidates, non-member candidates and built-in candidates, are + // constructed as follows: + QualType T1 = Args[0]->getType(); + QualType T2; + if (NumArgs > 1) + T2 = Args[1]->getType(); + + // -- If T1 is a class type, the set of member candidates is the + // result of the qualified lookup of T1::operator@ + // (13.3.1.1.1); otherwise, the set of member candidates is + // empty. + // FIXME: Lookup in base classes, too! + if (const RecordType *T1Rec = T1->getAsRecordType()) { + DeclContext::lookup_const_iterator Oper, OperEnd; + for (llvm::tie(Oper, OperEnd) = T1Rec->getDecl()->lookup(Context, OpName); + Oper != OperEnd; ++Oper) + AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Args[0], + Args+1, NumArgs - 1, CandidateSet, + /*SuppressUserConversions=*/false); + } +} + +/// AddBuiltinCandidate - Add a candidate for a built-in +/// operator. ResultTy and ParamTys are the result and parameter types +/// of the built-in candidate, respectively. Args and NumArgs are the +/// arguments being passed to the candidate. IsAssignmentOperator +/// should be true when this built-in candidate is an assignment +/// operator. NumContextualBoolArguments is the number of arguments +/// (at the beginning of the argument list) that will be contextually +/// converted to bool. +void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet, + bool IsAssignmentOperator, + unsigned NumContextualBoolArguments) { + // Add this candidate + CandidateSet.push_back(OverloadCandidate()); + OverloadCandidate& Candidate = CandidateSet.back(); + Candidate.Function = 0; + Candidate.IsSurrogate = false; + Candidate.IgnoreObjectArgument = false; + Candidate.BuiltinTypes.ResultTy = ResultTy; + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) + Candidate.BuiltinTypes.ParamTypes[ArgIdx] = ParamTys[ArgIdx]; + + // Determine the implicit conversion sequences for each of the + // arguments. + Candidate.Viable = true; + Candidate.Conversions.resize(NumArgs); + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + // C++ [over.match.oper]p4: + // For the built-in assignment operators, conversions of the + // left operand are restricted as follows: + // -- no temporaries are introduced to hold the left operand, and + // -- no user-defined conversions are applied to the left + // operand to achieve a type match with the left-most + // parameter of a built-in candidate. + // + // We block these conversions by turning off user-defined + // conversions, since that is the only way that initialization of + // a reference to a non-class type can occur from something that + // is not of the same type. + if (ArgIdx < NumContextualBoolArguments) { + assert(ParamTys[ArgIdx] == Context.BoolTy && + "Contextual conversion to bool requires bool type"); + Candidate.Conversions[ArgIdx] = TryContextuallyConvertToBool(Args[ArgIdx]); + } else { + Candidate.Conversions[ArgIdx] + = TryCopyInitialization(Args[ArgIdx], ParamTys[ArgIdx], + ArgIdx == 0 && IsAssignmentOperator); + } + if (Candidate.Conversions[ArgIdx].ConversionKind + == ImplicitConversionSequence::BadConversion) { + Candidate.Viable = false; + break; + } + } +} + +/// BuiltinCandidateTypeSet - A set of types that will be used for the +/// candidate operator functions for built-in operators (C++ +/// [over.built]). The types are separated into pointer types and +/// enumeration types. +class BuiltinCandidateTypeSet { + /// TypeSet - A set of types. + typedef llvm::SmallPtrSet<QualType, 8> TypeSet; + + /// PointerTypes - The set of pointer types that will be used in the + /// built-in candidates. + TypeSet PointerTypes; + + /// MemberPointerTypes - The set of member pointer types that will be + /// used in the built-in candidates. + TypeSet MemberPointerTypes; + + /// EnumerationTypes - The set of enumeration types that will be + /// used in the built-in candidates. + TypeSet EnumerationTypes; + + /// Context - The AST context in which we will build the type sets. + ASTContext &Context; + + bool AddPointerWithMoreQualifiedTypeVariants(QualType Ty); + bool AddMemberPointerWithMoreQualifiedTypeVariants(QualType Ty); + +public: + /// iterator - Iterates through the types that are part of the set. + typedef TypeSet::iterator iterator; + + BuiltinCandidateTypeSet(ASTContext &Context) : Context(Context) { } + + void AddTypesConvertedFrom(QualType Ty, bool AllowUserConversions, + bool AllowExplicitConversions); + + /// pointer_begin - First pointer type found; + iterator pointer_begin() { return PointerTypes.begin(); } + + /// pointer_end - Past the last pointer type found; + iterator pointer_end() { return PointerTypes.end(); } + + /// member_pointer_begin - First member pointer type found; + iterator member_pointer_begin() { return MemberPointerTypes.begin(); } + + /// member_pointer_end - Past the last member pointer type found; + iterator member_pointer_end() { return MemberPointerTypes.end(); } + + /// enumeration_begin - First enumeration type found; + iterator enumeration_begin() { return EnumerationTypes.begin(); } + + /// enumeration_end - Past the last enumeration type found; + iterator enumeration_end() { return EnumerationTypes.end(); } +}; + +/// AddPointerWithMoreQualifiedTypeVariants - Add the pointer type @p Ty to +/// the set of pointer types along with any more-qualified variants of +/// that type. For example, if @p Ty is "int const *", this routine +/// will add "int const *", "int const volatile *", "int const +/// restrict *", and "int const volatile restrict *" to the set of +/// pointer types. Returns true if the add of @p Ty itself succeeded, +/// false otherwise. +bool +BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty) { + // Insert this type. + if (!PointerTypes.insert(Ty)) + return false; + + if (const PointerType *PointerTy = Ty->getAsPointerType()) { + QualType PointeeTy = PointerTy->getPointeeType(); + // FIXME: Optimize this so that we don't keep trying to add the same types. + + // FIXME: Do we have to add CVR qualifiers at *all* levels to deal with all + // pointer conversions that don't cast away constness? + if (!PointeeTy.isConstQualified()) + AddPointerWithMoreQualifiedTypeVariants + (Context.getPointerType(PointeeTy.withConst())); + if (!PointeeTy.isVolatileQualified()) + AddPointerWithMoreQualifiedTypeVariants + (Context.getPointerType(PointeeTy.withVolatile())); + if (!PointeeTy.isRestrictQualified()) + AddPointerWithMoreQualifiedTypeVariants + (Context.getPointerType(PointeeTy.withRestrict())); + } + + return true; +} + +/// AddMemberPointerWithMoreQualifiedTypeVariants - Add the pointer type @p Ty +/// to the set of pointer types along with any more-qualified variants of +/// that type. For example, if @p Ty is "int const *", this routine +/// will add "int const *", "int const volatile *", "int const +/// restrict *", and "int const volatile restrict *" to the set of +/// pointer types. Returns true if the add of @p Ty itself succeeded, +/// false otherwise. +bool +BuiltinCandidateTypeSet::AddMemberPointerWithMoreQualifiedTypeVariants( + QualType Ty) { + // Insert this type. + if (!MemberPointerTypes.insert(Ty)) + return false; + + if (const MemberPointerType *PointerTy = Ty->getAsMemberPointerType()) { + QualType PointeeTy = PointerTy->getPointeeType(); + const Type *ClassTy = PointerTy->getClass(); + // FIXME: Optimize this so that we don't keep trying to add the same types. + + if (!PointeeTy.isConstQualified()) + AddMemberPointerWithMoreQualifiedTypeVariants + (Context.getMemberPointerType(PointeeTy.withConst(), ClassTy)); + if (!PointeeTy.isVolatileQualified()) + AddMemberPointerWithMoreQualifiedTypeVariants + (Context.getMemberPointerType(PointeeTy.withVolatile(), ClassTy)); + if (!PointeeTy.isRestrictQualified()) + AddMemberPointerWithMoreQualifiedTypeVariants + (Context.getMemberPointerType(PointeeTy.withRestrict(), ClassTy)); + } + + return true; +} + +/// AddTypesConvertedFrom - Add each of the types to which the type @p +/// Ty can be implicit converted to the given set of @p Types. We're +/// primarily interested in pointer types and enumeration types. We also +/// take member pointer types, for the conditional operator. +/// AllowUserConversions is true if we should look at the conversion +/// functions of a class type, and AllowExplicitConversions if we +/// should also include the explicit conversion functions of a class +/// type. +void +BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, + bool AllowUserConversions, + bool AllowExplicitConversions) { + // Only deal with canonical types. + Ty = Context.getCanonicalType(Ty); + + // Look through reference types; they aren't part of the type of an + // expression for the purposes of conversions. + if (const ReferenceType *RefTy = Ty->getAsReferenceType()) + Ty = RefTy->getPointeeType(); + + // We don't care about qualifiers on the type. + Ty = Ty.getUnqualifiedType(); + + if (const PointerType *PointerTy = Ty->getAsPointerType()) { + QualType PointeeTy = PointerTy->getPointeeType(); + + // Insert our type, and its more-qualified variants, into the set + // of types. + if (!AddPointerWithMoreQualifiedTypeVariants(Ty)) + return; + + // Add 'cv void*' to our set of types. + if (!Ty->isVoidType()) { + QualType QualVoid + = Context.VoidTy.getQualifiedType(PointeeTy.getCVRQualifiers()); + AddPointerWithMoreQualifiedTypeVariants(Context.getPointerType(QualVoid)); + } + + // If this is a pointer to a class type, add pointers to its bases + // (with the same level of cv-qualification as the original + // derived class, of course). + if (const RecordType *PointeeRec = PointeeTy->getAsRecordType()) { + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(PointeeRec->getDecl()); + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(); + Base != ClassDecl->bases_end(); ++Base) { + QualType BaseTy = Context.getCanonicalType(Base->getType()); + BaseTy = BaseTy.getQualifiedType(PointeeTy.getCVRQualifiers()); + + // Add the pointer type, recursively, so that we get all of + // the indirect base classes, too. + AddTypesConvertedFrom(Context.getPointerType(BaseTy), false, false); + } + } + } else if (Ty->isMemberPointerType()) { + // Member pointers are far easier, since the pointee can't be converted. + if (!AddMemberPointerWithMoreQualifiedTypeVariants(Ty)) + return; + } else if (Ty->isEnumeralType()) { + EnumerationTypes.insert(Ty); + } else if (AllowUserConversions) { + if (const RecordType *TyRec = Ty->getAsRecordType()) { + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl()); + // FIXME: Visit conversion functions in the base classes, too. + OverloadedFunctionDecl *Conversions + = ClassDecl->getConversionFunctions(); + for (OverloadedFunctionDecl::function_iterator Func + = Conversions->function_begin(); + Func != Conversions->function_end(); ++Func) { + CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func); + if (AllowExplicitConversions || !Conv->isExplicit()) + AddTypesConvertedFrom(Conv->getConversionType(), false, false); + } + } + } +} + +/// AddBuiltinOperatorCandidates - Add the appropriate built-in +/// operator overloads to the candidate set (C++ [over.built]), based +/// on the operator @p Op and the arguments given. For example, if the +/// operator is a binary '+', this routine might add "int +/// operator+(int, int)" to cover integer addition. +void +Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet) { + // The set of "promoted arithmetic types", which are the arithmetic + // types are that preserved by promotion (C++ [over.built]p2). Note + // that the first few of these types are the promoted integral + // types; these types need to be first. + // FIXME: What about complex? + const unsigned FirstIntegralType = 0; + const unsigned LastIntegralType = 13; + const unsigned FirstPromotedIntegralType = 7, + LastPromotedIntegralType = 13; + const unsigned FirstPromotedArithmeticType = 7, + LastPromotedArithmeticType = 16; + const unsigned NumArithmeticTypes = 16; + QualType ArithmeticTypes[NumArithmeticTypes] = { + Context.BoolTy, Context.CharTy, Context.WCharTy, + Context.SignedCharTy, Context.ShortTy, + Context.UnsignedCharTy, Context.UnsignedShortTy, + Context.IntTy, Context.LongTy, Context.LongLongTy, + Context.UnsignedIntTy, Context.UnsignedLongTy, Context.UnsignedLongLongTy, + Context.FloatTy, Context.DoubleTy, Context.LongDoubleTy + }; + + // Find all of the types that the arguments can convert to, but only + // if the operator we're looking at has built-in operator candidates + // that make use of these types. + BuiltinCandidateTypeSet CandidateTypes(Context); + if (Op == OO_Less || Op == OO_Greater || Op == OO_LessEqual || + Op == OO_GreaterEqual || Op == OO_EqualEqual || Op == OO_ExclaimEqual || + Op == OO_Plus || (Op == OO_Minus && NumArgs == 2) || Op == OO_Equal || + Op == OO_PlusEqual || Op == OO_MinusEqual || Op == OO_Subscript || + Op == OO_ArrowStar || Op == OO_PlusPlus || Op == OO_MinusMinus || + (Op == OO_Star && NumArgs == 1) || Op == OO_Conditional) { + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) + CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType(), + true, + (Op == OO_Exclaim || + Op == OO_AmpAmp || + Op == OO_PipePipe)); + } + + bool isComparison = false; + switch (Op) { + case OO_None: + case NUM_OVERLOADED_OPERATORS: + assert(false && "Expected an overloaded operator"); + break; + + case OO_Star: // '*' is either unary or binary + if (NumArgs == 1) + goto UnaryStar; + else + goto BinaryStar; + break; + + case OO_Plus: // '+' is either unary or binary + if (NumArgs == 1) + goto UnaryPlus; + else + goto BinaryPlus; + break; + + case OO_Minus: // '-' is either unary or binary + if (NumArgs == 1) + goto UnaryMinus; + else + goto BinaryMinus; + break; + + case OO_Amp: // '&' is either unary or binary + if (NumArgs == 1) + goto UnaryAmp; + else + goto BinaryAmp; + + case OO_PlusPlus: + case OO_MinusMinus: + // C++ [over.built]p3: + // + // For every pair (T, VQ), where T is an arithmetic type, and VQ + // is either volatile or empty, there exist candidate operator + // functions of the form + // + // VQ T& operator++(VQ T&); + // T operator++(VQ T&, int); + // + // C++ [over.built]p4: + // + // For every pair (T, VQ), where T is an arithmetic type other + // than bool, and VQ is either volatile or empty, there exist + // candidate operator functions of the form + // + // VQ T& operator--(VQ T&); + // T operator--(VQ T&, int); + for (unsigned Arith = (Op == OO_PlusPlus? 0 : 1); + Arith < NumArithmeticTypes; ++Arith) { + QualType ArithTy = ArithmeticTypes[Arith]; + QualType ParamTypes[2] + = { Context.getLValueReferenceType(ArithTy), Context.IntTy }; + + // Non-volatile version. + if (NumArgs == 1) + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); + else + AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet); + + // Volatile version + ParamTypes[0] = Context.getLValueReferenceType(ArithTy.withVolatile()); + if (NumArgs == 1) + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); + else + AddBuiltinCandidate(ArithTy, ParamTypes, Args, 2, CandidateSet); + } + + // C++ [over.built]p5: + // + // For every pair (T, VQ), where T is a cv-qualified or + // cv-unqualified object type, and VQ is either volatile or + // empty, there exist candidate operator functions of the form + // + // T*VQ& operator++(T*VQ&); + // T*VQ& operator--(T*VQ&); + // T* operator++(T*VQ&, int); + // T* operator--(T*VQ&, int); + for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); + Ptr != CandidateTypes.pointer_end(); ++Ptr) { + // Skip pointer types that aren't pointers to object types. + if (!(*Ptr)->getAsPointerType()->getPointeeType()->isObjectType()) + continue; + + QualType ParamTypes[2] = { + Context.getLValueReferenceType(*Ptr), Context.IntTy + }; + + // Without volatile + if (NumArgs == 1) + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); + else + AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); + + if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) { + // With volatile + ParamTypes[0] = Context.getLValueReferenceType((*Ptr).withVolatile()); + if (NumArgs == 1) + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); + else + AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); + } + } + break; + + UnaryStar: + // C++ [over.built]p6: + // For every cv-qualified or cv-unqualified object type T, there + // exist candidate operator functions of the form + // + // T& operator*(T*); + // + // C++ [over.built]p7: + // For every function type T, there exist candidate operator + // functions of the form + // T& operator*(T*); + for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); + Ptr != CandidateTypes.pointer_end(); ++Ptr) { + QualType ParamTy = *Ptr; + QualType PointeeTy = ParamTy->getAsPointerType()->getPointeeType(); + AddBuiltinCandidate(Context.getLValueReferenceType(PointeeTy), + &ParamTy, Args, 1, CandidateSet); + } + break; + + UnaryPlus: + // C++ [over.built]p8: + // For every type T, there exist candidate operator functions of + // the form + // + // T* operator+(T*); + for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); + Ptr != CandidateTypes.pointer_end(); ++Ptr) { + QualType ParamTy = *Ptr; + AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet); + } + + // Fall through + + UnaryMinus: + // C++ [over.built]p9: + // For every promoted arithmetic type T, there exist candidate + // operator functions of the form + // + // T operator+(T); + // T operator-(T); + for (unsigned Arith = FirstPromotedArithmeticType; + Arith < LastPromotedArithmeticType; ++Arith) { + QualType ArithTy = ArithmeticTypes[Arith]; + AddBuiltinCandidate(ArithTy, &ArithTy, Args, 1, CandidateSet); + } + break; + + case OO_Tilde: + // C++ [over.built]p10: + // For every promoted integral type T, there exist candidate + // operator functions of the form + // + // T operator~(T); + for (unsigned Int = FirstPromotedIntegralType; + Int < LastPromotedIntegralType; ++Int) { + QualType IntTy = ArithmeticTypes[Int]; + AddBuiltinCandidate(IntTy, &IntTy, Args, 1, CandidateSet); + } + break; + + case OO_New: + case OO_Delete: + case OO_Array_New: + case OO_Array_Delete: + case OO_Call: + assert(false && "Special operators don't use AddBuiltinOperatorCandidates"); + break; + + case OO_Comma: + UnaryAmp: + case OO_Arrow: + // C++ [over.match.oper]p3: + // -- For the operator ',', the unary operator '&', or the + // operator '->', the built-in candidates set is empty. + break; + + case OO_Less: + case OO_Greater: + case OO_LessEqual: + case OO_GreaterEqual: + case OO_EqualEqual: + case OO_ExclaimEqual: + // C++ [over.built]p15: + // + // For every pointer or enumeration type T, there exist + // candidate operator functions of the form + // + // bool operator<(T, T); + // bool operator>(T, T); + // bool operator<=(T, T); + // bool operator>=(T, T); + // bool operator==(T, T); + // bool operator!=(T, T); + for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); + Ptr != CandidateTypes.pointer_end(); ++Ptr) { + QualType ParamTypes[2] = { *Ptr, *Ptr }; + AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet); + } + for (BuiltinCandidateTypeSet::iterator Enum + = CandidateTypes.enumeration_begin(); + Enum != CandidateTypes.enumeration_end(); ++Enum) { + QualType ParamTypes[2] = { *Enum, *Enum }; + AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet); + } + + // Fall through. + isComparison = true; + + BinaryPlus: + BinaryMinus: + if (!isComparison) { + // We didn't fall through, so we must have OO_Plus or OO_Minus. + + // C++ [over.built]p13: + // + // For every cv-qualified or cv-unqualified object type T + // there exist candidate operator functions of the form + // + // T* operator+(T*, ptrdiff_t); + // T& operator[](T*, ptrdiff_t); [BELOW] + // T* operator-(T*, ptrdiff_t); + // T* operator+(ptrdiff_t, T*); + // T& operator[](ptrdiff_t, T*); [BELOW] + // + // C++ [over.built]p14: + // + // For every T, where T is a pointer to object type, there + // exist candidate operator functions of the form + // + // ptrdiff_t operator-(T, T); + for (BuiltinCandidateTypeSet::iterator Ptr + = CandidateTypes.pointer_begin(); + Ptr != CandidateTypes.pointer_end(); ++Ptr) { + QualType ParamTypes[2] = { *Ptr, Context.getPointerDiffType() }; + + // operator+(T*, ptrdiff_t) or operator-(T*, ptrdiff_t) + AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); + + if (Op == OO_Plus) { + // T* operator+(ptrdiff_t, T*); + ParamTypes[0] = ParamTypes[1]; + ParamTypes[1] = *Ptr; + AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); + } else { + // ptrdiff_t operator-(T, T); + ParamTypes[1] = *Ptr; + AddBuiltinCandidate(Context.getPointerDiffType(), ParamTypes, + Args, 2, CandidateSet); + } + } + } + // Fall through + + case OO_Slash: + BinaryStar: + Conditional: + // C++ [over.built]p12: + // + // For every pair of promoted arithmetic types L and R, there + // exist candidate operator functions of the form + // + // LR operator*(L, R); + // LR operator/(L, R); + // LR operator+(L, R); + // LR operator-(L, R); + // bool operator<(L, R); + // bool operator>(L, R); + // bool operator<=(L, R); + // bool operator>=(L, R); + // bool operator==(L, R); + // bool operator!=(L, R); + // + // where LR is the result of the usual arithmetic conversions + // between types L and R. + // + // C++ [over.built]p24: + // + // For every pair of promoted arithmetic types L and R, there exist + // candidate operator functions of the form + // + // LR operator?(bool, L, R); + // + // where LR is the result of the usual arithmetic conversions + // between types L and R. + // Our candidates ignore the first parameter. + for (unsigned Left = FirstPromotedArithmeticType; + Left < LastPromotedArithmeticType; ++Left) { + for (unsigned Right = FirstPromotedArithmeticType; + Right < LastPromotedArithmeticType; ++Right) { + QualType LandR[2] = { ArithmeticTypes[Left], ArithmeticTypes[Right] }; + QualType Result + = isComparison? Context.BoolTy + : UsualArithmeticConversionsType(LandR[0], LandR[1]); + AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet); + } + } + break; + + case OO_Percent: + BinaryAmp: + case OO_Caret: + case OO_Pipe: + case OO_LessLess: + case OO_GreaterGreater: + // C++ [over.built]p17: + // + // For every pair of promoted integral types L and R, there + // exist candidate operator functions of the form + // + // LR operator%(L, R); + // LR operator&(L, R); + // LR operator^(L, R); + // LR operator|(L, R); + // L operator<<(L, R); + // L operator>>(L, R); + // + // where LR is the result of the usual arithmetic conversions + // between types L and R. + for (unsigned Left = FirstPromotedIntegralType; + Left < LastPromotedIntegralType; ++Left) { + for (unsigned Right = FirstPromotedIntegralType; + Right < LastPromotedIntegralType; ++Right) { + QualType LandR[2] = { ArithmeticTypes[Left], ArithmeticTypes[Right] }; + QualType Result = (Op == OO_LessLess || Op == OO_GreaterGreater) + ? LandR[0] + : UsualArithmeticConversionsType(LandR[0], LandR[1]); + AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet); + } + } + break; + + case OO_Equal: + // C++ [over.built]p20: + // + // For every pair (T, VQ), where T is an enumeration or + // (FIXME:) pointer to member type and VQ is either volatile or + // empty, there exist candidate operator functions of the form + // + // VQ T& operator=(VQ T&, T); + for (BuiltinCandidateTypeSet::iterator Enum + = CandidateTypes.enumeration_begin(); + Enum != CandidateTypes.enumeration_end(); ++Enum) { + QualType ParamTypes[2]; + + // T& operator=(T&, T) + ParamTypes[0] = Context.getLValueReferenceType(*Enum); + ParamTypes[1] = *Enum; + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + /*IsAssignmentOperator=*/false); + + if (!Context.getCanonicalType(*Enum).isVolatileQualified()) { + // volatile T& operator=(volatile T&, T) + ParamTypes[0] = Context.getLValueReferenceType((*Enum).withVolatile()); + ParamTypes[1] = *Enum; + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + /*IsAssignmentOperator=*/false); + } + } + // Fall through. + + case OO_PlusEqual: + case OO_MinusEqual: + // C++ [over.built]p19: + // + // For every pair (T, VQ), where T is any type and VQ is either + // volatile or empty, there exist candidate operator functions + // of the form + // + // T*VQ& operator=(T*VQ&, T*); + // + // C++ [over.built]p21: + // + // For every pair (T, VQ), where T is a cv-qualified or + // cv-unqualified object type and VQ is either volatile or + // empty, there exist candidate operator functions of the form + // + // T*VQ& operator+=(T*VQ&, ptrdiff_t); + // T*VQ& operator-=(T*VQ&, ptrdiff_t); + for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); + Ptr != CandidateTypes.pointer_end(); ++Ptr) { + QualType ParamTypes[2]; + ParamTypes[1] = (Op == OO_Equal)? *Ptr : Context.getPointerDiffType(); + + // non-volatile version + ParamTypes[0] = Context.getLValueReferenceType(*Ptr); + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + /*IsAssigmentOperator=*/Op == OO_Equal); + + if (!Context.getCanonicalType(*Ptr).isVolatileQualified()) { + // volatile version + ParamTypes[0] = Context.getLValueReferenceType((*Ptr).withVolatile()); + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + /*IsAssigmentOperator=*/Op == OO_Equal); + } + } + // Fall through. + + case OO_StarEqual: + case OO_SlashEqual: + // C++ [over.built]p18: + // + // For every triple (L, VQ, R), where L is an arithmetic type, + // VQ is either volatile or empty, and R is a promoted + // arithmetic type, there exist candidate operator functions of + // the form + // + // VQ L& operator=(VQ L&, R); + // VQ L& operator*=(VQ L&, R); + // VQ L& operator/=(VQ L&, R); + // VQ L& operator+=(VQ L&, R); + // VQ L& operator-=(VQ L&, R); + for (unsigned Left = 0; Left < NumArithmeticTypes; ++Left) { + for (unsigned Right = FirstPromotedArithmeticType; + Right < LastPromotedArithmeticType; ++Right) { + QualType ParamTypes[2]; + ParamTypes[1] = ArithmeticTypes[Right]; + + // Add this built-in operator as a candidate (VQ is empty). + ParamTypes[0] = Context.getLValueReferenceType(ArithmeticTypes[Left]); + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + /*IsAssigmentOperator=*/Op == OO_Equal); + + // Add this built-in operator as a candidate (VQ is 'volatile'). + ParamTypes[0] = ArithmeticTypes[Left].withVolatile(); + ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]); + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + /*IsAssigmentOperator=*/Op == OO_Equal); + } + } + break; + + case OO_PercentEqual: + case OO_LessLessEqual: + case OO_GreaterGreaterEqual: + case OO_AmpEqual: + case OO_CaretEqual: + case OO_PipeEqual: + // C++ [over.built]p22: + // + // For every triple (L, VQ, R), where L is an integral type, VQ + // is either volatile or empty, and R is a promoted integral + // type, there exist candidate operator functions of the form + // + // VQ L& operator%=(VQ L&, R); + // VQ L& operator<<=(VQ L&, R); + // VQ L& operator>>=(VQ L&, R); + // VQ L& operator&=(VQ L&, R); + // VQ L& operator^=(VQ L&, R); + // VQ L& operator|=(VQ L&, R); + for (unsigned Left = FirstIntegralType; Left < LastIntegralType; ++Left) { + for (unsigned Right = FirstPromotedIntegralType; + Right < LastPromotedIntegralType; ++Right) { + QualType ParamTypes[2]; + ParamTypes[1] = ArithmeticTypes[Right]; + + // Add this built-in operator as a candidate (VQ is empty). + ParamTypes[0] = Context.getLValueReferenceType(ArithmeticTypes[Left]); + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); + + // Add this built-in operator as a candidate (VQ is 'volatile'). + ParamTypes[0] = ArithmeticTypes[Left]; + ParamTypes[0].addVolatile(); + ParamTypes[0] = Context.getLValueReferenceType(ParamTypes[0]); + AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); + } + } + break; + + case OO_Exclaim: { + // C++ [over.operator]p23: + // + // There also exist candidate operator functions of the form + // + // bool operator!(bool); + // bool operator&&(bool, bool); [BELOW] + // bool operator||(bool, bool); [BELOW] + QualType ParamTy = Context.BoolTy; + AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet, + /*IsAssignmentOperator=*/false, + /*NumContextualBoolArguments=*/1); + break; + } + + case OO_AmpAmp: + case OO_PipePipe: { + // C++ [over.operator]p23: + // + // There also exist candidate operator functions of the form + // + // bool operator!(bool); [ABOVE] + // bool operator&&(bool, bool); + // bool operator||(bool, bool); + QualType ParamTypes[2] = { Context.BoolTy, Context.BoolTy }; + AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet, + /*IsAssignmentOperator=*/false, + /*NumContextualBoolArguments=*/2); + break; + } + + case OO_Subscript: + // C++ [over.built]p13: + // + // For every cv-qualified or cv-unqualified object type T there + // exist candidate operator functions of the form + // + // T* operator+(T*, ptrdiff_t); [ABOVE] + // T& operator[](T*, ptrdiff_t); + // T* operator-(T*, ptrdiff_t); [ABOVE] + // T* operator+(ptrdiff_t, T*); [ABOVE] + // T& operator[](ptrdiff_t, T*); + for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); + Ptr != CandidateTypes.pointer_end(); ++Ptr) { + QualType ParamTypes[2] = { *Ptr, Context.getPointerDiffType() }; + QualType PointeeType = (*Ptr)->getAsPointerType()->getPointeeType(); + QualType ResultTy = Context.getLValueReferenceType(PointeeType); + + // T& operator[](T*, ptrdiff_t) + AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet); + + // T& operator[](ptrdiff_t, T*); + ParamTypes[0] = ParamTypes[1]; + ParamTypes[1] = *Ptr; + AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet); + } + break; + + case OO_ArrowStar: + // FIXME: No support for pointer-to-members yet. + break; + + case OO_Conditional: + // Note that we don't consider the first argument, since it has been + // contextually converted to bool long ago. The candidates below are + // therefore added as binary. + // + // C++ [over.built]p24: + // For every type T, where T is a pointer or pointer-to-member type, + // there exist candidate operator functions of the form + // + // T operator?(bool, T, T); + // + for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(), + E = CandidateTypes.pointer_end(); Ptr != E; ++Ptr) { + QualType ParamTypes[2] = { *Ptr, *Ptr }; + AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); + } + for (BuiltinCandidateTypeSet::iterator Ptr = + CandidateTypes.member_pointer_begin(), + E = CandidateTypes.member_pointer_end(); Ptr != E; ++Ptr) { + QualType ParamTypes[2] = { *Ptr, *Ptr }; + AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); + } + goto Conditional; + } +} + +/// \brief Add function candidates found via argument-dependent lookup +/// to the set of overloading candidates. +/// +/// This routine performs argument-dependent name lookup based on the +/// given function name (which may also be an operator name) and adds +/// all of the overload candidates found by ADL to the overload +/// candidate set (C++ [basic.lookup.argdep]). +void +Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet) { + FunctionSet Functions; + + // Record all of the function candidates that we've already + // added to the overload set, so that we don't add those same + // candidates a second time. + for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), + CandEnd = CandidateSet.end(); + Cand != CandEnd; ++Cand) + if (Cand->Function) + Functions.insert(Cand->Function); + + ArgumentDependentLookup(Name, Args, NumArgs, Functions); + + // Erase all of the candidates we already knew about. + // FIXME: This is suboptimal. Is there a better way? + for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), + CandEnd = CandidateSet.end(); + Cand != CandEnd; ++Cand) + if (Cand->Function) + Functions.erase(Cand->Function); + + // For each of the ADL candidates we found, add it to the overload + // set. + for (FunctionSet::iterator Func = Functions.begin(), + FuncEnd = Functions.end(); + Func != FuncEnd; ++Func) + AddOverloadCandidate(*Func, Args, NumArgs, CandidateSet); +} + +/// isBetterOverloadCandidate - Determines whether the first overload +/// candidate is a better candidate than the second (C++ 13.3.3p1). +bool +Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1, + const OverloadCandidate& Cand2) +{ + // Define viable functions to be better candidates than non-viable + // functions. + if (!Cand2.Viable) + return Cand1.Viable; + else if (!Cand1.Viable) + return false; + + // C++ [over.match.best]p1: + // + // -- if F is a static member function, ICS1(F) is defined such + // that ICS1(F) is neither better nor worse than ICS1(G) for + // any function G, and, symmetrically, ICS1(G) is neither + // better nor worse than ICS1(F). + unsigned StartArg = 0; + if (Cand1.IgnoreObjectArgument || Cand2.IgnoreObjectArgument) + StartArg = 1; + + // (C++ 13.3.3p1): a viable function F1 is defined to be a better + // function than another viable function F2 if for all arguments i, + // ICSi(F1) is not a worse conversion sequence than ICSi(F2), and + // then... + unsigned NumArgs = Cand1.Conversions.size(); + assert(Cand2.Conversions.size() == NumArgs && "Overload candidate mismatch"); + bool HasBetterConversion = false; + for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) { + switch (CompareImplicitConversionSequences(Cand1.Conversions[ArgIdx], + Cand2.Conversions[ArgIdx])) { + case ImplicitConversionSequence::Better: + // Cand1 has a better conversion sequence. + HasBetterConversion = true; + break; + + case ImplicitConversionSequence::Worse: + // Cand1 can't be better than Cand2. + return false; + + case ImplicitConversionSequence::Indistinguishable: + // Do nothing. + break; + } + } + + if (HasBetterConversion) + return true; + + // FIXME: Several other bullets in (C++ 13.3.3p1) need to be + // implemented, but they require template support. + + // C++ [over.match.best]p1b4: + // + // -- the context is an initialization by user-defined conversion + // (see 8.5, 13.3.1.5) and the standard conversion sequence + // from the return type of F1 to the destination type (i.e., + // the type of the entity being initialized) is a better + // conversion sequence than the standard conversion sequence + // from the return type of F2 to the destination type. + if (Cand1.Function && Cand2.Function && + isa<CXXConversionDecl>(Cand1.Function) && + isa<CXXConversionDecl>(Cand2.Function)) { + switch (CompareStandardConversionSequences(Cand1.FinalConversion, + Cand2.FinalConversion)) { + case ImplicitConversionSequence::Better: + // Cand1 has a better conversion sequence. + return true; + + case ImplicitConversionSequence::Worse: + // Cand1 can't be better than Cand2. + return false; + + case ImplicitConversionSequence::Indistinguishable: + // Do nothing + break; + } + } + + return false; +} + +/// BestViableFunction - Computes the best viable function (C++ 13.3.3) +/// within an overload candidate set. If overloading is successful, +/// the result will be OR_Success and Best will be set to point to the +/// best viable function within the candidate set. Otherwise, one of +/// several kinds of errors will be returned; see +/// Sema::OverloadingResult. +Sema::OverloadingResult +Sema::BestViableFunction(OverloadCandidateSet& CandidateSet, + OverloadCandidateSet::iterator& Best) +{ + // Find the best viable function. + Best = CandidateSet.end(); + for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); + Cand != CandidateSet.end(); ++Cand) { + if (Cand->Viable) { + if (Best == CandidateSet.end() || isBetterOverloadCandidate(*Cand, *Best)) + Best = Cand; + } + } + + // If we didn't find any viable functions, abort. + if (Best == CandidateSet.end()) + return OR_No_Viable_Function; + + // Make sure that this function is better than every other viable + // function. If not, we have an ambiguity. + for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); + Cand != CandidateSet.end(); ++Cand) { + if (Cand->Viable && + Cand != Best && + !isBetterOverloadCandidate(*Best, *Cand)) { + Best = CandidateSet.end(); + return OR_Ambiguous; + } + } + + // Best is the best viable function. + if (Best->Function && + (Best->Function->isDeleted() || + Best->Function->getAttr<UnavailableAttr>())) + return OR_Deleted; + + // If Best refers to a function that is either deleted (C++0x) or + // unavailable (Clang extension) report an error. + + return OR_Success; +} + +/// PrintOverloadCandidates - When overload resolution fails, prints +/// diagnostic messages containing the candidates in the candidate +/// set. If OnlyViable is true, only viable candidates will be printed. +void +Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, + bool OnlyViable) +{ + OverloadCandidateSet::iterator Cand = CandidateSet.begin(), + LastCand = CandidateSet.end(); + for (; Cand != LastCand; ++Cand) { + if (Cand->Viable || !OnlyViable) { + if (Cand->Function) { + if (Cand->Function->isDeleted() || + Cand->Function->getAttr<UnavailableAttr>()) { + // Deleted or "unavailable" function. + Diag(Cand->Function->getLocation(), diag::err_ovl_candidate_deleted) + << Cand->Function->isDeleted(); + } else { + // Normal function + // FIXME: Give a better reason! + Diag(Cand->Function->getLocation(), diag::err_ovl_candidate); + } + } else if (Cand->IsSurrogate) { + // Desugar the type of the surrogate down to a function type, + // retaining as many typedefs as possible while still showing + // the function type (and, therefore, its parameter types). + QualType FnType = Cand->Surrogate->getConversionType(); + bool isLValueReference = false; + bool isRValueReference = false; + bool isPointer = false; + if (const LValueReferenceType *FnTypeRef = + FnType->getAsLValueReferenceType()) { + FnType = FnTypeRef->getPointeeType(); + isLValueReference = true; + } else if (const RValueReferenceType *FnTypeRef = + FnType->getAsRValueReferenceType()) { + FnType = FnTypeRef->getPointeeType(); + isRValueReference = true; + } + if (const PointerType *FnTypePtr = FnType->getAsPointerType()) { + FnType = FnTypePtr->getPointeeType(); + isPointer = true; + } + // Desugar down to a function type. + FnType = QualType(FnType->getAsFunctionType(), 0); + // Reconstruct the pointer/reference as appropriate. + if (isPointer) FnType = Context.getPointerType(FnType); + if (isRValueReference) FnType = Context.getRValueReferenceType(FnType); + if (isLValueReference) FnType = Context.getLValueReferenceType(FnType); + + Diag(Cand->Surrogate->getLocation(), diag::err_ovl_surrogate_cand) + << FnType; + } else { + // FIXME: We need to get the identifier in here + // FIXME: Do we want the error message to point at the operator? + // (built-ins won't have a location) + QualType FnType + = Context.getFunctionType(Cand->BuiltinTypes.ResultTy, + Cand->BuiltinTypes.ParamTypes, + Cand->Conversions.size(), + false, 0); + + Diag(SourceLocation(), diag::err_ovl_builtin_candidate) << FnType; + } + } + } +} + +/// ResolveAddressOfOverloadedFunction - Try to resolve the address of +/// an overloaded function (C++ [over.over]), where @p From is an +/// expression with overloaded function type and @p ToType is the type +/// we're trying to resolve to. For example: +/// +/// @code +/// int f(double); +/// int f(int); +/// +/// int (*pfd)(double) = f; // selects f(double) +/// @endcode +/// +/// This routine returns the resulting FunctionDecl if it could be +/// resolved, and NULL otherwise. When @p Complain is true, this +/// routine will emit diagnostics if there is an error. +FunctionDecl * +Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, + bool Complain) { + QualType FunctionType = ToType; + bool IsMember = false; + if (const PointerType *ToTypePtr = ToType->getAsPointerType()) + FunctionType = ToTypePtr->getPointeeType(); + else if (const ReferenceType *ToTypeRef = ToType->getAsReferenceType()) + FunctionType = ToTypeRef->getPointeeType(); + else if (const MemberPointerType *MemTypePtr = + ToType->getAsMemberPointerType()) { + FunctionType = MemTypePtr->getPointeeType(); + IsMember = true; + } + + // We only look at pointers or references to functions. + if (!FunctionType->isFunctionType()) + return 0; + + // Find the actual overloaded function declaration. + OverloadedFunctionDecl *Ovl = 0; + + // C++ [over.over]p1: + // [...] [Note: any redundant set of parentheses surrounding the + // overloaded function name is ignored (5.1). ] + Expr *OvlExpr = From->IgnoreParens(); + + // C++ [over.over]p1: + // [...] The overloaded function name can be preceded by the & + // operator. + if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(OvlExpr)) { + if (UnOp->getOpcode() == UnaryOperator::AddrOf) + OvlExpr = UnOp->getSubExpr()->IgnoreParens(); + } + + // Try to dig out the overloaded function. + if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(OvlExpr)) + Ovl = dyn_cast<OverloadedFunctionDecl>(DR->getDecl()); + + // If there's no overloaded function declaration, we're done. + if (!Ovl) + return 0; + + // Look through all of the overloaded functions, searching for one + // whose type matches exactly. + // FIXME: When templates or using declarations come along, we'll actually + // have to deal with duplicates, partial ordering, etc. For now, we + // can just do a simple search. + FunctionType = Context.getCanonicalType(FunctionType.getUnqualifiedType()); + for (OverloadedFunctionDecl::function_iterator Fun = Ovl->function_begin(); + Fun != Ovl->function_end(); ++Fun) { + // C++ [over.over]p3: + // Non-member functions and static member functions match + // targets of type "pointer-to-function" or "reference-to-function." + // Nonstatic member functions match targets of + // type "pointer-to-member-function." + // Note that according to DR 247, the containing class does not matter. + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Fun)) { + // Skip non-static functions when converting to pointer, and static + // when converting to member pointer. + if (Method->isStatic() == IsMember) + continue; + } else if (IsMember) + continue; + + if (FunctionType == Context.getCanonicalType((*Fun)->getType())) + return *Fun; + } + + return 0; +} + +/// ResolveOverloadedCallFn - Given the call expression that calls Fn +/// (which eventually refers to the declaration Func) and the call +/// arguments Args/NumArgs, attempt to resolve the function call down +/// to a specific function. If overload resolution succeeds, returns +/// the function declaration produced by overload +/// resolution. Otherwise, emits diagnostics, deletes all of the +/// arguments and Fn, and returns NULL. +FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee, + DeclarationName UnqualifiedName, + SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc, + bool &ArgumentDependentLookup) { + OverloadCandidateSet CandidateSet; + + // Add the functions denoted by Callee to the set of candidate + // functions. While we're doing so, track whether argument-dependent + // lookup still applies, per: + // + // C++0x [basic.lookup.argdep]p3: + // Let X be the lookup set produced by unqualified lookup (3.4.1) + // and let Y be the lookup set produced by argument dependent + // lookup (defined as follows). If X contains + // + // -- a declaration of a class member, or + // + // -- a block-scope function declaration that is not a + // using-declaration, or + // + // -- a declaration that is neither a function or a function + // template + // + // then Y is empty. + if (OverloadedFunctionDecl *Ovl + = dyn_cast_or_null<OverloadedFunctionDecl>(Callee)) { + for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(), + FuncEnd = Ovl->function_end(); + Func != FuncEnd; ++Func) { + AddOverloadCandidate(*Func, Args, NumArgs, CandidateSet); + + if ((*Func)->getDeclContext()->isRecord() || + (*Func)->getDeclContext()->isFunctionOrMethod()) + ArgumentDependentLookup = false; + } + } else if (FunctionDecl *Func = dyn_cast_or_null<FunctionDecl>(Callee)) { + AddOverloadCandidate(Func, Args, NumArgs, CandidateSet); + + if (Func->getDeclContext()->isRecord() || + Func->getDeclContext()->isFunctionOrMethod()) + ArgumentDependentLookup = false; + } + + if (Callee) + UnqualifiedName = Callee->getDeclName(); + + if (ArgumentDependentLookup) + AddArgumentDependentLookupCandidates(UnqualifiedName, Args, NumArgs, + CandidateSet); + + OverloadCandidateSet::iterator Best; + switch (BestViableFunction(CandidateSet, Best)) { + case OR_Success: + return Best->Function; + + case OR_No_Viable_Function: + Diag(Fn->getSourceRange().getBegin(), + diag::err_ovl_no_viable_function_in_call) + << UnqualifiedName << Fn->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + break; + + case OR_Ambiguous: + Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_ambiguous_call) + << UnqualifiedName << Fn->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + break; + + case OR_Deleted: + Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_deleted_call) + << Best->Function->isDeleted() + << UnqualifiedName + << Fn->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + break; + } + + // Overload resolution failed. Destroy all of the subexpressions and + // return NULL. + Fn->Destroy(Context); + for (unsigned Arg = 0; Arg < NumArgs; ++Arg) + Args[Arg]->Destroy(Context); + return 0; +} + +/// \brief Create a unary operation that may resolve to an overloaded +/// operator. +/// +/// \param OpLoc The location of the operator itself (e.g., '*'). +/// +/// \param OpcIn The UnaryOperator::Opcode that describes this +/// operator. +/// +/// \param Functions The set of non-member functions that will be +/// considered by overload resolution. The caller needs to build this +/// set based on the context using, e.g., +/// LookupOverloadedOperatorName() and ArgumentDependentLookup(). This +/// set should not contain any member functions; those will be added +/// by CreateOverloadedUnaryOp(). +/// +/// \param input The input argument. +Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, + unsigned OpcIn, + FunctionSet &Functions, + ExprArg input) { + UnaryOperator::Opcode Opc = static_cast<UnaryOperator::Opcode>(OpcIn); + Expr *Input = (Expr *)input.get(); + + OverloadedOperatorKind Op = UnaryOperator::getOverloadedOperator(Opc); + assert(Op != OO_None && "Invalid opcode for overloaded unary operator"); + DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); + + Expr *Args[2] = { Input, 0 }; + unsigned NumArgs = 1; + + // For post-increment and post-decrement, add the implicit '0' as + // the second argument, so that we know this is a post-increment or + // post-decrement. + if (Opc == UnaryOperator::PostInc || Opc == UnaryOperator::PostDec) { + llvm::APSInt Zero(Context.getTypeSize(Context.IntTy), false); + Args[1] = new (Context) IntegerLiteral(Zero, Context.IntTy, + SourceLocation()); + NumArgs = 2; + } + + if (Input->isTypeDependent()) { + OverloadedFunctionDecl *Overloads + = OverloadedFunctionDecl::Create(Context, CurContext, OpName); + for (FunctionSet::iterator Func = Functions.begin(), + FuncEnd = Functions.end(); + Func != FuncEnd; ++Func) + Overloads->addOverload(*Func); + + DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy, + OpLoc, false, false); + + input.release(); + return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, + &Args[0], NumArgs, + Context.DependentTy, + OpLoc)); + } + + // Build an empty overload set. + OverloadCandidateSet CandidateSet; + + // Add the candidates from the given function set. + AddFunctionCandidates(Functions, &Args[0], NumArgs, CandidateSet, false); + + // Add operator candidates that are member functions. + AddMemberOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet); + + // Add builtin operator candidates. + AddBuiltinOperatorCandidates(Op, &Args[0], NumArgs, CandidateSet); + + // Perform overload resolution. + OverloadCandidateSet::iterator Best; + switch (BestViableFunction(CandidateSet, Best)) { + case OR_Success: { + // We found a built-in operator or an overloaded operator. + FunctionDecl *FnDecl = Best->Function; + + if (FnDecl) { + // We matched an overloaded operator. Build a call to that + // operator. + + // Convert the arguments. + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { + if (PerformObjectArgumentInitialization(Input, Method)) + return ExprError(); + } else { + // Convert the arguments. + if (PerformCopyInitialization(Input, + FnDecl->getParamDecl(0)->getType(), + "passing")) + return ExprError(); + } + + // Determine the result type + QualType ResultTy + = FnDecl->getType()->getAsFunctionType()->getResultType(); + ResultTy = ResultTy.getNonReferenceType(); + + // Build the actual expression node. + Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(), + SourceLocation()); + UsualUnaryConversions(FnExpr); + + input.release(); + return Owned(new (Context) CXXOperatorCallExpr(Context, Op, FnExpr, + &Input, 1, ResultTy, + OpLoc)); + } else { + // We matched a built-in operator. Convert the arguments, then + // break out so that we will build the appropriate built-in + // operator node. + if (PerformImplicitConversion(Input, Best->BuiltinTypes.ParamTypes[0], + Best->Conversions[0], "passing")) + return ExprError(); + + break; + } + } + + case OR_No_Viable_Function: + // No viable function; fall through to handling this as a + // built-in operator, which will produce an error message for us. + break; + + case OR_Ambiguous: + Diag(OpLoc, diag::err_ovl_ambiguous_oper) + << UnaryOperator::getOpcodeStr(Opc) + << Input->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + return ExprError(); + + case OR_Deleted: + Diag(OpLoc, diag::err_ovl_deleted_oper) + << Best->Function->isDeleted() + << UnaryOperator::getOpcodeStr(Opc) + << Input->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + return ExprError(); + } + + // Either we found no viable overloaded operator or we matched a + // built-in operator. In either case, fall through to trying to + // build a built-in operation. + input.release(); + return CreateBuiltinUnaryOp(OpLoc, Opc, Owned(Input)); +} + +/// \brief Create a binary operation that may resolve to an overloaded +/// operator. +/// +/// \param OpLoc The location of the operator itself (e.g., '+'). +/// +/// \param OpcIn The BinaryOperator::Opcode that describes this +/// operator. +/// +/// \param Functions The set of non-member functions that will be +/// considered by overload resolution. The caller needs to build this +/// set based on the context using, e.g., +/// LookupOverloadedOperatorName() and ArgumentDependentLookup(). This +/// set should not contain any member functions; those will be added +/// by CreateOverloadedBinOp(). +/// +/// \param LHS Left-hand argument. +/// \param RHS Right-hand argument. +Sema::OwningExprResult +Sema::CreateOverloadedBinOp(SourceLocation OpLoc, + unsigned OpcIn, + FunctionSet &Functions, + Expr *LHS, Expr *RHS) { + Expr *Args[2] = { LHS, RHS }; + + BinaryOperator::Opcode Opc = static_cast<BinaryOperator::Opcode>(OpcIn); + OverloadedOperatorKind Op = BinaryOperator::getOverloadedOperator(Opc); + DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); + + // If either side is type-dependent, create an appropriate dependent + // expression. + if (LHS->isTypeDependent() || RHS->isTypeDependent()) { + // .* cannot be overloaded. + if (Opc == BinaryOperator::PtrMemD) + return Owned(new (Context) BinaryOperator(LHS, RHS, Opc, + Context.DependentTy, OpLoc)); + + OverloadedFunctionDecl *Overloads + = OverloadedFunctionDecl::Create(Context, CurContext, OpName); + for (FunctionSet::iterator Func = Functions.begin(), + FuncEnd = Functions.end(); + Func != FuncEnd; ++Func) + Overloads->addOverload(*Func); + + DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy, + OpLoc, false, false); + + return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, + Args, 2, + Context.DependentTy, + OpLoc)); + } + + // If this is the .* operator, which is not overloadable, just + // create a built-in binary operator. + if (Opc == BinaryOperator::PtrMemD) + return CreateBuiltinBinOp(OpLoc, Opc, LHS, RHS); + + // If this is one of the assignment operators, we only perform + // overload resolution if the left-hand side is a class or + // enumeration type (C++ [expr.ass]p3). + if (Opc >= BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign && + !LHS->getType()->isOverloadableType()) + return CreateBuiltinBinOp(OpLoc, Opc, LHS, RHS); + + // Build an empty overload set. + OverloadCandidateSet CandidateSet; + + // Add the candidates from the given function set. + AddFunctionCandidates(Functions, Args, 2, CandidateSet, false); + + // Add operator candidates that are member functions. + AddMemberOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet); + + // Add builtin operator candidates. + AddBuiltinOperatorCandidates(Op, Args, 2, CandidateSet); + + // Perform overload resolution. + OverloadCandidateSet::iterator Best; + switch (BestViableFunction(CandidateSet, Best)) { + case OR_Success: { + // We found a built-in operator or an overloaded operator. + FunctionDecl *FnDecl = Best->Function; + + if (FnDecl) { + // We matched an overloaded operator. Build a call to that + // operator. + + // Convert the arguments. + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { + if (PerformObjectArgumentInitialization(LHS, Method) || + PerformCopyInitialization(RHS, FnDecl->getParamDecl(0)->getType(), + "passing")) + return ExprError(); + } else { + // Convert the arguments. + if (PerformCopyInitialization(LHS, FnDecl->getParamDecl(0)->getType(), + "passing") || + PerformCopyInitialization(RHS, FnDecl->getParamDecl(1)->getType(), + "passing")) + return ExprError(); + } + + // Determine the result type + QualType ResultTy + = FnDecl->getType()->getAsFunctionType()->getResultType(); + ResultTy = ResultTy.getNonReferenceType(); + + // Build the actual expression node. + Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(), + SourceLocation()); + UsualUnaryConversions(FnExpr); + + return Owned(new (Context) CXXOperatorCallExpr(Context, Op, FnExpr, + Args, 2, ResultTy, + OpLoc)); + } else { + // We matched a built-in operator. Convert the arguments, then + // break out so that we will build the appropriate built-in + // operator node. + if (PerformImplicitConversion(LHS, Best->BuiltinTypes.ParamTypes[0], + Best->Conversions[0], "passing") || + PerformImplicitConversion(RHS, Best->BuiltinTypes.ParamTypes[1], + Best->Conversions[1], "passing")) + return ExprError(); + + break; + } + } + + case OR_No_Viable_Function: + // For class as left operand for assignment or compound assigment operator + // do not fall through to handling in built-in, but report that no overloaded + // assignment operator found + if (LHS->getType()->isRecordType() && Opc >= BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign) { + Diag(OpLoc, diag::err_ovl_no_viable_oper) + << BinaryOperator::getOpcodeStr(Opc) + << LHS->getSourceRange() << RHS->getSourceRange(); + return ExprError(); + } + // No viable function; fall through to handling this as a + // built-in operator, which will produce an error message for us. + break; + + case OR_Ambiguous: + Diag(OpLoc, diag::err_ovl_ambiguous_oper) + << BinaryOperator::getOpcodeStr(Opc) + << LHS->getSourceRange() << RHS->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + return ExprError(); + + case OR_Deleted: + Diag(OpLoc, diag::err_ovl_deleted_oper) + << Best->Function->isDeleted() + << BinaryOperator::getOpcodeStr(Opc) + << LHS->getSourceRange() << RHS->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + return ExprError(); + } + + // Either we found no viable overloaded operator or we matched a + // built-in operator. In either case, try to build a built-in + // operation. + return CreateBuiltinBinOp(OpLoc, Opc, LHS, RHS); +} + +/// BuildCallToMemberFunction - Build a call to a member +/// function. MemExpr is the expression that refers to the member +/// function (and includes the object parameter), Args/NumArgs are the +/// arguments to the function call (not including the object +/// parameter). The caller needs to validate that the member +/// expression refers to a member function or an overloaded member +/// function. +Sema::ExprResult +Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, + SourceLocation LParenLoc, Expr **Args, + unsigned NumArgs, SourceLocation *CommaLocs, + SourceLocation RParenLoc) { + // Dig out the member expression. This holds both the object + // argument and the member function we're referring to. + MemberExpr *MemExpr = 0; + if (ParenExpr *ParenE = dyn_cast<ParenExpr>(MemExprE)) + MemExpr = dyn_cast<MemberExpr>(ParenE->getSubExpr()); + else + MemExpr = dyn_cast<MemberExpr>(MemExprE); + assert(MemExpr && "Building member call without member expression"); + + // Extract the object argument. + Expr *ObjectArg = MemExpr->getBase(); + + CXXMethodDecl *Method = 0; + if (OverloadedFunctionDecl *Ovl + = dyn_cast<OverloadedFunctionDecl>(MemExpr->getMemberDecl())) { + // Add overload candidates + OverloadCandidateSet CandidateSet; + for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(), + FuncEnd = Ovl->function_end(); + Func != FuncEnd; ++Func) { + assert(isa<CXXMethodDecl>(*Func) && "Function is not a method"); + Method = cast<CXXMethodDecl>(*Func); + AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet, + /*SuppressUserConversions=*/false); + } + + OverloadCandidateSet::iterator Best; + switch (BestViableFunction(CandidateSet, Best)) { + case OR_Success: + Method = cast<CXXMethodDecl>(Best->Function); + break; + + case OR_No_Viable_Function: + Diag(MemExpr->getSourceRange().getBegin(), + diag::err_ovl_no_viable_member_function_in_call) + << Ovl->getDeclName() << MemExprE->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + // FIXME: Leaking incoming expressions! + return true; + + case OR_Ambiguous: + Diag(MemExpr->getSourceRange().getBegin(), + diag::err_ovl_ambiguous_member_call) + << Ovl->getDeclName() << MemExprE->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + // FIXME: Leaking incoming expressions! + return true; + + case OR_Deleted: + Diag(MemExpr->getSourceRange().getBegin(), + diag::err_ovl_deleted_member_call) + << Best->Function->isDeleted() + << Ovl->getDeclName() << MemExprE->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + // FIXME: Leaking incoming expressions! + return true; + } + + FixOverloadedFunctionReference(MemExpr, Method); + } else { + Method = dyn_cast<CXXMethodDecl>(MemExpr->getMemberDecl()); + } + + assert(Method && "Member call to something that isn't a method?"); + ExprOwningPtr<CXXMemberCallExpr> + TheCall(this, new (Context) CXXMemberCallExpr(Context, MemExpr, Args, + NumArgs, + Method->getResultType().getNonReferenceType(), + RParenLoc)); + + // Convert the object argument (for a non-static member function call). + if (!Method->isStatic() && + PerformObjectArgumentInitialization(ObjectArg, Method)) + return true; + MemExpr->setBase(ObjectArg); + + // Convert the rest of the arguments + const FunctionProtoType *Proto = cast<FunctionProtoType>(Method->getType()); + if (ConvertArgumentsForCall(&*TheCall, MemExpr, Method, Proto, Args, NumArgs, + RParenLoc)) + return true; + + return CheckFunctionCall(Method, TheCall.take()).release(); +} + +/// BuildCallToObjectOfClassType - Build a call to an object of class +/// type (C++ [over.call.object]), which can end up invoking an +/// overloaded function call operator (@c operator()) or performing a +/// user-defined conversion on the object argument. +Sema::ExprResult +Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, + SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc) { + assert(Object->getType()->isRecordType() && "Requires object type argument"); + const RecordType *Record = Object->getType()->getAsRecordType(); + + // C++ [over.call.object]p1: + // If the primary-expression E in the function call syntax + // evaluates to a class object of type “cv T”, then the set of + // candidate functions includes at least the function call + // operators of T. The function call operators of T are obtained by + // ordinary lookup of the name operator() in the context of + // (E).operator(). + OverloadCandidateSet CandidateSet; + DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call); + DeclContext::lookup_const_iterator Oper, OperEnd; + for (llvm::tie(Oper, OperEnd) = Record->getDecl()->lookup(Context, OpName); + Oper != OperEnd; ++Oper) + AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Object, Args, NumArgs, + CandidateSet, /*SuppressUserConversions=*/false); + + // C++ [over.call.object]p2: + // In addition, for each conversion function declared in T of the + // form + // + // operator conversion-type-id () cv-qualifier; + // + // where cv-qualifier is the same cv-qualification as, or a + // greater cv-qualification than, cv, and where conversion-type-id + // denotes the type "pointer to function of (P1,...,Pn) returning + // R", or the type "reference to pointer to function of + // (P1,...,Pn) returning R", or the type "reference to function + // of (P1,...,Pn) returning R", a surrogate call function [...] + // is also considered as a candidate function. Similarly, + // surrogate call functions are added to the set of candidate + // functions for each conversion function declared in an + // accessible base class provided the function is not hidden + // within T by another intervening declaration. + // + // FIXME: Look in base classes for more conversion operators! + OverloadedFunctionDecl *Conversions + = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions(); + for (OverloadedFunctionDecl::function_iterator + Func = Conversions->function_begin(), + FuncEnd = Conversions->function_end(); + Func != FuncEnd; ++Func) { + CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func); + + // Strip the reference type (if any) and then the pointer type (if + // any) to get down to what might be a function type. + QualType ConvType = Conv->getConversionType().getNonReferenceType(); + if (const PointerType *ConvPtrType = ConvType->getAsPointerType()) + ConvType = ConvPtrType->getPointeeType(); + + if (const FunctionProtoType *Proto = ConvType->getAsFunctionProtoType()) + AddSurrogateCandidate(Conv, Proto, Object, Args, NumArgs, CandidateSet); + } + + // Perform overload resolution. + OverloadCandidateSet::iterator Best; + switch (BestViableFunction(CandidateSet, Best)) { + case OR_Success: + // Overload resolution succeeded; we'll build the appropriate call + // below. + break; + + case OR_No_Viable_Function: + Diag(Object->getSourceRange().getBegin(), + diag::err_ovl_no_viable_object_call) + << Object->getType() << Object->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + break; + + case OR_Ambiguous: + Diag(Object->getSourceRange().getBegin(), + diag::err_ovl_ambiguous_object_call) + << Object->getType() << Object->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + break; + + case OR_Deleted: + Diag(Object->getSourceRange().getBegin(), + diag::err_ovl_deleted_object_call) + << Best->Function->isDeleted() + << Object->getType() << Object->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + break; + } + + if (Best == CandidateSet.end()) { + // We had an error; delete all of the subexpressions and return + // the error. + Object->Destroy(Context); + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) + Args[ArgIdx]->Destroy(Context); + return true; + } + + if (Best->Function == 0) { + // Since there is no function declaration, this is one of the + // surrogate candidates. Dig out the conversion function. + CXXConversionDecl *Conv + = cast<CXXConversionDecl>( + Best->Conversions[0].UserDefined.ConversionFunction); + + // We selected one of the surrogate functions that converts the + // object parameter to a function pointer. Perform the conversion + // on the object argument, then let ActOnCallExpr finish the job. + // FIXME: Represent the user-defined conversion in the AST! + ImpCastExprToType(Object, + Conv->getConversionType().getNonReferenceType(), + Conv->getConversionType()->isLValueReferenceType()); + return ActOnCallExpr(S, ExprArg(*this, Object), LParenLoc, + MultiExprArg(*this, (ExprTy**)Args, NumArgs), + CommaLocs, RParenLoc).release(); + } + + // We found an overloaded operator(). Build a CXXOperatorCallExpr + // that calls this method, using Object for the implicit object + // parameter and passing along the remaining arguments. + CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function); + const FunctionProtoType *Proto = Method->getType()->getAsFunctionProtoType(); + + unsigned NumArgsInProto = Proto->getNumArgs(); + unsigned NumArgsToCheck = NumArgs; + + // Build the full argument list for the method call (the + // implicit object parameter is placed at the beginning of the + // list). + Expr **MethodArgs; + if (NumArgs < NumArgsInProto) { + NumArgsToCheck = NumArgsInProto; + MethodArgs = new Expr*[NumArgsInProto + 1]; + } else { + MethodArgs = new Expr*[NumArgs + 1]; + } + MethodArgs[0] = Object; + for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) + MethodArgs[ArgIdx + 1] = Args[ArgIdx]; + + Expr *NewFn = new (Context) DeclRefExpr(Method, Method->getType(), + SourceLocation()); + UsualUnaryConversions(NewFn); + + // Once we've built TheCall, all of the expressions are properly + // owned. + QualType ResultTy = Method->getResultType().getNonReferenceType(); + ExprOwningPtr<CXXOperatorCallExpr> + TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Call, NewFn, + MethodArgs, NumArgs + 1, + ResultTy, RParenLoc)); + delete [] MethodArgs; + + // We may have default arguments. If so, we need to allocate more + // slots in the call for them. + if (NumArgs < NumArgsInProto) + TheCall->setNumArgs(Context, NumArgsInProto + 1); + else if (NumArgs > NumArgsInProto) + NumArgsToCheck = NumArgsInProto; + + bool IsError = false; + + // Initialize the implicit object parameter. + IsError |= PerformObjectArgumentInitialization(Object, Method); + TheCall->setArg(0, Object); + + + // Check the argument types. + for (unsigned i = 0; i != NumArgsToCheck; i++) { + Expr *Arg; + if (i < NumArgs) { + Arg = Args[i]; + + // Pass the argument. + QualType ProtoArgType = Proto->getArgType(i); + IsError |= PerformCopyInitialization(Arg, ProtoArgType, "passing"); + } else { + Arg = new (Context) CXXDefaultArgExpr(Method->getParamDecl(i)); + } + + TheCall->setArg(i + 1, Arg); + } + + // If this is a variadic call, handle args passed through "...". + if (Proto->isVariadic()) { + // Promote the arguments (C99 6.5.2.2p7). + for (unsigned i = NumArgsInProto; i != NumArgs; i++) { + Expr *Arg = Args[i]; + IsError |= DefaultVariadicArgumentPromotion(Arg, VariadicMethod); + TheCall->setArg(i + 1, Arg); + } + } + + if (IsError) return true; + + return CheckFunctionCall(Method, TheCall.take()).release(); +} + +/// BuildOverloadedArrowExpr - Build a call to an overloaded @c operator-> +/// (if one exists), where @c Base is an expression of class type and +/// @c Member is the name of the member we're trying to find. +Action::ExprResult +Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, + SourceLocation MemberLoc, + IdentifierInfo &Member) { + assert(Base->getType()->isRecordType() && "left-hand side must have class type"); + + // C++ [over.ref]p1: + // + // [...] An expression x->m is interpreted as (x.operator->())->m + // for a class object x of type T if T::operator->() exists and if + // the operator is selected as the best match function by the + // overload resolution mechanism (13.3). + // FIXME: look in base classes. + DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Arrow); + OverloadCandidateSet CandidateSet; + const RecordType *BaseRecord = Base->getType()->getAsRecordType(); + + DeclContext::lookup_const_iterator Oper, OperEnd; + for (llvm::tie(Oper, OperEnd) + = BaseRecord->getDecl()->lookup(Context, OpName); + Oper != OperEnd; ++Oper) + AddMethodCandidate(cast<CXXMethodDecl>(*Oper), Base, 0, 0, CandidateSet, + /*SuppressUserConversions=*/false); + + ExprOwningPtr<Expr> BasePtr(this, Base); + + // Perform overload resolution. + OverloadCandidateSet::iterator Best; + switch (BestViableFunction(CandidateSet, Best)) { + case OR_Success: + // Overload resolution succeeded; we'll build the call below. + break; + + case OR_No_Viable_Function: + if (CandidateSet.empty()) + Diag(OpLoc, diag::err_typecheck_member_reference_arrow) + << BasePtr->getType() << BasePtr->getSourceRange(); + else + Diag(OpLoc, diag::err_ovl_no_viable_oper) + << "operator->" << BasePtr->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + return true; + + case OR_Ambiguous: + Diag(OpLoc, diag::err_ovl_ambiguous_oper) + << "operator->" << BasePtr->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + return true; + + case OR_Deleted: + Diag(OpLoc, diag::err_ovl_deleted_oper) + << Best->Function->isDeleted() + << "operator->" << BasePtr->getSourceRange(); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + return true; + } + + // Convert the object parameter. + CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function); + if (PerformObjectArgumentInitialization(Base, Method)) + return true; + + // No concerns about early exits now. + BasePtr.take(); + + // Build the operator call. + Expr *FnExpr = new (Context) DeclRefExpr(Method, Method->getType(), + SourceLocation()); + UsualUnaryConversions(FnExpr); + Base = new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr, &Base, 1, + Method->getResultType().getNonReferenceType(), + OpLoc); + return ActOnMemberReferenceExpr(S, ExprArg(*this, Base), OpLoc, tok::arrow, + MemberLoc, Member, DeclPtrTy()).release(); +} + +/// FixOverloadedFunctionReference - E is an expression that refers to +/// a C++ overloaded function (possibly with some parentheses and +/// perhaps a '&' around it). We have resolved the overloaded function +/// to the function declaration Fn, so patch up the expression E to +/// refer (possibly indirectly) to Fn. +void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { + if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) { + FixOverloadedFunctionReference(PE->getSubExpr(), Fn); + E->setType(PE->getSubExpr()->getType()); + } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(E)) { + assert(UnOp->getOpcode() == UnaryOperator::AddrOf && + "Can only take the address of an overloaded function"); + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) { + if (Method->isStatic()) { + // Do nothing: static member functions aren't any different + // from non-member functions. + } + else if (QualifiedDeclRefExpr *DRE + = dyn_cast<QualifiedDeclRefExpr>(UnOp->getSubExpr())) { + // We have taken the address of a pointer to member + // function. Perform the computation here so that we get the + // appropriate pointer to member type. + DRE->setDecl(Fn); + DRE->setType(Fn->getType()); + QualType ClassType + = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext())); + E->setType(Context.getMemberPointerType(Fn->getType(), + ClassType.getTypePtr())); + return; + } + } + FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn); + E->setType(Context.getPointerType(UnOp->getSubExpr()->getType())); + } else if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) { + assert(isa<OverloadedFunctionDecl>(DR->getDecl()) && + "Expected overloaded function"); + DR->setDecl(Fn); + E->setType(Fn->getType()); + } else if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(E)) { + MemExpr->setMemberDecl(Fn); + E->setType(Fn->getType()); + } else { + assert(false && "Invalid reference to overloaded function"); + } +} + +} // end namespace clang diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h new file mode 100644 index 0000000..9de3806 --- /dev/null +++ b/lib/Sema/SemaOverload.h @@ -0,0 +1,263 @@ +//===--- Overload.h - C++ Overloading ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the data structures and types used in C++ +// overload resolution. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_OVERLOAD_H +#define LLVM_CLANG_SEMA_OVERLOAD_H + +#include "llvm/ADT/SmallVector.h" + +namespace clang { + class CXXConstructorDecl; + class FunctionDecl; + + /// ImplicitConversionKind - The kind of implicit conversion used to + /// convert an argument to a parameter's type. The enumerator values + /// match with Table 9 of (C++ 13.3.3.1.1) and are listed such that + /// better conversion kinds have smaller values. + enum ImplicitConversionKind { + ICK_Identity = 0, ///< Identity conversion (no conversion) + ICK_Lvalue_To_Rvalue, ///< Lvalue-to-rvalue conversion (C++ 4.1) + ICK_Array_To_Pointer, ///< Array-to-pointer conversion (C++ 4.2) + ICK_Function_To_Pointer, ///< Function-to-pointer (C++ 4.3) + ICK_Qualification, ///< Qualification conversions (C++ 4.4) + ICK_Integral_Promotion, ///< Integral promotions (C++ 4.5) + ICK_Floating_Promotion, ///< Floating point promotions (C++ 4.6) + ICK_Complex_Promotion, ///< Complex promotions (Clang extension) + ICK_Integral_Conversion, ///< Integral conversions (C++ 4.7) + 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_Num_Conversion_Kinds ///< The number of conversion kinds + }; + + /// ImplicitConversionCategory - The category of an implicit + /// conversion kind. The enumerator values match with Table 9 of + /// (C++ 13.3.3.1.1) and are listed such that better conversion + /// categories have smaller values. + enum ImplicitConversionCategory { + ICC_Identity = 0, ///< Identity + ICC_Lvalue_Transformation, ///< Lvalue transformation + ICC_Qualification_Adjustment, ///< Qualification adjustment + ICC_Promotion, ///< Promotion + ICC_Conversion ///< Conversion + }; + + ImplicitConversionCategory + GetConversionCategory(ImplicitConversionKind Kind); + + /// ImplicitConversionRank - The rank of an implicit conversion + /// kind. The enumerator values match with Table 9 of (C++ + /// 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 + }; + + ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind); + + /// StandardConversionSequence - represents a standard conversion + /// sequence (C++ 13.3.3.1.1). A standard conversion sequence + /// contains between zero and three conversions. If a particular + /// conversion is not needed, it will be set to the identity conversion + /// (ICK_Identity). Note that the three conversions are + /// specified as separate members (rather than in an array) so that + /// we can keep the size of a standard conversion sequence to a + /// single word. + struct StandardConversionSequence { + /// First -- The first conversion can be an lvalue-to-rvalue + /// conversion, array-to-pointer conversion, or + /// function-to-pointer conversion. + ImplicitConversionKind First : 8; + + /// Second - The second conversion can be an integral promotion, + /// floating point promotion, integral conversion, floating point + /// conversion, floating-integral conversion, pointer conversion, + /// pointer-to-member conversion, or boolean conversion. + ImplicitConversionKind Second : 8; + + /// Third - The third conversion can be a qualification conversion. + ImplicitConversionKind Third : 8; + + /// Deprecated - Whether this the deprecated conversion of a + /// string literal to a pointer to non-const character data + /// (C++ 4.2p2). + bool Deprecated : 1; + + /// IncompatibleObjC - Whether this is an Objective-C conversion + /// that we should warn about (if we actually use it). + bool IncompatibleObjC : 1; + + /// ReferenceBinding - True when this is a reference binding + /// (C++ [over.ics.ref]). + bool ReferenceBinding : 1; + + /// DirectBinding - True when this is a reference binding that is a + /// direct binding (C++ [dcl.init.ref]). + bool DirectBinding : 1; + + /// RRefBinding - True when this is a reference binding of an rvalue + /// reference to an rvalue (C++0x [over.ics.rank]p3b4). + bool RRefBinding : 1; + + /// FromType - The type that this conversion is converting + /// from. This is an opaque pointer that can be translated into a + /// QualType. + void *FromTypePtr; + + /// ToType - The type that this conversion is converting to. This + /// is an opaque pointer that can be translated into a QualType. + void *ToTypePtr; + + /// CopyConstructor - The copy constructor that is used to perform + /// this conversion, when the conversion is actually just the + /// initialization of an object via copy constructor. Such + /// conversions are either identity conversions or derived-to-base + /// conversions. + CXXConstructorDecl *CopyConstructor; + + void setAsIdentityConversion(); + ImplicitConversionRank getRank() const; + bool isPointerConversionToBool() const; + bool isPointerConversionToVoidPointer(ASTContext& Context) const; + void DebugPrint() const; + }; + + /// UserDefinedConversionSequence - Represents a user-defined + /// conversion sequence (C++ 13.3.3.1.2). + struct UserDefinedConversionSequence { + /// Before - Represents the standard conversion that occurs before + /// the actual user-defined conversion. (C++ 13.3.3.1.2p1): + /// + /// If the user-defined conversion is specified by a constructor + /// (12.3.1), the initial standard conversion sequence converts + /// the source type to the type required by the argument of the + /// constructor. If the user-defined conversion is specified by + /// a conversion function (12.3.2), the initial standard + /// conversion sequence converts the source type to the implicit + /// object parameter of the conversion function. + StandardConversionSequence Before; + + /// After - Represents the standard conversion that occurs after + /// the actual user-defined conversion. + StandardConversionSequence After; + + /// ConversionFunction - The function that will perform the + /// user-defined conversion. + FunctionDecl* ConversionFunction; + + void DebugPrint() const; + }; + + /// ImplicitConversionSequence - Represents an implicit conversion + /// sequence, which may be a standard conversion sequence + /// (C++ 13.3.3.1.1), user-defined conversion sequence (C++ 13.3.3.1.2), + /// or an ellipsis conversion sequence (C++ 13.3.3.1.3). + struct ImplicitConversionSequence { + /// Kind - The kind of implicit conversion sequence. BadConversion + /// specifies that there is no conversion from the source type to + /// the target type. The enumerator values are ordered such that + /// better implicit conversions have smaller values. + enum Kind { + StandardConversion = 0, + UserDefinedConversion, + EllipsisConversion, + BadConversion + }; + + /// ConversionKind - The kind of implicit conversion sequence. + Kind ConversionKind; + + union { + /// When ConversionKind == StandardConversion, provides the + /// details of the standard conversion sequence. + StandardConversionSequence Standard; + + /// When ConversionKind == UserDefinedConversion, provides the + /// details of the user-defined conversion sequence. + UserDefinedConversionSequence UserDefined; + }; + + // The result of a comparison between implicit conversion + // sequences. Use Sema::CompareImplicitConversionSequences to + // actually perform the comparison. + enum CompareKind { + Better = -1, + Indistinguishable = 0, + Worse = 1 + }; + + void DebugPrint() const; + }; + + /// OverloadCandidate - A single candidate in an overload set (C++ 13.3). + struct OverloadCandidate { + /// Function - The actual function that this candidate + /// represents. When NULL, this is a built-in candidate + /// (C++ [over.oper]) or a surrogate for a conversion to a + /// function pointer or reference (C++ [over.call.object]). + FunctionDecl *Function; + + // BuiltinTypes - Provides the return and parameter types of a + // built-in overload candidate. Only valid when Function is NULL. + struct { + QualType ResultTy; + QualType ParamTypes[3]; + } BuiltinTypes; + + /// Surrogate - The conversion function for which this candidate + /// is a surrogate, but only if IsSurrogate is true. + CXXConversionDecl *Surrogate; + + /// Conversions - The conversion sequences used to convert the + /// function arguments to the function parameters. + llvm::SmallVector<ImplicitConversionSequence, 4> Conversions; + + /// Viable - True to indicate that this overload candidate is viable. + bool Viable; + + /// IsSurrogate - True to indicate that this candidate is a + /// surrogate for a conversion to a function pointer or reference + /// (C++ [over.call.object]). + bool IsSurrogate; + + /// IgnoreObjectArgument - True to indicate that the first + /// argument's conversion, which for this function represents the + /// implicit object argument, should be ignored. This will be true + /// when the candidate is a static member function (where the + /// implicit object argument is just a placeholder) or a + /// non-static member function when the call doesn't have an + /// object argument. + bool IgnoreObjectArgument; + + /// FinalConversion - For a conversion function (where Function is + /// a CXXConversionDecl), the standard conversion that occurs + /// after the call to the overload candidate to convert the result + /// of calling the conversion function to the required type. + StandardConversionSequence FinalConversion; + }; + + /// OverloadCandidateSet - A set of overload candidates, used in C++ + /// overload resolution (C++ 13.3). + typedef llvm::SmallVector<OverloadCandidate, 16> OverloadCandidateSet; +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_OVERLOAD_H diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp new file mode 100644 index 0000000..15262e9 --- /dev/null +++ b/lib/Sema/SemaStmt.cpp @@ -0,0 +1,1266 @@ +//===--- SemaStmt.cpp - Semantic Analysis for Statements ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for statements. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/AST/APValue.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Expr.h" +#include "clang/AST/StmtObjC.h" +#include "clang/AST/StmtCXX.h" +#include "clang/Basic/TargetInfo.h" +using namespace clang; + +Sema::OwningStmtResult Sema::ActOnExprStmt(FullExprArg expr) { + Expr *E = expr->takeAs<Expr>(); + assert(E && "ActOnExprStmt(): missing expression"); + + // C99 6.8.3p2: The expression in an expression statement is evaluated as a + // void expression for its side effects. Conversion to void allows any + // operand, even incomplete types. + + // Same thing in for stmt first clause (when expr) and third clause. + return Owned(static_cast<Stmt*>(E)); +} + + +Sema::OwningStmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc) { + return Owned(new (Context) NullStmt(SemiLoc)); +} + +Sema::OwningStmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, + SourceLocation StartLoc, + SourceLocation EndLoc) { + DeclGroupRef DG = dg.getAsVal<DeclGroupRef>(); + + // If we have an invalid decl, just return an error. + if (DG.isNull()) return StmtError(); + + return Owned(new (Context) DeclStmt(DG, StartLoc, EndLoc)); +} + +Action::OwningStmtResult +Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, + MultiStmtArg elts, bool isStmtExpr) { + unsigned NumElts = elts.size(); + Stmt **Elts = reinterpret_cast<Stmt**>(elts.release()); + // If we're in C89 mode, check that we don't have any decls after stmts. If + // so, emit an extension diagnostic. + if (!getLangOptions().C99 && !getLangOptions().CPlusPlus) { + // Note that __extension__ can be around a decl. + unsigned i = 0; + // Skip over all declarations. + for (; i != NumElts && isa<DeclStmt>(Elts[i]); ++i) + /*empty*/; + + // We found the end of the list or a statement. Scan for another declstmt. + for (; i != NumElts && !isa<DeclStmt>(Elts[i]); ++i) + /*empty*/; + + if (i != NumElts) { + Decl *D = *cast<DeclStmt>(Elts[i])->decl_begin(); + Diag(D->getLocation(), diag::ext_mixed_decls_code); + } + } + // Warn about unused expressions in statements. + for (unsigned i = 0; i != NumElts; ++i) { + Expr *E = dyn_cast<Expr>(Elts[i]); + if (!E) continue; + + // Warn about expressions with unused results if they are non-void and if + // this not the last stmt in a stmt expr. + if (E->getType()->isVoidType() || (isStmtExpr && i == NumElts-1)) + continue; + + SourceLocation Loc; + SourceRange R1, R2; + if (!E->isUnusedResultAWarning(Loc, R1, R2)) + continue; + + Diag(Loc, diag::warn_unused_expr) << R1 << R2; + } + + return Owned(new (Context) CompoundStmt(Context, Elts, NumElts, L, R)); +} + +Action::OwningStmtResult +Sema::ActOnCaseStmt(SourceLocation CaseLoc, ExprArg lhsval, + SourceLocation DotDotDotLoc, ExprArg rhsval, + SourceLocation ColonLoc) { + assert((lhsval.get() != 0) && "missing expression in case statement"); + + // C99 6.8.4.2p3: The expression shall be an integer constant. + // However, GCC allows any evaluatable integer expression. + Expr *LHSVal = static_cast<Expr*>(lhsval.get()); + if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent() && + VerifyIntegerConstantExpression(LHSVal)) + return StmtError(); + + // GCC extension: The expression shall be an integer constant. + + Expr *RHSVal = static_cast<Expr*>(rhsval.get()); + if (RHSVal && !RHSVal->isTypeDependent() && !RHSVal->isValueDependent() && + VerifyIntegerConstantExpression(RHSVal)) { + RHSVal = 0; // Recover by just forgetting about it. + rhsval = 0; + } + + if (getSwitchStack().empty()) { + Diag(CaseLoc, diag::err_case_not_in_switch); + return StmtError(); + } + + // Only now release the smart pointers. + lhsval.release(); + rhsval.release(); + CaseStmt *CS = new (Context) CaseStmt(LHSVal, RHSVal, CaseLoc, DotDotDotLoc, + ColonLoc); + getSwitchStack().back()->addSwitchCase(CS); + return Owned(CS); +} + +/// ActOnCaseStmtBody - This installs a statement as the body of a case. +void Sema::ActOnCaseStmtBody(StmtTy *caseStmt, StmtArg subStmt) { + CaseStmt *CS = static_cast<CaseStmt*>(caseStmt); + Stmt *SubStmt = subStmt.takeAs<Stmt>(); + CS->setSubStmt(SubStmt); +} + +Action::OwningStmtResult +Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, + StmtArg subStmt, Scope *CurScope) { + Stmt *SubStmt = subStmt.takeAs<Stmt>(); + + if (getSwitchStack().empty()) { + Diag(DefaultLoc, diag::err_default_not_in_switch); + return Owned(SubStmt); + } + + DefaultStmt *DS = new (Context) DefaultStmt(DefaultLoc, ColonLoc, SubStmt); + getSwitchStack().back()->addSwitchCase(DS); + return Owned(DS); +} + +Action::OwningStmtResult +Sema::ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II, + SourceLocation ColonLoc, StmtArg subStmt) { + Stmt *SubStmt = subStmt.takeAs<Stmt>(); + // Look up the record for this label identifier. + LabelStmt *&LabelDecl = getLabelMap()[II]; + + // If not forward referenced or defined already, just create a new LabelStmt. + if (LabelDecl == 0) + return Owned(LabelDecl = new (Context) LabelStmt(IdentLoc, II, SubStmt)); + + assert(LabelDecl->getID() == II && "Label mismatch!"); + + // Otherwise, this label was either forward reference or multiply defined. If + // multiply defined, reject it now. + if (LabelDecl->getSubStmt()) { + Diag(IdentLoc, diag::err_redefinition_of_label) << LabelDecl->getID(); + Diag(LabelDecl->getIdentLoc(), diag::note_previous_definition); + return Owned(SubStmt); + } + + // Otherwise, this label was forward declared, and we just found its real + // definition. Fill in the forward definition and return it. + LabelDecl->setIdentLoc(IdentLoc); + LabelDecl->setSubStmt(SubStmt); + return Owned(LabelDecl); +} + +Action::OwningStmtResult +Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, + StmtArg ThenVal, SourceLocation ElseLoc, + StmtArg ElseVal) { + OwningExprResult CondResult(CondVal.release()); + + Expr *condExpr = CondResult.takeAs<Expr>(); + + assert(condExpr && "ActOnIfStmt(): missing expression"); + + if (!condExpr->isTypeDependent()) { + DefaultFunctionArrayConversion(condExpr); + // Take ownership again until we're past the error checking. + CondResult = condExpr; + QualType condType = condExpr->getType(); + + if (getLangOptions().CPlusPlus) { + if (CheckCXXBooleanCondition(condExpr)) // C++ 6.4p4 + return StmtError(); + } else if (!condType->isScalarType()) // C99 6.8.4.1p1 + return StmtError(Diag(IfLoc, + diag::err_typecheck_statement_requires_scalar) + << condType << condExpr->getSourceRange()); + } + + Stmt *thenStmt = ThenVal.takeAs<Stmt>(); + + // Warn if the if block has a null body without an else value. + // this helps prevent bugs due to typos, such as + // if (condition); + // do_stuff(); + if (!ElseVal.get()) { + if (NullStmt* stmt = dyn_cast<NullStmt>(thenStmt)) + Diag(stmt->getSemiLoc(), diag::warn_empty_if_body); + } + + CondResult.release(); + return Owned(new (Context) IfStmt(IfLoc, condExpr, thenStmt, + ElseLoc, ElseVal.takeAs<Stmt>())); +} + +Action::OwningStmtResult +Sema::ActOnStartOfSwitchStmt(ExprArg cond) { + Expr *Cond = cond.takeAs<Expr>(); + + if (getLangOptions().CPlusPlus) { + // C++ 6.4.2.p2: + // The condition shall be of integral type, enumeration type, or of a class + // type for which a single conversion function to integral or enumeration + // type exists (12.3). If the condition is of class type, the condition is + // converted by calling that conversion function, and the result of the + // conversion is used in place of the original condition for the remainder + // of this section. Integral promotions are performed. + if (!Cond->isTypeDependent()) { + QualType Ty = Cond->getType(); + + // FIXME: Handle class types. + + // If the type is wrong a diagnostic will be emitted later at + // ActOnFinishSwitchStmt. + if (Ty->isIntegralType() || Ty->isEnumeralType()) { + // Integral promotions are performed. + // FIXME: Integral promotions for C++ are not complete. + UsualUnaryConversions(Cond); + } + } + } else { + // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr. + UsualUnaryConversions(Cond); + } + + SwitchStmt *SS = new (Context) SwitchStmt(Cond); + getSwitchStack().push_back(SS); + return Owned(SS); +} + +/// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have +/// the specified width and sign. If an overflow occurs, detect it and emit +/// the specified diagnostic. +void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val, + unsigned NewWidth, bool NewSign, + SourceLocation Loc, + unsigned DiagID) { + // 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); + } else if (NewWidth < Val.getBitWidth()) { + // If this is a truncation, check for overflow. + llvm::APSInt ConvVal(Val); + ConvVal.trunc(NewWidth); + ConvVal.setIsSigned(NewSign); + ConvVal.extend(Val.getBitWidth()); + ConvVal.setIsSigned(Val.isSigned()); + if (ConvVal != Val) + Diag(Loc, DiagID) << Val.toString(10) << ConvVal.toString(10); + + // Regardless of whether a diagnostic was emitted, really do the + // truncation. + Val.trunc(NewWidth); + Val.setIsSigned(NewSign); + } else if (NewSign != Val.isSigned()) { + // Convert the sign to match the sign of the condition. This can cause + // overflow as well: unsigned(INTMIN) + llvm::APSInt OldVal(Val); + Val.setIsSigned(NewSign); + + if (Val.isNegative()) // Sign bit changes meaning. + Diag(Loc, DiagID) << OldVal.toString(10) << Val.toString(10); + } +} + +namespace { + struct CaseCompareFunctor { + bool operator()(const std::pair<llvm::APSInt, CaseStmt*> &LHS, + const llvm::APSInt &RHS) { + return LHS.first < RHS; + } + bool operator()(const std::pair<llvm::APSInt, CaseStmt*> &LHS, + const std::pair<llvm::APSInt, CaseStmt*> &RHS) { + return LHS.first < RHS.first; + } + bool operator()(const llvm::APSInt &LHS, + const std::pair<llvm::APSInt, CaseStmt*> &RHS) { + return LHS < RHS.first; + } + }; +} + +/// CmpCaseVals - Comparison predicate for sorting case values. +/// +static bool CmpCaseVals(const std::pair<llvm::APSInt, CaseStmt*>& lhs, + const std::pair<llvm::APSInt, CaseStmt*>& rhs) { + if (lhs.first < rhs.first) + return true; + + if (lhs.first == rhs.first && + lhs.second->getCaseLoc().getRawEncoding() + < rhs.second->getCaseLoc().getRawEncoding()) + return true; + return false; +} + +Action::OwningStmtResult +Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, + StmtArg Body) { + Stmt *BodyStmt = Body.takeAs<Stmt>(); + + SwitchStmt *SS = getSwitchStack().back(); + assert(SS == (SwitchStmt*)Switch.get() && "switch stack missing push/pop!"); + + SS->setBody(BodyStmt, SwitchLoc); + getSwitchStack().pop_back(); + + Expr *CondExpr = SS->getCond(); + QualType CondType = CondExpr->getType(); + + if (!CondExpr->isTypeDependent() && + !CondType->isIntegerType()) { // C99 6.8.4.2p1 + Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer) + << CondType << CondExpr->getSourceRange(); + return StmtError(); + } + + // Get the bitwidth of the switched-on value before promotions. We must + // convert the integer case values to this width before comparison. + bool HasDependentValue + = CondExpr->isTypeDependent() || CondExpr->isValueDependent(); + unsigned CondWidth + = HasDependentValue? 0 + : static_cast<unsigned>(Context.getTypeSize(CondType)); + bool CondIsSigned = CondType->isSignedIntegerType(); + + // Accumulate all of the case values in a vector so that we can sort them + // and detect duplicates. This vector contains the APInt for the case after + // it has been converted to the condition type. + typedef llvm::SmallVector<std::pair<llvm::APSInt, CaseStmt*>, 64> CaseValsTy; + CaseValsTy CaseVals; + + // Keep track of any GNU case ranges we see. The APSInt is the low value. + std::vector<std::pair<llvm::APSInt, CaseStmt*> > CaseRanges; + + DefaultStmt *TheDefaultStmt = 0; + + bool CaseListIsErroneous = false; + + for (SwitchCase *SC = SS->getSwitchCaseList(); SC && !HasDependentValue; + SC = SC->getNextSwitchCase()) { + + if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SC)) { + if (TheDefaultStmt) { + Diag(DS->getDefaultLoc(), diag::err_multiple_default_labels_defined); + Diag(TheDefaultStmt->getDefaultLoc(), diag::note_duplicate_case_prev); + + // FIXME: Remove the default statement from the switch block so that + // we'll return a valid AST. This requires recursing down the AST and + // finding it, not something we are set up to do right now. For now, + // just lop the entire switch stmt out of the AST. + CaseListIsErroneous = true; + } + TheDefaultStmt = DS; + + } else { + CaseStmt *CS = cast<CaseStmt>(SC); + + // We already verified that the expression has a i-c-e value (C99 + // 6.8.4.2p3) - get that value now. + Expr *Lo = CS->getLHS(); + + if (Lo->isTypeDependent() || Lo->isValueDependent()) { + HasDependentValue = true; + break; + } + + llvm::APSInt LoVal = Lo->EvaluateAsInt(Context); + + // Convert the value to the same width/sign as the condition. + ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned, + CS->getLHS()->getLocStart(), + diag::warn_case_value_overflow); + + // If the LHS is not the same type as the condition, insert an implicit + // cast. + ImpCastExprToType(Lo, CondType); + CS->setLHS(Lo); + + // If this is a case range, remember it in CaseRanges, otherwise CaseVals. + if (CS->getRHS()) { + if (CS->getRHS()->isTypeDependent() || + CS->getRHS()->isValueDependent()) { + HasDependentValue = true; + break; + } + CaseRanges.push_back(std::make_pair(LoVal, CS)); + } else + CaseVals.push_back(std::make_pair(LoVal, CS)); + } + } + + if (!HasDependentValue) { + // Sort all the scalar case values so we can easily detect duplicates. + std::stable_sort(CaseVals.begin(), CaseVals.end(), CmpCaseVals); + + if (!CaseVals.empty()) { + for (unsigned i = 0, e = CaseVals.size()-1; i != e; ++i) { + if (CaseVals[i].first == CaseVals[i+1].first) { + // If we have a duplicate, report it. + Diag(CaseVals[i+1].second->getLHS()->getLocStart(), + diag::err_duplicate_case) << CaseVals[i].first.toString(10); + Diag(CaseVals[i].second->getLHS()->getLocStart(), + diag::note_duplicate_case_prev); + // FIXME: We really want to remove the bogus case stmt from the + // substmt, but we have no way to do this right now. + CaseListIsErroneous = true; + } + } + } + + // Detect duplicate case ranges, which usually don't exist at all in + // the first place. + if (!CaseRanges.empty()) { + // Sort all the case ranges by their low value so we can easily detect + // overlaps between ranges. + std::stable_sort(CaseRanges.begin(), CaseRanges.end()); + + // Scan the ranges, computing the high values and removing empty ranges. + std::vector<llvm::APSInt> HiVals; + for (unsigned i = 0, e = CaseRanges.size(); i != e; ++i) { + CaseStmt *CR = CaseRanges[i].second; + Expr *Hi = CR->getRHS(); + llvm::APSInt HiVal = Hi->EvaluateAsInt(Context); + + // Convert the value to the same width/sign as the condition. + ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned, + CR->getRHS()->getLocStart(), + diag::warn_case_value_overflow); + + // If the LHS is not the same type as the condition, insert an implicit + // cast. + ImpCastExprToType(Hi, CondType); + CR->setRHS(Hi); + + // If the low value is bigger than the high value, the case is empty. + if (CaseRanges[i].first > HiVal) { + Diag(CR->getLHS()->getLocStart(), diag::warn_case_empty_range) + << SourceRange(CR->getLHS()->getLocStart(), + CR->getRHS()->getLocEnd()); + CaseRanges.erase(CaseRanges.begin()+i); + --i, --e; + continue; + } + HiVals.push_back(HiVal); + } + + // Rescan the ranges, looking for overlap with singleton values and other + // ranges. Since the range list is sorted, we only need to compare case + // ranges with their neighbors. + for (unsigned i = 0, e = CaseRanges.size(); i != e; ++i) { + llvm::APSInt &CRLo = CaseRanges[i].first; + llvm::APSInt &CRHi = HiVals[i]; + CaseStmt *CR = CaseRanges[i].second; + + // Check to see whether the case range overlaps with any + // singleton cases. + CaseStmt *OverlapStmt = 0; + llvm::APSInt OverlapVal(32); + + // Find the smallest value >= the lower bound. If I is in the + // case range, then we have overlap. + CaseValsTy::iterator I = std::lower_bound(CaseVals.begin(), + CaseVals.end(), CRLo, + CaseCompareFunctor()); + if (I != CaseVals.end() && I->first < CRHi) { + OverlapVal = I->first; // Found overlap with scalar. + OverlapStmt = I->second; + } + + // Find the smallest value bigger than the upper bound. + I = std::upper_bound(I, CaseVals.end(), CRHi, CaseCompareFunctor()); + if (I != CaseVals.begin() && (I-1)->first >= CRLo) { + OverlapVal = (I-1)->first; // Found overlap with scalar. + OverlapStmt = (I-1)->second; + } + + // Check to see if this case stmt overlaps with the subsequent + // case range. + if (i && CRLo <= HiVals[i-1]) { + OverlapVal = HiVals[i-1]; // Found overlap with range. + OverlapStmt = CaseRanges[i-1].second; + } + + if (OverlapStmt) { + // If we have a duplicate, report it. + Diag(CR->getLHS()->getLocStart(), diag::err_duplicate_case) + << OverlapVal.toString(10); + Diag(OverlapStmt->getLHS()->getLocStart(), + diag::note_duplicate_case_prev); + // FIXME: We really want to remove the bogus case stmt from the + // substmt, but we have no way to do this right now. + CaseListIsErroneous = true; + } + } + } + } + + // FIXME: If the case list was broken is some way, we don't have a good system + // to patch it up. Instead, just return the whole substmt as broken. + if (CaseListIsErroneous) + return StmtError(); + + Switch.release(); + return Owned(SS); +} + +Action::OwningStmtResult +Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, StmtArg Body) { + ExprArg CondArg(Cond.release()); + Expr *condExpr = CondArg.takeAs<Expr>(); + assert(condExpr && "ActOnWhileStmt(): missing expression"); + + if (!condExpr->isTypeDependent()) { + DefaultFunctionArrayConversion(condExpr); + CondArg = condExpr; + QualType condType = condExpr->getType(); + + if (getLangOptions().CPlusPlus) { + if (CheckCXXBooleanCondition(condExpr)) // C++ 6.4p4 + return StmtError(); + } else if (!condType->isScalarType()) // C99 6.8.5p2 + return StmtError(Diag(WhileLoc, + diag::err_typecheck_statement_requires_scalar) + << condType << condExpr->getSourceRange()); + } + + CondArg.release(); + return Owned(new (Context) WhileStmt(condExpr, Body.takeAs<Stmt>(), + WhileLoc)); +} + +Action::OwningStmtResult +Sema::ActOnDoStmt(SourceLocation DoLoc, StmtArg Body, + SourceLocation WhileLoc, ExprArg Cond) { + Expr *condExpr = Cond.takeAs<Expr>(); + assert(condExpr && "ActOnDoStmt(): missing expression"); + + if (!condExpr->isTypeDependent()) { + DefaultFunctionArrayConversion(condExpr); + Cond = condExpr; + QualType condType = condExpr->getType(); + + if (getLangOptions().CPlusPlus) { + if (CheckCXXBooleanCondition(condExpr)) // C++ 6.4p4 + return StmtError(); + } else if (!condType->isScalarType()) // C99 6.8.5p2 + return StmtError(Diag(DoLoc, + diag::err_typecheck_statement_requires_scalar) + << condType << condExpr->getSourceRange()); + } + + Cond.release(); + return Owned(new (Context) DoStmt(Body.takeAs<Stmt>(), condExpr, DoLoc, + WhileLoc)); +} + +Action::OwningStmtResult +Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, + StmtArg first, ExprArg second, ExprArg third, + SourceLocation RParenLoc, StmtArg body) { + Stmt *First = static_cast<Stmt*>(first.get()); + Expr *Second = static_cast<Expr*>(second.get()); + Expr *Third = static_cast<Expr*>(third.get()); + Stmt *Body = static_cast<Stmt*>(body.get()); + + if (!getLangOptions().CPlusPlus) { + if (DeclStmt *DS = dyn_cast_or_null<DeclStmt>(First)) { + // C99 6.8.5p3: The declaration part of a 'for' statement shall only + // declare identifiers for objects having storage class 'auto' or + // 'register'. + for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE=DS->decl_end(); + DI!=DE; ++DI) { + VarDecl *VD = dyn_cast<VarDecl>(*DI); + if (VD && VD->isBlockVarDecl() && !VD->hasLocalStorage()) + VD = 0; + if (VD == 0) + Diag((*DI)->getLocation(), diag::err_non_variable_decl_in_for); + // FIXME: mark decl erroneous! + } + } + } + if (Second && !Second->isTypeDependent()) { + DefaultFunctionArrayConversion(Second); + QualType SecondType = Second->getType(); + + if (getLangOptions().CPlusPlus) { + if (CheckCXXBooleanCondition(Second)) // C++ 6.4p4 + return StmtError(); + } else if (!SecondType->isScalarType()) // C99 6.8.5p2 + return StmtError(Diag(ForLoc, + diag::err_typecheck_statement_requires_scalar) + << SecondType << Second->getSourceRange()); + } + first.release(); + second.release(); + third.release(); + body.release(); + return Owned(new (Context) ForStmt(First, Second, Third, Body, ForLoc, + LParenLoc, RParenLoc)); +} + +Action::OwningStmtResult +Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, + SourceLocation LParenLoc, + StmtArg first, ExprArg second, + SourceLocation RParenLoc, StmtArg body) { + Stmt *First = static_cast<Stmt*>(first.get()); + Expr *Second = static_cast<Expr*>(second.get()); + Stmt *Body = static_cast<Stmt*>(body.get()); + if (First) { + QualType FirstType; + if (DeclStmt *DS = dyn_cast<DeclStmt>(First)) { + if (!DS->isSingleDecl()) + return StmtError(Diag((*DS->decl_begin())->getLocation(), + diag::err_toomany_element_decls)); + + Decl *D = DS->getSingleDecl(); + FirstType = cast<ValueDecl>(D)->getType(); + // C99 6.8.5p3: The declaration part of a 'for' statement shall only + // declare identifiers for objects having storage class 'auto' or + // 'register'. + VarDecl *VD = cast<VarDecl>(D); + if (VD->isBlockVarDecl() && !VD->hasLocalStorage()) + return StmtError(Diag(VD->getLocation(), + diag::err_non_variable_decl_in_for)); + } else { + if (cast<Expr>(First)->isLvalue(Context) != Expr::LV_Valid) + return StmtError(Diag(First->getLocStart(), + diag::err_selector_element_not_lvalue) + << First->getSourceRange()); + + FirstType = static_cast<Expr*>(First)->getType(); + } + if (!Context.isObjCObjectPointerType(FirstType)) + Diag(ForLoc, diag::err_selector_element_type) + << FirstType << First->getSourceRange(); + } + if (Second) { + DefaultFunctionArrayConversion(Second); + QualType SecondType = Second->getType(); + if (!Context.isObjCObjectPointerType(SecondType)) + Diag(ForLoc, diag::err_collection_expr_type) + << SecondType << Second->getSourceRange(); + } + first.release(); + second.release(); + body.release(); + return Owned(new (Context) ObjCForCollectionStmt(First, Second, Body, + ForLoc, RParenLoc)); +} + +Action::OwningStmtResult +Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, + IdentifierInfo *LabelII) { + // If we are in a block, reject all gotos for now. + if (CurBlock) + return StmtError(Diag(GotoLoc, diag::err_goto_in_block)); + + // Look up the record for this label identifier. + LabelStmt *&LabelDecl = getLabelMap()[LabelII]; + + // If we haven't seen this label yet, create a forward reference. + if (LabelDecl == 0) + LabelDecl = new (Context) LabelStmt(LabelLoc, LabelII, 0); + + return Owned(new (Context) GotoStmt(LabelDecl, GotoLoc, LabelLoc)); +} + +Action::OwningStmtResult +Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc, + ExprArg DestExp) { + // Convert operand to void* + Expr* E = DestExp.takeAs<Expr>(); + if (!E->isTypeDependent()) { + QualType ETy = E->getType(); + AssignConvertType ConvTy = + CheckSingleAssignmentConstraints(Context.VoidPtrTy, E); + if (DiagnoseAssignmentResult(ConvTy, StarLoc, Context.VoidPtrTy, ETy, + E, "passing")) + return StmtError(); + } + return Owned(new (Context) IndirectGotoStmt(GotoLoc, StarLoc, E)); +} + +Action::OwningStmtResult +Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) { + Scope *S = CurScope->getContinueParent(); + if (!S) { + // C99 6.8.6.2p1: A break shall appear only in or as a loop body. + return StmtError(Diag(ContinueLoc, diag::err_continue_not_in_loop)); + } + + return Owned(new (Context) ContinueStmt(ContinueLoc)); +} + +Action::OwningStmtResult +Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { + Scope *S = CurScope->getBreakParent(); + if (!S) { + // C99 6.8.6.3p1: A break shall appear only in or as a switch/loop body. + return StmtError(Diag(BreakLoc, diag::err_break_not_in_loop_or_switch)); + } + + return Owned(new (Context) BreakStmt(BreakLoc)); +} + +/// ActOnBlockReturnStmt - Utility routine to figure out block's return type. +/// +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. + if (CurBlock->ReturnType == 0) { + if (RetValExp) { + // Don't call UsualUnaryConversions(), since we don't want to do + // integer promotions here. + DefaultFunctionArrayConversion(RetValExp); + CurBlock->ReturnType = RetValExp->getType().getTypePtr(); + } else + CurBlock->ReturnType = Context.VoidTy.getTypePtr(); + } + QualType FnRetType = QualType(CurBlock->ReturnType, 0); + + if (CurBlock->TheDecl->hasAttr<NoReturnAttr>()) { + Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr) + << getCurFunctionOrMethodDecl()->getDeclName(); + return StmtError(); + } + + // Otherwise, verify that this result type matches the previous one. We are + // pickier with blocks than for normal functions because we don't have GCC + // compatibility to worry about here. + if (CurBlock->ReturnType->isVoidType()) { + if (RetValExp) { + Diag(ReturnLoc, diag::err_return_block_has_expr); + RetValExp->Destroy(Context); + RetValExp = 0; + } + return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp)); + } + + if (!RetValExp) + return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr)); + + if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { + // we have a non-void block with an expression, continue checking + QualType RetValType = RetValExp->getType(); + + // C99 6.8.6.4p3(136): The return statement is not an assignment. The + // overlap restriction of subclause 6.5.16.1 does not apply to the case of + // function return. + + // In C++ the return statement is handled via a copy initialization. + // the C version of which boils down to CheckSingleAssignmentConstraints. + // FIXME: Leaks RetValExp. + if (PerformCopyInitialization(RetValExp, FnRetType, "returning")) + return StmtError(); + + if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); + } + + return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp)); +} + +/// IsReturnCopyElidable - Whether returning @p RetExpr from a function that +/// returns a @p RetType fulfills the criteria for copy elision (C++0x 12.8p15). +static bool IsReturnCopyElidable(ASTContext &Ctx, QualType RetType, + Expr *RetExpr) { + QualType ExprType = RetExpr->getType(); + // - in a return statement in a function with ... + // ... a class return type ... + if (!RetType->isRecordType()) + return false; + // ... the same cv-unqualified type as the function return type ... + if (Ctx.getCanonicalType(RetType).getUnqualifiedType() != + Ctx.getCanonicalType(ExprType).getUnqualifiedType()) + return false; + // ... the expression is the name of a non-volatile automatic object ... + // We ignore parentheses here. + // FIXME: Is this compliant? + const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetExpr->IgnoreParens()); + if (!DR) + return false; + const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); + if (!VD) + return false; + return VD->hasLocalStorage() && !VD->getType()->isReferenceType() + && !VD->getType().isVolatileQualified(); +} + +Action::OwningStmtResult +Sema::ActOnReturnStmt(SourceLocation ReturnLoc, FullExprArg rex) { + Expr *RetValExp = rex->takeAs<Expr>(); + if (CurBlock) + return ActOnBlockReturnStmt(ReturnLoc, RetValExp); + + QualType FnRetType; + if (const FunctionDecl *FD = getCurFunctionDecl()) { + FnRetType = FD->getResultType(); + if (FD->hasAttr<NoReturnAttr>()) + Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr) + << getCurFunctionOrMethodDecl()->getDeclName(); + } else if (ObjCMethodDecl *MD = getCurMethodDecl()) + FnRetType = MD->getResultType(); + else // If we don't have a function/method context, bail. + return StmtError(); + + if (FnRetType->isVoidType()) { + if (RetValExp) {// C99 6.8.6.4p1 (ext_ since GCC warns) + unsigned D = diag::ext_return_has_expr; + if (RetValExp->getType()->isVoidType()) + D = diag::ext_return_has_void_expr; + + // return (some void expression); is legal in C++. + if (D != diag::ext_return_has_void_expr || + !getLangOptions().CPlusPlus) { + NamedDecl *CurDecl = getCurFunctionOrMethodDecl(); + Diag(ReturnLoc, D) + << CurDecl->getDeclName() << isa<ObjCMethodDecl>(CurDecl) + << RetValExp->getSourceRange(); + } + } + return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp)); + } + + if (!RetValExp && !FnRetType->isDependentType()) { + unsigned DiagID = diag::warn_return_missing_expr; // C90 6.6.6.4p4 + // C99 6.8.6.4p1 (ext_ since GCC warns) + if (getLangOptions().C99) DiagID = diag::ext_return_missing_expr; + + if (FunctionDecl *FD = getCurFunctionDecl()) + Diag(ReturnLoc, DiagID) << FD->getIdentifier() << 0/*fn*/; + else + Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/; + return Owned(new (Context) ReturnStmt(ReturnLoc, (Expr*)0)); + } + + if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { + // we have a non-void function with an expression, continue checking + + // C99 6.8.6.4p3(136): The return statement is not an assignment. The + // overlap restriction of subclause 6.5.16.1 does not apply to the case of + // function return. + + // C++0x 12.8p15: When certain criteria are met, an implementation is + // allowed to omit the copy construction of a class object, [...] + // - in a return statement in a function with a class return type, when + // the expression is the name of a non-volatile automatic object with + // the same cv-unqualified type as the function return type, the copy + // operation can be omitted [...] + // C++0x 12.8p16: When the criteria for elision of a copy operation are met + // and the object to be copied is designated by an lvalue, overload + // resolution to select the constructor for the copy is first performed + // as if the object were designated by an rvalue. + // Note that we only compute Elidable if we're in C++0x, since we don't + // care otherwise. + bool Elidable = getLangOptions().CPlusPlus0x ? + IsReturnCopyElidable(Context, FnRetType, RetValExp) : + false; + + // In C++ the return statement is handled via a copy initialization. + // the C version of which boils down to CheckSingleAssignmentConstraints. + // FIXME: Leaks RetValExp on error. + if (PerformCopyInitialization(RetValExp, FnRetType, "returning", Elidable)) + return StmtError(); + + if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); + } + + return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp)); +} + +/// CheckAsmLValue - GNU C has an extremely ugly extension whereby they silently +/// ignore "noop" casts in places where an lvalue is required by an inline asm. +/// We emulate this behavior when -fheinous-gnu-extensions is specified, but +/// provide a strong guidance to not use it. +/// +/// This method checks to see if the argument is an acceptable l-value and +/// returns false if it is a case we can handle. +static bool CheckAsmLValue(const Expr *E, Sema &S) { + if (E->isLvalue(S.Context) == Expr::LV_Valid) + return false; // Cool, this is an lvalue. + + // Okay, this is not an lvalue, but perhaps it is the result of a cast that we + // are supposed to allow. + const Expr *E2 = E->IgnoreParenNoopCasts(S.Context); + if (E != E2 && E2->isLvalue(S.Context) == Expr::LV_Valid) { + if (!S.getLangOptions().HeinousExtensions) + S.Diag(E2->getLocStart(), diag::err_invalid_asm_cast_lvalue) + << E->getSourceRange(); + else + S.Diag(E2->getLocStart(), diag::warn_invalid_asm_cast_lvalue) + << E->getSourceRange(); + // Accept, even if we emitted an error diagnostic. + return false; + } + + // None of the above, just randomly invalid non-lvalue. + return true; +} + + +Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, + bool IsSimple, + bool IsVolatile, + unsigned NumOutputs, + unsigned NumInputs, + std::string *Names, + MultiExprArg constraints, + MultiExprArg exprs, + ExprArg asmString, + MultiExprArg clobbers, + SourceLocation RParenLoc) { + unsigned NumClobbers = clobbers.size(); + StringLiteral **Constraints = + reinterpret_cast<StringLiteral**>(constraints.get()); + Expr **Exprs = reinterpret_cast<Expr **>(exprs.get()); + StringLiteral *AsmString = cast<StringLiteral>((Expr *)asmString.get()); + StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.get()); + + llvm::SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos; + + // The parser verifies that there is a string literal here. + if (AsmString->isWide()) + return StmtError(Diag(AsmString->getLocStart(),diag::err_asm_wide_character) + << AsmString->getSourceRange()); + + for (unsigned i = 0; i != NumOutputs; i++) { + StringLiteral *Literal = Constraints[i]; + if (Literal->isWide()) + return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) + << Literal->getSourceRange()); + + TargetInfo::ConstraintInfo Info(Literal->getStrData(), + Literal->getByteLength(), + Names[i]); + if (!Context.Target.validateOutputConstraint(Info)) + return StmtError(Diag(Literal->getLocStart(), + diag::err_asm_invalid_output_constraint) + << Info.getConstraintStr()); + + // Check that the output exprs are valid lvalues. + Expr *OutputExpr = Exprs[i]; + if (CheckAsmLValue(OutputExpr, *this)) { + return StmtError(Diag(OutputExpr->getLocStart(), + diag::err_asm_invalid_lvalue_in_output) + << OutputExpr->getSourceRange()); + } + + OutputConstraintInfos.push_back(Info); + } + + llvm::SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos; + + for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) { + StringLiteral *Literal = Constraints[i]; + if (Literal->isWide()) + return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) + << Literal->getSourceRange()); + + TargetInfo::ConstraintInfo Info(Literal->getStrData(), + Literal->getByteLength(), + Names[i]); + if (!Context.Target.validateInputConstraint(OutputConstraintInfos.data(), + NumOutputs, Info)) { + return StmtError(Diag(Literal->getLocStart(), + diag::err_asm_invalid_input_constraint) + << Info.getConstraintStr()); + } + + Expr *InputExpr = Exprs[i]; + + // Only allow void types for memory constraints. + if (Info.allowsMemory() && !Info.allowsRegister()) { + if (CheckAsmLValue(InputExpr, *this)) + return StmtError(Diag(InputExpr->getLocStart(), + diag::err_asm_invalid_lvalue_in_input) + << Info.getConstraintStr() + << InputExpr->getSourceRange()); + } + + if (Info.allowsRegister()) { + if (InputExpr->getType()->isVoidType()) { + return StmtError(Diag(InputExpr->getLocStart(), + diag::err_asm_invalid_type_in_input) + << InputExpr->getType() << Info.getConstraintStr() + << InputExpr->getSourceRange()); + } + } + + DefaultFunctionArrayConversion(Exprs[i]); + + InputConstraintInfos.push_back(Info); + } + + // Check that the clobbers are valid. + for (unsigned i = 0; i != NumClobbers; i++) { + StringLiteral *Literal = Clobbers[i]; + if (Literal->isWide()) + return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) + << Literal->getSourceRange()); + + llvm::SmallString<16> Clobber(Literal->getStrData(), + Literal->getStrData() + + Literal->getByteLength()); + + if (!Context.Target.isValidGCCRegisterName(Clobber.c_str())) + return StmtError(Diag(Literal->getLocStart(), + diag::err_asm_unknown_register_name) << Clobber.c_str()); + } + + constraints.release(); + exprs.release(); + asmString.release(); + clobbers.release(); + AsmStmt *NS = + new (Context) AsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs, + Names, Constraints, Exprs, AsmString, NumClobbers, + Clobbers, RParenLoc); + // Validate the asm string, ensuring it makes sense given the operands we + // have. + llvm::SmallVector<AsmStmt::AsmStringPiece, 8> Pieces; + unsigned DiagOffs; + if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) { + Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID) + << AsmString->getSourceRange(); + DeleteStmt(NS); + return StmtError(); + } + + // Validate tied input operands for type mismatches. + for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) { + TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i]; + + // If this is a tied constraint, verify that the output and input have + // either exactly the same type, or that they are int/ptr operands with the + // same size (int/long, int*/long, are ok etc). + if (!Info.hasTiedOperand()) continue; + + unsigned TiedTo = Info.getTiedOperand(); + Expr *OutputExpr = Exprs[TiedTo]; + Expr *InputExpr = Exprs[i+NumOutputs]; + QualType InTy = InputExpr->getType(); + QualType OutTy = OutputExpr->getType(); + if (Context.hasSameType(InTy, OutTy)) + continue; // All types can be tied to themselves. + + // Int/ptr operands have some special cases that we allow. + if ((OutTy->isIntegerType() || OutTy->isPointerType()) && + (InTy->isIntegerType() || InTy->isPointerType())) { + + // They are ok if they are the same size. Tying void* to int is ok if + // they are the same size, for example. This also allows tying void* to + // int*. + uint64_t OutSize = Context.getTypeSize(OutTy); + uint64_t InSize = Context.getTypeSize(InTy); + if (OutSize == InSize) + continue; + + // If the smaller input/output operand is not mentioned in the asm string, + // then we can promote it and the asm string won't notice. Check this + // case now. + bool SmallerValueMentioned = false; + for (unsigned p = 0, e = Pieces.size(); p != e; ++p) { + AsmStmt::AsmStringPiece &Piece = Pieces[p]; + if (!Piece.isOperand()) continue; + + // If this is a reference to the input and if the input was the smaller + // one, then we have to reject this asm. + if (Piece.getOperandNo() == i+NumOutputs) { + if (InSize < OutSize) { + SmallerValueMentioned = true; + break; + } + } + + // If this is a reference to the input and if the input was the smaller + // one, then we have to reject this asm. + if (Piece.getOperandNo() == TiedTo) { + if (InSize > OutSize) { + SmallerValueMentioned = true; + break; + } + } + } + + // If the smaller value wasn't mentioned in the asm string, and if the + // output was a register, just extend the shorter one to the size of the + // larger one. + if (!SmallerValueMentioned && + OutputConstraintInfos[TiedTo].allowsRegister()) + continue; + } + + Diag(InputExpr->getLocStart(), + diag::err_asm_tying_incompatible_types) + << InTy << OutTy << OutputExpr->getSourceRange() + << InputExpr->getSourceRange(); + DeleteStmt(NS); + return StmtError(); + } + + return Owned(NS); +} + +Action::OwningStmtResult +Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc, + SourceLocation RParen, DeclPtrTy Parm, + StmtArg Body, StmtArg catchList) { + Stmt *CatchList = catchList.takeAs<Stmt>(); + ParmVarDecl *PVD = cast_or_null<ParmVarDecl>(Parm.getAs<Decl>()); + + // PVD == 0 implies @catch(...). + if (PVD) { + // If we already know the decl is invalid, reject it. + if (PVD->isInvalidDecl()) + return StmtError(); + + if (!Context.isObjCObjectPointerType(PVD->getType())) + return StmtError(Diag(PVD->getLocation(), + diag::err_catch_param_not_objc_type)); + if (PVD->getType()->isObjCQualifiedIdType()) + return StmtError(Diag(PVD->getLocation(), + diag::err_illegal_qualifiers_on_catch_parm)); + } + + ObjCAtCatchStmt *CS = new (Context) ObjCAtCatchStmt(AtLoc, RParen, + PVD, Body.takeAs<Stmt>(), CatchList); + return Owned(CatchList ? CatchList : CS); +} + +Action::OwningStmtResult +Sema::ActOnObjCAtFinallyStmt(SourceLocation AtLoc, StmtArg Body) { + return Owned(new (Context) ObjCAtFinallyStmt(AtLoc, + static_cast<Stmt*>(Body.release()))); +} + +Action::OwningStmtResult +Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, + StmtArg Try, StmtArg Catch, StmtArg Finally) { + CurFunctionNeedsScopeChecking = true; + return Owned(new (Context) ObjCAtTryStmt(AtLoc, Try.takeAs<Stmt>(), + Catch.takeAs<Stmt>(), + Finally.takeAs<Stmt>())); +} + +Action::OwningStmtResult +Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr,Scope *CurScope) { + Expr *ThrowExpr = expr.takeAs<Expr>(); + if (!ThrowExpr) { + // @throw without an expression designates a rethrow (which much occur + // in the context of an @catch clause). + Scope *AtCatchParent = CurScope; + while (AtCatchParent && !AtCatchParent->isAtCatchScope()) + AtCatchParent = AtCatchParent->getParent(); + if (!AtCatchParent) + return StmtError(Diag(AtLoc, diag::error_rethrow_used_outside_catch)); + } else { + QualType ThrowType = ThrowExpr->getType(); + // Make sure the expression type is an ObjC pointer or "void *". + if (!Context.isObjCObjectPointerType(ThrowType)) { + const PointerType *PT = ThrowType->getAsPointerType(); + if (!PT || !PT->getPointeeType()->isVoidType()) + return StmtError(Diag(AtLoc, diag::error_objc_throw_expects_object) + << ThrowExpr->getType() << ThrowExpr->getSourceRange()); + } + } + return Owned(new (Context) ObjCAtThrowStmt(AtLoc, ThrowExpr)); +} + +Action::OwningStmtResult +Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprArg SynchExpr, + StmtArg SynchBody) { + CurFunctionNeedsScopeChecking = true; + + // Make sure the expression type is an ObjC pointer or "void *". + Expr *SyncExpr = static_cast<Expr*>(SynchExpr.get()); + if (!Context.isObjCObjectPointerType(SyncExpr->getType())) { + const PointerType *PT = SyncExpr->getType()->getAsPointerType(); + if (!PT || !PT->getPointeeType()->isVoidType()) + return StmtError(Diag(AtLoc, diag::error_objc_synchronized_expects_object) + << SyncExpr->getType() << SyncExpr->getSourceRange()); + } + + return Owned(new (Context) ObjCAtSynchronizedStmt(AtLoc, + SynchExpr.takeAs<Stmt>(), + SynchBody.takeAs<Stmt>())); +} + +/// ActOnCXXCatchBlock - Takes an exception declaration and a handler block +/// and creates a proper catch handler from them. +Action::OwningStmtResult +Sema::ActOnCXXCatchBlock(SourceLocation CatchLoc, DeclPtrTy ExDecl, + StmtArg HandlerBlock) { + // There's nothing to test that ActOnExceptionDecl didn't already test. + return Owned(new (Context) CXXCatchStmt(CatchLoc, + cast_or_null<VarDecl>(ExDecl.getAs<Decl>()), + HandlerBlock.takeAs<Stmt>())); +} + +/// ActOnCXXTryBlock - Takes a try compound-statement and a number of +/// handlers and creates a try statement from them. +Action::OwningStmtResult +Sema::ActOnCXXTryBlock(SourceLocation TryLoc, StmtArg TryBlock, + MultiStmtArg RawHandlers) { + unsigned NumHandlers = RawHandlers.size(); + assert(NumHandlers > 0 && + "The parser shouldn't call this if there are no handlers."); + Stmt **Handlers = reinterpret_cast<Stmt**>(RawHandlers.get()); + + for(unsigned i = 0; i < NumHandlers - 1; ++i) { + CXXCatchStmt *Handler = llvm::cast<CXXCatchStmt>(Handlers[i]); + if (!Handler->getExceptionDecl()) + return StmtError(Diag(Handler->getLocStart(), diag::err_early_catch_all)); + } + // FIXME: We should detect handlers for the same type as an earlier one. + // This one is rather easy. + // FIXME: We should detect handlers that cannot catch anything because an + // earlier handler catches a superclass. Need to find a method that is not + // quadratic for this. + // Neither of these are explicitly forbidden, but every compiler detects them + // and warns. + + CurFunctionNeedsScopeChecking = true; + RawHandlers.release(); + return Owned(new (Context) CXXTryStmt(TryLoc, + static_cast<Stmt*>(TryBlock.release()), + Handlers, NumHandlers)); +} diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp new file mode 100644 index 0000000..782a0d8 --- /dev/null +++ b/lib/Sema/SemaTemplate.cpp @@ -0,0 +1,2651 @@ +//===------- SemaTemplate.cpp - Semantic Analysis for C++ Templates -------===/ + +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +//===----------------------------------------------------------------------===/ + +// +// This file implements semantic analysis for C++ templates. +//===----------------------------------------------------------------------===/ + +#include "Sema.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/Parse/DeclSpec.h" +#include "clang/Basic/LangOptions.h" + +using namespace clang; + +/// isTemplateName - Determines whether the identifier II is a +/// template name in the current scope, and returns the template +/// declaration if II names a template. An optional CXXScope can be +/// passed to indicate the C++ scope in which the identifier will be +/// found. +TemplateNameKind Sema::isTemplateName(const IdentifierInfo &II, Scope *S, + TemplateTy &TemplateResult, + const CXXScopeSpec *SS) { + NamedDecl *IIDecl = LookupParsedName(S, SS, &II, LookupOrdinaryName); + + TemplateNameKind TNK = TNK_Non_template; + TemplateDecl *Template = 0; + + if (IIDecl) { + if ((Template = dyn_cast<TemplateDecl>(IIDecl))) { + if (isa<FunctionTemplateDecl>(IIDecl)) + TNK = TNK_Function_template; + else if (isa<ClassTemplateDecl>(IIDecl) || + isa<TemplateTemplateParmDecl>(IIDecl)) + TNK = TNK_Type_template; + else + assert(false && "Unknown template declaration kind"); + } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(IIDecl)) { + // C++ [temp.local]p1: + // Like normal (non-template) classes, class templates have an + // injected-class-name (Clause 9). The injected-class-name + // can be used with or without a template-argument-list. When + // it is used without a template-argument-list, it is + // equivalent to the injected-class-name followed by the + // template-parameters of the class template enclosed in + // <>. When it is used with a template-argument-list, it + // refers to the specified class template specialization, + // which could be the current specialization or another + // specialization. + if (Record->isInjectedClassName()) { + Record = cast<CXXRecordDecl>(Context.getCanonicalDecl(Record)); + if ((Template = Record->getDescribedClassTemplate())) + TNK = TNK_Type_template; + else if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(Record)) { + Template = Spec->getSpecializedTemplate(); + TNK = TNK_Type_template; + } + } + } + + // FIXME: What follows is a gross hack. + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(IIDecl)) { + if (FD->getType()->isDependentType()) { + TemplateResult = TemplateTy::make(FD); + return TNK_Function_template; + } + } else if (OverloadedFunctionDecl *Ovl + = dyn_cast<OverloadedFunctionDecl>(IIDecl)) { + for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(), + FEnd = Ovl->function_end(); + F != FEnd; ++F) { + if ((*F)->getType()->isDependentType()) { + TemplateResult = TemplateTy::make(Ovl); + return TNK_Function_template; + } + } + } + + if (TNK != TNK_Non_template) { + if (SS && SS->isSet() && !SS->isInvalid()) { + NestedNameSpecifier *Qualifier + = static_cast<NestedNameSpecifier *>(SS->getScopeRep()); + TemplateResult + = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, + false, + Template)); + } else + TemplateResult = TemplateTy::make(TemplateName(Template)); + } + } + return TNK; +} + +/// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining +/// that the template parameter 'PrevDecl' is being shadowed by a new +/// declaration at location Loc. Returns true to indicate that this is +/// an error, and false otherwise. +bool Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) { + assert(PrevDecl->isTemplateParameter() && "Not a template parameter"); + + // Microsoft Visual C++ permits template parameters to be shadowed. + if (getLangOptions().Microsoft) + return false; + + // C++ [temp.local]p4: + // A template-parameter shall not be redeclared within its + // scope (including nested scopes). + Diag(Loc, diag::err_template_param_shadow) + << cast<NamedDecl>(PrevDecl)->getDeclName(); + Diag(PrevDecl->getLocation(), diag::note_template_param_here); + return true; +} + +/// AdjustDeclIfTemplate - If the given decl happens to be a template, reset +/// the parameter D to reference the templated declaration and return a pointer +/// to the template declaration. Otherwise, do nothing to D and return null. +TemplateDecl *Sema::AdjustDeclIfTemplate(DeclPtrTy &D) { + if (TemplateDecl *Temp = dyn_cast<TemplateDecl>(D.getAs<Decl>())) { + D = DeclPtrTy::make(Temp->getTemplatedDecl()); + return Temp; + } + return 0; +} + +/// ActOnTypeParameter - Called when a C++ template type parameter +/// (e.g., "typename T") has been parsed. Typename specifies whether +/// the keyword "typename" was used to declare the type parameter +/// (otherwise, "class" was used), and KeyLoc is the location of the +/// "class" or "typename" keyword. ParamName is the name of the +/// parameter (NULL indicates an unnamed template parameter) and +/// ParamName is the location of the parameter name (if any). +/// If the type parameter has a default argument, it will be added +/// later via ActOnTypeParameterDefault. +Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, + SourceLocation KeyLoc, + IdentifierInfo *ParamName, + SourceLocation ParamNameLoc, + unsigned Depth, unsigned Position) { + assert(S->isTemplateParamScope() && + "Template type parameter not in template parameter scope!"); + bool Invalid = false; + + if (ParamName) { + NamedDecl *PrevDecl = LookupName(S, ParamName, LookupTagName); + if (PrevDecl && PrevDecl->isTemplateParameter()) + Invalid = Invalid || DiagnoseTemplateParameterShadow(ParamNameLoc, + PrevDecl); + } + + SourceLocation Loc = ParamNameLoc; + if (!ParamName) + Loc = KeyLoc; + + TemplateTypeParmDecl *Param + = TemplateTypeParmDecl::Create(Context, CurContext, Loc, + Depth, Position, ParamName, Typename); + if (Invalid) + Param->setInvalidDecl(); + + if (ParamName) { + // Add the template parameter into the current scope. + S->AddDecl(DeclPtrTy::make(Param)); + IdResolver.AddDecl(Param); + } + + return DeclPtrTy::make(Param); +} + +/// ActOnTypeParameterDefault - Adds a default argument (the type +/// Default) to the given template type parameter (TypeParam). +void Sema::ActOnTypeParameterDefault(DeclPtrTy TypeParam, + SourceLocation EqualLoc, + SourceLocation DefaultLoc, + TypeTy *DefaultT) { + TemplateTypeParmDecl *Parm + = cast<TemplateTypeParmDecl>(TypeParam.getAs<Decl>()); + QualType Default = QualType::getFromOpaquePtr(DefaultT); + + // C++ [temp.param]p14: + // A template-parameter shall not be used in its own default argument. + // FIXME: Implement this check! Needs a recursive walk over the types. + + // Check the template argument itself. + if (CheckTemplateArgument(Parm, Default, DefaultLoc)) { + Parm->setInvalidDecl(); + return; + } + + Parm->setDefaultArgument(Default, DefaultLoc, false); +} + +/// \brief Check that the type of a non-type template parameter is +/// well-formed. +/// +/// \returns the (possibly-promoted) parameter type if valid; +/// otherwise, produces a diagnostic and returns a NULL type. +QualType +Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) { + // C++ [temp.param]p4: + // + // A non-type template-parameter shall have one of the following + // (optionally cv-qualified) types: + // + // -- integral or enumeration type, + if (T->isIntegralType() || T->isEnumeralType() || + // -- pointer to object or pointer to function, + (T->isPointerType() && + (T->getAsPointerType()->getPointeeType()->isObjectType() || + T->getAsPointerType()->getPointeeType()->isFunctionType())) || + // -- reference to object or reference to function, + T->isReferenceType() || + // -- pointer to member. + T->isMemberPointerType() || + // If T is a dependent type, we can't do the check now, so we + // assume that it is well-formed. + T->isDependentType()) + return T; + // C++ [temp.param]p8: + // + // A non-type template-parameter of type "array of T" or + // "function returning T" is adjusted to be of type "pointer to + // T" or "pointer to function returning T", respectively. + else if (T->isArrayType()) + // FIXME: Keep the type prior to promotion? + return Context.getArrayDecayedType(T); + else if (T->isFunctionType()) + // FIXME: Keep the type prior to promotion? + return Context.getPointerType(T); + + Diag(Loc, diag::err_template_nontype_parm_bad_type) + << T; + + return QualType(); +} + +/// ActOnNonTypeTemplateParameter - Called when a C++ non-type +/// template parameter (e.g., "int Size" in "template<int Size> +/// class Array") has been parsed. S is the current scope and D is +/// the parsed declarator. +Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, + unsigned Depth, + unsigned Position) { + QualType T = GetTypeForDeclarator(D, S); + + assert(S->isTemplateParamScope() && + "Non-type template parameter not in template parameter scope!"); + bool Invalid = false; + + IdentifierInfo *ParamName = D.getIdentifier(); + if (ParamName) { + NamedDecl *PrevDecl = LookupName(S, ParamName, LookupTagName); + if (PrevDecl && PrevDecl->isTemplateParameter()) + Invalid = Invalid || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), + PrevDecl); + } + + T = CheckNonTypeTemplateParameterType(T, D.getIdentifierLoc()); + if (T.isNull()) { + T = Context.IntTy; // Recover with an 'int' type. + Invalid = true; + } + + NonTypeTemplateParmDecl *Param + = NonTypeTemplateParmDecl::Create(Context, CurContext, D.getIdentifierLoc(), + Depth, Position, ParamName, T); + if (Invalid) + Param->setInvalidDecl(); + + if (D.getIdentifier()) { + // Add the template parameter into the current scope. + S->AddDecl(DeclPtrTy::make(Param)); + IdResolver.AddDecl(Param); + } + return DeclPtrTy::make(Param); +} + +/// \brief Adds a default argument to the given non-type template +/// parameter. +void Sema::ActOnNonTypeTemplateParameterDefault(DeclPtrTy TemplateParamD, + SourceLocation EqualLoc, + ExprArg DefaultE) { + NonTypeTemplateParmDecl *TemplateParm + = cast<NonTypeTemplateParmDecl>(TemplateParamD.getAs<Decl>()); + Expr *Default = static_cast<Expr *>(DefaultE.get()); + + // C++ [temp.param]p14: + // A template-parameter shall not be used in its own default argument. + // FIXME: Implement this check! Needs a recursive walk over the types. + + // Check the well-formedness of the default template argument. + if (CheckTemplateArgument(TemplateParm, TemplateParm->getType(), Default)) { + TemplateParm->setInvalidDecl(); + return; + } + + TemplateParm->setDefaultArgument(DefaultE.takeAs<Expr>()); +} + + +/// ActOnTemplateTemplateParameter - Called when a C++ template template +/// parameter (e.g. T in template <template <typename> class T> class array) +/// has been parsed. S is the current scope. +Sema::DeclPtrTy Sema::ActOnTemplateTemplateParameter(Scope* S, + SourceLocation TmpLoc, + TemplateParamsTy *Params, + IdentifierInfo *Name, + SourceLocation NameLoc, + unsigned Depth, + unsigned Position) +{ + assert(S->isTemplateParamScope() && + "Template template parameter not in template parameter scope!"); + + // Construct the parameter object. + TemplateTemplateParmDecl *Param = + TemplateTemplateParmDecl::Create(Context, CurContext, TmpLoc, Depth, + Position, Name, + (TemplateParameterList*)Params); + + // Make sure the parameter is valid. + // FIXME: Decl object is not currently invalidated anywhere so this doesn't + // do anything yet. However, if the template parameter list or (eventual) + // default value is ever invalidated, that will propagate here. + bool Invalid = false; + if (Invalid) { + Param->setInvalidDecl(); + } + + // If the tt-param has a name, then link the identifier into the scope + // and lookup mechanisms. + if (Name) { + S->AddDecl(DeclPtrTy::make(Param)); + IdResolver.AddDecl(Param); + } + + return DeclPtrTy::make(Param); +} + +/// \brief Adds a default argument to the given template template +/// parameter. +void Sema::ActOnTemplateTemplateParameterDefault(DeclPtrTy TemplateParamD, + SourceLocation EqualLoc, + ExprArg DefaultE) { + TemplateTemplateParmDecl *TemplateParm + = cast<TemplateTemplateParmDecl>(TemplateParamD.getAs<Decl>()); + + // Since a template-template parameter's default argument is an + // id-expression, it must be a DeclRefExpr. + DeclRefExpr *Default + = cast<DeclRefExpr>(static_cast<Expr *>(DefaultE.get())); + + // C++ [temp.param]p14: + // A template-parameter shall not be used in its own default argument. + // FIXME: Implement this check! Needs a recursive walk over the types. + + // Check the well-formedness of the template argument. + if (!isa<TemplateDecl>(Default->getDecl())) { + Diag(Default->getSourceRange().getBegin(), + diag::err_template_arg_must_be_template) + << Default->getSourceRange(); + TemplateParm->setInvalidDecl(); + return; + } + if (CheckTemplateArgument(TemplateParm, Default)) { + TemplateParm->setInvalidDecl(); + return; + } + + DefaultE.release(); + TemplateParm->setDefaultArgument(Default); +} + +/// ActOnTemplateParameterList - Builds a TemplateParameterList that +/// contains the template parameters in Params/NumParams. +Sema::TemplateParamsTy * +Sema::ActOnTemplateParameterList(unsigned Depth, + SourceLocation ExportLoc, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + DeclPtrTy *Params, unsigned NumParams, + SourceLocation RAngleLoc) { + if (ExportLoc.isValid()) + Diag(ExportLoc, diag::note_template_export_unsupported); + + return TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc, + (Decl**)Params, NumParams, RAngleLoc); +} + +Sema::DeclResult +Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK, + SourceLocation KWLoc, const CXXScopeSpec &SS, + IdentifierInfo *Name, SourceLocation NameLoc, + AttributeList *Attr, + MultiTemplateParamsArg TemplateParameterLists, + AccessSpecifier AS) { + assert(TemplateParameterLists.size() > 0 && "No template parameter lists?"); + assert(TK != TK_Reference && "Can only declare or define class templates"); + bool Invalid = false; + + // Check that we can declare a template here. + if (CheckTemplateDeclScope(S, TemplateParameterLists)) + return true; + + TagDecl::TagKind Kind; + switch (TagSpec) { + default: assert(0 && "Unknown tag type!"); + case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break; + case DeclSpec::TST_union: Kind = TagDecl::TK_union; break; + case DeclSpec::TST_class: Kind = TagDecl::TK_class; break; + } + + // There is no such thing as an unnamed class template. + if (!Name) { + Diag(KWLoc, diag::err_template_unnamed_class); + return true; + } + + // Find any previous declaration with this name. + LookupResult Previous = LookupParsedName(S, &SS, Name, LookupOrdinaryName, + true); + assert(!Previous.isAmbiguous() && "Ambiguity in class template redecl?"); + NamedDecl *PrevDecl = 0; + if (Previous.begin() != Previous.end()) + PrevDecl = *Previous.begin(); + + DeclContext *SemanticContext = CurContext; + if (SS.isNotEmpty() && !SS.isInvalid()) { + SemanticContext = computeDeclContext(SS); + + // FIXME: need to match up several levels of template parameter lists here. + } + + // FIXME: member templates! + TemplateParameterList *TemplateParams + = static_cast<TemplateParameterList *>(*TemplateParameterLists.release()); + + // If there is a previous declaration with the same name, check + // whether this is a valid redeclaration. + ClassTemplateDecl *PrevClassTemplate + = dyn_cast_or_null<ClassTemplateDecl>(PrevDecl); + if (PrevClassTemplate) { + // Ensure that the template parameter lists are compatible. + if (!TemplateParameterListsAreEqual(TemplateParams, + PrevClassTemplate->getTemplateParameters(), + /*Complain=*/true)) + return true; + + // C++ [temp.class]p4: + // In a redeclaration, partial specialization, explicit + // specialization or explicit instantiation of a class template, + // the class-key shall agree in kind with the original class + // template declaration (7.1.5.3). + RecordDecl *PrevRecordDecl = PrevClassTemplate->getTemplatedDecl(); + if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind, KWLoc, *Name)) { + Diag(KWLoc, diag::err_use_with_wrong_tag) + << Name + << CodeModificationHint::CreateReplacement(KWLoc, + PrevRecordDecl->getKindName()); + Diag(PrevRecordDecl->getLocation(), diag::note_previous_use); + Kind = PrevRecordDecl->getTagKind(); + } + + // Check for redefinition of this class template. + if (TK == TK_Definition) { + if (TagDecl *Def = PrevRecordDecl->getDefinition(Context)) { + Diag(NameLoc, diag::err_redefinition) << Name; + Diag(Def->getLocation(), diag::note_previous_definition); + // FIXME: Would it make sense to try to "forget" the previous + // definition, as part of error recovery? + return true; + } + } + } else if (PrevDecl && PrevDecl->isTemplateParameter()) { + // Maybe we will complain about the shadowed template parameter. + DiagnoseTemplateParameterShadow(NameLoc, PrevDecl); + // Just pretend that we didn't see the previous declaration. + PrevDecl = 0; + } else if (PrevDecl) { + // C++ [temp]p5: + // A class template shall not have the same name as any other + // template, class, function, object, enumeration, enumerator, + // namespace, or type in the same scope (3.3), except as specified + // in (14.5.4). + Diag(NameLoc, diag::err_redefinition_different_kind) << Name; + Diag(PrevDecl->getLocation(), diag::note_previous_definition); + return true; + } + + // Check the template parameter list of this declaration, possibly + // merging in the template parameter list from the previous class + // template declaration. + if (CheckTemplateParameterList(TemplateParams, + PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0)) + Invalid = true; + + // FIXME: If we had a scope specifier, we better have a previous template + // declaration! + + CXXRecordDecl *NewClass = + CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name, + PrevClassTemplate? + PrevClassTemplate->getTemplatedDecl() : 0, + /*DelayTypeCreation=*/true); + + ClassTemplateDecl *NewTemplate + = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc, + DeclarationName(Name), TemplateParams, + NewClass, PrevClassTemplate); + NewClass->setDescribedClassTemplate(NewTemplate); + + // Build the type for the class template declaration now. + QualType T = + Context.getTypeDeclType(NewClass, + PrevClassTemplate? + PrevClassTemplate->getTemplatedDecl() : 0); + assert(T->isDependentType() && "Class template type is not dependent?"); + (void)T; + + // Set the access specifier. + SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS); + + // Set the lexical context of these templates + NewClass->setLexicalDeclContext(CurContext); + NewTemplate->setLexicalDeclContext(CurContext); + + if (TK == TK_Definition) + NewClass->startDefinition(); + + if (Attr) + ProcessDeclAttributeList(NewClass, Attr); + + PushOnScopeChains(NewTemplate, S); + + if (Invalid) { + NewTemplate->setInvalidDecl(); + NewClass->setInvalidDecl(); + } + return DeclPtrTy::make(NewTemplate); +} + +/// \brief Checks the validity of a template parameter list, possibly +/// considering the template parameter list from a previous +/// declaration. +/// +/// If an "old" template parameter list is provided, it must be +/// equivalent (per TemplateParameterListsAreEqual) to the "new" +/// template parameter list. +/// +/// \param NewParams Template parameter list for a new template +/// declaration. This template parameter list will be updated with any +/// default arguments that are carried through from the previous +/// template parameter list. +/// +/// \param OldParams If provided, template parameter list from a +/// previous declaration of the same template. Default template +/// arguments will be merged from the old template parameter list to +/// the new template parameter list. +/// +/// \returns true if an error occurred, false otherwise. +bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, + TemplateParameterList *OldParams) { + bool Invalid = false; + + // C++ [temp.param]p10: + // The set of default template-arguments available for use with a + // template declaration or definition is obtained by merging the + // default arguments from the definition (if in scope) and all + // declarations in scope in the same way default function + // arguments are (8.3.6). + bool SawDefaultArgument = false; + SourceLocation PreviousDefaultArgLoc; + + // Dummy initialization to avoid warnings. + TemplateParameterList::iterator OldParam = NewParams->end(); + if (OldParams) + OldParam = OldParams->begin(); + + for (TemplateParameterList::iterator NewParam = NewParams->begin(), + NewParamEnd = NewParams->end(); + NewParam != NewParamEnd; ++NewParam) { + // Variables used to diagnose redundant default arguments + bool RedundantDefaultArg = false; + SourceLocation OldDefaultLoc; + SourceLocation NewDefaultLoc; + + // Variables used to diagnose missing default arguments + bool MissingDefaultArg = false; + + // Merge default arguments for template type parameters. + if (TemplateTypeParmDecl *NewTypeParm + = dyn_cast<TemplateTypeParmDecl>(*NewParam)) { + TemplateTypeParmDecl *OldTypeParm + = OldParams? cast<TemplateTypeParmDecl>(*OldParam) : 0; + + if (OldTypeParm && OldTypeParm->hasDefaultArgument() && + NewTypeParm->hasDefaultArgument()) { + OldDefaultLoc = OldTypeParm->getDefaultArgumentLoc(); + NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc(); + SawDefaultArgument = true; + RedundantDefaultArg = true; + PreviousDefaultArgLoc = NewDefaultLoc; + } else if (OldTypeParm && OldTypeParm->hasDefaultArgument()) { + // Merge the default argument from the old declaration to the + // new declaration. + SawDefaultArgument = true; + NewTypeParm->setDefaultArgument(OldTypeParm->getDefaultArgument(), + OldTypeParm->getDefaultArgumentLoc(), + true); + PreviousDefaultArgLoc = OldTypeParm->getDefaultArgumentLoc(); + } else if (NewTypeParm->hasDefaultArgument()) { + SawDefaultArgument = true; + PreviousDefaultArgLoc = NewTypeParm->getDefaultArgumentLoc(); + } else if (SawDefaultArgument) + MissingDefaultArg = true; + } + // Merge default arguments for non-type template parameters + else if (NonTypeTemplateParmDecl *NewNonTypeParm + = dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) { + NonTypeTemplateParmDecl *OldNonTypeParm + = OldParams? cast<NonTypeTemplateParmDecl>(*OldParam) : 0; + if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() && + NewNonTypeParm->hasDefaultArgument()) { + OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc(); + NewDefaultLoc = NewNonTypeParm->getDefaultArgumentLoc(); + SawDefaultArgument = true; + RedundantDefaultArg = true; + PreviousDefaultArgLoc = NewDefaultLoc; + } else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument()) { + // Merge the default argument from the old declaration to the + // new declaration. + SawDefaultArgument = true; + // FIXME: We need to create a new kind of "default argument" + // expression that points to a previous template template + // parameter. + NewNonTypeParm->setDefaultArgument( + OldNonTypeParm->getDefaultArgument()); + PreviousDefaultArgLoc = OldNonTypeParm->getDefaultArgumentLoc(); + } else if (NewNonTypeParm->hasDefaultArgument()) { + SawDefaultArgument = true; + PreviousDefaultArgLoc = NewNonTypeParm->getDefaultArgumentLoc(); + } else if (SawDefaultArgument) + MissingDefaultArg = true; + } + // Merge default arguments for template template parameters + else { + TemplateTemplateParmDecl *NewTemplateParm + = cast<TemplateTemplateParmDecl>(*NewParam); + TemplateTemplateParmDecl *OldTemplateParm + = OldParams? cast<TemplateTemplateParmDecl>(*OldParam) : 0; + if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() && + NewTemplateParm->hasDefaultArgument()) { + OldDefaultLoc = OldTemplateParm->getDefaultArgumentLoc(); + NewDefaultLoc = NewTemplateParm->getDefaultArgumentLoc(); + SawDefaultArgument = true; + RedundantDefaultArg = true; + PreviousDefaultArgLoc = NewDefaultLoc; + } else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument()) { + // Merge the default argument from the old declaration to the + // new declaration. + SawDefaultArgument = true; + // FIXME: We need to create a new kind of "default argument" expression + // that points to a previous template template parameter. + NewTemplateParm->setDefaultArgument( + OldTemplateParm->getDefaultArgument()); + PreviousDefaultArgLoc = OldTemplateParm->getDefaultArgumentLoc(); + } else if (NewTemplateParm->hasDefaultArgument()) { + SawDefaultArgument = true; + PreviousDefaultArgLoc = NewTemplateParm->getDefaultArgumentLoc(); + } else if (SawDefaultArgument) + MissingDefaultArg = true; + } + + if (RedundantDefaultArg) { + // C++ [temp.param]p12: + // A template-parameter shall not be given default arguments + // by two different declarations in the same scope. + Diag(NewDefaultLoc, diag::err_template_param_default_arg_redefinition); + Diag(OldDefaultLoc, diag::note_template_param_prev_default_arg); + Invalid = true; + } else if (MissingDefaultArg) { + // C++ [temp.param]p11: + // If a template-parameter has a default template-argument, + // all subsequent template-parameters shall have a default + // template-argument supplied. + Diag((*NewParam)->getLocation(), + diag::err_template_param_default_arg_missing); + Diag(PreviousDefaultArgLoc, diag::note_template_param_prev_default_arg); + Invalid = true; + } + + // If we have an old template parameter list that we're merging + // in, move on to the next parameter. + if (OldParams) + ++OldParam; + } + + return Invalid; +} + +/// \brief Translates template arguments as provided by the parser +/// into template arguments used by semantic analysis. +static void +translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, + SourceLocation *TemplateArgLocs, + llvm::SmallVector<TemplateArgument, 16> &TemplateArgs) { + TemplateArgs.reserve(TemplateArgsIn.size()); + + void **Args = TemplateArgsIn.getArgs(); + bool *ArgIsType = TemplateArgsIn.getArgIsType(); + for (unsigned Arg = 0, Last = TemplateArgsIn.size(); Arg != Last; ++Arg) { + TemplateArgs.push_back( + ArgIsType[Arg]? TemplateArgument(TemplateArgLocs[Arg], + QualType::getFromOpaquePtr(Args[Arg])) + : TemplateArgument(reinterpret_cast<Expr *>(Args[Arg]))); + } +} + +/// \brief Build a canonical version of a template argument list. +/// +/// This function builds a canonical version of the given template +/// argument list, where each of the template arguments has been +/// converted into its canonical form. This routine is typically used +/// to canonicalize a template argument list when the template name +/// itself is dependent. When the template name refers to an actual +/// template declaration, Sema::CheckTemplateArgumentList should be +/// used to check and canonicalize the template arguments. +/// +/// \param TemplateArgs The incoming template arguments. +/// +/// \param NumTemplateArgs The number of template arguments in \p +/// TemplateArgs. +/// +/// \param Canonical A vector to be filled with the canonical versions +/// of the template arguments. +/// +/// \param Context The ASTContext in which the template arguments live. +static void CanonicalizeTemplateArguments(const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + llvm::SmallVectorImpl<TemplateArgument> &Canonical, + ASTContext &Context) { + Canonical.reserve(NumTemplateArgs); + for (unsigned Idx = 0; Idx < NumTemplateArgs; ++Idx) { + switch (TemplateArgs[Idx].getKind()) { + case TemplateArgument::Expression: + // FIXME: Build canonical expression (!) + Canonical.push_back(TemplateArgs[Idx]); + break; + + case TemplateArgument::Declaration: + Canonical.push_back( + TemplateArgument(SourceLocation(), + Context.getCanonicalDecl(TemplateArgs[Idx].getAsDecl()))); + break; + + case TemplateArgument::Integral: + Canonical.push_back(TemplateArgument(SourceLocation(), + *TemplateArgs[Idx].getAsIntegral(), + TemplateArgs[Idx].getIntegralType())); + + case TemplateArgument::Type: { + QualType CanonType + = Context.getCanonicalType(TemplateArgs[Idx].getAsType()); + Canonical.push_back(TemplateArgument(SourceLocation(), CanonType)); + } + } + } +} + +QualType Sema::CheckTemplateIdType(TemplateName Name, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceLocation RAngleLoc) { + TemplateDecl *Template = Name.getAsTemplateDecl(); + if (!Template) { + // The template name does not resolve to a template, so we just + // build a dependent template-id type. + + // Canonicalize the template arguments to build the canonical + // template-id type. + llvm::SmallVector<TemplateArgument, 16> CanonicalTemplateArgs; + CanonicalizeTemplateArguments(TemplateArgs, NumTemplateArgs, + CanonicalTemplateArgs, Context); + + TemplateName CanonName = Context.getCanonicalTemplateName(Name); + QualType CanonType + = Context.getTemplateSpecializationType(CanonName, + &CanonicalTemplateArgs[0], + CanonicalTemplateArgs.size()); + + // Build the dependent template-id type. + return Context.getTemplateSpecializationType(Name, TemplateArgs, + NumTemplateArgs, CanonType); + } + + // Check that the template argument list is well-formed for this + // template. + llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs; + if (CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc, + TemplateArgs, NumTemplateArgs, RAngleLoc, + ConvertedTemplateArgs)) + return QualType(); + + assert((ConvertedTemplateArgs.size() == + Template->getTemplateParameters()->size()) && + "Converted template argument list is too short!"); + + QualType CanonType; + + if (TemplateSpecializationType::anyDependentTemplateArguments( + TemplateArgs, + NumTemplateArgs)) { + // This class template specialization is a dependent + // type. Therefore, its canonical type is another class template + // specialization type that contains all of the converted + // arguments in canonical form. This ensures that, e.g., A<T> and + // A<T, T> have identical types when A is declared as: + // + // template<typename T, typename U = T> struct A; + TemplateName CanonName = Context.getCanonicalTemplateName(Name); + CanonType = Context.getTemplateSpecializationType(CanonName, + &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size()); + } else if (ClassTemplateDecl *ClassTemplate + = dyn_cast<ClassTemplateDecl>(Template)) { + // Find the class template specialization declaration that + // corresponds to these arguments. + llvm::FoldingSetNodeID ID; + ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size()); + void *InsertPos = 0; + ClassTemplateSpecializationDecl *Decl + = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos); + if (!Decl) { + // This is the first time we have referenced this class template + // specialization. Create the canonical declaration and add it to + // the set of specializations. + Decl = ClassTemplateSpecializationDecl::Create(Context, + ClassTemplate->getDeclContext(), + TemplateLoc, + ClassTemplate, + &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size(), + 0); + ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos); + Decl->setLexicalDeclContext(CurContext); + } + + CanonType = Context.getTypeDeclType(Decl); + } + + // Build the fully-sugared type for this class template + // specialization, which refers back to the class template + // specialization we created or found. + return Context.getTemplateSpecializationType(Name, TemplateArgs, + NumTemplateArgs, CanonType); +} + +Action::TypeResult +Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgsIn, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc) { + TemplateName Template = TemplateD.getAsVal<TemplateName>(); + + // Translate the parser's template argument list in our AST format. + llvm::SmallVector<TemplateArgument, 16> TemplateArgs; + translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); + + QualType Result = CheckTemplateIdType(Template, TemplateLoc, LAngleLoc, + TemplateArgs.data(), + TemplateArgs.size(), + RAngleLoc); + TemplateArgsIn.release(); + + if (Result.isNull()) + return true; + + return Result.getAsOpaquePtr(); +} + +/// \brief Form a dependent template name. +/// +/// This action forms a dependent template name given the template +/// name and its (presumably dependent) scope specifier. For +/// example, given "MetaFun::template apply", the scope specifier \p +/// SS will be "MetaFun::", \p TemplateKWLoc contains the location +/// of the "template" keyword, and "apply" is the \p Name. +Sema::TemplateTy +Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, + const IdentifierInfo &Name, + SourceLocation NameLoc, + const CXXScopeSpec &SS) { + if (!SS.isSet() || SS.isInvalid()) + return TemplateTy(); + + NestedNameSpecifier *Qualifier + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + + // FIXME: member of the current instantiation + + if (!Qualifier->isDependent()) { + // C++0x [temp.names]p5: + // If a name prefixed by the keyword template is not the name of + // a template, the program is ill-formed. [Note: the keyword + // template may not be applied to non-template members of class + // templates. -end note ] [ Note: as is the case with the + // typename prefix, the template prefix is allowed in cases + // where it is not strictly necessary; i.e., when the + // nested-name-specifier or the expression on the left of the -> + // or . is not dependent on a template-parameter, or the use + // does not appear in the scope of a template. -end note] + // + // Note: C++03 was more strict here, because it banned the use of + // the "template" keyword prior to a template-name that was not a + // dependent name. C++ DR468 relaxed this requirement (the + // "template" keyword is now permitted). We follow the C++0x + // rules, even in C++03 mode, retroactively applying the DR. + TemplateTy Template; + TemplateNameKind TNK = isTemplateName(Name, 0, Template, &SS); + if (TNK == TNK_Non_template) { + Diag(NameLoc, diag::err_template_kw_refers_to_non_template) + << &Name; + return TemplateTy(); + } + + return Template; + } + + return TemplateTy::make(Context.getDependentTemplateName(Qualifier, &Name)); +} + +/// \brief Check that the given template argument list is well-formed +/// for specializing the given template. +bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceLocation RAngleLoc, + llvm::SmallVectorImpl<TemplateArgument> &Converted) { + TemplateParameterList *Params = Template->getTemplateParameters(); + unsigned NumParams = Params->size(); + unsigned NumArgs = NumTemplateArgs; + bool Invalid = false; + + if (NumArgs > NumParams || + NumArgs < Params->getMinRequiredArguments()) { + // FIXME: point at either the first arg beyond what we can handle, + // or the '>', depending on whether we have too many or too few + // arguments. + SourceRange Range; + if (NumArgs > NumParams) + Range = SourceRange(TemplateArgs[NumParams].getLocation(), RAngleLoc); + Diag(TemplateLoc, diag::err_template_arg_list_different_arity) + << (NumArgs > NumParams) + << (isa<ClassTemplateDecl>(Template)? 0 : + isa<FunctionTemplateDecl>(Template)? 1 : + isa<TemplateTemplateParmDecl>(Template)? 2 : 3) + << Template << Range; + Diag(Template->getLocation(), diag::note_template_decl_here) + << Params->getSourceRange(); + Invalid = true; + } + + // C++ [temp.arg]p1: + // [...] The type and form of each template-argument specified in + // a template-id shall match the type and form specified for the + // corresponding parameter declared by the template in its + // template-parameter-list. + unsigned ArgIdx = 0; + for (TemplateParameterList::iterator Param = Params->begin(), + ParamEnd = Params->end(); + Param != ParamEnd; ++Param, ++ArgIdx) { + // Decode the template argument + TemplateArgument Arg; + if (ArgIdx >= NumArgs) { + // Retrieve the default template argument from the template + // parameter. + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) { + if (!TTP->hasDefaultArgument()) + break; + + QualType ArgType = TTP->getDefaultArgument(); + + // If the argument type is dependent, instantiate it now based + // on the previously-computed template arguments. + if (ArgType->isDependentType()) { + InstantiatingTemplate Inst(*this, TemplateLoc, + Template, &Converted[0], + Converted.size(), + SourceRange(TemplateLoc, RAngleLoc)); + + TemplateArgumentList TemplateArgs(Context, &Converted[0], + Converted.size(), + /*CopyArgs=*/false); + ArgType = InstantiateType(ArgType, TemplateArgs, + TTP->getDefaultArgumentLoc(), + TTP->getDeclName()); + } + + if (ArgType.isNull()) + return true; + + Arg = TemplateArgument(TTP->getLocation(), ArgType); + } else if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { + if (!NTTP->hasDefaultArgument()) + break; + + // FIXME: Instantiate default argument + Arg = TemplateArgument(NTTP->getDefaultArgument()); + } else { + TemplateTemplateParmDecl *TempParm + = cast<TemplateTemplateParmDecl>(*Param); + + if (!TempParm->hasDefaultArgument()) + break; + + // FIXME: Instantiate default argument + Arg = TemplateArgument(TempParm->getDefaultArgument()); + } + } else { + // Retrieve the template argument produced by the user. + Arg = TemplateArgs[ArgIdx]; + } + + + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) { + // Check template type parameters. + if (Arg.getKind() == TemplateArgument::Type) { + if (CheckTemplateArgument(TTP, Arg.getAsType(), Arg.getLocation())) + Invalid = true; + + // Add the converted template type argument. + Converted.push_back( + TemplateArgument(Arg.getLocation(), + Context.getCanonicalType(Arg.getAsType()))); + continue; + } + + // C++ [temp.arg.type]p1: + // A template-argument for a template-parameter which is a + // type shall be a type-id. + + // We have a template type parameter but the template argument + // is not a type. + Diag(Arg.getLocation(), diag::err_template_arg_must_be_type); + Diag((*Param)->getLocation(), diag::note_template_param_here); + Invalid = true; + } else if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { + // Check non-type template parameters. + + // Instantiate the type of the non-type template parameter with + // the template arguments we've seen thus far. + QualType NTTPType = NTTP->getType(); + if (NTTPType->isDependentType()) { + // Instantiate the type of the non-type template parameter. + InstantiatingTemplate Inst(*this, TemplateLoc, + Template, &Converted[0], + Converted.size(), + SourceRange(TemplateLoc, RAngleLoc)); + + TemplateArgumentList TemplateArgs(Context, &Converted[0], + Converted.size(), + /*CopyArgs=*/false); + NTTPType = InstantiateType(NTTPType, TemplateArgs, + NTTP->getLocation(), + NTTP->getDeclName()); + // If that worked, check the non-type template parameter type + // for validity. + if (!NTTPType.isNull()) + NTTPType = CheckNonTypeTemplateParameterType(NTTPType, + NTTP->getLocation()); + + if (NTTPType.isNull()) { + Invalid = true; + break; + } + } + + switch (Arg.getKind()) { + case TemplateArgument::Expression: { + Expr *E = Arg.getAsExpr(); + if (CheckTemplateArgument(NTTP, NTTPType, E, &Converted)) + Invalid = true; + break; + } + + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + // We've already checked this template argument, so just copy + // it to the list of converted arguments. + Converted.push_back(Arg); + break; + + case TemplateArgument::Type: + // We have a non-type template parameter but the template + // argument is a type. + + // C++ [temp.arg]p2: + // In a template-argument, an ambiguity between a type-id and + // an expression is resolved to a type-id, regardless of the + // form of the corresponding template-parameter. + // + // We warn specifically about this case, since it can be rather + // confusing for users. + if (Arg.getAsType()->isFunctionType()) + Diag(Arg.getLocation(), diag::err_template_arg_nontype_ambig) + << Arg.getAsType(); + else + Diag(Arg.getLocation(), diag::err_template_arg_must_be_expr); + Diag((*Param)->getLocation(), diag::note_template_param_here); + Invalid = true; + } + } else { + // Check template template parameters. + TemplateTemplateParmDecl *TempParm + = cast<TemplateTemplateParmDecl>(*Param); + + switch (Arg.getKind()) { + case TemplateArgument::Expression: { + Expr *ArgExpr = Arg.getAsExpr(); + if (ArgExpr && isa<DeclRefExpr>(ArgExpr) && + isa<TemplateDecl>(cast<DeclRefExpr>(ArgExpr)->getDecl())) { + if (CheckTemplateArgument(TempParm, cast<DeclRefExpr>(ArgExpr))) + Invalid = true; + + // Add the converted template argument. + Decl *D + = Context.getCanonicalDecl(cast<DeclRefExpr>(ArgExpr)->getDecl()); + Converted.push_back(TemplateArgument(Arg.getLocation(), D)); + continue; + } + } + // fall through + + case TemplateArgument::Type: { + // We have a template template parameter but the template + // argument does not refer to a template. + Diag(Arg.getLocation(), diag::err_template_arg_must_be_template); + Invalid = true; + break; + } + + case TemplateArgument::Declaration: + // We've already checked this template argument, so just copy + // it to the list of converted arguments. + Converted.push_back(Arg); + break; + + case TemplateArgument::Integral: + assert(false && "Integral argument with template template parameter"); + break; + } + } + } + + return Invalid; +} + +/// \brief Check a template argument against its corresponding +/// template type parameter. +/// +/// This routine implements the semantics of C++ [temp.arg.type]. It +/// returns true if an error occurred, and false otherwise. +bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, + QualType Arg, SourceLocation ArgLoc) { + // C++ [temp.arg.type]p2: + // A local type, a type with no linkage, an unnamed type or a type + // compounded from any of these types shall not be used as a + // template-argument for a template type-parameter. + // + // FIXME: Perform the recursive and no-linkage type checks. + const TagType *Tag = 0; + if (const EnumType *EnumT = Arg->getAsEnumType()) + Tag = EnumT; + else if (const RecordType *RecordT = Arg->getAsRecordType()) + Tag = RecordT; + if (Tag && Tag->getDecl()->getDeclContext()->isFunctionOrMethod()) + return Diag(ArgLoc, diag::err_template_arg_local_type) + << QualType(Tag, 0); + else if (Tag && !Tag->getDecl()->getDeclName() && + !Tag->getDecl()->getTypedefForAnonDecl()) { + Diag(ArgLoc, diag::err_template_arg_unnamed_type); + Diag(Tag->getDecl()->getLocation(), diag::note_template_unnamed_type_here); + return true; + } + + return false; +} + +/// \brief Checks whether the given template argument is the address +/// of an object or function according to C++ [temp.arg.nontype]p1. +bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, + NamedDecl *&Entity) { + bool Invalid = false; + + // See through any implicit casts we added to fix the type. + if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg)) + Arg = Cast->getSubExpr(); + + // C++0x allows nullptr, and there's no further checking to be done for that. + if (Arg->getType()->isNullPtrType()) + return false; + + // C++ [temp.arg.nontype]p1: + // + // A template-argument for a non-type, non-template + // template-parameter shall be one of: [...] + // + // -- the address of an object or function with external + // linkage, including function templates and function + // template-ids but excluding non-static class members, + // expressed as & id-expression where the & is optional if + // the name refers to a function or array, or if the + // corresponding template-parameter is a reference; or + DeclRefExpr *DRE = 0; + + // Ignore (and complain about) any excess parentheses. + while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) { + if (!Invalid) { + Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_extra_parens) + << Arg->getSourceRange(); + Invalid = true; + } + + Arg = Parens->getSubExpr(); + } + + if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) { + if (UnOp->getOpcode() == UnaryOperator::AddrOf) + DRE = dyn_cast<DeclRefExpr>(UnOp->getSubExpr()); + } else + DRE = dyn_cast<DeclRefExpr>(Arg); + + if (!DRE || !isa<ValueDecl>(DRE->getDecl())) + return Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_not_object_or_func_form) + << Arg->getSourceRange(); + + // Cannot refer to non-static data members + if (FieldDecl *Field = dyn_cast<FieldDecl>(DRE->getDecl())) + return Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_field) + << Field << Arg->getSourceRange(); + + // Cannot refer to non-static member functions + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(DRE->getDecl())) + if (!Method->isStatic()) + return Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_method) + << Method << Arg->getSourceRange(); + + // Functions must have external linkage. + if (FunctionDecl *Func = dyn_cast<FunctionDecl>(DRE->getDecl())) { + if (Func->getStorageClass() == FunctionDecl::Static) { + Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_function_not_extern) + << Func << Arg->getSourceRange(); + Diag(Func->getLocation(), diag::note_template_arg_internal_object) + << true; + return true; + } + + // Okay: we've named a function with external linkage. + Entity = Func; + return Invalid; + } + + if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) { + if (!Var->hasGlobalStorage()) { + Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_object_not_extern) + << Var << Arg->getSourceRange(); + Diag(Var->getLocation(), diag::note_template_arg_internal_object) + << true; + return true; + } + + // Okay: we've named an object with external linkage + Entity = Var; + return Invalid; + } + + // We found something else, but we don't know specifically what it is. + Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_not_object_or_func) + << Arg->getSourceRange(); + Diag(DRE->getDecl()->getLocation(), + diag::note_template_arg_refers_here); + return true; +} + +/// \brief Checks whether the given template argument is a pointer to +/// member constant according to C++ [temp.arg.nontype]p1. +bool +Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { + bool Invalid = false; + + // See through any implicit casts we added to fix the type. + if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg)) + Arg = Cast->getSubExpr(); + + // C++0x allows nullptr, and there's no further checking to be done for that. + if (Arg->getType()->isNullPtrType()) + return false; + + // C++ [temp.arg.nontype]p1: + // + // A template-argument for a non-type, non-template + // template-parameter shall be one of: [...] + // + // -- a pointer to member expressed as described in 5.3.1. + QualifiedDeclRefExpr *DRE = 0; + + // Ignore (and complain about) any excess parentheses. + while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) { + if (!Invalid) { + Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_extra_parens) + << Arg->getSourceRange(); + Invalid = true; + } + + Arg = Parens->getSubExpr(); + } + + if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) + if (UnOp->getOpcode() == UnaryOperator::AddrOf) + DRE = dyn_cast<QualifiedDeclRefExpr>(UnOp->getSubExpr()); + + if (!DRE) + return Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_not_pointer_to_member_form) + << Arg->getSourceRange(); + + if (isa<FieldDecl>(DRE->getDecl()) || isa<CXXMethodDecl>(DRE->getDecl())) { + assert((isa<FieldDecl>(DRE->getDecl()) || + !cast<CXXMethodDecl>(DRE->getDecl())->isStatic()) && + "Only non-static member pointers can make it here"); + + // Okay: this is the address of a non-static member, and therefore + // a member pointer constant. + Member = DRE->getDecl(); + return Invalid; + } + + // We found something else, but we don't know specifically what it is. + Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_not_pointer_to_member_form) + << Arg->getSourceRange(); + Diag(DRE->getDecl()->getLocation(), + diag::note_template_arg_refers_here); + return true; +} + +/// \brief Check a template argument against its corresponding +/// non-type template parameter. +/// +/// This routine implements the semantics of C++ [temp.arg.nontype]. +/// It returns true if an error occurred, and false otherwise. \p +/// InstantiatedParamType is the type of the non-type template +/// parameter after it has been instantiated. +/// +/// If Converted is non-NULL and no errors occur, the value +/// of this argument will be added to the end of the Converted vector. +bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, + QualType InstantiatedParamType, Expr *&Arg, + llvm::SmallVectorImpl<TemplateArgument> *Converted) { + SourceLocation StartLoc = Arg->getSourceRange().getBegin(); + + // If either the parameter has a dependent type or the argument is + // type-dependent, there's nothing we can check now. + // FIXME: Add template argument to Converted! + if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent()) { + // FIXME: Produce a cloned, canonical expression? + Converted->push_back(TemplateArgument(Arg)); + return false; + } + + // C++ [temp.arg.nontype]p5: + // The following conversions are performed on each expression used + // as a non-type template-argument. If a non-type + // template-argument cannot be converted to the type of the + // corresponding template-parameter then the program is + // ill-formed. + // + // -- for a non-type template-parameter of integral or + // enumeration type, integral promotions (4.5) and integral + // conversions (4.7) are applied. + QualType ParamType = InstantiatedParamType; + QualType ArgType = Arg->getType(); + if (ParamType->isIntegralType() || ParamType->isEnumeralType()) { + // C++ [temp.arg.nontype]p1: + // A template-argument for a non-type, non-template + // template-parameter shall be one of: + // + // -- an integral constant-expression of integral or enumeration + // type; or + // -- the name of a non-type template-parameter; or + SourceLocation NonConstantLoc; + llvm::APSInt Value; + if (!ArgType->isIntegralType() && !ArgType->isEnumeralType()) { + Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_not_integral_or_enumeral) + << ArgType << Arg->getSourceRange(); + Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } else if (!Arg->isValueDependent() && + !Arg->isIntegerConstantExpr(Value, Context, &NonConstantLoc)) { + Diag(NonConstantLoc, diag::err_template_arg_not_ice) + << ArgType << Arg->getSourceRange(); + return true; + } + + // FIXME: We need some way to more easily get the unqualified form + // of the types without going all the way to the + // canonical type. + if (Context.getCanonicalType(ParamType).getCVRQualifiers()) + ParamType = Context.getCanonicalType(ParamType).getUnqualifiedType(); + if (Context.getCanonicalType(ArgType).getCVRQualifiers()) + ArgType = Context.getCanonicalType(ArgType).getUnqualifiedType(); + + // Try to convert the argument to the parameter's type. + if (ParamType == ArgType) { + // Okay: no conversion necessary + } else if (IsIntegralPromotion(Arg, ArgType, ParamType) || + !ParamType->isEnumeralType()) { + // This is an integral promotion or conversion. + ImpCastExprToType(Arg, ParamType); + } else { + // We can't perform this conversion. + Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_not_convertible) + << Arg->getType() << InstantiatedParamType << Arg->getSourceRange(); + Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + + QualType IntegerType = Context.getCanonicalType(ParamType); + if (const EnumType *Enum = IntegerType->getAsEnumType()) + IntegerType = Enum->getDecl()->getIntegerType(); + + if (!Arg->isValueDependent()) { + // Check that an unsigned parameter does not receive a negative + // value. + if (IntegerType->isUnsignedIntegerType() + && (Value.isSigned() && Value.isNegative())) { + Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_negative) + << Value.toString(10) << Param->getType() + << Arg->getSourceRange(); + Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + + // Check that we don't overflow the template parameter type. + unsigned AllowedBits = Context.getTypeSize(IntegerType); + if (Value.getActiveBits() > AllowedBits) { + Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_too_large) + << Value.toString(10) << Param->getType() + << Arg->getSourceRange(); + Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + + if (Value.getBitWidth() != AllowedBits) + Value.extOrTrunc(AllowedBits); + Value.setIsSigned(IntegerType->isSignedIntegerType()); + } + + if (Converted) { + // Add the value of this argument to the list of converted + // arguments. We use the bitwidth and signedness of the template + // parameter. + if (Arg->isValueDependent()) { + // The argument is value-dependent. Create a new + // TemplateArgument with the converted expression. + Converted->push_back(TemplateArgument(Arg)); + return false; + } + + Converted->push_back(TemplateArgument(StartLoc, Value, + ParamType->isEnumeralType() ? ParamType : IntegerType)); + } + + return false; + } + + // Handle pointer-to-function, reference-to-function, and + // pointer-to-member-function all in (roughly) the same way. + if (// -- For a non-type template-parameter of type pointer to + // function, only the function-to-pointer conversion (4.3) is + // applied. If the template-argument represents a set of + // overloaded functions (or a pointer to such), the matching + // function is selected from the set (13.4). + // In C++0x, any std::nullptr_t value can be converted. + (ParamType->isPointerType() && + ParamType->getAsPointerType()->getPointeeType()->isFunctionType()) || + // -- For a non-type template-parameter of type reference to + // function, no conversions apply. If the template-argument + // represents a set of overloaded functions, the matching + // function is selected from the set (13.4). + (ParamType->isReferenceType() && + ParamType->getAsReferenceType()->getPointeeType()->isFunctionType()) || + // -- For a non-type template-parameter of type pointer to + // member function, no conversions apply. If the + // template-argument represents a set of overloaded member + // functions, the matching member function is selected from + // the set (13.4). + // Again, C++0x allows a std::nullptr_t value. + (ParamType->isMemberPointerType() && + ParamType->getAsMemberPointerType()->getPointeeType() + ->isFunctionType())) { + if (Context.hasSameUnqualifiedType(ArgType, + ParamType.getNonReferenceType())) { + // We don't have to do anything: the types already match. + } else if (ArgType->isNullPtrType() && (ParamType->isPointerType() || + ParamType->isMemberPointerType())) { + ArgType = ParamType; + ImpCastExprToType(Arg, ParamType); + } else if (ArgType->isFunctionType() && ParamType->isPointerType()) { + ArgType = Context.getPointerType(ArgType); + ImpCastExprToType(Arg, ArgType); + } else if (FunctionDecl *Fn + = ResolveAddressOfOverloadedFunction(Arg, ParamType, true)) { + if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) + return true; + + FixOverloadedFunctionReference(Arg, Fn); + ArgType = Arg->getType(); + if (ArgType->isFunctionType() && ParamType->isPointerType()) { + ArgType = Context.getPointerType(Arg->getType()); + ImpCastExprToType(Arg, ArgType); + } + } + + if (!Context.hasSameUnqualifiedType(ArgType, + ParamType.getNonReferenceType())) { + // We can't perform this conversion. + Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_not_convertible) + << Arg->getType() << InstantiatedParamType << Arg->getSourceRange(); + Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + + if (ParamType->isMemberPointerType()) { + NamedDecl *Member = 0; + if (CheckTemplateArgumentPointerToMember(Arg, Member)) + return true; + + if (Converted) { + Member = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Member)); + Converted->push_back(TemplateArgument(StartLoc, Member)); + } + + return false; + } + + NamedDecl *Entity = 0; + if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) + return true; + + if (Converted) { + Entity = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Entity)); + Converted->push_back(TemplateArgument(StartLoc, Entity)); + } + return false; + } + + if (ParamType->isPointerType()) { + // -- for a non-type template-parameter of type pointer to + // object, qualification conversions (4.4) and the + // array-to-pointer conversion (4.2) are applied. + // C++0x also allows a value of std::nullptr_t. + assert(ParamType->getAsPointerType()->getPointeeType()->isObjectType() && + "Only object pointers allowed here"); + + if (ArgType->isNullPtrType()) { + ArgType = ParamType; + ImpCastExprToType(Arg, ParamType); + } else if (ArgType->isArrayType()) { + ArgType = Context.getArrayDecayedType(ArgType); + ImpCastExprToType(Arg, ArgType); + } + + if (IsQualificationConversion(ArgType, ParamType)) { + ArgType = ParamType; + ImpCastExprToType(Arg, ParamType); + } + + if (!Context.hasSameUnqualifiedType(ArgType, ParamType)) { + // We can't perform this conversion. + Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_not_convertible) + << Arg->getType() << InstantiatedParamType << Arg->getSourceRange(); + Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + + NamedDecl *Entity = 0; + if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) + return true; + + if (Converted) { + Entity = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Entity)); + Converted->push_back(TemplateArgument(StartLoc, Entity)); + } + + return false; + } + + if (const ReferenceType *ParamRefType = ParamType->getAsReferenceType()) { + // -- For a non-type template-parameter of type reference to + // object, no conversions apply. The type referred to by the + // reference may be more cv-qualified than the (otherwise + // identical) type of the template-argument. The + // template-parameter is bound directly to the + // template-argument, which must be an lvalue. + assert(ParamRefType->getPointeeType()->isObjectType() && + "Only object references allowed here"); + + if (!Context.hasSameUnqualifiedType(ParamRefType->getPointeeType(), ArgType)) { + Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_no_ref_bind) + << InstantiatedParamType << Arg->getType() + << Arg->getSourceRange(); + Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + + unsigned ParamQuals + = Context.getCanonicalType(ParamType).getCVRQualifiers(); + unsigned ArgQuals = Context.getCanonicalType(ArgType).getCVRQualifiers(); + + if ((ParamQuals | ArgQuals) != ParamQuals) { + Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_ref_bind_ignores_quals) + << InstantiatedParamType << Arg->getType() + << Arg->getSourceRange(); + Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + + NamedDecl *Entity = 0; + if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) + return true; + + if (Converted) { + Entity = cast<NamedDecl>(Context.getCanonicalDecl(Entity)); + Converted->push_back(TemplateArgument(StartLoc, Entity)); + } + + return false; + } + + // -- For a non-type template-parameter of type pointer to data + // member, qualification conversions (4.4) are applied. + // C++0x allows std::nullptr_t values. + assert(ParamType->isMemberPointerType() && "Only pointers to members remain"); + + if (Context.hasSameUnqualifiedType(ParamType, ArgType)) { + // Types match exactly: nothing more to do here. + } else if (ArgType->isNullPtrType()) { + ImpCastExprToType(Arg, ParamType); + } else if (IsQualificationConversion(ArgType, ParamType)) { + ImpCastExprToType(Arg, ParamType); + } else { + // We can't perform this conversion. + Diag(Arg->getSourceRange().getBegin(), + diag::err_template_arg_not_convertible) + << Arg->getType() << InstantiatedParamType << Arg->getSourceRange(); + Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + + NamedDecl *Member = 0; + if (CheckTemplateArgumentPointerToMember(Arg, Member)) + return true; + + if (Converted) { + Member = cast_or_null<NamedDecl>(Context.getCanonicalDecl(Member)); + Converted->push_back(TemplateArgument(StartLoc, Member)); + } + + return false; +} + +/// \brief Check a template argument against its corresponding +/// template template parameter. +/// +/// This routine implements the semantics of C++ [temp.arg.template]. +/// It returns true if an error occurred, and false otherwise. +bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, + DeclRefExpr *Arg) { + assert(isa<TemplateDecl>(Arg->getDecl()) && "Only template decls allowed"); + TemplateDecl *Template = cast<TemplateDecl>(Arg->getDecl()); + + // C++ [temp.arg.template]p1: + // A template-argument for a template template-parameter shall be + // the name of a class template, expressed as id-expression. Only + // primary class templates are considered when matching the + // template template argument with the corresponding parameter; + // partial specializations are not considered even if their + // parameter lists match that of the template template parameter. + if (!isa<ClassTemplateDecl>(Template)) { + assert(isa<FunctionTemplateDecl>(Template) && + "Only function templates are possible here"); + Diag(Arg->getSourceRange().getBegin(), + diag::note_template_arg_refers_here_func) + << Template; + } + + return !TemplateParameterListsAreEqual(Template->getTemplateParameters(), + Param->getTemplateParameters(), + true, true, + Arg->getSourceRange().getBegin()); +} + +/// \brief Determine whether the given template parameter lists are +/// equivalent. +/// +/// \param New The new template parameter list, typically written in the +/// source code as part of a new template declaration. +/// +/// \param Old The old template parameter list, typically found via +/// name lookup of the template declared with this template parameter +/// list. +/// +/// \param Complain If true, this routine will produce a diagnostic if +/// the template parameter lists are not equivalent. +/// +/// \param IsTemplateTemplateParm If true, this routine is being +/// called to compare the template parameter lists of a template +/// template parameter. +/// +/// \param TemplateArgLoc If this source location is valid, then we +/// are actually checking the template parameter list of a template +/// argument (New) against the template parameter list of its +/// corresponding template template parameter (Old). We produce +/// slightly different diagnostics in this scenario. +/// +/// \returns True if the template parameter lists are equal, false +/// otherwise. +bool +Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, + TemplateParameterList *Old, + bool Complain, + bool IsTemplateTemplateParm, + SourceLocation TemplateArgLoc) { + if (Old->size() != New->size()) { + if (Complain) { + unsigned NextDiag = diag::err_template_param_list_different_arity; + if (TemplateArgLoc.isValid()) { + Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch); + NextDiag = diag::note_template_param_list_different_arity; + } + Diag(New->getTemplateLoc(), NextDiag) + << (New->size() > Old->size()) + << IsTemplateTemplateParm + << SourceRange(New->getTemplateLoc(), New->getRAngleLoc()); + Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration) + << IsTemplateTemplateParm + << SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc()); + } + + return false; + } + + for (TemplateParameterList::iterator OldParm = Old->begin(), + OldParmEnd = Old->end(), NewParm = New->begin(); + OldParm != OldParmEnd; ++OldParm, ++NewParm) { + if ((*OldParm)->getKind() != (*NewParm)->getKind()) { + unsigned NextDiag = diag::err_template_param_different_kind; + if (TemplateArgLoc.isValid()) { + Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch); + NextDiag = diag::note_template_param_different_kind; + } + Diag((*NewParm)->getLocation(), NextDiag) + << IsTemplateTemplateParm; + Diag((*OldParm)->getLocation(), diag::note_template_prev_declaration) + << IsTemplateTemplateParm; + return false; + } + + if (isa<TemplateTypeParmDecl>(*OldParm)) { + // Okay; all template type parameters are equivalent (since we + // know we're at the same index). +#if 0 + // FIXME: Enable this code in debug mode *after* we properly go through + // and "instantiate" the template parameter lists of template template + // parameters. It's only after this instantiation that (1) any dependent + // types within the template parameter list of the template template + // parameter can be checked, and (2) the template type parameter depths + // will match up. + QualType OldParmType + = Context.getTypeDeclType(cast<TemplateTypeParmDecl>(*OldParm)); + QualType NewParmType + = Context.getTypeDeclType(cast<TemplateTypeParmDecl>(*NewParm)); + assert(Context.getCanonicalType(OldParmType) == + Context.getCanonicalType(NewParmType) && + "type parameter mismatch?"); +#endif + } else if (NonTypeTemplateParmDecl *OldNTTP + = dyn_cast<NonTypeTemplateParmDecl>(*OldParm)) { + // The types of non-type template parameters must agree. + NonTypeTemplateParmDecl *NewNTTP + = cast<NonTypeTemplateParmDecl>(*NewParm); + if (Context.getCanonicalType(OldNTTP->getType()) != + Context.getCanonicalType(NewNTTP->getType())) { + if (Complain) { + unsigned NextDiag = diag::err_template_nontype_parm_different_type; + if (TemplateArgLoc.isValid()) { + Diag(TemplateArgLoc, + diag::err_template_arg_template_params_mismatch); + NextDiag = diag::note_template_nontype_parm_different_type; + } + Diag(NewNTTP->getLocation(), NextDiag) + << NewNTTP->getType() + << IsTemplateTemplateParm; + Diag(OldNTTP->getLocation(), + diag::note_template_nontype_parm_prev_declaration) + << OldNTTP->getType(); + } + return false; + } + } else { + // The template parameter lists of template template + // parameters must agree. + // FIXME: Could we perform a faster "type" comparison here? + assert(isa<TemplateTemplateParmDecl>(*OldParm) && + "Only template template parameters handled here"); + TemplateTemplateParmDecl *OldTTP + = cast<TemplateTemplateParmDecl>(*OldParm); + TemplateTemplateParmDecl *NewTTP + = cast<TemplateTemplateParmDecl>(*NewParm); + if (!TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(), + OldTTP->getTemplateParameters(), + Complain, + /*IsTemplateTemplateParm=*/true, + TemplateArgLoc)) + return false; + } + } + + return true; +} + +/// \brief Check whether a template can be declared within this scope. +/// +/// If the template declaration is valid in this scope, returns +/// false. Otherwise, issues a diagnostic and returns true. +bool +Sema::CheckTemplateDeclScope(Scope *S, + MultiTemplateParamsArg &TemplateParameterLists) { + assert(TemplateParameterLists.size() > 0 && "Not a template"); + + // Find the nearest enclosing declaration scope. + while ((S->getFlags() & Scope::DeclScope) == 0 || + (S->getFlags() & Scope::TemplateParamScope) != 0) + S = S->getParent(); + + TemplateParameterList *TemplateParams = + static_cast<TemplateParameterList*>(*TemplateParameterLists.get()); + SourceLocation TemplateLoc = TemplateParams->getTemplateLoc(); + SourceRange TemplateRange + = SourceRange(TemplateLoc, TemplateParams->getRAngleLoc()); + + // C++ [temp]p2: + // A template-declaration can appear only as a namespace scope or + // class scope declaration. + DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity()); + while (Ctx && isa<LinkageSpecDecl>(Ctx)) { + if (cast<LinkageSpecDecl>(Ctx)->getLanguage() != LinkageSpecDecl::lang_cxx) + return Diag(TemplateLoc, diag::err_template_linkage) + << TemplateRange; + + Ctx = Ctx->getParent(); + } + + if (Ctx && (Ctx->isFileContext() || Ctx->isRecord())) + return false; + + return Diag(TemplateLoc, diag::err_template_outside_namespace_or_class_scope) + << TemplateRange; +} + +/// \brief Check whether a class template specialization or explicit +/// instantiation in the current context is well-formed. +/// +/// This routine determines whether a class template specialization or +/// explicit instantiation can be declared in the current context +/// (C++ [temp.expl.spec]p2, C++0x [temp.explicit]p2) and emits +/// appropriate diagnostics if there was an error. It returns true if +// there was an error that we cannot recover from, and false otherwise. +bool +Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate, + ClassTemplateSpecializationDecl *PrevDecl, + SourceLocation TemplateNameLoc, + SourceRange ScopeSpecifierRange, + bool ExplicitInstantiation) { + // C++ [temp.expl.spec]p2: + // An explicit specialization shall be declared in the namespace + // of which the template is a member, or, for member templates, in + // the namespace of which the enclosing class or enclosing class + // template is a member. An explicit specialization of a member + // function, member class or static data member of a class + // template shall be declared in the namespace of which the class + // template is a member. Such a declaration may also be a + // definition. If the declaration is not a definition, the + // specialization may be defined later in the name- space in which + // the explicit specialization was declared, or in a namespace + // that encloses the one in which the explicit specialization was + // declared. + if (CurContext->getLookupContext()->isFunctionOrMethod()) { + Diag(TemplateNameLoc, diag::err_template_spec_decl_function_scope) + << ExplicitInstantiation << ClassTemplate; + return true; + } + + DeclContext *DC = CurContext->getEnclosingNamespaceContext(); + DeclContext *TemplateContext + = ClassTemplate->getDeclContext()->getEnclosingNamespaceContext(); + if ((!PrevDecl || PrevDecl->getSpecializationKind() == TSK_Undeclared) && + !ExplicitInstantiation) { + // There is no prior declaration of this entity, so this + // specialization must be in the same context as the template + // itself. + if (DC != TemplateContext) { + if (isa<TranslationUnitDecl>(TemplateContext)) + Diag(TemplateNameLoc, diag::err_template_spec_decl_out_of_scope_global) + << ClassTemplate << ScopeSpecifierRange; + else if (isa<NamespaceDecl>(TemplateContext)) + Diag(TemplateNameLoc, diag::err_template_spec_decl_out_of_scope) + << ClassTemplate << cast<NamedDecl>(TemplateContext) + << ScopeSpecifierRange; + + Diag(ClassTemplate->getLocation(), diag::note_template_decl_here); + } + + return false; + } + + // We have a previous declaration of this entity. Make sure that + // this redeclaration (or definition) occurs in an enclosing namespace. + if (!CurContext->Encloses(TemplateContext)) { + // FIXME: In C++98, we would like to turn these errors into warnings, + // dependent on a -Wc++0x flag. + bool SuppressedDiag = false; + if (isa<TranslationUnitDecl>(TemplateContext)) { + if (!ExplicitInstantiation || getLangOptions().CPlusPlus0x) + Diag(TemplateNameLoc, diag::err_template_spec_redecl_global_scope) + << ExplicitInstantiation << ClassTemplate << ScopeSpecifierRange; + else + SuppressedDiag = true; + } else if (isa<NamespaceDecl>(TemplateContext)) { + if (!ExplicitInstantiation || getLangOptions().CPlusPlus0x) + Diag(TemplateNameLoc, diag::err_template_spec_redecl_out_of_scope) + << ExplicitInstantiation << ClassTemplate + << cast<NamedDecl>(TemplateContext) << ScopeSpecifierRange; + else + SuppressedDiag = true; + } + + if (!SuppressedDiag) + Diag(ClassTemplate->getLocation(), diag::note_template_decl_here); + } + + return false; +} + +Sema::DeclResult +Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, + SourceLocation KWLoc, + const CXXScopeSpec &SS, + TemplateTy TemplateD, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgsIn, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc, + AttributeList *Attr, + MultiTemplateParamsArg TemplateParameterLists) { + // Find the class template we're specializing + TemplateName Name = TemplateD.getAsVal<TemplateName>(); + ClassTemplateDecl *ClassTemplate + = cast<ClassTemplateDecl>(Name.getAsTemplateDecl()); + + bool isPartialSpecialization = false; + + // Check the validity of the template headers that introduce this + // template. + // FIXME: Once we have member templates, we'll need to check + // C++ [temp.expl.spec]p17-18, where we could have multiple levels of + // template<> headers. + if (TemplateParameterLists.size() == 0) + Diag(KWLoc, diag::err_template_spec_needs_header) + << CodeModificationHint::CreateInsertion(KWLoc, "template<> "); + else { + TemplateParameterList *TemplateParams + = static_cast<TemplateParameterList*>(*TemplateParameterLists.get()); + if (TemplateParameterLists.size() > 1) { + Diag(TemplateParams->getTemplateLoc(), + diag::err_template_spec_extra_headers); + return true; + } + + // FIXME: We'll need more checks, here! + if (TemplateParams->size() > 0) + isPartialSpecialization = true; + } + + // Check that the specialization uses the same tag kind as the + // original template. + TagDecl::TagKind Kind; + switch (TagSpec) { + default: assert(0 && "Unknown tag type!"); + case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break; + case DeclSpec::TST_union: Kind = TagDecl::TK_union; break; + case DeclSpec::TST_class: Kind = TagDecl::TK_class; break; + } + if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(), + Kind, KWLoc, + *ClassTemplate->getIdentifier())) { + Diag(KWLoc, diag::err_use_with_wrong_tag) + << ClassTemplate + << CodeModificationHint::CreateReplacement(KWLoc, + ClassTemplate->getTemplatedDecl()->getKindName()); + Diag(ClassTemplate->getTemplatedDecl()->getLocation(), + diag::note_previous_use); + Kind = ClassTemplate->getTemplatedDecl()->getTagKind(); + } + + // Translate the parser's template argument list in our AST format. + llvm::SmallVector<TemplateArgument, 16> TemplateArgs; + translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); + + // Check that the template argument list is well-formed for this + // template. + llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs; + if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc, + &TemplateArgs[0], TemplateArgs.size(), + RAngleLoc, ConvertedTemplateArgs)) + return true; + + assert((ConvertedTemplateArgs.size() == + ClassTemplate->getTemplateParameters()->size()) && + "Converted template argument list is too short!"); + + // Find the class template (partial) specialization declaration that + // corresponds to these arguments. + llvm::FoldingSetNodeID ID; + if (isPartialSpecialization) + // FIXME: Template parameter list matters, too + ClassTemplatePartialSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size()); + else + ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size()); + void *InsertPos = 0; + ClassTemplateSpecializationDecl *PrevDecl = 0; + + if (isPartialSpecialization) + PrevDecl + = ClassTemplate->getPartialSpecializations().FindNodeOrInsertPos(ID, + InsertPos); + else + PrevDecl + = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos); + + ClassTemplateSpecializationDecl *Specialization = 0; + + // Check whether we can declare a class template specialization in + // the current scope. + if (CheckClassTemplateSpecializationScope(ClassTemplate, PrevDecl, + TemplateNameLoc, + SS.getRange(), + /*ExplicitInstantiation=*/false)) + return true; + + if (PrevDecl && PrevDecl->getSpecializationKind() == TSK_Undeclared) { + // Since the only prior class template specialization with these + // arguments was referenced but not declared, reuse that + // declaration node as our own, updating its source location to + // reflect our new declaration. + Specialization = PrevDecl; + Specialization->setLocation(TemplateNameLoc); + PrevDecl = 0; + } else if (isPartialSpecialization) { + // FIXME: extra checking for partial specializations + + // Create a new class template partial specialization declaration node. + TemplateParameterList *TemplateParams + = static_cast<TemplateParameterList*>(*TemplateParameterLists.get()); + ClassTemplatePartialSpecializationDecl *PrevPartial + = cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl); + ClassTemplatePartialSpecializationDecl *Partial + = ClassTemplatePartialSpecializationDecl::Create(Context, + ClassTemplate->getDeclContext(), + TemplateNameLoc, + TemplateParams, + ClassTemplate, + &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size(), + PrevPartial); + + if (PrevPartial) { + ClassTemplate->getPartialSpecializations().RemoveNode(PrevPartial); + ClassTemplate->getPartialSpecializations().GetOrInsertNode(Partial); + } else { + ClassTemplate->getPartialSpecializations().InsertNode(Partial, InsertPos); + } + Specialization = Partial; + } else { + // Create a new class template specialization declaration node for + // this explicit specialization. + Specialization + = ClassTemplateSpecializationDecl::Create(Context, + ClassTemplate->getDeclContext(), + TemplateNameLoc, + ClassTemplate, + &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size(), + PrevDecl); + + if (PrevDecl) { + ClassTemplate->getSpecializations().RemoveNode(PrevDecl); + ClassTemplate->getSpecializations().GetOrInsertNode(Specialization); + } else { + ClassTemplate->getSpecializations().InsertNode(Specialization, + InsertPos); + } + } + + // Note that this is an explicit specialization. + Specialization->setSpecializationKind(TSK_ExplicitSpecialization); + + // Check that this isn't a redefinition of this specialization. + if (TK == TK_Definition) { + if (RecordDecl *Def = Specialization->getDefinition(Context)) { + // FIXME: Should also handle explicit specialization after implicit + // instantiation with a special diagnostic. + SourceRange Range(TemplateNameLoc, RAngleLoc); + Diag(TemplateNameLoc, diag::err_redefinition) + << Context.getTypeDeclType(Specialization) << Range; + Diag(Def->getLocation(), diag::note_previous_definition); + Specialization->setInvalidDecl(); + return true; + } + } + + // Build the fully-sugared type for this class template + // specialization as the user wrote in the specialization + // itself. This means that we'll pretty-print the type retrieved + // from the specialization's declaration the way that the user + // actually wrote the specialization, rather than formatting the + // name based on the "canonical" representation used to store the + // template arguments in the specialization. + QualType WrittenTy + = Context.getTemplateSpecializationType(Name, + &TemplateArgs[0], + TemplateArgs.size(), + Context.getTypeDeclType(Specialization)); + Specialization->setTypeAsWritten(WrittenTy); + TemplateArgsIn.release(); + + // C++ [temp.expl.spec]p9: + // A template explicit specialization is in the scope of the + // namespace in which the template was defined. + // + // We actually implement this paragraph where we set the semantic + // context (in the creation of the ClassTemplateSpecializationDecl), + // but we also maintain the lexical context where the actual + // definition occurs. + Specialization->setLexicalDeclContext(CurContext); + + // We may be starting the definition of this specialization. + if (TK == TK_Definition) + Specialization->startDefinition(); + + // Add the specialization into its lexical context, so that it can + // be seen when iterating through the list of declarations in that + // context. However, specializations are not found by name lookup. + CurContext->addDecl(Context, Specialization); + return DeclPtrTy::make(Specialization); +} + +// Explicit instantiation of a class template specialization +Sema::DeclResult +Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, + unsigned TagSpec, + SourceLocation KWLoc, + const CXXScopeSpec &SS, + TemplateTy TemplateD, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgsIn, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc, + AttributeList *Attr) { + // Find the class template we're specializing + TemplateName Name = TemplateD.getAsVal<TemplateName>(); + ClassTemplateDecl *ClassTemplate + = cast<ClassTemplateDecl>(Name.getAsTemplateDecl()); + + // Check that the specialization uses the same tag kind as the + // original template. + TagDecl::TagKind Kind; + switch (TagSpec) { + default: assert(0 && "Unknown tag type!"); + case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break; + case DeclSpec::TST_union: Kind = TagDecl::TK_union; break; + case DeclSpec::TST_class: Kind = TagDecl::TK_class; break; + } + if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(), + Kind, KWLoc, + *ClassTemplate->getIdentifier())) { + Diag(KWLoc, diag::err_use_with_wrong_tag) + << ClassTemplate + << CodeModificationHint::CreateReplacement(KWLoc, + ClassTemplate->getTemplatedDecl()->getKindName()); + Diag(ClassTemplate->getTemplatedDecl()->getLocation(), + diag::note_previous_use); + Kind = ClassTemplate->getTemplatedDecl()->getTagKind(); + } + + // C++0x [temp.explicit]p2: + // [...] An explicit instantiation shall appear in an enclosing + // namespace of its template. [...] + // + // This is C++ DR 275. + if (CheckClassTemplateSpecializationScope(ClassTemplate, 0, + TemplateNameLoc, + SS.getRange(), + /*ExplicitInstantiation=*/true)) + return true; + + // Translate the parser's template argument list in our AST format. + llvm::SmallVector<TemplateArgument, 16> TemplateArgs; + translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); + + // Check that the template argument list is well-formed for this + // template. + llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs; + if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc, + &TemplateArgs[0], TemplateArgs.size(), + RAngleLoc, ConvertedTemplateArgs)) + return true; + + assert((ConvertedTemplateArgs.size() == + ClassTemplate->getTemplateParameters()->size()) && + "Converted template argument list is too short!"); + + // Find the class template specialization declaration that + // corresponds to these arguments. + llvm::FoldingSetNodeID ID; + ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size()); + void *InsertPos = 0; + ClassTemplateSpecializationDecl *PrevDecl + = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos); + + ClassTemplateSpecializationDecl *Specialization = 0; + + bool SpecializationRequiresInstantiation = true; + if (PrevDecl) { + if (PrevDecl->getSpecializationKind() == TSK_ExplicitInstantiation) { + // This particular specialization has already been declared or + // instantiated. We cannot explicitly instantiate it. + Diag(TemplateNameLoc, diag::err_explicit_instantiation_duplicate) + << Context.getTypeDeclType(PrevDecl); + Diag(PrevDecl->getLocation(), + diag::note_previous_explicit_instantiation); + return DeclPtrTy::make(PrevDecl); + } + + if (PrevDecl->getSpecializationKind() == TSK_ExplicitSpecialization) { + // C++ DR 259, C++0x [temp.explicit]p4: + // For a given set of template parameters, if an explicit + // instantiation of a template appears after a declaration of + // an explicit specialization for that template, the explicit + // instantiation has no effect. + if (!getLangOptions().CPlusPlus0x) { + Diag(TemplateNameLoc, + diag::ext_explicit_instantiation_after_specialization) + << Context.getTypeDeclType(PrevDecl); + Diag(PrevDecl->getLocation(), + diag::note_previous_template_specialization); + } + + // Create a new class template specialization declaration node + // for this explicit specialization. This node is only used to + // record the existence of this explicit instantiation for + // accurate reproduction of the source code; we don't actually + // use it for anything, since it is semantically irrelevant. + Specialization + = ClassTemplateSpecializationDecl::Create(Context, + ClassTemplate->getDeclContext(), + TemplateNameLoc, + ClassTemplate, + &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size(), + 0); + Specialization->setLexicalDeclContext(CurContext); + CurContext->addDecl(Context, Specialization); + return DeclPtrTy::make(Specialization); + } + + // If we have already (implicitly) instantiated this + // specialization, there is less work to do. + if (PrevDecl->getSpecializationKind() == TSK_ImplicitInstantiation) + SpecializationRequiresInstantiation = false; + + // Since the only prior class template specialization with these + // arguments was referenced but not declared, reuse that + // declaration node as our own, updating its source location to + // reflect our new declaration. + Specialization = PrevDecl; + Specialization->setLocation(TemplateNameLoc); + PrevDecl = 0; + } else { + // Create a new class template specialization declaration node for + // this explicit specialization. + Specialization + = ClassTemplateSpecializationDecl::Create(Context, + ClassTemplate->getDeclContext(), + TemplateNameLoc, + ClassTemplate, + &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size(), + 0); + + ClassTemplate->getSpecializations().InsertNode(Specialization, + InsertPos); + } + + // Build the fully-sugared type for this explicit instantiation as + // the user wrote in the explicit instantiation itself. This means + // that we'll pretty-print the type retrieved from the + // specialization's declaration the way that the user actually wrote + // the explicit instantiation, rather than formatting the name based + // on the "canonical" representation used to store the template + // arguments in the specialization. + QualType WrittenTy + = Context.getTemplateSpecializationType(Name, + &TemplateArgs[0], + TemplateArgs.size(), + Context.getTypeDeclType(Specialization)); + Specialization->setTypeAsWritten(WrittenTy); + TemplateArgsIn.release(); + + // Add the explicit instantiation into its lexical context. However, + // since explicit instantiations are never found by name lookup, we + // just put it into the declaration context directly. + Specialization->setLexicalDeclContext(CurContext); + CurContext->addDecl(Context, Specialization); + + // C++ [temp.explicit]p3: + // A definition of a class template or class member template + // shall be in scope at the point of the explicit instantiation of + // the class template or class member template. + // + // This check comes when we actually try to perform the + // instantiation. + if (SpecializationRequiresInstantiation) + InstantiateClassTemplateSpecialization(Specialization, true); + else // Instantiate the members of this class template specialization. + InstantiateClassTemplateSpecializationMembers(TemplateLoc, Specialization); + + return DeclPtrTy::make(Specialization); +} + +// Explicit instantiation of a member class of a class template. +Sema::DeclResult +Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, + unsigned TagSpec, + SourceLocation KWLoc, + const CXXScopeSpec &SS, + IdentifierInfo *Name, + SourceLocation NameLoc, + AttributeList *Attr) { + + bool Owned = false; + DeclPtrTy TagD = ActOnTag(S, TagSpec, Action::TK_Reference, + KWLoc, SS, Name, NameLoc, Attr, AS_none, Owned); + if (!TagD) + return true; + + TagDecl *Tag = cast<TagDecl>(TagD.getAs<Decl>()); + if (Tag->isEnum()) { + Diag(TemplateLoc, diag::err_explicit_instantiation_enum) + << Context.getTypeDeclType(Tag); + return true; + } + + if (Tag->isInvalidDecl()) + return true; + + CXXRecordDecl *Record = cast<CXXRecordDecl>(Tag); + CXXRecordDecl *Pattern = Record->getInstantiatedFromMemberClass(); + if (!Pattern) { + Diag(TemplateLoc, diag::err_explicit_instantiation_nontemplate_type) + << Context.getTypeDeclType(Record); + Diag(Record->getLocation(), diag::note_nontemplate_decl_here); + return true; + } + + // C++0x [temp.explicit]p2: + // [...] An explicit instantiation shall appear in an enclosing + // namespace of its template. [...] + // + // This is C++ DR 275. + if (getLangOptions().CPlusPlus0x) { + // FIXME: In C++98, we would like to turn these errors into warnings, + // dependent on a -Wc++0x flag. + DeclContext *PatternContext + = Pattern->getDeclContext()->getEnclosingNamespaceContext(); + if (!CurContext->Encloses(PatternContext)) { + Diag(TemplateLoc, diag::err_explicit_instantiation_out_of_scope) + << Record << cast<NamedDecl>(PatternContext) << SS.getRange(); + Diag(Pattern->getLocation(), diag::note_previous_declaration); + } + } + + if (!Record->getDefinition(Context)) { + // If the class has a definition, instantiate it (and all of its + // members, recursively). + Pattern = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context)); + if (Pattern && InstantiateClass(TemplateLoc, Record, Pattern, + getTemplateInstantiationArgs(Record), + /*ExplicitInstantiation=*/true)) + return true; + } else // Instantiate all of the members of class. + InstantiateClassMembers(TemplateLoc, Record, + getTemplateInstantiationArgs(Record)); + + // FIXME: We don't have any representation for explicit instantiations of + // member classes. Such a representation is not needed for compilation, but it + // should be available for clients that want to see all of the declarations in + // the source code. + return TagD; +} + +Sema::TypeResult +Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, + const IdentifierInfo &II, SourceLocation IdLoc) { + NestedNameSpecifier *NNS + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + if (!NNS) + return true; + + QualType T = CheckTypenameType(NNS, II, SourceRange(TypenameLoc, IdLoc)); + if (T.isNull()) + return true; + return T.getAsOpaquePtr(); +} + +Sema::TypeResult +Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, + SourceLocation TemplateLoc, TypeTy *Ty) { + QualType T = QualType::getFromOpaquePtr(Ty); + NestedNameSpecifier *NNS + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + const TemplateSpecializationType *TemplateId + = T->getAsTemplateSpecializationType(); + assert(TemplateId && "Expected a template specialization type"); + + if (NNS->isDependent()) + return Context.getTypenameType(NNS, TemplateId).getAsOpaquePtr(); + + return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr(); +} + +/// \brief Build the type that describes a C++ typename specifier, +/// e.g., "typename T::type". +QualType +Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, + SourceRange Range) { + CXXRecordDecl *CurrentInstantiation = 0; + if (NNS->isDependent()) { + CurrentInstantiation = getCurrentInstantiationOf(NNS); + + // If the nested-name-specifier does not refer to the current + // instantiation, then build a typename type. + if (!CurrentInstantiation) + return Context.getTypenameType(NNS, &II); + } + + DeclContext *Ctx = 0; + + if (CurrentInstantiation) + Ctx = CurrentInstantiation; + else { + CXXScopeSpec SS; + SS.setScopeRep(NNS); + SS.setRange(Range); + if (RequireCompleteDeclContext(SS)) + return QualType(); + + Ctx = computeDeclContext(SS); + } + assert(Ctx && "No declaration context?"); + + DeclarationName Name(&II); + LookupResult Result = LookupQualifiedName(Ctx, Name, LookupOrdinaryName, + false); + unsigned DiagID = 0; + Decl *Referenced = 0; + switch (Result.getKind()) { + case LookupResult::NotFound: + if (Ctx->isTranslationUnit()) + DiagID = diag::err_typename_nested_not_found_global; + else + DiagID = diag::err_typename_nested_not_found; + break; + + case LookupResult::Found: + if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getAsDecl())) { + // We found a type. Build a QualifiedNameType, since the + // typename-specifier was just sugar. FIXME: Tell + // QualifiedNameType that it has a "typename" prefix. + return Context.getQualifiedNameType(NNS, Context.getTypeDeclType(Type)); + } + + DiagID = diag::err_typename_nested_not_type; + Referenced = Result.getAsDecl(); + break; + + case LookupResult::FoundOverloaded: + DiagID = diag::err_typename_nested_not_type; + Referenced = *Result.begin(); + break; + + case LookupResult::AmbiguousBaseSubobjectTypes: + case LookupResult::AmbiguousBaseSubobjects: + case LookupResult::AmbiguousReference: + DiagnoseAmbiguousLookup(Result, Name, Range.getEnd(), Range); + return QualType(); + } + + // If we get here, it's because name lookup did not find a + // type. Emit an appropriate diagnostic and return an error. + if (NamedDecl *NamedCtx = dyn_cast<NamedDecl>(Ctx)) + Diag(Range.getEnd(), DiagID) << Range << Name << NamedCtx; + else + Diag(Range.getEnd(), DiagID) << Range << Name; + if (Referenced) + Diag(Referenced->getLocation(), diag::note_typename_refers_here) + << Name; + return QualType(); +} + +// FIXME: Move to SemaTemplateDeduction.cpp +bool +Sema::DeduceTemplateArguments(QualType Param, QualType Arg, + llvm::SmallVectorImpl<TemplateArgument> &Deduced) { + // We only want to look at the canonical types, since typedefs and + // sugar are not part of template argument deduction. + Param = Context.getCanonicalType(Param); + Arg = Context.getCanonicalType(Arg); + + // If the parameter type is not dependent, just compare the types + // directly. + if (!Param->isDependentType()) + return Param == Arg; + + // FIXME: Use a visitor or switch to handle all of the kinds of + // types that the parameter may be. + if (const TemplateTypeParmType *TemplateTypeParm + = Param->getAsTemplateTypeParmType()) { + (void)TemplateTypeParm; // FIXME: use this + // The argument type can not be less qualified than the parameter + // type. + if (Param.isMoreQualifiedThan(Arg)) + return false; + + unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers(); + QualType DeducedType = Arg.getQualifiedType(Quals); + // FIXME: actually save the deduced type, and check that this + // deduction is consistent. + return true; + } + + if (Param.getCVRQualifiers() != Arg.getCVRQualifiers()) + return false; + + if (const PointerType *PointerParam = Param->getAsPointerType()) { + const PointerType *PointerArg = Arg->getAsPointerType(); + if (!PointerArg) + return false; + + return DeduceTemplateArguments(PointerParam->getPointeeType(), + PointerArg->getPointeeType(), + Deduced); + } + + // FIXME: Many more cases to go (to go). + return false; +} + +bool +Sema::DeduceTemplateArguments(const TemplateArgument &Param, + const TemplateArgument &Arg, + llvm::SmallVectorImpl<TemplateArgument> &Deduced) { + assert(Param.getKind() == Arg.getKind() && + "Template argument kind mismatch during deduction"); + switch (Param.getKind()) { + case TemplateArgument::Type: + return DeduceTemplateArguments(Param.getAsType(), Arg.getAsType(), + Deduced); + + default: + return false; + } +} + +bool +Sema::DeduceTemplateArguments(const TemplateArgumentList &ParamList, + const TemplateArgumentList &ArgList, + llvm::SmallVectorImpl<TemplateArgument> &Deduced) { + assert(ParamList.size() == ArgList.size()); + for (unsigned I = 0, N = ParamList.size(); I != N; ++I) { + if (!DeduceTemplateArguments(ParamList[I], ArgList[I], Deduced)) + return false; + } + return true; +} + + +bool +Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, + const TemplateArgumentList &TemplateArgs) { + llvm::SmallVector<TemplateArgument, 4> Deduced; + Deduced.resize(Partial->getTemplateParameters()->size()); + return DeduceTemplateArguments(Partial->getTemplateArgs(), TemplateArgs, + Deduced); +} diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp new file mode 100644 index 0000000..d3d771b --- /dev/null +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -0,0 +1,1034 @@ +//===------- SemaTemplateInstantiate.cpp - C++ Template Instantiation ------===/ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +//===----------------------------------------------------------------------===/ +// +// This file implements C++ template instantiation. +// +//===----------------------------------------------------------------------===/ + +#include "Sema.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/Parse/DeclSpec.h" +#include "clang/Basic/LangOptions.h" +#include "llvm/Support/Compiler.h" + +using namespace clang; + +//===----------------------------------------------------------------------===/ +// Template Instantiation Support +//===----------------------------------------------------------------------===/ + +/// \brief Retrieve the template argument list that should be used to +/// instantiate the given declaration. +const TemplateArgumentList & +Sema::getTemplateInstantiationArgs(NamedDecl *D) { + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(D)) + return Spec->getTemplateArgs(); + + DeclContext *EnclosingTemplateCtx = D->getDeclContext(); + while (!isa<ClassTemplateSpecializationDecl>(EnclosingTemplateCtx)) { + assert(!EnclosingTemplateCtx->isFileContext() && + "Tried to get the instantiation arguments of a non-template"); + EnclosingTemplateCtx = EnclosingTemplateCtx->getParent(); + } + + ClassTemplateSpecializationDecl *EnclosingTemplate + = cast<ClassTemplateSpecializationDecl>(EnclosingTemplateCtx); + return EnclosingTemplate->getTemplateArgs(); +} + +Sema::InstantiatingTemplate:: +InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + Decl *Entity, + SourceRange InstantiationRange) + : SemaRef(SemaRef) { + + Invalid = CheckInstantiationDepth(PointOfInstantiation, + InstantiationRange); + if (!Invalid) { + ActiveTemplateInstantiation Inst; + Inst.Kind = ActiveTemplateInstantiation::TemplateInstantiation; + Inst.PointOfInstantiation = PointOfInstantiation; + Inst.Entity = reinterpret_cast<uintptr_t>(Entity); + Inst.TemplateArgs = 0; + Inst.NumTemplateArgs = 0; + Inst.InstantiationRange = InstantiationRange; + SemaRef.ActiveTemplateInstantiations.push_back(Inst); + Invalid = false; + } +} + +Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, + SourceLocation PointOfInstantiation, + TemplateDecl *Template, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceRange InstantiationRange) + : SemaRef(SemaRef) { + + Invalid = CheckInstantiationDepth(PointOfInstantiation, + InstantiationRange); + if (!Invalid) { + ActiveTemplateInstantiation Inst; + Inst.Kind + = ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation; + Inst.PointOfInstantiation = PointOfInstantiation; + Inst.Entity = reinterpret_cast<uintptr_t>(Template); + Inst.TemplateArgs = TemplateArgs; + Inst.NumTemplateArgs = NumTemplateArgs; + Inst.InstantiationRange = InstantiationRange; + SemaRef.ActiveTemplateInstantiations.push_back(Inst); + Invalid = false; + } +} + +void Sema::InstantiatingTemplate::Clear() { + if (!Invalid) { + SemaRef.ActiveTemplateInstantiations.pop_back(); + Invalid = true; + } +} + +bool Sema::InstantiatingTemplate::CheckInstantiationDepth( + SourceLocation PointOfInstantiation, + SourceRange InstantiationRange) { + if (SemaRef.ActiveTemplateInstantiations.size() + <= SemaRef.getLangOptions().InstantiationDepth) + return false; + + SemaRef.Diag(PointOfInstantiation, + diag::err_template_recursion_depth_exceeded) + << SemaRef.getLangOptions().InstantiationDepth + << InstantiationRange; + SemaRef.Diag(PointOfInstantiation, diag::note_template_recursion_depth) + << SemaRef.getLangOptions().InstantiationDepth; + return true; +} + +/// \brief Prints the current instantiation stack through a series of +/// notes. +void Sema::PrintInstantiationStack() { + for (llvm::SmallVector<ActiveTemplateInstantiation, 16>::reverse_iterator + Active = ActiveTemplateInstantiations.rbegin(), + ActiveEnd = ActiveTemplateInstantiations.rend(); + Active != ActiveEnd; + ++Active) { + switch (Active->Kind) { + case ActiveTemplateInstantiation::TemplateInstantiation: { + Decl *D = reinterpret_cast<Decl *>(Active->Entity); + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) { + unsigned DiagID = diag::note_template_member_class_here; + if (isa<ClassTemplateSpecializationDecl>(Record)) + DiagID = diag::note_template_class_instantiation_here; + Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + DiagID) + << Context.getTypeDeclType(Record) + << Active->InstantiationRange; + } else { + FunctionDecl *Function = cast<FunctionDecl>(D); + unsigned DiagID = diag::note_template_member_function_here; + // FIXME: check for a function template + Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + DiagID) + << Function + << Active->InstantiationRange; + } + break; + } + + case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation: { + TemplateDecl *Template = cast<TemplateDecl>((Decl *)Active->Entity); + std::string TemplateArgsStr + = TemplateSpecializationType::PrintTemplateArgumentList( + Active->TemplateArgs, + Active->NumTemplateArgs, + Context.PrintingPolicy); + Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + diag::note_default_arg_instantiation_here) + << (Template->getNameAsString() + TemplateArgsStr) + << Active->InstantiationRange; + break; + } + } + } +} + +//===----------------------------------------------------------------------===/ +// Template Instantiation for Types +//===----------------------------------------------------------------------===/ +namespace { + class VISIBILITY_HIDDEN TemplateTypeInstantiator { + Sema &SemaRef; + const TemplateArgumentList &TemplateArgs; + SourceLocation Loc; + DeclarationName Entity; + + public: + TemplateTypeInstantiator(Sema &SemaRef, + const TemplateArgumentList &TemplateArgs, + SourceLocation Loc, + DeclarationName Entity) + : SemaRef(SemaRef), TemplateArgs(TemplateArgs), + Loc(Loc), Entity(Entity) { } + + QualType operator()(QualType T) const { return Instantiate(T); } + + QualType Instantiate(QualType T) const; + + // Declare instantiate functions for each type. +#define TYPE(Class, Base) \ + QualType Instantiate##Class##Type(const Class##Type *T, \ + unsigned Quals) const; +#define ABSTRACT_TYPE(Class, Base) +#include "clang/AST/TypeNodes.def" + }; +} + +QualType +TemplateTypeInstantiator::InstantiateExtQualType(const ExtQualType *T, + unsigned Quals) const { + // FIXME: Implement this + assert(false && "Cannot instantiate ExtQualType yet"); + return QualType(); +} + +QualType +TemplateTypeInstantiator::InstantiateBuiltinType(const BuiltinType *T, + unsigned Quals) const { + assert(false && "Builtin types are not dependent and cannot be instantiated"); + return QualType(T, Quals); +} + +QualType +TemplateTypeInstantiator:: +InstantiateFixedWidthIntType(const FixedWidthIntType *T, unsigned Quals) const { + // FIXME: Implement this + assert(false && "Cannot instantiate FixedWidthIntType yet"); + return QualType(); +} + +QualType +TemplateTypeInstantiator::InstantiateComplexType(const ComplexType *T, + unsigned Quals) const { + // FIXME: Implement this + assert(false && "Cannot instantiate ComplexType yet"); + return QualType(); +} + +QualType +TemplateTypeInstantiator::InstantiatePointerType(const PointerType *T, + unsigned Quals) const { + QualType PointeeType = Instantiate(T->getPointeeType()); + if (PointeeType.isNull()) + return QualType(); + + return SemaRef.BuildPointerType(PointeeType, Quals, Loc, Entity); +} + +QualType +TemplateTypeInstantiator::InstantiateBlockPointerType(const BlockPointerType *T, + unsigned Quals) const { + // FIXME: Implement this + assert(false && "Cannot instantiate BlockPointerType yet"); + return QualType(); +} + +QualType +TemplateTypeInstantiator::InstantiateLValueReferenceType( + const LValueReferenceType *T, unsigned Quals) const { + QualType ReferentType = Instantiate(T->getPointeeType()); + if (ReferentType.isNull()) + return QualType(); + + return SemaRef.BuildReferenceType(ReferentType, true, Quals, Loc, Entity); +} + +QualType +TemplateTypeInstantiator::InstantiateRValueReferenceType( + const RValueReferenceType *T, unsigned Quals) const { + QualType ReferentType = Instantiate(T->getPointeeType()); + if (ReferentType.isNull()) + return QualType(); + + return SemaRef.BuildReferenceType(ReferentType, false, Quals, Loc, Entity); +} + +QualType +TemplateTypeInstantiator:: +InstantiateMemberPointerType(const MemberPointerType *T, + unsigned Quals) const { + // FIXME: Implement this + assert(false && "Cannot instantiate MemberPointerType yet"); + return QualType(); +} + +QualType +TemplateTypeInstantiator:: +InstantiateConstantArrayType(const ConstantArrayType *T, + unsigned Quals) const { + QualType ElementType = Instantiate(T->getElementType()); + if (ElementType.isNull()) + return ElementType; + + // Build a temporary integer literal to specify the size for + // BuildArrayType. Since we have already checked the size as part of + // creating the dependent array type in the first place, we know + // there aren't any errors. However, we do need to determine what + // C++ type to give the size expression. + llvm::APInt Size = T->getSize(); + QualType Types[] = { + SemaRef.Context.UnsignedCharTy, SemaRef.Context.UnsignedShortTy, + SemaRef.Context.UnsignedIntTy, SemaRef.Context.UnsignedLongTy, + SemaRef.Context.UnsignedLongLongTy, SemaRef.Context.UnsignedInt128Ty + }; + const unsigned NumTypes = sizeof(Types) / sizeof(QualType); + QualType SizeType; + for (unsigned I = 0; I != NumTypes; ++I) + if (Size.getBitWidth() == SemaRef.Context.getIntWidth(Types[I])) { + SizeType = Types[I]; + break; + } + + if (SizeType.isNull()) + SizeType = SemaRef.Context.getFixedWidthIntType(Size.getBitWidth(), false); + + IntegerLiteral ArraySize(Size, SizeType, Loc); + return SemaRef.BuildArrayType(ElementType, T->getSizeModifier(), + &ArraySize, T->getIndexTypeQualifier(), + Loc, Entity); +} + +QualType +TemplateTypeInstantiator:: +InstantiateIncompleteArrayType(const IncompleteArrayType *T, + unsigned Quals) const { + QualType ElementType = Instantiate(T->getElementType()); + if (ElementType.isNull()) + return ElementType; + + return SemaRef.BuildArrayType(ElementType, T->getSizeModifier(), + 0, T->getIndexTypeQualifier(), + Loc, Entity); +} + +QualType +TemplateTypeInstantiator:: +InstantiateVariableArrayType(const VariableArrayType *T, + unsigned Quals) const { + // FIXME: Implement this + assert(false && "Cannot instantiate VariableArrayType yet"); + return QualType(); +} + +QualType +TemplateTypeInstantiator:: +InstantiateDependentSizedArrayType(const DependentSizedArrayType *T, + unsigned Quals) const { + Expr *ArraySize = T->getSizeExpr(); + assert(ArraySize->isValueDependent() && + "dependent sized array types must have value dependent size expr"); + + // Instantiate the element type if needed + QualType ElementType = T->getElementType(); + if (ElementType->isDependentType()) { + ElementType = Instantiate(ElementType); + if (ElementType.isNull()) + return QualType(); + } + + // Instantiate the size expression + Sema::OwningExprResult InstantiatedArraySize = + SemaRef.InstantiateExpr(ArraySize, TemplateArgs); + if (InstantiatedArraySize.isInvalid()) + return QualType(); + + return SemaRef.BuildArrayType(ElementType, T->getSizeModifier(), + InstantiatedArraySize.takeAs<Expr>(), + T->getIndexTypeQualifier(), Loc, Entity); +} + +QualType +TemplateTypeInstantiator::InstantiateVectorType(const VectorType *T, + unsigned Quals) const { + // FIXME: Implement this + assert(false && "Cannot instantiate VectorType yet"); + return QualType(); +} + +QualType +TemplateTypeInstantiator::InstantiateExtVectorType(const ExtVectorType *T, + unsigned Quals) const { + // FIXME: Implement this + assert(false && "Cannot instantiate ExtVectorType yet"); + return QualType(); +} + +QualType +TemplateTypeInstantiator:: +InstantiateFunctionProtoType(const FunctionProtoType *T, + unsigned Quals) const { + QualType ResultType = Instantiate(T->getResultType()); + if (ResultType.isNull()) + return ResultType; + + llvm::SmallVector<QualType, 4> ParamTypes; + for (FunctionProtoType::arg_type_iterator Param = T->arg_type_begin(), + ParamEnd = T->arg_type_end(); + Param != ParamEnd; ++Param) { + QualType P = Instantiate(*Param); + if (P.isNull()) + return P; + + ParamTypes.push_back(P); + } + + return SemaRef.BuildFunctionType(ResultType, &ParamTypes[0], + ParamTypes.size(), + T->isVariadic(), T->getTypeQuals(), + Loc, Entity); +} + +QualType +TemplateTypeInstantiator:: +InstantiateFunctionNoProtoType(const FunctionNoProtoType *T, + unsigned Quals) const { + assert(false && "Functions without prototypes cannot be dependent."); + return QualType(); +} + +QualType +TemplateTypeInstantiator::InstantiateTypedefType(const TypedefType *T, + unsigned Quals) const { + TypedefDecl *Typedef + = cast_or_null<TypedefDecl>( + SemaRef.InstantiateCurrentDeclRef(T->getDecl())); + if (!Typedef) + return QualType(); + + return SemaRef.Context.getTypeDeclType(Typedef); +} + +QualType +TemplateTypeInstantiator::InstantiateTypeOfExprType(const TypeOfExprType *T, + unsigned Quals) const { + Sema::OwningExprResult E + = SemaRef.InstantiateExpr(T->getUnderlyingExpr(), TemplateArgs); + if (E.isInvalid()) + return QualType(); + + return SemaRef.Context.getTypeOfExprType(E.takeAs<Expr>()); +} + +QualType +TemplateTypeInstantiator::InstantiateTypeOfType(const TypeOfType *T, + unsigned Quals) const { + QualType Underlying = Instantiate(T->getUnderlyingType()); + if (Underlying.isNull()) + return QualType(); + + return SemaRef.Context.getTypeOfType(Underlying); +} + +QualType +TemplateTypeInstantiator::InstantiateRecordType(const RecordType *T, + unsigned Quals) const { + RecordDecl *Record + = cast_or_null<RecordDecl>(SemaRef.InstantiateCurrentDeclRef(T->getDecl())); + if (!Record) + return QualType(); + + return SemaRef.Context.getTypeDeclType(Record); +} + +QualType +TemplateTypeInstantiator::InstantiateEnumType(const EnumType *T, + unsigned Quals) const { + EnumDecl *Enum + = cast_or_null<EnumDecl>(SemaRef.InstantiateCurrentDeclRef(T->getDecl())); + if (!Enum) + return QualType(); + + return SemaRef.Context.getTypeDeclType(Enum); +} + +QualType +TemplateTypeInstantiator:: +InstantiateTemplateTypeParmType(const TemplateTypeParmType *T, + unsigned Quals) const { + if (T->getDepth() == 0) { + // Replace the template type parameter with its corresponding + // template argument. + assert(TemplateArgs[T->getIndex()].getKind() == TemplateArgument::Type && + "Template argument kind mismatch"); + QualType Result = TemplateArgs[T->getIndex()].getAsType(); + if (Result.isNull() || !Quals) + return Result; + + // C++ [dcl.ref]p1: + // [...] Cv-qualified references are ill-formed except when + // the cv-qualifiers are introduced through the use of a + // typedef (7.1.3) or of a template type argument (14.3), in + // which case the cv-qualifiers are ignored. + if (Quals && Result->isReferenceType()) + Quals = 0; + + return QualType(Result.getTypePtr(), Quals | Result.getCVRQualifiers()); + } + + // The template type parameter comes from an inner template (e.g., + // the template parameter list of a member template inside the + // template we are instantiating). Create a new template type + // parameter with the template "level" reduced by one. + return SemaRef.Context.getTemplateTypeParmType(T->getDepth() - 1, + T->getIndex(), + T->getName()) + .getQualifiedType(Quals); +} + +QualType +TemplateTypeInstantiator:: +InstantiateTemplateSpecializationType( + const TemplateSpecializationType *T, + unsigned Quals) const { + llvm::SmallVector<TemplateArgument, 4> InstantiatedTemplateArgs; + InstantiatedTemplateArgs.reserve(T->getNumArgs()); + for (TemplateSpecializationType::iterator Arg = T->begin(), ArgEnd = T->end(); + Arg != ArgEnd; ++Arg) { + switch (Arg->getKind()) { + case TemplateArgument::Type: { + QualType T = SemaRef.InstantiateType(Arg->getAsType(), + TemplateArgs, + Arg->getLocation(), + DeclarationName()); + if (T.isNull()) + return QualType(); + + InstantiatedTemplateArgs.push_back( + TemplateArgument(Arg->getLocation(), T)); + break; + } + + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + InstantiatedTemplateArgs.push_back(*Arg); + break; + + case TemplateArgument::Expression: + Sema::OwningExprResult E + = SemaRef.InstantiateExpr(Arg->getAsExpr(), TemplateArgs); + if (E.isInvalid()) + return QualType(); + InstantiatedTemplateArgs.push_back(E.takeAs<Expr>()); + break; + } + } + + // FIXME: We're missing the locations of the template name, '<', and '>'. + + TemplateName Name = SemaRef.InstantiateTemplateName(T->getTemplateName(), + Loc, + TemplateArgs); + + return SemaRef.CheckTemplateIdType(Name, Loc, SourceLocation(), + &InstantiatedTemplateArgs[0], + InstantiatedTemplateArgs.size(), + SourceLocation()); +} + +QualType +TemplateTypeInstantiator:: +InstantiateQualifiedNameType(const QualifiedNameType *T, + unsigned Quals) const { + // When we instantiated a qualified name type, there's no point in + // keeping the qualification around in the instantiated result. So, + // just instantiate the named type. + return (*this)(T->getNamedType()); +} + +QualType +TemplateTypeInstantiator:: +InstantiateTypenameType(const TypenameType *T, unsigned Quals) const { + if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) { + // When the typename type refers to a template-id, the template-id + // is dependent and has enough information to instantiate the + // result of the typename type. Since we don't care about keeping + // the spelling of the typename type in template instantiations, + // we just instantiate the template-id. + return InstantiateTemplateSpecializationType(TemplateId, Quals); + } + + NestedNameSpecifier *NNS + = SemaRef.InstantiateNestedNameSpecifier(T->getQualifier(), + SourceRange(Loc), + TemplateArgs); + if (!NNS) + return QualType(); + + return SemaRef.CheckTypenameType(NNS, *T->getIdentifier(), SourceRange(Loc)); +} + +QualType +TemplateTypeInstantiator:: +InstantiateObjCInterfaceType(const ObjCInterfaceType *T, + unsigned Quals) const { + assert(false && "Objective-C types cannot be dependent"); + return QualType(); +} + +QualType +TemplateTypeInstantiator:: +InstantiateObjCQualifiedInterfaceType(const ObjCQualifiedInterfaceType *T, + unsigned Quals) const { + assert(false && "Objective-C types cannot be dependent"); + return QualType(); +} + +QualType +TemplateTypeInstantiator:: +InstantiateObjCQualifiedIdType(const ObjCQualifiedIdType *T, + unsigned Quals) const { + assert(false && "Objective-C types cannot be dependent"); + return QualType(); +} + +/// \brief The actual implementation of Sema::InstantiateType(). +QualType TemplateTypeInstantiator::Instantiate(QualType T) const { + // If T is not a dependent type, there is nothing to do. + if (!T->isDependentType()) + return T; + + switch (T->getTypeClass()) { +#define TYPE(Class, Base) \ + case Type::Class: \ + return Instantiate##Class##Type(cast<Class##Type>(T.getTypePtr()), \ + T.getCVRQualifiers()); +#define ABSTRACT_TYPE(Class, Base) +#include "clang/AST/TypeNodes.def" + } + + assert(false && "Not all types have been decoded for instantiation"); + return QualType(); +} + +/// \brief Instantiate the type T with a given set of template arguments. +/// +/// This routine substitutes the given template arguments into the +/// type T and produces the instantiated type. +/// +/// \param T the type into which the template arguments will be +/// substituted. If this type is not dependent, it will be returned +/// immediately. +/// +/// \param TemplateArgs the template arguments that will be +/// substituted for the top-level template parameters within T. +/// +/// \param Loc the location in the source code where this substitution +/// is being performed. It will typically be the location of the +/// declarator (if we're instantiating the type of some declaration) +/// or the location of the type in the source code (if, e.g., we're +/// instantiating the type of a cast expression). +/// +/// \param Entity the name of the entity associated with a declaration +/// being instantiated (if any). May be empty to indicate that there +/// is no such entity (if, e.g., this is a type that occurs as part of +/// a cast expression) or that the entity has no name (e.g., an +/// unnamed function parameter). +/// +/// \returns If the instantiation succeeds, the instantiated +/// type. Otherwise, produces diagnostics and returns a NULL type. +QualType Sema::InstantiateType(QualType T, + const TemplateArgumentList &TemplateArgs, + SourceLocation Loc, DeclarationName Entity) { + assert(!ActiveTemplateInstantiations.empty() && + "Cannot perform an instantiation without some context on the " + "instantiation stack"); + + // If T is not a dependent type, there is nothing to do. + if (!T->isDependentType()) + return T; + + TemplateTypeInstantiator Instantiator(*this, TemplateArgs, Loc, Entity); + return Instantiator(T); +} + +/// \brief Instantiate the base class specifiers of the given class +/// template specialization. +/// +/// Produces a diagnostic and returns true on error, returns false and +/// attaches the instantiated base classes to the class template +/// specialization if successful. +bool +Sema::InstantiateBaseSpecifiers(CXXRecordDecl *Instantiation, + CXXRecordDecl *Pattern, + const TemplateArgumentList &TemplateArgs) { + bool Invalid = false; + llvm::SmallVector<CXXBaseSpecifier*, 4> InstantiatedBases; + for (ClassTemplateSpecializationDecl::base_class_iterator + Base = Pattern->bases_begin(), BaseEnd = Pattern->bases_end(); + Base != BaseEnd; ++Base) { + if (!Base->getType()->isDependentType()) { + // FIXME: Allocate via ASTContext + InstantiatedBases.push_back(new CXXBaseSpecifier(*Base)); + continue; + } + + QualType BaseType = InstantiateType(Base->getType(), + TemplateArgs, + Base->getSourceRange().getBegin(), + DeclarationName()); + if (BaseType.isNull()) { + Invalid = true; + continue; + } + + if (CXXBaseSpecifier *InstantiatedBase + = CheckBaseSpecifier(Instantiation, + Base->getSourceRange(), + Base->isVirtual(), + Base->getAccessSpecifierAsWritten(), + BaseType, + /*FIXME: Not totally accurate */ + Base->getSourceRange().getBegin())) + InstantiatedBases.push_back(InstantiatedBase); + else + Invalid = true; + } + + if (!Invalid && + AttachBaseSpecifiers(Instantiation, InstantiatedBases.data(), + InstantiatedBases.size())) + Invalid = true; + + return Invalid; +} + +/// \brief Instantiate the definition of a class from a given pattern. +/// +/// \param PointOfInstantiation The point of instantiation within the +/// source code. +/// +/// \param Instantiation is the declaration whose definition is being +/// instantiated. This will be either a class template specialization +/// or a member class of a class template specialization. +/// +/// \param Pattern is the pattern from which the instantiation +/// occurs. This will be either the declaration of a class template or +/// the declaration of a member class of a class template. +/// +/// \param TemplateArgs The template arguments to be substituted into +/// the pattern. +/// +/// \returns true if an error occurred, false otherwise. +bool +Sema::InstantiateClass(SourceLocation PointOfInstantiation, + CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, + const TemplateArgumentList &TemplateArgs, + bool ExplicitInstantiation) { + bool Invalid = false; + + CXXRecordDecl *PatternDef + = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context)); + if (!PatternDef) { + if (Pattern == Instantiation->getInstantiatedFromMemberClass()) { + Diag(PointOfInstantiation, + diag::err_implicit_instantiate_member_undefined) + << Context.getTypeDeclType(Instantiation); + Diag(Pattern->getLocation(), diag::note_member_of_template_here); + } else { + Diag(PointOfInstantiation, diag::err_template_instantiate_undefined) + << ExplicitInstantiation + << Context.getTypeDeclType(Instantiation); + Diag(Pattern->getLocation(), diag::note_template_decl_here); + } + return true; + } + Pattern = PatternDef; + + InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); + if (Inst) + return true; + + // Enter the scope of this instantiation. We don't use + // PushDeclContext because we don't have a scope. + DeclContext *PreviousContext = CurContext; + CurContext = Instantiation; + + // Start the definition of this instantiation. + Instantiation->startDefinition(); + + // Instantiate the base class specifiers. + if (InstantiateBaseSpecifiers(Instantiation, Pattern, TemplateArgs)) + Invalid = true; + + llvm::SmallVector<DeclPtrTy, 4> Fields; + for (RecordDecl::decl_iterator Member = Pattern->decls_begin(Context), + MemberEnd = Pattern->decls_end(Context); + Member != MemberEnd; ++Member) { + Decl *NewMember = InstantiateDecl(*Member, Instantiation, TemplateArgs); + if (NewMember) { + if (NewMember->isInvalidDecl()) + Invalid = true; + else if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) + Fields.push_back(DeclPtrTy::make(Field)); + } else { + // FIXME: Eventually, a NULL return will mean that one of the + // instantiations was a semantic disaster, and we'll want to set Invalid = + // true. For now, we expect to skip some members that we can't yet handle. + } + } + + // Finish checking fields. + ActOnFields(0, Instantiation->getLocation(), DeclPtrTy::make(Instantiation), + Fields.data(), Fields.size(), SourceLocation(), SourceLocation(), + 0); + + // Add any implicitly-declared members that we might need. + AddImplicitlyDeclaredMembersToClass(Instantiation); + + // Exit the scope of this instantiation. + CurContext = PreviousContext; + + if (!Invalid) + Consumer.HandleTagDeclDefinition(Instantiation); + + // If this is an explicit instantiation, instantiate our members, too. + if (!Invalid && ExplicitInstantiation) { + Inst.Clear(); + InstantiateClassMembers(PointOfInstantiation, Instantiation, TemplateArgs); + } + + return Invalid; +} + +bool +Sema::InstantiateClassTemplateSpecialization( + ClassTemplateSpecializationDecl *ClassTemplateSpec, + bool ExplicitInstantiation) { + // Perform the actual instantiation on the canonical declaration. + ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>( + Context.getCanonicalDecl(ClassTemplateSpec)); + + // We can only instantiate something that hasn't already been + // instantiated or specialized. Fail without any diagnostics: our + // caller will provide an error message. + if (ClassTemplateSpec->getSpecializationKind() != TSK_Undeclared) + return true; + + ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate(); + CXXRecordDecl *Pattern = Template->getTemplatedDecl(); + const TemplateArgumentList *TemplateArgs + = &ClassTemplateSpec->getTemplateArgs(); + + // Determine whether any class template partial specializations + // match the given template arguments. + llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> Matched; + for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator + Partial = Template->getPartialSpecializations().begin(), + PartialEnd = Template->getPartialSpecializations().end(); + Partial != PartialEnd; + ++Partial) { + if (DeduceTemplateArguments(&*Partial, ClassTemplateSpec->getTemplateArgs())) + Matched.push_back(&*Partial); + } + + if (Matched.size() == 1) { + Pattern = Matched[0]; + // FIXME: set TemplateArgs to the template arguments of the + // partial specialization, instantiated with the deduced template + // arguments. + } else if (Matched.size() > 1) { + // FIXME: Implement partial ordering of class template partial + // specializations. + Diag(ClassTemplateSpec->getLocation(), + diag::unsup_template_partial_spec_ordering); + } + + // Note that this is an instantiation. + ClassTemplateSpec->setSpecializationKind( + ExplicitInstantiation? TSK_ExplicitInstantiation + : TSK_ImplicitInstantiation); + + return InstantiateClass(ClassTemplateSpec->getLocation(), + ClassTemplateSpec, Pattern, *TemplateArgs, + ExplicitInstantiation); +} + +/// \brief Instantiate the definitions of all of the member of the +/// given class, which is an instantiation of a class template or a +/// member class of a template. +void +Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, + CXXRecordDecl *Instantiation, + const TemplateArgumentList &TemplateArgs) { + for (DeclContext::decl_iterator D = Instantiation->decls_begin(Context), + DEnd = Instantiation->decls_end(Context); + D != DEnd; ++D) { + if (FunctionDecl *Function = dyn_cast<FunctionDecl>(*D)) { + if (!Function->getBody(Context)) + InstantiateFunctionDefinition(PointOfInstantiation, Function); + } else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) { + const VarDecl *Def = 0; + if (!Var->getDefinition(Def)) + InstantiateVariableDefinition(Var); + } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) { + if (!Record->isInjectedClassName() && !Record->getDefinition(Context)) { + assert(Record->getInstantiatedFromMemberClass() && + "Missing instantiated-from-template information"); + InstantiateClass(PointOfInstantiation, Record, + Record->getInstantiatedFromMemberClass(), + TemplateArgs, true); + } + } + } +} + +/// \brief Instantiate the definitions of all of the members of the +/// given class template specialization, which was named as part of an +/// explicit instantiation. +void Sema::InstantiateClassTemplateSpecializationMembers( + SourceLocation PointOfInstantiation, + ClassTemplateSpecializationDecl *ClassTemplateSpec) { + // C++0x [temp.explicit]p7: + // An explicit instantiation that names a class template + // specialization is an explicit instantion of the same kind + // (declaration or definition) of each of its members (not + // including members inherited from base classes) that has not + // been previously explicitly specialized in the translation unit + // containing the explicit instantiation, except as described + // below. + InstantiateClassMembers(PointOfInstantiation, ClassTemplateSpec, + ClassTemplateSpec->getTemplateArgs()); +} + +/// \brief Instantiate a nested-name-specifier. +NestedNameSpecifier * +Sema::InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS, + SourceRange Range, + const TemplateArgumentList &TemplateArgs) { + // Instantiate the prefix of this nested name specifier. + NestedNameSpecifier *Prefix = NNS->getPrefix(); + if (Prefix) { + Prefix = InstantiateNestedNameSpecifier(Prefix, Range, TemplateArgs); + if (!Prefix) + return 0; + } + + switch (NNS->getKind()) { + case NestedNameSpecifier::Identifier: { + assert(Prefix && + "Can't have an identifier nested-name-specifier with no prefix"); + CXXScopeSpec SS; + // FIXME: The source location information is all wrong. + SS.setRange(Range); + SS.setScopeRep(Prefix); + return static_cast<NestedNameSpecifier *>( + ActOnCXXNestedNameSpecifier(0, SS, + Range.getEnd(), + Range.getEnd(), + *NNS->getAsIdentifier())); + break; + } + + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::Global: + return NNS; + + case NestedNameSpecifier::TypeSpecWithTemplate: + case NestedNameSpecifier::TypeSpec: { + QualType T = QualType(NNS->getAsType(), 0); + if (!T->isDependentType()) + return NNS; + + T = InstantiateType(T, TemplateArgs, Range.getBegin(), DeclarationName()); + if (T.isNull()) + return 0; + + if (T->isRecordType() || + (getLangOptions().CPlusPlus0x && T->isEnumeralType())) { + assert(T.getCVRQualifiers() == 0 && "Can't get cv-qualifiers here"); + return NestedNameSpecifier::Create(Context, Prefix, + NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate, + T.getTypePtr()); + } + + Diag(Range.getBegin(), diag::err_nested_name_spec_non_tag) << T; + return 0; + } + } + + // Required to silence a GCC warning + return 0; +} + +TemplateName +Sema::InstantiateTemplateName(TemplateName Name, SourceLocation Loc, + const TemplateArgumentList &TemplateArgs) { + if (TemplateTemplateParmDecl *TTP + = dyn_cast_or_null<TemplateTemplateParmDecl>( + Name.getAsTemplateDecl())) { + assert(TTP->getDepth() == 0 && + "Cannot reduce depth of a template template parameter"); + assert(TemplateArgs[TTP->getPosition()].getAsDecl() && + "Wrong kind of template template argument"); + ClassTemplateDecl *ClassTemplate + = dyn_cast<ClassTemplateDecl>( + TemplateArgs[TTP->getPosition()].getAsDecl()); + assert(ClassTemplate && "Expected a class template"); + if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) { + NestedNameSpecifier *NNS + = InstantiateNestedNameSpecifier(QTN->getQualifier(), + /*FIXME=*/SourceRange(Loc), + TemplateArgs); + if (NNS) + return Context.getQualifiedTemplateName(NNS, + QTN->hasTemplateKeyword(), + ClassTemplate); + } + + return TemplateName(ClassTemplate); + } else if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { + NestedNameSpecifier *NNS + = InstantiateNestedNameSpecifier(DTN->getQualifier(), + /*FIXME=*/SourceRange(Loc), + TemplateArgs); + + if (!NNS) // FIXME: Not the best recovery strategy. + return Name; + + if (NNS->isDependent()) + return Context.getDependentTemplateName(NNS, DTN->getName()); + + // Somewhat redundant with ActOnDependentTemplateName. + CXXScopeSpec SS; + SS.setRange(SourceRange(Loc)); + SS.setScopeRep(NNS); + TemplateTy Template; + TemplateNameKind TNK = isTemplateName(*DTN->getName(), 0, Template, &SS); + if (TNK == TNK_Non_template) { + Diag(Loc, diag::err_template_kw_refers_to_non_template) + << DTN->getName(); + return Name; + } else if (TNK == TNK_Function_template) { + Diag(Loc, diag::err_template_kw_refers_to_non_template) + << DTN->getName(); + return Name; + } + + return Template.getAsVal<TemplateName>(); + } + + + + // FIXME: Even if we're referring to a Decl that isn't a template template + // parameter, we may need to instantiate the outer contexts of that + // Decl. However, this won't be needed until we implement member templates. + return Name; +} diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp new file mode 100644 index 0000000..6d7dc2e --- /dev/null +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -0,0 +1,767 @@ +//===--- SemaTemplateInstantiateDecl.cpp - C++ Template Decl Instantiation ===/ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +//===----------------------------------------------------------------------===/ +// +// This file implements C++ template instantiation for declarations. +// +//===----------------------------------------------------------------------===/ +#include "Sema.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/Expr.h" +#include "llvm/Support/Compiler.h" + +using namespace clang; + +namespace { + class VISIBILITY_HIDDEN TemplateDeclInstantiator + : public DeclVisitor<TemplateDeclInstantiator, Decl *> { + Sema &SemaRef; + DeclContext *Owner; + const TemplateArgumentList &TemplateArgs; + + public: + typedef Sema::OwningExprResult OwningExprResult; + + TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner, + const TemplateArgumentList &TemplateArgs) + : SemaRef(SemaRef), Owner(Owner), TemplateArgs(TemplateArgs) { } + + // FIXME: Once we get closer to completion, replace these manually-written + // declarations with automatically-generated ones from + // clang/AST/DeclNodes.def. + Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D); + Decl *VisitNamespaceDecl(NamespaceDecl *D); + Decl *VisitTypedefDecl(TypedefDecl *D); + Decl *VisitVarDecl(VarDecl *D); + Decl *VisitFieldDecl(FieldDecl *D); + Decl *VisitStaticAssertDecl(StaticAssertDecl *D); + Decl *VisitEnumDecl(EnumDecl *D); + Decl *VisitEnumConstantDecl(EnumConstantDecl *D); + Decl *VisitCXXRecordDecl(CXXRecordDecl *D); + Decl *VisitCXXMethodDecl(CXXMethodDecl *D); + Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D); + Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D); + Decl *VisitCXXConversionDecl(CXXConversionDecl *D); + ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D); + Decl *VisitOriginalParmVarDecl(OriginalParmVarDecl *D); + + // Base case. FIXME: Remove once we can instantiate everything. + Decl *VisitDecl(Decl *) { + assert(false && "Template instantiation of unknown declaration kind!"); + return 0; + } + + // Helper functions for instantiating methods. + QualType InstantiateFunctionType(FunctionDecl *D, + llvm::SmallVectorImpl<ParmVarDecl *> &Params); + bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl); + }; +} + +Decl * +TemplateDeclInstantiator::VisitTranslationUnitDecl(TranslationUnitDecl *D) { + assert(false && "Translation units cannot be instantiated"); + return D; +} + +Decl * +TemplateDeclInstantiator::VisitNamespaceDecl(NamespaceDecl *D) { + assert(false && "Namespaces cannot be instantiated"); + return D; +} + +Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { + bool Invalid = false; + QualType T = D->getUnderlyingType(); + if (T->isDependentType()) { + T = SemaRef.InstantiateType(T, TemplateArgs, + D->getLocation(), D->getDeclName()); + if (T.isNull()) { + Invalid = true; + T = SemaRef.Context.IntTy; + } + } + + // Create the new typedef + TypedefDecl *Typedef + = TypedefDecl::Create(SemaRef.Context, Owner, D->getLocation(), + D->getIdentifier(), T); + if (Invalid) + Typedef->setInvalidDecl(); + + Owner->addDecl(SemaRef.Context, Typedef); + + return Typedef; +} + +Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { + // Instantiate the type of the declaration + QualType T = SemaRef.InstantiateType(D->getType(), TemplateArgs, + D->getTypeSpecStartLoc(), + D->getDeclName()); + if (T.isNull()) + return 0; + + // Build the instantiated declaration + VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner, + D->getLocation(), D->getIdentifier(), + T, D->getStorageClass(), + D->getTypeSpecStartLoc()); + Var->setThreadSpecified(D->isThreadSpecified()); + Var->setCXXDirectInitializer(D->hasCXXDirectInitializer()); + Var->setDeclaredInCondition(D->isDeclaredInCondition()); + + // FIXME: In theory, we could have a previous declaration for variables that + // are not static data members. + bool Redeclaration = false; + SemaRef.CheckVariableDeclaration(Var, 0, Redeclaration); + Owner->addDecl(SemaRef.Context, Var); + + if (D->getInit()) { + OwningExprResult Init + = SemaRef.InstantiateExpr(D->getInit(), TemplateArgs); + if (Init.isInvalid()) + Var->setInvalidDecl(); + else + SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), move(Init), + D->hasCXXDirectInitializer()); + } else { + // FIXME: Call ActOnUninitializedDecl? (Not always) + } + + return Var; +} + +Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { + bool Invalid = false; + QualType T = D->getType(); + if (T->isDependentType()) { + T = SemaRef.InstantiateType(T, TemplateArgs, + D->getLocation(), D->getDeclName()); + if (!T.isNull() && T->isFunctionType()) { + // C++ [temp.arg.type]p3: + // If a declaration acquires a function type through a type + // dependent on a template-parameter and this causes a + // declaration that does not use the syntactic form of a + // function declarator to have function type, the program is + // ill-formed. + SemaRef.Diag(D->getLocation(), diag::err_field_instantiates_to_function) + << T; + T = QualType(); + Invalid = true; + } + } + + Expr *BitWidth = D->getBitWidth(); + if (Invalid) + BitWidth = 0; + else if (BitWidth) { + OwningExprResult InstantiatedBitWidth + = SemaRef.InstantiateExpr(BitWidth, TemplateArgs); + if (InstantiatedBitWidth.isInvalid()) { + Invalid = true; + BitWidth = 0; + } else + BitWidth = InstantiatedBitWidth.takeAs<Expr>(); + } + + FieldDecl *Field = SemaRef.CheckFieldDecl(D->getDeclName(), T, + cast<RecordDecl>(Owner), + D->getLocation(), + D->isMutable(), + BitWidth, + D->getAccess(), + 0); + if (Field) { + if (Invalid) + Field->setInvalidDecl(); + + Owner->addDecl(SemaRef.Context, Field); + } + + return Field; +} + +Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) { + Expr *AssertExpr = D->getAssertExpr(); + + OwningExprResult InstantiatedAssertExpr + = SemaRef.InstantiateExpr(AssertExpr, TemplateArgs); + if (InstantiatedAssertExpr.isInvalid()) + return 0; + + OwningExprResult Message = SemaRef.Clone(D->getMessage()); + Decl *StaticAssert + = SemaRef.ActOnStaticAssertDeclaration(D->getLocation(), + move(InstantiatedAssertExpr), + move(Message)).getAs<Decl>(); + return StaticAssert; +} + +Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { + EnumDecl *Enum = EnumDecl::Create(SemaRef.Context, Owner, + D->getLocation(), D->getIdentifier(), + /*PrevDecl=*/0); + Enum->setInstantiationOfMemberEnum(D); + Enum->setAccess(D->getAccess()); + Owner->addDecl(SemaRef.Context, Enum); + Enum->startDefinition(); + + llvm::SmallVector<Sema::DeclPtrTy, 4> Enumerators; + + EnumConstantDecl *LastEnumConst = 0; + for (EnumDecl::enumerator_iterator EC = D->enumerator_begin(SemaRef.Context), + ECEnd = D->enumerator_end(SemaRef.Context); + EC != ECEnd; ++EC) { + // The specified value for the enumerator. + OwningExprResult Value = SemaRef.Owned((Expr *)0); + if (Expr *UninstValue = EC->getInitExpr()) + Value = SemaRef.InstantiateExpr(UninstValue, TemplateArgs); + + // Drop the initial value and continue. + bool isInvalid = false; + if (Value.isInvalid()) { + Value = SemaRef.Owned((Expr *)0); + isInvalid = true; + } + + EnumConstantDecl *EnumConst + = SemaRef.CheckEnumConstant(Enum, LastEnumConst, + EC->getLocation(), EC->getIdentifier(), + move(Value)); + + if (isInvalid) { + if (EnumConst) + EnumConst->setInvalidDecl(); + Enum->setInvalidDecl(); + } + + if (EnumConst) { + Enum->addDecl(SemaRef.Context, EnumConst); + Enumerators.push_back(Sema::DeclPtrTy::make(EnumConst)); + LastEnumConst = EnumConst; + } + } + + // FIXME: Fixup LBraceLoc and RBraceLoc + SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(), SourceLocation(), + Sema::DeclPtrTy::make(Enum), + &Enumerators[0], Enumerators.size()); + + return Enum; +} + +Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) { + assert(false && "EnumConstantDecls can only occur within EnumDecls."); + return 0; +} + +Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { + CXXRecordDecl *PrevDecl = 0; + if (D->isInjectedClassName()) + PrevDecl = cast<CXXRecordDecl>(Owner); + + CXXRecordDecl *Record + = CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner, + D->getLocation(), D->getIdentifier(), PrevDecl); + Record->setImplicit(D->isImplicit()); + Record->setAccess(D->getAccess()); + if (!D->isInjectedClassName()) + Record->setInstantiationOfMemberClass(D); + + Owner->addDecl(SemaRef.Context, Record); + return Record; +} + +Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) { + // Only handle actual methods; we'll deal with constructors, + // destructors, etc. separately. + if (D->getKind() != Decl::CXXMethod) + return 0; + + Sema::LocalInstantiationScope Scope(SemaRef); + + llvm::SmallVector<ParmVarDecl *, 4> Params; + QualType T = InstantiateFunctionType(D, Params); + if (T.isNull()) + return 0; + + // Build the instantiated method declaration. + CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner); + CXXMethodDecl *Method + = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(), + D->getDeclName(), T, D->isStatic(), + D->isInline()); + Method->setInstantiationOfMemberFunction(D); + + // Attach the parameters + for (unsigned P = 0; P < Params.size(); ++P) + Params[P]->setOwningFunction(Method); + Method->setParams(SemaRef.Context, Params.data(), Params.size()); + + if (InitMethodInstantiation(Method, D)) + Method->setInvalidDecl(); + + NamedDecl *PrevDecl + = SemaRef.LookupQualifiedName(Owner, Method->getDeclName(), + Sema::LookupOrdinaryName, true); + // In C++, the previous declaration we find might be a tag type + // (class or enum). In this case, the new declaration will hide the + // tag type. Note that this does does not apply if we're declaring a + // typedef (C++ [dcl.typedef]p4). + if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag) + PrevDecl = 0; + bool Redeclaration = false; + bool OverloadableAttrRequired = false; + SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration, + /*FIXME:*/OverloadableAttrRequired); + + if (!Method->isInvalidDecl() || !PrevDecl) + Owner->addDecl(SemaRef.Context, Method); + return Method; +} + +Decl *TemplateDeclInstantiator::VisitCXXConstructorDecl(CXXConstructorDecl *D) { + Sema::LocalInstantiationScope Scope(SemaRef); + + llvm::SmallVector<ParmVarDecl *, 4> Params; + QualType T = InstantiateFunctionType(D, Params); + if (T.isNull()) + return 0; + + // Build the instantiated method declaration. + CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner); + QualType ClassTy = SemaRef.Context.getTypeDeclType(Record); + DeclarationName Name + = SemaRef.Context.DeclarationNames.getCXXConstructorName( + SemaRef.Context.getCanonicalType(ClassTy)); + CXXConstructorDecl *Constructor + = CXXConstructorDecl::Create(SemaRef.Context, Record, D->getLocation(), + Name, T, D->isExplicit(), D->isInline(), + false); + Constructor->setInstantiationOfMemberFunction(D); + + // Attach the parameters + for (unsigned P = 0; P < Params.size(); ++P) + Params[P]->setOwningFunction(Constructor); + Constructor->setParams(SemaRef.Context, Params.data(), Params.size()); + + if (InitMethodInstantiation(Constructor, D)) + Constructor->setInvalidDecl(); + + NamedDecl *PrevDecl + = SemaRef.LookupQualifiedName(Owner, Name, Sema::LookupOrdinaryName, true); + + // In C++, the previous declaration we find might be a tag type + // (class or enum). In this case, the new declaration will hide the + // tag type. Note that this does does not apply if we're declaring a + // typedef (C++ [dcl.typedef]p4). + if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag) + PrevDecl = 0; + bool Redeclaration = false; + bool OverloadableAttrRequired = false; + SemaRef.CheckFunctionDeclaration(Constructor, PrevDecl, Redeclaration, + /*FIXME:*/OverloadableAttrRequired); + + Record->addedConstructor(SemaRef.Context, Constructor); + Owner->addDecl(SemaRef.Context, Constructor); + return Constructor; +} + +Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) { + Sema::LocalInstantiationScope Scope(SemaRef); + + llvm::SmallVector<ParmVarDecl *, 4> Params; + QualType T = InstantiateFunctionType(D, Params); + if (T.isNull()) + return 0; + assert(Params.size() == 0 && "Destructor with parameters?"); + + // Build the instantiated destructor declaration. + CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner); + QualType ClassTy = + SemaRef.Context.getCanonicalType(SemaRef.Context.getTypeDeclType(Record)); + CXXDestructorDecl *Destructor + = CXXDestructorDecl::Create(SemaRef.Context, Record, + D->getLocation(), + SemaRef.Context.DeclarationNames.getCXXDestructorName(ClassTy), + T, D->isInline(), false); + Destructor->setInstantiationOfMemberFunction(D); + if (InitMethodInstantiation(Destructor, D)) + Destructor->setInvalidDecl(); + + bool Redeclaration = false; + bool OverloadableAttrRequired = false; + NamedDecl *PrevDecl = 0; + SemaRef.CheckFunctionDeclaration(Destructor, PrevDecl, Redeclaration, + /*FIXME:*/OverloadableAttrRequired); + Owner->addDecl(SemaRef.Context, Destructor); + return Destructor; +} + +Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) { + Sema::LocalInstantiationScope Scope(SemaRef); + + llvm::SmallVector<ParmVarDecl *, 4> Params; + QualType T = InstantiateFunctionType(D, Params); + if (T.isNull()) + return 0; + assert(Params.size() == 0 && "Destructor with parameters?"); + + // Build the instantiated conversion declaration. + CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner); + QualType ClassTy = SemaRef.Context.getTypeDeclType(Record); + QualType ConvTy + = SemaRef.Context.getCanonicalType(T->getAsFunctionType()->getResultType()); + CXXConversionDecl *Conversion + = CXXConversionDecl::Create(SemaRef.Context, Record, + D->getLocation(), + SemaRef.Context.DeclarationNames.getCXXConversionFunctionName(ConvTy), + T, D->isInline(), D->isExplicit()); + Conversion->setInstantiationOfMemberFunction(D); + if (InitMethodInstantiation(Conversion, D)) + Conversion->setInvalidDecl(); + + bool Redeclaration = false; + bool OverloadableAttrRequired = false; + NamedDecl *PrevDecl = 0; + SemaRef.CheckFunctionDeclaration(Conversion, PrevDecl, Redeclaration, + /*FIXME:*/OverloadableAttrRequired); + Owner->addDecl(SemaRef.Context, Conversion); + return Conversion; +} + +ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) { + QualType OrigT = SemaRef.InstantiateType(D->getOriginalType(), TemplateArgs, + D->getLocation(), D->getDeclName()); + if (OrigT.isNull()) + return 0; + + QualType T = SemaRef.adjustParameterType(OrigT); + + if (D->getDefaultArg()) { + // FIXME: Leave a marker for "uninstantiated" default + // arguments. They only get instantiated on demand at the call + // site. + unsigned DiagID = SemaRef.Diags.getCustomDiagID(Diagnostic::Warning, + "sorry, dropping default argument during template instantiation"); + SemaRef.Diag(D->getDefaultArg()->getSourceRange().getBegin(), DiagID) + << D->getDefaultArg()->getSourceRange(); + } + + // Allocate the parameter + ParmVarDecl *Param = 0; + if (T == OrigT) + Param = ParmVarDecl::Create(SemaRef.Context, Owner, D->getLocation(), + D->getIdentifier(), T, D->getStorageClass(), + 0); + else + Param = OriginalParmVarDecl::Create(SemaRef.Context, Owner, + D->getLocation(), D->getIdentifier(), + T, OrigT, D->getStorageClass(), 0); + + // Note: we don't try to instantiate function parameters until after + // we've instantiated the function's type. Therefore, we don't have + // to check for 'void' parameter types here. + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param); + return Param; +} + +Decl * +TemplateDeclInstantiator::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) { + // Since parameter types can decay either before or after + // instantiation, we simply treat OriginalParmVarDecls as + // ParmVarDecls the same way, and create one or the other depending + // on what happens after template instantiation. + return VisitParmVarDecl(D); +} + +Decl *Sema::InstantiateDecl(Decl *D, DeclContext *Owner, + const TemplateArgumentList &TemplateArgs) { + TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs); + return Instantiator.Visit(D); +} + +/// \brief Instantiates the type of the given function, including +/// instantiating all of the function parameters. +/// +/// \param D The function that we will be instantiated +/// +/// \param Params the instantiated parameter declarations + +/// \returns the instantiated function's type if successfull, a NULL +/// type if there was an error. +QualType +TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D, + llvm::SmallVectorImpl<ParmVarDecl *> &Params) { + bool InvalidDecl = false; + + // Instantiate the function parameters + TemplateDeclInstantiator ParamInstantiator(SemaRef, 0, TemplateArgs); + llvm::SmallVector<QualType, 4> ParamTys; + for (FunctionDecl::param_iterator P = D->param_begin(), + PEnd = D->param_end(); + P != PEnd; ++P) { + if (ParmVarDecl *PInst = ParamInstantiator.VisitParmVarDecl(*P)) { + if (PInst->getType()->isVoidType()) { + SemaRef.Diag(PInst->getLocation(), diag::err_param_with_void_type); + PInst->setInvalidDecl(); + } + else if (SemaRef.RequireNonAbstractType(PInst->getLocation(), + PInst->getType(), + diag::err_abstract_type_in_decl, + Sema::AbstractParamType)) + PInst->setInvalidDecl(); + + Params.push_back(PInst); + ParamTys.push_back(PInst->getType()); + + if (PInst->isInvalidDecl()) + InvalidDecl = true; + } else + InvalidDecl = true; + } + + // FIXME: Deallocate dead declarations. + if (InvalidDecl) + return QualType(); + + const FunctionProtoType *Proto = D->getType()->getAsFunctionProtoType(); + assert(Proto && "Missing prototype?"); + QualType ResultType + = SemaRef.InstantiateType(Proto->getResultType(), TemplateArgs, + D->getLocation(), D->getDeclName()); + if (ResultType.isNull()) + return QualType(); + + return SemaRef.BuildFunctionType(ResultType, ParamTys.data(), ParamTys.size(), + Proto->isVariadic(), Proto->getTypeQuals(), + D->getLocation(), D->getDeclName()); +} + +/// \brief Initializes common fields of an instantiated method +/// declaration (New) from the corresponding fields of its template +/// (Tmpl). +/// +/// \returns true if there was an error +bool +TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, + CXXMethodDecl *Tmpl) { + CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner); + New->setAccess(Tmpl->getAccess()); + if (Tmpl->isVirtualAsWritten()) { + New->setVirtualAsWritten(true); + Record->setAggregate(false); + Record->setPOD(false); + Record->setPolymorphic(true); + } + if (Tmpl->isDeleted()) + New->setDeleted(); + if (Tmpl->isPure()) { + New->setPure(); + Record->setAbstract(true); + } + + // FIXME: attributes + // FIXME: New needs a pointer to Tmpl + return false; +} + +/// \brief Instantiate the definition of the given function from its +/// template. +/// +/// \param Function the already-instantiated declaration of a +/// function. +void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, + FunctionDecl *Function) { + // FIXME: make this work for function template specializations, too. + + if (Function->isInvalidDecl()) + return; + + // Find the function body that we'll be substituting. + const FunctionDecl *PatternDecl + = Function->getInstantiatedFromMemberFunction(); + Stmt *Pattern = 0; + if (PatternDecl) + Pattern = PatternDecl->getBody(Context, PatternDecl); + + if (!Pattern) + return; + + InstantiatingTemplate Inst(*this, PointOfInstantiation, Function); + if (Inst) + return; + + ActOnStartOfFunctionDef(0, DeclPtrTy::make(Function)); + + // Introduce a new scope where local variable instantiations will be + // recorded. + LocalInstantiationScope Scope(*this); + + // Introduce the instantiated function parameters into the local + // instantiation scope. + for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) + Scope.InstantiatedLocal(PatternDecl->getParamDecl(I), + Function->getParamDecl(I)); + + // Enter the scope of this instantiation. We don't use + // PushDeclContext because we don't have a scope. + DeclContext *PreviousContext = CurContext; + CurContext = Function; + + // Instantiate the function body. + OwningStmtResult Body + = InstantiateStmt(Pattern, getTemplateInstantiationArgs(Function)); + + ActOnFinishFunctionBody(DeclPtrTy::make(Function), move(Body), + /*IsInstantiation=*/true); + + CurContext = PreviousContext; + + DeclGroupRef DG(Function); + Consumer.HandleTopLevelDecl(DG); +} + +/// \brief Instantiate the definition of the given variable from its +/// template. +/// +/// \param Var the already-instantiated declaration of a variable. +void Sema::InstantiateVariableDefinition(VarDecl *Var) { + // FIXME: Implement this! +} + +static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { + if (D->getKind() != Other->getKind()) + return false; + + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Other)) + return Ctx.getCanonicalDecl(Record->getInstantiatedFromMemberClass()) + == Ctx.getCanonicalDecl(D); + + if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Other)) + return Ctx.getCanonicalDecl(Function->getInstantiatedFromMemberFunction()) + == Ctx.getCanonicalDecl(D); + + if (EnumDecl *Enum = dyn_cast<EnumDecl>(Other)) + return Ctx.getCanonicalDecl(Enum->getInstantiatedFromMemberEnum()) + == Ctx.getCanonicalDecl(D); + + // FIXME: How can we find instantiations of anonymous unions? + + return D->getDeclName() && isa<NamedDecl>(Other) && + D->getDeclName() == cast<NamedDecl>(Other)->getDeclName(); +} + +template<typename ForwardIterator> +static NamedDecl *findInstantiationOf(ASTContext &Ctx, + NamedDecl *D, + ForwardIterator first, + ForwardIterator last) { + for (; first != last; ++first) + if (isInstantiationOf(Ctx, D, *first)) + return cast<NamedDecl>(*first); + + return 0; +} + +/// \brief Find the instantiation of the given declaration within the +/// current instantiation. +/// +/// This routine is intended to be used when \p D is a declaration +/// referenced from within a template, that needs to mapped into the +/// corresponding declaration within an instantiation. For example, +/// given: +/// +/// \code +/// template<typename T> +/// struct X { +/// enum Kind { +/// KnownValue = sizeof(T) +/// }; +/// +/// bool getKind() const { return KnownValue; } +/// }; +/// +/// template struct X<int>; +/// \endcode +/// +/// In the instantiation of X<int>::getKind(), we need to map the +/// EnumConstantDecl for KnownValue (which refers to +/// X<T>::<Kind>::KnownValue) to its instantiation +/// (X<int>::<Kind>::KnownValue). InstantiateCurrentDeclRef() performs +/// this mapping from within the instantiation of X<int>. +NamedDecl * Sema::InstantiateCurrentDeclRef(NamedDecl *D) { + DeclContext *ParentDC = D->getDeclContext(); + if (isa<ParmVarDecl>(D) || ParentDC->isFunctionOrMethod()) { + // D is a local of some kind. Look into the map of local + // declarations to their instantiations. + return cast<NamedDecl>(CurrentInstantiationScope->getInstantiationOf(D)); + } + + if (NamedDecl *ParentDecl = dyn_cast<NamedDecl>(ParentDC)) { + ParentDecl = InstantiateCurrentDeclRef(ParentDecl); + if (!ParentDecl) + return 0; + + ParentDC = cast<DeclContext>(ParentDecl); + } + + if (ParentDC != D->getDeclContext()) { + // 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. + NamedDecl *Result = 0; + if (D->getDeclName()) { + DeclContext::lookup_result Found + = ParentDC->lookup(Context, D->getDeclName()); + Result = findInstantiationOf(Context, D, Found.first, Found.second); + } else { + // Since we don't have a name for the entity we're looking for, + // our only option is to walk through all of the declarations to + // find that name. This will occur in a few cases: + // + // - anonymous struct/union within a template + // - unnamed class/struct/union/enum within a template + // + // FIXME: Find a better way to find these instantiations! + Result = findInstantiationOf(Context, D, + ParentDC->decls_begin(Context), + ParentDC->decls_end(Context)); + } + assert(Result && "Unable to find instantiation of declaration!"); + D = Result; + } + + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) + if (ClassTemplateDecl *ClassTemplate + = Record->getDescribedClassTemplate()) { + // When the declaration D was parsed, it referred to the current + // instantiation. Therefore, look through the current context, + // which contains actual instantiations, to find the + // instantiation of the "current instantiation" that D refers + // to. Alternatively, we could just instantiate the + // injected-class-name with the current template arguments, but + // such an instantiation is far more expensive. + for (DeclContext *DC = CurContext; !DC->isFileContext(); + DC = DC->getParent()) { + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(DC)) + if (Context.getCanonicalDecl(Spec->getSpecializedTemplate()) + == Context.getCanonicalDecl(ClassTemplate)) + return Spec; + } + + assert(false && + "Unable to find declaration for the current instantiation"); + } + + return D; +} diff --git a/lib/Sema/SemaTemplateInstantiateExpr.cpp b/lib/Sema/SemaTemplateInstantiateExpr.cpp new file mode 100644 index 0000000..a6b9703 --- /dev/null +++ b/lib/Sema/SemaTemplateInstantiateExpr.cpp @@ -0,0 +1,1278 @@ +//===--- SemaTemplateInstantiateExpr.cpp - C++ Template Expr Instantiation ===/ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +//===----------------------------------------------------------------------===/ +// +// This file implements C++ template instantiation for expressions. +// +//===----------------------------------------------------------------------===/ +#include "Sema.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/Parse/DeclSpec.h" +#include "clang/Parse/Designator.h" +#include "clang/Lex/Preprocessor.h" // for the identifier table +#include "llvm/Support/Compiler.h" +using namespace clang; + +namespace { + class VISIBILITY_HIDDEN TemplateExprInstantiator + : public StmtVisitor<TemplateExprInstantiator, Sema::OwningExprResult> { + Sema &SemaRef; + const TemplateArgumentList &TemplateArgs; + + public: + typedef Sema::OwningExprResult OwningExprResult; + + TemplateExprInstantiator(Sema &SemaRef, + const TemplateArgumentList &TemplateArgs) + : SemaRef(SemaRef), TemplateArgs(TemplateArgs) { } + + // Declare VisitXXXStmt nodes for all of the expression kinds. +#define EXPR(Type, Base) OwningExprResult Visit##Type(Type *S); +#define STMT(Type, Base) +#include "clang/AST/StmtNodes.def" + + // Base case. We can't get here. + Sema::OwningExprResult VisitStmt(Stmt *S) { + S->dump(); + assert(false && "Cannot instantiate this kind of expression"); + return SemaRef.ExprError(); + } + }; +} + +// Base case. We can't get here. +Sema::OwningExprResult TemplateExprInstantiator::VisitExpr(Expr *E) { + E->dump(); + assert(false && "Cannot instantiate this kind of expression"); + return SemaRef.ExprError(); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitPredefinedExpr(PredefinedExpr *E) { + return SemaRef.Clone(E); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitIntegerLiteral(IntegerLiteral *E) { + return SemaRef.Clone(E); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitFloatingLiteral(FloatingLiteral *E) { + return SemaRef.Clone(E); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitStringLiteral(StringLiteral *E) { + return SemaRef.Clone(E); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCharacterLiteral(CharacterLiteral *E) { + return SemaRef.Clone(E); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitImaginaryLiteral(ImaginaryLiteral *E) { + return SemaRef.Clone(E); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { + return SemaRef.Clone(E); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) { + return SemaRef.Clone(E); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitGNUNullExpr(GNUNullExpr *E) { + return SemaRef.Clone(E); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitUnresolvedFunctionNameExpr( + UnresolvedFunctionNameExpr *E) { + return SemaRef.Clone(E); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitDeclRefExpr(DeclRefExpr *E) { + NamedDecl *D = E->getDecl(); + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) { + assert(NTTP->getDepth() == 0 && "No nested templates yet"); + const TemplateArgument &Arg = TemplateArgs[NTTP->getPosition()]; + QualType T = Arg.getIntegralType(); + if (T->isCharType() || T->isWideCharType()) + return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral( + Arg.getAsIntegral()->getZExtValue(), + T->isWideCharType(), + T, + E->getSourceRange().getBegin())); + else if (T->isBooleanType()) + return SemaRef.Owned(new (SemaRef.Context) CXXBoolLiteralExpr( + Arg.getAsIntegral()->getBoolValue(), + T, + E->getSourceRange().getBegin())); + + return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral( + *Arg.getAsIntegral(), + T, + E->getSourceRange().getBegin())); + } + + if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D)) { + // FIXME: instantiate each decl in the overload set + return SemaRef.Owned(new (SemaRef.Context) DeclRefExpr(Ovl, + SemaRef.Context.OverloadTy, + E->getLocation(), + false, false)); + } + + ValueDecl *NewD + = dyn_cast_or_null<ValueDecl>(SemaRef.InstantiateCurrentDeclRef(D)); + if (!NewD) + return SemaRef.ExprError(); + + // FIXME: Build QualifiedDeclRefExpr? + QualType T = NewD->getType(); + return SemaRef.Owned(new (SemaRef.Context) DeclRefExpr(NewD, + T.getNonReferenceType(), + E->getLocation(), + T->isDependentType(), + T->isDependentType())); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitParenExpr(ParenExpr *E) { + Sema::OwningExprResult SubExpr = Visit(E->getSubExpr()); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + + return SemaRef.Owned(new (SemaRef.Context) ParenExpr( + E->getLParen(), E->getRParen(), + (Expr *)SubExpr.release())); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitUnaryOperator(UnaryOperator *E) { + Sema::OwningExprResult Arg = Visit(E->getSubExpr()); + if (Arg.isInvalid()) + return SemaRef.ExprError(); + + return SemaRef.CreateBuiltinUnaryOp(E->getOperatorLoc(), + E->getOpcode(), + move(Arg)); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { + Sema::OwningExprResult LHS = Visit(E->getLHS()); + if (LHS.isInvalid()) + return SemaRef.ExprError(); + + Sema::OwningExprResult RHS = Visit(E->getRHS()); + if (RHS.isInvalid()) + return SemaRef.ExprError(); + + // Since the overloaded array-subscript operator (operator[]) can + // only be a member function, we can make several simplifying + // assumptions here: + // 1) Normal name lookup (from the current scope) will not ever + // find any declarations of operator[] that won't also be found be + // member operator lookup, so it is safe to pass a NULL Scope + // during the instantiation to avoid the lookup entirely. + // + // 2) Neither normal name lookup nor argument-dependent lookup at + // template definition time will find any operators that won't be + // found at template instantiation time, so we do not need to + // cache the results of name lookup as we do for the binary + // operators. + SourceLocation LLocFake = ((Expr*)LHS.get())->getSourceRange().getBegin(); + return SemaRef.ActOnArraySubscriptExpr(/*Scope=*/0, move(LHS), + /*FIXME:*/LLocFake, + move(RHS), + E->getRBracketLoc()); +} + +Sema::OwningExprResult TemplateExprInstantiator::VisitCallExpr(CallExpr *E) { + // Instantiate callee + OwningExprResult Callee = Visit(E->getCallee()); + if (Callee.isInvalid()) + return SemaRef.ExprError(); + + // Instantiate arguments + ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef); + llvm::SmallVector<SourceLocation, 4> FakeCommaLocs; + for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) { + OwningExprResult Arg = Visit(E->getArg(I)); + if (Arg.isInvalid()) + return SemaRef.ExprError(); + + FakeCommaLocs.push_back( + SemaRef.PP.getLocForEndOfToken(E->getArg(I)->getSourceRange().getEnd())); + Args.push_back(Arg.takeAs<Expr>()); + } + + SourceLocation FakeLParenLoc + = ((Expr *)Callee.get())->getSourceRange().getBegin(); + return SemaRef.ActOnCallExpr(/*Scope=*/0, move(Callee), + /*FIXME:*/FakeLParenLoc, + move_arg(Args), + /*FIXME:*/&FakeCommaLocs.front(), + E->getRParenLoc()); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitMemberExpr(MemberExpr *E) { + // Instantiate the base of the expression. + OwningExprResult Base = Visit(E->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + // FIXME: Handle declaration names here + SourceLocation FakeOperatorLoc = + SemaRef.PP.getLocForEndOfToken(E->getBase()->getSourceRange().getEnd()); + return SemaRef.ActOnMemberReferenceExpr(/*Scope=*/0, + move(Base), + /*FIXME*/FakeOperatorLoc, + E->isArrow()? tok::arrow + : tok::period, + E->getMemberLoc(), + /*FIXME:*/*E->getMemberDecl()->getIdentifier(), + /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0)); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { + SourceLocation FakeTypeLoc + = SemaRef.PP.getLocForEndOfToken(E->getLParenLoc()); + QualType T = SemaRef.InstantiateType(E->getType(), TemplateArgs, + FakeTypeLoc, + DeclarationName()); + if (T.isNull()) + return SemaRef.ExprError(); + + OwningExprResult Init = Visit(E->getInitializer()); + if (Init.isInvalid()) + return SemaRef.ExprError(); + + return SemaRef.ActOnCompoundLiteral(E->getLParenLoc(), + T.getAsOpaquePtr(), + /*FIXME*/E->getLParenLoc(), + move(Init)); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitBinaryOperator(BinaryOperator *E) { + Sema::OwningExprResult LHS = Visit(E->getLHS()); + if (LHS.isInvalid()) + return SemaRef.ExprError(); + + Sema::OwningExprResult RHS = Visit(E->getRHS()); + if (RHS.isInvalid()) + return SemaRef.ExprError(); + + Sema::OwningExprResult Result + = SemaRef.CreateBuiltinBinOp(E->getOperatorLoc(), + E->getOpcode(), + (Expr *)LHS.get(), + (Expr *)RHS.get()); + if (Result.isInvalid()) + return SemaRef.ExprError(); + + LHS.release(); + RHS.release(); + return move(Result); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCompoundAssignOperator( + CompoundAssignOperator *E) { + return VisitBinaryOperator(E); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + Sema::OwningExprResult First = Visit(E->getArg(0)); + if (First.isInvalid()) + return SemaRef.ExprError(); + + Expr *Args[2] = { (Expr *)First.get(), 0 }; + + Sema::OwningExprResult Second(SemaRef); + if (E->getNumArgs() == 2) { + Second = Visit(E->getArg(1)); + + if (Second.isInvalid()) + return SemaRef.ExprError(); + + Args[1] = (Expr *)Second.get(); + } + + if (!E->isTypeDependent()) { + // Since our original expression was not type-dependent, we do not + // perform lookup again at instantiation time (C++ [temp.dep]p1). + // Instead, we just build the new overloaded operator call + // expression. + OwningExprResult Callee = Visit(E->getCallee()); + if (Callee.isInvalid()) + return SemaRef.ExprError(); + + First.release(); + Second.release(); + + return SemaRef.Owned(new (SemaRef.Context) CXXOperatorCallExpr( + SemaRef.Context, + E->getOperator(), + Callee.takeAs<Expr>(), + Args, E->getNumArgs(), + E->getType(), + E->getOperatorLoc())); + } + + bool isPostIncDec = E->getNumArgs() == 2 && + (E->getOperator() == OO_PlusPlus || E->getOperator() == OO_MinusMinus); + if (E->getNumArgs() == 1 || isPostIncDec) { + if (!Args[0]->getType()->isOverloadableType()) { + // The argument is not of overloadable type, so try to create a + // built-in unary operation. + UnaryOperator::Opcode Opc + = UnaryOperator::getOverloadedOpcode(E->getOperator(), isPostIncDec); + + return SemaRef.CreateBuiltinUnaryOp(E->getOperatorLoc(), Opc, + move(First)); + } + + // Fall through to perform overload resolution + } else { + assert(E->getNumArgs() == 2 && "Expected binary operation"); + + Sema::OwningExprResult Result(SemaRef); + if (!Args[0]->getType()->isOverloadableType() && + !Args[1]->getType()->isOverloadableType()) { + // Neither of the arguments is an overloadable type, so try to + // create a built-in binary operation. + BinaryOperator::Opcode Opc = + BinaryOperator::getOverloadedOpcode(E->getOperator()); + Result = SemaRef.CreateBuiltinBinOp(E->getOperatorLoc(), Opc, + Args[0], Args[1]); + if (Result.isInvalid()) + return SemaRef.ExprError(); + + First.release(); + Second.release(); + return move(Result); + } + + // Fall through to perform overload resolution. + } + + // Compute the set of functions that were found at template + // definition time. + Sema::FunctionSet Functions; + DeclRefExpr *DRE = cast<DeclRefExpr>(E->getCallee()); + OverloadedFunctionDecl *Overloads + = cast<OverloadedFunctionDecl>(DRE->getDecl()); + + // FIXME: Do we have to check + // IsAcceptableNonMemberOperatorCandidate for each of these? + for (OverloadedFunctionDecl::function_iterator + F = Overloads->function_begin(), + FEnd = Overloads->function_end(); + F != FEnd; ++F) + Functions.insert(*F); + + // Add any functions found via argument-dependent lookup. + DeclarationName OpName + = SemaRef.Context.DeclarationNames.getCXXOperatorName(E->getOperator()); + SemaRef.ArgumentDependentLookup(OpName, Args, E->getNumArgs(), Functions); + + // Create the overloaded operator invocation. + if (E->getNumArgs() == 1 || isPostIncDec) { + UnaryOperator::Opcode Opc + = UnaryOperator::getOverloadedOpcode(E->getOperator(), isPostIncDec); + return SemaRef.CreateOverloadedUnaryOp(E->getOperatorLoc(), Opc, + Functions, move(First)); + } + + // FIXME: This would be far less ugly if CreateOverloadedBinOp took in ExprArg + // arguments! + BinaryOperator::Opcode Opc = + BinaryOperator::getOverloadedOpcode(E->getOperator()); + OwningExprResult Result + = SemaRef.CreateOverloadedBinOp(E->getOperatorLoc(), Opc, + Functions, Args[0], Args[1]); + + if (Result.isInvalid()) + return SemaRef.ExprError(); + + First.release(); + Second.release(); + return move(Result); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXConditionDeclExpr(CXXConditionDeclExpr *E) { + VarDecl *Var + = cast_or_null<VarDecl>(SemaRef.InstantiateDecl(E->getVarDecl(), + SemaRef.CurContext, + TemplateArgs)); + if (!Var) + return SemaRef.ExprError(); + + SemaRef.CurrentInstantiationScope->InstantiatedLocal(E->getVarDecl(), Var); + return SemaRef.Owned(new (SemaRef.Context) CXXConditionDeclExpr( + E->getStartLoc(), + SourceLocation(), + Var)); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitConditionalOperator(ConditionalOperator *E) { + Sema::OwningExprResult Cond = Visit(E->getCond()); + if (Cond.isInvalid()) + return SemaRef.ExprError(); + + Sema::OwningExprResult LHS = SemaRef.InstantiateExpr(E->getLHS(), + TemplateArgs); + if (LHS.isInvalid()) + return SemaRef.ExprError(); + + Sema::OwningExprResult RHS = Visit(E->getRHS()); + if (RHS.isInvalid()) + return SemaRef.ExprError(); + + if (!E->isTypeDependent()) { + // Since our original expression was not type-dependent, we do not + // perform lookup again at instantiation time (C++ [temp.dep]p1). + // Instead, we just build the new conditional operator call expression. + return SemaRef.Owned(new (SemaRef.Context) ConditionalOperator( + Cond.takeAs<Expr>(), + LHS.takeAs<Expr>(), + RHS.takeAs<Expr>(), + E->getType())); + } + + + return SemaRef.ActOnConditionalOp(/*FIXME*/E->getCond()->getLocEnd(), + /*FIXME*/E->getFalseExpr()->getLocStart(), + move(Cond), move(LHS), move(RHS)); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitAddrLabelExpr(AddrLabelExpr *E) { + return SemaRef.ActOnAddrLabel(E->getAmpAmpLoc(), + E->getLabelLoc(), + E->getLabel()->getID()); +} + +Sema::OwningExprResult TemplateExprInstantiator::VisitStmtExpr(StmtExpr *E) { + Sema::OwningStmtResult SubStmt + = SemaRef.InstantiateCompoundStmt(E->getSubStmt(), TemplateArgs, true); + if (SubStmt.isInvalid()) + return SemaRef.ExprError(); + + return SemaRef.ActOnStmtExpr(E->getLParenLoc(), move(SubStmt), + E->getRParenLoc()); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitTypesCompatibleExpr(TypesCompatibleExpr *E) { + assert(false && "__builtin_types_compatible_p is not legal in C++"); + return SemaRef.ExprError(); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { + ASTOwningVector<&ActionBase::DeleteExpr> SubExprs(SemaRef); + for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I) { + OwningExprResult SubExpr = Visit(E->getExpr(I)); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + + SubExprs.push_back(SubExpr.takeAs<Expr>()); + } + + // Find the declaration for __builtin_shufflevector + const IdentifierInfo &Name + = SemaRef.Context.Idents.get("__builtin_shufflevector"); + TranslationUnitDecl *TUDecl = SemaRef.Context.getTranslationUnitDecl(); + DeclContext::lookup_result Lookup + = TUDecl->lookup(SemaRef.Context, DeclarationName(&Name)); + assert(Lookup.first != Lookup.second && "No __builtin_shufflevector?"); + + // Build a reference to the __builtin_shufflevector builtin + FunctionDecl *Builtin = cast<FunctionDecl>(*Lookup.first); + Expr *Callee = new (SemaRef.Context) DeclRefExpr(Builtin, Builtin->getType(), + E->getBuiltinLoc(), + false, false); + SemaRef.UsualUnaryConversions(Callee); + + // Build the CallExpr + CallExpr *TheCall = new (SemaRef.Context) CallExpr(SemaRef.Context, Callee, + SubExprs.takeAs<Expr>(), + SubExprs.size(), + Builtin->getResultType(), + E->getRParenLoc()); + OwningExprResult OwnedCall(SemaRef.Owned(TheCall)); + + // Type-check the __builtin_shufflevector expression. + OwningExprResult Result = SemaRef.SemaBuiltinShuffleVector(TheCall); + if (Result.isInvalid()) + return SemaRef.ExprError(); + + OwnedCall.release(); + return move(Result); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitChooseExpr(ChooseExpr *E) { + OwningExprResult Cond = Visit(E->getCond()); + if (Cond.isInvalid()) + return SemaRef.ExprError(); + + OwningExprResult LHS = SemaRef.InstantiateExpr(E->getLHS(), TemplateArgs); + if (LHS.isInvalid()) + return SemaRef.ExprError(); + + OwningExprResult RHS = Visit(E->getRHS()); + if (RHS.isInvalid()) + return SemaRef.ExprError(); + + return SemaRef.ActOnChooseExpr(E->getBuiltinLoc(), + move(Cond), move(LHS), move(RHS), + E->getRParenLoc()); +} + +Sema::OwningExprResult TemplateExprInstantiator::VisitVAArgExpr(VAArgExpr *E) { + OwningExprResult SubExpr = Visit(E->getSubExpr()); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + + SourceLocation FakeTypeLoc + = SemaRef.PP.getLocForEndOfToken(E->getSubExpr()->getSourceRange() + .getEnd()); + QualType T = SemaRef.InstantiateType(E->getType(), TemplateArgs, + /*FIXME:*/FakeTypeLoc, + DeclarationName()); + if (T.isNull()) + return SemaRef.ExprError(); + + return SemaRef.ActOnVAArg(E->getBuiltinLoc(), move(SubExpr), + T.getAsOpaquePtr(), E->getRParenLoc()); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitInitListExpr(InitListExpr *E) { + ASTOwningVector<&ActionBase::DeleteExpr, 4> Inits(SemaRef); + for (unsigned I = 0, N = E->getNumInits(); I != N; ++I) { + OwningExprResult Init = Visit(E->getInit(I)); + if (Init.isInvalid()) + return SemaRef.ExprError(); + Inits.push_back(Init.takeAs<Expr>()); + } + + return SemaRef.ActOnInitList(E->getLBraceLoc(), move_arg(Inits), + E->getRBraceLoc()); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitDesignatedInitExpr(DesignatedInitExpr *E) { + Designation Desig; + + // Instantiate the initializer value + OwningExprResult Init = Visit(E->getInit()); + if (Init.isInvalid()) + return SemaRef.ExprError(); + + // Instantiate the designators. + ASTOwningVector<&ActionBase::DeleteExpr, 4> ArrayExprs(SemaRef); + for (DesignatedInitExpr::designators_iterator D = E->designators_begin(), + DEnd = E->designators_end(); + D != DEnd; ++D) { + if (D->isFieldDesignator()) { + Desig.AddDesignator(Designator::getField(D->getFieldName(), + D->getDotLoc(), + D->getFieldLoc())); + continue; + } + + if (D->isArrayDesignator()) { + OwningExprResult Index = Visit(E->getArrayIndex(*D)); + if (Index.isInvalid()) + return SemaRef.ExprError(); + + Desig.AddDesignator(Designator::getArray(Index.get(), + D->getLBracketLoc())); + + ArrayExprs.push_back(Index.release()); + continue; + } + + assert(D->isArrayRangeDesignator() && "New kind of designator?"); + OwningExprResult Start = Visit(E->getArrayRangeStart(*D)); + if (Start.isInvalid()) + return SemaRef.ExprError(); + + OwningExprResult End = Visit(E->getArrayRangeEnd(*D)); + if (End.isInvalid()) + return SemaRef.ExprError(); + + Desig.AddDesignator(Designator::getArrayRange(Start.get(), + End.get(), + D->getLBracketLoc(), + D->getEllipsisLoc())); + + ArrayExprs.push_back(Start.release()); + ArrayExprs.push_back(End.release()); + } + + OwningExprResult Result = + SemaRef.ActOnDesignatedInitializer(Desig, + E->getEqualOrColonLoc(), + E->usesGNUSyntax(), + move(Init)); + if (Result.isInvalid()) + return SemaRef.ExprError(); + + ArrayExprs.take(); + return move(Result); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitImplicitValueInitExpr( + ImplicitValueInitExpr *E) { + assert(!E->isTypeDependent() && !E->isValueDependent() && + "ImplicitValueInitExprs are never dependent"); + return SemaRef.Clone(E); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitExtVectorElementExpr(ExtVectorElementExpr *E) { + OwningExprResult Base = Visit(E->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + SourceLocation FakeOperatorLoc = + SemaRef.PP.getLocForEndOfToken(E->getBase()->getSourceRange().getEnd()); + return SemaRef.ActOnMemberReferenceExpr(/*Scope=*/0, + move(Base), + /*FIXME*/FakeOperatorLoc, + tok::period, + E->getAccessorLoc(), + E->getAccessor(), + /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0)); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitBlockExpr(BlockExpr *E) { + assert(false && "FIXME:Template instantiation for blocks is unimplemented"); + return SemaRef.ExprError(); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { + assert(false && "FIXME:Template instantiation for blocks is unimplemented"); + return SemaRef.ExprError(); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { + bool isSizeOf = E->isSizeOf(); + + if (E->isArgumentType()) { + QualType T = E->getArgumentType(); + if (T->isDependentType()) { + T = SemaRef.InstantiateType(T, TemplateArgs, + /*FIXME*/E->getOperatorLoc(), + &SemaRef.PP.getIdentifierTable().get("sizeof")); + if (T.isNull()) + return SemaRef.ExprError(); + } + + return SemaRef.CreateSizeOfAlignOfExpr(T, E->getOperatorLoc(), isSizeOf, + E->getSourceRange()); + } + + Sema::OwningExprResult Arg = Visit(E->getArgumentExpr()); + if (Arg.isInvalid()) + return SemaRef.ExprError(); + + Sema::OwningExprResult Result + = SemaRef.CreateSizeOfAlignOfExpr((Expr *)Arg.get(), E->getOperatorLoc(), + isSizeOf, E->getSourceRange()); + if (Result.isInvalid()) + return SemaRef.ExprError(); + + Arg.release(); + return move(Result); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *E) { + NestedNameSpecifier *NNS + = SemaRef.InstantiateNestedNameSpecifier(E->getQualifier(), + E->getQualifierRange(), + TemplateArgs); + if (!NNS) + return SemaRef.ExprError(); + + CXXScopeSpec SS; + SS.setRange(E->getQualifierRange()); + SS.setScopeRep(NNS); + + // FIXME: We're passing in a NULL scope, because + // ActOnDeclarationNameExpr doesn't actually use the scope when we + // give it a non-empty scope specifier. Investigate whether it would + // be better to refactor ActOnDeclarationNameExpr. + return SemaRef.ActOnDeclarationNameExpr(/*Scope=*/0, E->getLocation(), + E->getDeclName(), + /*HasTrailingLParen=*/false, + &SS, + /*FIXME:isAddressOfOperand=*/false); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXTemporaryObjectExpr( + CXXTemporaryObjectExpr *E) { + QualType T = E->getType(); + if (T->isDependentType()) { + T = SemaRef.InstantiateType(T, TemplateArgs, + E->getTypeBeginLoc(), DeclarationName()); + if (T.isNull()) + return SemaRef.ExprError(); + } + + ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef); + Args.reserve(E->getNumArgs()); + for (CXXTemporaryObjectExpr::arg_iterator Arg = E->arg_begin(), + ArgEnd = E->arg_end(); + Arg != ArgEnd; ++Arg) { + OwningExprResult InstantiatedArg = Visit(*Arg); + if (InstantiatedArg.isInvalid()) + return SemaRef.ExprError(); + + Args.push_back((Expr *)InstantiatedArg.release()); + } + + SourceLocation CommaLoc; + // FIXME: HACK! + if (Args.size() > 1) { + Expr *First = (Expr *)Args[0]; + CommaLoc + = SemaRef.PP.getLocForEndOfToken(First->getSourceRange().getEnd()); + } + return SemaRef.ActOnCXXTypeConstructExpr(SourceRange(E->getTypeBeginLoc() + /*, FIXME*/), + T.getAsOpaquePtr(), + /*FIXME*/E->getTypeBeginLoc(), + move_arg(Args), + /*HACK*/&CommaLoc, + E->getSourceRange().getEnd()); +} + +Sema::OwningExprResult TemplateExprInstantiator::VisitCastExpr(CastExpr *E) { + assert(false && "Cannot instantiate abstract CastExpr"); + return SemaRef.ExprError(); +} + +Sema::OwningExprResult TemplateExprInstantiator::VisitImplicitCastExpr( + ImplicitCastExpr *E) { + assert(!E->isTypeDependent() && "Implicit casts must have known types"); + + Sema::OwningExprResult SubExpr = Visit(E->getSubExpr()); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + + ImplicitCastExpr *ICE = + new (SemaRef.Context) ImplicitCastExpr(E->getType(), + (Expr *)SubExpr.release(), + E->isLvalueCast()); + return SemaRef.Owned(ICE); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitExplicitCastExpr(ExplicitCastExpr *E) { + assert(false && "Cannot instantiate abstract ExplicitCastExpr"); + return SemaRef.ExprError(); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCStyleCastExpr(CStyleCastExpr *E) { + // Instantiate the type that we're casting to. + SourceLocation TypeStartLoc + = SemaRef.PP.getLocForEndOfToken(E->getLParenLoc()); + QualType ExplicitTy = SemaRef.InstantiateType(E->getTypeAsWritten(), + TemplateArgs, + TypeStartLoc, + DeclarationName()); + if (ExplicitTy.isNull()) + return SemaRef.ExprError(); + + // Instantiate the subexpression. + OwningExprResult SubExpr = Visit(E->getSubExpr()); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + + return SemaRef.ActOnCastExpr(E->getLParenLoc(), + ExplicitTy.getAsOpaquePtr(), + E->getRParenLoc(), + move(SubExpr)); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) { + return VisitCallExpr(E); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) { + // Figure out which cast operator we're dealing with. + tok::TokenKind Kind; + switch (E->getStmtClass()) { + case Stmt::CXXStaticCastExprClass: + Kind = tok::kw_static_cast; + break; + + case Stmt::CXXDynamicCastExprClass: + Kind = tok::kw_dynamic_cast; + break; + + case Stmt::CXXReinterpretCastExprClass: + Kind = tok::kw_reinterpret_cast; + break; + + case Stmt::CXXConstCastExprClass: + Kind = tok::kw_const_cast; + break; + + default: + assert(false && "Invalid C++ named cast"); + return SemaRef.ExprError(); + } + + // Instantiate the type that we're casting to. + SourceLocation TypeStartLoc + = SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc()); + QualType ExplicitTy = SemaRef.InstantiateType(E->getTypeAsWritten(), + TemplateArgs, + TypeStartLoc, + DeclarationName()); + if (ExplicitTy.isNull()) + return SemaRef.ExprError(); + + // Instantiate the subexpression. + OwningExprResult SubExpr = Visit(E->getSubExpr()); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + + SourceLocation FakeLAngleLoc + = SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc()); + SourceLocation FakeRAngleLoc = E->getSubExpr()->getSourceRange().getBegin(); + SourceLocation FakeRParenLoc + = SemaRef.PP.getLocForEndOfToken( + E->getSubExpr()->getSourceRange().getEnd()); + return SemaRef.ActOnCXXNamedCast(E->getOperatorLoc(), Kind, + /*FIXME:*/FakeLAngleLoc, + ExplicitTy.getAsOpaquePtr(), + /*FIXME:*/FakeRAngleLoc, + /*FIXME:*/FakeRAngleLoc, + move(SubExpr), + /*FIXME:*/FakeRParenLoc); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) { + return VisitCXXNamedCastExpr(E); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E) { + return VisitCXXNamedCastExpr(E); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXReinterpretCastExpr( + CXXReinterpretCastExpr *E) { + return VisitCXXNamedCastExpr(E); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXConstCastExpr(CXXConstCastExpr *E) { + return VisitCXXNamedCastExpr(E); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXThisExpr(CXXThisExpr *E) { + QualType ThisType = + cast<CXXMethodDecl>(SemaRef.CurContext)->getThisType(SemaRef.Context); + + CXXThisExpr *TE = + new (SemaRef.Context) CXXThisExpr(E->getLocStart(), ThisType); + + return SemaRef.Owned(TE); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXTypeidExpr(CXXTypeidExpr *E) { + if (E->isTypeOperand()) { + QualType T = SemaRef.InstantiateType(E->getTypeOperand(), + TemplateArgs, + /*FIXME*/E->getSourceRange().getBegin(), + DeclarationName()); + if (T.isNull()) + return SemaRef.ExprError(); + + return SemaRef.ActOnCXXTypeid(E->getSourceRange().getBegin(), + /*FIXME*/E->getSourceRange().getBegin(), + true, T.getAsOpaquePtr(), + E->getSourceRange().getEnd()); + } + + OwningExprResult Operand = Visit(E->getExprOperand()); + if (Operand.isInvalid()) + return SemaRef.ExprError(); + + OwningExprResult Result + = SemaRef.ActOnCXXTypeid(E->getSourceRange().getBegin(), + /*FIXME*/E->getSourceRange().getBegin(), + false, Operand.get(), + E->getSourceRange().getEnd()); + if (Result.isInvalid()) + return SemaRef.ExprError(); + + Operand.release(); // FIXME: since ActOnCXXTypeid silently took ownership + return move(Result); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXThrowExpr(CXXThrowExpr *E) { + OwningExprResult SubExpr(SemaRef, (void *)0); + if (E->getSubExpr()) { + SubExpr = Visit(E->getSubExpr()); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + } + + return SemaRef.ActOnCXXThrow(E->getThrowLoc(), move(SubExpr)); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { + assert(false && + "FIXME: Instantiation for default arguments is unimplemented"); + return SemaRef.ExprError(); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXBindTemporaryExpr( + CXXBindTemporaryExpr *E) { + OwningExprResult SubExpr = Visit(E->getSubExpr()); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + + return SemaRef.MaybeBindToTemporary(SubExpr.takeAs<Expr>()); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXConstructExpr(CXXConstructExpr *E) { + assert(!cast<CXXRecordDecl>(E->getConstructor()->getDeclContext()) + ->isDependentType() && "Dependent constructor shouldn't be here"); + + QualType T = SemaRef.InstantiateType(E->getType(), TemplateArgs, + /*FIXME*/E->getSourceRange().getBegin(), + DeclarationName()); + if (T.isNull()) + return SemaRef.ExprError(); + + ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef); + for (CXXConstructExpr::arg_iterator Arg = E->arg_begin(), + ArgEnd = E->arg_end(); + Arg != ArgEnd; ++Arg) { + OwningExprResult ArgInst = Visit(*Arg); + if (ArgInst.isInvalid()) + return SemaRef.ExprError(); + + Args.push_back(ArgInst.takeAs<Expr>()); + } + + return SemaRef.Owned(CXXConstructExpr::Create(SemaRef.Context, T, + E->getConstructor(), + E->isElidable(), + Args.takeAs<Expr>(), + Args.size())); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXFunctionalCastExpr( + CXXFunctionalCastExpr *E) { + // Instantiate the type that we're casting to. + QualType ExplicitTy = SemaRef.InstantiateType(E->getTypeAsWritten(), + TemplateArgs, + E->getTypeBeginLoc(), + DeclarationName()); + if (ExplicitTy.isNull()) + return SemaRef.ExprError(); + + // Instantiate the subexpression. + OwningExprResult SubExpr = Visit(E->getSubExpr()); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + + // FIXME: The end of the type's source range is wrong + Expr *Sub = SubExpr.takeAs<Expr>(); + return SemaRef.ActOnCXXTypeConstructExpr(SourceRange(E->getTypeBeginLoc()), + ExplicitTy.getAsOpaquePtr(), + /*FIXME:*/E->getTypeBeginLoc(), + Sema::MultiExprArg(SemaRef, + (void **)&Sub, + 1), + 0, + E->getRParenLoc()); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) { + return SemaRef.Clone(E); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXNewExpr(CXXNewExpr *E) { + // Instantiate the type that we're allocating + QualType AllocType = SemaRef.InstantiateType(E->getAllocatedType(), + TemplateArgs, + /*FIXME:*/E->getSourceRange().getBegin(), + DeclarationName()); + if (AllocType.isNull()) + return SemaRef.ExprError(); + + // Instantiate the size of the array we're allocating (if any). + OwningExprResult ArraySize = SemaRef.InstantiateExpr(E->getArraySize(), + TemplateArgs); + if (ArraySize.isInvalid()) + return SemaRef.ExprError(); + + // Instantiate the placement arguments (if any). + ASTOwningVector<&ActionBase::DeleteExpr> PlacementArgs(SemaRef); + for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I) { + OwningExprResult Arg = Visit(E->getPlacementArg(I)); + if (Arg.isInvalid()) + return SemaRef.ExprError(); + + PlacementArgs.push_back(Arg.take()); + } + + // Instantiate the constructor arguments (if any). + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(SemaRef); + for (unsigned I = 0, N = E->getNumConstructorArgs(); I != N; ++I) { + OwningExprResult Arg = Visit(E->getConstructorArg(I)); + if (Arg.isInvalid()) + return SemaRef.ExprError(); + + ConstructorArgs.push_back(Arg.take()); + } + + return SemaRef.BuildCXXNew(E->getSourceRange().getBegin(), + E->isGlobalNew(), + /*FIXME*/SourceLocation(), + move_arg(PlacementArgs), + /*FIXME*/SourceLocation(), + E->isParenTypeId(), + AllocType, + /*FIXME*/E->getSourceRange().getBegin(), + SourceRange(), + move(ArraySize), + /*FIXME*/SourceLocation(), + Sema::MultiExprArg(SemaRef, + ConstructorArgs.take(), + ConstructorArgs.size()), + E->getSourceRange().getEnd()); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXDeleteExpr(CXXDeleteExpr *E) { + OwningExprResult Operand = Visit(E->getArgument()); + if (Operand.isInvalid()) + return SemaRef.ExprError(); + + return SemaRef.ActOnCXXDelete(E->getSourceRange().getBegin(), + E->isGlobalDelete(), + E->isArrayForm(), + move(Operand)); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { + QualType T = SemaRef.InstantiateType(E->getQueriedType(), TemplateArgs, + /*FIXME*/E->getSourceRange().getBegin(), + DeclarationName()); + if (T.isNull()) + return SemaRef.ExprError(); + + SourceLocation FakeLParenLoc + = SemaRef.PP.getLocForEndOfToken(E->getSourceRange().getBegin()); + return SemaRef.ActOnUnaryTypeTrait(E->getTrait(), + E->getSourceRange().getBegin(), + /*FIXME*/FakeLParenLoc, + T.getAsOpaquePtr(), + E->getSourceRange().getEnd()); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitQualifiedDeclRefExpr(QualifiedDeclRefExpr *E) { + NestedNameSpecifier *NNS + = SemaRef.InstantiateNestedNameSpecifier(E->getQualifier(), + E->getQualifierRange(), + TemplateArgs); + if (!NNS) + return SemaRef.ExprError(); + + CXXScopeSpec SS; + SS.setRange(E->getQualifierRange()); + SS.setScopeRep(NNS); + return SemaRef.ActOnDeclarationNameExpr(/*Scope=*/0, + E->getLocation(), + E->getDecl()->getDeclName(), + /*Trailing lparen=*/false, + &SS, + /*FIXME:*/false); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXExprWithTemporaries( + CXXExprWithTemporaries *E) { + OwningExprResult SubExpr = Visit(E->getSubExpr()); + if (SubExpr.isInvalid()) + return SemaRef.ExprError(); + + return SemaRef.ActOnFinishFullExpr(move(SubExpr)); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXUnresolvedConstructExpr( + CXXUnresolvedConstructExpr *E) { + QualType T = SemaRef.InstantiateType(E->getTypeAsWritten(), TemplateArgs, + E->getTypeBeginLoc(), + DeclarationName()); + if (T.isNull()) + return SemaRef.ExprError(); + + ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef); + llvm::SmallVector<SourceLocation, 8> FakeCommaLocs; + for (CXXUnresolvedConstructExpr::arg_iterator Arg = E->arg_begin(), + ArgEnd = E->arg_end(); + Arg != ArgEnd; ++Arg) { + OwningExprResult InstArg = Visit(*Arg); + if (InstArg.isInvalid()) + return SemaRef.ExprError(); + + FakeCommaLocs.push_back( + SemaRef.PP.getLocForEndOfToken((*Arg)->getSourceRange().getEnd())); + Args.push_back(InstArg.takeAs<Expr>()); + } + + // FIXME: The end of the type range isn't exactly correct. + // FIXME: we're faking the locations of the commas + return SemaRef.ActOnCXXTypeConstructExpr(SourceRange(E->getTypeBeginLoc(), + E->getLParenLoc()), + T.getAsOpaquePtr(), + E->getLParenLoc(), + move_arg(Args), + &FakeCommaLocs.front(), + E->getRParenLoc()); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXUnresolvedMemberExpr( + CXXUnresolvedMemberExpr *E) { + // Instantiate the base of the expression. + OwningExprResult Base = Visit(E->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + // FIXME: Instantiate the declaration name. + return SemaRef.ActOnMemberReferenceExpr(/*Scope=*/0, + move(Base), E->getOperatorLoc(), + E->isArrow()? tok::arrow + : tok::period, + E->getMemberLoc(), + /*FIXME:*/*E->getMember().getAsIdentifierInfo(), + /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0)); +} + +//---------------------------------------------------------------------------- +// Objective-C Expressions +//---------------------------------------------------------------------------- +Sema::OwningExprResult +TemplateExprInstantiator::VisitObjCStringLiteral(ObjCStringLiteral *E) { + assert(false && "FIXME: Template instantiations for ObjC expressions"); + return SemaRef.ExprError(); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitObjCEncodeExpr(ObjCEncodeExpr *E) { + assert(false && "FIXME: Template instantiations for ObjC expressions"); + return SemaRef.ExprError(); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitObjCMessageExpr(ObjCMessageExpr *E) { + assert(false && "FIXME: Template instantiations for ObjC expressions"); + return SemaRef.ExprError(); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitObjCSelectorExpr(ObjCSelectorExpr *E) { + assert(false && "FIXME: Template instantiations for ObjC expressions"); + return SemaRef.ExprError(); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitObjCProtocolExpr(ObjCProtocolExpr *E) { + assert(false && "FIXME: Template instantiations for ObjC expressions"); + return SemaRef.ExprError(); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { + assert(false && "FIXME: Template instantiations for ObjC expressions"); + return SemaRef.ExprError(); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { + assert(false && "FIXME: Template instantiations for ObjC expressions"); + return SemaRef.ExprError(); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitObjCKVCRefExpr(ObjCKVCRefExpr *E) { + assert(false && "FIXME: Template instantiations for ObjC expressions"); + return SemaRef.ExprError(); +} + +Sema::OwningExprResult +TemplateExprInstantiator::VisitObjCSuperExpr(ObjCSuperExpr *E) { + assert(false && "FIXME: Template instantiations for ObjC expressions"); + return SemaRef.ExprError(); +} + +Sema::OwningExprResult +Sema::InstantiateExpr(Expr *E, const TemplateArgumentList &TemplateArgs) { + if (!E) + return Owned((Expr *)0); + + TemplateExprInstantiator Instantiator(*this, TemplateArgs); + return Instantiator.Visit(E); +} diff --git a/lib/Sema/SemaTemplateInstantiateStmt.cpp b/lib/Sema/SemaTemplateInstantiateStmt.cpp new file mode 100644 index 0000000..1f69479 --- /dev/null +++ b/lib/Sema/SemaTemplateInstantiateStmt.cpp @@ -0,0 +1,443 @@ +//===--- SemaTemplateInstantiateStmt.cpp - C++ Template Stmt Instantiation ===/ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +//===----------------------------------------------------------------------===/ +// +// This file implements C++ template instantiation for statements. +// +//===----------------------------------------------------------------------===/ +#include "Sema.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/Parse/DeclSpec.h" +#include "llvm/Support/Compiler.h" +using namespace clang; + +namespace { + class VISIBILITY_HIDDEN TemplateStmtInstantiator + : public StmtVisitor<TemplateStmtInstantiator, Sema::OwningStmtResult> { + Sema &SemaRef; + const TemplateArgumentList &TemplateArgs; + + template<typename T> + Sema::FullExprArg FullExpr(T &expr) { + return SemaRef.FullExpr(expr); + } + + public: + typedef Sema::OwningExprResult OwningExprResult; + typedef Sema::OwningStmtResult OwningStmtResult; + + TemplateStmtInstantiator(Sema &SemaRef, + const TemplateArgumentList &TemplateArgs) + : SemaRef(SemaRef), TemplateArgs(TemplateArgs) { } + + // Declare VisitXXXStmt nodes for all of the statement kinds. +#define STMT(Type, Base) OwningStmtResult Visit##Type(Type *S); +#define EXPR(Type, Base) +#include "clang/AST/StmtNodes.def" + + // Visit an expression (which will use the expression + // instantiator). + OwningStmtResult VisitExpr(Expr *E); + + // Base case. I'm supposed to ignore this. + OwningStmtResult VisitStmt(Stmt *S) { + S->dump(); + assert(false && "Cannot instantiate this kind of statement"); + return SemaRef.StmtError(); + } + }; +} + +//===----------------------------------------------------------------------===/ +// Common/C statements +//===----------------------------------------------------------------------===/ +Sema::OwningStmtResult TemplateStmtInstantiator::VisitDeclStmt(DeclStmt *S) { + llvm::SmallVector<Decl *, 4> Decls; + for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); + D != DEnd; ++D) { + Decl *Instantiated = SemaRef.InstantiateDecl(*D, SemaRef.CurContext, + TemplateArgs); + if (!Instantiated) + return SemaRef.StmtError(); + + Decls.push_back(Instantiated); + SemaRef.CurrentInstantiationScope->InstantiatedLocal(*D, Instantiated); + } + + return SemaRef.Owned(new (SemaRef.Context) DeclStmt( + DeclGroupRef::Create(SemaRef.Context, + &Decls[0], + Decls.size()), + S->getStartLoc(), + S->getEndLoc())); +} + +Sema::OwningStmtResult TemplateStmtInstantiator::VisitNullStmt(NullStmt *S) { + return SemaRef.Owned(S->Clone(SemaRef.Context)); +} + +Sema::OwningStmtResult TemplateStmtInstantiator::VisitLabelStmt(LabelStmt *S) { + OwningStmtResult SubStmt = Visit(S->getSubStmt()); + + if (SubStmt.isInvalid()) + return SemaRef.StmtError(); + + // FIXME: Pass the real colon loc in. + return SemaRef.ActOnLabelStmt(S->getIdentLoc(), S->getID(), SourceLocation(), + move(SubStmt)); +} + +Sema::OwningStmtResult TemplateStmtInstantiator::VisitGotoStmt(GotoStmt *S) { + return SemaRef.ActOnGotoStmt(S->getGotoLoc(), S->getLabelLoc(), + S->getLabel()->getID()); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitIndirectGotoStmt(IndirectGotoStmt *S) { + OwningExprResult Target = SemaRef.InstantiateExpr(S->getTarget(), + TemplateArgs); + if (Target.isInvalid()) + return SemaRef.StmtError(); + + return SemaRef.ActOnIndirectGotoStmt(S->getGotoLoc(), S->getStarLoc(), + move(Target)); +} + +Sema::OwningStmtResult TemplateStmtInstantiator::VisitBreakStmt(BreakStmt *S) { + return SemaRef.Owned(S->Clone(SemaRef.Context)); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitContinueStmt(ContinueStmt *S) { + return SemaRef.Owned(S->Clone(SemaRef.Context)); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitReturnStmt(ReturnStmt *S) { + Sema::OwningExprResult Result = SemaRef.ExprEmpty(); + if (Expr *E = S->getRetValue()) { + Result = SemaRef.InstantiateExpr(E, TemplateArgs); + + if (Result.isInvalid()) + return SemaRef.StmtError(); + } + + return SemaRef.ActOnReturnStmt(S->getReturnLoc(), FullExpr(Result)); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitCompoundStmt(CompoundStmt *S) { + return SemaRef.InstantiateCompoundStmt(S, TemplateArgs, false); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitSwitchCase(SwitchCase *S) { + assert(false && "SwitchCase statements are never directly instantiated"); + return SemaRef.StmtError(); +} + +Sema::OwningStmtResult TemplateStmtInstantiator::VisitCaseStmt(CaseStmt *S) { + // Instantiate left-hand case value. + OwningExprResult LHS = SemaRef.InstantiateExpr(S->getLHS(), TemplateArgs); + if (LHS.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate right-hand case value (for the GNU case-range extension). + OwningExprResult RHS = SemaRef.InstantiateExpr(S->getRHS(), TemplateArgs); + if (RHS.isInvalid()) + return SemaRef.StmtError(); + + // Build the case statement. + OwningStmtResult Case = SemaRef.ActOnCaseStmt(S->getCaseLoc(), + move(LHS), + S->getEllipsisLoc(), + move(RHS), + S->getColonLoc()); + if (Case.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the statement following the case + OwningStmtResult SubStmt = SemaRef.InstantiateStmt(S->getSubStmt(), + TemplateArgs); + if (SubStmt.isInvalid()) + return SemaRef.StmtError(); + + SemaRef.ActOnCaseStmtBody(Case.get(), move(SubStmt)); + return move(Case); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitDefaultStmt(DefaultStmt *S) { + // Instantiate the statement following the default case + OwningStmtResult SubStmt = SemaRef.InstantiateStmt(S->getSubStmt(), + TemplateArgs); + if (SubStmt.isInvalid()) + return SemaRef.StmtError(); + + return SemaRef.ActOnDefaultStmt(S->getDefaultLoc(), + S->getColonLoc(), + move(SubStmt), + /*CurScope=*/0); +} + +Sema::OwningStmtResult TemplateStmtInstantiator::VisitIfStmt(IfStmt *S) { + // Instantiate the condition + OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs); + if (Cond.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the "then" branch. + OwningStmtResult Then = SemaRef.InstantiateStmt(S->getThen(), TemplateArgs); + if (Then.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the "else" branch. + OwningStmtResult Else = SemaRef.InstantiateStmt(S->getElse(), TemplateArgs); + if (Else.isInvalid()) + return SemaRef.StmtError(); + + return SemaRef.ActOnIfStmt(S->getIfLoc(), FullExpr(Cond), move(Then), + S->getElseLoc(), move(Else)); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitSwitchStmt(SwitchStmt *S) { + // Instantiate the condition. + OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs); + if (Cond.isInvalid()) + return SemaRef.StmtError(); + + // Start the switch statement itself. + OwningStmtResult Switch = SemaRef.ActOnStartOfSwitchStmt(move(Cond)); + if (Switch.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the body of the switch statement. + OwningStmtResult Body = SemaRef.InstantiateStmt(S->getBody(), TemplateArgs); + if (Body.isInvalid()) + return SemaRef.StmtError(); + + // Complete the switch statement. + return SemaRef.ActOnFinishSwitchStmt(S->getSwitchLoc(), move(Switch), + move(Body)); +} + +Sema::OwningStmtResult TemplateStmtInstantiator::VisitWhileStmt(WhileStmt *S) { + // Instantiate the condition + OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs); + if (Cond.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the body + OwningStmtResult Body = SemaRef.InstantiateStmt(S->getBody(), TemplateArgs); + if (Body.isInvalid()) + return SemaRef.StmtError(); + + return SemaRef.ActOnWhileStmt(S->getWhileLoc(), FullExpr(Cond), move(Body)); +} + +Sema::OwningStmtResult TemplateStmtInstantiator::VisitDoStmt(DoStmt *S) { + // Instantiate the condition + OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs); + if (Cond.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the body + OwningStmtResult Body = SemaRef.InstantiateStmt(S->getBody(), TemplateArgs); + if (Body.isInvalid()) + return SemaRef.StmtError(); + + return SemaRef.ActOnDoStmt(S->getDoLoc(), move(Body), S->getWhileLoc(), + move(Cond)); +} + +Sema::OwningStmtResult TemplateStmtInstantiator::VisitForStmt(ForStmt *S) { + // Instantiate the initialization statement + OwningStmtResult Init = SemaRef.InstantiateStmt(S->getInit(), TemplateArgs); + if (Init.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the condition + OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs); + if (Cond.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the increment + OwningExprResult Inc = SemaRef.InstantiateExpr(S->getInc(), TemplateArgs); + if (Inc.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the body + OwningStmtResult Body = SemaRef.InstantiateStmt(S->getBody(), TemplateArgs); + if (Body.isInvalid()) + return SemaRef.StmtError(); + + return SemaRef.ActOnForStmt(S->getForLoc(), S->getLParenLoc(), + move(Init), move(Cond), move(Inc), + S->getRParenLoc(), move(Body)); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitAsmStmt(AsmStmt *S) { + // FIXME: Implement this + assert(false && "Cannot instantiate an 'asm' statement"); + return SemaRef.StmtError(); +} + +//===----------------------------------------------------------------------===/ +// C++ statements +//===----------------------------------------------------------------------===/ +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitCXXTryStmt(CXXTryStmt *S) { + // Instantiate the try block itself. + OwningStmtResult TryBlock = VisitCompoundStmt(S->getTryBlock()); + if (TryBlock.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the handlers. + ASTOwningVector<&ActionBase::DeleteStmt> Handlers(SemaRef); + for (unsigned I = 0, N = S->getNumHandlers(); I != N; ++I) { + OwningStmtResult Handler = VisitCXXCatchStmt(S->getHandler(I)); + if (Handler.isInvalid()) + return SemaRef.StmtError(); + + Handlers.push_back(Handler.takeAs<Stmt>()); + } + + return SemaRef.ActOnCXXTryBlock(S->getTryLoc(), move(TryBlock), + move_arg(Handlers)); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitCXXCatchStmt(CXXCatchStmt *S) { + // Instantiate the exception declaration, if any. + VarDecl *Var = 0; + if (S->getExceptionDecl()) { + VarDecl *ExceptionDecl = S->getExceptionDecl(); + QualType T = SemaRef.InstantiateType(ExceptionDecl->getType(), + TemplateArgs, + ExceptionDecl->getLocation(), + ExceptionDecl->getDeclName()); + if (T.isNull()) + return SemaRef.StmtError(); + + Var = SemaRef.BuildExceptionDeclaration(0, T, + ExceptionDecl->getIdentifier(), + ExceptionDecl->getLocation(), + /*FIXME: Inaccurate*/ + SourceRange(ExceptionDecl->getLocation())); + if (Var->isInvalidDecl()) { + Var->Destroy(SemaRef.Context); + return SemaRef.StmtError(); + } + + // Introduce the exception declaration into scope. + SemaRef.CurrentInstantiationScope->InstantiatedLocal(ExceptionDecl, Var); + } + + // Instantiate the actual exception handler. + OwningStmtResult Handler = Visit(S->getHandlerBlock()); + if (Handler.isInvalid()) { + if (Var) + Var->Destroy(SemaRef.Context); + return SemaRef.StmtError(); + } + + return SemaRef.Owned(new (SemaRef.Context) CXXCatchStmt(S->getCatchLoc(), + Var, + Handler.takeAs<Stmt>())); +} + +//===----------------------------------------------------------------------===/ +// Objective-C statements +//===----------------------------------------------------------------------===/ +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { + // FIXME: Implement this + assert(false && "Cannot instantiate an Objective-C @finally statement"); + return SemaRef.StmtError(); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitObjCAtSynchronizedStmt( + ObjCAtSynchronizedStmt *S) { + // FIXME: Implement this + assert(false && "Cannot instantiate an Objective-C @synchronized statement"); + return SemaRef.StmtError(); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitObjCAtTryStmt(ObjCAtTryStmt *S) { + // FIXME: Implement this + assert(false && "Cannot instantiate an Objective-C @try statement"); + return SemaRef.StmtError(); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitObjCForCollectionStmt( + ObjCForCollectionStmt *S) { + // FIXME: Implement this + assert(false && "Cannot instantiate an Objective-C \"for\" statement"); + return SemaRef.StmtError(); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) { + // FIXME: Implement this + assert(false && "Cannot instantiate an Objective-C @throw statement"); + return SemaRef.StmtError(); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) { + // FIXME: Implement this + assert(false && "Cannot instantiate an Objective-C @catch statement"); + return SemaRef.StmtError(); +} + +Sema::OwningStmtResult TemplateStmtInstantiator::VisitExpr(Expr *E) { + Sema::OwningExprResult Result = SemaRef.InstantiateExpr(E, TemplateArgs); + if (Result.isInvalid()) + return SemaRef.StmtError(); + + return SemaRef.Owned(Result.takeAs<Stmt>()); +} + +Sema::OwningStmtResult +Sema::InstantiateStmt(Stmt *S, const TemplateArgumentList &TemplateArgs) { + if (!S) + return Owned((Stmt *)0); + + TemplateStmtInstantiator Instantiator(*this, TemplateArgs); + return Instantiator.Visit(S); +} + +Sema::OwningStmtResult +Sema::InstantiateCompoundStmt(CompoundStmt *S, + const TemplateArgumentList &TemplateArgs, + bool isStmtExpr) { + if (!S) + return Owned((Stmt *)0); + + TemplateStmtInstantiator Instantiator(*this, TemplateArgs); + ASTOwningVector<&ActionBase::DeleteStmt> Statements(*this); + for (CompoundStmt::body_iterator B = S->body_begin(), BEnd = S->body_end(); + B != BEnd; ++B) { + OwningStmtResult Result = Instantiator.Visit(*B); + if (Result.isInvalid()) + return StmtError(); + + Statements.push_back(Result.takeAs<Stmt>()); + } + + return ActOnCompoundStmt(S->getLBracLoc(), S->getRBracLoc(), + move_arg(Statements), isStmtExpr); +} diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp new file mode 100644 index 0000000..81ac211 --- /dev/null +++ b/lib/Sema/SemaType.cpp @@ -0,0 +1,1301 @@ +//===--- SemaType.cpp - Semantic Analysis for Types -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements type-related semantic analysis. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/Parse/DeclSpec.h" +using namespace clang; + +/// \brief Perform adjustment on the parameter type of a function. +/// +/// This routine adjusts the given parameter type @p T to the actual +/// parameter type used by semantic analysis (C99 6.7.5.3p[7,8], +/// C++ [dcl.fct]p3). The adjusted parameter type is returned. +QualType Sema::adjustParameterType(QualType T) { + // C99 6.7.5.3p7: + if (T->isArrayType()) { + // C99 6.7.5.3p7: + // A declaration of a parameter as "array of type" shall be + // adjusted to "qualified pointer to type", where the type + // qualifiers (if any) are those specified within the [ and ] of + // the array type derivation. + return Context.getArrayDecayedType(T); + } else if (T->isFunctionType()) + // C99 6.7.5.3p8: + // A declaration of a parameter as "function returning type" + // shall be adjusted to "pointer to function returning type", as + // in 6.3.2.1. + return Context.getPointerType(T); + + return T; +} + +/// \brief Convert the specified declspec to the appropriate type +/// object. +/// \param DS the declaration specifiers +/// \param DeclLoc The location of the declarator identifier or invalid if none. +/// \returns The type described by the declaration specifiers. This function +/// never returns null. +QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS, + SourceLocation DeclLoc, + bool &isInvalid) { + // FIXME: Should move the logic from DeclSpec::Finish to here for validity + // checking. + QualType Result; + + switch (DS.getTypeSpecType()) { + case DeclSpec::TST_void: + Result = Context.VoidTy; + break; + case DeclSpec::TST_char: + if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified) + Result = Context.CharTy; + else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed) + Result = Context.SignedCharTy; + else { + assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned && + "Unknown TSS value"); + Result = Context.UnsignedCharTy; + } + break; + case DeclSpec::TST_wchar: + if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified) + Result = Context.WCharTy; + else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed) { + Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) + << DS.getSpecifierName(DS.getTypeSpecType()); + Result = Context.getSignedWCharType(); + } else { + assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned && + "Unknown TSS value"); + Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) + << DS.getSpecifierName(DS.getTypeSpecType()); + Result = Context.getUnsignedWCharType(); + } + break; + case DeclSpec::TST_unspecified: + // "<proto1,proto2>" is an objc qualified ID with a missing id. + if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { + Result = Context.getObjCQualifiedIdType((ObjCProtocolDecl**)PQ, + DS.getNumProtocolQualifiers()); + break; + } + + // Unspecified typespec defaults to int in C90. However, the C90 grammar + // [C90 6.5] only allows a decl-spec if there was *some* type-specifier, + // type-qualifier, or storage-class-specifier. If not, emit an extwarn. + // Note that the one exception to this is function definitions, which are + // allowed to be completely missing a declspec. This is handled in the + // parser already though by it pretending to have seen an 'int' in this + // case. + if (getLangOptions().ImplicitInt) { + // In C89 mode, we only warn if there is a completely missing declspec + // when one is not allowed. + if (DS.isEmpty()) { + if (DeclLoc.isInvalid()) + DeclLoc = DS.getSourceRange().getBegin(); + Diag(DeclLoc, diag::warn_missing_declspec) + << DS.getSourceRange() + << CodeModificationHint::CreateInsertion(DS.getSourceRange().getBegin(), + "int"); + } + } else if (!DS.hasTypeSpecifier()) { + // C99 and C++ require a type specifier. For example, C99 6.7.2p2 says: + // "At least one type specifier shall be given in the declaration + // specifiers in each declaration, and in the specifier-qualifier list in + // each struct declaration and type name." + // FIXME: Does Microsoft really have the implicit int extension in C++? + if (DeclLoc.isInvalid()) + DeclLoc = DS.getSourceRange().getBegin(); + + if (getLangOptions().CPlusPlus && !getLangOptions().Microsoft) + Diag(DeclLoc, diag::err_missing_type_specifier) + << DS.getSourceRange(); + else + Diag(DeclLoc, diag::warn_missing_type_specifier) + << DS.getSourceRange(); + + // FIXME: If we could guarantee that the result would be well-formed, it + // would be useful to have a code insertion hint here. However, after + // emitting this warning/error, we often emit other errors. + } + + // FALL THROUGH. + case DeclSpec::TST_int: { + if (DS.getTypeSpecSign() != DeclSpec::TSS_unsigned) { + switch (DS.getTypeSpecWidth()) { + case DeclSpec::TSW_unspecified: Result = Context.IntTy; break; + case DeclSpec::TSW_short: Result = Context.ShortTy; break; + case DeclSpec::TSW_long: Result = Context.LongTy; break; + case DeclSpec::TSW_longlong: Result = Context.LongLongTy; break; + } + } else { + switch (DS.getTypeSpecWidth()) { + case DeclSpec::TSW_unspecified: Result = Context.UnsignedIntTy; break; + case DeclSpec::TSW_short: Result = Context.UnsignedShortTy; break; + case DeclSpec::TSW_long: Result = Context.UnsignedLongTy; break; + case DeclSpec::TSW_longlong: Result =Context.UnsignedLongLongTy; break; + } + } + break; + } + case DeclSpec::TST_float: Result = Context.FloatTy; break; + case DeclSpec::TST_double: + if (DS.getTypeSpecWidth() == DeclSpec::TSW_long) + Result = Context.LongDoubleTy; + else + Result = Context.DoubleTy; + break; + case DeclSpec::TST_bool: Result = Context.BoolTy; break; // _Bool or bool + case DeclSpec::TST_decimal32: // _Decimal32 + case DeclSpec::TST_decimal64: // _Decimal64 + case DeclSpec::TST_decimal128: // _Decimal128 + Diag(DS.getTypeSpecTypeLoc(), diag::err_decimal_unsupported); + Result = Context.IntTy; + isInvalid = true; + break; + case DeclSpec::TST_class: + case DeclSpec::TST_enum: + case DeclSpec::TST_union: + case DeclSpec::TST_struct: { + Decl *D = static_cast<Decl *>(DS.getTypeRep()); + assert(D && "Didn't get a decl for a class/enum/union/struct?"); + assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && + DS.getTypeSpecSign() == 0 && + "Can't handle qualifiers on typedef names yet!"); + // TypeQuals handled by caller. + Result = Context.getTypeDeclType(cast<TypeDecl>(D)); + + if (D->isInvalidDecl()) + isInvalid = true; + break; + } + case DeclSpec::TST_typename: { + assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && + DS.getTypeSpecSign() == 0 && + "Can't handle qualifiers on typedef names yet!"); + Result = QualType::getFromOpaquePtr(DS.getTypeRep()); + + if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { + // FIXME: Adding a TST_objcInterface clause doesn't seem ideal, so we have + // this "hack" for now... + if (const ObjCInterfaceType *Interface = Result->getAsObjCInterfaceType()) + Result = Context.getObjCQualifiedInterfaceType(Interface->getDecl(), + (ObjCProtocolDecl**)PQ, + DS.getNumProtocolQualifiers()); + else if (Result == Context.getObjCIdType()) + // id<protocol-list> + Result = Context.getObjCQualifiedIdType((ObjCProtocolDecl**)PQ, + DS.getNumProtocolQualifiers()); + else if (Result == Context.getObjCClassType()) { + if (DeclLoc.isInvalid()) + DeclLoc = DS.getSourceRange().getBegin(); + // Class<protocol-list> + Diag(DeclLoc, diag::err_qualified_class_unsupported) + << DS.getSourceRange(); + } else { + if (DeclLoc.isInvalid()) + DeclLoc = DS.getSourceRange().getBegin(); + Diag(DeclLoc, diag::err_invalid_protocol_qualifiers) + << DS.getSourceRange(); + isInvalid = true; + } + } + + // If this is a reference to an invalid typedef, propagate the invalidity. + if (TypedefType *TDT = dyn_cast<TypedefType>(Result)) + if (TDT->getDecl()->isInvalidDecl()) + isInvalid = true; + + // TypeQuals handled by caller. + break; + } + case DeclSpec::TST_typeofType: + Result = QualType::getFromOpaquePtr(DS.getTypeRep()); + assert(!Result.isNull() && "Didn't get a type for typeof?"); + // TypeQuals handled by caller. + Result = Context.getTypeOfType(Result); + break; + case DeclSpec::TST_typeofExpr: { + Expr *E = static_cast<Expr *>(DS.getTypeRep()); + assert(E && "Didn't get an expression for typeof?"); + // TypeQuals handled by caller. + Result = Context.getTypeOfExprType(E); + break; + } + case DeclSpec::TST_error: + Result = Context.IntTy; + isInvalid = true; + break; + } + + // Handle complex types. + if (DS.getTypeSpecComplex() == DeclSpec::TSC_complex) { + if (getLangOptions().Freestanding) + Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex); + Result = Context.getComplexType(Result); + } + + assert(DS.getTypeSpecComplex() != DeclSpec::TSC_imaginary && + "FIXME: imaginary types not supported yet!"); + + // See if there are any attributes on the declspec that apply to the type (as + // opposed to the decl). + if (const AttributeList *AL = DS.getAttributes()) + ProcessTypeAttributeList(Result, AL); + + // Apply const/volatile/restrict qualifiers to T. + if (unsigned TypeQuals = DS.getTypeQualifiers()) { + + // Enforce C99 6.7.3p2: "Types other than pointer types derived from object + // or incomplete types shall not be restrict-qualified." C++ also allows + // restrict-qualified references. + if (TypeQuals & QualType::Restrict) { + if (Result->isPointerType() || Result->isReferenceType()) { + QualType EltTy = Result->isPointerType() ? + Result->getAsPointerType()->getPointeeType() : + Result->getAsReferenceType()->getPointeeType(); + + // If we have a pointer or reference, the pointee must have an object + // incomplete type. + if (!EltTy->isIncompleteOrObjectType()) { + Diag(DS.getRestrictSpecLoc(), + diag::err_typecheck_invalid_restrict_invalid_pointee) + << EltTy << DS.getSourceRange(); + TypeQuals &= ~QualType::Restrict; // Remove the restrict qualifier. + } + } else { + Diag(DS.getRestrictSpecLoc(), + diag::err_typecheck_invalid_restrict_not_pointer) + << Result << DS.getSourceRange(); + TypeQuals &= ~QualType::Restrict; // Remove the restrict qualifier. + } + } + + // Warn about CV qualifiers on functions: C99 6.7.3p8: "If the specification + // of a function type includes any type qualifiers, the behavior is + // undefined." + if (Result->isFunctionType() && TypeQuals) { + // Get some location to point at, either the C or V location. + SourceLocation Loc; + if (TypeQuals & QualType::Const) + Loc = DS.getConstSpecLoc(); + else { + assert((TypeQuals & QualType::Volatile) && + "Has CV quals but not C or V?"); + Loc = DS.getVolatileSpecLoc(); + } + Diag(Loc, diag::warn_typecheck_function_qualifiers) + << Result << DS.getSourceRange(); + } + + // C++ [dcl.ref]p1: + // Cv-qualified references are ill-formed except when the + // cv-qualifiers are introduced through the use of a typedef + // (7.1.3) or of a template type argument (14.3), in which + // case the cv-qualifiers are ignored. + // FIXME: Shouldn't we be checking SCS_typedef here? + if (DS.getTypeSpecType() == DeclSpec::TST_typename && + TypeQuals && Result->isReferenceType()) { + TypeQuals &= ~QualType::Const; + TypeQuals &= ~QualType::Volatile; + } + + Result = Result.getQualifiedType(TypeQuals); + } + return Result; +} + +static std::string getPrintableNameForEntity(DeclarationName Entity) { + if (Entity) + return Entity.getAsString(); + + return "type name"; +} + +/// \brief Build a pointer type. +/// +/// \param T The type to which we'll be building a pointer. +/// +/// \param Quals The cvr-qualifiers to be applied to the pointer type. +/// +/// \param Loc The location of the entity whose type involves this +/// pointer type or, if there is no such entity, the location of the +/// type that will have pointer type. +/// +/// \param Entity The name of the entity that involves the pointer +/// type, if known. +/// +/// \returns A suitable pointer type, if there are no +/// errors. Otherwise, returns a NULL type. +QualType Sema::BuildPointerType(QualType T, unsigned Quals, + SourceLocation Loc, DeclarationName Entity) { + if (T->isReferenceType()) { + // C++ 8.3.2p4: There shall be no ... pointers to references ... + Diag(Loc, diag::err_illegal_decl_pointer_to_reference) + << getPrintableNameForEntity(Entity); + return QualType(); + } + + // Enforce C99 6.7.3p2: "Types other than pointer types derived from + // object or incomplete types shall not be restrict-qualified." + if ((Quals & QualType::Restrict) && !T->isIncompleteOrObjectType()) { + Diag(Loc, diag::err_typecheck_invalid_restrict_invalid_pointee) + << T; + Quals &= ~QualType::Restrict; + } + + // Build the pointer type. + return Context.getPointerType(T).getQualifiedType(Quals); +} + +/// \brief Build a reference type. +/// +/// \param T The type to which we'll be building a reference. +/// +/// \param Quals The cvr-qualifiers to be applied to the reference type. +/// +/// \param Loc The location of the entity whose type involves this +/// reference type or, if there is no such entity, the location of the +/// type that will have reference type. +/// +/// \param Entity The name of the entity that involves the reference +/// type, if known. +/// +/// \returns A suitable reference type, if there are no +/// errors. Otherwise, returns a NULL type. +QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned Quals, + SourceLocation Loc, DeclarationName Entity) { + if (LValueRef) { + if (const RValueReferenceType *R = T->getAsRValueReferenceType()) { + // C++0x [dcl.typedef]p9: If a typedef TD names a type that is a + // reference to a type T, and attempt to create the type "lvalue + // reference to cv TD" creates the type "lvalue reference to T". + // We use the qualifiers (restrict or none) of the original reference, + // not the new ones. This is consistent with GCC. + return Context.getLValueReferenceType(R->getPointeeType()). + getQualifiedType(T.getCVRQualifiers()); + } + } + if (T->isReferenceType()) { + // C++ [dcl.ref]p4: There shall be no references to references. + // + // According to C++ DR 106, references to references are only + // diagnosed when they are written directly (e.g., "int & &"), + // but not when they happen via a typedef: + // + // typedef int& intref; + // typedef intref& intref2; + // + // Parser::ParserDeclaratorInternal diagnoses the case where + // references are written directly; here, we handle the + // collapsing of references-to-references as described in C++ + // DR 106 and amended by C++ DR 540. + return T; + } + + // C++ [dcl.ref]p1: + // A declarator that specifies the type “reference to cv void” + // is ill-formed. + if (T->isVoidType()) { + Diag(Loc, diag::err_reference_to_void); + return QualType(); + } + + // Enforce C99 6.7.3p2: "Types other than pointer types derived from + // object or incomplete types shall not be restrict-qualified." + if ((Quals & QualType::Restrict) && !T->isIncompleteOrObjectType()) { + Diag(Loc, diag::err_typecheck_invalid_restrict_invalid_pointee) + << T; + Quals &= ~QualType::Restrict; + } + + // C++ [dcl.ref]p1: + // [...] Cv-qualified references are ill-formed except when the + // cv-qualifiers are introduced through the use of a typedef + // (7.1.3) or of a template type argument (14.3), in which case + // the cv-qualifiers are ignored. + // + // We diagnose extraneous cv-qualifiers for the non-typedef, + // non-template type argument case within the parser. Here, we just + // ignore any extraneous cv-qualifiers. + Quals &= ~QualType::Const; + Quals &= ~QualType::Volatile; + + // Handle restrict on references. + if (LValueRef) + return Context.getLValueReferenceType(T).getQualifiedType(Quals); + return Context.getRValueReferenceType(T).getQualifiedType(Quals); +} + +/// \brief Build an array type. +/// +/// \param T The type of each element in the array. +/// +/// \param ASM C99 array size modifier (e.g., '*', 'static'). +/// +/// \param ArraySize Expression describing the size of the array. +/// +/// \param Quals The cvr-qualifiers to be applied to the array's +/// element type. +/// +/// \param Loc The location of the entity whose type involves this +/// array type or, if there is no such entity, the location of the +/// type that will have array type. +/// +/// \param Entity The name of the entity that involves the array +/// type, if known. +/// +/// \returns A suitable array type, if there are no errors. Otherwise, +/// returns a NULL type. +QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, + Expr *ArraySize, unsigned Quals, + SourceLocation Loc, DeclarationName Entity) { + // C99 6.7.5.2p1: If the element type is an incomplete or function type, + // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]()) + if (RequireCompleteType(Loc, T, + diag::err_illegal_decl_array_incomplete_type)) + return QualType(); + + if (T->isFunctionType()) { + Diag(Loc, diag::err_illegal_decl_array_of_functions) + << getPrintableNameForEntity(Entity); + return QualType(); + } + + // C++ 8.3.2p4: There shall be no ... arrays of references ... + if (T->isReferenceType()) { + Diag(Loc, diag::err_illegal_decl_array_of_references) + << getPrintableNameForEntity(Entity); + return QualType(); + } + + if (const RecordType *EltTy = T->getAsRecordType()) { + // If the element type is a struct or union that contains a variadic + // array, accept it as a GNU extension: C99 6.7.2.1p2. + if (EltTy->getDecl()->hasFlexibleArrayMember()) + Diag(Loc, diag::ext_flexible_array_in_array) << T; + } else if (T->isObjCInterfaceType()) { + Diag(Loc, diag::err_objc_array_of_interfaces) << T; + return QualType(); + } + + // C99 6.7.5.2p1: The size expression shall have integer type. + if (ArraySize && !ArraySize->isTypeDependent() && + !ArraySize->getType()->isIntegerType()) { + Diag(ArraySize->getLocStart(), diag::err_array_size_non_int) + << ArraySize->getType() << ArraySize->getSourceRange(); + ArraySize->Destroy(Context); + return QualType(); + } + llvm::APSInt ConstVal(32); + if (!ArraySize) { + if (ASM == ArrayType::Star) + T = Context.getVariableArrayType(T, 0, ASM, Quals); + else + T = Context.getIncompleteArrayType(T, ASM, Quals); + } else if (ArraySize->isValueDependent()) { + T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals); + } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) || + (!T->isDependentType() && !T->isConstantSizeType())) { + // Per C99, a variable array is an array with either a non-constant + // size or an element type that has a non-constant-size + T = Context.getVariableArrayType(T, ArraySize, ASM, Quals); + } else { + // C99 6.7.5.2p1: If the expression is a constant expression, it shall + // have a value greater than zero. + if (ConstVal.isSigned()) { + if (ConstVal.isNegative()) { + Diag(ArraySize->getLocStart(), + diag::err_typecheck_negative_array_size) + << ArraySize->getSourceRange(); + return QualType(); + } else if (ConstVal == 0) { + // GCC accepts zero sized static arrays. + Diag(ArraySize->getLocStart(), diag::ext_typecheck_zero_array_size) + << ArraySize->getSourceRange(); + } + } + T = Context.getConstantArrayType(T, ConstVal, ASM, Quals); + } + // If this is not C99, extwarn about VLA's and C99 array size modifiers. + if (!getLangOptions().C99) { + if (ArraySize && !ArraySize->isTypeDependent() && + !ArraySize->isValueDependent() && + !ArraySize->isIntegerConstantExpr(Context)) + Diag(Loc, diag::ext_vla); + else if (ASM != ArrayType::Normal || Quals != 0) + Diag(Loc, diag::ext_c99_array_usage); + } + + return T; +} + +/// \brief Build a function type. +/// +/// This routine checks the function type according to C++ rules and +/// under the assumption that the result type and parameter types have +/// just been instantiated from a template. It therefore duplicates +/// some of the behavior of GetTypeForDeclarator, but in a much +/// simpler form that is only suitable for this narrow use case. +/// +/// \param T The return type of the function. +/// +/// \param ParamTypes The parameter types of the function. This array +/// will be modified to account for adjustments to the types of the +/// function parameters. +/// +/// \param NumParamTypes The number of parameter types in ParamTypes. +/// +/// \param Variadic Whether this is a variadic function type. +/// +/// \param Quals The cvr-qualifiers to be applied to the function type. +/// +/// \param Loc The location of the entity whose type involves this +/// function type or, if there is no such entity, the location of the +/// type that will have function type. +/// +/// \param Entity The name of the entity that involves the function +/// type, if known. +/// +/// \returns A suitable function type, if there are no +/// errors. Otherwise, returns a NULL type. +QualType Sema::BuildFunctionType(QualType T, + QualType *ParamTypes, + unsigned NumParamTypes, + bool Variadic, unsigned Quals, + SourceLocation Loc, DeclarationName Entity) { + if (T->isArrayType() || T->isFunctionType()) { + Diag(Loc, diag::err_func_returning_array_function) << T; + return QualType(); + } + + bool Invalid = false; + for (unsigned Idx = 0; Idx < NumParamTypes; ++Idx) { + QualType ParamType = adjustParameterType(ParamTypes[Idx]); + if (ParamType->isVoidType()) { + Diag(Loc, diag::err_param_with_void_type); + Invalid = true; + } + + ParamTypes[Idx] = ParamType; + } + + if (Invalid) + return QualType(); + + return Context.getFunctionType(T, ParamTypes, NumParamTypes, Variadic, + Quals); +} + +/// GetTypeForDeclarator - Convert the type for the specified +/// declarator to Type instances. Skip the outermost Skip type +/// objects. +/// +/// If OwnedDecl is non-NULL, and this declarator's decl-specifier-seq +/// owns the declaration of a type (e.g., the definition of a struct +/// type), then *OwnedDecl will receive the owned declaration. +QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, + TagDecl **OwnedDecl) { + bool OmittedReturnType = false; + + if (D.getContext() == Declarator::BlockLiteralContext + && Skip == 0 + && !D.getDeclSpec().hasTypeSpecifier() + && (D.getNumTypeObjects() == 0 + || (D.getNumTypeObjects() == 1 + && D.getTypeObject(0).Kind == DeclaratorChunk::Function))) + OmittedReturnType = true; + + // long long is a C99 feature. + if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x && + D.getDeclSpec().getTypeSpecWidth() == DeclSpec::TSW_longlong) + Diag(D.getDeclSpec().getTypeSpecWidthLoc(), diag::ext_longlong); + + // Determine the type of the declarator. Not all forms of declarator + // have a type. + QualType T; + switch (D.getKind()) { + case Declarator::DK_Abstract: + case Declarator::DK_Normal: + case Declarator::DK_Operator: { + const DeclSpec &DS = D.getDeclSpec(); + if (OmittedReturnType) { + // We default to a dependent type initially. Can be modified by + // the first return statement. + T = Context.DependentTy; + } else { + bool isInvalid = false; + T = ConvertDeclSpecToType(DS, D.getIdentifierLoc(), isInvalid); + if (isInvalid) + D.setInvalidType(true); + else if (OwnedDecl && DS.isTypeSpecOwned()) + *OwnedDecl = cast<TagDecl>((Decl *)DS.getTypeRep()); + } + break; + } + + case Declarator::DK_Constructor: + case Declarator::DK_Destructor: + case Declarator::DK_Conversion: + // Constructors and destructors don't have return types. Use + // "void" instead. Conversion operators will check their return + // types separately. + T = Context.VoidTy; + break; + } + + // The name we're declaring, if any. + DeclarationName Name; + if (D.getIdentifier()) + Name = D.getIdentifier(); + + // Walk the DeclTypeInfo, building the recursive type as we go. + // DeclTypeInfos are ordered from the identifier out, which is + // opposite of what we want :). + for (unsigned i = Skip, e = D.getNumTypeObjects(); i != e; ++i) { + DeclaratorChunk &DeclType = D.getTypeObject(e-i-1+Skip); + switch (DeclType.Kind) { + default: assert(0 && "Unknown decltype!"); + case DeclaratorChunk::BlockPointer: + // If blocks are disabled, emit an error. + if (!LangOpts.Blocks) + Diag(DeclType.Loc, diag::err_blocks_disable); + + if (!T.getTypePtr()->isFunctionType()) + Diag(D.getIdentifierLoc(), diag::err_nonfunction_block_type); + else + T = (Context.getBlockPointerType(T) + .getQualifiedType(DeclType.Cls.TypeQuals)); + break; + case DeclaratorChunk::Pointer: + // Verify that we're not building a pointer to pointer to function with + // exception specification. + if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { + Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); + D.setInvalidType(true); + // Build the type anyway. + } + T = BuildPointerType(T, DeclType.Ptr.TypeQuals, DeclType.Loc, Name); + break; + case DeclaratorChunk::Reference: + // Verify that we're not building a reference to pointer to function with + // exception specification. + if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { + Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); + D.setInvalidType(true); + // Build the type anyway. + } + T = BuildReferenceType(T, DeclType.Ref.LValueRef, + DeclType.Ref.HasRestrict ? QualType::Restrict : 0, + DeclType.Loc, Name); + break; + case DeclaratorChunk::Array: { + // Verify that we're not building an array of pointers to function with + // exception specification. + if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { + Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); + D.setInvalidType(true); + // Build the type anyway. + } + DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr; + Expr *ArraySize = static_cast<Expr*>(ATI.NumElts); + ArrayType::ArraySizeModifier ASM; + if (ATI.isStar) + ASM = ArrayType::Star; + else if (ATI.hasStatic) + ASM = ArrayType::Static; + else + ASM = ArrayType::Normal; + if (ASM == ArrayType::Star && + D.getContext() != Declarator::PrototypeContext) { + // FIXME: This check isn't quite right: it allows star in prototypes + // for function definitions, and disallows some edge cases detailed + // in http://gcc.gnu.org/ml/gcc-patches/2009-02/msg00133.html + Diag(DeclType.Loc, diag::err_array_star_outside_prototype); + ASM = ArrayType::Normal; + D.setInvalidType(true); + } + T = BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals, DeclType.Loc, Name); + break; + } + case DeclaratorChunk::Function: { + // If the function declarator has a prototype (i.e. it is not () and + // does not have a K&R-style identifier list), then the arguments are part + // of the type, otherwise the argument list is (). + const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; + + // C99 6.7.5.3p1: The return type may not be a function or array type. + if (T->isArrayType() || T->isFunctionType()) { + Diag(DeclType.Loc, diag::err_func_returning_array_function) << T; + T = Context.IntTy; + D.setInvalidType(true); + } + + if (getLangOptions().CPlusPlus && D.getDeclSpec().isTypeSpecOwned()) { + // C++ [dcl.fct]p6: + // Types shall not be defined in return or parameter types. + TagDecl *Tag = cast<TagDecl>((Decl *)D.getDeclSpec().getTypeRep()); + if (Tag->isDefinition()) + Diag(Tag->getLocation(), diag::err_type_defined_in_result_type) + << Context.getTypeDeclType(Tag); + } + + // Exception specs are not allowed in typedefs. Complain, but add it + // anyway. + if (FTI.hasExceptionSpec && + D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) + Diag(FTI.getThrowLoc(), diag::err_exception_spec_in_typedef); + + if (FTI.NumArgs == 0) { + if (getLangOptions().CPlusPlus) { + // C++ 8.3.5p2: If the parameter-declaration-clause is empty, the + // function takes no arguments. + llvm::SmallVector<QualType, 4> Exceptions; + Exceptions.reserve(FTI.NumExceptions); + for(unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) { + QualType ET = QualType::getFromOpaquePtr(FTI.Exceptions[ei].Ty); + // Check that the type is valid for an exception spec, and drop it + // if not. + if (!CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range)) + Exceptions.push_back(ET); + } + T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic, FTI.TypeQuals, + FTI.hasExceptionSpec, + FTI.hasAnyExceptionSpec, + Exceptions.size(), Exceptions.data()); + } else if (FTI.isVariadic) { + // We allow a zero-parameter variadic function in C if the + // function is marked with the "overloadable" + // attribute. Scan for this attribute now. + bool Overloadable = false; + for (const AttributeList *Attrs = D.getAttributes(); + Attrs; Attrs = Attrs->getNext()) { + if (Attrs->getKind() == AttributeList::AT_overloadable) { + Overloadable = true; + break; + } + } + + if (!Overloadable) + Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_arg); + T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic, 0); + } else { + // Simple void foo(), where the incoming T is the result type. + T = Context.getFunctionNoProtoType(T); + } + } else if (FTI.ArgInfo[0].Param == 0) { + // C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function definition. + Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration); + } else { + // Otherwise, we have a function with an argument list that is + // potentially variadic. + llvm::SmallVector<QualType, 16> ArgTys; + + for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { + ParmVarDecl *Param = + cast<ParmVarDecl>(FTI.ArgInfo[i].Param.getAs<Decl>()); + QualType ArgTy = Param->getType(); + assert(!ArgTy.isNull() && "Couldn't parse type?"); + + // Adjust the parameter type. + assert((ArgTy == adjustParameterType(ArgTy)) && "Unadjusted type?"); + + // Look for 'void'. void is allowed only as a single argument to a + // function with no other parameters (C99 6.7.5.3p10). We record + // int(void) as a FunctionProtoType with an empty argument list. + if (ArgTy->isVoidType()) { + // If this is something like 'float(int, void)', reject it. 'void' + // is an incomplete type (C99 6.2.5p19) and function decls cannot + // have arguments of incomplete type. + if (FTI.NumArgs != 1 || FTI.isVariadic) { + Diag(DeclType.Loc, diag::err_void_only_param); + ArgTy = Context.IntTy; + Param->setType(ArgTy); + } else if (FTI.ArgInfo[i].Ident) { + // Reject, but continue to parse 'int(void abc)'. + Diag(FTI.ArgInfo[i].IdentLoc, + diag::err_param_with_void_type); + ArgTy = Context.IntTy; + Param->setType(ArgTy); + } else { + // Reject, but continue to parse 'float(const void)'. + if (ArgTy.getCVRQualifiers()) + Diag(DeclType.Loc, diag::err_void_param_qualified); + + // Do not add 'void' to the ArgTys list. + break; + } + } else if (!FTI.hasPrototype) { + if (ArgTy->isPromotableIntegerType()) { + ArgTy = Context.IntTy; + } else if (const BuiltinType* BTy = ArgTy->getAsBuiltinType()) { + if (BTy->getKind() == BuiltinType::Float) + ArgTy = Context.DoubleTy; + } + } + + ArgTys.push_back(ArgTy); + } + + llvm::SmallVector<QualType, 4> Exceptions; + Exceptions.reserve(FTI.NumExceptions); + for(unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) { + QualType ET = QualType::getFromOpaquePtr(FTI.Exceptions[ei].Ty); + // Check that the type is valid for an exception spec, and drop it if + // not. + if (!CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range)) + Exceptions.push_back(ET); + } + + T = Context.getFunctionType(T, ArgTys.data(), ArgTys.size(), + FTI.isVariadic, FTI.TypeQuals, + FTI.hasExceptionSpec, + FTI.hasAnyExceptionSpec, + Exceptions.size(), Exceptions.data()); + } + break; + } + case DeclaratorChunk::MemberPointer: + // Verify that we're not building a pointer to pointer to function with + // exception specification. + if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { + Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); + D.setInvalidType(true); + // Build the type anyway. + } + // The scope spec must refer to a class, or be dependent. + DeclContext *DC = computeDeclContext(DeclType.Mem.Scope()); + QualType ClsType; + // FIXME: Extend for dependent types when it's actually supported. + // See ActOnCXXNestedNameSpecifier. + if (CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(DC)) { + ClsType = Context.getTagDeclType(RD); + } else { + if (DC) { + Diag(DeclType.Mem.Scope().getBeginLoc(), + diag::err_illegal_decl_mempointer_in_nonclass) + << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name") + << DeclType.Mem.Scope().getRange(); + } + D.setInvalidType(true); + ClsType = Context.IntTy; + } + + // C++ 8.3.3p3: A pointer to member shall not pointer to ... a member + // with reference type, or "cv void." + if (T->isReferenceType()) { + Diag(DeclType.Loc, diag::err_illegal_decl_pointer_to_reference) + << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name"); + D.setInvalidType(true); + T = Context.IntTy; + } + if (T->isVoidType()) { + Diag(DeclType.Loc, diag::err_illegal_decl_mempointer_to_void) + << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name"); + T = Context.IntTy; + } + + // Enforce C99 6.7.3p2: "Types other than pointer types derived from + // object or incomplete types shall not be restrict-qualified." + if ((DeclType.Mem.TypeQuals & QualType::Restrict) && + !T->isIncompleteOrObjectType()) { + Diag(DeclType.Loc, diag::err_typecheck_invalid_restrict_invalid_pointee) + << T; + DeclType.Mem.TypeQuals &= ~QualType::Restrict; + } + + T = Context.getMemberPointerType(T, ClsType.getTypePtr()). + getQualifiedType(DeclType.Mem.TypeQuals); + + break; + } + + if (T.isNull()) { + D.setInvalidType(true); + T = Context.IntTy; + } + + // See if there are any attributes on this declarator chunk. + if (const AttributeList *AL = DeclType.getAttrs()) + ProcessTypeAttributeList(T, AL); + } + + if (getLangOptions().CPlusPlus && T->isFunctionType()) { + const FunctionProtoType *FnTy = T->getAsFunctionProtoType(); + assert(FnTy && "Why oh why is there not a FunctionProtoType here ?"); + + // C++ 8.3.5p4: A cv-qualifier-seq shall only be part of the function type + // for a nonstatic member function, the function type to which a pointer + // to member refers, or the top-level function type of a function typedef + // declaration. + if (FnTy->getTypeQuals() != 0 && + D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && + ((D.getContext() != Declarator::MemberContext && + (!D.getCXXScopeSpec().isSet() || + !computeDeclContext(D.getCXXScopeSpec())->isRecord())) || + D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) { + if (D.isFunctionDeclarator()) + Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type); + else + Diag(D.getIdentifierLoc(), + diag::err_invalid_qualified_typedef_function_type_use); + + // Strip the cv-quals from the type. + T = Context.getFunctionType(FnTy->getResultType(), FnTy->arg_type_begin(), + FnTy->getNumArgs(), FnTy->isVariadic(), 0); + } + } + + // If there were any type attributes applied to the decl itself (not the + // type, apply the type attribute to the type!) + if (const AttributeList *Attrs = D.getAttributes()) + ProcessTypeAttributeList(T, Attrs); + + return T; +} + +/// CheckSpecifiedExceptionType - Check if the given type is valid in an +/// exception specification. Incomplete types, or pointers to incomplete types +/// other than void are not allowed. +bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) { + // FIXME: This may not correctly work with the fix for core issue 437, + // where a class's own type is considered complete within its body. + + // C++ 15.4p2: A type denoted in an exception-specification shall not denote + // an incomplete type. + if (T->isIncompleteType()) + return Diag(Range.getBegin(), diag::err_incomplete_in_exception_spec) + << Range << T << /*direct*/0; + + // C++ 15.4p2: A type denoted in an exception-specification shall not denote + // an incomplete type a pointer or reference to an incomplete type, other + // than (cv) void*. + int kind; + if (const PointerType* IT = T->getAsPointerType()) { + T = IT->getPointeeType(); + kind = 1; + } else if (const ReferenceType* IT = T->getAsReferenceType()) { + T = IT->getPointeeType(); + kind = 2; + } else + return false; + + if (T->isIncompleteType() && !T->isVoidType()) + return Diag(Range.getBegin(), diag::err_incomplete_in_exception_spec) + << Range << T << /*indirect*/kind; + + return false; +} + +/// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer +/// to member to a function with an exception specification. This means that +/// it is invalid to add another level of indirection. +bool Sema::CheckDistantExceptionSpec(QualType T) { + if (const PointerType *PT = T->getAsPointerType()) + T = PT->getPointeeType(); + else if (const MemberPointerType *PT = T->getAsMemberPointerType()) + T = PT->getPointeeType(); + else + return false; + + const FunctionProtoType *FnT = T->getAsFunctionProtoType(); + if (!FnT) + return false; + + return FnT->hasExceptionSpec(); +} + +/// ObjCGetTypeForMethodDefinition - Builds the type for a method definition +/// declarator +QualType Sema::ObjCGetTypeForMethodDefinition(DeclPtrTy D) { + ObjCMethodDecl *MDecl = cast<ObjCMethodDecl>(D.getAs<Decl>()); + QualType T = MDecl->getResultType(); + llvm::SmallVector<QualType, 16> ArgTys; + + // Add the first two invisible argument types for self and _cmd. + if (MDecl->isInstanceMethod()) { + QualType selfTy = Context.getObjCInterfaceType(MDecl->getClassInterface()); + selfTy = Context.getPointerType(selfTy); + ArgTys.push_back(selfTy); + } else + ArgTys.push_back(Context.getObjCIdType()); + ArgTys.push_back(Context.getObjCSelType()); + + for (ObjCMethodDecl::param_iterator PI = MDecl->param_begin(), + E = MDecl->param_end(); PI != E; ++PI) { + QualType ArgTy = (*PI)->getType(); + assert(!ArgTy.isNull() && "Couldn't parse type?"); + ArgTy = adjustParameterType(ArgTy); + ArgTys.push_back(ArgTy); + } + T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(), + MDecl->isVariadic(), 0); + return T; +} + +/// UnwrapSimilarPointerTypes - If T1 and T2 are pointer types that +/// may be similar (C++ 4.4), replaces T1 and T2 with the type that +/// they point to and return true. If T1 and T2 aren't pointer types +/// or pointer-to-member types, or if they are not similar at this +/// level, returns false and leaves T1 and T2 unchanged. Top-level +/// qualifiers on T1 and T2 are ignored. This function will typically +/// be called in a loop that successively "unwraps" pointer and +/// pointer-to-member types to compare them at each level. +bool Sema::UnwrapSimilarPointerTypes(QualType& T1, QualType& T2) { + const PointerType *T1PtrType = T1->getAsPointerType(), + *T2PtrType = T2->getAsPointerType(); + if (T1PtrType && T2PtrType) { + T1 = T1PtrType->getPointeeType(); + T2 = T2PtrType->getPointeeType(); + return true; + } + + const MemberPointerType *T1MPType = T1->getAsMemberPointerType(), + *T2MPType = T2->getAsMemberPointerType(); + if (T1MPType && T2MPType && + Context.getCanonicalType(T1MPType->getClass()) == + Context.getCanonicalType(T2MPType->getClass())) { + T1 = T1MPType->getPointeeType(); + T2 = T2MPType->getPointeeType(); + return true; + } + return false; +} + +Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { + // C99 6.7.6: Type names have no identifier. This is already validated by + // the parser. + assert(D.getIdentifier() == 0 && "Type name should have no identifier!"); + + TagDecl *OwnedTag = 0; + QualType T = GetTypeForDeclarator(D, S, /*Skip=*/0, &OwnedTag); + if (D.isInvalidType()) + return true; + + if (getLangOptions().CPlusPlus) { + // Check that there are no default arguments (C++ only). + CheckExtraCXXDefaultArguments(D); + + // C++0x [dcl.type]p3: + // A type-specifier-seq shall not define a class or enumeration + // unless it appears in the type-id of an alias-declaration + // (7.1.3). + if (OwnedTag && OwnedTag->isDefinition()) + Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier) + << Context.getTypeDeclType(OwnedTag); + } + + return T.getAsOpaquePtr(); +} + + + +//===----------------------------------------------------------------------===// +// Type Attribute Processing +//===----------------------------------------------------------------------===// + +/// HandleAddressSpaceTypeAttribute - Process an address_space attribute on the +/// specified type. The attribute contains 1 argument, the id of the address +/// space for the type. +static void HandleAddressSpaceTypeAttribute(QualType &Type, + const AttributeList &Attr, Sema &S){ + // If this type is already address space qualified, reject it. + // Clause 6.7.3 - Type qualifiers: "No type shall be qualified by qualifiers + // for two or more different address spaces." + if (Type.getAddressSpace()) { + S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers); + return; + } + + // Check the attribute arguments. + if (Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + Expr *ASArgExpr = static_cast<Expr *>(Attr.getArg(0)); + llvm::APSInt addrSpace(32); + if (!ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_address_space_not_int) + << ASArgExpr->getSourceRange(); + return; + } + + unsigned ASIdx = static_cast<unsigned>(addrSpace.getZExtValue()); + Type = S.Context.getAddrSpaceQualType(Type, ASIdx); +} + +/// HandleObjCGCTypeAttribute - Process an objc's gc attribute on the +/// specified type. The attribute contains 1 argument, weak or strong. +static void HandleObjCGCTypeAttribute(QualType &Type, + const AttributeList &Attr, Sema &S) { + if (Type.getObjCGCAttr() != QualType::GCNone) { + S.Diag(Attr.getLoc(), diag::err_attribute_multiple_objc_gc); + return; + } + + // Check the attribute arguments. + if (!Attr.getParameterName()) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) + << "objc_gc" << 1; + return; + } + QualType::GCAttrTypes GCAttr; + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + if (Attr.getParameterName()->isStr("weak")) + GCAttr = QualType::Weak; + else if (Attr.getParameterName()->isStr("strong")) + GCAttr = QualType::Strong; + else { + S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) + << "objc_gc" << Attr.getParameterName(); + return; + } + + Type = S.Context.getObjCGCQualType(Type, GCAttr); +} + +void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL) { + // Scan through and apply attributes to this type where it makes sense. Some + // attributes (such as __address_space__, __vector_size__, etc) apply to the + // type, but others can be present in the type specifiers even though they + // apply to the decl. Here we apply type attributes and ignore the rest. + for (; AL; AL = AL->getNext()) { + // If this is an attribute we can handle, do so now, otherwise, add it to + // the LeftOverAttrs list for rechaining. + switch (AL->getKind()) { + default: break; + case AttributeList::AT_address_space: + HandleAddressSpaceTypeAttribute(Result, *AL, *this); + break; + case AttributeList::AT_objc_gc: + HandleObjCGCTypeAttribute(Result, *AL, *this); + break; + } + } +} + +/// @brief Ensure that the type T is a complete type. +/// +/// This routine checks whether the type @p T is complete in any +/// context where a complete type is required. If @p T is a complete +/// type, returns false. If @p T is a class template specialization, +/// this routine then attempts to perform class template +/// instantiation. If instantiation fails, or if @p T is incomplete +/// and cannot be completed, issues the diagnostic @p diag (giving it +/// the type @p T) and returns true. +/// +/// @param Loc The location in the source that the incomplete type +/// diagnostic should refer to. +/// +/// @param T The type that this routine is examining for completeness. +/// +/// @param diag The diagnostic value (e.g., +/// @c diag::err_typecheck_decl_incomplete_type) that will be used +/// for the error message if @p T is incomplete. +/// +/// @param Range1 An optional range in the source code that will be a +/// part of the "incomplete type" error message. +/// +/// @param Range2 An optional range in the source code that will be a +/// part of the "incomplete type" error message. +/// +/// @param PrintType If non-NULL, the type that should be printed +/// instead of @p T. This parameter should be used when the type that +/// we're checking for incompleteness isn't the type that should be +/// displayed to the user, e.g., when T is a type and PrintType is a +/// pointer to T. +/// +/// @returns @c true if @p T is incomplete and a diagnostic was emitted, +/// @c false otherwise. +bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag, + SourceRange Range1, SourceRange Range2, + QualType PrintType) { + // FIXME: Add this assertion to help us flush out problems with + // checking for dependent types and type-dependent expressions. + // + // assert(!T->isDependentType() && + // "Can't ask whether a dependent type is complete"); + + // If we have a complete type, we're done. + if (!T->isIncompleteType()) + return false; + + // If we have a class template specialization or a class member of a + // class template specialization, try to instantiate it. + if (const RecordType *Record = T->getAsRecordType()) { + if (ClassTemplateSpecializationDecl *ClassTemplateSpec + = dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) { + if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) { + // Update the class template specialization's location to + // refer to the point of instantiation. + if (Loc.isValid()) + ClassTemplateSpec->setLocation(Loc); + return InstantiateClassTemplateSpecialization(ClassTemplateSpec, + /*ExplicitInstantiation=*/false); + } + } else if (CXXRecordDecl *Rec + = dyn_cast<CXXRecordDecl>(Record->getDecl())) { + if (CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass()) { + // Find the class template specialization that surrounds this + // member class. + ClassTemplateSpecializationDecl *Spec = 0; + for (DeclContext *Parent = Rec->getDeclContext(); + Parent && !Spec; Parent = Parent->getParent()) + Spec = dyn_cast<ClassTemplateSpecializationDecl>(Parent); + assert(Spec && "Not a member of a class template specialization?"); + return InstantiateClass(Loc, Rec, Pattern, Spec->getTemplateArgs(), + /*ExplicitInstantiation=*/false); + } + } + } + + if (PrintType.isNull()) + PrintType = T; + + // We have an incomplete type. Produce a diagnostic. + Diag(Loc, diag) << PrintType << Range1 << Range2; + + // If the type was a forward declaration of a class/struct/union + // type, produce + const TagType *Tag = 0; + if (const RecordType *Record = T->getAsRecordType()) + Tag = Record; + else if (const EnumType *Enum = T->getAsEnumType()) + Tag = Enum; + + if (Tag && !Tag->getDecl()->isInvalidDecl()) + Diag(Tag->getDecl()->getLocation(), + Tag->isBeingDefined() ? diag::note_type_being_defined + : diag::note_forward_declaration) + << QualType(Tag, 0); + + return true; +} + +/// \brief Retrieve a version of the type 'T' that is qualified by the +/// nested-name-specifier contained in SS. +QualType Sema::getQualifiedNameType(const CXXScopeSpec &SS, QualType T) { + if (!SS.isSet() || SS.isInvalid() || T.isNull()) + return T; + + NestedNameSpecifier *NNS + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + return Context.getQualifiedNameType(NNS, T); +} |