aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/CMakeLists.txt33
-rw-r--r--lib/Sema/CXXFieldCollector.h76
-rw-r--r--lib/Sema/IdentifierResolver.cpp293
-rw-r--r--lib/Sema/IdentifierResolver.h214
-rw-r--r--lib/Sema/JumpDiagnostics.cpp327
-rw-r--r--lib/Sema/Makefile23
-rw-r--r--lib/Sema/ParseAST.cpp85
-rw-r--r--lib/Sema/Sema.cpp333
-rw-r--r--lib/Sema/Sema.h2814
-rw-r--r--lib/Sema/SemaAccess.cpp124
-rw-r--r--lib/Sema/SemaAttr.cpp211
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp312
-rw-r--r--lib/Sema/SemaChecking.cpp1449
-rw-r--r--lib/Sema/SemaDecl.cpp4415
-rw-r--r--lib/Sema/SemaDeclAttr.cpp1803
-rw-r--r--lib/Sema/SemaDeclCXX.cpp2823
-rw-r--r--lib/Sema/SemaDeclObjC.cpp2166
-rw-r--r--lib/Sema/SemaExpr.cpp5395
-rw-r--r--lib/Sema/SemaExprCXX.cpp1603
-rw-r--r--lib/Sema/SemaExprObjC.cpp860
-rw-r--r--lib/Sema/SemaInherit.cpp344
-rw-r--r--lib/Sema/SemaInherit.h248
-rw-r--r--lib/Sema/SemaInit.cpp1784
-rw-r--r--lib/Sema/SemaLookup.cpp1626
-rw-r--r--lib/Sema/SemaNamedCast.cpp932
-rw-r--r--lib/Sema/SemaOverload.cpp4485
-rw-r--r--lib/Sema/SemaOverload.h263
-rw-r--r--lib/Sema/SemaStmt.cpp1266
-rw-r--r--lib/Sema/SemaTemplate.cpp2651
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp1034
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp767
-rw-r--r--lib/Sema/SemaTemplateInstantiateExpr.cpp1278
-rw-r--r--lib/Sema/SemaTemplateInstantiateStmt.cpp443
-rw-r--r--lib/Sema/SemaType.cpp1301
34 files changed, 43781 insertions, 0 deletions
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
new file mode 100644
index 000000000000..321dac18b6a2
--- /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 000000000000..69d13515fa65
--- /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 000000000000..ceab859c90aa
--- /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 000000000000..0b0e6b388dde
--- /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 000000000000..ae863f2df1ee
--- /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 000000000000..0f4c7965dca2
--- /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 000000000000..e2ee88ac86bc
--- /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 000000000000..1212d070f699
--- /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 000000000000..c428d29367de
--- /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 000000000000..bae69ac6dc74
--- /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 000000000000..1bf8444c42b7
--- /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 000000000000..11ac0bd30056
--- /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 000000000000..4856e7fd2164
--- /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 000000000000..959154c4ec1b
--- /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 000000000000..99b4d77fad42
--- /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 000000000000..f13179f0438f
--- /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 000000000000..8f580341bdc6
--- /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 000000000000..ee5132a7d8e0
--- /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 000000000000..65018daff75b
--- /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 000000000000..eabc87d7f3b8
--- /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 000000000000..1b968f0fbcce
--- /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 000000000000..b1e791a17ba3
--- /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 000000000000..4e0eb1d431fe
--- /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 000000000000..6212449744ca
--- /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 000000000000..daf6800ea0c0
--- /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 000000000000..98ee13af856a
--- /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 000000000000..9de380657612
--- /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 000000000000..15262e9c3ac2
--- /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 000000000000..782a0d87d897
--- /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 000000000000..d3d771b0ebb6
--- /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 000000000000..6d7dc2e6d531
--- /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 000000000000..a6b9703cee0b
--- /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 000000000000..1f69479a0e7c
--- /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 000000000000..81ac21123e91
--- /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);
+}