diff options
169 files changed, 5621 insertions, 3065 deletions
@@ -39,19 +39,19 @@ cscope.files: install-local:: $(Echo) Installing include files - $(Verb) $(MKDIR) $(PROJ_includedir) + $(Verb) $(MKDIR) $(DESTDIR)$(PROJ_includedir) $(Verb) if test -d "$(PROJ_SRC_ROOT)/tools/clang/include" ; then \ cd $(PROJ_SRC_ROOT)/tools/clang/include && \ for hdr in `find . -type f '!' '(' -name '*~' \ -o -name '.#*' -o -name '*.in' -o -name '*.txt' \ -o -name 'Makefile' -o -name '*.td' ')' -print \ | grep -v CVS | grep -v .svn | grep -v .dir` ; do \ - instdir=`dirname "$(PROJ_includedir)/$$hdr"` ; \ + instdir=$(DESTDIR)`dirname "$(PROJ_includedir)/$$hdr"` ; \ if test \! -d "$$instdir" ; then \ $(EchoCmd) Making install directory $$instdir ; \ $(MKDIR) $$instdir ;\ fi ; \ - $(DataInstall) $$hdr $(PROJ_includedir)/$$hdr ; \ + $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \ done ; \ fi ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT)) @@ -59,7 +59,7 @@ ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT)) cd $(PROJ_OBJ_ROOT)/tools/clang/include && \ for hdr in `find . -type f '!' '(' -name 'Makefile' ')' -print \ | grep -v CVS | grep -v .tmp | grep -v .dir` ; do \ - $(DataInstall) $$hdr $(PROJ_includedir)/$$hdr ; \ + $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \ done ; \ fi endif diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index 1fcc7c8ad493..7bf633532d2a 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -49,6 +49,7 @@ 1A81AA19108144F40094E50B /* CGVtable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A81AA18108144F40094E50B /* CGVtable.cpp */; }; 1A869A700BA2164C008DA07A /* LiteralSupport.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */; }; 1A869AA80BA21ABA008DA07A /* LiteralSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */; }; + 1A96785211486FDC00F24372 /* RecordLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A96785111486FDC00F24372 /* RecordLayout.cpp */; }; 1A97825B1108BA18002B98FC /* CGVTT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A97825A1108BA18002B98FC /* CGVTT.cpp */; }; 1A986AB710D0746D00A8EA9E /* CGDeclCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A986AB610D0746D00A8EA9E /* CGDeclCXX.cpp */; }; 1AA1D91810125DE30078DEBC /* RecordLayoutBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */; }; @@ -420,6 +421,7 @@ 1A81AA5D108278A20094E50B /* CGVtable.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGVtable.h; path = lib/CodeGen/CGVtable.h; sourceTree = "<group>"; tabWidth = 2; }; 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiteralSupport.h; sourceTree = "<group>"; }; 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LiteralSupport.cpp; sourceTree = "<group>"; }; + 1A96785111486FDC00F24372 /* RecordLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = RecordLayout.cpp; path = lib/AST/RecordLayout.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1A97825A1108BA18002B98FC /* CGVTT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGVTT.cpp; path = lib/CodeGen/CGVTT.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1A986AB610D0746D00A8EA9E /* CGDeclCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGDeclCXX.cpp; path = lib/CodeGen/CGDeclCXX.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = RecordLayoutBuilder.cpp; path = lib/AST/RecordLayoutBuilder.cpp; sourceTree = "<group>"; tabWidth = 2; }; @@ -1438,6 +1440,7 @@ 3557D1A80EB136B100C59739 /* InheritViz.cpp */, DEDFE5CE0F7206E40035BD10 /* NestedNameSpecifier.cpp */, 35EE48B00E0C4CCA00715C54 /* ParentMap.cpp */, + 1A96785111486FDC00F24372 /* RecordLayout.cpp */, 1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */, 1AA1D91710125DE30078DEBC /* RecordLayoutBuilder.h */, DE3452400AEF1A2D00DBC861 /* Stmt.cpp */, @@ -1993,6 +1996,7 @@ 1A621C4411111D61009E6834 /* CIndexInclusionStack.cpp in Sources */, 1A621C4511111D61009E6834 /* CIndexUSRs.cpp in Sources */, 1A621C4611111D61009E6834 /* CXCursor.cpp in Sources */, + 1A96785211486FDC00F24372 /* RecordLayout.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index da186f6424de..15afe8f50376 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -171,7 +171,7 @@ CINDEX_LINKAGE void clang_disposeString(CXString string); */ CINDEX_LINKAGE CXIndex clang_createIndex(int excludeDeclarationsFromPCH, int displayDiagnostics); - + /** * \brief Destroy the given index. * @@ -297,7 +297,7 @@ CINDEX_LINKAGE CXSourceLocation clang_getLocation(CXTranslationUnit tu, * \brief Retrieve a NULL (invalid) source range. */ CINDEX_LINKAGE CXSourceRange clang_getNullRange(); - + /** * \brief Retrieve a source range given the beginning and ending source * locations. @@ -357,11 +357,11 @@ CINDEX_LINKAGE CXSourceLocation clang_getRangeEnd(CXSourceRange range); */ enum CXDiagnosticSeverity { /** - * \brief A diagnostic that has been suppressed, e.g., by a command-line + * \brief A diagnostic that has been suppressed, e.g., by a command-line * option. */ CXDiagnostic_Ignored = 0, - + /** * \brief This diagnostic is a note that should be attached to the * previous (non-note) diagnostic. @@ -451,7 +451,7 @@ enum CXDiagnosticDisplayOptions { * diagnostic, also include information about source ranges in a * machine-parsable format. * - * This option corresponds to the clang flag + * This option corresponds to the clang flag * \c -fdiagnostics-print-source-range-info. */ CXDiagnostic_DisplaySourceRanges = 0x04 @@ -461,13 +461,13 @@ enum CXDiagnosticDisplayOptions { * \brief Format the given diagnostic in a manner that is suitable for display. * * This routine will format the given diagnostic to a string, rendering - * the diagnostic according to the various options given. The - * \c clang_defaultDiagnosticDisplayOptions() function returns the set of + * the diagnostic according to the various options given. The + * \c clang_defaultDiagnosticDisplayOptions() function returns the set of * options that most closely mimics the behavior of the clang compiler. * * \param Diagnostic The diagnostic to print. * - * \param Options A set of options that control the diagnostic display, + * \param Options A set of options that control the diagnostic display, * created by combining \c CXDiagnosticDisplayOptions values. * * \returns A new string containing for formatted diagnostic. @@ -491,7 +491,7 @@ CINDEX_LINKAGE unsigned clang_defaultDiagnosticDisplayOptions(void); /** * \brief Determine the severity of the given diagnostic. */ -CINDEX_LINKAGE enum CXDiagnosticSeverity +CINDEX_LINKAGE enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic); /** @@ -512,21 +512,21 @@ CINDEX_LINKAGE CXString clang_getDiagnosticSpelling(CXDiagnostic); * diagnostic. */ CINDEX_LINKAGE unsigned clang_getDiagnosticNumRanges(CXDiagnostic); - + /** * \brief Retrieve a source range associated with the diagnostic. * * A diagnostic's source ranges highlight important elements in the source * code. On the command line, Clang displays source ranges by - * underlining them with '~' characters. + * underlining them with '~' characters. * * \param Diagnostic the diagnostic whose range is being extracted. * - * \param Range the zero-based index specifying which range to + * \param Range the zero-based index specifying which range to * * \returns the requested source range. */ -CINDEX_LINKAGE CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diagnostic, +CINDEX_LINKAGE CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diagnostic, unsigned Range); /** @@ -560,7 +560,7 @@ CINDEX_LINKAGE unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diagnostic); * \returns A string containing text that should be replace the source * code indicated by the \c ReplacementRange. */ -CINDEX_LINKAGE CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, +CINDEX_LINKAGE CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, unsigned FixIt, CXSourceRange *ReplacementRange); @@ -577,7 +577,7 @@ CINDEX_LINKAGE CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, * * @{ */ - + /** * \brief Get the original translation unit source file name. */ @@ -625,22 +625,22 @@ CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnitFromSourceFile( const char **clang_command_line_args, unsigned num_unsaved_files, struct CXUnsavedFile *unsaved_files); - + /** * \brief Create a translation unit from an AST file (-emit-ast). */ -CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnit(CXIndex, +CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnit(CXIndex, const char *ast_filename); /** * \brief Destroy the specified CXTranslationUnit object. */ CINDEX_LINKAGE void clang_disposeTranslationUnit(CXTranslationUnit); - + /** * @} */ - + /** * \brief Describes the kind of entity that a cursor refers to. */ @@ -1083,6 +1083,47 @@ CINDEX_LINKAGE unsigned clang_visitChildren(CXCursor parent, CINDEX_LINKAGE CXString clang_getCursorUSR(CXCursor); /** + * \brief Construct a USR for a specified Objective-C class. + */ +CINDEX_LINKAGE CXString clang_constructUSR_ObjCClass(const char *class_name); + +/** + * \brief Construct a USR for a specified Objective-C category. + */ +CINDEX_LINKAGE CXString + clang_constructUSR_ObjCCategory(const char *class_name, + const char *category_name); + +/** + * \brief Construct a USR for a specified Objective-C protocol. + */ +CINDEX_LINKAGE CXString + clang_constructUSR_ObjCProtocol(const char *protocol_name); + + +/** + * \brief Construct a USR for a specified Objective-C instance variable and + * the USR for its containing class. + */ +CINDEX_LINKAGE CXString clang_constructUSR_ObjCIvar(const char *name, + CXString classUSR); + +/** + * \brief Construct a USR for a specified Objective-C method and + * the USR for its containing class. + */ +CINDEX_LINKAGE CXString clang_constructUSR_ObjCMethod(const char *name, + unsigned isInstanceMethod, + CXString classUSR); + +/** + * \brief Construct a USR for a specified Objective-C property and the USR + * for its containing class. + */ +CINDEX_LINKAGE CXString clang_constructUSR_ObjCProperty(const char *property, + CXString classUSR); + +/** * \brief Retrieve a name for the entity referenced by this cursor. */ CINDEX_LINKAGE CXString clang_getCursorSpelling(CXCursor); @@ -1157,22 +1198,22 @@ typedef enum CXTokenKind { * \brief A token that contains some kind of punctuation. */ CXToken_Punctuation, - + /** * \brief A language keyword. */ CXToken_Keyword, - + /** * \brief An identifier (that is not a keyword). */ CXToken_Identifier, - + /** * \brief A numeric, string, or character literal. */ CXToken_Literal, - + /** * \brief A comment. */ @@ -1191,7 +1232,7 @@ typedef struct { * \brief Determine the kind of the given token. */ CINDEX_LINKAGE CXTokenKind clang_getTokenKind(CXToken); - + /** * \brief Determine the spelling of the given token. * @@ -1199,13 +1240,13 @@ CINDEX_LINKAGE CXTokenKind clang_getTokenKind(CXToken); * the text of an identifier or keyword. */ CINDEX_LINKAGE CXString clang_getTokenSpelling(CXTranslationUnit, CXToken); - + /** * \brief Retrieve the source location of the given token. */ -CINDEX_LINKAGE CXSourceLocation clang_getTokenLocation(CXTranslationUnit, +CINDEX_LINKAGE CXSourceLocation clang_getTokenLocation(CXTranslationUnit, CXToken); - + /** * \brief Retrieve a source range that covers the given token. */ @@ -1230,7 +1271,7 @@ CINDEX_LINKAGE CXSourceRange clang_getTokenExtent(CXTranslationUnit, CXToken); */ CINDEX_LINKAGE void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, CXToken **Tokens, unsigned *NumTokens); - + /** * \brief Annotate the given set of tokens by providing cursors for each token * that can be mapped to a specific entity within the abstract syntax tree. @@ -1264,17 +1305,17 @@ CINDEX_LINKAGE void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, CINDEX_LINKAGE void clang_annotateTokens(CXTranslationUnit TU, CXToken *Tokens, unsigned NumTokens, CXCursor *Cursors); - + /** * \brief Free the given set of tokens. */ -CINDEX_LINKAGE void clang_disposeTokens(CXTranslationUnit TU, +CINDEX_LINKAGE void clang_disposeTokens(CXTranslationUnit TU, CXToken *Tokens, unsigned NumTokens); - + /** * @} */ - + /** * \defgroup CINDEX_DEBUG Debugging facilities * @@ -1689,7 +1730,7 @@ void clang_disposeCodeCompleteResults(CXCodeCompleteResults *Results); * \brief Determine the number of diagnostics produced prior to the * location where code completion was performed. */ -CINDEX_LINKAGE +CINDEX_LINKAGE unsigned clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *Results); /** @@ -1701,7 +1742,7 @@ unsigned clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *Results); * \returns the requested diagnostic. This diagnostic must be freed * via a call to \c clang_disposeDiagnostic(). */ -CINDEX_LINKAGE +CINDEX_LINKAGE CXDiagnostic clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *Results, unsigned Index); @@ -1726,10 +1767,10 @@ CINDEX_LINKAGE CXString clang_getClangVersion(); * \brief Return a version string, suitable for showing to a user, but not * intended to be parsed (the format is not guaranteed to be stable). */ - - + + /** - * \brief Visitor invoked for each file in a translation unit + * \brief Visitor invoked for each file in a translation unit * (used with clang_getInclusions()). * * This visitor function will be invoked by clang_getInclusions() for each diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index cf9aa50af2a1..d12a182078e4 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -40,6 +40,7 @@ namespace clang { class ASTRecordLayout; class BlockExpr; class CharUnits; + class Diagnostic; class Expr; class ExternalASTSource; class IdentifierTable; @@ -950,8 +951,6 @@ public: llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars); void CollectNonClassIvars(const ObjCInterfaceDecl *OI, llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars); - void CollectProtocolSynthesizedIvars(const ObjCProtocolDecl *PD, - llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars); unsigned CountSynthesizedIvars(const ObjCInterfaceDecl *OI); unsigned CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD); void CollectInheritedProtocols(const Decl *CDecl, diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index bd9f01b0b5ef..e23811d8f9c0 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -319,7 +319,19 @@ public: /// \brief Represents a ValueDecl that came out of a declarator. /// Contains type source information through TypeSourceInfo. class DeclaratorDecl : public ValueDecl { - TypeSourceInfo *DeclInfo; + // A struct representing both a TInfo and a syntactic qualifier, + // to be used for the (uncommon) case of out-of-line declarations. + struct ExtInfo { + TypeSourceInfo *TInfo; + NestedNameSpecifier *NNS; + SourceRange NNSRange; + }; + + llvm::PointerUnion<TypeSourceInfo*, ExtInfo*> DeclInfo; + + bool hasExtInfo() const { return DeclInfo.is<ExtInfo*>(); } + ExtInfo *getExtInfo() { return DeclInfo.get<ExtInfo*>(); } + const ExtInfo *getExtInfo() const { return DeclInfo.get<ExtInfo*>(); } protected: DeclaratorDecl(Kind DK, DeclContext *DC, SourceLocation L, @@ -327,8 +339,29 @@ protected: : ValueDecl(DK, DC, L, N, T), DeclInfo(TInfo) {} public: - TypeSourceInfo *getTypeSourceInfo() const { return DeclInfo; } - void setTypeSourceInfo(TypeSourceInfo *TInfo) { DeclInfo = TInfo; } + virtual ~DeclaratorDecl(); + virtual void Destroy(ASTContext &C); + + TypeSourceInfo *getTypeSourceInfo() const { + return hasExtInfo() + ? DeclInfo.get<ExtInfo*>()->TInfo + : DeclInfo.get<TypeSourceInfo*>(); + } + void setTypeSourceInfo(TypeSourceInfo *TI) { + if (hasExtInfo()) + DeclInfo.get<ExtInfo*>()->TInfo = TI; + else + DeclInfo = TI; + } + + NestedNameSpecifier *getQualifier() const { + return hasExtInfo() ? DeclInfo.get<ExtInfo*>()->NNS : 0; + } + SourceRange getQualifierRange() const { + return hasExtInfo() ? DeclInfo.get<ExtInfo*>()->NNSRange : SourceRange(); + } + void setQualifierInfo(NestedNameSpecifier *Qualifier, + SourceRange QualifierRange); SourceLocation getTypeSpecStartLoc() const; @@ -500,7 +533,8 @@ public: bool isExternC() const; /// isBlockVarDecl - Returns true for local variable declarations. Note that - /// this includes static variables inside of functions. + /// this includes static variables inside of functions. It also includes + /// variables inside blocks. /// /// void foo() { int x; static int y; extern int z; } /// @@ -512,6 +546,17 @@ public: return false; } + /// isFunctionOrMethodVarDecl - Similar to isBlockVarDecl, but excludes + /// variables declared in blocks. + bool isFunctionOrMethodVarDecl() const { + if (getKind() != Decl::Var) + return false; + if (const DeclContext *DC = getDeclContext()) + return DC->getLookupContext()->isFunctionOrMethod() && + DC->getLookupContext()->getDeclKind() != Decl::Block; + return false; + } + /// \brief Determines whether this is a static data member. /// /// This will only be true in C++, and applies to, e.g., the @@ -797,12 +842,14 @@ class ParmVarDecl : public VarDecl { /// FIXME: Also can be paced into the bitfields in Decl. /// in, inout, etc. unsigned objcDeclQualifier : 6; + bool HasInheritedDefaultArg : 1; protected: ParmVarDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S, Expr *DefArg) - : VarDecl(DK, DC, L, Id, T, TInfo, S), objcDeclQualifier(OBJC_TQ_None) { + : VarDecl(DK, DC, L, Id, T, TInfo, S), + objcDeclQualifier(OBJC_TQ_None), HasInheritedDefaultArg(false) { setDefaultArg(DefArg); } @@ -881,6 +928,14 @@ public: Init = (UnparsedDefaultArgument *)0; } + bool hasInheritedDefaultArg() const { + return HasInheritedDefaultArg; + } + + void setHasInheritedDefaultArg(bool I = true) { + HasInheritedDefaultArg = I; + } + QualType getOriginalType() const { if (getTypeSourceInfo()) return getTypeSourceInfo()->getType(); @@ -1512,22 +1567,38 @@ private: /// IsEmbeddedInDeclarator - True if this tag declaration is /// "embedded" (i.e., defined or declared for the very first time) - /// in the syntax of a declarator, + /// in the syntax of a declarator. bool IsEmbeddedInDeclarator : 1; - /// TypedefForAnonDecl - If a TagDecl is anonymous and part of a typedef, - /// this points to the TypedefDecl. Used for mangling. - TypedefDecl *TypedefForAnonDecl; - SourceLocation TagKeywordLoc; SourceLocation RBraceLoc; + // A struct representing syntactic qualifier info, + // to be used for the (uncommon) case of out-of-line declarations. + struct ExtInfo { + NestedNameSpecifier *NNS; + SourceRange NNSRange; + }; + + /// TypedefDeclOrQualifier - If the (out-of-line) tag declaration name + /// is qualified, it points to the qualifier info (nns and range); + /// otherwise, if the tag declaration is anonymous and it is part of + /// a typedef, it points to the TypedefDecl (used for mangling); + /// otherwise, it is a null (TypedefDecl) pointer. + llvm::PointerUnion<TypedefDecl*, ExtInfo*> TypedefDeclOrQualifier; + + bool hasExtInfo() const { return TypedefDeclOrQualifier.is<ExtInfo*>(); } + ExtInfo *getExtInfo() { return TypedefDeclOrQualifier.get<ExtInfo*>(); } + const ExtInfo *getExtInfo() const { + return TypedefDeclOrQualifier.get<ExtInfo*>(); + } + protected: - TagDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, TagDecl *PrevDecl, - SourceLocation TKL = SourceLocation()) - : TypeDecl(DK, DC, L, Id), DeclContext(DK), TypedefForAnonDecl(0), - TagKeywordLoc(TKL) { + TagDecl(Kind DK, TagKind TK, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + TagDecl *PrevDecl, SourceLocation TKL = SourceLocation()) + : TypeDecl(DK, DC, L, Id), DeclContext(DK), TagKeywordLoc(TKL), + TypedefDeclOrQualifier((TypedefDecl*) 0) { assert((DK != Enum || TK == TK_enum) &&"EnumDecl not matched with TK_enum"); TagDeclKind = TK; IsDefinition = false; @@ -1539,6 +1610,8 @@ protected: virtual TagDecl *getNextRedeclaration() { return RedeclLink.getNext(); } public: + void Destroy(ASTContext &C); + typedef redeclarable_base::redecl_iterator redecl_iterator; redecl_iterator redecls_begin() const { return redeclarable_base::redecls_begin(); @@ -1618,8 +1691,21 @@ public: bool isUnion() const { return getTagKind() == TK_union; } bool isEnum() const { return getTagKind() == TK_enum; } - TypedefDecl *getTypedefForAnonDecl() const { return TypedefForAnonDecl; } - void setTypedefForAnonDecl(TypedefDecl *TDD) { TypedefForAnonDecl = TDD; } + TypedefDecl *getTypedefForAnonDecl() const { + return hasExtInfo() ? 0 : TypedefDeclOrQualifier.get<TypedefDecl*>(); + } + void setTypedefForAnonDecl(TypedefDecl *TDD) { TypedefDeclOrQualifier = TDD; } + + NestedNameSpecifier *getQualifier() const { + return hasExtInfo() ? TypedefDeclOrQualifier.get<ExtInfo*>()->NNS : 0; + } + SourceRange getQualifierRange() const { + return hasExtInfo() + ? TypedefDeclOrQualifier.get<ExtInfo*>()->NNSRange + : SourceRange(); + } + void setQualifierInfo(NestedNameSpecifier *Qualifier, + SourceRange QualifierRange); // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 0bdc6f54b7ca..6f8284458f2b 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -660,7 +660,7 @@ public: /// \brief Determine whether this declaration context is equivalent /// to the declaration context DC. bool Equals(DeclContext *DC) { - return this->getPrimaryContext() == DC->getPrimaryContext(); + return DC && this->getPrimaryContext() == DC->getPrimaryContext(); } /// \brief Determine whether this declaration context encloses the diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index af00c8d7e8ad..6b04ed54109a 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -7,7 +7,8 @@ // //===----------------------------------------------------------------------===// // -// This file defines the C++ Decl subclasses. +// This file defines the C++ Decl subclasses, other than those for +// templates (in DeclTemplate.h) and friends (in DeclFriend.h). // //===----------------------------------------------------------------------===// @@ -32,6 +33,7 @@ class CXXDestructorDecl; class CXXMethodDecl; class CXXRecordDecl; class CXXMemberLookupCriteria; +class FriendDecl; /// \brief Represents any kind of function declaration, whether it is a /// concrete function or a function template. @@ -298,6 +300,11 @@ class CXXRecordDecl : public RecordDecl { /// Definition - The declaration which defines this record. CXXRecordDecl *Definition; + /// FirstFriend - The first friend declaration in this class, or + /// null if there aren't any. This is actually currently stored + /// in reverse order. + FriendDecl *FirstFriend; + } *DefinitionData; struct DefinitionData &data() { @@ -322,12 +329,6 @@ class CXXRecordDecl : public RecordDecl { llvm::PointerUnion<ClassTemplateDecl*, MemberSpecializationInfo*> TemplateOrInstantiation; - void getNestedVisibleConversionFunctions(CXXRecordDecl *RD, - const llvm::SmallPtrSet<CanQualType, 8> &TopConversionsTypeSet, - const llvm::SmallPtrSet<CanQualType, 8> &HiddenConversionTypes); - void collectConversionFunctions( - llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet) const; - protected: CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, @@ -458,6 +459,13 @@ public: return ctor_iterator(decls_end()); } + /// An iterator over friend declarations. All of these are defined + /// in DeclFriend.h. + class friend_iterator; + friend_iterator friend_begin() const; + friend_iterator friend_end() const; + void pushFriendDecl(FriendDecl *FD); + /// hasConstCopyConstructor - Determines whether this class has a /// copy constructor that accepts a const-qualified argument. bool hasConstCopyConstructor(ASTContext &Context) const; @@ -545,14 +553,6 @@ public: /// in current class; including conversion function templates. const UnresolvedSetImpl *getVisibleConversionFunctions(); - /// addVisibleConversionFunction - Add a new conversion function to the - /// list of visible conversion functions. - void addVisibleConversionFunction(CXXConversionDecl *ConvDecl); - - /// \brief Add a new conversion function template to the list of visible - /// conversion functions. - void addVisibleConversionFunction(FunctionTemplateDecl *ConvDecl); - /// addConversionFunction - Add a new conversion function to the /// list of conversion functions. void addConversionFunction(CXXConversionDecl *ConvDecl); @@ -1385,77 +1385,6 @@ public: static bool classofKind(Kind K) { return K == CXXConversion; } }; -/// FriendDecl - Represents the declaration of a friend entity, -/// which can be a function, a type, or a templated function or type. -// For example: -/// -/// @code -/// template <typename T> class A { -/// friend int foo(T); -/// friend class B; -/// friend T; // only in C++0x -/// template <typename U> friend class C; -/// template <typename U> friend A& operator+=(A&, const U&) { ... } -/// }; -/// @endcode -/// -/// The semantic context of a friend decl is its declaring class. -class FriendDecl : public Decl { -public: - typedef llvm::PointerUnion<NamedDecl*,Type*> FriendUnion; - -private: - // The declaration that's a friend of this class. - FriendUnion Friend; - - // Location of the 'friend' specifier. - SourceLocation FriendLoc; - - // FIXME: Hack to keep track of whether this was a friend function - // template specialization. - bool WasSpecialization; - - FriendDecl(DeclContext *DC, SourceLocation L, FriendUnion Friend, - SourceLocation FriendL) - : Decl(Decl::Friend, DC, L), - Friend(Friend), - FriendLoc(FriendL), - WasSpecialization(false) { - } - -public: - static FriendDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation L, FriendUnion Friend_, - SourceLocation FriendL); - - /// If this friend declaration names an (untemplated but - /// possibly dependent) type, return the type; otherwise - /// return null. This is used only for C++0x's unelaborated - /// friend type declarations. - Type *getFriendType() const { - return Friend.dyn_cast<Type*>(); - } - - /// If this friend declaration doesn't name an unelaborated - /// type, return the inner declaration. - NamedDecl *getFriendDecl() const { - return Friend.dyn_cast<NamedDecl*>(); - } - - /// Retrieves the location of the 'friend' keyword. - SourceLocation getFriendLoc() const { - return FriendLoc; - } - - bool wasSpecialization() const { return WasSpecialization; } - void setSpecialization(bool WS) { WasSpecialization = WS; } - - // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { return classofKind(D->getKind()); } - static bool classof(const FriendDecl *D) { return true; } - static bool classofKind(Kind K) { return K == Decl::Friend; } -}; - /// LinkageSpecDecl - This represents a linkage specification. For example: /// extern "C" void foo(); /// diff --git a/include/clang/AST/DeclFriend.h b/include/clang/AST/DeclFriend.h new file mode 100644 index 000000000000..5022ad018f4f --- /dev/null +++ b/include/clang/AST/DeclFriend.h @@ -0,0 +1,167 @@ +//===-- DeclFriend.h - Classes for C++ friend declarations -*- C++ -*------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the section of the AST representing C++ friend +// declarations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLFRIEND_H +#define LLVM_CLANG_AST_DECLFRIEND_H + +#include "clang/AST/DeclCXX.h" + +namespace clang { + +/// FriendDecl - Represents the declaration of a friend entity, +/// which can be a function, a type, or a templated function or type. +// For example: +/// +/// @code +/// template <typename T> class A { +/// friend int foo(T); +/// friend class B; +/// friend T; // only in C++0x +/// template <typename U> friend class C; +/// template <typename U> friend A& operator+=(A&, const U&) { ... } +/// }; +/// @endcode +/// +/// The semantic context of a friend decl is its declaring class. +class FriendDecl : public Decl { +public: + typedef llvm::PointerUnion<NamedDecl*,Type*> FriendUnion; + +private: + // The declaration that's a friend of this class. + FriendUnion Friend; + + // A pointer to the next friend in the sequence. + FriendDecl *NextFriend; + + // Location of the 'friend' specifier. + SourceLocation FriendLoc; + + // FIXME: Hack to keep track of whether this was a friend function + // template specialization. + bool WasSpecialization; + + friend class CXXRecordDecl::friend_iterator; + friend class CXXRecordDecl; + + FriendDecl(DeclContext *DC, SourceLocation L, FriendUnion Friend, + SourceLocation FriendL) + : Decl(Decl::Friend, DC, L), + Friend(Friend), + NextFriend(0), + FriendLoc(FriendL), + WasSpecialization(false) { + } + +public: + static FriendDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, FriendUnion Friend_, + SourceLocation FriendL); + + /// If this friend declaration names an (untemplated but + /// possibly dependent) type, return the type; otherwise + /// return null. This is used only for C++0x's unelaborated + /// friend type declarations. + Type *getFriendType() const { + return Friend.dyn_cast<Type*>(); + } + + /// If this friend declaration doesn't name an unelaborated + /// type, return the inner declaration. + NamedDecl *getFriendDecl() const { + return Friend.dyn_cast<NamedDecl*>(); + } + + /// Retrieves the location of the 'friend' keyword. + SourceLocation getFriendLoc() const { + return FriendLoc; + } + + bool wasSpecialization() const { return WasSpecialization; } + void setSpecialization(bool WS) { WasSpecialization = WS; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const FriendDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Decl::Friend; } +}; + +/// An iterator over the friend declarations of a class. +class CXXRecordDecl::friend_iterator { + FriendDecl *Ptr; + + friend class CXXRecordDecl; + explicit friend_iterator(FriendDecl *Ptr) : Ptr(Ptr) {} +public: + friend_iterator() {} + + typedef FriendDecl *value_type; + typedef FriendDecl *reference; + typedef FriendDecl *pointer; + typedef int difference_type; + typedef std::forward_iterator_tag iterator_category; + + reference operator*() const { return Ptr; } + + friend_iterator &operator++() { + assert(Ptr && "attempt to increment past end of friend list"); + Ptr = Ptr->NextFriend; + return *this; + } + + friend_iterator operator++(int) { + friend_iterator tmp = *this; + ++*this; + return tmp; + } + + bool operator==(const friend_iterator &Other) const { + return Ptr == Other.Ptr; + } + + bool operator!=(const friend_iterator &Other) const { + return Ptr != Other.Ptr; + } + + friend_iterator &operator+=(difference_type N) { + assert(N >= 0 && "cannot rewind a CXXRecordDecl::friend_iterator"); + while (N--) + ++*this; + return *this; + } + + friend_iterator operator+(difference_type N) const { + friend_iterator tmp = *this; + tmp += N; + return tmp; + } +}; + +inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_begin() const { + return friend_iterator(data().FirstFriend); +} + +inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_end() const { + return friend_iterator(0); +} + +inline void CXXRecordDecl::pushFriendDecl(FriendDecl *FD) { + assert(FD->NextFriend == 0 && "friend already has next friend?"); + FD->NextFriend = data().FirstFriend; + data().FirstFriend = FD; +} + +} + +#endif diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 889e0d6c1be8..a1f565341e2c 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -381,8 +381,6 @@ public: ObjCIvarDecl *getIvarDecl(IdentifierInfo *Id) const; ObjCPropertyDecl *FindPropertyDeclaration(IdentifierInfo *PropertyId) const; - ObjCPropertyDecl *FindPropertyVisibleInPrimaryClass( - IdentifierInfo *PropertyId) const; // Marks the end of the container. SourceRange getAtEndRange() const { @@ -445,9 +443,6 @@ class ObjCInterfaceDecl : public ObjCContainerDecl { /// Protocols referenced in interface header declaration ObjCProtocolList ReferencedProtocols; - /// Instance variables in the interface. This list is completely redundant. - ObjCList<ObjCIvarDecl> IVars; - /// List of categories defined for this class. /// FIXME: Why is this a linked list?? ObjCCategoryDecl *CategoryList; @@ -538,7 +533,10 @@ public: } ObjCCategoryDecl* getClassExtension() const; - + + ObjCPropertyDecl + *FindPropertyVisibleInPrimaryClass(IdentifierInfo *PropertyId) const; + /// isSuperClassOf - Return true if this class is the specified class or is a /// super class of the specified interface class. bool isSuperClassOf(const ObjCInterfaceDecl *I) const { @@ -1330,6 +1328,10 @@ public: return PropertyIvarDecl; } + /// Lookup a property by name in the specified DeclContext. + static ObjCPropertyDecl *findPropertyDecl(const DeclContext *DC, + IdentifierInfo *propertyID); + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ObjCPropertyDecl *D) { return true; } static bool classofKind(Kind K) { return K == ObjCProperty; } diff --git a/include/clang/AST/DeclVisitor.h b/include/clang/AST/DeclVisitor.h index 9423c319c3e3..140e5c0a2a99 100644 --- a/include/clang/AST/DeclVisitor.h +++ b/include/clang/AST/DeclVisitor.h @@ -16,6 +16,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclFriend.h" #include "clang/AST/DeclTemplate.h" namespace clang { diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h index cd25969db0b0..e78476ef51bb 100644 --- a/include/clang/AST/RecordLayout.h +++ b/include/clang/AST/RecordLayout.h @@ -112,13 +112,14 @@ private: /// PrimaryBase - The primary base info for this record. PrimaryBaseInfo PrimaryBase; - /// BaseOffsets - Contains a map from base classes to their offset. /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :) - llvm::DenseMap<const CXXRecordDecl *, uint64_t> BaseOffsets; + typedef llvm::DenseMap<const CXXRecordDecl *, uint64_t> BaseOffsetsMapTy; + + /// BaseOffsets - Contains a map from base classes to their offset. + BaseOffsetsMapTy BaseOffsets; /// VBaseOffsets - Contains a map from vbase classes to their offset. - /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :) - llvm::DenseMap<const CXXRecordDecl *, uint64_t> VBaseOffsets; + BaseOffsetsMapTy VBaseOffsets; }; /// CXXInfo - If the record layout is for a C++ record, this will have @@ -133,15 +134,14 @@ private: unsigned fieldcount); // Constructor for C++ records. + typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy; ASTRecordLayout(ASTContext &Ctx, uint64_t size, unsigned alignment, uint64_t datasize, const uint64_t *fieldoffsets, unsigned fieldcount, uint64_t nonvirtualsize, unsigned nonvirtualalign, const PrimaryBaseInfo &PrimaryBase, - const std::pair<const CXXRecordDecl *, uint64_t> *bases, - unsigned numbases, - const std::pair<const CXXRecordDecl *, uint64_t> *vbases, - unsigned numvbases); + const BaseOffsetsMapTy& BaseOffsets, + const BaseOffsetsMapTy& VBaseOffsets); ~ASTRecordLayout() {} diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h index 528cf878031e..b7256c9dc3db 100644 --- a/include/clang/Analysis/CFG.h +++ b/include/clang/Analysis/CFG.h @@ -286,7 +286,8 @@ public: /// constructed CFG belongs to the caller. static CFG* buildCFG(const Decl *D, Stmt* AST, ASTContext *C, bool AddEHEdges = false, - bool AddScopes = false); + bool AddScopes = false /* NOT FULLY IMPLEMENTED. + NOT READY FOR GENERAL USE. */); /// createBlock - Create a new block in the CFG. The CFG owns the block; /// the caller should not directly free it. diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index af233b81e0a5..3afdaf5b0eb1 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -46,8 +46,8 @@ // U -> unsigned // // Types may be postfixed with the following modifiers: -// * -> pointer -// & -> reference +// * -> pointer (optionally followed by an address space number) +// & -> reference (optionally followed by an address space number) // C -> const // D -> volatile diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def index 880b4bab6e26..9a79f90d1e52 100644 --- a/include/clang/Basic/BuiltinsX86.def +++ b/include/clang/Basic/BuiltinsX86.def @@ -287,6 +287,10 @@ BUILTIN(__builtin_ia32_roundpd, "V2dV2di", "") BUILTIN(__builtin_ia32_dpps, "V4fV4fV4fi", "") BUILTIN(__builtin_ia32_dppd, "V2dV2dV2di", "") BUILTIN(__builtin_ia32_movntdqa, "V2LLiV2LLi*", "") - +BUILTIN(__builtin_ia32_ptestz128, "iV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_ptestc128, "iV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_ptestnzc128, "iV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_pcmpeqq, "V2LLiV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_mpsadbw128, "V16cV16cV16ci", "") #undef BUILTIN diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td index 66f84dbbbabe..849e6437fbe6 100644 --- a/include/clang/Basic/DiagnosticCommonKinds.td +++ b/include/clang/Basic/DiagnosticCommonKinds.td @@ -63,4 +63,12 @@ def err_target_unknown_cpu : Error<"unknown target CPU '%0'">; def err_target_unknown_abi : Error<"unknown target ABI '%0'">; def err_target_invalid_feature : Error<"invalid target feature '%0'">; +// Source manager +def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal; +def err_file_size_changed : Error< + "size of file '%0' changed since it was first processed (from %1 to %2)">, + DefaultFatal; +def err_file_modified : Error< + "file '%0' modified since it was first processed">, DefaultFatal; + } diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 17bad64e9c82..e5793fa58b04 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -59,7 +59,7 @@ def : DiagGroup<"nested-externs">; def : DiagGroup<"newline-eof">; def LongLong : DiagGroup<"long-long">; def MismatchedTags : DiagGroup<"mismatched-tags">; -def : DiagGroup<"missing-field-initializers">; +def MissingFieldInitializers : DiagGroup<"missing-field-initializers">; def NonNull : DiagGroup<"nonnull">; def : DiagGroup<"nonportable-cfstrings">; def : DiagGroup<"non-virtual-dtor">; @@ -147,6 +147,7 @@ def Format2 : DiagGroup<"format=2", [FormatNonLiteral, FormatSecurity, FormatY2K]>; def Extra : DiagGroup<"extra", [ + MissingFieldInitializers, SemiBeforeMethodBody, SignCompare, UnusedParameter diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 80a4eaee1120..9d001d48cc2a 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -183,6 +183,7 @@ def err_objc_no_attributes_on_category : Error< def err_objc_missing_end : Error<"missing @end">; def warn_objc_protocol_qualifier_missing_id : Warning< "protocol qualifiers without 'id' is archaic">; +def err_objc_unknown_at : Error<"expected an Objective-C directive after '@'">; def err_objc_illegal_visibility_spec : Error< "illegal visibility specification">; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 13ac9ece542b..9a9b7cc85f6a 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -428,11 +428,39 @@ def err_deep_exception_specs_differ : Error< // C++ access checking def err_class_redeclared_with_different_access : Error< "%0 redeclared with '%1' access">; -def err_access_private : Error<"%0 is a private member of %1">; -def err_access_ctor_private : Error<"calling a private constructor of %0">; -// Say something about the context for these? -def err_access_protected : Error<"%0 is a protected member of %1">; -def err_access_ctor_protected : Error<"calling a protected constructor of %0">; +def err_access : + Error<"%1 is a %select{private|protected}0 member of %3">, + NoSFINAE; +def err_access_ctor : + Error<"calling a %select{private|protected}0 constructor of class %2">, + NoSFINAE; +def err_access_dtor_base : + Error<"base class %0 has %select{private|protected}1 destructor">, + NoSFINAE; +def err_access_dtor_vbase : + Error<"inherited virtual base class %0 has " + "%select{private|protected}1 destructor">, + NoSFINAE; +def err_access_dtor_field : + Error<"field of type %1 has %select{private|protected}2 destructor">, + NoSFINAE; +def err_access_dtor_var : + Error<"variable of type %1 has %select{private|protected}2 destructor">, + NoSFINAE; +def err_access_assign_field : + Error<"field of type %1 has %select{private|protected}2 copy assignment" + " operator">, + NoSFINAE; +def err_access_assign_base : + Error<"base class %0 has %select{private|protected}1 copy assignment" + " operator">, + NoSFINAE; +def err_access_copy_field : + Error<"field of type %1 has %select{private|protected}2 copy constructor">, + NoSFINAE; +def err_access_copy_base : + Error<"base class %0 has %select{private|protected}1 copy constructor">, + NoSFINAE; def note_previous_access_declaration : Note< "previously declared '%1' here">; def err_access_outside_class : Error< @@ -1251,7 +1279,7 @@ def err_not_class_template_specialization : Error< def err_template_spec_needs_header : Error< "template specialization requires 'template<>'">; def err_template_spec_needs_template_parameters : Error< - "template specialization or definition requires a template parameter list" + "template specialization or definition requires a template parameter list " "corresponding to the nested type %0">; def err_template_param_list_matches_nontemplate : Error< "template parameter list matching the non-templated nested type %0 should " @@ -1562,6 +1590,9 @@ def warn_excess_initializers_in_char_array_initializer : ExtWarn< "excess elements in char array initializer">; def warn_initializer_string_for_char_array_too_long : ExtWarn< "initializer-string for char array is too long">; +def warn_missing_field_initializers : Warning< + "missing field '%0' initializer">, + InGroup<MissingFieldInitializers>, DefaultIgnore; def warn_braces_around_scalar_init : Warning< "braces around scalar initializer">; def err_many_braces_around_scalar_init : Error< @@ -1854,6 +1885,12 @@ def warn_mixed_sign_comparison : Warning< def warn_mixed_sign_conditional : Warning< "operands of ? are integers of different signs: %0 and %1">, InGroup<DiagGroup<"sign-compare">>, DefaultIgnore; +def warn_lunsigned_always_true_comparison : Warning< + "comparison of unsigned expression %0 is always %1">, + InGroup<DiagGroup<"sign-compare">>, DefaultIgnore; +def warn_runsigned_always_true_comparison : Warning< + "comparison of %0 unsigned expression is always %1">, + InGroup<DiagGroup<"sign-compare">>, DefaultIgnore; def err_invalid_this_use : Error< "invalid use of 'this' outside of a nonstatic member function">; diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h index 75a7b8192c5a..582d59c18a37 100644 --- a/include/clang/Basic/IdentifierTable.h +++ b/include/clang/Basic/IdentifierTable.h @@ -18,6 +18,7 @@ #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/TokenKinds.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/PointerLikeTypeTraits.h" @@ -236,9 +237,7 @@ public: /// Unlike the version in IdentifierTable, this returns a pointer instead /// of a reference. If the pointer is NULL then the IdentifierInfo cannot /// be found. - // - // FIXME: Move to StringRef API. - virtual IdentifierInfo* get(const char *NameStart, const char *NameEnd) = 0; + virtual IdentifierInfo* get(llvm::StringRef Name) = 0; }; /// \brief An abstract class used to resolve numerical identifier @@ -283,16 +282,16 @@ public: /// get - Return the identifier token info for the specified named identifier. /// - IdentifierInfo &get(const char *NameStart, const char *NameEnd) { + IdentifierInfo &get(llvm::StringRef Name) { llvm::StringMapEntry<IdentifierInfo*> &Entry = - HashTable.GetOrCreateValue(NameStart, NameEnd); + HashTable.GetOrCreateValue(Name); IdentifierInfo *II = Entry.getValue(); if (II) return *II; // No entry; if we have an external lookup, look there first. if (ExternalLookup) { - II = ExternalLookup->get(NameStart, NameEnd); + II = ExternalLookup->get(Name); if (II) { // Cache in the StringMap for subsequent lookups. Entry.setValue(II); @@ -312,6 +311,14 @@ public: return *II; } + IdentifierInfo &get(const char *NameStart, const char *NameEnd) { + return get(llvm::StringRef(NameStart, NameEnd-NameStart)); + } + + IdentifierInfo &get(const char *Name, size_t NameLen) { + return get(llvm::StringRef(Name, NameLen)); + } + /// \brief Creates a new IdentifierInfo from the given string. /// /// This is a lower-level version of get() that requires that this @@ -343,10 +350,6 @@ public: return CreateIdentifierInfo(Name.begin(), Name.end()); } - IdentifierInfo &get(llvm::StringRef Name) { - return get(Name.begin(), Name.end()); - } - typedef HashTableTy::const_iterator iterator; typedef HashTableTy::const_iterator const_iterator; @@ -474,9 +477,7 @@ public: SelectorName = "set"; SelectorName += Name->getName(); SelectorName[3] = toupper(SelectorName[3]); - IdentifierInfo *SetterName = - &Idents.get(SelectorName.data(), - SelectorName.data() + SelectorName.size()); + IdentifierInfo *SetterName = &Idents.get(SelectorName); return SelTable.getUnarySelector(SetterName); } }; @@ -533,7 +534,7 @@ struct DenseMapInfo<clang::Selector> { return LHS == RHS; } }; - + template <> struct isPodLike<clang::Selector> { static const bool value = true; }; diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h index 23e6efe8bd70..fdf69d063f4d 100644 --- a/include/clang/Basic/LangOptions.h +++ b/include/clang/Basic/LangOptions.h @@ -44,6 +44,7 @@ public: unsigned PascalStrings : 1; // Allow Pascal strings unsigned WritableStrings : 1; // Allow writable strings + unsigned ConstStrings : 1; // Add const qualifier to strings (-Wwrite-strings) unsigned LaxVectorConversions : 1; unsigned AltiVec : 1; // Support AltiVec-style vector initializers. unsigned Exceptions : 1; // Support exception handling. @@ -129,7 +130,7 @@ public: HexFloats = 0; GC = ObjC1 = ObjC2 = ObjCNonFragileABI = ObjCNonFragileABI2 = 0; C99 = Microsoft = CPlusPlus = CPlusPlus0x = 0; - CXXOperatorNames = PascalStrings = WritableStrings = 0; + CXXOperatorNames = PascalStrings = WritableStrings = ConstStrings = 0; Exceptions = SjLjExceptions = Freestanding = NoBuiltin = 0; NeXTRuntime = 1; RTTI = 1; diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h index 873aaeecb6bf..fb861dcf934d 100644 --- a/include/clang/Basic/PartialDiagnostic.h +++ b/include/clang/Basic/PartialDiagnostic.h @@ -69,6 +69,10 @@ class PartialDiagnostic { CodeModificationHint CodeModificationHints[MaxCodeModificationHints]; }; + // NOTE: Sema assumes that PartialDiagnostic is location-invariant + // in the sense that its bits can be safely memcpy'ed and destructed + // in the new location. + /// DiagID - The diagnostic ID. mutable unsigned DiagID; diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h index d4f557b57d0b..34dfecd9b6a8 100644 --- a/include/clang/Basic/SourceLocation.h +++ b/include/clang/Basic/SourceLocation.h @@ -20,6 +20,7 @@ namespace llvm { class MemoryBuffer; class raw_ostream; + class StringRef; template <typename T> struct DenseMapInfo; template <typename T> struct isPodLike; } @@ -209,9 +210,9 @@ public: const llvm::MemoryBuffer* getBuffer() const; - /// getBufferData - Return a pointer to the start and end of the source buffer - /// data for the specified FileID. - std::pair<const char*, const char*> getBufferData() const; + /// getBufferData - Return a StringRef to the source buffer data for the + /// specified FileID. + llvm::StringRef getBufferData() const; /// getDecomposedLoc - Decompose the specified location into a raw FileID + /// Offset pair. The first element is the FileID, the second is the diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h index 15ece685104c..ef51a5888379 100644 --- a/include/clang/Basic/SourceManager.h +++ b/include/clang/Basic/SourceManager.h @@ -17,22 +17,24 @@ #include "clang/Basic/SourceLocation.h" #include "llvm/Support/Allocator.h" #include "llvm/System/DataTypes.h" +#include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/DenseMap.h" #include <vector> #include <cassert> namespace llvm { class MemoryBuffer; +class StringRef; } namespace clang { +class Diagnostic; class SourceManager; class FileManager; class FileEntry; -class IdentifierTokenInfo; class LineTableInfo; - + /// SrcMgr - Public enums and private classes that are part of the /// SourceManager implementation. /// @@ -69,10 +71,14 @@ namespace SrcMgr { /// if SourceLineCache is non-null. unsigned NumLines; - /// getBuffer - Returns the memory buffer for the associated content. If - /// there is an error opening this buffer the first time, this manufactures - /// a temporary buffer and returns a non-empty error string. - const llvm::MemoryBuffer *getBuffer(std::string *ErrorStr = 0) const; + /// getBuffer - Returns the memory buffer for the associated content. + /// + /// \param Diag Object through which diagnostics will be emitted it the + /// buffer cannot be retrieved. + /// + /// \param Invalid If non-NULL, will be set \c true if an error occurred. + const llvm::MemoryBuffer *getBuffer(Diagnostic &Diag, + bool *Invalid = 0) const; /// getSize - Returns the size of the content encapsulated by this /// ContentCache. This can be the size of the source file or the size of an @@ -277,6 +283,9 @@ public: /// location indicates where the expanded token came from and the instantiation /// location specifies where it was expanded. class SourceManager { + /// \brief Diagnostic object. + Diagnostic &Diag; + mutable llvm::BumpPtrAllocator ContentCacheAlloc; /// FileInfos - Memoized information about all of the files tracked by this @@ -336,8 +345,8 @@ class SourceManager { explicit SourceManager(const SourceManager&); void operator=(const SourceManager&); public: - SourceManager() - : ExternalSLocEntries(0), LineTable(0), NumLinearScans(0), + SourceManager(Diagnostic &Diag) + : Diag(Diag), ExternalSLocEntries(0), LineTable(0), NumLinearScans(0), NumBinaryProbes(0) { clearIDTables(); } @@ -408,7 +417,11 @@ public: unsigned Offset = 0); /// \brief Retrieve the memory buffer associated with the given file. - const llvm::MemoryBuffer *getMemoryBufferForFile(const FileEntry *File); + /// + /// \param Invalid If non-NULL, will be set \c true if an error + /// occurs while retrieving the memory buffer. + const llvm::MemoryBuffer *getMemoryBufferForFile(const FileEntry *File, + bool *Invalid = 0); /// \brief Override the contents of the given source file by providing an /// already-allocated buffer. @@ -429,8 +442,9 @@ public: /// getBuffer - Return the buffer for the specified FileID. If there is an /// error opening this buffer the first time, this manufactures a temporary /// buffer and returns a non-empty error string. - const llvm::MemoryBuffer *getBuffer(FileID FID, std::string *Error = 0) const{ - return getSLocEntry(FID).getFile().getContentCache()->getBuffer(Error); + const llvm::MemoryBuffer *getBuffer(FileID FID, bool *Invalid = 0) const { + return getSLocEntry(FID).getFile().getContentCache()->getBuffer(Diag, + Invalid); } /// getFileEntryForID - Returns the FileEntry record for the provided FileID. @@ -438,9 +452,12 @@ public: return getSLocEntry(FID).getFile().getContentCache()->Entry; } - /// getBufferData - Return a pointer to the start and end of the source buffer - /// data for the specified FileID. - std::pair<const char*, const char*> getBufferData(FileID FID) const; + /// getBufferData - Return a StringRef to the source buffer data for the + /// specified FileID. + /// + /// \param FID The file ID whose contents will be returned. + /// \param Invalid If non-NULL, will be set true if an error occurred. + llvm::StringRef getBufferData(FileID FID, bool *Invalid = 0) const; //===--------------------------------------------------------------------===// @@ -558,31 +575,37 @@ public: /// getCharacterData - Return a pointer to the start of the specified location /// in the appropriate spelling MemoryBuffer. - const char *getCharacterData(SourceLocation SL) const; + /// + /// \param Invalid If non-NULL, will be set \c true if an error occurs. + const char *getCharacterData(SourceLocation SL, bool *Invalid = 0) const; /// getColumnNumber - Return the column # for the specified file position. /// This is significantly cheaper to compute than the line number. This /// returns zero if the column number isn't known. This may only be called on /// a file sloc, so you must choose a spelling or instantiation location /// before calling this method. - unsigned getColumnNumber(FileID FID, unsigned FilePos) const; - unsigned getSpellingColumnNumber(SourceLocation Loc) const; - unsigned getInstantiationColumnNumber(SourceLocation Loc) const; + unsigned getColumnNumber(FileID FID, unsigned FilePos, + bool *Invalid = 0) const; + unsigned getSpellingColumnNumber(SourceLocation Loc, + bool *Invalid = 0) const; + unsigned getInstantiationColumnNumber(SourceLocation Loc, + bool *Invalid = 0) const; /// getLineNumber - Given a SourceLocation, return the spelling line number /// for the position indicated. This requires building and caching a table of /// line offsets for the MemoryBuffer, so this is not cheap: use only when /// about to emit a diagnostic. - unsigned getLineNumber(FileID FID, unsigned FilePos) const; + unsigned getLineNumber(FileID FID, unsigned FilePos, bool *Invalid = 0) const; - unsigned getInstantiationLineNumber(SourceLocation Loc) const; - unsigned getSpellingLineNumber(SourceLocation Loc) const; + unsigned getInstantiationLineNumber(SourceLocation Loc, + bool *Invalid = 0) const; + unsigned getSpellingLineNumber(SourceLocation Loc, bool *Invalid = 0) const; /// Return the filename or buffer identifier of the buffer the location is in. /// Note that this name does not respect #line directives. Use getPresumedLoc /// for normal clients. - const char *getBufferName(SourceLocation Loc) const; + const char *getBufferName(SourceLocation Loc, bool *Invalid = 0) const; /// getFileCharacteristic - return the file characteristic of the specified /// source location, indicating whether this is a normal file, a system @@ -678,7 +701,7 @@ public: void PrintStats() const; unsigned sloc_entry_size() const { return SLocEntryTable.size(); } - + // FIXME: Exposing this is a little gross; what we want is a good way // to iterate the entries that were not defined in a PCH file (or // any other external source). @@ -692,8 +715,8 @@ public: ExternalSLocEntries->ReadSLocEntry(ID); return SLocEntryTable[ID]; } - - const SrcMgr::SLocEntry &getSLocEntry(FileID FID) const { + + const SrcMgr::SLocEntry &getSLocEntry(FileID FID) const { return getSLocEntry(FID.ID); } diff --git a/include/clang/Checker/PathSensitive/GRExprEngine.h b/include/clang/Checker/PathSensitive/GRExprEngine.h index 763bbcc9e1da..916511e8bd09 100644 --- a/include/clang/Checker/PathSensitive/GRExprEngine.h +++ b/include/clang/Checker/PathSensitive/GRExprEngine.h @@ -347,7 +347,10 @@ protected: void VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred, ExplodedNodeSet & Dst); - + + void VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, + ExplodedNode *Pred, + ExplodedNodeSet &Dst); /// Create a C++ temporary object for an rvalue. void CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst); diff --git a/include/clang/Driver/Action.h b/include/clang/Driver/Action.h index 679704c39587..ab3162a04707 100644 --- a/include/clang/Driver/Action.h +++ b/include/clang/Driver/Action.h @@ -66,17 +66,23 @@ private: ActionList Inputs; + unsigned OwnsInputs : 1; + protected: - Action(ActionClass _Kind, types::ID _Type) : Kind(_Kind), Type(_Type) {} + Action(ActionClass _Kind, types::ID _Type) + : Kind(_Kind), Type(_Type), OwnsInputs(true) {} Action(ActionClass _Kind, Action *Input, types::ID _Type) - : Kind(_Kind), Type(_Type), Inputs(&Input, &Input + 1) {} + : Kind(_Kind), Type(_Type), Inputs(&Input, &Input + 1), OwnsInputs(true) {} Action(ActionClass _Kind, const ActionList &_Inputs, types::ID _Type) - : Kind(_Kind), Type(_Type), Inputs(_Inputs) {} + : Kind(_Kind), Type(_Type), Inputs(_Inputs), OwnsInputs(true) {} public: virtual ~Action(); const char *getClassName() const { return Action::getClassName(getKind()); } + bool getOwnsInputs() { return OwnsInputs; } + void setOwnsInputs(bool Value) { OwnsInputs = Value; } + ActionClass getKind() const { return Kind; } types::ID getType() const { return Type; } diff --git a/include/clang/Driver/ArgList.h b/include/clang/Driver/ArgList.h index ab1abff7409b..0a8eaeaf238f 100644 --- a/include/clang/Driver/ArgList.h +++ b/include/clang/Driver/ArgList.h @@ -287,7 +287,7 @@ namespace driver { arglist_type ActualArgs; /// The list of arguments we synthesized. - arglist_type SynthesizedArgs; + mutable arglist_type SynthesizedArgs; /// Is this only a proxy for the base ArgList? bool OnlyProxy; diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index 7cd26ef04cc2..1ecd8d6adaf6 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -197,6 +197,8 @@ def fcolor_diagnostics : Flag<"-fcolor-diagnostics">, HelpText<"Use colors in diagnostics">; def Wno_rewrite_macros : Flag<"-Wno-rewrite-macros">, HelpText<"Silence ObjC rewriting warnings">; +def Wwrite_strings : Flag<"-Wwrite-strings">, + HelpText<"Add const qualifier to string literals">; def verify : Flag<"-verify">, HelpText<"Verify emitted diagnostics and warnings">; diff --git a/include/clang/Driver/Job.h b/include/clang/Driver/Job.h index 74ca083417a6..5a789fbb8f41 100644 --- a/include/clang/Driver/Job.h +++ b/include/clang/Driver/Job.h @@ -100,7 +100,9 @@ private: public: PipedJob(); + virtual ~PipedJob(); + /// Add a command to the piped job (taking ownership). void addCommand(Command *C) { Commands.push_back(C); } const list_type &getCommands() const { return Commands; } @@ -130,7 +132,9 @@ private: public: JobList(); + virtual ~JobList(); + /// Add a job to the list (taking ownership). void addJob(Job *J) { Jobs.push_back(J); } const list_type &getJobs() const { return Jobs; } diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 7f11c85ae35b..27ec12e4e4cd 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -121,7 +121,7 @@ public: }; friend class ConcurrencyCheck; - ASTUnit(bool MainFileIsAST); + ASTUnit(Diagnostic &Diag, bool MainFileIsAST); ~ASTUnit(); bool isMainFileAST() const { return MainFileIsAST; } diff --git a/include/clang/Lex/PTHManager.h b/include/clang/Lex/PTHManager.h index ac5594e55d7d..5e8a4f144c96 100644 --- a/include/clang/Lex/PTHManager.h +++ b/include/clang/Lex/PTHManager.h @@ -115,7 +115,7 @@ public: /// Unlike the version in IdentifierTable, this returns a pointer instead /// of a reference. If the pointer is NULL then the IdentifierInfo cannot /// be found. - IdentifierInfo *get(const char *NameStart, const char *NameEnd); + IdentifierInfo *get(llvm::StringRef Name); /// Create - This method creates PTHManager objects. The 'file' argument /// is the name of the PTH file. This method returns NULL upon failure. diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 532d8e4b46f3..2b27a06070f8 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -547,7 +547,9 @@ public: /// after trigraph expansion and escaped-newline folding. In particular, this /// wants to get the true, uncanonicalized, spelling of things like digraphs /// UCNs, etc. - std::string getSpelling(const Token &Tok) const; + /// + /// \param Invalid If non-NULL, will be set \c true if an error occurs. + std::string getSpelling(const Token &Tok, bool *Invalid = 0) const; /// getSpelling() - Return the 'spelling' of the Tok token. The spelling of a /// token is the characters used to represent the token in the source file @@ -556,7 +558,8 @@ public: /// UCNs, etc. static std::string getSpelling(const Token &Tok, const SourceManager &SourceMgr, - const LangOptions &Features); + const LangOptions &Features, + bool *Invalid = 0); /// getSpelling - This method is used to get the spelling of a token into a /// preallocated buffer, instead of as an std::string. The caller is required @@ -568,17 +571,20 @@ public: /// to point to a constant buffer with the data already in it (avoiding a /// copy). The caller is not allowed to modify the returned buffer pointer /// if an internal buffer is returned. - unsigned getSpelling(const Token &Tok, const char *&Buffer) const; + unsigned getSpelling(const Token &Tok, const char *&Buffer, + bool *Invalid = 0) const; /// getSpelling - This method is used to get the spelling of a token into a /// SmallVector. Note that the returned StringRef may not point to the /// supplied buffer if a copy can be avoided. llvm::StringRef getSpelling(const Token &Tok, - llvm::SmallVectorImpl<char> &Buffer) const; + llvm::SmallVectorImpl<char> &Buffer, + bool *Invalid = 0) const; /// getSpellingOfSingleCharacterNumericConstant - Tok is a numeric constant /// with length 1, return the character. - char getSpellingOfSingleCharacterNumericConstant(const Token &Tok) const { + char getSpellingOfSingleCharacterNumericConstant(const Token &Tok, + bool *Invalid = 0) const { assert(Tok.is(tok::numeric_constant) && Tok.getLength() == 1 && "Called on unsupported token"); assert(!Tok.needsCleaning() && "Token can't need cleaning with length 1"); @@ -730,7 +736,7 @@ public: /// This code concatenates and consumes tokens up to the '>' token. It returns /// false if the > was found, otherwise it returns true if it finds and consumes /// the EOM marker. - bool ConcatenateIncludeName(llvm::SmallVector<char, 128> &FilenameBuffer); + bool ConcatenateIncludeName(llvm::SmallString<128> &FilenameBuffer); private: diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 26b10b58713e..8230cde3b2d5 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -423,10 +423,15 @@ namespace { /// (which requires a < after the Doxygen-comment delimiter). Otherwise, /// we only return true when we find a non-member comment. static bool -isDoxygenComment(SourceManager &SourceMgr, SourceRange Comment, +isDoxygenComment(SourceManager &SourceMgr, SourceRange Comment, bool Member = false) { + bool Invalid = false; const char *BufferStart - = SourceMgr.getBufferData(SourceMgr.getFileID(Comment.getBegin())).first; + = SourceMgr.getBufferData(SourceMgr.getFileID(Comment.getBegin()), + &Invalid).data(); + if (Invalid) + return false; + const char *Start = BufferStart + SourceMgr.getFileOffset(Comment.getBegin()); const char* End = BufferStart + SourceMgr.getFileOffset(Comment.getEnd()); @@ -488,9 +493,12 @@ const char *ASTContext::getCommentForDecl(const Decl *D) { // beginning of the file buffer. std::pair<FileID, unsigned> DeclStartDecomp = SourceMgr.getDecomposedLoc(DeclStartLoc); + bool Invalid = false; const char *FileBufferStart - = SourceMgr.getBufferData(DeclStartDecomp.first).first; - + = SourceMgr.getBufferData(DeclStartDecomp.first, &Invalid).data(); + if (Invalid) + return 0; + // First check whether we have a comment for a member. if (LastComment != Comments.end() && !isa<TagDecl>(D) && !isa<NamespaceDecl>(D) && @@ -971,22 +979,10 @@ void ASTContext::ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI, CollectNonClassIvars(OI, Ivars); } -void ASTContext::CollectProtocolSynthesizedIvars(const ObjCProtocolDecl *PD, - llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) { - for (ObjCContainerDecl::prop_iterator I = PD->prop_begin(), - E = PD->prop_end(); I != E; ++I) - if (ObjCIvarDecl *Ivar = (*I)->getPropertyIvarDecl()) - Ivars.push_back(Ivar); - - // Also look into nested protocols. - for (ObjCProtocolDecl::protocol_iterator P = PD->protocol_begin(), - E = PD->protocol_end(); P != E; ++P) - CollectProtocolSynthesizedIvars(*P, Ivars); -} - /// CollectNonClassIvars - /// This routine collects all other ivars which are not declared in the class. -/// This includes synthesized ivars and those in class's implementation. +/// This includes synthesized ivars (via @synthesize) and those in +// class's @implementation. /// void ASTContext::CollectNonClassIvars(const ObjCInterfaceDecl *OI, llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) { @@ -997,21 +993,9 @@ void ASTContext::CollectNonClassIvars(const ObjCInterfaceDecl *OI, Ivars.push_back(*I); } } - - for (ObjCInterfaceDecl::prop_iterator I = OI->prop_begin(), - E = OI->prop_end(); I != E; ++I) { - if (ObjCIvarDecl *Ivar = (*I)->getPropertyIvarDecl()) - Ivars.push_back(Ivar); - } - // Also look into interface's protocol list for properties declared - // in the protocol and whose ivars are synthesized. - for (ObjCInterfaceDecl::protocol_iterator P = OI->protocol_begin(), - PE = OI->protocol_end(); P != PE; ++P) { - ObjCProtocolDecl *PD = (*P); - CollectProtocolSynthesizedIvars(PD, Ivars); - } - // Also add any ivar defined in this class's implementation + // Also add any ivar defined in this class's implementation. This + // includes synthesized ivars. if (ObjCImplementationDecl *ImplDecl = OI->getImplementation()) { for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(), E = ImplDecl->ivar_end(); I != E; ++I) @@ -4760,7 +4744,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { return QualType(); case Type::Vector: // FIXME: The merged type should be an ExtVector! - if (areCompatVectorTypes(LHS->getAs<VectorType>(), RHS->getAs<VectorType>())) + if (areCompatVectorTypes(LHSCan->getAs<VectorType>(), + RHSCan->getAs<VectorType>())) return LHS; return QualType(); case Type::ObjCInterface: { @@ -4997,13 +4982,24 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, Done = false; while (!Done) { - switch (*Str++) { + switch (char c = *Str++) { default: Done = true; --Str; break; case '*': - Type = Context.getPointerType(Type); - break; case '&': - Type = Context.getLValueReferenceType(Type); + { + // Both pointers and references can have their pointee types + // qualified with an address space. + char *End; + unsigned AddrSpace = strtoul(Str, &End, 10); + if (End != Str && AddrSpace != 0) { + Type = Context.getAddrSpaceQualType(Type, AddrSpace); + Str = End; + } + } + if (c == '*') + Type = Context.getPointerType(Type); + else + Type = Context.getLValueReferenceType(Type); break; // FIXME: There's no way to have a built-in with an rvalue ref arg. case 'C': diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index d9c0d7b6bed4..dd2528a6b3b3 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -1592,6 +1592,12 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { Name.getAsIdentifierInfo(), Importer.Import(D->getTagKeywordLoc()), 0); + // Import the qualifier, if any. + if (D->getQualifier()) { + NestedNameSpecifier *NNS = Importer.Import(D->getQualifier()); + SourceRange NNSRange = Importer.Import(D->getQualifierRange()); + D2->setQualifierInfo(NNS, NNSRange); + } D2->setAccess(D->getAccess()); D2->setLexicalDeclContext(LexicalDC); Importer.Imported(D, D2); @@ -1734,6 +1740,12 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { Name.getAsIdentifierInfo(), Importer.Import(D->getTagKeywordLoc())); } + // Import the qualifier, if any. + if (D->getQualifier()) { + NestedNameSpecifier *NNS = Importer.Import(D->getQualifier()); + SourceRange NNSRange = Importer.Import(D->getQualifierRange()); + D2->setQualifierInfo(NNS, NNSRange); + } D2->setLexicalDeclContext(LexicalDC); LexicalDC->addDecl(D2); } @@ -1900,6 +1912,13 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { D->isInlineSpecified(), D->hasWrittenPrototype()); } + + // Import the qualifier, if any. + if (D->getQualifier()) { + NestedNameSpecifier *NNS = Importer.Import(D->getQualifier()); + SourceRange NNSRange = Importer.Import(D->getQualifierRange()); + ToFunction->setQualifierInfo(NNS, NNSRange); + } ToFunction->setAccess(D->getAccess()); ToFunction->setLexicalDeclContext(LexicalDC); Importer.Imported(D, ToFunction); @@ -2110,6 +2129,12 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, Loc, Name.getAsIdentifierInfo(), T, TInfo, D->getStorageClass()); + // Import the qualifier, if any. + if (D->getQualifier()) { + NestedNameSpecifier *NNS = Importer.Import(D->getQualifier()); + SourceRange NNSRange = Importer.Import(D->getQualifierRange()); + ToVar->setQualifierInfo(NNS, NNSRange); + } ToVar->setAccess(D->getAccess()); ToVar->setLexicalDeclContext(LexicalDC); Importer.Imported(D, ToVar); @@ -2176,6 +2201,7 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) { Loc, Name.getAsIdentifierInfo(), T, TInfo, D->getStorageClass(), /*FIXME: Default argument*/ 0); + ToParm->setHasInheritedDefaultArg(D->hasInheritedDefaultArg()); return Importer.Imported(D, ToParm); } @@ -3063,7 +3089,7 @@ FileID ASTImporter::Import(FileID FromID) { FromSLoc.getFile().getFileCharacteristic()); } else { // FIXME: We want to re-use the existing MemoryBuffer! - const llvm::MemoryBuffer *FromBuf = Cache->getBuffer(); + const llvm::MemoryBuffer *FromBuf = Cache->getBuffer(getDiags()); llvm::MemoryBuffer *ToBuf = llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBufferStart(), FromBuf->getBufferEnd(), diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 2f1a6af77aa9..3408a1e3cc74 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -11,6 +11,7 @@ add_clang_library(clangAST Decl.cpp DeclBase.cpp DeclCXX.cpp + DeclFriend.cpp DeclGroup.cpp DeclObjC.cpp DeclPrinter.cpp diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 23f5fba437a5..f568d1cdd45e 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -495,9 +495,16 @@ NamedDecl *NamedDecl::getUnderlyingDecl() { // DeclaratorDecl Implementation //===----------------------------------------------------------------------===// +DeclaratorDecl::~DeclaratorDecl() {} +void DeclaratorDecl::Destroy(ASTContext &C) { + if (hasExtInfo()) + C.Deallocate(getExtInfo()); + ValueDecl::Destroy(C); +} + SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const { if (DeclInfo) { - TypeLoc TL = DeclInfo->getTypeLoc(); + TypeLoc TL = getTypeSourceInfo()->getTypeLoc(); while (true) { TypeLoc NextTL = TL.getNextTypeLoc(); if (!NextTL) @@ -508,6 +515,36 @@ SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const { return SourceLocation(); } +void DeclaratorDecl::setQualifierInfo(NestedNameSpecifier *Qualifier, + SourceRange QualifierRange) { + if (Qualifier) { + // Make sure the extended decl info is allocated. + if (!hasExtInfo()) { + // Save (non-extended) type source info pointer. + TypeSourceInfo *savedTInfo = DeclInfo.get<TypeSourceInfo*>(); + // Allocate external info struct. + DeclInfo = new (getASTContext()) ExtInfo; + // Restore savedTInfo into (extended) decl info. + getExtInfo()->TInfo = savedTInfo; + } + // Set qualifier info. + getExtInfo()->NNS = Qualifier; + getExtInfo()->NNSRange = QualifierRange; + } + else { + // Here Qualifier == 0, i.e., we are removing the qualifier (if any). + assert(QualifierRange.isInvalid()); + if (hasExtInfo()) { + // Save type source info pointer. + TypeSourceInfo *savedTInfo = getExtInfo()->TInfo; + // Deallocate the extended decl info. + getASTContext().Deallocate(getExtInfo()); + // Restore savedTInfo into (non-extended) decl info. + DeclInfo = savedTInfo; + } + } +} + //===----------------------------------------------------------------------===// // VarDecl Implementation //===----------------------------------------------------------------------===// @@ -542,7 +579,7 @@ void VarDecl::Destroy(ASTContext& C) { } } this->~VarDecl(); - C.Deallocate((void *)this); + DeclaratorDecl::Destroy(C); } VarDecl::~VarDecl() { @@ -818,7 +855,7 @@ void FunctionDecl::Destroy(ASTContext& C) { C.Deallocate(ParamInfo); - Decl::Destroy(C); + DeclaratorDecl::Destroy(C); } void FunctionDecl::getNameForDiagnostic(std::string &S, @@ -1348,6 +1385,12 @@ bool FieldDecl::isAnonymousStructOrUnion() const { // TagDecl Implementation //===----------------------------------------------------------------------===// +void TagDecl::Destroy(ASTContext &C) { + if (hasExtInfo()) + C.Deallocate(getExtInfo()); + TypeDecl::Destroy(C); +} + SourceRange TagDecl::getSourceRange() const { SourceLocation E = RBraceLoc.isValid() ? RBraceLoc : getLocation(); return SourceRange(TagKeywordLoc, E); @@ -1409,6 +1452,26 @@ TagDecl::TagKind TagDecl::getTagKindForTypeSpec(unsigned TypeSpec) { } } +void TagDecl::setQualifierInfo(NestedNameSpecifier *Qualifier, + SourceRange QualifierRange) { + if (Qualifier) { + // Make sure the extended qualifier info is allocated. + if (!hasExtInfo()) + TypedefDeclOrQualifier = new (getASTContext()) ExtInfo; + // Set qualifier info. + getExtInfo()->NNS = Qualifier; + getExtInfo()->NNSRange = QualifierRange; + } + else { + // Here Qualifier == 0, i.e., we are removing the qualifier (if any). + assert(QualifierRange.isInvalid()); + if (hasExtInfo()) { + getASTContext().Deallocate(getExtInfo()); + TypedefDeclOrQualifier = (TypedefDecl*) 0; + } + } +} + //===----------------------------------------------------------------------===// // EnumDecl Implementation //===----------------------------------------------------------------------===// @@ -1422,7 +1485,7 @@ EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, } void EnumDecl::Destroy(ASTContext& C) { - Decl::Destroy(C); + TagDecl::Destroy(C); } void EnumDecl::completeDefinition(QualType NewType, @@ -1529,7 +1592,7 @@ void NamespaceDecl::Destroy(ASTContext& C) { // together. They are all top-level Decls. this->~NamespaceDecl(); - C.Deallocate((void *)this); + Decl::Destroy(C); } @@ -1563,7 +1626,7 @@ EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD, void EnumConstantDecl::Destroy(ASTContext& C) { if (Init) Init->Destroy(C); - Decl::Destroy(C); + ValueDecl::Destroy(C); } TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index a9495343e887..1aac7cfd598a 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -15,6 +15,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclContextInternals.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclFriend.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExternalASTSource.h" diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 7f4ad34fb7f8..37f7479b36cd 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -33,7 +33,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true), HasTrivialDestructor(true), ComputedVisibleConversions(false), Bases(0), NumBases(0), VBases(0), NumVBases(0), - Definition(D) { + Definition(D), FirstFriend(0) { } CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, @@ -318,105 +318,128 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context, data().PlainOldData = false; } -void -CXXRecordDecl::collectConversionFunctions( - llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet) const -{ - const UnresolvedSetImpl *Cs = getConversionFunctions(); - for (UnresolvedSetImpl::iterator I = Cs->begin(), E = Cs->end(); - I != E; ++I) { - NamedDecl *TopConv = *I; - CanQualType TConvType; - if (FunctionTemplateDecl *TConversionTemplate = - dyn_cast<FunctionTemplateDecl>(TopConv)) - TConvType = - getASTContext().getCanonicalType( - TConversionTemplate->getTemplatedDecl()->getResultType()); - else - TConvType = - getASTContext().getCanonicalType( - cast<CXXConversionDecl>(TopConv)->getConversionType()); - ConversionsTypeSet.insert(TConvType); - } -} - -/// getNestedVisibleConversionFunctions - imports unique conversion -/// functions from base classes into the visible conversion function -/// list of the class 'RD'. This is a private helper method. -/// TopConversionsTypeSet is the set of conversion functions of the class -/// we are interested in. HiddenConversionTypes is set of conversion functions -/// of the immediate derived class which hides the conversion functions found -/// in current class. -void -CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD, - const llvm::SmallPtrSet<CanQualType, 8> &TopConversionsTypeSet, - const llvm::SmallPtrSet<CanQualType, 8> &HiddenConversionTypes) -{ - bool inTopClass = (RD == this); - QualType ClassType = getASTContext().getTypeDeclType(this); - if (const RecordType *Record = ClassType->getAs<RecordType>()) { - const UnresolvedSetImpl *Cs - = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions(); - - for (UnresolvedSetImpl::iterator I = Cs->begin(), E = Cs->end(); - I != E; ++I) { - NamedDecl *Conv = *I; - // Only those conversions not exact match of conversions in current - // class are candidateconversion routines. - CanQualType ConvType; - if (FunctionTemplateDecl *ConversionTemplate = - dyn_cast<FunctionTemplateDecl>(Conv)) - ConvType = - getASTContext().getCanonicalType( - ConversionTemplate->getTemplatedDecl()->getResultType()); - else - ConvType = - getASTContext().getCanonicalType( - cast<CXXConversionDecl>(Conv)->getConversionType()); - // We only add conversion functions found in the base class if they - // are not hidden by those found in HiddenConversionTypes which are - // the conversion functions in its derived class. - if (inTopClass || - (!TopConversionsTypeSet.count(ConvType) && - !HiddenConversionTypes.count(ConvType)) ) { - if (FunctionTemplateDecl *ConversionTemplate = - dyn_cast<FunctionTemplateDecl>(Conv)) - RD->addVisibleConversionFunction(ConversionTemplate); +static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) { + QualType T; + if (FunctionTemplateDecl *ConvTemp = dyn_cast<FunctionTemplateDecl>(Conv)) + T = ConvTemp->getTemplatedDecl()->getResultType(); + else + T = cast<CXXConversionDecl>(Conv)->getConversionType(); + return Context.getCanonicalType(T); +} + +/// Collect the visible conversions of a base class. +/// +/// \param Base a base class of the class we're considering +/// \param InVirtual whether this base class is a virtual base (or a base +/// of a virtual base) +/// \param Access the access along the inheritance path to this base +/// \param ParentHiddenTypes the conversions provided by the inheritors +/// of this base +/// \param Output the set to which to add conversions from non-virtual bases +/// \param VOutput the set to which to add conversions from virtual bases +/// \param HiddenVBaseCs the set of conversions which were hidden in a +/// virtual base along some inheritance path +static void CollectVisibleConversions(ASTContext &Context, + CXXRecordDecl *Record, + bool InVirtual, + AccessSpecifier Access, + const llvm::SmallPtrSet<CanQualType, 8> &ParentHiddenTypes, + UnresolvedSetImpl &Output, + UnresolvedSetImpl &VOutput, + llvm::SmallPtrSet<NamedDecl*, 8> &HiddenVBaseCs) { + // The set of types which have conversions in this class or its + // subclasses. As an optimization, we don't copy the derived set + // unless it might change. + const llvm::SmallPtrSet<CanQualType, 8> *HiddenTypes = &ParentHiddenTypes; + llvm::SmallPtrSet<CanQualType, 8> HiddenTypesBuffer; + + // Collect the direct conversions and figure out which conversions + // will be hidden in the subclasses. + UnresolvedSetImpl &Cs = *Record->getConversionFunctions(); + if (!Cs.empty()) { + HiddenTypesBuffer = ParentHiddenTypes; + HiddenTypes = &HiddenTypesBuffer; + + for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I) { + bool Hidden = + !HiddenTypesBuffer.insert(GetConversionType(Context, I.getDecl())); + + // If this conversion is hidden and we're in a virtual base, + // remember that it's hidden along some inheritance path. + if (Hidden && InVirtual) + HiddenVBaseCs.insert(cast<NamedDecl>(I.getDecl()->getCanonicalDecl())); + + // If this conversion isn't hidden, add it to the appropriate output. + else if (!Hidden) { + AccessSpecifier IAccess + = CXXRecordDecl::MergeAccess(Access, I.getAccess()); + + if (InVirtual) + VOutput.addDecl(I.getDecl(), IAccess); else - RD->addVisibleConversionFunction(cast<CXXConversionDecl>(Conv)); + Output.addDecl(I.getDecl(), IAccess); } } } - if (getNumBases() == 0 && getNumVBases() == 0) - return; + // Collect information recursively from any base classes. + for (CXXRecordDecl::base_class_iterator + I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) { + const RecordType *RT = I->getType()->getAs<RecordType>(); + if (!RT) continue; - llvm::SmallPtrSet<CanQualType, 8> ConversionFunctions; - if (!inTopClass) - collectConversionFunctions(ConversionFunctions); + AccessSpecifier BaseAccess + = CXXRecordDecl::MergeAccess(Access, I->getAccessSpecifier()); + bool BaseInVirtual = InVirtual || I->isVirtual(); - for (CXXRecordDecl::base_class_iterator VBase = vbases_begin(), - E = vbases_end(); VBase != E; ++VBase) { - if (const RecordType *RT = VBase->getType()->getAs<RecordType>()) { - CXXRecordDecl *VBaseClassDecl - = cast<CXXRecordDecl>(RT->getDecl()); - VBaseClassDecl->getNestedVisibleConversionFunctions(RD, - TopConversionsTypeSet, - (inTopClass ? TopConversionsTypeSet : ConversionFunctions)); - } + CXXRecordDecl *Base = cast<CXXRecordDecl>(RT->getDecl()); + CollectVisibleConversions(Context, Base, BaseInVirtual, BaseAccess, + *HiddenTypes, Output, VOutput, HiddenVBaseCs); } - for (CXXRecordDecl::base_class_iterator Base = bases_begin(), - E = bases_end(); Base != E; ++Base) { - if (Base->isVirtual()) - continue; - if (const RecordType *RT = Base->getType()->getAs<RecordType>()) { - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(RT->getDecl()); +} - BaseClassDecl->getNestedVisibleConversionFunctions(RD, - TopConversionsTypeSet, - (inTopClass ? TopConversionsTypeSet : ConversionFunctions)); - } +/// Collect the visible conversions of a class. +/// +/// This would be extremely straightforward if it weren't for virtual +/// bases. It might be worth special-casing that, really. +static void CollectVisibleConversions(ASTContext &Context, + CXXRecordDecl *Record, + UnresolvedSetImpl &Output) { + // The collection of all conversions in virtual bases that we've + // found. These will be added to the output as long as they don't + // appear in the hidden-conversions set. + UnresolvedSet<8> VBaseCs; + + // The set of conversions in virtual bases that we've determined to + // be hidden. + llvm::SmallPtrSet<NamedDecl*, 8> HiddenVBaseCs; + + // The set of types hidden by classes derived from this one. + llvm::SmallPtrSet<CanQualType, 8> HiddenTypes; + + // Go ahead and collect the direct conversions and add them to the + // hidden-types set. + UnresolvedSetImpl &Cs = *Record->getConversionFunctions(); + Output.append(Cs.begin(), Cs.end()); + for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I) + HiddenTypes.insert(GetConversionType(Context, I.getDecl())); + + // Recursively collect conversions from base classes. + for (CXXRecordDecl::base_class_iterator + I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) { + const RecordType *RT = I->getType()->getAs<RecordType>(); + if (!RT) continue; + + CollectVisibleConversions(Context, cast<CXXRecordDecl>(RT->getDecl()), + I->isVirtual(), I->getAccessSpecifier(), + HiddenTypes, Output, VBaseCs, HiddenVBaseCs); + } + + // Add any unhidden conversions provided by virtual bases. + for (UnresolvedSetIterator I = VBaseCs.begin(), E = VBaseCs.end(); + I != E; ++I) { + if (!HiddenVBaseCs.count(cast<NamedDecl>(I.getDecl()->getCanonicalDecl()))) + Output.addDecl(I.getDecl(), I.getAccess()); } } @@ -429,37 +452,27 @@ const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() { // If visible conversion list is already evaluated, return it. if (data().ComputedVisibleConversions) return &data().VisibleConversions; - llvm::SmallPtrSet<CanQualType, 8> TopConversionsTypeSet; - collectConversionFunctions(TopConversionsTypeSet); - getNestedVisibleConversionFunctions(this, TopConversionsTypeSet, - TopConversionsTypeSet); + CollectVisibleConversions(getASTContext(), this, data().VisibleConversions); data().ComputedVisibleConversions = true; return &data().VisibleConversions; } -void CXXRecordDecl::addVisibleConversionFunction( - CXXConversionDecl *ConvDecl) { - assert(!ConvDecl->getDescribedFunctionTemplate() && - "Conversion function templates should cast to FunctionTemplateDecl."); - data().VisibleConversions.addDecl(ConvDecl); -} - -void CXXRecordDecl::addVisibleConversionFunction( - FunctionTemplateDecl *ConvDecl) { - assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) && - "Function template is not a conversion function template"); - data().VisibleConversions.addDecl(ConvDecl); -} - void CXXRecordDecl::addConversionFunction(CXXConversionDecl *ConvDecl) { assert(!ConvDecl->getDescribedFunctionTemplate() && "Conversion function templates should cast to FunctionTemplateDecl."); + assert(ConvDecl->getDeclContext() == this && + "conversion function does not belong to this record"); + + // We intentionally don't use the decl's access here because it + // hasn't been set yet. That's really just a misdesign in Sema. data().Conversions.addDecl(ConvDecl); } void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) { assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) && "Function template is not a conversion function template"); + assert(ConvDecl->getDeclContext() == this && + "conversion function does not belong to this record"); data().Conversions.addDecl(ConvDecl); } @@ -846,28 +859,6 @@ CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD, return new (C) CXXConversionDecl(RD, L, N, T, TInfo, isInline, isExplicit); } -FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, - FriendUnion Friend, - SourceLocation FriendL) { -#ifndef NDEBUG - if (Friend.is<NamedDecl*>()) { - NamedDecl *D = Friend.get<NamedDecl*>(); - assert(isa<FunctionDecl>(D) || - isa<CXXRecordDecl>(D) || - isa<FunctionTemplateDecl>(D) || - isa<ClassTemplateDecl>(D)); - - // As a temporary hack, we permit template instantiation to point - // to the original declaration when instantiating members. - assert(D->getFriendObjectKind() || - (cast<CXXRecordDecl>(DC)->getTemplateSpecializationKind())); - } -#endif - - return new (C) FriendDecl(DC, L, Friend, FriendL); -} - LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, @@ -952,8 +943,7 @@ StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC, void StaticAssertDecl::Destroy(ASTContext& C) { AssertExpr->Destroy(C); Message->Destroy(C); - this->~StaticAssertDecl(); - C.Deallocate((void *)this); + Decl::Destroy(C); } StaticAssertDecl::~StaticAssertDecl() { diff --git a/lib/AST/DeclFriend.cpp b/lib/AST/DeclFriend.cpp new file mode 100644 index 000000000000..ab3552db28e0 --- /dev/null +++ b/lib/AST/DeclFriend.cpp @@ -0,0 +1,41 @@ +//===--- DeclFriend.cpp - C++ Friend Declaration AST Node Implementation --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the AST classes related to C++ friend +// declarations. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/DeclFriend.h" +#include "clang/AST/DeclTemplate.h" +using namespace clang; + +FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + FriendUnion Friend, + SourceLocation FriendL) { +#ifndef NDEBUG + if (Friend.is<NamedDecl*>()) { + NamedDecl *D = Friend.get<NamedDecl*>(); + assert(isa<FunctionDecl>(D) || + isa<CXXRecordDecl>(D) || + isa<FunctionTemplateDecl>(D) || + isa<ClassTemplateDecl>(D)); + + // As a temporary hack, we permit template instantiation to point + // to the original declaration when instantiating members. + assert(D->getFriendObjectKind() || + (cast<CXXRecordDecl>(DC)->getTemplateSpecializationKind())); + } +#endif + + FriendDecl *FD = new (C) FriendDecl(DC, L, Friend, FriendL); + cast<CXXRecordDecl>(DC)->pushFriendDecl(FD); + return FD; +} diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 67b71a0c44e5..7d1033d4f15f 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -89,47 +89,69 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const { return 0; } +ObjCPropertyDecl * +ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC, + IdentifierInfo *propertyID) { + + DeclContext::lookup_const_iterator I, E; + llvm::tie(I, E) = DC->lookup(propertyID); + for ( ; I != E; ++I) + if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(*I)) + return PD; + + return 0; +} + /// FindPropertyDeclaration - Finds declaration of the property given its name /// in 'PropertyId' and returns it. It returns 0, if not found. -/// FIXME: Convert to DeclContext lookup... -/// ObjCPropertyDecl * ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { - for (prop_iterator I = prop_begin(), E = prop_end(); I != E; ++I) - if ((*I)->getIdentifier() == PropertyId) - return *I; - - const ObjCProtocolDecl *PID = dyn_cast<ObjCProtocolDecl>(this); - if (PID) { - for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(), - E = PID->protocol_end(); I != E; ++I) - if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) - return P; - } - if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(this)) { - // Look through categories. - for (ObjCCategoryDecl *Category = OID->getCategoryList(); - Category; Category = Category->getNextClassCategory()) { - if (!Category->IsClassExtension()) - if (ObjCPropertyDecl *P = Category->FindPropertyDeclaration(PropertyId)) + if (ObjCPropertyDecl *PD = + ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId)) + return PD; + + switch (getKind()) { + default: + break; + case Decl::ObjCProtocol: { + const ObjCProtocolDecl *PID = cast<ObjCProtocolDecl>(this); + for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(), + E = PID->protocol_end(); I != E; ++I) + if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) return P; + break; } - // Look through protocols. - for (ObjCInterfaceDecl::protocol_iterator I = OID->protocol_begin(), - E = OID->protocol_end(); I != E; ++I) { - if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) - return P; + case Decl::ObjCInterface: { + const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(this); + // Look through categories. + for (ObjCCategoryDecl *Cat = OID->getCategoryList(); + Cat; Cat = Cat->getNextClassCategory()) + if (!Cat->IsClassExtension()) + if (ObjCPropertyDecl *P = Cat->FindPropertyDeclaration(PropertyId)) + return P; + + // Look through protocols. + for (ObjCInterfaceDecl::protocol_iterator + I = OID->protocol_begin(), E = OID->protocol_end(); I != E; ++I) + if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) + return P; + + // Finally, check the super class. + if (const ObjCInterfaceDecl *superClass = OID->getSuperClass()) + return superClass->FindPropertyDeclaration(PropertyId); + break; } - if (OID->getSuperClass()) - return OID->getSuperClass()->FindPropertyDeclaration(PropertyId); - } else if (const ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(this)) { - // Look through protocols. - if (!OCD->IsClassExtension()) - for (ObjCInterfaceDecl::protocol_iterator I = OCD->protocol_begin(), - E = OCD->protocol_end(); I != E; ++I) { + case Decl::ObjCCategory: { + const ObjCCategoryDecl *OCD = cast<ObjCCategoryDecl>(this); + // Look through protocols. + if (!OCD->IsClassExtension()) + for (ObjCCategoryDecl::protocol_iterator + I = OCD->protocol_begin(), E = OCD->protocol_end(); I != E; ++I) if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) return P; + + break; } } return 0; @@ -137,22 +159,21 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { /// FindPropertyVisibleInPrimaryClass - Finds declaration of the property /// with name 'PropertyId' in the primary class; including those in protocols -/// (direct or indirect) used by the promary class. -/// FIXME: Convert to DeclContext lookup... +/// (direct or indirect) used by the primary class. /// ObjCPropertyDecl * -ObjCContainerDecl::FindPropertyVisibleInPrimaryClass( +ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass( IdentifierInfo *PropertyId) const { - assert(isa<ObjCInterfaceDecl>(this) && "FindPropertyVisibleInPrimaryClass"); - for (prop_iterator I = prop_begin(), E = prop_end(); I != E; ++I) - if ((*I)->getIdentifier() == PropertyId) - return *I; - const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(this); + if (ObjCPropertyDecl *PD = + ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId)) + return PD; + // Look through protocols. - for (ObjCInterfaceDecl::protocol_iterator I = OID->protocol_begin(), - E = OID->protocol_end(); I != E; ++I) + for (ObjCInterfaceDecl::protocol_iterator + I = protocol_begin(), E = protocol_end(); I != E; ++I) if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) return P; + return 0; } @@ -441,7 +462,6 @@ void ObjCInterfaceDecl::Destroy(ASTContext &C) { for (ivar_iterator I = ivar_begin(), E = ivar_end(); I != E; ++I) if (*I) (*I)->Destroy(C); - IVars.Destroy(C); // FIXME: CategoryList? // FIXME: Because there is no clear ownership diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index efd0fd1b8dcb..1b3202dd4282 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -788,6 +788,8 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, switch (getStmtClass()) { default: + if (getType()->isVoidType()) + return false; Loc = getExprLoc(); R1 = getSourceRange(); return true; @@ -834,8 +836,8 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, if (IE->getValue() == 0) return false; - return (BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) || - BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); + return (BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) || + BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); } if (BO->isAssignmentOp()) @@ -936,6 +938,8 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, if (const Expr *E = dyn_cast<Expr>(CS->body_back())) return E->isUnusedResultAWarning(Loc, R1, R2, Ctx); + if (getType()->isVoidType()) + return false; Loc = cast<StmtExpr>(this)->getLParenLoc(); R1 = getSourceRange(); return true; @@ -949,6 +953,8 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, R1 = cast<CStyleCastExpr>(this)->getSubExpr()->getSourceRange(); return true; case CXXFunctionalCastExprClass: { + if (getType()->isVoidType()) + return false; const CastExpr *CE = cast<CastExpr>(this); // If this is a cast to void or a constructor conversion, check the operand. diff --git a/lib/AST/Makefile b/lib/AST/Makefile index 8afc629d6b3b..ede25777c90b 100644 --- a/lib/AST/Makefile +++ b/lib/AST/Makefile @@ -15,7 +15,7 @@ LEVEL = ../../../.. LIBRARYNAME := clangAST BUILD_ARCHIVE = 1 -CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include +CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include include $(LEVEL)/Makefile.common diff --git a/lib/AST/RecordLayout.cpp b/lib/AST/RecordLayout.cpp index 838753a1433f..ade2483722ef 100644 --- a/lib/AST/RecordLayout.cpp +++ b/lib/AST/RecordLayout.cpp @@ -38,17 +38,15 @@ ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx, uint64_t size, unsigned alignm // Constructor for C++ records. ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx, - uint64_t size, unsigned alignment, - uint64_t datasize, - const uint64_t *fieldoffsets, - unsigned fieldcount, - uint64_t nonvirtualsize, - unsigned nonvirtualalign, - const PrimaryBaseInfo &PrimaryBase, - const std::pair<const CXXRecordDecl *, uint64_t> *bases, - unsigned numbases, - const std::pair<const CXXRecordDecl *, uint64_t> *vbases, - unsigned numvbases) + uint64_t size, unsigned alignment, + uint64_t datasize, + const uint64_t *fieldoffsets, + unsigned fieldcount, + uint64_t nonvirtualsize, + unsigned nonvirtualalign, + const PrimaryBaseInfo &PrimaryBase, + const BaseOffsetsMapTy& BaseOffsets, + const BaseOffsetsMapTy& VBaseOffsets) : Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment), FieldCount(fieldcount), CXXInfo(new (Ctx) CXXRecordLayoutInfo) { @@ -60,8 +58,17 @@ ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx, CXXInfo->PrimaryBase = PrimaryBase; CXXInfo->NonVirtualSize = nonvirtualsize; CXXInfo->NonVirtualAlign = nonvirtualalign; - for (unsigned i = 0; i != numbases; ++i) - CXXInfo->BaseOffsets[bases[i].first] = bases[i].second; - for (unsigned i = 0; i != numvbases; ++i) - CXXInfo->VBaseOffsets[vbases[i].first] = vbases[i].second; + CXXInfo->BaseOffsets = BaseOffsets; + CXXInfo->VBaseOffsets = VBaseOffsets; + +#ifndef NDEBUG + if (const CXXRecordDecl *PrimaryBase = getPrimaryBase()) { + if (getPrimaryBaseWasVirtual()) + assert(getVBaseClassOffset(PrimaryBase) == 0 && + "Primary virtual base must be at offset 0!"); + else + assert(getBaseClassOffset(PrimaryBase) == 0 && + "Primary base must be at offset 0!"); + } +#endif } diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 22285ca42032..93edb42bf4c0 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -23,43 +23,8 @@ using namespace clang; ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx) : Ctx(Ctx), Size(0), Alignment(8), Packed(false), UnfilledBitsInLastByte(0), MaxFieldAlignment(0), DataSize(0), IsUnion(false), NonVirtualSize(0), - NonVirtualAlignment(8) { } + NonVirtualAlignment(8), FirstNearlyEmptyVBase(0) { } -/// LayoutVtable - Lay out the vtable and set PrimaryBase. -void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) { - if (!RD->isDynamicClass()) { - // There is no primary base in this case. - return; - } - - SelectPrimaryBase(RD); - if (!PrimaryBase.getBase()) { - int AS = 0; - UpdateAlignment(Ctx.Target.getPointerAlign(AS)); - Size += Ctx.Target.getPointerWidth(AS); - DataSize = Size; - } -} - -void -ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - if (!i->isVirtual()) { - assert(!i->getType()->isDependentType() && - "Cannot layout class with dependent bases."); - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - // Skip the PrimaryBase here, as it is laid down first. - if (Base != PrimaryBase.getBase() || PrimaryBase.isVirtual()) - LayoutBaseNonVirtually(Base, false); - } - } -} - -// Helper routines related to the abi definition from: -// http://www.codesourcery.com/public/cxx-abi/abi.html -// /// IsNearlyEmpty - Indicates when a class has a vtable pointer, but /// no other data. bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const { @@ -97,44 +62,48 @@ void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) { } void -ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD, - const CXXRecordDecl *&FirstPrimary) { - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - assert(!i->getType()->isDependentType() && +ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) { + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + assert(!I->getType()->isDependentType() && "Cannot layout class with dependent bases."); + const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - if (!i->isVirtual()) { - SelectPrimaryVBase(Base, FirstPrimary); - if (PrimaryBase.getBase()) - return; - continue; - } - if (IsNearlyEmpty(Base)) { - if (FirstPrimary==0) - FirstPrimary = Base; + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Check if this is a nearly empty virtual base. + if (I->isVirtual() && IsNearlyEmpty(Base)) { + // If it's not an indirect primary base, then we've found our primary + // base. if (!IndirectPrimaryBases.count(Base)) { - setPrimaryBase(Base, /*IsVirtual=*/true); + PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(Base, + /*IsVirtual=*/true); return; } + + // Is this the first nearly empty virtual base? + if (!FirstNearlyEmptyVBase) + FirstNearlyEmptyVBase = Base; } - assert(i->isVirtual()); - SelectPrimaryVBase(Base, FirstPrimary); + + SelectPrimaryVBase(Base); if (PrimaryBase.getBase()) return; } } -/// SelectPrimaryBase - Selects the primary base for the given class and -/// record that with setPrimaryBase. We also calculate the IndirectPrimaries. -void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) { +/// DeterminePrimaryBase - Determine the primary base of the given class. +void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { + // If the class isn't dynamic, it won't have a primary base. + if (!RD->isDynamicClass()) + return; + // Compute all the primary virtual bases for all of our direct and // indirect bases, and record all their primary virtual base classes. for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { assert(!i->getType()->isDependentType() && - "Cannot layout class with dependent bases."); + "Cannot lay out class with dependent bases."); const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); IdentifyPrimaryBases(Base); @@ -161,90 +130,201 @@ void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) { // Otherwise, it is the first nearly empty virtual base that is not an // indirect primary virtual base class, if one exists. + if (RD->getNumVBases() != 0) { + SelectPrimaryVBase(RD); + if (PrimaryBase.getBase()) + return; + } - // If we have no virtual bases at this point, bail out as the searching below - // is expensive. - if (RD->getNumVBases() == 0) + // Otherwise, it is the first nearly empty virtual base that is not an + // indirect primary virtual base class, if one exists. + if (FirstNearlyEmptyVBase) { + PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(FirstNearlyEmptyVBase, + /*IsVirtual=*/true); return; + } - // Then we can search for the first nearly empty virtual base itself. - const CXXRecordDecl *FirstPrimary = 0; - SelectPrimaryVBase(RD, FirstPrimary); - - // Otherwise if is the first nearly empty virtual base, if one exists, - // otherwise there is no primary base class. - if (!PrimaryBase.getBase()) - setPrimaryBase(FirstPrimary, /*IsVirtual=*/true); -} + // Otherwise there is no primary base class. + assert(!PrimaryBase.getBase() && "Should not get here with a primary base!"); -void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) { - LayoutBaseNonVirtually(RD, true); + // Allocate the virtual table pointer at offset zero. + assert(DataSize == 0 && "Vtable pointer must be at offset zero!"); + + // Update the size. + Size += Ctx.Target.getPointerWidth(0); + DataSize = Size; + + // Update the alignment. + UpdateAlignment(Ctx.Target.getPointerAlign(0)); } -uint64_t ASTRecordLayoutBuilder::getBaseOffset(const CXXRecordDecl *Base) { - for (size_t i = 0; i < Bases.size(); ++i) { - if (Bases[i].first == Base) - return Bases[i].second; +void +ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { + // First, determine the primary base class. + DeterminePrimaryBase(RD); + + // If we have a primary base class, lay it out. + if (const CXXRecordDecl *Base = PrimaryBase.getBase()) { + if (PrimaryBase.isVirtual()) { + // We have a virtual primary base, insert it as an indirect primary base. + IndirectPrimaryBases.insert(Base); + + LayoutVirtualBase(Base); + } else + LayoutNonVirtualBase(Base); } - for (size_t i = 0; i < VBases.size(); ++i) { - if (VBases[i].first == Base) - return VBases[i].second; + + // Now lay out the non-virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + + // Ignore virtual bases. + if (I->isVirtual()) + continue; + + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Skip the primary base. + if (Base == PrimaryBase.getBase() && !PrimaryBase.isVirtual()) + continue; + + // Lay out the base. + LayoutNonVirtualBase(Base); } - assert(0 && "missing base"); - return 0; } +void ASTRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *RD) { + // Layout the base. + uint64_t Offset = LayoutBase(RD); + + // Add its base class offset. + if (!Bases.insert(std::make_pair(RD, Offset)).second) + assert(false && "Added same base offset more than once!"); +} -void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *Class, - const CXXRecordDecl *RD, - const CXXRecordDecl *PB, - uint64_t Offset, - llvm::SmallSet<const CXXRecordDecl*, 32> &mark, - llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary) { - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - assert(!i->getType()->isDependentType() && +void +ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, + uint64_t Offset, + const CXXRecordDecl *MostDerivedClass) { + const CXXRecordDecl *PrimaryBase; + + if (MostDerivedClass == RD) + PrimaryBase = this->PrimaryBase.getBase(); + else { + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); + PrimaryBase = Layout.getPrimaryBase(); + } + + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + assert(!I->getType()->isDependentType() && "Cannot layout class with dependent bases."); + const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - uint64_t BaseOffset = Offset; - if (i->isVirtual()) { - if (Base == PB) { - // Only lay things out once. - if (mark.count(Base)) - continue; - // Mark it so we don't lay it out twice. - mark.insert(Base); - assert (IndirectPrimary.count(Base) && "IndirectPrimary was wrong"); - VBases.push_back(std::make_pair(Base, Offset)); - } else if (IndirectPrimary.count(Base)) { - // Someone else will eventually lay this out. - ; - } else { + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + if (I->isVirtual()) { + bool IndirectPrimaryBase = IndirectPrimaryBases.count(Base); + + // We only want to visit this virtual base if it's either a primary base, + // or not an indirect primary base. + if (Base == PrimaryBase || !IndirectPrimaryBase) { // Only lay things out once. - if (mark.count(Base)) + if (!VisitedVirtualBases.insert(Base)) continue; - // Mark it so we don't lay it out twice. - mark.insert(Base); - LayoutVirtualBase(Base); - BaseOffset = VBases.back().second; - } - } else { - if (RD == Class) - BaseOffset = getBaseOffset(Base); - else { - const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); - BaseOffset = Offset + Layout.getBaseClassOffset(Base); + + if (Base == PrimaryBase) { + assert(IndirectPrimaryBase && + "Base is supposed to be an indirect primary base!"); + + // We only want to add a vbase offset if this primary base is not the + // primary base of the most derived class. + if (PrimaryBase != this->PrimaryBase.getBase() || + !this->PrimaryBase.isVirtual()) { + if (!VBases.insert(std::make_pair(Base, Offset)).second) + assert(false && "Added same vbase offset more than once!"); + } + } else { + // We actually do want to lay out this base. + LayoutVirtualBase(Base); + } } } - if (Base->getNumVBases()) { - const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Base); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBaseInfo().getBase(); - LayoutVirtualBases(Class, Base, PrimaryBase, BaseOffset, mark, - IndirectPrimary); + if (!Base->getNumVBases()) { + // This base isn't interesting since it doesn't have any virtual bases. + continue; + } + + // Compute the offset of this base. + uint64_t BaseOffset; + + if (I->isVirtual()) { + // We want the vbase offset from the class we're currently laying out. + assert(VBases.count(Base) && "Did not find virtual base!"); + BaseOffset = VBases[Base]; + } else if (RD == MostDerivedClass) { + // We want the base offset from the class we're currently laying out. + assert(Bases.count(Base) && "Did not find base!"); + BaseOffset = Bases[Base]; + } else { + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); + BaseOffset = Offset + Layout.getBaseClassOffset(Base); } + + LayoutVirtualBases(Base, BaseOffset, MostDerivedClass); + } +} + +void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) { + // Layout the base. + uint64_t Offset = LayoutBase(RD); + + // Add its base class offset. + if (!VBases.insert(std::make_pair(RD, Offset)).second) + assert(false && "Added same vbase offset more than once!"); +} + +uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) { + const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD); + + // If we have an empty base class, try to place it at offset 0. + if (RD->isEmpty() && canPlaceRecordAtOffset(RD, 0)) { + // We were able to place the class at offset 0. + UpdateEmptyClassOffsets(RD, 0); + + Size = std::max(Size, BaseInfo.getSize()); + + return 0; + } + + unsigned BaseAlign = BaseInfo.getNonVirtualAlign(); + + // Round up the current record size to the base's alignment boundary. + uint64_t Offset = llvm::RoundUpToAlignment(DataSize, BaseAlign); + + // Try to place the base. + while (true) { + if (canPlaceRecordAtOffset(RD, Offset)) + break; + + Offset += BaseAlign; } + + if (!RD->isEmpty()) { + // Update the data size. + DataSize = Offset + BaseInfo.getNonVirtualSize(); + + Size = std::max(Size, DataSize); + } else + Size = std::max(Size, Offset + BaseInfo.getSize()); + + // Remember max struct/class alignment. + UpdateAlignment(BaseAlign); + + UpdateEmptyClassOffsets(RD, Offset); + return Offset; } bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD, @@ -393,59 +473,6 @@ ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD, } } -uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) { - const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD); - - // If we have an empty base class, try to place it at offset 0. - if (RD->isEmpty() && canPlaceRecordAtOffset(RD, 0)) { - // We were able to place the class at offset 0. - UpdateEmptyClassOffsets(RD, 0); - - Size = std::max(Size, BaseInfo.getSize()); - - return 0; - } - - unsigned BaseAlign = BaseInfo.getNonVirtualAlign(); - - // Round up the current record size to the base's alignment boundary. - uint64_t Offset = llvm::RoundUpToAlignment(DataSize, BaseAlign); - - // Try to place the base. - while (true) { - if (canPlaceRecordAtOffset(RD, Offset)) - break; - - Offset += BaseAlign; - } - - if (!RD->isEmpty()) { - // Update the data size. - DataSize = Offset + BaseInfo.getNonVirtualSize(); - - Size = std::max(Size, DataSize); - } else - Size = std::max(Size, Offset + BaseInfo.getSize()); - - // Remember max struct/class alignment. - UpdateAlignment(BaseAlign); - - UpdateEmptyClassOffsets(RD, Offset); - return Offset; -} - -void ASTRecordLayoutBuilder::LayoutBaseNonVirtually(const CXXRecordDecl *RD, - bool IsVirtualBase) { - // Layout the base. - uint64_t Offset = LayoutBase(RD); - - // Add base class offsets. - if (IsVirtualBase) - VBases.push_back(std::make_pair(RD, Offset)); - else - Bases.push_back(std::make_pair(RD, Offset)); -} - void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { IsUnion = D->isUnion(); @@ -460,27 +487,17 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { // If this is a C++ class, lay out the vtable and the non-virtual bases. const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D); - if (RD) { - LayoutVtable(RD); - // PrimaryBase goes first. - if (PrimaryBase.getBase()) { - if (PrimaryBase.isVirtual()) - IndirectPrimaryBases.insert(PrimaryBase.getBase()); - LayoutBaseNonVirtually(PrimaryBase.getBase(), PrimaryBase.isVirtual()); - } + if (RD) LayoutNonVirtualBases(RD); - } LayoutFields(D); NonVirtualSize = Size; NonVirtualAlignment = Alignment; - if (RD) { - llvm::SmallSet<const CXXRecordDecl*, 32> mark; - LayoutVirtualBases(RD, RD, PrimaryBase.getBase(), - 0, mark, IndirectPrimaryBases); - } + // If this is a C++ class, lay out its virtual bases. + if (RD) + LayoutVirtualBases(RD, 0, RD); // Finally, round the size of the total struct up to the alignment of the // struct itself. @@ -697,10 +714,7 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, NonVirtualSize, Builder.NonVirtualAlignment, Builder.PrimaryBase, - Builder.Bases.data(), - Builder.Bases.size(), - Builder.VBases.data(), - Builder.VBases.size()); + Builder.Bases, Builder.VBases); } const ASTRecordLayout * diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h index d4171d3cc9a9..a4bce753126a 100644 --- a/lib/AST/RecordLayoutBuilder.h +++ b/lib/AST/RecordLayoutBuilder.h @@ -56,21 +56,28 @@ class ASTRecordLayoutBuilder { uint64_t NonVirtualSize; unsigned NonVirtualAlignment; + /// PrimaryBase - the primary base class (if one exists) of the class + /// we're laying out. ASTRecordLayout::PrimaryBaseInfo PrimaryBase; - typedef llvm::SmallVector<std::pair<const CXXRecordDecl *, - uint64_t>, 4> BaseOffsetsTy; + /// Bases - base classes and their offsets in the record. + ASTRecordLayout::BaseOffsetsMapTy Bases; - /// Bases - base classes and their offsets from the record. - BaseOffsetsTy Bases; - - // VBases - virtual base classes and their offsets from the record. - BaseOffsetsTy VBases; + // VBases - virtual base classes and their offsets in the record. + ASTRecordLayout::BaseOffsetsMapTy VBases; /// IndirectPrimaryBases - Virtual base classes, direct or indirect, that are /// primary base classes for some other direct or indirect base class. llvm::SmallSet<const CXXRecordDecl*, 32> IndirectPrimaryBases; + /// FirstNearlyEmptyVBase - The first nearly empty virtual base class in + /// inheritance graph order. Used for determining the primary base class. + const CXXRecordDecl *FirstNearlyEmptyVBase; + + /// VisitedVirtualBases - A set of all the visited virtual bases, used to + /// avoid visiting virtual bases more than once. + llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases; + /// EmptyClassOffsets - A map from offsets to empty record decls. typedef std::multimap<uint64_t, const CXXRecordDecl *> EmptyClassOffsetsTy; EmptyClassOffsetsTy EmptyClassOffsets; @@ -86,33 +93,35 @@ class ASTRecordLayoutBuilder { void LayoutField(const FieldDecl *D); void LayoutBitField(const FieldDecl *D); - void SelectPrimaryBase(const CXXRecordDecl *RD); - void SelectPrimaryVBase(const CXXRecordDecl *RD, - const CXXRecordDecl *&FirstPrimary); + /// DeterminePrimaryBase - Determine the primary base of the given class. + void DeterminePrimaryBase(const CXXRecordDecl *RD); + + void SelectPrimaryVBase(const CXXRecordDecl *RD); /// IdentifyPrimaryBases - Identify all virtual base classes, direct or /// indirect, that are primary base classes for some other direct or indirect /// base class. void IdentifyPrimaryBases(const CXXRecordDecl *RD); - void setPrimaryBase(const CXXRecordDecl *Base, bool IsVirtual) { - PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(Base, IsVirtual); - } - bool IsNearlyEmpty(const CXXRecordDecl *RD) const; + /// LayoutNonVirtualBases - Determines the primary base class (if any) and + /// lays it out. Will then proceed to lay out all non-virtual base clasess. + void LayoutNonVirtualBases(const CXXRecordDecl *RD); + + /// LayoutNonVirtualBase - Lays out a single non-virtual base. + void LayoutNonVirtualBase(const CXXRecordDecl *RD); + + /// LayoutVirtualBases - Lays out all the virtual bases. + void LayoutVirtualBases(const CXXRecordDecl *RD, uint64_t Offset, + const CXXRecordDecl *MostDerivedClass); + + /// LayoutVirtualBase - Lays out a single virtual base. + void LayoutVirtualBase(const CXXRecordDecl *RD); + /// LayoutBase - Will lay out a base and return the offset where it was /// placed, in bits. uint64_t LayoutBase(const CXXRecordDecl *RD); - - void LayoutVtable(const CXXRecordDecl *RD); - void LayoutNonVirtualBases(const CXXRecordDecl *RD); - void LayoutBaseNonVirtually(const CXXRecordDecl *RD, bool IsVBase); - void LayoutVirtualBase(const CXXRecordDecl *RD); - void LayoutVirtualBases(const CXXRecordDecl *Class, const CXXRecordDecl *RD, - const CXXRecordDecl *PB, uint64_t Offset, - llvm::SmallSet<const CXXRecordDecl*, 32> &mark, - llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary); /// canPlaceRecordAtOffset - Return whether a record (either a base class /// or a field) can be placed at the given offset. @@ -134,9 +143,6 @@ class ASTRecordLayoutBuilder { /// given offset. void UpdateEmptyClassOffsets(const FieldDecl *FD, uint64_t Offset); - /// getBaseOffset - Get the offset of a direct base class. - uint64_t getBaseOffset(const CXXRecordDecl *Base); - /// FinishLayout - Finalize record layout. Adjust record size based on the /// alignment. void FinishLayout(); diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 037bc14e7a91..09a61736d27e 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -474,7 +474,12 @@ void TypePrinter::PrintEnum(const EnumType *T, std::string &S) { void TypePrinter::PrintElaborated(const ElaboratedType *T, std::string &S) { Print(T->getUnderlyingType(), S); - S = std::string(T->getNameForTagKind(T->getTagKind())) + ' ' + S; + + // We don't actually make these in C, but the language options + // sometimes lie to us -- for example, if someone calls + // QualType::getAsString(). Just suppress the redundant tag if so. + if (Policy.LangOpts.CPlusPlus) + S = std::string(T->getNameForTagKind(T->getTagKind())) + ' ' + S; } void TypePrinter::PrintTemplateTypeParm(const TemplateTypeParmType *T, diff --git a/lib/Analysis/Makefile b/lib/Analysis/Makefile index d6411122e322..9b473803fa92 100644 --- a/lib/Analysis/Makefile +++ b/lib/Analysis/Makefile @@ -15,7 +15,7 @@ LEVEL = ../../../.. LIBRARYNAME := clangAnalysis BUILD_ARCHIVE = 1 -CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include +CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include include $(LEVEL)/Makefile.common diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 16a61b7156fa..3da19ca16d5d 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -16,6 +16,7 @@ #include "clang/Basic/LangOptions.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/raw_ostream.h" #include <cstdio> @@ -81,7 +82,7 @@ namespace { /// enabled in the specified langauge, set to 1 if it is an extension /// in the specified language, and set to 2 if disabled in the /// specified language. -static void AddKeyword(const char *Keyword, unsigned KWLen, +static void AddKeyword(llvm::StringRef Keyword, tok::TokenKind TokenCode, unsigned Flags, const LangOptions &LangOpts, IdentifierTable &Table) { unsigned AddResult = 0; @@ -97,27 +98,27 @@ static void AddKeyword(const char *Keyword, unsigned KWLen, // Don't add this keyword if disabled in this language. if (AddResult == 0) return; - IdentifierInfo &Info = Table.get(Keyword, Keyword+KWLen); + IdentifierInfo &Info = Table.get(Keyword); Info.setTokenID(TokenCode); Info.setIsExtensionToken(AddResult == 1); } /// AddCXXOperatorKeyword - Register a C++ operator keyword alternative /// representations. -static void AddCXXOperatorKeyword(const char *Keyword, unsigned KWLen, +static void AddCXXOperatorKeyword(llvm::StringRef Keyword, tok::TokenKind TokenCode, IdentifierTable &Table) { - IdentifierInfo &Info = Table.get(Keyword, Keyword + KWLen); + IdentifierInfo &Info = Table.get(Keyword); Info.setTokenID(TokenCode); Info.setIsCPlusPlusOperatorKeyword(); } /// AddObjCKeyword - Register an Objective-C @keyword like "class" "selector" or /// "property". -static void AddObjCKeyword(tok::ObjCKeywordKind ObjCID, - const char *Name, unsigned NameLen, +static void AddObjCKeyword(llvm::StringRef Name, + tok::ObjCKeywordKind ObjCID, IdentifierTable &Table) { - Table.get(Name, Name+NameLen).setObjCKeywordID(ObjCID); + Table.get(Name).setObjCKeywordID(ObjCID); } /// AddKeywords - Add all keywords to the symbol table. @@ -125,20 +126,20 @@ static void AddObjCKeyword(tok::ObjCKeywordKind ObjCID, void IdentifierTable::AddKeywords(const LangOptions &LangOpts) { // Add keywords and tokens for the current language. #define KEYWORD(NAME, FLAGS) \ - AddKeyword(#NAME, strlen(#NAME), tok::kw_ ## NAME, \ + AddKeyword(llvm::StringRef(#NAME), tok::kw_ ## NAME, \ FLAGS, LangOpts, *this); #define ALIAS(NAME, TOK, FLAGS) \ - AddKeyword(NAME, strlen(NAME), tok::kw_ ## TOK, \ + AddKeyword(llvm::StringRef(NAME), tok::kw_ ## TOK, \ FLAGS, LangOpts, *this); #define CXX_KEYWORD_OPERATOR(NAME, ALIAS) \ if (LangOpts.CXXOperatorNames) \ - AddCXXOperatorKeyword(#NAME, strlen(#NAME), tok::ALIAS, *this); + AddCXXOperatorKeyword(llvm::StringRef(#NAME), tok::ALIAS, *this); #define OBJC1_AT_KEYWORD(NAME) \ if (LangOpts.ObjC1) \ - AddObjCKeyword(tok::objc_##NAME, #NAME, strlen(#NAME), *this); + AddObjCKeyword(llvm::StringRef(#NAME), tok::objc_##NAME, *this); #define OBJC2_AT_KEYWORD(NAME) \ if (LangOpts.ObjC2) \ - AddObjCKeyword(tok::objc_##NAME, #NAME, strlen(#NAME), *this); + AddObjCKeyword(llvm::StringRef(#NAME), tok::objc_##NAME, *this); #include "clang/Basic/TokenKinds.def" } @@ -388,12 +389,12 @@ const char *clang::getOperatorSpelling(OverloadedOperatorKind Operator) { case OO_None: case NUM_OVERLOADED_OPERATORS: return 0; - + #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ case OO_##Name: return Spelling; #include "clang/Basic/OperatorKinds.def" } - + return 0; } diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp index 578a4eb34bab..126d640364d0 100644 --- a/lib/Basic/SourceLocation.cpp +++ b/lib/Basic/SourceLocation.cpp @@ -115,9 +115,8 @@ const llvm::MemoryBuffer* FullSourceLoc::getBuffer() const { return SrcMgr->getBuffer(SrcMgr->getFileID(*this)); } -std::pair<const char*, const char*> FullSourceLoc::getBufferData() const { - const llvm::MemoryBuffer *Buf = getBuffer(); - return std::make_pair(Buf->getBufferStart(), Buf->getBufferEnd()); +llvm::StringRef FullSourceLoc::getBufferData() const { + return getBuffer()->getBuffer(); } std::pair<FileID, unsigned> FullSourceLoc::getDecomposedLoc() const { diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index 0c22de7bddb1..4007ccf2a61e 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -13,12 +13,16 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/SourceManagerInternals.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" #include <algorithm> +#include <string> +#include <cstring> + using namespace clang; using namespace SrcMgr; using llvm::MemoryBuffer; @@ -43,7 +47,8 @@ unsigned ContentCache::getSizeBytesMapped() const { /// scratch buffer. If the ContentCache encapsulates a source file, that /// file is not lazily brought in from disk to satisfy this query. unsigned ContentCache::getSize() const { - return Buffer ? Buffer->getBufferSize() : Entry->getSize(); + return Buffer ? (unsigned) Buffer->getBufferSize() + : (unsigned) Entry->getSize(); } void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) { @@ -53,10 +58,17 @@ void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) { Buffer = B; } -const llvm::MemoryBuffer *ContentCache::getBuffer(std::string *ErrorStr) const { +const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, + bool *Invalid) const { + if (Invalid) + *Invalid = false; + // Lazily create the Buffer for ContentCaches that wrap files. if (!Buffer && Entry) { - Buffer = MemoryBuffer::getFile(Entry->getName(), ErrorStr,Entry->getSize()); + std::string ErrorStr; + struct stat FileInfo; + Buffer = MemoryBuffer::getFile(Entry->getName(), &ErrorStr, + Entry->getSize(), &FileInfo); // If we were unable to open the file, then we are in an inconsistent // situation where the content cache referenced a file which no longer @@ -74,8 +86,27 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(std::string *ErrorStr) const { char *Ptr = const_cast<char*>(Buffer->getBufferStart()); for (unsigned i = 0, e = Entry->getSize(); i != e; ++i) Ptr[i] = FillStr[i % FillStr.size()]; + Diag.Report(diag::err_cannot_open_file) + << Entry->getName() << ErrorStr; + if (Invalid) + *Invalid = true; + } else { + // Check that the file's size and modification time is the same as + // in the file entry (which may have come from a stat cache). + if (FileInfo.st_size != Entry->getSize()) { + Diag.Report(diag::err_file_size_changed) + << Entry->getName() << (unsigned)Entry->getSize() + << (unsigned)FileInfo.st_size; + if (Invalid) + *Invalid = true; + } else if (FileInfo.st_mtime != Entry->getModificationTime()) { + Diag.Report(diag::err_file_modified) << Entry->getName(); + if (Invalid) + *Invalid = true; + } } } + return Buffer; } @@ -426,12 +457,11 @@ SourceLocation SourceManager::createInstantiationLoc(SourceLocation SpellingLoc, } const llvm::MemoryBuffer * -SourceManager::getMemoryBufferForFile(const FileEntry *File) { +SourceManager::getMemoryBufferForFile(const FileEntry *File, + bool *Invalid) { const SrcMgr::ContentCache *IR = getOrCreateContentCache(File); - if (IR == 0) - return 0; - - return IR->getBuffer(); + assert(IR && "getOrCreateContentCache() cannot return NULL"); + return IR->getBuffer(Diag, Invalid); } bool SourceManager::overrideFileContents(const FileEntry *SourceFile, @@ -444,15 +474,19 @@ bool SourceManager::overrideFileContents(const FileEntry *SourceFile, return false; } -/// getBufferData - Return a pointer to the start and end of the source buffer -/// data for the specified FileID. -std::pair<const char*, const char*> -SourceManager::getBufferData(FileID FID) const { +llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const { + if (Invalid) + *Invalid = false; + const llvm::MemoryBuffer *Buf = getBuffer(FID); - return std::make_pair(Buf->getBufferStart(), Buf->getBufferEnd()); + if (!Buf) { + if (*Invalid) + *Invalid = true; + return ""; + } + return Buf->getBuffer(); } - //===----------------------------------------------------------------------===// // SourceLocation manipulation methods. //===----------------------------------------------------------------------===// @@ -666,21 +700,34 @@ SourceManager::getInstantiationRange(SourceLocation Loc) const { /// getCharacterData - Return a pointer to the start of the specified location /// in the appropriate MemoryBuffer. -const char *SourceManager::getCharacterData(SourceLocation SL) const { +const char *SourceManager::getCharacterData(SourceLocation SL, + bool *Invalid) const { // Note that this is a hot function in the getSpelling() path, which is // heavily used by -E mode. std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(SL); // Note that calling 'getBuffer()' may lazily page in a source file. - return getSLocEntry(LocInfo.first).getFile().getContentCache() - ->getBuffer()->getBufferStart() + LocInfo.second; + bool CharDataInvalid = false; + const llvm::MemoryBuffer *Buffer + = getSLocEntry(LocInfo.first).getFile().getContentCache()->getBuffer(Diag, + &CharDataInvalid); + if (Invalid) + *Invalid = CharDataInvalid; + return Buffer->getBufferStart() + (CharDataInvalid? 0 : LocInfo.second); } /// getColumnNumber - Return the column # for the specified file position. /// this is significantly cheaper to compute than the line number. -unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos) const { - const char *Buf = getBuffer(FID)->getBufferStart(); +unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos, + bool *Invalid) const { + bool MyInvalid = false; + const char *Buf = getBuffer(FID, &MyInvalid)->getBufferStart(); + if (Invalid) + *Invalid = MyInvalid; + + if (MyInvalid) + return 1; unsigned LineStart = FilePos; while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r') @@ -688,25 +735,30 @@ unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos) const { return FilePos-LineStart+1; } -unsigned SourceManager::getSpellingColumnNumber(SourceLocation Loc) const { +unsigned SourceManager::getSpellingColumnNumber(SourceLocation Loc, + bool *Invalid) const { if (Loc.isInvalid()) return 0; std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc); - return getColumnNumber(LocInfo.first, LocInfo.second); + return getColumnNumber(LocInfo.first, LocInfo.second, Invalid); } -unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc) const { +unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc, + bool *Invalid) const { if (Loc.isInvalid()) return 0; std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); - return getColumnNumber(LocInfo.first, LocInfo.second); + return getColumnNumber(LocInfo.first, LocInfo.second, Invalid); } - - -static DISABLE_INLINE void ComputeLineNumbers(ContentCache* FI, - llvm::BumpPtrAllocator &Alloc); -static void ComputeLineNumbers(ContentCache* FI, llvm::BumpPtrAllocator &Alloc){ +static DISABLE_INLINE void ComputeLineNumbers(Diagnostic &Diag, + ContentCache* FI, + llvm::BumpPtrAllocator &Alloc, + bool &Invalid); +static void ComputeLineNumbers(Diagnostic &Diag, ContentCache* FI, + llvm::BumpPtrAllocator &Alloc, bool &Invalid) { // Note that calling 'getBuffer()' may lazily page in the file. - const MemoryBuffer *Buffer = FI->getBuffer(); + const MemoryBuffer *Buffer = FI->getBuffer(Diag, &Invalid); + if (Invalid) + return; // Find the file offsets of all of the *physical* source lines. This does // not look at trigraphs, escaped newlines, or anything else tricky. @@ -752,7 +804,8 @@ static void ComputeLineNumbers(ContentCache* FI, llvm::BumpPtrAllocator &Alloc){ /// for the position indicated. This requires building and caching a table of /// line offsets for the MemoryBuffer, so this is not cheap: use only when /// about to emit a diagnostic. -unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos) const { +unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos, + bool *Invalid) const { ContentCache *Content; if (LastLineNoFileIDQuery == FID) Content = LastLineNoContentCache; @@ -762,8 +815,15 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos) const { // If this is the first use of line information for this buffer, compute the /// SourceLineCache for it on demand. - if (Content->SourceLineCache == 0) - ComputeLineNumbers(Content, ContentCacheAlloc); + if (Content->SourceLineCache == 0) { + bool MyInvalid = false; + ComputeLineNumbers(Diag, Content, ContentCacheAlloc, MyInvalid); + if (Invalid) + *Invalid = MyInvalid; + if (MyInvalid) + return 1; + } else if (Invalid) + *Invalid = false; // Okay, we know we have a line number table. Do a binary search to find the // line number that this character position lands on. @@ -849,12 +909,14 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos) const { return LineNo; } -unsigned SourceManager::getInstantiationLineNumber(SourceLocation Loc) const { +unsigned SourceManager::getInstantiationLineNumber(SourceLocation Loc, + bool *Invalid) const { if (Loc.isInvalid()) return 0; std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); return getLineNumber(LocInfo.first, LocInfo.second); } -unsigned SourceManager::getSpellingLineNumber(SourceLocation Loc) const { +unsigned SourceManager::getSpellingLineNumber(SourceLocation Loc, + bool *Invalid) const { if (Loc.isInvalid()) return 0; std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc); return getLineNumber(LocInfo.first, LocInfo.second); @@ -894,10 +956,11 @@ SourceManager::getFileCharacteristic(SourceLocation Loc) const { /// Return the filename or buffer identifier of the buffer the location is in. /// Note that this name does not respect #line directives. Use getPresumedLoc /// for normal clients. -const char *SourceManager::getBufferName(SourceLocation Loc) const { +const char *SourceManager::getBufferName(SourceLocation Loc, + bool *Invalid) const { if (Loc.isInvalid()) return "<invalid loc>"; - return getBuffer(getFileID(Loc))->getBufferIdentifier(); + return getBuffer(getFileID(Loc), Invalid)->getBufferIdentifier(); } @@ -921,7 +984,7 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const { // before the MemBuffer as this will avoid unnecessarily paging in the // MemBuffer. const char *Filename = - C->Entry ? C->Entry->getName() : C->getBuffer()->getBufferIdentifier(); + C->Entry ? C->Entry->getName() : C->getBuffer(Diag)->getBufferIdentifier(); unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second); unsigned ColNo = getColumnNumber(LocInfo.first, LocInfo.second); SourceLocation IncludeLoc = FI.getIncludeLoc(); @@ -977,8 +1040,12 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, // If this is the first use of line information for this buffer, compute the /// SourceLineCache for it on demand. - if (Content->SourceLineCache == 0) - ComputeLineNumbers(Content, ContentCacheAlloc); + if (Content->SourceLineCache == 0) { + bool MyInvalid = false; + ComputeLineNumbers(Diag, Content, ContentCacheAlloc, MyInvalid); + if (MyInvalid) + return SourceLocation(); + } // Find the first file ID that corresponds to the given file. FileID FirstFID; @@ -1007,15 +1074,15 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, return SourceLocation(); if (Line > Content->NumLines) { - unsigned Size = Content->getBuffer()->getBufferSize(); + unsigned Size = Content->getBuffer(Diag)->getBufferSize(); if (Size > 0) --Size; return getLocForStartOfFile(FirstFID).getFileLocWithOffset(Size); } unsigned FilePos = Content->SourceLineCache[Line - 1]; - const char *Buf = Content->getBuffer()->getBufferStart() + FilePos; - unsigned BufLength = Content->getBuffer()->getBufferEnd() - Buf; + const char *Buf = Content->getBuffer(Diag)->getBufferStart() + FilePos; + unsigned BufLength = Content->getBuffer(Diag)->getBufferEnd() - Buf; unsigned i = 0; // Check that the given column is valid. diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 3b226d0cdc52..8f472b3d3d45 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -935,6 +935,7 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) { .Case("sse42", SSE42) .Case("sse41", SSE41) .Case("ssse3", SSSE3) + .Case("sse3", SSE3) .Case("sse2", SSE2) .Case("sse", SSE1) .Case("mmx", MMX) diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp index 130d805bb8aa..e64ba9446d89 100644 --- a/lib/Checker/GRExprEngine.cpp +++ b/lib/Checker/GRExprEngine.cpp @@ -19,6 +19,7 @@ #include "clang/AST/CharUnits.h" #include "clang/AST/ParentMap.h" #include "clang/AST/StmtObjC.h" +#include "clang/AST/DeclCXX.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/SourceManager.h" @@ -2335,7 +2336,11 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, ExplodedNodeSet Tmp; if (InitEx) { - if (VD->getType()->isReferenceType()) + if (const CXXConstructExpr *E = dyn_cast<CXXConstructExpr>(InitEx)) { + VisitCXXConstructExpr(E, GetState(Pred)->getLValue(VD, + Pred->getLocationContext()), Pred, Dst); + return; + } else if (VD->getType()->isReferenceType()) VisitLValue(InitEx, Pred, Tmp); else Visit(InitEx, Pred, Tmp); @@ -2826,7 +2831,8 @@ void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred, ExplodedNodeSet & Dst) { // Get the this object region from StoreManager. const MemRegion *R = - ValMgr.getRegionManager().getCXXThisRegion(TE->getType(), + ValMgr.getRegionManager().getCXXThisRegion( + getContext().getCanonicalType(TE->getType()), Pred->getLocationContext()); const GRState *state = GetState(Pred); @@ -3126,6 +3132,78 @@ void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred, } } +void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + + const CXXConstructorDecl *CD = E->getConstructor(); + assert(CD); + + if (!CD->isThisDeclarationADefinition()) + // FIXME: invalidate the object. + return; + + + // Evaluate other arguments. + CXXConstructExpr::arg_iterator AB + = const_cast<CXXConstructExpr*>(E)->arg_begin(); + CXXConstructExpr::arg_iterator AE + = const_cast<CXXConstructExpr*>(E)->arg_end(); + llvm::SmallVector<CallExprWLItem, 20> WorkList; + WorkList.reserve(AE - AB); + WorkList.push_back(CallExprWLItem(AB, Pred)); + ExplodedNodeSet ArgsEvaluated; + const FunctionProtoType *Proto = CD->getType()->getAs<FunctionProtoType>(); + + while (!WorkList.empty()) { + CallExprWLItem Item = WorkList.back(); + WorkList.pop_back(); + + if (Item.I == AE) { + ArgsEvaluated.insert(Item.N); + continue; + } + + // Evaluate the argument. + ExplodedNodeSet Tmp; + const unsigned ParamIdx = Item.I - AB; + + bool VisitAsLvalue = false; + + if (ParamIdx < Proto->getNumArgs()) + VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType(); + + if (VisitAsLvalue) + VisitLValue(*Item.I, Item.N, Tmp); + else + Visit(*Item.I, Item.N, Tmp); + + ++(Item.I); + + for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) + WorkList.push_back(CallExprWLItem(Item.I, *NI)); + } + // The callee stack frame context used to create the 'this' parameter region. + const StackFrameContext *SFC = AMgr.getStackFrame(CD, + Pred->getLocationContext(), + E, Builder->getBlock(), Builder->getIndex()); + + Type *T = CD->getParent()->getTypeForDecl(); + QualType PT = getContext().getPointerType(QualType(T,0)); + const CXXThisRegion *ThisR = ValMgr.getRegionManager().getCXXThisRegion(PT, + SFC); + + CallEnter Loc(E, CD, Pred->getLocationContext()); + for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(), + NE = ArgsEvaluated.end(); NI != NE; ++NI) { + const GRState *state = GetState(*NI); + // Setup 'this' region. + state = state->bindLoc(loc::MemRegionVal(ThisR), Dest); + ExplodedNode *N = Builder->generateNode(Loc, state, Pred); + if (N) + Dst.Add(N); + } +} //===----------------------------------------------------------------------===// // Checker registration/lookup. //===----------------------------------------------------------------------===// diff --git a/lib/Checker/Makefile b/lib/Checker/Makefile index 673d152270ca..c45ab294dec4 100644 --- a/lib/Checker/Makefile +++ b/lib/Checker/Makefile @@ -15,7 +15,7 @@ LEVEL = ../../../.. LIBRARYNAME := clangChecker BUILD_ARCHIVE = 1 -CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include +CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include include $(LEVEL)/Makefile.common diff --git a/lib/Checker/RegionStore.cpp b/lib/Checker/RegionStore.cpp index 91c3a15f4473..307ef7880388 100644 --- a/lib/Checker/RegionStore.cpp +++ b/lib/Checker/RegionStore.cpp @@ -22,6 +22,8 @@ #include "clang/Analysis/Support/Optional.h" #include "clang/Basic/TargetInfo.h" #include "clang/AST/CharUnits.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/ExprCXX.h" #include "llvm/ADT/ImmutableMap.h" #include "llvm/ADT/ImmutableList.h" @@ -29,8 +31,6 @@ using namespace clang; -#define USE_EXPLICIT_COMPOUND 0 - //===----------------------------------------------------------------------===// // Representation of binding keys. //===----------------------------------------------------------------------===// @@ -1336,54 +1336,13 @@ SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) { SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) { QualType T = R->getValueType(getContext()); assert(T->isStructureType()); - - const RecordType* RT = T->getAsStructureType(); - RecordDecl* RD = RT->getDecl(); - assert(RD->isDefinition()); - (void)RD; -#if USE_EXPLICIT_COMPOUND - llvm::ImmutableList<SVal> StructVal = getBasicVals().getEmptySValList(); - - // FIXME: We shouldn't use a std::vector. If RecordDecl doesn't have a - // reverse iterator, we should implement one. - std::vector<FieldDecl *> Fields(RD->field_begin(), RD->field_end()); - - for (std::vector<FieldDecl *>::reverse_iterator Field = Fields.rbegin(), - FieldEnd = Fields.rend(); - Field != FieldEnd; ++Field) { - FieldRegion* FR = MRMgr.getFieldRegion(*Field, R); - QualType FTy = (*Field)->getType(); - SVal FieldValue = Retrieve(store, loc::MemRegionVal(FR), FTy).getSVal(); - StructVal = getBasicVals().consVals(FieldValue, StructVal); - } - - return ValMgr.makeCompoundVal(T, StructVal); -#else + assert(T->getAsStructureType()->getDecl()->isDefinition()); return ValMgr.makeLazyCompoundVal(store, R); -#endif } SVal RegionStoreManager::RetrieveArray(Store store, const TypedRegion * R) { -#if USE_EXPLICIT_COMPOUND - QualType T = R->getValueType(getContext()); - ConstantArrayType* CAT = cast<ConstantArrayType>(T.getTypePtr()); - - llvm::ImmutableList<SVal> ArrayVal = getBasicVals().getEmptySValList(); - uint64_t size = CAT->getSize().getZExtValue(); - for (uint64_t i = 0; i < size; ++i) { - SVal Idx = ValMgr.makeArrayIndex(i); - ElementRegion* ER = MRMgr.getElementRegion(CAT->getElementType(), Idx, R, - getContext()); - QualType ETy = ER->getElementType(); - SVal ElementVal = Retrieve(store, loc::MemRegionVal(ER), ETy).getSVal(); - ArrayVal = getBasicVals().consVals(ElementVal, ArrayVal); - } - - return ValMgr.makeCompoundVal(T, ArrayVal); -#else assert(isa<ConstantArrayType>(R->getValueType(getContext()))); return ValMgr.makeLazyCompoundVal(store, R); -#endif } //===----------------------------------------------------------------------===// @@ -1884,18 +1843,29 @@ Store RegionStoreManager::RemoveDeadBindings(Store store, Stmt* Loc, GRState const *RegionStoreManager::EnterStackFrame(GRState const *state, StackFrameContext const *frame) { FunctionDecl const *FD = cast<FunctionDecl>(frame->getDecl()); - CallExpr const *CE = cast<CallExpr>(frame->getCallSite()); - FunctionDecl::param_const_iterator PI = FD->param_begin(); + Store store = state->getStore(); - CallExpr::const_arg_iterator AI = CE->arg_begin(), AE = CE->arg_end(); + if (CallExpr const *CE = dyn_cast<CallExpr>(frame->getCallSite())) { + CallExpr::const_arg_iterator AI = CE->arg_begin(), AE = CE->arg_end(); - // Copy the arg expression value to the arg variables. - Store store = state->getStore(); - for (; AI != AE; ++AI, ++PI) { - SVal ArgVal = state->getSVal(*AI); - store = Bind(store, ValMgr.makeLoc(MRMgr.getVarRegion(*PI, frame)), ArgVal); - } + // Copy the arg expression value to the arg variables. + for (; AI != AE; ++AI, ++PI) { + SVal ArgVal = state->getSVal(*AI); + store = Bind(store, ValMgr.makeLoc(MRMgr.getVarRegion(*PI,frame)),ArgVal); + } + } else if (const CXXConstructExpr *CE = + dyn_cast<CXXConstructExpr>(frame->getCallSite())) { + CXXConstructExpr::const_arg_iterator AI = CE->arg_begin(), + AE = CE->arg_end(); + + // Copy the arg expression value to the arg variables. + for (; AI != AE; ++AI, ++PI) { + SVal ArgVal = state->getSVal(*AI); + store = Bind(store, ValMgr.makeLoc(MRMgr.getVarRegion(*PI,frame)),ArgVal); + } + } else + assert(0 && "Unhandled call expression."); return state->makeWithStore(store); } diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 99c6dfd7ebc4..525e85841646 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -98,7 +98,7 @@ CodeGenModule::ComputeThunkAdjustment(const CXXRecordDecl *ClassDecl, } if (VBase) VirtualOffset = - getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl); + getVtableInfo().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl); uint64_t Offset = ComputeNonVirtualBaseClassOffset(getContext(), Paths.front(), Start); @@ -1540,11 +1540,11 @@ CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This, Int8PtrTy->getPointerTo()); VTablePtr = Builder.CreateLoad(VTablePtr, "vtable"); - int64_t VBaseOffsetIndex = - CGM.getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl); + int64_t VBaseOffsetOffset = + CGM.getVtableInfo().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl); llvm::Value *VBaseOffsetPtr = - Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetIndex, "vbase.offset.ptr"); + Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetOffset, "vbase.offset.ptr"); const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType()); diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index c3302e661dfb..60aa4e784e6c 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -104,7 +104,10 @@ llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) { void CGDebugInfo::CreateCompileUnit() { // Get absolute path name. - llvm::sys::Path AbsFileName(CGM.getCodeGenOpts().MainFileName); + std::string MainFileName = CGM.getCodeGenOpts().MainFileName; + if (MainFileName.empty()) + MainFileName = "<unknown>"; + llvm::sys::Path AbsFileName(MainFileName); AbsFileName.makeAbsolute(); unsigned LangTag; @@ -649,9 +652,9 @@ CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit, cast<CXXRecordDecl>(BI->getType()->getAs<RecordType>()->getDecl()); if (BI->isVirtual()) { - // virtual base offset index is -ve. The code generator emits dwarf + // virtual base offset offset is -ve. The code generator emits dwarf // expression where it expects +ve number. - BaseOffset = 0 - CGM.getVtableInfo().getVirtualBaseOffsetIndex(RD, Base); + BaseOffset = 0 - CGM.getVtableInfo().getVirtualBaseOffsetOffset(RD, Base); BFlags = llvm::DIType::FlagVirtual; } else BaseOffset = RL.getBaseClassOffset(Base); @@ -774,9 +777,8 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, // A RD->getName() is not unique. However, the debug info descriptors // are uniqued so use type name to ensure uniquness. - llvm::SmallString<256> FwdDeclName; - FwdDeclName.resize(256); - sprintf(&FwdDeclName[0], "fwd.type.%d", FwdDeclCount++); + llvm::SmallString<128> FwdDeclName; + llvm::raw_svector_ostream(FwdDeclName) << "fwd.type." << FwdDeclCount++; llvm::DIDescriptor FDContext = getContextDescriptor(dyn_cast<Decl>(RD->getDeclContext()), Unit); llvm::DICompositeType FwdDecl = @@ -792,6 +794,9 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, // Otherwise, insert it into the TypeCache so that recursive uses will find // it. TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl.getNode(); + // Push the struct on region stack. + RegionStack.push_back(FwdDecl.getNode()); + RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl.getNode()); // Convert all the elements. llvm::SmallVector<llvm::DIDescriptor, 16> EltTys; @@ -822,6 +827,12 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, uint64_t Size = CGM.getContext().getTypeSize(Ty); uint64_t Align = CGM.getContext().getTypeAlign(Ty); + RegionStack.pop_back(); + llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator RI = + RegionMap.find(Ty->getDecl()); + if (RI != RegionMap.end()) + RegionMap.erase(RI); + llvm::DIDescriptor RDContext = getContextDescriptor(dyn_cast<Decl>(RD->getDeclContext()), Unit); llvm::DICompositeType RealDecl = @@ -834,7 +845,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, // Now that we have a real decl for the struct, replace anything using the // old decl with the new one. This will recursively update the debug info. llvm::DIDerivedType(FwdDeclNode).replaceAllUsesWith(RealDecl); - + RegionMap[RD] = llvm::WeakVH(RealDecl.getNode()); return RealDecl; } @@ -874,6 +885,9 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, // Otherwise, insert it into the TypeCache so that recursive uses will find // it. TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl.getNode(); + // Push the struct on region stack. + RegionStack.push_back(FwdDecl.getNode()); + RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl.getNode()); // Convert all the elements. llvm::SmallVector<llvm::DIDescriptor, 16> EltTys; @@ -946,6 +960,12 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, llvm::DIArray Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); + RegionStack.pop_back(); + llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator RI = + RegionMap.find(Ty->getDecl()); + if (RI != RegionMap.end()) + RegionMap.erase(RI); + // Bit size, align and offset of the type. uint64_t Size = CGM.getContext().getTypeSize(Ty); uint64_t Align = CGM.getContext().getTypeAlign(Ty); @@ -958,6 +978,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, // Now that we have a real decl for the struct, replace anything using the // old decl with the new one. This will recursively update the debug info. llvm::DIDerivedType(FwdDeclNode).replaceAllUsesWith(RealDecl); + RegionMap[ID] = llvm::WeakVH(RealDecl.getNode()); return RealDecl; } diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 793a22050677..1dc083f387ba 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -211,6 +211,8 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D, if (D.getInit()) GV = AddInitializerToGlobalBlockVarDecl(D, GV); + GV->setAlignment(getContext().getDeclAlign(&D).getQuantity()); + // FIXME: Merge attribute handling. if (const AnnotateAttr *AA = D.getAttr<AnnotateAttr>()) { SourceManager &SM = CGM.getContext().getSourceManager(); @@ -471,68 +473,6 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { EnsureInsertPoint(); } - if (Init) { - llvm::Value *Loc = DeclPtr; - if (isByRef) - Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D), - D.getNameAsString()); - - bool isVolatile = - getContext().getCanonicalType(D.getType()).isVolatileQualified(); - - // If the initializer was a simple constant initializer, we can optimize it - // in various ways. - if (IsSimpleConstantInitializer) { - llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(),D.getType(),this); - assert(Init != 0 && "Wasn't a simple constant init?"); - - llvm::Value *AlignVal = - llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), - Align.getQuantity()); - const llvm::Type *IntPtr = - llvm::IntegerType::get(VMContext, LLVMPointerWidth); - llvm::Value *SizeVal = - llvm::ConstantInt::get(IntPtr, - getContext().getTypeSizeInChars(Ty).getQuantity()); - - const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext); - if (Loc->getType() != BP) - Loc = Builder.CreateBitCast(Loc, BP, "tmp"); - - // If the initializer is all zeros, codegen with memset. - if (isa<llvm::ConstantAggregateZero>(Init)) { - llvm::Value *Zero = - llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 0); - Builder.CreateCall4(CGM.getMemSetFn(), Loc, Zero, SizeVal, AlignVal); - } else { - // Otherwise, create a temporary global with the initializer then - // memcpy from the global to the alloca. - std::string Name = GetStaticDeclName(*this, D, "."); - llvm::GlobalVariable *GV = - new llvm::GlobalVariable(CGM.getModule(), Init->getType(), true, - llvm::GlobalValue::InternalLinkage, - Init, Name, 0, false, 0); - GV->setAlignment(Align.getQuantity()); - - llvm::Value *SrcPtr = GV; - if (SrcPtr->getType() != BP) - SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp"); - - Builder.CreateCall4(CGM.getMemCpyFn(), Loc, SrcPtr, SizeVal, AlignVal); - } - } else if (Ty->isReferenceType()) { - RValue RV = EmitReferenceBindingToExpr(Init, /*IsInitializer=*/true); - EmitStoreOfScalar(RV.getScalarVal(), Loc, false, Ty); - } else if (!hasAggregateLLVMType(Init->getType())) { - llvm::Value *V = EmitScalarExpr(Init); - EmitStoreOfScalar(V, Loc, isVolatile, D.getType()); - } else if (Init->getType()->isAnyComplexType()) { - EmitComplexExprIntoAddr(Init, Loc, isVolatile); - } else { - EmitAggExpr(Init, Loc, isVolatile); - } - } - if (isByRef) { const llvm::PointerType *PtrToInt8Ty = llvm::Type::getInt8PtrTy(VMContext); @@ -591,6 +531,68 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { } } + if (Init) { + llvm::Value *Loc = DeclPtr; + if (isByRef) + Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D), + D.getNameAsString()); + + bool isVolatile = + getContext().getCanonicalType(D.getType()).isVolatileQualified(); + + // If the initializer was a simple constant initializer, we can optimize it + // in various ways. + if (IsSimpleConstantInitializer) { + llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(),D.getType(),this); + assert(Init != 0 && "Wasn't a simple constant init?"); + + llvm::Value *AlignVal = + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + Align.getQuantity()); + const llvm::Type *IntPtr = + llvm::IntegerType::get(VMContext, LLVMPointerWidth); + llvm::Value *SizeVal = + llvm::ConstantInt::get(IntPtr, + getContext().getTypeSizeInChars(Ty).getQuantity()); + + const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext); + if (Loc->getType() != BP) + Loc = Builder.CreateBitCast(Loc, BP, "tmp"); + + // If the initializer is all zeros, codegen with memset. + if (isa<llvm::ConstantAggregateZero>(Init)) { + llvm::Value *Zero = + llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 0); + Builder.CreateCall4(CGM.getMemSetFn(), Loc, Zero, SizeVal, AlignVal); + } else { + // Otherwise, create a temporary global with the initializer then + // memcpy from the global to the alloca. + std::string Name = GetStaticDeclName(*this, D, "."); + llvm::GlobalVariable *GV = + new llvm::GlobalVariable(CGM.getModule(), Init->getType(), true, + llvm::GlobalValue::InternalLinkage, + Init, Name, 0, false, 0); + GV->setAlignment(Align.getQuantity()); + + llvm::Value *SrcPtr = GV; + if (SrcPtr->getType() != BP) + SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp"); + + Builder.CreateCall4(CGM.getMemCpyFn(), Loc, SrcPtr, SizeVal, AlignVal); + } + } else if (Ty->isReferenceType()) { + RValue RV = EmitReferenceBindingToExpr(Init, /*IsInitializer=*/true); + EmitStoreOfScalar(RV.getScalarVal(), Loc, false, Ty); + } else if (!hasAggregateLLVMType(Init->getType())) { + llvm::Value *V = EmitScalarExpr(Init); + EmitStoreOfScalar(V, Loc, isVolatile, D.getType()); + } else if (Init->getType()->isAnyComplexType()) { + EmitComplexExprIntoAddr(Init, Loc, isVolatile); + } else { + EmitAggExpr(Init, Loc, isVolatile); + } + } + // Handle CXX destruction of variables. QualType DtorTy(Ty); while (const ArrayType *Array = getContext().getAsArrayType(DtorTy)) diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index 198e2d12fca3..243635744ffb 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -1147,8 +1147,8 @@ void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) { // Collect the names of referenced protocols llvm::SmallVector<std::string, 16> Protocols; - const ObjCInterfaceDecl *ClassDecl = OCD->getClassInterface(); - const ObjCList<ObjCProtocolDecl> &Protos =ClassDecl->getReferencedProtocols(); + const ObjCCategoryDecl *CatDecl = OCD->getCategoryDecl(); + const ObjCList<ObjCProtocolDecl> &Protos = CatDecl->getReferencedProtocols(); for (ObjCList<ObjCProtocolDecl>::iterator I = Protos.begin(), E = Protos.end(); I != E; ++I) Protocols.push_back((*I)->getNameAsString()); diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp index 5236d2063489..4907223fe346 100644 --- a/lib/CodeGen/CGRTTI.cpp +++ b/lib/CodeGen/CGRTTI.cpp @@ -760,7 +760,7 @@ void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) { // subobject. For a virtual base, this is the offset in the virtual table of // the virtual base offset for the virtual base referenced (negative). if (Base->isVirtual()) - OffsetFlags = CGM.getVtableInfo().getVirtualBaseOffsetIndex(RD, BaseDecl); + OffsetFlags = CGM.getVtableInfo().getVirtualBaseOffsetOffset(RD, BaseDecl); else { const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); OffsetFlags = Layout.getBaseClassOffset(BaseDecl) / 8; diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index 4500ec033cd8..9bcf986af842 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -63,10 +63,7 @@ public: /// Offset - the base offset of the overrider in the layout class. uint64_t Offset; - /// OldOffset - FIXME: Remove this. - int64_t OldOffset; - - OverriderInfo() : Method(0), Offset(0), OldOffset(0) { } + OverriderInfo() : Method(0), Offset(0) { } }; private: @@ -251,7 +248,6 @@ void FinalOverriders::AddOverriders(BaseSubobject Base, OverriderInfo& Overrider = OverridersMap[std::make_pair(Base, MD)]; assert(!Overrider.Method && "Overrider should not exist yet!"); - Overrider.OldOffset = Base.getBaseOffset(); Overrider.Offset = OffsetInLayoutClass; Overrider.Method = MD; } @@ -415,7 +411,6 @@ void FinalOverriders::PropagateOverrider(const CXXMethodDecl *OldMD, // Set the new overrider. Overrider.Offset = OverriderOffsetInLayoutClass; - Overrider.OldOffset = NewBase.getBaseOffset(); Overrider.Method = NewMD; // And propagate it further. @@ -559,7 +554,7 @@ void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base) { Out << " " << MD->getQualifiedNameAsString() << " - ("; Out << Overrider.Method->getQualifiedNameAsString(); - Out << ", " << Overrider.OldOffset / 8 << ", " << Overrider.Offset / 8 << ')'; + Out << ", " << ", " << Overrider.Offset / 8 << ')'; AdjustmentOffsetsMapTy::const_iterator AI = ReturnAdjustments.find(std::make_pair(Base, MD)); @@ -834,6 +829,11 @@ int64_t VCallOffsetMap::getVCallOffsetOffset(const CXXMethodDecl *MD) { /// VCallAndVBaseOffsetBuilder - Class for building vcall and vbase offsets. class VCallAndVBaseOffsetBuilder { +public: + typedef llvm::DenseMap<const CXXRecordDecl *, int64_t> + VBaseOffsetOffsetsMapTy; + +private: /// MostDerivedClass - The most derived class for which we're building vcall /// and vbase offsets. const CXXRecordDecl *MostDerivedClass; @@ -856,6 +856,11 @@ class VCallAndVBaseOffsetBuilder { /// VCallOffsets - Keeps track of vcall offsets. VCallOffsetMap VCallOffsets; + + /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets, + /// relative to the address point. + VBaseOffsetOffsetsMapTy VBaseOffsetOffsets; + /// FinalOverriders - The final overriders of the most derived class. /// (Can be null when we're not building a vtable of the most derived class). const FinalOverriders *Overriders; @@ -871,6 +876,10 @@ class VCallAndVBaseOffsetBuilder { /// AddVBaseOffsets - Add vbase offsets for the given class. void AddVBaseOffsets(const CXXRecordDecl *Base, uint64_t OffsetInLayoutClass); + /// getCurrentOffsetOffset - Get the current vcall or vbase offset offset in + /// bytes, relative to the vtable address point. + int64_t getCurrentOffsetOffset() const; + public: VCallAndVBaseOffsetBuilder(const CXXRecordDecl *MostDerivedClass, const CXXRecordDecl *LayoutClass, @@ -889,7 +898,10 @@ public: const_iterator components_begin() const { return Components.rbegin(); } const_iterator components_end() const { return Components.rend(); } - const VCallOffsetMap& getVCallOffsets() const { return VCallOffsets; } + const VCallOffsetMap &getVCallOffsets() const { return VCallOffsets; } + const VBaseOffsetOffsetsMapTy &getVBaseOffsetOffsets() const { + return VBaseOffsetOffsets; + } }; void @@ -940,6 +952,20 @@ VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base, AddVCallOffsets(Base, RealBaseOffset); } +int64_t VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const { + // OffsetIndex is the index of this vcall or vbase offset, relative to the + // vtable address point. (We subtract 3 to account for the information just + // above the address point, the RTTI info, the offset to top, and the + // vcall offset itself). + int64_t OffsetIndex = -(int64_t)(3 + Components.size()); + + // FIXME: We shouldn't use / 8 here. + int64_t OffsetOffset = OffsetIndex * + (int64_t)Context.Target.getPointerWidth(0) / 8; + + return OffsetOffset; +} + void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base, uint64_t VBaseOffset) { const CXXRecordDecl *RD = Base.getBase(); @@ -980,15 +1006,7 @@ void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base, if (!MD->isVirtual()) continue; - // OffsetIndex is the index of this vcall offset, relative to the vtable - // address point. (We subtract 3 to account for the information just - // above the address point, the RTTI info, the offset to top, and the - // vcall offset itself). - int64_t OffsetIndex = -(int64_t)(3 + Components.size()); - - // FIXME: We shouldn't use / 8 here. - int64_t OffsetOffset = OffsetIndex * - (int64_t)Context.Target.getPointerWidth(0) / 8; + int64_t OffsetOffset = getCurrentOffsetOffset(); // Don't add a vcall offset if we already have one for this member function // signature. @@ -1048,10 +1066,17 @@ void VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD, int64_t Offset = (int64_t)(LayoutClassLayout.getVBaseClassOffset(BaseDecl) - OffsetInLayoutClass) / 8; - + + // Add the vbase offset offset. + assert(!VBaseOffsetOffsets.count(BaseDecl) && + "vbase offset offset already exists!"); + + int64_t VBaseOffsetOffset = getCurrentOffsetOffset(); + VBaseOffsetOffsets.insert(std::make_pair(BaseDecl, VBaseOffsetOffset)); + Components.push_back(VtableComponent::MakeVBaseOffset(Offset)); } - + // Check the base class looking for more vbase offsets. AddVBaseOffsets(BaseDecl, OffsetInLayoutClass); } @@ -1096,6 +1121,13 @@ private: /// bases in this vtable. llvm::DenseMap<const CXXRecordDecl *, VCallOffsetMap> VCallOffsetsForVBases; + typedef llvm::DenseMap<const CXXRecordDecl *, int64_t> + VBaseOffsetOffsetsMapTy; + + /// VBaseOffsetOffsets - Contains the offsets of the virtual base offsets for + /// the most derived class. + VBaseOffsetOffsetsMapTy VBaseOffsetOffsets; + /// Components - The components of the vtable being built. llvm::SmallVector<VtableComponent, 64> Components; @@ -1117,24 +1149,27 @@ private: bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; } }; - /// ReturnAdjustments - The return adjustments needed in this vtable. - llvm::SmallVector<std::pair<uint64_t, ReturnAdjustment>, 16> - ReturnAdjustments; - /// MethodInfo - Contains information about a method in a vtable. /// (Used for computing 'this' pointer adjustment thunks. struct MethodInfo { /// BaseOffset - The base offset of this method. const uint64_t BaseOffset; + /// BaseOffsetInLayoutClass - The base offset in the layout class of this + /// method. + const uint64_t BaseOffsetInLayoutClass; + /// VtableIndex - The index in the vtable that this method has. /// (For destructors, this is the index of the complete destructor). const uint64_t VtableIndex; - MethodInfo(uint64_t BaseOffset, uint64_t VtableIndex) - : BaseOffset(BaseOffset), VtableIndex(VtableIndex) { } + MethodInfo(uint64_t BaseOffset, uint64_t BaseOffsetInLayoutClass, + uint64_t VtableIndex) + : BaseOffset(BaseOffset), + BaseOffsetInLayoutClass(BaseOffsetInLayoutClass), + VtableIndex(VtableIndex) { } - MethodInfo() : BaseOffset(0), VtableIndex(0) { } + MethodInfo() : BaseOffset(0), BaseOffsetInLayoutClass(0), VtableIndex(0) { } }; typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy; @@ -1158,9 +1193,27 @@ private: bool isEmpty() const { return !NonVirtual && !VCallOffsetOffset; } }; - /// ThisAdjustments - The 'this' pointer adjustments needed in this vtable. - llvm::SmallVector<std::pair<uint64_t, ThisAdjustment>, 16> - ThisAdjustments; + /// ThunkInfo - The 'this' pointer adjustment as well as an optional return + /// adjustment for a thunk. + struct ThunkInfo { + /// This - The 'this' pointer adjustment. + ThisAdjustment This; + + /// Return - The return adjustment. + ReturnAdjustment Return; + + ThunkInfo() { } + + ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return) + : This(This), Return(Return) { } + + bool isEmpty() const { return This.isEmpty() && Return.isEmpty(); } + }; + + typedef llvm::DenseMap<uint64_t, ThunkInfo> ThunksInfoMapTy; + + /// Thunks - The thunks by vtable index in the vtable currently being built. + ThunksInfoMapTy Thunks; /// ComputeThisAdjustments - Compute the 'this' pointer adjustments for the /// part of the vtable we're currently building. @@ -1182,11 +1235,13 @@ private: BaseSubobject Derived) const; /// ComputeThisAdjustment - Compute the 'this' pointer adjustment for the - /// given virtual member function and the 'this' pointer adjustment base - /// offset. - ThisAdjustment ComputeThisAdjustment(const CXXMethodDecl *MD, - BaseOffset Offset); - + /// given virtual member function, its offset in the layout class and its + /// final overrider. + ThisAdjustment + ComputeThisAdjustment(const CXXMethodDecl *MD, + uint64_t BaseOffsetInLayoutClass, + FinalOverriders::OverriderInfo Overrider); + /// AddMethod - Add a single virtual member function to the vtable /// components vector. void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment); @@ -1235,7 +1290,11 @@ private: /// LayoutSecondaryVtables - Layout the secondary vtables for the given base /// subobject. - void LayoutSecondaryVtables(BaseSubobject Base, uint64_t OffsetInLayoutClass); + /// + /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base + /// or a direct or indirect base of a virtual base. + void LayoutSecondaryVtables(BaseSubobject Base, bool BaseIsMorallyVirtual, + uint64_t OffsetInLayoutClass); /// DeterminePrimaryVirtualBases - Determine the primary virtual bases in this /// class hierarchy. @@ -1292,8 +1351,6 @@ OverridesMethodInBases(const CXXMethodDecl *MD, } void VtableBuilder::ComputeThisAdjustments() { - std::map<uint64_t, ThisAdjustment> SortedThisAdjustments; - // Now go through the method info map and see if any of the methods need // 'this' pointer adjustments. for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(), @@ -1301,56 +1358,34 @@ void VtableBuilder::ComputeThisAdjustments() { const CXXMethodDecl *MD = I->first; const MethodInfo &MethodInfo = I->second; - BaseSubobject OverriddenBaseSubobject(MD->getParent(), - MethodInfo.BaseOffset); - - // Get the final overrider for this method. - FinalOverriders::OverriderInfo Overrider = - Overriders.getOverrider(OverriddenBaseSubobject, MD); - - // Check if we need an adjustment. - if (Overrider.OldOffset == (int64_t)MethodInfo.BaseOffset) - continue; - - uint64_t VtableIndex = MethodInfo.VtableIndex; - - // Ignore adjustments for pure virtual member functions. - if (Overrider.Method->isPure()) - continue; - // Ignore adjustments for unused function pointers. + uint64_t VtableIndex = MethodInfo.VtableIndex; if (Components[VtableIndex].getKind() == VtableComponent::CK_UnusedFunctionPointer) continue; + + // Get the final overrider for this method. + FinalOverriders::OverriderInfo Overrider = + Overriders.getOverrider(BaseSubobject(MD->getParent(), + MethodInfo.BaseOffset), MD); + + ThisAdjustment ThisAdjustment = + ComputeThisAdjustment(MD, MethodInfo.BaseOffsetInLayoutClass, Overrider); - BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(), - Overrider.OldOffset); - - // Compute the adjustment offset. - BaseOffset ThisAdjustmentOffset = - ComputeThisAdjustmentBaseOffset(OverriddenBaseSubobject, - OverriderBaseSubobject); - - // Then compute the adjustment itself. - ThisAdjustment ThisAdjustment = ComputeThisAdjustment(Overrider.Method, - ThisAdjustmentOffset); + if (ThisAdjustment.isEmpty()) + continue; // Add it. - SortedThisAdjustments.insert(std::make_pair(VtableIndex, ThisAdjustment)); - + Thunks[VtableIndex].This = ThisAdjustment; + if (isa<CXXDestructorDecl>(MD)) { // Add an adjustment for the deleting destructor as well. - SortedThisAdjustments.insert(std::make_pair(VtableIndex + 1, - ThisAdjustment)); + Thunks[VtableIndex + 1].This = ThisAdjustment; } } /// Clear the method info map. MethodInfoMap.clear(); - - // Add the sorted elements. - ThisAdjustments.append(SortedThisAdjustments.begin(), - SortedThisAdjustments.end()); } VtableBuilder::ReturnAdjustment @@ -1360,13 +1395,20 @@ VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { if (!Offset.isEmpty()) { if (Offset.VirtualBase) { // Get the virtual base offset offset. - Adjustment.VBaseOffsetOffset = - VtableInfo.getVirtualBaseOffsetIndex(Offset.DerivedClass, - Offset.VirtualBase); - // FIXME: Once the assert in getVirtualBaseOffsetIndex is back again, + if (Offset.DerivedClass == MostDerivedClass) { + // We can get the offset offset directly from our map. + Adjustment.VBaseOffsetOffset = + VBaseOffsetOffsets.lookup(Offset.VirtualBase); + } else { + Adjustment.VBaseOffsetOffset = + VtableInfo.getVirtualBaseOffsetOffset(Offset.DerivedClass, + Offset.VirtualBase); + } + + // FIXME: Once the assert in getVirtualBaseOffsetOffset is back again, // we can get rid of this assert. assert(Adjustment.VBaseOffsetOffset != 0 && - "Invalid base offset offset!"); + "Invalid vbase offset offset!"); } Adjustment.NonVirtual = Offset.NonVirtualOffset; @@ -1402,13 +1444,13 @@ VtableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base, if (Offset.VirtualBase) { // If we have a virtual base class, the non-virtual offset is relative // to the virtual base class offset. - const ASTRecordLayout &MostDerivedClassLayout = - Context.getASTRecordLayout(MostDerivedClass); + const ASTRecordLayout &LayoutClassLayout = + Context.getASTRecordLayout(LayoutClass); /// Get the virtual base offset, relative to the most derived class /// layout. OffsetToBaseSubobject += - MostDerivedClassLayout.getVBaseClassOffset(Offset.VirtualBase); + LayoutClassLayout.getVBaseClassOffset(Offset.VirtualBase); } else { // Otherwise, the non-virtual offset is relative to the derived class // offset. @@ -1427,38 +1469,57 @@ VtableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base, return BaseOffset(); } +VtableBuilder::ThisAdjustment +VtableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD, + uint64_t BaseOffsetInLayoutClass, + FinalOverriders::OverriderInfo Overrider) { + // Check if we need an adjustment at all. + if (BaseOffsetInLayoutClass == Overrider.Offset) + return ThisAdjustment(); + + // Ignore adjustments for pure virtual member functions. + if (Overrider.Method->isPure()) + return ThisAdjustment(); + + BaseSubobject OverriddenBaseSubobject(MD->getParent(), + BaseOffsetInLayoutClass); + + BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(), + Overrider.Offset); + + // Compute the adjustment offset. + BaseOffset Offset = ComputeThisAdjustmentBaseOffset(OverriddenBaseSubobject, + OverriderBaseSubobject); + if (Offset.isEmpty()) + return ThisAdjustment(); -VtableBuilder::ThisAdjustment -VtableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD, - BaseOffset Offset) { ThisAdjustment Adjustment; - if (!Offset.isEmpty()) { - if (Offset.VirtualBase) { - // Get the vcall offset map for this virtual base. - VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Offset.VirtualBase]; - - if (VCallOffsets.empty()) { - // We don't have vcall offsets for this virtual base, go ahead and - // build them. - VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, MostDerivedClass, - /*FinalOverriders=*/0, - BaseSubobject(Offset.VirtualBase, 0), - /*BaseIsVirtual=*/true, - /*OffsetInLayoutClass=*/0); + if (Offset.VirtualBase) { + // Get the vcall offset map for this virtual base. + VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Offset.VirtualBase]; + + if (VCallOffsets.empty()) { + // We don't have vcall offsets for this virtual base, go ahead and + // build them. + VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, MostDerivedClass, + /*FinalOverriders=*/0, + BaseSubobject(Offset.VirtualBase, 0), + /*BaseIsVirtual=*/true, + /*OffsetInLayoutClass=*/0); - VCallOffsets = Builder.getVCallOffsets(); - } - - Adjustment.VCallOffsetOffset = VCallOffsets.getVCallOffsetOffset(MD); + VCallOffsets = Builder.getVCallOffsets(); } - - Adjustment.NonVirtual = Offset.NonVirtualOffset; + + Adjustment.VCallOffsetOffset = VCallOffsets.getVCallOffsetOffset(MD); } + + // Set the non-virtual part of the adjustment. + Adjustment.NonVirtual = Offset.NonVirtualOffset; return Adjustment; } - + void VtableBuilder::AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment) { @@ -1472,8 +1533,7 @@ VtableBuilder::AddMethod(const CXXMethodDecl *MD, } else { // Add the return adjustment if necessary. if (!ReturnAdjustment.isEmpty()) - ReturnAdjustments.push_back(std::make_pair(Components.size(), - ReturnAdjustment)); + Thunks[Components.size()].Return = ReturnAdjustment; // Add the function. Components.push_back(VtableComponent::MakeFunction(MD)); @@ -1665,6 +1725,7 @@ VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass, MethodInfo &OverriddenMethodInfo = MethodInfoMap[OverriddenMD]; MethodInfo MethodInfo(Base.getBaseOffset(), + BaseOffsetInLayoutClass, OverriddenMethodInfo.VtableIndex); assert(!MethodInfoMap.count(MD) && @@ -1677,7 +1738,8 @@ VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass, } // Insert the method info for this method. - MethodInfo MethodInfo(Base.getBaseOffset(), Components.size()); + MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass, + Components.size()); assert(!MethodInfoMap.count(MD) && "Should not have method info for this method yet!"); @@ -1737,6 +1799,11 @@ VtableBuilder::LayoutPrimaryAndSecondaryVtables(BaseSubobject Base, VCallOffsets = Builder.getVCallOffsets(); } + // If we're laying out the most derived class we want to keep track of the + // virtual base class offset offsets. + if (Base.getBase() == MostDerivedClass) + VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets(); + // Add the offset to top. // FIXME: We should not use / 8 here. int64_t OffsetToTop = -(int64_t)(OffsetInLayoutClass - @@ -1772,11 +1839,16 @@ VtableBuilder::LayoutPrimaryAndSecondaryVtables(BaseSubobject Base, AddressPoints.insert(std::make_pair(PrimaryBase, AddressPoint)); } + bool BaseIsMorallyVirtual = BaseIsVirtual; + if (isBuildingConstructorVtable() && Base.getBase() == MostDerivedClass) + BaseIsMorallyVirtual = false; + // Layout secondary vtables. - LayoutSecondaryVtables(Base, OffsetInLayoutClass); + LayoutSecondaryVtables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass); } void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base, + bool BaseIsMorallyVirtual, uint64_t OffsetInLayoutClass) { // Itanium C++ ABI 2.5.2: // Following the primary virtual table of a derived class are secondary @@ -1800,6 +1872,16 @@ void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base, if (!BaseDecl->isDynamicClass()) continue; + if (isBuildingConstructorVtable()) { + // Itanium C++ ABI 2.6.4: + // Some of the base class subobjects may not need construction virtual + // tables, which will therefore not be present in the construction + // virtual table group, even though the subobject virtual tables are + // present in the main virtual table group for the complete object. + if (!BaseIsMorallyVirtual && !BaseDecl->getNumVBases()) + continue; + } + // Get the base offset of this base. uint64_t RelativeBaseOffset = Layout.getBaseClassOffset(BaseDecl); uint64_t BaseOffset = Base.getBaseOffset() + RelativeBaseOffset; @@ -1810,7 +1892,7 @@ void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base, // to emit secondary vtables for other bases of this base. if (BaseDecl == PrimaryBase) { LayoutSecondaryVtables(BaseSubobject(BaseDecl, BaseOffset), - BaseOffsetInLayoutClass); + BaseIsMorallyVirtual, BaseOffsetInLayoutClass); continue; } @@ -1920,15 +2002,15 @@ VtableBuilder::LayoutVtablesForVirtualBases(const CXXRecordDecl *RD, /// dumpLayout - Dump the vtable layout. void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { - if (MostDerivedClass == LayoutClass) { - Out << "Vtable for '"; - Out << MostDerivedClass->getQualifiedNameAsString(); - } else { + if (isBuildingConstructorVtable()) { Out << "Construction vtable for ('"; Out << MostDerivedClass->getQualifiedNameAsString() << "', "; // FIXME: Don't use / 8 . Out << MostDerivedClassOffset / 8 << ") in '"; Out << LayoutClass->getQualifiedNameAsString(); + } else { + Out << "Vtable for '"; + Out << MostDerivedClass->getQualifiedNameAsString(); } Out << "' (" << Components.size() << " entries).\n"; @@ -1945,8 +2027,6 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { AddressPointsByIndex.insert(std::make_pair(Index, Base)); } - unsigned NextReturnAdjustmentIndex = 0; - unsigned NextThisAdjustmentIndex = 0; for (unsigned I = 0, E = Components.size(); I != E; ++I) { uint64_t Index = I; @@ -1983,38 +2063,33 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { if (MD->isPure()) Out << " [pure]"; - // If this function pointer has a return adjustment, dump it. - if (NextReturnAdjustmentIndex < ReturnAdjustments.size() && - ReturnAdjustments[NextReturnAdjustmentIndex].first == I) { - const ReturnAdjustment Adjustment = - ReturnAdjustments[NextReturnAdjustmentIndex].second; - - Out << "\n [return adjustment: "; - Out << Adjustment.NonVirtual << " non-virtual"; - - if (Adjustment.VBaseOffsetOffset) - Out << ", " << Adjustment.VBaseOffsetOffset << " vbase offset offset"; - - Out << ']'; + ThunkInfo Thunk = Thunks.lookup(I); + if (!Thunk.isEmpty()) { + // If this function pointer has a return adjustment, dump it. + if (!Thunk.Return.isEmpty()) { + Out << "\n [return adjustment: "; + Out << Thunk.Return.NonVirtual << " non-virtual"; + + if (Thunk.Return.VBaseOffsetOffset) { + Out << ", " << Thunk.Return.VBaseOffsetOffset; + Out << " vbase offset offset"; + } - NextReturnAdjustmentIndex++; - } - - // If this function pointer has a 'this' pointer adjustment, dump it. - if (NextThisAdjustmentIndex < ThisAdjustments.size() && - ThisAdjustments[NextThisAdjustmentIndex].first == I) { - const ThisAdjustment Adjustment = - ThisAdjustments[NextThisAdjustmentIndex].second; - - Out << "\n [this adjustment: "; - Out << Adjustment.NonVirtual << " non-virtual"; + Out << ']'; + } - if (Adjustment.VCallOffsetOffset) - Out << ", " << Adjustment.VCallOffsetOffset << " vcall offset offset"; + // If this function pointer has a 'this' pointer adjustment, dump it. + if (!Thunk.This.isEmpty()) { + Out << "\n [this adjustment: "; + Out << Thunk.This.NonVirtual << " non-virtual"; + + if (Thunk.This.VCallOffsetOffset) { + Out << ", " << Thunk.This.VCallOffsetOffset; + Out << " vcall offset offset"; + } - Out << ']'; - - NextThisAdjustmentIndex++; + Out << ']'; + } } break; @@ -2036,23 +2111,21 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { if (DD->isPure()) Out << " [pure]"; - // If this destructor has a 'this' pointer adjustment, dump it. - if (NextThisAdjustmentIndex < ThisAdjustments.size() && - ThisAdjustments[NextThisAdjustmentIndex].first == I) { - const ThisAdjustment Adjustment = - ThisAdjustments[NextThisAdjustmentIndex].second; - - Out << "\n [this adjustment: "; - Out << Adjustment.NonVirtual << " non-virtual"; - - if (Adjustment.VCallOffsetOffset) - Out << ", " << Adjustment.VCallOffsetOffset << " vcall offset offset"; - - Out << ']'; - - NextThisAdjustmentIndex++; - } - + ThunkInfo Thunk = Thunks.lookup(I); + if (!Thunk.isEmpty()) { + // If this destructor has a 'this' pointer adjustment, dump it. + if (!Thunk.This.isEmpty()) { + Out << "\n [this adjustment: "; + Out << Thunk.This.NonVirtual << " non-virtual"; + + if (Thunk.This.VCallOffsetOffset) { + Out << ", " << Thunk.This.VCallOffsetOffset; + Out << " vcall offset offset"; + } + + Out << ']'; + } + } break; } @@ -2108,6 +2181,29 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { } Out << '\n'; + + if (!isBuildingConstructorVtable() && MostDerivedClass->getNumVBases()) { + Out << "Virtual base offset offsets for '"; + Out << MostDerivedClass->getQualifiedNameAsString() << "'.\n"; + + // We store the virtual base class names and their offsets in a map to get + // a stable order. + std::map<std::string, int64_t> ClassNamesAndOffsets; + + for (VBaseOffsetOffsetsMapTy::const_iterator I = VBaseOffsetOffsets.begin(), + E = VBaseOffsetOffsets.end(); I != E; ++I) { + std::string ClassName = I->first->getQualifiedNameAsString(); + int64_t OffsetOffset = I->second; + ClassNamesAndOffsets.insert(std::make_pair(ClassName, OffsetOffset)); + } + + for (std::map<std::string, int64_t>::const_iterator I = + ClassNamesAndOffsets.begin(), E = ClassNamesAndOffsets.end(); + I != E; ++I) + Out << " " << I->first << " | " << I->second << '\n'; + + Out << "\n"; + } } } @@ -2598,7 +2694,7 @@ public: CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl()); CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl()); if (D != MostDerivedClass) - return CGM.getVtableInfo().getVirtualBaseOffsetIndex(D, B); + return CGM.getVtableInfo().getVirtualBaseOffsetOffset(D, B); llvm::DenseMap<const CXXRecordDecl *, Index_t>::iterator i; i = VBIndex.find(B); if (i != VBIndex.end()) @@ -3346,39 +3442,39 @@ CGVtableInfo::getAdjustments(GlobalDecl GD) { return 0; } -int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, - const CXXRecordDecl *VBase) { +int64_t CGVtableInfo::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, + const CXXRecordDecl *VBase) { ClassPairTy ClassPair(RD, VBase); - VirtualBaseClassIndiciesTy::iterator I = - VirtualBaseClassIndicies.find(ClassPair); - if (I != VirtualBaseClassIndicies.end()) + VirtualBaseClassOffsetOffsetsMapTy::iterator I = + VirtualBaseClassOffsetOffsets.find(ClassPair); + if (I != VirtualBaseClassOffsetOffsets.end()) return I->second; - // FIXME: This seems expensive. Can we do a partial job to get - // just this data. - AddressPointsMapTy AddressPoints; - OldVtableBuilder b(RD, RD, 0, CGM, false, AddressPoints); - D1(printf("vtable %s\n", RD->getNameAsCString())); - b.GenerateVtableForBase(RD); - b.GenerateVtableForVBases(RD); + VCallAndVBaseOffsetBuilder Builder(RD, RD, /*FinalOverriders=*/0, + BaseSubobject(RD, 0), + /*BaseIsVirtual=*/false, + /*OffsetInLayoutClass=*/0); - for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I = - b.getVBIndex().begin(), E = b.getVBIndex().end(); I != E; ++I) { + + for (VCallAndVBaseOffsetBuilder::VBaseOffsetOffsetsMapTy::const_iterator I = + Builder.getVBaseOffsetOffsets().begin(), + E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) { // Insert all types. ClassPairTy ClassPair(RD, I->first); - VirtualBaseClassIndicies.insert(std::make_pair(ClassPair, I->second)); + VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I->second)); } - I = VirtualBaseClassIndicies.find(ClassPair); + I = VirtualBaseClassOffsetOffsets.find(ClassPair); + // FIXME: The assertion below assertion currently fails with the old vtable /// layout code if there is a non-virtual thunk adjustment in a vtable. // Once the new layout is in place, this return should be removed. - if (I == VirtualBaseClassIndicies.end()) + if (I == VirtualBaseClassOffsetOffsets.end()) return 0; - assert(I != VirtualBaseClassIndicies.end() && "Did not find index!"); + assert(I != VirtualBaseClassOffsetOffsets.end() && "Did not find index!"); return I->second; } @@ -3400,20 +3496,17 @@ CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage, if (GenerateDefinition) { if (LayoutClass == RD) { assert(!IsVirtual && - "Can't only have a virtual base in construction vtables!"); - VtableBuilder Builder(*this, RD, Offset, - /*MostDerivedClassIsVirtual=*/false, - LayoutClass); - - if (CGM.getLangOptions().DumpVtableLayouts) - Builder.dumpLayout(llvm::errs()); - } else if (CGM.getLangOptions().DumpVtableLayouts) { - // We only build construction vtables when dumping vtable layouts for now. - VtableBuilder Builder(*this, RD, Offset, - /*MostDerivedClassIsVirtual=*/IsVirtual, - LayoutClass); - Builder.dumpLayout(llvm::errs()); + "Can only have a virtual base in construction vtables!"); + assert(!Offset && + "Can only have a base offset in construction vtables!"); } + + VtableBuilder Builder(*this, RD, Offset, + /*MostDerivedClassIsVirtual=*/IsVirtual, + LayoutClass); + + if (CGM.getLangOptions().DumpVtableLayouts) + Builder.dumpLayout(llvm::errs()); } llvm::SmallString<256> OutName; diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h index 57220d9d5af5..5a146ab97c99 100644 --- a/lib/CodeGen/CGVtable.h +++ b/lib/CodeGen/CGVtable.h @@ -149,10 +149,12 @@ private: typedef std::pair<const CXXRecordDecl *, const CXXRecordDecl *> ClassPairTy; - /// VirtualBaseClassIndicies - Contains the index into the vtable where the - /// offsets for virtual bases of a class are stored. - typedef llvm::DenseMap<ClassPairTy, int64_t> VirtualBaseClassIndiciesTy; - VirtualBaseClassIndiciesTy VirtualBaseClassIndicies; + /// VirtualBaseClassOffsetOffsets - Contains the vtable offset (relative to + /// the address point) in bytes where the offsets for virtual bases of a class + /// are stored. + typedef llvm::DenseMap<ClassPairTy, int64_t> + VirtualBaseClassOffsetOffsetsMapTy; + VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets; /// Vtables - All the vtables which have been defined. llvm::DenseMap<const CXXRecordDecl *, llvm::GlobalVariable *> Vtables; @@ -202,13 +204,13 @@ public: /// stored. uint64_t getMethodVtableIndex(GlobalDecl GD); - /// getVirtualBaseOffsetIndex - Return the index (relative to the vtable - /// address point) where the offset of the virtual base that contains the - /// given Base is stored, otherwise, if no virtual base contains the given + /// getVirtualBaseOffsetOffset - Return the offset in bytes (relative to the + /// vtable address point) where the offset of the virtual base that contains + /// the given base is stored, otherwise, if no virtual base contains the given /// class, return 0. Base must be a virtual base class or an unambigious /// base. - int64_t getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, - const CXXRecordDecl *VBase); + int64_t getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, + const CXXRecordDecl *VBase); AdjustmentVectorTy *getAdjustments(GlobalDecl GD); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index c67948d27f08..f41db14f1a66 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -285,8 +285,7 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, break; case TSK_ExplicitInstantiationDefinition: - // FIXME: explicit instantiation definitions should use weak linkage - return CodeGenModule::GVA_StrongExternal; + return CodeGenModule::GVA_ExplicitTemplateInstantiation; case TSK_ExplicitInstantiationDeclaration: case TSK_ImplicitInstantiation: @@ -343,6 +342,12 @@ CodeGenModule::getFunctionLinkage(const FunctionDecl *D) { // merged with other definitions. c) C++ has the ODR, so we know the // definition is dependable. return llvm::Function::LinkOnceODRLinkage; + } else if (Linkage == GVA_ExplicitTemplateInstantiation) { + // An explicit instantiation of a template has weak linkage, since + // explicit instantiations can occur in multiple translation units + // and must all be equivalent. However, we are not allowed to + // throw away these explicit instantiations. + return llvm::Function::WeakODRLinkage; } else { assert(Linkage == GVA_StrongExternal); // Otherwise, we have strong external linkage. @@ -589,6 +594,7 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) { // static, static inline, always_inline, and extern inline functions can // always be deferred. Normal inline functions can be deferred in C99/C++. + // Implicit template instantiations can also be deferred in C++. if (Linkage == GVA_Internal || Linkage == GVA_C99Inline || Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation) return true; @@ -1043,15 +1049,15 @@ GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) { switch (TSK) { case TSK_Undeclared: case TSK_ExplicitSpecialization: - - // FIXME: ExplicitInstantiationDefinition should be weak! - case TSK_ExplicitInstantiationDefinition: return CodeGenModule::GVA_StrongExternal; - + case TSK_ExplicitInstantiationDeclaration: llvm_unreachable("Variable should not be instantiated"); // Fall through to treat this like any other instantiation. + case TSK_ExplicitInstantiationDefinition: + return CodeGenModule::GVA_ExplicitTemplateInstantiation; + case TSK_ImplicitInstantiation: return CodeGenModule::GVA_TemplateInstantiation; } @@ -1171,7 +1177,10 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { GV->setLinkage(llvm::GlobalVariable::WeakODRLinkage); else GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage); - } else if (Linkage == GVA_TemplateInstantiation) + } else if (Linkage == GVA_TemplateInstantiation || + Linkage == GVA_ExplicitTemplateInstantiation) + // FIXME: It seems like we can provide more specific linkage here + // (LinkOnceODR, WeakODR). GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage); else if (!getLangOptions().CPlusPlus && !CodeGenOpts.NoCommon && !D->hasExternalStorage() && !D->getInit() && diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 40dc56388981..9077adedd0b9 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -437,7 +437,8 @@ public: GVA_C99Inline, GVA_CXXInline, GVA_StrongExternal, - GVA_TemplateInstantiation + GVA_TemplateInstantiation, + GVA_ExplicitTemplateInstantiation }; llvm::GlobalVariable::LinkageTypes diff --git a/lib/CodeGen/Makefile b/lib/CodeGen/Makefile index 83cb36738709..3cea6bbd9f06 100644 --- a/lib/CodeGen/Makefile +++ b/lib/CodeGen/Makefile @@ -16,9 +16,9 @@ LEVEL = ../../../.. LIBRARYNAME := clangCodeGen BUILD_ARCHIVE = 1 -CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include +CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include ifdef CLANG_VENDOR -CPPFLAGS += -DCLANG_VENDOR='"$(CLANG_VENDOR) "' +CPP.Flags += -DCLANG_VENDOR='"$(CLANG_VENDOR) "' endif include $(LEVEL)/Makefile.common diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index 2e0580f5e79b..32555ab70579 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -53,19 +53,19 @@ static const DeclContext *GetLocalClassFunctionDeclContext( static const CXXMethodDecl *getStructor(const CXXMethodDecl *MD) { assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) && "Passed in decl is not a ctor or dtor!"); - + if (const TemplateDecl *TD = MD->getPrimaryTemplate()) { MD = cast<CXXMethodDecl>(TD->getTemplatedDecl()); assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) && "Templated decl is not a ctor or dtor!"); } - + return MD; } static const unsigned UnknownArity = ~0U; - + /// CXXNameMangler - Manage the mangling of a single name. class CXXNameMangler { MangleContext &Context; @@ -73,7 +73,7 @@ class CXXNameMangler { const CXXMethodDecl *Structor; unsigned StructorType; - + llvm::DenseMap<uintptr_t, unsigned> Substitutions; ASTContext &getASTContext() const { return Context.getASTContext(); } @@ -92,7 +92,7 @@ public: ~CXXNameMangler() { if (Out.str()[0] == '\01') return; - + int status = 0; char *result = abi::__cxa_demangle(Out.str().str().c_str(), 0, 0, &status); assert(status == 0 && "Could not demangle mangled name!"); @@ -151,7 +151,7 @@ private: void mangleQualifiers(Qualifiers Quals); void mangleObjCMethodName(const ObjCMethodDecl *MD); - + // Declare manglers for every type class. #define ABSTRACT_TYPE(CLASS, PARENT) #define NON_CANONICAL_TYPE(CLASS, PARENT) @@ -172,10 +172,12 @@ private: void mangleCXXCtorType(CXXCtorType T); void mangleCXXDtorType(CXXDtorType T); - void mangleTemplateArgs(const TemplateArgument *TemplateArgs, + void mangleTemplateArgs(const TemplateParameterList &PL, + const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); - void mangleTemplateArgs(const TemplateArgumentList &L); - void mangleTemplateArg(const TemplateArgument &A); + void mangleTemplateArgs(const TemplateParameterList &PL, + const TemplateArgumentList &AL); + void mangleTemplateArg(const NamedDecl *P, const TemplateArgument &A); void mangleTemplateParameter(unsigned Index); }; @@ -248,8 +250,10 @@ void CXXNameMangler::mangle(const NamedDecl *D, llvm::StringRef Prefix) { Out << Prefix; if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) mangleFunctionEncoding(FD); + else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) + mangleName(VD); else - mangleName(cast<VarDecl>(D)); + mangleName(cast<FieldDecl>(D)); } void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { @@ -306,7 +310,7 @@ static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) { LinkageSpecDecl::lang_cxx && "Unexpected linkage decl!"); DC = DC->getParent(); } - + return DC; } @@ -315,10 +319,10 @@ static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) { static bool isStdNamespace(const DeclContext *DC) { if (!DC->isNamespace()) return false; - + if (!IgnoreLinkageSpecDecls(DC->getParent())->isTranslationUnit()) return false; - + return isStd(cast<NamespaceDecl>(DC)); } @@ -349,12 +353,12 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) { // ::= <local-name> // const DeclContext *DC = ND->getDeclContext(); - + if (GetLocalClassFunctionDeclContext(DC)) { mangleLocalName(ND); return; } - + // If this is an extern variable declared locally, the relevant DeclContext // is that of the containing namespace, or the translation unit. if (isa<FunctionDecl>(DC) && ND->hasLinkage()) @@ -369,7 +373,8 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) { const TemplateArgumentList *TemplateArgs = 0; if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { mangleUnscopedTemplateName(TD); - mangleTemplateArgs(*TemplateArgs); + TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); + mangleTemplateArgs(*TemplateParameters, *TemplateArgs); return; } @@ -391,7 +396,8 @@ void CXXNameMangler::mangleName(const TemplateDecl *TD, if (DC->isTranslationUnit() || isStdNamespace(DC)) { mangleUnscopedTemplateName(TD); - mangleTemplateArgs(TemplateArgs, NumTemplateArgs); + TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); + mangleTemplateArgs(*TemplateParameters, TemplateArgs, NumTemplateArgs); } else { mangleNestedName(TD, TemplateArgs, NumTemplateArgs); } @@ -417,7 +423,7 @@ void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) { = dyn_cast<TemplateTemplateParmDecl>(ND)) { mangleTemplateParameter(TTP->getIndex()); return; - } + } mangleUnscopedName(ND->getTemplatedDecl()); addSubstitution(ND); @@ -429,7 +435,7 @@ void CXXNameMangler::mangleNumber(int64_t Number) { Out << 'n'; Number = -Number; } - + Out << Number; } @@ -445,7 +451,7 @@ void CXXNameMangler::mangleCallOffset(const ThunkAdjustment &Adjustment) { Out << '_'; return; } - + Out << 'v'; mangleNumber(Adjustment.NonVirtual); Out << '_'; @@ -496,7 +502,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, case DeclarationName::Identifier: { if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) { // We must avoid conflicts between internally- and externally- - // linked variable declaration names in the same TU. + // linked variable declaration names in the same TU. // This naming convention is the same as that followed by GCC, though it // shouldn't actually matter. if (ND && isa<VarDecl>(ND) && ND->getLinkage() == InternalLinkage && @@ -582,7 +588,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, unsigned Arity; if (ND) { Arity = cast<FunctionDecl>(ND)->getNumParams(); - + // If we have a C++ member function, we need to include the 'this' pointer. // FIXME: This does not make sense for operators that are static, but their // names stay the same regardless of the arity (operator new for instance). @@ -628,7 +634,8 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND, const TemplateArgumentList *TemplateArgs = 0; if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { mangleTemplatePrefix(TD); - mangleTemplateArgs(*TemplateArgs); + TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); + mangleTemplateArgs(*TemplateParameters, *TemplateArgs); } else { manglePrefix(DC, NoFunction); @@ -645,7 +652,8 @@ void CXXNameMangler::mangleNestedName(const TemplateDecl *TD, Out << 'N'; mangleTemplatePrefix(TD); - mangleTemplateArgs(TemplateArgs, NumTemplateArgs); + TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); + mangleTemplateArgs(*TemplateParameters, TemplateArgs, NumTemplateArgs); Out << 'E'; } @@ -656,26 +664,26 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) { // <discriminator> := _ <non-negative number> const DeclContext *DC = ND->getDeclContext(); Out << 'Z'; - + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) mangleObjCMethodName(MD); else if (const DeclContext *CDC = GetLocalClassFunctionDeclContext(DC)) { mangleFunctionEncoding(cast<FunctionDecl>(CDC)); Out << 'E'; mangleNestedName(ND, DC, true /*NoFunction*/); - + // FIXME. This still does not cover all cases. unsigned disc; if (Context.getNextDiscriminator(ND, disc)) { if (disc < 10) Out << '_' << disc; - else + else Out << "__" << disc << '_'; } return; } - else + else mangleFunctionEncoding(cast<FunctionDecl>(DC)); Out << 'E'; @@ -702,7 +710,8 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) { const TemplateArgumentList *TemplateArgs = 0; if (const TemplateDecl *TD = isTemplate(cast<NamedDecl>(DC), TemplateArgs)) { mangleTemplatePrefix(TD); - mangleTemplateArgs(*TemplateArgs); + TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); + mangleTemplateArgs(*TemplateParameters, *TemplateArgs); } else if(NoFunction && isa<FunctionDecl>(DC)) return; @@ -729,7 +738,7 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) { = dyn_cast<TemplateTemplateParmDecl>(ND)) { mangleTemplateParameter(TTP->getIndex()); return; - } + } manglePrefix(ND->getDeclContext()); mangleUnqualifiedName(ND->getTemplatedDecl()); @@ -749,22 +758,22 @@ CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) { case OO_Array_Delete: Out << "da"; break; // ::= ps # + (unary) // ::= pl # + - case OO_Plus: + case OO_Plus: assert((Arity == 1 || Arity == 2) && "Invalid arity!"); Out << (Arity == 1? "ps" : "pl"); break; // ::= ng # - (unary) // ::= mi # - - case OO_Minus: + case OO_Minus: assert((Arity == 1 || Arity == 2) && "Invalid arity!"); Out << (Arity == 1? "ng" : "mi"); break; // ::= ad # & (unary) // ::= an # & - case OO_Amp: + case OO_Amp: assert((Arity == 1 || Arity == 2) && "Invalid arity!"); Out << (Arity == 1? "ad" : "an"); break; // ::= de # * (unary) // ::= ml # * - case OO_Star: + case OO_Star: assert((Arity == 1 || Arity == 2) && "Invalid arity!"); Out << (Arity == 1? "de" : "ml"); break; // ::= co # ~ @@ -863,15 +872,15 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { llvm::SmallString<64> Name; llvm::raw_svector_ostream OS(Name); - - const ObjCContainerDecl *CD = + + const ObjCContainerDecl *CD = dyn_cast<ObjCContainerDecl>(MD->getDeclContext()); assert (CD && "Missing container decl in GetNameForMethod"); OS << (MD->isInstanceMethod() ? '-' : '+') << '[' << CD->getName(); if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(CD)) OS << '(' << CID->getNameAsString() << ')'; OS << ' ' << MD->getSelector().getAsString() << ']'; - + Out << OS.str().size() << OS.str(); } @@ -1143,7 +1152,9 @@ void CXXNameMangler::mangleType(const TypenameType *T) { TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl(); assert(TD && "FIXME: Support dependent template names"); mangleTemplatePrefix(TD); - mangleTemplateArgs(TST->getArgs(), TST->getNumArgs()); + TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); + mangleTemplateArgs(*TemplateParameters, TST->getArgs(), + TST->getNumArgs()); addSubstitution(QualType(TST, 0)); } } else if (const TemplateTypeParmType *TTPT = @@ -1173,7 +1184,7 @@ void CXXNameMangler::mangleType(const TypeOfExprType *T) { void CXXNameMangler::mangleType(const DecltypeType *T) { Expr *E = T->getUnderlyingExpr(); - + // type ::= Dt <expression> E # decltype of an id-expression // # or class member access // ::= DT <expression> E # decltype of an expression @@ -1195,11 +1206,11 @@ void CXXNameMangler::mangleType(const DecltypeType *T) { Out << 'E'; } -void CXXNameMangler::mangleIntegerLiteral(QualType T, +void CXXNameMangler::mangleIntegerLiteral(QualType T, const llvm::APSInt &Value) { // <expr-primary> ::= L <type> <value number> E # integer literal Out << 'L'; - + mangleType(T); if (T->isBooleanType()) { // Boolean values are encoded as 0/1. @@ -1210,7 +1221,7 @@ void CXXNameMangler::mangleIntegerLiteral(QualType T, Value.abs().print(Out, false); } Out << 'E'; - + } void CXXNameMangler::mangleCalledExpression(const Expr *E, unsigned Arity) { @@ -1314,7 +1325,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) { break; } - case Expr::CXXUnresolvedConstructExprClass: { + case Expr::CXXUnresolvedConstructExprClass: { const CXXUnresolvedConstructExpr *CE = cast<CXXUnresolvedConstructExpr>(E); unsigned N = CE->arg_size(); @@ -1323,7 +1334,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) { if (N != 1) Out << "_"; for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I)); if (N != 1) Out << "E"; - break; + break; } case Expr::CXXTemporaryObjectExprClass: @@ -1355,18 +1366,18 @@ void CXXNameMangler::mangleExpression(const Expr *E) { case Expr::UnaryOperatorClass: { const UnaryOperator *UO = cast<UnaryOperator>(E); - mangleOperatorName(UnaryOperator::getOverloadedOperator(UO->getOpcode()), + mangleOperatorName(UnaryOperator::getOverloadedOperator(UO->getOpcode()), /*Arity=*/1); mangleExpression(UO->getSubExpr()); break; } - + case Expr::BinaryOperatorClass: { const BinaryOperator *BO = cast<BinaryOperator>(E); - mangleOperatorName(BinaryOperator::getOverloadedOperator(BO->getOpcode()), + mangleOperatorName(BinaryOperator::getOverloadedOperator(BO->getOpcode()), /*Arity=*/2); mangleExpression(BO->getLHS()); - mangleExpression(BO->getRHS()); + mangleExpression(BO->getRHS()); break; } @@ -1396,7 +1407,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) { mangleExpression(ECE->getSubExpr()); break; } - + case Expr::CXXOperatorCallExprClass: { const CXXOperatorCallExpr *CE = cast<CXXOperatorCallExpr>(E); unsigned NumArgs = CE->getNumArgs(); @@ -1406,7 +1417,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) { mangleExpression(CE->getArg(i)); break; } - + case Expr::ParenExprClass: mangleExpression(cast<ParenExpr>(E)->getSubExpr()); break; @@ -1415,7 +1426,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) { const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl(); switch (D->getKind()) { - default: + default: // <expr-primary> ::= L <mangled-name> E # external name Out << 'L'; mangle(D, "_Z"); @@ -1466,7 +1477,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) { mangleType(FL->getType()); // TODO: avoid this copy with careful stream management. - llvm::SmallVector<char,20> Buffer; + llvm::SmallString<20> Buffer; FL->getValue().bitcastToAPInt().toString(Buffer, 16, false); Out.write(Buffer.data(), Buffer.size()); @@ -1475,7 +1486,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) { } case Expr::IntegerLiteralClass: - mangleIntegerLiteral(E->getType(), + mangleIntegerLiteral(E->getType(), llvm::APSInt(cast<IntegerLiteral>(E)->getValue())); break; @@ -1521,24 +1532,27 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) { } } -void CXXNameMangler::mangleTemplateArgs(const TemplateArgumentList &L) { +void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL, + const TemplateArgumentList &AL) { // <template-args> ::= I <template-arg>+ E Out << "I"; - for (unsigned i = 0, e = L.size(); i != e; ++i) - mangleTemplateArg(L[i]); + for (unsigned i = 0, e = AL.size(); i != e; ++i) + mangleTemplateArg(PL.getParam(i), AL[i]); Out << "E"; } -void CXXNameMangler::mangleTemplateArgs(const TemplateArgument *TemplateArgs, +void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL, + const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs) { // <template-args> ::= I <template-arg>+ E Out << "I"; for (unsigned i = 0; i != NumTemplateArgs; ++i) - mangleTemplateArg(TemplateArgs[i]); + mangleTemplateArg(PL.getParam(i), TemplateArgs[i]); Out << "E"; } -void CXXNameMangler::mangleTemplateArg(const TemplateArgument &A) { +void CXXNameMangler::mangleTemplateArg(const NamedDecl *P, + const TemplateArgument &A) { // <template-arg> ::= <type> # type or template // ::= X <expression> E # expression // ::= <expr-primary> # simple expressions @@ -1554,7 +1568,7 @@ void CXXNameMangler::mangleTemplateArg(const TemplateArgument &A) { assert(A.getAsTemplate().getAsTemplateDecl() && "FIXME: Support dependent template names"); mangleName(A.getAsTemplate().getAsTemplateDecl()); - break; + break; case TemplateArgument::Expression: Out << 'X'; mangleExpression(A.getAsExpr()); @@ -1566,18 +1580,33 @@ void CXXNameMangler::mangleTemplateArg(const TemplateArgument &A) { case TemplateArgument::Declaration: { // <expr-primary> ::= L <mangled-name> E # external name - // FIXME: Clang produces AST's where pointer-to-member-function expressions + // Clang produces AST's where pointer-to-member-function expressions // and pointer-to-function expressions are represented as a declaration not - // an expression; this is not how gcc represents them and this changes the - // mangling. + // an expression. We compensate for it here to produce the correct mangling. + NamedDecl *D = cast<NamedDecl>(A.getAsDecl()); + const NonTypeTemplateParmDecl *Parameter = cast<NonTypeTemplateParmDecl>(P); + bool compensateMangling = D->isCXXClassMember() && + !Parameter->getType()->isReferenceType(); + if (compensateMangling) { + Out << 'X'; + mangleOperatorName(OO_Amp, 1); + } + Out << 'L'; // References to external entities use the mangled name; if the name would // not normally be manged then mangle it as unqualified. // // FIXME: The ABI specifies that external names here should have _Z, but // gcc leaves this off. - mangle(cast<NamedDecl>(A.getAsDecl()), "Z"); + if (compensateMangling) + mangle(D, "_Z"); + else + mangle(D, "Z"); Out << 'E'; + + if (compensateMangling) + Out << 'E'; + break; } } @@ -1689,20 +1718,20 @@ bool isStreamCharSpecialization(const ClassTemplateSpecializationDecl *SD, const char (&Str)[StrLen]) { if (!SD->getIdentifier()->isStr(Str)) return false; - + const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); if (TemplateArgs.size() != 2) return false; - + if (!isCharType(TemplateArgs[0].getAsType())) return false; - + if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits")) return false; - + return true; } - + bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { // <substitution> ::= St # ::std:: if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) { @@ -1769,7 +1798,7 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { Out << "So"; return true; } - + // <substitution> ::= Sd # ::std::basic_iostream<char, // ::std::char_traits<char> > if (isStreamCharSpecialization(SD, "basic_iostream")) { @@ -1838,7 +1867,7 @@ void MangleContext::mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, /// \brief Mangles the a thunk with the offset n for the declaration D and /// emits that name to the given output stream. -void MangleContext::mangleThunk(const FunctionDecl *FD, +void MangleContext::mangleThunk(const FunctionDecl *FD, const ThunkAdjustment &ThisAdjustment, llvm::SmallVectorImpl<char> &Res) { assert(!isa<CXXDestructorDecl>(FD) && @@ -1866,7 +1895,7 @@ void MangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *D, /// \brief Mangles the a covariant thunk for the declaration D and emits that /// name to the given output stream. -void +void MangleContext::mangleCovariantThunk(const FunctionDecl *FD, const CovariantThunkAdjustment& Adjustment, llvm::SmallVectorImpl<char> &Res) { diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index cb6a7df68d45..59e8e77756cd 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -268,16 +268,15 @@ llvm::Value *DefaultABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context, llvm::LLVMContext &VMContext) const { - if (CodeGenFunction::hasAggregateLLVMType(Ty)) { + if (CodeGenFunction::hasAggregateLLVMType(Ty)) return ABIArgInfo::getIndirect(0); - } else { - // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs<EnumType>()) - Ty = EnumTy->getDecl()->getIntegerType(); + + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = Ty->getAs<EnumType>()) + Ty = EnumTy->getDecl()->getIntegerType(); - return (Ty->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - } + return (Ty->isPromotableIntegerType() ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } /// X86_32ABIInfo - The X86-32 ABI information. @@ -1367,6 +1366,8 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, // i8* reg_save_area; // }; unsigned neededInt, neededSSE; + + Ty = CGF.getContext().getCanonicalType(Ty); ABIArgInfo AI = classifyArgumentType(Ty, CGF.getContext(), VMContext, neededInt, neededSSE); @@ -1596,6 +1597,80 @@ llvm::Value *PIC16ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, } +// PowerPC-32 + +namespace { +class PPC32TargetCodeGenInfo : public DefaultTargetCodeGenInfo { +public: + int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const { + // This is recovered from gcc output. + return 1; // r1 is the dedicated stack pointer + } + + bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, + llvm::Value *Address) const; +}; + +} + +bool +PPC32TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, + llvm::Value *Address) const { + // This is calculated from the LLVM and GCC tables and verified + // against gcc output. AFAIK all ABIs use the same encoding. + + CodeGen::CGBuilderTy &Builder = CGF.Builder; + llvm::LLVMContext &Context = CGF.getLLVMContext(); + + const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context); + llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4); + llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8); + llvm::Value *Sixteen8 = llvm::ConstantInt::get(i8, 16); + + // 0-31: r0-31, the 4-byte general-purpose registers + for (unsigned I = 0, E = 32; I != E; ++I) { + llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I); + Builder.CreateStore(Four8, Slot); + } + + // 32-63: fp0-31, the 8-byte floating-point registers + for (unsigned I = 32, E = 64; I != E; ++I) { + llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I); + Builder.CreateStore(Eight8, Slot); + } + + // 64-76 are various 4-byte special-purpose registers: + // 64: mq + // 65: lr + // 66: ctr + // 67: ap + // 68-75 cr0-7 + // 76: xer + for (unsigned I = 64, E = 77; I != E; ++I) { + llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I); + Builder.CreateStore(Four8, Slot); + } + + // 77-108: v0-31, the 16-byte vector registers + for (unsigned I = 77, E = 109; I != E; ++I) { + llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I); + Builder.CreateStore(Sixteen8, Slot); + } + + // 109: vrsave + // 110: vscr + // 111: spe_acc + // 112: spefscr + // 113: sfp + for (unsigned I = 109, E = 114; I != E; ++I) { + llvm::Value *Slot = Builder.CreateConstInBoundsGEP1_32(Address, I); + Builder.CreateStore(Four8, Slot); + } + + return false; +} + + // ARM ABI Implementation namespace { @@ -2040,6 +2115,9 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() const { case llvm::Triple::pic16: return *(TheTargetCodeGenInfo = new PIC16TargetCodeGenInfo()); + case llvm::Triple::ppc: + return *(TheTargetCodeGenInfo = new PPC32TargetCodeGenInfo()); + case llvm::Triple::systemz: return *(TheTargetCodeGenInfo = new SystemZTargetCodeGenInfo()); diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp index 62434893f939..b9a3306d53c9 100644 --- a/lib/Driver/Action.cpp +++ b/lib/Driver/Action.cpp @@ -13,8 +13,10 @@ using namespace clang::driver; Action::~Action() { - // FIXME: Free the inputs. The problem is that BindArchAction shares - // inputs; so we can't just walk the inputs. + if (OwnsInputs) { + for (iterator it = begin(), ie = end(); it != ie; ++it) + delete *it; + } } const char *Action::getClassName(ActionClass AC) { diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp index 8a57d14932d3..95805b016b1f 100644 --- a/lib/Driver/ArgList.cpp +++ b/lib/Driver/ArgList.cpp @@ -80,9 +80,9 @@ Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1, Arg *A1 = getLastArgNoClaim(Id1); Arg *A2 = getLastArgNoClaim(Id2); - int A0Idx = A0 ? A0->getIndex() : -1; - int A1Idx = A1 ? A1->getIndex() : -1; - int A2Idx = A2 ? A2->getIndex() : -1; + int A0Idx = A0 ? (int) A0->getIndex() : -1; + int A1Idx = A1 ? (int) A1->getIndex() : -1; + int A2Idx = A2 ? (int) A2->getIndex() : -1; if (A0Idx > A1Idx) { if (A0Idx > A2Idx) @@ -218,23 +218,30 @@ const char *DerivedArgList::MakeArgString(llvm::StringRef Str) const { } Arg *DerivedArgList::MakeFlagArg(const Arg *BaseArg, const Option *Opt) const { - return new FlagArg(Opt, BaseArgs.MakeIndex(Opt->getName()), BaseArg); + Arg *A = new FlagArg(Opt, BaseArgs.MakeIndex(Opt->getName()), BaseArg); + SynthesizedArgs.push_back(A); + return A; } Arg *DerivedArgList::MakePositionalArg(const Arg *BaseArg, const Option *Opt, llvm::StringRef Value) const { - return new PositionalArg(Opt, BaseArgs.MakeIndex(Value), BaseArg); + Arg *A = new PositionalArg(Opt, BaseArgs.MakeIndex(Value), BaseArg); + SynthesizedArgs.push_back(A); + return A; } Arg *DerivedArgList::MakeSeparateArg(const Arg *BaseArg, const Option *Opt, llvm::StringRef Value) const { - return new SeparateArg(Opt, BaseArgs.MakeIndex(Opt->getName(), Value), 1, - BaseArg); + Arg *A = new SeparateArg(Opt, BaseArgs.MakeIndex(Opt->getName(), Value), 1, + BaseArg); + SynthesizedArgs.push_back(A); + return A; } Arg *DerivedArgList::MakeJoinedArg(const Arg *BaseArg, const Option *Opt, llvm::StringRef Value) const { - std::string Joined(Opt->getName()); - Joined += Value; - return new JoinedArg(Opt, BaseArgs.MakeIndex(Joined.c_str()), BaseArg); + Arg *A = new JoinedArg(Opt, BaseArgs.MakeIndex(Opt->getName() + Value.str()), + BaseArg); + SynthesizedArgs.push_back(A); + return A; } diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 64168b4d8395..3257ee55a7b9 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -503,8 +503,11 @@ void Driver::BuildUniversalActions(const ArgList &Args, << types::getTypeName(Act->getType()); ActionList Inputs; - for (unsigned i = 0, e = Archs.size(); i != e; ++i) + for (unsigned i = 0, e = Archs.size(); i != e; ++i) { Inputs.push_back(new BindArchAction(Act, Archs[i])); + if (i != 0) + Inputs.back()->setOwnsInputs(false); + } // Lipo if necessary, we do it this way because we need to set the arch flag // so that -Xarch_ gets overwritten. diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp index 1bd123e220ec..bfeb41a94299 100644 --- a/lib/Driver/Job.cpp +++ b/lib/Driver/Job.cpp @@ -23,8 +23,18 @@ Command::Command(const Action &_Source, const Tool &_Creator, PipedJob::PipedJob() : Job(PipedJobClass) {} +PipedJob::~PipedJob() { + for (iterator it = begin(), ie = end(); it != ie; ++it) + delete *it; +} + JobList::JobList() : Job(JobListClass) {} +JobList::~JobList() { + for (iterator it = begin(), ie = end(); it != ie; ++it) + delete *it; +} + void Job::addCommand(Command *C) { if (PipedJob *PJ = dyn_cast<PipedJob>(this)) PJ->addCommand(C); diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 63cf98d3da5d..3bf1fab1c27d 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -35,8 +35,9 @@ #include "llvm/System/Path.h" using namespace clang; -ASTUnit::ASTUnit(bool _MainFileIsAST) - : MainFileIsAST(_MainFileIsAST), ConcurrencyCheckValue(CheckUnlocked) { +ASTUnit::ASTUnit(Diagnostic &Diag, bool _MainFileIsAST) + : SourceMgr(Diag), MainFileIsAST(_MainFileIsAST), + ConcurrencyCheckValue(CheckUnlocked) { } ASTUnit::~ASTUnit() { ConcurrencyCheckValue = CheckLocked; @@ -146,7 +147,7 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, RemappedFile *RemappedFiles, unsigned NumRemappedFiles, bool CaptureDiagnostics) { - llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true)); + llvm::OwningPtr<ASTUnit> AST(new ASTUnit(Diags, true)); AST->OnlyLocalDecls = OnlyLocalDecls; AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager())); @@ -311,7 +312,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, "FIXME: AST inputs not yet supported here!"); // Create the AST unit. - AST.reset(new ASTUnit(false)); + AST.reset(new ASTUnit(Diags, false)); AST->OnlyLocalDecls = OnlyLocalDecls; AST->OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second; diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp index c845d56f4ec1..02d6cec8fcab 100644 --- a/lib/Frontend/CacheTokens.cpp +++ b/lib/Frontend/CacheTokens.cpp @@ -196,6 +196,11 @@ class PTHWriter { Out.write(Ptr, NumBytes); } + void EmitString(llvm::StringRef V) { + ::Emit16(Out, V.size()); + EmitBuf(V.data(), V.size()); + } + /// EmitIdentifierTable - Emits two tables to the PTH file. The first is /// a hashtable mapping from identifier strings to persistent IDs. /// The second is a straight table mapping from persistent IDs to string data @@ -214,7 +219,7 @@ public: : Out(out), PP(pp), idcount(0), CurStrOffset(0) {} PTHMap &getPM() { return PM; } - void GeneratePTH(const std::string *MainFile = 0); + void GeneratePTH(const std::string &MainFile); }; } // end anonymous namespace @@ -295,7 +300,7 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) { } if (Tok.is(tok::identifier)) { - Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok)); + PP.LookUpIdentifierInfo(Tok); EmitToken(Tok); continue; } @@ -321,7 +326,6 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) { } IdentifierInfo* II = PP.LookUpIdentifierInfo(Tok); - Tok.setIdentifierInfo(II); tok::PPKeywordKind K = II->getPPKeywordID(); ParsingPreprocessorDirective = true; @@ -344,7 +348,7 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) { L.setParsingPreprocessorDirective(false); assert(!Tok.isAtStartOfLine()); if (Tok.is(tok::identifier)) - Tok.setIdentifierInfo(PP.LookUpIdentifierInfo(Tok)); + PP.LookUpIdentifierInfo(Tok); break; } @@ -436,7 +440,7 @@ Offset PTHWriter::EmitCachedSpellings() { return SpellingsOff; } -void PTHWriter::GeneratePTH(const std::string *MainFile) { +void PTHWriter::GeneratePTH(const std::string &MainFile) { // Generate the prologue. Out << "cfe-pth"; Emit32(PTHManager::Version); @@ -447,9 +451,8 @@ void PTHWriter::GeneratePTH(const std::string *MainFile) { Emit32(0); // Write the name of the MainFile. - if (MainFile && !MainFile->empty()) { - Emit16(MainFile->length()); - EmitBuf(MainFile->data(), MainFile->length()); + if (!MainFile.empty()) { + EmitString(MainFile); } else { // String with 0 bytes. Emit16(0); @@ -471,7 +474,7 @@ void PTHWriter::GeneratePTH(const std::string *MainFile) { if (!P.isAbsolute()) continue; - const llvm::MemoryBuffer *B = C.getBuffer(); + const llvm::MemoryBuffer *B = C.getBuffer(PP.getDiagnostics()); if (!B) continue; FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User); @@ -533,15 +536,8 @@ void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) { const SourceManager &SrcMgr = PP.getSourceManager(); const FileEntry *MainFile = SrcMgr.getFileEntryForID(SrcMgr.getMainFileID()); llvm::sys::Path MainFilePath(MainFile->getName()); - std::string MainFileName; - if (!MainFilePath.isAbsolute()) { - llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory(); - P.appendComponent(MainFilePath.str()); - MainFileName = P.str(); - } else { - MainFileName = MainFilePath.str(); - } + MainFilePath.makeAbsolute(); // Create the PTHWriter. PTHWriter PW(*OS, PP); @@ -558,18 +554,18 @@ void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) { // Generate the PTH file. PP.getFileManager().removeStatCache(StatCache); - PW.GeneratePTH(&MainFileName); + PW.GeneratePTH(MainFilePath.str()); } //===----------------------------------------------------------------------===// +namespace { class PTHIdKey { public: const IdentifierInfo* II; uint32_t FileOffset; }; -namespace { class PTHIdentifierTableTrait { public: typedef PTHIdKey* key_type; diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 25b804aba7fc..3bc566192965 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -185,7 +185,7 @@ void CompilerInstance::createFileManager() { // Source Manager void CompilerInstance::createSourceManager() { - SourceMgr.reset(new SourceManager()); + SourceMgr.reset(new SourceManager(getDiagnostics())); } // Preprocessor @@ -294,6 +294,8 @@ void CompilerInstance::createCodeCompletionConsumer() { getFrontendOpts().DebugCodeCompletionPrinter, getFrontendOpts().ShowMacrosInCodeCompletion, llvm::outs())); + if (!CompletionConsumer) + return; if (CompletionConsumer->isOutputBinary() && llvm::sys::Program::ChangeStdoutToBinary()) { diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 64a42bc0ec40..5798f2f71005 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -474,6 +474,8 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-fcatch-undefined-behavior"); if (Opts.WritableStrings) Res.push_back("-fwritable-strings"); + if (Opts.ConstStrings) + Res.push_back("-Wwrite-strings"); if (!Opts.LaxVectorConversions) Res.push_back("-fno-lax-vector-conversions"); if (Opts.AltiVec) @@ -1162,6 +1164,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings); Opts.Microsoft = Args.hasArg(OPT_fms_extensions); Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings); + Opts.ConstStrings = Args.hasArg(OPT_Wwrite_strings); if (Args.hasArg(OPT_fno_lax_vector_conversions)) Opts.LaxVectorConversions = 0; if (Args.hasArg(OPT_fno_threadsafe_statics)) diff --git a/lib/Frontend/HTMLDiagnostics.cpp b/lib/Frontend/HTMLDiagnostics.cpp index f695254cb466..da99cb8b7b89 100644 --- a/lib/Frontend/HTMLDiagnostics.cpp +++ b/lib/Frontend/HTMLDiagnostics.cpp @@ -40,13 +40,13 @@ class HTMLDiagnostics : public PathDiagnosticClient { std::vector<const PathDiagnostic*> BatchedDiags; public: HTMLDiagnostics(const std::string& prefix, const Preprocessor &pp); - + virtual ~HTMLDiagnostics() { FlushDiagnostics(NULL); } - + virtual void FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade); virtual void HandlePathDiagnostic(const PathDiagnostic* D); - + virtual llvm::StringRef getName() const { return "HTMLDiagnostics"; } @@ -108,7 +108,7 @@ HTMLDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade) ReportDiag(*D, FilesMade); delete D; } - + BatchedDiags.clear(); } @@ -294,7 +294,7 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, llvm::raw_fd_ostream os(H.c_str(), ErrorMsg); if (!ErrorMsg.empty()) { - (llvm::errs() << "warning: could not create file '" << F.str() + (llvm::errs() << "warning: could not create file '" << F.str() << "'\n").flush(); return; } @@ -439,10 +439,10 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, { FullSourceLoc L = MP->getLocation().asLocation().getInstantiationLoc(); assert(L.isFileID()); - std::pair<const char*, const char*> BufferInfo = L.getBufferData(); - const char* MacroName = L.getDecomposedLoc().second + BufferInfo.first; - Lexer rawLexer(L, PP.getLangOptions(), BufferInfo.first, - MacroName, BufferInfo.second); + llvm::StringRef BufferInfo = L.getBufferData(); + const char* MacroName = L.getDecomposedLoc().second + BufferInfo.data(); + Lexer rawLexer(L, PP.getLangOptions(), BufferInfo.begin(), + MacroName, BufferInfo.end()); Token TheTok; rawLexer.LexFromRawLexer(TheTok); @@ -502,19 +502,13 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, } static void EmitAlphaCounter(llvm::raw_ostream& os, unsigned n) { - llvm::SmallVector<char, 10> buf; - - do { - unsigned x = n % ('z' - 'a'); - buf.push_back('a' + x); - n = n / ('z' - 'a'); - } while (n); + unsigned x = n % ('z' - 'a'); + n /= 'z' - 'a'; - assert(!buf.empty()); + if (n > 0) + EmitAlphaCounter(os, n); - for (llvm::SmallVectorImpl<char>::reverse_iterator I=buf.rbegin(), - E=buf.rend(); I!=E; ++I) - os << *I; + os << char('a' + x); } unsigned HTMLDiagnostics::ProcessMacroPiece(llvm::raw_ostream& os, diff --git a/lib/Frontend/Makefile b/lib/Frontend/Makefile index a630b0133632..9e1a864d96e3 100644 --- a/lib/Frontend/Makefile +++ b/lib/Frontend/Makefile @@ -11,7 +11,7 @@ LEVEL = ../../../.. LIBRARYNAME := clangFrontend BUILD_ARCHIVE = 1 -CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include +CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include include $(LEVEL)/Makefile.common diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 267f4c158508..49eb2a0e600d 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -2628,7 +2628,7 @@ IdentifierInfo *PCHReader::DecodeIdentifierInfo(unsigned ID) { unsigned StrLen = (((unsigned) StrLenPtr[0]) | (((unsigned) StrLenPtr[1]) << 8)) - 1; IdentifiersLoaded[ID - 1] - = &PP->getIdentifierTable().get(Str, Str + StrLen); + = &PP->getIdentifierTable().get(Str, StrLen); } return IdentifiersLoaded[ID - 1]; diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index a3f5eac480cd..f847becb15b8 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -131,10 +131,11 @@ void PCHDeclReader::VisitTagDecl(TagDecl *TD) { TD->setTagKind((TagDecl::TagKind)Record[Idx++]); TD->setDefinition(Record[Idx++]); TD->setEmbeddedInDeclarator(Record[Idx++]); - TD->setTypedefForAnonDecl( - cast_or_null<TypedefDecl>(Reader.GetDecl(Record[Idx++]))); TD->setRBraceLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); TD->setTagKeywordLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + // FIXME: maybe read optional qualifier and its range. + TD->setTypedefForAnonDecl( + cast_or_null<TypedefDecl>(Reader.GetDecl(Record[Idx++]))); } void PCHDeclReader::VisitEnumDecl(EnumDecl *ED) { @@ -168,6 +169,7 @@ void PCHDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) { TypeSourceInfo *TInfo = Reader.GetTypeSourceInfo(Record, Idx); if (TInfo) DD->setTypeSourceInfo(TInfo); + // FIXME: read optional qualifier and its range. } void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) { @@ -411,6 +413,7 @@ void PCHDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) { void PCHDeclReader::VisitParmVarDecl(ParmVarDecl *PD) { VisitVarDecl(PD); PD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]); + PD->setHasInheritedDefaultArg(Record[Idx++]); } void PCHDeclReader::VisitFileScopeAsmDecl(FileScopeAsmDecl *AD) { diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index eed3cc1a5b3d..c256b4103a7d 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -565,7 +565,7 @@ void PCHWriter::WriteBlockInfoBlock() { RECORD(EXT_VECTOR_DECLS); RECORD(COMMENT_RANGES); RECORD(VERSION_CONTROL_BRANCH_REVISION); - + // SourceManager Block. BLOCK(SOURCE_MANAGER_BLOCK); RECORD(SM_SLOC_FILE_ENTRY); @@ -710,24 +710,17 @@ void PCHWriter::WriteMetadata(ASTContext &Context, const char *isysroot) { unsigned FileAbbrevCode = Stream.EmitAbbrev(FileAbbrev); llvm::sys::Path MainFilePath(MainFile->getName()); - std::string MainFileName; - if (!MainFilePath.isAbsolute()) { - llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory(); - P.appendComponent(MainFilePath.str()); - MainFileName = P.str(); - } else { - MainFileName = MainFilePath.str(); - } + MainFilePath.makeAbsolute(); - const char *MainFileNameStr = MainFileName.c_str(); + const char *MainFileNameStr = MainFilePath.c_str(); MainFileNameStr = adjustFilenameForRelocatablePCH(MainFileNameStr, isysroot); RecordData Record; Record.push_back(pch::ORIGINAL_FILE_NAME); Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr); } - + // Repository branch/version information. BitCodeAbbrev *RepoAbbrev = new BitCodeAbbrev(); RepoAbbrev->Add(BitCodeAbbrevOp(pch::VERSION_CONTROL_BRANCH_REVISION)); @@ -758,9 +751,9 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) { Record.push_back(LangOpts.ObjC1); // Objective-C 1 support enabled. Record.push_back(LangOpts.ObjC2); // Objective-C 2 support enabled. - Record.push_back(LangOpts.ObjCNonFragileABI); // Objective-C + Record.push_back(LangOpts.ObjCNonFragileABI); // Objective-C // modern abi enabled. - Record.push_back(LangOpts.ObjCNonFragileABI2); // Objective-C enhanced + Record.push_back(LangOpts.ObjCNonFragileABI2); // Objective-C enhanced // modern abi enabled. Record.push_back(LangOpts.PascalStrings); // Allow Pascal strings @@ -1048,7 +1041,7 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, for (unsigned I = 1, N = SourceMgr.sloc_entry_size(); I != N; ++I) { // Get this source location entry. const SrcMgr::SLocEntry *SLoc = &SourceMgr.getSLocEntry(I); - + // Record the offset of this source-location entry. SLocEntryOffsets.push_back(Stream.GetCurrentBitNo()); @@ -1079,13 +1072,8 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, // Turn the file name into an absolute path, if it isn't already. const char *Filename = Content->Entry->getName(); llvm::sys::Path FilePath(Filename, strlen(Filename)); - std::string FilenameStr; - if (!FilePath.isAbsolute()) { - llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory(); - P.appendComponent(FilePath.str()); - FilenameStr = P.str(); - Filename = FilenameStr.c_str(); - } + FilePath.makeAbsolute(); + Filename = FilePath.c_str(); Filename = adjustFilenameForRelocatablePCH(Filename, isysroot); Stream.EmitRecordWithBlob(SLocFileAbbrv, Record, Filename); @@ -1101,7 +1089,8 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, // We add one to the size so that we capture the trailing NULL // that is required by llvm::MemoryBuffer::getMemBuffer (on // the reader side). - const llvm::MemoryBuffer *Buffer = Content->getBuffer(); + const llvm::MemoryBuffer *Buffer + = Content->getBuffer(PP.getDiagnostics()); const char *Name = Buffer->getBufferIdentifier(); Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record, llvm::StringRef(Name, strlen(Name) + 1)); @@ -1998,9 +1987,9 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls, // Build a record containing all of the static unused functions in this file. RecordData UnusedStaticFuncs; - for (unsigned i=0, e = SemaRef.UnusedStaticFuncs.size(); i !=e; ++i) + for (unsigned i=0, e = SemaRef.UnusedStaticFuncs.size(); i !=e; ++i) AddDeclRef(SemaRef.UnusedStaticFuncs[i], UnusedStaticFuncs); - + // Build a record containing all of the locally-scoped external // declarations in this header file. Generally, this record will be // empty. @@ -2063,7 +2052,7 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls, WriteDecl(Context, DOT.getDecl()); } Stream.ExitBlock(); - + WritePreprocessor(PP); WriteMethodPool(SemaRef); WriteIdentifierTable(PP); @@ -2105,7 +2094,7 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls, // Write the record containing unused static functions. if (!UnusedStaticFuncs.empty()) Stream.EmitRecord(pch::UNUSED_STATIC_FUNCS, UnusedStaticFuncs); - + // Write the record containing locally-scoped external definitions. if (!LocallyScopedExternalDecls.empty()) Stream.EmitRecord(pch::LOCALLY_SCOPED_EXTERNAL_DECLS, @@ -2206,7 +2195,7 @@ void PCHWriter::AddTypeSourceInfo(TypeSourceInfo *TInfo, RecordData &Record) { AddTypeRef(TInfo->getType(), Record); TypeLocWriter TLW(*this, Record); for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) - TLW.Visit(TL); + TLW.Visit(TL); } void PCHWriter::AddTypeRef(QualType T, RecordData &Record) { @@ -2227,14 +2216,14 @@ void PCHWriter::AddTypeRef(QualType T, RecordData &Record) { ID = NextTypeID++; DeclTypesToEmit.push(T); } - + // Encode the type qualifiers in the type reference. Record.push_back((ID << Qualifiers::FastWidth) | FastQuals); return; } assert(!T.hasLocalQualifiers()); - + if (const BuiltinType *BT = dyn_cast<BuiltinType>(T.getTypePtr())) { pch::TypeID ID = 0; switch (BT->getKind()) { diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index 0774797463e0..7917280295ad 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -127,9 +127,10 @@ void PCHDeclWriter::VisitTagDecl(TagDecl *D) { Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding Record.push_back(D->isDefinition()); Record.push_back(D->isEmbeddedInDeclarator()); - Writer.AddDeclRef(D->getTypedefForAnonDecl(), Record); Writer.AddSourceLocation(D->getRBraceLoc(), Record); Writer.AddSourceLocation(D->getTagKeywordLoc(), Record); + // FIXME: maybe write optional qualifier and its range. + Writer.AddDeclRef(D->getTypedefForAnonDecl(), Record); } void PCHDeclWriter::VisitEnumDecl(EnumDecl *D) { @@ -165,6 +166,7 @@ void PCHDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) { void PCHDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) { VisitValueDecl(D); Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); + // FIXME: write optional qualifier and its range. } void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) { @@ -398,6 +400,7 @@ void PCHDeclWriter::VisitImplicitParamDecl(ImplicitParamDecl *D) { void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { VisitVarDecl(D); Record.push_back(D->getObjCDeclQualifier()); // FIXME: stable encoding + Record.push_back(D->hasInheritedDefaultArg()); Code = pch::DECL_PARM_VAR; @@ -412,7 +415,8 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { D->getPCHLevel() == 0 && D->getStorageClass() == 0 && !D->hasCXXDirectInitializer() && // Can params have this ever? - D->getObjCDeclQualifier() == 0) + D->getObjCDeclQualifier() == 0 && + !D->hasInheritedDefaultArg()) AbbrevToUse = Writer.getParmVarDeclAbbrev(); // Check things we know are true of *every* PARM_VAR_DECL, which is more than @@ -496,6 +500,7 @@ void PCHWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // HasInit // ParmVarDecl Abv->Add(BitCodeAbbrevOp(0)); // ObjCDeclQualifier + Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedDefaultArg ParmVarDeclAbbrev = Stream.EmitAbbrev(Abv); } diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index be5bb0dade87..44e0e1390604 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -61,7 +61,7 @@ static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI, if (MI.tokens_empty() || !MI.tokens_begin()->hasLeadingSpace()) OS << ' '; - llvm::SmallVector<char, 128> SpellingBuffer; + llvm::SmallString<128> SpellingBuffer; for (MacroInfo::tokens_iterator I = MI.tokens_begin(), E = MI.tokens_end(); I != E; ++I) { if (I->hasLeadingSpace()) diff --git a/lib/Frontend/RewriteMacros.cpp b/lib/Frontend/RewriteMacros.cpp index 0bcbd4ff0ee4..954e8e23cac7 100644 --- a/lib/Frontend/RewriteMacros.cpp +++ b/lib/Frontend/RewriteMacros.cpp @@ -79,7 +79,7 @@ static void LexRawTokensFromMainFile(Preprocessor &PP, // up the indentifier info. This is important for equality comparison of // identifier tokens. if (RawTok.is(tok::identifier) && !RawTok.getIdentifierInfo()) - RawTok.setIdentifierInfo(PP.LookUpIdentifierInfo(RawTok)); + PP.LookUpIdentifierInfo(RawTok); RawTokens.push_back(RawTok); } while (RawTok.isNot(tok::eof)); diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index 378b4225c53e..79aecceb70d0 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -89,6 +89,7 @@ namespace { FunctionDecl *MsgSendFpretFunctionDecl; FunctionDecl *GetClassFunctionDecl; FunctionDecl *GetMetaClassFunctionDecl; + FunctionDecl *GetSuperClassFunctionDecl; FunctionDecl *SelGetUidFunctionDecl; FunctionDecl *CFStringFunctionDecl; FunctionDecl *SuperContructorFunctionDecl; @@ -133,7 +134,8 @@ namespace { llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDeclsPtrSet; llvm::DenseMap<ValueDecl *, unsigned> BlockByRefDeclNo; llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls; - + llvm::SmallPtrSet<VarDecl *, 8> ImportedLocalExternalDecls; + llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs; // This maps a property to it's assignment statement. @@ -271,7 +273,7 @@ namespace { void RewriteTypeOfDecl(VarDecl *VD); void RewriteObjCQualifiedInterfaceTypes(Expr *E); bool needToScanForQualifiers(QualType T); - ObjCInterfaceDecl *isSuperReceiver(Expr *recExpr); + bool isSuperReceiver(Expr *recExpr); QualType getSuperStructType(); QualType getConstantStringStructType(); bool BufferContainsPPDirectives(const char *startBuf, const char *endBuf); @@ -323,6 +325,7 @@ namespace { void SynthMsgSendSuperStretFunctionDecl(); void SynthGetClassFunctionDecl(); void SynthGetMetaClassFunctionDecl(); + void SynthGetSuperClassFunctionDecl(); void SynthSelGetUidFunctionDecl(); void SynthSuperContructorFunctionDecl(); @@ -370,6 +373,7 @@ namespace { void RewriteByRefVar(VarDecl *VD); std::string SynthesizeByrefCopyDestroyHelper(VarDecl *VD, int flag); Stmt *RewriteBlockDeclRefExpr(Expr *VD); + Stmt *RewriteLocalVariableExternalStorage(DeclRefExpr *DRE); void RewriteBlockPointerFunctionArgs(FunctionDecl *FD); std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, @@ -510,6 +514,7 @@ void RewriteObjC::Initialize(ASTContext &context) { MsgSendFpretFunctionDecl = 0; GetClassFunctionDecl = 0; GetMetaClassFunctionDecl = 0; + GetSuperClassFunctionDecl = 0; SelGetUidFunctionDecl = 0; CFStringFunctionDecl = 0; ConstantStringClassReference = 0; @@ -572,6 +577,8 @@ void RewriteObjC::Initialize(ASTContext &context) { Preamble += "(struct objc_object *, struct objc_selector *, ...);\n"; Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getClass"; Preamble += "(const char *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *class_getSuperclass"; + Preamble += "(struct objc_class *);\n"; Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getMetaClass"; Preamble += "(const char *);\n"; Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_throw(struct objc_object *);\n"; @@ -699,9 +706,9 @@ void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) { void RewriteObjC::RewriteInclude() { SourceLocation LocStart = SM->getLocForStartOfFile(MainFileID); - std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID); - const char *MainBufStart = MainBuf.first; - const char *MainBufEnd = MainBuf.second; + llvm::StringRef MainBuf = SM->getBufferData(MainFileID); + const char *MainBufStart = MainBuf.begin(); + const char *MainBufEnd = MainBuf.end(); size_t ImportLen = strlen("import"); // Loop over the whole file, looking for includes. @@ -724,9 +731,9 @@ void RewriteObjC::RewriteInclude() { } void RewriteObjC::RewriteTabs() { - std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID); - const char *MainBufStart = MainBuf.first; - const char *MainBufEnd = MainBuf.second; + llvm::StringRef MainBuf = SM->getBufferData(MainFileID); + const char *MainBufStart = MainBuf.begin(); + const char *MainBufEnd = MainBuf.end(); // Loop over the whole file, looking for tabs. for (const char *BufPtr = MainBufStart; BufPtr != MainBufEnd; ++BufPtr) { @@ -966,8 +973,6 @@ void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) { } void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) { - std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID); - SourceLocation LocStart = PDecl->getLocStart(); // FIXME: handle protocol headers that are declared across multiple lines. @@ -2491,6 +2496,23 @@ void RewriteObjC::SynthGetClassFunctionDecl() { FunctionDecl::Extern, false); } +// SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls); +void RewriteObjC::SynthGetSuperClassFunctionDecl() { + IdentifierInfo *getSuperClassIdent = + &Context->Idents.get("class_getSuperclass"); + llvm::SmallVector<QualType, 16> ArgTys; + ArgTys.push_back(Context->getObjCClassType()); + QualType getClassType = Context->getFunctionType(Context->getObjCClassType(), + &ArgTys[0], ArgTys.size(), + false /*isVariadic*/, 0, + false, false, 0, 0, false, + CC_Default); + GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + getSuperClassIdent, getClassType, 0, + FunctionDecl::Extern, false); +} + // SynthGetMetaClassFunctionDecl - id objc_getClass(const char *name); void RewriteObjC::SynthGetMetaClassFunctionDecl() { IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass"); @@ -2551,18 +2573,10 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { return cast; } -ObjCInterfaceDecl *RewriteObjC::isSuperReceiver(Expr *recExpr) { +bool RewriteObjC::isSuperReceiver(Expr *recExpr) { // check if we are sending a message to 'super' - if (!CurMethodDef || !CurMethodDef->isInstanceMethod()) return 0; - - if (ObjCSuperExpr *Super = dyn_cast<ObjCSuperExpr>(recExpr)) { - const ObjCObjectPointerType *OPT = - Super->getType()->getAs<ObjCObjectPointerType>(); - assert(OPT); - const ObjCInterfaceType *IT = OPT->getInterfaceType(); - return IT->getDecl(); - } - return 0; + if (!CurMethodDef || !CurMethodDef->isInstanceMethod()) return false; + return isa<ObjCSuperExpr>(recExpr); } // struct objc_super { struct objc_object *receiver; struct objc_class *super; }; @@ -2640,6 +2654,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, SynthMsgSendFpretFunctionDecl(); if (!GetClassFunctionDecl) SynthGetClassFunctionDecl(); + if (!GetSuperClassFunctionDecl) + SynthGetSuperClassFunctionDecl(); if (!GetMetaClassFunctionDecl) SynthGetMetaClassFunctionDecl(); @@ -2669,8 +2685,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); - ObjCInterfaceDecl *SuperDecl = - CurMethodDef->getClassInterface()->getSuperClass(); + ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface(); llvm::SmallVector<Expr*, 4> InitExprs; @@ -2683,19 +2698,31 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, SourceLocation())) ); // set the 'receiver'. + // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) llvm::SmallVector<Expr*, 8> ClsExprs; QualType argType = Context->getPointerType(Context->CharTy); ClsExprs.push_back(StringLiteral::Create(*Context, - SuperDecl->getIdentifier()->getNameStart(), - SuperDecl->getIdentifier()->getLength(), + ClassDecl->getIdentifier()->getNameStart(), + ClassDecl->getIdentifier()->getLength(), false, argType, SourceLocation())); CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl, &ClsExprs[0], ClsExprs.size(), StartLoc, EndLoc); + // (Class)objc_getClass("CurrentClass") + CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context, + Context->getObjCClassType(), + CastExpr::CK_Unknown, Cls); + ClsExprs.clear(); + ClsExprs.push_back(ArgExpr); + Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, + &ClsExprs[0], ClsExprs.size(), + StartLoc, EndLoc); + + // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) // To turn off a warning, type-cast to 'id' - InitExprs.push_back( // set 'super class', using objc_getClass(). + InitExprs.push_back( // set 'super class', using class_getSuperclass(). NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), CastExpr::CK_Unknown, Cls)); @@ -2755,12 +2782,12 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, } else { // instance message. Expr *recExpr = Exp->getReceiver(); - if (ObjCInterfaceDecl *SuperDecl = isSuperReceiver(recExpr)) { + if (isSuperReceiver(recExpr)) { MsgSendFlavor = MsgSendSuperFunctionDecl; if (MsgSendStretFlavor) MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); - + ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface(); llvm::SmallVector<Expr*, 4> InitExprs; InitExprs.push_back( @@ -2770,20 +2797,32 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, Context->getObjCIdType(), SourceLocation())) ); // set the 'receiver'. - + + // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) llvm::SmallVector<Expr*, 8> ClsExprs; QualType argType = Context->getPointerType(Context->CharTy); ClsExprs.push_back(StringLiteral::Create(*Context, - SuperDecl->getIdentifier()->getNameStart(), - SuperDecl->getIdentifier()->getLength(), + ClassDecl->getIdentifier()->getNameStart(), + ClassDecl->getIdentifier()->getLength(), false, argType, SourceLocation())); CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, &ClsExprs[0], ClsExprs.size(), StartLoc, EndLoc); + // (Class)objc_getClass("CurrentClass") + CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context, + Context->getObjCClassType(), + CastExpr::CK_Unknown, Cls); + ClsExprs.clear(); + ClsExprs.push_back(ArgExpr); + Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, + &ClsExprs[0], ClsExprs.size(), + StartLoc, EndLoc); + + // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) // To turn off a warning, type-cast to 'id' InitExprs.push_back( - // set 'super class', using objc_getClass(). + // set 'super class', using class_getSuperclass(). NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), CastExpr::CK_Unknown, Cls)); // struct objc_super @@ -3986,6 +4025,12 @@ void RewriteObjC::RewriteByRefString(std::string &ResultStr, "_" + utostr(BlockByRefDeclNo[VD]) ; } +static bool HasLocalVariableExternalStorage(ValueDecl *VD) { + if (VarDecl *Var = dyn_cast<VarDecl>(VD)) + return (Var->isFunctionOrMethodVarDecl() && !Var->hasLocalStorage()); + return false; +} + std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, const char *funcName, std::string Tag) { @@ -4060,7 +4105,10 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, } else { std::string Name = (*I)->getNameAsString(); - (*I)->getType().getAsStringInternal(Name, Context->PrintingPolicy); + QualType QT = (*I)->getType(); + if (HasLocalVariableExternalStorage(*I)) + QT = Context->getPointerType(QT); + QT.getAsStringInternal(Name, Context->PrintingPolicy); S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by copy\n"; } @@ -4149,8 +4197,11 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, S += "struct __block_impl *"; Constructor += ", void *" + ArgName; } else { - (*I)->getType().getAsStringInternal(FieldName, Context->PrintingPolicy); - (*I)->getType().getAsStringInternal(ArgName, Context->PrintingPolicy); + QualType QT = (*I)->getType(); + if (HasLocalVariableExternalStorage(*I)) + QT = Context->getPointerType(QT); + QT.getAsStringInternal(FieldName, Context->PrintingPolicy); + QT.getAsStringInternal(ArgName, Context->PrintingPolicy); Constructor += ", " + ArgName; } S += FieldName + ";\n"; @@ -4380,10 +4431,19 @@ void RewriteObjC::GetBlockDeclRefExprs(Stmt *S) { GetBlockDeclRefExprs(*CI); } // Handle specific things. - if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S)) + if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S)) { // FIXME: Handle enums. if (!isa<FunctionDecl>(CDRE->getDecl())) BlockDeclRefs.push_back(CDRE); + } + else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) + if (HasLocalVariableExternalStorage(DRE->getDecl())) { + BlockDeclRefExpr *BDRE = + new (Context)BlockDeclRefExpr(DRE->getDecl(), DRE->getType(), + DRE->getLocation(), false); + BlockDeclRefs.push_back(BDRE); + } + return; } @@ -4406,10 +4466,16 @@ void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S, } // Handle specific things. - if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S)) + if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S)) { if (!isa<FunctionDecl>(CDRE->getDecl()) && !InnerContexts.count(CDRE->getDecl()->getDeclContext())) InnerBlockDeclRefs.push_back(CDRE); + } + else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) { + if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) + if (Var->isFunctionOrMethodVarDecl()) + ImportedLocalExternalDecls.insert(Var); + } return; } @@ -4572,6 +4638,23 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) { return PE; } +// Rewrites the imported local variable V with external storage +// (static, extern, etc.) as *V +// +Stmt *RewriteObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) { + ValueDecl *VD = DRE->getDecl(); + if (VarDecl *Var = dyn_cast<VarDecl>(VD)) + if (!ImportedLocalExternalDecls.count(Var)) + return DRE; + Expr *Exp = new (Context) UnaryOperator(DRE, UnaryOperator::Deref, + DRE->getType(), DRE->getLocation()); + // Need parens to enforce precedence. + ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), + Exp); + ReplaceStmt(DRE, PE); + return PE; +} + void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) { SourceLocation LocStart = CE->getLParenLoc(); SourceLocation LocEnd = CE->getRParenLoc(); @@ -5091,6 +5174,13 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, } else { FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString()); Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); + if (HasLocalVariableExternalStorage(*I)) { + QualType QT = (*I)->getType(); + QT = Context->getPointerType(QT); + Exp = new (Context) UnaryOperator(Exp, UnaryOperator::AddrOf, QT, + SourceLocation()); + } + } InitExprs.push_back(Exp); } @@ -5205,11 +5295,12 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { llvm::SmallVector<BlockDeclRefExpr *, 8> InnerBlockDeclRefs; llvm::SmallPtrSet<const DeclContext *, 8> InnerContexts; InnerContexts.insert(BE->getBlockDecl()); + ImportedLocalExternalDecls.clear(); GetInnerBlockDeclRefExprs(BE->getBody(), InnerBlockDeclRefs, InnerContexts); // Rewrite the block body in place. RewriteFunctionBodyOrGlobalInitializer(BE->getBody()); - + ImportedLocalExternalDecls.clear(); // Now we snarf the rewritten text and stash it away for later use. std::string Str = Rewrite.getRewrittenText(BE->getSourceRange()); RewrittenBlockExprs[BE] = Str; @@ -5392,6 +5483,8 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { ValueDecl *VD = DRE->getDecl(); if (VD->hasAttr<BlocksAttr>()) return RewriteBlockDeclRefExpr(DRE); + if (HasLocalVariableExternalStorage(VD)) + return RewriteLocalVariableExternalStorage(DRE); } if (CallExpr *CE = dyn_cast<CallExpr>(S)) { diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index d2aa5480b4b1..24d51e2c78dc 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -119,19 +119,19 @@ void TextDiagnosticPrinter::HighlightRange(const SourceRange &R, } assert(StartColNo <= EndColNo && "Invalid range!"); - + // Pick the first non-whitespace column. while (StartColNo < SourceLine.size() && (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t')) ++StartColNo; - + // Pick the last non-whitespace column. if (EndColNo > SourceLine.size()) EndColNo = SourceLine.size(); while (EndColNo-1 && (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t')) --EndColNo; - + // If the start/end passed each other, then we are trying to highlight a range // that just exists in whitespace, which must be some sort of other bug. assert(StartColNo <= EndColNo && "Trying to highlight whitespace??"); @@ -300,10 +300,10 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, if (E.isMacroID()) E = SM.getImmediateSpellingLoc(E); Ranges[i] = SourceRange(S, E); } - + // Get the pretty name, according to #line directives etc. PresumedLoc PLoc = SM.getPresumedLoc(Loc); - + // If this diagnostic is not in the main file, print out the "included from" // lines. if (LastWarningLoc != PLoc.getIncludeLoc()) { @@ -330,8 +330,10 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, unsigned FileOffset = LocInfo.second; // Get information about the buffer it points into. - std::pair<const char*, const char*> BufferInfo = SM.getBufferData(FID); - const char *BufStart = BufferInfo.first; + bool Invalid = false; + const char *BufStart = SM.getBufferData(FID, &Invalid).data(); + if (Invalid) + return; unsigned ColNo = SM.getColumnNumber(FID, FileOffset); unsigned CaretEndColNo @@ -563,7 +565,7 @@ static unsigned findEndOfWord(unsigned Start, // We have the start of a balanced punctuation sequence (quotes, // parentheses, etc.). Determine the full sequence is. - llvm::SmallVector<char, 16> PunctuationEndStack; + llvm::SmallString<16> PunctuationEndStack; PunctuationEndStack.push_back(EndPunct); while (End < Length && !PunctuationEndStack.empty()) { if (Str[End] == PunctuationEndStack.back()) @@ -704,7 +706,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, if (DiagOpts->ShowLocation) { if (DiagOpts->ShowColors) OS.changeColor(savedColor, true); - + // Emit a Visual Studio compatible line number syntax. if (LangOpts && LangOpts->Microsoft) { OS << PLoc.getFilename() << '(' << LineNo << ')'; diff --git a/lib/Headers/smmintrin.h b/lib/Headers/smmintrin.h index b3bdac68855e..972b2e0d3038 100644 --- a/lib/Headers/smmintrin.h +++ b/lib/Headers/smmintrin.h @@ -199,6 +199,143 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) /* Extract a float from X at index N into the first index of the return. */ #define _MM_PICK_OUT_PS(X, N) _mm_insert_ps (_mm_setzero_ps(), (X), \ _MM_MK_INSERTPS_NDX((N), 0, 0x0e)) + +/* Insert int into packed integer array at index. */ +#define _mm_insert_epi8(X, I, N) (__extension__ ({ __v16qi __a = (__v16qi)X; \ + __a[N] = I; \ + __a;})) +#define _mm_insert_epi32(X, I, N) (__extension__ ({ __v4si __a = (__v4si)X; \ + __a[N] = I; \ + __a;})) +#ifdef __x86_64__ +#define _mm_insert_epi64(X, I, N) (__extension__ ({ __v2di __a = (__v2di)X; \ + __a[N] = I; \ + __a;})) +#endif /* __x86_64__ */ + +/* Extract int from packed integer array at index. */ +#define _mm_extract_epi8(X, N) (__extension__ ({ __v16qi __a = (__v16qi)X; \ + __a[N];})) +#define _mm_extract_epi32(X, N) (__extension__ ({ __v4si __a = (__v4si)X; \ + __a[N];})) +#ifdef __x86_64__ +#define _mm_extract_epi64(X, N) (__extension__ ({ __v2di __a = (__v2di)X; \ + __a[N];})) +#endif /* __x86_64 */ + +/* SSE4 128-bit Packed Integer Comparisons. */ +static inline int __attribute__((__always_inline__, __nodebug__)) +_mm_testz_si128(__m128i __M, __m128i __V) +{ + return __builtin_ia32_ptestz128((__v2di)__M, (__v2di)__V); +} + +static inline int __attribute__((__always_inline__, __nodebug__)) +_mm_testc_si128(__m128i __M, __m128i __V) +{ + return __builtin_ia32_ptestc128((__v2di)__M, (__v2di)__V); +} + +static inline int __attribute__((__always_inline__, __nodebug__)) +_mm_testnzc_si128(__m128i __M, __m128i __V) +{ + return __builtin_ia32_ptestnzc128((__v2di)__M, (__v2di)__V); +} + +#define _mm_test_all_ones(V) _mm_testc_si128((V), _mm_cmpeq_epi32((V), (V))) +#define _mm_test_mix_ones_zeros(M, V) _mm_testnzc_si128((M), (V)) +#define _mm_test_all_zeros(M, V) _mm_testz_si128 ((V), (V)) + +/* SSE4 64-bit Packed Integer Comparisons. */ +static inline __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_cmpeq_epi64(__m128i __V1, __m128i __V2) +{ + return (__m128i) __builtin_ia32_pcmpeqq((__v2di)__V1, (__v2di)__V2); +} + +/* SSE4 Packed Integer Sign-Extension. */ +static inline __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_cvtepi8_epi16(__m128i __V) +{ + return (__m128i) __builtin_ia32_pmovsxbw128((__v16qi) __V); +} + +static inline __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_cvtepi8_epi32(__m128i __V) +{ + return (__m128i) __builtin_ia32_pmovsxbd128((__v16qi) __V); +} + +static inline __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_cvtepi8_epi64(__m128i __V) +{ + return (__m128i) __builtin_ia32_pmovsxbq128((__v16qi) __V); +} + +static inline __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_cvtepi16_epi32(__m128i __V) +{ + return (__m128i) __builtin_ia32_pmovsxwd128((__v8hi) __V); +} + +static inline __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_cvtepi16_epi64(__m128i __V) +{ + return (__m128i) __builtin_ia32_pmovsxwq128((__v8hi)__V); +} + +static inline __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_cvtepi32_epi64(__m128i __V) +{ + return (__m128i) __builtin_ia32_pmovsxdq128((__v4si)__V); +} + +/* SSE4 Packed Integer Zero-Extension. */ +static inline __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_cvtepu8_epi16(__m128i __V) +{ + return (__m128i) __builtin_ia32_pmovzxbw128((__v16qi) __V); +} + +static inline __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_cvtepu8_epi32(__m128i __V) +{ + return (__m128i) __builtin_ia32_pmovzxbd128((__v16qi)__V); +} + +static inline __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_cvtepu8_epi64(__m128i __V) +{ + return (__m128i) __builtin_ia32_pmovzxbq128((__v16qi)__V); +} + +static inline __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_cvtepu16_epi32(__m128i __V) +{ + return (__m128i) __builtin_ia32_pmovzxwd128((__v8hi)__V); +} + +static inline __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_cvtepu16_epi64(__m128i __V) +{ + return (__m128i) __builtin_ia32_pmovzxwq128((__v8hi)__V); +} + +static inline __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_cvtepu32_epi64(__m128i __V) +{ + return (__m128i) __builtin_ia32_pmovzxdq128((__v4si)__V); +} + +/* SSE4 Pack with Unsigned Saturation. */ +static inline __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_packus_epi32(__m128i __V1, __m128i __V2) +{ + return (__m128i) __builtin_ia32_packusdw128((__v4si)__V1, (__v4si)__V2); +} + +/* SSE4 Multiple Packed Sums of Absolute Difference. */ +#define _mm_mpsadbw_epu8(X, Y, M) __builtin_ia32_mpsadbw128((X), (Y), (M)) #endif /* __SSE4_1__ */ diff --git a/lib/Index/Entity.cpp b/lib/Index/Entity.cpp index 03fe9f73af40..cd9d277bb6cb 100644 --- a/lib/Index/Entity.cpp +++ b/lib/Index/Entity.cpp @@ -71,9 +71,7 @@ Entity EntityGetter::VisitNamedDecl(NamedDecl *D) { DeclarationName GlobName; if (IdentifierInfo *II = LocalName.getAsIdentifierInfo()) { - IdentifierInfo *GlobII = - &ProgImpl.getIdents().get(II->getNameStart(), - II->getNameStart() + II->getLength()); + IdentifierInfo *GlobII = &ProgImpl.getIdents().get(II->getName()); GlobName = DeclarationName(GlobII); } else { Selector LocalSel = LocalName.getObjCSelector(); @@ -140,9 +138,7 @@ Decl *EntityImpl::getDecl(ASTContext &AST) { DeclarationName LocalName; if (IdentifierInfo *GlobII = Name.getAsIdentifierInfo()) { - IdentifierInfo &II = - AST.Idents.get(GlobII->getNameStart(), - GlobII->getNameStart() + GlobII->getLength()); + IdentifierInfo &II = AST.Idents.get(GlobII->getName()); LocalName = DeclarationName(&II); } else { Selector GlobSel = Name.getObjCSelector(); diff --git a/lib/Index/GlobalSelector.cpp b/lib/Index/GlobalSelector.cpp index 2b2ca6d3b1cc..34679185b166 100644 --- a/lib/Index/GlobalSelector.cpp +++ b/lib/Index/GlobalSelector.cpp @@ -29,9 +29,7 @@ Selector GlobalSelector::getSelector(ASTContext &AST) const { for (unsigned i = 0, e = GlobSel.isUnarySelector() ? 1 : GlobSel.getNumArgs(); i != e; ++i) { IdentifierInfo *GlobII = GlobSel.getIdentifierInfoForSlot(i); - IdentifierInfo *II = - &AST.Idents.get(GlobII->getNameStart(), - GlobII->getNameStart() + GlobII->getLength()); + IdentifierInfo *II = &AST.Idents.get(GlobII->getName()); Ids.push_back(II); } @@ -58,9 +56,7 @@ GlobalSelector GlobalSelector::get(Selector Sel, Program &Prog) { for (unsigned i = 0, e = Sel.isUnarySelector() ? 1 : Sel.getNumArgs(); i != e; ++i) { IdentifierInfo *II = Sel.getIdentifierInfoForSlot(i); - IdentifierInfo *GlobII = - &ProgImpl.getIdents().get(II->getNameStart(), - II->getNameStart() + II->getLength()); + IdentifierInfo *GlobII = &ProgImpl.getIdents().get(II->getName()); Ids.push_back(GlobII); } diff --git a/lib/Index/Makefile b/lib/Index/Makefile index 9d33a2d175e3..4d8671361cdf 100644 --- a/lib/Index/Makefile +++ b/lib/Index/Makefile @@ -18,10 +18,10 @@ LIBRARYNAME := clangIndex BUILD_ARCHIVE = 1 ifeq ($(ARCH),PowerPC) -CXXFLAGS += -maltivec +CXX.Flags += -maltivec endif -CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include +CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include include $(LEVEL)/Makefile.common diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 3207062ccadd..6cdb96f37de4 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -229,14 +229,18 @@ unsigned Lexer::MeasureTokenLength(SourceLocation Loc, // the token this macro expanded to. Loc = SM.getInstantiationLoc(Loc); std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); - std::pair<const char *,const char *> Buffer = SM.getBufferData(LocInfo.first); - const char *StrData = Buffer.first+LocInfo.second; + bool Invalid = false; + llvm::StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); + if (Invalid) + return 0; + + const char *StrData = Buffer.data()+LocInfo.second; if (isWhitespace(StrData[0])) return 0; // Create a lexer starting at the beginning of this token. - Lexer TheLexer(Loc, LangOpts, Buffer.first, StrData, Buffer.second); + Lexer TheLexer(Loc, LangOpts, Buffer.begin(), StrData, Buffer.end()); TheLexer.SetCommentRetentionState(true); Token TheTok; TheLexer.LexFromRawLexer(TheTok); diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp index 004e6755e5f5..1cfa0e374506 100644 --- a/lib/Lex/LiteralSupport.cpp +++ b/lib/Lex/LiteralSupport.cpp @@ -806,7 +806,14 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks, // Get the spelling of the token, which eliminates trigraphs, etc. We know // that ThisTokBuf points to a buffer that is big enough for the whole token // and 'spelled' tokens can only shrink. - unsigned ThisTokLen = PP.getSpelling(StringToks[i], ThisTokBuf); + bool StringInvalid = false; + unsigned ThisTokLen = PP.getSpelling(StringToks[i], ThisTokBuf, + &StringInvalid); + if (StringInvalid) { + hadError = 1; + continue; + } + const char *ThisTokEnd = ThisTokBuf+ThisTokLen-1; // Skip end quote. // TODO: Input character set mapping support. @@ -904,8 +911,12 @@ unsigned StringLiteralParser::getOffsetOfStringByte(const Token &Tok, llvm::SmallString<16> SpellingBuffer; SpellingBuffer.resize(Tok.getLength()); + bool StringInvalid = false; const char *SpellingPtr = &SpellingBuffer[0]; - unsigned TokLen = PP.getSpelling(Tok, SpellingPtr); + unsigned TokLen = PP.getSpelling(Tok, SpellingPtr, &StringInvalid); + if (StringInvalid) { + return 0; + } assert(SpellingPtr[0] != 'L' && "Doesn't handle wide strings yet"); diff --git a/lib/Lex/Makefile b/lib/Lex/Makefile index 509077017c2d..bd3c7a872d3a 100644 --- a/lib/Lex/Makefile +++ b/lib/Lex/Makefile @@ -18,10 +18,10 @@ LIBRARYNAME := clangLex BUILD_ARCHIVE = 1 ifeq ($(ARCH),PowerPC) -CXXFLAGS += -maltivec +CXX.Flags += -maltivec endif -CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include +CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include include $(LEVEL)/Makefile.common diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 976c94eda364..cddc6cff727a 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -471,7 +471,7 @@ void Preprocessor::HandleDirective(Token &Result) { CurPPLexer->ParsingPreprocessorDirective = true; ++NumDirectives; - + // We are about to read a token. For the multiple-include optimization FA to // work, we have to remember if we had read any tokens *before* this // pp-directive. @@ -964,7 +964,7 @@ bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc, /// false if the > was found, otherwise it returns true if it finds and consumes /// the EOM marker. bool Preprocessor::ConcatenateIncludeName( - llvm::SmallVector<char, 128> &FilenameBuffer) { + llvm::SmallString<128> &FilenameBuffer) { Token CurTok; Lex(CurTok); @@ -1042,7 +1042,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok, return; } - bool isAngled = + bool isAngled = GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename); // If GetIncludeFilenameSpelling set the start ptr to null, there was an // error. @@ -1070,7 +1070,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok, Diag(FilenameTok, diag::err_pp_file_not_found) << Filename; return; } - + // Ask HeaderInfo if we should enter this #include file. If not, #including // this file will have no effect. if (!HeaderInfo.ShouldEnterIncludeFile(File, isImport)) @@ -1512,7 +1512,7 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef, IdentifierInfo *MII = MacroNameTok.getIdentifierInfo(); MacroInfo *MI = getMacroInfo(MII); - + if (CurPPLexer->getConditionalStackDepth() == 0) { // If the start of a top-level #ifdef and if the macro is not defined, // inform MIOpt that this might be the start of a proper include guard. diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp index ede129edcb6f..756ce27a93dc 100644 --- a/lib/Lex/PPExpressions.cpp +++ b/lib/Lex/PPExpressions.cpp @@ -170,7 +170,12 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, return true; case tok::numeric_constant: { llvm::SmallString<64> IntegerBuffer; - llvm::StringRef Spelling = PP.getSpelling(PeekTok, IntegerBuffer); + bool NumberInvalid = false; + llvm::StringRef Spelling = PP.getSpelling(PeekTok, IntegerBuffer, + &NumberInvalid); + if (NumberInvalid) + return true; // a diagnostic was already reported + NumericLiteralParser Literal(Spelling.begin(), Spelling.end(), PeekTok.getLocation(), PP); if (Literal.hadError) @@ -216,7 +221,10 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, } case tok::char_constant: { // 'x' llvm::SmallString<32> CharBuffer; - llvm::StringRef ThisTok = PP.getSpelling(PeekTok, CharBuffer); + bool CharInvalid = false; + llvm::StringRef ThisTok = PP.getSpelling(PeekTok, CharBuffer, &CharInvalid); + if (CharInvalid) + return true; CharLiteralParser Literal(ThisTok.begin(), ThisTok.end(), PeekTok.getLocation(), PP); diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp index 0b26ccbecbab..81e6bf809025 100644 --- a/lib/Lex/PPLexerChange.cpp +++ b/lib/Lex/PPLexerChange.cpp @@ -80,9 +80,8 @@ bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir, } // Get the MemoryBuffer for this FID, if it fails, we fail. - const llvm::MemoryBuffer *InputFile = - getSourceManager().getBuffer(FID, &ErrorStr); - if (!ErrorStr.empty()) + const llvm::MemoryBuffer *InputFile = getSourceManager().getBuffer(FID); + if (!InputFile) return true; EnterSourceFileWithLexer(new Lexer(FID, InputFile, *this), CurDir); diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp index a64008ab1806..3b949d0ab40a 100644 --- a/lib/Lex/PTHLexer.cpp +++ b/lib/Lex/PTHLexer.cpp @@ -549,12 +549,12 @@ IdentifierInfo* PTHManager::LazilyCreateIdentifierInfo(unsigned PersistentID) { return II; } -IdentifierInfo* PTHManager::get(const char *NameStart, const char *NameEnd) { +IdentifierInfo* PTHManager::get(llvm::StringRef Name) { PTHStringIdLookup& SL = *((PTHStringIdLookup*)StringIdLookup); // Double check our assumption that the last character isn't '\0'. - assert(NameEnd==NameStart || NameStart[NameEnd-NameStart-1] != '\0'); - PTHStringIdLookup::iterator I = SL.find(std::make_pair(NameStart, - NameEnd - NameStart)); + assert(Name.empty() || Name.data()[Name.size()-1] != '\0'); + PTHStringIdLookup::iterator I = SL.find(std::make_pair(Name.data(), + Name.size())); if (I == SL.end()) // No identifier found? return 0; @@ -662,7 +662,7 @@ public: CacheTy::iterator I = Cache.find(path); // If we don't get a hit in the PTH file just forward to 'stat'. - if (I == Cache.end()) + if (I == Cache.end()) return StatSysCallCache::stat(path, buf); const PTHStatData& Data = *I; diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index 2c6ad6ee462c..5584b18da15f 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -52,7 +52,7 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, bool OwnsHeaders) : Diags(&diags), Features(opts), Target(target),FileMgr(Headers.getFileMgr()), SourceMgr(SM), HeaderInfo(Headers), ExternalSource(0), - Identifiers(opts, IILookup), BuiltinInfo(Target), CodeCompletionFile(0), + Identifiers(opts, IILookup), BuiltinInfo(Target), CodeCompletionFile(0), CurPPLexer(0), CurDirLookup(0), Callbacks(0), MacroArgCache(0) { ScratchBuf = new ScratchBuffer(SourceMgr); CounterValue = 0; // __COUNTER__ starts at 0. @@ -80,7 +80,7 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, // We haven't read anything from the external source. ReadMacrosFromExternalSource = false; - + // "Poison" __VA_ARGS__, which can only appear in the expansion of a macro. // This gets unpoisoned where it is allowed. (Ident__VA_ARGS__ = getIdentifierInfo("__VA_ARGS__"))->setIsPoisoned(); @@ -116,7 +116,7 @@ Preprocessor::~Preprocessor() { // Free any cached macro expanders. for (unsigned i = 0, e = NumCachedTokenLexers; i != e; ++i) delete TokenLexerCache[i]; - + // Free any cached MacroArgs. for (MacroArgs *ArgList = MacroArgCache; ArgList; ) ArgList = ArgList->deallocate(); @@ -198,30 +198,30 @@ void Preprocessor::PrintStats() { << NumFastTokenPaste << " on the fast path.\n"; } -Preprocessor::macro_iterator -Preprocessor::macro_begin(bool IncludeExternalMacros) const { - if (IncludeExternalMacros && ExternalSource && +Preprocessor::macro_iterator +Preprocessor::macro_begin(bool IncludeExternalMacros) const { + if (IncludeExternalMacros && ExternalSource && !ReadMacrosFromExternalSource) { ReadMacrosFromExternalSource = true; ExternalSource->ReadDefinedMacros(); } - - return Macros.begin(); + + return Macros.begin(); } -Preprocessor::macro_iterator -Preprocessor::macro_end(bool IncludeExternalMacros) const { - if (IncludeExternalMacros && ExternalSource && +Preprocessor::macro_iterator +Preprocessor::macro_end(bool IncludeExternalMacros) const { + if (IncludeExternalMacros && ExternalSource && !ReadMacrosFromExternalSource) { ReadMacrosFromExternalSource = true; ExternalSource->ReadDefinedMacros(); } - - return Macros.end(); + + return Macros.end(); } -bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File, - unsigned TruncateAtLine, +bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File, + unsigned TruncateAtLine, unsigned TruncateAtColumn) { using llvm::MemoryBuffer; @@ -242,7 +242,7 @@ bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File, for (; *Position; ++Position) { if (*Position != '\r' && *Position != '\n') continue; - + // Eat \r\n or \n\r as a single line. if ((Position[1] == '\r' || Position[1] == '\n') && Position[0] != Position[1]) @@ -251,13 +251,13 @@ bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File, break; } } - + Position += TruncateAtColumn - 1; - + // Truncate the buffer. if (Position < Buffer->getBufferEnd()) { - MemoryBuffer *TruncatedBuffer - = MemoryBuffer::getMemBufferCopy(Buffer->getBufferStart(), Position, + MemoryBuffer *TruncatedBuffer + = MemoryBuffer::getMemBufferCopy(Buffer->getBufferStart(), Position, Buffer->getBufferIdentifier()); SourceMgr.overrideFileContents(File, TruncatedBuffer); } @@ -282,11 +282,19 @@ bool Preprocessor::isCodeCompletionFile(SourceLocation FileLoc) const { /// UCNs, etc. std::string Preprocessor::getSpelling(const Token &Tok, const SourceManager &SourceMgr, - const LangOptions &Features) { + const LangOptions &Features, + bool *Invalid) { assert((int)Tok.getLength() >= 0 && "Token character range is bogus!"); // If this token contains nothing interesting, return it directly. - const char* TokStart = SourceMgr.getCharacterData(Tok.getLocation()); + bool CharDataInvalid = false; + const char* TokStart = SourceMgr.getCharacterData(Tok.getLocation(), + &CharDataInvalid); + if (Invalid) + *Invalid = CharDataInvalid; + if (CharDataInvalid) + return std::string(); + if (!Tok.needsCleaning()) return std::string(TokStart, TokStart+Tok.getLength()); @@ -310,8 +318,8 @@ std::string Preprocessor::getSpelling(const Token &Tok, /// after trigraph expansion and escaped-newline folding. In particular, this /// wants to get the true, uncanonicalized, spelling of things like digraphs /// UCNs, etc. -std::string Preprocessor::getSpelling(const Token &Tok) const { - return getSpelling(Tok, SourceMgr, Features); +std::string Preprocessor::getSpelling(const Token &Tok, bool *Invalid) const { + return getSpelling(Tok, SourceMgr, Features, Invalid); } /// getSpelling - This method is used to get the spelling of a token into a @@ -325,7 +333,7 @@ std::string Preprocessor::getSpelling(const Token &Tok) const { /// copy). The caller is not allowed to modify the returned buffer pointer /// if an internal buffer is returned. unsigned Preprocessor::getSpelling(const Token &Tok, - const char *&Buffer) const { + const char *&Buffer, bool *Invalid) const { assert((int)Tok.getLength() >= 0 && "Token character range is bogus!"); // If this token is an identifier, just return the string from the identifier @@ -341,8 +349,16 @@ unsigned Preprocessor::getSpelling(const Token &Tok, if (Tok.isLiteral()) TokStart = Tok.getLiteralData(); - if (TokStart == 0) - TokStart = SourceMgr.getCharacterData(Tok.getLocation()); + if (TokStart == 0) { + bool CharDataInvalid = false; + TokStart = SourceMgr.getCharacterData(Tok.getLocation(), &CharDataInvalid); + if (Invalid) + *Invalid = CharDataInvalid; + if (CharDataInvalid) { + Buffer = ""; + return 0; + } + } // If this token contains nothing interesting, return it directly. if (!Tok.needsCleaning()) { @@ -368,7 +384,8 @@ unsigned Preprocessor::getSpelling(const Token &Tok, /// SmallVector. Note that the returned StringRef may not point to the /// supplied buffer if a copy can be avoided. llvm::StringRef Preprocessor::getSpelling(const Token &Tok, - llvm::SmallVectorImpl<char> &Buffer) const { + llvm::SmallVectorImpl<char> &Buffer, + bool *Invalid) const { // Try the fast path. if (const IdentifierInfo *II = Tok.getIdentifierInfo()) return II->getName(); @@ -378,7 +395,7 @@ llvm::StringRef Preprocessor::getSpelling(const Token &Tok, Buffer.resize(Tok.getLength()); const char *Ptr = Buffer.data(); - unsigned Len = getSpelling(Tok, Ptr); + unsigned Len = getSpelling(Tok, Ptr, Invalid); return llvm::StringRef(Ptr, Len); } @@ -446,7 +463,7 @@ SourceLocation Preprocessor::AdvanceToTokenCharacter(SourceLocation TokStart, return TokStart.getFileLocWithOffset(PhysOffset); } -SourceLocation Preprocessor::getLocForEndOfToken(SourceLocation Loc, +SourceLocation Preprocessor::getLocForEndOfToken(SourceLocation Loc, unsigned Offset) { if (Loc.isInvalid() || !Loc.isFileID()) return SourceLocation(); @@ -456,7 +473,7 @@ SourceLocation Preprocessor::getLocForEndOfToken(SourceLocation Loc, Len = Len - Offset; else return Loc; - + return AdvanceToTokenCharacter(Loc, Len); } @@ -519,7 +536,7 @@ IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier, II = getIdentifierInfo(llvm::StringRef(BufPtr, Identifier.getLength())); } else { // Cleaning needed, alloca a buffer, clean into it, then use the buffer. - llvm::SmallVector<char, 64> IdentifierBuffer; + llvm::SmallString<64> IdentifierBuffer; llvm::StringRef CleanedStr = getSpelling(Identifier, IdentifierBuffer); II = getIdentifierInfo(CleanedStr); } diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp index 5d95eb39c89e..dbd1b8400de3 100644 --- a/lib/Lex/TokenLexer.cpp +++ b/lib/Lex/TokenLexer.cpp @@ -325,7 +325,7 @@ void TokenLexer::Lex(Token &Tok) { // returned by PasteTokens, not the pasted token. if (PasteTokens(Tok)) return; - + TokenIsFromPaste = true; } @@ -379,7 +379,7 @@ void TokenLexer::Lex(Token &Tok) { /// are more ## after it, chomp them iteratively. Return the result as Tok. /// If this returns true, the caller should immediately return the token. bool TokenLexer::PasteTokens(Token &Tok) { - llvm::SmallVector<char, 128> Buffer; + llvm::SmallString<128> Buffer; const char *ResultTokStrPtr = 0; do { // Consume the ## operator. @@ -439,7 +439,11 @@ bool TokenLexer::PasteTokens(Token &Tok) { SourceManager &SourceMgr = PP.getSourceManager(); FileID LocFileID = SourceMgr.getFileID(ResultTokLoc); - const char *ScratchBufStart = SourceMgr.getBufferData(LocFileID).first; + bool Invalid = false; + const char *ScratchBufStart + = SourceMgr.getBufferData(LocFileID, &Invalid).data(); + if (Invalid) + return false; // Make a lexer to lex this string from. Lex just this one token. // Make a lexer object so that we lex and expand the paste result. @@ -506,8 +510,7 @@ bool TokenLexer::PasteTokens(Token &Tok) { if (Tok.is(tok::identifier)) { // Look up the identifier info for the token. We disabled identifier lookup // by saying we're skipping contents, so we need to do this manually. - IdentifierInfo *II = PP.LookUpIdentifierInfo(Tok, ResultTokStrPtr); - Tok.setIdentifierInfo(II); + PP.LookUpIdentifierInfo(Tok, ResultTokStrPtr); } return false; } diff --git a/lib/Parse/Makefile b/lib/Parse/Makefile index de16e3ea665a..6a5540f73356 100644 --- a/lib/Parse/Makefile +++ b/lib/Parse/Makefile @@ -15,7 +15,7 @@ LEVEL = ../../../.. LIBRARYNAME := clangParse BUILD_ARCHIVE = 1 -CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include +CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include include $(LEVEL)/Makefile.common diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index bfb75d2dd3d4..b92e7539deda 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -52,7 +52,7 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context, Actions.CodeCompleteNamespaceDecl(CurScope); ConsumeToken(); } - + SourceLocation IdentLoc; IdentifierInfo *Ident = 0; @@ -130,7 +130,7 @@ Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, Actions.CodeCompleteNamespaceAliasDecl(CurScope); ConsumeToken(); } - + CXXScopeSpec SS; // Parse (optional) nested-name-specifier. ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); @@ -165,7 +165,7 @@ Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, Parser::DeclPtrTy Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) { assert(Tok.is(tok::string_literal) && "Not a string literal!"); - llvm::SmallVector<char, 8> LangBuffer; + llvm::SmallString<8> LangBuffer; // LangBuffer is guaranteed to be big enough. llvm::StringRef Lang = PP.getSpelling(Tok, LangBuffer); @@ -183,7 +183,7 @@ Parser::DeclPtrTy Parser::ParseLinkage(ParsingDeclSpec &DS, if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { Attr = ParseCXX0XAttributes(); } - + if (Tok.isNot(tok::l_brace)) { ParseDeclarationOrFunctionDefinition(DS, Attr.AttrList); return Actions.ActOnFinishLinkageSpecification(CurScope, LinkageSpec, @@ -222,7 +222,7 @@ Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, Actions.CodeCompleteUsing(CurScope); ConsumeToken(); } - + if (Tok.is(tok::kw_namespace)) // Next token after 'using' is 'namespace' so it must be using-directive return ParseUsingDirective(Context, UsingLoc, DeclEnd, Attr.AttrList); @@ -259,7 +259,7 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context, Actions.CodeCompleteUsingDirective(CurScope); ConsumeToken(); } - + CXXScopeSpec SS; // Parse (optional) nested-name-specifier. ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); @@ -332,20 +332,20 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, return DeclPtrTy(); } - // Parse the unqualified-id. We allow parsing of both constructor and + // Parse the unqualified-id. We allow parsing of both constructor and // destructor names and allow the action module to diagnose any semantic // errors. UnqualifiedId Name; - if (ParseUnqualifiedId(SS, + if (ParseUnqualifiedId(SS, /*EnteringContext=*/false, /*AllowDestructorName=*/true, - /*AllowConstructorName=*/true, - /*ObjectType=*/0, + /*AllowConstructorName=*/true, + /*ObjectType=*/0, Name)) { SkipUntil(tok::semi); return DeclPtrTy(); } - + // Parse (optional) attributes (most likely GNU strong-using extension). llvm::OwningPtr<AttributeList> AttrList; if (Tok.is(tok::kw___attribute)) @@ -354,7 +354,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, // Eat ';'. DeclEnd = Tok.getLocation(); ExpectAndConsume(tok::semi, diag::err_expected_semi_after, - AttrList ? "attributes list" : "using declaration", + AttrList ? "attributes list" : "using declaration", tok::semi); return Actions.ActOnUsingDeclaration(CurScope, AS, true, UsingLoc, SS, Name, @@ -502,26 +502,26 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, Diag(IdLoc, diag::err_unknown_template_name) << Id; } - + if (!Template) return true; - // Form the template name + // Form the template name UnqualifiedId TemplateName; TemplateName.setIdentifier(Id, IdLoc); - + // Parse the full template-id, then turn it into a type. if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName, SourceLocation(), true)) return true; if (TNK == TNK_Dependent_template_name) AnnotateTemplateIdTokenAsType(SS); - + // If we didn't end up with a typename token, there's nothing more we // can do. if (Tok.isNot(tok::annot_typename)) return true; - + // Retrieve the type from the annotation token, consume that token, and // return. EndLocation = Tok.getAnnotationEndLoc(); @@ -532,7 +532,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, // We have an identifier; check whether it is actually a type. TypeTy *Type = Actions.getTypeName(*Id, IdLoc, CurScope, SS, true); - if (!Type) { + if (!Type) { Diag(IdLoc, diag::err_expected_class_name); return true; } @@ -601,7 +601,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, Actions.CodeCompleteTag(CurScope, TagType); ConsumeToken(); } - + AttributeList *AttrList = 0; // If attributes exist after tag, parse them. if (Tok.is(tok::kw___attribute)) @@ -610,7 +610,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // If declspecs exist after tag, parse them. if (Tok.is(tok::kw___declspec)) AttrList = ParseMicrosoftDeclSpec(AttrList); - + // If C++0x attributes exist here, parse them. // FIXME: Are we consistent with the ordering of parsing of different // styles of attributes? @@ -642,7 +642,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (getLang().CPlusPlus) { // "FOO : BAR" is not a potential typo for "FOO::BAR". ColonProtectionRAIIObject X(*this); - + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true); if (SS.isSet()) if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) @@ -658,21 +658,21 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (Tok.is(tok::identifier)) { Name = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); - + if (Tok.is(tok::less)) { - // The name was supposed to refer to a template, but didn't. + // The name was supposed to refer to a template, but didn't. // Eat the template argument list and try to continue parsing this as // a class (or template thereof). TemplateArgList TemplateArgs; SourceLocation LAngleLoc, RAngleLoc; - if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, &SS, + if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, &SS, true, LAngleLoc, TemplateArgs, RAngleLoc)) { // We couldn't parse the template argument list at all, so don't // try to give any location information for the list. LAngleLoc = RAngleLoc = SourceLocation(); } - + Diag(NameLoc, diag::err_explicit_spec_non_template) << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) << (TagType == DeclSpec::TST_class? 0 @@ -680,30 +680,30 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, : 2) << Name << SourceRange(LAngleLoc, RAngleLoc); - - // Strip off the last template parameter list if it was empty, since + + // Strip off the last template parameter list if it was empty, since // we've removed its template argument list. if (TemplateParams && TemplateInfo.LastParameterListWasEmpty) { if (TemplateParams && TemplateParams->size() > 1) { TemplateParams->pop_back(); } else { TemplateParams = 0; - const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind + const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind = ParsedTemplateInfo::NonTemplate; } } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) { // Pretend this is just a forward declaration. TemplateParams = 0; - const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind + const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind = ParsedTemplateInfo::NonTemplate; - const_cast<ParsedTemplateInfo&>(TemplateInfo).TemplateLoc + const_cast<ParsedTemplateInfo&>(TemplateInfo).TemplateLoc = SourceLocation(); const_cast<ParsedTemplateInfo&>(TemplateInfo).ExternLoc = SourceLocation(); } - - + + } } else if (Tok.is(tok::annot_template_id)) { TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); @@ -896,7 +896,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // less common call. if (IsDependent) TypeResult = Actions.ActOnDependentTag(CurScope, TagType, TUK, - SS, Name, StartLoc, NameLoc); + SS, Name, StartLoc, NameLoc); } // If there is a body, parse it and inform the actions module. @@ -927,11 +927,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // FIXME: The DeclSpec should keep the locations of both the keyword and the // name (if there is one). SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc; - + if (DS.SetTypeSpecType(TagType, TSTLoc, PrevSpec, DiagID, Result, Owned)) Diag(StartLoc, DiagID) << PrevSpec; - + // At this point, we've successfully parsed a class-specifier in 'definition' // form (e.g. "struct foo { int x; }". While we could just return here, we're // going to look at what comes after it to improve error recovery. If an @@ -984,14 +984,14 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (!isKnownToBeTypeSpecifier(NextToken())) ExpectedSemi = false; break; - - case tok::r_brace: // struct bar { struct foo {...} } + + case tok::r_brace: // struct bar { struct foo {...} } // Missing ';' at end of struct is accepted as an extension in C mode. if (!getLang().CPlusPlus) ExpectedSemi = false; break; } - + if (ExpectedSemi) { ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, TagType == DeclSpec::TST_class ? "class" @@ -1000,7 +1000,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // to ';' so that the rest of the code recovers as though there were an // ';' after the definition. PP.EnterToken(Tok); - Tok.setKind(tok::semi); + Tok.setKind(tok::semi); } } } @@ -1084,7 +1084,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) { // Parse optional '::' and optional nested-name-specifier. CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, /*EnteringContext=*/false); // The location of the base class itself. @@ -1251,7 +1251,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it // is a bitfield. ColonProtectionRAIIObject X(*this); - + CXX0XAttributeList AttrList; // Optional C++0x attribute-specifier if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) @@ -1259,7 +1259,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (Tok.is(tok::kw_using)) { // FIXME: Check for template aliases - + if (AttrList.HasAttr) Diag(AttrList.Range.getBegin(), diag::err_attributes_not_allowed) << AttrList.Range; @@ -1628,14 +1628,14 @@ void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) { llvm::SmallVector<MemInitTy*, 4> MemInitializers; bool AnyErrors = false; - + do { MemInitResult MemInit = ParseMemInitializer(ConstructorDecl); if (!MemInit.isInvalid()) MemInitializers.push_back(MemInit.get()); else AnyErrors = true; - + if (Tok.is(tok::comma)) ConsumeToken(); else if (Tok.is(tok::l_brace)) @@ -1869,7 +1869,7 @@ CXX0XAttributeList Parser::ParseCXX0XAttributes(SourceLocation *EndLoc) { ConsumeBracket(); ConsumeBracket(); - + if (Tok.is(tok::comma)) { Diag(Tok.getLocation(), diag::err_expected_ident); ConsumeToken(); @@ -1884,7 +1884,7 @@ CXX0XAttributeList Parser::ParseCXX0XAttributes(SourceLocation *EndLoc) { IdentifierInfo *ScopeName = 0, *AttrName = Tok.getIdentifierInfo(); SourceLocation ScopeLoc, AttrLoc = ConsumeToken(); - + // scoped attribute if (Tok.is(tok::coloncolon)) { ConsumeToken(); @@ -1894,7 +1894,7 @@ CXX0XAttributeList Parser::ParseCXX0XAttributes(SourceLocation *EndLoc) { SkipUntil(tok::r_square, tok::comma, true, true); continue; } - + ScopeName = AttrName; ScopeLoc = AttrLoc; diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 7ab0e71dc235..7b2b6e855bb7 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -375,6 +375,10 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, AtEnd.setBegin(AtLoc); AtEnd.setEnd(Tok.getLocation()); break; + } else if (DirectiveKind == tok::objc_not_keyword) { + Diag(Tok, diag::err_objc_unknown_at); + SkipUntil(tok::semi); + continue; } // Eat the identifier. diff --git a/lib/Rewrite/HTMLRewrite.cpp b/lib/Rewrite/HTMLRewrite.cpp index 342b0e6ef5e5..7b78070a27f8 100644 --- a/lib/Rewrite/HTMLRewrite.cpp +++ b/lib/Rewrite/HTMLRewrite.cpp @@ -43,8 +43,13 @@ void html::HighlightRange(Rewriter &R, SourceLocation B, SourceLocation E, // Include the whole end token in the range. EOffset += Lexer::MeasureTokenLength(E, R.getSourceMgr(), R.getLangOpts()); + bool Invalid = false; + const char *BufferStart = SM.getBufferData(FID, &Invalid).data(); + if (Invalid) + return; + HighlightRange(R.getEditBuffer(FID), BOffset, EOffset, - SM.getBufferData(FID).first, StartTag, EndTag); + BufferStart, StartTag, EndTag); } /// HighlightRange - This is the same as the above method, but takes diff --git a/lib/Rewrite/Makefile b/lib/Rewrite/Makefile index a6d3f7725689..04c353090dc7 100644 --- a/lib/Rewrite/Makefile +++ b/lib/Rewrite/Makefile @@ -15,7 +15,7 @@ LEVEL = ../../../.. LIBRARYNAME := clangRewrite BUILD_ARCHIVE = 1 -CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include +CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include include $(LEVEL)/Makefile.common diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Rewriter.cpp index 9744496ac4fe..bf8ba701a842 100644 --- a/lib/Rewrite/Rewriter.cpp +++ b/lib/Rewrite/Rewriter.cpp @@ -165,8 +165,8 @@ RewriteBuffer &Rewriter::getEditBuffer(FileID FID) { return I->second; I = RewriteBuffers.insert(I, std::make_pair(FID, RewriteBuffer())); - std::pair<const char*, const char*> MB = SourceMgr->getBufferData(FID); - I->second.Initialize(MB.first, MB.second); + llvm::StringRef MB = SourceMgr->getBufferData(FID); + I->second.Initialize(MB.begin(), MB.end()); return I->second; } diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 5be6712c8397..237803a1c453 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -22,6 +22,7 @@ add_clang_library(clangSema SemaExprObjC.cpp SemaInit.cpp SemaLookup.cpp + SemaObjCProperty.cpp SemaOverload.cpp SemaStmt.cpp SemaTemplate.cpp diff --git a/lib/Sema/Makefile b/lib/Sema/Makefile index 158f1af213d4..3a5a99ad576a 100644 --- a/lib/Sema/Makefile +++ b/lib/Sema/Makefile @@ -16,7 +16,7 @@ LEVEL = ../../../.. LIBRARYNAME := clangSema BUILD_ARCHIVE = 1 -CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include +CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include include $(LEVEL)/Makefile.common diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index a94d07a6acc8..4c258448daf2 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -300,60 +300,38 @@ public: /// \brief The set of static functions seen so far that have not been used. std::vector<FunctionDecl*> UnusedStaticFuncs; - /// An enum describing the kind of diagnostics to use when checking - /// access. - enum AccessDiagnosticsKind { - /// Suppress diagnostics. - ADK_quiet, - - /// Use the normal diagnostics. - ADK_normal, - - /// Use the diagnostics appropriate for checking a covariant - /// return type. - ADK_covariance - }; - class AccessedEntity { public: - enum Kind { - /// A member declaration found through lookup. The target is the - /// member. - Member, - - /// A base-to-derived conversion. The target is the base class. - BaseToDerivedConversion, - - /// A derived-to-base conversion. The target is the base class. - DerivedToBaseConversion - }; - - bool isMemberAccess() const { return K == Member; } - - static AccessedEntity makeMember(CXXRecordDecl *NamingClass, - AccessSpecifier Access, - NamedDecl *Target) { - AccessedEntity E; - E.K = Member; - E.Access = Access; - E.Target = Target; - E.NamingClass = NamingClass; - return E; + /// A member declaration found through lookup. The target is the + /// member. + enum MemberNonce { Member }; + + /// A hierarchy (base-to-derived or derived-to-base) conversion. + /// The target is the base class. + enum BaseNonce { Base }; + + bool isMemberAccess() const { return IsMember; } + + AccessedEntity(MemberNonce _, + CXXRecordDecl *NamingClass, + AccessSpecifier Access, + NamedDecl *Target) + : Access(Access), IsMember(true), + Target(Target), NamingClass(NamingClass), + Diag(0) { } - static AccessedEntity makeBaseClass(bool BaseToDerived, - CXXRecordDecl *BaseClass, - CXXRecordDecl *DerivedClass, - AccessSpecifier Access) { - AccessedEntity E; - E.K = BaseToDerived ? BaseToDerivedConversion : DerivedToBaseConversion; - E.Access = Access; - E.Target = BaseClass; - E.NamingClass = DerivedClass; - return E; + AccessedEntity(BaseNonce _, + CXXRecordDecl *BaseClass, + CXXRecordDecl *DerivedClass, + AccessSpecifier Access) + : Access(Access), IsMember(false), + Target(BaseClass), NamingClass(DerivedClass), + Diag(0) { } - Kind getKind() const { return Kind(K); } + bool isQuiet() const { return Diag.getDiagID() == 0; } + AccessSpecifier getAccess() const { return AccessSpecifier(Access); } // These apply to member decls... @@ -364,11 +342,32 @@ public: CXXRecordDecl *getBaseClass() const { return cast<CXXRecordDecl>(Target); } CXXRecordDecl *getDerivedClass() const { return NamingClass; } + /// Sets a diagnostic to be performed. The diagnostic is given + /// four (additional) arguments: + /// %0 - 0 if the entity was private, 1 if protected + /// %1 - the DeclarationName of the entity + /// %2 - the TypeDecl type of the naming class + /// %3 - the TypeDecl type of the declaring class + void setDiag(const PartialDiagnostic &PDiag) { + assert(isQuiet() && "partial diagnostic already defined"); + Diag = PDiag; + } + PartialDiagnostic &setDiag(unsigned DiagID) { + assert(isQuiet() && "partial diagnostic already defined"); + assert(DiagID && "creating null diagnostic"); + Diag = PartialDiagnostic(DiagID); + return Diag; + } + const PartialDiagnostic &getDiag() const { + return Diag; + } + private: - unsigned K : 2; unsigned Access : 2; + bool IsMember; NamedDecl *Target; CXXRecordDecl *NamingClass; + PartialDiagnostic Diag; }; struct DelayedDiagnostic { @@ -384,9 +383,16 @@ public: struct { NamedDecl *Decl; } DeprecationData; /// Access control. - AccessedEntity AccessData; + char AccessData[sizeof(AccessedEntity)]; }; + void destroy() { + switch (Kind) { + case Access: getAccessData().~AccessedEntity(); break; + case Deprecation: break; + } + } + static DelayedDiagnostic makeDeprecation(SourceLocation Loc, NamedDecl *D) { DelayedDiagnostic DD; @@ -403,10 +409,16 @@ public: DD.Kind = Access; DD.Triggered = false; DD.Loc = Loc; - DD.AccessData = Entity; + new (&DD.getAccessData()) AccessedEntity(Entity); return DD; } + AccessedEntity &getAccessData() { + return *reinterpret_cast<AccessedEntity*>(AccessData); + } + const AccessedEntity &getAccessData() const { + return *reinterpret_cast<const AccessedEntity*>(AccessData); + } }; /// \brief The stack of diagnostics that were delayed due to being @@ -1469,7 +1481,7 @@ public: void DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, ObjCContainerDecl *CDecl, const llvm::DenseSet<Selector>& InsMap); - + /// CollectImmediateProperties - This routine collects all properties in /// the class and its conforming protocols; but not those it its super class. void CollectImmediateProperties(ObjCContainerDecl *CDecl, @@ -1482,7 +1494,35 @@ public: ObjCIvarDecl *SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl, IdentifierInfo *NameII); - + + /// Called by ActOnProperty to handle @property declarations in + //// class extensions. + DeclPtrTy HandlePropertyInClassExtension(Scope *S, + ObjCCategoryDecl *CDecl, + SourceLocation AtLoc, + FieldDeclarator &FD, + Selector GetterSel, + Selector SetterSel, + const bool isAssign, + const bool isReadWrite, + const unsigned Attributes, + bool *isOverridingProperty, + QualType T, + tok::ObjCKeywordKind MethodImplKind); + + /// Called by ActOnProperty and HandlePropertyInClassExtension to + /// handle creating the ObjcPropertyDecl for a category or @interface. + ObjCPropertyDecl *CreatePropertyDecl(Scope *S, + ObjCContainerDecl *CDecl, + SourceLocation AtLoc, + FieldDeclarator &FD, + Selector GetterSel, + Selector SetterSel, + const bool isAssign, + const bool isReadWrite, + const unsigned Attributes, QualType T, + tok::ObjCKeywordKind MethodImplKind); + /// AtomicPropertySetterGetterRules - This routine enforces the rule (via /// warning) when atomic property has one but not the other user-declared /// setter or getter. @@ -2538,7 +2578,7 @@ public: SourceLocation Loc, SourceRange Range, bool IgnoreAccess = false); bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, - AccessDiagnosticsKind ADK, + unsigned InaccessibleBaseID, unsigned AmbigiousBaseConvID, SourceLocation Loc, SourceRange Range, DeclarationName Name); @@ -2586,18 +2626,22 @@ public: CXXConstructorDecl *D, AccessSpecifier Access); AccessResult CheckDestructorAccess(SourceLocation Loc, - const RecordType *Record); + CXXDestructorDecl *Dtor, + const PartialDiagnostic &PDiag); + AccessResult CheckDirectMemberAccess(SourceLocation Loc, + NamedDecl *D, + const PartialDiagnostic &PDiag); AccessResult CheckMemberOperatorAccess(SourceLocation Loc, Expr *ObjectExpr, + Expr *ArgExpr, NamedDecl *D, AccessSpecifier Access); AccessResult CheckBaseClassAccess(SourceLocation AccessLoc, - bool IsBaseToDerived, QualType Base, QualType Derived, const CXXBasePath &Path, + unsigned DiagID, bool ForceCheck = false, - bool ForceUnprivileged = false, - AccessDiagnosticsKind ADK = ADK_normal); + bool ForceUnprivileged = false); void CheckLookupAccess(const LookupResult &R); @@ -3593,6 +3637,8 @@ public: DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC, const MultiLevelTemplateArgumentList &TemplateArgs); + bool CheckInstantiatedParams(llvm::SmallVectorImpl<ParmVarDecl *> &Params); + // Objective-C declarations. virtual DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, @@ -4243,8 +4289,7 @@ private: SourceLocation ReturnLoc); void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex); void CheckSignCompare(Expr *LHS, Expr *RHS, SourceLocation Loc, - const PartialDiagnostic &PD, - bool Equality = false); + const BinaryOperator::Opcode* BinOpc = 0); void CheckImplicitConversion(Expr *E, QualType Target); }; diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index eca8bb4c2a9b..f0a38d5970cc 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -16,6 +16,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclFriend.h" #include "clang/AST/ExprCXX.h" using namespace clang; @@ -55,7 +56,7 @@ struct EffectiveContext { explicit EffectiveContext(DeclContext *DC) { if (isa<FunctionDecl>(DC)) { - Function = cast<FunctionDecl>(DC); + Function = cast<FunctionDecl>(DC)->getCanonicalDecl(); DC = Function->getDeclContext(); } else Function = 0; @@ -85,10 +86,34 @@ static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) { static Sema::AccessResult GetFriendKind(Sema &S, const EffectiveContext &EC, const CXXRecordDecl *Class) { + // A class always has access to its own members. if (EC.isClass(Class)) return Sema::AR_accessible; - // FIXME: implement + // Okay, check friends. + for (CXXRecordDecl::friend_iterator I = Class->friend_begin(), + E = Class->friend_end(); I != E; ++I) { + FriendDecl *Friend = *I; + + if (Type *T = Friend->getFriendType()) { + if (EC.Record && + S.Context.hasSameType(QualType(T, 0), + S.Context.getTypeDeclType(EC.Record))) + return Sema::AR_accessible; + } else { + NamedDecl *D + = cast<NamedDecl>(Friend->getFriendDecl()->getCanonicalDecl()); + + // The decl pointers in EC have been canonicalized, so pointer + // equality is sufficient. + if (D == EC.Function || D == EC.Record) + return Sema::AR_accessible; + } + + // FIXME: templates! templated contexts! dependent delay! + } + + // That's it, give up. return Sema::AR_inaccessible; } @@ -230,18 +255,11 @@ static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc, NamedDecl *D = Entity.getTargetDecl(); CXXRecordDecl *DeclaringClass = FindDeclaringClass(D); - if (isa<CXXConstructorDecl>(D)) { - unsigned DiagID = (Access == AS_protected ? diag::err_access_ctor_protected - : diag::err_access_ctor_private); - S.Diag(Loc, DiagID) - << S.Context.getTypeDeclType(DeclaringClass); - } else { - unsigned DiagID = (Access == AS_protected ? diag::err_access_protected - : diag::err_access_private); - S.Diag(Loc, DiagID) - << D->getDeclName() - << S.Context.getTypeDeclType(DeclaringClass); - } + S.Diag(Loc, Entity.getDiag()) + << (Access == AS_protected) + << D->getDeclName() + << S.Context.getTypeDeclType(NamingClass) + << S.Context.getTypeDeclType(DeclaringClass); DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access); } @@ -249,39 +267,25 @@ static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc, static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc, const EffectiveContext &EC, AccessSpecifier Access, - const Sema::AccessedEntity &Entity, - Sema::AccessDiagnosticsKind ADK) { - if (ADK == Sema::ADK_covariance) { - S.Diag(Loc, diag::err_covariant_return_inaccessible_base) - << S.Context.getTypeDeclType(Entity.getDerivedClass()) - << S.Context.getTypeDeclType(Entity.getBaseClass()) - << (Access == AS_protected); - } else if (Entity.getKind() == Sema::AccessedEntity::BaseToDerivedConversion) { - S.Diag(Loc, diag::err_downcast_from_inaccessible_base) - << S.Context.getTypeDeclType(Entity.getDerivedClass()) - << S.Context.getTypeDeclType(Entity.getBaseClass()) - << (Access == AS_protected); - } else { - S.Diag(Loc, diag::err_upcast_to_inaccessible_base) - << S.Context.getTypeDeclType(Entity.getDerivedClass()) - << S.Context.getTypeDeclType(Entity.getBaseClass()) - << (Access == AS_protected); - } + const Sema::AccessedEntity &Entity) { + S.Diag(Loc, Entity.getDiag()) + << (Access == AS_protected) + << DeclarationName() + << S.Context.getTypeDeclType(Entity.getDerivedClass()) + << S.Context.getTypeDeclType(Entity.getBaseClass()); DiagnoseAccessPath(S, EC, Entity.getDerivedClass(), Entity.getBaseClass(), 0, Access); } -static void DiagnoseBadAccess(Sema &S, - SourceLocation Loc, +static void DiagnoseBadAccess(Sema &S, SourceLocation Loc, const EffectiveContext &EC, CXXRecordDecl *NamingClass, AccessSpecifier Access, - const Sema::AccessedEntity &Entity, - Sema::AccessDiagnosticsKind ADK) { + const Sema::AccessedEntity &Entity) { if (Entity.isMemberAccess()) DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity); else - DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity, ADK); + DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity); } @@ -344,8 +348,7 @@ static void TryElevateAccess(Sema &S, static Sema::AccessResult CheckEffectiveAccess(Sema &S, const EffectiveContext &EC, SourceLocation Loc, - Sema::AccessedEntity const &Entity, - Sema::AccessDiagnosticsKind ADK) { + Sema::AccessedEntity const &Entity) { AccessSpecifier Access = Entity.getAccess(); assert(Access != AS_public); @@ -353,14 +356,14 @@ static Sema::AccessResult CheckEffectiveAccess(Sema &S, while (NamingClass->isAnonymousStructOrUnion()) // This should be guaranteed by the fact that the decl has // non-public access. If not, we should make it guaranteed! - NamingClass = cast<CXXRecordDecl>(NamingClass); + NamingClass = cast<CXXRecordDecl>(NamingClass->getParent()); if (!EC.Record) { TryElevateAccess(S, EC, Entity, Access); if (Access == AS_public) return Sema::AR_accessible; - if (ADK != Sema::ADK_quiet) - DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK); + if (!Entity.isQuiet()) + DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity); return Sema::AR_inaccessible; } @@ -393,15 +396,13 @@ static Sema::AccessResult CheckEffectiveAccess(Sema &S, } // Okay, that's it, reject it. - if (ADK != Sema::ADK_quiet) - DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK); + if (!Entity.isQuiet()) + DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity); return Sema::AR_inaccessible; } static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, - const Sema::AccessedEntity &Entity, - Sema::AccessDiagnosticsKind ADK - = Sema::ADK_normal) { + const Sema::AccessedEntity &Entity) { // If the access path is public, it's accessible everywhere. if (Entity.getAccess() == AS_public) return Sema::AR_accessible; @@ -411,14 +412,13 @@ static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, // can actually change our effective context for the purposes of // access control. if (S.CurContext->isFileContext() && S.ParsingDeclDepth) { - assert(ADK == Sema::ADK_normal && "delaying abnormal access check"); S.DelayedDiagnostics.push_back( Sema::DelayedDiagnostic::makeAccess(Loc, Entity)); return Sema::AR_delayed; } return CheckEffectiveAccess(S, EffectiveContext(S.CurContext), - Loc, Entity, ADK); + Loc, Entity); } void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) { @@ -426,18 +426,23 @@ void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) { // declaration. EffectiveContext EC(Ctx->getDeclContext()); - if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.AccessData, ADK_normal)) + if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.getAccessData())) DD.Triggered = true; } Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, NamedDecl *D, AccessSpecifier Access) { - if (!getLangOptions().AccessControl || !E->getNamingClass()) + if (!getLangOptions().AccessControl || + !E->getNamingClass() || + Access == AS_public) return AR_accessible; - return CheckAccess(*this, E->getNameLoc(), - AccessedEntity::makeMember(E->getNamingClass(), Access, D)); + AccessedEntity Entity(AccessedEntity::Member, + E->getNamingClass(), Access, D); + Entity.setDiag(diag::err_access) << E->getSourceRange(); + + return CheckAccess(*this, E->getNameLoc(), Entity); } /// Perform access-control checking on a previously-unresolved member @@ -445,56 +450,90 @@ Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, NamedDecl *D, AccessSpecifier Access) { - if (!getLangOptions().AccessControl) + if (!getLangOptions().AccessControl || + Access == AS_public) return AR_accessible; - return CheckAccess(*this, E->getMemberLoc(), - AccessedEntity::makeMember(E->getNamingClass(), Access, D)); + AccessedEntity Entity(AccessedEntity::Member, + E->getNamingClass(), Access, D); + Entity.setDiag(diag::err_access) << E->getSourceRange(); + + return CheckAccess(*this, E->getMemberLoc(), Entity); } Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc, - const RecordType *RT) { + CXXDestructorDecl *Dtor, + const PartialDiagnostic &PDiag) { if (!getLangOptions().AccessControl) return AR_accessible; - CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl()); - CXXDestructorDecl *Dtor = NamingClass->getDestructor(Context); - + // There's never a path involved when checking implicit destructor access. AccessSpecifier Access = Dtor->getAccess(); if (Access == AS_public) return AR_accessible; - return CheckAccess(*this, Loc, - AccessedEntity::makeMember(NamingClass, Access, Dtor)); + CXXRecordDecl *NamingClass = Dtor->getParent(); + AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Dtor); + Entity.setDiag(PDiag); // TODO: avoid copy + + return CheckAccess(*this, Loc, Entity); } /// Checks access to a constructor. Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, CXXConstructorDecl *Constructor, AccessSpecifier Access) { - if (!getLangOptions().AccessControl) + if (!getLangOptions().AccessControl || + Access == AS_public) return AR_accessible; CXXRecordDecl *NamingClass = Constructor->getParent(); - return CheckAccess(*this, UseLoc, - AccessedEntity::makeMember(NamingClass, Access, Constructor)); + AccessedEntity Entity(AccessedEntity::Member, + NamingClass, Access, Constructor); + Entity.setDiag(diag::err_access_ctor); + + return CheckAccess(*this, UseLoc, Entity); +} + +/// Checks direct (i.e. non-inherited) access to an arbitrary class +/// member. +Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc, + NamedDecl *Target, + const PartialDiagnostic &Diag) { + AccessSpecifier Access = Target->getAccess(); + if (!getLangOptions().AccessControl || + Access == AS_public) + return AR_accessible; + + CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext()); + AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Target); + Entity.setDiag(Diag); + return CheckAccess(*this, UseLoc, Entity); } + /// Checks access to an overloaded member operator, including /// conversion operators. Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, Expr *ObjectExpr, + Expr *ArgExpr, NamedDecl *MemberOperator, AccessSpecifier Access) { - if (!getLangOptions().AccessControl) + if (!getLangOptions().AccessControl || + Access == AS_public) return AR_accessible; const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>(); assert(RT && "found member operator but object expr not of record type"); CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl()); - return CheckAccess(*this, OpLoc, - AccessedEntity::makeMember(NamingClass, Access, MemberOperator)); + AccessedEntity Entity(AccessedEntity::Member, + NamingClass, Access, MemberOperator); + Entity.setDiag(diag::err_access) + << ObjectExpr->getSourceRange() + << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange()); + + return CheckAccess(*this, OpLoc, Entity); } /// Checks access for a hierarchy conversion. @@ -507,31 +546,29 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, /// context had no special privileges /// \param ADK controls the kind of diagnostics that are used Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc, - bool IsBaseToDerived, QualType Base, QualType Derived, const CXXBasePath &Path, + unsigned DiagID, bool ForceCheck, - bool ForceUnprivileged, - AccessDiagnosticsKind ADK) { + bool ForceUnprivileged) { if (!ForceCheck && !getLangOptions().AccessControl) return AR_accessible; if (Path.Access == AS_public) return AR_accessible; - // TODO: preserve the information about which types exactly were used. CXXRecordDecl *BaseD, *DerivedD; BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl()); DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl()); - AccessedEntity Entity = AccessedEntity::makeBaseClass(IsBaseToDerived, - BaseD, DerivedD, - Path.Access); + + AccessedEntity Entity(AccessedEntity::Base, BaseD, DerivedD, Path.Access); + if (DiagID) + Entity.setDiag(DiagID) << Derived << Base; if (ForceUnprivileged) - return CheckEffectiveAccess(*this, EffectiveContext(), - AccessLoc, Entity, ADK); - return CheckAccess(*this, AccessLoc, Entity, ADK); + return CheckEffectiveAccess(*this, EffectiveContext(), AccessLoc, Entity); + return CheckAccess(*this, AccessLoc, Entity); } /// Checks access to all the declarations in the given result set. @@ -540,9 +577,13 @@ void Sema::CheckLookupAccess(const LookupResult &R) { && "performing access check without access control"); assert(R.getNamingClass() && "performing access check without naming class"); - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) - if (I.getAccess() != AS_public) - CheckAccess(*this, R.getNameLoc(), - AccessedEntity::makeMember(R.getNamingClass(), - I.getAccess(), *I)); + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { + if (I.getAccess() != AS_public) { + AccessedEntity Entity(AccessedEntity::Member, + R.getNamingClass(), I.getAccess(), *I); + Entity.setDiag(diag::err_access); + + CheckAccess(*this, R.getNameLoc(), Entity); + } + } } diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index e04abd2aac97..014cec2b650c 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -780,9 +780,9 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, } if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(), - /*IsBaseToDerived*/ true, SrcType, DestType, - Paths.front())) { + Paths.front(), + diag::err_downcast_from_inaccessible_base)) { msg = 0; return TC_Failed; } @@ -858,9 +858,9 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, } if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(), - /*IsBaseToDerived*/ false, DestType, SrcType, - Paths.front())) { + Paths.front(), + diag::err_upcast_to_inaccessible_base)) { msg = 0; return TC_Failed; } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 30a6ab465538..3fac79deba4b 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -59,9 +59,12 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL, // Re-lex the token to get its length and original spelling. std::pair<FileID, unsigned> LocInfo = SourceMgr.getDecomposedLoc(StrTokSpellingLoc); - std::pair<const char *,const char *> Buffer = - SourceMgr.getBufferData(LocInfo.first); - const char *StrData = Buffer.first+LocInfo.second; + bool Invalid = false; + llvm::StringRef Buffer = SourceMgr.getBufferData(LocInfo.first, &Invalid); + if (Invalid) + return StrTokSpellingLoc; + + const char *StrData = Buffer.data()+LocInfo.second; // Create a langops struct and enable trigraphs. This is sufficient for // relexing tokens. @@ -69,8 +72,8 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL, LangOpts.Trigraphs = true; // Create a lexer starting at the beginning of this token. - Lexer TheLexer(StrTokSpellingLoc, LangOpts, Buffer.first, StrData, - Buffer.second); + Lexer TheLexer(StrTokSpellingLoc, LangOpts, Buffer.begin(), StrData, + Buffer.end()); Token TheTok; TheLexer.LexFromRawLexer(TheTok); @@ -2011,10 +2014,9 @@ bool IsSameFloatAfterCast(const APValue &value, /// \param lex the left-hand expression /// \param rex the right-hand expression /// \param OpLoc the location of the joining operator -/// \param Equality whether this is an "equality-like" join, which -/// suppresses the warning in some cases +/// \param BinOpc binary opcode or 0 void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc, - const PartialDiagnostic &PD, bool Equality) { + const BinaryOperator::Opcode* BinOpc) { // Don't warn if we're in an unevaluated context. if (ExprEvalContexts.back().Context == Unevaluated) return; @@ -2075,17 +2077,51 @@ void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc, // If the signed operand is non-negative, then the signed->unsigned // conversion won't change it. - if (signedRange.NonNegative) + if (signedRange.NonNegative) { + // Emit warnings for comparisons of unsigned to integer constant 0. + // always false: x < 0 (or 0 > x) + // always true: x >= 0 (or 0 <= x) + llvm::APSInt X; + if (BinOpc && signedOperand->isIntegerConstantExpr(X, Context) && X == 0) { + if (signedOperand != lex) { + if (*BinOpc == BinaryOperator::LT) { + Diag(OpLoc, diag::warn_lunsigned_always_true_comparison) + << "< 0" << "false" + << lex->getSourceRange() << rex->getSourceRange(); + } + else if (*BinOpc == BinaryOperator::GE) { + Diag(OpLoc, diag::warn_lunsigned_always_true_comparison) + << ">= 0" << "true" + << lex->getSourceRange() << rex->getSourceRange(); + } + } + else { + if (*BinOpc == BinaryOperator::GT) { + Diag(OpLoc, diag::warn_runsigned_always_true_comparison) + << "0 >" << "false" + << lex->getSourceRange() << rex->getSourceRange(); + } + else if (*BinOpc == BinaryOperator::LE) { + Diag(OpLoc, diag::warn_runsigned_always_true_comparison) + << "0 <=" << "true" + << lex->getSourceRange() << rex->getSourceRange(); + } + } + } return; + } // For (in)equality comparisons, if the unsigned operand is a // constant which cannot collide with a overflowed signed operand, // then reinterpreting the signed operand as unsigned will not // change the result of the comparison. - if (Equality && unsignedRange.Width < unsignedWidth) + if (BinOpc && + (*BinOpc == BinaryOperator::EQ || *BinOpc == BinaryOperator::NE) && + unsignedRange.Width < unsignedWidth) return; - Diag(OpLoc, PD) + Diag(OpLoc, BinOpc ? diag::warn_mixed_sign_comparison + : diag::warn_mixed_sign_conditional) << lt << rt << lex->getSourceRange() << rex->getSourceRange(); } diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index edf1bc51eb92..4693fa974edb 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -365,8 +365,7 @@ bool ResultBuilder::isInterestingDecl(NamedDecl *ND, // Friend declarations and declarations introduced due to friends are never // added as results. - if (isa<FriendDecl>(ND) || - (IDNS & (Decl::IDNS_OrdinaryFriend | Decl::IDNS_TagFriend))) + if (IDNS & (Decl::IDNS_OrdinaryFriend | Decl::IDNS_TagFriend)) return false; // Class template (partial) specializations are never added as results. diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 94fcfc6c29e6..dab7d883a1d6 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2262,6 +2262,13 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC, return true; } +static void SetNestedNameSpecifier(DeclaratorDecl *DD, Declarator &D) { + CXXScopeSpec &SS = D.getCXXScopeSpec(); + if (!SS.isSet()) return; + DD->setQualifierInfo(static_cast<NestedNameSpecifier*>(SS.getScopeRep()), + SS.getRange()); +} + NamedDecl* Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, TypeSourceInfo *TInfo, @@ -2371,6 +2378,8 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (D.isInvalidType()) NewVD->setInvalidDecl(); + SetNestedNameSpecifier(NewVD, D); + if (D.getDeclSpec().isThreadSpecified()) { if (NewVD->hasLocalStorage()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_non_global); @@ -2718,6 +2727,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, D.getIdentifierLoc(), Name, R, isInline, /*isImplicitlyDeclared=*/false); + NewFD->setTypeSourceInfo(TInfo); isVirtualOkay = true; } else { @@ -2798,6 +2808,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (D.isInvalidType()) NewFD->setInvalidDecl(); + SetNestedNameSpecifier(NewFD, D); + // Set the lexical context. If the declarator has a C++ // scope specifier, or is the object of a friend declaration, the // lexical context will be different from the semantic context. @@ -4248,9 +4260,10 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, CompoundStmt *Compound = isa<CXXTryStmt>(Body) ? cast<CXXTryStmt>(Body)->getTryBlock() : cast<CompoundStmt>(Body); - std::vector<Stmt*> Elements(Compound->body_begin(), Compound->body_end()); + llvm::SmallVector<Stmt*, 64> Elements(Compound->body_begin(), + Compound->body_end()); Elements.push_back(L); - Compound->setStmts(Context, &Elements[0], Elements.size()); + Compound->setStmts(Context, Elements.data(), Elements.size()); } if (Body) { @@ -4845,6 +4858,13 @@ CreateNewDecl: cast_or_null<RecordDecl>(PrevDecl)); } + // Maybe add qualifier info. + if (SS.isNotEmpty()) { + NestedNameSpecifier *NNS + = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); + New->setQualifierInfo(NNS, SS.getRange()); + } + if (Kind != TagDecl::TK_enum) { // Handle #pragma pack: if the #pragma pack stack has non-default // alignment, make up a packed attribute for this decl. These diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 242d66fa521f..73a34f8107e0 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -1945,11 +1945,19 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) { NewD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(), FD->getLocation(), DeclarationName(II), FD->getType(), FD->getTypeSourceInfo()); + if (FD->getQualifier()) { + FunctionDecl *NewFD = cast<FunctionDecl>(NewD); + NewFD->setQualifierInfo(FD->getQualifier(), FD->getQualifierRange()); + } } else if (VarDecl *VD = dyn_cast<VarDecl>(ND)) { NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(), VD->getLocation(), II, VD->getType(), VD->getTypeSourceInfo(), VD->getStorageClass()); + if (VD->getQualifier()) { + VarDecl *NewVD = cast<VarDecl>(NewD); + NewVD->setQualifierInfo(VD->getQualifier(), VD->getQualifierRange()); + } } return NewD; } @@ -2030,6 +2038,8 @@ void Sema::PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy Ctx) { assert(SavedIndex <= DelayedDiagnostics.size() && "saved index is out of bounds"); + unsigned E = DelayedDiagnostics.size(); + // We only want to actually emit delayed diagnostics when we // successfully parsed a decl. Decl *D = Ctx ? Ctx.getAs<Decl>() : 0; @@ -2040,7 +2050,7 @@ void Sema::PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy Ctx) { // only the declarator pops will be passed decls. This is correct; // we really do need to consider delayed diagnostics from the decl spec // for each of the different declarations. - for (unsigned I = 0, E = DelayedDiagnostics.size(); I != E; ++I) { + for (unsigned I = 0; I != E; ++I) { if (DelayedDiagnostics[I].Triggered) continue; @@ -2056,6 +2066,10 @@ void Sema::PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy Ctx) { } } + // Destroy all the delayed diagnostics we're about to pop off. + for (unsigned I = SavedIndex; I != E; ++I) + DelayedDiagnostics[I].destroy(); + DelayedDiagnostics.set_size(SavedIndex); } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index e694cb470c25..c27b0d5013c6 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -298,6 +298,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { Invalid = true; } else if (OldParam->hasDefaultArg()) { // Merge the old default argument into the new parameter + NewParam->setHasInheritedDefaultArg(); if (OldParam->hasUninstantiatedDefaultArg()) NewParam->setUninstantiatedDefaultArg( OldParam->getUninstantiatedDefaultArg()); @@ -719,7 +720,7 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) { /// if there is an error. bool Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, - AccessDiagnosticsKind ADK, + unsigned InaccessibleBaseID, unsigned AmbigiousBaseConvID, SourceLocation Loc, SourceRange Range, DeclarationName Name) { @@ -735,15 +736,12 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, (void)DerivationOkay; if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) { - if (ADK == ADK_quiet) + if (!InaccessibleBaseID) return false; // Check that the base class can be accessed. - switch (CheckBaseClassAccess(Loc, /*IsBaseToDerived*/ false, - Base, Derived, Paths.front(), - /*force*/ false, - /*unprivileged*/ false, - ADK)) { + switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(), + InaccessibleBaseID)) { case AR_accessible: return false; case AR_inaccessible: return true; case AR_dependent: return false; @@ -779,7 +777,8 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, SourceLocation Loc, SourceRange Range, bool IgnoreAccess) { return CheckDerivedToBaseConversion(Derived, Base, - IgnoreAccess ? ADK_quiet : ADK_normal, + IgnoreAccess ? 0 + : diag::err_upcast_to_inaccessible_base, diag::err_ambiguous_derived_to_base_conv, Loc, Range, DeclarationName()); } @@ -1657,6 +1656,11 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, continue; CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl()); + + // We don't know if a dependent type will have an implicit destructor. + if (BaseClassDecl->isDependentType()) + continue; + if (BaseClassDecl->hasTrivialDestructor()) continue; CXXDestructorDecl *DD = BaseClassDecl->getDestructor(Context); @@ -1848,6 +1852,11 @@ Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) { // Ignore dependent destructors. if (Destructor->isDependentContext()) return; + + // FIXME: all the access-control diagnostics are positioned on the + // field/base declaration. That's probably good; that said, the + // user might reasonably want to know why the destructor is being + // emitted, and we currently don't say. CXXRecordDecl *ClassDecl = Destructor->getParent(); @@ -1866,25 +1875,41 @@ Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) { if (FieldClassDecl->hasTrivialDestructor()) continue; - const CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor(Context); + CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor(Context); + CheckDestructorAccess(Field->getLocation(), Dtor, + PartialDiagnostic(diag::err_access_dtor_field) + << Field->getDeclName() + << FieldType); + MarkDeclarationReferenced(Destructor->getLocation(), const_cast<CXXDestructorDecl*>(Dtor)); } + llvm::SmallPtrSet<const RecordType *, 8> DirectVirtualBases; + // Bases. for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), E = ClassDecl->bases_end(); Base != E; ++Base) { - // Ignore virtual bases. + // Bases are always records in a well-formed non-dependent class. + const RecordType *RT = Base->getType()->getAs<RecordType>(); + + // Remember direct virtual bases. if (Base->isVirtual()) - continue; + DirectVirtualBases.insert(RT); // Ignore trivial destructors. - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl()); if (BaseClassDecl->hasTrivialDestructor()) continue; + + CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context); + + // FIXME: caret should be on the start of the class name + CheckDestructorAccess(Base->getSourceRange().getBegin(), Dtor, + PartialDiagnostic(diag::err_access_dtor_base) + << Base->getType() + << Base->getSourceRange()); - const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context); MarkDeclarationReferenced(Destructor->getLocation(), const_cast<CXXDestructorDecl*>(Dtor)); } @@ -1892,13 +1917,24 @@ Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) { // Virtual bases. for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); VBase != E; ++VBase) { + + // Bases are always records in a well-formed non-dependent class. + const RecordType *RT = VBase->getType()->getAs<RecordType>(); + + // Ignore direct virtual bases. + if (DirectVirtualBases.count(RT)) + continue; + // Ignore trivial destructors. - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl()); + CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl()); if (BaseClassDecl->hasTrivialDestructor()) continue; - - const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context); + + CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context); + CheckDestructorAccess(ClassDecl->getLocation(), Dtor, + PartialDiagnostic(diag::err_access_dtor_vbase) + << VBase->getType()); + MarkDeclarationReferenced(Destructor->getLocation(), const_cast<CXXDestructorDecl*>(Dtor)); } @@ -2392,22 +2428,26 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { // If a class has no user-declared destructor, a destructor is // declared implicitly. An implicitly-declared destructor is an // inline public member of its class. + QualType Ty = Context.getFunctionType(Context.VoidTy, + 0, 0, false, 0, + /*FIXME:*/false, + false, 0, 0, false, + CC_Default); + DeclarationName Name = Context.DeclarationNames.getCXXDestructorName(ClassType); CXXDestructorDecl *Destructor = CXXDestructorDecl::Create(Context, ClassDecl, - ClassDecl->getLocation(), Name, - Context.getFunctionType(Context.VoidTy, - 0, 0, false, 0, - /*FIXME:*/false, - false, 0, 0, false, - CC_Default), + ClassDecl->getLocation(), Name, Ty, /*isInline=*/true, /*isImplicitlyDeclared=*/true); Destructor->setAccess(AS_public); Destructor->setImplicit(); Destructor->setTrivial(ClassDecl->hasTrivialDestructor()); ClassDecl->addDecl(Destructor); + + // This could be uniqued if it ever proves significant. + Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty)); AddOverriddenMethods(ClassDecl, Destructor); } @@ -3779,45 +3819,8 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, DeclContext *PreviousContext = CurContext; CurContext = Destructor; - // C++ [class.dtor] p5 - // Before the implicitly-declared default destructor for a class is - // implicitly defined, all the implicitly-declared default destructors - // for its base class and its non-static data members shall have been - // implicitly defined. - for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), - E = ClassDecl->bases_end(); Base != E; ++Base) { - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - if (!BaseClassDecl->hasTrivialDestructor()) { - if (CXXDestructorDecl *BaseDtor = - const_cast<CXXDestructorDecl*>(BaseClassDecl->getDestructor(Context))) - MarkDeclarationReferenced(CurrentLocation, BaseDtor); - else - assert(false && - "DefineImplicitDestructor - missing dtor in a base class"); - } - } + MarkBaseAndMemberDestructorsReferenced(Destructor); - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - E = ClassDecl->field_end(); Field != E; ++Field) { - QualType FieldType = Context.getCanonicalType((*Field)->getType()); - if (const ArrayType *Array = Context.getAsArrayType(FieldType)) - FieldType = Array->getElementType(); - if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { - CXXRecordDecl *FieldClassDecl - = cast<CXXRecordDecl>(FieldClassType->getDecl()); - if (!FieldClassDecl->hasTrivialDestructor()) { - if (CXXDestructorDecl *FieldDtor = - const_cast<CXXDestructorDecl*>( - FieldClassDecl->getDestructor(Context))) - MarkDeclarationReferenced(CurrentLocation, FieldDtor); - else - assert(false && - "DefineImplicitDestructor - missing dtor in class of a data member"); - } - } - } - // FIXME: If CheckDestructor fails, we should emit a note about where the // implicit destructor was needed. if (CheckDestructor(Destructor)) { @@ -3859,8 +3862,14 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); if (CXXMethodDecl *BaseAssignOpMethod = getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0), - BaseClassDecl)) + BaseClassDecl)) { + CheckDirectMemberAccess(Base->getSourceRange().getBegin(), + BaseAssignOpMethod, + PartialDiagnostic(diag::err_access_assign_base) + << Base->getType()); + MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod); + } } for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), E = ClassDecl->field_end(); Field != E; ++Field) { @@ -3872,8 +3881,14 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, = cast<CXXRecordDecl>(FieldClassType->getDecl()); if (CXXMethodDecl *FieldAssignOpMethod = getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0), - FieldClassDecl)) + FieldClassDecl)) { + CheckDirectMemberAccess(Field->getLocation(), + FieldAssignOpMethod, + PartialDiagnostic(diag::err_access_assign_field) + << Field->getDeclName() << Field->getType()); + MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod); + } } else if (FieldType->isReferenceType()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); @@ -3948,8 +3963,14 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); if (CXXConstructorDecl *BaseCopyCtor = - BaseClassDecl->getCopyConstructor(Context, TypeQuals)) + BaseClassDecl->getCopyConstructor(Context, TypeQuals)) { + CheckDirectMemberAccess(Base->getSourceRange().getBegin(), + BaseCopyCtor, + PartialDiagnostic(diag::err_access_copy_base) + << Base->getType()); + MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor); + } } for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); @@ -3961,8 +3982,14 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(FieldClassType->getDecl()); if (CXXConstructorDecl *FieldCopyCtor = - FieldClassDecl->getCopyConstructor(Context, TypeQuals)) + FieldClassDecl->getCopyConstructor(Context, TypeQuals)) { + CheckDirectMemberAccess(Field->getLocation(), + FieldCopyCtor, + PartialDiagnostic(diag::err_access_copy_field) + << Field->getDeclName() << Field->getType()); + MarkDeclarationReferenced(CurrentLocation, FieldCopyCtor); + } } } CopyConstructor->setUsed(); @@ -4052,7 +4079,10 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { !ClassDecl->hasTrivialDestructor()) { CXXDestructorDecl *Destructor = ClassDecl->getDestructor(Context); MarkDeclarationReferenced(VD->getLocation(), Destructor); - CheckDestructorAccess(VD->getLocation(), Record); + CheckDestructorAccess(VD->getLocation(), Destructor, + PartialDiagnostic(diag::err_access_dtor_var) + << VD->getDeclName() + << VD->getType()); } } @@ -5715,7 +5745,8 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, } // Check if we the conversion from derived to base is valid. - if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy, ADK_covariance, + if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy, + diag::err_covariant_return_inaccessible_base, diag::err_covariant_return_ambiguous_derived_to_base_conv, // FIXME: Should this point to the return type? New->getLocation(), SourceRange(), New->getDeclName())) { diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 762ef38c9736..b2f671760ebe 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -20,25 +20,6 @@ #include "clang/Parse/DeclSpec.h" using namespace clang; -bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property, - ObjCMethodDecl *GetterMethod, - SourceLocation Loc) { - if (GetterMethod && - GetterMethod->getResultType() != property->getType()) { - AssignConvertType result = Incompatible; - if (property->getType()->isObjCObjectPointerType()) - result = CheckAssignmentConstraints(GetterMethod->getResultType(), property->getType()); - if (result != Compatible) { - Diag(Loc, diag::warn_accessor_property_type_mismatch) - << property->getDeclName() - << GetterMethod->getSelector(); - Diag(GetterMethod->getLocation(), diag::note_declared_at); - return true; - } - } - return false; -} - /// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible /// and user declared, in the method definition's AST. void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) { @@ -361,171 +342,6 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, } } -/// DiagnosePropertyMismatch - Compares two properties for their -/// attributes and types and warns on a variety of inconsistencies. -/// -void -Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property, - ObjCPropertyDecl *SuperProperty, - const IdentifierInfo *inheritedName) { - ObjCPropertyDecl::PropertyAttributeKind CAttr = - Property->getPropertyAttributes(); - ObjCPropertyDecl::PropertyAttributeKind SAttr = - SuperProperty->getPropertyAttributes(); - if ((CAttr & ObjCPropertyDecl::OBJC_PR_readonly) - && (SAttr & ObjCPropertyDecl::OBJC_PR_readwrite)) - Diag(Property->getLocation(), diag::warn_readonly_property) - << Property->getDeclName() << inheritedName; - if ((CAttr & ObjCPropertyDecl::OBJC_PR_copy) - != (SAttr & ObjCPropertyDecl::OBJC_PR_copy)) - Diag(Property->getLocation(), diag::warn_property_attribute) - << Property->getDeclName() << "copy" << inheritedName; - else if ((CAttr & ObjCPropertyDecl::OBJC_PR_retain) - != (SAttr & ObjCPropertyDecl::OBJC_PR_retain)) - Diag(Property->getLocation(), diag::warn_property_attribute) - << Property->getDeclName() << "retain" << inheritedName; - - if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic) - != (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)) - Diag(Property->getLocation(), diag::warn_property_attribute) - << Property->getDeclName() << "atomic" << inheritedName; - if (Property->getSetterName() != SuperProperty->getSetterName()) - Diag(Property->getLocation(), diag::warn_property_attribute) - << Property->getDeclName() << "setter" << inheritedName; - if (Property->getGetterName() != SuperProperty->getGetterName()) - Diag(Property->getLocation(), diag::warn_property_attribute) - << Property->getDeclName() << "getter" << inheritedName; - - QualType LHSType = - Context.getCanonicalType(SuperProperty->getType()); - QualType RHSType = - Context.getCanonicalType(Property->getType()); - - if (!Context.typesAreCompatible(LHSType, RHSType)) { - // FIXME: Incorporate this test with typesAreCompatible. - if (LHSType->isObjCQualifiedIdType() && RHSType->isObjCQualifiedIdType()) - if (Context.ObjCQualifiedIdTypesAreCompatible(LHSType, RHSType, false)) - return; - Diag(Property->getLocation(), diag::warn_property_types_are_incompatible) - << Property->getType() << SuperProperty->getType() << inheritedName; - } -} - -/// ComparePropertiesInBaseAndSuper - This routine compares property -/// declarations in base and its super class, if any, and issues -/// diagnostics in a variety of inconsistant situations. -/// -void Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) { - ObjCInterfaceDecl *SDecl = IDecl->getSuperClass(); - if (!SDecl) - return; - // FIXME: O(N^2) - for (ObjCInterfaceDecl::prop_iterator S = SDecl->prop_begin(), - E = SDecl->prop_end(); S != E; ++S) { - ObjCPropertyDecl *SuperPDecl = (*S); - // Does property in super class has declaration in current class? - for (ObjCInterfaceDecl::prop_iterator I = IDecl->prop_begin(), - E = IDecl->prop_end(); I != E; ++I) { - ObjCPropertyDecl *PDecl = (*I); - if (SuperPDecl->getIdentifier() == PDecl->getIdentifier()) - DiagnosePropertyMismatch(PDecl, SuperPDecl, - SDecl->getIdentifier()); - } - } -} - -/// MatchOneProtocolPropertiesInClass - This routine goes thru the list -/// of properties declared in a protocol and compares their attribute against -/// the same property declared in the class or category. -void -Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl, - ObjCProtocolDecl *PDecl) { - ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl); - if (!IDecl) { - // Category - ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl); - assert (CatDecl && "MatchOneProtocolPropertiesInClass"); - if (!CatDecl->IsClassExtension()) - for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), - E = PDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Pr = (*P); - ObjCCategoryDecl::prop_iterator CP, CE; - // Is this property already in category's list of properties? - for (CP = CatDecl->prop_begin(), CE = CatDecl->prop_end(); CP != CE; ++CP) - if ((*CP)->getIdentifier() == Pr->getIdentifier()) - break; - if (CP != CE) - // Property protocol already exist in class. Diagnose any mismatch. - DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier()); - } - return; - } - for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), - E = PDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Pr = (*P); - ObjCInterfaceDecl::prop_iterator CP, CE; - // Is this property already in class's list of properties? - for (CP = IDecl->prop_begin(), CE = IDecl->prop_end(); CP != CE; ++CP) - if ((*CP)->getIdentifier() == Pr->getIdentifier()) - break; - if (CP != CE) - // Property protocol already exist in class. Diagnose any mismatch. - DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier()); - } -} - -/// CompareProperties - This routine compares properties -/// declared in 'ClassOrProtocol' objects (which can be a class or an -/// inherited protocol with the list of properties for class/category 'CDecl' -/// -void Sema::CompareProperties(Decl *CDecl, - DeclPtrTy ClassOrProtocol) { - Decl *ClassDecl = ClassOrProtocol.getAs<Decl>(); - ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl); - - if (!IDecl) { - // Category - ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl); - assert (CatDecl && "CompareProperties"); - if (ObjCCategoryDecl *MDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) { - for (ObjCCategoryDecl::protocol_iterator P = MDecl->protocol_begin(), - E = MDecl->protocol_end(); P != E; ++P) - // Match properties of category with those of protocol (*P) - MatchOneProtocolPropertiesInClass(CatDecl, *P); - - // Go thru the list of protocols for this category and recursively match - // their properties with those in the category. - for (ObjCCategoryDecl::protocol_iterator P = CatDecl->protocol_begin(), - E = CatDecl->protocol_end(); P != E; ++P) - CompareProperties(CatDecl, DeclPtrTy::make(*P)); - } else { - ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl); - for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(), - E = MD->protocol_end(); P != E; ++P) - MatchOneProtocolPropertiesInClass(CatDecl, *P); - } - return; - } - - if (ObjCInterfaceDecl *MDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) { - for (ObjCInterfaceDecl::protocol_iterator P = MDecl->protocol_begin(), - E = MDecl->protocol_end(); P != E; ++P) - // Match properties of class IDecl with those of protocol (*P). - MatchOneProtocolPropertiesInClass(IDecl, *P); - - // Go thru the list of protocols for this class and recursively match - // their properties with those declared in the class. - for (ObjCInterfaceDecl::protocol_iterator P = IDecl->protocol_begin(), - E = IDecl->protocol_end(); P != E; ++P) - CompareProperties(IDecl, DeclPtrTy::make(*P)); - } else { - ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl); - for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(), - E = MD->protocol_end(); P != E; ++P) - MatchOneProtocolPropertiesInClass(IDecl, *P); - } -} - /// DiagnoseClassExtensionDupMethods - Check for duplicate declaration of /// a class method in its extension. /// @@ -941,57 +757,6 @@ void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl, } } -/// isPropertyReadonly - Return true if property is readonly, by searching -/// for the property in the class and in its categories and implementations -/// -bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl, - ObjCInterfaceDecl *IDecl) { - // by far the most common case. - if (!PDecl->isReadOnly()) - return false; - // Even if property is ready only, if interface has a user defined setter, - // it is not considered read only. - if (IDecl->getInstanceMethod(PDecl->getSetterName())) - return false; - - // Main class has the property as 'readonly'. Must search - // through the category list to see if the property's - // attribute has been over-ridden to 'readwrite'. - for (ObjCCategoryDecl *Category = IDecl->getCategoryList(); - Category; Category = Category->getNextClassCategory()) { - // Even if property is ready only, if a category has a user defined setter, - // it is not considered read only. - if (Category->getInstanceMethod(PDecl->getSetterName())) - return false; - ObjCPropertyDecl *P = - Category->FindPropertyDeclaration(PDecl->getIdentifier()); - if (P && !P->isReadOnly()) - return false; - } - - // Also, check for definition of a setter method in the implementation if - // all else failed. - if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(CurContext)) { - if (ObjCImplementationDecl *IMD = - dyn_cast<ObjCImplementationDecl>(OMD->getDeclContext())) { - if (IMD->getInstanceMethod(PDecl->getSetterName())) - return false; - } else if (ObjCCategoryImplDecl *CIMD = - dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) { - if (CIMD->getInstanceMethod(PDecl->getSetterName())) - return false; - } - } - // Lastly, look through the implementation (if one is in scope). - if (ObjCImplementationDecl *ImpDecl = IDecl->getImplementation()) - if (ImpDecl->getInstanceMethod(PDecl->getSetterName())) - return false; - // If all fails, look at the super class. - if (ObjCInterfaceDecl *SIDecl = IDecl->getSuperClass()) - return isPropertyReadonly(PDecl, SIDecl); - return true; -} - /// FIXME: Type hierarchies in Objective-C can be deep. We could most likely /// improve the efficiency of selector lookups and type checking by associating /// with each protocol / interface / category the flattened instance tables. If @@ -1131,140 +896,6 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, } } -/// CollectImmediateProperties - This routine collects all properties in -/// the class and its conforming protocols; but not those it its super class. -void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, - llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) { - if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) { - for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(), - E = IDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Prop = (*P); - PropMap[Prop->getIdentifier()] = Prop; - } - // scan through class's protocols. - for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(), - E = IDecl->protocol_end(); PI != E; ++PI) - CollectImmediateProperties((*PI), PropMap); - } - if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) { - if (!CATDecl->IsClassExtension()) - for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(), - E = CATDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Prop = (*P); - PropMap[Prop->getIdentifier()] = Prop; - } - // scan through class's protocols. - for (ObjCInterfaceDecl::protocol_iterator PI = CATDecl->protocol_begin(), - E = CATDecl->protocol_end(); PI != E; ++PI) - CollectImmediateProperties((*PI), PropMap); - } - else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) { - for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), - E = PDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Prop = (*P); - ObjCPropertyDecl *&PropEntry = PropMap[Prop->getIdentifier()]; - if (!PropEntry) - PropEntry = Prop; - } - // scan through protocol's protocols. - for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), - E = PDecl->protocol_end(); PI != E; ++PI) - CollectImmediateProperties((*PI), PropMap); - } -} - -/// LookupPropertyDecl - Looks up a property in the current class and all -/// its protocols. -ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl, - IdentifierInfo *II) { - if (const ObjCInterfaceDecl *IDecl = - dyn_cast<ObjCInterfaceDecl>(CDecl)) { - for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(), - E = IDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Prop = (*P); - if (Prop->getIdentifier() == II) - return Prop; - } - // scan through class's protocols. - for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(), - E = IDecl->protocol_end(); PI != E; ++PI) { - ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II); - if (Prop) - return Prop; - } - } - else if (const ObjCProtocolDecl *PDecl = - dyn_cast<ObjCProtocolDecl>(CDecl)) { - for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), - E = PDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Prop = (*P); - if (Prop->getIdentifier() == II) - return Prop; - } - // scan through protocol's protocols. - for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), - E = PDecl->protocol_end(); PI != E; ++PI) { - ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II); - if (Prop) - return Prop; - } - } - return 0; -} - - -void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, - ObjCContainerDecl *CDecl, - const llvm::DenseSet<Selector>& InsMap) { - llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap; - CollectImmediateProperties(CDecl, PropMap); - if (PropMap.empty()) - return; - - llvm::DenseSet<ObjCPropertyDecl *> PropImplMap; - for (ObjCImplDecl::propimpl_iterator - I = IMPDecl->propimpl_begin(), - EI = IMPDecl->propimpl_end(); I != EI; ++I) - PropImplMap.insert((*I)->getPropertyDecl()); - - for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator - P = PropMap.begin(), E = PropMap.end(); P != E; ++P) { - ObjCPropertyDecl *Prop = P->second; - // Is there a matching propery synthesize/dynamic? - if (Prop->isInvalidDecl() || - Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional || - PropImplMap.count(Prop)) - continue; - if (LangOpts.ObjCNonFragileABI2) { - ActOnPropertyImplDecl(IMPDecl->getLocation(), - SourceLocation(), - true, DeclPtrTy::make(IMPDecl), - Prop->getIdentifier(), - Prop->getIdentifier()); - continue; - } - if (!InsMap.count(Prop->getGetterName())) { - Diag(Prop->getLocation(), - isa<ObjCCategoryDecl>(CDecl) ? - diag::warn_setter_getter_impl_required_in_category : - diag::warn_setter_getter_impl_required) - << Prop->getDeclName() << Prop->getGetterName(); - Diag(IMPDecl->getLocation(), - diag::note_property_impl_required); - } - - if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) { - Diag(Prop->getLocation(), - isa<ObjCCategoryDecl>(CDecl) ? - diag::warn_setter_getter_impl_required_in_category : - diag::warn_setter_getter_impl_required) - << Prop->getDeclName() << Prop->getSetterName(); - Diag(IMPDecl->getLocation(), - diag::note_property_impl_required); - } - } -} - void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, ObjCContainerDecl* CDecl, bool IncompleteImpl) { @@ -1336,41 +967,6 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, assert(false && "invalid ObjCContainerDecl type."); } -void -Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, - ObjCContainerDecl* IDecl) { - // Rules apply in non-GC mode only - if (getLangOptions().getGCMode() != LangOptions::NonGC) - return; - for (ObjCContainerDecl::prop_iterator I = IDecl->prop_begin(), - E = IDecl->prop_end(); - I != E; ++I) { - ObjCPropertyDecl *Property = (*I); - unsigned Attributes = Property->getPropertyAttributes(); - // We only care about readwrite atomic property. - if ((Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) || - !(Attributes & ObjCPropertyDecl::OBJC_PR_readwrite)) - continue; - if (const ObjCPropertyImplDecl *PIDecl - = IMPDecl->FindPropertyImplDecl(Property->getIdentifier())) { - if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) - continue; - ObjCMethodDecl *GetterMethod = - IMPDecl->getInstanceMethod(Property->getGetterName()); - ObjCMethodDecl *SetterMethod = - IMPDecl->getInstanceMethod(Property->getSetterName()); - if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) { - SourceLocation MethodLoc = - (GetterMethod ? GetterMethod->getLocation() - : SetterMethod->getLocation()); - Diag(MethodLoc, diag::warn_atomic_property_rule) - << Property->getIdentifier(); - Diag(Property->getLocation(), diag::note_property_declare); - } - } - } -} - /// ActOnForwardClassDeclaration - Action::DeclPtrTy Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, @@ -1638,111 +1234,6 @@ ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel, return MethList.Method; } -/// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods -/// have the property type and issue diagnostics if they don't. -/// Also synthesize a getter/setter method if none exist (and update the -/// appropriate lookup tables. FIXME: Should reconsider if adding synthesized -/// methods is the "right" thing to do. -void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, - ObjCContainerDecl *CD) { - ObjCMethodDecl *GetterMethod, *SetterMethod; - - GetterMethod = CD->getInstanceMethod(property->getGetterName()); - SetterMethod = CD->getInstanceMethod(property->getSetterName()); - DiagnosePropertyAccessorMismatch(property, GetterMethod, - property->getLocation()); - - if (SetterMethod) { - ObjCPropertyDecl::PropertyAttributeKind CAttr = - property->getPropertyAttributes(); - if ((!(CAttr & ObjCPropertyDecl::OBJC_PR_readonly)) && - Context.getCanonicalType(SetterMethod->getResultType()) != - Context.VoidTy) - Diag(SetterMethod->getLocation(), diag::err_setter_type_void); - if (SetterMethod->param_size() != 1 || - ((*SetterMethod->param_begin())->getType() != property->getType())) { - Diag(property->getLocation(), - diag::warn_accessor_property_type_mismatch) - << property->getDeclName() - << SetterMethod->getSelector(); - Diag(SetterMethod->getLocation(), diag::note_declared_at); - } - } - - // Synthesize getter/setter methods if none exist. - // Find the default getter and if one not found, add one. - // FIXME: The synthesized property we set here is misleading. We almost always - // synthesize these methods unless the user explicitly provided prototypes - // (which is odd, but allowed). Sema should be typechecking that the - // declarations jive in that situation (which it is not currently). - if (!GetterMethod) { - // No instance method of same name as property getter name was found. - // Declare a getter method and add it to the list of methods - // for this class. - GetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(), - property->getLocation(), property->getGetterName(), - property->getType(), 0, CD, true, false, true, - (property->getPropertyImplementation() == - ObjCPropertyDecl::Optional) ? - ObjCMethodDecl::Optional : - ObjCMethodDecl::Required); - CD->addDecl(GetterMethod); - } else - // A user declared getter will be synthesize when @synthesize of - // the property with the same name is seen in the @implementation - GetterMethod->setSynthesized(true); - property->setGetterMethodDecl(GetterMethod); - - // Skip setter if property is read-only. - if (!property->isReadOnly()) { - // Find the default setter and if one not found, add one. - if (!SetterMethod) { - // No instance method of same name as property setter name was found. - // Declare a setter method and add it to the list of methods - // for this class. - SetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(), - property->getLocation(), - property->getSetterName(), - Context.VoidTy, 0, CD, true, false, true, - (property->getPropertyImplementation() == - ObjCPropertyDecl::Optional) ? - ObjCMethodDecl::Optional : - ObjCMethodDecl::Required); - // Invent the arguments for the setter. We don't bother making a - // nice name for the argument. - ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod, - property->getLocation(), - property->getIdentifier(), - property->getType(), - /*TInfo=*/0, - VarDecl::None, - 0); - SetterMethod->setMethodParams(Context, &Argument, 1); - CD->addDecl(SetterMethod); - } else - // A user declared setter will be synthesize when @synthesize of - // the property with the same name is seen in the @implementation - SetterMethod->setSynthesized(true); - property->setSetterMethodDecl(SetterMethod); - } - // Add any synthesized methods to the global pool. This allows us to - // handle the following, which is supported by GCC (and part of the design). - // - // @interface Foo - // @property double bar; - // @end - // - // void thisIsUnfortunate() { - // id foo; - // double bar = [foo bar]; - // } - // - if (GetterMethod) - AddInstanceMethodToGlobalPool(GetterMethod); - if (SetterMethod) - AddInstanceMethodToGlobalPool(SetterMethod); -} - /// CompareMethodParamsInBaseAndSuper - This routine compares methods with /// identical selector names in current and its super classes and issues /// a warning if any of their argument types are incompatible. @@ -2106,501 +1597,6 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( return DeclPtrTy::make(ObjCMethod); } -void Sema::CheckObjCPropertyAttributes(QualType PropertyTy, - SourceLocation Loc, - unsigned &Attributes) { - // FIXME: Improve the reported location. - - // readonly and readwrite/assign/retain/copy conflict. - if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) && - (Attributes & (ObjCDeclSpec::DQ_PR_readwrite | - ObjCDeclSpec::DQ_PR_assign | - ObjCDeclSpec::DQ_PR_copy | - ObjCDeclSpec::DQ_PR_retain))) { - const char * which = (Attributes & ObjCDeclSpec::DQ_PR_readwrite) ? - "readwrite" : - (Attributes & ObjCDeclSpec::DQ_PR_assign) ? - "assign" : - (Attributes & ObjCDeclSpec::DQ_PR_copy) ? - "copy" : "retain"; - - Diag(Loc, (Attributes & (ObjCDeclSpec::DQ_PR_readwrite)) ? - diag::err_objc_property_attr_mutually_exclusive : - diag::warn_objc_property_attr_mutually_exclusive) - << "readonly" << which; - } - - // Check for copy or retain on non-object types. - if ((Attributes & (ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) && - !PropertyTy->isObjCObjectPointerType() && - !PropertyTy->isBlockPointerType() && - !Context.isObjCNSObjectType(PropertyTy)) { - Diag(Loc, diag::err_objc_property_requires_object) - << (Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain"); - Attributes &= ~(ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain); - } - - // Check for more than one of { assign, copy, retain }. - if (Attributes & ObjCDeclSpec::DQ_PR_assign) { - if (Attributes & ObjCDeclSpec::DQ_PR_copy) { - Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) - << "assign" << "copy"; - Attributes &= ~ObjCDeclSpec::DQ_PR_copy; - } - if (Attributes & ObjCDeclSpec::DQ_PR_retain) { - Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) - << "assign" << "retain"; - Attributes &= ~ObjCDeclSpec::DQ_PR_retain; - } - } else if (Attributes & ObjCDeclSpec::DQ_PR_copy) { - if (Attributes & ObjCDeclSpec::DQ_PR_retain) { - Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) - << "copy" << "retain"; - Attributes &= ~ObjCDeclSpec::DQ_PR_retain; - } - } - - // Warn if user supplied no assignment attribute, property is - // readwrite, and this is an object type. - if (!(Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_copy | - ObjCDeclSpec::DQ_PR_retain)) && - !(Attributes & ObjCDeclSpec::DQ_PR_readonly) && - PropertyTy->isObjCObjectPointerType()) { - // Skip this warning in gc-only mode. - if (getLangOptions().getGCMode() != LangOptions::GCOnly) - Diag(Loc, diag::warn_objc_property_no_assignment_attribute); - - // If non-gc code warn that this is likely inappropriate. - if (getLangOptions().getGCMode() == LangOptions::NonGC) - Diag(Loc, diag::warn_objc_property_default_assign_on_object); - - // FIXME: Implement warning dependent on NSCopying being - // implemented. See also: - // <rdar://5168496&4855821&5607453&5096644&4947311&5698469&4947014&5168496> - // (please trim this list while you are at it). - } - - if (!(Attributes & ObjCDeclSpec::DQ_PR_copy) - && getLangOptions().getGCMode() == LangOptions::GCOnly - && PropertyTy->isBlockPointerType()) - Diag(Loc, diag::warn_objc_property_copy_missing_on_block); -} - -Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, - FieldDeclarator &FD, - ObjCDeclSpec &ODS, - Selector GetterSel, - Selector SetterSel, - DeclPtrTy ClassCategory, - bool *isOverridingProperty, - tok::ObjCKeywordKind MethodImplKind) { - unsigned Attributes = ODS.getPropertyAttributes(); - bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) || - // default is readwrite! - !(Attributes & ObjCDeclSpec::DQ_PR_readonly)); - // property is defaulted to 'assign' if it is readwrite and is - // not retain or copy - bool isAssign = ((Attributes & ObjCDeclSpec::DQ_PR_assign) || - (isReadWrite && - !(Attributes & ObjCDeclSpec::DQ_PR_retain) && - !(Attributes & ObjCDeclSpec::DQ_PR_copy))); - QualType T = GetTypeForDeclarator(FD.D, S); - if (T->isReferenceType()) { - Diag(AtLoc, diag::error_reference_property); - return DeclPtrTy(); - } - Decl *ClassDecl = ClassCategory.getAs<Decl>(); - ObjCInterfaceDecl *CCPrimary = 0; // continuation class's primary class - // May modify Attributes. - CheckObjCPropertyAttributes(T, AtLoc, Attributes); - if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) - if (CDecl->IsClassExtension()) { - // Diagnose if this property is already in continuation class. - DeclContext *DC = dyn_cast<DeclContext>(ClassDecl); - assert(DC && "ClassDecl is not a DeclContext"); - DeclContext::lookup_result Found = DC->lookup(FD.D.getIdentifier()); - if (Found.first != Found.second && isa<ObjCPropertyDecl>(*Found.first)) { - Diag(AtLoc, diag::err_duplicate_property); - Diag((*Found.first)->getLocation(), diag::note_property_declare); - return DeclPtrTy(); - } - ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, - FD.D.getIdentifierLoc(), - FD.D.getIdentifier(), - AtLoc, T); - DC->addDecl(PDecl); - - // This is a continuation class. property requires special - // handling. - if ((CCPrimary = CDecl->getClassInterface())) { - // Find the property in continuation class's primary class only. - IdentifierInfo *PropertyId = FD.D.getIdentifier(); - if (ObjCPropertyDecl *PIDecl = - CCPrimary->FindPropertyVisibleInPrimaryClass(PropertyId)) { - // property 'PIDecl's readonly attribute will be over-ridden - // with continuation class's readwrite property attribute! - unsigned PIkind = PIDecl->getPropertyAttributes(); - if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) { - unsigned retainCopyNonatomic = - (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_copy | - ObjCPropertyDecl::OBJC_PR_nonatomic); - if ((Attributes & retainCopyNonatomic) != - (PIkind & retainCopyNonatomic)) { - Diag(AtLoc, diag::warn_property_attr_mismatch); - Diag(PIDecl->getLocation(), diag::note_property_declare); - } - DeclContext *DC = dyn_cast<DeclContext>(CCPrimary); - assert(DC && "ClassDecl is not a DeclContext"); - DeclContext::lookup_result Found = - DC->lookup(PIDecl->getDeclName()); - bool PropertyInPrimaryClass = false; - for (; Found.first != Found.second; ++Found.first) - if (isa<ObjCPropertyDecl>(*Found.first)) { - PropertyInPrimaryClass = true; - break; - } - if (!PropertyInPrimaryClass) { - // Protocol is not in the primary class. Must build one for it. - ObjCDeclSpec ProtocolPropertyODS; - // FIXME. Assuming that ObjCDeclSpec::ObjCPropertyAttributeKind and - // ObjCPropertyDecl::PropertyAttributeKind have identical values. - // Should consolidate both into one enum type. - ProtocolPropertyODS.setPropertyAttributes( - (ObjCDeclSpec::ObjCPropertyAttributeKind)PIkind); - DeclPtrTy ProtocolPtrTy = - ActOnProperty(S, AtLoc, FD, ProtocolPropertyODS, - PIDecl->getGetterName(), - PIDecl->getSetterName(), - DeclPtrTy::make(CCPrimary), isOverridingProperty, - MethodImplKind); - PIDecl = ProtocolPtrTy.getAs<ObjCPropertyDecl>(); - } - PIDecl->makeitReadWriteAttribute(); - if (Attributes & ObjCDeclSpec::DQ_PR_retain) - PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); - if (Attributes & ObjCDeclSpec::DQ_PR_copy) - PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); - PIDecl->setSetterName(SetterSel); - } else { - Diag(AtLoc, diag::err_use_continuation_class) - << CCPrimary->getDeclName(); - Diag(PIDecl->getLocation(), diag::note_property_declare); - } - *isOverridingProperty = true; - // Make sure setter decl is synthesized, and added to primary - // class's list. - ProcessPropertyDecl(PIDecl, CCPrimary); - return DeclPtrTy(); - } - - // No matching property found in the primary class. Just fall thru - // and add property to continuation class's primary class. - ClassDecl = CCPrimary; - } else { - Diag(CDecl->getLocation(), diag::err_continuation_class); - *isOverridingProperty = true; - return DeclPtrTy(); - } - } - - // Issue a warning if property is 'assign' as default and its object, which is - // gc'able conforms to NSCopying protocol - if (getLangOptions().getGCMode() != LangOptions::NonGC && - isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign)) - if (T->isObjCObjectPointerType()) { - QualType InterfaceTy = T->getPointeeType(); - if (const ObjCInterfaceType *OIT = - InterfaceTy->getAs<ObjCInterfaceType>()) { - ObjCInterfaceDecl *IDecl = OIT->getDecl(); - if (IDecl) - if (ObjCProtocolDecl* PNSCopying = - LookupProtocol(&Context.Idents.get("NSCopying"))) - if (IDecl->ClassImplementsProtocol(PNSCopying, true)) - Diag(AtLoc, diag::warn_implements_nscopying) - << FD.D.getIdentifier(); - } - } - if (T->isObjCInterfaceType()) - Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object); - - DeclContext *DC = dyn_cast<DeclContext>(ClassDecl); - assert(DC && "ClassDecl is not a DeclContext"); - ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, - FD.D.getIdentifierLoc(), - FD.D.getIdentifier(), - AtLoc, T); - DeclContext::lookup_result Found = DC->lookup(PDecl->getDeclName()); - if (Found.first != Found.second && isa<ObjCPropertyDecl>(*Found.first)) { - Diag(PDecl->getLocation(), diag::err_duplicate_property); - Diag((*Found.first)->getLocation(), diag::note_property_declare); - PDecl->setInvalidDecl(); - } - else - DC->addDecl(PDecl); - - if (T->isArrayType() || T->isFunctionType()) { - Diag(AtLoc, diag::err_property_type) << T; - PDecl->setInvalidDecl(); - } - - ProcessDeclAttributes(S, PDecl, FD.D); - - // Regardless of setter/getter attribute, we save the default getter/setter - // selector names in anticipation of declaration of setter/getter methods. - PDecl->setGetterName(GetterSel); - PDecl->setSetterName(SetterSel); - - if (Attributes & ObjCDeclSpec::DQ_PR_readonly) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly); - - if (Attributes & ObjCDeclSpec::DQ_PR_getter) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_getter); - - if (Attributes & ObjCDeclSpec::DQ_PR_setter) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_setter); - - if (isReadWrite) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite); - - if (Attributes & ObjCDeclSpec::DQ_PR_retain) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); - - if (Attributes & ObjCDeclSpec::DQ_PR_copy) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); - - if (isAssign) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign); - - if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic); - - if (MethodImplKind == tok::objc_required) - PDecl->setPropertyImplementation(ObjCPropertyDecl::Required); - else if (MethodImplKind == tok::objc_optional) - PDecl->setPropertyImplementation(ObjCPropertyDecl::Optional); - // A case of continuation class adding a new property in the class. This - // is not what it was meant for. However, gcc supports it and so should we. - // Make sure setter/getters are declared here. - if (CCPrimary) - ProcessPropertyDecl(PDecl, CCPrimary); - - return DeclPtrTy::make(PDecl); -} - -ObjCIvarDecl* -Sema::SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl, - IdentifierInfo *NameII) { - ObjCIvarDecl *Ivar = 0; - ObjCPropertyDecl *Prop = LookupPropertyDecl(IDecl, NameII); - if (Prop && !Prop->isInvalidDecl()) { - DeclContext *EnclosingContext = cast_or_null<DeclContext>(IDecl); - QualType PropType = Context.getCanonicalType(Prop->getType()); - assert(EnclosingContext && - "null DeclContext for synthesized ivar - SynthesizeNewPropertyIvar"); - Ivar = ObjCIvarDecl::Create(Context, EnclosingContext, - Prop->getLocation(), - NameII, PropType, /*Dinfo=*/0, - ObjCIvarDecl::Public, - (Expr *)0); - Ivar->setLexicalDeclContext(IDecl); - IDecl->addDecl(Ivar); - Prop->setPropertyIvarDecl(Ivar); - } - return Ivar; -} - -/// ActOnPropertyImplDecl - This routine performs semantic checks and -/// builds the AST node for a property implementation declaration; declared -/// as @synthesize or @dynamic. -/// -Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, - SourceLocation PropertyLoc, - bool Synthesize, - DeclPtrTy ClassCatImpDecl, - IdentifierInfo *PropertyId, - IdentifierInfo *PropertyIvar) { - Decl *ClassImpDecl = ClassCatImpDecl.getAs<Decl>(); - // Make sure we have a context for the property implementation declaration. - if (!ClassImpDecl) { - Diag(AtLoc, diag::error_missing_property_context); - return DeclPtrTy(); - } - ObjCPropertyDecl *property = 0; - ObjCInterfaceDecl* IDecl = 0; - // Find the class or category class where this property must have - // a declaration. - ObjCImplementationDecl *IC = 0; - ObjCCategoryImplDecl* CatImplClass = 0; - if ((IC = dyn_cast<ObjCImplementationDecl>(ClassImpDecl))) { - IDecl = IC->getClassInterface(); - // We always synthesize an interface for an implementation - // without an interface decl. So, IDecl is always non-zero. - assert(IDecl && - "ActOnPropertyImplDecl - @implementation without @interface"); - - // Look for this property declaration in the @implementation's @interface - property = IDecl->FindPropertyDeclaration(PropertyId); - if (!property) { - Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName(); - return DeclPtrTy(); - } - if (const ObjCCategoryDecl *CD = - dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) { - if (!CD->IsClassExtension()) { - Diag(PropertyLoc, diag::error_category_property) << CD->getDeclName(); - Diag(property->getLocation(), diag::note_property_declare); - return DeclPtrTy(); - } - } - } else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) { - if (Synthesize) { - Diag(AtLoc, diag::error_synthesize_category_decl); - return DeclPtrTy(); - } - IDecl = CatImplClass->getClassInterface(); - if (!IDecl) { - Diag(AtLoc, diag::error_missing_property_interface); - return DeclPtrTy(); - } - ObjCCategoryDecl *Category = - IDecl->FindCategoryDeclaration(CatImplClass->getIdentifier()); - - // If category for this implementation not found, it is an error which - // has already been reported eralier. - if (!Category) - return DeclPtrTy(); - // Look for this property declaration in @implementation's category - property = Category->FindPropertyDeclaration(PropertyId); - if (!property) { - Diag(PropertyLoc, diag::error_bad_category_property_decl) - << Category->getDeclName(); - return DeclPtrTy(); - } - } else { - Diag(AtLoc, diag::error_bad_property_context); - return DeclPtrTy(); - } - ObjCIvarDecl *Ivar = 0; - // Check that we have a valid, previously declared ivar for @synthesize - if (Synthesize) { - // @synthesize - if (!PropertyIvar) - PropertyIvar = PropertyId; - QualType PropType = Context.getCanonicalType(property->getType()); - // Check that this is a previously declared 'ivar' in 'IDecl' interface - ObjCInterfaceDecl *ClassDeclared; - Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared); - if (!Ivar) { - DeclContext *EnclosingContext = cast_or_null<DeclContext>(IDecl); - assert(EnclosingContext && - "null DeclContext for synthesized ivar - ActOnPropertyImplDecl"); - Ivar = ObjCIvarDecl::Create(Context, EnclosingContext, PropertyLoc, - PropertyIvar, PropType, /*Dinfo=*/0, - ObjCIvarDecl::Public, - (Expr *)0); - IDecl->makeDeclVisibleInContext(Ivar, false); - property->setPropertyIvarDecl(Ivar); - if (!getLangOptions().ObjCNonFragileABI) - Diag(PropertyLoc, diag::error_missing_property_ivar_decl) << PropertyId; - // Note! I deliberately want it to fall thru so, we have a - // a property implementation and to avoid future warnings. - } else if (getLangOptions().ObjCNonFragileABI && - ClassDeclared != IDecl) { - Diag(PropertyLoc, diag::error_ivar_in_superclass_use) - << property->getDeclName() << Ivar->getDeclName() - << ClassDeclared->getDeclName(); - Diag(Ivar->getLocation(), diag::note_previous_access_declaration) - << Ivar << Ivar->getNameAsCString(); - // Note! I deliberately want it to fall thru so more errors are caught. - } - QualType IvarType = Context.getCanonicalType(Ivar->getType()); - - // Check that type of property and its ivar are type compatible. - if (PropType != IvarType) { - if (CheckAssignmentConstraints(PropType, IvarType) != Compatible) { - Diag(PropertyLoc, diag::error_property_ivar_type) - << property->getDeclName() << Ivar->getDeclName(); - // Note! I deliberately want it to fall thru so, we have a - // a property implementation and to avoid future warnings. - } - - // FIXME! Rules for properties are somewhat different that those - // for assignments. Use a new routine to consolidate all cases; - // specifically for property redeclarations as well as for ivars. - QualType lhsType =Context.getCanonicalType(PropType).getUnqualifiedType(); - QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType(); - if (lhsType != rhsType && - lhsType->isArithmeticType()) { - Diag(PropertyLoc, diag::error_property_ivar_type) - << property->getDeclName() << Ivar->getDeclName(); - // Fall thru - see previous comment - } - // __weak is explicit. So it works on Canonical type. - if (PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() && - getLangOptions().getGCMode() != LangOptions::NonGC) { - Diag(PropertyLoc, diag::error_weak_property) - << property->getDeclName() << Ivar->getDeclName(); - // Fall thru - see previous comment - } - if ((property->getType()->isObjCObjectPointerType() || - PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() && - getLangOptions().getGCMode() != LangOptions::NonGC) { - Diag(PropertyLoc, diag::error_strong_property) - << property->getDeclName() << Ivar->getDeclName(); - // Fall thru - see previous comment - } - } - } else if (PropertyIvar) - // @dynamic - Diag(PropertyLoc, diag::error_dynamic_property_ivar_decl); - assert (property && "ActOnPropertyImplDecl - property declaration missing"); - ObjCPropertyImplDecl *PIDecl = - ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc, - property, - (Synthesize ? - ObjCPropertyImplDecl::Synthesize - : ObjCPropertyImplDecl::Dynamic), - Ivar); - if (IC) { - if (Synthesize) - if (ObjCPropertyImplDecl *PPIDecl = - IC->FindPropertyImplIvarDecl(PropertyIvar)) { - Diag(PropertyLoc, diag::error_duplicate_ivar_use) - << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier() - << PropertyIvar; - Diag(PPIDecl->getLocation(), diag::note_previous_use); - } - - if (ObjCPropertyImplDecl *PPIDecl - = IC->FindPropertyImplDecl(PropertyId)) { - Diag(PropertyLoc, diag::error_property_implemented) << PropertyId; - Diag(PPIDecl->getLocation(), diag::note_previous_declaration); - return DeclPtrTy(); - } - IC->addPropertyImplementation(PIDecl); - } else { - if (Synthesize) - if (ObjCPropertyImplDecl *PPIDecl = - CatImplClass->FindPropertyImplIvarDecl(PropertyIvar)) { - Diag(PropertyLoc, diag::error_duplicate_ivar_use) - << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier() - << PropertyIvar; - Diag(PPIDecl->getLocation(), diag::note_previous_use); - } - - if (ObjCPropertyImplDecl *PPIDecl = - CatImplClass->FindPropertyImplDecl(PropertyId)) { - Diag(PropertyLoc, diag::error_property_implemented) << PropertyId; - Diag(PPIDecl->getLocation(), diag::note_previous_declaration); - return DeclPtrTy(); - } - CatImplClass->addPropertyImplementation(PIDecl); - } - - return DeclPtrTy::make(PIDecl); -} - bool Sema::CheckObjCDeclScope(Decl *D) { if (isa<TranslationUnitDecl>(CurContext->getLookupContext())) return false; diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 9be411b552ad..4ce1ce9b019f 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -294,12 +294,12 @@ bool Sema::CheckExceptionSpecSubset( continue; // Do this check from a context without privileges. - switch (CheckBaseClassAccess(SourceLocation(), false, + switch (CheckBaseClassAccess(SourceLocation(), CanonicalSuperT, CanonicalSubT, Paths.front(), + /*Diagnostic*/ 0, /*ForceCheck*/ true, - /*ForceUnprivileged*/ true, - ADK_quiet)) { + /*ForceUnprivileged*/ true)) { case AR_accessible: break; case AR_inaccessible: continue; case AR_dependent: diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 2249579ba4e1..a39ba2f7d06e 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -58,7 +58,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) { Diag(Loc, diag::warn_unavailable) << D->getDeclName(); Diag(D->getLocation(), diag::note_unavailable_here) << 0; } - + // See if this is a deleted function. if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { if (FD->isDeleted()) { @@ -202,7 +202,7 @@ void Sema::DefaultFunctionArrayConversion(Expr *&E) { void Sema::DefaultFunctionArrayLvalueConversion(Expr *&E) { DefaultFunctionArrayConversion(E); - + QualType Ty = E->getType(); assert(!Ty.isNull() && "DefaultFunctionArrayLvalueConversion - missing type"); if (!Ty->isDependentType() && Ty.hasQualifiers() && @@ -214,8 +214,8 @@ void Sema::DefaultFunctionArrayLvalueConversion(Expr *&E) { // rvalue is T // // C99 6.3.2.1p2: - // If the lvalue has qualified type, the value has the unqualified - // version of the type of the lvalue; otherwise, the value has the + // If the lvalue has qualified type, the value has the unqualified + // version of the type of the lvalue; otherwise, the value has the // type of the lvalue. ImpCastExprToType(E, Ty.getUnqualifiedType(), CastExpr::CK_NoOp); } @@ -289,7 +289,7 @@ bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT) { return true; if (!Expr->getType()->isPODType() && - DiagRuntimeBehavior(Expr->getLocStart(), + DiagRuntimeBehavior(Expr->getLocStart(), PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg) << Expr->getType() << CT)) return true; @@ -370,7 +370,7 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) { if (Literal.Pascal) StrTy = Context.UnsignedCharTy; // A C++ string literal has a const-qualified element type (C++ 2.13.4p1). - if (getLangOptions().CPlusPlus) + if (getLangOptions().CPlusPlus || getLangOptions().ConstStrings ) StrTy.addConst(); // Get an array type for the string, according to C99 6.4.5. This includes @@ -423,10 +423,10 @@ static bool ShouldSnapshotBlockValueReference(Sema &S, BlockScopeInfo *CurBlock, // all get the bit). Walk the nesting chain. for (unsigned I = S.FunctionScopes.size() - 1; I; --I) { BlockScopeInfo *NextBlock = dyn_cast<BlockScopeInfo>(S.FunctionScopes[I]); - + if (!NextBlock) continue; - + // If we found the defining block for the variable, don't mark the block as // having a reference outside it. if (NextBlock->TheDecl == VD->getDeclContext()) @@ -469,9 +469,9 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc, MarkDeclarationReferenced(Loc, D); - return Owned(DeclRefExpr::Create(Context, - SS? (NestedNameSpecifier *)SS->getScopeRep() : 0, - SS? SS->getRange() : SourceRange(), + return Owned(DeclRefExpr::Create(Context, + SS? (NestedNameSpecifier *)SS->getScopeRep() : 0, + SS? SS->getRange() : SourceRange(), D, Loc, Ty)); } @@ -768,14 +768,14 @@ static bool IsProvablyNotDerivedFrom(Sema &SemaRef, return true; } - + /// Determines if this is an instance member of a class. static bool IsInstanceMember(NamedDecl *D) { assert(D->isCXXClassMember() && "checking whether non-member is instance member"); if (isa<FieldDecl>(D)) return true; - + if (isa<CXXMethodDecl>(D)) return !cast<CXXMethodDecl>(D)->isStatic(); @@ -971,7 +971,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName() << CodeModificationHint::CreateReplacement(R.getNameLoc(), R.getLookupName().getAsString()); - else + else Diag(R.getNameLoc(), diag::err_no_member_suggest) << Name << computeDeclContext(SS, false) << R.getLookupName() << SS.getRange() @@ -980,7 +980,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, if (NamedDecl *ND = R.getAsSingle<NamedDecl>()) Diag(ND->getLocation(), diag::note_previous_decl) << ND->getDeclName(); - + // Tell the callee to try to recover. return false; } @@ -993,7 +993,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, // to recover well anyway. if (SS.isEmpty()) Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName(); - else + else Diag(R.getNameLoc(), diag::err_no_member_suggest) << Name << computeDeclContext(SS, false) << R.getLookupName() << SS.getRange(); @@ -1107,7 +1107,7 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // If we found an Objective-C instance variable, let // LookupInObjCMethod build the appropriate expression to - // reference the ivar. + // reference the ivar. if (ObjCIvarDecl *Ivar = R.getAsSingle<ObjCIvarDecl>()) { R.clear(); OwningExprResult E(LookupInObjCMethod(R, S, Ivar->getIdentifier())); @@ -1303,7 +1303,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, // turn this into Self->ivar, just return a BareIVarExpr or something. IdentifierInfo &II = Context.Idents.get("self"); UnqualifiedId SelfName; - SelfName.setIdentifier(&II, SourceLocation()); + SelfName.setIdentifier(&II, SourceLocation()); CXXScopeSpec SelfScopeSpec; OwningExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec, SelfName, false, false); @@ -1326,7 +1326,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, // Needed to implement property "super.method" notation. if (Lookup.empty() && II->isStr("super")) { QualType T; - + if (getCurMethodDecl()->isInstanceMethod()) T = Context.getObjCObjectPointerType(Context.getObjCInterfaceType( getCurMethodDecl()->getClassInterface())); @@ -1363,7 +1363,7 @@ Sema::PerformObjectMemberConversion(Expr *&From, CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Member->getDeclContext()); if (!RD) return false; - + QualType DestRecordType; QualType DestType; QualType FromRecordType; @@ -1371,7 +1371,7 @@ Sema::PerformObjectMemberConversion(Expr *&From, bool PointerConversions = false; if (isa<FieldDecl>(Member)) { DestRecordType = Context.getCanonicalType(Context.getTypeDeclType(RD)); - + if (FromType->getAs<PointerType>()) { DestType = Context.getPointerType(DestRecordType); FromRecordType = FromType->getPointeeType(); @@ -1383,10 +1383,10 @@ Sema::PerformObjectMemberConversion(Expr *&From, } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Member)) { if (Method->isStatic()) return false; - + DestType = Method->getThisType(Context); DestRecordType = DestType->getPointeeType(); - + if (FromType->getAs<PointerType>()) { FromRecordType = FromType->getPointeeType(); PointerConversions = true; @@ -1398,16 +1398,16 @@ Sema::PerformObjectMemberConversion(Expr *&From, // No conversion necessary. return false; } - + if (DestType->isDependentType() || FromType->isDependentType()) return false; - + // If the unqualified types are the same, no conversion is necessary. if (Context.hasSameUnqualifiedType(FromRecordType, DestRecordType)) return false; - + // C++ [class.member.lookup]p8: - // [...] Ambiguities can often be resolved by qualifying a name with its + // [...] Ambiguities can often be resolved by qualifying a name with its // class name. // // If the member was a qualified name and the qualified referred to a @@ -1435,7 +1435,7 @@ Sema::PerformObjectMemberConversion(Expr *&From, IntermediateType = Context.getPointerType(IntermediateType); } } - + if (!IntermediateType.isNull() && IsDerivedFrom(FromRecordType, IntermediateRecordType) && IsDerivedFrom(IntermediateRecordType, DestRecordType)) { @@ -1448,18 +1448,18 @@ Sema::PerformObjectMemberConversion(Expr *&From, return true; ImpCastExprToType(From, IntermediateType, CastExpr::CK_DerivedToBase, - /*isLvalue=*/!PointerConversions); + /*isLvalue=*/!PointerConversions); ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase, /*isLvalue=*/!PointerConversions); return false; } - + if (CheckDerivedToBaseConversion(FromRecordType, DestRecordType, From->getSourceRange().getBegin(), From->getSourceRange())) return true; - + ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase, /*isLvalue=*/true); return false; @@ -1633,7 +1633,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, return Owned(ULE); } - + /// \brief Complete semantic analysis for a reference to the given declaration. Sema::OwningExprResult @@ -1658,7 +1658,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, // Make sure that we're referring to a value. ValueDecl *VD = dyn_cast<ValueDecl>(D); if (!VD) { - Diag(Loc, diag::err_ref_non_value) + Diag(Loc, diag::err_ref_non_value) << D << SS.getRange(); Diag(D->getLocation(), diag::note_declared_at); return ExprError(); @@ -1683,7 +1683,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, // We do not do this for things like enum constants, global variables, etc, // as they do not get snapshotted. // - if (getCurBlock() && + if (getCurBlock() && ShouldSnapshotBlockValueReference(*this, getCurBlock(), VD)) { if (VD->getType().getTypePtr()->isVariablyModifiedType()) { Diag(Loc, diag::err_ref_vm_type); @@ -1819,7 +1819,7 @@ Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) { if ((result & APFloat::opOverflow) || ((result & APFloat::opUnderflow) && Val.isZero())) { unsigned diagnostic; - llvm::SmallVector<char, 20> buffer; + llvm::SmallString<20> buffer; if (result & APFloat::opOverflow) { diagnostic = diag::warn_float_overflow; APFloat::getLargest(Format).toString(buffer); @@ -2531,7 +2531,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, } assert(DC && "Cannot handle non-computable dependent contexts in lookup"); - + if (!isa<TypeDecl>(DC)) { SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass) << DC << SS.getRange(); @@ -2548,7 +2548,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, // We didn't find anything with the given name, so try to correct // for typos. DeclarationName Name = R.getLookupName(); - if (SemaRef.CorrectTypo(R, 0, &SS, DC) && + if (SemaRef.CorrectTypo(R, 0, &SS, DC) && (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin()))) { SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest) << Name << DC << R.getLookupName() << SS.getRange() @@ -2685,7 +2685,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, return Owned(MemExpr); } - assert(R.isSingleResult()); + assert(R.isSingleResult()); NamedDecl *MemberDecl = R.getFoundDecl(); // FIXME: diagnose the presence of template arguments now. @@ -2831,13 +2831,13 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, Diag(Loc, diag::err_member_reference_needs_call) << QualType(Fun, 0) << CodeModificationHint::CreateInsertion(Loc, "()"); - + OwningExprResult NewBase - = ActOnCallExpr(0, ExprArg(*this, BaseExpr), Loc, + = ActOnCallExpr(0, ExprArg(*this, BaseExpr), Loc, MultiExprArg(*this, 0, 0), 0, Loc); if (NewBase.isInvalid()) return ExprError(); - + BaseExpr = NewBase.takeAs<Expr>(); DefaultFunctionArrayConversion(BaseExpr); BaseType = BaseExpr->getType(); @@ -2907,20 +2907,20 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // Look through local category implementations associated with the class. if (!Setter) Setter = IFace->getCategoryClassMethod(SetterSel); - + if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) return ExprError(); - + if (Getter || Setter) { QualType PType; - + if (Getter) PType = Getter->getResultType(); else // Get the expression type from Setter's incoming parameter. PType = (*(Setter->param_end() -1))->getType(); // FIXME: we must check that the setter has property type. - return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, + return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType, Setter, MemberLoc, BaseExpr)); } @@ -2928,7 +2928,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, << MemberName << BaseType); } } - + if (BaseType->isObjCClassType() && BaseType != Context.ObjCClassRedefinitionType) { BaseType = Context.ObjCClassRedefinitionType; @@ -2975,7 +2975,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, } } } - + // Handle field access to simple records. This also handles access // to fields of the ObjC 'id' struct. if (const RecordType *RTy = BaseType->getAs<RecordType>()) { @@ -3005,13 +3005,13 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, LookupMemberName); if (CorrectTypo(Res, 0, 0, IDecl) && (IV = Res.getAsSingle<ObjCIvarDecl>())) { - Diag(R.getNameLoc(), + Diag(R.getNameLoc(), diag::err_typecheck_member_reference_ivar_suggest) << IDecl->getDeclName() << MemberName << IV->getDeclName() << CodeModificationHint::CreateReplacement(R.getNameLoc(), IV->getNameAsString()); Diag(IV->getLocation(), diag::note_previous_decl) - << IV->getDeclName(); + << IV->getDeclName(); } } @@ -3179,7 +3179,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // Attempt to correct for typos in property names. LookupResult Res(*this, R.getLookupName(), R.getNameLoc(), LookupOrdinaryName); - if (CorrectTypo(Res, 0, 0, IFace, false, OPT) && + if (CorrectTypo(Res, 0, 0, IFace, false, OPT) && Res.getAsSingle<ObjCPropertyDecl>()) { Diag(R.getNameLoc(), diag::err_property_not_found_suggest) << MemberName << BaseType << Res.getLookupName() @@ -3187,7 +3187,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, Res.getLookupName().getAsString()); ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>(); Diag(Property->getLocation(), diag::note_previous_decl) - << Property->getDeclName(); + << Property->getDeclName(); return LookupMemberExpr(Res, BaseExpr, IsArrow, OpLoc, SS, ObjCImpDecl); @@ -3216,7 +3216,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, return Owned(new (Context) ExtVectorElementExpr(ret, BaseExpr, *Member, MemberLoc)); } - + Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union) << BaseType << BaseExpr->getSourceRange(); @@ -3341,11 +3341,11 @@ Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, Expr *ResultE = Result.takeAs<Expr>(); InitializationSequence InitSeq(*this, Entity, Kind, &ResultE, 1); - Result = InitSeq.Perform(*this, Entity, Kind, + Result = InitSeq.Perform(*this, Entity, Kind, MultiExprArg(*this, (void**)&ResultE, 1)); if (Result.isInvalid()) return ExprError(); - + // Build the default argument expression. return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param, Result.takeAs<Expr>())); @@ -3380,7 +3380,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, // assignment, to the types of the corresponding parameter, ... unsigned NumArgsInProto = Proto->getNumArgs(); bool Invalid = false; - + // If too few arguments are available (and we don't have default // arguments for the remaining parameters), don't make the call. if (NumArgs < NumArgsInProto) { @@ -3405,7 +3405,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, } } llvm::SmallVector<Expr *, 8> AllArgs; - VariadicCallType CallType = + VariadicCallType CallType = Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply; if (Fn->getType()->isBlockPointerType()) CallType = VariadicBlock; // Block @@ -3418,7 +3418,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, unsigned TotalNumArgs = AllArgs.size(); for (unsigned i = 0; i < TotalNumArgs; ++i) Call->setArg(i, AllArgs[i]); - + return false; } @@ -3439,23 +3439,23 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, // Continue to check argument types (even if we have too few/many args). for (unsigned i = FirstProtoArg; i != NumArgsToCheck; i++) { QualType ProtoArgType = Proto->getArgType(i); - + Expr *Arg; if (ArgIx < NumArgs) { Arg = Args[ArgIx++]; - + if (RequireCompleteType(Arg->getSourceRange().getBegin(), ProtoArgType, PDiag(diag::err_call_incomplete_argument) << Arg->getSourceRange())) return true; - + // Pass the argument ParmVarDecl *Param = 0; if (FDecl && i < FDecl->getNumParams()) Param = FDecl->getParamDecl(i); - + InitializedEntity Entity = Param? InitializedEntity::InitializeParameter(Param) : InitializedEntity::InitializeParameter(ProtoArgType); @@ -3468,17 +3468,17 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, Arg = ArgE.takeAs<Expr>(); } else { ParmVarDecl *Param = FDecl->getParamDecl(i); - + OwningExprResult ArgExpr = BuildCXXDefaultArgExpr(CallLoc, FDecl, Param); if (ArgExpr.isInvalid()) return true; - + Arg = ArgExpr.takeAs<Expr>(); } AllArgs.push_back(Arg); } - + // If this is a variadic call, handle args passed through "...". if (CallType != VariadicDoesNotApply) { // Promote the arguments (C99 6.5.2.2p7). @@ -3570,32 +3570,32 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, CommaLocs, RParenLoc); } - + // Determine whether this is a call to a pointer-to-member function. if (BinaryOperator *BO = dyn_cast<BinaryOperator>(NakedFn)) { if (BO->getOpcode() == BinaryOperator::PtrMemD || BO->getOpcode() == BinaryOperator::PtrMemI) { - if (const FunctionProtoType *FPT = + if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(BO->getType())) { QualType ResultTy = FPT->getResultType().getNonReferenceType(); - - ExprOwningPtr<CXXMemberCallExpr> - TheCall(this, new (Context) CXXMemberCallExpr(Context, BO, Args, + + ExprOwningPtr<CXXMemberCallExpr> + TheCall(this, new (Context) CXXMemberCallExpr(Context, BO, Args, NumArgs, ResultTy, RParenLoc)); - - if (CheckCallReturnType(FPT->getResultType(), - BO->getRHS()->getSourceRange().getBegin(), + + if (CheckCallReturnType(FPT->getResultType(), + BO->getRHS()->getSourceRange().getBegin(), TheCall.get(), 0)) return ExprError(); - if (ConvertArgumentsForCall(&*TheCall, BO, 0, FPT, Args, NumArgs, + if (ConvertArgumentsForCall(&*TheCall, BO, 0, FPT, Args, NumArgs, RParenLoc)) return ExprError(); return Owned(MaybeBindToTemporary(TheCall.release()).release()); } - return ExprError(Diag(Fn->getLocStart(), + return ExprError(Diag(Fn->getLocStart(), diag::err_typecheck_call_not_function) << Fn->getType() << Fn->getSourceRange()); } @@ -3661,7 +3661,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, << Fn->getType() << Fn->getSourceRange()); // Check for a valid return type - if (CheckCallReturnType(FuncT->getResultType(), + if (CheckCallReturnType(FuncT->getResultType(), Fn->getSourceRange().getBegin(), TheCall.get(), FDecl)) return ExprError(); @@ -3762,7 +3762,7 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, InitializedEntity Entity = InitializedEntity::InitializeTemporary(literalType); InitializationKind Kind - = InitializationKind::CreateCast(SourceRange(LParenLoc, RParenLoc), + = InitializationKind::CreateCast(SourceRange(LParenLoc, RParenLoc), /*IsCStyleCast=*/true); InitializationSequence InitSeq(*this, Entity, Kind, &literalExpr, 1); OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, @@ -3780,7 +3780,7 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, } Result.release(); - + return Owned(new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType, literalExpr, isFileScope)); } @@ -3807,13 +3807,13 @@ static CastExpr::CastKind getScalarCastKind(ASTContext &Context, if (SrcTy->hasPointerRepresentation()) { if (DestTy->hasPointerRepresentation()) - return DestTy->isObjCObjectPointerType() ? - CastExpr::CK_AnyPointerToObjCPointerCast : + return DestTy->isObjCObjectPointerType() ? + CastExpr::CK_AnyPointerToObjCPointerCast : CastExpr::CK_BitCast; if (DestTy->isIntegerType()) return CastExpr::CK_PointerToIntegral; } - + if (SrcTy->isIntegerType()) { if (DestTy->isIntegerType()) return CastExpr::CK_IntegralCast; @@ -3822,14 +3822,14 @@ static CastExpr::CastKind getScalarCastKind(ASTContext &Context, if (DestTy->isRealFloatingType()) return CastExpr::CK_IntegralToFloating; } - + if (SrcTy->isRealFloatingType()) { if (DestTy->isRealFloatingType()) return CastExpr::CK_FloatingCast; if (DestTy->isIntegerType()) return CastExpr::CK_FloatingToIntegral; } - + // FIXME: Assert here. // assert(false && "Unhandled cast combination!"); return CastExpr::CK_Unknown; @@ -3853,7 +3853,7 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, Kind = CastExpr::CK_ToVoid; return false; } - + if (!castType->isScalarType() && !castType->isVectorType()) { if (Context.hasSameUnqualifiedType(castType, castExpr->getType()) && (castType->isStructureType() || castType->isUnionType())) { @@ -3864,14 +3864,14 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, Kind = CastExpr::CK_NoOp; return false; } - + if (castType->isUnionType()) { // GCC cast to union extension RecordDecl *RD = castType->getAs<RecordType>()->getDecl(); RecordDecl::field_iterator Field, FieldEnd; for (Field = RD->field_begin(), FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) { - if (Context.hasSameUnqualifiedType(Field->getType(), + if (Context.hasSameUnqualifiedType(Field->getType(), castExpr->getType())) { Diag(TyR.getBegin(), diag::ext_typecheck_cast_to_union) << castExpr->getSourceRange(); @@ -3884,22 +3884,22 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, Kind = CastExpr::CK_ToUnion; return false; } - + // Reject any other conversions to non-scalar types. return Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar) << castType << castExpr->getSourceRange(); } - - if (!castExpr->getType()->isScalarType() && + + if (!castExpr->getType()->isScalarType() && !castExpr->getType()->isVectorType()) { return Diag(castExpr->getLocStart(), diag::err_typecheck_expect_scalar_operand) << castExpr->getType() << castExpr->getSourceRange(); } - - if (castType->isExtVectorType()) + + if (castType->isExtVectorType()) return CheckExtVectorCast(TyR, castType, castExpr, Kind); - + if (castType->isVectorType()) return CheckVectorCast(TyR, castType, castExpr->getType(), Kind); if (castExpr->getType()->isVectorType()) @@ -3907,10 +3907,10 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, if (getLangOptions().ObjC1 && isa<ObjCSuperExpr>(castExpr)) return Diag(castExpr->getLocStart(), diag::err_illegal_super_cast) << TyR; - + if (isa<ObjCSelectorExpr>(castExpr)) return Diag(castExpr->getLocStart(), diag::err_cast_selector_expr); - + if (!castType->isArithmeticType()) { QualType castExprType = castExpr->getType(); if (!castExprType->isIntegralType() && castExprType->isArithmeticType()) @@ -3948,12 +3948,12 @@ bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, return false; } -bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr, +bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr, CastExpr::CastKind &Kind) { assert(DestTy->isExtVectorType() && "Not an extended vector type!"); - + QualType SrcTy = CastExpr->getType(); - + // If SrcTy is a VectorType, the total size must match to explicitly cast to // an ExtVectorType. if (SrcTy->isVectorType()) { @@ -3975,7 +3975,7 @@ bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr, QualType DestElemTy = DestTy->getAs<ExtVectorType>()->getElementType(); ImpCastExprToType(CastExpr, DestElemTy, getScalarCastKind(Context, SrcTy, DestElemTy)); - + Kind = CastExpr::CK_VectorSplat; return false; } @@ -4105,7 +4105,7 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (getLangOptions().CPlusPlus) return CXXCheckConditionalOperands(Cond, LHS, RHS, QuestionLoc); - CheckSignCompare(LHS, RHS, QuestionLoc, diag::warn_mixed_sign_conditional); + CheckSignCompare(LHS, RHS, QuestionLoc); UsualUnaryConversions(Cond); UsualUnaryConversions(LHS); @@ -4169,14 +4169,14 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, ImpCastExprToType(LHS, RHSTy, CastExpr::CK_Unknown); return RHSTy; } - + // All objective-c pointer type analysis is done here. QualType compositeType = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc); if (!compositeType.isNull()) return compositeType; - - + + // Handle block pointer types. if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) { if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) { @@ -4198,7 +4198,7 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // The block pointer types aren't identical, continue checking. QualType lhptee = LHSTy->getAs<BlockPointerType>()->getPointeeType(); QualType rhptee = RHSTy->getAs<BlockPointerType>()->getPointeeType(); - + if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(), rhptee.getUnqualifiedType())) { Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers) @@ -4216,7 +4216,7 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); return LHSTy; } - + // Check constraints for C object pointers types (C99 6.5.15p3,6). if (LHSTy->isPointerType() && RHSTy->isPointerType()) { // get the "pointed to" types @@ -4300,7 +4300,7 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, SourceLocation QuestionLoc) { QualType LHSTy = LHS->getType(); QualType RHSTy = RHS->getType(); - + // Handle things like Class and struct objc_class*. Here we case the result // to the pseudo-builtin, because that will be implicitly cast back to the // redefinition type if an attempt is made to access its fields. @@ -4338,7 +4338,7 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, } // Check constraints for Objective-C object pointers types. if (LHSTy->isObjCObjectPointerType() && RHSTy->isObjCObjectPointerType()) { - + if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) { // Two identical object pointer types are always compatible. return LHSTy; @@ -4346,7 +4346,7 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, const ObjCObjectPointerType *LHSOPT = LHSTy->getAs<ObjCObjectPointerType>(); const ObjCObjectPointerType *RHSOPT = RHSTy->getAs<ObjCObjectPointerType>(); QualType compositeType = LHSTy; - + // If both operands are interfaces and either operand can be // assigned to the other, use that type as the composite // type. This allows @@ -4357,7 +4357,7 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, // allow silent coercion. Finally, if the types are // incompatible then make sure to use 'id' as the composite // type so the result is acceptable for sending messages to. - + // FIXME: Consider unifying with 'areComparableObjCPointerTypes'. // It could return the composite type. if (Context.canAssignObjCInterfaces(LHSOPT, RHSOPT)) { @@ -4374,7 +4374,7 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, compositeType = Context.getObjCIdType(); } else if (LHSTy->isObjCIdType() || RHSTy->isObjCIdType()) { compositeType = Context.getObjCIdType(); - } else if (!(compositeType = + } else if (!(compositeType = Context.areCommonBaseCompatible(LHSOPT, RHSOPT)).isNull()) ; else { @@ -4512,7 +4512,7 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { lhptee = Context.UnsignedCharTy; else if (lhptee->isSignedIntegerType()) lhptee = Context.getCorrespondingUnsignedType(lhptee); - + if (rhptee->isCharType()) rhptee = Context.UnsignedCharTy; else if (rhptee->isSignedIntegerType()) @@ -4526,7 +4526,7 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { return ConvTy; return IncompatiblePointerSign; } - + // If we are a multi-level pointer, it's possible that our issue is simply // one of qualification - e.g. char ** -> const char ** is not allowed. If // the eventual target type is the same and the pointers have the same @@ -4535,15 +4535,15 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { do { lhptee = lhptee->getAs<PointerType>()->getPointeeType(); rhptee = rhptee->getAs<PointerType>()->getPointeeType(); - + lhptee = Context.getCanonicalType(lhptee); rhptee = Context.getCanonicalType(rhptee); } while (lhptee->isPointerType() && rhptee->isPointerType()); - + if (Context.hasSameUnqualifiedType(lhptee, rhptee)) return IncompatibleNestedPointerQualifiers; } - + // General pointer incompatibility takes priority over qualifiers. return IncompatiblePointer; } @@ -4584,21 +4584,21 @@ Sema::AssignConvertType Sema::CheckObjCPointerTypesForAssignment(QualType lhsType, QualType rhsType) { if (lhsType->isObjCBuiltinType() || rhsType->isObjCBuiltinType()) return Compatible; - QualType lhptee = + QualType lhptee = lhsType->getAs<ObjCObjectPointerType>()->getPointeeType(); - QualType rhptee = + QualType rhptee = rhsType->getAs<ObjCObjectPointerType>()->getPointeeType(); // make sure we operate on the canonical type lhptee = Context.getCanonicalType(lhptee); rhptee = Context.getCanonicalType(rhptee); if (!lhptee.isAtLeastAsQualifiedAs(rhptee)) return CompatiblePointerDiscardsQualifiers; - + if (Context.typesAreCompatible(lhsType, rhsType)) return Compatible; if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType()) return IncompatibleObjCQualifiedId; - return IncompatiblePointer; + return IncompatiblePointer; } /// CheckAssignmentConstraints (C99 6.5.16) - This routine currently @@ -4824,7 +4824,7 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) { break; } - if (rExpr->isNullPointerConstant(Context, + if (rExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { ImpCastExprToType(rExpr, it->getType(), CastExpr::CK_IntegralToPointer); InitField = *it; @@ -4868,7 +4868,7 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { if ((lhsType->isPointerType() || lhsType->isObjCObjectPointerType() || lhsType->isBlockPointerType()) - && rExpr->isNullPointerConstant(Context, + && rExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { ImpCastExprToType(rExpr, lhsType, CastExpr::CK_Unknown); return Compatible; @@ -4976,13 +4976,13 @@ QualType Sema::CheckMultiplyDivideOperands( if (!lex->getType()->isArithmeticType() || !rex->getType()->isArithmeticType()) return InvalidOperands(Loc, lex, rex); - + // Check for division by zero. if (isDiv && rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) - DiagRuntimeBehavior(Loc, PDiag(diag::warn_division_by_zero) + DiagRuntimeBehavior(Loc, PDiag(diag::warn_division_by_zero) << rex->getSourceRange()); - + return compType; } @@ -4998,12 +4998,12 @@ QualType Sema::CheckRemainderOperands( if (!lex->getType()->isIntegerType() || !rex->getType()->isIntegerType()) return InvalidOperands(Loc, lex, rex); - + // Check for remainder by zero. if (rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) DiagRuntimeBehavior(Loc, PDiag(diag::warn_remainder_by_zero) << rex->getSourceRange()); - + return compType; } @@ -5282,8 +5282,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) return CheckVectorCompareOperands(lex, rex, Loc, isRelational); - CheckSignCompare(lex, rex, Loc, diag::warn_mixed_sign_comparison, - (Opc == BinaryOperator::EQ || Opc == BinaryOperator::NE)); + CheckSignCompare(lex, rex, Loc, &Opc); // C99 6.5.8p3 / C99 6.5.9p4 if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) @@ -5320,13 +5319,13 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, Expr *literalString = 0; Expr *literalStringStripped = 0; if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) && - !RHSStripped->isNullPointerConstant(Context, + !RHSStripped->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { literalString = lex; literalStringStripped = LHSStripped; } else if ((isa<StringLiteral>(RHSStripped) || isa<ObjCEncodeExpr>(RHSStripped)) && - !LHSStripped->isNullPointerConstant(Context, + !LHSStripped->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { literalString = rex; literalStringStripped = RHSStripped; @@ -5343,7 +5342,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, case BinaryOperator::NE: resultComparison = ") != 0"; break; default: assert(false && "Invalid comparison operator"); } - + DiagRuntimeBehavior(Loc, PDiag(diag::warn_stringcompare) << isa<ObjCEncodeExpr>(literalStringStripped) @@ -5372,9 +5371,9 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, return ResultTy; } - bool LHSIsNull = lex->isNullPointerConstant(Context, + bool LHSIsNull = lex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull); - bool RHSIsNull = rex->isNullPointerConstant(Context, + bool RHSIsNull = rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull); // All of the following pointer related warnings are GCC extensions, except @@ -5417,9 +5416,9 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, << lType << rType << lex->getSourceRange() << rex->getSourceRange(); return QualType(); } else if (NonStandardCompositeType) { - Diag(Loc, + Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard) - << lType << rType << T + << lType << rType << T << lex->getSourceRange() << rex->getSourceRange(); } @@ -5490,9 +5489,9 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, << lType << rType << lex->getSourceRange() << rex->getSourceRange(); return QualType(); } else if (NonStandardCompositeType) { - Diag(Loc, + Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard) - << lType << rType << T + << lType << rType << T << lex->getSourceRange() << rex->getSourceRange(); } @@ -5678,10 +5677,10 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] if (!lex->getType()->isScalarType() || !rex->getType()->isScalarType()) return InvalidOperands(Loc, lex, rex); - + return Context.IntTy; } - + // C++ [expr.log.and]p1 // C++ [expr.log.or]p1 // The operands are both implicitly converted to type bool (clause 4). @@ -5693,16 +5692,16 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] if (PerformImplicitConversion(lex, Context.BoolTy, LHS, AA_Passing, /*IgnoreBaseAccess=*/false)) return InvalidOperands(Loc, lex, rex); - + StandardConversionSequence RHS; if (!IsStandardConversion(rex, Context.BoolTy, /*InOverloadResolution=*/false, RHS)) return InvalidOperands(Loc, lex, rex); - + if (PerformImplicitConversion(rex, Context.BoolTy, RHS, AA_Passing, /*IgnoreBaseAccess=*/false)) return InvalidOperands(Loc, lex, rex); - + // C++ [expr.log.and]p2 // C++ [expr.log.or]p2 // The result is a bool. @@ -6342,10 +6341,10 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc, Self.Diag(Loc, PD) << CodeModificationHint::CreateInsertion(ParenRange.getBegin(), "(") << CodeModificationHint::CreateInsertion(EndLoc, ")"); - + if (!SecondPD.getDiagID()) return; - + EndLoc = Self.PP.getLocForEndOfToken(SecondParenRange.getEnd()); if (!SecondParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { // We can't display the parentheses, so just dig the @@ -6353,7 +6352,7 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc, Self.Diag(Loc, SecondPD); return; } - + Self.Diag(Loc, SecondPD) << CodeModificationHint::CreateInsertion(SecondParenRange.getBegin(), "(") << CodeModificationHint::CreateInsertion(EndLoc, ")"); @@ -6443,12 +6442,12 @@ Action::OwningExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, if (S && OverOp != OO_None) LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(), Functions); - + // Build the (potentially-overloaded, potentially-dependent) // binary operation. return CreateOverloadedBinOp(OpLoc, Opc, Functions, lhs, rhs); } - + // Build a built-in binary operation. return CreateBuiltinBinOp(OpLoc, Opc, lhs, rhs); } @@ -6556,10 +6555,10 @@ Action::OwningExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, if (S && OverOp != OO_None) LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(), Functions); - + return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(input)); } - + return CreateBuiltinUnaryOp(OpLoc, Opc, move(input)); } @@ -6819,7 +6818,7 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) { void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { assert(ParamInfo.getIdentifier()==0 && "block-id should have no identifier!"); BlockScopeInfo *CurBlock = getCurBlock(); - + if (ParamInfo.getNumTypeObjects() == 0 || ParamInfo.getTypeObject(0).Kind != DeclaratorChunk::Function) { ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo); @@ -6986,13 +6985,13 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, PopFunctionOrBlockScope(); return ExprError(); } - + AnalysisContext AC(BSI->TheDecl); CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody(), AC); CheckUnreachable(AC); Expr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy, BSI->hasBlockDeclRefExprs); - PopFunctionOrBlockScope(); + PopFunctionOrBlockScope(); return Owned(Result); } @@ -7049,14 +7048,14 @@ Sema::OwningExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) { return Owned(new (Context) GNUNullExpr(Ty, TokenLoc)); } -static void +static void MakeObjCStringLiteralCodeModificationHint(Sema& SemaRef, QualType DstType, Expr *SrcExpr, CodeModificationHint &Hint) { if (!SemaRef.getLangOptions().ObjC1) return; - + const ObjCObjectPointerType *PT = DstType->getAs<ObjCObjectPointerType>(); if (!PT) return; @@ -7068,12 +7067,12 @@ MakeObjCStringLiteralCodeModificationHint(Sema& SemaRef, if (!ID || !ID->getIdentifier()->isStr("NSString")) return; } - + // Strip off any parens and casts. StringLiteral *SL = dyn_cast<StringLiteral>(SrcExpr->IgnoreParenCasts()); if (!SL || SL->isWide()) return; - + Hint = CodeModificationHint::CreateInsertion(SL->getLocStart(), "@"); } @@ -7085,7 +7084,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, bool isInvalid = false; unsigned DiagKind; CodeModificationHint Hint; - + switch (ConvTy) { default: assert(0 && "Unknown conversion type"); case Compatible: return false; @@ -7202,7 +7201,7 @@ Sema::PopExpressionEvaluationContext() { // Mark any remaining declarations in the current position of the stack // as "referenced". If they were not meant to be referenced, semantic // analysis would have eliminated them (e.g., in ActOnCXXTypeId). - for (PotentiallyReferencedDecls::iterator + for (PotentiallyReferencedDecls::iterator I = Rec.PotentiallyReferenced->begin(), IEnd = Rec.PotentiallyReferenced->end(); I != IEnd; ++I) @@ -7217,13 +7216,13 @@ Sema::PopExpressionEvaluationContext() { I != IEnd; ++I) Diag(I->first, I->second); } - } + } // When are coming out of an unevaluated context, clear out any // temporaries that we may have created as part of the evaluation of // the expression in that context: they aren't relevant because they // will never be constructed. - if (Rec.Context == Unevaluated && + if (Rec.Context == Unevaluated && ExprTemporaries.size() > Rec.NumTemporaries) ExprTemporaries.erase(ExprTemporaries.begin() + Rec.NumTemporaries, ExprTemporaries.end()); @@ -7252,7 +7251,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { // template or not. The reason for this is that unevaluated expressions // (e.g. (void)sizeof()) constitute a use for warning purposes (-Wunused-variables and // -Wunused-parameters) - if (isa<ParmVarDecl>(D) || + if (isa<ParmVarDecl>(D) || (isa<VarDecl>(D) && D->getDeclContext()->isFunctionOrMethod())) D->setUsed(true); @@ -7290,7 +7289,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { if (!Constructor->isUsed()) DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals); } - + MaybeMarkVirtualMembersReferenced(Loc, Constructor); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { if (Destructor->isImplicit() && !Destructor->isUsed()) @@ -7312,32 +7311,32 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { = Function->getTemplateSpecializationInfo()) { if (SpecInfo->getPointOfInstantiation().isInvalid()) SpecInfo->setPointOfInstantiation(Loc); - else if (SpecInfo->getTemplateSpecializationKind() + else if (SpecInfo->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) AlreadyInstantiated = true; - } else if (MemberSpecializationInfo *MSInfo + } else if (MemberSpecializationInfo *MSInfo = Function->getMemberSpecializationInfo()) { if (MSInfo->getPointOfInstantiation().isInvalid()) MSInfo->setPointOfInstantiation(Loc); - else if (MSInfo->getTemplateSpecializationKind() + else if (MSInfo->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) AlreadyInstantiated = true; } - + if (!AlreadyInstantiated) { if (isa<CXXRecordDecl>(Function->getDeclContext()) && cast<CXXRecordDecl>(Function->getDeclContext())->isLocalClass()) PendingLocalImplicitInstantiations.push_back(std::make_pair(Function, Loc)); else - PendingImplicitInstantiations.push_back(std::make_pair(Function, + PendingImplicitInstantiations.push_back(std::make_pair(Function, Loc)); } } - + // FIXME: keep track of references to static functions Function->setUsed(true); - + return; } @@ -7365,29 +7364,29 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { /// of the program being compiled. /// /// This routine emits the given diagnostic when the code currently being -/// type-checked is "potentially evaluated", meaning that there is a +/// type-checked is "potentially evaluated", meaning that there is a /// possibility that the code will actually be executable. Code in sizeof() /// expressions, code used only during overload resolution, etc., are not /// potentially evaluated. This routine will suppress such diagnostics or, /// in the absolutely nutty case of potentially potentially evaluated -/// expressions (C++ typeid), queue the diagnostic to potentially emit it +/// expressions (C++ typeid), queue the diagnostic to potentially emit it /// later. -/// +/// /// This routine should be used for all diagnostics that describe the run-time /// behavior of a program, such as passing a non-POD value through an ellipsis. /// Failure to do so will likely result in spurious diagnostics or failures /// during overload resolution or within sizeof/alignof/typeof/typeid. -bool Sema::DiagRuntimeBehavior(SourceLocation Loc, +bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const PartialDiagnostic &PD) { switch (ExprEvalContexts.back().Context ) { case Unevaluated: // The argument will never be evaluated, so don't complain. break; - + case PotentiallyEvaluated: Diag(Loc, PD); return true; - + case PotentiallyPotentiallyEvaluated: ExprEvalContexts.back().addDiagnostic(Loc, PD); break; @@ -7405,12 +7404,12 @@ bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc, FD ? PDiag(diag::note_function_with_incomplete_return_type_declared_here) << FD->getDeclName() : PDiag(); SourceLocation NoteLoc = FD ? FD->getLocation() : SourceLocation(); - + if (RequireCompleteType(Loc, ReturnType, - FD ? + FD ? PDiag(diag::err_call_function_incomplete_return) << CE->getSourceRange() << FD->getDeclName() : - PDiag(diag::err_call_incomplete_return) + PDiag(diag::err_call_incomplete_return) << CE->getSourceRange(), std::make_pair(NoteLoc, Note))) return true; @@ -7460,7 +7459,7 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) { SourceLocation Open = E->getSourceRange().getBegin(); SourceLocation Close = PP.getLocForEndOfToken(E->getSourceRange().getEnd()); - + Diag(Loc, diagnostic) << E->getSourceRange() << CodeModificationHint::CreateInsertion(Open, "(") diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index b9c8afa195fd..e1e5efa7d3a9 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -2085,7 +2085,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (LHS->isTypeDependent() || RHS->isTypeDependent()) return Context.DependentTy; - CheckSignCompare(LHS, RHS, QuestionLoc, diag::warn_mixed_sign_conditional); + CheckSignCompare(LHS, RHS, QuestionLoc); // C++0x 5.16p2 // If either the second or the third operand has type (cv) void, ... diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index c60455d8456c..c98ba435c789 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -106,7 +106,7 @@ Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, // which is an array type. StrTy = Context.CharTy; // A C++ string literal has a const-qualified element type (C++ 2.13.4p1). - if (getLangOptions().CPlusPlus) + if (getLangOptions().CPlusPlus || getLangOptions().ConstStrings) StrTy.addConst(); StrTy = Context.getConstantArrayType(StrTy, llvm::APInt(32, Str.size()+1), ArrayType::Normal, 0); diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 3540cd02e6da..98a7eec232f6 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -1051,6 +1051,7 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl(); RecordDecl::field_iterator FieldEnd = RD->field_end(); bool InitializedSomething = false; + bool CheckForMissingFields = true; while (Index < IList->getNumInits()) { Expr *Init = IList->getInit(Index); @@ -1070,6 +1071,10 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, hadError = true; InitializedSomething = true; + + // Disable check for missing fields when designators are used. + // This matches gcc behaviour. + CheckForMissingFields = false; continue; } @@ -1106,6 +1111,21 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, ++Field; } + // Emit warnings for missing struct field initializers. + if (CheckForMissingFields && Field != FieldEnd && + !Field->getType()->isIncompleteArrayType() && !DeclType->isUnionType()) { + // It is possible we have one or more unnamed bitfields remaining. + // Find first (if any) named field and emit warning. + for (RecordDecl::field_iterator it = Field, end = RD->field_end(); + it != end; ++it) { + if (!it->isUnnamedBitfield()) { + SemaRef.Diag(IList->getSourceRange().getEnd(), + diag::warn_missing_field_initializers) << it->getName(); + break; + } + } + } + if (Field == FieldEnd || !Field->getType()->isIncompleteArrayType() || Index >= IList->getNumInits()) return; @@ -3381,7 +3401,7 @@ InitializationSequence::Perform(Sema &S, // Build a call to the conversion function. CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn); - S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, + S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, 0, Conversion, FnAccess); // FIXME: Should we move this initialization into a separate diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 744b80632848..6caeec620d01 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -590,13 +590,73 @@ static bool isNamespaceOrTranslationUnitScope(Scope *S) { return false; } -// Find the next outer declaration context corresponding to this scope. -static DeclContext *findOuterContext(Scope *S) { - for (S = S->getParent(); S; S = S->getParent()) - if (S->getEntity()) - return static_cast<DeclContext *>(S->getEntity())->getPrimaryContext(); +// Find the next outer declaration context from this scope. This +// routine actually returns the semantic outer context, which may +// differ from the lexical context (encoded directly in the Scope +// stack) when we are parsing a member of a class template. In this +// case, the second element of the pair will be true, to indicate that +// name lookup should continue searching in this semantic context when +// it leaves the current template parameter scope. +static std::pair<DeclContext *, bool> findOuterContext(Scope *S) { + DeclContext *DC = static_cast<DeclContext *>(S->getEntity()); + DeclContext *Lexical = 0; + for (Scope *OuterS = S->getParent(); OuterS; + OuterS = OuterS->getParent()) { + if (OuterS->getEntity()) { + Lexical = static_cast<DeclContext *>(OuterS->getEntity()); + break; + } + } + + // C++ [temp.local]p8: + // In the definition of a member of a class template that appears + // outside of the namespace containing the class template + // definition, the name of a template-parameter hides the name of + // a member of this namespace. + // + // Example: + // + // namespace N { + // class C { }; + // + // template<class T> class B { + // void f(T); + // }; + // } + // + // template<class C> void N::B<C>::f(C) { + // C b; // C is the template parameter, not N::C + // } + // + // In this example, the lexical context we return is the + // TranslationUnit, while the semantic context is the namespace N. + if (!Lexical || !DC || !S->getParent() || + !S->getParent()->isTemplateParamScope()) + return std::make_pair(Lexical, false); + + // Find the outermost template parameter scope. + // For the example, this is the scope for the template parameters of + // template<class C>. + Scope *OutermostTemplateScope = S->getParent(); + while (OutermostTemplateScope->getParent() && + OutermostTemplateScope->getParent()->isTemplateParamScope()) + OutermostTemplateScope = OutermostTemplateScope->getParent(); - return 0; + // Find the namespace context in which the original scope occurs. In + // the example, this is namespace N. + DeclContext *Semantic = DC; + while (!Semantic->isFileContext()) + Semantic = Semantic->getParent(); + + // Find the declaration context just outside of the template + // parameter scope. This is the context in which the template is + // being lexically declaration (a namespace context). In the + // example, this is the global scope. + if (Lexical->isFileContext() && !Lexical->Equals(Semantic) && + Lexical->Encloses(Semantic)) + return std::make_pair(Semantic, true); + + return std::make_pair(Lexical, false); } bool Sema::CppLookupName(LookupResult &R, Scope *S) { @@ -627,6 +687,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // } // } // + DeclContext *OutsideOfTemplateParamDC = 0; for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) { // Check whether the IdResolver has anything in this scope. bool Found = false; @@ -641,10 +702,26 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { return true; } - if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) { - DeclContext *OuterCtx = findOuterContext(S); - for (; Ctx && Ctx->getPrimaryContext() != OuterCtx; - Ctx = Ctx->getLookupParent()) { + DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity()); + if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC && + S->getParent() && !S->getParent()->isTemplateParamScope()) { + // We've just searched the last template parameter scope and + // found nothing, so look into the the contexts between the + // lexical and semantic declaration contexts returned by + // findOuterContext(). This implements the name lookup behavior + // of C++ [temp.local]p8. + Ctx = OutsideOfTemplateParamDC; + OutsideOfTemplateParamDC = 0; + } + + if (Ctx) { + DeclContext *OuterCtx; + bool SearchAfterTemplateScope; + llvm::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S); + if (SearchAfterTemplateScope) + OutsideOfTemplateParamDC = OuterCtx; + + for (; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { // We do not directly look into transparent contexts, since // those entities will be found in the nearest enclosing // non-transparent context. @@ -725,7 +802,10 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { } } - if (Ctx) { + // If we have a context, and it's not a context stashed in the + // template parameter scope for an out-of-line definition, also + // look into that context. + if (Ctx && !(Found && S && S->isTemplateParamScope())) { assert(Ctx->isFileContext() && "We should have been looking only at file context here already."); @@ -2216,15 +2296,16 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, } } + // FIXME: C++ [temp.local]p8 DeclContext *Entity = 0; if (S->getEntity()) { // Look into this scope's declaration context, along with any of its // parent lookup contexts (e.g., enclosing classes), up to the point // where we hit the context stored in the next outer scope. Entity = (DeclContext *)S->getEntity(); - DeclContext *OuterCtx = findOuterContext(S); + DeclContext *OuterCtx = findOuterContext(S).first; // FIXME - for (DeclContext *Ctx = Entity; Ctx && Ctx->getPrimaryContext() != OuterCtx; + for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(Ctx)) { if (Method->isInstanceMethod()) { diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp new file mode 100644 index 000000000000..3a0fe0a61afe --- /dev/null +++ b/lib/Sema/SemaObjCProperty.cpp @@ -0,0 +1,1085 @@ +//===--- SemaObjCProperty.cpp - Semantic Analysis for ObjC @property ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for Objective C @property and +// @synthesize declarations. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" + +using namespace clang; + +//===----------------------------------------------------------------------===// +// Grammar actions. +//===----------------------------------------------------------------------===// + +Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, + FieldDeclarator &FD, + ObjCDeclSpec &ODS, + Selector GetterSel, + Selector SetterSel, + DeclPtrTy ClassCategory, + bool *isOverridingProperty, + tok::ObjCKeywordKind MethodImplKind) { + unsigned Attributes = ODS.getPropertyAttributes(); + bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) || + // default is readwrite! + !(Attributes & ObjCDeclSpec::DQ_PR_readonly)); + // property is defaulted to 'assign' if it is readwrite and is + // not retain or copy + bool isAssign = ((Attributes & ObjCDeclSpec::DQ_PR_assign) || + (isReadWrite && + !(Attributes & ObjCDeclSpec::DQ_PR_retain) && + !(Attributes & ObjCDeclSpec::DQ_PR_copy))); + + QualType T = GetTypeForDeclarator(FD.D, S); + if (T->isReferenceType()) { + Diag(AtLoc, diag::error_reference_property); + return DeclPtrTy(); + } + // Validate the attributes on the @property. + CheckObjCPropertyAttributes(T, AtLoc, Attributes); + + // Proceed with constructing the ObjCPropertDecls. + ObjCContainerDecl *ClassDecl = + cast<ObjCContainerDecl>(ClassCategory.getAs<Decl>()); + + if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) + if (CDecl->IsClassExtension()) + return HandlePropertyInClassExtension(S, CDecl, AtLoc, + FD, GetterSel, SetterSel, + isAssign, isReadWrite, + Attributes, + isOverridingProperty, T, + MethodImplKind); + + return DeclPtrTy::make(CreatePropertyDecl(S, ClassDecl, AtLoc, FD, + GetterSel, SetterSel, + isAssign, isReadWrite, + Attributes, T, MethodImplKind)); +} + +Sema::DeclPtrTy +Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, + SourceLocation AtLoc, FieldDeclarator &FD, + Selector GetterSel, Selector SetterSel, + const bool isAssign, + const bool isReadWrite, + const unsigned Attributes, + bool *isOverridingProperty, + QualType T, + tok::ObjCKeywordKind MethodImplKind) { + + // Diagnose if this property is already in continuation class. + DeclContext *DC = cast<DeclContext>(CDecl); + IdentifierInfo *PropertyId = FD.D.getIdentifier(); + + if (ObjCPropertyDecl *prevDecl = + ObjCPropertyDecl::findPropertyDecl(DC, PropertyId)) { + Diag(AtLoc, diag::err_duplicate_property); + Diag(prevDecl->getLocation(), diag::note_property_declare); + return DeclPtrTy(); + } + + // Create a new ObjCPropertyDecl with the DeclContext being + // the class extension. + ObjCPropertyDecl *PDecl = + ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(), + PropertyId, AtLoc, T); + DC->addDecl(PDecl); + + // We need to look in the @interface to see if the @property was + // already declared. + ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface(); + if (!CCPrimary) { + Diag(CDecl->getLocation(), diag::err_continuation_class); + *isOverridingProperty = true; + return DeclPtrTy(); + } + + // Find the property in continuation class's primary class only. + ObjCPropertyDecl *PIDecl = + CCPrimary->FindPropertyVisibleInPrimaryClass(PropertyId); + + if (!PIDecl) { + // No matching property found in the primary class. Just fall thru + // and add property to continuation class's primary class. + ObjCPropertyDecl *PDecl = + CreatePropertyDecl(S, CCPrimary, AtLoc, + FD, GetterSel, SetterSel, isAssign, isReadWrite, + Attributes, T, MethodImplKind); + + // A case of continuation class adding a new property in the class. This + // is not what it was meant for. However, gcc supports it and so should we. + // Make sure setter/getters are declared here. + ProcessPropertyDecl(PDecl, CCPrimary); + return DeclPtrTy::make(PDecl); + + } + + // The property 'PIDecl's readonly attribute will be over-ridden + // with continuation class's readwrite property attribute! + unsigned PIkind = PIDecl->getPropertyAttributes(); + if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) { + unsigned retainCopyNonatomic = + (ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_copy | + ObjCPropertyDecl::OBJC_PR_nonatomic); + if ((Attributes & retainCopyNonatomic) != + (PIkind & retainCopyNonatomic)) { + Diag(AtLoc, diag::warn_property_attr_mismatch); + Diag(PIDecl->getLocation(), diag::note_property_declare); + } + DeclContext *DC = dyn_cast<DeclContext>(CCPrimary); + assert(DC && "ClassDecl is not a DeclContext"); + DeclContext::lookup_result Found = + DC->lookup(PIDecl->getDeclName()); + bool PropertyInPrimaryClass = false; + for (; Found.first != Found.second; ++Found.first) + if (isa<ObjCPropertyDecl>(*Found.first)) { + PropertyInPrimaryClass = true; + break; + } + if (!PropertyInPrimaryClass) { + // Protocol is not in the primary class. Must build one for it. + ObjCDeclSpec ProtocolPropertyODS; + // FIXME. Assuming that ObjCDeclSpec::ObjCPropertyAttributeKind + // and ObjCPropertyDecl::PropertyAttributeKind have identical + // values. Should consolidate both into one enum type. + ProtocolPropertyODS. + setPropertyAttributes((ObjCDeclSpec::ObjCPropertyAttributeKind) + PIkind); + + DeclPtrTy ProtocolPtrTy = + ActOnProperty(S, AtLoc, FD, ProtocolPropertyODS, + PIDecl->getGetterName(), + PIDecl->getSetterName(), + DeclPtrTy::make(CCPrimary), isOverridingProperty, + MethodImplKind); + PIDecl = ProtocolPtrTy.getAs<ObjCPropertyDecl>(); + } + PIDecl->makeitReadWriteAttribute(); + if (Attributes & ObjCDeclSpec::DQ_PR_retain) + PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); + if (Attributes & ObjCDeclSpec::DQ_PR_copy) + PIDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); + PIDecl->setSetterName(SetterSel); + } else { + Diag(AtLoc, diag::err_use_continuation_class) + << CCPrimary->getDeclName(); + Diag(PIDecl->getLocation(), diag::note_property_declare); + } + *isOverridingProperty = true; + // Make sure setter decl is synthesized, and added to primary class's list. + ProcessPropertyDecl(PIDecl, CCPrimary); + return DeclPtrTy(); +} + +ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, + ObjCContainerDecl *CDecl, + SourceLocation AtLoc, + FieldDeclarator &FD, + Selector GetterSel, + Selector SetterSel, + const bool isAssign, + const bool isReadWrite, + const unsigned Attributes, + QualType T, + tok::ObjCKeywordKind MethodImplKind){ + + IdentifierInfo *PropertyId = FD.D.getIdentifier(); + + // Issue a warning if property is 'assign' as default and its object, which is + // gc'able conforms to NSCopying protocol + if (getLangOptions().getGCMode() != LangOptions::NonGC && + isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign)) + if (T->isObjCObjectPointerType()) { + QualType InterfaceTy = T->getPointeeType(); + if (const ObjCInterfaceType *OIT = + InterfaceTy->getAs<ObjCInterfaceType>()) { + ObjCInterfaceDecl *IDecl = OIT->getDecl(); + if (IDecl) + if (ObjCProtocolDecl* PNSCopying = + LookupProtocol(&Context.Idents.get("NSCopying"))) + if (IDecl->ClassImplementsProtocol(PNSCopying, true)) + Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId; + } + } + if (T->isObjCInterfaceType()) + Diag(FD.D.getIdentifierLoc(), diag::err_statically_allocated_object); + + DeclContext *DC = cast<DeclContext>(CDecl); + ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, + FD.D.getIdentifierLoc(), + PropertyId, AtLoc, T); + + if (ObjCPropertyDecl *prevDecl = + ObjCPropertyDecl::findPropertyDecl(DC, PropertyId)) { + Diag(PDecl->getLocation(), diag::err_duplicate_property); + Diag(prevDecl->getLocation(), diag::note_property_declare); + PDecl->setInvalidDecl(); + } + else + DC->addDecl(PDecl); + + if (T->isArrayType() || T->isFunctionType()) { + Diag(AtLoc, diag::err_property_type) << T; + PDecl->setInvalidDecl(); + } + + ProcessDeclAttributes(S, PDecl, FD.D); + + // Regardless of setter/getter attribute, we save the default getter/setter + // selector names in anticipation of declaration of setter/getter methods. + PDecl->setGetterName(GetterSel); + PDecl->setSetterName(SetterSel); + + if (Attributes & ObjCDeclSpec::DQ_PR_readonly) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly); + + if (Attributes & ObjCDeclSpec::DQ_PR_getter) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_getter); + + if (Attributes & ObjCDeclSpec::DQ_PR_setter) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_setter); + + if (isReadWrite) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite); + + if (Attributes & ObjCDeclSpec::DQ_PR_retain) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); + + if (Attributes & ObjCDeclSpec::DQ_PR_copy) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); + + if (isAssign) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign); + + if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic); + + if (MethodImplKind == tok::objc_required) + PDecl->setPropertyImplementation(ObjCPropertyDecl::Required); + else if (MethodImplKind == tok::objc_optional) + PDecl->setPropertyImplementation(ObjCPropertyDecl::Optional); + + return PDecl; +} + + +/// ActOnPropertyImplDecl - This routine performs semantic checks and +/// builds the AST node for a property implementation declaration; declared +/// as @synthesize or @dynamic. +/// +Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, + SourceLocation PropertyLoc, + bool Synthesize, + DeclPtrTy ClassCatImpDecl, + IdentifierInfo *PropertyId, + IdentifierInfo *PropertyIvar) { + Decl *ClassImpDecl = ClassCatImpDecl.getAs<Decl>(); + // Make sure we have a context for the property implementation declaration. + if (!ClassImpDecl) { + Diag(AtLoc, diag::error_missing_property_context); + return DeclPtrTy(); + } + ObjCPropertyDecl *property = 0; + ObjCInterfaceDecl* IDecl = 0; + // Find the class or category class where this property must have + // a declaration. + ObjCImplementationDecl *IC = 0; + ObjCCategoryImplDecl* CatImplClass = 0; + if ((IC = dyn_cast<ObjCImplementationDecl>(ClassImpDecl))) { + IDecl = IC->getClassInterface(); + // We always synthesize an interface for an implementation + // without an interface decl. So, IDecl is always non-zero. + assert(IDecl && + "ActOnPropertyImplDecl - @implementation without @interface"); + + // Look for this property declaration in the @implementation's @interface + property = IDecl->FindPropertyDeclaration(PropertyId); + if (!property) { + Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName(); + return DeclPtrTy(); + } + if (const ObjCCategoryDecl *CD = + dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) { + if (!CD->IsClassExtension()) { + Diag(PropertyLoc, diag::error_category_property) << CD->getDeclName(); + Diag(property->getLocation(), diag::note_property_declare); + return DeclPtrTy(); + } + } + } else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) { + if (Synthesize) { + Diag(AtLoc, diag::error_synthesize_category_decl); + return DeclPtrTy(); + } + IDecl = CatImplClass->getClassInterface(); + if (!IDecl) { + Diag(AtLoc, diag::error_missing_property_interface); + return DeclPtrTy(); + } + ObjCCategoryDecl *Category = + IDecl->FindCategoryDeclaration(CatImplClass->getIdentifier()); + + // If category for this implementation not found, it is an error which + // has already been reported eralier. + if (!Category) + return DeclPtrTy(); + // Look for this property declaration in @implementation's category + property = Category->FindPropertyDeclaration(PropertyId); + if (!property) { + Diag(PropertyLoc, diag::error_bad_category_property_decl) + << Category->getDeclName(); + return DeclPtrTy(); + } + } else { + Diag(AtLoc, diag::error_bad_property_context); + return DeclPtrTy(); + } + ObjCIvarDecl *Ivar = 0; + // Check that we have a valid, previously declared ivar for @synthesize + if (Synthesize) { + // @synthesize + if (!PropertyIvar) + PropertyIvar = PropertyId; + QualType PropType = Context.getCanonicalType(property->getType()); + // Check that this is a previously declared 'ivar' in 'IDecl' interface + ObjCInterfaceDecl *ClassDeclared; + Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared); + if (!Ivar) { + DeclContext *EnclosingContext = cast_or_null<DeclContext>(ClassImpDecl); + assert(EnclosingContext && + "null DeclContext for synthesized ivar - ActOnPropertyImplDecl"); + Ivar = ObjCIvarDecl::Create(Context, EnclosingContext, PropertyLoc, + PropertyIvar, PropType, /*Dinfo=*/0, + ObjCIvarDecl::Public, + (Expr *)0); + EnclosingContext->addDecl(Ivar); + IDecl->makeDeclVisibleInContext(Ivar, false); + property->setPropertyIvarDecl(Ivar); + + if (!getLangOptions().ObjCNonFragileABI) + Diag(PropertyLoc, diag::error_missing_property_ivar_decl) << PropertyId; + // Note! I deliberately want it to fall thru so, we have a + // a property implementation and to avoid future warnings. + } else if (getLangOptions().ObjCNonFragileABI && + ClassDeclared != IDecl) { + Diag(PropertyLoc, diag::error_ivar_in_superclass_use) + << property->getDeclName() << Ivar->getDeclName() + << ClassDeclared->getDeclName(); + Diag(Ivar->getLocation(), diag::note_previous_access_declaration) + << Ivar << Ivar->getNameAsCString(); + // Note! I deliberately want it to fall thru so more errors are caught. + } + QualType IvarType = Context.getCanonicalType(Ivar->getType()); + + // Check that type of property and its ivar are type compatible. + if (PropType != IvarType) { + if (CheckAssignmentConstraints(PropType, IvarType) != Compatible) { + Diag(PropertyLoc, diag::error_property_ivar_type) + << property->getDeclName() << Ivar->getDeclName(); + // Note! I deliberately want it to fall thru so, we have a + // a property implementation and to avoid future warnings. + } + + // FIXME! Rules for properties are somewhat different that those + // for assignments. Use a new routine to consolidate all cases; + // specifically for property redeclarations as well as for ivars. + QualType lhsType =Context.getCanonicalType(PropType).getUnqualifiedType(); + QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType(); + if (lhsType != rhsType && + lhsType->isArithmeticType()) { + Diag(PropertyLoc, diag::error_property_ivar_type) + << property->getDeclName() << Ivar->getDeclName(); + // Fall thru - see previous comment + } + // __weak is explicit. So it works on Canonical type. + if (PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() && + getLangOptions().getGCMode() != LangOptions::NonGC) { + Diag(PropertyLoc, diag::error_weak_property) + << property->getDeclName() << Ivar->getDeclName(); + // Fall thru - see previous comment + } + if ((property->getType()->isObjCObjectPointerType() || + PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() && + getLangOptions().getGCMode() != LangOptions::NonGC) { + Diag(PropertyLoc, diag::error_strong_property) + << property->getDeclName() << Ivar->getDeclName(); + // Fall thru - see previous comment + } + } + } else if (PropertyIvar) + // @dynamic + Diag(PropertyLoc, diag::error_dynamic_property_ivar_decl); + assert (property && "ActOnPropertyImplDecl - property declaration missing"); + ObjCPropertyImplDecl *PIDecl = + ObjCPropertyImplDecl::Create(Context, CurContext, AtLoc, PropertyLoc, + property, + (Synthesize ? + ObjCPropertyImplDecl::Synthesize + : ObjCPropertyImplDecl::Dynamic), + Ivar); + if (IC) { + if (Synthesize) + if (ObjCPropertyImplDecl *PPIDecl = + IC->FindPropertyImplIvarDecl(PropertyIvar)) { + Diag(PropertyLoc, diag::error_duplicate_ivar_use) + << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier() + << PropertyIvar; + Diag(PPIDecl->getLocation(), diag::note_previous_use); + } + + if (ObjCPropertyImplDecl *PPIDecl + = IC->FindPropertyImplDecl(PropertyId)) { + Diag(PropertyLoc, diag::error_property_implemented) << PropertyId; + Diag(PPIDecl->getLocation(), diag::note_previous_declaration); + return DeclPtrTy(); + } + IC->addPropertyImplementation(PIDecl); + } else { + if (Synthesize) + if (ObjCPropertyImplDecl *PPIDecl = + CatImplClass->FindPropertyImplIvarDecl(PropertyIvar)) { + Diag(PropertyLoc, diag::error_duplicate_ivar_use) + << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier() + << PropertyIvar; + Diag(PPIDecl->getLocation(), diag::note_previous_use); + } + + if (ObjCPropertyImplDecl *PPIDecl = + CatImplClass->FindPropertyImplDecl(PropertyId)) { + Diag(PropertyLoc, diag::error_property_implemented) << PropertyId; + Diag(PPIDecl->getLocation(), diag::note_previous_declaration); + return DeclPtrTy(); + } + CatImplClass->addPropertyImplementation(PIDecl); + } + + return DeclPtrTy::make(PIDecl); +} + +//===----------------------------------------------------------------------===// +// Helper methods. +//===----------------------------------------------------------------------===// + +/// DiagnosePropertyMismatch - Compares two properties for their +/// attributes and types and warns on a variety of inconsistencies. +/// +void +Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property, + ObjCPropertyDecl *SuperProperty, + const IdentifierInfo *inheritedName) { + ObjCPropertyDecl::PropertyAttributeKind CAttr = + Property->getPropertyAttributes(); + ObjCPropertyDecl::PropertyAttributeKind SAttr = + SuperProperty->getPropertyAttributes(); + if ((CAttr & ObjCPropertyDecl::OBJC_PR_readonly) + && (SAttr & ObjCPropertyDecl::OBJC_PR_readwrite)) + Diag(Property->getLocation(), diag::warn_readonly_property) + << Property->getDeclName() << inheritedName; + if ((CAttr & ObjCPropertyDecl::OBJC_PR_copy) + != (SAttr & ObjCPropertyDecl::OBJC_PR_copy)) + Diag(Property->getLocation(), diag::warn_property_attribute) + << Property->getDeclName() << "copy" << inheritedName; + else if ((CAttr & ObjCPropertyDecl::OBJC_PR_retain) + != (SAttr & ObjCPropertyDecl::OBJC_PR_retain)) + Diag(Property->getLocation(), diag::warn_property_attribute) + << Property->getDeclName() << "retain" << inheritedName; + + if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic) + != (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)) + Diag(Property->getLocation(), diag::warn_property_attribute) + << Property->getDeclName() << "atomic" << inheritedName; + if (Property->getSetterName() != SuperProperty->getSetterName()) + Diag(Property->getLocation(), diag::warn_property_attribute) + << Property->getDeclName() << "setter" << inheritedName; + if (Property->getGetterName() != SuperProperty->getGetterName()) + Diag(Property->getLocation(), diag::warn_property_attribute) + << Property->getDeclName() << "getter" << inheritedName; + + QualType LHSType = + Context.getCanonicalType(SuperProperty->getType()); + QualType RHSType = + Context.getCanonicalType(Property->getType()); + + if (!Context.typesAreCompatible(LHSType, RHSType)) { + // FIXME: Incorporate this test with typesAreCompatible. + if (LHSType->isObjCQualifiedIdType() && RHSType->isObjCQualifiedIdType()) + if (Context.ObjCQualifiedIdTypesAreCompatible(LHSType, RHSType, false)) + return; + Diag(Property->getLocation(), diag::warn_property_types_are_incompatible) + << Property->getType() << SuperProperty->getType() << inheritedName; + } +} + +bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property, + ObjCMethodDecl *GetterMethod, + SourceLocation Loc) { + if (GetterMethod && + GetterMethod->getResultType() != property->getType()) { + AssignConvertType result = Incompatible; + if (property->getType()->isObjCObjectPointerType()) + result = CheckAssignmentConstraints(GetterMethod->getResultType(), + property->getType()); + if (result != Compatible) { + Diag(Loc, diag::warn_accessor_property_type_mismatch) + << property->getDeclName() + << GetterMethod->getSelector(); + Diag(GetterMethod->getLocation(), diag::note_declared_at); + return true; + } + } + return false; +} + +/// ComparePropertiesInBaseAndSuper - This routine compares property +/// declarations in base and its super class, if any, and issues +/// diagnostics in a variety of inconsistant situations. +/// +void Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) { + ObjCInterfaceDecl *SDecl = IDecl->getSuperClass(); + if (!SDecl) + return; + // FIXME: O(N^2) + for (ObjCInterfaceDecl::prop_iterator S = SDecl->prop_begin(), + E = SDecl->prop_end(); S != E; ++S) { + ObjCPropertyDecl *SuperPDecl = (*S); + // Does property in super class has declaration in current class? + for (ObjCInterfaceDecl::prop_iterator I = IDecl->prop_begin(), + E = IDecl->prop_end(); I != E; ++I) { + ObjCPropertyDecl *PDecl = (*I); + if (SuperPDecl->getIdentifier() == PDecl->getIdentifier()) + DiagnosePropertyMismatch(PDecl, SuperPDecl, + SDecl->getIdentifier()); + } + } +} + +/// MatchOneProtocolPropertiesInClass - This routine goes thru the list +/// of properties declared in a protocol and compares their attribute against +/// the same property declared in the class or category. +void +Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl, + ObjCProtocolDecl *PDecl) { + ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl); + if (!IDecl) { + // Category + ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl); + assert (CatDecl && "MatchOneProtocolPropertiesInClass"); + if (!CatDecl->IsClassExtension()) + for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), + E = PDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Pr = (*P); + ObjCCategoryDecl::prop_iterator CP, CE; + // Is this property already in category's list of properties? + for (CP = CatDecl->prop_begin(), CE = CatDecl->prop_end(); CP!=CE; ++CP) + if ((*CP)->getIdentifier() == Pr->getIdentifier()) + break; + if (CP != CE) + // Property protocol already exist in class. Diagnose any mismatch. + DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier()); + } + return; + } + for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), + E = PDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Pr = (*P); + ObjCInterfaceDecl::prop_iterator CP, CE; + // Is this property already in class's list of properties? + for (CP = IDecl->prop_begin(), CE = IDecl->prop_end(); CP != CE; ++CP) + if ((*CP)->getIdentifier() == Pr->getIdentifier()) + break; + if (CP != CE) + // Property protocol already exist in class. Diagnose any mismatch. + DiagnosePropertyMismatch((*CP), Pr, PDecl->getIdentifier()); + } +} + +/// CompareProperties - This routine compares properties +/// declared in 'ClassOrProtocol' objects (which can be a class or an +/// inherited protocol with the list of properties for class/category 'CDecl' +/// +void Sema::CompareProperties(Decl *CDecl, + DeclPtrTy ClassOrProtocol) { + Decl *ClassDecl = ClassOrProtocol.getAs<Decl>(); + ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl); + + if (!IDecl) { + // Category + ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl); + assert (CatDecl && "CompareProperties"); + if (ObjCCategoryDecl *MDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) { + for (ObjCCategoryDecl::protocol_iterator P = MDecl->protocol_begin(), + E = MDecl->protocol_end(); P != E; ++P) + // Match properties of category with those of protocol (*P) + MatchOneProtocolPropertiesInClass(CatDecl, *P); + + // Go thru the list of protocols for this category and recursively match + // their properties with those in the category. + for (ObjCCategoryDecl::protocol_iterator P = CatDecl->protocol_begin(), + E = CatDecl->protocol_end(); P != E; ++P) + CompareProperties(CatDecl, DeclPtrTy::make(*P)); + } else { + ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl); + for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(), + E = MD->protocol_end(); P != E; ++P) + MatchOneProtocolPropertiesInClass(CatDecl, *P); + } + return; + } + + if (ObjCInterfaceDecl *MDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) { + for (ObjCInterfaceDecl::protocol_iterator P = MDecl->protocol_begin(), + E = MDecl->protocol_end(); P != E; ++P) + // Match properties of class IDecl with those of protocol (*P). + MatchOneProtocolPropertiesInClass(IDecl, *P); + + // Go thru the list of protocols for this class and recursively match + // their properties with those declared in the class. + for (ObjCInterfaceDecl::protocol_iterator P = IDecl->protocol_begin(), + E = IDecl->protocol_end(); P != E; ++P) + CompareProperties(IDecl, DeclPtrTy::make(*P)); + } else { + ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl); + for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(), + E = MD->protocol_end(); P != E; ++P) + MatchOneProtocolPropertiesInClass(IDecl, *P); + } +} + +/// isPropertyReadonly - Return true if property is readonly, by searching +/// for the property in the class and in its categories and implementations +/// +bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl, + ObjCInterfaceDecl *IDecl) { + // by far the most common case. + if (!PDecl->isReadOnly()) + return false; + // Even if property is ready only, if interface has a user defined setter, + // it is not considered read only. + if (IDecl->getInstanceMethod(PDecl->getSetterName())) + return false; + + // Main class has the property as 'readonly'. Must search + // through the category list to see if the property's + // attribute has been over-ridden to 'readwrite'. + for (ObjCCategoryDecl *Category = IDecl->getCategoryList(); + Category; Category = Category->getNextClassCategory()) { + // Even if property is ready only, if a category has a user defined setter, + // it is not considered read only. + if (Category->getInstanceMethod(PDecl->getSetterName())) + return false; + ObjCPropertyDecl *P = + Category->FindPropertyDeclaration(PDecl->getIdentifier()); + if (P && !P->isReadOnly()) + return false; + } + + // Also, check for definition of a setter method in the implementation if + // all else failed. + if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(CurContext)) { + if (ObjCImplementationDecl *IMD = + dyn_cast<ObjCImplementationDecl>(OMD->getDeclContext())) { + if (IMD->getInstanceMethod(PDecl->getSetterName())) + return false; + } else if (ObjCCategoryImplDecl *CIMD = + dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) { + if (CIMD->getInstanceMethod(PDecl->getSetterName())) + return false; + } + } + // Lastly, look through the implementation (if one is in scope). + if (ObjCImplementationDecl *ImpDecl = IDecl->getImplementation()) + if (ImpDecl->getInstanceMethod(PDecl->getSetterName())) + return false; + // If all fails, look at the super class. + if (ObjCInterfaceDecl *SIDecl = IDecl->getSuperClass()) + return isPropertyReadonly(PDecl, SIDecl); + return true; +} + +/// CollectImmediateProperties - This routine collects all properties in +/// the class and its conforming protocols; but not those it its super class. +void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, + llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) { + if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) { + for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(), + E = IDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + PropMap[Prop->getIdentifier()] = Prop; + } + // scan through class's protocols. + for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(), + E = IDecl->protocol_end(); PI != E; ++PI) + CollectImmediateProperties((*PI), PropMap); + } + if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) { + if (!CATDecl->IsClassExtension()) + for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(), + E = CATDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + PropMap[Prop->getIdentifier()] = Prop; + } + // scan through class's protocols. + for (ObjCInterfaceDecl::protocol_iterator PI = CATDecl->protocol_begin(), + E = CATDecl->protocol_end(); PI != E; ++PI) + CollectImmediateProperties((*PI), PropMap); + } + else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) { + for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), + E = PDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + ObjCPropertyDecl *&PropEntry = PropMap[Prop->getIdentifier()]; + if (!PropEntry) + PropEntry = Prop; + } + // scan through protocol's protocols. + for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), + E = PDecl->protocol_end(); PI != E; ++PI) + CollectImmediateProperties((*PI), PropMap); + } +} + +/// LookupPropertyDecl - Looks up a property in the current class and all +/// its protocols. +ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl, + IdentifierInfo *II) { + if (const ObjCInterfaceDecl *IDecl = + dyn_cast<ObjCInterfaceDecl>(CDecl)) { + for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(), + E = IDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + if (Prop->getIdentifier() == II) + return Prop; + } + // scan through class's protocols. + for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(), + E = IDecl->protocol_end(); PI != E; ++PI) { + ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II); + if (Prop) + return Prop; + } + } + else if (const ObjCProtocolDecl *PDecl = + dyn_cast<ObjCProtocolDecl>(CDecl)) { + for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), + E = PDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + if (Prop->getIdentifier() == II) + return Prop; + } + // scan through protocol's protocols. + for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), + E = PDecl->protocol_end(); PI != E; ++PI) { + ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II); + if (Prop) + return Prop; + } + } + return 0; +} + + +void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, + ObjCContainerDecl *CDecl, + const llvm::DenseSet<Selector>& InsMap) { + llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap; + CollectImmediateProperties(CDecl, PropMap); + if (PropMap.empty()) + return; + + llvm::DenseSet<ObjCPropertyDecl *> PropImplMap; + for (ObjCImplDecl::propimpl_iterator + I = IMPDecl->propimpl_begin(), + EI = IMPDecl->propimpl_end(); I != EI; ++I) + PropImplMap.insert((*I)->getPropertyDecl()); + + for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator + P = PropMap.begin(), E = PropMap.end(); P != E; ++P) { + ObjCPropertyDecl *Prop = P->second; + // Is there a matching propery synthesize/dynamic? + if (Prop->isInvalidDecl() || + Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional || + PropImplMap.count(Prop)) + continue; + if (LangOpts.ObjCNonFragileABI2) { + ActOnPropertyImplDecl(IMPDecl->getLocation(), + SourceLocation(), + true, DeclPtrTy::make(IMPDecl), + Prop->getIdentifier(), + Prop->getIdentifier()); + continue; + } + if (!InsMap.count(Prop->getGetterName())) { + Diag(Prop->getLocation(), + isa<ObjCCategoryDecl>(CDecl) ? + diag::warn_setter_getter_impl_required_in_category : + diag::warn_setter_getter_impl_required) + << Prop->getDeclName() << Prop->getGetterName(); + Diag(IMPDecl->getLocation(), + diag::note_property_impl_required); + } + + if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) { + Diag(Prop->getLocation(), + isa<ObjCCategoryDecl>(CDecl) ? + diag::warn_setter_getter_impl_required_in_category : + diag::warn_setter_getter_impl_required) + << Prop->getDeclName() << Prop->getSetterName(); + Diag(IMPDecl->getLocation(), + diag::note_property_impl_required); + } + } +} + +void +Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, + ObjCContainerDecl* IDecl) { + // Rules apply in non-GC mode only + if (getLangOptions().getGCMode() != LangOptions::NonGC) + return; + for (ObjCContainerDecl::prop_iterator I = IDecl->prop_begin(), + E = IDecl->prop_end(); + I != E; ++I) { + ObjCPropertyDecl *Property = (*I); + unsigned Attributes = Property->getPropertyAttributes(); + // We only care about readwrite atomic property. + if ((Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) || + !(Attributes & ObjCPropertyDecl::OBJC_PR_readwrite)) + continue; + if (const ObjCPropertyImplDecl *PIDecl + = IMPDecl->FindPropertyImplDecl(Property->getIdentifier())) { + if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) + continue; + ObjCMethodDecl *GetterMethod = + IMPDecl->getInstanceMethod(Property->getGetterName()); + ObjCMethodDecl *SetterMethod = + IMPDecl->getInstanceMethod(Property->getSetterName()); + if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) { + SourceLocation MethodLoc = + (GetterMethod ? GetterMethod->getLocation() + : SetterMethod->getLocation()); + Diag(MethodLoc, diag::warn_atomic_property_rule) + << Property->getIdentifier(); + Diag(Property->getLocation(), diag::note_property_declare); + } + } + } +} + +/// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods +/// have the property type and issue diagnostics if they don't. +/// Also synthesize a getter/setter method if none exist (and update the +/// appropriate lookup tables. FIXME: Should reconsider if adding synthesized +/// methods is the "right" thing to do. +void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, + ObjCContainerDecl *CD) { + ObjCMethodDecl *GetterMethod, *SetterMethod; + + GetterMethod = CD->getInstanceMethod(property->getGetterName()); + SetterMethod = CD->getInstanceMethod(property->getSetterName()); + DiagnosePropertyAccessorMismatch(property, GetterMethod, + property->getLocation()); + + if (SetterMethod) { + ObjCPropertyDecl::PropertyAttributeKind CAttr = + property->getPropertyAttributes(); + if ((!(CAttr & ObjCPropertyDecl::OBJC_PR_readonly)) && + Context.getCanonicalType(SetterMethod->getResultType()) != + Context.VoidTy) + Diag(SetterMethod->getLocation(), diag::err_setter_type_void); + if (SetterMethod->param_size() != 1 || + ((*SetterMethod->param_begin())->getType() != property->getType())) { + Diag(property->getLocation(), + diag::warn_accessor_property_type_mismatch) + << property->getDeclName() + << SetterMethod->getSelector(); + Diag(SetterMethod->getLocation(), diag::note_declared_at); + } + } + + // Synthesize getter/setter methods if none exist. + // Find the default getter and if one not found, add one. + // FIXME: The synthesized property we set here is misleading. We almost always + // synthesize these methods unless the user explicitly provided prototypes + // (which is odd, but allowed). Sema should be typechecking that the + // declarations jive in that situation (which it is not currently). + if (!GetterMethod) { + // No instance method of same name as property getter name was found. + // Declare a getter method and add it to the list of methods + // for this class. + GetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(), + property->getLocation(), property->getGetterName(), + property->getType(), 0, CD, true, false, true, + (property->getPropertyImplementation() == + ObjCPropertyDecl::Optional) ? + ObjCMethodDecl::Optional : + ObjCMethodDecl::Required); + CD->addDecl(GetterMethod); + } else + // A user declared getter will be synthesize when @synthesize of + // the property with the same name is seen in the @implementation + GetterMethod->setSynthesized(true); + property->setGetterMethodDecl(GetterMethod); + + // Skip setter if property is read-only. + if (!property->isReadOnly()) { + // Find the default setter and if one not found, add one. + if (!SetterMethod) { + // No instance method of same name as property setter name was found. + // Declare a setter method and add it to the list of methods + // for this class. + SetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(), + property->getLocation(), + property->getSetterName(), + Context.VoidTy, 0, CD, true, false, true, + (property->getPropertyImplementation() == + ObjCPropertyDecl::Optional) ? + ObjCMethodDecl::Optional : + ObjCMethodDecl::Required); + // Invent the arguments for the setter. We don't bother making a + // nice name for the argument. + ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod, + property->getLocation(), + property->getIdentifier(), + property->getType(), + /*TInfo=*/0, + VarDecl::None, + 0); + SetterMethod->setMethodParams(Context, &Argument, 1); + CD->addDecl(SetterMethod); + } else + // A user declared setter will be synthesize when @synthesize of + // the property with the same name is seen in the @implementation + SetterMethod->setSynthesized(true); + property->setSetterMethodDecl(SetterMethod); + } + // Add any synthesized methods to the global pool. This allows us to + // handle the following, which is supported by GCC (and part of the design). + // + // @interface Foo + // @property double bar; + // @end + // + // void thisIsUnfortunate() { + // id foo; + // double bar = [foo bar]; + // } + // + if (GetterMethod) + AddInstanceMethodToGlobalPool(GetterMethod); + if (SetterMethod) + AddInstanceMethodToGlobalPool(SetterMethod); +} + +void Sema::CheckObjCPropertyAttributes(QualType PropertyTy, + SourceLocation Loc, + unsigned &Attributes) { + // FIXME: Improve the reported location. + + // readonly and readwrite/assign/retain/copy conflict. + if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) && + (Attributes & (ObjCDeclSpec::DQ_PR_readwrite | + ObjCDeclSpec::DQ_PR_assign | + ObjCDeclSpec::DQ_PR_copy | + ObjCDeclSpec::DQ_PR_retain))) { + const char * which = (Attributes & ObjCDeclSpec::DQ_PR_readwrite) ? + "readwrite" : + (Attributes & ObjCDeclSpec::DQ_PR_assign) ? + "assign" : + (Attributes & ObjCDeclSpec::DQ_PR_copy) ? + "copy" : "retain"; + + Diag(Loc, (Attributes & (ObjCDeclSpec::DQ_PR_readwrite)) ? + diag::err_objc_property_attr_mutually_exclusive : + diag::warn_objc_property_attr_mutually_exclusive) + << "readonly" << which; + } + + // Check for copy or retain on non-object types. + if ((Attributes & (ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain)) && + !PropertyTy->isObjCObjectPointerType() && + !PropertyTy->isBlockPointerType() && + !Context.isObjCNSObjectType(PropertyTy)) { + Diag(Loc, diag::err_objc_property_requires_object) + << (Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain"); + Attributes &= ~(ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain); + } + + // Check for more than one of { assign, copy, retain }. + if (Attributes & ObjCDeclSpec::DQ_PR_assign) { + if (Attributes & ObjCDeclSpec::DQ_PR_copy) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "assign" << "copy"; + Attributes &= ~ObjCDeclSpec::DQ_PR_copy; + } + if (Attributes & ObjCDeclSpec::DQ_PR_retain) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "assign" << "retain"; + Attributes &= ~ObjCDeclSpec::DQ_PR_retain; + } + } else if (Attributes & ObjCDeclSpec::DQ_PR_copy) { + if (Attributes & ObjCDeclSpec::DQ_PR_retain) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) + << "copy" << "retain"; + Attributes &= ~ObjCDeclSpec::DQ_PR_retain; + } + } + + // Warn if user supplied no assignment attribute, property is + // readwrite, and this is an object type. + if (!(Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_copy | + ObjCDeclSpec::DQ_PR_retain)) && + !(Attributes & ObjCDeclSpec::DQ_PR_readonly) && + PropertyTy->isObjCObjectPointerType()) { + // Skip this warning in gc-only mode. + if (getLangOptions().getGCMode() != LangOptions::GCOnly) + Diag(Loc, diag::warn_objc_property_no_assignment_attribute); + + // If non-gc code warn that this is likely inappropriate. + if (getLangOptions().getGCMode() == LangOptions::NonGC) + Diag(Loc, diag::warn_objc_property_default_assign_on_object); + + // FIXME: Implement warning dependent on NSCopying being + // implemented. See also: + // <rdar://5168496&4855821&5607453&5096644&4947311&5698469&4947014&5168496> + // (please trim this list while you are at it). + } + + if (!(Attributes & ObjCDeclSpec::DQ_PR_copy) + && getLangOptions().getGCMode() == LangOptions::GCOnly + && PropertyTy->isBlockPointerType()) + Diag(Loc, diag::warn_objc_property_copy_missing_on_block); +} + +ObjCIvarDecl* +Sema::SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl, + IdentifierInfo *NameII) { + ObjCIvarDecl *Ivar = 0; + ObjCPropertyDecl *Prop = LookupPropertyDecl(IDecl, NameII); + if (Prop && !Prop->isInvalidDecl()) { + DeclContext *EnclosingContext = cast_or_null<DeclContext>(IDecl); + QualType PropType = Context.getCanonicalType(Prop->getType()); + assert(EnclosingContext && + "null DeclContext for synthesized ivar - SynthesizeNewPropertyIvar"); + Ivar = ObjCIvarDecl::Create(Context, EnclosingContext, + Prop->getLocation(), + NameII, PropType, /*Dinfo=*/0, + ObjCIvarDecl::Public, + (Expr *)0); + Ivar->setLexicalDeclContext(IDecl); + IDecl->addDecl(Ivar); + Prop->setPropertyIvarDecl(Ivar); + } + return Ivar; +} + diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index ff59fc3a7d36..f73ec9cb61c5 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1135,6 +1135,12 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, // Objective C++: We're able to convert from a pointer to an // interface to a pointer to a different interface. if (Context.canAssignObjCInterfaces(ToObjCPtr, FromObjCPtr)) { + const ObjCInterfaceType* LHS = ToObjCPtr->getInterfaceType(); + const ObjCInterfaceType* RHS = FromObjCPtr->getInterfaceType(); + if (getLangOptions().CPlusPlus && LHS && RHS && + !ToObjCPtr->getPointeeType().isAtLeastAsQualifiedAs( + FromObjCPtr->getPointeeType())) + return false; ConvertedType = ToType; return true; } @@ -1405,8 +1411,9 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType, } if (!IgnoreBaseAccess) - CheckBaseClassAccess(From->getExprLoc(), /*BaseToDerived*/ true, - FromClass, ToClass, Paths.front()); + CheckBaseClassAccess(From->getExprLoc(), FromClass, ToClass, + Paths.front(), + diag::err_downcast_from_inaccessible_base); // Must be a base to derived member conversion. Kind = CastExpr::CK_BaseToDerivedMemberPointer; @@ -5542,7 +5549,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, // Convert the arguments. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { - CheckMemberOperatorAccess(OpLoc, Args[0], Method, Best->getAccess()); + CheckMemberOperatorAccess(OpLoc, Args[0], 0, Method, Best->getAccess()); if (PerformObjectArgumentInitialization(Input, /*Qualifier=*/0, Method)) return ExprError(); @@ -5726,7 +5733,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // Convert the arguments. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { // Best->Access is only meaningful for class members. - CheckMemberOperatorAccess(OpLoc, Args[0], Method, Best->getAccess()); + CheckMemberOperatorAccess(OpLoc, Args[0], Args[1], Method, + Best->getAccess()); OwningExprResult Arg1 = PerformCopyInitialization( @@ -5900,7 +5908,8 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // We matched an overloaded operator. Build a call to that // operator. - CheckMemberOperatorAccess(LLoc, Args[0], FnDecl, Best->getAccess()); + CheckMemberOperatorAccess(LLoc, Args[0], Args[1], FnDecl, + Best->getAccess()); // Convert the arguments. CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl); @@ -6269,7 +6278,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, = cast<CXXConversionDecl>( Best->Conversions[0].UserDefined.ConversionFunction); - CheckMemberOperatorAccess(LParenLoc, Object, Conv, Best->getAccess()); + CheckMemberOperatorAccess(LParenLoc, Object, 0, Conv, Best->getAccess()); // We selected one of the surrogate functions that converts the // object parameter to a function pointer. Perform the conversion @@ -6284,7 +6293,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, CommaLocs, RParenLoc).release(); } - CheckMemberOperatorAccess(LParenLoc, Object, + CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->Function, Best->getAccess()); // We found an overloaded operator(). Build a CXXOperatorCallExpr diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 75d9f67ad9d2..fd65c32c203e 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -76,10 +76,6 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { if (!E) return; - // Ignore expressions that have void type. - if (E->getType()->isVoidType()) - return; - SourceLocation Loc; SourceRange R1, R2; if (!E->isUnusedResultAWarning(Loc, R1, R2, Context)) @@ -103,6 +99,9 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { } if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { + if (E->getType()->isVoidType()) + return; + // If the callee has attribute pure, const, or warn_unused_result, warn with // a more specific message to make it clear what is happening. if (const Decl *FD = CE->getCalleeDecl()) { diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 7c4cab118366..434d5563e1b3 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -15,6 +15,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/DeclFriend.h" #include "clang/AST/DeclTemplate.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Template.h" @@ -696,6 +697,12 @@ Sema::ActOnTemplateParameterList(unsigned Depth, RAngleLoc); } +static void SetNestedNameSpecifier(TagDecl *T, const CXXScopeSpec &SS) { + if (SS.isSet()) + T->setQualifierInfo(static_cast<NestedNameSpecifier*>(SS.getScopeRep()), + SS.getRange()); +} + Sema::DeclResult Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, const CXXScopeSpec &SS, @@ -863,6 +870,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, PrevClassTemplate? PrevClassTemplate->getTemplatedDecl() : 0, /*DelayTypeCreation=*/true); + SetNestedNameSpecifier(NewClass, SS); ClassTemplateDecl *NewTemplate = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc, @@ -3490,6 +3498,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TemplateArgs, CanonType, PrevPartial); + SetNestedNameSpecifier(Partial, SS); if (PrevPartial) { ClassTemplate->getPartialSpecializations().RemoveNode(PrevPartial); @@ -3546,6 +3555,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, ClassTemplate, Converted, PrevDecl); + SetNestedNameSpecifier(Specialization, SS); if (PrevDecl) { ClassTemplate->getSpecializations().RemoveNode(PrevDecl); @@ -4327,6 +4337,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, TemplateNameLoc, ClassTemplate, Converted, PrevDecl); + SetNestedNameSpecifier(Specialization, SS); if (PrevDecl) { // Remove the previous declaration from the folding set, since we want diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 8f73337e436e..0d6acd0e81c8 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -567,6 +567,15 @@ namespace { Sema::OwningExprResult TransformTemplateParmRefExpr(DeclRefExpr *E, NonTypeTemplateParmDecl *D); + /// \brief Transforms a function proto type by performing + /// substitution in the function parameters, possibly adjusting + /// their types and marking default arguments as uninstantiated. + bool TransformFunctionTypeParams(FunctionProtoTypeLoc TL, + llvm::SmallVectorImpl<QualType> &PTypes, + llvm::SmallVectorImpl<ParmVarDecl*> &PVars); + + ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm); + /// \brief Transforms a template type parameter type by performing /// substitution of the corresponding template type argument. QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, @@ -859,6 +868,61 @@ Sema::OwningExprResult TemplateInstantiator::TransformCXXDefaultArgExpr( } +bool +TemplateInstantiator::TransformFunctionTypeParams(FunctionProtoTypeLoc TL, + llvm::SmallVectorImpl<QualType> &PTypes, + llvm::SmallVectorImpl<ParmVarDecl*> &PVars) { + // Create a local instantiation scope for the parameters. + Sema::LocalInstantiationScope + Scope(SemaRef, SemaRef.CurrentInstantiationScope != 0); + + if (TreeTransform<TemplateInstantiator>:: + TransformFunctionTypeParams(TL, PTypes, PVars)) + return true; + + // Check instantiated parameters. + if (SemaRef.CheckInstantiatedParams(PVars)) + return true; + + return false; +} + +ParmVarDecl * +TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm) { + TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); + TypeSourceInfo *NewDI = getDerived().TransformType(OldDI); + if (!NewDI) + return 0; + + // TODO: do we have to clone this decl if the types match and + // there's no default argument? + + ParmVarDecl *NewParm + = ParmVarDecl::Create(SemaRef.Context, + OldParm->getDeclContext(), + OldParm->getLocation(), + OldParm->getIdentifier(), + NewDI->getType(), + NewDI, + OldParm->getStorageClass(), + /* DefArg */ NULL); + + // Maybe adjust new parameter type. + NewParm->setType(SemaRef.adjustParameterType(NewParm->getType())); + + // Mark the (new) default argument as uninstantiated (if any). + if (OldParm->hasUninstantiatedDefaultArg()) { + Expr *Arg = OldParm->getUninstantiatedDefaultArg(); + NewParm->setUninstantiatedDefaultArg(Arg); + } else if (Expr *Arg = OldParm->getDefaultArg()) + NewParm->setUninstantiatedDefaultArg(Arg); + + NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg()); + + SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm); + return NewParm; +} + QualType TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, TemplateTypeParmTypeLoc TL, diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index cf8d38c09583..dbe041c4aade 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclVisitor.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/TypeLoc.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/Lex/Preprocessor.h" @@ -89,13 +90,18 @@ namespace { } // Helper functions for instantiating methods. - QualType SubstFunctionType(FunctionDecl *D, + TypeSourceInfo *SubstFunctionType(FunctionDecl *D, llvm::SmallVectorImpl<ParmVarDecl *> &Params); bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl); bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl); TemplateParameterList * SubstTemplateParams(TemplateParameterList *List); + + bool SubstQualifier(const DeclaratorDecl *OldDecl, + DeclaratorDecl *NewDecl); + bool SubstQualifier(const TagDecl *OldDecl, + TagDecl *NewDecl); bool InstantiateClassTemplatePartialSpecialization( ClassTemplateDecl *ClassTemplate, @@ -103,6 +109,38 @@ namespace { }; } +bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl, + DeclaratorDecl *NewDecl) { + NestedNameSpecifier *OldQual = OldDecl->getQualifier(); + if (!OldQual) return false; + + SourceRange QualRange = OldDecl->getQualifierRange(); + + NestedNameSpecifier *NewQual + = SemaRef.SubstNestedNameSpecifier(OldQual, QualRange, TemplateArgs); + if (!NewQual) + return true; + + NewDecl->setQualifierInfo(NewQual, QualRange); + return false; +} + +bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl, + TagDecl *NewDecl) { + NestedNameSpecifier *OldQual = OldDecl->getQualifier(); + if (!OldQual) return false; + + SourceRange QualRange = OldDecl->getQualifierRange(); + + NestedNameSpecifier *NewQual + = SemaRef.SubstNestedNameSpecifier(OldQual, QualRange, TemplateArgs); + if (!NewQual) + return true; + + NewDecl->setQualifierInfo(NewQual, QualRange); + return false; +} + // FIXME: Is this too simple? void TemplateDeclInstantiator::InstantiateAttrs(Decl *Tmpl, Decl *New) { for (const Attr *TmplAttr = Tmpl->getAttrs(); TmplAttr; @@ -286,6 +324,10 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { Var->setCXXDirectInitializer(D->hasCXXDirectInitializer()); Var->setDeclaredInCondition(D->isDeclaredInCondition()); + // Substitute the nested name specifier, if any. + if (SubstQualifier(D, Var)) + return 0; + // If we are instantiating a static data member defined // out-of-line, the instantiation will have the same lexical // context (which will be a namespace scope) as the template. @@ -510,6 +552,7 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { /*PrevDecl=*/0); Enum->setInstantiationOfMemberEnum(D); Enum->setAccess(D->getAccess()); + if (SubstQualifier(D, Enum)) return 0; Owner->addDecl(Enum); Enum->startDefinition(); @@ -610,6 +653,10 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { Pattern->getTagKeywordLoc(), /*PrevDecl=*/ NULL, /*DelayTypeCreation=*/true); + // Substitute the nested name specifier, if any. + if (SubstQualifier(Pattern, RecordInst)) + return 0; + ClassTemplateDecl *Inst = ClassTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), InstParams, RecordInst, 0); @@ -744,6 +791,11 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { = CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner, D->getLocation(), D->getIdentifier(), D->getTagKeywordLoc(), PrevDecl); + + // Substitute the nested name specifier, if any. + if (SubstQualifier(D, Record)) + return 0; + Record->setImplicit(D->isImplicit()); // FIXME: Check against AS_none is an ugly hack to work around the issue that // the tag decls introduced by friend class declarations don't have an access @@ -797,9 +849,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, Sema::LocalInstantiationScope Scope(SemaRef, MergeWithParentScope); llvm::SmallVector<ParmVarDecl *, 4> Params; - QualType T = SubstFunctionType(D, Params); - if (T.isNull()) + TypeSourceInfo *TInfo = D->getTypeSourceInfo(); + TInfo = SubstFunctionType(D, Params); + if (!TInfo) return 0; + QualType T = TInfo->getType(); // If we're instantiating a local function declaration, put the result // in the owner; otherwise we need to find the instantiated context. @@ -812,9 +866,14 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, FunctionDecl *Function = FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(), - D->getDeclName(), T, D->getTypeSourceInfo(), + D->getDeclName(), T, TInfo, D->getStorageClass(), D->isInlineSpecified(), D->hasWrittenPrototype()); + + // Substitute the nested name specifier, if any. + if (SubstQualifier(D, Function)) + return 0; + Function->setLexicalDeclContext(Owner); // Attach the parameters @@ -932,9 +991,11 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Sema::LocalInstantiationScope Scope(SemaRef, MergeWithParentScope); llvm::SmallVector<ParmVarDecl *, 4> Params; - QualType T = SubstFunctionType(D, Params); - if (T.isNull()) + TypeSourceInfo *TInfo = D->getTypeSourceInfo(); + TInfo = SubstFunctionType(D, Params); + if (!TInfo) return 0; + QualType T = TInfo->getType(); // Build the instantiated method declaration. CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner); @@ -947,8 +1008,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, SemaRef.Context.getCanonicalType(ClassTy)); Method = CXXConstructorDecl::Create(SemaRef.Context, Record, Constructor->getLocation(), - Name, T, - Constructor->getTypeSourceInfo(), + Name, T, TInfo, Constructor->isExplicit(), Constructor->isInlineSpecified(), false); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { @@ -966,15 +1026,19 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, ConvTy); Method = CXXConversionDecl::Create(SemaRef.Context, Record, Conversion->getLocation(), Name, - T, Conversion->getTypeSourceInfo(), + T, TInfo, Conversion->isInlineSpecified(), Conversion->isExplicit()); } else { Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(), - D->getDeclName(), T, D->getTypeSourceInfo(), + D->getDeclName(), T, TInfo, D->isStatic(), D->isInlineSpecified()); } + // Substitute the nested name specifier, if any. + if (SubstQualifier(D, Method)) + return 0; + if (TemplateParams) { // Our resulting instantiation is actually a function template, since we // are substituting only the outer template parameters. For example, given @@ -1504,6 +1568,10 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( InstTemplateArgs, CanonType, 0); + // Substitute the nested name specifier, if any. + if (SubstQualifier(PartialSpec, InstPartialSpec)) + return 0; + InstPartialSpec->setInstantiatedFromMember(PartialSpec); InstPartialSpec->setTypeAsWritten(WrittenTy); @@ -1514,60 +1582,49 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( return false; } -/// \brief Does substitution on the type of the given function, including -/// all of the function parameters. -/// -/// \param D The function whose type will be the basis of the substitution -/// -/// \param Params the instantiated parameter declarations - -/// \returns the instantiated function's type if successful, a NULL -/// type if there was an error. -QualType -TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, - llvm::SmallVectorImpl<ParmVarDecl *> &Params) { - bool InvalidDecl = false; - - // Substitute all of the function's formal parameter types. - TemplateDeclInstantiator ParamInstantiator(SemaRef, 0, TemplateArgs); - llvm::SmallVector<QualType, 4> ParamTys; - for (FunctionDecl::param_iterator P = D->param_begin(), - PEnd = D->param_end(); - P != PEnd; ++P) { - if (ParmVarDecl *PInst = ParamInstantiator.VisitParmVarDecl(*P)) { - if (PInst->getType()->isVoidType()) { - SemaRef.Diag(PInst->getLocation(), diag::err_param_with_void_type); +bool +Sema::CheckInstantiatedParams(llvm::SmallVectorImpl<ParmVarDecl*> &Params) { + bool Invalid = false; + for (unsigned i = 0, i_end = Params.size(); i != i_end; ++i) + if (ParmVarDecl *PInst = Params[i]) { + if (PInst->isInvalidDecl()) + Invalid = true; + else if (PInst->getType()->isVoidType()) { + Diag(PInst->getLocation(), diag::err_param_with_void_type); PInst->setInvalidDecl(); - } else if (SemaRef.RequireNonAbstractType(PInst->getLocation(), - PInst->getType(), - diag::err_abstract_type_in_decl, - Sema::AbstractParamType)) + Invalid = true; + } + else if (RequireNonAbstractType(PInst->getLocation(), + PInst->getType(), + diag::err_abstract_type_in_decl, + Sema::AbstractParamType)) { PInst->setInvalidDecl(); + Invalid = true; + } + } + return Invalid; +} - Params.push_back(PInst); - ParamTys.push_back(PInst->getType()); +TypeSourceInfo* +TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, + llvm::SmallVectorImpl<ParmVarDecl *> &Params) { + TypeSourceInfo *OldTInfo = D->getTypeSourceInfo(); + assert(OldTInfo && "substituting function without type source info"); + assert(Params.empty() && "parameter vector is non-empty at start"); + TypeSourceInfo *NewTInfo = SemaRef.SubstType(OldTInfo, TemplateArgs, + D->getTypeSpecStartLoc(), + D->getDeclName()); + if (!NewTInfo) + return 0; - if (PInst->isInvalidDecl()) - InvalidDecl = true; - } else - InvalidDecl = true; - } + // Get parameters from the new type info. + TypeLoc NewTL = NewTInfo->getTypeLoc(); + FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL); + assert(NewProtoLoc && "Missing prototype?"); + for (unsigned i = 0, i_end = NewProtoLoc->getNumArgs(); i != i_end; ++i) + Params.push_back(NewProtoLoc->getArg(i)); - // FIXME: Deallocate dead declarations. - if (InvalidDecl) - return QualType(); - - const FunctionProtoType *Proto = D->getType()->getAs<FunctionProtoType>(); - assert(Proto && "Missing prototype?"); - QualType ResultType - = SemaRef.SubstType(Proto->getResultType(), TemplateArgs, - D->getLocation(), D->getDeclName()); - if (ResultType.isNull()) - return QualType(); - - return SemaRef.BuildFunctionType(ResultType, ParamTys.data(), ParamTys.size(), - Proto->isVariadic(), Proto->getTypeQuals(), - D->getLocation(), D->getDeclName()); + return NewTInfo; } /// \brief Initializes the common fields of an instantiation function diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 17f94193fed4..d6f3352266aa 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -315,6 +315,21 @@ public: QualType ObjectType = QualType()); #include "clang/AST/TypeLocNodes.def" + /// \brief Transforms the parameters of a function type into the + /// given vectors. + /// + /// The result vectors should be kept in sync; null entries in the + /// variables vector are acceptable. + /// + /// Return true on error. + bool TransformFunctionTypeParams(FunctionProtoTypeLoc TL, + llvm::SmallVectorImpl<QualType> &PTypes, + llvm::SmallVectorImpl<ParmVarDecl*> &PVars); + + /// \brief Transforms a single function-type parameter. Return null + /// on error. + ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm); + QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL, QualType ObjectType); @@ -2520,18 +2535,33 @@ QualType TreeTransform<Derived>::TransformExtVectorType(TypeLocBuilder &TLB, } template<typename Derived> -QualType -TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, - FunctionProtoTypeLoc TL, - QualType ObjectType) { +ParmVarDecl * +TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm) { + TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); + TypeSourceInfo *NewDI = getDerived().TransformType(OldDI); + if (!NewDI) + return 0; + + if (NewDI == OldDI) + return OldParm; + else + return ParmVarDecl::Create(SemaRef.Context, + OldParm->getDeclContext(), + OldParm->getLocation(), + OldParm->getIdentifier(), + NewDI->getType(), + NewDI, + OldParm->getStorageClass(), + /* DefArg */ NULL); +} + +template<typename Derived> +bool TreeTransform<Derived>:: + TransformFunctionTypeParams(FunctionProtoTypeLoc TL, + llvm::SmallVectorImpl<QualType> &PTypes, + llvm::SmallVectorImpl<ParmVarDecl*> &PVars) { FunctionProtoType *T = TL.getTypePtr(); - QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); - if (ResultType.isNull()) - return QualType(); - // Transform the parameters. - llvm::SmallVector<QualType, 4> ParamTypes; - llvm::SmallVector<ParmVarDecl*, 4> ParamDecls; for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { ParmVarDecl *OldParm = TL.getArg(i); @@ -2539,24 +2569,9 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, ParmVarDecl *NewParm; if (OldParm) { - TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); - assert(OldDI->getType() == T->getArgType(i)); - - TypeSourceInfo *NewDI = getDerived().TransformType(OldDI); - if (!NewDI) - return QualType(); - - if (NewDI == OldDI) - NewParm = OldParm; - else - NewParm = ParmVarDecl::Create(SemaRef.Context, - OldParm->getDeclContext(), - OldParm->getLocation(), - OldParm->getIdentifier(), - NewDI->getType(), - NewDI, - OldParm->getStorageClass(), - /* DefArg */ NULL); + NewParm = getDerived().TransformFunctionTypeParam(OldParm); + if (!NewParm) + return true; NewType = NewParm->getType(); // Deal with the possibility that we don't have a parameter @@ -2567,13 +2582,32 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, QualType OldType = T->getArgType(i); NewType = getDerived().TransformType(OldType); if (NewType.isNull()) - return QualType(); + return true; } - ParamTypes.push_back(NewType); - ParamDecls.push_back(NewParm); + PTypes.push_back(NewType); + PVars.push_back(NewParm); } + return false; +} + +template<typename Derived> +QualType +TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, + FunctionProtoTypeLoc TL, + QualType ObjectType) { + FunctionProtoType *T = TL.getTypePtr(); + QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); + if (ResultType.isNull()) + return QualType(); + + // Transform the parameters. + llvm::SmallVector<QualType, 4> ParamTypes; + llvm::SmallVector<ParmVarDecl*, 4> ParamDecls; + if (getDerived().TransformFunctionTypeParams(TL, ParamTypes, ParamDecls)) + return QualType(); + QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ResultType != T->getResultType() || diff --git a/test/CXX/class.access/class.friend/p1.cpp b/test/CXX/class.access/class.friend/p1.cpp index a06fb2e3e3c2..83b4227aa3bc 100644 --- a/test/CXX/class.access/class.friend/p1.cpp +++ b/test/CXX/class.access/class.friend/p1.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s // C++'0x [class.friend] p1: // A friend of a class is a function or class that is given permission to use @@ -60,3 +60,58 @@ namespace N { x.g2(); // expected-error{{no member named 'g2' in 'N::X'}} } } + +namespace test0 { + class ClassFriend { + void test(); + }; + + class MemberFriend { + void test(); + }; + + void declared_test(); + + class Class { + static void member(); // expected-note 2 {{declared private here}} + + friend class ClassFriend; + friend class UndeclaredClassFriend; + + friend void undeclared_test(); + friend void declared_test(); + friend void MemberFriend::test(); + }; + + void declared_test() { + Class::member(); + } + + void undeclared_test() { + Class::member(); + } + + void unfriended_test() { + Class::member(); // expected-error {{'member' is a private member of 'test0::Class'}} + } + + void ClassFriend::test() { + Class::member(); + } + + void MemberFriend::test() { + Class::member(); + } + + class UndeclaredClassFriend { + void test() { + Class::member(); + } + }; + + class ClassNonFriend { + void test() { + Class::member(); // expected-error {{'member' is a private member of 'test0::Class'}} + } + }; +} diff --git a/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp index 7aa614cd8b1a..15b336a4d8e6 100644 --- a/test/CXX/class.access/p4.cpp +++ b/test/CXX/class.access/p4.cpp @@ -99,16 +99,124 @@ namespace test2 { // Implicit destructor calls. namespace test3 { - class A{ + class A { private: ~A(); // expected-note 3 {{declared private here}} static A foo; }; - A a; // expected-error {{'~A' is a private member}} + A a; // expected-error {{variable of type 'test3::A' has private destructor}} A A::foo; - void foo(A param) { // expected-error {{'~A' is a private member}} - A local; // expected-error {{'~A' is a private member}} + void foo(A param) { // expected-error {{variable of type 'test3::A' has private destructor}} + A local; // expected-error {{variable of type 'test3::A' has private destructor}} + } + + template <unsigned N> class Base { ~Base(); }; // expected-note 8 {{declared private here}} + class Base2 : virtual Base<2> { ~Base2(); }; // expected-note 2 {{declared private here}} + class Base3 : virtual Base<3> { public: ~Base3(); }; + + // These don't cause diagnostics because we don't need the destructor. + class Derived0 : Base<0> { ~Derived0(); }; + class Derived1 : Base<1> { }; + + class Derived2 : // expected-error {{inherited virtual base class 'Base<2>' has private destructor}} \ + // expected-error {{inherited virtual base class 'Base<3>' has private destructor}} + Base<0>, // expected-error {{base class 'Base<0>' has private destructor}} + virtual Base<1>, // expected-error {{base class 'Base<1>' has private destructor}} + Base2, // expected-error {{base class 'test3::Base2' has private destructor}} + virtual Base3 + { + ~Derived2() {} + }; + + class Derived3 : // expected-error {{inherited virtual base class 'Base<2>' has private destructor}} \ + // expected-error {{inherited virtual base class 'Base<3>' has private destructor}} + Base<0>, // expected-error {{base class 'Base<0>' has private destructor}} + virtual Base<1>, // expected-error {{base class 'Base<1>' has private destructor}} + Base2, // expected-error {{base class 'test3::Base2' has private destructor}} + virtual Base3 + {}; + Derived3 d3; +} + +// Conversion functions. +namespace test4 { + class Base { + private: + operator Private(); // expected-note 4 {{declared private here}} + public: + operator Public(); + }; + + class Derived1 : private Base { // expected-note 2 {{declared private here}} \ + // expected-note {{constrained by private inheritance}} + Private test1() { return *this; } // expected-error {{'operator Private' is a private member}} + Public test2() { return *this; } + }; + Private test1(Derived1 &d) { return d; } // expected-error {{'operator Private' is a private member}} \ + // expected-error {{cannot cast 'test4::Derived1' to its private base class}} + Public test2(Derived1 &d) { return d; } // expected-error {{cannot cast 'test4::Derived1' to its private base class}} \ + // expected-error {{'operator Public' is a private member}} + + + class Derived2 : public Base { + Private test1() { return *this; } // expected-error {{'operator Private' is a private member}} + Public test2() { return *this; } + }; + Private test1(Derived2 &d) { return d; } // expected-error {{'operator Private' is a private member}} + Public test2(Derived2 &d) { return d; } + + class Derived3 : private Base { // expected-note {{constrained by private inheritance here}} \ + // expected-note {{declared private here}} + public: + operator Private(); + }; + Private test1(Derived3 &d) { return d; } + Public test2(Derived3 &d) { return d; } // expected-error {{'operator Public' is a private member of 'test4::Base'}} \ + // expected-error {{cannot cast 'test4::Derived3' to its private base class}} + + class Derived4 : public Base { + public: + operator Private(); + }; + Private test1(Derived4 &d) { return d; } + Public test2(Derived4 &d) { return d; } +} + +// Implicit copy assignment operator uses. +namespace test5 { + class A { + void operator=(const A &); // expected-note 2 {{declared private here}} + }; + + class Test1 { A a; }; // expected-error {{field of type 'test5::A' has private copy assignment operator}} + void test1() { + Test1 a; + a = Test1(); + } + + class Test2 : A {}; // expected-error {{base class 'test5::A' has private copy assignment operator}} + void test2() { + Test2 a; + a = Test2(); + } +} + +// Implicit copy constructor uses. +namespace test6 { + class A { + public: A(); + private: A(const A &); // expected-note 2 {{declared private here}} + }; + + class Test1 { A a; }; // expected-error {{field of type 'test6::A' has private copy constructor}} + void test1(const Test1 &t) { + Test1 a = t; + } + + class Test2 : A {}; // expected-error {{base class 'test6::A' has private copy constructor}} + void test2(const Test2 &t) { + Test2 a = t; } } diff --git a/test/CXX/temp/temp.res/temp.local/p7.cpp b/test/CXX/temp/temp.res/temp.local/p7.cpp new file mode 100644 index 000000000000..bd05e756a19e --- /dev/null +++ b/test/CXX/temp/temp.res/temp.local/p7.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +template<class T> struct A { + int B; + int f(); +}; + +template<class B> int A<B>::f() { + return B; +} diff --git a/test/CXX/temp/temp.res/temp.local/p8.cpp b/test/CXX/temp/temp.res/temp.local/p8.cpp new file mode 100644 index 000000000000..5d9d50913f36 --- /dev/null +++ b/test/CXX/temp/temp.res/temp.local/p8.cpp @@ -0,0 +1,53 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +namespace N { + enum { C }; + template<class T> class B { + void f(T); + }; +} + +template<class C> void N::B<C>::f(C) { + C b; +} + +namespace N { + enum { D }; + namespace M { + enum { C , D }; + template<typename C> class X { + template<typename U> void f(C, U); + + template<typename D> void g(C, D) { + C c; + D d; + } + }; + + struct Y { + template<typename U> void f(U); + }; + } + + struct Y { + template<typename D> void f(D); + }; +} + +template<typename C> +template<typename D> +void N::M::X<C>::f(C, D) { + C c; + D d; +} + +template<typename C> +void N::M::Y::f(C) { + C c; +} + +template<typename D> +void N::Y::f(D) { + D d; +} + diff --git a/test/CXX/temp/temp.res/temp.local/p9.cpp b/test/CXX/temp/temp.res/temp.local/p9.cpp new file mode 100644 index 000000000000..9ca8d8877d7d --- /dev/null +++ b/test/CXX/temp/temp.res/temp.local/p9.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +struct A { + struct B { void f(); }; + int a; + int Y; +}; + +template<class B, class a> struct X : A { + B b; // A's B + a c; // expected-error{{unknown type name 'a'}} + + void g() { + b.g(); // expected-error{{no member named 'g' in 'A::B'}} + } +}; diff --git a/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp b/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp index 70eb69641867..d8f7b52145dd 100644 --- a/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp +++ b/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp @@ -12,10 +12,10 @@ T X<T>::member1; template<typename T> T X<T>::member2 = 17; -// CHECK: @_ZN1XIiE7member1E = global i32 0 +// CHECK: @_ZN1XIiE7member1E = weak global i32 0 template int X<int>::member1; -// CHECK: @_ZN1XIiE7member2E = global i32 17 +// CHECK: @_ZN1XIiE7member2E = weak global i32 17 template int X<int>::member2; // For implicit instantiation of diff --git a/test/CodeGen/varargs.c b/test/CodeGen/varargs.c new file mode 100644 index 000000000000..b3dba240b559 --- /dev/null +++ b/test/CodeGen/varargs.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s + + +// PR6433 - Don't crash on va_arg(typedef). +typedef double gdouble; +void focus_changed_cb () { + __builtin_va_list pa; + double mfloat; + mfloat = __builtin_va_arg((pa), gdouble); +} + diff --git a/test/CodeGenCXX/PR6474.cpp b/test/CodeGenCXX/PR6474.cpp index 68c09c9b95d5..0b155cef8355 100644 --- a/test/CodeGenCXX/PR6474.cpp +++ b/test/CodeGenCXX/PR6474.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -emit-llvm +// RUN: %clang_cc1 %s -emit-llvm-only namespace test0 { template <typename T> struct X { diff --git a/test/CodeGenCXX/explicit-instantiation.cpp b/test/CodeGenCXX/explicit-instantiation.cpp index ab9174e8f406..24d1a6739229 100644 --- a/test/CodeGenCXX/explicit-instantiation.cpp +++ b/test/CodeGenCXX/explicit-instantiation.cpp @@ -1,5 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm -triple i686-pc-linux-gnu -o %t %s -// RUN: grep "define i32 @_ZNK4plusIillEclERKiRKl" %t | count 1 +// RUN: %clang_cc1 -emit-llvm -triple i686-pc-linux-gnu -o - %s | FileCheck %s template<typename T, typename U, typename Result> struct plus { @@ -11,4 +10,5 @@ Result plus<T, U, Result>::operator()(const T& t, const U& u) const { return t + u; } +// CHECK: define weak_odr i32 @_ZNK4plusIillEclERKiRKl template struct plus<int, long, long>; diff --git a/test/CodeGenCXX/mangle-exprs.cpp b/test/CodeGenCXX/mangle-exprs.cpp index cdad39852c9f..6f1ca5568ed6 100644 --- a/test/CodeGenCXX/mangle-exprs.cpp +++ b/test/CodeGenCXX/mangle-exprs.cpp @@ -30,15 +30,15 @@ namespace Casts { template <int N> T<N> f() { return T<N>(); } - // CHECK: define void @_ZN5Casts8implicitILj4EEEvPN9enable_ifIXleT_Li4EEvE4typeE + // CHECK: define weak_odr void @_ZN5Casts8implicitILj4EEEvPN9enable_ifIXleT_Li4EEvE4typeE template void implicit<4>(void*); - // CHECK: define void @_ZN5Casts6cstyleILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE + // CHECK: define weak_odr void @_ZN5Casts6cstyleILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE template void cstyle<4>(void*); - // CHECK: define void @_ZN5Casts10functionalILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE + // CHECK: define weak_odr void @_ZN5Casts10functionalILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE template void functional<4>(void*); - // CHECK: define void @_ZN5Casts7static_ILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE + // CHECK: define weak_odr void @_ZN5Casts7static_ILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE template void static_<4>(void*); - // CHECK: define i64 @_ZN5Casts1fILi6EEENS_1TIXT_EEEv + // CHECK: define weak_odr i64 @_ZN5Casts1fILi6EEENS_1TIXT_EEEv template T<6> f<6>(); } diff --git a/test/CodeGenCXX/mangle-template.cpp b/test/CodeGenCXX/mangle-template.cpp index 57f30a762ed0..22949da64ad8 100644 --- a/test/CodeGenCXX/mangle-template.cpp +++ b/test/CodeGenCXX/mangle-template.cpp @@ -82,7 +82,7 @@ namespace test7 { X(U*, typename int_c<(meta<T>::value + meta<U>::value)>::type *) { } }; - // CHECK: define void @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsrNS6_IS3_EE5valueEE4typeE + // CHECK: define weak_odr void @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsrNS6_IS3_EE5valueEE4typeE template X<int>::X(double*, float*); } @@ -101,6 +101,6 @@ namespace test8 { template<typename T> void f(int_c<meta<T>::type::value>) { } - // CHECK: define void @_ZN5test81fIiEEvNS_5int_cIXsrNS_4metaIT_E4typeE5valueEEE + // CHECK: define weak_odr void @_ZN5test81fIiEEvNS_5int_cIXsrNS_4metaIT_E4typeE5valueEEE template void f<int>(int_c<sizeof(int)>); } diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp index e18ca03d1be2..8dee41beb482 100644 --- a/test/CodeGenCXX/mangle.cpp +++ b/test/CodeGenCXX/mangle.cpp @@ -250,26 +250,26 @@ void f() { __fill_a<int>(); } namespace Expressions { // Unary operators. -// CHECK: define void @_ZN11Expressions2f1ILi1EEEvPAplngT_Li2E_i +// CHECK: define weak_odr void @_ZN11Expressions2f1ILi1EEEvPAplngT_Li2E_i template <int i> void f1(int (*)[(-i) + 2]) { }; template void f1<1>(int (*)[1]); -// CHECK: define void @_ZN11Expressions2f2ILi1EEEvPApsT__i +// CHECK: define weak_odr void @_ZN11Expressions2f2ILi1EEEvPApsT__i template <int i> void f2(int (*)[+i]) { }; template void f2<1>(int (*)[1]); // Binary operators. -// CHECK: define void @_ZN11Expressions2f3ILi1EEEvPAplT_T__i +// CHECK: define weak_odr void @_ZN11Expressions2f3ILi1EEEvPAplT_T__i template <int i> void f3(int (*)[i+i]) { }; template void f3<1>(int (*)[2]); -// CHECK: define void @_ZN11Expressions2f4ILi1EEEvPAplplLi2ET_T__i +// CHECK: define weak_odr void @_ZN11Expressions2f4ILi1EEEvPAplplLi2ET_T__i template <int i> void f4(int (*)[2 + i+i]) { }; template void f4<1>(int (*)[4]); // The ternary operator. -// CHECK: define void @_ZN11Expressions2f4ILb1EEEvPAquT_Li1ELi2E_i +// CHECK: define weak_odr void @_ZN11Expressions2f4ILb1EEEvPAquT_Li1ELi2E_i template <bool b> void f4(int (*)[b ? 1 : 2]) { }; template void f4<true>(int (*)[1]); } @@ -305,7 +305,7 @@ template<typename T, typename = Policy<P, true> > class Alloc T *allocate(int, const void*) { return 0; } }; -// CHECK: define i8* @_ZN6PR58615AllocIcNS_6PolicyINS_1PELb1EEEE8allocateEiPKv +// CHECK: define weak_odr i8* @_ZN6PR58615AllocIcNS_6PolicyINS_1PELb1EEEE8allocateEiPKv template class Alloc<char>; } @@ -369,7 +369,7 @@ namespace test0 { namespace test1 { template<typename T> struct X { }; template<template<class> class Y, typename T> void f(Y<T>) { } - // CHECK: define void @_ZN5test11fINS_1XEiEEvT_IT0_E + // CHECK: define weak_odr void @_ZN5test11fINS_1XEiEEvT_IT0_E template void f(X<int>); } @@ -399,10 +399,10 @@ namespace test3 { //template <class T> decltype(((T*) 0)->Path1::ab) get_ab_1(T &ref) { return ref.Path1::ab; } //template <class T> decltype(((T*) 0)->Path2::ab) get_ab_2(T &ref) { return ref.Path2::ab; } - // define linkonce_odr float @_ZN5test37get_p_1INS_7DerivedEEEDtptcvPT_Li0E5Path11pERS2_( + // define weak_odr float @_ZN5test37get_p_1INS_7DerivedEEEDtptcvPT_Li0E5Path11pERS2_( template <class T> decltype(((T*) 0)->Path1::p) get_p_1(T &ref) { return ref.Path1::p; } - // define linkonce_odr double @_ZN5test37get_p_1INS_7DerivedEEEDtptcvPT_Li0E5Path21pERS2_( + // define weak_odr double @_ZN5test37get_p_1INS_7DerivedEEEDtptcvPT_Li0E5Path21pERS2_( template <class T> decltype(((T*) 0)->Path2::p) get_p_2(T &ref) { return ref.Path2::p; } Derived obj; @@ -414,3 +414,42 @@ namespace test3 { get_p_2(obj); } } + +// CHECK: define void @_ZN5test41gEPNS_3zedIXadL_ZNS_3foo3barEEEEE +namespace test4 { + struct foo { int bar; }; + template <int (foo::*)> + struct zed {}; + void g(zed<&foo::bar>*) + {} +} +// CHECK: define void @_ZN5test51gEPNS_3zedIXadL_ZNS_3foo3barEEEEE +namespace test5 { + struct foo { static int bar; }; + template <int *> + struct zed {}; + void g(zed<&foo::bar>*) + {} +} +// CHECK: define void @_ZN5test61gEPNS_3zedIXadL_ZNS_3foo3barEvEEEE +namespace test6 { + struct foo { int bar(); }; + template <int (foo::*)()> + struct zed {}; + void g(zed<&foo::bar>*) + {} +} +// CHECK: define void @_ZN5test71gEPNS_3zedIXadL_ZNS_3foo3barEvEEEE +namespace test7 { + struct foo { static int bar(); }; + template <int (*f)()> + struct zed {}; + void g(zed<&foo::bar>*) + {} +} +// CHECK: define weak_odr void @_ZN5test81AILZNS_1B5valueEEE3incEv +namespace test8 { + template <int &counter> class A { void inc() { counter++; } }; + class B { static int value; }; + template class A<B::value>; +} diff --git a/test/CodeGenCXX/member-templates.cpp b/test/CodeGenCXX/member-templates.cpp index 355ba20e171f..bcf1187e623f 100644 --- a/test/CodeGenCXX/member-templates.cpp +++ b/test/CodeGenCXX/member-templates.cpp @@ -15,8 +15,8 @@ struct B { template<typename T> B::B(T) {} -// CHECK: define void @_ZN1BC1IiEET_(%struct.B* %this, i32) -// CHECK: define void @_ZN1BC2IiEET_(%struct.B* %this, i32) +// CHECK: define weak_odr void @_ZN1BC1IiEET_(%struct.B* %this, i32) +// CHECK: define weak_odr void @_ZN1BC2IiEET_(%struct.B* %this, i32) template B::B(int); template<typename T> diff --git a/test/CodeGenCXX/template-linkage.cpp b/test/CodeGenCXX/template-linkage.cpp index 5d573d6e829b..ccd61a7bbe30 100644 --- a/test/CodeGenCXX/template-linkage.cpp +++ b/test/CodeGenCXX/template-linkage.cpp @@ -6,19 +6,19 @@ template<typename T> struct A { // Explicit instantiations have external linkage. -// CHECK: define void @_ZN1AIiE1gEv( +// CHECK: define weak_odr void @_ZN1AIiE1gEv( template void A<int>::g(); -// CHECK: define void @_ZN1AIfE1fEf( -// CHECK: define void @_ZN1AIfE1gEv( +// CHECK: define weak_odr void @_ZN1AIfE1fEf( +// CHECK: define weak_odr void @_ZN1AIfE1gEv( // FIXME: This should also emit the vtable. template struct A<float>; -// CHECK: define void @_Z1fIiEvT_ +// CHECK: define weak_odr void @_Z1fIiEvT_ template <typename T> void f(T) { } template void f<int>(int); -// CHECK: define void @_Z1gIiEvT_ +// CHECK: define weak_odr void @_Z1gIiEvT_ template <typename T> inline void g(T) { } template void g<int>(int); diff --git a/test/CodeGenCXX/temporaries.cpp b/test/CodeGenCXX/temporaries.cpp index 3b624afd0ad1..cd0cf77f53b2 100644 --- a/test/CodeGenCXX/temporaries.cpp +++ b/test/CodeGenCXX/temporaries.cpp @@ -256,7 +256,7 @@ namespace PR6199 { struct B { operator A(); }; - // CHECK: define void @_ZN6PR61992f2IiEENS_1AET_ + // CHECK: define weak_odr void @_ZN6PR61992f2IiEENS_1AET_ template<typename T> A f2(T) { B b; // CHECK: call void @_ZN6PR61991BcvNS_1AEEv diff --git a/test/CodeGenCXX/vtable-layout.cpp b/test/CodeGenCXX/vtable-layout.cpp index 5c783f1f23dc..f11ae345cc7b 100644 --- a/test/CodeGenCXX/vtable-layout.cpp +++ b/test/CodeGenCXX/vtable-layout.cpp @@ -698,6 +698,65 @@ struct C : A, B { // CHECK-NEXT: 22 | void Test18::D::f() // CHECK-NEXT: [this adjustment: -8 non-virtual, -32 vcall offset offset] // CHECK-NEXT: 23 | [unused] void Test18::C::g() + +// CHECK: Construction vtable for ('Test18::B', 0) in 'Test18::D' (7 entries). +// CHECK-NEXT: 0 | vbase_offset (0) +// CHECK-NEXT: 1 | vcall_offset (0) +// CHECK-NEXT: 2 | vcall_offset (0) +// CHECK-NEXT: 3 | offset_to_top (0) +// CHECK-NEXT: 4 | Test18::B RTTI +// CHECK-NEXT: -- (Test18::A, 0) vtable address -- +// CHECK-NEXT: -- (Test18::B, 0) vtable address -- +// CHECK-NEXT: 5 | void Test18::B::f() +// CHECK-NEXT: 6 | void Test18::A::g() + +// CHECK: Construction vtable for ('Test18::C', 8) in 'Test18::D' (20 entries). +// CHECK-NEXT: 0 | vcall_offset (0) +// CHECK-NEXT: 1 | vcall_offset (0) +// CHECK-NEXT: 2 | vbase_offset (-8) +// CHECK-NEXT: 3 | offset_to_top (0) +// CHECK-NEXT: 4 | Test18::C RTTI +// CHECK-NEXT: -- (Test18::A, 8) vtable address -- +// CHECK-NEXT: -- (Test18::C, 8) vtable address -- +// CHECK-NEXT: 5 | void Test18::A::f() +// CHECK-NEXT: 6 | void Test18::C::g() +// CHECK-NEXT: 7 | vbase_offset (-16) +// CHECK-NEXT: 8 | vcall_offset (-8) +// CHECK-NEXT: 9 | vcall_offset (0) +// CHECK-NEXT: 10 | offset_to_top (-8) +// CHECK-NEXT: 11 | Test18::C RTTI +// CHECK-NEXT: -- (Test18::A, 16) vtable address -- +// CHECK-NEXT: -- (Test18::B, 16) vtable address -- +// CHECK-NEXT: 12 | void Test18::B::f() +// CHECK-NEXT: 13 | [unused] void Test18::C::g() +// CHECK-NEXT: 14 | vcall_offset (8) +// CHECK-NEXT: 15 | vcall_offset (16) +// CHECK-NEXT: 16 | offset_to_top (8) +// CHECK-NEXT: 17 | Test18::C RTTI +// CHECK-NEXT: -- (Test18::A, 0) vtable address -- +// CHECK-NEXT: 18 | void Test18::B::f() +// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-NEXT: 19 | void Test18::C::g() +// CHECK-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] + +// CHECK: Construction vtable for ('Test18::B', 16) in 'Test18::D' (13 entries). +// CHECK-NEXT: 0 | vbase_offset (-16) +// CHECK-NEXT: 1 | vcall_offset (-16) +// CHECK-NEXT: 2 | vcall_offset (0) +// CHECK-NEXT: 3 | offset_to_top (0) +// CHECK-NEXT: 4 | Test18::B RTTI +// CHECK-NEXT: -- (Test18::A, 16) vtable address -- +// CHECK-NEXT: -- (Test18::B, 16) vtable address -- +// CHECK-NEXT: 5 | void Test18::B::f() +// CHECK-NEXT: 6 | [unused] void Test18::A::g() +// CHECK-NEXT: 7 | vcall_offset (0) +// CHECK-NEXT: 8 | vcall_offset (16) +// CHECK-NEXT: 9 | offset_to_top (16) +// CHECK-NEXT: 10 | Test18::B RTTI +// CHECK-NEXT: -- (Test18::A, 0) vtable address -- +// CHECK-NEXT: 11 | void Test18::B::f() +// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-NEXT: 12 | void Test18::A::g() struct D : virtual B, virtual C, virtual A { virtual void f(); @@ -827,6 +886,13 @@ class E : virtual C { }; // CHECK-NEXT: -- (Test21::C, 8) vtable address -- // CHECK-NEXT: -- (Test21::E, 8) vtable address -- // CHECK-NEXT: 15 | [unused] void Test21::F::f() +// +// CHECK: Virtual base offset offsets for 'Test21::F'. +// CHECK-NEXT: Test21::A | -32 +// CHECK-NEXT: Test21::B | -40 +// CHECK-NEXT: Test21::C | -48 +// CHECK-NEXT: Test21::D | -56 +// CHECK-NEXT: Test21::E | -64 class F : virtual D, virtual E { virtual void f(); }; @@ -1091,3 +1157,130 @@ class D : virtual B, virtual C { void D::d() { } } + +namespace Test27 { + +// Test that we don't generate a secondary vtable for C in the D-in-E vtable, since +// C doesn't have any virtual bases. + +struct A { + virtual void a(); +}; + +struct B { + virtual void b(); +}; + +struct C { + virtual void c(); +}; + +struct D : A, virtual B, C { + virtual void d(); +}; + +// CHECK: Vtable for 'Test27::E' (13 entries). +// CHECK-NEXT: 0 | vbase_offset (16) +// CHECK-NEXT: 1 | offset_to_top (0) +// CHECK-NEXT: 2 | Test27::E RTTI +// CHECK-NEXT: -- (Test27::A, 0) vtable address -- +// CHECK-NEXT: -- (Test27::D, 0) vtable address -- +// CHECK-NEXT: -- (Test27::E, 0) vtable address -- +// CHECK-NEXT: 3 | void Test27::A::a() +// CHECK-NEXT: 4 | void Test27::D::d() +// CHECK-NEXT: 5 | void Test27::E::e() +// CHECK-NEXT: 6 | offset_to_top (-8) +// CHECK-NEXT: 7 | Test27::E RTTI +// CHECK-NEXT: -- (Test27::C, 8) vtable address -- +// CHECK-NEXT: 8 | void Test27::C::c() +// CHECK-NEXT: 9 | vcall_offset (0) +// CHECK-NEXT: 10 | offset_to_top (-16) +// CHECK-NEXT: 11 | Test27::E RTTI +// CHECK-NEXT: -- (Test27::B, 16) vtable address -- +// CHECK-NEXT: 12 | void Test27::B::b() + +// CHECK: Construction vtable for ('Test27::D', 0) in 'Test27::E' (9 entries). +// CHECK-NEXT: 0 | vbase_offset (16) +// CHECK-NEXT: 1 | offset_to_top (0) +// CHECK-NEXT: 2 | Test27::D RTTI +// CHECK-NEXT: -- (Test27::A, 0) vtable address -- +// CHECK-NEXT: -- (Test27::D, 0) vtable address -- +// CHECK-NEXT: 3 | void Test27::A::a() +// CHECK-NEXT: 4 | void Test27::D::d() +// CHECK-NEXT: 5 | vcall_offset (0) +// CHECK-NEXT: 6 | offset_to_top (-16) +// CHECK-NEXT: 7 | Test27::D RTTI +// CHECK-NEXT: -- (Test27::B, 16) vtable address -- +// CHECK-NEXT: 8 | void Test27::B::b() +struct E : D { + virtual void e(); +}; +void E::e() { } + +} + +namespace Test28 { + +// Check that we do include the vtable for B in the D-in-E construction vtable, since +// B is a base class of a virtual base (C). + +struct A { + virtual void a(); +}; + +struct B { + virtual void b(); +}; + +struct C : A, B { + virtual void c(); +}; + +struct D : virtual C { +}; + +// CHECK: Vtable for 'Test28::E' (14 entries). +// CHECK-NEXT: 0 | vbase_offset (8) +// CHECK-NEXT: 1 | offset_to_top (0) +// CHECK-NEXT: 2 | Test28::E RTTI +// CHECK-NEXT: -- (Test28::D, 0) vtable address -- +// CHECK-NEXT: -- (Test28::E, 0) vtable address -- +// CHECK-NEXT: 3 | void Test28::E::e() +// CHECK-NEXT: 4 | vcall_offset (8) +// CHECK-NEXT: 5 | vcall_offset (0) +// CHECK-NEXT: 6 | vcall_offset (0) +// CHECK-NEXT: 7 | offset_to_top (-8) +// CHECK-NEXT: 8 | Test28::E RTTI +// CHECK-NEXT: -- (Test28::A, 8) vtable address -- +// CHECK-NEXT: -- (Test28::C, 8) vtable address -- +// CHECK-NEXT: 9 | void Test28::A::a() +// CHECK-NEXT: 10 | void Test28::C::c() +// CHECK-NEXT: 11 | offset_to_top (-16) +// CHECK-NEXT: 12 | Test28::E RTTI +// CHECK-NEXT: -- (Test28::B, 16) vtable address -- +// CHECK-NEXT: 13 | void Test28::B::b() + +// CHECK: Construction vtable for ('Test28::D', 0) in 'Test28::E' (13 entries). +// CHECK-NEXT: 0 | vbase_offset (8) +// CHECK-NEXT: 1 | offset_to_top (0) +// CHECK-NEXT: 2 | Test28::D RTTI +// CHECK-NEXT: -- (Test28::D, 0) vtable address -- +// CHECK-NEXT: 3 | vcall_offset (8) +// CHECK-NEXT: 4 | vcall_offset (0) +// CHECK-NEXT: 5 | vcall_offset (0) +// CHECK-NEXT: 6 | offset_to_top (-8) +// CHECK-NEXT: 7 | Test28::D RTTI +// CHECK-NEXT: -- (Test28::A, 8) vtable address -- +// CHECK-NEXT: -- (Test28::C, 8) vtable address -- +// CHECK-NEXT: 8 | void Test28::A::a() +// CHECK-NEXT: 9 | void Test28::C::c() +// CHECK-NEXT: 10 | offset_to_top (-16) +// CHECK-NEXT: 11 | Test28::D RTTI +// CHECK-NEXT: -- (Test28::B, 16) vtable address -- +// CHECK-NEXT: 12 | void Test28::B::b() +struct E : D { + virtual void e(); +}; +void E::e() { } + +} diff --git a/test/PCH/changed-files.c b/test/PCH/changed-files.c new file mode 100644 index 000000000000..36453c48e716 --- /dev/null +++ b/test/PCH/changed-files.c @@ -0,0 +1,11 @@ +const char *s0 = m0; + +// RUN: echo '#define m0 ""' > %t.h +// RUN: %clang_cc1 -emit-pch -o %t.h.pch %t.h +// RUN: echo '' > %t.h +// RUN: not %clang_cc1 -include-pch %t.h.pch %s 2>&1 | grep "size of file" + +// RUN: echo '#define m0 000' > %t.h +// RUN: %clang_cc1 -emit-pch -o %t.h.pch %t.h +// RUN: echo '' > %t.h +// RUN: not %clang_cc1 -include-pch %t.h.pch %s 2>&1 | grep "size of file" diff --git a/test/Parser/missing-end.m b/test/Parser/missing-end.m new file mode 100644 index 000000000000..fb264610aecb --- /dev/null +++ b/test/Parser/missing-end.m @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +@interface AAA +{ +} +@ x// expected-error{{expected an Objective-C directive after '@'}} +// expected-error{{missing @end}} diff --git a/test/Rewriter/rewrite-local-externs-in-block.mm b/test/Rewriter/rewrite-local-externs-in-block.mm new file mode 100644 index 000000000000..d1a56a89ee58 --- /dev/null +++ b/test/Rewriter/rewrite-local-externs-in-block.mm @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp +// radar 7735987 + +extern "C" int printf(const char*, ...); + +void bar(void (^block)()) { + block(); +} + +int main() { + static int myArr[3] = {1, 2, 3}; + printf ("%d %d %d\n", myArr[0], myArr[1], myArr[2]); + + bar(^{ + printf ("%d %d %d\n", myArr[0], myArr[1], myArr[2]); + myArr[0] = 42; + myArr[2] = 100; + printf ("%d %d %d\n", myArr[0], myArr[1], myArr[2]); + }); + + printf ("%d %d %d\n", myArr[0], myArr[1], myArr[2]); +} diff --git a/test/Rewriter/rewrite-super-message.mm b/test/Rewriter/rewrite-super-message.mm new file mode 100644 index 000000000000..036aa1bb3186 --- /dev/null +++ b/test/Rewriter/rewrite-super-message.mm @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fblocks -fms-extensions -rewrite-objc %s -o %t-rw.cpp +// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"id=struct objc_object *" -D"Class=struct objc_class *" -D"SEL=void*" -D"__declspec(X)=" -emit-llvm -o - %t-rw.cpp | FileCheck %t-rw.cpp +// radar 7738453 + +void *sel_registerName(const char *); + +@interface __NSCFType +@end + +@interface __NSCFString : __NSCFType +- (const char *)UTF8String; +@end + +@implementation __NSCFString +- (const char *)UTF8String { + return (const char *)[super UTF8String]; +} +@end + +// CHECK: call %struct.objc_class* @class_getSuperclass diff --git a/test/Sema/compare.c b/test/Sema/compare.c index 2821a935c3c7..7c8c36f0c145 100644 --- a/test/Sema/compare.c +++ b/test/Sema/compare.c @@ -274,3 +274,11 @@ void test4() { if (value < (unsigned long) &ptr4) // expected-warning {{comparison of integers of different signs}} return; } + +// PR4807 +int test5(unsigned int x) { + return (x < 0) // expected-warning {{comparison of unsigned expression < 0 is always false}} + && (0 > x) // expected-warning {{comparison of 0 > unsigned expression is always false}} + && (x >= 0) // expected-warning {{comparison of unsigned expression >= 0 is always true}} + && (0 <= x); // expected-warning {{comparison of 0 <= unsigned expression is always true}} +} diff --git a/test/Sema/missing-field-initializers.c b/test/Sema/missing-field-initializers.c new file mode 100644 index 000000000000..828191462444 --- /dev/null +++ b/test/Sema/missing-field-initializers.c @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wmissing-field-initializers %s + +// This was PR4808. + +struct Foo { int a, b; }; + +struct Foo foo0 = { 1 }; // expected-warning {{missing field 'b' initializer}} +struct Foo foo1 = { .a = 1 }; // designator avoids MFI warning +struct Foo foo2 = { .b = 1 }; // designator avoids MFI warning + +struct Foo bar0[] = { + { 1,2 }, + { 1 }, // expected-warning {{missing field 'b' initializer}} + { 1,2 } +}; + +struct Foo bar1[] = { + 1, 2, + 1, 2, + 1 +}; // expected-warning {{missing field 'b' initializer}} + +struct One { int a; int b; }; +struct Two { float c; float d; float e; }; + +struct Three { + union { + struct One one; + struct Two two; + } both; +}; + +struct Three t0 = { + { .one = { 1, 2 } } +}; +struct Three t1 = { + { .two = { 1.0f, 2.0f, 3.0f } } +}; + +struct Three data[] = { + { { .one = { 1, 2 } } }, + { { .one = { 1 } } }, // expected-warning {{missing field 'b' initializer}} + { { .two = { 1.0f, 2.0f, 3.0f } } }, + { { .two = { 1.0f, 2.0f } } } // expected-warning {{missing field 'e' initializer}} +}; + +struct { int:5; int a; int:5; int b; int:5 } noNamedImplicit[] = { + { 1, 2 }, + { 1 } // expected-warning {{missing field 'b' initializer}} +}; diff --git a/test/Sema/overloadable.c b/test/Sema/overloadable.c index ff631ed9c85e..28c3e4cf8c90 100644 --- a/test/Sema/overloadable.c +++ b/test/Sema/overloadable.c @@ -50,4 +50,13 @@ void test_promote(short* sp) { promote(sp); // expected-error{{call to unavailable function 'promote'}} } - +// PR6600 +typedef double Double; +typedef Double DoubleVec __attribute__((vector_size(16))); +typedef int Int; +typedef Int IntVec __attribute__((vector_size(16))); +double magnitude(DoubleVec) __attribute__((__overloadable__)); +double magnitude(IntVec) __attribute__((__overloadable__)); +double test_p6600(DoubleVec d) { + return magnitude(d) * magnitude(d); +} diff --git a/test/Sema/return.c b/test/Sema/return.c index 5d1c97f2a2ef..3ab23f4f8f8e 100644 --- a/test/Sema/return.c +++ b/test/Sema/return.c @@ -1,4 +1,4 @@ -// RUN: %clang %s -fsyntax-only -Xclang -verify -fblocks -Wno-unreachable-code +// RUN: %clang %s -fsyntax-only -Xclang -verify -fblocks -Wno-unreachable-code -Wno-unused-value // clang emits the following warning by default. // With GCC, -pedantic, -Wreturn-type or -Wall are required to produce the diff --git a/test/Sema/warn-unused-value.c b/test/Sema/warn-unused-value.c new file mode 100644 index 000000000000..2e0fa54effbf --- /dev/null +++ b/test/Sema/warn-unused-value.c @@ -0,0 +1,53 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value %s + +int i = 0; +int j = 0; + +void foo(); + +// PR4806 +void pr4806() { + 1,foo(); // expected-warning {{expression result unused}} + + // other + foo(); + i; // expected-warning {{expression result unused}} + + i,foo(); // expected-warning {{expression result unused}} + foo(),i; // expected-warning {{expression result unused}} + + i,j,foo(); // expected-warning {{expression result unused}} + i,foo(),j; // expected-warning {{expression result unused}} + foo(),i,j; // expected-warning {{expression result unused}} + + i++; + + i++,foo(); + foo(),i++; + + i++,j,foo(); // expected-warning {{expression result unused}} + i++,foo(),j; // expected-warning {{expression result unused}} + foo(),i++,j; // expected-warning {{expression result unused}} + + i,j++,foo(); // expected-warning {{expression result unused}} + i,foo(),j++; // expected-warning {{expression result unused}} + foo(),i,j++; // expected-warning {{expression result unused}} + + i++,j++,foo(); + i++,foo(),j++; + foo(),i++,j++; + + {}; + ({}); + ({}),foo(); + foo(),({}); + + (int)1U; // expected-warning {{expression result unused}} + (void)1U; + + // pointer to volatile has side effect (thus no warning) + int* pi = &i; + volatile int* pj = &j; + *pi; // expected-warning {{expression result unused}} + *pj; +} diff --git a/test/Sema/warn-write-strings.c b/test/Sema/warn-write-strings.c new file mode 100644 index 000000000000..938f0be7721f --- /dev/null +++ b/test/Sema/warn-write-strings.c @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -verify -fsyntax-only -Wwrite-strings %s + +// PR4804 +char* x = "foo"; // expected-warning {{initializing 'char const [4]' discards qualifiers, expected 'char *'}} diff --git a/test/SemaCXX/PR6562.cpp b/test/SemaCXX/PR6562.cpp new file mode 100644 index 000000000000..854d9b058bc3 --- /dev/null +++ b/test/SemaCXX/PR6562.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +struct X { ~X(); }; +template <typename T> +struct A { + struct B { X x; }; + struct C : public B { + C() : B() { } + }; +}; diff --git a/test/SemaCXX/decl-expr-ambiguity.cpp b/test/SemaCXX/decl-expr-ambiguity.cpp index 81f68392d85a..4243c1c0ead4 100644 --- a/test/SemaCXX/decl-expr-ambiguity.cpp +++ b/test/SemaCXX/decl-expr-ambiguity.cpp @@ -10,7 +10,7 @@ void f() { int(a)++; // expected-error {{expression is not assignable}} __extension__ int(a)++; // expected-error {{expression is not assignable}} __typeof(int)(a,5)<<a; // expected-error {{function-style cast to a builtin type can only take one argument}} - void(a), ++a; // expected-warning {{expression result unused}} + void(a), ++a; if (int(a)+1) {} for (int(a)+1;;) {} // expected-warning {{expression result unused}} a = sizeof(int()+1); diff --git a/test/SemaCXX/warn-unused-value.cpp b/test/SemaCXX/warn-unused-value.cpp new file mode 100644 index 000000000000..775c3cf01f24 --- /dev/null +++ b/test/SemaCXX/warn-unused-value.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value %s + +// PR4806 +namespace test0 { + class Box { + public: + int i; + volatile int j; + }; + + void doit() { + // pointer to volatile has side effect (thus no warning) + Box* box = new Box; + box->i; // expected-warning {{expression result unused}} + box->j; + } +} diff --git a/test/SemaObjC/duplicate-property.m b/test/SemaObjC/duplicate-property.m new file mode 100644 index 000000000000..bc1fe71a1546 --- /dev/null +++ b/test/SemaObjC/duplicate-property.m @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +@interface Foo { + id x; +} +@property (nonatomic, retain) id x; // expected-note{{property declared here}} +@property (nonatomic, retain) id x; // expected-error{{property has a previous declaration}} +@end diff --git a/test/SemaObjC/warn-write-strings.m b/test/SemaObjC/warn-write-strings.m new file mode 100644 index 000000000000..938f0be7721f --- /dev/null +++ b/test/SemaObjC/warn-write-strings.m @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -verify -fsyntax-only -Wwrite-strings %s + +// PR4804 +char* x = "foo"; // expected-warning {{initializing 'char const [4]' discards qualifiers, expected 'char *'}} diff --git a/test/SemaObjCXX/objc-pointer-conv.mm b/test/SemaObjCXX/objc-pointer-conv.mm index c03e3aaad3db..144bda4390d5 100644 --- a/test/SemaObjCXX/objc-pointer-conv.mm +++ b/test/SemaObjCXX/objc-pointer-conv.mm @@ -24,3 +24,15 @@ void RandomFunc(CFMDRef theDict, const void *key, const void *value); RandomFunc((CFMDRef)dict, key, objects[3]); } @end + +@interface I +- (void) Meth : (I*) Arg; +@end + +void Func (I* arg); // expected-note {{candidate function not viable: no known conversion from 'I const *' to 'I *' for 1st argument}} + +void foo(const I *p, I* sel) { + [sel Meth : p]; // expected-error {{incompatible type sending 'I const *', expected 'I *'}} + Func(p); // expected-error {{no matching function for call to 'Func'}} +} + diff --git a/test/SemaTemplate/instantiate-function-1.cpp b/test/SemaTemplate/instantiate-function-1.cpp index 7b4c53cfe0d7..6e0d71159004 100644 --- a/test/SemaTemplate/instantiate-function-1.cpp +++ b/test/SemaTemplate/instantiate-function-1.cpp @@ -214,3 +214,9 @@ template<typename T> struct X; template<typename T> struct Y : public X<T> { Y& x() { return *this; } }; + +// Make sure our assertions don't get too uppity. +namespace test0 { + template <class T> class A { void foo(T array[10]); }; + template class A<int>; +} diff --git a/test/SemaTemplate/virtual-member-functions.cpp b/test/SemaTemplate/virtual-member-functions.cpp index 8df808d2569a..59df3c22aa1c 100644 --- a/test/SemaTemplate/virtual-member-functions.cpp +++ b/test/SemaTemplate/virtual-member-functions.cpp @@ -36,10 +36,10 @@ struct Base { template<typename T> struct Derived : Base<T> { - virtual void foo() { } // expected-note {{in instantiation of member function 'Base<int>::~Base' requested here}} + virtual void foo() { } }; -template struct Derived<int>; +template struct Derived<int>; // expected-note {{in instantiation of member function 'Base<int>::~Base' requested here}} template<typename T> struct HasOutOfLineKey { diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp index b52a32ed9b51..663b32fa1a06 100644 --- a/tools/CIndex/CIndex.cpp +++ b/tools/CIndex/CIndex.cpp @@ -1133,7 +1133,8 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, // We failed to load the ASTUnit, but we can still deserialize the // diagnostics and emit them. FileManager FileMgr; - SourceManager SourceMgr; + Diagnostic Diag; + SourceManager SourceMgr(Diag); // FIXME: Faked LangOpts! LangOptions LangOpts; llvm::SmallVector<StoredDiagnostic, 4> Diags; @@ -2042,11 +2043,13 @@ CXString clang_getTokenSpelling(CXTranslationUnit TU, CXToken CXTok) { SourceLocation Loc = SourceLocation::getFromRawEncoding(CXTok.int_data[1]); std::pair<FileID, unsigned> LocInfo = CXXUnit->getSourceManager().getDecomposedLoc(Loc); - std::pair<const char *,const char *> Buffer - = CXXUnit->getSourceManager().getBufferData(LocInfo.first); + bool Invalid = false; + llvm::StringRef Buffer + = CXXUnit->getSourceManager().getBufferData(LocInfo.first, &Invalid); + if (Invalid) + return createCXString(""); - return createCXString(llvm::StringRef(Buffer.first+LocInfo.second, - CXTok.int_data[2])); + return createCXString(Buffer.substr(LocInfo.second, CXTok.int_data[2])); } CXSourceLocation clang_getTokenLocation(CXTranslationUnit TU, CXToken CXTok) { @@ -2095,15 +2098,17 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, return; // Create a lexer - std::pair<const char *,const char *> Buffer - = SourceMgr.getBufferData(BeginLocInfo.first); + bool Invalid = false; + llvm::StringRef Buffer + = SourceMgr.getBufferData(BeginLocInfo.first, &Invalid); + Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first), CXXUnit->getASTContext().getLangOptions(), - Buffer.first, Buffer.first + BeginLocInfo.second, Buffer.second); + Buffer.begin(), Buffer.data() + BeginLocInfo.second, Buffer.end()); Lex.SetCommentRetentionState(true); // Lex tokens until we hit the end of the range. - const char *EffectiveBufferEnd = Buffer.first + EndLocInfo.second; + const char *EffectiveBufferEnd = Buffer.data() + EndLocInfo.second; llvm::SmallVector<CXToken, 32> CXTokens; Token Tok; do { @@ -2125,12 +2130,16 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, CXTok.int_data[0] = CXToken_Literal; CXTok.ptr_data = (void *)Tok.getLiteralData(); } else if (Tok.is(tok::identifier)) { - // Lookup the identifier to determine whether we have a + // Lookup the identifier to determine whether we have a keyword. std::pair<FileID, unsigned> LocInfo = SourceMgr.getDecomposedLoc(Tok.getLocation()); - const char *StartPos - = CXXUnit->getSourceManager().getBufferData(LocInfo.first).first + - LocInfo.second; + bool Invalid = false; + llvm::StringRef Buf + = CXXUnit->getSourceManager().getBufferData(LocInfo.first, &Invalid); + if (Invalid) + return; + + const char *StartPos = Buf.data() + LocInfo.second; IdentifierInfo *II = CXXUnit->getPreprocessor().LookUpIdentifierInfo(Tok, StartPos); CXTok.int_data[0] = II->getTokenID() == tok::identifier? diff --git a/tools/CIndex/CIndex.exports b/tools/CIndex/CIndex.exports index 5b9530052b51..fe0396d2b140 100644 --- a/tools/CIndex/CIndex.exports +++ b/tools/CIndex/CIndex.exports @@ -2,6 +2,12 @@ _clang_annotateTokens _clang_codeComplete _clang_codeCompleteGetDiagnostic _clang_codeCompleteGetNumDiagnostics +_clang_constructUSR_ObjCClass +_clang_constructUSR_ObjCCategory +_clang_constructUSR_ObjCIvar +_clang_constructUSR_ObjCMethod +_clang_constructUSR_ObjCProtocol +_clang_constructUSR_ObjCProperty _clang_createIndex _clang_createTranslationUnit _clang_createTranslationUnitFromSourceFile diff --git a/tools/CIndex/CIndexCodeCompletion.cpp b/tools/CIndex/CIndexCodeCompletion.cpp index 3b7674ec0d1d..264e5064ddb4 100644 --- a/tools/CIndex/CIndexCodeCompletion.cpp +++ b/tools/CIndex/CIndexCodeCompletion.cpp @@ -187,6 +187,9 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { /// \brief Diagnostics produced while performing code completion. llvm::SmallVector<StoredDiagnostic, 8> Diagnostics; + /// \brief Diag object + Diagnostic Diag; + /// \brief Language options used to adjust source locations. LangOptions LangOpts; @@ -202,7 +205,7 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { }; AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults() - : CXCodeCompleteResults(), Buffer(0) { } + : CXCodeCompleteResults(), Buffer(0), SourceMgr(Diag) { } AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() { for (unsigned I = 0, N = NumResults; I != N; ++I) diff --git a/tools/CIndex/CIndexUSRs.cpp b/tools/CIndex/CIndexUSRs.cpp index 922f4b3fa73f..9dbbd3541e4c 100644 --- a/tools/CIndex/CIndexUSRs.cpp +++ b/tools/CIndex/CIndexUSRs.cpp @@ -29,23 +29,77 @@ class USRGenerator : public DeclVisitor<USRGenerator> { bool IgnoreResults; public: USRGenerator(llvm::raw_ostream &out) : Out(out), IgnoreResults(false) {} - + bool ignoreResults() const { return IgnoreResults; } - + + // Visitation methods from generating USRs from AST elements. void VisitBlockDecl(BlockDecl *D); void VisitDeclContext(DeclContext *D); void VisitFieldDecl(FieldDecl *D); void VisitFunctionDecl(FunctionDecl *D); void VisitNamedDecl(NamedDecl *D); void VisitNamespaceDecl(NamespaceDecl *D); - void VisitObjCContainerDecl(ObjCContainerDecl *CD); + void VisitObjCContainerDecl(ObjCContainerDecl *CD); void VisitObjCMethodDecl(ObjCMethodDecl *MD); void VisitObjCPropertyDecl(ObjCPropertyDecl *D); void VisitTagDecl(TagDecl *D); void VisitTypedefDecl(TypedefDecl *D); + + + /// String generation methods used both by the visitation methods + /// and from other clients that want to directly generate USRs. These + /// methods do not construct complete USRs (which incorporate the parents + /// of an AST element), but only the fragments concerning the AST element + /// itself. + + /// Generate a USR fragment for a named declaration. This does + /// not include the USR component for the parent. + void GenNamedDecl(llvm::StringRef name); + + /// Generate a USR for an Objective-C class. + void GenObjCClass(llvm::StringRef cls); + /// Generate a USR for an Objective-C class category. + void GenObjCCategory(llvm::StringRef cls, llvm::StringRef cat); + /// Generate a USR fragment for an Objective-C instance variable. The + /// complete USR can be created by concatenating the USR for the + /// encompassing class with this USR fragment. + void GenObjCIvar(llvm::StringRef ivar); + /// Generate a USR fragment for an Objective-C method. + void GenObjCMethod(llvm::StringRef sel, bool isInstanceMethod); + /// Generate a USR fragment for an Objective-C property. + void GenObjCProperty(llvm::StringRef prop); + /// Generate a USR for an Objective-C protocol. + void GenObjCProtocol(llvm::StringRef prot); +}; + +class StringUSRGenerator { +private: + llvm::SmallString<1024> StrBuf; + llvm::raw_svector_ostream Out; + USRGenerator UG; +public: + StringUSRGenerator() + : Out(StrBuf), UG(Out) {} + + llvm::StringRef str() { + return Out.str(); + } + + USRGenerator* operator->() { return &UG; } + + template <typename T> + llvm::raw_svector_ostream &operator<<(const T &x) { + Out << x; + return Out; + } }; + } // end anonymous namespace +//===----------------------------------------------------------------------===// +// Generating USRs from ASTS. +//===----------------------------------------------------------------------===// + void USRGenerator::VisitBlockDecl(BlockDecl *D) { VisitDeclContext(D->getDeclContext()); // FIXME: Better support for anonymous blocks. @@ -76,8 +130,8 @@ void USRGenerator::VisitFunctionDecl(FunctionDecl *D) { void USRGenerator::VisitNamedDecl(NamedDecl *D) { VisitDeclContext(D->getDeclContext()); const std::string &s = D->getNameAsString(); -// assert(!s.empty()); - Out << "@^" << s; + // assert(!s.empty()); + GenNamedDecl(s); } void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) { @@ -87,8 +141,8 @@ void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) { void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) { Visit(cast<Decl>(D->getDeclContext())); - Out << (D->isInstanceMethod() ? "(im)" : "(cm)"); - Out << DeclarationName(D->getSelector()).getAsString(); + GenObjCMethod(DeclarationName(D->getSelector()).getAsString(), + D->isInstanceMethod()); } void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) { @@ -97,29 +151,29 @@ void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) { assert(false && "Invalid ObjC container."); case Decl::ObjCInterface: case Decl::ObjCImplementation: - Out << "objc(cs)" << D->getName(); + GenObjCClass(D->getName()); break; case Decl::ObjCCategory: { ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D); - Out << "objc(cy)" << CD->getClassInterface()->getName() - << '^' << CD->getName(); + GenObjCCategory(CD->getClassInterface()->getName(), + CD->getName()); break; } case Decl::ObjCCategoryImpl: { ObjCCategoryImplDecl *CD = cast<ObjCCategoryImplDecl>(D); - Out << "objc(cy)" << CD->getClassInterface()->getName() - << '^' << CD->getName(); + GenObjCCategory(CD->getClassInterface()->getName(), + CD->getName()); break; } case Decl::ObjCProtocol: - Out << "objc(pl)" << cast<ObjCProtocolDecl>(D)->getName(); + GenObjCProtocol(cast<ObjCProtocolDecl>(D)->getName()); break; } } void USRGenerator::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { Visit(cast<Decl>(D->getDeclContext())); - Out << "(py)" << D->getName(); + GenObjCProperty(D->getName()); } void USRGenerator::VisitTagDecl(TagDecl *D) { @@ -130,12 +184,12 @@ void USRGenerator::VisitTagDecl(TagDecl *D) { case TagDecl::TK_union: Out << "@U^"; break; case TagDecl::TK_enum: Out << "@E^"; break; } - + // FIXME: Better support for anonymous structures and enums. const std::string &s = D->getNameAsString(); if (s.empty()) { if (TypedefDecl *TD = D->getTypedefForAnonDecl()) - Out << "^anontd^" << TD->getNameAsString(); + Out << "^anontd^" << TD->getNameAsString(); else Out << "^anon"; } @@ -146,36 +200,104 @@ void USRGenerator::VisitTagDecl(TagDecl *D) { void USRGenerator::VisitTypedefDecl(TypedefDecl *D) { DeclContext *DC = D->getDeclContext(); if (NamedDecl *DCN = dyn_cast<NamedDecl>(DC)) - Visit(DCN); + Visit(DCN); Out << "typedef@" << D->getName(); } -// FIXME: This is a skeleton implementation. It will be overhauled. -static CXString ConstructUSR(Decl *D) { - llvm::SmallString<1024> StrBuf; - { - llvm::raw_svector_ostream Out(StrBuf); - USRGenerator UG(Out); - UG.Visit(static_cast<Decl*>(D)); - if (UG.ignoreResults()) - return createCXString(NULL); - } - - if (StrBuf.empty()) - return createCXString(NULL); - - // Return a copy of the string that must be disposed by the caller. - return createCXString(StrBuf.str(), true); -} +//===----------------------------------------------------------------------===// +// General purpose USR generation methods. +//===----------------------------------------------------------------------===// + +void USRGenerator::GenNamedDecl(llvm::StringRef name) { + Out << "@^" << name; +} + +void USRGenerator::GenObjCClass(llvm::StringRef cls) { + Out << "objc(cs)" << cls; +} +void USRGenerator::GenObjCCategory(llvm::StringRef cls, llvm::StringRef cat) { + Out << "objc(cy)" << cls << '^' << cat; +} + +void USRGenerator::GenObjCIvar(llvm::StringRef ivar) { + GenNamedDecl(ivar); +} + +void USRGenerator::GenObjCMethod(llvm::StringRef meth, bool isInstanceMethod) { + Out << (isInstanceMethod ? "(im)" : "(cm)") << meth; +} + +void USRGenerator::GenObjCProperty(llvm::StringRef prop) { + Out << "(py)" << prop; +} + +void USRGenerator::GenObjCProtocol(llvm::StringRef prot) { + Out << "objc(pl)" << prot; +} + +//===----------------------------------------------------------------------===// +// API hooks. +//===----------------------------------------------------------------------===// extern "C" { CXString clang_getCursorUSR(CXCursor C) { - if (Decl *D = cxcursor::getCursorDecl(C)) - return ConstructUSR(D); - - return createCXString(NULL); + Decl *D = cxcursor::getCursorDecl(C); + if (!D) + return createCXString(NULL); + + StringUSRGenerator SUG; + SUG->Visit(static_cast<Decl*>(D)); + + if (SUG->ignoreResults() || SUG.str().empty()) + return createCXString(NULL); + + // Return a copy of the string that must be disposed by the caller. + return createCXString(SUG.str(), true); +} + +CXString clang_constructUSR_ObjCIvar(const char *name, CXString classUSR) { + StringUSRGenerator SUG; + SUG << clang_getCString(classUSR); + SUG->GenObjCIvar(name); + return createCXString(SUG.str(), true); +} + +CXString clang_constructUSR_ObjCMethod(const char *name, + unsigned isInstanceMethod, + CXString classUSR) { + StringUSRGenerator SUG; + SUG << clang_getCString(classUSR); + SUG->GenObjCMethod(name, isInstanceMethod); + return createCXString(SUG.str(), true); +} + +CXString clang_constructUSR_ObjCClass(const char *name) { + StringUSRGenerator SUG; + SUG->GenObjCClass(name); + return createCXString(SUG.str(), true); +} + +CXString clang_constructUSR_ObjCProtocol(const char *name) { + StringUSRGenerator SUG; + SUG->GenObjCProtocol(name); + return createCXString(SUG.str(), true); +} + +CXString clang_constructUSR_ObjCCategory(const char *class_name, + const char *category_name) { + StringUSRGenerator SUG; + SUG->GenObjCCategory(class_name, category_name); + return createCXString(SUG.str(), true); +} + +CXString clang_constructUSR_ObjCProperty(const char *property, + CXString classUSR) { + StringUSRGenerator SUG; + SUG << clang_getCString(classUSR); + SUG->GenObjCProperty(property); + return createCXString(SUG.str(), true); } } // end extern "C" diff --git a/tools/CIndex/Makefile b/tools/CIndex/Makefile index 3e288623e5eb..650bcd3645d2 100644 --- a/tools/CIndex/Makefile +++ b/tools/CIndex/Makefile @@ -10,7 +10,7 @@ LEVEL = ../../../.. LIBRARYNAME = CIndex -CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include +CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include # Include this here so we can get the configuration of the targets # that have been configured for construction. We have to do this diff --git a/tools/Makefile b/tools/Makefile index 5a9c67421b78..bfd5ad12f93d 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -13,8 +13,7 @@ DIRS := driver CIndex c-index-test include $(LEVEL)/Makefile.config ifeq ($(OS), $(filter $(OS), Cygwin MingW)) -DIRS := $(filter $(DIRS), CIndex) -DIRS := $(filter $(DIRS), c-index-test) +DIRS := $(filter-out CIndex c-index-test, $(DIRS)) endif include $(LEVEL)/Makefile.common diff --git a/tools/driver/Makefile b/tools/driver/Makefile index e5a9280a0cbe..6434cb4ef551 100644 --- a/tools/driver/Makefile +++ b/tools/driver/Makefile @@ -12,7 +12,7 @@ TOOLNAME = clang ifndef CLANG_IS_PRODUCTION TOOLALIAS = clang++ endif -CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include +CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include # Clang tool has no plugins, optimize startup time. TOOL_NO_EXPORTS = 1 diff --git a/www/analyzer/index.html b/www/analyzer/index.html index 335ca8b34aa1..082d35fdc488 100644 --- a/www/analyzer/index.html +++ b/www/analyzer/index.html @@ -27,7 +27,7 @@ tool</a> or <a href="/xcode.html">within Xcode</a>. The standalone tool is invoked from the command-line, and is intended to be run in tandem with a build of a codebase.</p> -<p>The analyzer is 100% open source and are part of the <a +<p>The analyzer is 100% open source and is part of the <a href="http://clang.llvm.org">Clang</a> project. Like the rest of Clang, the analyzer is implemented as a C++ library that can be used by other tools and applications.</p> diff --git a/www/analyzer/latest_checker.html.incl b/www/analyzer/latest_checker.html.incl index 3368167b7fab..63084b53a7e6 100644 --- a/www/analyzer/latest_checker.html.incl +++ b/www/analyzer/latest_checker.html.incl @@ -1 +1 @@ -<b><a href="http://checker.minormatter.com/checker-236.tar.bz2">checker-236.tar.bz2</a></b> (built February 25, 2010) +<b><a href="http://checker.minormatter.com/checker-237.tar.bz2">checker-237.tar.bz2</a></b> (built March 11, 2010) |