diff options
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/Makefile | 23 | ||||
-rw-r--r-- | clang/lib/Sema/ParseAST.cpp | 69 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 222 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.h | 823 | ||||
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 802 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 2297 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclObjC.cpp | 927 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 2286 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 51 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprObjC.cpp | 297 | ||||
-rw-r--r-- | clang/lib/Sema/SemaStmt.cpp | 821 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 498 | ||||
-rw-r--r-- | clang/lib/Sema/SemaUtil.h | 35 |
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 |