Stage two of getting CFE top correct.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@39734 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Sema/ASTStreamer.cpp b/Sema/ASTStreamer.cpp
new file mode 100644
index 0000000..1057d93
--- /dev/null
+++ b/Sema/ASTStreamer.cpp
@@ -0,0 +1,111 @@
+//===--- ASTStreamer.cpp - Provide streaming interface to ASTs ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the ASTStreamer interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/ASTStreamer.h"
+#include "clang/AST/ASTContext.h"
+#include "Sema.h"
+#include "clang/Parse/Action.h"
+#include "clang/Parse/Parser.h"
+using namespace clang;
+
+namespace {
+ class ASTStreamer {
+ Parser P;
+ std::vector<Decl*> LastInGroupList;
+ public:
+ ASTStreamer(Preprocessor &pp, ASTContext &ctxt, unsigned MainFileID)
+ : P(pp, *new Sema(pp, ctxt, LastInGroupList)) {
+ pp.EnterSourceFile(MainFileID, 0, true);
+
+ // Initialize the parser.
+ P.Initialize();
+ }
+
+ /// ReadTopLevelDecl - Parse and return the next top-level declaration.
+ Decl *ReadTopLevelDecl();
+
+ void PrintStats() const;
+
+ ~ASTStreamer() {
+ P.Finalize();
+ delete &P.getActions();
+ }
+ };
+}
+
+/// ReadTopLevelDecl - Parse and return the next top-level declaration.
+///
+Decl *ASTStreamer::ReadTopLevelDecl() {
+ Parser::DeclTy *Result;
+
+ /// If the previous time through we read something like 'int X, Y', return
+ /// the next declarator.
+ if (!LastInGroupList.empty()) {
+ Result = LastInGroupList.back();
+ LastInGroupList.pop_back();
+ return static_cast<Decl*>(Result);
+ }
+
+ do {
+ if (P.ParseTopLevelDecl(Result))
+ return 0; // End of file.
+
+ // If we got a null return and something *was* parsed, try again. This
+ // is due to a top-level semicolon, an action override, or a parse error
+ // skipping something.
+ } while (Result == 0);
+
+ // If we parsed a declspec with multiple declarators, reverse the list and
+ // return the first one.
+ if (!LastInGroupList.empty()) {
+ LastInGroupList.push_back((Decl*)Result);
+ std::reverse(LastInGroupList.begin(), LastInGroupList.end());
+ Result = LastInGroupList.back();
+ LastInGroupList.pop_back();
+ }
+
+ return static_cast<Decl*>(Result);
+}
+
+void ASTStreamer::PrintStats() const {
+}
+
+//===----------------------------------------------------------------------===//
+// Public interface to the file
+//===----------------------------------------------------------------------===//
+
+/// ASTStreamer_Init - Create an ASTStreamer with the specified preprocessor
+/// and FileID.
+ASTStreamerTy *clang::ASTStreamer_Init(Preprocessor &pp, ASTContext &ctxt,
+ unsigned MainFileID) {
+ return new ASTStreamer(pp, ctxt, MainFileID);
+}
+
+/// ASTStreamer_ReadTopLevelDecl - Parse and return one top-level declaration. This
+/// returns null at end of file.
+Decl *clang::ASTStreamer_ReadTopLevelDecl(ASTStreamerTy *Streamer) {
+ return static_cast<ASTStreamer*>(Streamer)->ReadTopLevelDecl();
+}
+
+
+/// ASTStreamer_PrintStats - Emit statistic information to stderr.
+///
+void clang::ASTStreamer_PrintStats(ASTStreamerTy *Streamer) {
+ return static_cast<ASTStreamer*>(Streamer)->PrintStats();
+}
+
+/// ASTStreamer_Terminate - Gracefully shut down the streamer.
+///
+void clang::ASTStreamer_Terminate(ASTStreamerTy *Streamer) {
+ delete static_cast<ASTStreamer*>(Streamer);
+}
diff --git a/Sema/Makefile b/Sema/Makefile
new file mode 100644
index 0000000..83a1eff
--- /dev/null
+++ b/Sema/Makefile
@@ -0,0 +1,23 @@
+##===- clang/Sema/Makefile ---------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file was developed by Chris Lattner and 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/Sema/Sema.cpp b/Sema/Sema.cpp
new file mode 100644
index 0000000..64c18a8
--- /dev/null
+++ b/Sema/Sema.cpp
@@ -0,0 +1,88 @@
+//===--- Sema.cpp - AST Builder and Semantic Analysis Implementation ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and 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"
+using namespace clang;
+
+Sema::Sema(Preprocessor &pp, ASTContext &ctxt, std::vector<Decl*> &prevInGroup)
+ : PP(pp), Context(ctxt), CurFunctionDecl(0), LastInGroupList(prevInGroup) {
+}
+
+//===----------------------------------------------------------------------===//
+// Helper functions.
+//===----------------------------------------------------------------------===//
+
+bool Sema::Diag(SourceLocation Loc, unsigned DiagID) {
+ PP.getDiagnostics().Report(Loc, DiagID);
+ return true;
+}
+
+bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg) {
+ PP.getDiagnostics().Report(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(Loc, DiagID, MsgArr, 2);
+ return true;
+}
+
+bool Sema::Diag(SourceLocation Loc, unsigned DiagID, SourceRange Range) {
+ PP.getDiagnostics().Report(Loc, DiagID, 0, 0, &Range, 1);
+ return true;
+}
+
+bool Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg,
+ SourceRange Range) {
+ PP.getDiagnostics().Report(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(Loc, DiagID, MsgArr, 2, &Range, 1);
+ return true;
+}
+
+bool Sema::Diag(SourceLocation Loc, unsigned DiagID,
+ SourceRange R1, SourceRange R2) {
+ SourceRange RangeArr[] = { R1, R2 };
+ PP.getDiagnostics().Report(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(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(Range, DiagID, MsgArr, 2, RangeArr, 2);
+ return true;
+}
+
+const LangOptions &Sema::getLangOptions() const {
+ return PP.getLangOptions();
+}
diff --git a/Sema/Sema.h b/Sema/Sema.h
new file mode 100644
index 0000000..ac85868
--- /dev/null
+++ b/Sema/Sema.h
@@ -0,0 +1,353 @@
+//===--- Sema.h - Semantic Analysis & AST Building --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and 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 "llvm/ADT/DenseMap.h"
+#include <vector>
+#include <string>
+
+namespace clang {
+ class ASTContext;
+ class Preprocessor;
+ class Decl;
+ class Expr;
+ class VarDecl;
+ class ParmVarDecl;
+ class TypedefDecl;
+ class FunctionDecl;
+ class QualType;
+ class LangOptions;
+ class DeclaratorChunk;
+ class LexerToken;
+ class IntegerLiteral;
+ class ArrayType;
+ class LabelStmt;
+
+/// Sema - This implements semantic analysis and AST building for C.
+class Sema : public Action {
+ Preprocessor &PP;
+
+ ASTContext &Context;
+
+ /// CurFunctionDecl - If inside of a function body, this contains a pointer to
+ /// the function decl for the function being parsed.
+ FunctionDecl *CurFunctionDecl;
+
+ /// LastInGroupList - This vector is populated when there are multiple
+ /// declarators in a single decl group (e.g. "int A, B, C"). In this case,
+ /// all but the last decl will be entered into this. This is used by the
+ /// ASTStreamer.
+ std::vector<Decl*> &LastInGroupList;
+
+ /// 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;
+public:
+ Sema(Preprocessor &pp, ASTContext &ctxt, std::vector<Decl*> &prevInGroup);
+
+ 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,
+ SourceRange R1, SourceRange R2);
+
+ //===--------------------------------------------------------------------===//
+ // Type Analysis / Processing: SemaType.cpp.
+ //
+ QualType GetTypeForDeclarator(Declarator &D, Scope *S);
+
+ virtual TypeResult ParseTypeName(Scope *S, Declarator &D);
+
+ virtual TypeResult ParseParamDeclaratorType(Scope *S, Declarator &D);
+private:
+ //===--------------------------------------------------------------------===//
+ // Symbol table / Decl tracking callbacks: SemaDecl.cpp.
+ //
+ virtual DeclTy *isTypeName(const IdentifierInfo &II, Scope *S) const;
+ virtual DeclTy *ParseDeclarator(Scope *S, Declarator &D, ExprTy *Init,
+ DeclTy *LastInGroup);
+ virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group);
+
+ virtual DeclTy *ParseStartOfFunctionDef(Scope *S, Declarator &D);
+ virtual DeclTy *ParseFunctionDefBody(DeclTy *Decl, StmtTy *Body);
+ virtual void PopScope(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 *ParseTag(Scope *S, unsigned TagType, TagKind TK,
+ SourceLocation KWLoc, IdentifierInfo *Name,
+ SourceLocation NameLoc, AttributeList *Attr);
+ virtual DeclTy *ParseField(Scope *S, DeclTy *TagDecl,SourceLocation DeclStart,
+ Declarator &D, ExprTy *BitfieldWidth);
+ virtual void ParseRecordBody(SourceLocation RecLoc, DeclTy *TagDecl,
+ DeclTy **Fields, unsigned NumFields);
+ virtual DeclTy *ParseEnumConstant(Scope *S, DeclTy *EnumDecl,
+ DeclTy *LastEnumConstant,
+ SourceLocation IdLoc, IdentifierInfo *Id,
+ SourceLocation EqualLoc, ExprTy *Val);
+ virtual void ParseEnumBody(SourceLocation EnumLoc, DeclTy *EnumDecl,
+ DeclTy **Elements, unsigned NumElements);
+private:
+ /// Subroutines of ParseDeclarator()...
+ TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, Decl *LastDeclarator);
+ TypedefDecl *MergeTypeDefDecl(TypedefDecl *New, Decl *Old);
+ FunctionDecl *MergeFunctionDecl(FunctionDecl *New, Decl *Old);
+ VarDecl *MergeVarDecl(VarDecl *New, Decl *Old);
+ /// AddTopLevelDecl - called after the decl has been fully processed.
+ /// Allows for bookkeeping and post-processing of each declaration.
+ void AddTopLevelDecl(Decl *current, Decl *last);
+
+ /// More parsing and symbol table subroutines...
+ ParmVarDecl *ParseParamDeclarator(DeclaratorChunk &FI, unsigned ArgNo,
+ Scope *FnBodyScope);
+ Decl *LookupScopedDecl(IdentifierInfo *II, unsigned NSI, SourceLocation IdLoc,
+ Scope *S);
+ Decl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, Scope *S);
+ Decl *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);
+
+ // 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);
+
+ //===--------------------------------------------------------------------===//
+ // Statement Parsing Callbacks: SemaStmt.cpp.
+public:
+ virtual StmtResult ParseExprStmt(ExprTy *Expr);
+
+ virtual StmtResult ParseNullStmt(SourceLocation SemiLoc);
+ virtual StmtResult ParseCompoundStmt(SourceLocation L, SourceLocation R,
+ StmtTy **Elts, unsigned NumElts);
+ virtual StmtResult ParseDeclStmt(DeclTy *Decl);
+ virtual StmtResult ParseCaseStmt(SourceLocation CaseLoc, ExprTy *LHSVal,
+ SourceLocation DotDotDotLoc, ExprTy *RHSVal,
+ SourceLocation ColonLoc, StmtTy *SubStmt);
+ virtual StmtResult ParseDefaultStmt(SourceLocation DefaultLoc,
+ SourceLocation ColonLoc, StmtTy *SubStmt);
+ virtual StmtResult ParseLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II,
+ SourceLocation ColonLoc, StmtTy *SubStmt);
+ virtual StmtResult ParseIfStmt(SourceLocation IfLoc, ExprTy *CondVal,
+ StmtTy *ThenVal, SourceLocation ElseLoc,
+ StmtTy *ElseVal);
+ virtual StmtResult ParseSwitchStmt(SourceLocation SwitchLoc, ExprTy *Cond,
+ StmtTy *Body);
+ virtual StmtResult ParseWhileStmt(SourceLocation WhileLoc, ExprTy *Cond,
+ StmtTy *Body);
+ virtual StmtResult ParseDoStmt(SourceLocation DoLoc, StmtTy *Body,
+ SourceLocation WhileLoc, ExprTy *Cond);
+
+ virtual StmtResult ParseForStmt(SourceLocation ForLoc,
+ SourceLocation LParenLoc,
+ StmtTy *First, ExprTy *Second, ExprTy *Third,
+ SourceLocation RParenLoc, StmtTy *Body);
+ virtual StmtResult ParseGotoStmt(SourceLocation GotoLoc,
+ SourceLocation LabelLoc,
+ IdentifierInfo *LabelII);
+ virtual StmtResult ParseIndirectGotoStmt(SourceLocation GotoLoc,
+ SourceLocation StarLoc,
+ ExprTy *DestExp);
+ virtual StmtResult ParseContinueStmt(SourceLocation ContinueLoc,
+ Scope *CurScope);
+ virtual StmtResult ParseBreakStmt(SourceLocation GotoLoc, Scope *CurScope);
+
+ virtual StmtResult ParseReturnStmt(SourceLocation ReturnLoc,
+ ExprTy *RetValExp);
+
+ //===--------------------------------------------------------------------===//
+ // Expression Parsing Callbacks: SemaExpr.cpp.
+
+ // Primary Expressions.
+ virtual ExprResult ParseIdentifierExpr(Scope *S, SourceLocation Loc,
+ IdentifierInfo &II,
+ bool HasTrailingLParen);
+ virtual ExprResult ParseSimplePrimaryExpr(SourceLocation Loc,
+ tok::TokenKind Kind);
+ virtual ExprResult ParseNumericConstant(const LexerToken &);
+ virtual ExprResult ParseCharacterConstant(const LexerToken &);
+ virtual ExprResult ParseParenExpr(SourceLocation L, SourceLocation R,
+ ExprTy *Val);
+
+ /// ParseStringLiteral - The specified tokens were lexed as pasted string
+ /// fragments (e.g. "foo" "bar" L"baz").
+ virtual ExprResult ParseStringLiteral(const LexerToken *Toks, unsigned NumToks);
+
+ // Binary/Unary Operators. 'Tok' is the token for the operator.
+ virtual ExprResult ParseUnaryOp(SourceLocation OpLoc, tok::TokenKind Op,
+ ExprTy *Input);
+ virtual ExprResult
+ ParseSizeOfAlignOfTypeExpr(SourceLocation OpLoc, bool isSizeof,
+ SourceLocation LParenLoc, TypeTy *Ty,
+ SourceLocation RParenLoc);
+
+ virtual ExprResult ParsePostfixUnaryOp(SourceLocation OpLoc,
+ tok::TokenKind Kind, ExprTy *Input);
+
+ virtual ExprResult ParseArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc,
+ ExprTy *Idx, SourceLocation RLoc);
+ virtual ExprResult ParseMemberReferenceExpr(ExprTy *Base,SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation MemberLoc,
+ IdentifierInfo &Member);
+
+ /// ParseCallExpr - 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 ParseCallExpr(ExprTy *Fn, SourceLocation LParenLoc,
+ ExprTy **Args, unsigned NumArgs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc);
+
+ virtual ExprResult ParseCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
+ SourceLocation RParenLoc, ExprTy *Op);
+
+ virtual ExprResult ParseBinOp(SourceLocation TokLoc, tok::TokenKind Kind,
+ ExprTy *LHS,ExprTy *RHS);
+
+ /// ParseConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
+ /// in the case of a the GNU conditional expr extension.
+ virtual ExprResult ParseConditionalOp(SourceLocation QuestionLoc,
+ SourceLocation ColonLoc,
+ ExprTy *Cond, ExprTy *LHS, ExprTy *RHS);
+
+ /// ParseAddrLabel - Parse the GNU address of label extension: "&&foo".
+ virtual ExprResult ParseAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc,
+ IdentifierInfo *LabelII);
+
+ /// ParseCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's.
+ virtual ExprResult ParseCXXCasts(SourceLocation OpLoc, tok::TokenKind Kind,
+ SourceLocation LAngleBracketLoc, TypeTy *Ty,
+ SourceLocation RAngleBracketLoc,
+ SourceLocation LParenLoc, ExprTy *E,
+ SourceLocation RParenLoc);
+
+ /// ParseCXXBoolLiteral - Parse {true,false} literals.
+ virtual ExprResult ParseCXXBoolLiteral(SourceLocation OpLoc,
+ tok::TokenKind Kind);
+private:
+ // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts
+ // functions and arrays to their respective pointers (C99 6.3.2.1)
+ QualType UsualUnaryConversions(QualType t);
+ // 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(QualType &t1, QualType &t2);
+ // DefaultFunctionArrayConversion - converts functions and arrays
+ // to their respective pointers (C99 6.3.2.1). If the type isn't a function
+ // or array, this routine simply returns the input type (unmodified).
+ QualType DefaultFunctionArrayConversion(QualType t);
+
+ enum AssignmentCheckResult {
+ Compatible,
+ Incompatible,
+ PointerFromInt,
+ IntFromPointer,
+ IncompatiblePointer,
+ CompatiblePointerDiscardsQualifiers
+ };
+ // CheckAssignmentConstraints - conversions for assignment, argument passing,
+ // variable initialization, and function return values. Currently used by
+ // CheckAssignmentOperands, ParseCallExpr, and ParseReturnStmt. C99 6.5.16.
+ AssignmentCheckResult CheckAssignmentConstraints(QualType lhs, QualType rhs);
+ // Helper function for CheckAssignmentConstraints (C99 6.5.16.1p1)
+ AssignmentCheckResult 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 ParseBinOp).
+ inline void 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);
+ inline QualType CheckRemainderOperands( // C99 6.5.5
+ Expr *lex, Expr *rex, SourceLocation OpLoc);
+ inline QualType CheckAdditionOperands( // C99 6.5.6
+ Expr *lex, Expr *rex, SourceLocation OpLoc);
+ inline QualType CheckSubtractionOperands( // C99 6.5.6
+ Expr *lex, Expr *rex, SourceLocation OpLoc);
+ inline QualType CheckShiftOperands( // C99 6.5.7
+ Expr *lex, Expr *rex, SourceLocation OpLoc);
+ inline QualType CheckRelationalOperands( // C99 6.5.8
+ Expr *lex, Expr *rex, SourceLocation OpLoc);
+ inline QualType CheckEqualityOperands( // C99 6.5.9
+ Expr *lex, Expr *rex, SourceLocation OpLoc);
+ inline QualType CheckBitwiseOperands( // C99 6.5.[10...12]
+ Expr *lex, Expr *rex, SourceLocation OpLoc);
+ 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 ParseUnaryOp).
+ /// 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);
+
+ /// C99: 6.7.5p3: Used by ParseDeclarator/ParseField to make sure we have
+ /// a constant expression of type int with a value greater than zero. If the
+ /// array has an incomplete type or a valid constant size, return false,
+ /// otherwise emit a diagnostic and return true.
+ bool VerifyConstantArrayType(const ArrayType *ary, SourceLocation loc);
+};
+
+
+} // end namespace clang
+
+#endif
diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp
new file mode 100644
index 0000000..9b98c4b
--- /dev/null
+++ b/Sema/SemaDecl.cpp
@@ -0,0 +1,1024 @@
+//===--- SemaDecl.cpp - Semantic Analysis for Declarations ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and 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/ASTContext.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/Lex/IdentifierTable.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/SmallSet.h"
+using namespace clang;
+
+// C99: 6.7.5p3: Used by ParseDeclarator/ParseField to make sure we have
+// a constant expression of type int with a value greater than zero.
+bool Sema::VerifyConstantArrayType(const ArrayType *Array,
+ SourceLocation DeclLoc) {
+ const Expr *Size = Array->getSize();
+ if (Size == 0) return false; // incomplete type.
+
+ if (!Size->getType()->isIntegerType()) {
+ Diag(Size->getLocStart(), diag::err_array_size_non_int,
+ Size->getType().getAsString(), Size->getSourceRange());
+ return true;
+ }
+
+ // Verify that the size of the array is an integer constant expr.
+ SourceLocation Loc;
+ llvm::APSInt SizeVal(32);
+ if (!Size->isIntegerConstantExpr(SizeVal, &Loc)) {
+ // FIXME: This emits the diagnostic to enforce 6.7.2.1p8, but the message
+ // is wrong. It is also wrong for static variables.
+ // FIXME: This is also wrong for:
+ // int sub1(int i, char *pi) { typedef int foo[i];
+ // struct bar {foo f1; int f2:3; int f3:4} *p; }
+ Diag(DeclLoc, diag::err_typecheck_illegal_vla, Size->getSourceRange());
+ return true;
+ }
+
+ // We have a constant expression with an integer type, now make sure
+ // value greater than zero (C99 6.7.5.2p1).
+
+ // FIXME: This check isn't specific to static VLAs, this should be moved
+ // elsewhere or replicated. 'int X[-1];' inside a function should emit an
+ // error.
+ if (SizeVal.isSigned()) {
+ llvm::APSInt Zero(SizeVal.getBitWidth());
+ Zero.setIsUnsigned(false);
+ if (SizeVal < Zero) {
+ Diag(DeclLoc, diag::err_typecheck_negative_array_size,
+ Size->getSourceRange());
+ return true;
+ } else if (SizeVal == 0) {
+ // GCC accepts zero sized static arrays.
+ Diag(DeclLoc, diag::err_typecheck_zero_array_size,
+ Size->getSourceRange());
+ }
+ }
+ return false;
+}
+
+Sema::DeclTy *Sema::isTypeName(const IdentifierInfo &II, Scope *S) const {
+ return dyn_cast_or_null<TypedefDecl>(II.getFETokenInfo<Decl>());
+}
+
+void Sema::PopScope(SourceLocation Loc, Scope *S) {
+ for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end();
+ I != E; ++I) {
+ Decl *D = static_cast<Decl*>(*I);
+ assert(D && "This decl didn't get pushed??");
+ 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.
+ Decl *SomeDecl = II->getFETokenInfo<Decl>();
+ 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);
+ }
+}
+
+/// LookupScopedDecl - Look up the inner-most declaration in the specified
+/// namespace.
+Decl *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 (Decl *D = II->getFETokenInfo<Decl>(); 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 some other target, or if this builtin varies
+ // across targets (e.g. in type), emit a diagnostic and mark the translation
+ // unit non-portable for using it.
+ if (II->isNonPortableBuiltin()) {
+ // Only emit this diagnostic once for this builtin.
+ II->setNonPortableBuiltin(false);
+ Context.Target.DiagnoseNonPortability(IdLoc,
+ diag::port_target_builtin_use);
+ }
+ // 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;
+}
+
+/// LazilyCreateBuiltin - The specified Builtin-ID was first used at file scope.
+/// lazily create a decl for it.
+Decl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, Scope *S) {
+ Builtin::ID BID = (Builtin::ID)bid;
+
+ QualType R = Context.BuiltinInfo.GetBuiltinType(BID, Context);
+ FunctionDecl *New = new FunctionDecl(SourceLocation(), II, R,
+ FunctionDecl::Extern, 0);
+
+ // Find translation-unit scope to insert this function into.
+ while (S->getParent())
+ S = S->getParent();
+ S->AddDecl(New);
+
+ // Add this decl to the end of the identifier info.
+ if (Decl *LastDecl = II->getFETokenInfo<Decl>()) {
+ // 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);
+ }
+ // Make sure clients iterating over decls see this.
+ LastInGroupList.push_back(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, Decl *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;
+ }
+
+ // 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;
+}
+
+/// 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, Decl *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;
+ }
+
+ // This is not right, but it's a start. If 'Old' is a function prototype with
+ // the same type as 'New', silently allow this. FIXME: We should link up decl
+ // objects here.
+ if (Old->getBody() == 0 &&
+ Old->getCanonicalType() == New->getCanonicalType()) {
+ 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;
+}
+
+/// 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, Decl *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;
+ }
+ // Verify the types match.
+ if (Old->getCanonicalType() != New->getCanonicalType()) {
+ Diag(New->getLocation(), diag::err_redefinition, New->getName());
+ Diag(Old->getLocation(), diag::err_previous_definition);
+ return New;
+ }
+ // We've verified the types match, now check if Old is "extern".
+ if (Old->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 0;
+}
+
+Sema::DeclTy *
+Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *Init,
+ DeclTy *lastDeclarator) {
+ Decl *LastDeclarator = (Decl*)lastDeclarator;
+ IdentifierInfo *II = D.getIdentifier();
+
+ // See if this is a redefinition of a variable in the same scope.
+ Decl *PrevDecl = LookupScopedDecl(II, Decl::IDNS_Ordinary,
+ D.getIdentifierLoc(), S);
+ if (PrevDecl && !S->isDeclScope(PrevDecl))
+ PrevDecl = 0; // If in outer scope, it isn't the same thing.
+
+ Decl *New;
+ if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
+ TypedefDecl *NewTD = ParseTypedefDecl(S, D, 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 (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 (ArrayType *ary = dyn_cast<ArrayType>(NewTD->getUnderlyingType())) {
+ if (VerifyConstantArrayType(ary, D.getIdentifierLoc()))
+ return 0;
+ }
+ }
+ } else if (D.isFunctionDeclarator()) {
+ QualType R = GetTypeForDeclarator(D, S);
+ if (R.isNull()) return 0; // FIXME: "auto func();" passes through...
+
+ FunctionDecl::StorageClass SC;
+ 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());
+ return 0;
+ case DeclSpec::SCS_unspecified: SC = FunctionDecl::None; break;
+ case DeclSpec::SCS_extern: SC = FunctionDecl::Extern; break;
+ case DeclSpec::SCS_static: SC = FunctionDecl::Static; break;
+ }
+
+ FunctionDecl *NewFD = new FunctionDecl(D.getIdentifierLoc(), II, R, SC,
+ LastDeclarator);
+
+ // Merge the decl with the existing one if appropriate.
+ if (PrevDecl) {
+ NewFD = MergeFunctionDecl(NewFD, PrevDecl);
+ if (NewFD == 0) return 0;
+ }
+ New = NewFD;
+ } else {
+ QualType R = GetTypeForDeclarator(D, S);
+ if (R.isNull()) return 0;
+
+ 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;
+ }
+ if (S->getParent() == 0) {
+ // 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 (!Init && SC == VarDecl::Static) {
+ // 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.
+ if (R->isIncompleteType()) {
+ Diag(D.getIdentifierLoc(), diag::err_typecheck_decl_incomplete_type,
+ R.getAsString());
+ return 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());
+ return 0;
+ }
+ // 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 (ArrayType *ary = dyn_cast<ArrayType>(R.getCanonicalType())) {
+ if (VerifyConstantArrayType(ary, D.getIdentifierLoc()))
+ return 0;
+ }
+ NewVD = new FileVarDecl(D.getIdentifierLoc(), II, R, SC, LastDeclarator);
+ } else {
+ // 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 (SC != VarDecl::Extern) {
+ if (R->isIncompleteType()) {
+ Diag(D.getIdentifierLoc(), diag::err_typecheck_decl_incomplete_type,
+ R.getAsString());
+ return 0;
+ }
+ }
+ if (SC == VarDecl::Static) {
+ // 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 (ArrayType *ary = dyn_cast<ArrayType>(R.getCanonicalType())) {
+ if (VerifyConstantArrayType(ary, D.getIdentifierLoc()))
+ return 0;
+ }
+ }
+ NewVD = new BlockVarDecl(D.getIdentifierLoc(), II, R, SC, LastDeclarator);
+ }
+ // Handle attributes prior to checking for duplicates in MergeVarDecl
+ HandleDeclAttributes(NewVD, D.getDeclSpec().getAttributes(),
+ D.getAttributes());
+
+ // Merge the decl with the existing one if appropriate.
+ if (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<Decl>());
+ II->setFETokenInfo(New);
+ S->AddDecl(New);
+ }
+
+ if (S->getParent() == 0)
+ AddTopLevelDecl(New, LastDeclarator);
+
+ return New;
+}
+
+/// 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 *Group = static_cast<Decl*>(group);
+ if (Group == 0 || Group->getNextDeclarator() == 0) return Group;
+
+ Decl *NewGroup = 0;
+ while (Group) {
+ Decl *Next = Group->getNextDeclarator();
+ Group->setNextDeclarator(NewGroup);
+ NewGroup = Group;
+ Group = Next;
+ }
+ return NewGroup;
+}
+
+ParmVarDecl *
+Sema::ParseParamDeclarator(DeclaratorChunk &FTI, unsigned ArgNo,
+ Scope *FnScope) {
+ const DeclaratorChunk::ParamInfo &PI = FTI.Fun.ArgInfo[ArgNo];
+
+ 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?
+ ParmVarDecl *New = new ParmVarDecl(PI.IdentLoc, II,
+ QualType::getFromOpaquePtr(PI.TypeInfo),
+ VarDecl::None, 0);
+
+ // If this has an identifier, add it to the scope stack.
+ if (II) {
+ New->setNext(II->getFETokenInfo<Decl>());
+ II->setFETokenInfo(New);
+ FnScope->AddDecl(New);
+ }
+
+ return New;
+}
+
+
+Sema::DeclTy *Sema::ParseStartOfFunctionDef(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.
+ FTI.hasPrototype = true;
+ } else {
+ // FIXME: Diagnose arguments without names in C.
+
+ }
+
+ Scope *GlobalScope = FnBodyScope->getParent();
+
+ FunctionDecl *FD =
+ static_cast<FunctionDecl*>(ParseDeclarator(GlobalScope, D, 0, 0));
+ 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 &&
+ FTI.ArgInfo[0].TypeInfo == Context.VoidTy.getAsOpaquePtr()) {
+ // empty arg list, don't push any params.
+ } else {
+ for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
+ Params.push_back(ParseParamDeclarator(D.getTypeObject(0), i,FnBodyScope));
+ }
+
+ FD->setParams(&Params[0], Params.size());
+
+ return FD;
+}
+
+Sema::DeclTy *Sema::ParseFunctionDefBody(DeclTy *D, StmtTy *Body) {
+ FunctionDecl *FD = static_cast<FunctionDecl*>(D);
+ FD->setBody((Stmt*)Body);
+
+ assert(FD == CurFunctionDecl && "Function parsing confused");
+ CurFunctionDecl = 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.
+ L->setSubStmt(new NullStmt(L->getIdentLoc()));
+ cast<CompoundStmt>((Stmt*)Body)->push_back(L);
+ }
+ }
+ LabelMap.clear();
+
+ return FD;
+}
+
+
+/// ImplicitlyDefineFunction - An undeclared identifier was used in a function
+/// call, forming a call to an implicitly defined function (per C99 6.5.1p2).
+Decl *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.
+ while (S->getParent())
+ S = S->getParent();
+
+ return static_cast<Decl*>(ParseDeclarator(S, D, 0, 0));
+}
+
+
+TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D,
+ Decl *LastDeclarator) {
+ assert(D.getIdentifier() && "Wrong callback for declspec without declarator");
+
+ QualType T = GetTypeForDeclarator(D, S);
+ if (T.isNull()) return 0;
+
+ // Scope manipulation handled by caller.
+ return new TypedefDecl(D.getIdentifierLoc(), D.getIdentifier(), T,
+ LastDeclarator);
+}
+
+
+/// ParseTag - 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::ParseTag(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 = new EnumDecl(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 = new RecordDecl(Kind, Loc, Name, 0);
+ break;
+ }
+
+ // If this has an identifier, add it to the scope stack.
+ if (Name) {
+ New->setNext(Name->getFETokenInfo<Decl>());
+ Name->setFETokenInfo(New);
+ S->AddDecl(New);
+ }
+
+ return New;
+}
+
+/// ParseField - Each field of a struct/union/class is passed into this in order
+/// to create a FieldDecl object for it.
+Sema::DeclTy *Sema::ParseField(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);
+ if (T.isNull()) return 0;
+
+ // C99 6.7.2.1p8: A member of a structure or union may have any type other
+ // than a variably modified type.
+ if (ArrayType *ary = dyn_cast<ArrayType>(T.getCanonicalType())) {
+ if (VerifyConstantArrayType(ary, Loc))
+ return 0;
+ }
+
+ // FIXME: Chain fielddecls together.
+ return new FieldDecl(Loc, II, T, 0);
+}
+
+void Sema::ParseRecordBody(SourceLocation RecLoc, DeclTy *RecDecl,
+ DeclTy **Fields, unsigned NumFields) {
+ RecordDecl *Record = cast<RecordDecl>(static_cast<Decl*>(RecDecl));
+ if (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);
+ 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]));
+ if (!FD) continue; // Already issued a diagnostic.
+
+ // Get the type for the field.
+ Type *FDTy = FD->getType().getCanonicalType().getTypePtr();
+
+ // C99 6.7.2.1p2 - A field may not be a function type.
+ if (isa<FunctionType>(FDTy)) {
+ Diag(FD->getLocation(), diag::err_field_declared_as_function,
+ FD->getName());
+ delete FD;
+ continue;
+ }
+
+ // C99 6.7.2.1p2 - A field may not be an incomplete type except...
+ if (FDTy->isIncompleteType()) {
+ if (i != NumFields-1 || // ... that the last member ...
+ Record->getKind() != Decl::Struct || // ... of a structure ...
+ !isa<ArrayType>(FDTy)) { //... may have incomplete array type.
+ Diag(FD->getLocation(), diag::err_field_incomplete, FD->getName());
+ delete FD;
+ continue;
+ }
+ if (NumNamedMembers < 1) { //... must have more than named member ...
+ Diag(FD->getLocation(), diag::err_flexible_array_empty_struct,
+ FD->getName());
+ delete FD;
+ continue;
+ }
+
+ // Okay, we have a legal flexible array member at the end of the struct.
+ 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 (RecordType *FDTTy = dyn_cast<RecordType>(FDTy)) {
+ if (FDTTy->getDecl()->hasFlexibleArrayMember()) {
+ // If this is a member of a union, then entire union becomes "flexible".
+ if (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());
+ delete FD;
+ 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());
+ Record->setHasFlexibleArrayMember(true);
+ }
+ }
+ }
+
+ // 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);
+ delete FD;
+ continue;
+ }
+ ++NumNamedMembers;
+ }
+
+ // Remember good fields.
+ RecFields.push_back(FD);
+ }
+
+
+ // Okay, we successfully defined 'Record'.
+ Record->defineBody(&RecFields[0], RecFields.size());
+}
+
+Sema::DeclTy *Sema::ParseEnumConstant(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);
+
+ // Verify that there isn't already something declared with this name in this
+ // scope.
+ if (Decl *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);
+ // FIXME: Don't leak memory: delete Val;
+ return 0;
+ }
+ }
+
+ llvm::APSInt EnumVal(32);
+ QualType EltTy;
+ if (Val) {
+ // C99 6.7.2.2p2: Make sure we have an integer constant expression.
+ SourceLocation ExpLoc;
+ if (!Val->isIntegerConstantExpr(EnumVal, &ExpLoc)) {
+ Diag(ExpLoc, diag::err_enum_value_not_integer_constant_expr,
+ Id->getName());
+ // FIXME: Don't leak memory: delete Val;
+ return 0;
+ }
+ EltTy = Val->getType();
+ } else if (LastEnumConst) {
+ // Assign the last value + 1.
+ EnumVal = LastEnumConst->getInitVal();
+ ++EnumVal;
+ // FIXME: detect overflow!
+ EltTy = LastEnumConst->getType();
+ } else {
+ // First value, set to zero.
+ EltTy = Context.IntTy;
+ // FIXME: Resize EnumVal to the size of int.
+ }
+
+ // TODO: Default promotions to int/uint.
+
+ // 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.
+
+ EnumConstantDecl *New = new EnumConstantDecl(IdLoc, Id, EltTy, Val, EnumVal,
+ LastEnumConst);
+
+ // Register this decl in the current scope stack.
+ New->setNext(Id->getFETokenInfo<Decl>());
+ Id->setFETokenInfo(New);
+ S->AddDecl(New);
+ return New;
+}
+
+void Sema::ParseEnumBody(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");
+
+ // Verify that all the values are okay, and reverse the list.
+ 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.
+
+ ECD->setNextDeclarator(EltList);
+ EltList = ECD;
+ }
+
+ Enum->defineElements(EltList);
+}
+
+void Sema::AddTopLevelDecl(Decl *current, Decl *last) {
+ if (!current) return;
+
+ // If this is a top-level decl that is chained to some other (e.g. int A,B,C;)
+ // remember this in the LastInGroupList list.
+ if (last)
+ LastInGroupList.push_back((Decl*)last);
+}
+
+void Sema::HandleDeclAttribute(Decl *New, AttributeList *rawAttr) {
+ if (strcmp(rawAttr->getAttributeName()->getName(), "vector_size") == 0) {
+ if (ValueDecl *vDecl = dyn_cast<ValueDecl>(New)) {
+ QualType newType = HandleVectorTypeAttribute(vDecl->getType(), rawAttr);
+ 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(),
+ rawAttr);
+ if (!newType.isNull()) // install the new vector type into the decl
+ tDecl->setUnderlyingType(newType);
+ }
+ }
+ // FIXME: add other attributes...
+}
+
+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();
+ }
+}
+
+QualType Sema::HandleVectorTypeAttribute(QualType curType,
+ AttributeList *rawAttr) {
+ // check the attribute arugments.
+ if (rawAttr->getNumArgs() != 1) {
+ Diag(rawAttr->getAttributeLoc(), 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)) {
+ Diag(rawAttr->getAttributeLoc(), diag::err_attribute_vector_size_not_int,
+ 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();
+
+ while (canonType->isPointerType() || canonType->isArrayType() ||
+ canonType->isFunctionType()) {
+ 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();
+ }
+ // the base type must be integer or float.
+ if (!(canonType->isIntegerType() || canonType->isRealFloatingType())) {
+ Diag(rawAttr->getAttributeLoc(), diag::err_attribute_invalid_vector_type,
+ curType.getCanonicalType().getAsString());
+ return QualType();
+ }
+ BuiltinType *baseType = cast<BuiltinType>(canonType);
+ unsigned typeSize = baseType->getSize();
+ // vecSize is specified in bytes - convert to bits.
+ unsigned vectorSize = vecSize.getZExtValue() * 8;
+
+ // the vector size needs to be an integral multiple of the type size.
+ if (vectorSize % typeSize) {
+ Diag(rawAttr->getAttributeLoc(), diag::err_attribute_invalid_size,
+ sizeExpr->getSourceRange());
+ return QualType();
+ }
+ if (vectorSize == 0) {
+ Diag(rawAttr->getAttributeLoc(), diag::err_attribute_zero_size,
+ sizeExpr->getSourceRange());
+ return QualType();
+ }
+ // Since OpenCU requires 3 element vectors (OpenCU 5.1.2), we don't restrict
+ // the number of elements to be a power of two (unlike GCC).
+ // Instantiate the vector type, the number of elements is > 0.
+ return Context.convertToVectorType(curType, vectorSize/typeSize);
+}
+
diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp
new file mode 100644
index 0000000..4f0935a
--- /dev/null
+++ b/Sema/SemaExpr.cpp
@@ -0,0 +1,1364 @@
+//===--- SemaExpr.cpp - Semantic Analysis for Expressions -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements semantic analysis for expressions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.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"
+using namespace clang;
+
+/// ParseStringLiteral - 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::ParseStringLiteral(const LexerToken *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());
+
+ // FIXME: handle wchar_t
+ QualType t = Context.getPointerType(Context.CharTy);
+
+ // Pass &StringTokLocs[0], StringTokLocs.size() to factory!
+ return new StringLiteral(Literal.GetString(), Literal.GetStringLength(),
+ Literal.AnyWide, t, StringToks[0].getLocation(),
+ StringToks[NumStringToks-1].getLocation());
+}
+
+
+/// ParseIdentifierExpr - 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::ParseIdentifierExpr(Scope *S, SourceLocation Loc,
+ IdentifierInfo &II,
+ bool HasTrailingLParen) {
+ // Could be enum-constant or decl.
+ Decl *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 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))
+ return new DeclRefExpr(VD, VD->getType(), Loc);
+ if (isa<TypedefDecl>(D))
+ return Diag(Loc, diag::err_unexpected_typedef, II.getName());
+
+ assert(0 && "Invalid decl");
+}
+
+Sema::ExprResult Sema::ParseSimplePrimaryExpr(SourceLocation Loc,
+ tok::TokenKind Kind) {
+ switch (Kind) {
+ default:
+ assert(0 && "Unknown simple primary expr!");
+ // TODO: MOVE this to be some other callback.
+ case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2]
+ case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU]
+ case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU]
+ return 0;
+ }
+}
+
+Sema::ExprResult Sema::ParseCharacterConstant(const LexerToken &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);
+ return new CharacterLiteral(Literal.getValue(), Context.IntTy,
+ Tok.getLocation());
+}
+
+Action::ExprResult Sema::ParseNumericConstant(const LexerToken &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 = Context.Target.getIntWidth(Tok.getLocation());
+ 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);
+
+ if (Literal.isIntegerLiteral()) {
+ QualType t;
+
+ // Get the value in the widest-possible width.
+ llvm::APInt ResultVal(Context.Target.getIntMaxTWidth(Tok.getLocation()), 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.getIntegerBitwidth(t, Tok.getLocation()) ==
+ 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) { // Are int/unsigned possibilities?
+ unsigned IntSize = Context.Target.getIntWidth(Tok.getLocation());
+ // 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 = Context.Target.getLongWidth(Tok.getLocation());
+
+ // 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 =
+ Context.Target.getLongLongWidth(Tok.getLocation());
+
+ // 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;
+ }
+ }
+
+ return new IntegerLiteral(ResultVal, t, Tok.getLocation());
+ } else if (Literal.isFloatingLiteral()) {
+ // FIXME: handle float values > 32 (including compute the real type...).
+ return new FloatingLiteral(Literal.GetFloatValue(), Context.FloatTy,
+ Tok.getLocation());
+ }
+ return ExprResult(true);
+}
+
+Action::ExprResult Sema::ParseParenExpr(SourceLocation L, SourceLocation R,
+ ExprTy *Val) {
+ Expr *e = (Expr *)Val;
+ assert((e != 0) && "ParseParenExpr() 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::
+ParseSizeOfAlignOfTypeExpr(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);
+}
+
+
+Action::ExprResult Sema::ParsePostfixUnaryOp(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::
+ParseArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc,
+ ExprTy *Idx, SourceLocation RLoc) {
+ QualType t1 = ((Expr *)Base)->getType();
+ QualType t2 = ((Expr *)Idx)->getType();
+
+ assert(!t1.isNull() && "no type for array base expression");
+ assert(!t2.isNull() && "no type for array index expression");
+
+ QualType canonT1 = DefaultFunctionArrayConversion(t1).getCanonicalType();
+ QualType canonT2 = DefaultFunctionArrayConversion(t2).getCanonicalType();
+
+ // 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 baseType, indexType;
+ if (isa<PointerType>(canonT1) || isa<VectorType>(canonT1)) {
+ baseType = canonT1;
+ indexType = canonT2;
+ baseExpr = static_cast<Expr *>(Base);
+ indexExpr = static_cast<Expr *>(Idx);
+ } else if (isa<PointerType>(canonT2)) { // uncommon
+ baseType = canonT2;
+ indexType = canonT1;
+ baseExpr = static_cast<Expr *>(Idx);
+ indexExpr = static_cast<Expr *>(Base);
+ } else {
+ return Diag(static_cast<Expr *>(Base)->getLocStart(),
+ diag::err_typecheck_subscript_value,
+ static_cast<Expr *>(Base)->getSourceRange());
+ }
+ // C99 6.5.2.1p1
+ if (!indexType->isIntegerType()) {
+ return Diag(indexExpr->getLocStart(), diag::err_typecheck_subscript,
+ indexExpr->getSourceRange());
+ }
+ QualType resultType;
+ if (PointerType *ary = dyn_cast<PointerType>(baseType)) {
+ // FIXME: need to deal with const...
+ resultType = ary->getPointeeType();
+ // 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,
+ baseType.getAsString(), baseExpr->getSourceRange());
+ }
+ } else if (VectorType *vec = dyn_cast<VectorType>(baseType))
+ resultType = vec->getElementType();
+
+ return new ArraySubscriptExpr((Expr*)Base, (Expr*)Idx, resultType, RLoc);
+}
+
+Action::ExprResult Sema::
+ParseMemberReferenceExpr(ExprTy *Base, SourceLocation OpLoc,
+ tok::TokenKind OpKind, SourceLocation MemberLoc,
+ IdentifierInfo &Member) {
+ QualType qualifiedType = ((Expr *)Base)->getType();
+
+ assert(!qualifiedType.isNull() && "no type for member expression");
+
+ QualType canonType = qualifiedType.getCanonicalType();
+
+ if (OpKind == tok::arrow) {
+ if (PointerType *PT = dyn_cast<PointerType>(canonType)) {
+ qualifiedType = PT->getPointeeType();
+ canonType = qualifiedType.getCanonicalType();
+ } else
+ return Diag(OpLoc, diag::err_typecheck_member_reference_arrow);
+ }
+ if (!isa<RecordType>(canonType))
+ return Diag(OpLoc, diag::err_typecheck_member_reference_structUnion);
+
+ // get the struct/union definition from the type.
+ RecordDecl *RD = cast<RecordType>(canonType)->getDecl();
+
+ if (canonType->isIncompleteType())
+ return Diag(OpLoc, diag::err_typecheck_incomplete_tag, RD->getName());
+
+ FieldDecl *MemberDecl = RD->getMember(&Member);
+ if (!MemberDecl)
+ return Diag(OpLoc, diag::err_typecheck_no_member, Member.getName());
+
+ return new MemberExpr((Expr*)Base, OpKind == tok::arrow,
+ MemberDecl, MemberLoc);
+}
+
+/// ParseCallExpr - 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::
+ParseCallExpr(ExprTy *Fn, SourceLocation LParenLoc,
+ ExprTy **Args, unsigned NumArgsInCall,
+ SourceLocation *CommaLocs, SourceLocation RParenLoc) {
+ Expr *funcExpr = (Expr *)Fn;
+ assert(funcExpr && "no function call expression");
+
+ QualType qType = UsualUnaryConversions(funcExpr->getType());
+ assert(!qType.isNull() && "no type for function call expression");
+
+ // C99 6.5.2.2p1 - "The expression that denotes the called function shall have
+ // type pointer to function".
+ const PointerType *PT = dyn_cast<PointerType>(qType);
+ if (PT == 0) PT = dyn_cast<PointerType>(qType.getCanonicalType());
+
+ if (PT == 0)
+ return Diag(funcExpr->getLocStart(), diag::err_typecheck_call_not_function,
+ SourceRange(funcExpr->getLocStart(), RParenLoc));
+
+ const FunctionType *funcT = dyn_cast<FunctionType>(PT->getPointeeType());
+ if (funcT == 0)
+ funcT = dyn_cast<FunctionType>(PT->getPointeeType().getCanonicalType());
+
+ if (funcT == 0)
+ return Diag(funcExpr->getLocStart(), diag::err_typecheck_call_not_function,
+ SourceRange(funcExpr->getLocStart(), RParenLoc));
+
+ // If a prototype isn't declared, the parser implicitly defines a func decl
+ QualType resultType = 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 = NumArgsInCall;
+
+ if (NumArgsInCall < NumArgsInProto)
+ Diag(RParenLoc, diag::err_typecheck_call_too_few_args,
+ funcExpr->getSourceRange());
+ else if (NumArgsInCall > NumArgsInProto) {
+ if (!proto->isVariadic()) {
+ Diag(((Expr **)Args)[NumArgsInProto+1]->getLocStart(),
+ diag::err_typecheck_call_too_many_args, funcExpr->getSourceRange(),
+ ((Expr **)Args)[NumArgsInProto+1]->getSourceRange());
+ }
+ NumArgsToCheck = NumArgsInProto;
+ }
+ // Continue to check argument types (even if we have too few/many args).
+ for (unsigned i = 0; i < NumArgsToCheck; i++) {
+ Expr *argExpr = ((Expr **)Args)[i];
+ assert(argExpr && "ParseCallExpr(): missing argument expression");
+
+ QualType lhsType = proto->getArgType(i);
+ QualType rhsType = argExpr->getType();
+
+ if (lhsType == rhsType) // common case, fast path...
+ continue;
+
+ AssignmentCheckResult result = CheckAssignmentConstraints(lhsType,
+ rhsType);
+ SourceLocation l = argExpr->getLocStart();
+
+ // decode the result (notice that AST's are still created for extensions).
+ switch (result) {
+ case Compatible:
+ break;
+ case PointerFromInt:
+ // check for null pointer constant (C99 6.3.2.3p3)
+ if (!argExpr->isNullPointerConstant()) {
+ Diag(l, diag::ext_typecheck_passing_pointer_int,
+ lhsType.getAsString(), rhsType.getAsString(),
+ funcExpr->getSourceRange(), argExpr->getSourceRange());
+ }
+ break;
+ case IntFromPointer:
+ Diag(l, diag::ext_typecheck_passing_pointer_int,
+ lhsType.getAsString(), rhsType.getAsString(),
+ funcExpr->getSourceRange(), argExpr->getSourceRange());
+ break;
+ case IncompatiblePointer:
+ Diag(l, diag::ext_typecheck_passing_incompatible_pointer,
+ rhsType.getAsString(), lhsType.getAsString(),
+ funcExpr->getSourceRange(), argExpr->getSourceRange());
+ break;
+ case CompatiblePointerDiscardsQualifiers:
+ Diag(l, diag::ext_typecheck_passing_discards_qualifiers,
+ rhsType.getAsString(), lhsType.getAsString(),
+ funcExpr->getSourceRange(), argExpr->getSourceRange());
+ break;
+ case Incompatible:
+ return Diag(l, diag::err_typecheck_passing_incompatible,
+ rhsType.getAsString(), lhsType.getAsString(),
+ funcExpr->getSourceRange(), argExpr->getSourceRange());
+ }
+ }
+ // Even if the types checked, bail if we had the wrong number of arguments.
+ if ((NumArgsInCall != NumArgsInProto) && !proto->isVariadic())
+ return true;
+ }
+ return new CallExpr((Expr*)Fn, (Expr**)Args, NumArgsInCall, resultType,
+ RParenLoc);
+}
+
+Action::ExprResult Sema::
+ParseCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
+ SourceLocation RParenLoc, ExprTy *Op) {
+ // If error parsing type, ignore.
+ assert((Ty != 0) && "ParseCastExpr(): missing type");
+ // FIXME: Sema for cast is completely missing.
+ return new CastExpr(QualType::getFromOpaquePtr(Ty), (Expr*)Op, LParenLoc);
+}
+
+inline QualType Sema::CheckConditionalOperands( // C99 6.5.15
+ Expr *Cond, Expr *LHS, Expr *RHS, SourceLocation questionLoc) {
+ QualType cond = Cond->getType();
+ QualType lhs = LHS->getType();
+ QualType rhs = RHS->getType();
+
+ assert(!cond.isNull() && "ParseConditionalOp(): no conditional type");
+ assert(!lhs.isNull() && "ParseConditionalOp(): no lhs type");
+ assert(!rhs.isNull() && "ParseConditionalOp(): no rhs type");
+
+ cond = UsualUnaryConversions(cond);
+ lhs = UsualUnaryConversions(lhs);
+ rhs = UsualUnaryConversions(rhs);
+
+ // first, check the condition.
+ if (!cond->isScalarType()) { // C99 6.5.15p2
+ Diag(Cond->getLocStart(), diag::err_typecheck_cond_expect_scalar,
+ cond.getAsString());
+ return QualType();
+ }
+ // now check the two expressions.
+ if (lhs->isArithmeticType() && rhs->isArithmeticType()) // C99 6.5.15p3,5
+ return UsualArithmeticConversions(lhs, rhs);
+
+ if ((lhs->isStructureType() && rhs->isStructureType()) || // C99 6.5.15p3
+ (lhs->isUnionType() && rhs->isUnionType())) {
+ TagType *lTag = cast<TagType>(lhs.getCanonicalType());
+ TagType *rTag = cast<TagType>(rhs.getCanonicalType());
+
+ if (lTag->getDecl()->getIdentifier() == rTag->getDecl()->getIdentifier())
+ return lhs;
+ else {
+ Diag(questionLoc, diag::err_typecheck_cond_incompatible_operands,
+ lhs.getAsString(), rhs.getAsString(),
+ LHS->getSourceRange(), RHS->getSourceRange());
+ return QualType();
+ }
+ }
+ if (lhs->isPointerType() && RHS->isNullPointerConstant()) // C99 6.5.15p3
+ return lhs;
+ if (rhs->isPointerType() && LHS->isNullPointerConstant())
+ return rhs;
+
+ if (lhs->isPointerType() && rhs->isPointerType()) { // C99 6.5.15p3,6
+ QualType lhptee, rhptee;
+
+ // get the "pointed to" type
+ lhptee = cast<PointerType>(lhs.getCanonicalType())->getPointeeType();
+ rhptee = cast<PointerType>(rhs.getCanonicalType())->getPointeeType();
+
+ // ignore qualifiers on void (C99 6.5.15p3, clause 6)
+ if (lhptee.getUnqualifiedType()->isVoidType() &&
+ (rhptee->isObjectType() || rhptee->isIncompleteType()))
+ return lhs;
+ if (rhptee.getUnqualifiedType()->isVoidType() &&
+ (lhptee->isObjectType() || lhptee->isIncompleteType()))
+ return rhs;
+
+ // FIXME: 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.
+ if (!Type::typesAreCompatible(lhptee.getUnqualifiedType(),
+ rhptee.getUnqualifiedType())) {
+ Diag(questionLoc, diag::ext_typecheck_cond_incompatible_pointers,
+ lhs.getAsString(), rhs.getAsString(),
+ LHS->getSourceRange(), RHS->getSourceRange());
+ return lhs; // FIXME: this is an _ext - is this return o.k?
+ }
+ }
+ if (lhs->isVoidType() && rhs->isVoidType()) // C99 6.5.15p3
+ return lhs;
+
+ Diag(questionLoc, diag::err_typecheck_cond_incompatible_operands,
+ lhs.getAsString(), rhs.getAsString(),
+ LHS->getSourceRange(), RHS->getSourceRange());
+ return QualType();
+}
+
+/// ParseConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
+/// in the case of a the GNU conditional expr extension.
+Action::ExprResult Sema::ParseConditionalOp(SourceLocation QuestionLoc,
+ SourceLocation ColonLoc,
+ ExprTy *Cond, ExprTy *LHS,
+ ExprTy *RHS) {
+ QualType result = CheckConditionalOperands((Expr *)Cond, (Expr *)LHS,
+ (Expr *)RHS, QuestionLoc);
+ if (result.isNull())
+ return true;
+ return new ConditionalOperator((Expr*)Cond, (Expr*)LHS, (Expr*)RHS, result);
+}
+
+inline QualType Sema::DefaultFunctionArrayConversion(QualType t) {
+ if (t->isFunctionType()) // C99 6.3.2.1p4
+ return Context.getPointerType(t);
+ if (const ArrayType *ary = dyn_cast<ArrayType>(t.getCanonicalType()))
+ return Context.getPointerType(ary->getElementType()); // C99 6.3.2.1p3
+ return t;
+}
+
+/// UsualUnaryConversion - 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.
+QualType Sema::UsualUnaryConversions(QualType t) {
+ assert(!t.isNull() && "UsualUnaryConversions - missing type");
+
+ if (t->isPromotableIntegerType()) // C99 6.3.1.1p2
+ return Context.IntTy;
+ return DefaultFunctionArrayConversion(t);
+}
+
+/// 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.
+QualType Sema::UsualArithmeticConversions(QualType &lhs, QualType &rhs) {
+ lhs = UsualUnaryConversions(lhs);
+ rhs = UsualUnaryConversions(rhs);
+
+ // 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())
+ return lhs;
+ if (!rhs->isArithmeticType())
+ return rhs;
+
+ // 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())
+ return lhs;
+ if (lhs->isIntegerType())
+ return rhs;
+
+ return Context.maxComplexType(lhs, rhs);
+ }
+
+ // 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())
+ return lhs;
+ if (lhs->isIntegerType())
+ return rhs;
+
+ // we have two real floating types, float/complex combos were handled above.
+ return Context.maxFloatingType(lhs, rhs);
+ }
+ return Context.maxIntegerType(lhs, 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::AssignmentCheckResult
+Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
+ QualType lhptee, rhptee;
+
+ // get the "pointed to" type (ignoring qualifiers at the top level)
+ lhptee = cast<PointerType>(lhsType.getCanonicalType())->getPointeeType();
+ rhptee = cast<PointerType>(rhsType.getCanonicalType())->getPointeeType();
+
+ // make sure we operate on the canonical type
+ lhptee = lhptee.getCanonicalType();
+ rhptee = rhptee.getCanonicalType();
+
+ AssignmentCheckResult r = 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;
+ if ((lhptee.getQualifiers() & rhptee.getQualifiers()) !=
+ rhptee.getQualifiers())
+ r = 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.getUnqualifiedType()->isVoidType() &&
+ (rhptee->isObjectType() || rhptee->isIncompleteType()))
+ ;
+ else if (rhptee.getUnqualifiedType()->isVoidType() &&
+ (lhptee->isObjectType() || lhptee->isIncompleteType()))
+ ;
+ // C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or
+ // unqualified versions of compatible types, ...
+ else if (!Type::typesAreCompatible(lhptee.getUnqualifiedType(),
+ rhptee.getUnqualifiedType()))
+ r = IncompatiblePointer; // this "trumps" PointerAssignDiscardsQualifiers
+ return r;
+}
+
+/// 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::AssignmentCheckResult
+Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
+ // This check seems unnatural, however it is necessary to insure the proper
+ // conversion of functions/arrays. If the conversion were done for all
+ // DeclExpr's (created by ParseIdentifierExpr), it would mess up the unary
+ // expressions that surpress this implicit conversion (&, sizeof).
+ rhsType = DefaultFunctionArrayConversion(rhsType);
+
+ if (lhsType->isArithmeticType() && rhsType->isArithmeticType()) {
+ if (lhsType->isVectorType() || rhsType->isVectorType()) {
+ if (lhsType.getCanonicalType() != rhsType.getCanonicalType())
+ return Incompatible;
+ }
+ return Compatible;
+ } else if (lhsType->isPointerType()) {
+ if (rhsType->isIntegerType())
+ return PointerFromInt;
+
+ if (rhsType->isPointerType())
+ return CheckPointerTypesForAssignment(lhsType, rhsType);
+ } else 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 IntFromPointer;
+
+ if (lhsType->isPointerType())
+ return CheckPointerTypesForAssignment(lhsType, rhsType);
+ } else if (isa<TagType>(lhsType) && isa<TagType>(rhsType)) {
+ if (Type::tagTypesAreCompatible(lhsType, rhsType))
+ return Compatible;
+ } else if (lhsType->isReferenceType() || rhsType->isReferenceType()) {
+ if (Type::referenceTypesAreCompatible(lhsType, rhsType))
+ return Compatible;
+ }
+ return Incompatible;
+}
+
+inline void 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());
+}
+
+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;
+ // 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)
+{
+ QualType lhsType = lex->getType(), rhsType = rex->getType();
+
+ if (lhsType->isVectorType() || rhsType->isVectorType())
+ return CheckVectorOperands(loc, lex, rex);
+ QualType resType = UsualArithmeticConversions(lhsType, rhsType);
+
+ if (resType->isArithmeticType())
+ return resType;
+ InvalidOperands(loc, lex, rex);
+ return QualType();
+}
+
+inline QualType Sema::CheckRemainderOperands(
+ Expr *lex, Expr *rex, SourceLocation loc)
+{
+ QualType lhsType = lex->getType(), rhsType = rex->getType();
+ QualType resType = UsualArithmeticConversions(lhsType, rhsType);
+
+ if (resType->isIntegerType())
+ return resType;
+ InvalidOperands(loc, lex, rex);
+ return QualType();
+}
+
+inline QualType Sema::CheckAdditionOperands( // C99 6.5.6
+ Expr *lex, Expr *rex, SourceLocation loc)
+{
+ QualType lhsType = lex->getType(), rhsType = rex->getType();
+
+ if (lhsType->isVectorType() || rhsType->isVectorType())
+ return CheckVectorOperands(loc, lex, rex);
+ QualType resType = UsualArithmeticConversions(lhsType, rhsType);
+
+ // handle the common case first (both operands are arithmetic).
+ if (resType->isArithmeticType())
+ return resType;
+
+ if ((lhsType->isPointerType() && rhsType->isIntegerType()) ||
+ (lhsType->isIntegerType() && rhsType->isPointerType()))
+ return resType;
+ InvalidOperands(loc, lex, rex);
+ return QualType();
+}
+
+inline QualType Sema::CheckSubtractionOperands( // C99 6.5.6
+ Expr *lex, Expr *rex, SourceLocation loc)
+{
+ QualType lhsType = lex->getType(), rhsType = rex->getType();
+
+ if (lhsType->isVectorType() || rhsType->isVectorType())
+ return CheckVectorOperands(loc, lex, rex);
+ QualType resType = UsualArithmeticConversions(lhsType, rhsType);
+
+ // handle the common case first (both operands are arithmetic).
+ if (resType->isArithmeticType())
+ return resType;
+ if ((lhsType->isPointerType() && rhsType->isIntegerType()) ||
+ (lhsType->isPointerType() && rhsType->isPointerType()))
+ return resType;
+ InvalidOperands(loc, lex, rex);
+ return QualType();
+}
+
+inline QualType Sema::CheckShiftOperands( // C99 6.5.7
+ Expr *lex, Expr *rex, SourceLocation loc)
+{
+ // FIXME: Shifts don't perform usual arithmetic conversions. This is wrong
+ // for int << longlong -> the result type should be int, not long long.
+ QualType lhsType = lex->getType(), rhsType = rex->getType();
+ QualType resType = UsualArithmeticConversions(lhsType, rhsType);
+
+ if (resType->isIntegerType())
+ return resType;
+ InvalidOperands(loc, lex, rex);
+ return QualType();
+}
+
+inline QualType Sema::CheckRelationalOperands( // C99 6.5.8
+ Expr *lex, Expr *rex, SourceLocation loc)
+{
+ QualType lType = UsualUnaryConversions(lex->getType());
+ QualType rType = UsualUnaryConversions(rex->getType());
+
+ if (lType->isRealType() && rType->isRealType())
+ return Context.IntTy;
+
+ if (lType->isPointerType()) {
+ if (rType->isPointerType())
+ return Context.IntTy;
+ if (rType->isIntegerType()) {
+ if (!rex->isNullPointerConstant())
+ Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer,
+ lex->getSourceRange(), rex->getSourceRange());
+ return Context.IntTy; // the previous diagnostic is a GCC extension.
+ }
+ } else if (rType->isPointerType()) {
+ if (lType->isIntegerType()) {
+ if (!lex->isNullPointerConstant())
+ Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer,
+ lex->getSourceRange(), rex->getSourceRange());
+ return Context.IntTy; // the previous diagnostic is a GCC extension.
+ }
+ }
+ InvalidOperands(loc, lex, rex);
+ return QualType();
+}
+
+inline QualType Sema::CheckEqualityOperands( // C99 6.5.9
+ Expr *lex, Expr *rex, SourceLocation loc)
+{
+ QualType lType = UsualUnaryConversions(lex->getType());
+ QualType rType = UsualUnaryConversions(rex->getType());
+
+ if (lType->isArithmeticType() && rType->isArithmeticType())
+ return Context.IntTy;
+
+ if (lType->isPointerType()) {
+ if (rType->isPointerType())
+ return Context.IntTy;
+ if (rType->isIntegerType()) {
+ if (!rex->isNullPointerConstant())
+ Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer,
+ lex->getSourceRange(), rex->getSourceRange());
+ return Context.IntTy; // the previous diagnostic is a GCC extension.
+ }
+ } else if (rType->isPointerType()) {
+ if (lType->isIntegerType()) {
+ if (!lex->isNullPointerConstant())
+ Diag(loc, diag::ext_typecheck_comparison_of_pointer_integer,
+ lex->getSourceRange(), rex->getSourceRange());
+ return Context.IntTy; // the previous diagnostic is a GCC extension.
+ }
+ }
+ InvalidOperands(loc, lex, rex);
+ return QualType();
+}
+
+inline QualType Sema::CheckBitwiseOperands(
+ Expr *lex, Expr *rex, SourceLocation loc)
+{
+ QualType lhsType = lex->getType(), rhsType = rex->getType();
+
+ if (lhsType->isVectorType() || rhsType->isVectorType())
+ return CheckVectorOperands(loc, lex, rex);
+ QualType resType = UsualArithmeticConversions(lhsType, rhsType);
+
+ if (resType->isIntegerType())
+ return resType;
+ InvalidOperands(loc, lex, rex);
+ return QualType();
+}
+
+inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
+ Expr *lex, Expr *rex, SourceLocation loc)
+{
+ QualType lhsType = UsualUnaryConversions(lex->getType());
+ QualType rhsType = UsualUnaryConversions(rex->getType());
+
+ if (lhsType->isScalarType() || rhsType->isScalarType())
+ return Context.IntTy;
+ InvalidOperands(loc, lex, rex);
+ return QualType();
+}
+
+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;
+ bool hadError = false;
+ 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());
+ hadError = true;
+ break;
+ 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();
+ }
+ if (lhsType == rhsType) // common case, fast path...
+ return lhsType;
+
+ AssignmentCheckResult result = CheckAssignmentConstraints(lhsType, rhsType);
+
+ // decode the result (notice that extensions still return a type).
+ switch (result) {
+ case Compatible:
+ break;
+ case Incompatible:
+ Diag(loc, diag::err_typecheck_assign_incompatible,
+ lhsType.getAsString(), rhsType.getAsString(),
+ lex->getSourceRange(), rex->getSourceRange());
+ hadError = true;
+ break;
+ case PointerFromInt:
+ // check for null pointer constant (C99 6.3.2.3p3)
+ if (compoundType.isNull() && !rex->isNullPointerConstant()) {
+ Diag(loc, diag::ext_typecheck_assign_pointer_int,
+ lhsType.getAsString(), rhsType.getAsString(),
+ lex->getSourceRange(), rex->getSourceRange());
+ }
+ break;
+ case IntFromPointer:
+ Diag(loc, diag::ext_typecheck_assign_pointer_int,
+ lhsType.getAsString(), rhsType.getAsString(),
+ lex->getSourceRange(), rex->getSourceRange());
+ break;
+ case IncompatiblePointer:
+ Diag(loc, diag::ext_typecheck_assign_incompatible_pointer,
+ lhsType.getAsString(), rhsType.getAsString(),
+ lex->getSourceRange(), rex->getSourceRange());
+ break;
+ case CompatiblePointerDiscardsQualifiers:
+ Diag(loc, diag::ext_typecheck_assign_discards_qualifiers,
+ lhsType.getAsString(), rhsType.getAsString(),
+ lex->getSourceRange(), rex->getSourceRange());
+ break;
+ }
+ // 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 hadError ? QualType() : lhsType.getUnqualifiedType();
+}
+
+inline QualType Sema::CheckCommaOperands( // C99 6.5.17
+ Expr *lex, Expr *rex, SourceLocation loc) {
+ return UsualUnaryConversions(rex->getType());
+}
+
+QualType Sema::CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc) {
+ QualType lhsType = op->getType(), rhsType = Context.IntTy;
+ QualType resType = UsualArithmeticConversions(lhsType, rhsType);
+ assert(!resType.isNull() && "no type for increment/decrement expression");
+
+ // C99 6.5.2.4p1
+ if (const PointerType *pt = dyn_cast<PointerType>(resType)) {
+ 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()) {
+ // FIXME: Allow Complex as a GCC extension.
+ Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement,
+ resType.getAsString(), op->getSourceRange());
+ return QualType();
+ }
+ // At this point, we know we have a real 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;
+}
+
+/// getPrimaryDeclaration - 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 Decl *getPrimaryDeclaration(Expr *e) {
+ switch (e->getStmtClass()) {
+ case Stmt::DeclRefExprClass:
+ return cast<DeclRefExpr>(e)->getDecl();
+ case Stmt::MemberExprClass:
+ return getPrimaryDeclaration(cast<MemberExpr>(e)->getBase());
+ case Stmt::ArraySubscriptExprClass:
+ return getPrimaryDeclaration(cast<ArraySubscriptExpr>(e)->getBase());
+ case Stmt::CallExprClass:
+ return getPrimaryDeclaration(cast<CallExpr>(e)->getCallee());
+ case Stmt::UnaryOperatorClass:
+ return getPrimaryDeclaration(cast<UnaryOperator>(e)->getSubExpr());
+ case Stmt::ParenExprClass:
+ return getPrimaryDeclaration(cast<ParenExpr>(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) {
+ Decl *dcl = getPrimaryDeclaration(op);
+ Expr::isLvalueResult lval = op->isLvalue();
+
+ if (lval != Expr::LV_Valid) { // C99 6.5.3.2p1
+ if (dcl && isa<FunctionDecl>(dcl)) // allow function designators
+ ;
+ else { // FIXME: emit more specific diag...
+ Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof,
+ op->getSourceRange());
+ return QualType();
+ }
+ } else if (dcl) {
+ // We have an lvalue with a decl. Make sure the decl is not declared
+ // with the register storage-class specifier.
+ if (const VarDecl *vd = dyn_cast<VarDecl>(dcl)) {
+ if (vd->getStorageClass() == VarDecl::Register) {
+ Diag(OpLoc, diag::err_typecheck_address_of_register,
+ op->getSourceRange());
+ return QualType();
+ }
+ } else
+ assert(0 && "Unknown/unexpected decl type");
+
+ // FIXME: add check for bitfields!
+ }
+ // 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) {
+ QualType qType = UsualUnaryConversions(op->getType());
+
+ assert(!qType.isNull() && "no type for * expression");
+
+ if (PointerType *PT = dyn_cast<PointerType>(qType.getCanonicalType())) {
+ QualType ptype = PT->getPointeeType();
+ // C99 6.5.3.2p4. "if it points to an object,...".
+ if (ptype->isIncompleteType()) { // An incomplete type is not an object
+ // GCC compat: special case 'void *' (treat as warning).
+ if (ptype->isVoidType()) {
+ Diag(OpLoc, diag::ext_typecheck_deref_ptr_to_void,
+ qType.getAsString(), op->getSourceRange());
+ } else {
+ Diag(OpLoc, diag::err_typecheck_deref_incomplete_type,
+ ptype.getAsString(), op->getSourceRange());
+ return QualType();
+ }
+ }
+ return ptype;
+ }
+ 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::ParseBinOp(SourceLocation TokLoc, tok::TokenKind Kind,
+ ExprTy *LHS, ExprTy *RHS) {
+ BinaryOperator::Opcode Opc = ConvertTokenKindToBinaryOpcode(Kind);
+ Expr *lhs = (Expr *)LHS, *rhs = (Expr*)RHS;
+
+ assert((lhs != 0) && "ParseBinOp(): missing left expression");
+ assert((rhs != 0) && "ParseBinOp(): 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 = CheckRelationalOperands(lhs, rhs, TokLoc);
+ break;
+ case BinaryOperator::EQ:
+ case BinaryOperator::NE:
+ ResultTy = CheckEqualityOperands(lhs, rhs, TokLoc);
+ 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);
+ if (!CompTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy);
+ break;
+ case BinaryOperator::RemAssign:
+ CompTy = CheckRemainderOperands(lhs, rhs, TokLoc);
+ if (!CompTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy);
+ break;
+ case BinaryOperator::AddAssign:
+ CompTy = CheckAdditionOperands(lhs, rhs, TokLoc);
+ if (!CompTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy);
+ break;
+ case BinaryOperator::SubAssign:
+ CompTy = CheckSubtractionOperands(lhs, rhs, TokLoc);
+ if (!CompTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy);
+ break;
+ case BinaryOperator::ShlAssign:
+ case BinaryOperator::ShrAssign:
+ CompTy = CheckShiftOperands(lhs, rhs, TokLoc);
+ if (!CompTy.isNull())
+ ResultTy = CheckAssignmentOperands(lhs, rhs, TokLoc, CompTy);
+ break;
+ case BinaryOperator::AndAssign:
+ case BinaryOperator::XorAssign:
+ case BinaryOperator::OrAssign:
+ CompTy = CheckBitwiseOperands(lhs, rhs, TokLoc);
+ 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);
+ else
+ return new CompoundAssignOperator(lhs, rhs, Opc, ResultTy, CompTy);
+}
+
+// Unary Operators. 'Tok' is the token for the operator.
+Action::ExprResult Sema::ParseUnaryOp(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:
+ resultType = CheckIndirectionOperand(Input, OpLoc);
+ break;
+ case UnaryOperator::Plus:
+ case UnaryOperator::Minus:
+ resultType = UsualUnaryConversions(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
+ if (Input->getType()->isVectorType())
+ resultType = Input->getType();
+ else {
+ resultType = UsualUnaryConversions(Input->getType());
+ if (!resultType->isIntegerType()) // C99 6.5.3.3p1
+ 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).
+ resultType = DefaultFunctionArrayConversion(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::Extension:
+ // FIXME: does __extension__ cause any promotions? I would think not.
+ resultType = Input->getType();
+ break;
+ }
+ if (resultType.isNull())
+ return true;
+ return new UnaryOperator(Input, Opc, resultType, OpLoc);
+}
+
+/// ParseAddrLabel - Parse the GNU address of label extension: "&&foo".
+Sema::ExprResult Sema::ParseAddrLabel(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 AddrLabel(OpLoc, LabLoc, LabelDecl,
+ Context.getPointerType(Context.VoidTy));
+}
+
diff --git a/Sema/SemaExprCXX.cpp b/Sema/SemaExprCXX.cpp
new file mode 100644
index 0000000..74be79a
--- /dev/null
+++ b/Sema/SemaExprCXX.cpp
@@ -0,0 +1,44 @@
+//===--- SemaExprCXX.cpp - Semantic Analysis for Expressions --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Bill Wendling and 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"
+using namespace clang;
+
+/// ParseCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's.
+Action::ExprResult
+Sema::ParseCXXCasts(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);
+}
+
+/// ParseCXXBoolLiteral - Parse {true,false} literals.
+Action::ExprResult
+Sema::ParseCXXBoolLiteral(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, OpLoc);
+}
diff --git a/Sema/SemaStmt.cpp b/Sema/SemaStmt.cpp
new file mode 100644
index 0000000..5a5ab45
--- /dev/null
+++ b/Sema/SemaStmt.cpp
@@ -0,0 +1,294 @@
+//===--- SemaStmt.cpp - Semantic Analysis for Statements ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and 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/Stmt.h"
+#include "clang/AST/Expr.h"
+#include "clang/Parse/Scope.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Lex/IdentifierTable.h"
+using namespace clang;
+
+Sema::StmtResult Sema::ParseExprStmt(ExprTy *expr) {
+ Expr *E = static_cast<Expr*>(expr);
+
+ // Exprs are statements, so there is no need to do a conversion here. However,
+ // diagnose some potentially bad code.
+ if (!E->hasLocalSideEffect())
+ Diag(E->getExprLoc(), diag::warn_unused_expr, E->getSourceRange());
+
+ return E;
+}
+
+
+Sema::StmtResult Sema::ParseNullStmt(SourceLocation SemiLoc) {
+ return new NullStmt(SemiLoc);
+}
+
+Sema::StmtResult Sema::ParseDeclStmt(DeclTy *decl) {
+ if (decl)
+ return new DeclStmt(static_cast<Decl *>(decl));
+ else
+ return true; // error
+}
+
+Action::StmtResult
+Sema::ParseCompoundStmt(SourceLocation L, SourceLocation R,
+ StmtTy **Elts, unsigned NumElts) {
+ return new CompoundStmt((Stmt**)Elts, NumElts);
+}
+
+Action::StmtResult
+Sema::ParseCaseStmt(SourceLocation CaseLoc, ExprTy *lhsval,
+ SourceLocation DotDotDotLoc, ExprTy *RHSVal,
+ SourceLocation ColonLoc, StmtTy *SubStmt) {
+ Expr *LHSVal = ((Expr *)lhsval);
+ 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(&ExpLoc))
+ return Diag(ExpLoc, diag::err_case_label_not_integer_constant_expr,
+ LHSVal->getSourceRange());
+
+ // FIXME: SEMA for RHS of case range.
+
+ return new CaseStmt(LHSVal, (Expr*)RHSVal, (Stmt*)SubStmt);
+}
+
+Action::StmtResult
+Sema::ParseDefaultStmt(SourceLocation DefaultLoc,
+ SourceLocation ColonLoc, StmtTy *SubStmt) {
+ return new DefaultStmt((Stmt*)SubStmt);
+}
+
+Action::StmtResult
+Sema::ParseLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II,
+ SourceLocation ColonLoc, StmtTy *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, (Stmt*)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 (Stmt*)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((Stmt*)SubStmt);
+ return LabelDecl;
+}
+
+Action::StmtResult
+Sema::ParseIfStmt(SourceLocation IfLoc, ExprTy *CondVal,
+ StmtTy *ThenVal, SourceLocation ElseLoc,
+ StmtTy *ElseVal) {
+ Expr *condExpr = (Expr *)CondVal;
+ assert(condExpr && "ParseIfStmt(): missing expression");
+
+ QualType condType = DefaultFunctionArrayConversion(condExpr->getType());
+ assert(!condType.isNull() && "ParseIfStmt(): missing expression type");
+
+ if (!condType->isScalarType()) // C99 6.8.4.1p1
+ return Diag(IfLoc, diag::err_typecheck_statement_requires_scalar,
+ condType.getAsString(), condExpr->getSourceRange());
+
+ return new IfStmt(condExpr, (Stmt*)ThenVal, (Stmt*)ElseVal);
+}
+
+Action::StmtResult
+Sema::ParseSwitchStmt(SourceLocation SwitchLoc, ExprTy *Cond, StmtTy *Body) {
+ return new SwitchStmt((Expr*)Cond, (Stmt*)Body);
+}
+
+Action::StmtResult
+Sema::ParseWhileStmt(SourceLocation WhileLoc, ExprTy *Cond, StmtTy *Body) {
+ Expr *condExpr = (Expr *)Cond;
+ assert(condExpr && "ParseWhileStmt(): missing expression");
+
+ QualType condType = DefaultFunctionArrayConversion(condExpr->getType());
+ assert(!condType.isNull() && "ParseWhileStmt(): missing expression type");
+
+ 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);
+}
+
+Action::StmtResult
+Sema::ParseDoStmt(SourceLocation DoLoc, StmtTy *Body,
+ SourceLocation WhileLoc, ExprTy *Cond) {
+ Expr *condExpr = (Expr *)Cond;
+ assert(condExpr && "ParseDoStmt(): missing expression");
+
+ QualType condType = DefaultFunctionArrayConversion(condExpr->getType());
+ assert(!condType.isNull() && "ParseDoStmt(): missing expression type");
+
+ 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);
+}
+
+Action::StmtResult
+Sema::ParseForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
+ StmtTy *First, ExprTy *Second, ExprTy *Third,
+ SourceLocation RParenLoc, StmtTy *Body) {
+ if (First) {
+ // C99 6.8.5p3: FIXME. Need to hack Parser::ParseForStatement() and
+ // declaration support to create a DeclStmt node. Once this is done,
+ // we can test for DeclStmt vs. Expr (already a sub-class of Stmt).
+ }
+ if (Second) {
+ Expr *testExpr = (Expr *)Second;
+ QualType testType = DefaultFunctionArrayConversion(testExpr->getType());
+ assert(!testType.isNull() && "ParseForStmt(): missing test expression type");
+
+ if (!testType->isScalarType()) // C99 6.8.5p2
+ return Diag(ForLoc, diag::err_typecheck_statement_requires_scalar,
+ testType.getAsString(), testExpr->getSourceRange());
+ }
+ return new ForStmt((Stmt*)First, (Expr*)Second, (Expr*)Third, (Stmt*)Body);
+}
+
+
+Action::StmtResult
+Sema::ParseGotoStmt(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);
+}
+
+Action::StmtResult
+Sema::ParseIndirectGotoStmt(SourceLocation GotoLoc,SourceLocation StarLoc,
+ ExprTy *DestExp) {
+ // FIXME: Verify that the operand is convertible to void*.
+
+ return new IndirectGotoStmt((Expr*)DestExp);
+}
+
+Action::StmtResult
+Sema::ParseContinueStmt(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;
+ }
+
+ // FIXME: Remember that this continue goes with this loop.
+ return new ContinueStmt();
+}
+
+Action::StmtResult
+Sema::ParseBreakStmt(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;
+ }
+
+ // FIXME: Remember that this break goes with this loop/switch.
+ return new BreakStmt();
+}
+
+
+Action::StmtResult
+Sema::ParseReturnStmt(SourceLocation ReturnLoc, ExprTy *RetValExp) {
+ QualType lhsType = CurFunctionDecl->getResultType();
+
+ if (lhsType->isVoidType()) {
+ if (RetValExp) // C99 6.8.6.4p1 (ext_ since GCC warns)
+ Diag(ReturnLoc, diag::ext_return_has_expr,
+ CurFunctionDecl->getIdentifier()->getName(),
+ ((Expr *)RetValExp)->getSourceRange());
+ return new ReturnStmt((Expr*)RetValExp);
+ } else {
+ if (!RetValExp) {
+ const char *funcName = CurFunctionDecl->getIdentifier()->getName();
+ 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((Expr*)0);
+ }
+ }
+ // we have a non-void function with an expression, continue checking
+ QualType rhsType = ((Expr *)RetValExp)->getType();
+
+ if (lhsType == rhsType) // common case, fast path...
+ return new ReturnStmt((Expr*)RetValExp);
+
+ // 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.
+ AssignmentCheckResult result = CheckAssignmentConstraints(lhsType, rhsType);
+ bool hadError = false;
+
+ // decode the result (notice that extensions still return a type).
+ switch (result) {
+ case Compatible:
+ break;
+ case Incompatible:
+ Diag(ReturnLoc, diag::err_typecheck_return_incompatible,
+ lhsType.getAsString(), rhsType.getAsString(),
+ ((Expr *)RetValExp)->getSourceRange());
+ hadError = true;
+ break;
+ case PointerFromInt:
+ // check for null pointer constant (C99 6.3.2.3p3)
+ if (!((Expr *)RetValExp)->isNullPointerConstant()) {
+ Diag(ReturnLoc, diag::ext_typecheck_return_pointer_int,
+ lhsType.getAsString(), rhsType.getAsString(),
+ ((Expr *)RetValExp)->getSourceRange());
+ }
+ break;
+ case IntFromPointer:
+ Diag(ReturnLoc, diag::ext_typecheck_return_pointer_int,
+ lhsType.getAsString(), rhsType.getAsString(),
+ ((Expr *)RetValExp)->getSourceRange());
+ break;
+ case IncompatiblePointer:
+ Diag(ReturnLoc, diag::ext_typecheck_return_incompatible_pointer,
+ lhsType.getAsString(), rhsType.getAsString(),
+ ((Expr *)RetValExp)->getSourceRange());
+ break;
+ case CompatiblePointerDiscardsQualifiers:
+ Diag(ReturnLoc, diag::ext_typecheck_return_discards_qualifiers,
+ lhsType.getAsString(), rhsType.getAsString(),
+ ((Expr *)RetValExp)->getSourceRange());
+ break;
+ }
+ return new ReturnStmt((Expr*)RetValExp);
+}
+
diff --git a/Sema/SemaType.cpp b/Sema/SemaType.cpp
new file mode 100644
index 0000000..cdb767f
--- /dev/null
+++ b/Sema/SemaType.cpp
@@ -0,0 +1,262 @@
+//===--- SemaType.cpp - Semantic Analysis for Types -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and 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/Parse/DeclSpec.h"
+#include "clang/Lex/IdentifierTable.h"
+using namespace clang;
+
+/// ConvertDeclSpecToType - Convert the specified declspec to the appropriate
+/// type object. This returns null on error.
+static QualType ConvertDeclSpecToType(const DeclSpec &DS, ASTContext &Ctx) {
+ // FIXME: Should move the logic from DeclSpec::Finish to here for validity
+ // checking.
+
+ switch (DS.getTypeSpecType()) {
+ default: return QualType(); // FIXME: Handle unimp cases!
+ case DeclSpec::TST_void: return Ctx.VoidTy;
+ case DeclSpec::TST_char:
+ if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified)
+ return Ctx.CharTy;
+ else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed)
+ return Ctx.SignedCharTy;
+ else {
+ assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned &&
+ "Unknown TSS value");
+ return Ctx.UnsignedCharTy;
+ }
+ case DeclSpec::TST_int:
+ if (DS.getTypeSpecSign() != DeclSpec::TSS_unsigned) {
+ switch (DS.getTypeSpecWidth()) {
+ case DeclSpec::TSW_unspecified: return Ctx.IntTy;
+ case DeclSpec::TSW_short: return Ctx.ShortTy;
+ case DeclSpec::TSW_long: return Ctx.LongTy;
+ case DeclSpec::TSW_longlong: return Ctx.LongLongTy;
+ }
+ } else {
+ switch (DS.getTypeSpecWidth()) {
+ case DeclSpec::TSW_unspecified: return Ctx.UnsignedIntTy;
+ case DeclSpec::TSW_short: return Ctx.UnsignedShortTy;
+ case DeclSpec::TSW_long: return Ctx.UnsignedLongTy;
+ case DeclSpec::TSW_longlong: return Ctx.UnsignedLongLongTy;
+ }
+ }
+ case DeclSpec::TST_float:
+ if (DS.getTypeSpecComplex() == DeclSpec::TSC_unspecified)
+ return Ctx.FloatTy;
+ assert(DS.getTypeSpecComplex() == DeclSpec::TSC_complex &&
+ "FIXME: imaginary types not supported yet!");
+ return Ctx.FloatComplexTy;
+
+ case DeclSpec::TST_double: {
+ bool isLong = DS.getTypeSpecWidth() == DeclSpec::TSW_long;
+ if (DS.getTypeSpecComplex() == DeclSpec::TSC_unspecified)
+ return isLong ? Ctx.LongDoubleTy : Ctx.DoubleTy;
+ assert(DS.getTypeSpecComplex() == DeclSpec::TSC_complex &&
+ "FIXME: imaginary types not supported yet!");
+ return isLong ? Ctx.LongDoubleComplexTy : Ctx.DoubleComplexTy;
+ }
+ case DeclSpec::TST_bool: // _Bool or bool
+ return Ctx.BoolTy;
+ 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.
+ return Ctx.getTagDeclType(cast<TagDecl>(D));
+ }
+ 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!");
+ // TypeQuals handled by caller.
+ return Ctx.getTypedefType(cast<TypedefDecl>(D));
+ }
+ }
+}
+
+/// GetTypeForDeclarator - Convert the type for the specified declarator to Type
+/// instances.
+QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
+ QualType T = ConvertDeclSpecToType(D.getDeclSpec(), Context);
+
+ // If there was an error parsing declspecs, return a null type pointer.
+ if (T.isNull()) return T;
+
+ // 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) {
+ const DeclaratorChunk &DeclType = D.getTypeObject(e-i-1);
+ switch (DeclType.Kind) {
+ default: assert(0 && "Unknown decltype!");
+ case DeclaratorChunk::Pointer:
+ if (isa<ReferenceType>(T.getCanonicalType().getTypePtr())) {
+ // C++ 8.3.2p4: There shall be no ... pointers to references ...
+ Diag(D.getIdentifierLoc(), diag::err_illegal_decl_pointer_to_reference,
+ D.getIdentifier()->getName());
+ return QualType();
+ }
+
+ // Apply the pointer typequals to the pointer object.
+ T = Context.getPointerType(T).getQualifiedType(DeclType.Ptr.TypeQuals);
+ break;
+ case DeclaratorChunk::Reference:
+ if (isa<ReferenceType>(T.getCanonicalType().getTypePtr())) {
+ // C++ 8.3.2p4: There shall be no references to references ...
+ Diag(D.getIdentifierLoc(),
+ diag::err_illegal_decl_reference_to_reference,
+ D.getIdentifier()->getName());
+ return QualType();
+ }
+
+ T = Context.getReferenceType(T);
+ break;
+ case DeclaratorChunk::Array: {
+ const DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr;
+ ArrayType::ArraySizeModifier ASM;
+ if (ATI.isStar)
+ ASM = ArrayType::Star;
+ else if (ATI.hasStatic)
+ ASM = ArrayType::Static;
+ else
+ ASM = ArrayType::Normal;
+
+ Type *CanonicalT = T.getCanonicalType().getTypePtr();
+
+ // 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());
+ return QualType();
+ } else if (isa<FunctionType>(CanonicalT)) {
+ Diag(D.getIdentifierLoc(), diag::err_illegal_decl_array_of_functions,
+ D.getIdentifier()->getName());
+ return QualType();
+ } else if (isa<ReferenceType>(CanonicalT)) {
+ // C++ 8.3.2p4: There shall be no ... arrays of references ...
+ Diag(D.getIdentifierLoc(), diag::err_illegal_decl_array_of_references,
+ D.getIdentifier()->getName());
+ return QualType();
+ } else if (RecordType *EltTy = dyn_cast<RecordType>(CanonicalT)) {
+ // 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());
+ return QualType();
+ }
+ }
+ T = Context.getArrayType(T, ASM, ATI.TypeQuals,
+ static_cast<Expr *>(ATI.NumElts));
+ 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;
+ 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);
+ if (ArgTy.isNull())
+ return QualType(); // Error occurred parsing argument type.
+
+ // Look for 'void'. void is allowed only as a single argument to a
+ // function with no other parameters (C99 6.7.5.3p10). We record
+ // int(void) as a FunctionTypeProto with an empty argument list.
+ if (ArgTy->isVoidType()) {
+ // If this is something like 'float(int, void)', reject it. 'void'
+ // is an incomplete type (C99 6.2.5p19) and function decls cannot
+ // have arguments of incomplete type.
+ if (FTI.NumArgs != 1 || FTI.isVariadic) {
+ Diag(DeclType.Loc, diag::err_void_only_param);
+ return QualType();
+ }
+ // Reject, but continue to parse 'int(void abc)'.
+ if (FTI.ArgInfo[i].Ident)
+ Diag(FTI.ArgInfo[i].IdentLoc,
+ diag::err_void_param_with_identifier);
+
+ // Reject, but continue to parse 'float(const void)'.
+ if (ArgTy.getQualifiers())
+ 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;
+}
+
+Sema::TypeResult Sema::ParseTypeName(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);
+
+ // If the type of the declarator was invalid, this is an invalid typename.
+ if (T.isNull())
+ return true;
+
+ return T.getAsOpaquePtr();
+}
+
+Sema::TypeResult Sema::ParseParamDeclaratorType(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);
+
+ // If the type of the declarator was invalid, this is an invalid typename.
+ if (T.isNull())
+ return true;
+
+ return T.getAsOpaquePtr();
+}