summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/Makefile23
-rw-r--r--clang/lib/Sema/ParseAST.cpp69
-rw-r--r--clang/lib/Sema/Sema.cpp222
-rw-r--r--clang/lib/Sema/Sema.h823
-rw-r--r--clang/lib/Sema/SemaChecking.cpp802
-rw-r--r--clang/lib/Sema/SemaDecl.cpp2297
-rw-r--r--clang/lib/Sema/SemaDeclObjC.cpp927
-rw-r--r--clang/lib/Sema/SemaExpr.cpp2286
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp51
-rw-r--r--clang/lib/Sema/SemaExprObjC.cpp297
-rw-r--r--clang/lib/Sema/SemaStmt.cpp821
-rw-r--r--clang/lib/Sema/SemaType.cpp498
-rw-r--r--clang/lib/Sema/SemaUtil.h35
13 files changed, 9151 insertions, 0 deletions
diff --git a/clang/lib/Sema/Makefile b/clang/lib/Sema/Makefile
new file mode 100644
index 00000000000..19a00275f0f
--- /dev/null
+++ b/clang/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
+
+include $(LEVEL)/Makefile.common
+
diff --git a/clang/lib/Sema/ParseAST.cpp b/clang/lib/Sema/ParseAST.cpp
new file mode 100644
index 00000000000..364b0729100
--- /dev/null
+++ b/clang/lib/Sema/ParseAST.cpp
@@ -0,0 +1,69 @@
+//===--- 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 "clang/AST/ASTContext.h"
+#include "clang/AST/ASTConsumer.h"
+#include "Sema.h"
+#include "clang/Parse/Action.h"
+#include "clang/Parse/Parser.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Public interface to the file
+//===----------------------------------------------------------------------===//
+
+/// ParseAST - Parse the entire file specified, notifying the ASTConsumer as
+/// the file is parsed. This takes ownership of the ASTConsumer and
+/// ultimately deletes it.
+void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, bool PrintStats) {
+ // Collect global stats on Decls/Stmts (until we have a module streamer).
+ if (PrintStats) {
+ Decl::CollectingStats(true);
+ Stmt::CollectingStats(true);
+ }
+
+ ASTContext Context(PP.getSourceManager(), PP.getTargetInfo(),
+ PP.getIdentifierTable(), PP.getSelectorTable());
+
+ Parser P(PP, *new Sema(PP, Context, *Consumer));
+ PP.EnterMainSourceFile();
+
+ // Initialize the parser.
+ P.Initialize();
+
+ Consumer->Initialize(Context);
+
+ Parser::DeclTy *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(static_cast<Decl*>(ADecl));
+ };
+
+ if (PrintStats) {
+ fprintf(stderr, "\nSTATISTICS:\n");
+ P.getActions().PrintStats();
+ Context.PrintStats();
+ Decl::PrintStats();
+ Stmt::PrintStats();
+ Consumer->PrintStats();
+
+ Decl::CollectingStats(false);
+ Stmt::CollectingStats(false);
+ }
+
+ delete Consumer;
+}
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
new file mode 100644
index 00000000000..4bd04e3a1a5
--- /dev/null
+++ b/clang/lib/Sema/Sema.cpp
@@ -0,0 +1,222 @@
+//===--- 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/ASTContext.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Parse/Scope.h"
+
+using namespace clang;
+
+bool Sema::isBuiltinObjCType(TypedefDecl *TD) {
+ const char *typeName = TD->getIdentifier()->getName();
+ return strcmp(typeName, "id") == 0 || strcmp(typeName, "Class") == 0 ||
+ strcmp(typeName, "SEL") == 0 || strcmp(typeName, "Protocol") == 0;
+}
+
+bool Sema::isObjCObjectPointerType(QualType type) const {
+ if (!type->isPointerType() && !type->isObjCQualifiedIdType())
+ return false;
+ if (type == Context.getObjCIdType() || type == Context.getObjCClassType() ||
+ type->isObjCQualifiedIdType())
+ return true;
+
+ if (type->isPointerType()) {
+ PointerType *pointerType = static_cast<PointerType*>(type.getTypePtr());
+ type = pointerType->getPointeeType();
+ }
+ return (type->isObjCInterfaceType() || type->isObjCQualifiedIdType());
+}
+
+void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
+ TUScope = S;
+ if (!PP.getLangOptions().ObjC1) return;
+
+ TypedefType *t;
+
+ // Add the built-in ObjC types.
+ t = cast<TypedefType>(Context.getObjCIdType().getTypePtr());
+ t->getDecl()->getIdentifier()->setFETokenInfo(t->getDecl());
+ TUScope->AddDecl(t->getDecl());
+ t = cast<TypedefType>(Context.getObjCClassType().getTypePtr());
+ t->getDecl()->getIdentifier()->setFETokenInfo(t->getDecl());
+ TUScope->AddDecl(t->getDecl());
+ ObjCInterfaceType *it = cast<ObjCInterfaceType>(Context.getObjCProtoType());
+ ObjCInterfaceDecl *IDecl = it->getDecl();
+ IDecl->getIdentifier()->setFETokenInfo(IDecl);
+ TUScope->AddDecl(IDecl);
+
+ // Synthesize "typedef struct objc_selector *SEL;"
+ RecordDecl *SelTag = RecordDecl::Create(Context, Decl::Struct,
+ SourceLocation(),
+ &Context.Idents.get("objc_selector"),
+ 0);
+ SelTag->getIdentifier()->setFETokenInfo(SelTag);
+ TUScope->AddDecl(SelTag);
+
+ QualType SelT = Context.getPointerType(Context.getTagDeclType(SelTag));
+ TypedefDecl *SelTypedef = TypedefDecl::Create(Context, SourceLocation(),
+ &Context.Idents.get("SEL"),
+ SelT, 0);
+ SelTypedef->getIdentifier()->setFETokenInfo(SelTypedef);
+ TUScope->AddDecl(SelTypedef);
+ Context.setObjCSelType(SelTypedef);
+}
+
+Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer)
+ : PP(pp), Context(ctxt), Consumer(consumer),
+ CurFunctionDecl(0), CurMethodDecl(0) {
+
+ // Get IdentifierInfo objects for known functions for which we
+ // do extra checking.
+ IdentifierTable &IT = PP.getIdentifierTable();
+
+ KnownFunctionIDs[id_printf] = &IT.get("printf");
+ KnownFunctionIDs[id_fprintf] = &IT.get("fprintf");
+ KnownFunctionIDs[id_sprintf] = &IT.get("sprintf");
+ KnownFunctionIDs[id_snprintf] = &IT.get("snprintf");
+ KnownFunctionIDs[id_asprintf] = &IT.get("asprintf");
+ KnownFunctionIDs[id_vsnprintf] = &IT.get("vsnprintf");
+ KnownFunctionIDs[id_vasprintf] = &IT.get("vasprintf");
+ KnownFunctionIDs[id_vfprintf] = &IT.get("vfprintf");
+ KnownFunctionIDs[id_vsprintf] = &IT.get("vsprintf");
+ KnownFunctionIDs[id_vprintf] = &IT.get("vprintf");
+
+ // FIXME: Move this initialization up to Sema::ActOnTranslationUnitScope()
+ // and make sure the decls get inserted into TUScope!
+ if (PP.getLangOptions().ObjC1) {
+ // Synthesize "typedef struct objc_class *Class;"
+ RecordDecl *ClassTag = RecordDecl::Create(Context, Decl::Struct,
+ SourceLocation(),
+ &IT.get("objc_class"), 0);
+ QualType ClassT = Context.getPointerType(Context.getTagDeclType(ClassTag));
+ TypedefDecl *ClassTypedef =
+ TypedefDecl::Create(Context, SourceLocation(),
+ &Context.Idents.get("Class"), ClassT, 0);
+ Context.setObjCClassType(ClassTypedef);
+
+ // Synthesize "@class Protocol;
+ ObjCInterfaceDecl *ProtocolDecl = new ObjCInterfaceDecl(SourceLocation(), 0,
+ &Context.Idents.get("Protocol"), true);
+ Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl));
+
+ // Synthesize "typedef struct objc_object { Class isa; } *id;"
+ RecordDecl *ObjectTag =
+ RecordDecl::Create(Context, Decl::Struct, SourceLocation(),
+ &IT.get("objc_object"), 0);
+ FieldDecl *IsaDecl = new FieldDecl(SourceLocation(), 0,
+ Context.getObjCClassType());
+ ObjectTag->defineBody(&IsaDecl, 1);
+ QualType ObjT = Context.getPointerType(Context.getTagDeclType(ObjectTag));
+ TypedefDecl *IdTypedef = TypedefDecl::Create(Context, SourceLocation(),
+ &Context.Idents.get("id"),
+ ObjT, 0);
+ Context.setObjCIdType(IdTypedef);
+ }
+ TUScope = 0;
+}
+
+/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
+/// If there is already an implicit cast, merge into the existing one.
+void Sema::ImpCastExprToType(Expr *&Expr, QualType Type) {
+ if (Expr->getType().getCanonicalType() == Type.getCanonicalType()) return;
+
+ if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr))
+ ImpCast->setType(Type);
+ else
+ Expr = new ImplicitCastExpr(Type, Expr);
+}
+
+
+
+void Sema::DeleteExpr(ExprTy *E) {
+ delete static_cast<Expr*>(E);
+}
+void Sema::DeleteStmt(StmtTy *S) {
+ delete static_cast<Stmt*>(S);
+}
+
+//===----------------------------------------------------------------------===//
+// Helper functions.
+//===----------------------------------------------------------------------===//
+
+bool Sema::Diag(SourceLocation Loc, unsigned DiagID) {
+ PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID);
+ return true;
+}
+
+bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg) {
+ PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, &Msg, 1);
+ return true;
+}
+
+bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1,
+ const std::string &Msg2) {
+ std::string MsgArr[] = { Msg1, Msg2 };
+ PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, MsgArr, 2);
+ return true;
+}
+
+bool Sema::Diag(SourceLocation Loc, unsigned DiagID, SourceRange Range) {
+ PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, 0, 0, &Range,1);
+ return true;
+}
+
+bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg,
+ SourceRange Range) {
+ PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, &Msg, 1, &Range,1);
+ return true;
+}
+
+bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1,
+ const std::string &Msg2, SourceRange Range) {
+ std::string MsgArr[] = { Msg1, Msg2 };
+ PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, MsgArr, 2, &Range, 1);
+ return true;
+}
+
+bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1,
+ const std::string &Msg2, const std::string &Msg3,
+ SourceRange R1) {
+ std::string MsgArr[] = { Msg1, Msg2, Msg3 };
+ PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, MsgArr, 3, &R1, 1);
+ return true;
+}
+
+bool Sema::Diag(SourceLocation Loc, unsigned DiagID,
+ SourceRange R1, SourceRange R2) {
+ SourceRange RangeArr[] = { R1, R2 };
+ PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, 0, 0, RangeArr, 2);
+ return true;
+}
+
+bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg,
+ SourceRange R1, SourceRange R2) {
+ SourceRange RangeArr[] = { R1, R2 };
+ PP.getDiagnostics().Report(PP.getFullLoc(Loc), DiagID, &Msg, 1, RangeArr, 2);
+ return true;
+}
+
+bool Sema::Diag(SourceLocation Range, unsigned DiagID, const std::string &Msg1,
+ const std::string &Msg2, SourceRange R1, SourceRange R2) {
+ std::string MsgArr[] = { Msg1, Msg2 };
+ SourceRange RangeArr[] = { R1, R2 };
+ PP.getDiagnostics().Report(PP.getFullLoc(Range),DiagID, MsgArr,2,RangeArr, 2);
+ return true;
+}
+
+const LangOptions &Sema::getLangOptions() const {
+ return PP.getLangOptions();
+}
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h
new file mode 100644
index 00000000000..fc81781911c
--- /dev/null
+++ b/clang/lib/Sema/Sema.h
@@ -0,0 +1,823 @@
+//===--- 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 "clang/Parse/Action.h"
+#include "clang/Parse/DeclSpec.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include <vector>
+#include <string>
+
+namespace llvm {
+ class APSInt;
+}
+
+namespace clang {
+ class ASTContext;
+ class ASTConsumer;
+ class Preprocessor;
+ class Decl;
+ class ScopedDecl;
+ class Expr;
+ class InitListExpr;
+ class CallExpr;
+ class VarDecl;
+ class ParmVarDecl;
+ class TypedefDecl;
+ class FunctionDecl;
+ class QualType;
+ struct LangOptions;
+ class Token;
+ class IntegerLiteral;
+ class StringLiteral;
+ class ArrayType;
+ class LabelStmt;
+ class SwitchStmt;
+ class OCUVectorType;
+ class TypedefDecl;
+ class ObjCInterfaceDecl;
+ class ObjCProtocolDecl;
+ class ObjCImplementationDecl;
+ class ObjCCategoryImplDecl;
+ class ObjCCategoryDecl;
+ class ObjCIvarDecl;
+ class ObjCMethodDecl;
+
+/// Sema - This implements semantic analysis and AST building for C.
+class Sema : public Action {
+ Preprocessor &PP;
+ ASTContext &Context;
+ ASTConsumer &Consumer;
+
+ /// CurFunctionDecl - If inside of a function body, this contains a pointer to
+ /// the function decl for the function being parsed.
+ FunctionDecl *CurFunctionDecl;
+
+ /// CurMethodDecl - If inside of a method body, this contains a pointer to
+ /// the method decl for the method being parsed.
+ ObjCMethodDecl *CurMethodDecl;
+
+ /// 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;
+
+ llvm::SmallVector<SwitchStmt*, 8> SwitchStack;
+
+ /// OCUVectorDecls - This is a list all the OCU vector types. This allows
+ /// us to associate a raw vector type with one of the OCU type names.
+ /// This is only necessary for issuing pretty diagnostics.
+ llvm::SmallVector<TypedefDecl*, 24> OCUVectorDecls;
+
+ /// ObjCImplementations - Keep track of all of the classes with
+ /// @implementation's, so that we can emit errors on duplicates.
+ llvm::DenseMap<IdentifierInfo*, ObjCImplementationDecl*> ObjCImplementations;
+
+ /// ObjCProtocols - Keep track of all protocol declarations declared
+ /// with @protocol keyword, so that we can emit errors on duplicates and
+ /// find the declarations when needed.
+ llvm::DenseMap<IdentifierInfo*, ObjCProtocolDecl*> ObjCProtocols;
+
+ // Enum values used by KnownFunctionIDs (see below).
+ enum {
+ id_printf,
+ id_fprintf,
+ id_sprintf,
+ id_snprintf,
+ id_asprintf,
+ id_vsnprintf,
+ id_vasprintf,
+ id_vfprintf,
+ id_vsprintf,
+ id_vprintf,
+ id_num_known_functions
+ };
+
+ /// KnownFunctionIDs - This is a list of IdentifierInfo objects to a set
+ /// of known functions used by the semantic analysis to do various
+ /// kinds of checking (e.g. checking format string errors in printf calls).
+ /// This list is populated upon the creation of a Sema object.
+ IdentifierInfo* KnownFunctionIDs[ id_num_known_functions ];
+
+ /// 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;
+
+ /// ObjCMethodList - a linked list of methods with different signatures.
+ struct ObjCMethodList {
+ ObjCMethodDecl *Method;
+ ObjCMethodList *Next;
+
+ ObjCMethodList() {
+ Method = 0;
+ Next = 0;
+ }
+ ObjCMethodList(ObjCMethodDecl *M, ObjCMethodList *C) {
+ Method = M;
+ Next = C;
+ }
+ };
+ /// 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").
+ llvm::DenseMap<Selector, ObjCMethodList> InstanceMethodPool;
+ llvm::DenseMap<Selector, ObjCMethodList> FactoryMethodPool;
+public:
+ Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer);
+
+ const LangOptions &getLangOptions() const;
+
+ /// The primitive diagnostic helpers - always returns true, which simplifies
+ /// error handling (i.e. less code).
+ bool Diag(SourceLocation Loc, unsigned DiagID);
+ bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg);
+ bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1,
+ const std::string &Msg2);
+
+ /// More expressive diagnostic helpers for expressions (say that 6 times:-)
+ bool Diag(SourceLocation Loc, unsigned DiagID, SourceRange R1);
+ bool Diag(SourceLocation Loc, unsigned DiagID,
+ SourceRange R1, SourceRange R2);
+ bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg,
+ SourceRange R1);
+ bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg,
+ SourceRange R1, SourceRange R2);
+ bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1,
+ const std::string &Msg2, SourceRange R1);
+ bool Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg1,
+ const std::string &Msg2, const std::string &Msg3, SourceRange R1);
+ bool Diag(SourceLocation Loc, unsigned DiagID,
+ const std::string &Msg1, const std::string &Msg2,
+ SourceRange R1, SourceRange R2);
+
+ virtual void DeleteExpr(ExprTy *E);
+ virtual void DeleteStmt(StmtTy *S);
+
+ //===--------------------------------------------------------------------===//
+ // Type Analysis / Processing: SemaType.cpp.
+ //
+ QualType ConvertDeclSpecToType(DeclSpec &DS);
+ AttributeList *ProcessTypeAttributes(QualType &Result, AttributeList *AL);
+ QualType GetTypeForDeclarator(Declarator &D, Scope *S);
+
+
+ QualType ObjCGetTypeForMethodDefinition(DeclTy *D);
+
+
+ virtual TypeResult ActOnTypeName(Scope *S, Declarator &D);
+
+ virtual TypeResult ActOnParamDeclaratorType(Scope *S, Declarator &D);
+private:
+ //===--------------------------------------------------------------------===//
+ // Symbol table / Decl tracking callbacks: SemaDecl.cpp.
+ //
+ virtual DeclTy *isTypeName(const IdentifierInfo &II, Scope *S) const;
+ virtual DeclTy *ActOnDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup);
+ void AddInitializerToDecl(DeclTy *dcl, ExprTy *init);
+ virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group);
+
+ virtual DeclTy *ActOnStartOfFunctionDef(Scope *S, Declarator &D);
+ virtual void ObjCActOnStartOfMethodDef(Scope *S, DeclTy *D);
+
+ virtual DeclTy *ActOnFinishFunctionBody(DeclTy *Decl, StmtTy *Body);
+ virtual DeclTy *ActOnLinkageSpec(SourceLocation Loc, SourceLocation LBrace,
+ SourceLocation RBrace, const char *Lang,
+ unsigned StrSize, DeclTy *D);
+ virtual DeclTy *ActOnFileScopeAsmDecl(SourceLocation Loc, ExprTy *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 DeclTy *ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS);
+
+ virtual DeclTy *ActOnTag(Scope *S, unsigned TagType, TagKind TK,
+ SourceLocation KWLoc, IdentifierInfo *Name,
+ SourceLocation NameLoc, AttributeList *Attr);
+ virtual DeclTy *ActOnField(Scope *S, DeclTy *TagDecl,SourceLocation DeclStart,
+ Declarator &D, ExprTy *BitfieldWidth);
+
+ // This is used for both record definitions and ObjC interface declarations.
+ virtual void ActOnFields(Scope* S,
+ SourceLocation RecLoc, DeclTy *TagDecl,
+ DeclTy **Fields, unsigned NumFields,
+ SourceLocation LBrac, SourceLocation RBrac,
+ tok::ObjCKeywordKind *visibility = 0);
+ virtual DeclTy *ActOnEnumConstant(Scope *S, DeclTy *EnumDecl,
+ DeclTy *LastEnumConstant,
+ SourceLocation IdLoc, IdentifierInfo *Id,
+ SourceLocation EqualLoc, ExprTy *Val);
+ virtual void ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDecl,
+ DeclTy **Elements, unsigned NumElements);
+private:
+ /// Subroutines of ActOnDeclarator().
+ TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
+ ScopedDecl *LastDecl);
+ TypedefDecl *MergeTypeDefDecl(TypedefDecl *New, ScopedDecl *Old);
+ FunctionDecl *MergeFunctionDecl(FunctionDecl *New, ScopedDecl *Old);
+ VarDecl *MergeVarDecl(VarDecl *New, ScopedDecl *Old);
+
+ /// More parsing and symbol table subroutines...
+ ParmVarDecl *ActOnParamDeclarator(struct DeclaratorChunk::ParamInfo &PI,
+ Scope *FnBodyScope);
+ ScopedDecl *LookupScopedDecl(IdentifierInfo *II, unsigned NSI,
+ SourceLocation IdLoc, Scope *S);
+ ScopedDecl *LookupInterfaceDecl(IdentifierInfo *II);
+ ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id);
+ ScopedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, Scope *S);
+ ScopedDecl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II,
+ Scope *S);
+ // Decl attributes - this routine is the top level dispatcher.
+ void HandleDeclAttributes(Decl *New, AttributeList *declspec_prefix,
+ AttributeList *declarator_postfix);
+ void HandleDeclAttribute(Decl *New, AttributeList *rawAttr);
+
+ /// HandleAddressSpaceTypeAttribute - this attribute is only applicable to
+ /// objects without automatic storage duration.
+ /// The raw attribute contains 1 argument, the id of the address space
+ /// for the type.
+ QualType HandleAddressSpaceTypeAttribute(QualType curType,
+ AttributeList *rawAttr);
+
+ // HandleVectorTypeAttribute - 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.
+ QualType HandleVectorTypeAttribute(QualType curType, AttributeList *rawAttr);
+ void HandleOCUVectorTypeAttribute(TypedefDecl *d, AttributeList *rawAttr);
+
+ void HandleAlignedAttribute(Decl *d, AttributeList *rawAttr);
+ void HandlePackedAttribute(Decl *d, AttributeList *rawAttr);
+ void HandleAnnotateAttribute(Decl *d, AttributeList *rawAttr);
+ void HandleNoReturnAttribute(Decl *d, AttributeList *rawAttr);
+ void HandleDeprecatedAttribute(Decl *d, AttributeList *rawAttr);
+ void HandleWeakAttribute(Decl *d, AttributeList *rawAttr);
+ void HandleDLLImportAttribute(Decl *d, AttributeList *rawAttr);
+ void HandleDLLExportAttribute(Decl *d, AttributeList *rawAttr);
+ void HandleVisibilityAttribute(Decl *d, AttributeList *rawAttr);
+ void HandleNothrowAttribute(Decl *d, AttributeList *rawAttr);
+ void HandleFormatAttribute(Decl *d, AttributeList *rawAttr);
+ void HandleStdCallAttribute(Decl *d, AttributeList *rawAttr);
+ void HandleFastCallAttribute(Decl *d, AttributeList *rawAttr);
+
+ void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
+ bool &IncompleteImpl);
+
+ /// CheckProtocolMethodDefs - This routine checks unimpletented methods
+ /// Declared in protocol, and those referenced by it.
+ void CheckProtocolMethodDefs(SourceLocation ImpLoc,
+ ObjCProtocolDecl *PDecl,
+ bool& IncompleteImpl,
+ const llvm::DenseSet<Selector> &InsMap,
+ const llvm::DenseSet<Selector> &ClsMap);
+
+ /// 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 @implementation class.
+ void ImplMethodsVsClassMethods(ObjCImplementationDecl* IMPDecl,
+ ObjCInterfaceDecl* IDecl);
+
+ /// ImplCategoryMethodsVsIntfMethods - Checks that methods declared in the
+ /// category interface is implemented in the category @implementation.
+ void ImplCategoryMethodsVsIntfMethods(ObjCCategoryImplDecl *CatImplDecl,
+ ObjCCategoryDecl *CatClassDecl);
+ /// MatchTwoMethodDeclarations - Checks if two methods' type match and returns
+ /// true, or false, accordingly.
+ bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method,
+ const ObjCMethodDecl *PrevMethod);
+
+ /// isBuiltinObjCType - Returns true of the type is "id", "SEL", "Class"
+ /// or "Protocol".
+ bool isBuiltinObjCType(TypedefDecl *TD);
+
+ /// isObjCObjectPointerType - Returns true if type is an objective-c pointer
+ /// to an object type; such as "id", "Class", Intf*, id<P>, etc.
+ bool isObjCObjectPointerType(QualType type) const;
+
+ /// 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);
+
+ /// AddFactoryMethodToGlobalPool - Same as above, but for factory methods.
+ void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method);
+ //===--------------------------------------------------------------------===//
+ // Statement Parsing Callbacks: SemaStmt.cpp.
+public:
+ virtual StmtResult ActOnExprStmt(ExprTy *Expr);
+
+ virtual StmtResult ActOnNullStmt(SourceLocation SemiLoc);
+ virtual StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R,
+ StmtTy **Elts, unsigned NumElts,
+ bool isStmtExpr);
+ virtual StmtResult ActOnDeclStmt(DeclTy *Decl, SourceLocation StartLoc,
+ SourceLocation EndLoc);
+ virtual StmtResult ActOnCaseStmt(SourceLocation CaseLoc, ExprTy *LHSVal,
+ SourceLocation DotDotDotLoc, ExprTy *RHSVal,
+ SourceLocation ColonLoc, StmtTy *SubStmt);
+ virtual StmtResult ActOnDefaultStmt(SourceLocation DefaultLoc,
+ SourceLocation ColonLoc, StmtTy *SubStmt,
+ Scope *CurScope);
+ virtual StmtResult ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II,
+ SourceLocation ColonLoc, StmtTy *SubStmt);
+ virtual StmtResult ActOnIfStmt(SourceLocation IfLoc, ExprTy *CondVal,
+ StmtTy *ThenVal, SourceLocation ElseLoc,
+ StmtTy *ElseVal);
+ virtual StmtResult ActOnStartOfSwitchStmt(ExprTy *Cond);
+ virtual StmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc,
+ StmtTy *Switch, ExprTy *Body);
+ virtual StmtResult ActOnWhileStmt(SourceLocation WhileLoc, ExprTy *Cond,
+ StmtTy *Body);
+ virtual StmtResult ActOnDoStmt(SourceLocation DoLoc, StmtTy *Body,
+ SourceLocation WhileLoc, ExprTy *Cond);
+
+ virtual StmtResult ActOnForStmt(SourceLocation ForLoc,
+ SourceLocation LParenLoc,
+ StmtTy *First, ExprTy *Second, ExprTy *Third,
+ SourceLocation RParenLoc, StmtTy *Body);
+ virtual StmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc,
+ SourceLocation LParenLoc,
+ StmtTy *First, ExprTy *Second,
+ SourceLocation RParenLoc, StmtTy *Body);
+
+ virtual StmtResult ActOnGotoStmt(SourceLocation GotoLoc,
+ SourceLocation LabelLoc,
+ IdentifierInfo *LabelII);
+ virtual StmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc,
+ SourceLocation StarLoc,
+ ExprTy *DestExp);
+ virtual StmtResult ActOnContinueStmt(SourceLocation ContinueLoc,
+ Scope *CurScope);
+ virtual StmtResult ActOnBreakStmt(SourceLocation GotoLoc, Scope *CurScope);
+
+ virtual StmtResult ActOnReturnStmt(SourceLocation ReturnLoc,
+ ExprTy *RetValExp);
+
+ virtual StmtResult ActOnAsmStmt(SourceLocation AsmLoc,
+ bool IsSimple,
+ bool IsVolatile,
+ unsigned NumOutputs,
+ unsigned NumInputs,
+ std::string *Names,
+ ExprTy **Constraints,
+ ExprTy **Exprs,
+ ExprTy *AsmString,
+ unsigned NumClobbers,
+ ExprTy **Clobbers,
+ SourceLocation RParenLoc);
+
+ virtual StmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc,
+ SourceLocation RParen, StmtTy *Parm,
+ StmtTy *Body, StmtTy *CatchList);
+
+ virtual StmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc,
+ StmtTy *Body);
+
+ virtual StmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc,
+ StmtTy *Try,
+ StmtTy *Catch, StmtTy *Finally);
+
+ virtual StmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc,
+ StmtTy *Throw);
+ virtual StmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc,
+ ExprTy *SynchExpr,
+ StmtTy *SynchBody);
+
+ //===--------------------------------------------------------------------===//
+ // Expression Parsing Callbacks: SemaExpr.cpp.
+
+ // Primary Expressions.
+ virtual ExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
+ IdentifierInfo &II,
+ bool HasTrailingLParen);
+ virtual ExprResult ActOnPreDefinedExpr(SourceLocation Loc,
+ tok::TokenKind Kind);
+ virtual ExprResult ActOnNumericConstant(const Token &);
+ virtual ExprResult ActOnCharacterConstant(const Token &);
+ virtual ExprResult ActOnParenExpr(SourceLocation L, SourceLocation R,
+ ExprTy *Val);
+
+ /// ActOnStringLiteral - The specified tokens were lexed as pasted string
+ /// fragments (e.g. "foo" "bar" L"baz").
+ virtual ExprResult ActOnStringLiteral(const Token *Toks, unsigned NumToks);
+
+ // Binary/Unary Operators. 'Tok' is the token for the operator.
+ virtual ExprResult ActOnUnaryOp(SourceLocation OpLoc, tok::TokenKind Op,
+ ExprTy *Input);
+ virtual ExprResult
+ ActOnSizeOfAlignOfTypeExpr(SourceLocation OpLoc, bool isSizeof,
+ SourceLocation LParenLoc, TypeTy *Ty,
+ SourceLocation RParenLoc);
+
+ virtual ExprResult ActOnPostfixUnaryOp(SourceLocation OpLoc,
+ tok::TokenKind Kind, ExprTy *Input);
+
+ virtual ExprResult ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc,
+ ExprTy *Idx, SourceLocation RLoc);
+ virtual ExprResult ActOnMemberReferenceExpr(ExprTy *Base,SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation MemberLoc,
+ IdentifierInfo &Member);
+
+ /// 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 ExprResult ActOnCallExpr(ExprTy *Fn, SourceLocation LParenLoc,
+ ExprTy **Args, unsigned NumArgs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc);
+
+ virtual ExprResult ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
+ SourceLocation RParenLoc, ExprTy *Op);
+
+ virtual ExprResult ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty,
+ SourceLocation RParenLoc, ExprTy *Op);
+
+ virtual ExprResult ActOnInitList(SourceLocation LParenLoc,
+ ExprTy **InitList, unsigned NumInit,
+ SourceLocation RParenLoc);
+
+ virtual ExprResult ActOnBinOp(SourceLocation TokLoc, tok::TokenKind Kind,
+ ExprTy *LHS,ExprTy *RHS);
+
+ /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
+ /// in the case of a the GNU conditional expr extension.
+ virtual ExprResult ActOnConditionalOp(SourceLocation QuestionLoc,
+ SourceLocation ColonLoc,
+ ExprTy *Cond, ExprTy *LHS, ExprTy *RHS);
+
+ /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo".
+ virtual ExprResult ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc,
+ IdentifierInfo *LabelII);
+
+ virtual ExprResult ActOnStmtExpr(SourceLocation LPLoc, StmtTy *SubStmt,
+ SourceLocation RPLoc); // "({..})"
+
+ /// __builtin_offsetof(type, a.b[123][456].c)
+ virtual ExprResult ActOnBuiltinOffsetOf(SourceLocation BuiltinLoc,
+ SourceLocation TypeLoc, TypeTy *Arg1,
+ OffsetOfComponent *CompPtr,
+ unsigned NumComponents,
+ SourceLocation RParenLoc);
+
+ // __builtin_types_compatible_p(type1, type2)
+ virtual ExprResult ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc,
+ TypeTy *arg1, TypeTy *arg2,
+ SourceLocation RPLoc);
+
+ // __builtin_choose_expr(constExpr, expr1, expr2)
+ virtual ExprResult ActOnChooseExpr(SourceLocation BuiltinLoc,
+ ExprTy *cond, ExprTy *expr1, ExprTy *expr2,
+ SourceLocation RPLoc);
+
+ // __builtin_overload(...)
+ virtual ExprResult ActOnOverloadExpr(ExprTy **Args, unsigned NumArgs,
+ SourceLocation *CommaLocs,
+ SourceLocation BuiltinLoc,
+ SourceLocation RParenLoc);
+
+ // __builtin_va_arg(expr, type)
+ virtual ExprResult ActOnVAArg(SourceLocation BuiltinLoc,
+ ExprTy *expr, TypeTy *type,
+ SourceLocation RPLoc);
+
+ /// ActOnCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's.
+ virtual ExprResult ActOnCXXCasts(SourceLocation OpLoc, tok::TokenKind Kind,
+ SourceLocation LAngleBracketLoc, TypeTy *Ty,
+ SourceLocation RAngleBracketLoc,
+ SourceLocation LParenLoc, ExprTy *E,
+ SourceLocation RParenLoc);
+
+ /// ActOnCXXBoolLiteral - Parse {true,false} literals.
+ virtual ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc,
+ tok::TokenKind Kind);
+
+ //// ActOnCXXThrow - Parse throw expressions.
+ virtual ExprResult ActOnCXXThrow(SourceLocation OpLoc,
+ ExprTy *expr);
+
+ // 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);
+
+ // Objective-C declarations.
+ virtual DeclTy *ActOnStartClassInterface(
+ SourceLocation AtInterafceLoc,
+ IdentifierInfo *ClassName, SourceLocation ClassLoc,
+ IdentifierInfo *SuperName, SourceLocation SuperLoc,
+ IdentifierInfo **ProtocolNames, unsigned NumProtocols,
+ SourceLocation EndProtoLoc, AttributeList *AttrList);
+
+ virtual DeclTy *ActOnCompatiblityAlias(
+ SourceLocation AtCompatibilityAliasLoc,
+ IdentifierInfo *AliasName, SourceLocation AliasLocation,
+ IdentifierInfo *ClassName, SourceLocation ClassLocation);
+
+ virtual DeclTy *ActOnStartProtocolInterface(
+ SourceLocation AtProtoInterfaceLoc,
+ IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc,
+ IdentifierInfo **ProtoRefNames, unsigned NumProtoRefs,
+ SourceLocation EndProtoLoc);
+
+ virtual DeclTy *ActOnStartCategoryInterface(
+ SourceLocation AtInterfaceLoc,
+ IdentifierInfo *ClassName, SourceLocation ClassLoc,
+ IdentifierInfo *CategoryName, SourceLocation CategoryLoc,
+ IdentifierInfo **ProtoRefNames, unsigned NumProtoRefs,
+ SourceLocation EndProtoLoc);
+
+ virtual DeclTy *ActOnStartClassImplementation(
+ SourceLocation AtClassImplLoc,
+ IdentifierInfo *ClassName, SourceLocation ClassLoc,
+ IdentifierInfo *SuperClassname,
+ SourceLocation SuperClassLoc);
+
+ virtual DeclTy *ActOnStartCategoryImplementation(
+ SourceLocation AtCatImplLoc,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassLoc,
+ IdentifierInfo *CatName,
+ SourceLocation CatLoc);
+
+ virtual DeclTy *ActOnForwardClassDeclaration(SourceLocation Loc,
+ IdentifierInfo **IdentList,
+ unsigned NumElts);
+
+ virtual DeclTy *ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
+ IdentifierInfo **IdentList,
+ unsigned NumElts);
+
+ virtual void FindProtocolDeclaration(SourceLocation TypeLoc,
+ IdentifierInfo **ProtocolId,
+ unsigned NumProtocols,
+ llvm::SmallVector<DeclTy *, 8> &
+ Protocols);
+
+ virtual void ActOnAtEnd(SourceLocation AtEndLoc, DeclTy *classDecl,
+ DeclTy **allMethods = 0, unsigned allNum = 0,
+ DeclTy **allProperties = 0, unsigned pNum = 0);
+
+ virtual DeclTy *ActOnAddObjCProperties(SourceLocation AtLoc,
+ DeclTy **allProperties,
+ unsigned NumProperties,
+ ObjCDeclSpec &DS);
+
+ virtual DeclTy *ActOnMethodDeclaration(
+ SourceLocation BeginLoc, // location of the + or -.
+ SourceLocation EndLoc, // location of the ; or {.
+ tok::TokenKind MethodType,
+ DeclTy *ClassDecl, ObjCDeclSpec &ReturnQT, TypeTy *ReturnType,
+ Selector Sel,
+ // optional arguments. The number of types/arguments is obtained
+ // from the Sel.getNumArgs().
+ ObjCDeclSpec *ArgQT, TypeTy **ArgTypes, IdentifierInfo **ArgNames,
+ AttributeList *AttrList, tok::ObjCKeywordKind MethodImplKind,
+ bool isVariadic = false);
+
+ // 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 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 rbrac,
+ ExprTy **ArgExprs, unsigned NumArgs);
+private:
+ /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit
+ /// cast. If there is already an implicit cast, merge into the existing one.
+ void ImpCastExprToType(Expr *&Expr, QualType Type);
+
+ // 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);
+
+ // 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);
+
+ /// 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,
+
+ /// CompatiblePointerDiscardsQualifiers - The assignment discards
+ /// c/v/r qualifiers, which we accept as an extension.
+ CompatiblePointerDiscardsQualifiers,
+
+ /// 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 ActOnCallExpr,
+ // CheckAssignmentOperands, and ActOnReturnStmt. Prior to type checking,
+ // this routine performs the default function/array converions.
+ AssignConvertType CheckSingleAssignmentConstraints(QualType lhs,
+ Expr *&rExpr);
+ // CheckCompoundAssignmentConstraints - Type check without performing any
+ // conversions. For compound assignments, the "Check...Operands" methods
+ // perform the necessary conversions.
+ AssignConvertType CheckCompoundAssignmentConstraints(QualType lhs,
+ QualType rhs);
+
+ // Helper function for CheckAssignmentConstraints (C99 6.5.16.1p1)
+ AssignConvertType CheckPointerTypesForAssignment(QualType lhsType,
+ QualType rhsType);
+
+ /// 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 ActOnBinOp).
+ inline QualType InvalidOperands(SourceLocation l, Expr *&lex, Expr *&rex);
+ inline QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex);
+ inline QualType CheckMultiplyDivideOperands( // C99 6.5.5
+ Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
+ inline QualType CheckRemainderOperands( // C99 6.5.5
+ Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
+ inline QualType CheckAdditionOperands( // C99 6.5.6
+ Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
+ inline QualType CheckSubtractionOperands( // C99 6.5.6
+ Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
+ inline QualType CheckShiftOperands( // C99 6.5.7
+ Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
+ inline QualType CheckCompareOperands( // C99 6.5.8/9
+ Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isRelational);
+ inline QualType CheckBitwiseOperands( // C99 6.5.[10...12]
+ Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
+ inline 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.
+ inline QualType CheckAssignmentOperands( // C99 6.5.16.[1,2]
+ Expr *lex, Expr *&rex, SourceLocation OpLoc, QualType convertedType);
+ inline QualType CheckCommaOperands( // C99 6.5.17
+ Expr *&lex, Expr *&rex, SourceLocation OpLoc);
+ inline QualType CheckConditionalOperands( // C99 6.5.15
+ Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc);
+
+ /// 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);
+ QualType CheckAddressOfOperand(Expr *op, SourceLocation OpLoc);
+ QualType CheckIndirectionOperand(Expr *op, SourceLocation OpLoc);
+ QualType CheckSizeOfAlignOfOperand(QualType type, SourceLocation loc,
+ bool isSizeof);
+ QualType CheckRealImagOperand(Expr *&Op, SourceLocation OpLoc);
+
+ /// type checking primary expressions.
+ QualType CheckOCUVectorComponent(QualType baseType, SourceLocation OpLoc,
+ IdentifierInfo &Comp, SourceLocation CmpLoc);
+
+ /// type checking declaration initializers (C99 6.7.8)
+ bool CheckInitializerTypes(Expr *&simpleInit_or_initList, QualType &declType);
+ bool CheckSingleInitializer(Expr *&simpleInit, QualType declType);
+ bool CheckInitExpr(Expr *expr, InitListExpr *IList, unsigned slot,
+ QualType ElementType);
+ bool CheckInitializerListTypes(InitListExpr*& IList, QualType &DeclType,
+ bool topLevel, unsigned& startIndex);
+ bool CheckForConstantInitializer(Expr *e, QualType t);
+
+ StringLiteral *IsStringLiteralInit(Expr *Init, QualType DeclType);
+ bool CheckStringLiteralInit(StringLiteral *strLiteral, QualType &DeclT);
+
+ // 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);
+
+ // returns true if there were any incompatible arguments.
+ bool CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
+ ObjCMethodDecl *Method);
+
+ /// 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);
+
+ void InitBuiltinVaListType();
+
+ //===--------------------------------------------------------------------===//
+ // Extra semantic analysis beyond the C type system
+private:
+ bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall);
+ bool CheckBuiltinCFStringArgument(Expr* Arg);
+ bool SemaBuiltinVAStart(CallExpr *TheCall);
+ bool SemaBuiltinUnorderedCompare(CallExpr *TheCall);
+ void CheckPrintfArguments(CallExpr *TheCall,
+ bool HasVAListArg, unsigned format_idx);
+ void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
+ SourceLocation ReturnLoc);
+ void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex);
+};
+
+
+} // end namespace clang
+
+#endif
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
new file mode 100644
index 00000000000..6d3eea5e730
--- /dev/null
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -0,0 +1,802 @@
+//===--- 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/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/LiteralSupport.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "SemaUtil.h"
+using namespace clang;
+
+/// CheckFunctionCall - Check a direct function call for various correctness
+/// and safety properties not strictly enforced by the C type system.
+bool
+Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
+
+ // Get the IdentifierInfo* for the called function.
+ IdentifierInfo *FnInfo = FDecl->getIdentifier();
+
+ switch (FnInfo->getBuiltinID()) {
+ case Builtin::BI__builtin___CFStringMakeConstantString:
+ assert(TheCall->getNumArgs() == 1 &&
+ "Wrong # arguments to builtin CFStringMakeConstantString");
+ return CheckBuiltinCFStringArgument(TheCall->getArg(0));
+ case Builtin::BI__builtin_va_start:
+ return SemaBuiltinVAStart(TheCall);
+
+ 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:
+ return SemaBuiltinUnorderedCompare(TheCall);
+ }
+
+ // Search the KnownFunctionIDs for the identifier.
+ unsigned i = 0, e = id_num_known_functions;
+ for (; i != e; ++i) { if (KnownFunctionIDs[i] == FnInfo) break; }
+ if (i == e) return false;
+
+ // Printf checking.
+ if (i <= id_vprintf) {
+ // Retrieve the index of the format string parameter and determine
+ // if the function is passed a va_arg argument.
+ unsigned format_idx = 0;
+ bool HasVAListArg = false;
+
+ switch (i) {
+ default: assert(false && "No format string argument index.");
+ case id_printf: format_idx = 0; break;
+ case id_fprintf: format_idx = 1; break;
+ case id_sprintf: format_idx = 1; break;
+ case id_snprintf: format_idx = 2; break;
+ case id_asprintf: format_idx = 1; break;
+ case id_vsnprintf: format_idx = 2; HasVAListArg = true; break;
+ case id_vasprintf: format_idx = 1; HasVAListArg = true; break;
+ case id_vfprintf: format_idx = 1; HasVAListArg = true; break;
+ case id_vsprintf: format_idx = 1; HasVAListArg = true; break;
+ case id_vprintf: format_idx = 0; HasVAListArg = true; break;
+ }
+
+ CheckPrintfArguments(TheCall, HasVAListArg, format_idx);
+ }
+
+ return false;
+}
+
+/// CheckBuiltinCFStringArgument - Checks that the argument to the builtin
+/// CFString constructor is correct
+bool Sema::CheckBuiltinCFStringArgument(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 (!isascii(Data[i])) {
+ Diag(PP.AdvanceToTokenCharacter(Arg->getLocStart(), i + 1),
+ diag::warn_cfstring_literal_contains_non_ascii_character,
+ Arg->getSourceRange());
+ break;
+ }
+
+ if (!Data[i]) {
+ Diag(PP.AdvanceToTokenCharacter(Arg->getLocStart(), i + 1),
+ 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, Fn->getSourceRange(),
+ SourceRange(TheCall->getArg(2)->getLocStart(),
+ (*(TheCall->arg_end()-1))->getLocEnd()));
+ return true;
+ }
+
+ // Determine whether the current function is variadic or not.
+ bool isVariadic;
+ if (CurFunctionDecl)
+ isVariadic =
+ cast<FunctionTypeProto>(CurFunctionDecl->getType())->isVariadic();
+ else
+ isVariadic = CurMethodDecl->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 (CurFunctionDecl)
+ LastArg = *(CurFunctionDecl->param_end()-1);
+ else
+ LastArg = *(CurMethodDecl->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);
+ if (TheCall->getNumArgs() > 2)
+ return Diag(TheCall->getArg(2)->getLocStart(),
+ diag::err_typecheck_call_too_many_args,
+ 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);
+
+ // 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().getAsString(),
+ OrigArg1->getType().getAsString(),
+ SourceRange(OrigArg0->getLocStart(), OrigArg1->getLocEnd()));
+
+ return false;
+}
+
+
+/// 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(CallExpr *TheCall, bool HasVAListArg,
+ unsigned format_idx) {
+ 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;
+ }
+
+ 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.
+ StringLiteral *FExpr = dyn_cast<StringLiteral>(OrigFormatExpr);
+ if (FExpr == NULL) {
+ // 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 (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(OrigFormatExpr))
+ if (isa<ParmVarDecl>(DR->getDecl()))
+ return;
+
+ Diag(TheCall->getArg(format_idx)->getLocStart(),
+ diag::warn_printf_not_string_constant, Fn->getSourceRange());
+ return;
+ }
+
+ // CHECK: is the format string a wide literal?
+ if (FExpr->isWide()) {
+ Diag(FExpr->getLocStart(),
+ diag::warn_printf_format_string_is_wide_literal, Fn->getSourceRange());
+ return;
+ }
+
+ // Str - The format string. NOTE: this is NOT null-terminated!
+ const char * const Str = FExpr->getStrData();
+
+ // CHECK: empty format string?
+ const unsigned StrLen = FExpr->getByteLength();
+
+ if (StrLen == 0) {
+ Diag(FExpr->getLocStart(), diag::warn_printf_empty_format_string,
+ Fn->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()-(format_idx+1);
+
+ // 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(PP.AdvanceToTokenCharacter(FExpr->getLocStart(), StrIdx+1),
+ diag::warn_printf_format_string_contains_null_char,
+ Fn->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 && numConversions > numDataArgs) {
+ SourceLocation Loc = FExpr->getLocStart();
+ Loc = PP.AdvanceToTokenCharacter(Loc, StrIdx+1);
+
+ if (Str[StrIdx-1] == '.')
+ Diag(Loc, diag::warn_printf_asterisk_precision_missing_arg,
+ Fn->getSourceRange());
+ else
+ Diag(Loc, diag::warn_printf_asterisk_width_missing_arg,
+ Fn->getSourceRange());
+
+ // Don't do any more checking. We'll just emit spurious errors.
+ return;
+ }
+
+ // Perform type checking on width/precision specifier.
+ Expr *E = TheCall->getArg(format_idx+numConversions);
+ if (const BuiltinType *BT = E->getType()->getAsBuiltinType())
+ if (BT->getKind() == BuiltinType::Int)
+ break;
+
+ SourceLocation Loc =
+ PP.AdvanceToTokenCharacter(FExpr->getLocStart(), StrIdx+1);
+
+ if (Str[StrIdx-1] == '.')
+ Diag(Loc, diag::warn_printf_asterisk_precision_wrong_type,
+ E->getType().getAsString(), E->getSourceRange());
+ else
+ Diag(Loc, diag::warn_printf_asterisk_width_wrong_type,
+ E->getType().getAsString(), 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;
+
+ // CHECK: Are we using "%n"? Issue a warning.
+ case 'n': {
+ ++numConversions;
+ CurrentState = state_OrdChr;
+ SourceLocation Loc = PP.AdvanceToTokenCharacter(FExpr->getLocStart(),
+ LastConversionIdx+1);
+
+ Diag(Loc, diag::warn_printf_write_back, Fn->getSourceRange());
+ 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 = PP.AdvanceToTokenCharacter(FExpr->getLocStart(),
+ LastConversionIdx+1);
+
+ Diag(Loc, diag::warn_printf_invalid_conversion,
+ std::string(Str+LastConversionIdx, Str+StrIdx),
+ Fn->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 = PP.AdvanceToTokenCharacter(FExpr->getLocStart(),
+ LastConversionIdx+1);
+
+ Diag(Loc, diag::warn_printf_invalid_conversion,
+ std::string(Str+LastConversionIdx,
+ Str+std::min(LastConversionIdx+2, StrLen)),
+ Fn->getSourceRange());
+ return;
+ }
+
+ if (!HasVAListArg) {
+ // CHECK: Does the number of format conversions exceed the number
+ // of data arguments?
+ if (numConversions > numDataArgs) {
+ SourceLocation Loc = PP.AdvanceToTokenCharacter(FExpr->getLocStart(),
+ LastConversionIdx);
+
+ Diag(Loc, diag::warn_printf_insufficient_data_args,
+ Fn->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, Fn->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()) {
+ if (DeclRefExpr *DR = EvalAddr(RetValExp))
+ Diag(DR->getLocStart(), diag::warn_ret_stack_addr,
+ DR->getDecl()->getIdentifier()->getName(),
+ RetValExp->getSourceRange());
+ }
+ // Perform checking for stack values returned by reference.
+ else if (lhsType->isReferenceType()) {
+ // Check for an implicit cast to a reference.
+ if (ImplicitCastExpr *I = dyn_cast<ImplicitCastExpr>(RetValExp))
+ if (DeclRefExpr *DR = EvalVal(I->getSubExpr()))
+ Diag(DR->getLocStart(), diag::warn_ret_stack_ref,
+ DR->getDecl()->getIdentifier()->getName(),
+ 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()->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 implicit casts, we need to handle conversions from arrays to
+ // pointer values, and implicit pointer-to-pointer conversions.
+ case Stmt::ImplicitCastExprClass: {
+ ImplicitCastExpr *IE = cast<ImplicitCastExpr>(E);
+ Expr* SubExpr = IE->getSubExpr();
+
+ if (SubExpr->getType()->isPointerType() ||
+ SubExpr->getType()->isObjCQualifiedIdType())
+ return EvalAddr(SubExpr);
+ else
+ return EvalVal(SubExpr);
+ }
+
+ // For casts, we handle pointer-to-pointer conversions (which
+ // is essentially a no-op from our mini-interpreter's standpoint).
+ // For other casts we abort.
+ case Stmt::CastExprClass: {
+ CastExpr *C = cast<CastExpr>(E);
+ Expr *SubExpr = C->getSubExpr();
+
+ if (SubExpr->getType()->isPointerType())
+ return EvalAddr(SubExpr);
+ else
+ return NULL;
+ }
+
+ // 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
+ case Stmt::CXXCastExprClass: {
+ CXXCastExpr *C = cast<CXXCastExpr>(E);
+
+ if (C->getOpcode() == CXXCastExpr::ReinterpretCast) {
+ Expr *S = C->getSubExpr();
+ if (S->getType()->isPointerType())
+ return EvalAddr(S);
+ else
+ return NULL;
+ }
+ else
+ return EvalAddr(C->getSubExpr());
+ }
+
+ // 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: {
+ // 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()) 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 (isCallBuiltin(CL))
+ EmitWarning = false;
+
+ if (EmitWarning)
+ if (CallExpr* CR = dyn_cast<CallExpr>(RightExprSansParen))
+ if (isCallBuiltin(CR))
+ EmitWarning = false;
+
+ // Emit the diagnostic.
+ if (EmitWarning)
+ Diag(loc, diag::warn_floatingpoint_eq,
+ lex->getSourceRange(),rex->getSourceRange());
+}
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
new file mode 100644
index 00000000000..7914e865741
--- /dev/null
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -0,0 +1,2297 @@
+//===--- 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 "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/Builtins.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Scope.h"
+#include "clang/Basic/LangOptions.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/SmallString.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/DenseSet.h"
+using namespace clang;
+
+Sema::DeclTy *Sema::isTypeName(const IdentifierInfo &II, Scope *S) const {
+ Decl *IIDecl = II.getFETokenInfo<Decl>();
+ // Find first occurance of none-tagged declaration
+ while(IIDecl && IIDecl->getIdentifierNamespace() != Decl::IDNS_Ordinary)
+ IIDecl = cast<ScopedDecl>(IIDecl)->getNext();
+ if (!IIDecl)
+ return 0;
+ if (isa<TypedefDecl>(IIDecl) || isa<ObjCInterfaceDecl>(IIDecl))
+ return IIDecl;
+ if (ObjCCompatibleAliasDecl *ADecl =
+ dyn_cast<ObjCCompatibleAliasDecl>(IIDecl))
+ return ADecl->getClassInterface();
+ return 0;
+}
+
+void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
+ if (S->decl_empty()) return;
+ assert((S->getFlags() & Scope::DeclScope) &&"Scope shouldn't contain decls!");
+
+ for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end();
+ I != E; ++I) {
+ Decl *TmpD = static_cast<Decl*>(*I);
+ assert(TmpD && "This decl didn't get pushed??");
+ ScopedDecl *D = dyn_cast<ScopedDecl>(TmpD);
+ assert(D && "This decl isn't a ScopedDecl?");
+
+ IdentifierInfo *II = D->getIdentifier();
+ if (!II) continue;
+
+ // Unlink this decl from the identifier. Because the scope contains decls
+ // in an unordered collection, and because we have multiple identifier
+ // namespaces (e.g. tag, normal, label),the decl may not be the first entry.
+ if (II->getFETokenInfo<Decl>() == D) {
+ // Normal case, no multiple decls in different namespaces.
+ II->setFETokenInfo(D->getNext());
+ } else {
+ // Scan ahead. There are only three namespaces in C, so this loop can
+ // never execute more than 3 times.
+ ScopedDecl *SomeDecl = II->getFETokenInfo<ScopedDecl>();
+ while (SomeDecl->getNext() != D) {
+ SomeDecl = SomeDecl->getNext();
+ assert(SomeDecl && "Didn't find this decl on its identifier's chain!");
+ }
+ SomeDecl->setNext(D->getNext());
+ }
+
+ // This will have to be revisited for C++: there we want to nest stuff in
+ // namespace decls etc. Even for C, we might want a top-level translation
+ // unit decl or something.
+ if (!CurFunctionDecl)
+ continue;
+
+ // Chain this decl to the containing function, it now owns the memory for
+ // the decl.
+ D->setNext(CurFunctionDecl->getDeclChain());
+ CurFunctionDecl->setDeclChain(D);
+ }
+}
+
+/// LookupInterfaceDecl - Lookup interface declaration in the scope chain.
+/// Return the first declaration found (which may or may not be a class
+/// declaration. Caller is responsible for handling the none-class case.
+/// Bypassing the alias of a class by returning the aliased class.
+ScopedDecl *Sema::LookupInterfaceDecl(IdentifierInfo *ClassName) {
+ ScopedDecl *IDecl;
+ // Scan up the scope chain looking for a decl that matches this identifier
+ // that is in the appropriate namespace.
+ for (IDecl = ClassName->getFETokenInfo<ScopedDecl>(); IDecl;
+ IDecl = IDecl->getNext())
+ if (IDecl->getIdentifierNamespace() == Decl::IDNS_Ordinary)
+ break;
+
+ if (ObjCCompatibleAliasDecl *ADecl =
+ dyn_cast_or_null<ObjCCompatibleAliasDecl>(IDecl))
+ return ADecl->getClassInterface();
+ return IDecl;
+}
+
+/// getObjCInterfaceDecl - Look up a for a class declaration in the scope.
+/// return 0 if one not found.
+ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) {
+ ScopedDecl *IdDecl = LookupInterfaceDecl(Id);
+ return cast_or_null<ObjCInterfaceDecl>(IdDecl);
+}
+
+/// LookupScopedDecl - Look up the inner-most declaration in the specified
+/// namespace.
+ScopedDecl *Sema::LookupScopedDecl(IdentifierInfo *II, unsigned NSI,
+ SourceLocation IdLoc, Scope *S) {
+ if (II == 0) return 0;
+ Decl::IdentifierNamespace NS = (Decl::IdentifierNamespace)NSI;
+
+ // 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.
+ for (ScopedDecl *D = II->getFETokenInfo<ScopedDecl>(); D; D = D->getNext())
+ if (D->getIdentifierNamespace() == NS)
+ return D;
+
+ // 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 (NS == Decl::IDNS_Ordinary) {
+ // If this is a builtin on this (or all) targets, create the decl.
+ if (unsigned BuiltinID = II->getBuiltinID())
+ return LazilyCreateBuiltin(II, BuiltinID, S);
+ }
+ return 0;
+}
+
+void Sema::InitBuiltinVaListType()
+{
+ if (!Context.getBuiltinVaListType().isNull())
+ return;
+
+ IdentifierInfo *VaIdent = &Context.Idents.get("__builtin_va_list");
+ ScopedDecl *VaDecl = LookupScopedDecl(VaIdent, Decl::IDNS_Ordinary,
+ SourceLocation(), TUScope);
+ 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.
+ScopedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
+ Scope *S) {
+ Builtin::ID BID = (Builtin::ID)bid;
+
+ if (BID == Builtin::BI__builtin_va_start ||
+ BID == Builtin::BI__builtin_va_copy ||
+ BID == Builtin::BI__builtin_va_end)
+ InitBuiltinVaListType();
+
+ QualType R = Context.BuiltinInfo.GetBuiltinType(BID, Context);
+ FunctionDecl *New = FunctionDecl::Create(Context, SourceLocation(), II, R,
+ FunctionDecl::Extern, false, 0);
+
+ // Find translation-unit scope to insert this function into.
+ if (Scope *FnS = S->getFnParent())
+ S = FnS->getParent(); // Skip all scopes in a function at once.
+ while (S->getParent())
+ S = S->getParent();
+ S->AddDecl(New);
+
+ // Add this decl to the end of the identifier info.
+ if (ScopedDecl *LastDecl = II->getFETokenInfo<ScopedDecl>()) {
+ // Scan until we find the last (outermost) decl in the id chain.
+ while (LastDecl->getNext())
+ LastDecl = LastDecl->getNext();
+ // Insert before (outside) it.
+ LastDecl->setNext(New);
+ } else {
+ II->setFETokenInfo(New);
+ }
+ return New;
+}
+
+/// 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.
+///
+TypedefDecl *Sema::MergeTypeDefDecl(TypedefDecl *New, ScopedDecl *OldD) {
+ // Verify the old decl was also a typedef.
+ TypedefDecl *Old = dyn_cast<TypedefDecl>(OldD);
+ if (!Old) {
+ Diag(New->getLocation(), diag::err_redefinition_different_kind,
+ New->getName());
+ Diag(OldD->getLocation(), diag::err_previous_definition);
+ return New;
+ }
+
+ // Allow multiple definitions for ObjC built-in typedefs.
+ // FIXME: Verify the underlying types are equivalent!
+ if (getLangOptions().ObjC1 && isBuiltinObjCType(New))
+ return Old;
+
+ // Redeclaration of a type is a constraint violation (6.7.2.3p1).
+ // Apparently GCC, Intel, and Sun all silently ignore the redeclaration if
+ // *either* declaration is in a system header. The code below implements
+ // this adhoc compatibility rule. FIXME: The following code will not
+ // work properly when compiling ".i" files (containing preprocessed output).
+ SourceManager &SrcMgr = Context.getSourceManager();
+ const FileEntry *OldDeclFile = SrcMgr.getFileEntryForLoc(Old->getLocation());
+ const FileEntry *NewDeclFile = SrcMgr.getFileEntryForLoc(New->getLocation());
+ HeaderSearch &HdrInfo = PP.getHeaderSearchInfo();
+ DirectoryLookup::DirType OldDirType = HdrInfo.getFileDirFlavor(OldDeclFile);
+ DirectoryLookup::DirType NewDirType = HdrInfo.getFileDirFlavor(NewDeclFile);
+
+ if ((OldDirType == DirectoryLookup::ExternCSystemHeaderDir ||
+ NewDirType == DirectoryLookup::ExternCSystemHeaderDir) ||
+ getLangOptions().Microsoft)
+ return New;
+
+ // TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope.
+ // TODO: This is totally simplistic. It should handle merging functions
+ // together etc, merging extern int X; int X; ...
+ Diag(New->getLocation(), diag::err_redefinition, New->getName());
+ Diag(Old->getLocation(), diag::err_previous_definition);
+ return New;
+}
+
+/// 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) {
+ Attr *attr = const_cast<Attr*>(Old->getAttrs()), *tmp;
+
+// FIXME: fix this code to cleanup the Old attrs correctly
+ while (attr) {
+ tmp = attr;
+ attr = attr->getNext();
+
+ if (!DeclHasAttr(New, tmp)) {
+ New->addAttr(tmp);
+ } else {
+ tmp->setNext(0);
+ delete(tmp);
+ }
+ }
+}
+
+/// MergeFunctionDecl - We just parsed a function '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.
+///
+FunctionDecl *Sema::MergeFunctionDecl(FunctionDecl *New, ScopedDecl *OldD) {
+ // 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->getName());
+ Diag(OldD->getLocation(), diag::err_previous_definition);
+ return New;
+ }
+
+ MergeAttributes(New, Old);
+
+
+ QualType OldQType = Old->getCanonicalType();
+ QualType NewQType = New->getCanonicalType();
+
+ // Function types need to be compatible, not identical. This handles
+ // duplicate function decls like "void f(int); void f(enum X);" properly.
+ if (Context.functionTypesAreCompatible(OldQType, NewQType))
+ return New;
+
+ // A function that has already been declared has been redeclared or defined
+ // with a different type- show appropriate diagnostic
+ diag::kind PrevDiag = Old->getBody() ? diag::err_previous_definition :
+ diag::err_previous_declaration;
+
+ // TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope.
+ // TODO: This is totally simplistic. It should handle merging functions
+ // together etc, merging extern int X; int X; ...
+ Diag(New->getLocation(), diag::err_conflicting_types, New->getName());
+ Diag(Old->getLocation(), PrevDiag);
+ return New;
+}
+
+/// equivalentArrayTypes - Used to determine whether two array types are
+/// equivalent.
+/// We need to check this explicitly as an incomplete array definition is
+/// considered a VariableArrayType, so will not match a complete array
+/// definition that would be otherwise equivalent.
+static bool areEquivalentArrayTypes(QualType NewQType, QualType OldQType) {
+ const ArrayType *NewAT = NewQType->getAsArrayType();
+ const ArrayType *OldAT = OldQType->getAsArrayType();
+
+ if (!NewAT || !OldAT)
+ return false;
+
+ // If either (or both) array types in incomplete we need to strip off the
+ // outer VariableArrayType. Once the outer VAT is removed the remaining
+ // types must be identical if the array types are to be considered
+ // equivalent.
+ // eg. int[][1] and int[1][1] become
+ // VAT(null, CAT(1, int)) and CAT(1, CAT(1, int))
+ // removing the outermost VAT gives
+ // CAT(1, int) and CAT(1, int)
+ // which are equal, therefore the array types are equivalent.
+ if (NewAT->isIncompleteArrayType() || OldAT->isIncompleteArrayType()) {
+ if (NewAT->getIndexTypeQualifier() != OldAT->getIndexTypeQualifier())
+ return false;
+ NewQType = NewAT->getElementType().getCanonicalType();
+ OldQType = OldAT->getElementType().getCanonicalType();
+ }
+
+ return NewQType == OldQType;
+}
+
+/// 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.
+///
+/// FIXME: Need to carefully consider tentative definition rules (C99 6.9.2p2).
+/// For example, we incorrectly complain about i1, i4 from C99 6.9.2p4.
+///
+VarDecl *Sema::MergeVarDecl(VarDecl *New, ScopedDecl *OldD) {
+ // 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->getName());
+ Diag(OldD->getLocation(), diag::err_previous_definition);
+ return New;
+ }
+
+ MergeAttributes(New, Old);
+
+ // Verify the types match.
+ if (Old->getCanonicalType() != New->getCanonicalType() &&
+ !areEquivalentArrayTypes(New->getCanonicalType(), Old->getCanonicalType())) {
+ Diag(New->getLocation(), diag::err_redefinition, New->getName());
+ Diag(Old->getLocation(), diag::err_previous_definition);
+ return New;
+ }
+ // 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->getStorageClass() == VarDecl::Extern)) {
+ Diag(New->getLocation(), diag::err_static_non_static, New->getName());
+ Diag(Old->getLocation(), diag::err_previous_definition);
+ return New;
+ }
+ // C99 6.2.2p4: Check if we have a non-static decl followed by a static.
+ if (New->getStorageClass() != VarDecl::Static &&
+ Old->getStorageClass() == VarDecl::Static) {
+ Diag(New->getLocation(), diag::err_non_static_static, New->getName());
+ Diag(Old->getLocation(), diag::err_previous_definition);
+ return New;
+ }
+ // We've verified the types match, now handle "tentative" definitions.
+ FileVarDecl *OldFSDecl = dyn_cast<FileVarDecl>(Old);
+ FileVarDecl *NewFSDecl = dyn_cast<FileVarDecl>(New);
+
+ if (OldFSDecl && NewFSDecl) {
+ // Handle C "tentative" external object definitions (C99 6.9.2).
+ bool OldIsTentative = false;
+ bool NewIsTentative = false;
+
+ if (!OldFSDecl->getInit() &&
+ (OldFSDecl->getStorageClass() == VarDecl::None ||
+ OldFSDecl->getStorageClass() == VarDecl::Static))
+ OldIsTentative = true;
+
+ // FIXME: this check doesn't work (since the initializer hasn't been
+ // attached yet). This check should be moved to FinalizeDeclaratorGroup.
+ // Unfortunately, by the time we get to FinializeDeclaratorGroup, we've
+ // thrown out the old decl.
+ if (!NewFSDecl->getInit() &&
+ (NewFSDecl->getStorageClass() == VarDecl::None ||
+ NewFSDecl->getStorageClass() == VarDecl::Static))
+ ; // change to NewIsTentative = true; once the code is moved.
+
+ if (NewIsTentative || OldIsTentative)
+ return New;
+ }
+ if (Old->getStorageClass() != VarDecl::Extern &&
+ New->getStorageClass() != VarDecl::Extern) {
+ Diag(New->getLocation(), diag::err_redefinition, New->getName());
+ Diag(Old->getLocation(), diag::err_previous_definition);
+ }
+ return New;
+}
+
+/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
+/// no declarator (e.g. "struct foo;") is parsed.
+Sema::DeclTy *Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
+ // TODO: emit error on 'int;' or 'const enum foo;'.
+ // TODO: emit error on 'typedef int;'
+ // if (!DS.isMissingDeclaratorOk()) Diag(...);
+
+ return dyn_cast_or_null<TagDecl>(static_cast<Decl *>(DS.getTypeRep()));
+}
+
+bool Sema::CheckSingleInitializer(Expr *&Init, QualType DeclType) {
+ // Get the type before calling CheckSingleAssignmentConstraints(), since
+ // it can promote the expression.
+ QualType InitType = Init->getType();
+
+ AssignConvertType ConvTy = CheckSingleAssignmentConstraints(DeclType, Init);
+ return DiagnoseAssignmentResult(ConvTy, Init->getLocStart(), DeclType,
+ InitType, Init, "initializing");
+}
+
+bool Sema::CheckInitExpr(Expr *expr, InitListExpr *IList, unsigned slot,
+ QualType ElementType) {
+ Expr *savExpr = expr; // Might be promoted by CheckSingleInitializer.
+ if (CheckSingleInitializer(expr, ElementType))
+ return true; // types weren't compatible.
+
+ if (savExpr != expr) // The type was promoted, update initializer list.
+ IList->setInit(slot, expr);
+ return false;
+}
+
+bool Sema::CheckStringLiteralInit(StringLiteral *strLiteral, QualType &DeclT) {
+ if (const IncompleteArrayType *IAT = DeclT->getAsIncompleteArrayType()) {
+ // 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 = strLiteral->getByteLength() + 1;
+ // Return a new array type (C99 6.7.8p22).
+ DeclT = Context.getConstantArrayType(IAT->getElementType(), ConstVal,
+ ArrayType::Normal, 0);
+ } else if (const ConstantArrayType *CAT = DeclT->getAsConstantArrayType()) {
+ // C99 6.7.8p14. We have an array of character type with known size.
+ if (strLiteral->getByteLength() > (unsigned)CAT->getMaximumElements())
+ Diag(strLiteral->getSourceRange().getBegin(),
+ diag::warn_initializer_string_for_char_array_too_long,
+ strLiteral->getSourceRange());
+ } else {
+ assert(0 && "HandleStringLiteralInit(): Invalid array type");
+ }
+ // Set type from "char *" to "constant array of char".
+ strLiteral->setType(DeclT);
+ // For now, we always return false (meaning success).
+ return false;
+}
+
+StringLiteral *Sema::IsStringLiteralInit(Expr *Init, QualType DeclType) {
+ const ArrayType *AT = DeclType->getAsArrayType();
+ if (AT && AT->getElementType()->isCharType()) {
+ return dyn_cast<StringLiteral>(Init);
+ }
+ return 0;
+}
+
+// CheckInitializerListTypes - Checks the types of elements of an initializer
+// list. This function is recursive: it calls itself to initialize subelements
+// of aggregate types. Note that the topLevel parameter essentially refers to
+// whether this expression "owns" the initializer list passed in, or if this
+// initialization is taking elements out of a parent initializer. Each
+// call to this function adds zero or more to startIndex, reports any errors,
+// and returns true if it found any inconsistent types.
+bool Sema::CheckInitializerListTypes(InitListExpr*& IList, QualType &DeclType,
+ bool topLevel, unsigned& startIndex) {
+ bool hadError = false;
+
+ if (DeclType->isScalarType()) {
+ // The simplest case: initializing a single scalar
+ if (topLevel) {
+ Diag(IList->getLocStart(), diag::warn_braces_around_scalar_init,
+ IList->getSourceRange());
+ }
+ if (startIndex < IList->getNumInits()) {
+ Expr* expr = IList->getInit(startIndex);
+ if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
+ // FIXME: Should an error be reported here instead?
+ unsigned newIndex = 0;
+ CheckInitializerListTypes(SubInitList, DeclType, true, newIndex);
+ } else {
+ hadError |= CheckInitExpr(expr, IList, startIndex, DeclType);
+ }
+ ++startIndex;
+ }
+ // FIXME: Should an error be reported for empty initializer list + scalar?
+ } else if (DeclType->isVectorType()) {
+ if (startIndex < 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 (startIndex >= IList->getNumInits())
+ break;
+ Expr* expr = IList->getInit(startIndex);
+ if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
+ unsigned newIndex = 0;
+ hadError |= CheckInitializerListTypes(SubInitList, elementType,
+ true, newIndex);
+ ++startIndex;
+ } else {
+ hadError |= CheckInitializerListTypes(IList, elementType,
+ false, startIndex);
+ }
+ }
+ }
+ } else if (DeclType->isAggregateType() || DeclType->isUnionType()) {
+ if (DeclType->isStructureType() || DeclType->isUnionType()) {
+ if (startIndex < IList->getNumInits() && !topLevel &&
+ Context.typesAreCompatible(IList->getInit(startIndex)->getType(),
+ DeclType)) {
+ // We found a compatible struct; per the standard, this initializes the
+ // struct. (The C standard technically says that this only applies for
+ // initializers for declarations with automatic scope; however, this
+ // construct is unambiguous anyway because a struct cannot contain
+ // a type compatible with itself. We'll output an error when we check
+ // if the initializer is constant.)
+ // FIXME: Is a call to CheckSingleInitializer required here?
+ ++startIndex;
+ } else {
+ 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())
+ return true;
+
+ // If structDecl is a forward declaration, this loop won't do anything;
+ // That's okay, because an error should get printed out elsewhere. It
+ // might be worthwhile to skip over the rest of the initializer, though.
+ int numMembers = structDecl->getNumMembers() -
+ structDecl->hasFlexibleArrayMember();
+ for (int i = 0; i < numMembers; i++) {
+ // Don't attempt to go past the end of the init list
+ if (startIndex >= IList->getNumInits())
+ break;
+ FieldDecl * curField = structDecl->getMember(i);
+ if (!curField->getIdentifier()) {
+ // Don't initialize unnamed fields, e.g. "int : 20;"
+ continue;
+ }
+ QualType fieldType = curField->getType();
+ Expr* expr = IList->getInit(startIndex);
+ if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
+ unsigned newStart = 0;
+ hadError |= CheckInitializerListTypes(SubInitList, fieldType,
+ true, newStart);
+ ++startIndex;
+ } else {
+ hadError |= CheckInitializerListTypes(IList, fieldType,
+ false, startIndex);
+ }
+ if (DeclType->isUnionType())
+ break;
+ }
+ // FIXME: Implement flexible array initialization GCC extension (it's a
+ // really messy extension to implement, unfortunately...the necessary
+ // information isn't actually even here!)
+ }
+ } else if (DeclType->isArrayType()) {
+ // Check for the special-case of initializing an array with a string.
+ if (startIndex < IList->getNumInits()) {
+ if (StringLiteral *lit = IsStringLiteralInit(IList->getInit(startIndex),
+ DeclType)) {
+ CheckStringLiteralInit(lit, DeclType);
+ ++startIndex;
+ if (topLevel && startIndex < IList->getNumInits()) {
+ // We have leftover initializers; warn
+ Diag(IList->getInit(startIndex)->getLocStart(),
+ diag::err_excess_initializers_in_char_array_initializer,
+ IList->getInit(startIndex)->getSourceRange());
+ }
+ return false;
+ }
+ }
+ int maxElements;
+ if (DeclType->isIncompleteArrayType()) {
+ // FIXME: use a proper constant
+ maxElements = 0x7FFFFFFF;
+ } else if (const VariableArrayType *VAT =
+ DeclType->getAsVariableArrayType()) {
+ // 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).
+ Diag(VAT->getSizeExpr()->getLocStart(),
+ diag::err_variable_object_no_init,
+ VAT->getSizeExpr()->getSourceRange());
+ hadError = true;
+ maxElements = 0x7FFFFFFF;
+ } else {
+ const ConstantArrayType *CAT = DeclType->getAsConstantArrayType();
+ maxElements = static_cast<int>(CAT->getSize().getZExtValue());
+ }
+ QualType elementType = DeclType->getAsArrayType()->getElementType();
+ int numElements = 0;
+ for (int i = 0; i < maxElements; ++i, ++numElements) {
+ // Don't attempt to go past the end of the init list
+ if (startIndex >= IList->getNumInits())
+ break;
+ Expr* expr = IList->getInit(startIndex);
+ if (InitListExpr *SubInitList = dyn_cast<InitListExpr>(expr)) {
+ unsigned newIndex = 0;
+ hadError |= CheckInitializerListTypes(SubInitList, elementType,
+ true, newIndex);
+ ++startIndex;
+ } else {
+ hadError |= CheckInitializerListTypes(IList, elementType,
+ false, startIndex);
+ }
+ }
+ if (DeclType->isIncompleteArrayType()) {
+ // If this is an incomplete array type, the actual type needs to
+ // be calculated here
+ if (numElements == 0) {
+ // Sizing an array implicitly to zero is not allowed
+ // (It could in theory be allowed, but it doesn't really matter.)
+ Diag(IList->getLocStart(),
+ diag::err_at_least_one_initializer_needed_to_size_array);
+ hadError = true;
+ } else {
+ llvm::APSInt ConstVal(32);
+ ConstVal = numElements;
+ DeclType = Context.getConstantArrayType(elementType, ConstVal,
+ ArrayType::Normal, 0);
+ }
+ }
+ } else {
+ assert(0 && "Aggregate that isn't a function or array?!");
+ }
+ } 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");
+ }
+
+ // If this init list is a base list, we set the type; an initializer doesn't
+ // fundamentally have a type, but this makes the ASTs a bit easier to read
+ if (topLevel)
+ IList->setType(DeclType);
+
+ if (topLevel && startIndex < IList->getNumInits()) {
+ // We have leftover initializers; warn
+ Diag(IList->getInit(startIndex)->getLocStart(),
+ diag::warn_excess_initializers,
+ IList->getInit(startIndex)->getSourceRange());
+ }
+ return hadError;
+}
+
+bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType) {
+ // 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 = DeclType->getAsVariableArrayType())
+ return Diag(VAT->getSizeExpr()->getLocStart(),
+ diag::err_variable_object_no_init,
+ VAT->getSizeExpr()->getSourceRange());
+
+ InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
+ if (!InitList) {
+ // FIXME: Handle wide strings
+ if (StringLiteral *strLiteral = IsStringLiteralInit(Init, DeclType))
+ return CheckStringLiteralInit(strLiteral, DeclType);
+
+ if (DeclType->isArrayType())
+ return Diag(Init->getLocStart(),
+ diag::err_array_init_list_required,
+ Init->getSourceRange());
+
+ return CheckSingleInitializer(Init, DeclType);
+ }
+ unsigned newIndex = 0;
+ return CheckInitializerListTypes(InitList, DeclType, true, newIndex);
+}
+
+Sema::DeclTy *
+Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
+ ScopedDecl *LastDeclarator = dyn_cast_or_null<ScopedDecl>((Decl *)lastDecl);
+ IdentifierInfo *II = D.getIdentifier();
+
+ // All of these full declarators require an identifier. If it doesn't have
+ // one, the ParsedFreeStandingDeclSpec action should be used.
+ if (II == 0) {
+ Diag(D.getDeclSpec().getSourceRange().getBegin(),
+ diag::err_declarator_need_ident,
+ D.getDeclSpec().getSourceRange(), D.getSourceRange());
+ return 0;
+ }
+
+ // 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 = S->getParent();
+
+ // See if this is a redefinition of a variable in the same scope.
+ ScopedDecl *PrevDecl = LookupScopedDecl(II, Decl::IDNS_Ordinary,
+ D.getIdentifierLoc(), S);
+ ScopedDecl *New;
+ bool InvalidDecl = false;
+
+ QualType R = GetTypeForDeclarator(D, S);
+ assert(!R.isNull() && "GetTypeForDeclarator() returned null type");
+
+ if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
+ TypedefDecl *NewTD = ParseTypedefDecl(S, D, R, LastDeclarator);
+ if (!NewTD) return 0;
+
+ // Handle attributes prior to checking for duplicates in MergeVarDecl
+ HandleDeclAttributes(NewTD, D.getDeclSpec().getAttributes(),
+ D.getAttributes());
+ // 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 && S->isDeclScope(PrevDecl)) {
+ NewTD = MergeTypeDefDecl(NewTD, PrevDecl);
+ if (NewTD == 0) return 0;
+ }
+ New = NewTD;
+ if (S->getParent() == 0) {
+ // C99 6.7.7p2: If a typedef name specifies a variably modified type
+ // then it shall have block scope.
+ if (NewTD->getUnderlyingType()->isVariablyModifiedType()) {
+ // FIXME: Diagnostic needs to be fixed.
+ Diag(D.getIdentifierLoc(), diag::err_typecheck_illegal_vla);
+ InvalidDecl = true;
+ }
+ }
+ } else if (R.getTypePtr()->isFunctionType()) {
+ FunctionDecl::StorageClass SC = FunctionDecl::None;
+ switch (D.getDeclSpec().getStorageClassSpec()) {
+ default: assert(0 && "Unknown storage class!");
+ case DeclSpec::SCS_auto:
+ case DeclSpec::SCS_register:
+ Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_func,
+ R.getAsString());
+ InvalidDecl = true;
+ break;
+ case DeclSpec::SCS_unspecified: SC = FunctionDecl::None; break;
+ case DeclSpec::SCS_extern: SC = FunctionDecl::Extern; break;
+ case DeclSpec::SCS_static: SC = FunctionDecl::Static; break;
+ case DeclSpec::SCS_private_extern: SC = FunctionDecl::PrivateExtern;break;
+ }
+
+ bool isInline = D.getDeclSpec().isInlineSpecified();
+ FunctionDecl *NewFD = FunctionDecl::Create(Context, D.getIdentifierLoc(),
+ II, R, SC, isInline,
+ LastDeclarator);
+ // Handle attributes.
+ HandleDeclAttributes(NewFD, D.getDeclSpec().getAttributes(),
+ D.getAttributes());
+
+ // Merge the decl with the existing one if appropriate. Since C functions
+ // are in a flat namespace, make sure we consider decls in outer scopes.
+ if (PrevDecl) {
+ NewFD = MergeFunctionDecl(NewFD, PrevDecl);
+ if (NewFD == 0) return 0;
+ }
+ New = NewFD;
+ } else {
+ if (R.getTypePtr()->isObjCInterfaceType()) {
+ Diag(D.getIdentifierLoc(), diag::err_statically_allocated_object,
+ D.getIdentifier()->getName());
+ InvalidDecl = true;
+ }
+
+ 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;
+ }
+ if (S->getParent() == 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) {
+ Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_fscope,
+ R.getAsString());
+ InvalidDecl = true;
+ }
+ NewVD = FileVarDecl::Create(Context, D.getIdentifierLoc(), II, R, SC,
+ LastDeclarator);
+ } else {
+ NewVD = BlockVarDecl::Create(Context, D.getIdentifierLoc(), II, R, SC,
+ LastDeclarator);
+ }
+ // Handle attributes prior to checking for duplicates in MergeVarDecl
+ HandleDeclAttributes(NewVD, D.getDeclSpec().getAttributes(),
+ D.getAttributes());
+
+ // 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()) {
+ QualType AutoTy = NewVD->getCanonicalType();
+ if (const ArrayType *AT = AutoTy->getAsArrayType())
+ AutoTy = AT->getElementType().getCanonicalType();
+ if (AutoTy.getAddressSpace() != 0) {
+ Diag(D.getIdentifierLoc(), diag::err_as_qualified_auto_decl);
+ InvalidDecl = true;
+ }
+ }
+ // 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 && S->isDeclScope(PrevDecl)) {
+ NewVD = MergeVarDecl(NewVD, PrevDecl);
+ if (NewVD == 0) return 0;
+ }
+ New = NewVD;
+ }
+
+ // If this has an identifier, add it to the scope stack.
+ if (II) {
+ New->setNext(II->getFETokenInfo<ScopedDecl>());
+ II->setFETokenInfo(New);
+ S->AddDecl(New);
+ }
+ // If any semantic error occurred, mark the decl as invalid.
+ if (D.getInvalidType() || InvalidDecl)
+ New->setInvalidDecl();
+
+ return New;
+}
+
+bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
+ SourceLocation loc;
+ // FIXME: Remove the isReference check and handle assignment to a reference.
+ if (!DclT->isReferenceType() && !Init->isConstantExpr(Context, &loc)) {
+ assert(loc.isValid() && "isConstantExpr didn't return a loc!");
+ Diag(loc, diag::err_init_element_not_constant, Init->getSourceRange());
+ return true;
+ }
+ return false;
+}
+
+void Sema::AddInitializerToDecl(DeclTy *dcl, ExprTy *init) {
+ Decl *RealDecl = static_cast<Decl *>(dcl);
+ Expr *Init = static_cast<Expr *>(init);
+ assert(Init && "missing initializer");
+
+ // If there is no declaration, there was an error parsing it. Just ignore
+ // the initializer.
+ if (RealDecl == 0) {
+ delete Init;
+ return;
+ }
+
+ VarDecl *VDecl = dyn_cast<VarDecl>(RealDecl);
+ if (!VDecl) {
+ Diag(dyn_cast<ScopedDecl>(RealDecl)->getLocation(),
+ diag::err_illegal_initializer);
+ RealDecl->setInvalidDecl();
+ return;
+ }
+ // Get the decls type and save a reference for later, since
+ // CheckInitializerTypes may change it.
+ QualType DclT = VDecl->getType(), SavT = DclT;
+ if (BlockVarDecl *BVD = dyn_cast<BlockVarDecl>(VDecl)) {
+ VarDecl::StorageClass SC = BVD->getStorageClass();
+ if (SC == VarDecl::Extern) { // C99 6.7.8p5
+ Diag(VDecl->getLocation(), diag::err_block_extern_cant_init);
+ BVD->setInvalidDecl();
+ } else if (!BVD->isInvalidDecl()) {
+ if (CheckInitializerTypes(Init, DclT))
+ BVD->setInvalidDecl();
+ if (SC == VarDecl::Static) // C99 6.7.8p4.
+ CheckForConstantInitializer(Init, DclT);
+ }
+ } else if (FileVarDecl *FVD = dyn_cast<FileVarDecl>(VDecl)) {
+ if (FVD->getStorageClass() == VarDecl::Extern)
+ Diag(VDecl->getLocation(), diag::warn_extern_init);
+ if (!FVD->isInvalidDecl())
+ if (CheckInitializerTypes(Init, DclT))
+ FVD->setInvalidDecl();
+
+ // 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(Init);
+ return;
+}
+
+/// The declarators are chained together backwards, reverse the list.
+Sema::DeclTy *Sema::FinalizeDeclaratorGroup(Scope *S, DeclTy *group) {
+ // Often we have single declarators, handle them quickly.
+ Decl *GroupDecl = static_cast<Decl*>(group);
+ if (GroupDecl == 0)
+ return 0;
+
+ ScopedDecl *Group = dyn_cast<ScopedDecl>(GroupDecl);
+ ScopedDecl *NewGroup = 0;
+ if (Group->getNextDeclarator() == 0)
+ NewGroup = Group;
+ else { // reverse the list.
+ while (Group) {
+ ScopedDecl *Next = Group->getNextDeclarator();
+ Group->setNextDeclarator(NewGroup);
+ NewGroup = Group;
+ Group = Next;
+ }
+ }
+ // Perform semantic analysis that depends on having fully processed both
+ // the declarator and initializer.
+ for (ScopedDecl *ID = NewGroup; ID; ID = ID->getNextDeclarator()) {
+ VarDecl *IDecl = dyn_cast<VarDecl>(ID);
+ if (!IDecl)
+ continue;
+ FileVarDecl *FVD = dyn_cast<FileVarDecl>(IDecl);
+ BlockVarDecl *BVD = dyn_cast<BlockVarDecl>(IDecl);
+ QualType T = IDecl->getType();
+
+ // C99 6.7.5.2p2: If an identifier is declared to be an object with
+ // static storage duration, it shall not have a variable length array.
+ if ((FVD || BVD) && IDecl->getStorageClass() == VarDecl::Static) {
+ if (T->getAsVariableArrayType()) {
+ Diag(IDecl->getLocation(), diag::err_typecheck_illegal_vla);
+ IDecl->setInvalidDecl();
+ }
+ }
+ // 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 (BVD && IDecl->getStorageClass() != VarDecl::Extern) {
+ if (T->isIncompleteType()) {
+ Diag(IDecl->getLocation(), diag::err_typecheck_decl_incomplete_type,
+ T.getAsString());
+ 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 (FVD && !FVD->getInit() && (FVD->getStorageClass() == VarDecl::Static ||
+ FVD->getStorageClass() == VarDecl::None)) {
+ if (T->isIncompleteArrayType()) {
+ // C99 6.9.2 (p2, p5): Implicit initialization causes an incomplete
+ // array to be completed. Don't issue a diagnostic.
+ } else if (T->isIncompleteType()) {
+ // 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.
+ Diag(IDecl->getLocation(), diag::err_typecheck_decl_incomplete_type,
+ T.getAsString());
+ IDecl->setInvalidDecl();
+ }
+ }
+ }
+ return NewGroup;
+}
+
+// Called from Sema::ParseStartOfFunctionDef().
+ParmVarDecl *
+Sema::ActOnParamDeclarator(struct DeclaratorChunk::ParamInfo &PI,
+ Scope *FnScope) {
+ IdentifierInfo *II = PI.Ident;
+ // 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.
+ if (/*Decl *PrevDecl = */LookupScopedDecl(II, Decl::IDNS_Ordinary,
+ PI.IdentLoc, FnScope)) {
+
+ }
+
+ // FIXME: Handle storage class (auto, register). No declarator?
+ // TODO: Chain to previous parameter with the prevdeclarator chain?
+
+ // Perform the default function/array conversion (C99 6.7.5.3p[7,8]).
+ // Doing the promotion here has a win and a loss. The win is the type for
+ // both Decl's and DeclRefExpr's will match (a convenient invariant for the
+ // code generator). The loss is the orginal type isn't preserved. For example:
+ //
+ // void func(int parmvardecl[5]) { // convert "int [5]" to "int *"
+ // int blockvardecl[5];
+ // sizeof(parmvardecl); // size == 4
+ // sizeof(blockvardecl); // size == 20
+ // }
+ //
+ // For expressions, all implicit conversions are captured using the
+ // ImplicitCastExpr AST node (we have no such mechanism for Decl's).
+ //
+ // FIXME: If a source translation tool needs to see the original type, then
+ // we need to consider storing both types (in ParmVarDecl)...
+ //
+ QualType parmDeclType = QualType::getFromOpaquePtr(PI.TypeInfo);
+ if (const ArrayType *AT = parmDeclType->getAsArrayType()) {
+ // int x[restrict 4] -> int *restrict
+ parmDeclType = Context.getPointerType(AT->getElementType());
+ parmDeclType = parmDeclType.getQualifiedType(AT->getIndexTypeQualifier());
+ } else if (parmDeclType->isFunctionType())
+ parmDeclType = Context.getPointerType(parmDeclType);
+
+ ParmVarDecl *New = ParmVarDecl::Create(Context, PI.IdentLoc, II, parmDeclType,
+ VarDecl::None, 0);
+
+ if (PI.InvalidType)
+ New->setInvalidDecl();
+
+ // If this has an identifier, add it to the scope stack.
+ if (II) {
+ New->setNext(II->getFETokenInfo<ScopedDecl>());
+ II->setFETokenInfo(New);
+ FnScope->AddDecl(New);
+ }
+
+ HandleDeclAttributes(New, PI.AttrList, 0);
+ return New;
+}
+
+Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) {
+ assert(CurFunctionDecl == 0 && "Function parsing confused");
+ 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 (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
+ if (FTI.ArgInfo[i].TypeInfo == 0) {
+ Diag(FTI.ArgInfo[i].IdentLoc, diag::ext_param_not_declared,
+ FTI.ArgInfo[i].Ident->getName());
+ // Implicitly declare the argument as type 'int' for lack of a better
+ // type.
+ FTI.ArgInfo[i].TypeInfo = Context.IntTy.getAsOpaquePtr();
+ }
+ }
+
+ // Since this is a function definition, act as though we have information
+ // about the arguments.
+ if (FTI.NumArgs)
+ FTI.hasPrototype = true;
+ } else {
+ // FIXME: Diagnose arguments without names in C.
+
+ }
+
+ Scope *GlobalScope = FnBodyScope->getParent();
+
+ // See if this is a redefinition.
+ ScopedDecl *PrevDcl = LookupScopedDecl(D.getIdentifier(), Decl::IDNS_Ordinary,
+ D.getIdentifierLoc(), GlobalScope);
+ if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(PrevDcl)) {
+ if (FD->getBody()) {
+ Diag(D.getIdentifierLoc(), diag::err_redefinition,
+ D.getIdentifier()->getName());
+ Diag(FD->getLocation(), diag::err_previous_definition);
+ }
+ }
+ Decl *decl = static_cast<Decl*>(ActOnDeclarator(GlobalScope, D, 0));
+ FunctionDecl *FD = cast<FunctionDecl>(decl);
+ CurFunctionDecl = FD;
+
+ // Create Decl objects for each parameter, adding them to the FunctionDecl.
+ llvm::SmallVector<ParmVarDecl*, 16> Params;
+
+ // 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.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
+ !QualType::getFromOpaquePtr(FTI.ArgInfo[0].TypeInfo).getCVRQualifiers() &&
+ QualType::getFromOpaquePtr(FTI.ArgInfo[0].TypeInfo)->isVoidType()) {
+ // empty arg list, don't push any params.
+ } else {
+ for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
+ Params.push_back(ActOnParamDeclarator(D.getTypeObject(0).Fun.ArgInfo[i],
+ FnBodyScope));
+ }
+ }
+
+ FD->setParams(&Params[0], Params.size());
+
+ return FD;
+}
+
+Sema::DeclTy *Sema::ActOnFinishFunctionBody(DeclTy *D, StmtTy *Body) {
+ Decl *dcl = static_cast<Decl *>(D);
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(dcl)) {
+ FD->setBody((Stmt*)Body);
+ assert(FD == CurFunctionDecl && "Function parsing confused");
+ CurFunctionDecl = 0;
+ } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(dcl)) {
+ MD->setBody((Stmt*)Body);
+ CurMethodDecl = 0;
+ }
+ // Verify and clean out per-function state.
+
+ // Check goto/label use.
+ for (llvm::DenseMap<IdentifierInfo*, LabelStmt*>::iterator
+ I = LabelMap.begin(), E = LabelMap.end(); I != E; ++I) {
+ // 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 (I->second->getSubStmt() == 0) {
+ LabelStmt *L = I->second;
+ // 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) {
+ L->setSubStmt(new NullStmt(L->getIdentLoc()));
+ cast<CompoundStmt>((Stmt*)Body)->push_back(L);
+ } else {
+ // The whole function wasn't parsed correctly, just delete this.
+ delete L;
+ }
+ }
+ }
+ LabelMap.clear();
+
+ 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).
+ScopedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
+ IdentifierInfo &II, Scope *S) {
+ if (getLangOptions().C99) // Extension in C99.
+ Diag(Loc, diag::ext_implicit_function_decl, II.getName());
+ else // Legal in C90, but warn about it.
+ Diag(Loc, diag::warn_implicit_function_decl, II.getName());
+
+ // 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, 0, 0, Loc));
+ D.SetIdentifier(&II, Loc);
+
+ // Find translation-unit scope to insert this function into.
+ if (Scope *FnS = S->getFnParent())
+ S = FnS->getParent(); // Skip all scopes in a function at once.
+ while (S->getParent())
+ S = S->getParent();
+
+ return dyn_cast<ScopedDecl>(static_cast<Decl*>(ActOnDeclarator(S, D, 0)));
+}
+
+
+TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
+ ScopedDecl *LastDeclarator) {
+ 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, D.getIdentifierLoc(),
+ D.getIdentifier(),
+ T, LastDeclarator);
+ if (D.getInvalidType())
+ NewTD->setInvalidDecl();
+ return NewTD;
+}
+
+/// 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.
+/// TagType indicates what kind of tag this is. TK indicates whether this is a
+/// reference/declaration/definition of a tag.
+Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK,
+ SourceLocation KWLoc, IdentifierInfo *Name,
+ SourceLocation NameLoc, AttributeList *Attr) {
+ // If this is a use of an existing tag, it must have a name.
+ assert((Name != 0 || TK == TK_Definition) &&
+ "Nameless record must be a definition!");
+
+ Decl::Kind Kind;
+ switch (TagType) {
+ default: assert(0 && "Unknown tag type!");
+ case DeclSpec::TST_struct: Kind = Decl::Struct; break;
+ case DeclSpec::TST_union: Kind = Decl::Union; break;
+//case DeclSpec::TST_class: Kind = Decl::Class; break;
+ case DeclSpec::TST_enum: Kind = Decl::Enum; break;
+ }
+
+ // If this is a named struct, check to see if there was a previous forward
+ // declaration or definition.
+ if (TagDecl *PrevDecl =
+ dyn_cast_or_null<TagDecl>(LookupScopedDecl(Name, Decl::IDNS_Tag,
+ NameLoc, S))) {
+
+ // 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 || S->isDeclScope(PrevDecl)) {
+ // Make sure that this wasn't declared as an enum and now used as a struct
+ // or something similar.
+ if (PrevDecl->getKind() != Kind) {
+ Diag(KWLoc, diag::err_use_with_wrong_tag, Name->getName());
+ Diag(PrevDecl->getLocation(), diag::err_previous_use);
+ }
+
+ // If this is a use or a forward declaration, we're good.
+ if (TK != TK_Definition)
+ return PrevDecl;
+
+ // Diagnose attempts to redefine a tag.
+ if (PrevDecl->isDefinition()) {
+ Diag(NameLoc, diag::err_redefinition, Name->getName());
+ Diag(PrevDecl->getLocation(), diag::err_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;
+ } else {
+ // Okay, this is definition of a previously declared or referenced tag.
+ // Move the location of the decl to be the definition site.
+ PrevDecl->setLocation(NameLoc);
+ return PrevDecl;
+ }
+ }
+ // If we get here, this is a definition of a new struct type in a nested
+ // scope, e.g. "struct foo; void bar() { struct foo; }", just create a new
+ // type.
+ }
+
+ // 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, if this is the first time we've seen this tag, create the decl.
+ TagDecl *New;
+ switch (Kind) {
+ default: assert(0 && "Unknown tag kind!");
+ case Decl::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, Loc, Name, 0);
+ // If this is an undefined enum, warn.
+ if (TK != TK_Definition) Diag(Loc, diag::ext_forward_ref_enum);
+ break;
+ case Decl::Union:
+ case Decl::Struct:
+ case Decl::Class:
+ // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
+ // struct X { int A; } D; D should chain to X.
+ New = RecordDecl::Create(Context, Kind, Loc, Name, 0);
+ break;
+ }
+
+ // If this has an identifier, add it to the scope stack.
+ if (Name) {
+ // 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 = S->getParent();
+
+ // Add it to the decl chain.
+ New->setNext(Name->getFETokenInfo<ScopedDecl>());
+ Name->setFETokenInfo(New);
+ S->AddDecl(New);
+ }
+
+ HandleDeclAttributes(New, Attr, 0);
+ return New;
+}
+
+/// ActOnField - Each field of a struct/union/class is passed into this in order
+/// to create a FieldDecl object for it.
+Sema::DeclTy *Sema::ActOnField(Scope *S, DeclTy *TagDecl,
+ SourceLocation DeclStart,
+ Declarator &D, ExprTy *BitfieldWidth) {
+ 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!
+
+
+ if (BitWidth) {
+ // TODO: Validate.
+ //printf("WARNING: BITFIELDS IGNORED!\n");
+
+ // 6.7.2.1p3
+ // 6.7.2.1p4
+
+ } else {
+ // Not a bitfield.
+
+ // validate II.
+
+ }
+
+ QualType T = GetTypeForDeclarator(D, S);
+ assert(!T.isNull() && "GetTypeForDeclarator() returned null type");
+ bool InvalidDecl = false;
+
+ // 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()) {
+ // FIXME: This diagnostic needs work
+ Diag(Loc, diag::err_typecheck_illegal_vla, Loc);
+ InvalidDecl = true;
+ }
+ // FIXME: Chain fielddecls together.
+ FieldDecl *NewFD;
+
+ if (isa<RecordDecl>(static_cast<Decl *>(TagDecl)))
+ NewFD = new FieldDecl(Loc, II, T, BitWidth);
+ else if (isa<ObjCInterfaceDecl>(static_cast<Decl *>(TagDecl)) ||
+ isa<ObjCImplementationDecl>(static_cast<Decl *>(TagDecl)) ||
+ isa<ObjCCategoryDecl>(static_cast<Decl *>(TagDecl)) ||
+ // FIXME: ivars are currently used to model properties, and
+ // properties can appear within a protocol.
+ // See corresponding FIXME in DeclObjC.h:ObjCPropertyDecl.
+ isa<ObjCProtocolDecl>(static_cast<Decl *>(TagDecl)))
+ NewFD = new ObjCIvarDecl(Loc, II, T);
+ else
+ assert(0 && "Sema::ActOnField(): Unknown TagDecl");
+
+ HandleDeclAttributes(NewFD, D.getDeclSpec().getAttributes(),
+ D.getAttributes());
+
+ if (D.getInvalidType() || InvalidDecl)
+ NewFD->setInvalidDecl();
+ return NewFD;
+}
+
+/// TranslateIvarVisibility - Translate visibility from a token ID to an
+/// AST enum value.
+static ObjCIvarDecl::AccessControl
+TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) {
+ switch (ivarVisibility) {
+ 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;
+ default: assert(false && "Unknown visitibility kind");
+ }
+}
+
+void Sema::ActOnFields(Scope* S,
+ SourceLocation RecLoc, DeclTy *RecDecl,
+ DeclTy **Fields, unsigned NumFields,
+ SourceLocation LBrac, SourceLocation RBrac,
+ tok::ObjCKeywordKind *visibility) {
+ Decl *EnclosingDecl = static_cast<Decl*>(RecDecl);
+ assert(EnclosingDecl && "missing record or interface decl");
+ RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl);
+
+ if (Record && Record->isDefinition()) {
+ // Diagnose code like:
+ // struct S { struct S {} X; };
+ // We discover this when we complete the outer S. Reject and ignore the
+ // outer S.
+ Diag(Record->getLocation(), diag::err_nested_redefinition,
+ Record->getKindName());
+ Diag(RecLoc, diag::err_previous_definition);
+ Record->setInvalidDecl();
+ return;
+ }
+ // Verify that all the fields are okay.
+ unsigned NumNamedMembers = 0;
+ llvm::SmallVector<FieldDecl*, 32> RecFields;
+ llvm::SmallSet<const IdentifierInfo*, 32> FieldIDs;
+
+ for (unsigned i = 0; i != NumFields; ++i) {
+
+ FieldDecl *FD = cast_or_null<FieldDecl>(static_cast<Decl*>(Fields[i]));
+ assert(FD && "missing field decl");
+
+ // Remember all fields.
+ RecFields.push_back(FD);
+
+ // Get the type for the field.
+ Type *FDTy = FD->getType().getTypePtr();
+
+ // If we have visibility info, make sure the AST is set accordingly.
+ if (visibility)
+ cast<ObjCIvarDecl>(FD)->setAccessControl(
+ TranslateIvarVisibility(visibility[i]));
+
+ // C99 6.7.2.1p2 - A field may not be a function type.
+ if (FDTy->isFunctionType()) {
+ Diag(FD->getLocation(), diag::err_field_declared_as_function,
+ FD->getName());
+ FD->setInvalidDecl();
+ EnclosingDecl->setInvalidDecl();
+ continue;
+ }
+ // C99 6.7.2.1p2 - A field may not be an incomplete type except...
+ if (FDTy->isIncompleteType()) {
+ if (!Record) { // Incomplete ivar type is always an error.
+ Diag(FD->getLocation(), diag::err_field_incomplete, FD->getName());
+ FD->setInvalidDecl();
+ EnclosingDecl->setInvalidDecl();
+ continue;
+ }
+ if (i != NumFields-1 || // ... that the last member ...
+ Record->getKind() != Decl::Struct || // ... of a structure ...
+ !FDTy->isArrayType()) { //... may have incomplete array type.
+ Diag(FD->getLocation(), diag::err_field_incomplete, FD->getName());
+ FD->setInvalidDecl();
+ EnclosingDecl->setInvalidDecl();
+ continue;
+ }
+ if (NumNamedMembers < 1) { //... must have more than named member ...
+ Diag(FD->getLocation(), diag::err_flexible_array_empty_struct,
+ FD->getName());
+ FD->setInvalidDecl();
+ EnclosingDecl->setInvalidDecl();
+ continue;
+ }
+ // Okay, we have a legal flexible array member at the end of the struct.
+ if (Record)
+ Record->setHasFlexibleArrayMember(true);
+ }
+ /// C99 6.7.2.1p2 - a struct ending in a flexible array member cannot be the
+ /// field of another structure or the element of an array.
+ 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->getKind() == Decl::Union) {
+ 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::err_variable_sized_type_in_struct,
+ FD->getName());
+ FD->setInvalidDecl();
+ EnclosingDecl->setInvalidDecl();
+ continue;
+ }
+ // 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->getName());
+ if (Record)
+ Record->setHasFlexibleArrayMember(true);
+ }
+ }
+ }
+ /// A field cannot be an Objective-c object
+ if (FDTy->isObjCInterfaceType()) {
+ Diag(FD->getLocation(), diag::err_statically_allocated_object,
+ FD->getName());
+ FD->setInvalidDecl();
+ EnclosingDecl->setInvalidDecl();
+ continue;
+ }
+ // Keep track of the number of named members.
+ if (IdentifierInfo *II = FD->getIdentifier()) {
+ // Detect duplicate member names.
+ if (!FieldIDs.insert(II)) {
+ Diag(FD->getLocation(), diag::err_duplicate_member, II->getName());
+ // Find the previous decl.
+ SourceLocation PrevLoc;
+ for (unsigned i = 0, e = RecFields.size(); ; ++i) {
+ assert(i != e && "Didn't find previous def!");
+ if (RecFields[i]->getIdentifier() == II) {
+ PrevLoc = RecFields[i]->getLocation();
+ break;
+ }
+ }
+ Diag(PrevLoc, diag::err_previous_definition);
+ FD->setInvalidDecl();
+ EnclosingDecl->setInvalidDecl();
+ continue;
+ }
+ ++NumNamedMembers;
+ }
+ }
+
+ // Okay, we successfully defined 'Record'.
+ if (Record) {
+ Record->defineBody(&RecFields[0], RecFields.size());
+ Consumer.HandleTagDeclDefinition(Record);
+ } else {
+ ObjCIvarDecl **ClsFields = reinterpret_cast<ObjCIvarDecl**>(&RecFields[0]);
+ if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(EnclosingDecl))
+ ID->addInstanceVariablesToClass(ClsFields, RecFields.size(), RBrac);
+ else if (ObjCImplementationDecl *IMPDecl =
+ dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) {
+ assert(IMPDecl && "ActOnFields - missing ObjCImplementationDecl");
+ IMPDecl->ObjCAddInstanceVariablesToClassImpl(ClsFields, RecFields.size());
+ CheckImplementationIvars(IMPDecl, ClsFields, RecFields.size(), RBrac);
+ }
+ }
+}
+
+Sema::DeclTy *Sema::ActOnEnumConstant(Scope *S, DeclTy *theEnumDecl,
+ DeclTy *lastEnumConst,
+ SourceLocation IdLoc, IdentifierInfo *Id,
+ SourceLocation EqualLoc, ExprTy *val) {
+ theEnumDecl = theEnumDecl; // silence unused warning.
+ EnumConstantDecl *LastEnumConst =
+ cast_or_null<EnumConstantDecl>(static_cast<Decl*>(lastEnumConst));
+ 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.
+ while ((S->getFlags() & Scope::DeclScope) == 0)
+ S = S->getParent();
+
+ // Verify that there isn't already something declared with this name in this
+ // scope.
+ if (ScopedDecl *PrevDecl = LookupScopedDecl(Id, Decl::IDNS_Ordinary,
+ IdLoc, S)) {
+ if (S->isDeclScope(PrevDecl)) {
+ if (isa<EnumConstantDecl>(PrevDecl))
+ Diag(IdLoc, diag::err_redefinition_of_enumerator, Id->getName());
+ else
+ Diag(IdLoc, diag::err_redefinition, Id->getName());
+ Diag(PrevDecl->getLocation(), diag::err_previous_definition);
+ delete Val;
+ return 0;
+ }
+ }
+
+ llvm::APSInt EnumVal(32);
+ QualType EltTy;
+ if (Val) {
+ // Make sure to promote the operand type to int.
+ UsualUnaryConversions(Val);
+
+ // C99 6.7.2.2p2: Make sure we have an integer constant expression.
+ SourceLocation ExpLoc;
+ if (!Val->isIntegerConstantExpr(EnumVal, Context, &ExpLoc)) {
+ Diag(ExpLoc, diag::err_enum_value_not_integer_constant_expr,
+ Id->getName());
+ delete Val;
+ Val = 0; // Just forget about it.
+ } 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)));
+ }
+ }
+
+ EnumConstantDecl *New =
+ EnumConstantDecl::Create(Context, IdLoc, Id, EltTy, Val, EnumVal,
+ LastEnumConst);
+
+ // Register this decl in the current scope stack.
+ New->setNext(Id->getFETokenInfo<ScopedDecl>());
+ Id->setFETokenInfo(New);
+ S->AddDecl(New);
+ return New;
+}
+
+void Sema::ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX,
+ DeclTy **Elements, unsigned NumElements) {
+ EnumDecl *Enum = cast<EnumDecl>(static_cast<Decl*>(EnumDeclX));
+ assert(!Enum->isDefinition() && "Enum redefinitions can't reach here");
+
+ // 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;
+
+ EnumConstantDecl *EltList = 0;
+ for (unsigned i = 0; i != NumElements; ++i) {
+ EnumConstantDecl *ECD =
+ cast_or_null<EnumConstantDecl>(static_cast<Decl*>(Elements[i]));
+ 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());
+ }
+
+ // 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;
+
+ ECD->setNextDeclarator(EltList);
+ EltList = ECD;
+ }
+
+ // 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>(static_cast<Decl*>(Elements[i]));
+ 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);
+ 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!
+ 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.
+ ECD->setInitExpr(new ImplicitCastExpr(NewTy, ECD->getInitExpr()));
+ ECD->setType(NewTy);
+ }
+
+ Enum->defineElements(EltList, BestType);
+ Consumer.HandleTagDeclDefinition(Enum);
+}
+
+Sema::DeclTy *Sema::ActOnFileScopeAsmDecl(SourceLocation Loc,
+ ExprTy *expr) {
+ StringLiteral *AsmString = cast<StringLiteral>((Expr*)expr);
+
+ return new FileScopeAsmDecl(Loc, AsmString);
+}
+
+Sema::DeclTy* Sema::ActOnLinkageSpec(SourceLocation Loc,
+ SourceLocation LBrace,
+ SourceLocation RBrace,
+ const char *Lang,
+ unsigned StrSize,
+ DeclTy *D) {
+ LinkageSpecDecl::LanguageIDs Language;
+ Decl *dcl = static_cast<Decl *>(D);
+ if (strncmp(Lang, "\"C\"", StrSize) == 0)
+ Language = LinkageSpecDecl::lang_c;
+ else if (strncmp(Lang, "\"C++\"", StrSize) == 0)
+ Language = LinkageSpecDecl::lang_cxx;
+ else {
+ Diag(Loc, diag::err_bad_language);
+ return 0;
+ }
+
+ // FIXME: Add all the various semantics of linkage specifications
+ return new LinkageSpecDecl(Loc, Language, dcl);
+}
+
+void Sema::HandleDeclAttribute(Decl *New, AttributeList *Attr) {
+
+ switch (Attr->getKind()) {
+ case AttributeList::AT_vector_size:
+ if (ValueDecl *vDecl = dyn_cast<ValueDecl>(New)) {
+ QualType newType = HandleVectorTypeAttribute(vDecl->getType(), Attr);
+ if (!newType.isNull()) // install the new vector type into the decl
+ vDecl->setType(newType);
+ }
+ if (TypedefDecl *tDecl = dyn_cast<TypedefDecl>(New)) {
+ QualType newType = HandleVectorTypeAttribute(tDecl->getUnderlyingType(),
+ Attr);
+ if (!newType.isNull()) // install the new vector type into the decl
+ tDecl->setUnderlyingType(newType);
+ }
+ break;
+ case AttributeList::AT_ocu_vector_type:
+ if (TypedefDecl *tDecl = dyn_cast<TypedefDecl>(New))
+ HandleOCUVectorTypeAttribute(tDecl, Attr);
+ else
+ Diag(Attr->getLoc(),
+ diag::err_typecheck_ocu_vector_not_typedef);
+ break;
+ case AttributeList::AT_address_space:
+ if (TypedefDecl *tDecl = dyn_cast<TypedefDecl>(New)) {
+ QualType newType = HandleAddressSpaceTypeAttribute(
+ tDecl->getUnderlyingType(),
+ Attr);
+ tDecl->setUnderlyingType(newType);
+ } else if (ValueDecl *vDecl = dyn_cast<ValueDecl>(New)) {
+ QualType newType = HandleAddressSpaceTypeAttribute(vDecl->getType(),
+ Attr);
+ // install the new addr spaced type into the decl
+ vDecl->setType(newType);
+ }
+ break;
+ case AttributeList::AT_deprecated:
+ HandleDeprecatedAttribute(New, Attr);
+ break;
+ case AttributeList::AT_visibility:
+ HandleVisibilityAttribute(New, Attr);
+ break;
+ case AttributeList::AT_weak:
+ HandleWeakAttribute(New, Attr);
+ break;
+ case AttributeList::AT_dllimport:
+ HandleDLLImportAttribute(New, Attr);
+ break;
+ case AttributeList::AT_dllexport:
+ HandleDLLExportAttribute(New, Attr);
+ break;
+ case AttributeList::AT_nothrow:
+ HandleNothrowAttribute(New, Attr);
+ break;
+ case AttributeList::AT_stdcall:
+ HandleStdCallAttribute(New, Attr);
+ break;
+ case AttributeList::AT_fastcall:
+ HandleFastCallAttribute(New, Attr);
+ break;
+ case AttributeList::AT_aligned:
+ HandleAlignedAttribute(New, Attr);
+ break;
+ case AttributeList::AT_packed:
+ HandlePackedAttribute(New, Attr);
+ break;
+ case AttributeList::AT_annotate:
+ HandleAnnotateAttribute(New, Attr);
+ break;
+ case AttributeList::AT_noreturn:
+ HandleNoReturnAttribute(New, Attr);
+ break;
+ case AttributeList::AT_format:
+ HandleFormatAttribute(New, Attr);
+ break;
+ default:
+#if 0
+ // TODO: when we have the full set of attributes, warn about unknown ones.
+ Diag(Attr->getLoc(), diag::warn_attribute_ignored,
+ Attr->getName()->getName());
+#endif
+ break;
+ }
+}
+
+void Sema::HandleDeclAttributes(Decl *New, AttributeList *declspec_prefix,
+ AttributeList *declarator_postfix) {
+ while (declspec_prefix) {
+ HandleDeclAttribute(New, declspec_prefix);
+ declspec_prefix = declspec_prefix->getNext();
+ }
+ while (declarator_postfix) {
+ HandleDeclAttribute(New, declarator_postfix);
+ declarator_postfix = declarator_postfix->getNext();
+ }
+}
+
+void Sema::HandleOCUVectorTypeAttribute(TypedefDecl *tDecl,
+ AttributeList *rawAttr) {
+ QualType curType = tDecl->getUnderlyingType();
+ // check the attribute arguments.
+ if (rawAttr->getNumArgs() != 1) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments,
+ std::string("1"));
+ return;
+ }
+ Expr *sizeExpr = static_cast<Expr *>(rawAttr->getArg(0));
+ llvm::APSInt vecSize(32);
+ if (!sizeExpr->isIntegerConstantExpr(vecSize, Context)) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_argument_not_int,
+ "ocu_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.).
+ Type *canonType = curType.getCanonicalType().getTypePtr();
+ if (!(canonType->isIntegerType() || canonType->isRealFloatingType())) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_invalid_vector_type,
+ curType.getCanonicalType().getAsString());
+ 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) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_zero_size,
+ sizeExpr->getSourceRange());
+ return;
+ }
+ // Instantiate/Install the vector type, the number of elements is > 0.
+ tDecl->setUnderlyingType(Context.getOCUVectorType(curType, vectorSize));
+ // Remember this typedef decl, we will need it later for diagnostics.
+ OCUVectorDecls.push_back(tDecl);
+}
+
+QualType Sema::HandleVectorTypeAttribute(QualType curType,
+ AttributeList *rawAttr) {
+ // check the attribute arugments.
+ if (rawAttr->getNumArgs() != 1) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments,
+ std::string("1"));
+ return QualType();
+ }
+ Expr *sizeExpr = static_cast<Expr *>(rawAttr->getArg(0));
+ llvm::APSInt vecSize(32);
+ if (!sizeExpr->isIntegerConstantExpr(vecSize, Context)) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_argument_not_int,
+ "vector_size", sizeExpr->getSourceRange());
+ return QualType();
+ }
+ // navigate to the base type - we need to provide for vector pointers,
+ // vector arrays, and functions returning vectors.
+ Type *canonType = curType.getCanonicalType().getTypePtr();
+
+ if (canonType->isPointerType() || canonType->isArrayType() ||
+ canonType->isFunctionType()) {
+ assert(0 && "HandleVector(): Complex type construction unimplemented");
+ /* 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.
+ if (!(canonType->isIntegerType() || canonType->isRealFloatingType())) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_invalid_vector_type,
+ curType.getCanonicalType().getAsString());
+ return QualType();
+ }
+ unsigned typeSize = static_cast<unsigned>(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) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_invalid_size,
+ sizeExpr->getSourceRange());
+ return QualType();
+ }
+ if (vectorSize == 0) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_zero_size,
+ sizeExpr->getSourceRange());
+ return QualType();
+ }
+ // Instantiate the vector type, the number of elements is > 0, and not
+ // required to be a power of 2, unlike GCC.
+ return Context.getVectorType(curType, vectorSize/typeSize);
+}
+
+void Sema::HandlePackedAttribute(Decl *d, AttributeList *rawAttr) {
+ // check the attribute arguments.
+ if (rawAttr->getNumArgs() > 0) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments,
+ std::string("0"));
+ return;
+ }
+
+ if (TagDecl *TD = dyn_cast<TagDecl>(d))
+ TD->addAttr(new PackedAttr);
+ 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 (Context.getTypeAlign(FD->getType()) <= 8)
+ Diag(rawAttr->getLoc(),
+ diag::warn_attribute_ignored_for_field_of_type,
+ rawAttr->getName()->getName(), FD->getType().getAsString());
+ else
+ FD->addAttr(new PackedAttr);
+ } else
+ Diag(rawAttr->getLoc(), diag::warn_attribute_ignored,
+ rawAttr->getName()->getName());
+}
+
+void Sema::HandleNoReturnAttribute(Decl *d, AttributeList *rawAttr) {
+ // check the attribute arguments.
+ if (rawAttr->getNumArgs() != 0) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments,
+ std::string("0"));
+ return;
+ }
+
+ FunctionDecl *Fn = dyn_cast<FunctionDecl>(d);
+
+ if (!Fn) {
+ Diag(rawAttr->getLoc(), diag::warn_attribute_wrong_decl_type,
+ "noreturn", "function");
+ return;
+ }
+
+ d->addAttr(new NoReturnAttr());
+}
+
+void Sema::HandleDeprecatedAttribute(Decl *d, AttributeList *rawAttr) {
+ // check the attribute arguments.
+ if (rawAttr->getNumArgs() != 0) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments,
+ std::string("0"));
+ return;
+ }
+
+ d->addAttr(new DeprecatedAttr());
+}
+
+void Sema::HandleVisibilityAttribute(Decl *d, AttributeList *rawAttr) {
+ // check the attribute arguments.
+ if (rawAttr->getNumArgs() != 1) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments,
+ std::string("1"));
+ return;
+ }
+
+ Expr *Arg = static_cast<Expr*>(rawAttr->getArg(0));
+ Arg = Arg->IgnoreParenCasts();
+ StringLiteral *Str = dyn_cast<StringLiteral>(Arg);
+
+ if (Str == 0 || Str->isWide()) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_string,
+ "visibility", std::string("1"));
+ return;
+ }
+
+ const char *TypeStr = Str->getStrData();
+ unsigned TypeLen = Str->getByteLength();
+ llvm::GlobalValue::VisibilityTypes type;
+
+ if (TypeLen == 7 && !memcmp(TypeStr, "default", 7))
+ type = llvm::GlobalValue::DefaultVisibility;
+ else if (TypeLen == 6 && !memcmp(TypeStr, "hidden", 6))
+ type = llvm::GlobalValue::HiddenVisibility;
+ else if (TypeLen == 8 && !memcmp(TypeStr, "internal", 8))
+ type = llvm::GlobalValue::HiddenVisibility; // FIXME
+ else if (TypeLen == 9 && !memcmp(TypeStr, "protected", 9))
+ type = llvm::GlobalValue::ProtectedVisibility;
+ else {
+ Diag(rawAttr->getLoc(), diag::warn_attribute_type_not_supported,
+ "visibility", TypeStr);
+ return;
+ }
+
+ d->addAttr(new VisibilityAttr(type));
+}
+
+void Sema::HandleWeakAttribute(Decl *d, AttributeList *rawAttr) {
+ // check the attribute arguments.
+ if (rawAttr->getNumArgs() != 0) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments,
+ std::string("0"));
+ return;
+ }
+
+ d->addAttr(new WeakAttr());
+}
+
+void Sema::HandleDLLImportAttribute(Decl *d, AttributeList *rawAttr) {
+ // check the attribute arguments.
+ if (rawAttr->getNumArgs() != 0) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments,
+ std::string("0"));
+ return;
+ }
+
+ d->addAttr(new DLLImportAttr());
+}
+
+void Sema::HandleDLLExportAttribute(Decl *d, AttributeList *rawAttr) {
+ // check the attribute arguments.
+ if (rawAttr->getNumArgs() != 0) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments,
+ std::string("0"));
+ return;
+ }
+
+ d->addAttr(new DLLExportAttr());
+}
+
+void Sema::HandleStdCallAttribute(Decl *d, AttributeList *rawAttr) {
+ // check the attribute arguments.
+ if (rawAttr->getNumArgs() != 0) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments,
+ std::string("0"));
+ return;
+ }
+
+ d->addAttr(new StdCallAttr());
+}
+
+void Sema::HandleFastCallAttribute(Decl *d, AttributeList *rawAttr) {
+ // check the attribute arguments.
+ if (rawAttr->getNumArgs() != 0) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments,
+ std::string("0"));
+ return;
+ }
+
+ d->addAttr(new FastCallAttr());
+}
+
+void Sema::HandleNothrowAttribute(Decl *d, AttributeList *rawAttr) {
+ // check the attribute arguments.
+ if (rawAttr->getNumArgs() != 0) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments,
+ std::string("0"));
+ return;
+ }
+
+ d->addAttr(new NoThrowAttr());
+}
+
+/// Handle __attribute__((format(type,idx,firstarg))) attributes
+/// based on http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
+void Sema::HandleFormatAttribute(Decl *d, AttributeList *rawAttr) {
+
+ if (!rawAttr->getParameterName()) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_string,
+ "format", std::string("1"));
+ return;
+ }
+
+ if (rawAttr->getNumArgs() != 2) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments,
+ std::string("3"));
+ return;
+ }
+
+ FunctionDecl *Fn = dyn_cast<FunctionDecl>(d);
+ if (!Fn) {
+ Diag(rawAttr->getLoc(), diag::warn_attribute_wrong_decl_type,
+ "format", "function");
+ return;
+ }
+
+ const FunctionTypeProto *proto =
+ dyn_cast<FunctionTypeProto>(Fn->getType()->getAsFunctionType());
+ if (!proto)
+ 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 = Fn->getNumParams();
+ unsigned FirstIdx = 1;
+
+ const char *Format = rawAttr->getParameterName()->getName();
+ unsigned FormatLen = rawAttr->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;
+ }
+
+ if (!((FormatLen == 5 && !memcmp(Format, "scanf", 5))
+ || (FormatLen == 6 && !memcmp(Format, "printf", 6))
+ || (FormatLen == 7 && !memcmp(Format, "strfmon", 7))
+ || (FormatLen == 8 && !memcmp(Format, "strftime", 8)))) {
+ Diag(rawAttr->getLoc(), diag::warn_attribute_type_not_supported,
+ "format", rawAttr->getParameterName()->getName());
+ return;
+ }
+
+ // checks for the 2nd argument
+ Expr *IdxExpr = static_cast<Expr *>(rawAttr->getArg(0));
+ llvm::APSInt Idx(Context.getTypeSize(IdxExpr->getType()));
+ if (!IdxExpr->isIntegerConstantExpr(Idx, Context)) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_int,
+ "format", std::string("2"), IdxExpr->getSourceRange());
+ return;
+ }
+
+ if (Idx.getZExtValue() < FirstIdx || Idx.getZExtValue() > NumArgs) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_argument_out_of_bounds,
+ "format", std::string("2"), IdxExpr->getSourceRange());
+ return;
+ }
+
+ // make sure the format string is really a string
+ QualType Ty = proto->getArgType(Idx.getZExtValue()-1);
+ if (!Ty->isPointerType() ||
+ !Ty->getAsPointerType()->getPointeeType()->isCharType()) {
+ Diag(rawAttr->getLoc(), diag::err_format_attribute_not_string,
+ IdxExpr->getSourceRange());
+ return;
+ }
+
+
+ // check the 3rd argument
+ Expr *FirstArgExpr = static_cast<Expr *>(rawAttr->getArg(1));
+ llvm::APSInt FirstArg(Context.getTypeSize(FirstArgExpr->getType()));
+ if (!FirstArgExpr->isIntegerConstantExpr(FirstArg, Context)) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_argument_n_not_int,
+ "format", std::string("3"), FirstArgExpr->getSourceRange());
+ return;
+ }
+
+ // check if the function is variadic if the 3rd argument non-zero
+ if (FirstArg != 0) {
+ if (proto->isVariadic()) {
+ ++NumArgs; // +1 for ...
+ } else {
+ 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 (FormatLen == 8 && !memcmp(Format, "strftime", 8)) {
+ if (FirstArg != 0) {
+ Diag(rawAttr->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) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_argument_out_of_bounds,
+ "format", std::string("3"), FirstArgExpr->getSourceRange());
+ return;
+ }
+
+ d->addAttr(new FormatAttr(std::string(Format, FormatLen),
+ Idx.getZExtValue(), FirstArg.getZExtValue()));
+}
+
+void Sema::HandleAnnotateAttribute(Decl *d, AttributeList *rawAttr) {
+ // check the attribute arguments.
+ if (rawAttr->getNumArgs() != 1) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments,
+ std::string("1"));
+ return;
+ }
+ Expr *argExpr = static_cast<Expr *>(rawAttr->getArg(0));
+ StringLiteral *SE = dyn_cast<StringLiteral>(argExpr);
+
+ // Make sure that there is a string literal as the annotation's single
+ // argument.
+ if (!SE) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_annotate_no_string);
+ return;
+ }
+ d->addAttr(new AnnotateAttr(std::string(SE->getStrData(),
+ SE->getByteLength())));
+}
+
+void Sema::HandleAlignedAttribute(Decl *d, AttributeList *rawAttr)
+{
+ // check the attribute arguments.
+ if (rawAttr->getNumArgs() > 1) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_wrong_number_arguments,
+ std::string("1"));
+ return;
+ }
+
+ unsigned Align = 0;
+
+ if (rawAttr->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;
+ return;
+ } else {
+ Expr *alignmentExpr = static_cast<Expr *>(rawAttr->getArg(0));
+ llvm::APSInt alignment(32);
+ if (!alignmentExpr->isIntegerConstantExpr(alignment, Context)) {
+ Diag(rawAttr->getLoc(), diag::err_attribute_argument_not_int,
+ "aligned", alignmentExpr->getSourceRange());
+ return;
+ }
+
+ Align = alignment.getZExtValue() * 8;
+ }
+
+ d->addAttr(new AlignedAttr(Align));
+}
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
new file mode 100644
index 00000000000..20d127b31eb
--- /dev/null
+++ b/clang/lib/Sema/SemaDeclObjC.cpp
@@ -0,0 +1,927 @@
+//===--- 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/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Parse/Scope.h"
+
+using namespace clang;
+
+/// ObjCActOnStartOfMethodDef - This routine sets up parameters; invisible
+/// and user declared, in the method definition's AST.
+void Sema::ObjCActOnStartOfMethodDef(Scope *FnBodyScope, DeclTy *D) {
+ assert(CurFunctionDecl == 0 && "Method parsing confused");
+ ObjCMethodDecl *MDecl = dyn_cast<ObjCMethodDecl>(static_cast<Decl *>(D));
+ assert(MDecl != 0 && "Not a method declarator!");
+
+ // Allow the rest of sema to find private method decl implementations.
+ if (MDecl->isInstance())
+ AddInstanceMethodToGlobalPool(MDecl);
+ else
+ AddFactoryMethodToGlobalPool(MDecl);
+
+ // Allow all of Sema to see that we are entering a method definition.
+ CurMethodDecl = MDecl;
+
+ // Create Decl objects for each parameter, entrring them in the scope for
+ // binding to their use.
+ struct DeclaratorChunk::ParamInfo PI;
+
+ // Insert the invisible arguments, self and _cmd!
+ PI.Ident = &Context.Idents.get("self");
+ PI.IdentLoc = SourceLocation(); // synthesized vars have a null location.
+ PI.InvalidType = false;
+ PI.AttrList = 0;
+ PI.TypeInfo = Context.getObjCIdType().getAsOpaquePtr();
+
+ if (MDecl->isInstance()) {
+ if (ObjCInterfaceDecl *OID = MDecl->getClassInterface()) {
+ // There may be no interface context due to error in declaration of the
+ // interface (which has been reported). Recover gracefully
+ QualType selfTy = Context.getObjCInterfaceType(OID);
+ selfTy = Context.getPointerType(selfTy);
+ PI.TypeInfo = selfTy.getAsOpaquePtr();
+ }
+ }
+
+ CurMethodDecl->setSelfDecl(ActOnParamDeclarator(PI, FnBodyScope));
+
+ PI.Ident = &Context.Idents.get("_cmd");
+ PI.TypeInfo = Context.getObjCSelType().getAsOpaquePtr();
+ ActOnParamDeclarator(PI, FnBodyScope);
+
+ for (int i = 0; i < MDecl->getNumParams(); i++) {
+ ParmVarDecl *PDecl = MDecl->getParamDecl(i);
+ PI.Ident = PDecl->getIdentifier();
+ PI.IdentLoc = PDecl->getLocation(); // user vars have a real location.
+ PI.TypeInfo = PDecl->getType().getAsOpaquePtr();
+ MDecl->setParamDecl(i, ActOnParamDeclarator(PI, FnBodyScope));
+ }
+}
+
+Sema::DeclTy *Sema::ActOnStartClassInterface(
+ SourceLocation AtInterfaceLoc,
+ IdentifierInfo *ClassName, SourceLocation ClassLoc,
+ IdentifierInfo *SuperName, SourceLocation SuperLoc,
+ IdentifierInfo **ProtocolNames, unsigned NumProtocols,
+ SourceLocation EndProtoLoc, AttributeList *AttrList) {
+ assert(ClassName && "Missing class identifier");
+
+ // Check for another declaration kind with the same name.
+ ScopedDecl *PrevDecl = LookupInterfaceDecl(ClassName);
+ if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
+ Diag(ClassLoc, diag::err_redefinition_different_kind,
+ ClassName->getName());
+ Diag(PrevDecl->getLocation(), diag::err_previous_definition);
+ }
+
+ ObjCInterfaceDecl* IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
+ if (IDecl) {
+ // Class already seen. Is it a forward declaration?
+ if (!IDecl->isForwardDecl())
+ Diag(AtInterfaceLoc, diag::err_duplicate_class_def, IDecl->getName());
+ else {
+ IDecl->setLocation(AtInterfaceLoc);
+ IDecl->setForwardDecl(false);
+ IDecl->AllocIntfRefProtocols(NumProtocols);
+ }
+ }
+ else {
+ IDecl = new ObjCInterfaceDecl(AtInterfaceLoc, NumProtocols, ClassName);
+
+ // Chain & install the interface decl into the identifier.
+ IDecl->setNext(ClassName->getFETokenInfo<ScopedDecl>());
+ ClassName->setFETokenInfo(IDecl);
+
+ // Remember that this needs to be removed when the scope is popped.
+ TUScope->AddDecl(IDecl);
+ }
+
+ if (SuperName) {
+ ObjCInterfaceDecl* SuperClassEntry = 0;
+ // Check if a different kind of symbol declared in this scope.
+ PrevDecl = LookupInterfaceDecl(SuperName);
+ if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
+ Diag(SuperLoc, diag::err_redefinition_different_kind,
+ SuperName->getName());
+ Diag(PrevDecl->getLocation(), diag::err_previous_definition);
+ }
+ else {
+ // Check that super class is previously defined
+ SuperClassEntry = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
+
+ if (!SuperClassEntry || SuperClassEntry->isForwardDecl()) {
+ Diag(AtInterfaceLoc, diag::err_undef_superclass,
+ SuperClassEntry ? SuperClassEntry->getName()
+ : SuperName->getName(),
+ ClassName->getName());
+ }
+ }
+ IDecl->setSuperClass(SuperClassEntry);
+ IDecl->setLocEnd(SuperLoc);
+ } else { // we have a root class.
+ IDecl->setLocEnd(ClassLoc);
+ }
+
+ /// Check then save referenced protocols
+ if (NumProtocols) {
+ for (unsigned int i = 0; i != NumProtocols; i++) {
+ ObjCProtocolDecl* RefPDecl = ObjCProtocols[ProtocolNames[i]];
+ if (!RefPDecl || RefPDecl->isForwardDecl())
+ Diag(ClassLoc, diag::warn_undef_protocolref,
+ ProtocolNames[i]->getName(),
+ ClassName->getName());
+ IDecl->setIntfRefProtocols(i, RefPDecl);
+ }
+ IDecl->setLocEnd(EndProtoLoc);
+ }
+ return IDecl;
+}
+
+/// ActOnCompatiblityAlias - this action is called after complete parsing of
+/// @compaatibility_alias declaration. It sets up the alias relationships.
+Sema::DeclTy *Sema::ActOnCompatiblityAlias(
+ SourceLocation AtCompatibilityAliasLoc,
+ IdentifierInfo *AliasName, SourceLocation AliasLocation,
+ IdentifierInfo *ClassName, SourceLocation ClassLocation) {
+ // Look for previous declaration of alias name
+ ScopedDecl *ADecl = LookupScopedDecl(AliasName, Decl::IDNS_Ordinary,
+ AliasLocation, TUScope);
+ if (ADecl) {
+ if (isa<ObjCCompatibleAliasDecl>(ADecl)) {
+ Diag(AliasLocation, diag::warn_previous_alias_decl);
+ Diag(ADecl->getLocation(), diag::warn_previous_declaration);
+ }
+ else {
+ Diag(AliasLocation, diag::err_conflicting_aliasing_type,
+ AliasName->getName());
+ Diag(ADecl->getLocation(), diag::err_previous_declaration);
+ }
+ return 0;
+ }
+ // Check for class declaration
+ ScopedDecl *CDecl = LookupScopedDecl(ClassName, Decl::IDNS_Ordinary,
+ ClassLocation, TUScope);
+ if (!CDecl || !isa<ObjCInterfaceDecl>(CDecl)) {
+ Diag(ClassLocation, diag::warn_undef_interface,
+ ClassName->getName());
+ if (CDecl)
+ Diag(CDecl->getLocation(), diag::warn_previous_declaration);
+ return 0;
+ }
+ // Everything checked out, instantiate a new alias declaration ast
+ ObjCCompatibleAliasDecl *AliasDecl =
+ new ObjCCompatibleAliasDecl(AtCompatibilityAliasLoc,
+ AliasName,
+ dyn_cast<ObjCInterfaceDecl>(CDecl));
+
+ // Chain & install the interface decl into the identifier.
+ AliasDecl->setNext(AliasName->getFETokenInfo<ScopedDecl>());
+ AliasName->setFETokenInfo(AliasDecl);
+ return AliasDecl;
+}
+
+Sema::DeclTy *Sema::ActOnStartProtocolInterface(
+ SourceLocation AtProtoInterfaceLoc,
+ IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc,
+ IdentifierInfo **ProtoRefNames, unsigned NumProtoRefs,
+ SourceLocation EndProtoLoc) {
+ assert(ProtocolName && "Missing protocol identifier");
+ ObjCProtocolDecl *PDecl = ObjCProtocols[ProtocolName];
+ if (PDecl) {
+ // Protocol already seen. Better be a forward protocol declaration
+ if (!PDecl->isForwardDecl())
+ Diag(ProtocolLoc, diag::err_duplicate_protocol_def,
+ ProtocolName->getName());
+ else {
+ PDecl->setForwardDecl(false);
+ PDecl->AllocReferencedProtocols(NumProtoRefs);
+ }
+ }
+ else {
+ PDecl = new ObjCProtocolDecl(AtProtoInterfaceLoc, NumProtoRefs,
+ ProtocolName);
+ ObjCProtocols[ProtocolName] = PDecl;
+ }
+
+ if (NumProtoRefs) {
+ /// Check then save referenced protocols
+ for (unsigned int i = 0; i != NumProtoRefs; i++) {
+ ObjCProtocolDecl* RefPDecl = ObjCProtocols[ProtoRefNames[i]];
+ if (!RefPDecl || RefPDecl->isForwardDecl())
+ Diag(ProtocolLoc, diag::warn_undef_protocolref,
+ ProtoRefNames[i]->getName(),
+ ProtocolName->getName());
+ PDecl->setReferencedProtocols(i, RefPDecl);
+ }
+ PDecl->setLocEnd(EndProtoLoc);
+ }
+ return PDecl;
+}
+
+/// FindProtocolDeclaration - This routine looks up protocols and
+/// issuer error if they are not declared. It returns list of protocol
+/// declarations in its 'Protocols' argument.
+void
+Sema::FindProtocolDeclaration(SourceLocation TypeLoc,
+ IdentifierInfo **ProtocolId,
+ unsigned NumProtocols,
+ llvm::SmallVector<DeclTy *,8> &Protocols) {
+ for (unsigned i = 0; i != NumProtocols; ++i) {
+ ObjCProtocolDecl *PDecl = ObjCProtocols[ProtocolId[i]];
+ if (!PDecl)
+ Diag(TypeLoc, diag::err_undeclared_protocol,
+ ProtocolId[i]->getName());
+ else
+ Protocols.push_back(PDecl);
+ }
+}
+
+/// ActOnForwardProtocolDeclaration -
+Action::DeclTy *
+Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
+ IdentifierInfo **IdentList, unsigned NumElts) {
+ llvm::SmallVector<ObjCProtocolDecl*, 32> Protocols;
+
+ for (unsigned i = 0; i != NumElts; ++i) {
+ IdentifierInfo *P = IdentList[i];
+ ObjCProtocolDecl *PDecl = ObjCProtocols[P];
+ if (!PDecl) { // Not already seen?
+ // FIXME: Pass in the location of the identifier!
+ PDecl = new ObjCProtocolDecl(AtProtocolLoc, 0, P, true);
+ ObjCProtocols[P] = PDecl;
+ }
+
+ Protocols.push_back(PDecl);
+ }
+ return new ObjCForwardProtocolDecl(AtProtocolLoc,
+ &Protocols[0], Protocols.size());
+}
+
+Sema::DeclTy *Sema::ActOnStartCategoryInterface(
+ SourceLocation AtInterfaceLoc,
+ IdentifierInfo *ClassName, SourceLocation ClassLoc,
+ IdentifierInfo *CategoryName, SourceLocation CategoryLoc,
+ IdentifierInfo **ProtoRefNames, unsigned NumProtoRefs,
+ SourceLocation EndProtoLoc) {
+ ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName);
+
+ ObjCCategoryDecl *CDecl = new ObjCCategoryDecl(AtInterfaceLoc, NumProtoRefs,
+ CategoryName);
+ CDecl->setClassInterface(IDecl);
+
+ /// Check that class of this category is already completely declared.
+ if (!IDecl || IDecl->isForwardDecl())
+ Diag(ClassLoc, diag::err_undef_interface, ClassName->getName());
+ else {
+ /// Check for duplicate interface declaration for this category
+ ObjCCategoryDecl *CDeclChain;
+ for (CDeclChain = IDecl->getCategoryList(); CDeclChain;
+ CDeclChain = CDeclChain->getNextClassCategory()) {
+ if (CDeclChain->getIdentifier() == CategoryName) {
+ Diag(CategoryLoc, diag::err_dup_category_def, ClassName->getName(),
+ CategoryName->getName());
+ break;
+ }
+ }
+ if (!CDeclChain)
+ CDecl->insertNextClassCategory();
+ }
+
+ if (NumProtoRefs) {
+ /// Check then save referenced protocols
+ for (unsigned int i = 0; i != NumProtoRefs; i++) {
+ ObjCProtocolDecl* RefPDecl = ObjCProtocols[ProtoRefNames[i]];
+ if (!RefPDecl || RefPDecl->isForwardDecl()) {
+ Diag(CategoryLoc, diag::warn_undef_protocolref,
+ ProtoRefNames[i]->getName(),
+ CategoryName->getName());
+ }
+ CDecl->setCatReferencedProtocols(i, RefPDecl);
+ }
+ CDecl->setLocEnd(EndProtoLoc);
+ }
+ return CDecl;
+}
+
+/// ActOnStartCategoryImplementation - Perform semantic checks on the
+/// category implementation declaration and build an ObjCCategoryImplDecl
+/// object.
+Sema::DeclTy *Sema::ActOnStartCategoryImplementation(
+ SourceLocation AtCatImplLoc,
+ IdentifierInfo *ClassName, SourceLocation ClassLoc,
+ IdentifierInfo *CatName, SourceLocation CatLoc) {
+ ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName);
+ ObjCCategoryImplDecl *CDecl = new ObjCCategoryImplDecl(AtCatImplLoc,
+ CatName, IDecl);
+ /// Check that class of this category is already completely declared.
+ if (!IDecl || IDecl->isForwardDecl())
+ Diag(ClassLoc, diag::err_undef_interface, ClassName->getName());
+
+ /// TODO: Check that CatName, category name, is not used in another
+ // implementation.
+ return CDecl;
+}
+
+Sema::DeclTy *Sema::ActOnStartClassImplementation(
+ SourceLocation AtClassImplLoc,
+ IdentifierInfo *ClassName, SourceLocation ClassLoc,
+ IdentifierInfo *SuperClassname,
+ SourceLocation SuperClassLoc) {
+ ObjCInterfaceDecl* IDecl = 0;
+ // Check for another declaration kind with the same name.
+ ScopedDecl *PrevDecl = LookupInterfaceDecl(ClassName);
+ if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
+ Diag(ClassLoc, diag::err_redefinition_different_kind,
+ ClassName->getName());
+ Diag(PrevDecl->getLocation(), diag::err_previous_definition);
+ }
+ else {
+ // Is there an interface declaration of this class; if not, warn!
+ IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
+ if (!IDecl)
+ Diag(ClassLoc, diag::warn_undef_interface, ClassName->getName());
+ }
+
+ // 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 = LookupInterfaceDecl(SuperClassname);
+ if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
+ Diag(SuperClassLoc, diag::err_redefinition_different_kind,
+ SuperClassname->getName());
+ Diag(PrevDecl->getLocation(), diag::err_previous_definition);
+ }
+ else {
+ SDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
+ if (!SDecl)
+ Diag(SuperClassLoc, diag::err_undef_superclass,
+ SuperClassname->getName(), ClassName->getName());
+ 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->getName());
+ Diag(SDecl->getLocation(), diag::err_previous_definition);
+ }
+ }
+ }
+
+ if (!IDecl) {
+ // Legacy case of @implementation with no corresponding @interface.
+ // Build, chain & install the interface decl into the identifier.
+ IDecl = new ObjCInterfaceDecl(AtClassImplLoc, 0, ClassName,
+ false, true);
+ IDecl->setNext(ClassName->getFETokenInfo<ScopedDecl>());
+ ClassName->setFETokenInfo(IDecl);
+ IDecl->setSuperClass(SDecl);
+ IDecl->setLocEnd(ClassLoc);
+
+ // Remember that this needs to be removed when the scope is popped.
+ TUScope->AddDecl(IDecl);
+ }
+
+ ObjCImplementationDecl* IMPDecl =
+ new ObjCImplementationDecl(AtClassImplLoc, ClassName, IDecl, SDecl);
+
+ // Check that there is no duplicate implementation of this class.
+ if (ObjCImplementations[ClassName])
+ Diag(ClassLoc, diag::err_dup_implementation_class, ClassName->getName());
+ else // add it to the list.
+ ObjCImplementations[ClassName] = IMPDecl;
+ return IMPDecl;
+}
+
+void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
+ ObjCIvarDecl **ivars, unsigned numIvars,
+ SourceLocation RBrace) {
+ assert(ImpDecl && "missing implementation decl");
+ ObjCInterfaceDecl* IDecl = getObjCInterfaceDecl(ImpDecl->getIdentifier());
+ 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->ImplicitInterfaceDecl()) {
+ IDecl->addInstanceVariablesToClass(ivars, numIvars, 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");
+ if (ImplIvar->getCanonicalType() != ClsIvar->getCanonicalType()) {
+ Diag(ImplIvar->getLocation(), diag::err_conflicting_ivar_type,
+ ImplIvar->getIdentifier()->getName());
+ Diag(ClsIvar->getLocation(), diag::err_previous_definition,
+ ClsIvar->getIdentifier()->getName());
+ }
+ // TODO: Two mismatched (unequal width) Ivar bitfields should be diagnosed
+ // as error.
+ else if (ImplIvar->getIdentifier() != ClsIvar->getIdentifier()) {
+ Diag(ImplIvar->getLocation(), diag::err_conflicting_ivar_name,
+ ImplIvar->getIdentifier()->getName());
+ Diag(ClsIvar->getLocation(), diag::err_previous_definition,
+ ClsIvar->getIdentifier()->getName());
+ return;
+ }
+ --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->getSelector().getName());
+}
+
+/// 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) {
+ // check unimplemented instance methods.
+ for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(),
+ E = PDecl->instmeth_end(); I != E; ++I) {
+ ObjCMethodDecl *method = *I;
+ if (!InsMap.count(method->getSelector()) &&
+ method->getImplementationControl() != ObjCMethodDecl::Optional)
+ WarnUndefinedMethod(ImpLoc, method, IncompleteImpl);
+ }
+ // check unimplemented class methods
+ for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(),
+ E = PDecl->classmeth_end(); I != E; ++I) {
+ ObjCMethodDecl *method = *I;
+ if (!ClsMap.count(method->getSelector()) &&
+ method->getImplementationControl() != ObjCMethodDecl::Optional)
+ WarnUndefinedMethod(ImpLoc, method, IncompleteImpl);
+ }
+ // Check on this protocols's referenced protocols, recursively
+ ObjCProtocolDecl** RefPDecl = PDecl->getReferencedProtocols();
+ for (unsigned i = 0; i < PDecl->getNumReferencedProtocols(); i++)
+ CheckProtocolMethodDefs(ImpLoc, RefPDecl[i], IncompleteImpl, InsMap, ClsMap);
+}
+
+void Sema::ImplMethodsVsClassMethods(ObjCImplementationDecl* IMPDecl,
+ ObjCInterfaceDecl* IDecl) {
+ 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(),
+ E = IMPDecl->instmeth_end(); I != E; ++I)
+ InsMap.insert((*I)->getSelector());
+
+ bool IncompleteImpl = false;
+ for (ObjCInterfaceDecl::instmeth_iterator I = IDecl->instmeth_begin(),
+ E = IDecl->instmeth_end(); I != E; ++I)
+ if (!InsMap.count((*I)->getSelector()))
+ WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl);
+
+ llvm::DenseSet<Selector> ClsMap;
+ // Check and see if class methods in class interface have been
+ // implemented in the implementation class.
+ for (ObjCImplementationDecl::classmeth_iterator I =IMPDecl->classmeth_begin(),
+ E = IMPDecl->classmeth_end(); I != E; ++I)
+ ClsMap.insert((*I)->getSelector());
+
+ for (ObjCInterfaceDecl::classmeth_iterator I = IDecl->classmeth_begin(),
+ E = IDecl->classmeth_end(); I != E; ++I)
+ if (!ClsMap.count((*I)->getSelector()))
+ WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl);
+
+ // Check the protocol list for unimplemented methods in the @implementation
+ // class.
+ ObjCProtocolDecl** protocols = IDecl->getReferencedProtocols();
+ for (unsigned i = 0; i < IDecl->getNumIntfRefProtocols(); i++)
+ CheckProtocolMethodDefs(IMPDecl->getLocation(), protocols[i],
+ IncompleteImpl, InsMap, ClsMap);
+}
+
+/// ImplCategoryMethodsVsIntfMethods - Checks that methods declared in the
+/// category interface is implemented in the category @implementation.
+void Sema::ImplCategoryMethodsVsIntfMethods(ObjCCategoryImplDecl *CatImplDecl,
+ ObjCCategoryDecl *CatClassDecl) {
+ llvm::DenseSet<Selector> InsMap;
+ // Check and see if instance methods in category interface have been
+ // implemented in its implementation class.
+ for (ObjCCategoryImplDecl::instmeth_iterator I =CatImplDecl->instmeth_begin(),
+ E = CatImplDecl->instmeth_end(); I != E; ++I)
+ InsMap.insert((*I)->getSelector());
+
+ bool IncompleteImpl = false;
+ for (ObjCCategoryDecl::instmeth_iterator I = CatClassDecl->instmeth_begin(),
+ E = CatClassDecl->instmeth_end(); I != E; ++I)
+ if (!InsMap.count((*I)->getSelector()))
+ WarnUndefinedMethod(CatImplDecl->getLocation(), *I, IncompleteImpl);
+
+ llvm::DenseSet<Selector> ClsMap;
+ // Check and see if class methods in category interface have been
+ // implemented in its implementation class.
+ for (ObjCCategoryImplDecl::classmeth_iterator
+ I = CatImplDecl->classmeth_begin(), E = CatImplDecl->classmeth_end();
+ I != E; ++I)
+ ClsMap.insert((*I)->getSelector());
+
+ for (ObjCCategoryDecl::classmeth_iterator I = CatClassDecl->classmeth_begin(),
+ E = CatClassDecl->classmeth_end(); I != E; ++I)
+ if (!ClsMap.count((*I)->getSelector()))
+ WarnUndefinedMethod(CatImplDecl->getLocation(), *I, IncompleteImpl);
+
+ // Check the protocol list for unimplemented methods in the @implementation
+ // class.
+ ObjCProtocolDecl** protocols = CatClassDecl->getReferencedProtocols();
+ for (unsigned i = 0; i < CatClassDecl->getNumReferencedProtocols(); i++) {
+ ObjCProtocolDecl* PDecl = protocols[i];
+ CheckProtocolMethodDefs(CatImplDecl->getLocation(), PDecl, IncompleteImpl,
+ InsMap, ClsMap);
+ }
+}
+
+/// ActOnForwardClassDeclaration -
+Action::DeclTy *
+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.
+ ScopedDecl *PrevDecl = LookupInterfaceDecl(IdentList[i]);
+ if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
+ Diag(AtClassLoc, diag::err_redefinition_different_kind,
+ IdentList[i]->getName());
+ Diag(PrevDecl->getLocation(), diag::err_previous_definition);
+ }
+ ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
+ if (!IDecl) { // Not already seen? Make a forward decl.
+ IDecl = new ObjCInterfaceDecl(AtClassLoc, 0, IdentList[i], true);
+ // Chain & install the interface decl into the identifier.
+ IDecl->setNext(IdentList[i]->getFETokenInfo<ScopedDecl>());
+ IdentList[i]->setFETokenInfo(IDecl);
+
+ // Remember that this needs to be removed when the scope is popped.
+ TUScope->AddDecl(IDecl);
+ }
+
+ Interfaces.push_back(IDecl);
+ }
+
+ return new ObjCClassDecl(AtClassLoc, &Interfaces[0], Interfaces.size());
+}
+
+
+/// 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) {
+ if (Method->getResultType().getCanonicalType() !=
+ PrevMethod->getResultType().getCanonicalType())
+ return false;
+ for (int i = 0; i < Method->getNumParams(); i++) {
+ ParmVarDecl *ParamDecl = Method->getParamDecl(i);
+ ParmVarDecl *PrevParamDecl = PrevMethod->getParamDecl(i);
+ if (ParamDecl->getCanonicalType() != PrevParamDecl->getCanonicalType())
+ return false;
+ }
+ return true;
+}
+
+void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method) {
+ ObjCMethodList &FirstMethod = InstanceMethodPool[Method->getSelector()];
+ 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;
+ }
+ }
+}
+
+void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) {
+ ObjCMethodList &FirstMethod = FactoryMethodPool[Method->getSelector()];
+ 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;
+ }
+ }
+}
+
+// Note: For class/category implemenations, allMethods/allProperties is
+// always null.
+void Sema::ActOnAtEnd(SourceLocation AtEndLoc, DeclTy *classDecl,
+ DeclTy **allMethods, unsigned allNum,
+ DeclTy **allProperties, unsigned pNum) {
+ Decl *ClassDecl = static_cast<Decl *>(classDecl);
+
+ // 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;
+
+ llvm::SmallVector<ObjCMethodDecl*, 32> insMethods;
+ llvm::SmallVector<ObjCMethodDecl*, 16> clsMethods;
+
+ llvm::DenseMap<Selector, const ObjCMethodDecl*> InsMap;
+ llvm::DenseMap<Selector, const ObjCMethodDecl*> ClsMap;
+
+ bool isInterfaceDeclKind =
+ (isa<ObjCInterfaceDecl>(ClassDecl) || isa<ObjCCategoryDecl>(ClassDecl)
+ || isa<ObjCProtocolDecl>(ClassDecl));
+ bool checkIdenticalMethods = isa<ObjCImplementationDecl>(ClassDecl);
+
+ // TODO: property declaration in category and protocols.
+ if (pNum != 0 && isa<ObjCInterfaceDecl>(ClassDecl)) {
+ ObjCPropertyDecl **properties = new ObjCPropertyDecl*[pNum];
+ memcpy(properties, allProperties, pNum*sizeof(ObjCPropertyDecl*));
+ dyn_cast<ObjCInterfaceDecl>(ClassDecl)->setPropertyDecls(properties);
+ dyn_cast<ObjCInterfaceDecl>(ClassDecl)->setNumPropertyDecl(pNum);
+ }
+
+ for (unsigned i = 0; i < allNum; i++ ) {
+ ObjCMethodDecl *Method =
+ cast_or_null<ObjCMethodDecl>(static_cast<Decl*>(allMethods[i]));
+
+ if (!Method) continue; // Already issued a diagnostic.
+ if (Method->isInstance()) {
+ /// 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::error_duplicate_method_decl,
+ Method->getSelector().getName());
+ Diag(PrevMethod->getLocation(), diag::err_previous_declaration);
+ } else {
+ insMethods.push_back(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::error_duplicate_method_decl,
+ Method->getSelector().getName());
+ Diag(PrevMethod->getLocation(), diag::err_previous_declaration);
+ } else {
+ clsMethods.push_back(Method);
+ ClsMap[Method->getSelector()] = Method;
+ /// The following allows us to typecheck messages to "Class".
+ AddFactoryMethodToGlobalPool(Method);
+ }
+ }
+ }
+
+ if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
+ I->addMethods(&insMethods[0], insMethods.size(),
+ &clsMethods[0], clsMethods.size(), AtEndLoc);
+ } else if (ObjCProtocolDecl *P = dyn_cast<ObjCProtocolDecl>(ClassDecl)) {
+ P->addMethods(&insMethods[0], insMethods.size(),
+ &clsMethods[0], clsMethods.size(), AtEndLoc);
+ }
+ else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
+ C->addMethods(&insMethods[0], insMethods.size(),
+ &clsMethods[0], clsMethods.size(), AtEndLoc);
+ }
+ else if (ObjCImplementationDecl *IC =
+ dyn_cast<ObjCImplementationDecl>(ClassDecl)) {
+ IC->setLocEnd(AtEndLoc);
+ if (ObjCInterfaceDecl* IDecl = getObjCInterfaceDecl(IC->getIdentifier()))
+ ImplMethodsVsClassMethods(IC, IDecl);
+ } else {
+ ObjCCategoryImplDecl* CatImplClass = cast<ObjCCategoryImplDecl>(ClassDecl);
+ CatImplClass->setLocEnd(AtEndLoc);
+ ObjCInterfaceDecl* IDecl = CatImplClass->getClassInterface();
+ // Find category interface decl and then check that all methods declared
+ // in this interface is implemented in the category @implementation.
+ if (IDecl) {
+ for (ObjCCategoryDecl *Categories = IDecl->getCategoryList();
+ Categories; Categories = Categories->getNextClassCategory()) {
+ if (Categories->getIdentifier() == CatImplClass->getIdentifier()) {
+ ImplCategoryMethodsVsIntfMethods(CatImplClass, Categories);
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+/// 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::DeclTy *Sema::ActOnMethodDeclaration(
+ SourceLocation MethodLoc, SourceLocation EndLoc,
+ tok::TokenKind MethodType, DeclTy *ClassDecl,
+ ObjCDeclSpec &ReturnQT, TypeTy *ReturnType,
+ Selector Sel,
+ // optional arguments. The number of types/arguments is obtained
+ // from the Sel.getNumArgs().
+ ObjCDeclSpec *ArgQT, TypeTy **ArgTypes, IdentifierInfo **ArgNames,
+ AttributeList *AttrList, tok::ObjCKeywordKind MethodDeclKind,
+ bool isVariadic) {
+
+ // Make sure we can establish a context for the method.
+ if (!ClassDecl) {
+ Diag(MethodLoc, diag::error_missing_method_context);
+ return 0;
+ }
+ llvm::SmallVector<ParmVarDecl*, 16> Params;
+
+ for (unsigned i = 0; i < Sel.getNumArgs(); i++) {
+ // FIXME: arg->AttrList must be stored too!
+ QualType argType;
+
+ if (ArgTypes[i])
+ argType = QualType::getFromOpaquePtr(ArgTypes[i]);
+ else
+ argType = Context.getObjCIdType();
+ ParmVarDecl* Param = ParmVarDecl::Create(Context, SourceLocation(/*FIXME*/),
+ ArgNames[i], argType,
+ VarDecl::None, 0);
+ Param->setObjCDeclQualifier(
+ CvtQTToAstBitMask(ArgQT[i].getObjCDeclQualifier()));
+ Params.push_back(Param);
+ }
+ QualType resultDeclType;
+
+ if (ReturnType)
+ resultDeclType = QualType::getFromOpaquePtr(ReturnType);
+ else // get the type for "id".
+ resultDeclType = Context.getObjCIdType();
+
+ Decl *CDecl = static_cast<Decl*>(ClassDecl);
+ ObjCMethodDecl* ObjCMethod = new ObjCMethodDecl(MethodLoc, EndLoc, Sel,
+ resultDeclType,
+ CDecl,
+ 0, -1, AttrList,
+ MethodType == tok::minus, isVariadic,
+ MethodDeclKind == tok::objc_optional ?
+ ObjCMethodDecl::Optional :
+ ObjCMethodDecl::Required);
+ ObjCMethod->setMethodParams(&Params[0], Sel.getNumArgs());
+ ObjCMethod->setObjCDeclQualifier(
+ CvtQTToAstBitMask(ReturnQT.getObjCDeclQualifier()));
+ const ObjCMethodDecl *PrevMethod = 0;
+
+ // For implementations (which can be very "coarse grain"), we add the
+ // method now. This allows the AST to implement lookup methods that work
+ // incrementally (without waiting until we parse the @end). It also allows
+ // us to flag multiple declaration errors as they occur.
+ if (ObjCImplementationDecl *ImpDecl =
+ dyn_cast<ObjCImplementationDecl>(CDecl)) {
+ if (MethodType == tok::minus) {
+ PrevMethod = ImpDecl->getInstanceMethod(Sel);
+ ImpDecl->addInstanceMethod(ObjCMethod);
+ } else {
+ PrevMethod = ImpDecl->getClassMethod(Sel);
+ ImpDecl->addClassMethod(ObjCMethod);
+ }
+ }
+ else if (ObjCCategoryImplDecl *CatImpDecl =
+ dyn_cast<ObjCCategoryImplDecl>(CDecl)) {
+ if (MethodType == tok::minus) {
+ PrevMethod = CatImpDecl->getInstanceMethod(Sel);
+ CatImpDecl->addInstanceMethod(ObjCMethod);
+ } else {
+ PrevMethod = CatImpDecl->getClassMethod(Sel);
+ CatImpDecl->addClassMethod(ObjCMethod);
+ }
+ }
+ if (PrevMethod) {
+ // You can never have two method definitions with the same name.
+ Diag(ObjCMethod->getLocation(), diag::error_duplicate_method_decl,
+ ObjCMethod->getSelector().getName());
+ Diag(PrevMethod->getLocation(), diag::err_previous_declaration);
+ }
+ return ObjCMethod;
+}
+
+Sema::DeclTy *Sema::ActOnAddObjCProperties(SourceLocation AtLoc,
+ DeclTy **allProperties, unsigned NumProperties, ObjCDeclSpec &DS) {
+ ObjCPropertyDecl *PDecl = new ObjCPropertyDecl(AtLoc);
+
+ if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_readonly)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
+
+ if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_getter) {
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_getter);
+ PDecl->setGetterName(DS.getGetterName());
+ }
+
+ if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_setter) {
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_setter);
+ PDecl->setSetterName(DS.getSetterName());
+ }
+
+ if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_assign)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign);
+
+ if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_readwrite)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite);
+
+ if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_retain)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain);
+
+ if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_copy)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy);
+
+ if(DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nonatomic)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic);
+
+ PDecl->setNumPropertyDecls(NumProperties);
+ if (NumProperties != 0) {
+ ObjCIvarDecl **properties = new ObjCIvarDecl*[NumProperties];
+ memcpy(properties, allProperties, NumProperties*sizeof(ObjCIvarDecl*));
+ PDecl->setPropertyDecls(properties);
+ }
+ return PDecl;
+}
+
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
new file mode 100644
index 00000000000..d756345c1a8
--- /dev/null
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -0,0 +1,2286 @@
+//===--- 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 "SemaUtil.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/LiteralSupport.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+using namespace clang;
+
+/// 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::ExprResult
+Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) {
+ assert(NumStringToks && "Must have at least one string!");
+
+ StringLiteralParser Literal(StringToks, NumStringToks, PP, Context.Target);
+ if (Literal.hadError)
+ return ExprResult(true);
+
+ llvm::SmallVector<SourceLocation, 4> StringTokLocs;
+ for (unsigned i = 0; i != NumStringToks; ++i)
+ StringTokLocs.push_back(StringToks[i].getLocation());
+
+ // Verify that pascal strings aren't too large.
+ if (Literal.Pascal && Literal.GetStringLength() > 256)
+ return Diag(StringToks[0].getLocation(), diag::err_pascal_string_too_long,
+ SourceRange(StringToks[0].getLocation(),
+ StringToks[NumStringToks-1].getLocation()));
+
+ QualType StrTy = Context.CharTy;
+ // FIXME: handle wchar_t
+ if (Literal.Pascal) StrTy = Context.UnsignedCharTy;
+
+ // 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.GetStringLength()+1),
+ ArrayType::Normal, 0);
+
+ // Pass &StringTokLocs[0], StringTokLocs.size() to factory!
+ return new StringLiteral(Literal.GetString(), Literal.GetStringLength(),
+ Literal.AnyWide, StrTy,
+ StringToks[0].getLocation(),
+ StringToks[NumStringToks-1].getLocation());
+}
+
+
+/// ActOnIdentifierExpr - The parser read an identifier in expression context,
+/// validate it per-C99 6.5.1. HasTrailingLParen indicates whether this
+/// identifier is used in an function call context.
+Sema::ExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
+ IdentifierInfo &II,
+ bool HasTrailingLParen) {
+ // Could be enum-constant or decl.
+ ScopedDecl *D = LookupScopedDecl(&II, Decl::IDNS_Ordinary, Loc, S);
+ if (D == 0) {
+ // Otherwise, this could be an implicitly declared function reference (legal
+ // in C90, extension in C99).
+ if (HasTrailingLParen &&
+ // Not in C++.
+ !getLangOptions().CPlusPlus)
+ D = ImplicitlyDefineFunction(Loc, II, S);
+ else {
+ if (CurMethodDecl) {
+ ObjCInterfaceDecl *IFace = CurMethodDecl->getClassInterface();
+ ObjCInterfaceDecl *clsDeclared;
+ if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(&II, clsDeclared)) {
+ IdentifierInfo &II = Context.Idents.get("self");
+ ExprResult SelfExpr = ActOnIdentifierExpr(S, Loc, II, false);
+ return new ObjCIvarRefExpr(IV, IV->getType(), Loc,
+ static_cast<Expr*>(SelfExpr.Val), true, true);
+ }
+ }
+ // If this name wasn't predeclared and if this is not a function call,
+ // diagnose the problem.
+ return Diag(Loc, diag::err_undeclared_var_use, II.getName());
+ }
+ }
+ if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
+ // check if referencing an identifier with __attribute__((deprecated)).
+ if (VD->getAttr<DeprecatedAttr>())
+ Diag(Loc, diag::warn_deprecated, VD->getName());
+
+ // Only create DeclRefExpr's for valid Decl's.
+ if (VD->isInvalidDecl())
+ return true;
+ return new DeclRefExpr(VD, VD->getType(), Loc);
+ }
+ if (isa<TypedefDecl>(D))
+ return Diag(Loc, diag::err_unexpected_typedef, II.getName());
+ if (isa<ObjCInterfaceDecl>(D))
+ return Diag(Loc, diag::err_unexpected_interface, II.getName());
+
+ assert(0 && "Invalid decl");
+ abort();
+}
+
+Sema::ExprResult 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;
+ }
+
+ // Verify that this is in a function context.
+ if (CurFunctionDecl == 0 && CurMethodDecl == 0)
+ return Diag(Loc, diag::err_predef_outside_function);
+
+ // Pre-defined identifiers are of type char[x], where x is the length of the
+ // string.
+ unsigned Length;
+ if (CurFunctionDecl)
+ Length = CurFunctionDecl->getIdentifier()->getLength();
+ else
+ Length = CurMethodDecl->getSynthesizedMethodSize();
+
+ llvm::APInt LengthI(32, Length + 1);
+ QualType ResTy = Context.CharTy.getQualifiedType(QualType::Const);
+ ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0);
+ return new PreDefinedExpr(Loc, ResTy, IT);
+}
+
+Sema::ExprResult 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 ExprResult(true);
+
+ QualType type = getLangOptions().CPlusPlus ? Context.CharTy : Context.IntTy;
+
+ return new CharacterLiteral(Literal.getValue(), type, Tok.getLocation());
+}
+
+Action::ExprResult 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 *t = PP.getSourceManager().getCharacterData(Tok.getLocation());
+
+ unsigned IntSize =static_cast<unsigned>(Context.getTypeSize(Context.IntTy));
+ return ExprResult(new IntegerLiteral(llvm::APInt(IntSize, *t-'0'),
+ Context.IntTy,
+ Tok.getLocation()));
+ }
+ llvm::SmallString<512> IntegerBuffer;
+ IntegerBuffer.resize(Tok.getLength());
+ 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 ExprResult(true);
+
+ Expr *Res;
+
+ if (Literal.isFloatingLiteral()) {
+ QualType Ty;
+ const llvm::fltSemantics *Format;
+
+ if (Literal.isFloat) {
+ Ty = Context.FloatTy;
+ Format = Context.Target.getFloatFormat();
+ } else if (!Literal.isLong) {
+ Ty = Context.DoubleTy;
+ Format = Context.Target.getDoubleFormat();
+ } else {
+ Ty = Context.LongDoubleTy;
+ Format = Context.Target.getLongDoubleFormat();
+ }
+
+ // isExact will be set by GetFloatValue().
+ bool isExact = false;
+
+ Res = new FloatingLiteral(Literal.GetFloatValue(*Format,&isExact), &isExact,
+ Ty, Tok.getLocation());
+
+ } else if (!Literal.isIntegerLiteral()) {
+ return ExprResult(true);
+ } else {
+ QualType t;
+
+ // 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);
+ t = Context.UnsignedLongLongTy;
+ assert(Context.getTypeSize(t) == 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.
+ if (!Literal.isLong && !Literal.isLongLong) {
+ // Are int/unsigned possibilities?
+ unsigned IntSize =
+ static_cast<unsigned>(Context.getTypeSize(Context.IntTy));
+ // 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)
+ t = Context.IntTy;
+ else if (AllowUnsigned)
+ t = Context.UnsignedIntTy;
+ }
+
+ if (!t.isNull())
+ ResultVal.trunc(IntSize);
+ }
+
+ // Are long/unsigned long possibilities?
+ if (t.isNull() && !Literal.isLongLong) {
+ unsigned LongSize =
+ static_cast<unsigned>(Context.getTypeSize(Context.LongTy));
+
+ // 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)
+ t = Context.LongTy;
+ else if (AllowUnsigned)
+ t = Context.UnsignedLongTy;
+ }
+ if (!t.isNull())
+ ResultVal.trunc(LongSize);
+ }
+
+ // Finally, check long long if needed.
+ if (t.isNull()) {
+ unsigned LongLongSize =
+ static_cast<unsigned>(Context.getTypeSize(Context.LongLongTy));
+
+ // 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)
+ t = Context.LongLongTy;
+ else if (AllowUnsigned)
+ t = Context.UnsignedLongLongTy;
+ }
+ }
+
+ // 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 (t.isNull()) {
+ Diag(Tok.getLocation(), diag::warn_integer_too_large_for_signed);
+ t = Context.UnsignedLongLongTy;
+ }
+ }
+
+ Res = new IntegerLiteral(ResultVal, t, Tok.getLocation());
+ }
+
+ // If this is an imaginary literal, create the ImaginaryLiteral wrapper.
+ if (Literal.isImaginary)
+ Res = new ImaginaryLiteral(Res, Context.getComplexType(Res->getType()));
+
+ return Res;
+}
+
+Action::ExprResult Sema::ActOnParenExpr(SourceLocation L, SourceLocation R,
+ ExprTy *Val) {
+ Expr *e = (Expr *)Val;
+ assert((e != 0) && "ActOnParenExpr() missing expr");
+ return new ParenExpr(L, R, e);
+}
+
+/// The UsualUnaryConversions() function is *not* called by this routine.
+/// See C99 6.3.2.1p[2-4] for more details.
+QualType Sema::CheckSizeOfAlignOfOperand(QualType exprType,
+ SourceLocation OpLoc, bool isSizeof) {
+ // C99 6.5.3.4p1:
+ if (isa<FunctionType>(exprType) && isSizeof)
+ // alignof(function) is allowed.
+ Diag(OpLoc, diag::ext_sizeof_function_type);
+ else if (exprType->isVoidType())
+ Diag(OpLoc, diag::ext_sizeof_void_type, isSizeof ? "sizeof" : "__alignof");
+ else if (exprType->isIncompleteType()) {
+ Diag(OpLoc, isSizeof ? diag::err_sizeof_incomplete_type :
+ diag::err_alignof_incomplete_type,
+ exprType.getAsString());
+ return QualType(); // error
+ }
+ // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
+ return Context.getSizeType();
+}
+
+Action::ExprResult Sema::
+ActOnSizeOfAlignOfTypeExpr(SourceLocation OpLoc, bool isSizeof,
+ SourceLocation LPLoc, TypeTy *Ty,
+ SourceLocation RPLoc) {
+ // If error parsing type, ignore.
+ if (Ty == 0) return true;
+
+ // Verify that this is a valid expression.
+ QualType ArgTy = QualType::getFromOpaquePtr(Ty);
+
+ QualType resultType = CheckSizeOfAlignOfOperand(ArgTy, OpLoc, isSizeof);
+
+ if (resultType.isNull())
+ return true;
+ return new SizeOfAlignOfTypeExpr(isSizeof, ArgTy, resultType, OpLoc, RPLoc);
+}
+
+QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc) {
+ DefaultFunctionArrayConversion(V);
+
+ // 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().getAsString());
+ return QualType();
+}
+
+
+
+Action::ExprResult Sema::ActOnPostfixUnaryOp(SourceLocation OpLoc,
+ tok::TokenKind Kind,
+ ExprTy *Input) {
+ 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;
+ }
+ QualType result = CheckIncrementDecrementOperand((Expr *)Input, OpLoc);
+ if (result.isNull())
+ return true;
+ return new UnaryOperator((Expr *)Input, Opc, result, OpLoc);
+}
+
+Action::ExprResult Sema::
+ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc,
+ ExprTy *Idx, SourceLocation RLoc) {
+ Expr *LHSExp = static_cast<Expr*>(Base), *RHSExp = static_cast<Expr*>(Idx);
+
+ // 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 (const PointerType *PTy = LHSTy->getAsPointerType()) {
+ BaseExpr = LHSExp;
+ IndexExpr = RHSExp;
+ // FIXME: need to deal with const...
+ ResultType = PTy->getPointeeType();
+ } else if (const PointerType *PTy = RHSTy->getAsPointerType()) {
+ // Handle the uncommon case of "123[Ptr]".
+ BaseExpr = RHSExp;
+ IndexExpr = LHSExp;
+ // FIXME: need to deal with const...
+ ResultType = PTy->getPointeeType();
+ } else if (const VectorType *VTy = LHSTy->getAsVectorType()) {
+ BaseExpr = LHSExp; // vectors: V[123]
+ IndexExpr = RHSExp;
+
+ // Component access limited to variables (reject vec4.rg[1]).
+ if (!isa<DeclRefExpr>(BaseExpr) && !isa<ArraySubscriptExpr>(BaseExpr))
+ return Diag(LLoc, diag::err_ocuvector_component_access,
+ SourceRange(LLoc, RLoc));
+ // FIXME: need to deal with const...
+ ResultType = VTy->getElementType();
+ } else {
+ return Diag(LHSExp->getLocStart(), diag::err_typecheck_subscript_value,
+ RHSExp->getSourceRange());
+ }
+ // C99 6.5.2.1p1
+ if (!IndexExpr->getType()->isIntegerType())
+ return Diag(IndexExpr->getLocStart(), diag::err_typecheck_subscript,
+ IndexExpr->getSourceRange());
+
+ // C99 6.5.2.1p1: "shall have type "pointer to *object* type". In practice,
+ // the following check catches trying to index a pointer to a function (e.g.
+ // void (*)(int)). Functions are not objects in C99.
+ if (!ResultType->isObjectType())
+ return Diag(BaseExpr->getLocStart(),
+ diag::err_typecheck_subscript_not_object,
+ BaseExpr->getType().getAsString(), BaseExpr->getSourceRange());
+
+ return new ArraySubscriptExpr(LHSExp, RHSExp, ResultType, RLoc);
+}
+
+QualType Sema::
+CheckOCUVectorComponent(QualType baseType, SourceLocation OpLoc,
+ IdentifierInfo &CompName, SourceLocation CompLoc) {
+ const OCUVectorType *vecType = baseType->getAsOCUVectorType();
+
+ // The vector accessor can't exceed the number of elements.
+ const char *compStr = CompName.getName();
+ if (strlen(compStr) > vecType->getNumElements()) {
+ Diag(OpLoc, diag::err_ocuvector_component_exceeds_length,
+ baseType.getAsString(), SourceRange(CompLoc));
+ return QualType();
+ }
+ // The component names must come from the same set.
+ if (vecType->getPointAccessorIdx(*compStr) != -1) {
+ do
+ compStr++;
+ while (*compStr && vecType->getPointAccessorIdx(*compStr) != -1);
+ } else if (vecType->getColorAccessorIdx(*compStr) != -1) {
+ do
+ compStr++;
+ while (*compStr && vecType->getColorAccessorIdx(*compStr) != -1);
+ } else if (vecType->getTextureAccessorIdx(*compStr) != -1) {
+ do
+ compStr++;
+ while (*compStr && vecType->getTextureAccessorIdx(*compStr) != -1);
+ }
+
+ if (*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_ocuvector_component_name_illegal,
+ std::string(compStr,compStr+1), SourceRange(CompLoc));
+ return QualType();
+ }
+ // Each component accessor can't exceed the vector type.
+ compStr = CompName.getName();
+ while (*compStr) {
+ if (vecType->isAccessorWithinNumElements(*compStr))
+ compStr++;
+ else
+ break;
+ }
+ if (*compStr) {
+ // We didn't get to the end of the string. This means a component accessor
+ // exceeds the number of elements in the vector.
+ Diag(OpLoc, diag::err_ocuvector_component_exceeds_length,
+ baseType.getAsString(), 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.
+ unsigned CompSize = strlen(CompName.getName());
+ if (CompSize == 1)
+ return vecType->getElementType();
+
+ QualType VT = Context.getOCUVectorType(vecType->getElementType(), CompSize);
+ // Now look up the TypeDefDecl from the vector type. Without this,
+ // diagostics look bad. We want OCU vector types to appear built-in.
+ for (unsigned i = 0, e = OCUVectorDecls.size(); i != e; ++i) {
+ if (OCUVectorDecls[i]->getUnderlyingType() == VT)
+ return Context.getTypedefType(OCUVectorDecls[i]);
+ }
+ return VT; // should never get here (a typedef type should always be found).
+}
+
+Action::ExprResult Sema::
+ActOnMemberReferenceExpr(ExprTy *Base, SourceLocation OpLoc,
+ tok::TokenKind OpKind, SourceLocation MemberLoc,
+ IdentifierInfo &Member) {
+ Expr *BaseExpr = static_cast<Expr *>(Base);
+ assert(BaseExpr && "no record expression");
+
+ // Perform default conversions.
+ DefaultFunctionArrayConversion(BaseExpr);
+
+ QualType BaseType = BaseExpr->getType();
+ assert(!BaseType.isNull() && "no type for member expression");
+
+ if (OpKind == tok::arrow) {
+ if (const PointerType *PT = BaseType->getAsPointerType())
+ BaseType = PT->getPointeeType();
+ else
+ return Diag(OpLoc, diag::err_typecheck_member_reference_arrow,
+ SourceRange(MemberLoc));
+ }
+ // The base type is either a record or an OCUVectorType.
+ if (const RecordType *RTy = BaseType->getAsRecordType()) {
+ RecordDecl *RDecl = RTy->getDecl();
+ if (RTy->isIncompleteType())
+ return Diag(OpLoc, diag::err_typecheck_incomplete_tag, RDecl->getName(),
+ BaseExpr->getSourceRange());
+ // The record definition is complete, now make sure the member is valid.
+ FieldDecl *MemberDecl = RDecl->getMember(&Member);
+ if (!MemberDecl)
+ return Diag(OpLoc, diag::err_typecheck_no_member, Member.getName(),
+ SourceRange(MemberLoc));
+
+ // Figure out the type of the member; see C99 6.5.2.3p3
+ // FIXME: Handle address space modifiers
+ QualType MemberType = MemberDecl->getType();
+ unsigned combinedQualifiers =
+ MemberType.getCVRQualifiers() | BaseType.getCVRQualifiers();
+ MemberType = MemberType.getQualifiedType(combinedQualifiers);
+
+ return new MemberExpr(BaseExpr, OpKind==tok::arrow, MemberDecl,
+ MemberLoc, MemberType);
+ } else if (BaseType->isOCUVectorType() && OpKind == tok::period) {
+ // Component access limited to variables (reject vec4.rg.g).
+ if (!isa<DeclRefExpr>(BaseExpr))
+ return Diag(OpLoc, diag::err_ocuvector_component_access,
+ SourceRange(MemberLoc));
+ QualType ret = CheckOCUVectorComponent(BaseType, OpLoc, Member, MemberLoc);
+ if (ret.isNull())
+ return true;
+ return new OCUVectorElementExpr(ret, BaseExpr, Member, MemberLoc);
+ } else if (BaseType->isObjCInterfaceType()) {
+ ObjCInterfaceDecl *IFace;
+ if (isa<ObjCInterfaceType>(BaseType.getCanonicalType()))
+ IFace = dyn_cast<ObjCInterfaceType>(BaseType)->getDecl();
+ else
+ IFace = dyn_cast<ObjCQualifiedInterfaceType>(BaseType)->getDecl();
+ ObjCInterfaceDecl *clsDeclared;
+ if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(&Member, clsDeclared))
+ return new ObjCIvarRefExpr(IV, IV->getType(), MemberLoc, BaseExpr,
+ OpKind==tok::arrow);
+ }
+ return Diag(OpLoc, diag::err_typecheck_member_reference_structUnion,
+ SourceRange(MemberLoc));
+}
+
+/// 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::ExprResult Sema::
+ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc,
+ ExprTy **args, unsigned NumArgs,
+ SourceLocation *CommaLocs, SourceLocation RParenLoc) {
+ Expr *Fn = static_cast<Expr *>(fn);
+ Expr **Args = reinterpret_cast<Expr**>(args);
+ assert(Fn && "no function call expression");
+
+ // Make the call expr early, before semantic checks. This guarantees cleanup
+ // of arguments and function on error.
+ llvm::OwningPtr<CallExpr> TheCall(new CallExpr(Fn, Args, NumArgs,
+ Context.BoolTy, RParenLoc));
+
+ // Promote the function operand.
+ TheCall->setCallee(UsualUnaryConversions(Fn));
+
+ // 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 Diag(Fn->getLocStart(), diag::err_typecheck_call_not_function,
+ SourceRange(Fn->getLocStart(), RParenLoc));
+ const FunctionType *FuncT = PT->getPointeeType()->getAsFunctionType();
+ if (FuncT == 0)
+ return Diag(Fn->getLocStart(), diag::err_typecheck_call_not_function,
+ SourceRange(Fn->getLocStart(), RParenLoc));
+
+ // We know the result type of the call, set it.
+ TheCall->setType(FuncT->getResultType());
+
+ if (const FunctionTypeProto *Proto = dyn_cast<FunctionTypeProto>(FuncT)) {
+ // 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;
+
+ // If too few arguments are available, don't make the call.
+ if (NumArgs < NumArgsInProto)
+ return Diag(RParenLoc, diag::err_typecheck_call_too_few_args,
+ Fn->getSourceRange());
+
+ // 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->getSourceRange(),
+ SourceRange(Args[NumArgsInProto]->getLocStart(),
+ Args[NumArgs-1]->getLocEnd()));
+ // This deletes the extra arguments.
+ TheCall->setNumArgs(NumArgsInProto);
+ }
+ NumArgsToCheck = NumArgsInProto;
+ }
+
+ // Continue to check argument types (even if we have too few/many args).
+ for (unsigned i = 0; i != NumArgsToCheck; i++) {
+ Expr *Arg = Args[i];
+ QualType ProtoArgType = Proto->getArgType(i);
+ QualType ArgType = Arg->getType();
+
+ // Compute implicit casts from the operand to the formal argument type.
+ AssignConvertType ConvTy =
+ CheckSingleAssignmentConstraints(ProtoArgType, Arg);
+ TheCall->setArg(i, Arg);
+
+ if (DiagnoseAssignmentResult(ConvTy, Arg->getLocStart(), ProtoArgType,
+ ArgType, Arg, "passing"))
+ return true;
+ }
+
+ // 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];
+ DefaultArgumentPromotion(Arg);
+ TheCall->setArg(i, Arg);
+ }
+ }
+ } else {
+ assert(isa<FunctionTypeNoProto>(FuncT) && "Unknown FunctionType!");
+
+ // Promote the arguments (C99 6.5.2.2p6).
+ for (unsigned i = 0; i != NumArgs; i++) {
+ Expr *Arg = Args[i];
+ DefaultArgumentPromotion(Arg);
+ TheCall->setArg(i, Arg);
+ }
+ }
+
+ // Do special checking on direct calls to functions.
+ if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(Fn))
+ if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(IcExpr->getSubExpr()))
+ if (FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRExpr->getDecl()))
+ if (CheckFunctionCall(FDecl, TheCall.get()))
+ return true;
+
+ return TheCall.take();
+}
+
+Action::ExprResult Sema::
+ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty,
+ SourceLocation RParenLoc, ExprTy *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);
+
+ // FIXME: add more semantic analysis (C99 6.5.2.5).
+ if (CheckInitializerTypes(literalExpr, literalType))
+ return true;
+
+ bool isFileScope = !CurFunctionDecl && !CurMethodDecl;
+ if (isFileScope) { // 6.5.2.5p3
+ if (CheckForConstantInitializer(literalExpr, literalType))
+ return true;
+ }
+ return new CompoundLiteralExpr(LParenLoc, literalType, literalExpr, isFileScope);
+}
+
+Action::ExprResult Sema::
+ActOnInitList(SourceLocation LBraceLoc, ExprTy **initlist, unsigned NumInit,
+ SourceLocation RBraceLoc) {
+ Expr **InitList = reinterpret_cast<Expr**>(initlist);
+
+ // Semantic analysis for initializers is done by ActOnDeclarator() and
+ // CheckInitializer() - it requires knowledge of the object being intialized.
+
+ InitListExpr *e = new InitListExpr(LBraceLoc, InitList, NumInit, RBraceLoc);
+ e->setType(Context.VoidTy); // FIXME: just a place holder for now.
+ return e;
+}
+
+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.getAsString().c_str(),
+ Ty.getAsString().c_str(), R);
+ } else
+ return Diag(R.getBegin(),
+ diag::err_invalid_conversion_between_vector_and_scalar,
+ VectorTy.getAsString().c_str(),
+ Ty.getAsString().c_str(), R);
+
+ return false;
+}
+
+Action::ExprResult Sema::
+ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
+ SourceLocation RParenLoc, ExprTy *Op) {
+ assert((Ty != 0) && (Op != 0) && "ActOnCastExpr(): missing type or expr");
+
+ Expr *castExpr = static_cast<Expr*>(Op);
+ QualType castType = QualType::getFromOpaquePtr(Ty);
+
+ 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.
+ if (!castType->isScalarType() && !castType->isVectorType())
+ return Diag(LParenLoc, diag::err_typecheck_cond_expect_scalar,
+ castType.getAsString(), SourceRange(LParenLoc, RParenLoc));
+ if (!castExpr->getType()->isScalarType() &&
+ !castExpr->getType()->isVectorType())
+ return Diag(castExpr->getLocStart(),
+ diag::err_typecheck_expect_scalar_operand,
+ castExpr->getType().getAsString(),castExpr->getSourceRange());
+
+ if (castExpr->getType()->isVectorType()) {
+ if (CheckVectorCast(SourceRange(LParenLoc, RParenLoc),
+ castExpr->getType(), castType))
+ return true;
+ } else if (castType->isVectorType()) {
+ if (CheckVectorCast(SourceRange(LParenLoc, RParenLoc),
+ castType, castExpr->getType()))
+ return true;
+ }
+ }
+ return new CastExpr(castType, castExpr, LParenLoc);
+}
+
+/// Note that lex is not null here, even if this is the gnu "x ?: y" extension.
+/// In that case, lex = cond.
+inline QualType Sema::CheckConditionalOperands( // C99 6.5.15
+ Expr *&cond, Expr *&lex, Expr *&rex, SourceLocation questionLoc) {
+ UsualUnaryConversions(cond);
+ UsualUnaryConversions(lex);
+ UsualUnaryConversions(rex);
+ QualType condT = cond->getType();
+ QualType lexT = lex->getType();
+ QualType rexT = rex->getType();
+
+ // first, check the condition.
+ if (!condT->isScalarType()) { // C99 6.5.15p2
+ Diag(cond->getLocStart(), diag::err_typecheck_cond_expect_scalar,
+ condT.getAsString());
+ 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 (lexT->isArithmeticType() && rexT->isArithmeticType()) {
+ UsualArithmeticConversions(lex, rex);
+ return lex->getType();
+ }
+
+ // If both operands are the same structure or union type, the result is that
+ // type.
+ if (const RecordType *LHSRT = lexT->getAsRecordType()) { // C99 6.5.15p3
+ if (const RecordType *RHSRT = rexT->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 lexT.getUnqualifiedType();
+ }
+
+ // C99 6.5.15p5: "If both operands have void type, the result has void type."
+ if (lexT->isVoidType() && rexT->isVoidType())
+ return lexT.getUnqualifiedType();
+
+ // C99 6.5.15p6 - "if one operand is a null pointer constant, the result has
+ // the type of the other operand."
+ if (lexT->isPointerType() && rex->isNullPointerConstant(Context)) {
+ ImpCastExprToType(rex, lexT); // promote the null to a pointer.
+ return lexT;
+ }
+ if (rexT->isPointerType() && lex->isNullPointerConstant(Context)) {
+ ImpCastExprToType(lex, rexT); // promote the null to a pointer.
+ return rexT;
+ }
+ // Handle the case where both operands are pointers before we handle null
+ // pointer constants in case both operands are null pointer constants.
+ if (const PointerType *LHSPT = lexT->getAsPointerType()) { // C99 6.5.15p3,6
+ if (const PointerType *RHSPT = rexT->getAsPointerType()) {
+ // get the "pointed to" types
+ QualType lhptee = LHSPT->getPointeeType();
+ QualType rhptee = RHSPT->getPointeeType();
+
+ // ignore qualifiers on void (C99 6.5.15p3, clause 6)
+ if (lhptee->isVoidType() &&
+ (rhptee->isObjectType() || rhptee->isIncompleteType())) {
+ // Figure out necessary qualifiers (C99 6.5.15p6)
+ QualType destPointee=lhptee.getQualifiedType(rhptee.getCVRQualifiers());
+ QualType destType = Context.getPointerType(destPointee);
+ ImpCastExprToType(lex, destType); // add qualifiers if necessary
+ ImpCastExprToType(rex, destType); // promote to void*
+ return destType;
+ }
+ if (rhptee->isVoidType() &&
+ (lhptee->isObjectType() || lhptee->isIncompleteType())) {
+ QualType destPointee=rhptee.getQualifiedType(lhptee.getCVRQualifiers());
+ QualType destType = Context.getPointerType(destPointee);
+ ImpCastExprToType(lex, destType); // add qualifiers if necessary
+ ImpCastExprToType(rex, destType); // promote to void*
+ return destType;
+ }
+
+ if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(),
+ rhptee.getUnqualifiedType())) {
+ Diag(questionLoc, diag::warn_typecheck_cond_incompatible_pointers,
+ lexT.getAsString(), rexT.getAsString(),
+ lex->getSourceRange(), rex->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 voidPtrTy = Context.getPointerType(Context.VoidTy);
+ ImpCastExprToType(lex, voidPtrTy);
+ ImpCastExprToType(rex, voidPtrTy);
+ return voidPtrTy;
+ }
+ // 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 return the composite type.
+ // FIXME: Need to add qualifiers
+ return lexT;
+ }
+ }
+
+ // Otherwise, the operands are not compatible.
+ Diag(questionLoc, diag::err_typecheck_cond_incompatible_operands,
+ lexT.getAsString(), rexT.getAsString(),
+ lex->getSourceRange(), rex->getSourceRange());
+ return QualType();
+}
+
+/// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
+/// in the case of a the GNU conditional expr extension.
+Action::ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
+ SourceLocation ColonLoc,
+ ExprTy *Cond, ExprTy *LHS,
+ ExprTy *RHS) {
+ Expr *CondExpr = (Expr *) Cond;
+ Expr *LHSExpr = (Expr *) LHS, *RHSExpr = (Expr *) RHS;
+
+ // 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 true;
+ return new ConditionalOperator(CondExpr, isLHSNull ? 0 : LHSExpr,
+ RHSExpr, result);
+}
+
+/// 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 (Ty == Context.FloatTy)
+ ImpCastExprToType(Expr, Context.DoubleTy);
+ else
+ UsualUnaryConversions(Expr);
+}
+
+/// DefaultFunctionArrayConversion (C99 6.3.2.1p3, C99 6.3.2.1p4).
+void Sema::DefaultFunctionArrayConversion(Expr *&e) {
+ QualType t = e->getType();
+ assert(!t.isNull() && "DefaultFunctionArrayConversion - missing type");
+
+ if (const ReferenceType *ref = t->getAsReferenceType()) {
+ ImpCastExprToType(e, ref->getReferenceeType()); // C++ [expr]
+ t = e->getType();
+ }
+ if (t->isFunctionType())
+ ImpCastExprToType(e, Context.getPointerType(t));
+ else if (const ArrayType *ary = t->getAsArrayType()) {
+ // Make sure we don't lose qualifiers when dealing with typedefs. Example:
+ // typedef int arr[10];
+ // void test2() {
+ // const arr b;
+ // b[4] = 1;
+ // }
+ QualType ELT = ary->getElementType();
+ // FIXME: Handle ASQualType
+ ELT = ELT.getQualifiedType(t.getCVRQualifiers()|ELT.getCVRQualifiers());
+ ImpCastExprToType(e, Context.getPointerType(ELT));
+ }
+}
+
+/// 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");
+
+ if (const ReferenceType *Ref = Ty->getAsReferenceType()) {
+ ImpCastExprToType(Expr, Ref->getReferenceeType()); // C++ [expr]
+ Ty = Expr->getType();
+ }
+ if (Ty->isPromotableIntegerType()) // C99 6.3.1.1p2
+ ImpCastExprToType(Expr, Context.IntTy);
+ else
+ DefaultFunctionArrayConversion(Expr);
+
+ return Expr;
+}
+
+/// 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 = lhsExpr->getType().getCanonicalType().getUnqualifiedType();
+ QualType rhs = rhsExpr->getType().getCanonicalType().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.
+ if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs);
+ return lhs;
+ }
+ if (lhs->isIntegerType() || lhs->isComplexIntegerType()) {
+ // convert the lhs to the rhs complex type.
+ if (!isCompAssign) ImpCastExprToType(lhsExpr, rhs);
+ 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.compareFloatingType(lhs, rhs);
+
+ if (result > 0) { // The left side is bigger, convert rhs.
+ rhs = Context.getFloatingTypeOfSizeWithinDomain(lhs, rhs);
+ if (!isCompAssign)
+ ImpCastExprToType(rhsExpr, rhs);
+ } else if (result < 0) { // The right side is bigger, convert lhs.
+ lhs = Context.getFloatingTypeOfSizeWithinDomain(rhs, lhs);
+ if (!isCompAssign)
+ ImpCastExprToType(lhsExpr, 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".
+ if (!isCompAssign)
+ ImpCastExprToType(lhsExpr, rhs);
+ return rhs;
+ } else { // handle "_Complex double, double".
+ if (!isCompAssign)
+ ImpCastExprToType(rhsExpr, lhs);
+ 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() || rhs->isComplexIntegerType()) {
+ // convert rhs to the lhs floating point type.
+ if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs);
+ return lhs;
+ }
+ if (lhs->isIntegerType() || lhs->isComplexIntegerType()) {
+ // convert lhs to the rhs floating point type.
+ if (!isCompAssign) ImpCastExprToType(lhsExpr, rhs);
+ return rhs;
+ }
+ // We have two real floating types, float/complex combos were handled above.
+ // Convert the smaller operand to the bigger result.
+ int result = Context.compareFloatingType(lhs, rhs);
+
+ if (result > 0) { // convert the rhs
+ if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs);
+ return lhs;
+ }
+ if (result < 0) { // convert the lhs
+ if (!isCompAssign) ImpCastExprToType(lhsExpr, rhs); // convert the lhs
+ return rhs;
+ }
+ assert(0 && "Sema::UsualArithmeticConversions(): illegal float comparison");
+ }
+ 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.maxIntegerType(lhsComplexInt->getElementType(),
+ rhsComplexInt->getElementType()) == lhs) {
+ // convert the rhs
+ if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs);
+ return lhs;
+ }
+ if (!isCompAssign)
+ ImpCastExprToType(lhsExpr, rhs); // convert the lhs
+ return rhs;
+ } else if (lhsComplexInt && rhs->isIntegerType()) {
+ // convert the rhs to the lhs complex type.
+ if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs);
+ return lhs;
+ } else if (rhsComplexInt && lhs->isIntegerType()) {
+ // convert the lhs to the rhs complex type.
+ if (!isCompAssign) ImpCastExprToType(lhsExpr, rhs);
+ return rhs;
+ }
+ }
+ // Finally, we have two differing integer types.
+ if (Context.maxIntegerType(lhs, rhs) == lhs) { // convert the rhs
+ if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs);
+ return lhs;
+ }
+ if (!isCompAssign) ImpCastExprToType(lhsExpr, rhs); // convert the lhs
+ return rhs;
+}
+
+// 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 = lhptee.getCanonicalType();
+ rhptee = rhptee.getCanonicalType();
+
+ 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 ASQualType
+ if ((lhptee.getCVRQualifiers() & rhptee.getCVRQualifiers()) !=
+ rhptee.getCVRQualifiers())
+ 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->isObjectType() || rhptee->isIncompleteType())
+ return ConvTy;
+
+ // As an extension, we allow cast to/from void* to function pointer.
+ if (rhptee->isFunctionType())
+ return FunctionVoidPointer;
+ }
+
+ if (rhptee->isVoidType()) {
+ if (lhptee->isObjectType() || lhptee->isIncompleteType())
+ return ConvTy;
+
+ // As an extension, we allow cast to/from void* to function pointer.
+ if (lhptee->isFunctionType())
+ return FunctionVoidPointer;
+ }
+
+ // C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or
+ // unqualified versions of compatible types, ...
+ if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(),
+ rhptee.getUnqualifiedType()))
+ return IncompatiblePointer; // this "trumps" PointerAssignDiscardsQualifiers
+ 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.
+/// Note: the warning above turn into errors when -pedantic-errors is enabled.
+///
+Sema::AssignConvertType
+Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
+ // Get canonical types. We're not formatting these types, just comparing
+ // them.
+ lhsType = lhsType.getCanonicalType();
+ rhsType = rhsType.getCanonicalType();
+
+ if (lhsType.getUnqualifiedType() == rhsType.getUnqualifiedType())
+ return Compatible; // Common case: fast path an exact match.
+
+ if (lhsType->isReferenceType() || rhsType->isReferenceType()) {
+ if (Context.referenceTypesAreCompatible(lhsType, rhsType))
+ return Compatible;
+ return Incompatible;
+ }
+
+ if (lhsType->isObjCQualifiedIdType()
+ || rhsType->isObjCQualifiedIdType()) {
+ if (Context.ObjCQualifiedIdTypesAreCompatible(lhsType, rhsType))
+ return Compatible;
+ return Incompatible;
+ }
+
+ if (lhsType->isVectorType() || rhsType->isVectorType()) {
+ // For OCUVector, allow vector splats; float -> <n x float>
+ if (const OCUVectorType *LV = lhsType->getAsOCUVectorType()) {
+ if (LV->getElementType().getTypePtr() == rhsType.getTypePtr())
+ return Compatible;
+ }
+
+ // If LHS and RHS are both vectors of integer or both vectors of floating
+ // point types, and the total vector length is the same, allow the
+ // conversion. This is a bitcast; no bits are changed but the result type
+ // is different.
+ if (getLangOptions().LaxVectorConversions &&
+ lhsType->isVectorType() && rhsType->isVectorType()) {
+ if ((lhsType->isIntegerType() && rhsType->isIntegerType()) ||
+ (lhsType->isRealFloatingType() && rhsType->isRealFloatingType())) {
+ if (Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType))
+ return Compatible;
+ }
+ }
+ return Incompatible;
+ }
+
+ if (lhsType->isArithmeticType() && rhsType->isArithmeticType())
+ return Compatible;
+
+ if (lhsType->isPointerType()) {
+ if (rhsType->isIntegerType())
+ return IntToPointer;
+
+ if (rhsType->isPointerType())
+ return CheckPointerTypesForAssignment(lhsType, rhsType);
+ return Incompatible;
+ }
+
+ if (rhsType->isPointerType()) {
+ // C99 6.5.16.1p1: the left operand is _Bool and the right is a pointer.
+ if ((lhsType->isIntegerType()) && (lhsType != Context.BoolTy))
+ return PointerToInt;
+
+ if (lhsType->isPointerType())
+ return CheckPointerTypesForAssignment(lhsType, rhsType);
+ return Incompatible;
+ }
+
+ if (isa<TagType>(lhsType) && isa<TagType>(rhsType)) {
+ if (Context.tagTypesAreCompatible(lhsType, rhsType))
+ return Compatible;
+ }
+ return Incompatible;
+}
+
+Sema::AssignConvertType
+Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
+ // C99 6.5.16.1p1: the left operand is a pointer and the right is
+ // a null pointer constant.
+ if ((lhsType->isPointerType() || lhsType->isObjCQualifiedIdType())
+ && 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: C99 8.5.3p5. FIXME: revisit when references
+ // are better understood.
+ 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.
+ if (rExpr->getType() != lhsType)
+ ImpCastExprToType(rExpr, lhsType);
+ return result;
+}
+
+Sema::AssignConvertType
+Sema::CheckCompoundAssignmentConstraints(QualType lhsType, QualType rhsType) {
+ return CheckAssignmentConstraints(lhsType, rhsType);
+}
+
+QualType Sema::InvalidOperands(SourceLocation loc, Expr *&lex, Expr *&rex) {
+ Diag(loc, diag::err_typecheck_invalid_operands,
+ lex->getType().getAsString(), rex->getType().getAsString(),
+ lex->getSourceRange(), rex->getSourceRange());
+ return QualType();
+}
+
+inline QualType Sema::CheckVectorOperands(SourceLocation loc, Expr *&lex,
+ Expr *&rex) {
+ QualType lhsType = lex->getType(), rhsType = rex->getType();
+
+ // make sure the vector types are identical.
+ if (lhsType == rhsType)
+ return lhsType;
+
+ // if the lhs is an ocu vector and the rhs is a scalar of the same type,
+ // promote the rhs to the vector type.
+ if (const OCUVectorType *V = lhsType->getAsOCUVectorType()) {
+ if (V->getElementType().getCanonicalType().getTypePtr()
+ == rhsType.getCanonicalType().getTypePtr()) {
+ ImpCastExprToType(rex, lhsType);
+ return lhsType;
+ }
+ }
+
+ // if the rhs is an ocu vector and the lhs is a scalar of the same type,
+ // promote the lhs to the vector type.
+ if (const OCUVectorType *V = rhsType->getAsOCUVectorType()) {
+ if (V->getElementType().getCanonicalType().getTypePtr()
+ == lhsType.getCanonicalType().getTypePtr()) {
+ ImpCastExprToType(lex, rhsType);
+ return rhsType;
+ }
+ }
+
+ // You cannot convert between vector values of different size.
+ Diag(loc, diag::err_typecheck_vector_not_convertable,
+ lex->getType().getAsString(), rex->getType().getAsString(),
+ lex->getSourceRange(), rex->getSourceRange());
+ return QualType();
+}
+
+inline QualType Sema::CheckMultiplyDivideOperands(
+ Expr *&lex, Expr *&rex, SourceLocation loc, bool isCompAssign)
+{
+ QualType lhsType = lex->getType(), rhsType = rex->getType();
+
+ if (lhsType->isVectorType() || rhsType->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)
+{
+ QualType lhsType = lex->getType(), rhsType = rex->getType();
+
+ 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, bool isCompAssign)
+{
+ if (lex->getType()->isVectorType() || rex->getType()->isVectorType())
+ return CheckVectorOperands(loc, lex, rex);
+
+ QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign);
+
+ // handle the common case first (both operands are arithmetic).
+ if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType())
+ return compType;
+
+ if (lex->getType()->isPointerType() && rex->getType()->isIntegerType())
+ return lex->getType();
+ if (lex->getType()->isIntegerType() && rex->getType()->isPointerType())
+ return rex->getType();
+ return InvalidOperands(loc, lex, rex);
+}
+
+inline QualType Sema::CheckSubtractionOperands( // C99 6.5.6
+ 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);
+
+ // Enforce type constraints: C99 6.5.6p3.
+
+ // Handle the common case first (both operands are arithmetic).
+ if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType())
+ return compType;
+
+ // Either ptr - int or ptr - ptr.
+ if (const PointerType *LHSPTy = lex->getType()->getAsPointerType()) {
+ QualType lpointee = LHSPTy->getPointeeType();
+
+ // The LHS must be an object type, not incomplete, function, etc.
+ if (!lpointee->isObjectType()) {
+ // Handle the GNU void* extension.
+ if (lpointee->isVoidType()) {
+ Diag(loc, diag::ext_gnu_void_ptr,
+ lex->getSourceRange(), rex->getSourceRange());
+ } else {
+ Diag(loc, diag::err_typecheck_sub_ptr_object,
+ lex->getType().getAsString(), lex->getSourceRange());
+ return QualType();
+ }
+ }
+
+ // The result type of a pointer-int computation is the pointer type.
+ if (rex->getType()->isIntegerType())
+ return lex->getType();
+
+ // Handle pointer-pointer subtractions.
+ if (const PointerType *RHSPTy = rex->getType()->getAsPointerType()) {
+ QualType rpointee = RHSPTy->getPointeeType();
+
+ // RHS must be an object type, unless void (GNU).
+ if (!rpointee->isObjectType()) {
+ // Handle the GNU void* extension.
+ if (rpointee->isVoidType()) {
+ if (!lpointee->isVoidType())
+ Diag(loc, diag::ext_gnu_void_ptr,
+ lex->getSourceRange(), rex->getSourceRange());
+ } else {
+ Diag(loc, diag::err_typecheck_sub_ptr_object,
+ rex->getType().getAsString(), rex->getSourceRange());
+ return QualType();
+ }
+ }
+
+ // Pointee types must be compatible.
+ if (!Context.typesAreCompatible(lpointee.getUnqualifiedType(),
+ rpointee.getUnqualifiedType())) {
+ Diag(loc, diag::err_typecheck_sub_ptr_compatible,
+ lex->getType().getAsString(), rex->getType().getAsString(),
+ lex->getSourceRange(), rex->getSourceRange());
+ return QualType();
+ }
+
+ return Context.getPointerDiffType();
+ }
+ }
+
+ return InvalidOperands(loc, lex, rex);
+}
+
+inline QualType Sema::CheckShiftOperands( // C99 6.5.7
+ 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
+ if (!isCompAssign)
+ UsualUnaryConversions(lex);
+ UsualUnaryConversions(rex);
+
+ // "The type of the result is that of the promoted left operand."
+ return lex->getType();
+}
+
+inline QualType Sema::CheckCompareOperands( // C99 6.5.8
+ Expr *&lex, Expr *&rex, SourceLocation loc, bool 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();
+
+ // 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);
+ }
+
+ if (isRelational) {
+ if (lType->isRealType() && rType->isRealType())
+ return Context.IntTy;
+ } 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 Context.IntTy;
+ }
+
+ 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 lpointee = lType->getAsPointerType()->getPointeeType();
+ QualType rpointee = rType->getAsPointerType()->getPointeeType();
+
+ if (!LHSIsNull && !RHSIsNull && // C99 6.5.9p2
+ !lpointee->isVoidType() && !lpointee->isVoidType() &&
+ !Context.typesAreCompatible(lpointee.getUnqualifiedType(),
+ rpointee.getUnqualifiedType())) {
+ Diag(loc, diag::ext_typecheck_comparison_of_distinct_pointers,
+ lType.getAsString(), rType.getAsString(),
+ lex->getSourceRange(), rex->getSourceRange());
+ }
+ ImpCastExprToType(rex, lType); // promote the pointer to pointer
+ return Context.IntTy;
+ }
+ if ((lType->isObjCQualifiedIdType() || rType->isObjCQualifiedIdType())
+ && Context.ObjCQualifiedIdTypesAreCompatible(lType, rType, true)) {
+ ImpCastExprToType(rex, lType);
+ return Context.IntTy;
+ }
+ if (lType->isPointerType() && rType->isIntegerType()) {
+ if (!RHSIsNull)
+ Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer,
+ lType.getAsString(), rType.getAsString(),
+ lex->getSourceRange(), rex->getSourceRange());
+ ImpCastExprToType(rex, lType); // promote the integer to pointer
+ return Context.IntTy;
+ }
+ if (lType->isIntegerType() && rType->isPointerType()) {
+ if (!LHSIsNull)
+ Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer,
+ lType.getAsString(), rType.getAsString(),
+ lex->getSourceRange(), rex->getSourceRange());
+ ImpCastExprToType(lex, rType); // promote the integer to pointer
+ return Context.IntTy;
+ }
+ return InvalidOperands(loc, lex, rex);
+}
+
+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);
+}
+
+inline QualType Sema::CheckAssignmentOperands( // C99 6.5.16.1
+ Expr *lex, Expr *&rex, SourceLocation loc, QualType compoundType)
+{
+ QualType lhsType = lex->getType();
+ QualType rhsType = compoundType.isNull() ? rex->getType() : compoundType;
+ Expr::isModifiableLvalueResult mlval = lex->isModifiableLvalue();
+
+ switch (mlval) { // C99 6.5.16p2
+ case Expr::MLV_Valid:
+ break;
+ case Expr::MLV_ConstQualified:
+ Diag(loc, diag::err_typecheck_assign_const, lex->getSourceRange());
+ return QualType();
+ case Expr::MLV_ArrayType:
+ Diag(loc, diag::err_typecheck_array_not_modifiable_lvalue,
+ lhsType.getAsString(), lex->getSourceRange());
+ return QualType();
+ case Expr::MLV_NotObjectType:
+ Diag(loc, diag::err_typecheck_non_object_not_modifiable_lvalue,
+ lhsType.getAsString(), lex->getSourceRange());
+ return QualType();
+ case Expr::MLV_InvalidExpression:
+ Diag(loc, diag::err_typecheck_expression_not_modifiable_lvalue,
+ lex->getSourceRange());
+ return QualType();
+ case Expr::MLV_IncompleteType:
+ case Expr::MLV_IncompleteVoidType:
+ Diag(loc, diag::err_typecheck_incomplete_type_not_modifiable_lvalue,
+ lhsType.getAsString(), lex->getSourceRange());
+ return QualType();
+ case Expr::MLV_DuplicateVectorComponents:
+ Diag(loc, diag::err_typecheck_duplicate_vector_components_not_mlvalue,
+ lex->getSourceRange());
+ return QualType();
+ }
+
+ AssignConvertType ConvTy;
+ if (compoundType.isNull())
+ ConvTy = CheckSingleAssignmentConstraints(lhsType, rex);
+ else
+ ConvTy = CheckCompoundAssignmentConstraints(lhsType, rhsType);
+
+ if (DiagnoseAssignmentResult(ConvTy, loc, lhsType, rhsType,
+ rex, "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
+ // oprdu.
+ return lhsType.getUnqualifiedType();
+}
+
+inline QualType Sema::CheckCommaOperands( // C99 6.5.17
+ Expr *&lex, Expr *&rex, SourceLocation loc) {
+ UsualUnaryConversions(rex);
+ return rex->getType();
+}
+
+/// CheckIncrementDecrementOperand - unlike most "Check" methods, this routine
+/// doesn't need to call UsualUnaryConversions or UsualArithmeticConversions.
+QualType Sema::CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc) {
+ QualType resType = op->getType();
+ assert(!resType.isNull() && "no type for increment/decrement expression");
+
+ // C99 6.5.2.4p1: We allow complex as a GCC extension.
+ if (const PointerType *pt = resType->getAsPointerType()) {
+ if (!pt->getPointeeType()->isObjectType()) { // C99 6.5.2.4p2, 6.5.6p2
+ Diag(OpLoc, diag::err_typecheck_arithmetic_incomplete_type,
+ resType.getAsString(), op->getSourceRange());
+ return QualType();
+ }
+ } else if (!resType->isRealType()) {
+ if (resType->isComplexType())
+ // C99 does not support ++/-- on complex types.
+ Diag(OpLoc, diag::ext_integer_increment_complex,
+ resType.getAsString(), op->getSourceRange());
+ else {
+ Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement,
+ resType.getAsString(), 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.
+ Expr::isModifiableLvalueResult mlval = op->isModifiableLvalue();
+ if (mlval != Expr::MLV_Valid) {
+ // FIXME: emit a more precise diagnostic...
+ Diag(OpLoc, diag::err_typecheck_invalid_lvalue_incr_decr,
+ op->getSourceRange());
+ 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. Here are some
+/// examples: &s.xx, &s.zz[1].yy, &(1+2), &(XX), &"123"[2].
+static ValueDecl *getPrimaryDecl(Expr *e) {
+ switch (e->getStmtClass()) {
+ case Stmt::DeclRefExprClass:
+ return cast<DeclRefExpr>(e)->getDecl();
+ case Stmt::MemberExprClass:
+ // Fields cannot be declared with a 'register' storage class.
+ // &X->f is always ok, even if X is declared register.
+ if (cast<MemberExpr>(e)->isArrow())
+ return 0;
+ return getPrimaryDecl(cast<MemberExpr>(e)->getBase());
+ case Stmt::ArraySubscriptExprClass: {
+ // &X[4] and &4[X] is invalid if X is invalid and X is not a pointer.
+
+ ValueDecl *VD = getPrimaryDecl(cast<ArraySubscriptExpr>(e)->getBase());
+ if (!VD || VD->getType()->isPointerType())
+ return 0;
+ else
+ return VD;
+ }
+ case Stmt::UnaryOperatorClass:
+ return getPrimaryDecl(cast<UnaryOperator>(e)->getSubExpr());
+ case Stmt::ParenExprClass:
+ return getPrimaryDecl(cast<ParenExpr>(e)->getSubExpr());
+ case Stmt::ImplicitCastExprClass:
+ // &X[4] when X is an array, has an implicit cast from array to pointer.
+ 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.
+QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
+ 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.
+ }
+ ValueDecl *dcl = getPrimaryDecl(op);
+ Expr::isLvalueResult lval = op->isLvalue();
+
+ if (lval != Expr::LV_Valid) { // C99 6.5.3.2p1
+ if (!dcl || !isa<FunctionDecl>(dcl)) {// allow function designators
+ // FIXME: emit more specific diag...
+ Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof,
+ op->getSourceRange());
+ return QualType();
+ }
+ } else if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(op)) { // C99 6.5.3.2p1
+ if (MemExpr->getMemberDecl()->isBitField()) {
+ Diag(OpLoc, diag::err_typecheck_address_of,
+ std::string("bit-field"), op->getSourceRange());
+ return QualType();
+ }
+ // Check for Apple extension for accessing vector components.
+ } else if (isa<ArraySubscriptExpr>(op) &&
+ cast<ArraySubscriptExpr>(op)->getBase()->getType()->isVectorType()) {
+ Diag(OpLoc, diag::err_typecheck_address_of,
+ std::string("vector"), 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,
+ std::string("register variable"), op->getSourceRange());
+ return QualType();
+ }
+ } else
+ assert(0 && "Unknown/unexpected decl type");
+ }
+ // 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) {
+ UsualUnaryConversions(op);
+ QualType qType = op->getType();
+
+ if (const PointerType *PT = qType->getAsPointerType()) {
+ // 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.
+ return PT->getPointeeType();
+ }
+ Diag(OpLoc, diag::err_typecheck_indirection_requires_pointer,
+ qType.getAsString(), op->getSourceRange());
+ return QualType();
+}
+
+static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode(
+ tok::TokenKind Kind) {
+ BinaryOperator::Opcode Opc;
+ switch (Kind) {
+ default: assert(0 && "Unknown binop!");
+ 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_sizeof: Opc = UnaryOperator::SizeOf; break;
+ case tok::kw___alignof: Opc = UnaryOperator::AlignOf; 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;
+}
+
+// Binary Operators. 'Tok' is the token for the operator.
+Action::ExprResult Sema::ActOnBinOp(SourceLocation TokLoc, tok::TokenKind Kind,
+ ExprTy *LHS, ExprTy *RHS) {
+ BinaryOperator::Opcode Opc = ConvertTokenKindToBinaryOpcode(Kind);
+ Expr *lhs = (Expr *)LHS, *rhs = (Expr*)RHS;
+
+ assert((lhs != 0) && "ActOnBinOp(): missing left expression");
+ assert((rhs != 0) && "ActOnBinOp(): missing right expression");
+
+ QualType ResultTy; // Result type of the binary operator.
+ QualType CompTy; // Computation type for compound assignments (e.g. '+=')
+
+ switch (Opc) {
+ default:
+ assert(0 && "Unknown binary expr!");
+ case BinaryOperator::Assign:
+ ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, QualType());
+ break;
+ case BinaryOperator::Mul:
+ case BinaryOperator::Div:
+ ResultTy = CheckMultiplyDivideOperands(lhs, rhs, TokLoc);
+ break;
+ case BinaryOperator::Rem:
+ ResultTy = CheckRemainderOperands(lhs, rhs, TokLoc);
+ break;
+ case BinaryOperator::Add:
+ ResultTy = CheckAdditionOperands(lhs, rhs, TokLoc);
+ break;
+ case BinaryOperator::Sub:
+ ResultTy = CheckSubtractionOperands(lhs, rhs, TokLoc);
+ break;
+ case BinaryOperator::Shl:
+ case BinaryOperator::Shr:
+ ResultTy = CheckShiftOperands(lhs, rhs, TokLoc);
+ break;
+ case BinaryOperator::LE:
+ case BinaryOperator::LT:
+ case BinaryOperator::GE:
+ case BinaryOperator::GT:
+ ResultTy = CheckCompareOperands(lhs, rhs, TokLoc, true);
+ break;
+ case BinaryOperator::EQ:
+ case BinaryOperator::NE:
+ ResultTy = CheckCompareOperands(lhs, rhs, TokLoc, false);
+ break;
+ case BinaryOperator::And:
+ case BinaryOperator::Xor:
+ case BinaryOperator::Or:
+ ResultTy = CheckBitwiseOperands(lhs, rhs, TokLoc);
+ break;
+ case BinaryOperator::LAnd:
+ case BinaryOperator::LOr:
+ ResultTy = CheckLogicalOperands(lhs, rhs, TokLoc);
+ break;
+ case BinaryOperator::MulAssign:
+ case BinaryOperator::DivAssign:
+ CompTy = CheckMultiplyDivideOperands(lhs, rhs, TokLoc, true);
+ if (!CompTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy);
+ break;
+ case BinaryOperator::RemAssign:
+ CompTy = CheckRemainderOperands(lhs, rhs, TokLoc, true);
+ if (!CompTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy);
+ break;
+ case BinaryOperator::AddAssign:
+ CompTy = CheckAdditionOperands(lhs, rhs, TokLoc, true);
+ if (!CompTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy);
+ break;
+ case BinaryOperator::SubAssign:
+ CompTy = CheckSubtractionOperands(lhs, rhs, TokLoc, true);
+ if (!CompTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy);
+ break;
+ case BinaryOperator::ShlAssign:
+ case BinaryOperator::ShrAssign:
+ CompTy = CheckShiftOperands(lhs, rhs, TokLoc, true);
+ if (!CompTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy);
+ break;
+ case BinaryOperator::AndAssign:
+ case BinaryOperator::XorAssign:
+ case BinaryOperator::OrAssign:
+ CompTy = CheckBitwiseOperands(lhs, rhs, TokLoc, true);
+ if (!CompTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy);
+ break;
+ case BinaryOperator::Comma:
+ ResultTy = CheckCommaOperands(lhs, rhs, TokLoc);
+ break;
+ }
+ if (ResultTy.isNull())
+ return true;
+ if (CompTy.isNull())
+ return new BinaryOperator(lhs, rhs, Opc, ResultTy, TokLoc);
+ else
+ return new CompoundAssignOperator(lhs, rhs, Opc, ResultTy, CompTy, TokLoc);
+}
+
+// Unary Operators. 'Tok' is the token for the operator.
+Action::ExprResult Sema::ActOnUnaryOp(SourceLocation OpLoc, tok::TokenKind Op,
+ ExprTy *input) {
+ Expr *Input = (Expr*)input;
+ UnaryOperator::Opcode Opc = ConvertTokenKindToUnaryOpcode(Op);
+ QualType resultType;
+ switch (Opc) {
+ default:
+ assert(0 && "Unimplemented unary expr!");
+ case UnaryOperator::PreInc:
+ case UnaryOperator::PreDec:
+ resultType = CheckIncrementDecrementOperand(Input, OpLoc);
+ 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->isArithmeticType()) // C99 6.5.3.3p1
+ return Diag(OpLoc, diag::err_typecheck_unary_expr,
+ resultType.getAsString());
+ break;
+ case UnaryOperator::Not: // bitwise complement
+ UsualUnaryConversions(Input);
+ resultType = Input->getType();
+ // C99 6.5.3.3p1. We allow complex as a GCC extension.
+ if (!resultType->isIntegerType()) {
+ if (resultType->isComplexType())
+ // C99 does not support '~' for complex conjugation.
+ Diag(OpLoc, diag::ext_integer_complement_complex,
+ resultType.getAsString());
+ else
+ return Diag(OpLoc, diag::err_typecheck_unary_expr,
+ resultType.getAsString());
+ }
+ 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->isScalarType()) // C99 6.5.3.3p1
+ return Diag(OpLoc, diag::err_typecheck_unary_expr,
+ resultType.getAsString());
+ // LNot always has type int. C99 6.5.3.3p5.
+ resultType = Context.IntTy;
+ break;
+ case UnaryOperator::SizeOf:
+ resultType = CheckSizeOfAlignOfOperand(Input->getType(), OpLoc, true);
+ break;
+ case UnaryOperator::AlignOf:
+ resultType = CheckSizeOfAlignOfOperand(Input->getType(), OpLoc, false);
+ break;
+ case UnaryOperator::Real:
+ case UnaryOperator::Imag:
+ resultType = CheckRealImagOperand(Input, OpLoc);
+ break;
+ case UnaryOperator::Extension:
+ resultType = Input->getType();
+ break;
+ }
+ if (resultType.isNull())
+ return true;
+ return new UnaryOperator(Input, Opc, resultType, OpLoc);
+}
+
+/// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo".
+Sema::ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc,
+ SourceLocation LabLoc,
+ IdentifierInfo *LabelII) {
+ // Look up the record for this label identifier.
+ LabelStmt *&LabelDecl = LabelMap[LabelII];
+
+ // If we haven't seen this label yet, create a forward reference.
+ if (LabelDecl == 0)
+ LabelDecl = new LabelStmt(LabLoc, LabelII, 0);
+
+ // Create the AST node. The address of a label always has type 'void*'.
+ return new AddrLabelExpr(OpLoc, LabLoc, LabelDecl,
+ Context.getPointerType(Context.VoidTy));
+}
+
+Sema::ExprResult Sema::ActOnStmtExpr(SourceLocation LPLoc, StmtTy *substmt,
+ SourceLocation RPLoc) { // "({..})"
+ Stmt *SubStmt = static_cast<Stmt*>(substmt);
+ assert(SubStmt && isa<CompoundStmt>(SubStmt) && "Invalid action invocation!");
+ CompoundStmt *Compound = cast<CompoundStmt>(SubStmt);
+
+ // 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.
+
+ // FIXME: the last statement in the compount stmt has its value used. We
+ // should not warn about it being unused.
+
+ // 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())
+ if (Expr *LastExpr = dyn_cast<Expr>(Compound->body_back()))
+ Ty = LastExpr->getType();
+
+ return new StmtExpr(Compound, Ty, LPLoc, RPLoc);
+}
+
+Sema::ExprResult Sema::ActOnBuiltinOffsetOf(SourceLocation BuiltinLoc,
+ SourceLocation TypeLoc,
+ TypeTy *argty,
+ OffsetOfComponent *CompPtr,
+ unsigned NumComponents,
+ SourceLocation RPLoc) {
+ QualType ArgTy = QualType::getFromOpaquePtr(argty);
+ assert(!ArgTy.isNull() && "Missing type argument!");
+
+ // 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 (!ArgTy->isRecordType())
+ return Diag(TypeLoc, diag::err_offsetof_record_type,ArgTy.getAsString());
+
+ // Otherwise, create a compound literal expression as the base, and
+ // iteratively process the offsetof designators.
+ Expr *Res = new CompoundLiteralExpr(SourceLocation(), ArgTy, 0, false);
+
+ // offsetof with non-identifier designators (e.g. "offsetof(x, a.b[c])") are a
+ // GCC extension, diagnose them.
+ if (NumComponents != 1)
+ Diag(BuiltinLoc, diag::ext_offsetof_extended_field_designator,
+ SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd));
+
+ 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 = Res->getType()->getAsArrayType();
+ if (!AT) {
+ delete Res;
+ return Diag(OC.LocEnd, diag::err_offsetof_array_type,
+ Res->getType().getAsString());
+ }
+
+ // FIXME: C++: Verify that operator[] isn't overloaded.
+
+ // C99 6.5.2.1p1
+ Expr *Idx = static_cast<Expr*>(OC.U.E);
+ if (!Idx->getType()->isIntegerType())
+ return Diag(Idx->getLocStart(), diag::err_typecheck_subscript,
+ Idx->getSourceRange());
+
+ Res = new ArraySubscriptExpr(Res, Idx, AT->getElementType(), OC.LocEnd);
+ continue;
+ }
+
+ const RecordType *RC = Res->getType()->getAsRecordType();
+ if (!RC) {
+ delete Res;
+ return Diag(OC.LocEnd, diag::err_offsetof_record_type,
+ Res->getType().getAsString());
+ }
+
+ // Get the decl corresponding to this.
+ RecordDecl *RD = RC->getDecl();
+ FieldDecl *MemberDecl = RD->getMember(OC.U.IdentInfo);
+ if (!MemberDecl)
+ return Diag(BuiltinLoc, diag::err_typecheck_no_member,
+ OC.U.IdentInfo->getName(),
+ SourceRange(OC.LocStart, OC.LocEnd));
+
+ // FIXME: C++: Verify that MemberDecl isn't a static field.
+ // FIXME: Verify that MemberDecl isn't a bitfield.
+ // MemberDecl->getType() doesn't get the right qualifiers, but it doesn't
+ // matter here.
+ Res = new MemberExpr(Res, false, MemberDecl, OC.LocEnd, MemberDecl->getType());
+ }
+
+ return new UnaryOperator(Res, UnaryOperator::OffsetOf, Context.getSizeType(),
+ BuiltinLoc);
+}
+
+
+Sema::ExprResult 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)");
+
+ return new TypesCompatibleExpr(Context.IntTy, BuiltinLoc, argT1, argT2,RPLoc);
+}
+
+Sema::ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, ExprTy *cond,
+ ExprTy *expr1, ExprTy *expr2,
+ SourceLocation RPLoc) {
+ Expr *CondExpr = static_cast<Expr*>(cond);
+ Expr *LHSExpr = static_cast<Expr*>(expr1);
+ Expr *RHSExpr = static_cast<Expr*>(expr2);
+
+ assert((CondExpr && LHSExpr && RHSExpr) && "Missing type argument(s)");
+
+ // The conditional expression is required to be a constant expression.
+ llvm::APSInt condEval(32);
+ SourceLocation ExpLoc;
+ if (!CondExpr->isIntegerConstantExpr(condEval, Context, &ExpLoc))
+ return 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.
+ QualType resType = condEval.getZExtValue() ? LHSExpr->getType() :
+ RHSExpr->getType();
+ return new ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr, resType, RPLoc);
+}
+
+/// ExprsMatchFnType - return true if the Exprs in array Args have
+/// QualTypes that match the QualTypes of the arguments of the FnType.
+/// The number of arguments has already been validated to match the number of
+/// arguments in FnType.
+static bool ExprsMatchFnType(Expr **Args, const FunctionTypeProto *FnType) {
+ unsigned NumParams = FnType->getNumArgs();
+ for (unsigned i = 0; i != NumParams; ++i)
+ if (Args[i]->getType().getCanonicalType() !=
+ FnType->getArgType(i).getCanonicalType())
+ return false;
+ return true;
+}
+
+Sema::ExprResult Sema::ActOnOverloadExpr(ExprTy **args, unsigned NumArgs,
+ SourceLocation *CommaLocs,
+ SourceLocation BuiltinLoc,
+ SourceLocation RParenLoc) {
+ // __builtin_overload requires at least 2 arguments
+ if (NumArgs < 2)
+ return Diag(RParenLoc, diag::err_typecheck_call_too_few_args,
+ SourceRange(BuiltinLoc, RParenLoc));
+
+ // The first argument is required to be a constant expression. It tells us
+ // the number of arguments to pass to each of the functions to be overloaded.
+ Expr **Args = reinterpret_cast<Expr**>(args);
+ Expr *NParamsExpr = Args[0];
+ llvm::APSInt constEval(32);
+ SourceLocation ExpLoc;
+ if (!NParamsExpr->isIntegerConstantExpr(constEval, Context, &ExpLoc))
+ return Diag(ExpLoc, diag::err_overload_expr_requires_non_zero_constant,
+ NParamsExpr->getSourceRange());
+
+ // Verify that the number of parameters is > 0
+ unsigned NumParams = constEval.getZExtValue();
+ if (NumParams == 0)
+ return Diag(ExpLoc, diag::err_overload_expr_requires_non_zero_constant,
+ NParamsExpr->getSourceRange());
+ // Verify that we have at least 1 + NumParams arguments to the builtin.
+ if ((NumParams + 1) > NumArgs)
+ return Diag(RParenLoc, diag::err_typecheck_call_too_few_args,
+ SourceRange(BuiltinLoc, RParenLoc));
+
+ // Figure out the return type, by matching the args to one of the functions
+ // listed after the parameters.
+ OverloadExpr *OE = 0;
+ for (unsigned i = NumParams + 1; i < NumArgs; ++i) {
+ // UsualUnaryConversions will convert the function DeclRefExpr into a
+ // pointer to function.
+ Expr *Fn = UsualUnaryConversions(Args[i]);
+ FunctionTypeProto *FnType = 0;
+ if (const PointerType *PT = Fn->getType()->getAsPointerType()) {
+ QualType PointeeType = PT->getPointeeType().getCanonicalType();
+ FnType = dyn_cast<FunctionTypeProto>(PointeeType);
+ }
+
+ // The Expr type must be FunctionTypeProto, since FunctionTypeProto has no
+ // parameters, and the number of parameters must match the value passed to
+ // the builtin.
+ if (!FnType || (FnType->getNumArgs() != NumParams))
+ return Diag(Fn->getExprLoc(), diag::err_overload_incorrect_fntype,
+ Fn->getSourceRange());
+
+ // Scan the parameter list for the FunctionType, checking the QualType of
+ // each parameter against the QualTypes of the arguments to the builtin.
+ // If they match, return a new OverloadExpr.
+ if (ExprsMatchFnType(Args+1, FnType)) {
+ if (OE)
+ return Diag(Fn->getExprLoc(), diag::err_overload_multiple_match,
+ OE->getFn()->getSourceRange());
+ // Remember our match, and continue processing the remaining arguments
+ // to catch any errors.
+ OE = new OverloadExpr(Args, NumArgs, i, FnType->getResultType(),
+ BuiltinLoc, RParenLoc);
+ }
+ }
+ // Return the newly created OverloadExpr node, if we succeded in matching
+ // exactly one of the candidate functions.
+ if (OE)
+ return OE;
+
+ // If we didn't find a matching function Expr in the __builtin_overload list
+ // the return an error.
+ std::string typeNames;
+ for (unsigned i = 0; i != NumParams; ++i) {
+ if (i != 0) typeNames += ", ";
+ typeNames += Args[i+1]->getType().getAsString();
+ }
+
+ return Diag(BuiltinLoc, diag::err_overload_no_match, typeNames,
+ SourceRange(BuiltinLoc, RParenLoc));
+}
+
+Sema::ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc,
+ ExprTy *expr, TypeTy *type,
+ SourceLocation RPLoc) {
+ Expr *E = static_cast<Expr*>(expr);
+ QualType T = QualType::getFromOpaquePtr(type);
+
+ InitBuiltinVaListType();
+
+ if (CheckAssignmentConstraints(Context.getBuiltinVaListType(), E->getType())
+ != Compatible)
+ return Diag(E->getLocStart(),
+ diag::err_first_argument_to_va_arg_not_of_type_va_list,
+ E->getType().getAsString(),
+ E->getSourceRange());
+
+ // FIXME: Warn if a non-POD type is passed in.
+
+ return new VAArgExpr(BuiltinLoc, E, T, RPLoc);
+}
+
+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 FunctionVoidPointer:
+ DiagKind = diag::ext_typecheck_convert_pointer_void_func;
+ break;
+ case CompatiblePointerDiscardsQualifiers:
+ DiagKind = diag::ext_typecheck_convert_discards_qualifiers;
+ break;
+ case Incompatible:
+ DiagKind = diag::err_typecheck_convert_incompatible;
+ isInvalid = true;
+ break;
+ }
+
+ Diag(Loc, DiagKind, DstType.getAsString(), SrcType.getAsString(), Flavor,
+ SrcExpr->getSourceRange());
+ return isInvalid;
+}
+
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
new file mode 100644
index 00000000000..e49a43c4728
--- /dev/null
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -0,0 +1,51 @@
+//===--- 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 "Sema.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ASTContext.h"
+using namespace clang;
+
+/// ActOnCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's.
+Action::ExprResult
+Sema::ActOnCXXCasts(SourceLocation OpLoc, tok::TokenKind Kind,
+ SourceLocation LAngleBracketLoc, TypeTy *Ty,
+ SourceLocation RAngleBracketLoc,
+ SourceLocation LParenLoc, ExprTy *E,
+ SourceLocation RParenLoc) {
+ CXXCastExpr::Opcode Op;
+
+ switch (Kind) {
+ default: assert(0 && "Unknown C++ cast!");
+ case tok::kw_const_cast: Op = CXXCastExpr::ConstCast; break;
+ case tok::kw_dynamic_cast: Op = CXXCastExpr::DynamicCast; break;
+ case tok::kw_reinterpret_cast: Op = CXXCastExpr::ReinterpretCast; break;
+ case tok::kw_static_cast: Op = CXXCastExpr::StaticCast; break;
+ }
+
+ return new CXXCastExpr(Op, QualType::getFromOpaquePtr(Ty), (Expr*)E, OpLoc);
+}
+
+/// ActOnCXXBoolLiteral - Parse {true,false} literals.
+Action::ExprResult
+Sema::ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) {
+ assert((Kind != tok::kw_true || Kind != tok::kw_false) &&
+ "Unknown C++ Boolean value!");
+ return new CXXBoolLiteralExpr(Kind == tok::kw_true, Context.BoolTy, OpLoc);
+}
+
+/// ActOnCXXThrow - Parse throw expressions.
+Action::ExprResult
+Sema::ActOnCXXThrow(SourceLocation OpLoc, ExprTy *E) {
+ return new CXXThrowExpr((Expr*)E, Context.VoidTy, OpLoc);
+}
diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp
new file mode 100644
index 00000000000..4cf435c3315
--- /dev/null
+++ b/clang/lib/Sema/SemaExprObjC.cpp
@@ -0,0 +1,297 @@
+//===--- 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/Expr.h"
+using namespace clang;
+
+Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
+ ExprTy **Strings,
+ unsigned NumStrings) {
+ SourceLocation AtLoc = AtLocs[0];
+ StringLiteral* S = static_cast<StringLiteral *>(Strings[0]);
+ if (NumStrings > 1) {
+ // Concatenate objc strings.
+ StringLiteral* ES = static_cast<StringLiteral *>(Strings[NumStrings-1]);
+ SourceLocation EndLoc = ES->getSourceRange().getEnd();
+ unsigned Length = 0;
+ for (unsigned i = 0; i < NumStrings; i++)
+ Length += static_cast<StringLiteral *>(Strings[i])->getByteLength();
+ char *strBuf = new char [Length];
+ char *p = strBuf;
+ bool isWide = false;
+ for (unsigned i = 0; i < NumStrings; i++) {
+ S = static_cast<StringLiteral *>(Strings[i]);
+ if (S->isWide())
+ isWide = true;
+ memcpy(p, S->getStrData(), S->getByteLength());
+ p += S->getByteLength();
+ delete S;
+ }
+ S = new StringLiteral(strBuf, Length,
+ isWide, Context.getPointerType(Context.CharTy),
+ AtLoc, EndLoc);
+ }
+
+ if (CheckBuiltinCFStringArgument(S))
+ return true;
+
+ if (Context.getObjCConstantStringInterface().isNull()) {
+ // Initialize the constant string interface lazily. This assumes
+ // the NSConstantString interface is seen in this translation unit.
+ IdentifierInfo *NSIdent = &Context.Idents.get("NSConstantString");
+ ScopedDecl *IFace = LookupScopedDecl(NSIdent, Decl::IDNS_Ordinary,
+ SourceLocation(), TUScope);
+ ObjCInterfaceDecl *strIFace = dyn_cast_or_null<ObjCInterfaceDecl>(IFace);
+ if (!strIFace)
+ return Diag(S->getLocStart(), diag::err_undef_interface,
+ NSIdent->getName());
+ Context.setObjCConstantStringInterface(strIFace);
+ }
+ QualType t = Context.getObjCConstantStringInterface();
+ t = Context.getPointerType(t);
+ return new ObjCStringLiteral(S, t, AtLoc);
+}
+
+Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc,
+ SourceLocation EncodeLoc,
+ SourceLocation LParenLoc,
+ TypeTy *Ty,
+ SourceLocation RParenLoc) {
+ QualType EncodedType = QualType::getFromOpaquePtr(Ty);
+
+ QualType t = Context.getPointerType(Context.CharTy);
+ return new ObjCEncodeExpr(t, EncodedType, AtLoc, RParenLoc);
+}
+
+Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
+ SourceLocation AtLoc,
+ SourceLocation SelLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc) {
+ QualType t = Context.getObjCSelType();
+ return new ObjCSelectorExpr(t, Sel, AtLoc, RParenLoc);
+}
+
+Sema::ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId,
+ SourceLocation AtLoc,
+ SourceLocation ProtoLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc) {
+ ObjCProtocolDecl* PDecl = ObjCProtocols[ProtocolId];
+ if (!PDecl) {
+ Diag(ProtoLoc, diag::err_undeclared_protocol, ProtocolId->getName());
+ return true;
+ }
+
+ QualType t = Context.getObjCProtoType();
+ if (t.isNull())
+ return true;
+ t = Context.getPointerType(t);
+ return new ObjCProtocolExpr(t, PDecl, AtLoc, RParenLoc);
+}
+
+bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
+ ObjCMethodDecl *Method) {
+ bool anyIncompatibleArgs = false;
+
+ for (unsigned i = 0; i < NumArgs; i++) {
+ Expr *argExpr = Args[i];
+ assert(argExpr && "CheckMessageArgumentTypes(): missing expression");
+
+ QualType lhsType = Method->getParamDecl(i)->getType();
+ QualType rhsType = argExpr->getType();
+
+ // If necessary, apply function/array conversion. C99 6.7.5.3p[7,8].
+ if (const ArrayType *ary = lhsType->getAsArrayType())
+ lhsType = Context.getPointerType(ary->getElementType());
+ 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.
+
+ anyIncompatibleArgs |=
+ DiagnoseAssignmentResult(Result, argExpr->getLocStart(), lhsType, rhsType,
+ argExpr, "sending");
+ }
+ return anyIncompatibleArgs;
+}
+
+// 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 rbrac, ExprTy **Args, unsigned NumArgs)
+{
+ assert(receiverName && "missing receiver class name");
+
+ Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
+ ObjCInterfaceDecl* ClassDecl = 0;
+ if (!strcmp(receiverName->getName(), "super") && CurMethodDecl) {
+ ClassDecl = CurMethodDecl->getClassInterface()->getSuperClass();
+ if (ClassDecl && CurMethodDecl->isInstance()) {
+ // Synthesize a cast to the super class. This hack allows us to loosely
+ // represent super without creating a special expression node.
+ IdentifierInfo &II = Context.Idents.get("self");
+ ExprResult ReceiverExpr = ActOnIdentifierExpr(S, lbrac, II, false);
+ QualType superTy = Context.getObjCInterfaceType(ClassDecl);
+ superTy = Context.getPointerType(superTy);
+ ReceiverExpr = ActOnCastExpr(SourceLocation(), superTy.getAsOpaquePtr(),
+ SourceLocation(), ReceiverExpr.Val);
+ // We are really in an instance method, redirect.
+ return ActOnInstanceMessage(ReceiverExpr.Val, Sel, lbrac, 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
+ ClassDecl = getObjCInterfaceDecl(receiverName);
+
+ // FIXME: can ClassDecl ever be null?
+ ObjCMethodDecl *Method = ClassDecl->lookupClassMethod(Sel);
+ QualType returnType;
+
+ // Before we give up, check if the selector is an instance method.
+ if (!Method)
+ Method = ClassDecl->lookupInstanceMethod(Sel);
+ if (!Method) {
+ Diag(lbrac, diag::warn_method_not_found, std::string("+"), Sel.getName(),
+ SourceRange(lbrac, rbrac));
+ returnType = Context.getObjCIdType();
+ } else {
+ returnType = Method->getResultType();
+ if (Sel.getNumArgs()) {
+ if (CheckMessageArgumentTypes(ArgExprs, Sel.getNumArgs(), Method))
+ return true;
+ }
+ }
+ return new ObjCMessageExpr(receiverName, 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 rbrac, ExprTy **Args, unsigned NumArgs)
+{
+ assert(receiver && "missing receiver expression");
+
+ Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
+ Expr *RExpr = static_cast<Expr *>(receiver);
+ QualType receiverType = RExpr->getType().getCanonicalType();
+ QualType returnType;
+ ObjCMethodDecl *Method = 0;
+
+ // FIXME: This code is not stripping off type qualifiers! Should it?
+ if (receiverType == Context.getObjCIdType().getCanonicalType() ||
+ receiverType == Context.getObjCClassType().getCanonicalType()) {
+ Method = InstanceMethodPool[Sel].Method;
+ if (!Method)
+ Method = FactoryMethodPool[Sel].Method;
+ if (!Method) {
+ Diag(lbrac, diag::warn_method_not_found, std::string("-"), Sel.getName(),
+ SourceRange(lbrac, rbrac));
+ returnType = Context.getObjCIdType();
+ } else {
+ returnType = Method->getResultType();
+ if (Sel.getNumArgs())
+ if (CheckMessageArgumentTypes(ArgExprs, Sel.getNumArgs(), Method))
+ return true;
+ }
+ } else {
+ bool receiverIsQualId = isa<ObjCQualifiedIdType>(receiverType);
+ // FIXME (snaroff): checking in this code from Patrick. Needs to be
+ // revisited. how do we get the ClassDecl from the receiver expression?
+ if (!receiverIsQualId)
+ while (const PointerType *PTy = receiverType->getAsPointerType())
+ receiverType = PTy->getPointeeType();
+
+ ObjCInterfaceDecl* ClassDecl = 0;
+ if (ObjCQualifiedInterfaceType *QIT =
+ dyn_cast<ObjCQualifiedInterfaceType>(receiverType)) {
+ ClassDecl = QIT->getDecl();
+ Method = ClassDecl->lookupInstanceMethod(Sel);
+ if (!Method) {
+ // search protocols
+ for (unsigned i = 0; i < QIT->getNumProtocols(); i++) {
+ ObjCProtocolDecl *PDecl = QIT->getProtocols(i);
+ if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel)))
+ break;
+ }
+ }
+ if (!Method)
+ Diag(lbrac, diag::warn_method_not_found_in_protocol,
+ std::string("-"), Sel.getName(),
+ SourceRange(lbrac, rbrac));
+ }
+ else if (ObjCQualifiedIdType *QIT =
+ dyn_cast<ObjCQualifiedIdType>(receiverType)) {
+ // search protocols
+ for (unsigned i = 0; i < QIT->getNumProtocols(); i++) {
+ ObjCProtocolDecl *PDecl = QIT->getProtocols(i);
+ if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel)))
+ break;
+ }
+ if (!Method)
+ Diag(lbrac, diag::warn_method_not_found_in_protocol,
+ std::string("-"), Sel.getName(),
+ SourceRange(lbrac, rbrac));
+ }
+ else {
+ ObjCInterfaceType *OCIReceiver =dyn_cast<ObjCInterfaceType>(receiverType);
+ if (OCIReceiver == 0) {
+ Diag(lbrac, diag::error_bad_receiver_type,
+ RExpr->getType().getAsString());
+ return true;
+ }
+ ClassDecl = OCIReceiver->getDecl();
+ // FIXME: consider using InstanceMethodPool, 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(Sel);
+ }
+ if (!Method) {
+ // If we have an implementation in scope, check "private" methods.
+ if (ClassDecl)
+ if (ObjCImplementationDecl *ImpDecl =
+ ObjCImplementations[ClassDecl->getIdentifier()])
+ Method = ImpDecl->getInstanceMethod(Sel);
+ // 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.
+ if (!Method)
+ Method = InstanceMethodPool[Sel].Method;
+ }
+ if (!Method) {
+ Diag(lbrac, diag::warn_method_not_found, std::string("-"), Sel.getName(),
+ SourceRange(lbrac, rbrac));
+ returnType = Context.getObjCIdType();
+ } else {
+ returnType = Method->getResultType();
+ if (Sel.getNumArgs())
+ if (CheckMessageArgumentTypes(ArgExprs, Sel.getNumArgs(), Method))
+ return true;
+ }
+ }
+ return new ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, rbrac,
+ ArgExprs, NumArgs);
+}
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
new file mode 100644
index 00000000000..14b2fdf7d0e
--- /dev/null
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -0,0 +1,821 @@
+//===--- 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/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Stmt.h"
+#include "clang/Parse/Scope.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/ADT/SmallString.h"
+using namespace clang;
+
+Sema::StmtResult Sema::ActOnExprStmt(ExprTy *expr) {
+ Expr *E = static_cast<Expr*>(expr);
+ assert(E && "ActOnExprStmt(): missing expression");
+ return E;
+}
+
+
+Sema::StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc) {
+ return new NullStmt(SemiLoc);
+}
+
+Sema::StmtResult Sema::ActOnDeclStmt(DeclTy *decl, SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ if (decl == 0)
+ return true;
+
+ ScopedDecl *SD = cast<ScopedDecl>(static_cast<Decl *>(decl));
+ return new DeclStmt(SD, StartLoc, EndLoc);
+}
+
+Action::StmtResult
+Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
+ StmtTy **elts, unsigned NumElts, bool isStmtExpr) {
+ Stmt **Elts = reinterpret_cast<Stmt**>(elts);
+ // 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) {
+ ScopedDecl *D = cast<DeclStmt>(Elts[i])->getDecl();
+ 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 (E->hasLocalSideEffect() || E->getType()->isVoidType())
+ continue;
+
+ // The last expr in a stmt expr really is used.
+ if (isStmtExpr && i == NumElts-1)
+ continue;
+
+ /// DiagnoseDeadExpr - This expression is side-effect free and evaluated in
+ /// a context where the result is unused. Emit a diagnostic to warn about
+ /// this.
+ if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E))
+ Diag(BO->getOperatorLoc(), diag::warn_unused_expr,
+ BO->getLHS()->getSourceRange(), BO->getRHS()->getSourceRange());
+ else if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E))
+ Diag(UO->getOperatorLoc(), diag::warn_unused_expr,
+ UO->getSubExpr()->getSourceRange());
+ else
+ Diag(E->getExprLoc(), diag::warn_unused_expr, E->getSourceRange());
+ }
+
+ return new CompoundStmt(Elts, NumElts, L, R);
+}
+
+Action::StmtResult
+Sema::ActOnCaseStmt(SourceLocation CaseLoc, ExprTy *lhsval,
+ SourceLocation DotDotDotLoc, ExprTy *rhsval,
+ SourceLocation ColonLoc, StmtTy *subStmt) {
+ Stmt *SubStmt = static_cast<Stmt*>(subStmt);
+ Expr *LHSVal = ((Expr *)lhsval), *RHSVal = ((Expr *)rhsval);
+ assert((LHSVal != 0) && "missing expression in case statement");
+
+ SourceLocation ExpLoc;
+ // C99 6.8.4.2p3: The expression shall be an integer constant.
+ if (!LHSVal->isIntegerConstantExpr(Context, &ExpLoc)) {
+ Diag(ExpLoc, diag::err_case_label_not_integer_constant_expr,
+ LHSVal->getSourceRange());
+ return SubStmt;
+ }
+
+ // GCC extension: The expression shall be an integer constant.
+ if (RHSVal && !RHSVal->isIntegerConstantExpr(Context, &ExpLoc)) {
+ Diag(ExpLoc, diag::err_case_label_not_integer_constant_expr,
+ RHSVal->getSourceRange());
+ RHSVal = 0; // Recover by just forgetting about it.
+ }
+
+ if (SwitchStack.empty()) {
+ Diag(CaseLoc, diag::err_case_not_in_switch);
+ return SubStmt;
+ }
+
+ CaseStmt *CS = new CaseStmt(LHSVal, RHSVal, SubStmt, CaseLoc);
+ SwitchStack.back()->addSwitchCase(CS);
+ return CS;
+}
+
+Action::StmtResult
+Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc,
+ StmtTy *subStmt, Scope *CurScope) {
+ Stmt *SubStmt = static_cast<Stmt*>(subStmt);
+
+ if (SwitchStack.empty()) {
+ Diag(DefaultLoc, diag::err_default_not_in_switch);
+ return SubStmt;
+ }
+
+ DefaultStmt *DS = new DefaultStmt(DefaultLoc, SubStmt);
+ SwitchStack.back()->addSwitchCase(DS);
+
+ return DS;
+}
+
+Action::StmtResult
+Sema::ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II,
+ SourceLocation ColonLoc, StmtTy *subStmt) {
+ Stmt *SubStmt = static_cast<Stmt*>(subStmt);
+ // Look up the record for this label identifier.
+ LabelStmt *&LabelDecl = LabelMap[II];
+
+ // If not forward referenced or defined already, just create a new LabelStmt.
+ if (LabelDecl == 0)
+ return LabelDecl = new 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->getName());
+ Diag(LabelDecl->getIdentLoc(), diag::err_previous_definition);
+ return 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 LabelDecl;
+}
+
+Action::StmtResult
+Sema::ActOnIfStmt(SourceLocation IfLoc, ExprTy *CondVal,
+ StmtTy *ThenVal, SourceLocation ElseLoc,
+ StmtTy *ElseVal) {
+ Expr *condExpr = (Expr *)CondVal;
+ Stmt *thenStmt = (Stmt *)ThenVal;
+
+ assert(condExpr && "ActOnIfStmt(): missing expression");
+
+ DefaultFunctionArrayConversion(condExpr);
+ QualType condType = condExpr->getType();
+
+ if (!condType->isScalarType()) // C99 6.8.4.1p1
+ return Diag(IfLoc, diag::err_typecheck_statement_requires_scalar,
+ condType.getAsString(), condExpr->getSourceRange());
+
+ // 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) {
+ if (NullStmt* stmt = dyn_cast<NullStmt>(thenStmt))
+ Diag(stmt->getSemiLoc(), diag::warn_empty_if_body);
+ }
+
+ return new IfStmt(IfLoc, condExpr, thenStmt, (Stmt*)ElseVal);
+}
+
+Action::StmtResult
+Sema::ActOnStartOfSwitchStmt(ExprTy *cond) {
+ Expr *Cond = static_cast<Expr*>(cond);
+
+ // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr.
+ UsualUnaryConversions(Cond);
+
+ SwitchStmt *SS = new SwitchStmt(Cond);
+ SwitchStack.push_back(SS);
+ return 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(), Val.toString());
+
+ 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(), ConvVal.toString());
+
+ // 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(), Val.toString());
+ }
+}
+
+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::StmtResult
+Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtTy *Switch,
+ ExprTy *Body) {
+ Stmt *BodyStmt = (Stmt*)Body;
+
+ SwitchStmt *SS = SwitchStack.back();
+ assert(SS == (SwitchStmt*)Switch && "switch stack missing push/pop!");
+
+ SS->setBody(BodyStmt, SwitchLoc);
+ SwitchStack.pop_back();
+
+ Expr *CondExpr = SS->getCond();
+ QualType CondType = CondExpr->getType();
+
+ if (!CondType->isIntegerType()) { // C99 6.8.4.2p1
+ Diag(SwitchLoc, diag::err_typecheck_statement_requires_integer,
+ CondType.getAsString(), CondExpr->getSourceRange());
+ return true;
+ }
+
+ // Get the bitwidth of the switched-on value before promotions. We must
+ // convert the integer case values to this width before comparison.
+ unsigned CondWidth = 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;
+ 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::err_first_label);
+
+ // 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.
+ llvm::APSInt LoVal(32);
+ Expr *Lo = CS->getLHS();
+ Lo->isIntegerConstantExpr(LoVal, 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())
+ CaseRanges.push_back(std::make_pair(LoVal, CS));
+ else
+ CaseVals.push_back(std::make_pair(LoVal, CS));
+ }
+ }
+
+ // 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());
+ Diag(CaseVals[i].second->getLHS()->getLocStart(),
+ diag::err_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;
+ llvm::APSInt HiVal(32);
+ Expr *Hi = CR->getRHS();
+ Hi->isIntegerConstantExpr(HiVal, 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());
+ Diag(OverlapStmt->getLHS()->getLocStart(),
+ diag::err_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 true;
+
+ return SS;
+}
+
+Action::StmtResult
+Sema::ActOnWhileStmt(SourceLocation WhileLoc, ExprTy *Cond, StmtTy *Body) {
+ Expr *condExpr = (Expr *)Cond;
+ assert(condExpr && "ActOnWhileStmt(): missing expression");
+
+ DefaultFunctionArrayConversion(condExpr);
+ QualType condType = condExpr->getType();
+
+ if (!condType->isScalarType()) // C99 6.8.5p2
+ return Diag(WhileLoc, diag::err_typecheck_statement_requires_scalar,
+ condType.getAsString(), condExpr->getSourceRange());
+
+ return new WhileStmt(condExpr, (Stmt*)Body, WhileLoc);
+}
+
+Action::StmtResult
+Sema::ActOnDoStmt(SourceLocation DoLoc, StmtTy *Body,
+ SourceLocation WhileLoc, ExprTy *Cond) {
+ Expr *condExpr = (Expr *)Cond;
+ assert(condExpr && "ActOnDoStmt(): missing expression");
+
+ DefaultFunctionArrayConversion(condExpr);
+ QualType condType = condExpr->getType();
+
+ if (!condType->isScalarType()) // C99 6.8.5p2
+ return Diag(DoLoc, diag::err_typecheck_statement_requires_scalar,
+ condType.getAsString(), condExpr->getSourceRange());
+
+ return new DoStmt((Stmt*)Body, condExpr, DoLoc);
+}
+
+Action::StmtResult
+Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
+ StmtTy *first, ExprTy *second, ExprTy *third,
+ SourceLocation RParenLoc, StmtTy *body) {
+ Stmt *First = static_cast<Stmt*>(first);
+ Expr *Second = static_cast<Expr*>(second);
+ Expr *Third = static_cast<Expr*>(third);
+ Stmt *Body = static_cast<Stmt*>(body);
+
+ 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 (ScopedDecl *D = DS->getDecl(); D; D = D->getNextDeclarator()) {
+ BlockVarDecl *BVD = dyn_cast<BlockVarDecl>(D);
+ if (BVD && !BVD->hasLocalStorage())
+ BVD = 0;
+ if (BVD == 0)
+ Diag(dyn_cast<ScopedDecl>(D)->getLocation(),
+ diag::err_non_variable_decl_in_for);
+ // FIXME: mark decl erroneous!
+ }
+ }
+ if (Second) {
+ DefaultFunctionArrayConversion(Second);
+ QualType SecondType = Second->getType();
+
+ if (!SecondType->isScalarType()) // C99 6.8.5p2
+ return Diag(ForLoc, diag::err_typecheck_statement_requires_scalar,
+ SecondType.getAsString(), Second->getSourceRange());
+ }
+ return new ForStmt(First, Second, Third, Body, ForLoc);
+}
+
+Action::StmtResult
+Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
+ SourceLocation LParenLoc,
+ StmtTy *first, ExprTy *second,
+ SourceLocation RParenLoc, StmtTy *body) {
+ Stmt *First = static_cast<Stmt*>(first);
+ Expr *Second = static_cast<Expr*>(second);
+ Stmt *Body = static_cast<Stmt*>(body);
+ if (First) {
+ QualType FirstType;
+ if (DeclStmt *DS = dyn_cast<DeclStmt>(First)) {
+ FirstType = cast<ValueDecl>(DS->getDecl())->getType();
+ // C99 6.8.5p3: The declaration part of a 'for' statement shall only declare
+ // identifiers for objects having storage class 'auto' or 'register'.
+ ScopedDecl *D = DS->getDecl();
+ BlockVarDecl *BVD = cast<BlockVarDecl>(D);
+ if (!BVD->hasLocalStorage())
+ return Diag(BVD->getLocation(), diag::err_non_variable_decl_in_for);
+ if (D->getNextDeclarator())
+ return Diag(D->getLocation(), diag::err_toomany_element_decls);
+ }
+ else
+ FirstType = static_cast<Expr*>(first)->getType();
+ if (!isObjCObjectPointerType(FirstType))
+ Diag(ForLoc, diag::err_selector_element_type,
+ FirstType.getAsString(), First->getSourceRange());
+ }
+ if (Second) {
+ DefaultFunctionArrayConversion(Second);
+ QualType SecondType = Second->getType();
+ if (!isObjCObjectPointerType(SecondType))
+ Diag(ForLoc, diag::err_collection_expr_type,
+ SecondType.getAsString(), Second->getSourceRange());
+ }
+ return new ObjCForCollectionStmt(First, Second, Body, ForLoc, RParenLoc);
+}
+
+Action::StmtResult
+Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc,
+ IdentifierInfo *LabelII) {
+ // Look up the record for this label identifier.
+ LabelStmt *&LabelDecl = LabelMap[LabelII];
+
+ // If we haven't seen this label yet, create a forward reference.
+ if (LabelDecl == 0)
+ LabelDecl = new LabelStmt(LabelLoc, LabelII, 0);
+
+ return new GotoStmt(LabelDecl, GotoLoc, LabelLoc);
+}
+
+Action::StmtResult
+Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc,SourceLocation StarLoc,
+ ExprTy *DestExp) {
+ // FIXME: Verify that the operand is convertible to void*.
+
+ return new IndirectGotoStmt((Expr*)DestExp);
+}
+
+Action::StmtResult
+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.
+ Diag(ContinueLoc, diag::err_continue_not_in_loop);
+ return true;
+ }
+
+ return new ContinueStmt(ContinueLoc);
+}
+
+Action::StmtResult
+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.
+ Diag(BreakLoc, diag::err_break_not_in_loop_or_switch);
+ return true;
+ }
+
+ return new BreakStmt(BreakLoc);
+}
+
+
+Action::StmtResult
+Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprTy *rex) {
+ Expr *RetValExp = static_cast<Expr *>(rex);
+ QualType FnRetType = CurFunctionDecl ? CurFunctionDecl->getResultType() :
+ CurMethodDecl->getResultType();
+
+ if (FnRetType->isVoidType()) {
+ if (RetValExp) // C99 6.8.6.4p1 (ext_ since GCC warns)
+ Diag(ReturnLoc, diag::ext_return_has_expr,
+ (CurFunctionDecl ? CurFunctionDecl->getIdentifier()->getName() :
+ CurMethodDecl->getSelector().getName()),
+ RetValExp->getSourceRange());
+ return new ReturnStmt(ReturnLoc, RetValExp);
+ } else {
+ if (!RetValExp) {
+ const char *funcName = CurFunctionDecl ?
+ CurFunctionDecl->getIdentifier()->getName() :
+ CurMethodDecl->getSelector().getName().c_str();
+ if (getLangOptions().C99) // C99 6.8.6.4p1 (ext_ since GCC warns)
+ Diag(ReturnLoc, diag::ext_return_missing_expr, funcName);
+ else // C90 6.6.6.4p4
+ Diag(ReturnLoc, diag::warn_return_missing_expr, funcName);
+ return new ReturnStmt(ReturnLoc, (Expr*)0);
+ }
+ }
+ // we have a non-void function 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.
+ AssignConvertType ConvTy = CheckSingleAssignmentConstraints(FnRetType,
+ RetValExp);
+ if (DiagnoseAssignmentResult(ConvTy, ReturnLoc, FnRetType,
+ RetValType, RetValExp, "returning"))
+ return true;
+
+ if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
+
+ return new ReturnStmt(ReturnLoc, (Expr*)RetValExp);
+}
+
+Sema::StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
+ bool IsSimple,
+ bool IsVolatile,
+ unsigned NumOutputs,
+ unsigned NumInputs,
+ std::string *Names,
+ ExprTy **Constraints,
+ ExprTy **Exprs,
+ ExprTy *AsmString,
+ unsigned NumClobbers,
+ ExprTy **Clobbers,
+ SourceLocation RParenLoc) {
+ Expr *E = (Expr *)AsmString;
+
+ for (unsigned i = 0; i < NumOutputs; i++) {
+ StringLiteral *Literal = cast<StringLiteral>((Expr *)Constraints[i]);
+ assert(!Literal->isWide() &&
+ "Output constraint strings should not be wide!");
+
+ std::string OutputConstraint(Literal->getStrData(),
+ Literal->getByteLength());
+
+ TargetInfo::ConstraintInfo info;
+ if (!Context.Target.validateOutputConstraint(OutputConstraint.c_str(),
+ info)) {
+ // FIXME: We currently leak memory here.
+ Diag(Literal->getLocStart(),
+ diag::err_invalid_output_constraint_in_asm);
+ return true;
+ }
+
+ // Check that the output exprs are valid lvalues.
+ Expr *OutputExpr = (Expr *)Exprs[i];
+ Expr::isLvalueResult Result = OutputExpr->isLvalue();
+ if (Result != Expr::LV_Valid) {
+ ParenExpr *PE = cast<ParenExpr>(OutputExpr);
+
+ Diag(PE->getSubExpr()->getLocStart(),
+ diag::err_invalid_lvalue_in_asm_output,
+ PE->getSubExpr()->getSourceRange());
+
+ // FIXME: We currently leak memory here.
+ return true;
+ }
+ }
+
+ for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) {
+ StringLiteral *Literal = cast<StringLiteral>((Expr *)Constraints[i]);
+ assert(!Literal->isWide() &&
+ "Output constraint strings should not be wide!");
+
+ std::string InputConstraint(Literal->getStrData(),
+ Literal->getByteLength());
+
+ TargetInfo::ConstraintInfo info;
+ if (!Context.Target.validateInputConstraint(InputConstraint.c_str(),
+ NumOutputs,
+ info)) {
+ // FIXME: We currently leak memory here.
+ Diag(Literal->getLocStart(),
+ diag::err_invalid_input_constraint_in_asm);
+ return true;
+ }
+
+ // Check that the input exprs aren't of type void.
+ Expr *InputExpr = (Expr *)Exprs[i];
+ if (InputExpr->getType()->isVoidType()) {
+ ParenExpr *PE = cast<ParenExpr>(InputExpr);
+
+ Diag(PE->getSubExpr()->getLocStart(),
+ diag::err_invalid_type_in_asm_input,
+ PE->getType().getAsString(),
+ PE->getSubExpr()->getSourceRange());
+
+ // FIXME: We currently leak memory here.
+ return true;
+ }
+ }
+
+ // Check that the clobbers are valid.
+ for (unsigned i = 0; i < NumClobbers; i++) {
+ StringLiteral *Literal = cast<StringLiteral>((Expr *)Clobbers[i]);
+ assert(!Literal->isWide() && "Clobber strings should not be wide!");
+
+ llvm::SmallString<16> Clobber(Literal->getStrData(),
+ Literal->getStrData() +
+ Literal->getByteLength());
+
+ if (!Context.Target.isValidGCCRegisterName(Clobber.c_str())) {
+ Diag(Literal->getLocStart(),
+ diag::err_unknown_register_name_in_asm,
+ Clobber.c_str());
+
+ // FIXME: We currently leak memory here.
+ return true;
+ }
+ }
+
+ return new AsmStmt(AsmLoc,
+ IsSimple,
+ IsVolatile,
+ NumOutputs,
+ NumInputs,
+ Names,
+ reinterpret_cast<StringLiteral**>(Constraints),
+ reinterpret_cast<Expr**>(Exprs),
+ cast<StringLiteral>(E),
+ NumClobbers,
+ reinterpret_cast<StringLiteral**>(Clobbers),
+ RParenLoc);
+}
+
+Action::StmtResult
+Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc,
+ SourceLocation RParen, StmtTy *Parm,
+ StmtTy *Body, StmtTy *CatchList) {
+ ObjCAtCatchStmt *CS = new ObjCAtCatchStmt(AtLoc, RParen,
+ static_cast<Stmt*>(Parm), static_cast<Stmt*>(Body),
+ static_cast<Stmt*>(CatchList));
+ return CatchList ? CatchList : CS;
+}
+
+Action::StmtResult
+Sema::ActOnObjCAtFinallyStmt(SourceLocation AtLoc, StmtTy *Body) {
+ ObjCAtFinallyStmt *FS = new ObjCAtFinallyStmt(AtLoc,
+ static_cast<Stmt*>(Body));
+ return FS;
+}
+
+Action::StmtResult
+Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc,
+ StmtTy *Try, StmtTy *Catch, StmtTy *Finally) {
+ ObjCAtTryStmt *TS = new ObjCAtTryStmt(AtLoc, static_cast<Stmt*>(Try),
+ static_cast<Stmt*>(Catch),
+ static_cast<Stmt*>(Finally));
+ return TS;
+}
+
+Action::StmtResult
+Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, StmtTy *Throw) {
+ ObjCAtThrowStmt *TS = new ObjCAtThrowStmt(AtLoc, static_cast<Stmt*>(Throw));
+ return TS;
+}
+
+Action::StmtResult
+Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprTy *SynchExpr,
+ StmtTy *SynchBody) {
+ ObjCAtSynchronizedStmt *SS = new ObjCAtSynchronizedStmt(AtLoc,
+ static_cast<Stmt*>(SynchExpr), static_cast<Stmt*>(SynchBody));
+ return SS;
+}
+
+
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
new file mode 100644
index 00000000000..f717b4139a5
--- /dev/null
+++ b/clang/lib/Sema/SemaType.cpp
@@ -0,0 +1,498 @@
+//===--- 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/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Basic/LangOptions.h"
+using namespace clang;
+
+/// ConvertDeclSpecToType - Convert the specified declspec to the appropriate
+/// type object. This returns null on error.
+QualType Sema::ConvertDeclSpecToType(DeclSpec &DS) {
+ // FIXME: Should move the logic from DeclSpec::Finish to here for validity
+ // checking.
+ QualType Result;
+
+ switch (DS.getTypeSpecType()) {
+ default: return QualType(); // FIXME: Handle unimp cases!
+ case DeclSpec::TST_void: return Context.VoidTy;
+ 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_unspecified: // Unspecific typespec defaults to int.
+ 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
+ assert(0 && "FIXME: GNU decimal extensions not supported yet!");
+ 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 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.getTagDeclType(cast<TagDecl>(D));
+ break;
+ }
+ case DeclSpec::TST_typedef: {
+ Decl *D = static_cast<Decl *>(DS.getTypeRep());
+ assert(D && "Didn't get a decl for a typedef?");
+ assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 &&
+ DS.getTypeSpecSign() == 0 &&
+ "Can't handle qualifiers on typedef names yet!");
+ // FIXME: Adding a TST_objcInterface clause doesn't seem ideal, so
+ // we have this "hack" for now...
+ if (ObjCInterfaceDecl *ObjCIntDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
+ if (DS.getProtocolQualifiers() == 0) {
+ Result = Context.getObjCInterfaceType(ObjCIntDecl);
+ break;
+ }
+
+ Action::DeclTy **PPDecl = &(*DS.getProtocolQualifiers())[0];
+ Result = Context.getObjCQualifiedInterfaceType(ObjCIntDecl,
+ reinterpret_cast<ObjCProtocolDecl**>(PPDecl),
+ DS.getNumProtocolQualifiers());
+ break;
+ }
+ else if (TypedefDecl *typeDecl = dyn_cast<TypedefDecl>(D)) {
+ if (Context.getObjCIdType() == Context.getTypedefType(typeDecl)
+ && DS.getProtocolQualifiers()) {
+ // id<protocol-list>
+ Action::DeclTy **PPDecl = &(*DS.getProtocolQualifiers())[0];
+ Result = Context.getObjCQualifiedIdType(typeDecl->getUnderlyingType(),
+ reinterpret_cast<ObjCProtocolDecl**>(PPDecl),
+ DS.getNumProtocolQualifiers());
+ break;
+ }
+ }
+ // TypeQuals handled by caller.
+ Result = Context.getTypedefType(cast<TypedefDecl>(D));
+ 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.getTypeOfExpr(E);
+ break;
+ }
+ }
+
+ // Handle complex types.
+ if (DS.getTypeSpecComplex() == DeclSpec::TSC_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 (AttributeList *AL = DS.getAttributes())
+ DS.SetAttributes(ProcessTypeAttributes(Result, AL));
+
+ return Result;
+}
+
+/// GetTypeForDeclarator - Convert the type for the specified declarator to Type
+/// instances.
+QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
+ // long long is a C99 feature.
+ if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x &&
+ D.getDeclSpec().getTypeSpecWidth() == DeclSpec::TSW_longlong)
+ Diag(D.getDeclSpec().getTypeSpecWidthLoc(), diag::ext_longlong);
+
+ QualType T = ConvertDeclSpecToType(D.getDeclSpec());
+
+ // Apply const/volatile/restrict qualifiers to T.
+ T = T.getQualifiedType(D.getDeclSpec().getTypeQualifiers());
+
+ // 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 = 0, e = D.getNumTypeObjects(); i != e; ++i) {
+ DeclaratorChunk &DeclType = D.getTypeObject(e-i-1);
+ switch (DeclType.Kind) {
+ default: assert(0 && "Unknown decltype!");
+ case DeclaratorChunk::Pointer:
+ if (T->isReferenceType()) {
+ // C++ 8.3.2p4: There shall be no ... pointers to references ...
+ Diag(D.getIdentifierLoc(), diag::err_illegal_decl_pointer_to_reference,
+ D.getIdentifier() ? D.getIdentifier()->getName() : "type name");
+ D.setInvalidType(true);
+ T = Context.IntTy;
+ }
+
+ // Apply the pointer typequals to the pointer object.
+ T = Context.getPointerType(T).getQualifiedType(DeclType.Ptr.TypeQuals);
+
+ // See if there are any attributes on the pointer that apply to it.
+ if (AttributeList *AL = DeclType.Ptr.AttrList)
+ DeclType.Ptr.AttrList = ProcessTypeAttributes(T, AL);
+
+ break;
+ case DeclaratorChunk::Reference:
+ if (const ReferenceType *RT = T->getAsReferenceType()) {
+ // C++ 8.3.2p4: There shall be no references to references.
+ Diag(D.getIdentifierLoc(),
+ diag::err_illegal_decl_reference_to_reference,
+ D.getIdentifier() ? D.getIdentifier()->getName() : "type name");
+ D.setInvalidType(true);
+ T = RT->getReferenceeType();
+ }
+
+ T = Context.getReferenceType(T);
+
+ // FIXME: Handle Ref.Restrict!
+
+ // See if there are any attributes on the pointer that apply to it.
+ if (AttributeList *AL = DeclType.Ref.AttrList)
+ DeclType.Ref.AttrList = ProcessTypeAttributes(T, AL);
+ break;
+ case DeclaratorChunk::Array: {
+ const 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;
+
+ // 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 (T->isIncompleteType()) {
+ Diag(D.getIdentifierLoc(), diag::err_illegal_decl_array_incomplete_type,
+ T.getAsString());
+ T = Context.IntTy;
+ D.setInvalidType(true);
+ } else if (T->isFunctionType()) {
+ Diag(D.getIdentifierLoc(), diag::err_illegal_decl_array_of_functions,
+ D.getIdentifier() ? D.getIdentifier()->getName() : "type name");
+ T = Context.getPointerType(T);
+ D.setInvalidType(true);
+ } else if (const ReferenceType *RT = T->getAsReferenceType()) {
+ // C++ 8.3.2p4: There shall be no ... arrays of references ...
+ Diag(D.getIdentifierLoc(), diag::err_illegal_decl_array_of_references,
+ D.getIdentifier() ? D.getIdentifier()->getName() : "type name");
+ T = RT->getReferenceeType();
+ D.setInvalidType(true);
+ } else if (const RecordType *EltTy = T->getAsRecordType()) {
+ // If the element type is a struct or union that contains a variadic
+ // array, reject it: C99 6.7.2.1p2.
+ if (EltTy->getDecl()->hasFlexibleArrayMember()) {
+ Diag(DeclType.Loc, diag::err_flexible_array_in_array,
+ T.getAsString());
+ T = Context.IntTy;
+ D.setInvalidType(true);
+ }
+ }
+ // C99 6.7.5.2p1: The size expression shall have integer type.
+ if (ArraySize && !ArraySize->getType()->isIntegerType()) {
+ Diag(ArraySize->getLocStart(), diag::err_array_size_non_int,
+ ArraySize->getType().getAsString(), ArraySize->getSourceRange());
+ D.setInvalidType(true);
+ }
+ llvm::APSInt ConstVal(32);
+ // If no expression was provided, we consider it a VLA.
+ if (!ArraySize) {
+ T = Context.getIncompleteArrayType(T, ASM, ATI.TypeQuals);
+ } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context)) {
+ T = Context.getVariableArrayType(T, ArraySize, ASM, ATI.TypeQuals);
+ } 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());
+ D.setInvalidType(true);
+ } 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, ATI.TypeQuals);
+ }
+ // If this is not C99, extwarn about VLA's and C99 array size modifiers.
+ if (!getLangOptions().C99 &&
+ (ASM != ArrayType::Normal ||
+ (ArraySize && !ArraySize->isIntegerConstantExpr(Context))))
+ Diag(D.getIdentifierLoc(), diag::ext_vla);
+ 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.getAsString());
+ T = Context.IntTy;
+ D.setInvalidType(true);
+ }
+
+ if (!FTI.hasPrototype) {
+ // Simple void foo(), where the incoming T is the result type.
+ T = Context.getFunctionTypeNoProto(T);
+
+ // C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function definition.
+ if (FTI.NumArgs != 0)
+ 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) {
+ QualType ArgTy = QualType::getFromOpaquePtr(FTI.ArgInfo[i].TypeInfo);
+ assert(!ArgTy.isNull() && "Couldn't parse type?");
+ //
+ // Perform the default function/array conversion (C99 6.7.5.3p[7,8]).
+ // This matches the conversion that is done in
+ // Sema::ActOnParamDeclarator(). Without this conversion, the
+ // argument type in the function prototype *will not* match the
+ // type in ParmVarDecl (which makes the code generator unhappy).
+ //
+ // FIXME: We still apparently need the conversion in
+ // Sema::ParseParamDeclarator(). This doesn't make any sense, since
+ // it should be driving off the type being created here.
+ //
+ // FIXME: If a source translation tool needs to see the original type,
+ // then we need to consider storing both types somewhere...
+ //
+ if (const ArrayType *AT = ArgTy->getAsArrayType()) {
+ // int x[restrict 4] -> int *restrict
+ ArgTy = Context.getPointerType(AT->getElementType());
+ ArgTy = ArgTy.getQualifiedType(AT->getIndexTypeQualifier());
+ } else if (ArgTy->isFunctionType())
+ ArgTy = Context.getPointerType(ArgTy);
+ // 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 FunctionTypeProto with an empty argument list.
+ else 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;
+ FTI.ArgInfo[i].TypeInfo = ArgTy.getAsOpaquePtr();
+ } 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;
+ FTI.ArgInfo[i].TypeInfo = ArgTy.getAsOpaquePtr();
+ } 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;
+ }
+ }
+
+ ArgTys.push_back(ArgTy);
+ }
+ T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(),
+ FTI.isVariadic);
+ }
+ break;
+ }
+ }
+
+ return T;
+}
+
+/// ObjCGetTypeForMethodDefinition - Builds the type for a method definition
+/// declarator
+QualType Sema::ObjCGetTypeForMethodDefinition(DeclTy *D) {
+ ObjCMethodDecl *MDecl = dyn_cast<ObjCMethodDecl>(static_cast<Decl *>(D));
+ QualType T = MDecl->getResultType();
+ llvm::SmallVector<QualType, 16> ArgTys;
+
+ // Add the first two invisible argument types for self and _cmd.
+ if (MDecl->isInstance()) {
+ 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 (int i = 0; i < MDecl->getNumParams(); i++) {
+ ParmVarDecl *PDecl = MDecl->getParamDecl(i);
+ QualType ArgTy = PDecl->getType();
+ assert(!ArgTy.isNull() && "Couldn't parse type?");
+ // Perform the default function/array conversion (C99 6.7.5.3p[7,8]).
+ // This matches the conversion that is done in
+ // Sema::ParseParamDeclarator().
+ if (const ArrayType *AT = ArgTy->getAsArrayType())
+ ArgTy = Context.getPointerType(AT->getElementType());
+ else if (ArgTy->isFunctionType())
+ ArgTy = Context.getPointerType(ArgTy);
+ ArgTys.push_back(ArgTy);
+ }
+ T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(),
+ MDecl->isVariadic());
+ return T;
+}
+
+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!");
+
+ QualType T = GetTypeForDeclarator(D, S);
+
+ assert(!T.isNull() && "GetTypeForDeclarator() returned null type");
+
+ // In this context, we *do not* check D.getInvalidType(). If the declarator
+ // type was invalid, GetTypeForDeclarator() still returns a "valid" type,
+ // though it will not reflect the user specified type.
+ return T.getAsOpaquePtr();
+}
+
+// Called from Parser::ParseParenDeclarator().
+Sema::TypeResult Sema::ActOnParamDeclaratorType(Scope *S, Declarator &D) {
+ // Note: parameters have identifiers, but we don't care about them here, we
+ // just want the type converted.
+ QualType T = GetTypeForDeclarator(D, S);
+
+ assert(!T.isNull() && "GetTypeForDeclarator() returned null type");
+
+ // In this context, we *do not* check D.getInvalidType(). If the declarator
+ // type was invalid, GetTypeForDeclarator() still returns a "valid" type,
+ // though it will not reflect the user specified type.
+ return T.getAsOpaquePtr();
+}
+
+AttributeList *Sema::ProcessTypeAttributes(QualType &Result, 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 and delete attributes that apply to the
+ // type and leave the others alone.
+ llvm::SmallVector<AttributeList *, 8> LeftOverAttrs;
+ while (AL) {
+ // Unlink this attribute from the chain, so we can process it independently.
+ AttributeList *ThisAttr = AL;
+ AL = AL->getNext();
+ ThisAttr->setNext(0);
+
+ // If this is an attribute we can handle, do so now, otherwise, add it to
+ // the LeftOverAttrs list for rechaining.
+ switch (ThisAttr->getKind()) {
+ default: break;
+ case AttributeList::AT_address_space:
+ Result = HandleAddressSpaceTypeAttribute(Result, ThisAttr);
+ delete ThisAttr; // Consume the attribute.
+ continue;
+ }
+
+ LeftOverAttrs.push_back(ThisAttr);
+ }
+
+ // Rechain any attributes that haven't been deleted to the DeclSpec.
+ AttributeList *List = 0;
+ for (unsigned i = 0, e = LeftOverAttrs.size(); i != e; ++i) {
+ LeftOverAttrs[i]->setNext(List);
+ List = LeftOverAttrs[i];
+ }
+
+ return List;
+}
+
+/// HandleAddressSpaceTypeAttribute - Process an address_space attribute on the
+/// specified type.
+QualType Sema::HandleAddressSpaceTypeAttribute(QualType Type,
+ AttributeList *Attr) {
+ // 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()) {
+ Diag(Attr->getLoc(), diag::err_attribute_address_multiple_qualifiers);
+ return Type;
+ }
+
+ // Check the attribute arguments.
+ if (Attr->getNumArgs() != 1) {
+ Diag(Attr->getLoc(), diag::err_attribute_wrong_number_arguments,
+ std::string("1"));
+ return Type;
+ }
+ Expr *ASArgExpr = static_cast<Expr *>(Attr->getArg(0));
+ llvm::APSInt addrSpace(32);
+ if (!ASArgExpr->isIntegerConstantExpr(addrSpace, Context)) {
+ Diag(Attr->getLoc(), diag::err_attribute_address_space_not_int,
+ ASArgExpr->getSourceRange());
+ return Type;
+ }
+
+ unsigned ASIdx = static_cast<unsigned>(addrSpace.getZExtValue());
+ return Context.getASQualType(Type, ASIdx);
+}
+
diff --git a/clang/lib/Sema/SemaUtil.h b/clang/lib/Sema/SemaUtil.h
new file mode 100644
index 00000000000..35452b18e6f
--- /dev/null
+++ b/clang/lib/Sema/SemaUtil.h
@@ -0,0 +1,35 @@
+//===--- SemaUtil.h - Utility functions for 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 a few static inline functions that are useful for
+// performing semantic analysis.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_UTIL_H
+#define LLVM_CLANG_SEMA_UTIL_H
+
+#include "clang/AST/Expr.h"
+
+namespace clang {
+
+/// Utility method to determine if a CallExpr is a call to a builtin.
+static inline bool isCallBuiltin(CallExpr* cexp) {
+ Expr* sub = cexp->getCallee()->IgnoreParenCasts();
+
+ if (DeclRefExpr* E = dyn_cast<DeclRefExpr>(sub))
+ if (E->getDecl()->getIdentifier()->getBuiltinID() > 0)
+ return true;
+
+ return false;
+}
+
+} // end namespace clang
+
+#endif
OpenPOWER on IntegriCloud