diff options
author | dim <dim@FreeBSD.org> | 2013-06-10 20:45:12 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2013-06-10 20:45:12 +0000 |
commit | ea266cad53e3d49771fa38103913d3ec7a166694 (patch) | |
tree | 8f7776b7310bebaf415ac5b69e46e9f928c37144 /lib | |
parent | c72c57c9e9b69944e3e009cd5e209634839581d3 (diff) | |
download | FreeBSD-src-ea266cad53e3d49771fa38103913d3ec7a166694.zip FreeBSD-src-ea266cad53e3d49771fa38103913d3ec7a166694.tar.gz |
Vendor import of clang tags/RELEASE_33/final r183502 (effectively, 3.3
release):
http://llvm.org/svn/llvm-project/cfe/tags/RELEASE_33/final@183502
Diffstat (limited to 'lib')
221 files changed, 13295 insertions, 5312 deletions
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp index 72f3520..a6d4876 100644 --- a/lib/ARCMigrate/ARCMT.cpp +++ b/lib/ARCMigrate/ARCMT.cpp @@ -140,12 +140,6 @@ public: // Non-ARC warnings are ignored. Diags.setLastDiagnosticIgnored(); } - - DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { - // Just drop any diagnostics that come from cloned consumers; they'll - // have different source managers anyway. - return new IgnoringDiagConsumer(); - } }; } // end anonymous namespace @@ -482,7 +476,7 @@ public: : ARCMTMacroLocs(ARCMTMacroLocs) { } virtual void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD, - SourceRange Range) { + SourceRange Range, const MacroArgs *Args) { if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName()) ARCMTMacroLocs.push_back(MacroNameTok.getLocation()); } diff --git a/lib/ARCMigrate/TransAPIUses.cpp b/lib/ARCMigrate/TransAPIUses.cpp index 2305b6d..a0994a6 100644 --- a/lib/ARCMigrate/TransAPIUses.cpp +++ b/lib/ARCMigrate/TransAPIUses.cpp @@ -91,12 +91,12 @@ public: E->getSelector() == zoneSel && Pass.TA.hasDiagnostic(diag::err_unavailable, diag::err_unavailable_message, - E->getInstanceReceiver()->getExprLoc())) { + E->getSelectorLoc(0))) { // Calling -zone is meaningless in ARC, change it to nil. Transaction Trans(Pass.TA); Pass.TA.clearDiagnostic(diag::err_unavailable, diag::err_unavailable_message, - E->getInstanceReceiver()->getExprLoc()); + E->getSelectorLoc(0)); Pass.TA.replace(E->getSourceRange(), getNilString(Pass.Ctx)); } return true; diff --git a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp index 0c8d155..446a284 100644 --- a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp +++ b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp @@ -118,7 +118,7 @@ public: return true; case ObjCMessageExpr::SuperInstance: { Transaction Trans(Pass.TA); - clearDiagnostics(E->getSuperLoc()); + clearDiagnostics(E->getSelectorLoc(0)); if (tryRemoving(E)) return true; Pass.TA.replace(E->getSourceRange(), "self"); @@ -132,7 +132,7 @@ public: if (!rec) return true; Transaction Trans(Pass.TA); - clearDiagnostics(rec->getExprLoc()); + clearDiagnostics(E->getSelectorLoc(0)); ObjCMessageExpr *Msg = E; Expr *RecContainer = Msg; diff --git a/lib/ARCMigrate/Transforms.h b/lib/ARCMigrate/Transforms.h index cb7d153..e20fe59 100644 --- a/lib/ARCMigrate/Transforms.h +++ b/lib/ARCMigrate/Transforms.h @@ -169,7 +169,7 @@ bool isPlusOne(const Expr *E); /// source location will be invalid. SourceLocation findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx); -/// \brief \arg Loc is the end of a statement range. This returns the location +/// \brief 'Loc' is the end of a statement range. This returns the location /// of the semicolon following the statement. /// If no semicolon is found or the location is inside a macro, the returned /// source location will be invalid. diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 7245c03..176aec5 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -97,7 +97,12 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { if (ED->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return NULL; } - + if (const TagDecl *TD = dyn_cast<TagDecl>(D)) { + // When tag declaration (but not definition!) is part of the + // decl-specifier-seq of some other declaration, it doesn't get comment + if (TD->isEmbeddedInDeclarator() && !TD->isCompleteDefinition()) + return NULL; + } // TODO: handle comments for function parameters properly. if (isa<ParmVarDecl>(D)) return NULL; @@ -141,7 +146,9 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { // When searching for comments during parsing, the comment we are looking // for is usually among the last two comments we parsed -- check them // first. - RawComment CommentAtDeclLoc(SourceMgr, SourceRange(DeclLoc)); + RawComment CommentAtDeclLoc( + SourceMgr, SourceRange(DeclLoc), false, + LangOpts.CommentOpts.ParseAllComments); BeforeThanCompare<RawComment> Compare(SourceMgr); ArrayRef<RawComment *>::iterator MaybeBeforeDecl = RawComments.end() - 1; bool Found = Compare(*MaybeBeforeDecl, &CommentAtDeclLoc); @@ -435,7 +442,7 @@ comments::FullComment *ASTContext::getCommentForDecl( if (comments::FullComment *FC = getCommentForDecl(Overridden[i], PP)) return cloneFullComment(FC, D); } - else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { + else if (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { // Attach any tag type's documentation to its typedef if latter // does not have one of its own. QualType QT = TD->getUnderlyingType(); @@ -444,6 +451,53 @@ comments::FullComment *ASTContext::getCommentForDecl( if (comments::FullComment *FC = getCommentForDecl(TD, PP)) return cloneFullComment(FC, D); } + else if (const ObjCInterfaceDecl *IC = dyn_cast<ObjCInterfaceDecl>(D)) { + while (IC->getSuperClass()) { + IC = IC->getSuperClass(); + if (comments::FullComment *FC = getCommentForDecl(IC, PP)) + return cloneFullComment(FC, D); + } + } + else if (const ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D)) { + if (const ObjCInterfaceDecl *IC = CD->getClassInterface()) + if (comments::FullComment *FC = getCommentForDecl(IC, PP)) + return cloneFullComment(FC, D); + } + else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { + if (!(RD = RD->getDefinition())) + return NULL; + // Check non-virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = + RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { + if (I->isVirtual() || (I->getAccessSpecifier() != AS_public)) + continue; + QualType Ty = I->getType(); + if (Ty.isNull()) + continue; + if (const CXXRecordDecl *NonVirtualBase = Ty->getAsCXXRecordDecl()) { + if (!(NonVirtualBase= NonVirtualBase->getDefinition())) + continue; + + if (comments::FullComment *FC = getCommentForDecl((NonVirtualBase), PP)) + return cloneFullComment(FC, D); + } + } + // Check virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = + RD->vbases_begin(), E = RD->vbases_end(); I != E; ++I) { + if (I->getAccessSpecifier() != AS_public) + continue; + QualType Ty = I->getType(); + if (Ty.isNull()) + continue; + if (const CXXRecordDecl *VirtualBase = Ty->getAsCXXRecordDecl()) { + if (!(VirtualBase= VirtualBase->getDefinition())) + continue; + if (comments::FullComment *FC = getCommentForDecl((VirtualBase), PP)) + return cloneFullComment(FC, D); + } + } + } return NULL; } @@ -1125,8 +1179,8 @@ void ASTContext::getOverriddenMethods( assert(D); if (const CXXMethodDecl *CXXMethod = dyn_cast<CXXMethodDecl>(D)) { - Overridden.append(CXXMethod->begin_overridden_methods(), - CXXMethod->end_overridden_methods()); + Overridden.append(overridden_methods_begin(CXXMethod), + overridden_methods_end(CXXMethod)); return; } @@ -1229,6 +1283,10 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { T = getBaseElementType(arrayType); } Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr())); + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (VD->hasGlobalStorage()) + Align = std::max(Align, getTargetInfo().getMinGlobalAlign()); + } } // Fields can be subject to extra alignment constraints, like if @@ -1543,7 +1601,8 @@ ASTContext::getTypeInfoImpl(const Type *T) const { case Type::Auto: { const AutoType *A = cast<AutoType>(T); - assert(A->isDeduced() && "Cannot request the size of a dependent type"); + assert(!A->getDeducedType().isNull() && + "cannot request the size of an undeduced or dependent auto type"); return getTypeInfo(A->getDeducedType().getTypePtr()); } @@ -1670,6 +1729,18 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { return ABIAlign; } +/// getAlignOfGlobalVar - Return the alignment in bits that should be given +/// to a global variable of the specified type. +unsigned ASTContext::getAlignOfGlobalVar(QualType T) const { + return std::max(getTypeAlign(T), getTargetInfo().getMinGlobalAlign()); +} + +/// getAlignOfGlobalVarInChars - Return the alignment in characters that +/// should be given to a global variable of the specified type. +CharUnits ASTContext::getAlignOfGlobalVarInChars(QualType T) const { + return toCharUnitsFromBits(getAlignOfGlobalVar(T)); +} + /// DeepCollectObjCIvars - /// This routine first collects all declared, but not synthesized, ivars in /// super class and then collects all ivars, including those synthesized for @@ -1980,6 +2051,16 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T, return cast<FunctionType>(Result.getTypePtr()); } +void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD, + QualType ResultType) { + // FIXME: Need to inform serialization code about this! + for (FD = FD->getMostRecentDecl(); FD; FD = FD->getPreviousDecl()) { + const FunctionProtoType *FPT = FD->getType()->castAs<FunctionProtoType>(); + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + FD->setType(getFunctionType(ResultType, FPT->getArgTypes(), EPI)); + } +} + /// getComplexType - Return the uniqued reference to the type for a complex /// number with the specified element type. QualType ASTContext::getComplexType(QualType T) const { @@ -3508,18 +3589,24 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType, return QualType(Ty, 0); } -/// getAutoType - We only unique auto types after they've been deduced. -QualType ASTContext::getAutoType(QualType DeducedType) const { +/// getAutoType - Return the uniqued reference to the 'auto' type which has been +/// deduced to the given type, or to the canonical undeduced 'auto' type, or the +/// canonical deduced-but-dependent 'auto' type. +QualType ASTContext::getAutoType(QualType DeducedType, bool IsDecltypeAuto, + bool IsDependent) const { + if (DeducedType.isNull() && !IsDecltypeAuto && !IsDependent) + return getAutoDeductType(); + + // Look in the folding set for an existing type. void *InsertPos = 0; - if (!DeducedType.isNull()) { - // Look in the folding set for an existing type. - llvm::FoldingSetNodeID ID; - AutoType::Profile(ID, DeducedType); - if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(AT, 0); - } + llvm::FoldingSetNodeID ID; + AutoType::Profile(ID, DeducedType, IsDecltypeAuto, IsDependent); + if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(AT, 0); - AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType); + AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType, + IsDecltypeAuto, + IsDependent); Types.push_back(AT); if (InsertPos) AutoTypes.InsertNode(AT, InsertPos); @@ -3557,8 +3644,10 @@ QualType ASTContext::getAtomicType(QualType T) const { /// getAutoDeductType - Get type pattern for deducing against 'auto'. QualType ASTContext::getAutoDeductType() const { if (AutoDeductTy.isNull()) - AutoDeductTy = getAutoType(QualType()); - assert(!AutoDeductTy.isNull() && "can't build 'auto' pattern"); + AutoDeductTy = QualType( + new (*this, TypeAlignment) AutoType(QualType(), /*decltype(auto)*/false, + /*dependent*/false), + 0); return AutoDeductTy; } @@ -4188,7 +4277,7 @@ QualType ASTContext::isPromotableBitField(Expr *E) const { if (E->isTypeDependent() || E->isValueDependent()) return QualType(); - FieldDecl *Field = E->getBitField(); + FieldDecl *Field = E->getSourceBitField(); // FIXME: conditional bit-fields? if (!Field) return QualType(); @@ -5331,6 +5420,11 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, // FIXME. We should do a better job than gcc. return; + case Type::Auto: + // We could see an undeduced auto type here during error recovery. + // Just ignore it. + return; + #define ABSTRACT_TYPE(KIND, BASE) #define TYPE(KIND, BASE) #define DEPENDENT_TYPE(KIND, BASE) \ @@ -5886,6 +5980,80 @@ CreateAAPCSABIBuiltinVaListDecl(const ASTContext *Context) { return VaListTypeDecl; } +static TypedefDecl * +CreateSystemZBuiltinVaListDecl(const ASTContext *Context) { + // typedef struct __va_list_tag { + RecordDecl *VaListTagDecl; + VaListTagDecl = CreateRecordDecl(*Context, TTK_Struct, + Context->getTranslationUnitDecl(), + &Context->Idents.get("__va_list_tag")); + VaListTagDecl->startDefinition(); + + const size_t NumFields = 4; + QualType FieldTypes[NumFields]; + const char *FieldNames[NumFields]; + + // long __gpr; + FieldTypes[0] = Context->LongTy; + FieldNames[0] = "__gpr"; + + // long __fpr; + FieldTypes[1] = Context->LongTy; + FieldNames[1] = "__fpr"; + + // void *__overflow_arg_area; + FieldTypes[2] = Context->getPointerType(Context->VoidTy); + FieldNames[2] = "__overflow_arg_area"; + + // void *__reg_save_area; + FieldTypes[3] = Context->getPointerType(Context->VoidTy); + FieldNames[3] = "__reg_save_area"; + + // Create fields + for (unsigned i = 0; i < NumFields; ++i) { + FieldDecl *Field = FieldDecl::Create(const_cast<ASTContext &>(*Context), + VaListTagDecl, + SourceLocation(), + SourceLocation(), + &Context->Idents.get(FieldNames[i]), + FieldTypes[i], /*TInfo=*/0, + /*BitWidth=*/0, + /*Mutable=*/false, + ICIS_NoInit); + Field->setAccess(AS_public); + VaListTagDecl->addDecl(Field); + } + VaListTagDecl->completeDefinition(); + QualType VaListTagType = Context->getRecordType(VaListTagDecl); + Context->VaListTagTy = VaListTagType; + + // } __va_list_tag; + TypedefDecl *VaListTagTypedefDecl + = TypedefDecl::Create(const_cast<ASTContext &>(*Context), + Context->getTranslationUnitDecl(), + SourceLocation(), SourceLocation(), + &Context->Idents.get("__va_list_tag"), + Context->getTrivialTypeSourceInfo(VaListTagType)); + QualType VaListTagTypedefType = + Context->getTypedefType(VaListTagTypedefDecl); + + // typedef __va_list_tag __builtin_va_list[1]; + llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 1); + QualType VaListTagArrayType + = Context->getConstantArrayType(VaListTagTypedefType, + Size, ArrayType::Normal,0); + TypeSourceInfo *TInfo + = Context->getTrivialTypeSourceInfo(VaListTagArrayType); + TypedefDecl *VaListTypedefDecl + = TypedefDecl::Create(const_cast<ASTContext &>(*Context), + Context->getTranslationUnitDecl(), + SourceLocation(), SourceLocation(), + &Context->Idents.get("__builtin_va_list"), + TInfo); + + return VaListTypedefDecl; +} + static TypedefDecl *CreateVaListDecl(const ASTContext *Context, TargetInfo::BuiltinVaListKind Kind) { switch (Kind) { @@ -5903,6 +6071,8 @@ static TypedefDecl *CreateVaListDecl(const ASTContext *Context, return CreatePNaClABIBuiltinVaListDecl(Context); case TargetInfo::AAPCSABIBuiltinVaList: return CreateAAPCSABIBuiltinVaListDecl(Context); + case TargetInfo::SystemZBuiltinVaList: + return CreateSystemZBuiltinVaListDecl(Context); } llvm_unreachable("Unhandled __builtin_va_list type kind"); @@ -6972,6 +7142,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, #include "clang/AST/TypeNodes.def" llvm_unreachable("Non-canonical and dependent types shouldn't get here"); + case Type::Auto: case Type::LValueReference: case Type::RValueReference: case Type::MemberPointer: diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index b1d174b..340cc41 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -853,8 +853,11 @@ void ASTDumper::VisitVarDecl(const VarDecl *D) { StorageClass SC = D->getStorageClass(); if (SC != SC_None) OS << ' ' << VarDecl::getStorageClassSpecifierString(SC); - if (D->isThreadSpecified()) - OS << " __thread"; + switch (D->getTLSKind()) { + case VarDecl::TLS_None: break; + case VarDecl::TLS_Static: OS << " tls"; break; + case VarDecl::TLS_Dynamic: OS << " tls_dynamic"; break; + } if (D->isModulePrivate()) OS << " __module_private__"; if (D->isNRVOVariable()) diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index d2e6d29..915eb6f 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -839,6 +839,12 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, RecordDecl *D2 = Field2->getType()->castAs<RecordType>()->getDecl(); return IsStructurallyEquivalent(Context, D1, D2); } + + // Check for equivalent field names. + IdentifierInfo *Name1 = Field1->getIdentifier(); + IdentifierInfo *Name2 = Field2->getIdentifier(); + if (!::IsStructurallyEquivalent(Name1, Name2)) + return false; if (!IsStructurallyEquivalent(Context, Field1->getType(), Field2->getType())) { @@ -1680,7 +1686,7 @@ QualType ASTNodeImporter::VisitUnaryTransformType(const UnaryTransformType *T) { } QualType ASTNodeImporter::VisitAutoType(const AutoType *T) { - // FIXME: Make sure that the "to" context supports C++0x! + // FIXME: Make sure that the "to" context supports C++11! QualType FromDeduced = T->getDeducedType(); QualType ToDeduced; if (!FromDeduced.isNull()) { @@ -1689,7 +1695,7 @@ QualType ASTNodeImporter::VisitAutoType(const AutoType *T) { return QualType(); } - return Importer.getToContext().getAutoType(ToDeduced); + return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto()); } QualType ASTNodeImporter::VisitRecordType(const RecordType *T) { @@ -3644,6 +3650,7 @@ Decl *ASTNodeImporter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { Iface, Super, Importer.Import(D->getLocation()), Importer.Import(D->getAtStartLoc()), + Importer.Import(D->getSuperClassLoc()), Importer.Import(D->getIvarLBraceLoc()), Importer.Import(D->getIvarRBraceLoc())); diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp index db55c04..68c73fd 100644 --- a/lib/AST/Comment.cpp +++ b/lib/AST/Comment.cpp @@ -134,7 +134,7 @@ void DeclInfo::fill() { IsObjCMethod = false; IsInstanceMethod = false; IsClassMethod = false; - ParamVars = ArrayRef<const ParmVarDecl *>(); + ParamVars = None; TemplateParameters = NULL; if (!CommentDecl) { diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp index 1194520..70410d6 100644 --- a/lib/AST/CommentLexer.cpp +++ b/lib/AST/CommentLexer.cpp @@ -1,5 +1,6 @@ #include "clang/AST/CommentLexer.h" #include "clang/AST/CommentCommandTraits.h" +#include "clang/AST/CommentDiagnostic.h" #include "clang/Basic/CharInfo.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" @@ -353,6 +354,7 @@ void Lexer::lexCommentText(Token &T) { if (!Info) { formTokenWithChars(T, TokenPtr, tok::unknown_command); T.setUnknownCommandName(CommandName); + Diag(T.getLocation(), diag::warn_unknown_comment_command_name); return; } if (Info->IsVerbatimBlockCommand) { @@ -685,10 +687,11 @@ void Lexer::lexHTMLEndTag(Token &T) { State = LS_Normal; } -Lexer::Lexer(llvm::BumpPtrAllocator &Allocator, const CommandTraits &Traits, +Lexer::Lexer(llvm::BumpPtrAllocator &Allocator, DiagnosticsEngine &Diags, + const CommandTraits &Traits, SourceLocation FileLoc, const char *BufferStart, const char *BufferEnd): - Allocator(Allocator), Traits(Traits), + Allocator(Allocator), Diags(Diags), Traits(Traits), BufferStart(BufferStart), BufferEnd(BufferEnd), FileLoc(FileLoc), BufferPtr(BufferStart), CommentState(LCS_BeforeComment), State(LS_Normal) { diff --git a/lib/AST/CommentParser.cpp b/lib/AST/CommentParser.cpp index 09912c6..d89c79b 100644 --- a/lib/AST/CommentParser.cpp +++ b/lib/AST/CommentParser.cpp @@ -302,22 +302,18 @@ void Parser::parseBlockCommandArgs(BlockCommandComment *BC, BlockCommandComment *Parser::parseBlockCommand() { assert(Tok.is(tok::backslash_command) || Tok.is(tok::at_command)); - ParamCommandComment *PC; - TParamCommandComment *TPC; - BlockCommandComment *BC; - bool IsParam = false; - bool IsTParam = false; + ParamCommandComment *PC = 0; + TParamCommandComment *TPC = 0; + BlockCommandComment *BC = 0; const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID()); CommandMarkerKind CommandMarker = Tok.is(tok::backslash_command) ? CMK_Backslash : CMK_At; if (Info->IsParamCommand) { - IsParam = true; PC = S.actOnParamCommandStart(Tok.getLocation(), Tok.getEndLocation(), Tok.getCommandID(), CommandMarker); } else if (Info->IsTParamCommand) { - IsTParam = true; TPC = S.actOnTParamCommandStart(Tok.getLocation(), Tok.getEndLocation(), Tok.getCommandID(), @@ -333,12 +329,11 @@ BlockCommandComment *Parser::parseBlockCommand() { if (isTokBlockCommand()) { // Block command ahead. We can't nest block commands, so pretend that this // command has an empty argument. - ParagraphComment *Paragraph = S.actOnParagraphComment( - ArrayRef<InlineContentComment *>()); - if (IsParam) { + ParagraphComment *Paragraph = S.actOnParagraphComment(None); + if (PC) { S.actOnParamCommandFinish(PC, Paragraph); return PC; - } else if (IsTParam) { + } else if (TPC) { S.actOnTParamCommandFinish(TPC, Paragraph); return TPC; } else { @@ -347,14 +342,14 @@ BlockCommandComment *Parser::parseBlockCommand() { } } - if (IsParam || IsTParam || Info->NumArgs > 0) { + if (PC || TPC || Info->NumArgs > 0) { // In order to parse command arguments we need to retokenize a few // following text tokens. TextTokenRetokenizer Retokenizer(Allocator, *this); - if (IsParam) + if (PC) parseParamCommandArgs(PC, Retokenizer); - else if (IsTParam) + else if (TPC) parseTParamCommandArgs(TPC, Retokenizer); else parseBlockCommandArgs(BC, Retokenizer, Info->NumArgs); @@ -376,7 +371,7 @@ BlockCommandComment *Parser::parseBlockCommand() { ParagraphComment *Paragraph; if (EmptyParagraph) - Paragraph = S.actOnParagraphComment(ArrayRef<InlineContentComment *>()); + Paragraph = S.actOnParagraphComment(None); else { BlockContentComment *Block = parseParagraphOrBlockCommand(); // Since we have checked for a block command, we should have parsed a @@ -384,10 +379,10 @@ BlockCommandComment *Parser::parseBlockCommand() { Paragraph = cast<ParagraphComment>(Block); } - if (IsParam) { + if (PC) { S.actOnParamCommandFinish(PC, Paragraph); return PC; - } else if (IsTParam) { + } else if (TPC) { S.actOnTParamCommandFinish(TPC, Paragraph); return TPC; } else { diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index bf807ae..ab9d73b 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -471,9 +471,16 @@ static bool useInlineVisibilityHidden(const NamedDecl *D) { FD->hasBody(Def) && Def->isInlined() && !Def->hasAttr<GNUInlineAttr>(); } -template <typename T> static bool isInExternCContext(T *D) { +template <typename T> static bool isFirstInExternCContext(T *D) { const T *First = D->getFirstDeclaration(); - return First->getDeclContext()->isExternCContext(); + return First->isInExternCContext(); +} + +static bool isSingleLineExternC(const Decl &D) { + if (const LinkageSpecDecl *SD = dyn_cast<LinkageSpecDecl>(D.getDeclContext())) + if (SD->getLanguage() == LinkageSpecDecl::lang_c && !SD->hasBraces()) + return true; + return false; } static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, @@ -504,7 +511,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, return PrevVar->getLinkageAndVisibility(); if (Var->getStorageClass() != SC_Extern && - Var->getStorageClass() != SC_PrivateExtern) + Var->getStorageClass() != SC_PrivateExtern && + !isSingleLineExternC(*Var)) return LinkageInfo::internal(); } @@ -540,8 +548,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, if (D->isInAnonymousNamespace()) { const VarDecl *Var = dyn_cast<VarDecl>(D); const FunctionDecl *Func = dyn_cast<FunctionDecl>(D); - if ((!Var || !isInExternCContext(Var)) && - (!Func || !isInExternCContext(Func))) + if ((!Var || !isFirstInExternCContext(Var)) && + (!Func || !isFirstInExternCContext(Func))) return LinkageInfo::uniqueExternal(); } @@ -618,7 +626,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // // Note that we don't want to make the variable non-external // because of this, but unique-external linkage suits us. - if (Context.getLangOpts().CPlusPlus && !isInExternCContext(Var)) { + if (Context.getLangOpts().CPlusPlus && !isFirstInExternCContext(Var)) { LinkageInfo TypeLV = Var->getType()->getLinkageAndVisibility(); if (TypeLV.getLinkage() != ExternalLinkage) return LinkageInfo::uniqueExternal(); @@ -652,7 +660,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // this translation unit. However, we should use the C linkage // rules instead for extern "C" declarations. if (Context.getLangOpts().CPlusPlus && - !Function->getDeclContext()->isExternCContext() && + !Function->isInExternCContext() && Function->getType()->getLinkage() == UniqueExternalLinkage) return LinkageInfo::uniqueExternal(); @@ -866,10 +874,6 @@ bool NamedDecl::isLinkageValid() const { Linkage(CachedLinkage); } -bool NamedDecl::hasExternalLinkageUncached() const { - return getLVForDecl(this, LVForExplicitValue).getLinkage() == ExternalLinkage; -} - Linkage NamedDecl::getLinkage() const { if (HasCachedLinkage) return Linkage(CachedLinkage); @@ -993,7 +997,7 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D, LVComputationKind computation) { if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { if (Function->isInAnonymousNamespace() && - !Function->getDeclContext()->isExternCContext()) + !Function->isInExternCContext()) return LinkageInfo::uniqueExternal(); // This is a "void f();" which got merged with a file static. @@ -1016,8 +1020,7 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D, if (const VarDecl *Var = dyn_cast<VarDecl>(D)) { if (Var->hasExternalStorage()) { - if (Var->isInAnonymousNamespace() && - !Var->getDeclContext()->isExternCContext()) + if (Var->isInAnonymousNamespace() && !Var->isInExternCContext()) return LinkageInfo::uniqueExternal(); LinkageInfo LV; @@ -1297,7 +1300,7 @@ bool NamedDecl::isCXXInstanceMember() const { if (isa<UsingShadowDecl>(D)) D = cast<UsingShadowDecl>(D)->getTargetDecl(); - if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D)) + if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D) || isa<MSPropertyDecl>(D)) return true; if (isa<CXXMethodDecl>(D)) return cast<CXXMethodDecl>(D)->isInstance(); @@ -1518,8 +1521,7 @@ static LanguageLinkage getLanguageLinkageTemplate(const T &D) { // If the first decl is in an extern "C" context, any other redeclaration // will have C language linkage. If the first one is not in an extern "C" // context, we would have reported an error for any other decl being in one. - const T *First = D.getFirstDeclaration(); - if (First->getDeclContext()->isExternCContext()) + if (isFirstInExternCContext(&D)) return CLanguageLinkage; return CXXLanguageLinkage; } @@ -1545,6 +1547,29 @@ bool VarDecl::isExternC() const { return isExternCTemplate(*this); } +static bool isLinkageSpecContext(const DeclContext *DC, + LinkageSpecDecl::LanguageIDs ID) { + while (DC->getDeclKind() != Decl::TranslationUnit) { + if (DC->getDeclKind() == Decl::LinkageSpec) + return cast<LinkageSpecDecl>(DC)->getLanguage() == ID; + DC = DC->getParent(); + } + return false; +} + +template <typename T> +static bool isInLanguageSpecContext(T *D, LinkageSpecDecl::LanguageIDs ID) { + return isLinkageSpecContext(D->getLexicalDeclContext(), ID); +} + +bool VarDecl::isInExternCContext() const { + return isInLanguageSpecContext(this, LinkageSpecDecl::lang_c); +} + +bool VarDecl::isInExternCXXContext() const { + return isInLanguageSpecContext(this, LinkageSpecDecl::lang_cxx); +} + VarDecl *VarDecl::getCanonicalDecl() { return getFirstDeclaration(); } @@ -1576,17 +1601,17 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition( // initializer, the declaration is an external definition for the identifier if (hasInit()) return Definition; - // AST for 'extern "C" int foo;' is annotated with 'extern'. + if (hasExternalStorage()) return DeclarationOnly; - if (hasExternalStorage()) { - for (const VarDecl *PrevVar = getPreviousDecl(); - PrevVar; PrevVar = PrevVar->getPreviousDecl()) { - if (PrevVar->getLinkage() == InternalLinkage) - return DeclarationOnly; - } - } + // [dcl.link] p7: + // A declaration directly contained in a linkage-specification is treated + // as if it contains the extern specifier for the purpose of determining + // the linkage of the declared name and whether it is a definition. + if (isSingleLineExternC(*this)) + return DeclarationOnly; + // C99 6.9.2p2: // A declaration of an object that has file scope without an initializer, // and without a storage class specifier or the scs 'static', constitutes @@ -1896,6 +1921,11 @@ SourceRange ParmVarDecl::getSourceRange() const { return SourceRange(getOuterLocStart(), ArgRange.getEnd()); } + // DeclaratorDecl considers the range of postfix types as overlapping with the + // declaration name, but this is not the case with parameters in ObjC methods. + if (isa<ObjCMethodDecl>(getDeclContext())) + return SourceRange(DeclaratorDecl::getLocStart(), getLocation()); + return DeclaratorDecl::getSourceRange(); } @@ -2061,6 +2091,14 @@ bool FunctionDecl::isExternC() const { return isExternCTemplate(*this); } +bool FunctionDecl::isInExternCContext() const { + return isInLanguageSpecContext(this, LinkageSpecDecl::lang_c); +} + +bool FunctionDecl::isInExternCXXContext() const { + return isInLanguageSpecContext(this, LinkageSpecDecl::lang_cxx); +} + bool FunctionDecl::isGlobal() const { if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(this)) return Method->isStatic(); @@ -3230,6 +3268,27 @@ BlockDecl *BlockDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (Mem) BlockDecl(0, SourceLocation()); } +MSPropertyDecl *MSPropertyDecl::CreateDeserialized(ASTContext &C, + unsigned ID) { + void *Mem = AllocateDeserializedDecl(C, ID, sizeof(MSPropertyDecl)); + return new (Mem) MSPropertyDecl(0, SourceLocation(), DeclarationName(), + QualType(), 0, SourceLocation(), + 0, 0); +} + +CapturedDecl *CapturedDecl::Create(ASTContext &C, DeclContext *DC, + unsigned NumParams) { + unsigned Size = sizeof(CapturedDecl) + NumParams * sizeof(ImplicitParamDecl*); + return new (C.Allocate(Size)) CapturedDecl(DC, NumParams); +} + +CapturedDecl *CapturedDecl::CreateDeserialized(ASTContext &C, unsigned ID, + unsigned NumParams) { + unsigned Size = sizeof(CapturedDecl) + NumParams * sizeof(ImplicitParamDecl*); + void *Mem = AllocateDeserializedDecl(C, ID, Size); + return new (Mem) CapturedDecl(0, NumParams); +} + EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD, SourceLocation L, IdentifierInfo *Id, QualType T, @@ -3399,7 +3458,7 @@ ImportDecl *ImportDecl::CreateDeserialized(ASTContext &C, unsigned ID, ArrayRef<SourceLocation> ImportDecl::getIdentifierLocs() const { if (!ImportedAndComplete.getInt()) - return ArrayRef<SourceLocation>(); + return None; const SourceLocation *StoredLocs = reinterpret_cast<const SourceLocation *>(this + 1); diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index bd6d99c..084a432 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -493,6 +493,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case NonTypeTemplateParm: case ObjCMethod: case ObjCProperty: + case MSProperty: return IDNS_Ordinary; case Label: return IDNS_Label; @@ -552,6 +553,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case StaticAssert: case ObjCPropertyImpl: case Block: + case Captured: case TranslationUnit: case UsingDirective: @@ -702,21 +704,37 @@ void Decl::CheckAccessDeclContext() const { #endif } -DeclContext *Decl::getNonClosureContext() { - return getDeclContext()->getNonClosureAncestor(); +static Decl::Kind getKind(const Decl *D) { return D->getKind(); } +static Decl::Kind getKind(const DeclContext *DC) { return DC->getDeclKind(); } + +/// Starting at a given context (a Decl or DeclContext), look for a +/// code context that is not a closure (a lambda, block, etc.). +template <class T> static Decl *getNonClosureContext(T *D) { + if (getKind(D) == Decl::CXXMethod) { + CXXMethodDecl *MD = cast<CXXMethodDecl>(D); + if (MD->getOverloadedOperator() == OO_Call && + MD->getParent()->isLambda()) + return getNonClosureContext(MD->getParent()->getParent()); + return MD; + } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + return FD; + } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + return MD; + } else if (BlockDecl *BD = dyn_cast<BlockDecl>(D)) { + return getNonClosureContext(BD->getParent()); + } else if (CapturedDecl *CD = dyn_cast<CapturedDecl>(D)) { + return getNonClosureContext(CD->getParent()); + } else { + return 0; + } } -DeclContext *DeclContext::getNonClosureAncestor() { - DeclContext *DC = this; - - // This is basically "while (DC->isClosure()) DC = DC->getParent();" - // except that it's significantly more efficient to cast to a known - // decl type and call getDeclContext() than to call getParent(). - while (isa<BlockDecl>(DC)) - DC = cast<BlockDecl>(DC)->getDeclContext(); +Decl *Decl::getNonClosureContext() { + return ::getNonClosureContext(this); +} - assert(!DC->isClosure()); - return DC; +Decl *DeclContext::getNonClosureAncestor() { + return ::getNonClosureContext(this); } //===----------------------------------------------------------------------===// @@ -801,28 +819,6 @@ bool DeclContext::isTransparentContext() const { return false; } -bool DeclContext::isExternCContext() const { - const DeclContext *DC = this; - while (DC->DeclKind != Decl::TranslationUnit) { - if (DC->DeclKind == Decl::LinkageSpec) - return cast<LinkageSpecDecl>(DC)->getLanguage() - == LinkageSpecDecl::lang_c; - DC = DC->getParent(); - } - return false; -} - -bool DeclContext::isExternCXXContext() const { - const DeclContext *DC = this; - while (DC->DeclKind != Decl::TranslationUnit) { - if (DC->DeclKind == Decl::LinkageSpec) - return cast<LinkageSpecDecl>(DC)->getLanguage() - == LinkageSpecDecl::lang_cxx; - DC = DC->getParent(); - } - return false; -} - bool DeclContext::Encloses(const DeclContext *DC) const { if (getPrimaryContext() != this) return getPrimaryContext()->Encloses(DC); @@ -838,6 +834,7 @@ DeclContext *DeclContext::getPrimaryContext() { case Decl::TranslationUnit: case Decl::LinkageSpec: case Decl::Block: + case Decl::Captured: // There is only one DeclContext for these entities. return this; @@ -1045,6 +1042,11 @@ bool DeclContext::decls_empty() const { return !FirstDecl; } +bool DeclContext::containsDecl(Decl *D) const { + return (D->getLexicalDeclContext() == this && + (D->NextInContextAndBits.getPointer() || D == LastDecl)); +} + void DeclContext::removeDecl(Decl *D) { assert(D->getLexicalDeclContext() == this && "decl being removed from non-lexical context"); diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index ffad9ae..0646499 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -186,7 +186,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, data().IsStandardLayout = false; // Record if this base is the first non-literal field or base. - if (!hasNonLiteralTypeFieldsOrBases() && !BaseType->isLiteralType()) + if (!hasNonLiteralTypeFieldsOrBases() && !BaseType->isLiteralType(C)) data().HasNonLiteralTypeFieldsOrBases = true; // Now go through all virtual bases of this base and add them. @@ -505,7 +505,7 @@ void CXXRecordDecl::addedMember(Decl *D) { // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class with no user-declared // constructors [...]. - // C++0x [dcl.init.aggr]p1: + // C++11 [dcl.init.aggr]p1: // An aggregate is an array or a class with no user-provided // constructors [...]. if (getASTContext().getLangOpts().CPlusPlus11 @@ -542,22 +542,28 @@ void CXXRecordDecl::addedMember(Decl *D) { // Keep the list of conversion functions up-to-date. if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) { - // FIXME: 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. + // FIXME: We use the 'unsafe' accessor for the access specifier here, + // because Sema may not have set it yet. That's really just a misdesign + // in Sema. However, LLDB *will* have set the access specifier correctly, + // and adds declarations after the class is technically completed, + // so completeDefinition()'s overriding of the access specifiers doesn't + // work. + AccessSpecifier AS = Conversion->getAccessUnsafe(); + if (Conversion->getPrimaryTemplate()) { // We don't record specializations. } else if (FunTmpl) { if (FunTmpl->getPreviousDecl()) data().Conversions.replace(FunTmpl->getPreviousDecl(), - FunTmpl); + FunTmpl, AS); else - data().Conversions.addDecl(getASTContext(), FunTmpl); + data().Conversions.addDecl(getASTContext(), FunTmpl, AS); } else { if (Conversion->getPreviousDecl()) data().Conversions.replace(Conversion->getPreviousDecl(), - Conversion); + Conversion, AS); else - data().Conversions.addDecl(getASTContext(), Conversion); + data().Conversions.addDecl(getASTContext(), Conversion, AS); } } @@ -670,7 +676,7 @@ void CXXRecordDecl::addedMember(Decl *D) { } // Record if this field is the first non-literal or volatile field or base. - if (!T->isLiteralType() || T.isVolatileQualified()) + if (!T->isLiteralType(Context) || T.isVolatileQualified()) data().HasNonLiteralTypeFieldsOrBases = true; if (Field->hasInClassInitializer()) { @@ -684,7 +690,10 @@ void CXXRecordDecl::addedMember(Decl *D) { // C++11 [dcl.init.aggr]p1: // An aggregate is a [...] class with [...] no // brace-or-equal-initializers for non-static data members. - data().Aggregate = false; + // + // This rule was removed in C++1y. + if (!getASTContext().getLangOpts().CPlusPlus1y) + data().Aggregate = false; // C++11 [class]p10: // A POD struct is [...] a trivial class. @@ -836,7 +845,7 @@ void CXXRecordDecl::addedMember(Decl *D) { } } else { // Base element type of field is a non-class type. - if (!T->isLiteralType() || + if (!T->isLiteralType(Context) || (!Field->hasInClassInitializer() && !isUnion())) data().DefaultedDefaultConstructorIsConstexpr = false; @@ -1252,20 +1261,7 @@ bool CXXRecordDecl::mayBeAbstract() const { void CXXMethodDecl::anchor() { } bool CXXMethodDecl::isStatic() const { - const CXXMethodDecl *MD = this; - for (;;) { - const CXXMethodDecl *C = MD->getCanonicalDecl(); - if (C != MD) { - MD = C; - continue; - } - - FunctionTemplateSpecializationInfo *Info = - MD->getTemplateSpecializationInfo(); - if (!Info) - break; - MD = cast<CXXMethodDecl>(Info->getTemplate()->getTemplatedDecl()); - } + const CXXMethodDecl *MD = getCanonicalDecl(); if (MD->getStorageClass() == SC_Static) return true; @@ -1820,14 +1816,14 @@ LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C, SourceLocation ExternLoc, SourceLocation LangLoc, LanguageIDs Lang, - SourceLocation RBraceLoc) { - return new (C) LinkageSpecDecl(DC, ExternLoc, LangLoc, Lang, RBraceLoc); + bool HasBraces) { + return new (C) LinkageSpecDecl(DC, ExternLoc, LangLoc, Lang, HasBraces); } LinkageSpecDecl *LinkageSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(LinkageSpecDecl)); return new (Mem) LinkageSpecDecl(0, SourceLocation(), SourceLocation(), - lang_c, SourceLocation()); + lang_c, false); } void UsingDirectiveDecl::anchor() { } diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 5f5ba52..4ddbb22 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -443,9 +443,12 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass( /// lookupMethod - This method returns an instance/class method by looking in /// the class, its categories, and its super classes (using a linear search). +/// When argument category "C" is specified, any implicit method found +/// in this category is ignored. ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel, bool isInstance, - bool shallowCategoryLookup) const { + bool shallowCategoryLookup, + const ObjCCategoryDecl *C) const { // FIXME: Should make sure no callers ever do this. if (!hasDefinition()) return 0; @@ -469,20 +472,22 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel, // Didn't find one yet - now look through categories. for (ObjCInterfaceDecl::visible_categories_iterator - Cat = ClassDecl->visible_categories_begin(), - CatEnd = ClassDecl->visible_categories_end(); + Cat = ClassDecl->visible_categories_begin(), + CatEnd = ClassDecl->visible_categories_end(); Cat != CatEnd; ++Cat) { if ((MethodDecl = Cat->getMethod(Sel, isInstance))) - return MethodDecl; + if (C != (*Cat) || !MethodDecl->isImplicit()) + return MethodDecl; if (!shallowCategoryLookup) { // Didn't find one yet - look through protocols. const ObjCList<ObjCProtocolDecl> &Protocols = - Cat->getReferencedProtocols(); + Cat->getReferencedProtocols(); for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance))) - return MethodDecl; + if (C != (*Cat) || !MethodDecl->isImplicit()) + return MethodDecl; } } @@ -599,12 +604,12 @@ void ObjCMethodDecl::setMethodParams(ASTContext &C, assert((!SelLocs.empty() || isImplicit()) && "No selector locs for non-implicit method"); if (isImplicit()) - return setParamsAndSelLocs(C, Params, ArrayRef<SourceLocation>()); + return setParamsAndSelLocs(C, Params, llvm::None); SelLocsKind = hasStandardSelectorLocs(getSelector(), SelLocs, Params, DeclEndLoc); if (SelLocsKind != SelLoc_NonStandard) - return setParamsAndSelLocs(C, Params, ArrayRef<SourceLocation>()); + return setParamsAndSelLocs(C, Params, llvm::None); setParamsAndSelLocs(C, Params, SelLocs); } @@ -959,52 +964,6 @@ static void collectOverriddenMethodsSlow(const ObjCMethodDecl *Method, } } -static void collectOnCategoriesAfterLocation(SourceLocation Loc, - const ObjCInterfaceDecl *Class, - SourceManager &SM, - const ObjCMethodDecl *Method, - SmallVectorImpl<const ObjCMethodDecl *> &Methods) { - if (!Class) - return; - - for (ObjCInterfaceDecl::known_categories_iterator - Cat = Class->known_categories_begin(), - CatEnd = Class->known_categories_end(); - Cat != CatEnd; ++Cat) { - if (SM.isBeforeInTranslationUnit(Loc, Cat->getLocation())) - CollectOverriddenMethodsRecurse(*Cat, Method, Methods, true); - } - - collectOnCategoriesAfterLocation(Loc, Class->getSuperClass(), SM, - Method, Methods); -} - -/// \brief Faster collection that is enabled when ObjCMethodDecl::isOverriding() -/// returns false. -/// You'd think that in that case there are no overrides but categories can -/// "introduce" new overridden methods that are missed by Sema because the -/// overrides lookup that it does for methods, inside implementations, will -/// stop at the interface level (if there is a method there) and not look -/// further in super classes. -/// Methods in an implementation can overide methods in super class's category -/// but not in current class's category. But, such methods -static void collectOverriddenMethodsFast(SourceManager &SM, - const ObjCMethodDecl *Method, - SmallVectorImpl<const ObjCMethodDecl *> &Methods) { - assert(!Method->isOverriding()); - - const ObjCContainerDecl * - ContD = cast<ObjCContainerDecl>(Method->getDeclContext()); - if (isa<ObjCInterfaceDecl>(ContD) || isa<ObjCProtocolDecl>(ContD)) - return; - const ObjCInterfaceDecl *Class = Method->getClassInterface(); - if (!Class) - return; - - collectOnCategoriesAfterLocation(Class->getLocation(), Class->getSuperClass(), - SM, Method, Methods); -} - void ObjCMethodDecl::getOverriddenMethods( SmallVectorImpl<const ObjCMethodDecl *> &Overridden) const { const ObjCMethodDecl *Method = this; @@ -1014,10 +973,7 @@ void ObjCMethodDecl::getOverriddenMethods( getMethod(Method->getSelector(), Method->isInstanceMethod()); } - if (!Method->isOverriding()) { - collectOverriddenMethodsFast(getASTContext().getSourceManager(), - Method, Overridden); - } else { + if (Method->isOverriding()) { collectOverriddenMethodsSlow(Method, Overridden); assert(!Overridden.empty() && "ObjCMethodDecl's overriding bit is not as expected"); @@ -1692,12 +1648,13 @@ ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC, ObjCInterfaceDecl *SuperDecl, SourceLocation nameLoc, SourceLocation atStartLoc, + SourceLocation superLoc, SourceLocation IvarLBraceLoc, SourceLocation IvarRBraceLoc) { if (ClassInterface && ClassInterface->hasDefinition()) ClassInterface = ClassInterface->getDefinition(); return new (C) ObjCImplementationDecl(DC, ClassInterface, SuperDecl, - nameLoc, atStartLoc, + nameLoc, atStartLoc, superLoc, IvarLBraceLoc, IvarRBraceLoc); } diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index c3bf8f8..d47972b 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -487,7 +487,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(), E = CDecl->init_end(); B != E; ++B) { - CXXCtorInitializer * BMInitializer = (*B); + CXXCtorInitializer *BMInitializer = (*B); if (BMInitializer->isInClassMemberInitializer()) continue; @@ -617,7 +617,8 @@ void DeclPrinter::VisitFieldDecl(FieldDecl *D) { if (!Policy.SuppressSpecifiers && D->isModulePrivate()) Out << "__module_private__ "; - Out << D->getType().stream(Policy, D->getName()); + Out << D->getASTContext().getUnqualifiedObjCPointerType(D->getType()). + stream(Policy, D->getName()); if (D->isBitField()) { Out << " : "; @@ -641,16 +642,30 @@ void DeclPrinter::VisitLabelDecl(LabelDecl *D) { void DeclPrinter::VisitVarDecl(VarDecl *D) { - StorageClass SC = D->getStorageClass(); - if (!Policy.SuppressSpecifiers && SC != SC_None) - Out << VarDecl::getStorageClassSpecifierString(SC) << " "; + if (!Policy.SuppressSpecifiers) { + StorageClass SC = D->getStorageClass(); + if (SC != SC_None) + Out << VarDecl::getStorageClassSpecifierString(SC) << " "; - if (!Policy.SuppressSpecifiers && D->isThreadSpecified()) - Out << "__thread "; - if (!Policy.SuppressSpecifiers && D->isModulePrivate()) - Out << "__module_private__ "; + switch (D->getTSCSpec()) { + case TSCS_unspecified: + break; + case TSCS___thread: + Out << "__thread "; + break; + case TSCS__Thread_local: + Out << "_Thread_local "; + break; + case TSCS_thread_local: + Out << "thread_local "; + break; + } + + if (D->isModulePrivate()) + Out << "__module_private__ "; + } - QualType T = D->getType(); + QualType T = D->getASTContext().getUnqualifiedObjCPointerType(D->getType()); if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) T = Parm->getOriginalType(); T.print(Out, Policy, D->getName()); @@ -899,7 +914,8 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) { else Out << "+ "; if (!OMD->getResultType().isNull()) - Out << '(' << OMD->getResultType().getAsString(Policy) << ")"; + Out << '(' << OMD->getASTContext().getUnqualifiedObjCPointerType(OMD->getResultType()). + getAsString(Policy) << ")"; std::string name = OMD->getSelector().getAsString(); std::string::size_type pos, lastPos = 0; @@ -908,7 +924,8 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) { // FIXME: selector is missing here! pos = name.find_first_of(':', lastPos); Out << " " << name.substr(lastPos, pos - lastPos); - Out << ":(" << (*PI)->getType().getAsString(Policy) << ')' << **PI; + Out << ":(" << (*PI)->getASTContext().getUnqualifiedObjCPointerType((*PI)->getType()). + getAsString(Policy) << ')' << **PI; lastPos = pos + 1; } @@ -941,7 +958,8 @@ void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) { Indentation += Policy.Indentation; for (ObjCImplementationDecl::ivar_iterator I = OID->ivar_begin(), E = OID->ivar_end(); I != E; ++I) { - Indent() << I->getType().getAsString(Policy) << ' ' << **I << ";\n"; + Indent() << I->getASTContext().getUnqualifiedObjCPointerType(I->getType()). + getAsString(Policy) << ' ' << **I << ";\n"; } Indentation -= Policy.Indentation; Out << "}\n"; @@ -979,7 +997,8 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { Indentation += Policy.Indentation; for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(), E = OID->ivar_end(); I != E; ++I) { - Indent() << I->getType().getAsString(Policy) << ' ' << **I << ";\n"; + Indent() << I->getASTContext().getUnqualifiedObjCPointerType(I->getType()). + getAsString(Policy) << ' ' << **I << ";\n"; } Indentation -= Policy.Indentation; Out << "}\n"; @@ -1030,7 +1049,8 @@ void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) { Indentation += Policy.Indentation; for (ObjCCategoryDecl::ivar_iterator I = PID->ivar_begin(), E = PID->ivar_end(); I != E; ++I) { - Indent() << I->getType().getAsString(Policy) << ' ' << **I << ";\n"; + Indent() << I->getASTContext().getUnqualifiedObjCPointerType(I->getType()). + getAsString(Policy) << ' ' << **I << ";\n"; } Indentation -= Policy.Indentation; Out << "}\n"; @@ -1116,7 +1136,8 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { (void) first; // Silence dead store warning due to idiomatic code. Out << " )"; } - Out << ' ' << PDecl->getType().getAsString(Policy) << ' ' << *PDecl; + Out << ' ' << PDecl->getASTContext().getUnqualifiedObjCPointerType(PDecl->getType()). + getAsString(Policy) << ' ' << *PDecl; if (Policy.PolishForDeclaration) Out << ';'; } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index b97f4d1..9538ddf 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -100,11 +100,20 @@ Expr::skipRValueSubobjectAdjustments( const Expr * Expr::findMaterializedTemporary(const MaterializeTemporaryExpr *&MTE) const { const Expr *E = this; + + // This might be a default initializer for a reference member. Walk over the + // wrapper node for that. + if (const CXXDefaultInitExpr *DAE = dyn_cast<CXXDefaultInitExpr>(E)) + E = DAE->getExpr(); + // Look through single-element init lists that claim to be lvalues. They're // just syntactic wrappers in this case. if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) { - if (ILE->getNumInits() == 1 && ILE->isGLValue()) + if (ILE->getNumInits() == 1 && ILE->isGLValue()) { E = ILE->getInit(0); + if (const CXXDefaultInitExpr *DAE = dyn_cast<CXXDefaultInitExpr>(E)) + E = DAE->getExpr(); + } } // Look through expressions for materialized temporaries (for now). @@ -280,7 +289,7 @@ static void computeDeclRefDependence(ASTContext &Ctx, NamedDecl *D, QualType T, // expression that is value-dependent [C++11] if (VarDecl *Var = dyn_cast<VarDecl>(D)) { if ((Ctx.getLangOpts().CPlusPlus11 ? - Var->getType()->isLiteralType() : + Var->getType()->isLiteralType(Ctx) : Var->getType()->isIntegralOrEnumerationType()) && (Var->getType().isConstQualified() || Var->getType()->isReferenceType())) { @@ -2174,6 +2183,9 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, case CXXDefaultArgExprClass: return (cast<CXXDefaultArgExpr>(this) ->getExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx)); + case CXXDefaultInitExprClass: + return (cast<CXXDefaultInitExpr>(this) + ->getExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx)); case CXXNewExprClass: // FIXME: In theory, there might be new expressions that don't have side @@ -2789,6 +2801,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { return false; case CallExprClass: + case MSPropertyRefExprClass: case CompoundAssignOperatorClass: case VAArgExprClass: case AtomicExprClass: @@ -2850,6 +2863,12 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { case CXXDefaultArgExprClass: return cast<CXXDefaultArgExpr>(this)->getExpr()->HasSideEffects(Ctx); + case CXXDefaultInitExprClass: + if (const Expr *E = cast<CXXDefaultInitExpr>(this)->getExpr()) + return E->HasSideEffects(Ctx); + // If we've not yet parsed the initializer, assume it has side-effects. + return true; + case CXXDynamicCastExprClass: { // A dynamic_cast expression has side-effects if it can throw. const CXXDynamicCastExpr *DCE = cast<CXXDynamicCastExpr>(this); @@ -3037,8 +3056,12 @@ Expr::isNullPointerConstant(ASTContext &Ctx, return GE->getResultExpr()->isNullPointerConstant(Ctx, NPC); } else if (const CXXDefaultArgExpr *DefaultArg = dyn_cast<CXXDefaultArgExpr>(this)) { - // See through default argument expressions + // See through default argument expressions. return DefaultArg->getExpr()->isNullPointerConstant(Ctx, NPC); + } else if (const CXXDefaultInitExpr *DefaultInit + = dyn_cast<CXXDefaultInitExpr>(this)) { + // See through default initializer expressions. + return DefaultInit->getExpr()->isNullPointerConstant(Ctx, NPC); } else if (isa<GNUNullExpr>(this)) { // The GNU __null extension is always a null pointer constant. return NPCK_GNUNull; @@ -3126,7 +3149,7 @@ bool Expr::isObjCSelfExpr() const { return M->getSelfDecl() == Param; } -FieldDecl *Expr::getBitField() { +FieldDecl *Expr::getSourceBitField() { Expr *E = this->IgnoreParens(); while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { @@ -3142,6 +3165,11 @@ FieldDecl *Expr::getBitField() { if (Field->isBitField()) return Field; + if (ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) + if (FieldDecl *Ivar = dyn_cast<FieldDecl>(IvarRef->getDecl())) + if (Ivar->isBitField()) + return Ivar; + if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E)) if (FieldDecl *Field = dyn_cast<FieldDecl>(DeclRef->getDecl())) if (Field->isBitField()) @@ -3149,10 +3177,10 @@ FieldDecl *Expr::getBitField() { if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(E)) { if (BinOp->isAssignmentOp() && BinOp->getLHS()) - return BinOp->getLHS()->getBitField(); + return BinOp->getLHS()->getSourceBitField(); if (BinOp->getOpcode() == BO_Comma && BinOp->getRHS()) - return BinOp->getRHS()->getBitField(); + return BinOp->getRHS()->getSourceBitField(); } return 0; diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 12a47fc..402d7b5 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -178,8 +178,7 @@ CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(ASTContext &Context, SourceLocation ColonColonLoc, SourceLocation TildeLoc, PseudoDestructorTypeStorage DestroyedType) : Expr(CXXPseudoDestructorExprClass, - Context.getPointerType(Context.getFunctionType(Context.VoidTy, - ArrayRef<QualType>(), + Context.getPointerType(Context.getFunctionType(Context.VoidTy, None, FunctionProtoType::ExtProtoInfo())), VK_RValue, OK_Ordinary, /*isTypeDependent=*/(Base->isTypeDependent() || @@ -704,6 +703,17 @@ CXXDefaultArgExpr::Create(ASTContext &C, SourceLocation Loc, SubExpr); } +CXXDefaultInitExpr::CXXDefaultInitExpr(ASTContext &C, SourceLocation Loc, + FieldDecl *Field, QualType T) + : Expr(CXXDefaultInitExprClass, T.getNonLValueExprType(C), + T->isLValueReferenceType() ? VK_LValue : T->isRValueReferenceType() + ? VK_XValue + : VK_RValue, + /*FIXME*/ OK_Ordinary, false, false, false, false), + Field(Field), Loc(Loc) { + assert(Field->hasInClassInitializer()); +} + CXXTemporary *CXXTemporary::Create(ASTContext &C, const CXXDestructorDecl *Destructor) { return new (C) CXXTemporary(Destructor); diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index 61bc3e2..bcb6d4e 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -134,6 +134,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { // FIXME: ObjC++0x might have different rules case Expr::ObjCIvarRefExprClass: case Expr::FunctionParmPackExprClass: + case Expr::MSPropertyRefExprClass: return Cl::CL_LValue; // C99 6.5.2.5p5 says that compound literals are lvalues. @@ -297,6 +298,10 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::CXXDefaultArgExprClass: return ClassifyInternal(Ctx, cast<CXXDefaultArgExpr>(E)->getExpr()); + // Same idea for default initializers. + case Expr::CXXDefaultInitExprClass: + return ClassifyInternal(Ctx, cast<CXXDefaultInitExpr>(E)->getExpr()); + // Same idea for temporary binding. case Expr::CXXBindTemporaryExprClass: return ClassifyInternal(Ctx, cast<CXXBindTemporaryExpr>(E)->getSubExpr()); diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index ae86150..8c65029 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -286,21 +286,37 @@ namespace { /// ParmBindings - Parameter bindings for this function call, indexed by /// parameters' function scope indices. - const APValue *Arguments; + APValue *Arguments; // Note that we intentionally use std::map here so that references to // values are stable. - typedef std::map<const Expr*, APValue> MapTy; + typedef std::map<const void*, APValue> MapTy; typedef MapTy::const_iterator temp_iterator; /// Temporaries - Temporary lvalues materialized within this stack frame. MapTy Temporaries; CallStackFrame(EvalInfo &Info, SourceLocation CallLoc, const FunctionDecl *Callee, const LValue *This, - const APValue *Arguments); + APValue *Arguments); ~CallStackFrame(); }; + /// Temporarily override 'this'. + class ThisOverrideRAII { + public: + ThisOverrideRAII(CallStackFrame &Frame, const LValue *NewThis, bool Enable) + : Frame(Frame), OldThis(Frame.This) { + if (Enable) + Frame.This = NewThis; + } + ~ThisOverrideRAII() { + Frame.This = OldThis; + } + private: + CallStackFrame &Frame; + const LValue *OldThis; + }; + /// A partial diagnostic which we might know in advance that we are not going /// to emit. class OptionalDiagnostic { @@ -581,7 +597,7 @@ void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info, CallStackFrame::CallStackFrame(EvalInfo &Info, SourceLocation CallLoc, const FunctionDecl *Callee, const LValue *This, - const APValue *Arguments) + APValue *Arguments) : Info(Info), Caller(Info.CurrentCall), CallLoc(CallLoc), Callee(Callee), Index(Info.NextCallIndex++), This(This), Arguments(Arguments) { Info.CurrentCall = this; @@ -897,6 +913,18 @@ static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info); // Misc utilities //===----------------------------------------------------------------------===// +/// Evaluate an expression to see if it had side-effects, and discard its +/// result. +/// \return \c true if the caller should keep evaluating. +static bool EvaluateIgnoredValue(EvalInfo &Info, const Expr *E) { + APValue Scratch; + if (!Evaluate(Scratch, Info, E)) { + Info.EvalStatus.HasSideEffects = true; + return Info.keepEvaluatingAfterFailure(); + } + return true; +} + /// Should this call expression be treated as a string literal? static bool IsStringLiteralCall(const CallExpr *E) { unsigned Builtin = E->isBuiltinCall(); @@ -999,7 +1027,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, // Check if this is a thread-local variable. if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) { if (const VarDecl *Var = dyn_cast<const VarDecl>(VD)) { - if (Var->isThreadSpecified()) + if (Var->getTLSKind()) return false; } } @@ -1030,7 +1058,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, /// Check that this core constant expression is of literal type, and if not, /// produce an appropriate diagnostic. static bool CheckLiteralType(EvalInfo &Info, const Expr *E) { - if (!E->isRValue() || E->getType()->isLiteralType()) + if (!E->isRValue() || E->getType()->isLiteralType(Info.Ctx)) return true; // Prvalue constant expressions must be of literal types. @@ -1427,9 +1455,16 @@ static bool HandleLValueComplexElement(EvalInfo &Info, const Expr *E, } /// Try to evaluate the initializer for a variable declaration. -static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E, - const VarDecl *VD, - CallStackFrame *Frame, APValue &Result) { +/// +/// \param Info Information about the ongoing evaluation. +/// \param E An expression to be used when printing diagnostics. +/// \param VD The variable whose initializer should be obtained. +/// \param Frame The frame in which the variable was created. Must be null +/// if this variable is not local to the evaluation. +/// \param Result Filled in with a pointer to the value of the variable. +static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, + const VarDecl *VD, CallStackFrame *Frame, + APValue *&Result) { // If this is a parameter to an active constexpr function call, perform // argument substitution. if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD)) { @@ -1441,10 +1476,19 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E, Info.Diag(E, diag::note_invalid_subexpr_in_const_expr); return false; } - Result = Frame->Arguments[PVD->getFunctionScopeIndex()]; + Result = &Frame->Arguments[PVD->getFunctionScopeIndex()]; return true; } + // If this is a local variable, dig out its value. + if (Frame) { + Result = &Frame->Temporaries[VD]; + // If we've carried on past an unevaluatable local variable initializer, + // we can't go any further. This can happen during potential constant + // expression checking. + return !Result->isUninit(); + } + // Dig out the initializer, and use the declaration which it's attached to. const Expr *Init = VD->getAnyInitializer(VD); if (!Init || Init->isValueDependent()) { @@ -1458,8 +1502,8 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E, // If we're currently evaluating the initializer of this declaration, use that // in-flight value. if (Info.EvaluatingDecl == VD) { - Result = *Info.EvaluatingDeclValue; - return !Result.isUninit(); + Result = Info.EvaluatingDeclValue; + return !Result->isUninit(); } // Never evaluate the initializer of a weak variable. We can't be sure that @@ -1485,7 +1529,7 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E, Info.addNotes(Notes); } - Result = *VD->getEvaluatedValue(); + Result = VD->getEvaluatedValue(); return true; } @@ -1509,15 +1553,15 @@ static unsigned getBaseIndex(const CXXRecordDecl *Derived, llvm_unreachable("base class missing from derived class's bases list"); } -/// Extract the value of a character from a string literal. CharType is used to -/// determine the expected signedness of the result -- a string literal used to -/// initialize an array of 'signed char' or 'unsigned char' might contain chars -/// of the wrong signedness. -static APSInt ExtractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit, - uint64_t Index, QualType CharType) { +/// Extract the value of a character from a string literal. +static APSInt extractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit, + uint64_t Index) { // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant - const StringLiteral *S = dyn_cast<StringLiteral>(Lit); - assert(S && "unexpected string literal expression kind"); + const StringLiteral *S = cast<StringLiteral>(Lit); + const ConstantArrayType *CAT = + Info.Ctx.getAsConstantArrayType(S->getType()); + assert(CAT && "string literal isn't an array"); + QualType CharType = CAT->getElementType(); assert(CharType->isIntegerType() && "unexpected character type"); APSInt Value(S->getCharByteWidth() * Info.Ctx.getCharWidth(), @@ -1527,26 +1571,99 @@ static APSInt ExtractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit, return Value; } -/// Extract the designated sub-object of an rvalue. -static bool ExtractSubobject(EvalInfo &Info, const Expr *E, - APValue &Obj, QualType ObjType, - const SubobjectDesignator &Sub, QualType SubType) { +// Expand a string literal into an array of characters. +static void expandStringLiteral(EvalInfo &Info, const Expr *Lit, + APValue &Result) { + const StringLiteral *S = cast<StringLiteral>(Lit); + const ConstantArrayType *CAT = + Info.Ctx.getAsConstantArrayType(S->getType()); + assert(CAT && "string literal isn't an array"); + QualType CharType = CAT->getElementType(); + assert(CharType->isIntegerType() && "unexpected character type"); + + unsigned Elts = CAT->getSize().getZExtValue(); + Result = APValue(APValue::UninitArray(), + std::min(S->getLength(), Elts), Elts); + APSInt Value(S->getCharByteWidth() * Info.Ctx.getCharWidth(), + CharType->isUnsignedIntegerType()); + if (Result.hasArrayFiller()) + Result.getArrayFiller() = APValue(Value); + for (unsigned I = 0, N = Result.getArrayInitializedElts(); I != N; ++I) { + Value = S->getCodeUnit(I); + Result.getArrayInitializedElt(I) = APValue(Value); + } +} + +// Expand an array so that it has more than Index filled elements. +static void expandArray(APValue &Array, unsigned Index) { + unsigned Size = Array.getArraySize(); + assert(Index < Size); + + // Always at least double the number of elements for which we store a value. + unsigned OldElts = Array.getArrayInitializedElts(); + unsigned NewElts = std::max(Index+1, OldElts * 2); + NewElts = std::min(Size, std::max(NewElts, 8u)); + + // Copy the data across. + APValue NewValue(APValue::UninitArray(), NewElts, Size); + for (unsigned I = 0; I != OldElts; ++I) + NewValue.getArrayInitializedElt(I).swap(Array.getArrayInitializedElt(I)); + for (unsigned I = OldElts; I != NewElts; ++I) + NewValue.getArrayInitializedElt(I) = Array.getArrayFiller(); + if (NewValue.hasArrayFiller()) + NewValue.getArrayFiller() = Array.getArrayFiller(); + Array.swap(NewValue); +} + +/// Kinds of access we can perform on an object. +enum AccessKinds { + AK_Read, + AK_Assign, + AK_Increment, + AK_Decrement +}; + +/// A handle to a complete object (an object that is not a subobject of +/// another object). +struct CompleteObject { + /// The value of the complete object. + APValue *Value; + /// The type of the complete object. + QualType Type; + + CompleteObject() : Value(0) {} + CompleteObject(APValue *Value, QualType Type) + : Value(Value), Type(Type) { + assert(Value && "missing value for complete object"); + } + + operator bool() const { return Value; } +}; + +/// Find the designated sub-object of an rvalue. +template<typename SubobjectHandler> +typename SubobjectHandler::result_type +findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, + const SubobjectDesignator &Sub, SubobjectHandler &handler) { if (Sub.Invalid) // A diagnostic will have already been produced. - return false; + return handler.failed(); if (Sub.isOnePastTheEnd()) { - Info.Diag(E, Info.getLangOpts().CPlusPlus11 ? - (unsigned)diag::note_constexpr_read_past_end : - (unsigned)diag::note_invalid_subexpr_in_const_expr); - return false; + if (Info.getLangOpts().CPlusPlus11) + Info.Diag(E, diag::note_constexpr_access_past_end) + << handler.AccessKind; + else + Info.Diag(E); + return handler.failed(); } if (Sub.Entries.empty()) - return true; - if (Info.CheckingPotentialConstantExpression && Obj.isUninit()) + return handler.found(*Obj.Value, Obj.Type); + if (Info.CheckingPotentialConstantExpression && Obj.Value->isUninit()) // This object might be initialized later. - return false; + return handler.failed(); - APValue *O = &Obj; + APValue *O = Obj.Value; + QualType ObjType = Obj.Type; // Walk the designator's path to find the subobject. for (unsigned I = 0, N = Sub.Entries.size(); I != N; ++I) { if (ObjType->isArrayType()) { @@ -1557,49 +1674,67 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E, if (CAT->getSize().ule(Index)) { // Note, it should not be possible to form a pointer with a valid // designator which points more than one past the end of the array. - Info.Diag(E, Info.getLangOpts().CPlusPlus11 ? - (unsigned)diag::note_constexpr_read_past_end : - (unsigned)diag::note_invalid_subexpr_in_const_expr); - return false; + if (Info.getLangOpts().CPlusPlus11) + Info.Diag(E, diag::note_constexpr_access_past_end) + << handler.AccessKind; + else + Info.Diag(E); + return handler.failed(); } + + ObjType = CAT->getElementType(); + // An array object is represented as either an Array APValue or as an // LValue which refers to a string literal. if (O->isLValue()) { assert(I == N - 1 && "extracting subobject of character?"); assert(!O->hasLValuePath() || O->getLValuePath().empty()); - Obj = APValue(ExtractStringLiteralCharacter( - Info, O->getLValueBase().get<const Expr*>(), Index, SubType)); - return true; - } else if (O->getArrayInitializedElts() > Index) + if (handler.AccessKind != AK_Read) + expandStringLiteral(Info, O->getLValueBase().get<const Expr *>(), + *O); + else + return handler.foundString(*O, ObjType, Index); + } + + if (O->getArrayInitializedElts() > Index) O = &O->getArrayInitializedElt(Index); - else + else if (handler.AccessKind != AK_Read) { + expandArray(*O, Index); + O = &O->getArrayInitializedElt(Index); + } else O = &O->getArrayFiller(); - ObjType = CAT->getElementType(); } else if (ObjType->isAnyComplexType()) { // Next subobject is a complex number. uint64_t Index = Sub.Entries[I].ArrayIndex; if (Index > 1) { - Info.Diag(E, Info.getLangOpts().CPlusPlus11 ? - (unsigned)diag::note_constexpr_read_past_end : - (unsigned)diag::note_invalid_subexpr_in_const_expr); - return false; + if (Info.getLangOpts().CPlusPlus11) + Info.Diag(E, diag::note_constexpr_access_past_end) + << handler.AccessKind; + else + Info.Diag(E); + return handler.failed(); } + + bool WasConstQualified = ObjType.isConstQualified(); + ObjType = ObjType->castAs<ComplexType>()->getElementType(); + if (WasConstQualified) + ObjType.addConst(); + assert(I == N - 1 && "extracting subobject of scalar?"); if (O->isComplexInt()) { - Obj = APValue(Index ? O->getComplexIntImag() - : O->getComplexIntReal()); + return handler.found(Index ? O->getComplexIntImag() + : O->getComplexIntReal(), ObjType); } else { assert(O->isComplexFloat()); - Obj = APValue(Index ? O->getComplexFloatImag() - : O->getComplexFloatReal()); + return handler.found(Index ? O->getComplexFloatImag() + : O->getComplexFloatReal(), ObjType); } - return true; } else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) { - if (Field->isMutable()) { + if (Field->isMutable() && handler.AccessKind == AK_Read) { Info.Diag(E, diag::note_constexpr_ltor_mutable, 1) << Field; Info.Note(Field->getLocation(), diag::note_declared_at); - return false; + return handler.failed(); } // Next subobject is a class, struct or union field. @@ -1608,49 +1743,150 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E, const FieldDecl *UnionField = O->getUnionField(); if (!UnionField || UnionField->getCanonicalDecl() != Field->getCanonicalDecl()) { - Info.Diag(E, diag::note_constexpr_read_inactive_union_member) - << Field << !UnionField << UnionField; - return false; + Info.Diag(E, diag::note_constexpr_access_inactive_union_member) + << handler.AccessKind << Field << !UnionField << UnionField; + return handler.failed(); } O = &O->getUnionValue(); } else O = &O->getStructField(Field->getFieldIndex()); + + bool WasConstQualified = ObjType.isConstQualified(); ObjType = Field->getType(); + if (WasConstQualified && !Field->isMutable()) + ObjType.addConst(); if (ObjType.isVolatileQualified()) { if (Info.getLangOpts().CPlusPlus) { // FIXME: Include a description of the path to the volatile subobject. - Info.Diag(E, diag::note_constexpr_ltor_volatile_obj, 1) - << 2 << Field; + Info.Diag(E, diag::note_constexpr_access_volatile_obj, 1) + << handler.AccessKind << 2 << Field; Info.Note(Field->getLocation(), diag::note_declared_at); } else { Info.Diag(E, diag::note_invalid_subexpr_in_const_expr); } - return false; + return handler.failed(); } } else { // Next subobject is a base class. const CXXRecordDecl *Derived = ObjType->getAsCXXRecordDecl(); const CXXRecordDecl *Base = getAsBaseClass(Sub.Entries[I]); O = &O->getStructBase(getBaseIndex(Derived, Base)); + + bool WasConstQualified = ObjType.isConstQualified(); ObjType = Info.Ctx.getRecordType(Base); + if (WasConstQualified) + ObjType.addConst(); } if (O->isUninit()) { if (!Info.CheckingPotentialConstantExpression) - Info.Diag(E, diag::note_constexpr_read_uninit); + Info.Diag(E, diag::note_constexpr_access_uninit) << handler.AccessKind; + return handler.failed(); + } + } + + return handler.found(*O, ObjType); +} + +namespace { +struct ExtractSubobjectHandler { + EvalInfo &Info; + APValue &Result; + + static const AccessKinds AccessKind = AK_Read; + + typedef bool result_type; + bool failed() { return false; } + bool found(APValue &Subobj, QualType SubobjType) { + Result = Subobj; + return true; + } + bool found(APSInt &Value, QualType SubobjType) { + Result = APValue(Value); + return true; + } + bool found(APFloat &Value, QualType SubobjType) { + Result = APValue(Value); + return true; + } + bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) { + Result = APValue(extractStringLiteralCharacter( + Info, Subobj.getLValueBase().get<const Expr *>(), Character)); + return true; + } +}; +} // end anonymous namespace + +const AccessKinds ExtractSubobjectHandler::AccessKind; + +/// Extract the designated sub-object of an rvalue. +static bool extractSubobject(EvalInfo &Info, const Expr *E, + const CompleteObject &Obj, + const SubobjectDesignator &Sub, + APValue &Result) { + ExtractSubobjectHandler Handler = { Info, Result }; + return findSubobject(Info, E, Obj, Sub, Handler); +} + +namespace { +struct ModifySubobjectHandler { + EvalInfo &Info; + APValue &NewVal; + const Expr *E; + + typedef bool result_type; + static const AccessKinds AccessKind = AK_Assign; + + bool checkConst(QualType QT) { + // Assigning to a const object has undefined behavior. + if (QT.isConstQualified()) { + Info.Diag(E, diag::note_constexpr_modify_const_type) << QT; return false; } + return true; } - // This may look super-stupid, but it serves an important purpose: if we just - // swapped Obj and *O, we'd create an object which had itself as a subobject. - // To avoid the leak, we ensure that Tmp ends up owning the original complete - // object, which is destroyed by Tmp's destructor. - APValue Tmp; - O->swap(Tmp); - Obj.swap(Tmp); - return true; + bool failed() { return false; } + bool found(APValue &Subobj, QualType SubobjType) { + if (!checkConst(SubobjType)) + return false; + // We've been given ownership of NewVal, so just swap it in. + Subobj.swap(NewVal); + return true; + } + bool found(APSInt &Value, QualType SubobjType) { + if (!checkConst(SubobjType)) + return false; + if (!NewVal.isInt()) { + // Maybe trying to write a cast pointer value into a complex? + Info.Diag(E); + return false; + } + Value = NewVal.getInt(); + return true; + } + bool found(APFloat &Value, QualType SubobjType) { + if (!checkConst(SubobjType)) + return false; + Value = NewVal.getFloat(); + return true; + } + bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) { + llvm_unreachable("shouldn't encounter string elements with ExpandArrays"); + } +}; +} // end anonymous namespace + +const AccessKinds ModifySubobjectHandler::AccessKind; + +/// Update the designated sub-object of an rvalue to the given value. +static bool modifySubobject(EvalInfo &Info, const Expr *E, + const CompleteObject &Obj, + const SubobjectDesignator &Sub, + APValue &NewVal) { + ModifySubobjectHandler Handler = { Info, NewVal, E }; + return findSubobject(Info, E, Obj, Sub, Handler); } /// Find the position where two subobject designators diverge, or equivalently @@ -1710,59 +1946,52 @@ static bool AreElementsOfSameArray(QualType ObjType, return CommonLength >= A.Entries.size() - IsArray; } -/// HandleLValueToRValueConversion - Perform an lvalue-to-rvalue conversion on -/// the given lvalue. This can also be used for 'lvalue-to-lvalue' conversions -/// for looking up the glvalue referred to by an entity of reference type. -/// -/// \param Info - Information about the ongoing evaluation. -/// \param Conv - The expression for which we are performing the conversion. -/// Used for diagnostics. -/// \param Type - The type we expect this conversion to produce, before -/// stripping cv-qualifiers in the case of a non-clas type. -/// \param LVal - The glvalue on which we are attempting to perform this action. -/// \param RVal - The produced value will be placed here. -static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, - QualType Type, - const LValue &LVal, APValue &RVal) { - if (LVal.Designator.Invalid) - // A diagnostic will have already been produced. - return false; - - const Expr *Base = LVal.Base.dyn_cast<const Expr*>(); - +/// Find the complete object to which an LValue refers. +CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK, + const LValue &LVal, QualType LValType) { if (!LVal.Base) { - // FIXME: Indirection through a null pointer deserves a specific diagnostic. - Info.Diag(Conv, diag::note_invalid_subexpr_in_const_expr); - return false; + Info.Diag(E, diag::note_constexpr_access_null) << AK; + return CompleteObject(); } CallStackFrame *Frame = 0; if (LVal.CallIndex) { Frame = Info.getCallFrame(LVal.CallIndex); if (!Frame) { - Info.Diag(Conv, diag::note_constexpr_lifetime_ended, 1) << !Base; + Info.Diag(E, diag::note_constexpr_lifetime_ended, 1) + << AK << LVal.Base.is<const ValueDecl*>(); NoteLValueLocation(Info, LVal.Base); - return false; + return CompleteObject(); } + } else if (AK != AK_Read) { + Info.Diag(E, diag::note_constexpr_modify_global); + return CompleteObject(); } // C++11 DR1311: An lvalue-to-rvalue conversion on a volatile-qualified type // is not a constant expression (even if the object is non-volatile). We also // apply this rule to C++98, in order to conform to the expected 'volatile' // semantics. - if (Type.isVolatileQualified()) { + if (LValType.isVolatileQualified()) { if (Info.getLangOpts().CPlusPlus) - Info.Diag(Conv, diag::note_constexpr_ltor_volatile_type) << Type; + Info.Diag(E, diag::note_constexpr_access_volatile_type) + << AK << LValType; else - Info.Diag(Conv); - return false; + Info.Diag(E); + return CompleteObject(); } + // Compute value storage location and type of base object. + APValue *BaseVal = 0; + QualType BaseType; + if (const ValueDecl *D = LVal.Base.dyn_cast<const ValueDecl*>()) { // In C++98, const, non-volatile integers initialized with ICEs are ICEs. // In C++11, constexpr, non-volatile variables initialized with constant // expressions are constant expressions too. Inside constexpr functions, // parameters are constant expressions even if they're non-const. + // In C++1y, objects local to a constant expression (those with a Frame) are + // both readable and writable inside constant expressions. // In C, such things can also be folded, although they are not ICEs. const VarDecl *VD = dyn_cast<VarDecl>(D); if (VD) { @@ -1770,120 +1999,312 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, VD = VDef; } if (!VD || VD->isInvalidDecl()) { - Info.Diag(Conv); - return false; + Info.Diag(E); + return CompleteObject(); } - // DR1313: If the object is volatile-qualified but the glvalue was not, - // behavior is undefined so the result is not a constant expression. - QualType VT = VD->getType(); - if (VT.isVolatileQualified()) { + // Accesses of volatile-qualified objects are not allowed. + BaseType = VD->getType(); + if (BaseType.isVolatileQualified()) { if (Info.getLangOpts().CPlusPlus) { - Info.Diag(Conv, diag::note_constexpr_ltor_volatile_obj, 1) << 1 << VD; + Info.Diag(E, diag::note_constexpr_access_volatile_obj, 1) + << AK << 1 << VD; Info.Note(VD->getLocation(), diag::note_declared_at); } else { - Info.Diag(Conv); + Info.Diag(E); } - return false; + return CompleteObject(); } - if (!isa<ParmVarDecl>(VD)) { + // Unless we're looking at a local variable or argument in a constexpr call, + // the variable we're reading must be const. + if (!Frame) { + assert(AK == AK_Read && "can't modify non-local"); if (VD->isConstexpr()) { // OK, we can read this variable. - } else if (VT->isIntegralOrEnumerationType()) { - if (!VT.isConstQualified()) { + } else if (BaseType->isIntegralOrEnumerationType()) { + if (!BaseType.isConstQualified()) { if (Info.getLangOpts().CPlusPlus) { - Info.Diag(Conv, diag::note_constexpr_ltor_non_const_int, 1) << VD; + Info.Diag(E, diag::note_constexpr_ltor_non_const_int, 1) << VD; Info.Note(VD->getLocation(), diag::note_declared_at); } else { - Info.Diag(Conv); + Info.Diag(E); } - return false; + return CompleteObject(); } - } else if (VT->isFloatingType() && VT.isConstQualified()) { + } else if (BaseType->isFloatingType() && BaseType.isConstQualified()) { // We support folding of const floating-point types, in order to make // static const data members of such types (supported as an extension) // more useful. if (Info.getLangOpts().CPlusPlus11) { - Info.CCEDiag(Conv, diag::note_constexpr_ltor_non_constexpr, 1) << VD; + Info.CCEDiag(E, diag::note_constexpr_ltor_non_constexpr, 1) << VD; Info.Note(VD->getLocation(), diag::note_declared_at); } else { - Info.CCEDiag(Conv); + Info.CCEDiag(E); } } else { // FIXME: Allow folding of values of any literal type in all languages. if (Info.getLangOpts().CPlusPlus11) { - Info.Diag(Conv, diag::note_constexpr_ltor_non_constexpr, 1) << VD; + Info.Diag(E, diag::note_constexpr_ltor_non_constexpr, 1) << VD; Info.Note(VD->getLocation(), diag::note_declared_at); } else { - Info.Diag(Conv); + Info.Diag(E); } - return false; + return CompleteObject(); } } - if (!EvaluateVarDeclInit(Info, Conv, VD, Frame, RVal)) - return false; + if (!evaluateVarDeclInit(Info, E, VD, Frame, BaseVal)) + return CompleteObject(); + } else { + const Expr *Base = LVal.Base.dyn_cast<const Expr*>(); + + if (!Frame) { + Info.Diag(E); + return CompleteObject(); + } - if (isa<ParmVarDecl>(VD) || !VD->getAnyInitializer()->isLValue()) - return ExtractSubobject(Info, Conv, RVal, VT, LVal.Designator, Type); - - // The declaration was initialized by an lvalue, with no lvalue-to-rvalue - // conversion. This happens when the declaration and the lvalue should be - // considered synonymous, for instance when initializing an array of char - // from a string literal. Continue as if the initializer lvalue was the - // value we were originally given. - assert(RVal.getLValueOffset().isZero() && - "offset for lvalue init of non-reference"); - Base = RVal.getLValueBase().get<const Expr*>(); - - if (unsigned CallIndex = RVal.getLValueCallIndex()) { - Frame = Info.getCallFrame(CallIndex); - if (!Frame) { - Info.Diag(Conv, diag::note_constexpr_lifetime_ended, 1) << !Base; - NoteLValueLocation(Info, RVal.getLValueBase()); + BaseType = Base->getType(); + BaseVal = &Frame->Temporaries[Base]; + + // Volatile temporary objects cannot be accessed in constant expressions. + if (BaseType.isVolatileQualified()) { + if (Info.getLangOpts().CPlusPlus) { + Info.Diag(E, diag::note_constexpr_access_volatile_obj, 1) + << AK << 0; + Info.Note(Base->getExprLoc(), diag::note_constexpr_temporary_here); + } else { + Info.Diag(E); + } + return CompleteObject(); + } + } + + // In C++1y, we can't safely access any mutable state when checking a + // potential constant expression. + if (Frame && Info.getLangOpts().CPlusPlus1y && + Info.CheckingPotentialConstantExpression) + return CompleteObject(); + + return CompleteObject(BaseVal, BaseType); +} + +/// \brief Perform an lvalue-to-rvalue conversion on the given glvalue. This +/// can also be used for 'lvalue-to-lvalue' conversions for looking up the +/// glvalue referred to by an entity of reference type. +/// +/// \param Info - Information about the ongoing evaluation. +/// \param Conv - The expression for which we are performing the conversion. +/// Used for diagnostics. +/// \param Type - The type of the glvalue (before stripping cv-qualifiers in the +/// case of a non-class type). +/// \param LVal - The glvalue on which we are attempting to perform this action. +/// \param RVal - The produced value will be placed here. +static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, + QualType Type, + const LValue &LVal, APValue &RVal) { + if (LVal.Designator.Invalid) + return false; + + // Check for special cases where there is no existing APValue to look at. + const Expr *Base = LVal.Base.dyn_cast<const Expr*>(); + if (!LVal.Designator.Invalid && Base && !LVal.CallIndex && + !Type.isVolatileQualified()) { + if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(Base)) { + // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the + // initializer until now for such expressions. Such an expression can't be + // an ICE in C, so this only matters for fold. + assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?"); + if (Type.isVolatileQualified()) { + Info.Diag(Conv); return false; } - } else { - Frame = 0; + APValue Lit; + if (!Evaluate(Lit, Info, CLE->getInitializer())) + return false; + CompleteObject LitObj(&Lit, Base->getType()); + return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal); + } else if (isa<StringLiteral>(Base)) { + // We represent a string literal array as an lvalue pointing at the + // corresponding expression, rather than building an array of chars. + // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant + APValue Str(Base, CharUnits::Zero(), APValue::NoLValuePath(), 0); + CompleteObject StrObj(&Str, Base->getType()); + return extractSubobject(Info, Conv, StrObj, LVal.Designator, RVal); } } - // Volatile temporary objects cannot be read in constant expressions. - if (Base->getType().isVolatileQualified()) { - if (Info.getLangOpts().CPlusPlus) { - Info.Diag(Conv, diag::note_constexpr_ltor_volatile_obj, 1) << 0; - Info.Note(Base->getExprLoc(), diag::note_constexpr_temporary_here); + CompleteObject Obj = findCompleteObject(Info, Conv, AK_Read, LVal, Type); + return Obj && extractSubobject(Info, Conv, Obj, LVal.Designator, RVal); +} + +/// Perform an assignment of Val to LVal. Takes ownership of Val. +static bool handleAssignment(EvalInfo &Info, const Expr *E, const LValue &LVal, + QualType LValType, APValue &Val) { + if (LVal.Designator.Invalid) + return false; + + if (!Info.getLangOpts().CPlusPlus1y) { + Info.Diag(E); + return false; + } + + CompleteObject Obj = findCompleteObject(Info, E, AK_Assign, LVal, LValType); + return Obj && modifySubobject(Info, E, Obj, LVal.Designator, Val); +} + +static bool isOverflowingIntegerType(ASTContext &Ctx, QualType T) { + return T->isSignedIntegerType() && + Ctx.getIntWidth(T) >= Ctx.getIntWidth(Ctx.IntTy); +} + +namespace { +struct IncDecSubobjectHandler { + EvalInfo &Info; + const Expr *E; + AccessKinds AccessKind; + APValue *Old; + + typedef bool result_type; + + bool checkConst(QualType QT) { + // Assigning to a const object has undefined behavior. + if (QT.isConstQualified()) { + Info.Diag(E, diag::note_constexpr_modify_const_type) << QT; + return false; + } + return true; + } + + bool failed() { return false; } + bool found(APValue &Subobj, QualType SubobjType) { + // Stash the old value. Also clear Old, so we don't clobber it later + // if we're post-incrementing a complex. + if (Old) { + *Old = Subobj; + Old = 0; + } + + switch (Subobj.getKind()) { + case APValue::Int: + return found(Subobj.getInt(), SubobjType); + case APValue::Float: + return found(Subobj.getFloat(), SubobjType); + case APValue::ComplexInt: + return found(Subobj.getComplexIntReal(), + SubobjType->castAs<ComplexType>()->getElementType() + .withCVRQualifiers(SubobjType.getCVRQualifiers())); + case APValue::ComplexFloat: + return found(Subobj.getComplexFloatReal(), + SubobjType->castAs<ComplexType>()->getElementType() + .withCVRQualifiers(SubobjType.getCVRQualifiers())); + case APValue::LValue: + return foundPointer(Subobj, SubobjType); + default: + // FIXME: can this happen? + Info.Diag(E); + return false; + } + } + bool found(APSInt &Value, QualType SubobjType) { + if (!checkConst(SubobjType)) + return false; + + if (!SubobjType->isIntegerType()) { + // We don't support increment / decrement on integer-cast-to-pointer + // values. + Info.Diag(E); + return false; + } + + if (Old) *Old = APValue(Value); + + // bool arithmetic promotes to int, and the conversion back to bool + // doesn't reduce mod 2^n, so special-case it. + if (SubobjType->isBooleanType()) { + if (AccessKind == AK_Increment) + Value = 1; + else + Value = !Value; + return true; + } + + bool WasNegative = Value.isNegative(); + if (AccessKind == AK_Increment) { + ++Value; + + if (!WasNegative && Value.isNegative() && + isOverflowingIntegerType(Info.Ctx, SubobjType)) { + APSInt ActualValue(Value, /*IsUnsigned*/true); + HandleOverflow(Info, E, ActualValue, SubobjType); + } } else { - Info.Diag(Conv); + --Value; + + if (WasNegative && !Value.isNegative() && + isOverflowingIntegerType(Info.Ctx, SubobjType)) { + unsigned BitWidth = Value.getBitWidth(); + APSInt ActualValue(Value.sext(BitWidth + 1), /*IsUnsigned*/false); + ActualValue.setBit(BitWidth); + HandleOverflow(Info, E, ActualValue, SubobjType); + } } - return false; + return true; } + bool found(APFloat &Value, QualType SubobjType) { + if (!checkConst(SubobjType)) + return false; - if (Frame) { - // If this is a temporary expression with a nontrivial initializer, grab the - // value from the relevant stack frame. - RVal = Frame->Temporaries[Base]; - } else if (const CompoundLiteralExpr *CLE - = dyn_cast<CompoundLiteralExpr>(Base)) { - // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the - // initializer until now for such expressions. Such an expression can't be - // an ICE in C, so this only matters for fold. - assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?"); - if (!Evaluate(RVal, Info, CLE->getInitializer())) + if (Old) *Old = APValue(Value); + + APFloat One(Value.getSemantics(), 1); + if (AccessKind == AK_Increment) + Value.add(One, APFloat::rmNearestTiesToEven); + else + Value.subtract(One, APFloat::rmNearestTiesToEven); + return true; + } + bool foundPointer(APValue &Subobj, QualType SubobjType) { + if (!checkConst(SubobjType)) return false; - } else if (isa<StringLiteral>(Base)) { - // We represent a string literal array as an lvalue pointing at the - // corresponding expression, rather than building an array of chars. - // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant - RVal = APValue(Base, CharUnits::Zero(), APValue::NoLValuePath(), 0); - } else { - Info.Diag(Conv, diag::note_invalid_subexpr_in_const_expr); + + QualType PointeeType; + if (const PointerType *PT = SubobjType->getAs<PointerType>()) + PointeeType = PT->getPointeeType(); + else { + Info.Diag(E); + return false; + } + + LValue LVal; + LVal.setFrom(Info.Ctx, Subobj); + if (!HandleLValueArrayAdjustment(Info, E, LVal, PointeeType, + AccessKind == AK_Increment ? 1 : -1)) + return false; + LVal.moveInto(Subobj); + return true; + } + bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) { + llvm_unreachable("shouldn't encounter string elements here"); + } +}; +} // end anonymous namespace + +/// Perform an increment or decrement on LVal. +static bool handleIncDec(EvalInfo &Info, const Expr *E, const LValue &LVal, + QualType LValType, bool IsIncrement, APValue *Old) { + if (LVal.Designator.Invalid) + return false; + + if (!Info.getLangOpts().CPlusPlus1y) { + Info.Diag(E); return false; } - return ExtractSubobject(Info, Conv, RVal, Base->getType(), LVal.Designator, - Type); + AccessKinds AK = IsIncrement ? AK_Increment : AK_Decrement; + CompleteObject Obj = findCompleteObject(Info, E, AK, LVal, LValType); + IncDecSubobjectHandler Handler = { Info, E, AK, Old }; + return Obj && findSubobject(Info, E, Obj, LVal.Designator, Handler); } /// Build an lvalue for the object argument of a member function call. @@ -1895,7 +2316,7 @@ static bool EvaluateObjectArgument(EvalInfo &Info, const Expr *Object, if (Object->isGLValue()) return EvaluateLValue(Object, This, Info); - if (Object->getType()->isLiteralType()) + if (Object->getType()->isLiteralType(Info.Ctx)) return EvaluateTemporary(Object, This, Info); return false; @@ -2040,24 +2461,95 @@ enum EvalStmtResult { /// Hit a 'return' statement. ESR_Returned, /// Evaluation succeeded. - ESR_Succeeded + ESR_Succeeded, + /// Hit a 'continue' statement. + ESR_Continue, + /// Hit a 'break' statement. + ESR_Break }; } +static bool EvaluateDecl(EvalInfo &Info, const Decl *D) { + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + // We don't need to evaluate the initializer for a static local. + if (!VD->hasLocalStorage()) + return true; + + LValue Result; + Result.set(VD, Info.CurrentCall->Index); + APValue &Val = Info.CurrentCall->Temporaries[VD]; + + if (!EvaluateInPlace(Val, Info, Result, VD->getInit())) { + // Wipe out any partially-computed value, to allow tracking that this + // evaluation failed. + Val = APValue(); + return false; + } + } + + return true; +} + +/// Evaluate a condition (either a variable declaration or an expression). +static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl, + const Expr *Cond, bool &Result) { + if (CondDecl && !EvaluateDecl(Info, CondDecl)) + return false; + return EvaluateAsBooleanCondition(Cond, Result, Info); +} + +static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, + const Stmt *S); + +/// Evaluate the body of a loop, and translate the result as appropriate. +static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info, + const Stmt *Body) { + switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body)) { + case ESR_Break: + return ESR_Succeeded; + case ESR_Succeeded: + case ESR_Continue: + return ESR_Continue; + case ESR_Failed: + case ESR_Returned: + return ESR; + } + llvm_unreachable("Invalid EvalStmtResult!"); +} + // Evaluate a statement. static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, const Stmt *S) { + // FIXME: Mark all temporaries in the current frame as destroyed at + // the end of each full-expression. switch (S->getStmtClass()) { default: + if (const Expr *E = dyn_cast<Expr>(S)) { + // Don't bother evaluating beyond an expression-statement which couldn't + // be evaluated. + if (!EvaluateIgnoredValue(Info, E)) + return ESR_Failed; + return ESR_Succeeded; + } + + Info.Diag(S->getLocStart()); return ESR_Failed; case Stmt::NullStmtClass: - case Stmt::DeclStmtClass: return ESR_Succeeded; + case Stmt::DeclStmtClass: { + const DeclStmt *DS = cast<DeclStmt>(S); + for (DeclStmt::const_decl_iterator DclIt = DS->decl_begin(), + DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt) + if (!EvaluateDecl(Info, *DclIt) && !Info.keepEvaluatingAfterFailure()) + return ESR_Failed; + return ESR_Succeeded; + } + case Stmt::ReturnStmtClass: { const Expr *RetExpr = cast<ReturnStmt>(S)->getRetValue(); - if (!Evaluate(Result, Info, RetExpr)) + if (RetExpr && !Evaluate(Result, Info, RetExpr)) return ESR_Failed; return ESR_Returned; } @@ -2072,6 +2564,123 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, } return ESR_Succeeded; } + + case Stmt::IfStmtClass: { + const IfStmt *IS = cast<IfStmt>(S); + + // Evaluate the condition, as either a var decl or as an expression. + bool Cond; + if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(), Cond)) + return ESR_Failed; + + if (const Stmt *SubStmt = Cond ? IS->getThen() : IS->getElse()) { + EvalStmtResult ESR = EvaluateStmt(Result, Info, SubStmt); + if (ESR != ESR_Succeeded) + return ESR; + } + return ESR_Succeeded; + } + + case Stmt::WhileStmtClass: { + const WhileStmt *WS = cast<WhileStmt>(S); + while (true) { + bool Continue; + if (!EvaluateCond(Info, WS->getConditionVariable(), WS->getCond(), + Continue)) + return ESR_Failed; + if (!Continue) + break; + + EvalStmtResult ESR = EvaluateLoopBody(Result, Info, WS->getBody()); + if (ESR != ESR_Continue) + return ESR; + } + return ESR_Succeeded; + } + + case Stmt::DoStmtClass: { + const DoStmt *DS = cast<DoStmt>(S); + bool Continue; + do { + EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody()); + if (ESR != ESR_Continue) + return ESR; + + if (!EvaluateAsBooleanCondition(DS->getCond(), Continue, Info)) + return ESR_Failed; + } while (Continue); + return ESR_Succeeded; + } + + case Stmt::ForStmtClass: { + const ForStmt *FS = cast<ForStmt>(S); + if (FS->getInit()) { + EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getInit()); + if (ESR != ESR_Succeeded) + return ESR; + } + while (true) { + bool Continue = true; + if (FS->getCond() && !EvaluateCond(Info, FS->getConditionVariable(), + FS->getCond(), Continue)) + return ESR_Failed; + if (!Continue) + break; + + EvalStmtResult ESR = EvaluateLoopBody(Result, Info, FS->getBody()); + if (ESR != ESR_Continue) + return ESR; + + if (FS->getInc() && !EvaluateIgnoredValue(Info, FS->getInc())) + return ESR_Failed; + } + return ESR_Succeeded; + } + + case Stmt::CXXForRangeStmtClass: { + const CXXForRangeStmt *FS = cast<CXXForRangeStmt>(S); + + // Initialize the __range variable. + EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getRangeStmt()); + if (ESR != ESR_Succeeded) + return ESR; + + // Create the __begin and __end iterators. + ESR = EvaluateStmt(Result, Info, FS->getBeginEndStmt()); + if (ESR != ESR_Succeeded) + return ESR; + + while (true) { + // Condition: __begin != __end. + bool Continue = true; + if (!EvaluateAsBooleanCondition(FS->getCond(), Continue, Info)) + return ESR_Failed; + if (!Continue) + break; + + // User's variable declaration, initialized by *__begin. + ESR = EvaluateStmt(Result, Info, FS->getLoopVarStmt()); + if (ESR != ESR_Succeeded) + return ESR; + + // Loop body. + ESR = EvaluateLoopBody(Result, Info, FS->getBody()); + if (ESR != ESR_Continue) + return ESR; + + // Increment: ++__begin + if (!EvaluateIgnoredValue(Info, FS->getInc())) + return ESR_Failed; + } + + return ESR_Succeeded; + } + + case Stmt::ContinueStmtClass: + return ESR_Continue; + + case Stmt::BreakStmtClass: + return ESR_Break; } } @@ -2165,7 +2774,13 @@ static bool HandleFunctionCall(SourceLocation CallLoc, return false; CallStackFrame Frame(Info, CallLoc, Callee, This, ArgValues.data()); - return EvaluateStmt(Result, Info, Body) == ESR_Returned; + EvalStmtResult ESR = EvaluateStmt(Result, Info, Body); + if (ESR == ESR_Succeeded) { + if (Callee->getResultType()->isVoidType()) + return true; + Info.Diag(Callee->getLocEnd(), diag::note_constexpr_no_return); + } + return ESR == ESR_Returned; } /// Evaluate a constructor call. @@ -2191,7 +2806,9 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, // If it's a delegating constructor, just delegate. if (Definition->isDelegatingConstructor()) { CXXConstructorDecl::init_const_iterator I = Definition->init_begin(); - return EvaluateInPlace(Result, Info, This, (*I)->getInit()); + if (!EvaluateInPlace(Result, Info, This, (*I)->getInit())) + return false; + return EvaluateStmt(Result, Info, Definition->getBody()) != ESR_Failed; } // For a trivial copy or move constructor, perform an APValue copy. This is @@ -2202,7 +2819,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, (Definition->isMoveConstructor() && Definition->isTrivial()))) { LValue RHS; RHS.setFrom(Info.Ctx, ArgValues[0]); - return HandleLValueToRValueConversion(Info, Args[0], Args[0]->getType(), + return handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(), RHS, Result); } @@ -2291,7 +2908,8 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, } } - return Success; + return Success && + EvaluateStmt(Result, Info, Definition->getBody()) != ESR_Failed; } //===----------------------------------------------------------------------===// @@ -2397,6 +3015,8 @@ public: { return StmtVisitorTy::Visit(E->getReplacement()); } RetTy VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) { return StmtVisitorTy::Visit(E->getExpr()); } + RetTy VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) + { return StmtVisitorTy::Visit(E->getExpr()); } // We cannot create any objects for which cleanups are required, so there is // nothing to do here; all cleanups must come from unevaluated subexpressions. RetTy VisitExprWithCleanups(const ExprWithCleanups *E) @@ -2426,7 +3046,7 @@ public: if (!HandleMemberPointerAccess(Info, E, Obj)) return false; APValue Result; - if (!HandleLValueToRValueConversion(Info, E, E->getType(), Obj, Result)) + if (!handleLValueToRValueConversion(Info, E, E->getType(), Obj, Result)) return false; return DerivedSuccess(Result, E); } @@ -2606,11 +3226,13 @@ public: assert(BaseTy->castAs<RecordType>()->getDecl()->getCanonicalDecl() == FD->getParent()->getCanonicalDecl() && "record / field mismatch"); + CompleteObject Obj(&Val, BaseTy); SubobjectDesignator Designator(BaseTy); Designator.addDeclUnchecked(FD); - return ExtractSubobject(Info, E, Val, BaseTy, Designator, E->getType()) && - DerivedSuccess(Val, E); + APValue Result; + return extractSubobject(Info, E, Obj, Designator, Result) && + DerivedSuccess(Result, E); } RetTy VisitCastExpr(const CastExpr *E) { @@ -2630,7 +3252,7 @@ public: return false; APValue RVal; // Note, we use the subexpression's type in order to retain cv-qualifiers. - if (!HandleLValueToRValueConversion(Info, E, E->getSubExpr()->getType(), + if (!handleLValueToRValueConversion(Info, E, E->getSubExpr()->getType(), LVal, RVal)) return false; return DerivedSuccess(RVal, E); @@ -2640,11 +3262,29 @@ public: return Error(E); } + RetTy VisitUnaryPostInc(const UnaryOperator *UO) { + return VisitUnaryPostIncDec(UO); + } + RetTy VisitUnaryPostDec(const UnaryOperator *UO) { + return VisitUnaryPostIncDec(UO); + } + RetTy VisitUnaryPostIncDec(const UnaryOperator *UO) { + if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure()) + return Error(UO); + + LValue LVal; + if (!EvaluateLValue(UO->getSubExpr(), LVal, Info)) + return false; + APValue RVal; + if (!handleIncDec(this->Info, UO, LVal, UO->getSubExpr()->getType(), + UO->isIncrementOp(), &RVal)) + return false; + return DerivedSuccess(RVal, UO); + } + /// Visit a value which is evaluated, but whose value is ignored. void VisitIgnoredValue(const Expr *E) { - APValue Scratch; - if (!Evaluate(Scratch, Info, E)) - Info.EvalStatus.HasSideEffects = true; + EvaluateIgnoredValue(Info, E); } }; @@ -2709,7 +3349,7 @@ public: if (MD->getType()->isReferenceType()) { APValue RefValue; - if (!HandleLValueToRValueConversion(this->Info, E, MD->getType(), Result, + if (!handleLValueToRValueConversion(this->Info, E, MD->getType(), Result, RefValue)) return false; return Success(RefValue, E); @@ -2792,6 +3432,7 @@ public: LValueExprEvaluatorBaseTy(Info, Result) {} bool VisitVarDecl(const Expr *E, const VarDecl *VD); + bool VisitUnaryPreIncDec(const UnaryOperator *UO); bool VisitDeclRefExpr(const DeclRefExpr *E); bool VisitPredefinedExpr(const PredefinedExpr *E) { return Success(E); } @@ -2806,6 +3447,14 @@ public: bool VisitUnaryDeref(const UnaryOperator *E); bool VisitUnaryReal(const UnaryOperator *E); bool VisitUnaryImag(const UnaryOperator *E); + bool VisitUnaryPreInc(const UnaryOperator *UO) { + return VisitUnaryPreIncDec(UO); + } + bool VisitUnaryPreDec(const UnaryOperator *UO) { + return VisitUnaryPreIncDec(UO); + } + bool VisitBinAssign(const BinaryOperator *BO); + bool VisitCompoundAssignOperator(const CompoundAssignOperator *CAO); bool VisitCastExpr(const CastExpr *E) { switch (E->getCastKind()) { @@ -2829,14 +3478,12 @@ public: } // end anonymous namespace /// Evaluate an expression as an lvalue. This can be legitimately called on -/// expressions which are not glvalues, in a few cases: -/// * function designators in C, -/// * "extern void" objects, -/// * temporaries, if building with -Wno-address-of-temporary. -static bool EvaluateLValue(const Expr* E, LValue& Result, EvalInfo &Info) { - assert((E->isGLValue() || E->getType()->isFunctionType() || - E->getType()->isVoidType() || isa<CXXTemporaryObjectExpr>(E)) && - "can't evaluate expression as an lvalue"); +/// expressions which are not glvalues, in two cases: +/// * function designators in C, and +/// * "extern void" objects +static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info) { + assert(E->isGLValue() || E->getType()->isFunctionType() || + E->getType()->isVoidType()); return LValueExprEvaluator(Info, Result).Visit(E); } @@ -2849,41 +3496,32 @@ bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { } bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { + CallStackFrame *Frame = 0; + if (VD->hasLocalStorage() && Info.CurrentCall->Index > 1) + Frame = Info.CurrentCall; + if (!VD->getType()->isReferenceType()) { - if (isa<ParmVarDecl>(VD)) { - Result.set(VD, Info.CurrentCall->Index); + if (Frame) { + Result.set(VD, Frame->Index); return true; } return Success(VD); } - APValue V; - if (!EvaluateVarDeclInit(Info, E, VD, Info.CurrentCall, V)) + APValue *V; + if (!evaluateVarDeclInit(Info, E, VD, Frame, V)) return false; - return Success(V, E); + return Success(*V, E); } bool LValueExprEvaluator::VisitMaterializeTemporaryExpr( const MaterializeTemporaryExpr *E) { - if (E->GetTemporaryExpr()->isRValue()) { - if (E->getType()->isRecordType()) - return EvaluateTemporary(E->GetTemporaryExpr(), Result, Info); + if (E->getType()->isRecordType()) + return EvaluateTemporary(E->GetTemporaryExpr(), Result, Info); - Result.set(E, Info.CurrentCall->Index); - return EvaluateInPlace(Info.CurrentCall->Temporaries[E], Info, - Result, E->GetTemporaryExpr()); - } - - // Materialization of an lvalue temporary occurs when we need to force a copy - // (for instance, if it's a bitfield). - // FIXME: The AST should contain an lvalue-to-rvalue node for such cases. - if (!Visit(E->GetTemporaryExpr())) - return false; - if (!HandleLValueToRValueConversion(Info, E, E->getType(), Result, - Info.CurrentCall->Temporaries[E])) - return false; Result.set(E, Info.CurrentCall->Index); - return true; + return EvaluateInPlace(Info.CurrentCall->Temporaries[E], Info, + Result, E->GetTemporaryExpr()); } bool @@ -2906,7 +3544,7 @@ bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) { bool LValueExprEvaluator::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { return Success(E); -} +} bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) { // Handle static data members. @@ -2967,6 +3605,64 @@ bool LValueExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { return true; } +bool LValueExprEvaluator::VisitUnaryPreIncDec(const UnaryOperator *UO) { + if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure()) + return Error(UO); + + if (!this->Visit(UO->getSubExpr())) + return false; + + return handleIncDec( + this->Info, UO, Result, UO->getSubExpr()->getType(), + UO->isIncrementOp(), 0); +} + +bool LValueExprEvaluator::VisitCompoundAssignOperator( + const CompoundAssignOperator *CAO) { + if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure()) + return Error(CAO); + + APValue RHS; + + // The overall lvalue result is the result of evaluating the LHS. + if (!this->Visit(CAO->getLHS())) { + if (Info.keepEvaluatingAfterFailure()) + Evaluate(RHS, this->Info, CAO->getRHS()); + return false; + } + + if (!Evaluate(RHS, this->Info, CAO->getRHS())) + return false; + + // FIXME: + //return handleCompoundAssignment( + // this->Info, CAO, + // Result, CAO->getLHS()->getType(), CAO->getComputationLHSType(), + // RHS, CAO->getRHS()->getType(), + // CAO->getOpForCompoundAssignment(CAO->getOpcode()), + // CAO->getComputationResultType()); + return Error(CAO); +} + +bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) { + if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure()) + return Error(E); + + APValue NewVal; + + if (!this->Visit(E->getLHS())) { + if (Info.keepEvaluatingAfterFailure()) + Evaluate(NewVal, this->Info, E->getRHS()); + return false; + } + + if (!Evaluate(NewVal, this->Info, E->getRHS())) + return false; + + return handleAssignment(this->Info, E, Result, E->getLHS()->getType(), + NewVal); +} + //===----------------------------------------------------------------------===// // Pointer Evaluation //===----------------------------------------------------------------------===// @@ -3411,12 +4107,20 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { // If the initializer list for a union does not contain any elements, the // first element of the union is value-initialized. + // FIXME: The element should be initialized from an initializer list. + // Is this difference ever observable for initializer lists which + // we don't build? ImplicitValueInitExpr VIE(Field->getType()); const Expr *InitExpr = E->getNumInits() ? E->getInit(0) : &VIE; LValue Subobject = This; if (!HandleLValueMember(Info, InitExpr, Subobject, Field, &Layout)) return false; + + // Temporarily override This, in case there's a CXXDefaultInitExpr in here. + ThisOverrideRAII ThisOverride(*Info.CurrentCall, &This, + isa<CXXDefaultInitExpr>(InitExpr)); + return EvaluateInPlace(Result.getUnionValue(), Info, Subobject, InitExpr); } @@ -3446,10 +4150,14 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { // Perform an implicit value-initialization for members beyond the end of // the initializer list. ImplicitValueInitExpr VIE(HaveInit ? Info.Ctx.IntTy : Field->getType()); + const Expr *Init = HaveInit ? E->getInit(ElementNo++) : &VIE; - if (!EvaluateInPlace( - Result.getStructField(Field->getFieldIndex()), - Info, Subobject, HaveInit ? E->getInit(ElementNo++) : &VIE)) { + // Temporarily override This, in case there's a CXXDefaultInitExpr in here. + ThisOverrideRAII ThisOverride(*Info.CurrentCall, &This, + isa<CXXDefaultInitExpr>(Init)); + + if (!EvaluateInPlace(Result.getStructField(Field->getFieldIndex()), Info, + Subobject, Init)) { if (!Info.keepEvaluatingAfterFailure()) return false; Success = false; @@ -3777,6 +4485,9 @@ namespace { bool VisitInitListExpr(const InitListExpr *E); bool VisitCXXConstructExpr(const CXXConstructExpr *E); + bool VisitCXXConstructExpr(const CXXConstructExpr *E, + const LValue &Subobject, + APValue *Value, QualType Type); }; } // end anonymous namespace @@ -3810,8 +4521,16 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { if (Result.isArray() && Result.hasArrayFiller()) Filler = Result.getArrayFiller(); - Result = APValue(APValue::UninitArray(), E->getNumInits(), - CAT->getSize().getZExtValue()); + unsigned NumEltsToInit = E->getNumInits(); + unsigned NumElts = CAT->getSize().getZExtValue(); + const Expr *FillerExpr = E->hasArrayFiller() ? E->getArrayFiller() : 0; + + // If the initializer might depend on the array index, run it for each + // array element. For now, just whitelist non-class value-initialization. + if (NumEltsToInit != NumElts && !isa<ImplicitValueInitExpr>(FillerExpr)) + NumEltsToInit = NumElts; + + Result = APValue(APValue::UninitArray(), NumEltsToInit, NumElts); // If the array was previously zero-initialized, preserve the // zero-initialized values. @@ -3824,12 +4543,12 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { LValue Subobject = This; Subobject.addArray(Info, E, CAT); - unsigned Index = 0; - for (InitListExpr::const_iterator I = E->begin(), End = E->end(); - I != End; ++I, ++Index) { + for (unsigned Index = 0; Index != NumEltsToInit; ++Index) { + const Expr *Init = + Index < E->getNumInits() ? E->getInit(Index) : FillerExpr; if (!EvaluateInPlace(Result.getArrayInitializedElt(Index), - Info, Subobject, cast<Expr>(*I)) || - !HandleLValueArrayAdjustment(Info, cast<Expr>(*I), Subobject, + Info, Subobject, Init) || + !HandleLValueArrayAdjustment(Info, Init, Subobject, CAT->getElementType(), 1)) { if (!Info.keepEvaluatingAfterFailure()) return false; @@ -3837,39 +4556,54 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) { } } - if (!Result.hasArrayFiller()) return Success; - assert(E->hasArrayFiller() && "no array filler for incomplete init list"); - // FIXME: The Subobject here isn't necessarily right. This rarely matters, - // but sometimes does: - // struct S { constexpr S() : p(&p) {} void *p; }; - // S s[10] = {}; - return EvaluateInPlace(Result.getArrayFiller(), Info, - Subobject, E->getArrayFiller()) && Success; + if (!Result.hasArrayFiller()) + return Success; + + // If we get here, we have a trivial filler, which we can just evaluate + // once and splat over the rest of the array elements. + assert(FillerExpr && "no array filler for incomplete init list"); + return EvaluateInPlace(Result.getArrayFiller(), Info, Subobject, + FillerExpr) && Success; } bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { - // FIXME: The Subobject here isn't necessarily right. This rarely matters, - // but sometimes does: - // struct S { constexpr S() : p(&p) {} void *p; }; - // S s[10]; - LValue Subobject = This; + return VisitCXXConstructExpr(E, This, &Result, E->getType()); +} - APValue *Value = &Result; - bool HadZeroInit = true; - QualType ElemTy = E->getType(); - while (const ConstantArrayType *CAT = - Info.Ctx.getAsConstantArrayType(ElemTy)) { - Subobject.addArray(Info, E, CAT); - HadZeroInit &= !Value->isUninit(); - if (!HadZeroInit) - *Value = APValue(APValue::UninitArray(), 0, CAT->getSize().getZExtValue()); - if (!Value->hasArrayFiller()) - return true; - Value = &Value->getArrayFiller(); - ElemTy = CAT->getElementType(); +bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, + const LValue &Subobject, + APValue *Value, + QualType Type) { + bool HadZeroInit = !Value->isUninit(); + + if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(Type)) { + unsigned N = CAT->getSize().getZExtValue(); + + // Preserve the array filler if we had prior zero-initialization. + APValue Filler = + HadZeroInit && Value->hasArrayFiller() ? Value->getArrayFiller() + : APValue(); + + *Value = APValue(APValue::UninitArray(), N, N); + + if (HadZeroInit) + for (unsigned I = 0; I != N; ++I) + Value->getArrayInitializedElt(I) = Filler; + + // Initialize the elements. + LValue ArrayElt = Subobject; + ArrayElt.addArray(Info, E, CAT); + for (unsigned I = 0; I != N; ++I) + if (!VisitCXXConstructExpr(E, ArrayElt, &Value->getArrayInitializedElt(I), + CAT->getElementType()) || + !HandleLValueArrayAdjustment(Info, E, ArrayElt, + CAT->getElementType(), 1)) + return false; + + return true; } - if (!ElemTy->isRecordType()) + if (!Type->isRecordType()) return Error(E); const CXXConstructorDecl *FD = E->getConstructor(); @@ -3880,7 +4614,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { return true; if (ZeroInit) { - ImplicitValueInitExpr VIE(ElemTy); + ImplicitValueInitExpr VIE(Type); return EvaluateInPlace(*Value, Info, Subobject, &VIE); } @@ -3901,7 +4635,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { return false; if (ZeroInit && !HadZeroInit) { - ImplicitValueInitExpr VIE(ElemTy); + ImplicitValueInitExpr VIE(Type); if (!EvaluateInPlace(*Value, Info, Subobject, &VIE)) return false; } @@ -5182,6 +5916,10 @@ CharUnits IntExprEvaluator::GetAlignOfType(QualType T) { CharUnits IntExprEvaluator::GetAlignOfExpr(const Expr *E) { E = E->IgnoreParens(); + // The kinds of expressions that we have special-case logic here for + // should be kept up to date with the special checks for those + // expressions in Sema. + // alignof decl is always accepted, even if it doesn't make sense: we default // to 1 in those cases. if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) @@ -6267,7 +7005,7 @@ static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) { if (E->isGLValue()) { LValue LV; LV.setFrom(Info.Ctx, Result); - if (!HandleLValueToRValueConversion(Info, E, E->getType(), LV, Result)) + if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result)) return false; } @@ -6501,6 +7239,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::CXXDynamicCastExprClass: case Expr::CXXTypeidExprClass: case Expr::CXXUuidofExprClass: + case Expr::MSPropertyRefExprClass: case Expr::CXXNullPtrLiteralExprClass: case Expr::UserDefinedLiteralClass: case Expr::CXXThisExprClass: @@ -6819,6 +7558,8 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { } case Expr::CXXDefaultArgExprClass: return CheckICE(cast<CXXDefaultArgExpr>(E)->getExpr(), Ctx); + case Expr::CXXDefaultInitExprClass: + return CheckICE(cast<CXXDefaultInitExpr>(E)->getExpr(), Ctx); case Expr::ChooseExprClass: { return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(Ctx), Ctx); } diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 21c4993..5ad8021 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -141,6 +141,8 @@ public: raw_ostream &); void mangleItaniumGuardVariable(const VarDecl *D, raw_ostream &); + void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &); + void mangleItaniumThreadLocalWrapper(const VarDecl *D, raw_ostream &); void mangleInitDiscriminator() { Discriminator = 0; @@ -1095,6 +1097,15 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, mangleSourceName(FD->getIdentifier()); break; } + + // Class extensions have no name as a category, and it's possible + // for them to be the semantic parent of certain declarations + // (primarily, tag decls defined within declarations). Such + // declarations will always have internal linkage, so the name + // doesn't really matter, but we shouldn't crash on them. For + // safety, just handle all ObjC containers here. + if (isa<ObjCContainerDecl>(ND)) + break; // We must have an anonymous struct. const TagDecl *TD = cast<TagDecl>(ND); @@ -2264,7 +2275,7 @@ void CXXNameMangler::mangleType(const AutoType *T) { QualType D = T->getDeducedType(); // <builtin-type> ::= Da # dependent auto if (D.isNull()) - Out << "Da"; + Out << (T->isDecltypeAuto() ? "Dc" : "Da"); else mangleType(D); } @@ -2385,6 +2396,7 @@ recurse: case Expr::ImplicitValueInitExprClass: case Expr::ParenListExprClass: case Expr::LambdaExprClass: + case Expr::MSPropertyRefExprClass: llvm_unreachable("unexpected statement kind"); // FIXME: invent manglings for all these. @@ -2461,6 +2473,10 @@ recurse: mangleExpression(cast<CXXDefaultArgExpr>(E)->getExpr(), Arity); break; + case Expr::CXXDefaultInitExprClass: + mangleExpression(cast<CXXDefaultInitExpr>(E)->getExpr(), Arity); + break; + case Expr::SubstNonTypeTemplateParmExprClass: mangleExpression(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(), Arity); @@ -3521,6 +3537,22 @@ void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D, Mangler.mangleName(D); } +void ItaniumMangleContext::mangleItaniumThreadLocalInit(const VarDecl *D, + raw_ostream &Out) { + // <special-name> ::= TH <object name> + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZTH"; + Mangler.mangleName(D); +} + +void ItaniumMangleContext::mangleItaniumThreadLocalWrapper(const VarDecl *D, + raw_ostream &Out) { + // <special-name> ::= TW <object name> + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZTW"; + Mangler.mangleName(D); +} + void ItaniumMangleContext::mangleReferenceTemporary(const VarDecl *D, raw_ostream &Out) { // We match the GCC mangling here. diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp index 6553e9d..fd932f7 100644 --- a/lib/AST/MicrosoftCXXABI.cpp +++ b/lib/AST/MicrosoftCXXABI.cpp @@ -89,8 +89,8 @@ MSInheritanceModel CXXRecordDecl::getMSInheritanceModel() const { if (this->getNumVBases() > 0) return MSIM_Virtual; if (usesMultipleInheritanceModel(this)) - return MSIM_Multiple; - return MSIM_Single; + return this->isPolymorphic() ? MSIM_MultiplePolymorphic : MSIM_Multiple; + return this->isPolymorphic() ? MSIM_SinglePolymorphic : MSIM_Single; } // Returns the number of pointer and integer slots used to represent a member @@ -119,15 +119,15 @@ MSInheritanceModel CXXRecordDecl::getMSInheritanceModel() const { // // // The offset of the vb-table pointer within the object. Only needed for // // incomplete types. -// int VBTableOffset; +// int VBPtrOffset; // }; -std::pair<unsigned, unsigned> -MemberPointerType::getMSMemberPointerSlots() const { - const CXXRecordDecl *RD = this->getClass()->getAsCXXRecordDecl(); +static std::pair<unsigned, unsigned> +getMSMemberPointerSlots(const MemberPointerType *MPT) { + const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); unsigned Ptrs; unsigned Ints = 0; - if (this->isMemberFunctionPointer()) { + if (MPT->isMemberFunctionPointer()) { // Member function pointers are a struct of a function pointer followed by a // variable number of ints depending on the inheritance model used. The // function pointer is a real function if it is non-virtual and a vftable @@ -137,7 +137,9 @@ MemberPointerType::getMSMemberPointerSlots() const { switch (Inheritance) { case MSIM_Unspecified: ++Ints; // VBTableOffset case MSIM_Virtual: ++Ints; // VirtualBaseAdjustmentOffset + case MSIM_MultiplePolymorphic: case MSIM_Multiple: ++Ints; // NonVirtualBaseAdjustment + case MSIM_SinglePolymorphic: case MSIM_Single: break; // Nothing } } else { @@ -147,7 +149,9 @@ MemberPointerType::getMSMemberPointerSlots() const { switch (Inheritance) { case MSIM_Unspecified: ++Ints; // VBTableOffset case MSIM_Virtual: ++Ints; // VirtualBaseAdjustmentOffset + case MSIM_MultiplePolymorphic: case MSIM_Multiple: // Nothing + case MSIM_SinglePolymorphic: case MSIM_Single: ++Ints; // Field offset } } @@ -160,7 +164,7 @@ std::pair<uint64_t, unsigned> MicrosoftCXXABI::getMemberPointerWidthAndAlign( assert(Target.getTriple().getArch() == llvm::Triple::x86 || Target.getTriple().getArch() == llvm::Triple::x86_64); unsigned Ptrs, Ints; - llvm::tie(Ptrs, Ints) = MPT->getMSMemberPointerSlots(); + llvm::tie(Ptrs, Ints) = getMSMemberPointerSlots(MPT); // The nominal struct is laid out with pointers followed by ints and aligned // to a pointer width if any are present and an int width otherwise. unsigned PtrSize = Target.getPointerWidth(0); diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index 40f8730..1785063 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -59,6 +59,8 @@ class MicrosoftCXXNameMangler { ASTContext &getASTContext() const { return Context.getASTContext(); } public: + enum QualifierMangleMode { QMM_Drop, QMM_Mangle, QMM_Escape, QMM_Result }; + MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_) : Context(C), Out(Out_), Structor(0), StructorType(-1), @@ -78,7 +80,8 @@ public: void mangleVariableEncoding(const VarDecl *VD); void mangleNumber(int64_t Number); void mangleNumber(const llvm::APSInt &Value); - void mangleType(QualType T, SourceRange Range, bool MangleQualifiers = true); + void mangleType(QualType T, SourceRange Range, + QualifierMangleMode QMM = QMM_Mangle); private: void disableBackReferences() { UseNameBackReferences = false; } @@ -112,10 +115,10 @@ private: #undef TYPE void mangleType(const TagType*); - void mangleType(const FunctionType *T, const FunctionDecl *D, - bool IsStructor, bool IsInstMethod); - void mangleType(const ArrayType *T, bool IsGlobal); - void mangleExtraDimensions(QualType T); + void mangleFunctionType(const FunctionType *T, const FunctionDecl *D, + bool IsStructor, bool IsInstMethod); + void mangleDecayedArrayType(const ArrayType *T, bool IsGlobal); + void mangleArrayType(const ArrayType *T, Qualifiers Quals); void mangleFunctionClass(const FunctionDecl *FD); void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false); void mangleIntegerLiteral(const llvm::APSInt &Number, bool IsBoolean); @@ -264,7 +267,7 @@ void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { // First, the function class. mangleFunctionClass(FD); - mangleType(FT, FD, InStructor, InInstMethod); + mangleFunctionType(FT, FD, InStructor, InInstMethod); } void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { @@ -297,14 +300,17 @@ void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { TypeLoc TL = VD->getTypeSourceInfo()->getTypeLoc(); QualType Ty = TL.getType(); if (Ty->isPointerType() || Ty->isReferenceType()) { - mangleType(Ty, TL.getSourceRange()); + mangleType(Ty, TL.getSourceRange(), QMM_Drop); mangleQualifiers(Ty->getPointeeType().getQualifiers(), false); } else if (const ArrayType *AT = getASTContext().getAsArrayType(Ty)) { // Global arrays are funny, too. - mangleType(AT, true); - mangleQualifiers(Ty.getQualifiers(), false); + mangleDecayedArrayType(AT, true); + if (AT->getElementType()->isArrayType()) + Out << 'A'; + else + mangleQualifiers(Ty.getQualifiers(), false); } else { - mangleType(Ty.getLocalUnqualifiedType(), TL.getSourceRange()); + mangleType(Ty, TL.getSourceRange(), QMM_Drop); mangleQualifiers(Ty.getLocalQualifiers(), false); } } @@ -824,9 +830,11 @@ MicrosoftCXXNameMangler::mangleTemplateArgs(const TemplateDecl *TD, switch (TA.getKind()) { case TemplateArgument::Null: llvm_unreachable("Can't mangle null template arguments!"); - case TemplateArgument::Type: - mangleType(TA.getAsType(), SourceRange()); + case TemplateArgument::Type: { + QualType T = TA.getAsType(); + mangleType(T, SourceRange(), QMM_Escape); break; + } case TemplateArgument::Declaration: mangle(cast<NamedDecl>(TA.getAsDecl()), "$1?"); break; @@ -964,7 +972,14 @@ void MicrosoftCXXNameMangler::mangleArgumentType(QualType T, if (Found == TypeBackReferences.end()) { size_t OutSizeBefore = Out.GetNumBytesInBuffer(); - mangleType(T, Range, false); + if (const ArrayType *AT = getASTContext().getAsArrayType(T)) { + mangleDecayedArrayType(AT, false); + } else if (const FunctionType *FT = T->getAs<FunctionType>()) { + Out << "P6"; + mangleFunctionType(FT, 0, false, false); + } else { + mangleType(T, Range, QMM_Drop); + } // See if it's worth creating a back reference. // Only types longer than 1 character are considered @@ -980,28 +995,53 @@ void MicrosoftCXXNameMangler::mangleArgumentType(QualType T, } void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range, - bool MangleQualifiers) { + QualifierMangleMode QMM) { // Only operate on the canonical type! T = getASTContext().getCanonicalType(T); - Qualifiers Quals = T.getLocalQualifiers(); - // We have to mangle these now, while we still have enough information. - if (T->isAnyPointerType() || T->isMemberPointerType() || - T->isBlockPointerType()) { - manglePointerQualifiers(Quals); - } else if (Quals && MangleQualifiers) { - mangleQualifiers(Quals, false); + + if (const ArrayType *AT = dyn_cast<ArrayType>(T)) { + if (QMM == QMM_Mangle) + Out << 'A'; + else if (QMM == QMM_Escape || QMM == QMM_Result) + Out << "$$B"; + mangleArrayType(AT, Quals); + return; } - SplitQualType split = T.split(); - const Type *ty = split.Ty; + bool IsPointer = T->isAnyPointerType() || T->isMemberPointerType() || + T->isBlockPointerType(); - // If we're mangling a qualified array type, push the qualifiers to - // the element type. - if (split.Quals && isa<ArrayType>(T)) { - ty = Context.getASTContext().getAsArrayType(T); + switch (QMM) { + case QMM_Drop: + break; + case QMM_Mangle: + if (const FunctionType *FT = dyn_cast<FunctionType>(T)) { + Out << '6'; + mangleFunctionType(FT, 0, false, false); + return; + } + mangleQualifiers(Quals, false); + break; + case QMM_Escape: + if (!IsPointer && Quals) { + Out << "$$C"; + mangleQualifiers(Quals, false); + } + break; + case QMM_Result: + if ((!IsPointer && Quals) || isa<TagType>(T)) { + Out << '?'; + mangleQualifiers(Quals, false); + } + break; } + // We have to mangle these now, while we still have enough information. + if (IsPointer) + manglePointerQualifiers(Quals); + const Type *ty = T.getTypePtr(); + switch (ty->getTypeClass()) { #define ABSTRACT_TYPE(CLASS, PARENT) #define NON_CANONICAL_TYPE(CLASS, PARENT) \ @@ -1111,17 +1151,17 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T, // structor type. // FIXME: This may not be lambda-friendly. Out << "$$A6"; - mangleType(T, NULL, false, false); + mangleFunctionType(T, NULL, false, false); } void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T, SourceRange) { llvm_unreachable("Can't mangle K&R function prototypes"); } -void MicrosoftCXXNameMangler::mangleType(const FunctionType *T, - const FunctionDecl *D, - bool IsStructor, - bool IsInstMethod) { +void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, + const FunctionDecl *D, + bool IsStructor, + bool IsInstMethod) { // <function-type> ::= <this-cvr-qualifiers> <calling-convention> // <return-type> <argument-list> <throw-spec> const FunctionProtoType *Proto = cast<FunctionProtoType>(T); @@ -1147,21 +1187,7 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionType *T, } Out << '@'; } else { - QualType Result = Proto->getResultType(); - const Type* RT = Result.getTypePtr(); - if (!RT->isAnyPointerType() && !RT->isReferenceType()) { - if (Result.hasQualifiers() || !RT->isBuiltinType()) - Out << '?'; - if (!RT->isBuiltinType() && !Result.hasQualifiers()) { - // Lack of qualifiers for user types is mangled as 'A'. - Out << 'A'; - } - } - - // FIXME: Get the source range for the result type. Or, better yet, - // implement the unimplemented stuff so we don't need accurate source - // location info anymore :). - mangleType(Result, SourceRange()); + mangleType(Proto->getResultType(), SourceRange(), QMM_Result); } // <argument-list> ::= X # void @@ -1356,7 +1382,8 @@ void MicrosoftCXXNameMangler::mangleType(const TagType *T) { // It's supposed to be the other way around, but for some strange reason, it // isn't. Today this behavior is retained for the sole purpose of backwards // compatibility. -void MicrosoftCXXNameMangler::mangleType(const ArrayType *T, bool IsGlobal) { +void MicrosoftCXXNameMangler::mangleDecayedArrayType(const ArrayType *T, + bool IsGlobal) { // This isn't a recursive mangling, so now we have to do it all in this // one call. if (IsGlobal) { @@ -1364,25 +1391,27 @@ void MicrosoftCXXNameMangler::mangleType(const ArrayType *T, bool IsGlobal) { } else { Out << 'Q'; } - mangleExtraDimensions(T->getElementType()); + mangleType(T->getElementType(), SourceRange()); } void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T, SourceRange) { - mangleType(cast<ArrayType>(T), false); + llvm_unreachable("Should have been special cased"); } void MicrosoftCXXNameMangler::mangleType(const VariableArrayType *T, SourceRange) { - mangleType(cast<ArrayType>(T), false); + llvm_unreachable("Should have been special cased"); } void MicrosoftCXXNameMangler::mangleType(const DependentSizedArrayType *T, SourceRange) { - mangleType(cast<ArrayType>(T), false); + llvm_unreachable("Should have been special cased"); } void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T, SourceRange) { - mangleType(cast<ArrayType>(T), false); + llvm_unreachable("Should have been special cased"); } -void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) { +void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T, + Qualifiers Quals) { + QualType ElementTy(T, 0); SmallVector<llvm::APInt, 3> Dimensions; for (;;) { if (const ConstantArrayType *CAT = @@ -1408,20 +1437,20 @@ void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) { Diags.Report(DSAT->getSizeExpr()->getExprLoc(), DiagID) << DSAT->getBracketsRange(); return; - } else if (ElementTy->isIncompleteArrayType()) continue; - else break; - } - mangleQualifiers(ElementTy.getQualifiers(), false); - // If there are any additional dimensions, mangle them now. - if (Dimensions.size() > 0) { - Out << 'Y'; - // <dimension-count> ::= <number> # number of extra dimensions - mangleNumber(Dimensions.size()); - for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim) { - mangleNumber(Dimensions[Dim].getLimitedValue()); + } else if (const IncompleteArrayType *IAT = + getASTContext().getAsIncompleteArrayType(ElementTy)) { + Dimensions.push_back(llvm::APInt(32, 0)); + ElementTy = IAT->getElementType(); } + else break; } - mangleType(ElementTy.getLocalUnqualifiedType(), SourceRange()); + Out << 'Y'; + // <dimension-count> ::= <number> # number of extra dimensions + mangleNumber(Dimensions.size()); + for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim) + mangleNumber(Dimensions[Dim].getLimitedValue()); + mangleType(getASTContext().getQualifiedType(ElementTy.getTypePtr(), Quals), + SourceRange(), QMM_Escape); } // <type> ::= <pointer-to-member-type> @@ -1433,11 +1462,11 @@ void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T, if (const FunctionProtoType *FPT = PointeeType->getAs<FunctionProtoType>()) { Out << '8'; mangleName(T->getClass()->castAs<RecordType>()->getDecl()); - mangleType(FPT, NULL, false, true); + mangleFunctionType(FPT, NULL, false, true); } else { mangleQualifiers(PointeeType.getQualifiers(), true); mangleName(T->getClass()->castAs<RecordType>()->getDecl()); - mangleType(PointeeType.getLocalUnqualifiedType(), Range); + mangleType(PointeeType, Range, QMM_Drop); } } @@ -1465,17 +1494,7 @@ void MicrosoftCXXNameMangler::mangleType( void MicrosoftCXXNameMangler::mangleType(const PointerType *T, SourceRange Range) { QualType PointeeTy = T->getPointeeType(); - if (PointeeTy->isArrayType()) { - // Pointers to arrays are mangled like arrays. - mangleExtraDimensions(PointeeTy); - } else if (const FunctionType *FT = PointeeTy->getAs<FunctionType>()) { - // Function pointers are special. - Out << '6'; - mangleType(FT, NULL, false, false); - } else { - mangleQualifiers(PointeeTy.getQualifiers(), false); - mangleType(PointeeTy, Range, false); - } + mangleType(PointeeTy, Range); } void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T, SourceRange Range) { @@ -1489,11 +1508,7 @@ void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T, void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T, SourceRange Range) { Out << 'A'; - QualType PointeeTy = T->getPointeeType(); - if (!PointeeTy.hasQualifiers()) - // Lack of qualifiers is mangled as 'A'. - Out << 'A'; - mangleType(PointeeTy, Range); + mangleType(T->getPointeeType(), Range); } // <type> ::= <r-value-reference-type> @@ -1501,11 +1516,7 @@ void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T, void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T, SourceRange Range) { Out << "$$Q"; - QualType PointeeTy = T->getPointeeType(); - if (!PointeeTy.hasQualifiers()) - // Lack of qualifiers is mangled as 'A'. - Out << 'A'; - mangleType(PointeeTy, Range); + mangleType(T->getPointeeType(), Range); } void MicrosoftCXXNameMangler::mangleType(const ComplexType *T, @@ -1587,7 +1598,7 @@ void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T, Out << "_E"; QualType pointee = T->getPointeeType(); - mangleType(pointee->castAs<FunctionProtoType>(), NULL, false, false); + mangleFunctionType(pointee->castAs<FunctionProtoType>(), NULL, false, false); } void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *T, diff --git a/lib/AST/RawCommentList.cpp b/lib/AST/RawCommentList.cpp index f2386a5..92b96dc 100644 --- a/lib/AST/RawCommentList.cpp +++ b/lib/AST/RawCommentList.cpp @@ -21,8 +21,10 @@ using namespace clang; namespace { /// Get comment kind and bool describing if it is a trailing comment. -std::pair<RawComment::CommentKind, bool> getCommentKind(StringRef Comment) { - if (Comment.size() < 3 || Comment[0] != '/') +std::pair<RawComment::CommentKind, bool> getCommentKind(StringRef Comment, + bool ParseAllComments) { + const size_t MinCommentLength = ParseAllComments ? 2 : 3; + if ((Comment.size() < MinCommentLength) || Comment[0] != '/') return std::make_pair(RawComment::RCK_Invalid, false); RawComment::CommentKind K; @@ -63,9 +65,10 @@ bool mergedCommentIsTrailingComment(StringRef Comment) { } // unnamed namespace RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR, - bool Merged) : + bool Merged, bool ParseAllComments) : Range(SR), RawTextValid(false), BriefTextValid(false), IsAttached(false), IsAlmostTrailingComment(false), + ParseAllComments(ParseAllComments), BeginLineValid(false), EndLineValid(false) { // Extract raw comment text, if possible. if (SR.getBegin() == SR.getEnd() || getRawText(SourceMgr).empty()) { @@ -75,7 +78,7 @@ RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR, if (!Merged) { // Guess comment kind. - std::pair<CommentKind, bool> K = getCommentKind(RawText); + std::pair<CommentKind, bool> K = getCommentKind(RawText, ParseAllComments); Kind = K.first; IsTrailingComment = K.second; @@ -143,7 +146,8 @@ const char *RawComment::extractBriefText(const ASTContext &Context) const { // a separate allocator for all temporary stuff. llvm::BumpPtrAllocator Allocator; - comments::Lexer L(Allocator, Context.getCommentCommandTraits(), + comments::Lexer L(Allocator, Context.getDiagnostics(), + Context.getCommentCommandTraits(), Range.getBegin(), RawText.begin(), RawText.end()); comments::BriefParser P(L, Context.getCommentCommandTraits()); @@ -164,7 +168,8 @@ comments::FullComment *RawComment::parse(const ASTContext &Context, // Make sure that RawText is valid. getRawText(Context.getSourceManager()); - comments::Lexer L(Context.getAllocator(), Context.getCommentCommandTraits(), + comments::Lexer L(Context.getAllocator(), Context.getDiagnostics(), + Context.getCommentCommandTraits(), getSourceRange().getBegin(), RawText.begin(), RawText.end()); comments::Sema S(Context.getAllocator(), Context.getSourceManager(), @@ -253,7 +258,8 @@ void RawCommentList::addComment(const RawComment &RC, if (C1EndLine + 1 == C2BeginLine || C1EndLine == C2BeginLine) { SourceRange MergedRange(C1.getSourceRange().getBegin(), C2.getSourceRange().getEnd()); - *Comments.back() = RawComment(SourceMgr, MergedRange, true); + *Comments.back() = RawComment(SourceMgr, MergedRange, true, + RC.isParseAllComments()); Merged = true; } } @@ -262,4 +268,3 @@ void RawCommentList::addComment(const RawComment &RC, OnlyWhitespaceSeen = true; } - diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 2ae5a12..5b29c07 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -673,19 +673,38 @@ GCCAsmStmt::GCCAsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, MSAsmStmt::MSAsmStmt(ASTContext &C, SourceLocation asmloc, SourceLocation lbraceloc, bool issimple, bool isvolatile, ArrayRef<Token> asmtoks, unsigned numoutputs, - unsigned numinputs, ArrayRef<IdentifierInfo*> names, + unsigned numinputs, ArrayRef<StringRef> constraints, ArrayRef<Expr*> exprs, StringRef asmstr, ArrayRef<StringRef> clobbers, SourceLocation endloc) : AsmStmt(MSAsmStmtClass, asmloc, issimple, isvolatile, numoutputs, numinputs, clobbers.size()), LBraceLoc(lbraceloc), - EndLoc(endloc), AsmStr(asmstr.str()), NumAsmToks(asmtoks.size()) { + EndLoc(endloc), NumAsmToks(asmtoks.size()) { - unsigned NumExprs = NumOutputs + NumInputs; + initialize(C, asmstr, asmtoks, constraints, exprs, clobbers); +} - Names = new (C) IdentifierInfo*[NumExprs]; - for (unsigned i = 0, e = NumExprs; i != e; ++i) - Names[i] = names[i]; +static StringRef copyIntoContext(ASTContext &C, StringRef str) { + size_t size = str.size(); + char *buffer = new (C) char[size]; + memcpy(buffer, str.data(), size); + return StringRef(buffer, size); +} + +void MSAsmStmt::initialize(ASTContext &C, + StringRef asmstr, + ArrayRef<Token> asmtoks, + ArrayRef<StringRef> constraints, + ArrayRef<Expr*> exprs, + ArrayRef<StringRef> clobbers) { + assert(NumAsmToks == asmtoks.size()); + assert(NumClobbers == clobbers.size()); + + unsigned NumExprs = exprs.size(); + assert(NumExprs == NumOutputs + NumInputs); + assert(NumExprs == constraints.size()); + + AsmStr = copyIntoContext(C, asmstr); Exprs = new (C) Stmt*[NumExprs]; for (unsigned i = 0, e = NumExprs; i != e; ++i) @@ -697,19 +716,13 @@ MSAsmStmt::MSAsmStmt(ASTContext &C, SourceLocation asmloc, Constraints = new (C) StringRef[NumExprs]; for (unsigned i = 0, e = NumExprs; i != e; ++i) { - size_t size = constraints[i].size(); - char *dest = new (C) char[size]; - std::strncpy(dest, constraints[i].data(), size); - Constraints[i] = StringRef(dest, size); + Constraints[i] = copyIntoContext(C, constraints[i]); } Clobbers = new (C) StringRef[NumClobbers]; for (unsigned i = 0, e = NumClobbers; i != e; ++i) { // FIXME: Avoid the allocation/copy if at all possible. - size_t size = clobbers[i].size(); - char *dest = new (C) char[size]; - std::strncpy(dest, clobbers[i].data(), size); - Clobbers[i] = StringRef(dest, size); + Clobbers[i] = copyIntoContext(C, clobbers[i]); } } @@ -1023,3 +1036,107 @@ SEHFinallyStmt* SEHFinallyStmt::Create(ASTContext &C, Stmt *Block) { return new(C)SEHFinallyStmt(Loc,Block); } + +CapturedStmt::Capture *CapturedStmt::getStoredCaptures() const { + unsigned Size = sizeof(CapturedStmt) + sizeof(Stmt *) * (NumCaptures + 1); + + // Offset of the first Capture object. + unsigned FirstCaptureOffset = + llvm::RoundUpToAlignment(Size, llvm::alignOf<Capture>()); + + return reinterpret_cast<Capture *>( + reinterpret_cast<char *>(const_cast<CapturedStmt *>(this)) + + FirstCaptureOffset); +} + +CapturedStmt::CapturedStmt(Stmt *S, CapturedRegionKind Kind, + ArrayRef<Capture> Captures, + ArrayRef<Expr *> CaptureInits, + CapturedDecl *CD, + RecordDecl *RD) + : Stmt(CapturedStmtClass), NumCaptures(Captures.size()), + CapDeclAndKind(CD, Kind), TheRecordDecl(RD) { + assert( S && "null captured statement"); + assert(CD && "null captured declaration for captured statement"); + assert(RD && "null record declaration for captured statement"); + + // Copy initialization expressions. + Stmt **Stored = getStoredStmts(); + for (unsigned I = 0, N = NumCaptures; I != N; ++I) + *Stored++ = CaptureInits[I]; + + // Copy the statement being captured. + *Stored = S; + + // Copy all Capture objects. + Capture *Buffer = getStoredCaptures(); + std::copy(Captures.begin(), Captures.end(), Buffer); +} + +CapturedStmt::CapturedStmt(EmptyShell Empty, unsigned NumCaptures) + : Stmt(CapturedStmtClass, Empty), NumCaptures(NumCaptures), + CapDeclAndKind(0, CR_Default), TheRecordDecl(0) { + getStoredStmts()[NumCaptures] = 0; +} + +CapturedStmt *CapturedStmt::Create(ASTContext &Context, Stmt *S, + CapturedRegionKind Kind, + ArrayRef<Capture> Captures, + ArrayRef<Expr *> CaptureInits, + CapturedDecl *CD, + RecordDecl *RD) { + // The layout is + // + // ----------------------------------------------------------- + // | CapturedStmt, Init, ..., Init, S, Capture, ..., Capture | + // ----------------^-------------------^---------------------- + // getStoredStmts() getStoredCaptures() + // + // where S is the statement being captured. + // + assert(CaptureInits.size() == Captures.size() && "wrong number of arguments"); + + unsigned Size = sizeof(CapturedStmt) + sizeof(Stmt *) * (Captures.size() + 1); + if (!Captures.empty()) { + // Realign for the following Capture array. + Size = llvm::RoundUpToAlignment(Size, llvm::alignOf<Capture>()); + Size += sizeof(Capture) * Captures.size(); + } + + void *Mem = Context.Allocate(Size); + return new (Mem) CapturedStmt(S, Kind, Captures, CaptureInits, CD, RD); +} + +CapturedStmt *CapturedStmt::CreateDeserialized(ASTContext &Context, + unsigned NumCaptures) { + unsigned Size = sizeof(CapturedStmt) + sizeof(Stmt *) * (NumCaptures + 1); + if (NumCaptures > 0) { + // Realign for the following Capture array. + Size = llvm::RoundUpToAlignment(Size, llvm::alignOf<Capture>()); + Size += sizeof(Capture) * NumCaptures; + } + + void *Mem = Context.Allocate(Size); + return new (Mem) CapturedStmt(EmptyShell(), NumCaptures); +} + +Stmt::child_range CapturedStmt::children() { + // Children are captured field initilizers. + return child_range(getStoredStmts(), getStoredStmts() + NumCaptures); +} + +bool CapturedStmt::capturesVariable(const VarDecl *Var) const { + for (const_capture_iterator I = capture_begin(), + E = capture_end(); I != E; ++I) { + if (I->capturesThis()) + continue; + + // This does not handle variable redeclarations. This should be + // extended to capture variables with redeclarations, for example + // a thread-private variable in OpenMP. + if (I->getCapturedVar() == Var) + return true; + } + + return false; +} diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 7df7fdb..9203dc1 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -445,11 +445,15 @@ void StmtPrinter::VisitMSAsmStmt(MSAsmStmt *Node) { Indent() << "__asm "; if (Node->hasBraces()) OS << "{\n"; - OS << *(Node->getAsmString()) << "\n"; + OS << Node->getAsmString() << "\n"; if (Node->hasBraces()) Indent() << "}\n"; } +void StmtPrinter::VisitCapturedStmt(CapturedStmt *Node) { + PrintStmt(Node->getCapturedDecl()->getBody()); +} + void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) { Indent() << "@try"; if (CompoundStmt *TS = dyn_cast<CompoundStmt>(Node->getTryBody())) { @@ -1109,24 +1113,25 @@ void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) { // AtomicExpr stores its subexpressions in a permuted order. PrintExpr(Node->getPtr()); - OS << ", "; if (Node->getOp() != AtomicExpr::AO__c11_atomic_load && Node->getOp() != AtomicExpr::AO__atomic_load_n) { - PrintExpr(Node->getVal1()); OS << ", "; + PrintExpr(Node->getVal1()); } if (Node->getOp() == AtomicExpr::AO__atomic_exchange || Node->isCmpXChg()) { - PrintExpr(Node->getVal2()); OS << ", "; + PrintExpr(Node->getVal2()); } if (Node->getOp() == AtomicExpr::AO__atomic_compare_exchange || Node->getOp() == AtomicExpr::AO__atomic_compare_exchange_n) { - PrintExpr(Node->getWeak()); OS << ", "; + PrintExpr(Node->getWeak()); } - if (Node->getOp() != AtomicExpr::AO__c11_atomic_init) + if (Node->getOp() != AtomicExpr::AO__c11_atomic_init) { + OS << ", "; PrintExpr(Node->getOrder()); + } if (Node->isCmpXChg()) { OS << ", "; PrintExpr(Node->getOrderFail()); @@ -1238,6 +1243,18 @@ void StmtPrinter::VisitCXXUuidofExpr(CXXUuidofExpr *Node) { OS << ")"; } +void StmtPrinter::VisitMSPropertyRefExpr(MSPropertyRefExpr *Node) { + PrintExpr(Node->getBaseExpr()); + if (Node->isArrow()) + OS << "->"; + else + OS << "."; + if (NestedNameSpecifier *Qualifier = + Node->getQualifierLoc().getNestedNameSpecifier()) + Qualifier->print(OS, Policy); + OS << Node->getPropertyDecl()->getDeclName(); +} + void StmtPrinter::VisitUserDefinedLiteral(UserDefinedLiteral *Node) { switch (Node->getLiteralOperatorKind()) { case UserDefinedLiteral::LOK_Raw: @@ -1298,7 +1315,11 @@ void StmtPrinter::VisitCXXThrowExpr(CXXThrowExpr *Node) { } void StmtPrinter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *Node) { - // Nothing to print: we picked up the default argument + // Nothing to print: we picked up the default argument. +} + +void StmtPrinter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *Node) { + // Nothing to print: we picked up the default initializer. } void StmtPrinter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) { diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index bfd3132..8ade242 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -215,6 +215,10 @@ void StmtProfiler::VisitSEHExceptStmt(const SEHExceptStmt *S) { VisitStmt(S); } +void StmtProfiler::VisitCapturedStmt(const CapturedStmt *S) { + VisitStmt(S); +} + void StmtProfiler::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) { VisitStmt(S); } @@ -766,6 +770,11 @@ void StmtProfiler::VisitCXXUuidofExpr(const CXXUuidofExpr *S) { VisitType(S->getTypeOperand()); } +void StmtProfiler::VisitMSPropertyRefExpr(const MSPropertyRefExpr *S) { + VisitExpr(S); + VisitDecl(S->getPropertyDecl()); +} + void StmtProfiler::VisitCXXThisExpr(const CXXThisExpr *S) { VisitExpr(S); ID.AddBoolean(S->isImplicit()); @@ -780,6 +789,11 @@ void StmtProfiler::VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *S) { VisitDecl(S->getParam()); } +void StmtProfiler::VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) { + VisitExpr(S); + VisitDecl(S->getField()); +} + void StmtProfiler::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) { VisitExpr(S); VisitDecl( diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 0c5636d..fa16fac 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1142,16 +1142,20 @@ bool QualType::isTriviallyCopyableType(ASTContext &Context) const { -bool Type::isLiteralType() const { +bool Type::isLiteralType(ASTContext &Ctx) const { if (isDependentType()) return false; - // C++0x [basic.types]p10: + // C++1y [basic.types]p10: + // A type is a literal type if it is: + // -- cv void; or + if (Ctx.getLangOpts().CPlusPlus1y && isVoidType()) + return true; + + // C++11 [basic.types]p10: // A type is a literal type if it is: // [...] - // -- an array of literal type. - // Extension: variable arrays cannot be literal types, since they're - // runtime-sized. + // -- an array of literal type other than an array of runtime bound; or if (isVariableArrayType()) return false; const Type *BaseTy = getBaseElementTypeUnsafe(); @@ -1162,7 +1166,7 @@ bool Type::isLiteralType() const { if (BaseTy->isIncompleteType()) return false; - // C++0x [basic.types]p10: + // C++11 [basic.types]p10: // A type is a literal type if it is: // -- a scalar type; or // As an extension, Clang treats vector types and complex types as @@ -2101,6 +2105,11 @@ static CachedProperties computeCachedProperties(const Type *T) { assert(T->isInstantiationDependentType()); return CachedProperties(ExternalLinkage, false); + case Type::Auto: + // Give non-deduced 'auto' types external linkage. We should only see them + // here in error recovery. + return CachedProperties(ExternalLinkage, false); + case Type::Builtin: // C++ [basic.link]p8: // A type is said to have linkage if and only if: @@ -2202,6 +2211,9 @@ static LinkageInfo computeLinkageInfo(const Type *T) { case Type::Builtin: return LinkageInfo::external(); + case Type::Auto: + return LinkageInfo::external(); + case Type::Record: case Type::Enum: return cast<TagType>(T)->getDecl()->getLinkageAndVisibility(); diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 9d1717a..0437076 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -776,16 +776,16 @@ void TypePrinter::printUnaryTransformAfter(const UnaryTransformType *T, void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) { // If the type has been deduced, do not print 'auto'. - if (T->isDeduced()) { + if (!T->getDeducedType().isNull()) { printBefore(T->getDeducedType(), OS); } else { - OS << "auto"; + OS << (T->isDecltypeAuto() ? "decltype(auto)" : "auto"); spaceBeforePlaceHolder(OS); } } void TypePrinter::printAutoAfter(const AutoType *T, raw_ostream &OS) { // If the type has been deduced, do not print 'auto'. - if (T->isDeduced()) + if (!T->getDeducedType().isNull()) printAfter(T->getDeducedType(), OS); } diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp index dda26bf..4d5c2ee 100644 --- a/lib/Analysis/BodyFarm.cpp +++ b/lib/Analysis/BodyFarm.cpp @@ -194,8 +194,8 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) { // (1) Create the call. DeclRefExpr *DR = M.makeDeclRefExpr(Block); ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty); - CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy, - VK_RValue, SourceLocation()); + CallExpr *CE = new (C) CallExpr(C, ICE, None, C.VoidTy, VK_RValue, + SourceLocation()); // (2) Create the assignment to the predicate. IntegerLiteral *IL = @@ -257,8 +257,8 @@ static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) { ASTMaker M(C); DeclRefExpr *DR = M.makeDeclRefExpr(PV); ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty); - CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy, - VK_RValue, SourceLocation()); + CallExpr *CE = new (C) CallExpr(C, ICE, None, C.VoidTy, VK_RValue, + SourceLocation()); return CE; } diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 1adb8b8..096c7a0 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -1085,11 +1085,16 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) { return VisitExprWithCleanups(cast<ExprWithCleanups>(S), asc); case Stmt::CXXDefaultArgExprClass: + case Stmt::CXXDefaultInitExprClass: // FIXME: The expression inside a CXXDefaultArgExpr is owned by the // called function's declaration, not by the caller. If we simply add // this expression to the CFG, we could end up with the same Expr // appearing multiple times. // PR13385 / <rdar://problem/12156507> + // + // It's likewise possible for multiple CXXDefaultInitExprs for the same + // expression to be used in the same function (through aggregate + // initialization). return VisitStmt(S, asc); case Stmt::CXXBindTemporaryExprClass: diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp index 4fe342d..479d9a3 100644 --- a/lib/Analysis/ThreadSafety.cpp +++ b/lib/Analysis/ThreadSafety.cpp @@ -2279,6 +2279,10 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { // Fill in source locations for all CFGBlocks. findBlockLocations(CFGraph, SortedGraph, BlockInfo); + MutexIDList ExclusiveLocksAcquired; + MutexIDList SharedLocksAcquired; + MutexIDList LocksReleased; + // Add locks from exclusive_locks_required and shared_locks_required // to initial lockset. Also turn off checking for lock and unlock functions. // FIXME: is there a more intelligent way to check lock/unlock functions? @@ -2300,15 +2304,30 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { } else if (SharedLocksRequiredAttr *A = dyn_cast<SharedLocksRequiredAttr>(Attr)) { getMutexIDs(SharedLocksToAdd, A, (Expr*) 0, D); - } else if (isa<UnlockFunctionAttr>(Attr)) { - // Don't try to check unlock functions for now - return; - } else if (isa<ExclusiveLockFunctionAttr>(Attr)) { - // Don't try to check lock functions for now - return; - } else if (isa<SharedLockFunctionAttr>(Attr)) { - // Don't try to check lock functions for now - return; + } else if (UnlockFunctionAttr *A = dyn_cast<UnlockFunctionAttr>(Attr)) { + if (!Handler.issueBetaWarnings()) + return; + // UNLOCK_FUNCTION() is used to hide the underlying lock implementation. + // We must ignore such methods. + if (A->args_size() == 0) + return; + // FIXME -- deal with exclusive vs. shared unlock functions? + getMutexIDs(ExclusiveLocksToAdd, A, (Expr*) 0, D); + getMutexIDs(LocksReleased, A, (Expr*) 0, D); + } else if (ExclusiveLockFunctionAttr *A + = dyn_cast<ExclusiveLockFunctionAttr>(Attr)) { + if (!Handler.issueBetaWarnings()) + return; + if (A->args_size() == 0) + return; + getMutexIDs(ExclusiveLocksAcquired, A, (Expr*) 0, D); + } else if (SharedLockFunctionAttr *A + = dyn_cast<SharedLockFunctionAttr>(Attr)) { + if (!Handler.issueBetaWarnings()) + return; + if (A->args_size() == 0) + return; + getMutexIDs(SharedLocksAcquired, A, (Expr*) 0, D); } else if (isa<ExclusiveTrylockFunctionAttr>(Attr)) { // Don't try to check trylock functions for now return; @@ -2491,8 +2510,27 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { if (!Final->Reachable) return; + // By default, we expect all locks held on entry to be held on exit. + FactSet ExpectedExitSet = Initial->EntrySet; + + // Adjust the expected exit set by adding or removing locks, as declared + // by *-LOCK_FUNCTION and UNLOCK_FUNCTION. The intersect below will then + // issue the appropriate warning. + // FIXME: the location here is not quite right. + for (unsigned i=0,n=ExclusiveLocksAcquired.size(); i<n; ++i) { + ExpectedExitSet.addLock(FactMan, ExclusiveLocksAcquired[i], + LockData(D->getLocation(), LK_Exclusive)); + } + for (unsigned i=0,n=SharedLocksAcquired.size(); i<n; ++i) { + ExpectedExitSet.addLock(FactMan, SharedLocksAcquired[i], + LockData(D->getLocation(), LK_Shared)); + } + for (unsigned i=0,n=LocksReleased.size(); i<n; ++i) { + ExpectedExitSet.removeLock(FactMan, LocksReleased[i]); + } + // FIXME: Should we call this function for all blocks which exit the function? - intersectAndWarn(Initial->EntrySet, Final->ExitSet, + intersectAndWarn(ExpectedExitSet, Final->ExitSet, Final->ExitLoc, LEK_LockedAtEndOfFunction, LEK_NotLockedAtEndOfFunction, diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 842bacb..45d4b53 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -971,6 +971,23 @@ bool DiagnosticConsumer::IncludeInDiagnosticCounts() const { return true; } void IgnoringDiagConsumer::anchor() { } +ForwardingDiagnosticConsumer::~ForwardingDiagnosticConsumer() {} + +void ForwardingDiagnosticConsumer::HandleDiagnostic( + DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) { + Target.HandleDiagnostic(DiagLevel, Info); +} + +void ForwardingDiagnosticConsumer::clear() { + DiagnosticConsumer::clear(); + Target.clear(); +} + +bool ForwardingDiagnosticConsumer::IncludeInDiagnosticCounts() const { + return Target.IncludeInDiagnosticCounts(); +} + PartialDiagnostic::StorageAllocator::StorageAllocator() { for (unsigned I = 0; I != NumCached; ++I) FreeList[I] = Cached + I; diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 429d9d8..951c718 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -65,7 +65,7 @@ namespace { }; } -IdentifierIterator *IdentifierInfoLookup::getIdentifiers() const { +IdentifierIterator *IdentifierInfoLookup::getIdentifiers() { return new EmptyLookupIterator(); } diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index 1b8383b..d6dc6d6 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -1848,23 +1848,42 @@ SourceManager::getMacroArgExpandedLocation(SourceLocation Loc) const { return Loc; } +std::pair<FileID, unsigned> +SourceManager::getDecomposedIncludedLoc(FileID FID) const { + // Uses IncludedLocMap to retrieve/cache the decomposed loc. + + typedef std::pair<FileID, unsigned> DecompTy; + typedef llvm::DenseMap<FileID, DecompTy> MapTy; + std::pair<MapTy::iterator, bool> + InsertOp = IncludedLocMap.insert(std::make_pair(FID, DecompTy())); + DecompTy &DecompLoc = InsertOp.first->second; + if (!InsertOp.second) + return DecompLoc; // already in map. + + SourceLocation UpperLoc; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID); + if (Entry.isExpansion()) + UpperLoc = Entry.getExpansion().getExpansionLocStart(); + else + UpperLoc = Entry.getFile().getIncludeLoc(); + + if (UpperLoc.isValid()) + DecompLoc = getDecomposedLoc(UpperLoc); + + return DecompLoc; +} + /// Given a decomposed source location, move it up the include/expansion stack /// to the parent source location. If this is possible, return the decomposed /// version of the parent in Loc and return false. If Loc is the top-level /// entry, return true and don't modify it. static bool MoveUpIncludeHierarchy(std::pair<FileID, unsigned> &Loc, const SourceManager &SM) { - SourceLocation UpperLoc; - const SrcMgr::SLocEntry &Entry = SM.getSLocEntry(Loc.first); - if (Entry.isExpansion()) - UpperLoc = Entry.getExpansion().getExpansionLocStart(); - else - UpperLoc = Entry.getFile().getIncludeLoc(); - - if (UpperLoc.isInvalid()) + std::pair<FileID, unsigned> UpperLoc = SM.getDecomposedIncludedLoc(Loc.first); + if (UpperLoc.first.isInvalid()) return true; // We reached the top. - - Loc = SM.getDecomposedLoc(UpperLoc); + + Loc = UpperLoc; return false; } @@ -1929,7 +1948,7 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, // of the other looking for a match. // We use a map from FileID to Offset to store the chain. Easier than writing // a custom set hash info that only depends on the first part of a pair. - typedef llvm::DenseMap<FileID, unsigned> LocSet; + typedef llvm::SmallDenseMap<FileID, unsigned, 16> LocSet; LocSet LChain; do { LChain.insert(LOffs); diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index 70ea235..0d44dc0 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -37,6 +37,7 @@ TargetInfo::TargetInfo(const std::string &T) : TargetOpts(), Triple(T) LongWidth = LongAlign = 32; LongLongWidth = LongLongAlign = 64; SuitableAlign = 64; + MinGlobalAlign = 0; HalfWidth = 16; HalfAlign = 16; FloatWidth = 32; @@ -373,7 +374,9 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const { Name++; } - return true; + // If a constraint allows neither memory nor register operands it contains + // only modifiers. Reject it. + return Info.allowsMemory() || Info.allowsRegister(); } bool TargetInfo::resolveSymbolicName(const char *&Name, diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 3eda9d8..a622a11 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -621,7 +621,7 @@ class NaClTargetInfo : public OSTargetInfo<Target> { this->SizeType = TargetInfo::UnsignedInt; this->PtrDiffType = TargetInfo::SignedInt; this->IntPtrType = TargetInfo::SignedInt; - this->RegParmMax = 2; + // RegParmMax is inherited from the underlying architecture this->LongDoubleFormat = &llvm::APFloat::IEEEdouble; this->DescriptionString = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-" "f32:32:32-f64:64:64-p:32:32:32-v128:32:32"; @@ -1835,6 +1835,7 @@ class X86TargetInfo : public TargetInfo { /// Bobcat architecture processors. //@{ CK_BTVER1, + CK_BTVER2, //@} /// \name Bulldozer @@ -1959,6 +1960,7 @@ public: .Case("opteron-sse3", CK_OpteronSSE3) .Case("amdfam10", CK_AMDFAM10) .Case("btver1", CK_BTVER1) + .Case("btver2", CK_BTVER2) .Case("bdver1", CK_BDVER1) .Case("bdver2", CK_BDVER2) .Case("x86-64", CK_x86_64) @@ -2024,6 +2026,7 @@ public: case CK_OpteronSSE3: case CK_AMDFAM10: case CK_BTVER1: + case CK_BTVER2: case CK_BDVER1: case CK_BDVER2: case CK_x86_64: @@ -2193,6 +2196,15 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { setFeatureEnabled(Features, "lzcnt", true); setFeatureEnabled(Features, "popcnt", true); break; + case CK_BTVER2: + setFeatureEnabled(Features, "avx", true); + setFeatureEnabled(Features, "sse4a", true); + setFeatureEnabled(Features, "lzcnt", true); + setFeatureEnabled(Features, "aes", true); + setFeatureEnabled(Features, "pclmul", true); + setFeatureEnabled(Features, "bmi", true); + setFeatureEnabled(Features, "f16c", true); + break; case CK_BDVER1: setFeatureEnabled(Features, "xop", true); setFeatureEnabled(Features, "lzcnt", true); @@ -2611,6 +2623,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, case CK_BTVER1: defineCPUMacros(Builder, "btver1"); break; + case CK_BTVER2: + defineCPUMacros(Builder, "btver2"); + break; case CK_BDVER1: defineCPUMacros(Builder, "bdver1"); break; @@ -3292,6 +3307,8 @@ namespace { class AArch64TargetInfo : public TargetInfo { static const char * const GCCRegNames[]; static const TargetInfo::GCCRegAlias GCCRegAliases[]; + + static const Builtin::Info BuiltinInfo[]; public: AArch64TargetInfo(const std::string& triple) : TargetInfo(triple) { BigEndian = false; @@ -3323,45 +3340,45 @@ public: // FIXME: these were written based on an unreleased version of a 32-bit ACLE // which was intended to be compatible with a 64-bit implementation. They // will need updating when a real 64-bit ACLE exists. Particularly pressing - // instances are: __AARCH_ISA_A32, __AARCH_ISA_T32, __ARCH_PCS. - Builder.defineMacro("__AARCH_ACLE", "101"); - Builder.defineMacro("__AARCH", "8"); - Builder.defineMacro("__AARCH_PROFILE", "'A'"); + // instances are: __ARM_ARCH_ISA_ARM, __ARM_ARCH_ISA_THUMB, __ARM_PCS. + Builder.defineMacro("__ARM_ACLE", "101"); + Builder.defineMacro("__ARM_ARCH", "8"); + Builder.defineMacro("__ARM_ARCH_PROFILE", "'A'"); - Builder.defineMacro("__AARCH_FEATURE_UNALIGNED"); - Builder.defineMacro("__AARCH_FEATURE_CLZ"); - Builder.defineMacro("__AARCH_FEATURE_FMA"); + Builder.defineMacro("__ARM_FEATURE_UNALIGNED"); + Builder.defineMacro("__ARM_FEATURE_CLZ"); + Builder.defineMacro("__ARM_FEATURE_FMA"); // FIXME: ACLE 1.1 reserves bit 4. Will almost certainly come to mean // 128-bit LDXP present, at which point this becomes 0x1f. - Builder.defineMacro("__AARCH_FEATURE_LDREX", "0xf"); + Builder.defineMacro("__ARM_FEATURE_LDREX", "0xf"); // 0xe implies support for half, single and double precision operations. - Builder.defineMacro("__AARCH_FP", "0xe"); + Builder.defineMacro("__ARM_FP", "0xe"); // PCS specifies this for SysV variants, which is all we support. Other ABIs - // may choose __AARCH_FP16_FORMAT_ALTERNATIVE. - Builder.defineMacro("__AARCH_FP16_FORMAT_IEEE"); + // may choose __ARM_FP16_FORMAT_ALTERNATIVE. + Builder.defineMacro("__ARM_FP16_FORMAT_IEEE"); if (Opts.FastMath || Opts.FiniteMathOnly) - Builder.defineMacro("__AARCH_FP_FAST"); + Builder.defineMacro("__ARM_FP_FAST"); if ((Opts.C99 || Opts.C11) && !Opts.Freestanding) - Builder.defineMacro("__AARCH_FP_FENV_ROUNDING"); + Builder.defineMacro("__ARM_FP_FENV_ROUNDING"); - Builder.defineMacro("__AARCH_SIZEOF_WCHAR_T", + Builder.defineMacro("__ARM_SIZEOF_WCHAR_T", Opts.ShortWChar ? "2" : "4"); - Builder.defineMacro("__AARCH_SIZEOF_MINIMAL_ENUM", + Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM", Opts.ShortEnums ? "1" : "4"); if (BigEndian) - Builder.defineMacro("__AARCH_BIG_ENDIAN"); + Builder.defineMacro("__ARM_BIG_ENDIAN"); } virtual void getTargetBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) const { - Records = 0; - NumRecords = 0; + Records = BuiltinInfo; + NumRecords = clang::AArch64::LastTSBuiltin-Builtin::FirstTSBuiltin; } virtual bool hasFeature(StringRef Feature) const { return Feature == "aarch64"; @@ -3470,6 +3487,14 @@ void AArch64TargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, NumAliases = llvm::array_lengthof(GCCRegAliases); } + +const Builtin::Info AArch64TargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\ + ALL_LANGUAGES }, +#include "clang/Basic/BuiltinsAArch64.def" +}; + } // end anonymous namespace namespace { @@ -3502,6 +3527,34 @@ class ARMTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; + static bool shouldUseInlineAtomic(const llvm::Triple &T) { + // On linux, binaries targeting old cpus call functions in libgcc to + // perform atomic operations. The implementation in libgcc then calls into + // the kernel which on armv6 and newer uses ldrex and strex. The net result + // is that if we assume the kernel is at least as recent as the hardware, + // it is safe to use atomic instructions on armv6 and newer. + if (T.getOS() != llvm::Triple::Linux) + return false; + StringRef ArchName = T.getArchName(); + if (T.getArch() == llvm::Triple::arm) { + if (!ArchName.startswith("armv")) + return false; + StringRef VersionStr = ArchName.substr(4); + unsigned Version; + if (VersionStr.getAsInteger(10, Version)) + return false; + return Version >= 6; + } + assert(T.getArch() == llvm::Triple::thumb); + if (!ArchName.startswith("thumbv")) + return false; + StringRef VersionStr = ArchName.substr(6); + unsigned Version; + if (VersionStr.getAsInteger(10, Version)) + return false; + return Version >= 7; + } + public: ARMTargetInfo(const std::string &TripleStr) : TargetInfo(TripleStr), ABI("aapcs-linux"), CPU("arm1136j-s"), IsAAPCS(true) @@ -3534,8 +3587,9 @@ public: TheCXXABI.set(TargetCXXABI::GenericARM); // ARM has atomics up to 8 bytes - // FIXME: Set MaxAtomicInlineWidth if we have the feature v6e MaxAtomicPromoteWidth = 64; + if (shouldUseInlineAtomic(getTriple())) + MaxAtomicInlineWidth = 64; // Do force alignment of members that follow zero length bitfields. If // the alignment of the zero-length bitfield is greater than the member @@ -4111,16 +4165,14 @@ const Builtin::Info HexagonTargetInfo::BuiltinInfo[] = { namespace { -class SparcV8TargetInfo : public TargetInfo { +// Shared base class for SPARC v8 (32-bit) and SPARC v9 (64-bit). +class SparcTargetInfo : public TargetInfo { static const TargetInfo::GCCRegAlias GCCRegAliases[]; static const char * const GCCRegNames[]; bool SoftFloat; public: - SparcV8TargetInfo(const std::string& triple) : TargetInfo(triple) { - // FIXME: Support Sparc quad-precision long double? - DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" - "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32"; - } + SparcTargetInfo(const std::string &triple) : TargetInfo(triple) {} + virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name, bool Enabled) const { @@ -4140,7 +4192,6 @@ public: virtual void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { DefineStd(Builder, "sparc", Opts); - Builder.defineMacro("__sparcv8"); Builder.defineMacro("__REGISTER_PREFIX__", ""); if (SoftFloat) @@ -4176,20 +4227,20 @@ public: } }; -const char * const SparcV8TargetInfo::GCCRegNames[] = { +const char * const SparcTargetInfo::GCCRegNames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" }; -void SparcV8TargetInfo::getGCCRegNames(const char * const *&Names, - unsigned &NumNames) const { +void SparcTargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { Names = GCCRegNames; NumNames = llvm::array_lengthof(GCCRegNames); } -const TargetInfo::GCCRegAlias SparcV8TargetInfo::GCCRegAliases[] = { +const TargetInfo::GCCRegAlias SparcTargetInfo::GCCRegAliases[] = { { { "g0" }, "r0" }, { { "g1" }, "r1" }, { { "g2" }, "r2" }, @@ -4224,11 +4275,53 @@ const TargetInfo::GCCRegAlias SparcV8TargetInfo::GCCRegAliases[] = { { { "i7" }, "r31" }, }; -void SparcV8TargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const { +void SparcTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { Aliases = GCCRegAliases; NumAliases = llvm::array_lengthof(GCCRegAliases); } + +// SPARC v8 is the 32-bit mode selected by Triple::sparc. +class SparcV8TargetInfo : public SparcTargetInfo { +public: + SparcV8TargetInfo(const std::string& triple) : SparcTargetInfo(triple) { + // FIXME: Support Sparc quad-precision long double? + DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64"; + } + + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + SparcTargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__sparcv8"); + } +}; + +// SPARC v9 is the 64-bit mode selected by Triple::sparcv9. +class SparcV9TargetInfo : public SparcTargetInfo { +public: + SparcV9TargetInfo(const std::string& triple) : SparcTargetInfo(triple) { + // FIXME: Support Sparc quad-precision long double? + DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32:64-S128"; + } + + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + SparcTargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__sparcv9"); + Builder.defineMacro("__arch64__"); + // Solaris and its derivative AuroraUX don't need these variants, but the + // BSDs do. + if (getTriple().getOS() != llvm::Triple::Solaris && + getTriple().getOS() != llvm::Triple::AuroraUX) { + Builder.defineMacro("__sparc64__"); + Builder.defineMacro("__sparc_v9__"); + Builder.defineMacro("__sparcv9__"); + } + } +}; + } // end anonymous namespace. namespace { @@ -4251,6 +4344,100 @@ public: } // end anonymous namespace. namespace { + class SystemZTargetInfo : public TargetInfo { + static const char *const GCCRegNames[]; + + public: + SystemZTargetInfo(const std::string& triple) : TargetInfo(triple) { + TLSSupported = true; + IntWidth = IntAlign = 32; + LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64; + PointerWidth = PointerAlign = 64; + LongDoubleWidth = 128; + LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEquad; + MinGlobalAlign = 16; + DescriptionString = "E-p:64:64:64-i1:8:16-i8:8:16-i16:16-i32:32-i64:64" + "-f32:32-f64:64-f128:64-a0:8:16-n32:64"; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__s390__"); + Builder.defineMacro("__s390x__"); + Builder.defineMacro("__zarch__"); + Builder.defineMacro("__LONG_DOUBLE_128__"); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + // FIXME: Implement. + Records = 0; + NumRecords = 0; + } + + virtual void getGCCRegNames(const char *const *&Names, + unsigned &NumNames) const; + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + // No aliases. + Aliases = 0; + NumAliases = 0; + } + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const; + virtual const char *getClobbers() const { + // FIXME: Is this really right? + return ""; + } + virtual BuiltinVaListKind getBuiltinVaListKind() const { + return TargetInfo::SystemZBuiltinVaList; + } + }; + + const char *const SystemZTargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "f0", "f2", "f4", "f6", "f1", "f3", "f5", "f7", + "f8", "f10", "f12", "f14", "f9", "f11", "f13", "f15" + }; + + void SystemZTargetInfo::getGCCRegNames(const char *const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); + } + + bool SystemZTargetInfo:: + validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const { + switch (*Name) { + default: + return false; + + case 'a': // Address register + case 'd': // Data register (equivalent to 'r') + case 'f': // Floating-point register + Info.setAllowsRegister(); + return true; + + case 'I': // Unsigned 8-bit constant + case 'J': // Unsigned 12-bit constant + case 'K': // Signed 16-bit constant + case 'L': // Signed 20-bit displacement (on all targets we support) + case 'M': // 0x7fffffff + return true; + + case 'Q': // Memory with base and unsigned 12-bit displacement + case 'R': // Likewise, plus an index + case 'S': // Memory with base and signed 20-bit displacement + case 'T': // Likewise, plus an index + Info.setAllowsMemory(); + return true; + } + } +} + +namespace { class MSP430TargetInfo : public TargetInfo { static const char * const GCCRegNames[]; public: @@ -4405,8 +4592,10 @@ class MipsTargetInfoBase : public TargetInfo { static const Builtin::Info BuiltinInfo[]; std::string CPU; bool IsMips16; + bool IsMicromips; + bool IsSingleFloat; enum MipsFloatABI { - HardFloat, SingleFloat, SoftFloat + HardFloat, SoftFloat } FloatABI; enum DspRevEnum { NoDSP, DSP1, DSP2 @@ -4422,6 +4611,8 @@ public: : TargetInfo(triple), CPU(CPUStr), IsMips16(false), + IsMicromips(false), + IsSingleFloat(false), FloatABI(HardFloat), DspRev(NoDSP), ABI(ABIStr) @@ -4448,18 +4639,20 @@ public: case HardFloat: Builder.defineMacro("__mips_hard_float", Twine(1)); break; - case SingleFloat: - Builder.defineMacro("__mips_hard_float", Twine(1)); - Builder.defineMacro("__mips_single_float", Twine(1)); - break; case SoftFloat: Builder.defineMacro("__mips_soft_float", Twine(1)); break; } + if (IsSingleFloat) + Builder.defineMacro("__mips_single_float", Twine(1)); + if (IsMips16) Builder.defineMacro("__mips16", Twine(1)); + if (IsMicromips) + Builder.defineMacro("__mips_micromips", Twine(1)); + switch (DspRev) { default: break; @@ -4549,7 +4742,8 @@ public: Name == "o32" || Name == "n32" || Name == "n64" || Name == "eabi" || Name == "mips32" || Name == "mips32r2" || Name == "mips64" || Name == "mips64r2" || - Name == "mips16" || Name == "dsp" || Name == "dspr2") { + Name == "mips16" || Name == "micromips" || + Name == "dsp" || Name == "dspr2") { Features[Name] = Enabled; return true; } else if (Name == "32") { @@ -4564,17 +4758,21 @@ public: virtual void HandleTargetFeatures(std::vector<std::string> &Features) { IsMips16 = false; + IsMicromips = false; + IsSingleFloat = false; FloatABI = HardFloat; DspRev = NoDSP; for (std::vector<std::string>::iterator it = Features.begin(), ie = Features.end(); it != ie; ++it) { if (*it == "+single-float") - FloatABI = SingleFloat; + IsSingleFloat = true; else if (*it == "+soft-float") FloatABI = SoftFloat; else if (*it == "+mips16") IsMips16 = true; + else if (*it == "+micromips") + IsMicromips = true; else if (*it == "+dsp") DspRev = std::max(DspRev, DSP1); else if (*it == "+dspr2") @@ -4862,7 +5060,7 @@ public: this->SizeType = TargetInfo::UnsignedInt; this->PtrDiffType = TargetInfo::SignedInt; this->IntPtrType = TargetInfo::SignedInt; - this->RegParmMax = 2; + this->RegParmMax = 0; // Disallow regparm DescriptionString = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-" "f32:32:32-f64:64:64-p:32:32:32-v128:32:32"; } @@ -5188,6 +5386,32 @@ static TargetInfo *AllocateTarget(const std::string &T) { return new SparcV8TargetInfo(T); } + case llvm::Triple::sparcv9: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<SparcV9TargetInfo>(T); + case llvm::Triple::AuroraUX: + return new AuroraUXTargetInfo<SparcV9TargetInfo>(T); + case llvm::Triple::Solaris: + return new SolarisTargetInfo<SparcV9TargetInfo>(T); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<SparcV9TargetInfo>(T); + case llvm::Triple::OpenBSD: + return new OpenBSDTargetInfo<SparcV9TargetInfo>(T); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<SparcV9TargetInfo>(T); + default: + return new SparcV9TargetInfo(T); + } + + case llvm::Triple::systemz: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<SystemZTargetInfo>(T); + default: + return new SystemZTargetInfo(T); + } + case llvm::Triple::tce: return new TCETargetInfo(T); diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp index 7381e70..743143d 100644 --- a/lib/Basic/Version.cpp +++ b/lib/Basic/Version.cpp @@ -36,7 +36,7 @@ std::string getClangRepositoryPath() { // If the SVN_REPOSITORY is empty, try to use the SVN keyword. This helps us // pick up a tag in an SVN export, for example. - static StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $"); + static StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/tags/RELEASE_33/final/lib/Basic/Version.cpp $"); if (URL.empty()) { URL = SVNRepository.slice(SVNRepository.find(':'), SVNRepository.find("/lib/Basic")); diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h index 35780f1..df6dc72 100644 --- a/lib/CodeGen/ABIInfo.h +++ b/lib/CodeGen/ABIInfo.h @@ -22,6 +22,7 @@ namespace llvm { namespace clang { class ASTContext; + class TargetInfo; namespace CodeGen { class CGFunctionInfo; @@ -196,6 +197,7 @@ namespace clang { ASTContext &getContext() const; llvm::LLVMContext &getVMContext() const; const llvm::DataLayout &getDataLayout() const; + const TargetInfo &getTarget() const; /// Return the calling convention to use for system runtime /// functions. diff --git a/lib/CodeGen/CGAtomic.cpp b/lib/CodeGen/CGAtomic.cpp index 817d5c4..0b48a5c 100644 --- a/lib/CodeGen/CGAtomic.cpp +++ b/lib/CodeGen/CGAtomic.cpp @@ -327,7 +327,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) { CharUnits alignChars = getContext().getTypeAlignInChars(AtomicTy); unsigned Align = alignChars.getQuantity(); unsigned MaxInlineWidthInBits = - getContext().getTargetInfo().getMaxAtomicInlineWidth(); + getTarget().getMaxAtomicInlineWidth(); bool UseLibcall = (Size != Align || getContext().toBits(sizeChars) > MaxInlineWidthInBits); @@ -483,15 +483,6 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) { Args.add(RValue::get(EmitCastToVoidPtr(Dest)), getContext().VoidPtrTy); break; -#if 0 - // These are only defined for 1-16 byte integers. It is not clear what - // their semantics would be on anything else... - case AtomicExpr::Add: LibCallName = "__atomic_fetch_add_generic"; break; - case AtomicExpr::Sub: LibCallName = "__atomic_fetch_sub_generic"; break; - case AtomicExpr::And: LibCallName = "__atomic_fetch_and_generic"; break; - case AtomicExpr::Or: LibCallName = "__atomic_fetch_or_generic"; break; - case AtomicExpr::Xor: LibCallName = "__atomic_fetch_xor_generic"; break; -#endif default: return EmitUnsupportedRValue(E, "atomic library call"); } // order is always the last parameter diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 227ee2d..ded019e 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -695,8 +695,8 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { bool isLambdaConv = blockInfo.getBlockDecl()->isConversionFromLambda(); llvm::Constant *blockFn = CodeGenFunction(CGM, true).GenerateBlockFunction(CurGD, blockInfo, - CurFuncDecl, LocalDeclMap, - isLambdaConv); + LocalDeclMap, + isLambdaConv); blockFn = llvm::ConstantExpr::getBitCast(blockFn, VoidPtrTy); // If there is nothing to capture, we can emit this as a global block. @@ -753,6 +753,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { if (capture.isConstant()) continue; QualType type = variable->getType(); + CharUnits align = getContext().getDeclAlign(variable); // This will be a [[type]]*, except that a byref entry will just be // an i8**. @@ -796,21 +797,21 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { if (ci->isByRef()) { // Get a void* that points to the byref struct. if (ci->isNested()) - src = Builder.CreateLoad(src, "byref.capture"); + src = Builder.CreateAlignedLoad(src, align.getQuantity(), + "byref.capture"); else src = Builder.CreateBitCast(src, VoidPtrTy); // Write that void* into the capture field. - Builder.CreateStore(src, blockField); + Builder.CreateAlignedStore(src, blockField, align.getQuantity()); // If we have a copy constructor, evaluate that into the block field. } else if (const Expr *copyExpr = ci->getCopyExpr()) { if (blockDecl->isConversionFromLambda()) { // If we have a lambda conversion, emit the expression // directly into the block instead. - CharUnits Align = getContext().getTypeAlignInChars(type); AggValueSlot Slot = - AggValueSlot::forAddr(blockField, Align, Qualifiers(), + AggValueSlot::forAddr(blockField, align, Qualifiers(), AggValueSlot::IsDestructed, AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased); @@ -821,7 +822,27 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { // If it's a reference variable, copy the reference into the block field. } else if (type->isReferenceType()) { - Builder.CreateStore(Builder.CreateLoad(src, "ref.val"), blockField); + llvm::Value *ref = + Builder.CreateAlignedLoad(src, align.getQuantity(), "ref.val"); + Builder.CreateAlignedStore(ref, blockField, align.getQuantity()); + + // If this is an ARC __strong block-pointer variable, don't do a + // block copy. + // + // TODO: this can be generalized into the normal initialization logic: + // we should never need to do a block-copy when initializing a local + // variable, because the local variable's lifetime should be strictly + // contained within the stack block's. + } else if (type.getObjCLifetime() == Qualifiers::OCL_Strong && + type->isBlockPointerType()) { + // Load the block and do a simple retain. + LValue srcLV = MakeAddrLValue(src, type, align); + llvm::Value *value = EmitLoadOfScalar(srcLV); + value = EmitARCRetainNonBlock(value); + + // Do a primitive store to the block field. + LValue destLV = MakeAddrLValue(blockField, type, align); + EmitStoreOfScalar(value, destLV, /*init*/ true); // Otherwise, fake up a POD copy into the block field. } else { @@ -839,8 +860,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { ImplicitCastExpr l2r(ImplicitCastExpr::OnStack, type, CK_LValueToRValue, &declRef, VK_RValue); EmitExprAsInit(&l2r, &blockFieldPseudoVar, - MakeAddrLValue(blockField, type, - getContext().getDeclAlign(variable)), + MakeAddrLValue(blockField, type, align), /*captured by init*/ false); } @@ -1014,7 +1034,7 @@ CodeGenModule::GetAddrOfGlobalBlock(const BlockExpr *blockExpr, llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap; blockFn = CodeGenFunction(*this).GenerateBlockFunction(GlobalDecl(), blockInfo, - 0, LocalDeclMap, + LocalDeclMap, false); } blockFn = llvm::ConstantExpr::getBitCast(blockFn, VoidPtrTy); @@ -1068,7 +1088,6 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM, llvm::Function * CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, const CGBlockInfo &blockInfo, - const Decl *outerFnDecl, const DeclMapTy &ldm, bool IsLambdaConversionToBlock) { const BlockDecl *blockDecl = blockInfo.getBlockDecl(); @@ -1128,7 +1147,6 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, // Begin generating the function. StartFunction(blockDecl, fnType->getResultType(), fn, fnInfo, args, blockInfo.getBlockExpr()->getBody()->getLocStart()); - CurFuncDecl = outerFnDecl; // StartFunction sets this to blockDecl // Okay. Undo some of what StartFunction did. @@ -1149,11 +1167,9 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, Alloca->setAlignment(Align); // Set the DebugLocation to empty, so the store is recognized as a // frame setup instruction by llvm::DwarfDebug::beginFunction(). - llvm::DebugLoc Empty; - llvm::DebugLoc Loc = Builder.getCurrentDebugLocation(); - Builder.SetCurrentDebugLocation(Empty); + Builder.DisableDebugLocations(); Builder.CreateAlignedStore(BlockPointer, Alloca, Align); - Builder.SetCurrentDebugLocation(Loc); + Builder.EnableDebugLocations(); BlockPointerDbgLoc = Alloca; } @@ -1166,23 +1182,6 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, CXXThisValue = Builder.CreateLoad(addr, "this"); } - // LoadObjCSelf() expects there to be an entry for 'self' in LocalDeclMap; - // appease it. - if (const ObjCMethodDecl *method - = dyn_cast_or_null<ObjCMethodDecl>(CurFuncDecl)) { - const VarDecl *self = method->getSelfDecl(); - - // There might not be a capture for 'self', but if there is... - if (blockInfo.Captures.count(self)) { - const CGBlockInfo::Capture &capture = blockInfo.getCapture(self); - - llvm::Value *selfAddr = Builder.CreateStructGEP(BlockPointer, - capture.getIndex(), - "block.captured-self"); - LocalDeclMap[self] = selfAddr; - } - } - // Also force all the constant captures. for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(), ce = blockDecl->capture_end(); ci != ce; ++ci) { @@ -1241,7 +1240,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, } // Recover location if it was changed in the above loop. DI->EmitLocation(Builder, - cast<CompoundStmt>(blockDecl->getBody())->getRBracLoc()); + cast<CompoundStmt>(blockDecl->getBody())->getRBracLoc()); } // And resume where we left off. @@ -2062,7 +2061,8 @@ llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) { bool Packed = false; CharUnits Align = getContext().getDeclAlign(D); - if (Align > getContext().toCharUnitsFromBits(Target.getPointerAlign(0))) { + if (Align > + getContext().toCharUnitsFromBits(getTarget().getPointerAlign(0))) { // We have to insert padding. // The struct above has 2 32-bit integers. diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 3c89652..d187678 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -296,7 +296,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType); llvm::Type *ResultType = ConvertType(E->getType()); - Value *ZeroUndef = Builder.getInt1(Target.isCLZForZeroUndef()); + Value *ZeroUndef = Builder.getInt1(getTarget().isCLZForZeroUndef()); Value *Result = Builder.CreateCall2(F, ArgValue, ZeroUndef); if (Result->getType() != ResultType) Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true, @@ -313,7 +313,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType); llvm::Type *ResultType = ConvertType(E->getType()); - Value *ZeroUndef = Builder.getInt1(Target.isCLZForZeroUndef()); + Value *ZeroUndef = Builder.getInt1(getTarget().isCLZForZeroUndef()); Value *Result = Builder.CreateCall2(F, ArgValue, ZeroUndef); if (Result->getType() != ResultType) Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true, @@ -1430,7 +1430,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, const char *Name = getContext().BuiltinInfo.GetName(BuiltinID); Intrinsic::ID IntrinsicID = Intrinsic::not_intrinsic; if (const char *Prefix = - llvm::Triple::getArchTypePrefix(Target.getTriple().getArch())) + llvm::Triple::getArchTypePrefix(getTarget().getTriple().getArch())) IntrinsicID = Intrinsic::getIntrinsicForGCCBuiltin(Prefix, Name); if (IntrinsicID != Intrinsic::not_intrinsic) { @@ -1501,7 +1501,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { - switch (Target.getTriple().getArch()) { + switch (getTarget().getTriple().getArch()) { + case llvm::Triple::aarch64: + return EmitAArch64BuiltinExpr(BuiltinID, E); case llvm::Triple::arm: case llvm::Triple::thumb: return EmitARMBuiltinExpr(BuiltinID, E); @@ -1621,6 +1623,25 @@ CodeGenFunction::EmitPointerWithAlignment(const Expr *Addr) { return std::make_pair(EmitScalarExpr(Addr), Align); } +Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, + const CallExpr *E) { + if (BuiltinID == AArch64::BI__clear_cache) { + assert(E->getNumArgs() == 2 && + "Variadic __clear_cache slipped through on AArch64"); + + const FunctionDecl *FD = E->getDirectCallee(); + SmallVector<Value *, 2> Ops; + for (unsigned i = 0; i < E->getNumArgs(); i++) + Ops.push_back(EmitScalarExpr(E->getArg(i))); + llvm::Type *Ty = CGM.getTypes().ConvertType(FD->getType()); + llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty); + StringRef Name = FD->getName(); + return EmitNounwindRuntimeCall(CGM.CreateRuntimeFunction(FTy, Name), Ops); + } + + return 0; +} + Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { if (BuiltinID == ARM::BI__clear_cache) { @@ -1852,7 +1873,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, // Generate target-independent intrinsic; also need to add second argument // for whether or not clz of zero is undefined; on ARM it isn't. Function *F = CGM.getIntrinsic(Intrinsic::ctlz, Ty); - Ops.push_back(Builder.getInt1(Target.isCLZForZeroUndef())); + Ops.push_back(Builder.getInt1(getTarget().isCLZForZeroUndef())); return EmitNeonCall(F, Ops, "vclz"); } case ARM::BI__builtin_neon_vcnt_v: diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp index 0c0a76f..68fecb2 100644 --- a/lib/CodeGen/CGCXXABI.cpp +++ b/lib/CodeGen/CGCXXABI.cpp @@ -220,8 +220,12 @@ void CGCXXABI::EmitGuardedInit(CodeGenFunction &CGF, } void CGCXXABI::registerGlobalDtor(CodeGenFunction &CGF, + const VarDecl &D, llvm::Constant *dtor, llvm::Constant *addr) { + if (D.getTLSKind()) + CGM.ErrorUnsupported(&D, "non-trivial TLS destruction"); + // The default behavior is to use atexit. CGF.registerGlobalDtorWithAtExit(dtor, addr); } @@ -255,3 +259,14 @@ llvm::BasicBlock *CGCXXABI::EmitCtorCompleteObjectHandler( ErrorUnsupportedABI(CGF, "complete object detection in ctor"); return 0; } + +void CGCXXABI::EmitThreadLocalInitFuncs( + llvm::ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls, + llvm::Function *InitFunc) { +} + +LValue CGCXXABI::EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF, + const DeclRefExpr *DRE) { + ErrorUnsupportedABI(CGF, "odr-use of thread_local global"); + return LValue(); +} diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index 702e59b..1e4da63 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -101,6 +101,27 @@ public: /// kinds that the ABI says returns 'this'. virtual bool HasThisReturn(GlobalDecl GD) const { return false; } + /// Returns true if the given record type should be returned indirectly. + virtual bool isReturnTypeIndirect(const CXXRecordDecl *RD) const = 0; + + /// Specify how one should pass an argument of a record type. + enum RecordArgABI { + /// Pass it using the normal C aggregate rules for the ABI, potentially + /// introducing extra copies and passing some or all of it in registers. + RAA_Default = 0, + + /// Pass it on the stack using its defined layout. The argument must be + /// evaluated directly into the correct stack position in the arguments area, + /// and the call machinery must not move it or introduce extra copies. + RAA_DirectInMemory, + + /// Pass it as a pointer to temporary memory. + RAA_Indirect + }; + + /// Returns how an argument of the given record type should be passed. + virtual RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const = 0; + /// Find the LLVM type used to represent the given member pointer /// type. virtual llvm::Type * @@ -330,8 +351,27 @@ public: /// /// \param dtor - a function taking a single pointer argument /// \param addr - a pointer to pass to the destructor function. - virtual void registerGlobalDtor(CodeGenFunction &CGF, llvm::Constant *dtor, - llvm::Constant *addr); + virtual void registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D, + llvm::Constant *dtor, llvm::Constant *addr); + + /*************************** thread_local initialization ********************/ + + /// Emits ABI-required functions necessary to initialize thread_local + /// variables in this translation unit. + /// + /// \param Decls The thread_local declarations in this translation unit. + /// \param InitFunc If this translation unit contains any non-constant + /// initialization or non-trivial destruction for thread_local + /// variables, a function to perform the initialization. Otherwise, 0. + virtual void EmitThreadLocalInitFuncs( + llvm::ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls, + llvm::Function *InitFunc); + + /// Emit a reference to a non-local thread_local variable (including + /// triggering the initialization of all thread_local variables in its + /// translation unit). + virtual LValue EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF, + const DeclRefExpr *DRE); }; // Create an instance of a C++ ABI class: diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index faf32e3..b0f460e 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -77,9 +77,7 @@ CodeGenTypes::arrangeFreeFunctionType(CanQual<FunctionNoProtoType> FTNP) { // When translating an unprototyped function type, always use a // variadic type. return arrangeLLVMFunctionInfo(FTNP->getResultType().getUnqualifiedType(), - ArrayRef<CanQualType>(), - FTNP->getExtInfo(), - RequiredArgs(0)); + None, FTNP->getExtInfo(), RequiredArgs(0)); } /// Arrange the LLVM function layout for a value of the given function @@ -257,10 +255,8 @@ CodeGenTypes::arrangeFunctionDeclaration(const FunctionDecl *FD) { // non-variadic type. if (isa<FunctionNoProtoType>(FTy)) { CanQual<FunctionNoProtoType> noProto = FTy.getAs<FunctionNoProtoType>(); - return arrangeLLVMFunctionInfo(noProto->getResultType(), - ArrayRef<CanQualType>(), - noProto->getExtInfo(), - RequiredArgs::All); + return arrangeLLVMFunctionInfo(noProto->getResultType(), None, + noProto->getExtInfo(), RequiredArgs::All); } assert(isa<FunctionProtoType>(FTy)); @@ -420,7 +416,7 @@ CodeGenTypes::arrangeFunctionDeclaration(QualType resultType, } const CGFunctionInfo &CodeGenTypes::arrangeNullaryFunction() { - return arrangeLLVMFunctionInfo(getContext().VoidTy, ArrayRef<CanQualType>(), + return arrangeLLVMFunctionInfo(getContext().VoidTy, None, FunctionType::ExtInfo(), RequiredArgs::All); } @@ -837,12 +833,11 @@ bool CodeGenModule::ReturnTypeUsesFPRet(QualType ResultType) { default: return false; case BuiltinType::Float: - return getContext().getTargetInfo().useObjCFPRetForRealType(TargetInfo::Float); + return getTarget().useObjCFPRetForRealType(TargetInfo::Float); case BuiltinType::Double: - return getContext().getTargetInfo().useObjCFPRetForRealType(TargetInfo::Double); + return getTarget().useObjCFPRetForRealType(TargetInfo::Double); case BuiltinType::LongDouble: - return getContext().getTargetInfo().useObjCFPRetForRealType( - TargetInfo::LongDouble); + return getTarget().useObjCFPRetForRealType(TargetInfo::LongDouble); } } @@ -853,7 +848,7 @@ bool CodeGenModule::ReturnTypeUsesFP2Ret(QualType ResultType) { if (const ComplexType *CT = ResultType->getAs<ComplexType>()) { if (const BuiltinType *BT = CT->getElementType()->getAs<BuiltinType>()) { if (BT->getKind() == BuiltinType::LongDouble) - return getContext().getTargetInfo().useObjCFP2RetForComplexLongDouble(); + return getTarget().useObjCFP2RetForComplexLongDouble(); } } @@ -1197,7 +1192,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // initialize the return value. TODO: it might be nice to have // a more general mechanism for this that didn't require synthesized // return statements. - if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl)) { + if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurCodeDecl)) { if (FD->hasImplicitReturnZero()) { QualType RetTy = FD->getResultType().getUnqualifiedType(); llvm::Type* LLVMTy = CGM.getTypes().ConvertType(RetTy); @@ -1626,7 +1621,8 @@ static bool checkThisPointer(llvm::Value *ThisArg, llvm::Value *This) { return false; } -void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) { +void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI, + bool EmitRetDbgLoc) { // Functions with no result always return void. if (ReturnValue == 0) { Builder.CreateRetVoid(); @@ -1671,8 +1667,10 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) { // If there is a dominating store to ReturnValue, we can elide // the load, zap the store, and usually zap the alloca. if (llvm::StoreInst *SI = findDominatingStoreToReturnValue(*this)) { + // Reuse the debug location from the store unless we're told not to. + if (EmitRetDbgLoc) + RetDbgLoc = SI->getDebugLoc(); // Get the stored value and nuke the now-dead store. - RetDbgLoc = SI->getDebugLoc(); RV = SI->getValueOperand(); SI->eraseFromParent(); diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 2ececb0..3fd0757 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -290,7 +290,7 @@ llvm::Value *CodeGenFunction::GetVTTParameter(GlobalDecl GD, return 0; } - const CXXRecordDecl *RD = cast<CXXMethodDecl>(CurFuncDecl)->getParent(); + const CXXRecordDecl *RD = cast<CXXMethodDecl>(CurCodeDecl)->getParent(); const CXXRecordDecl *Base = cast<CXXMethodDecl>(GD.getDecl())->getParent(); llvm::Value *VTT; @@ -710,7 +710,7 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) { // Before we go any further, try the complete->base constructor // delegation optimization. if (CtorType == Ctor_Complete && IsConstructorDelegationValid(Ctor) && - CGM.getContext().getTargetInfo().getCXXABI().hasConstructorVariants()) { + CGM.getTarget().getCXXABI().hasConstructorVariants()) { if (CGDebugInfo *DI = getDebugInfo()) DI->EmitLocation(Builder, Ctor->getLocEnd()); EmitDelegateCXXConstructorCall(Ctor, Ctor_Base, Args); @@ -1139,6 +1139,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, InitializeVTablePointers(ClassDecl); // And finally, initialize class members. + FieldConstructionScope FCS(*this, CXXThisValue); ConstructorMemcpyizer CM(*this, CD, Args); for (; B != E; B++) { CXXCtorInitializer *Member = (*B); @@ -1278,7 +1279,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { EnterDtorCleanups(Dtor, Dtor_Complete); if (!isTryBody && - CGM.getContext().getTargetInfo().getCXXABI().hasDestructorVariants()) { + CGM.getTarget().getCXXABI().hasDestructorVariants()) { EmitCXXDestructorCall(Dtor, Dtor_Base, /*ForVirtualBase=*/false, /*Delegating=*/false, LoadCXXThis()); break; @@ -2231,10 +2232,10 @@ void CodeGenFunction::EmitLambdaBlockInvokeBody() { } void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList &Args) { - if (cast<CXXMethodDecl>(CurFuncDecl)->isVariadic()) { + if (cast<CXXMethodDecl>(CurCodeDecl)->isVariadic()) { // FIXME: Making this work correctly is nasty because it requires either // cloning the body of the call operator or making the call operator forward. - CGM.ErrorUnsupported(CurFuncDecl, "lambda conversion to variadic function"); + CGM.ErrorUnsupported(CurCodeDecl, "lambda conversion to variadic function"); return; } diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp index 861d31f..ba6b56c 100644 --- a/lib/CodeGen/CGCleanup.cpp +++ b/lib/CodeGen/CGCleanup.cpp @@ -371,7 +371,8 @@ void CodeGenFunction::ResolveBranchFixups(llvm::BasicBlock *Block) { } /// Pops cleanup blocks until the given savepoint is reached. -void CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old) { +void CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old, + SourceLocation EHLoc) { assert(Old.isValid()); while (EHStack.stable_begin() != Old) { @@ -383,7 +384,7 @@ void CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old) { bool FallThroughIsBranchThrough = Old.strictlyEncloses(Scope.getEnclosingNormalCleanup()); - PopCleanupBlock(FallThroughIsBranchThrough); + PopCleanupBlock(FallThroughIsBranchThrough, EHLoc); } } @@ -532,7 +533,8 @@ static void destroyOptimisticNormalEntry(CodeGenFunction &CGF, /// Pops a cleanup block. If the block includes a normal cleanup, the /// current insertion point is threaded through the cleanup, as are /// any branch fixups on the cleanup. -void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { +void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough, + SourceLocation EHLoc) { assert(!EHStack.empty() && "cleanup stack is empty!"); assert(isa<EHCleanupScope>(*EHStack.begin()) && "top not a cleanup!"); EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.begin()); @@ -833,6 +835,9 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { // Emit the EH cleanup if required. if (RequiresEHCleanup) { + if (CGDebugInfo *DI = getDebugInfo()) + DI->EmitLocation(Builder, EHLoc); + CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP(); EmitBlock(EHEntry); @@ -840,6 +845,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { // We only actually emit the cleanup code if the cleanup is either // active or was used before it was deactivated. if (EHActiveFlag || IsActive) { + cleanupFlags.setIsForEHCleanup(); EmitCleanup(*this, Fn, cleanupFlags, EHActiveFlag); } diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 711d686..ddcb931 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -89,7 +89,7 @@ void CGDebugInfo::setLocation(SourceLocation Loc) { } /// getContextDescriptor - Get context info for the decl. -llvm::DIDescriptor CGDebugInfo::getContextDescriptor(const Decl *Context) { +llvm::DIScope CGDebugInfo::getContextDescriptor(const Decl *Context) { if (!Context) return TheCU; @@ -97,20 +97,17 @@ llvm::DIDescriptor CGDebugInfo::getContextDescriptor(const Decl *Context) { I = RegionMap.find(Context); if (I != RegionMap.end()) { llvm::Value *V = I->second; - return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(V)); + return llvm::DIScope(dyn_cast_or_null<llvm::MDNode>(V)); } // Check namespace. if (const NamespaceDecl *NSDecl = dyn_cast<NamespaceDecl>(Context)) - return llvm::DIDescriptor(getOrCreateNameSpace(NSDecl)); + return getOrCreateNameSpace(NSDecl); - if (const RecordDecl *RDecl = dyn_cast<RecordDecl>(Context)) { - if (!RDecl->isDependentType()) { - llvm::DIType Ty = getOrCreateType(CGM.getContext().getTypeDeclType(RDecl), + if (const RecordDecl *RDecl = dyn_cast<RecordDecl>(Context)) + if (!RDecl->isDependentType()) + return getOrCreateType(CGM.getContext().getTypeDeclType(RDecl), getOrCreateMainFile()); - return llvm::DIDescriptor(Ty); - } - } return TheCU; } @@ -642,7 +639,7 @@ llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag, // Size is always the size of a pointer. We can't use getTypeSize here // because that does not return the correct value for references. unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy); - uint64_t Size = CGM.getContext().getTargetInfo().getPointerWidth(AS); + uint64_t Size = CGM.getTarget().getPointerWidth(AS); uint64_t Align = CGM.getContext().getTypeAlign(Ty); return DBuilder.createPointerType(CreatePointeeType(PointeeTy, Unit), @@ -984,7 +981,7 @@ llvm::DIType CGDebugInfo::getOrCreateInstanceMethodType( const PointerType *ThisPtrTy = cast<PointerType>(ThisPtr); QualType PointeeTy = ThisPtrTy->getPointeeType(); unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy); - uint64_t Size = CGM.getContext().getTargetInfo().getPointerWidth(AS); + uint64_t Size = CGM.getTarget().getPointerWidth(AS); uint64_t Align = CGM.getContext().getTypeAlign(ThisPtrTy); llvm::DIType PointeeType = getOrCreateType(PointeeTy, Unit); llvm::DIType ThisPtrType = DBuilder.createPointerType(PointeeType, Size, Align); @@ -1699,7 +1696,7 @@ llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) { unsigned Line = getLineNumber(ED->getLocation()); llvm::DIDescriptor EnumContext = getContextDescriptor(cast<Decl>(ED->getDeclContext())); - llvm::DIType ClassTy = ED->isScopedUsingClassTag() ? + llvm::DIType ClassTy = ED->isFixed() ? getOrCreateType(ED->getIntegerType(), DefUnit) : llvm::DIType(); llvm::DIType DbgTy = DBuilder.createEnumerationType(EnumContext, ED->getName(), DefUnit, Line, @@ -2398,7 +2395,7 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD, CharUnits Align = CGM.getContext().getDeclAlign(VD); if (Align > CGM.getContext().toCharUnitsFromBits( - CGM.getContext().getTargetInfo().getPointerAlign(0))) { + CGM.getTarget().getPointerAlign(0))) { CharUnits FieldOffsetInBytes = CGM.getContext().toCharUnitsFromBits(FieldOffset); CharUnits AlignedOffsetInBytes @@ -2494,7 +2491,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); // offset of __forwarding field offset = CGM.getContext().toCharUnitsFromBits( - CGM.getContext().getTargetInfo().getPointerWidth(0)); + CGM.getTarget().getPointerWidth(0)); addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref)); addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); @@ -2932,6 +2929,16 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, getStaticDataMemberDeclaration(VD)); } +void CGDebugInfo::EmitUsingDirective(const UsingDirectiveDecl &UD) { + llvm::DIScope Scope = + LexicalBlockStack.empty() + ? getContextDescriptor(cast<Decl>(UD.getDeclContext())) + : llvm::DIScope(LexicalBlockStack.back()); + DBuilder.createImportedModule( + Scope, getOrCreateNameSpace(UD.getNominatedNamespace()), + getLineNumber(UD.getLocation())); +} + /// getOrCreateNamesSpace - Return namespace descriptor for the given /// namespace decl. llvm::DINameSpace diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index 3a0df99..4080492 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -262,6 +262,9 @@ public: /// EmitGlobalVariable - Emit global variable's debug info. void EmitGlobalVariable(const ValueDecl *VD, llvm::Constant *Init); + /// \brief - Emit C++ using directive. + void EmitUsingDirective(const UsingDirectiveDecl &UD); + /// getOrCreateRecordType - Emit record type's standalone debug info. llvm::DIType getOrCreateRecordType(QualType Ty, SourceLocation L); @@ -281,7 +284,7 @@ private: uint64_t *OffSet); /// getContextDescriptor - Get context info for the decl. - llvm::DIDescriptor getContextDescriptor(const Decl *Decl); + llvm::DIScope getContextDescriptor(const Decl *Decl); /// createRecordFwdDecl - Create a forward decl for a RecordType in a given /// context. diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 5375c5e..3ce6dec 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -45,6 +45,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::CXXDestructor: case Decl::CXXConversion: case Decl::Field: + case Decl::MSProperty: case Decl::IndirectField: case Decl::ObjCIvar: case Decl::ObjCAtDefsField: @@ -69,6 +70,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::Friend: case Decl::FriendTemplate: case Decl::Block: + case Decl::Captured: case Decl::ClassScopeFunctionSpecialization: llvm_unreachable("Declaration should not be in declstmts!"); case Decl::Function: // void X(); @@ -78,7 +80,6 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::CXXRecord: // struct/union/class X; [C++] case Decl::Using: // using X; [C++] case Decl::UsingShadow: - case Decl::UsingDirective: // using namespace X; [C++] case Decl::NamespaceAlias: case Decl::StaticAssert: // static_assert(X, ""); [C++0x] case Decl::Label: // __label__ x; @@ -88,6 +89,10 @@ void CodeGenFunction::EmitDecl(const Decl &D) { // None of these decls require codegen support. return; + case Decl::UsingDirective: // using namespace X; [C++] + if (CGDebugInfo *DI = getDebugInfo()) + DI->EmitUsingDirective(cast<UsingDirectiveDecl>(D)); + return; case Decl::Var: { const VarDecl &VD = cast<VarDecl>(D); assert(VD.isLocalVarDecl() && @@ -198,7 +203,7 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D, if (Linkage != llvm::GlobalValue::InternalLinkage) GV->setVisibility(CurFn->getVisibility()); - if (D.isThreadSpecified()) + if (D.getTLSKind()) CGM.setTLSMode(GV, D); return GV; @@ -898,7 +903,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { CharUnits allocaAlignment = alignment; if (isByRef) allocaAlignment = std::max(allocaAlignment, - getContext().toCharUnitsFromBits(Target.getPointerAlign(0))); + getContext().toCharUnitsFromBits(getTarget().getPointerAlign(0))); Alloc->setAlignment(allocaAlignment.getQuantity()); DeclPtr = Alloc; diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index 0448d31..9ffcff2 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -39,7 +39,7 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D, CodeGenModule &CGM = CGF.CGM; if (lv.isObjCStrong()) CGM.getObjCRuntime().EmitObjCGlobalAssign(CGF, CGF.EmitScalarExpr(Init), - DeclPtr, D.isThreadSpecified()); + DeclPtr, D.getTLSKind()); else if (lv.isObjCWeak()) CGM.getObjCRuntime().EmitObjCWeakAssign(CGF, CGF.EmitScalarExpr(Init), DeclPtr); @@ -80,6 +80,7 @@ static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D, case QualType::DK_objc_strong_lifetime: case QualType::DK_objc_weak_lifetime: // We don't care about releasing objects during process teardown. + assert(!D.getTLSKind() && "should have rejected this"); return; } @@ -105,7 +106,7 @@ static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D, argument = llvm::Constant::getNullValue(CGF.Int8PtrTy); } - CGM.getCXXABI().registerGlobalDtor(CGF, function, argument); + CGM.getCXXABI().registerGlobalDtor(CGF, D, function, argument); } /// Emit code to cause the variable at the given address to be considered as @@ -155,7 +156,8 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, static llvm::Function * CreateGlobalInitOrDestructFunction(CodeGenModule &CGM, llvm::FunctionType *ty, - const Twine &name); + const Twine &name, + bool TLS = false); /// Create a stub function, suitable for being passed to atexit, /// which passes the given address to the given destructor function. @@ -224,14 +226,14 @@ void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D, static llvm::Function * CreateGlobalInitOrDestructFunction(CodeGenModule &CGM, llvm::FunctionType *FTy, - const Twine &Name) { + const Twine &Name, bool TLS) { llvm::Function *Fn = llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, Name, &CGM.getModule()); - if (!CGM.getLangOpts().AppleKext) { + if (!CGM.getLangOpts().AppleKext && !TLS) { // Set the section if needed. if (const char *Section = - CGM.getContext().getTargetInfo().getStaticInitSectionSpecifier()) + CGM.getTarget().getStaticInitSectionSpecifier()) Fn->setSection(Section); } @@ -263,12 +265,20 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr, PerformInit); - if (D->hasAttr<InitPriorityAttr>()) { + if (D->getTLSKind()) { + // FIXME: Should we support init_priority for thread_local? + // FIXME: Ideally, initialization of instantiated thread_local static data + // members of class templates should not trigger initialization of other + // entities in the TU. + // FIXME: We only need to register one __cxa_thread_atexit function for the + // entire TU. + CXXThreadLocalInits.push_back(Fn); + } else if (D->hasAttr<InitPriorityAttr>()) { unsigned int order = D->getAttr<InitPriorityAttr>()->getPriority(); OrderGlobalInits Key(order, PrioritizedCXXGlobalInits.size()); PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn)); DelayedCXXInitPosition.erase(D); - } else { + } else { llvm::DenseMap<const Decl *, unsigned>::iterator I = DelayedCXXInitPosition.find(D); if (I == DelayedCXXInitPosition.end()) { @@ -281,6 +291,27 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, } } +void CodeGenModule::EmitCXXThreadLocalInitFunc() { + llvm::Function *InitFn = 0; + if (!CXXThreadLocalInits.empty()) { + // Generate a guarded initialization function. + llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false); + InitFn = CreateGlobalInitOrDestructFunction(*this, FTy, "__tls_init", + /*TLS*/ true); + llvm::GlobalVariable *Guard = new llvm::GlobalVariable( + getModule(), Int8Ty, false, llvm::GlobalVariable::InternalLinkage, + llvm::ConstantInt::get(Int8Ty, 0), "__tls_guard"); + Guard->setThreadLocal(true); + CodeGenFunction(*this) + .GenerateCXXGlobalInitFunc(InitFn, CXXThreadLocalInits, Guard); + } + + getCXXABI().EmitThreadLocalInitFuncs(CXXThreadLocals, InitFn); + + CXXThreadLocalInits.clear(); + CXXThreadLocals.clear(); +} + void CodeGenModule::EmitCXXGlobalInitFunc() { while (!CXXGlobalInits.empty() && !CXXGlobalInits.back()) @@ -320,9 +351,7 @@ CodeGenModule::EmitCXXGlobalInitFunc() { for (; I < PrioE; ++I) LocalCXXGlobalInits.push_back(I->second); - CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, - &LocalCXXGlobalInits[0], - LocalCXXGlobalInits.size()); + CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, LocalCXXGlobalInits); AddGlobalCtor(Fn, Priority); } } @@ -330,9 +359,7 @@ CodeGenModule::EmitCXXGlobalInitFunc() { llvm::Function *Fn = CreateGlobalInitOrDestructFunction(*this, FTy, "_GLOBAL__I_a"); - CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, - &CXXGlobalInits[0], - CXXGlobalInits.size()); + CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, CXXGlobalInits); AddGlobalCtor(Fn); CXXGlobalInits.clear(); @@ -379,9 +406,10 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, FinishFunction(); } -void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, - llvm::Constant **Decls, - unsigned NumDecls) { +void +CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, + ArrayRef<llvm::Constant *> Decls, + llvm::GlobalVariable *Guard) { // Initialize debug info if needed. maybeInitializeDebugInfo(); @@ -389,6 +417,22 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, getTypes().arrangeNullaryFunction(), FunctionArgList(), SourceLocation()); + llvm::BasicBlock *ExitBlock = 0; + if (Guard) { + // If we have a guard variable, check whether we've already performed these + // initializations. This happens for TLS initialization functions. + llvm::Value *GuardVal = Builder.CreateLoad(Guard); + llvm::Value *Uninit = Builder.CreateIsNull(GuardVal, "guard.uninitialized"); + // Mark as initialized before initializing anything else. If the + // initializers use previously-initialized thread_local vars, that's + // probably supposed to be OK, but the standard doesn't say. + Builder.CreateStore(llvm::ConstantInt::get(GuardVal->getType(), 1), Guard); + llvm::BasicBlock *InitBlock = createBasicBlock("init"); + ExitBlock = createBasicBlock("exit"); + Builder.CreateCondBr(Uninit, InitBlock, ExitBlock); + EmitBlock(InitBlock); + } + RunCleanupsScope Scope(*this); // When building in Objective-C++ ARC mode, create an autorelease pool @@ -397,13 +441,18 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, llvm::Value *token = EmitObjCAutoreleasePoolPush(); EmitObjCAutoreleasePoolCleanup(token); } - - for (unsigned i = 0; i != NumDecls; ++i) + + for (unsigned i = 0, e = Decls.size(); i != e; ++i) if (Decls[i]) EmitRuntimeCall(Decls[i]); Scope.ForceCleanup(); - + + if (ExitBlock) { + Builder.CreateBr(ExitBlock); + EmitBlock(ExitBlock); + } + FinishFunction(); } diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 36642bc..a088d78 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -419,14 +419,16 @@ llvm::Value *CodeGenFunction::getSelectorFromSlot() { return Builder.CreateLoad(getEHSelectorSlot(), "sel"); } -void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { +void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E, + bool KeepInsertionPoint) { if (!E->getSubExpr()) { EmitNoreturnRuntimeCallOrInvoke(getReThrowFn(CGM), ArrayRef<llvm::Value*>()); // throw is an expression, and the expression emitters expect us // to leave ourselves at a valid insertion point. - EmitBlock(createBasicBlock("throw.cont")); + if (KeepInsertionPoint) + EmitBlock(createBasicBlock("throw.cont")); return; } @@ -440,7 +442,8 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { CGM.getObjCRuntime().EmitThrowStmt(*this, S, false); // This will clear insertion point which was not cleared in // call to EmitThrowStmt. - EmitBlock(createBasicBlock("throw.cont")); + if (KeepInsertionPoint) + EmitBlock(createBasicBlock("throw.cont")); return; } @@ -478,7 +481,8 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { // throw is an expression, and the expression emitters expect us // to leave ourselves at a valid insertion point. - EmitBlock(createBasicBlock("throw.cont")); + if (KeepInsertionPoint) + EmitBlock(createBasicBlock("throw.cont")); } void CodeGenFunction::EmitStartEHSpec(const Decl *D) { diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 2f5186d..64670c5 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -184,12 +184,16 @@ CreateReferenceTemporary(CodeGenFunction &CGF, QualType Type, llvm::Type *RefTempTy = CGF.ConvertTypeForMem(Type); // Create the reference temporary. - llvm::GlobalValue *RefTemp = + llvm::GlobalVariable *RefTemp = new llvm::GlobalVariable(CGF.CGM.getModule(), RefTempTy, /*isConstant=*/false, llvm::GlobalValue::InternalLinkage, llvm::Constant::getNullValue(RefTempTy), Name.str()); + // If we're binding to a thread_local variable, the temporary is also + // thread local. + if (VD->getTLSKind()) + CGF.CGM.setTLSMode(RefTemp, *VD); return RefTemp; } } @@ -201,6 +205,7 @@ static llvm::Value * EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E, llvm::Value *&ReferenceTemporary, const CXXDestructorDecl *&ReferenceTemporaryDtor, + const InitListExpr *&ReferenceInitializerList, QualType &ObjCARCReferenceLifetimeType, const NamedDecl *InitializedDecl) { const MaterializeTemporaryExpr *M = NULL; @@ -222,156 +227,157 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E, return EmitExprForReferenceBinding(CGF, EWC->getSubExpr(), ReferenceTemporary, ReferenceTemporaryDtor, + ReferenceInitializerList, ObjCARCReferenceLifetimeType, InitializedDecl); } - RValue RV; if (E->isGLValue()) { // Emit the expression as an lvalue. LValue LV = CGF.EmitLValue(E); + assert(LV.isSimple()); + return LV.getAddress(); + } + + if (!ObjCARCReferenceLifetimeType.isNull()) { + ReferenceTemporary = CreateReferenceTemporary(CGF, + ObjCARCReferenceLifetimeType, + InitializedDecl); - if (LV.isSimple()) - return LV.getAddress(); - // We have to load the lvalue. - RV = CGF.EmitLoadOfLValue(LV); - } else { - if (!ObjCARCReferenceLifetimeType.isNull()) { - ReferenceTemporary = CreateReferenceTemporary(CGF, - ObjCARCReferenceLifetimeType, - InitializedDecl); - - - LValue RefTempDst = CGF.MakeAddrLValue(ReferenceTemporary, - ObjCARCReferenceLifetimeType); + LValue RefTempDst = CGF.MakeAddrLValue(ReferenceTemporary, + ObjCARCReferenceLifetimeType); - CGF.EmitScalarInit(E, dyn_cast_or_null<ValueDecl>(InitializedDecl), - RefTempDst, false); - - bool ExtendsLifeOfTemporary = false; - if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(InitializedDecl)) { - if (Var->extendsLifetimeOfTemporary()) - ExtendsLifeOfTemporary = true; - } else if (InitializedDecl && isa<FieldDecl>(InitializedDecl)) { + CGF.EmitScalarInit(E, dyn_cast_or_null<ValueDecl>(InitializedDecl), + RefTempDst, false); + + bool ExtendsLifeOfTemporary = false; + if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(InitializedDecl)) { + if (Var->extendsLifetimeOfTemporary()) ExtendsLifeOfTemporary = true; - } - - if (!ExtendsLifeOfTemporary) { - // Since the lifetime of this temporary isn't going to be extended, - // we need to clean it up ourselves at the end of the full expression. - switch (ObjCARCReferenceLifetimeType.getObjCLifetime()) { - case Qualifiers::OCL_None: - case Qualifiers::OCL_ExplicitNone: - case Qualifiers::OCL_Autoreleasing: - break; - - case Qualifiers::OCL_Strong: { - assert(!ObjCARCReferenceLifetimeType->isArrayType()); - CleanupKind cleanupKind = CGF.getARCCleanupKind(); - CGF.pushDestroy(cleanupKind, - ReferenceTemporary, - ObjCARCReferenceLifetimeType, - CodeGenFunction::destroyARCStrongImprecise, - cleanupKind & EHCleanup); - break; - } + } else if (InitializedDecl && isa<FieldDecl>(InitializedDecl)) { + ExtendsLifeOfTemporary = true; + } + + if (!ExtendsLifeOfTemporary) { + // Since the lifetime of this temporary isn't going to be extended, + // we need to clean it up ourselves at the end of the full expression. + switch (ObjCARCReferenceLifetimeType.getObjCLifetime()) { + case Qualifiers::OCL_None: + case Qualifiers::OCL_ExplicitNone: + case Qualifiers::OCL_Autoreleasing: + break; - case Qualifiers::OCL_Weak: - assert(!ObjCARCReferenceLifetimeType->isArrayType()); - CGF.pushDestroy(NormalAndEHCleanup, - ReferenceTemporary, - ObjCARCReferenceLifetimeType, - CodeGenFunction::destroyARCWeak, - /*useEHCleanupForArray*/ true); - break; - } + case Qualifiers::OCL_Strong: { + assert(!ObjCARCReferenceLifetimeType->isArrayType()); + CleanupKind cleanupKind = CGF.getARCCleanupKind(); + CGF.pushDestroy(cleanupKind, + ReferenceTemporary, + ObjCARCReferenceLifetimeType, + CodeGenFunction::destroyARCStrongImprecise, + cleanupKind & EHCleanup); + break; + } - ObjCARCReferenceLifetimeType = QualType(); + case Qualifiers::OCL_Weak: + assert(!ObjCARCReferenceLifetimeType->isArrayType()); + CGF.pushDestroy(NormalAndEHCleanup, + ReferenceTemporary, + ObjCARCReferenceLifetimeType, + CodeGenFunction::destroyARCWeak, + /*useEHCleanupForArray*/ true); + break; } - return ReferenceTemporary; + ObjCARCReferenceLifetimeType = QualType(); } + + return ReferenceTemporary; + } + + SmallVector<SubobjectAdjustment, 2> Adjustments; + E = E->skipRValueSubobjectAdjustments(Adjustments); + if (const OpaqueValueExpr *opaque = dyn_cast<OpaqueValueExpr>(E)) + if (opaque->getType()->isRecordType()) + return CGF.EmitOpaqueValueLValue(opaque).getAddress(); - SmallVector<SubobjectAdjustment, 2> Adjustments; - E = E->skipRValueSubobjectAdjustments(Adjustments); - if (const OpaqueValueExpr *opaque = dyn_cast<OpaqueValueExpr>(E)) - if (opaque->getType()->isRecordType()) - return CGF.EmitOpaqueValueLValue(opaque).getAddress(); - - // Create a reference temporary if necessary. - AggValueSlot AggSlot = AggValueSlot::ignored(); - if (CGF.hasAggregateEvaluationKind(E->getType())) { - ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(), - InitializedDecl); - CharUnits Alignment = CGF.getContext().getTypeAlignInChars(E->getType()); - AggValueSlot::IsDestructed_t isDestructed - = AggValueSlot::IsDestructed_t(InitializedDecl != 0); - AggSlot = AggValueSlot::forAddr(ReferenceTemporary, Alignment, - Qualifiers(), isDestructed, - AggValueSlot::DoesNotNeedGCBarriers, - AggValueSlot::IsNotAliased); + // Create a reference temporary if necessary. + AggValueSlot AggSlot = AggValueSlot::ignored(); + if (CGF.hasAggregateEvaluationKind(E->getType())) { + ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(), + InitializedDecl); + CharUnits Alignment = CGF.getContext().getTypeAlignInChars(E->getType()); + AggValueSlot::IsDestructed_t isDestructed + = AggValueSlot::IsDestructed_t(InitializedDecl != 0); + AggSlot = AggValueSlot::forAddr(ReferenceTemporary, Alignment, + Qualifiers(), isDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased); + } + + if (InitializedDecl) { + if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) { + if (ILE->initializesStdInitializerList()) { + ReferenceInitializerList = ILE; + } } - - if (InitializedDecl) { + else if (const RecordType *RT = + E->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()){ // Get the destructor for the reference temporary. - if (const RecordType *RT = - E->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) { - CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl()); - if (!ClassDecl->hasTrivialDestructor()) - ReferenceTemporaryDtor = ClassDecl->getDestructor(); - } + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl()); + if (!ClassDecl->hasTrivialDestructor()) + ReferenceTemporaryDtor = ClassDecl->getDestructor(); } + } - RV = CGF.EmitAnyExpr(E, AggSlot); - - // Check if need to perform derived-to-base casts and/or field accesses, to - // get from the temporary object we created (and, potentially, for which we - // extended the lifetime) to the subobject we're binding the reference to. - if (!Adjustments.empty()) { - llvm::Value *Object = RV.getAggregateAddr(); - for (unsigned I = Adjustments.size(); I != 0; --I) { - SubobjectAdjustment &Adjustment = Adjustments[I-1]; - switch (Adjustment.Kind) { - case SubobjectAdjustment::DerivedToBaseAdjustment: - Object = - CGF.GetAddressOfBaseClass(Object, - Adjustment.DerivedToBase.DerivedClass, - Adjustment.DerivedToBase.BasePath->path_begin(), - Adjustment.DerivedToBase.BasePath->path_end(), - /*NullCheckValue=*/false); - break; - - case SubobjectAdjustment::FieldAdjustment: { - LValue LV = CGF.MakeAddrLValue(Object, E->getType()); - LV = CGF.EmitLValueForField(LV, Adjustment.Field); - if (LV.isSimple()) { - Object = LV.getAddress(); - break; - } + RValue RV = CGF.EmitAnyExpr(E, AggSlot); + + // Check if need to perform derived-to-base casts and/or field accesses, to + // get from the temporary object we created (and, potentially, for which we + // extended the lifetime) to the subobject we're binding the reference to. + if (!Adjustments.empty()) { + llvm::Value *Object = RV.getAggregateAddr(); + for (unsigned I = Adjustments.size(); I != 0; --I) { + SubobjectAdjustment &Adjustment = Adjustments[I-1]; + switch (Adjustment.Kind) { + case SubobjectAdjustment::DerivedToBaseAdjustment: + Object = + CGF.GetAddressOfBaseClass(Object, + Adjustment.DerivedToBase.DerivedClass, + Adjustment.DerivedToBase.BasePath->path_begin(), + Adjustment.DerivedToBase.BasePath->path_end(), + /*NullCheckValue=*/false); + break; - // For non-simple lvalues, we actually have to create a copy of - // the object we're binding to. - QualType T = Adjustment.Field->getType().getNonReferenceType() - .getUnqualifiedType(); - Object = CreateReferenceTemporary(CGF, T, InitializedDecl); - LValue TempLV = CGF.MakeAddrLValue(Object, - Adjustment.Field->getType()); - CGF.EmitStoreThroughLValue(CGF.EmitLoadOfLValue(LV), TempLV); + case SubobjectAdjustment::FieldAdjustment: { + LValue LV = CGF.MakeAddrLValue(Object, E->getType()); + LV = CGF.EmitLValueForField(LV, Adjustment.Field); + if (LV.isSimple()) { + Object = LV.getAddress(); break; } - - case SubobjectAdjustment::MemberPointerAdjustment: { - llvm::Value *Ptr = CGF.EmitScalarExpr(Adjustment.Ptr.RHS); - Object = CGF.CGM.getCXXABI().EmitMemberDataPointerAddress( - CGF, Object, Ptr, Adjustment.Ptr.MPT); - break; - } - } + + // For non-simple lvalues, we actually have to create a copy of + // the object we're binding to. + QualType T = Adjustment.Field->getType().getNonReferenceType() + .getUnqualifiedType(); + Object = CreateReferenceTemporary(CGF, T, InitializedDecl); + LValue TempLV = CGF.MakeAddrLValue(Object, + Adjustment.Field->getType()); + CGF.EmitStoreThroughLValue(CGF.EmitLoadOfLValue(LV), TempLV); + break; } - return Object; + case SubobjectAdjustment::MemberPointerAdjustment: { + llvm::Value *Ptr = CGF.EmitScalarExpr(Adjustment.Ptr.RHS); + Object = CGF.CGM.getCXXABI().EmitMemberDataPointerAddress( + CGF, Object, Ptr, Adjustment.Ptr.MPT); + break; + } + } } + + return Object; } if (RV.isAggregate()) @@ -396,9 +402,11 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E, const NamedDecl *InitializedDecl) { llvm::Value *ReferenceTemporary = 0; const CXXDestructorDecl *ReferenceTemporaryDtor = 0; + const InitListExpr *ReferenceInitializerList = 0; QualType ObjCARCReferenceLifetimeType; llvm::Value *Value = EmitExprForReferenceBinding(*this, E, ReferenceTemporary, ReferenceTemporaryDtor, + ReferenceInitializerList, ObjCARCReferenceLifetimeType, InitializedDecl); if (SanitizePerformTypeCheck && !E->getType()->isFunctionType()) { @@ -410,7 +418,8 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E, QualType Ty = E->getType(); EmitTypeCheck(TCK_ReferenceBinding, E->getExprLoc(), Value, Ty); } - if (!ReferenceTemporaryDtor && ObjCARCReferenceLifetimeType.isNull()) + if (!ReferenceTemporaryDtor && !ReferenceInitializerList && + ObjCARCReferenceLifetimeType.isNull()) return RValue::get(Value); // Make sure to call the destructor for the reference temporary. @@ -429,9 +438,15 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E, CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete); CleanupArg = cast<llvm::Constant>(ReferenceTemporary); } - CGM.getCXXABI().registerGlobalDtor(*this, CleanupFn, CleanupArg); + CGM.getCXXABI().registerGlobalDtor(*this, *VD, CleanupFn, CleanupArg); + } else if (ReferenceInitializerList) { + // FIXME: This is wrong. We need to register a global destructor to clean + // up the initializer_list object, rather than adding it as a local + // cleanup. + EmitStdInitializerListCleanup(ReferenceTemporary, + ReferenceInitializerList); } else { - assert(!ObjCARCReferenceLifetimeType.isNull()); + assert(!ObjCARCReferenceLifetimeType.isNull() && !VD->getTLSKind()); // Note: We intentionally do not register a global "destructor" to // release the object. } @@ -445,6 +460,9 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E, destroyCXXObject, getLangOpts().Exceptions); else PushDestructorCleanup(ReferenceTemporaryDtor, ReferenceTemporary); + } else if (ReferenceInitializerList) { + EmitStdInitializerListCleanup(ReferenceTemporary, + ReferenceInitializerList); } else { switch (ObjCARCReferenceLifetimeType.getObjCLifetime()) { case Qualifiers::OCL_None: @@ -885,6 +903,10 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { return EmitNullInitializationLValue(cast<CXXScalarValueInitExpr>(E)); case Expr::CXXDefaultArgExprClass: return EmitLValue(cast<CXXDefaultArgExpr>(E)->getExpr()); + case Expr::CXXDefaultInitExprClass: { + CXXDefaultInitExprScope Scope(*this); + return EmitLValue(cast<CXXDefaultInitExpr>(E)->getExpr()); + } case Expr::CXXTypeidExprClass: return EmitCXXTypeidLValue(cast<CXXTypeidExpr>(E)); @@ -1164,7 +1186,7 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile, if (TBAAInfo) { llvm::MDNode *TBAAPath = CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo, TBAAOffset); - CGM.DecorateInstruction(Load, TBAAPath); + CGM.DecorateInstruction(Load, TBAAPath, false/*ConvertTypeToTag*/); } if ((SanOpts->Bool && hasBooleanRepresentation(Ty)) || @@ -1278,7 +1300,7 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr, if (TBAAInfo) { llvm::MDNode *TBAAPath = CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo, TBAAOffset); - CGM.DecorateInstruction(Store, TBAAPath); + CGM.DecorateInstruction(Store, TBAAPath, false/*ConvertTypeToTag*/); } } @@ -1656,7 +1678,7 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, if (const VarDecl *VD = dyn_cast<VarDecl>(Exp->getDecl())) { if (VD->hasGlobalStorage()) { LV.setGlobalObjCRef(true); - LV.setThreadLocalRef(VD->isThreadSpecified()); + LV.setThreadLocalRef(VD->getTLSKind() != VarDecl::TLS_None); } } LV.setObjCArray(E->getType()->isArrayType()); @@ -1806,8 +1828,12 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) { // Check if this is a global variable. - if (VD->hasLinkage() || VD->isStaticDataMember()) + if (VD->hasLinkage() || VD->isStaticDataMember()) { + // If it's thread_local, emit a call to its wrapper function instead. + if (VD->getTLSKind() == VarDecl::TLS_Dynamic) + return CGM.getCXXABI().EmitThreadLocalDeclRefExpr(*this, E); return EmitGlobalVarDeclLValue(*this, E, VD); + } bool isBlockVariable = VD->hasAttr<BlocksAttr>(); @@ -2469,6 +2495,17 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { llvm_unreachable("Unhandled member declaration!"); } +/// Given that we are currently emitting a lambda, emit an l-value for +/// one of its members. +LValue CodeGenFunction::EmitLValueForLambdaField(const FieldDecl *Field) { + assert(cast<CXXMethodDecl>(CurCodeDecl)->getParent()->isLambda()); + assert(cast<CXXMethodDecl>(CurCodeDecl)->getParent() == Field->getParent()); + QualType LambdaTagType = + getContext().getTagDeclType(Field->getParent()); + LValue LambdaLV = MakeNaturalAlignAddrLValue(CXXABIThisValue, LambdaTagType); + return EmitLValueForField(LambdaLV, Field); +} + LValue CodeGenFunction::EmitLValueForField(LValue base, const FieldDecl *field) { if (field->isBitField()) { @@ -2562,8 +2599,8 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, getContext().getASTRecordLayout(field->getParent()); // Set the base type to be the base type of the base LValue and // update offset to be relative to the base type. - LV.setTBAABaseType(base.getTBAABaseType()); - LV.setTBAAOffset(base.getTBAAOffset() + + LV.setTBAABaseType(mayAlias ? getContext().CharTy : base.getTBAABaseType()); + LV.setTBAAOffset(mayAlias ? 0 : base.getTBAAOffset() + Layout.getFieldOffset(field->getFieldIndex()) / getContext().getCharWidth()); } diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 1ac13c0..b974e1d 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -170,6 +170,10 @@ public: void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { Visit(DAE->getExpr()); } + void VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) { + CodeGenFunction::CXXDefaultInitExprScope Scope(CGF); + Visit(DIE->getExpr()); + } void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E); void VisitCXXConstructExpr(const CXXConstructExpr *E); void VisitLambdaExpr(LambdaExpr *E); @@ -1189,7 +1193,10 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { // the optimizer, especially with bitfields. unsigned NumInitElements = E->getNumInits(); RecordDecl *record = E->getType()->castAs<RecordType>()->getDecl(); - + + // Prepare a 'this' for CXXDefaultInitExprs. + CodeGenFunction::FieldConstructionScope FCS(CGF, Dest.getAddr()); + if (record->isUnion()) { // Only initialize one field of a union. The field itself is // specified by the initializer list. @@ -1341,7 +1348,7 @@ static CharUnits GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) { // Reference values are always non-null and have the width of a pointer. if (Field->getType()->isReferenceType()) NumNonZeroBytes += CGF.getContext().toCharUnitsFromBits( - CGF.getContext().getTargetInfo().getPointerWidth(0)); + CGF.getTarget().getPointerWidth(0)); else NumNonZeroBytes += GetNumNonZeroBytesInInit(E, CGF); } diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index 5fc73aa..36f974a 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -182,6 +182,10 @@ public: ComplexPairTy VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { return Visit(DAE->getExpr()); } + ComplexPairTy VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) { + CodeGenFunction::CXXDefaultInitExprScope Scope(CGF); + return Visit(DIE->getExpr()); + } ComplexPairTy VisitExprWithCleanups(ExprWithCleanups *E) { CGF.enterFullExpression(E); CodeGenFunction::RunCleanupsScope Scope(CGF); diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index faaf646..f5c8187 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -757,6 +757,12 @@ public: return Visit(DAE->getExpr()); } + llvm::Constant *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) { + // No need for a DefaultInitExprScope: we don't handle 'this' in a + // constant expression. + return Visit(DIE->getExpr()); + } + llvm::Constant *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { return Visit(E->GetTemporaryExpr()); } diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index ffd0eb5..c1c252d 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -344,6 +344,10 @@ public: Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { return Visit(DAE->getExpr()); } + Value *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) { + CodeGenFunction::CXXDefaultInitExprScope Scope(CGF); + return Visit(DIE->getExpr()); + } Value *VisitCXXThisExpr(CXXThisExpr *TE) { return CGF.LoadCXXThis(); } @@ -1634,8 +1638,8 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, else { llvm::APFloat F(static_cast<float>(amount)); bool ignored; - F.convert(CGF.Target.getLongDoubleFormat(), llvm::APFloat::rmTowardZero, - &ignored); + F.convert(CGF.getTarget().getLongDoubleFormat(), + llvm::APFloat::rmTowardZero, &ignored); amt = llvm::ConstantFP::get(VMContext, F); } value = Builder.CreateFAdd(value, amt, isInc ? "inc" : "dec"); diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 79d97b9..713509b 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -21,6 +21,7 @@ #include "clang/AST/StmtObjC.h" #include "clang/Basic/Diagnostic.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/CallSite.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/InlineAsm.h" using namespace clang; @@ -713,7 +714,7 @@ PropertyImplStrategy::PropertyImplStrategy(CodeGenModule &CGM, } llvm::Triple::ArchType arch = - CGM.getContext().getTargetInfo().getTriple().getArch(); + CGM.getTarget().getTriple().getArch(); // Most architectures require memory to fit within a single cache // line, so the alignment has to be at least the size of the access. @@ -1400,8 +1401,10 @@ bool CodeGenFunction::IvarTypeWithAggrGCObjects(QualType Ty) { } llvm::Value *CodeGenFunction::LoadObjCSelf() { - const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl); - return Builder.CreateLoad(LocalDeclMap[OMD->getSelfDecl()], "self"); + VarDecl *Self = cast<ObjCMethodDecl>(CurFuncDecl)->getSelfDecl(); + DeclRefExpr DRE(Self, /*is enclosing local*/ (CurFuncDecl != CurCodeDecl), + Self->getType(), VK_LValue, SourceLocation()); + return EmitLoadOfScalar(EmitDeclRefLValue(&DRE)); } QualType CodeGenFunction::TypeOfSelfObject() { @@ -2256,7 +2259,8 @@ void CodeGenFunction::EmitObjCAutoreleasePoolPop(llvm::Value *value) { fn = createARCRuntimeFunction(CGM, fnType, "objc_autoreleasePoolPop"); } - EmitNounwindRuntimeCall(fn, value); + // objc_autoreleasePoolPop can throw. + EmitRuntimeCallOrInvoke(fn, value); } /// Produce the code to do an MRR version objc_autoreleasepool_push. diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 6274e1b..e8498b0 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -1949,8 +1949,8 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM, bool hasUnion = false; SkipIvars.clear(); IvarsInfo.clear(); - unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0); - unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth(); + unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(0); + unsigned ByteSizeInBits = CGM.getTarget().getCharWidth(); // __isa is the first field in block descriptor and must assume by runtime's // convention that it is GC'able. @@ -2077,7 +2077,7 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout, if (RecFields.empty()) return; - unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth(); + unsigned ByteSizeInBits = CGM.getTarget().getCharWidth(); for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { const FieldDecl *Field = RecFields[i]; @@ -2316,8 +2316,8 @@ llvm::Constant *CGObjCCommonMac::getBitmapBlockLayout(bool ComputeByrefLayout) { llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy); if (RunSkipBlockVars.empty()) return nullPtr; - unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0); - unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth(); + unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(0); + unsigned ByteSizeInBits = CGM.getTarget().getCharWidth(); unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits; // Sort on byte position; captures might not be allocated in order, @@ -2393,7 +2393,7 @@ llvm::Constant *CGObjCCommonMac::getBitmapBlockLayout(bool ComputeByrefLayout) { printf("\n Inline instruction for BYREF variable layout: "); else printf("\n Inline instruction for block variable layout: "); - printf("0x0%llx\n", (unsigned long long)Result); + printf("0x0%" PRIx64 "\n", Result); } if (WordSizeInBytes == 8) { const llvm::APInt Instruction(64, Result); @@ -2468,8 +2468,8 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM, RunSkipBlockVars.clear(); bool hasUnion = false; - unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0); - unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth(); + unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(0); + unsigned ByteSizeInBits = CGM.getTarget().getCharWidth(); unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits; const BlockDecl *blockDecl = blockInfo.getBlockDecl(); @@ -4537,8 +4537,8 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, if (RecFields.empty()) return; - unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0); - unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth(); + unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(0); + unsigned ByteSizeInBits = CGM.getTarget().getCharWidth(); if (!RD && CGM.getLangOpts().ObjCAutoRefCount) { const FieldDecl *FirstField = RecFields[0]; FirstFieldDelta = diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp index abd10a2..9c0d518 100644 --- a/lib/CodeGen/CGObjCRuntime.cpp +++ b/lib/CodeGen/CGObjCRuntime.cpp @@ -117,7 +117,7 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, // a synthesized ivar can never be a bit-field, so this is safe. uint64_t FieldBitOffset = LookupFieldBitOffset(CGF.CGM, OID, 0, Ivar); uint64_t BitOffset = FieldBitOffset % CGF.CGM.getContext().getCharWidth(); - uint64_t AlignmentBits = CGF.CGM.getContext().getTargetInfo().getCharAlign(); + uint64_t AlignmentBits = CGF.CGM.getTarget().getCharAlign(); uint64_t BitFieldSize = Ivar->getBitWidthValue(CGF.getContext()); CharUnits StorageSize = CGF.CGM.getContext().toCharUnitsFromBits( diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp index 869843c..40dc6bf 100644 --- a/lib/CodeGen/CGRTTI.cpp +++ b/lib/CodeGen/CGRTTI.cpp @@ -412,6 +412,9 @@ void RTTIBuilder::BuildVTablePointer(const Type *Ty) { case Type::RValueReference: llvm_unreachable("References shouldn't get here"); + case Type::Auto: + llvm_unreachable("Undeduced auto type shouldn't get here"); + case Type::Builtin: // GCC treats vector and complex types as fundamental types. case Type::Vector: @@ -619,6 +622,9 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) { case Type::RValueReference: llvm_unreachable("References shouldn't get here"); + case Type::Auto: + llvm_unreachable("Undeduced auto type shouldn't get here"); + case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index 2c6438b..30ab528 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -276,7 +276,7 @@ bool CGRecordLayoutBuilder::LayoutBitfields(const ASTRecordLayout &Layout, uint64_t FirstFieldOffset = Layout.getFieldOffset(FirstFieldNo); uint64_t NextFieldOffsetInBits = Types.getContext().toBits(NextFieldOffset); - unsigned CharAlign = Types.getContext().getTargetInfo().getCharAlign(); + unsigned CharAlign = Types.getTarget().getCharAlign(); assert(FirstFieldOffset % CharAlign == 0 && "First field offset is misaligned"); CharUnits FirstFieldOffsetInBytes @@ -352,7 +352,7 @@ bool CGRecordLayoutBuilder::LayoutBitfields(const ASTRecordLayout &Layout, assert(EndOffset >= (FirstFieldOffset + TotalBits) && "End offset is not past the end of the known storage bits."); uint64_t SpaceBits = EndOffset - FirstFieldOffset; - uint64_t LongBits = Types.getContext().getTargetInfo().getLongWidth(); + uint64_t LongBits = Types.getTarget().getLongWidth(); uint64_t WidenedBits = (StorageBits / LongBits) * LongBits + llvm::NextPowerOf2(StorageBits % LongBits - 1); assert(WidenedBits >= StorageBits && "Widening shrunk the bits!"); @@ -455,7 +455,7 @@ CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field, return 0; unsigned StorageBits = llvm::RoundUpToAlignment( - FieldSize, Types.getContext().getTargetInfo().getCharAlign()); + FieldSize, Types.getTarget().getCharAlign()); CharUnits NumBytesToAppend = Types.getContext().toCharUnitsFromBits(StorageBits); @@ -814,7 +814,7 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { // Lay out the virtual bases. The MS ABI uses a different // algorithm here due to the lack of primary virtual bases. - if (Types.getContext().getTargetInfo().getCXXABI().hasPrimaryVBases()) { + if (Types.getTarget().getCXXABI().hasPrimaryVBases()) { RD->getIndirectPrimaryBases(IndirectPrimaryBases); if (Layout.isPrimaryBaseVirtual()) IndirectPrimaryBases.insert(Layout.getPrimaryBase()); diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 3153ca8..5e2ebe0 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -37,6 +37,9 @@ void CodeGenFunction::EmitStopPoint(const Stmt *S) { else Loc = S->getLocStart(); DI->EmitLocation(Builder, Loc); + + //if (++NumStopPoints == 1) + LastStopPoint = Loc; } } @@ -134,7 +137,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { case Stmt::SwitchStmtClass: EmitSwitchStmt(cast<SwitchStmt>(*S)); break; case Stmt::GCCAsmStmtClass: // Intentional fall-through. case Stmt::MSAsmStmtClass: EmitAsmStmt(cast<AsmStmt>(*S)); break; - + case Stmt::CapturedStmtClass: + EmitCapturedStmt(cast<CapturedStmt>(*S)); + break; case Stmt::ObjCAtTryStmtClass: EmitObjCAtTryStmt(cast<ObjCAtTryStmt>(*S)); break; @@ -837,6 +842,10 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { } } + NumReturnExprs += 1; + if (RV == 0 || RV->isEvaluatable(getContext())) + NumSimpleReturnExprs += 1; + cleanupScope.ForceCleanup(); EmitBranchThroughCleanup(ReturnBlock); } @@ -1449,7 +1458,7 @@ static llvm::MDNode *getAsmSrcLocInfo(const StringLiteral *Str, for (unsigned i = 0, e = StrVal.size()-1; i != e; ++i) { if (StrVal[i] != '\n') continue; SourceLocation LineLoc = Str->getLocationOfByte(i+1, SM, LangOpts, - CGF.Target); + CGF.getTarget()); Locs.push_back(llvm::ConstantInt::get(CGF.Int32Ty, LineLoc.getRawEncoding())); } @@ -1467,18 +1476,23 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos; for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) { - TargetInfo::ConstraintInfo Info(S.getOutputConstraint(i), - S.getOutputName(i)); - bool IsValid = Target.validateOutputConstraint(Info); (void)IsValid; + StringRef Name; + if (const GCCAsmStmt *GAS = dyn_cast<GCCAsmStmt>(&S)) + Name = GAS->getOutputName(i); + TargetInfo::ConstraintInfo Info(S.getOutputConstraint(i), Name); + bool IsValid = getTarget().validateOutputConstraint(Info); (void)IsValid; assert(IsValid && "Failed to parse output constraint"); OutputConstraintInfos.push_back(Info); } for (unsigned i = 0, e = S.getNumInputs(); i != e; i++) { - TargetInfo::ConstraintInfo Info(S.getInputConstraint(i), - S.getInputName(i)); - bool IsValid = Target.validateInputConstraint(OutputConstraintInfos.data(), - S.getNumOutputs(), Info); + StringRef Name; + if (const GCCAsmStmt *GAS = dyn_cast<GCCAsmStmt>(&S)) + Name = GAS->getInputName(i); + TargetInfo::ConstraintInfo Info(S.getInputConstraint(i), Name); + bool IsValid = + getTarget().validateInputConstraint(OutputConstraintInfos.data(), + S.getNumOutputs(), Info); assert(IsValid && "Failed to parse input constraint"); (void)IsValid; InputConstraintInfos.push_back(Info); } @@ -1502,13 +1516,14 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { // Simplify the output constraint. std::string OutputConstraint(S.getOutputConstraint(i)); - OutputConstraint = SimplifyConstraint(OutputConstraint.c_str() + 1, Target); + OutputConstraint = SimplifyConstraint(OutputConstraint.c_str() + 1, + getTarget()); const Expr *OutExpr = S.getOutputExpr(i); OutExpr = OutExpr->IgnoreParenNoopCasts(getContext()); OutputConstraint = AddVariableConstraints(OutputConstraint, *OutExpr, - Target, CGM, S); + getTarget(), CGM, S); LValue Dest = EmitLValue(OutExpr); if (!Constraints.empty()) @@ -1589,13 +1604,13 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { // Simplify the input constraint. std::string InputConstraint(S.getInputConstraint(i)); - InputConstraint = SimplifyConstraint(InputConstraint.c_str(), Target, + InputConstraint = SimplifyConstraint(InputConstraint.c_str(), getTarget(), &OutputConstraintInfos); InputConstraint = AddVariableConstraints(InputConstraint, *InputExpr->IgnoreParenNoopCasts(getContext()), - Target, CGM, S); + getTarget(), CGM, S); llvm::Value *Arg = EmitAsmInput(Info, InputExpr, Constraints); @@ -1647,7 +1662,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { StringRef Clobber = S.getClobber(i); if (Clobber != "memory" && Clobber != "cc") - Clobber = Target.getNormalizedGCCRegisterName(Clobber); + Clobber = getTarget().getNormalizedGCCRegisterName(Clobber); if (i != 0 || NumConstraints != 0) Constraints += ','; @@ -1658,7 +1673,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { } // Add machine specific clobbers - std::string MachineClobbers = Target.getClobbers(); + std::string MachineClobbers = getTarget().getClobbers(); if (!MachineClobbers.empty()) { if (!Constraints.empty()) Constraints += ','; @@ -1735,3 +1750,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { EmitStoreThroughLValue(RValue::get(Tmp), ResultRegDests[i]); } } + +void CodeGenFunction::EmitCapturedStmt(const CapturedStmt &S) { + llvm_unreachable("not implemented yet"); +} diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 2c3cabe..75c60ed 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -31,8 +31,7 @@ using namespace clang; using namespace CodeGen; CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext) - : CodeGenTypeCache(cgm), CGM(cgm), - Target(CGM.getContext().getTargetInfo()), + : CodeGenTypeCache(cgm), CGM(cgm), Target(cgm.getTarget()), Builder(cgm.getModule().getContext()), SanitizePerformTypeCheck(CGM.getSanOpts().Null | CGM.getSanOpts().Alignment | @@ -45,7 +44,9 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext) DebugInfo(0), DisableDebugInfo(false), CalleeWithThisReturn(0), DidCallStackSave(false), IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0), + NumReturnExprs(0), NumSimpleReturnExprs(0), CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0), + CXXDefaultInitExprThis(0), CXXStructorImplicitParamDecl(0), CXXStructorImplicitParamValue(0), OutermostConditional(0), CurLexicalScope(0), TerminateLandingPad(0), TerminateHandler(0), TrapBB(0) { @@ -91,6 +92,9 @@ TypeEvaluationKind CodeGenFunction::getEvaluationKind(QualType type) { #include "clang/AST/TypeNodes.def" llvm_unreachable("non-canonical or dependent type in IR-generation"); + case Type::Auto: + llvm_unreachable("undeduced auto type in IR-generation"); + // Various scalar types. case Type::Builtin: case Type::Pointer: @@ -184,15 +188,36 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { assert(BreakContinueStack.empty() && "mismatched push/pop in break/continue stack!"); - if (CGDebugInfo *DI = getDebugInfo()) - DI->EmitLocation(Builder, EndLoc); + bool OnlySimpleReturnStmts = NumSimpleReturnExprs > 0 + && NumSimpleReturnExprs == NumReturnExprs; + // If the function contains only a simple return statement, the + // cleanup code may become the first breakpoint in the function. To + // be safe, set the debug location for it to the location of the + // return statement. Otherwise point it to end of the function's + // lexical scope. + if (CGDebugInfo *DI = getDebugInfo()) { + if (OnlySimpleReturnStmts) + DI->EmitLocation(Builder, LastStopPoint); + else + DI->EmitLocation(Builder, EndLoc); + } // Pop any cleanups that might have been associated with the // parameters. Do this in whatever block we're currently in; it's // important to do this before we enter the return block or return // edges will be *really* confused. - if (EHStack.stable_begin() != PrologueCleanupDepth) - PopCleanupBlocks(PrologueCleanupDepth); + bool EmitRetDbgLoc = true; + if (EHStack.stable_begin() != PrologueCleanupDepth) { + PopCleanupBlocks(PrologueCleanupDepth, EndLoc); + + // Make sure the line table doesn't jump back into the body for + // the ret after it's been at EndLoc. + EmitRetDbgLoc = false; + + if (CGDebugInfo *DI = getDebugInfo()) + if (OnlySimpleReturnStmts) + DI->EmitLocation(Builder, EndLoc); + } // Emit function epilog (to return). EmitReturnBlock(); @@ -205,7 +230,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { DI->EmitFunctionEnd(Builder); } - EmitFunctionEpilog(*CurFnInfo); + EmitFunctionEpilog(*CurFnInfo, EmitRetDbgLoc); EmitEndEHSpec(CurCodeDecl); assert(EHStack.empty() && @@ -279,8 +304,8 @@ void CodeGenFunction::EmitFunctionInstrumentation(const char *Fn) { void CodeGenFunction::EmitMCountInstrumentation() { llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false); - llvm::Constant *MCountFn = CGM.CreateRuntimeFunction(FTy, - Target.getMCountName()); + llvm::Constant *MCountFn = + CGM.CreateRuntimeFunction(FTy, getTarget().getMCountName()); EmitNounwindRuntimeCall(MCountFn); } @@ -448,7 +473,8 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD, OpenCLKernelMetadata->addOperand(kernelMDNode); } -void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, +void CodeGenFunction::StartFunction(GlobalDecl GD, + QualType RetTy, llvm::Function *Fn, const CGFunctionInfo &FnInfo, const FunctionArgList &Args, @@ -456,7 +482,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, const Decl *D = GD.getDecl(); DidCallStackSave = false; - CurCodeDecl = CurFuncDecl = D; + CurCodeDecl = D; + CurFuncDecl = (D ? D->getNonClosureContext() : 0); FnRetTy = RetTy; CurFn = Fn; CurFnInfo = &FnInfo; @@ -555,12 +582,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, LambdaThisCaptureField); if (LambdaThisCaptureField) { // If this lambda captures this, load it. - QualType LambdaTagType = - getContext().getTagDeclType(LambdaThisCaptureField->getParent()); - LValue LambdaLV = MakeNaturalAlignAddrLValue(CXXABIThisValue, - LambdaTagType); - LValue ThisLValue = EmitLValueForField(LambdaLV, - LambdaThisCaptureField); + LValue ThisLValue = EmitLValueForLambdaField(LambdaThisCaptureField); CXXThisValue = EmitLoadOfLValue(ThisLValue).getScalarVal(); } } else { @@ -906,6 +928,16 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond, return; } + if (const CXXThrowExpr *Throw = dyn_cast<CXXThrowExpr>(Cond)) { + // Conditional operator handling can give us a throw expression as a + // condition for a case like: + // br(c ? throw x : y, t, f) -> br(c, br(throw x, t, f), br(y, t, f) + // Fold this to: + // br(c, throw x, br(y, t, f)) + EmitCXXThrowExpr(Throw, /*KeepInsertionPoint*/false); + return; + } + // Emit the code with the fully general case. llvm::Value *CondV = EvaluateExprAsBool(Cond); Builder.CreateCondBr(CondV, TrueBlock, FalseBlock); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 645d5ff..ff74c15 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -579,8 +579,8 @@ public: typedef std::pair<llvm::Value *, llvm::Value *> ComplexPairTy; CGBuilderTy Builder; - /// CurFuncDecl - Holds the Decl for the current function or ObjC method. - /// This excludes BlockDecls. + /// CurFuncDecl - Holds the Decl for the current outermost + /// non-closure context. const Decl *CurFuncDecl; /// CurCodeDecl - This is the inner-most code context, which includes blocks. const Decl *CurCodeDecl; @@ -784,7 +784,9 @@ public: /// PopCleanupBlock - Will pop the cleanup entry on the stack and /// process all branch fixups. - void PopCleanupBlock(bool FallThroughIsBranchThrough = false); + /// \param EHLoc - Optional debug location for EH code. + void PopCleanupBlock(bool FallThroughIsBranchThrough = false, + SourceLocation EHLoc=SourceLocation()); /// DeactivateCleanupBlock - Deactivates the given cleanup block. /// The block cannot be reactivated. Pops it if it's the top of the @@ -905,7 +907,9 @@ public: /// PopCleanupBlocks - Takes the old cleanup stack size and emits /// the cleanup blocks that have been added. - void PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize); + /// \param EHLoc - Optional debug location for EH code. + void PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize, + SourceLocation EHLoc=SourceLocation()); void ResolveBranchFixups(llvm::BasicBlock *Target); @@ -1206,12 +1210,62 @@ private: /// lazily by getUnreachableBlock(). llvm::BasicBlock *UnreachableBlock; + /// Counts of the number return expressions in the function. + unsigned NumReturnExprs; + + /// Count the number of simple (constant) return expressions in the function. + unsigned NumSimpleReturnExprs; + + /// The last regular (non-return) debug location (breakpoint) in the function. + SourceLocation LastStopPoint; + +public: + /// A scope within which we are constructing the fields of an object which + /// might use a CXXDefaultInitExpr. This stashes away a 'this' value to use + /// if we need to evaluate a CXXDefaultInitExpr within the evaluation. + class FieldConstructionScope { + public: + FieldConstructionScope(CodeGenFunction &CGF, llvm::Value *This) + : CGF(CGF), OldCXXDefaultInitExprThis(CGF.CXXDefaultInitExprThis) { + CGF.CXXDefaultInitExprThis = This; + } + ~FieldConstructionScope() { + CGF.CXXDefaultInitExprThis = OldCXXDefaultInitExprThis; + } + + private: + CodeGenFunction &CGF; + llvm::Value *OldCXXDefaultInitExprThis; + }; + + /// The scope of a CXXDefaultInitExpr. Within this scope, the value of 'this' + /// is overridden to be the object under construction. + class CXXDefaultInitExprScope { + public: + CXXDefaultInitExprScope(CodeGenFunction &CGF) + : CGF(CGF), OldCXXThisValue(CGF.CXXThisValue) { + CGF.CXXThisValue = CGF.CXXDefaultInitExprThis; + } + ~CXXDefaultInitExprScope() { + CGF.CXXThisValue = OldCXXThisValue; + } + + public: + CodeGenFunction &CGF; + llvm::Value *OldCXXThisValue; + }; + +private: /// CXXThisDecl - When generating code for a C++ member function, /// this will hold the implicit 'this' declaration. ImplicitParamDecl *CXXABIThisDecl; llvm::Value *CXXABIThisValue; llvm::Value *CXXThisValue; + /// The value of 'this' to use when evaluating CXXDefaultInitExprs within + /// this expression. + llvm::Value *CXXDefaultInitExprThis; + /// CXXStructorImplicitParamDecl - When generating code for a constructor or /// destructor, this will hold the implicit argument (e.g. VTT). ImplicitParamDecl *CXXStructorImplicitParamDecl; @@ -1300,6 +1354,7 @@ public: return getInvokeDestImpl(); } + const TargetInfo &getTarget() const { return Target; } llvm::LLVMContext &getLLVMContext() { return CGM.getLLVMContext(); } //===--------------------------------------------------------------------===// @@ -1400,7 +1455,6 @@ public: llvm::Function *GenerateBlockFunction(GlobalDecl GD, const CGBlockInfo &Info, - const Decl *OuterFuncDecl, const DeclMapTy &ldm, bool IsLambdaConversionToBlock); @@ -1431,7 +1485,8 @@ public: void GenerateCode(GlobalDecl GD, llvm::Function *Fn, const CGFunctionInfo &FnInfo); - void StartFunction(GlobalDecl GD, QualType RetTy, + void StartFunction(GlobalDecl GD, + QualType RetTy, llvm::Function *Fn, const CGFunctionInfo &FnInfo, const FunctionArgList &Args, @@ -1521,7 +1576,7 @@ public: /// EmitFunctionEpilog - Emit the target specific LLVM code to return the /// given temporary. - void EmitFunctionEpilog(const CGFunctionInfo &FI); + void EmitFunctionEpilog(const CGFunctionInfo &FI, bool EmitRetDbgLoc); /// EmitStartEHSpec - Emit the start of the exception spec. void EmitStartEHSpec(const Decl *D); @@ -2133,6 +2188,7 @@ public: void EmitCaseStmt(const CaseStmt &S); void EmitCaseStmtRange(const CaseStmt &S); void EmitAsmStmt(const AsmStmt &S); + void EmitCapturedStmt(const CapturedStmt &S); void EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S); void EmitObjCAtTryStmt(const ObjCAtTryStmt &S); @@ -2327,6 +2383,7 @@ public: llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar); LValue EmitLValueForField(LValue Base, const FieldDecl* Field); + LValue EmitLValueForLambdaField(const FieldDecl *Field); /// EmitLValueForFieldInitialization - Like EmitLValueForField, except that /// if the Field is a reference, this will return the address of the reference @@ -2446,6 +2503,7 @@ public: /// is unhandled by the current target. llvm::Value *EmitTargetBuiltinExpr(unsigned BuiltinID, const CallExpr *E); + llvm::Value *EmitAArch64BuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitARMBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitNeonCall(llvm::Function *F, SmallVectorImpl<llvm::Value*> &O, @@ -2625,8 +2683,8 @@ public: /// GenerateCXXGlobalInitFunc - Generates code for initializing global /// variables. void GenerateCXXGlobalInitFunc(llvm::Function *Fn, - llvm::Constant **Decls, - unsigned NumDecls); + ArrayRef<llvm::Constant *> Decls, + llvm::GlobalVariable *Guard = 0); /// GenerateCXXGlobalDtorsFunc - Generates code for destroying global /// variables. @@ -2650,7 +2708,7 @@ public: } void enterNonTrivialFullExpression(const ExprWithCleanups *E); - void EmitCXXThrowExpr(const CXXThrowExpr *E); + void EmitCXXThrowExpr(const CXXThrowExpr *E, bool KeepInsertionPoint = true); void EmitLambdaExpr(const LambdaExpr *E, AggValueSlot Dest); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index c518a55..0b03a3c 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -35,7 +35,6 @@ #include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" -#include "clang/Basic/TargetOptions.h" #include "clang/Frontend/CodeGenOptions.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/Triple.h" @@ -55,7 +54,7 @@ using namespace CodeGen; static const char AnnotationSection[] = "llvm.metadata"; static CGCXXABI &createCXXABI(CodeGenModule &CGM) { - switch (CGM.getContext().getTargetInfo().getCXXABI().getKind()) { + switch (CGM.getTarget().getCXXABI().getKind()) { case TargetCXXABI::GenericAArch64: case TargetCXXABI::GenericARM: case TargetCXXABI::iOS: @@ -70,19 +69,16 @@ static CGCXXABI &createCXXABI(CodeGenModule &CGM) { CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, - const TargetOptions &TO, llvm::Module &M, - const llvm::DataLayout &TD, + llvm::Module &M, const llvm::DataLayout &TD, DiagnosticsEngine &diags) - : Context(C), LangOpts(C.getLangOpts()), CodeGenOpts(CGO), TargetOpts(TO), - TheModule(M), TheDataLayout(TD), TheTargetCodeGenInfo(0), Diags(diags), - ABI(createCXXABI(*this)), - Types(*this), - TBAA(0), - VTables(*this), ObjCRuntime(0), OpenCLRuntime(0), CUDARuntime(0), + : Context(C), LangOpts(C.getLangOpts()), CodeGenOpts(CGO), TheModule(M), + Diags(diags), TheDataLayout(TD), Target(C.getTargetInfo()), + ABI(createCXXABI(*this)), VMContext(M.getContext()), TBAA(0), + TheTargetCodeGenInfo(0), Types(*this), VTables(*this), + ObjCRuntime(0), OpenCLRuntime(0), CUDARuntime(0), DebugInfo(0), ARCData(0), NoObjCARCExceptionsMetadata(0), RRData(0), CFConstantStringClassRef(0), ConstantStringClassRef(0), NSConstantStringType(0), - VMContext(M.getContext()), NSConcreteGlobalBlock(0), NSConcreteStackBlock(0), BlockObjectAssign(0), BlockObjectDispose(0), BlockDescriptorType(0), GenericBlockLiteralType(0), @@ -180,15 +176,17 @@ void CodeGenModule::Release() { EmitDeferred(); EmitCXXGlobalInitFunc(); EmitCXXGlobalDtorFunc(); + EmitCXXThreadLocalInitFunc(); if (ObjCRuntime) if (llvm::Function *ObjCInitFunction = ObjCRuntime->ModuleInitFunction()) AddGlobalCtor(ObjCInitFunction); EmitCtorList(GlobalCtors, "llvm.global_ctors"); EmitCtorList(GlobalDtors, "llvm.global_dtors"); EmitGlobalAnnotations(); + EmitStaticExternCAliases(); EmitLLVMUsed(); - if (CodeGenOpts.ModulesAutolink) { + if (CodeGenOpts.Autolink && Context.getLangOpts().Modules) { EmitModuleLinkOptions(); } @@ -241,13 +239,18 @@ llvm::MDNode *CodeGenModule::getTBAAStructTagInfo(QualType BaseTy, return TBAA->getTBAAStructTagInfo(BaseTy, AccessN, O); } +/// Decorate the instruction with a TBAA tag. For scalar TBAA, the tag +/// is the same as the type. For struct-path aware TBAA, the tag +/// is different from the type: base type, access type and offset. +/// When ConvertTypeToTag is true, we create a tag based on the scalar type. void CodeGenModule::DecorateInstruction(llvm::Instruction *Inst, - llvm::MDNode *TBAAInfo) { - Inst->setMetadata(llvm::LLVMContext::MD_tbaa, TBAAInfo); -} - -bool CodeGenModule::isTargetDarwin() const { - return getContext().getTargetInfo().getTriple().isOSDarwin(); + llvm::MDNode *TBAAInfo, + bool ConvertTypeToTag) { + if (ConvertTypeToTag && TBAA && CodeGenOpts.StructPathTBAA) + Inst->setMetadata(llvm::LLVMContext::MD_tbaa, + TBAA->getTBAAScalarTagInfo(TBAAInfo)); + else + Inst->setMetadata(llvm::LLVMContext::MD_tbaa, TBAAInfo); } void CodeGenModule::Error(SourceLocation loc, StringRef error) { @@ -323,7 +326,7 @@ static llvm::GlobalVariable::ThreadLocalMode GetLLVMTLSModel( void CodeGenModule::setTLSMode(llvm::GlobalVariable *GV, const VarDecl &D) const { - assert(D.isThreadSpecified() && "setting TLS mode on non-TLS var!"); + assert(D.getTLSKind() && "setting TLS mode on non-TLS var!"); llvm::GlobalVariable::ThreadLocalMode TLM; TLM = GetLLVMTLSModel(CodeGenOpts.getDefaultTLSModel()); @@ -1475,8 +1478,11 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, GV->setVisibility(GetLLVMVisibility(LV.getVisibility())); } - if (D->isThreadSpecified()) + if (D->getTLSKind()) { + if (D->getTLSKind() == VarDecl::TLS_Dynamic) + CXXThreadLocals.push_back(std::make_pair(D, GV)); setTLSMode(GV, *D); + } } if (AddrSpace != Ty->getAddressSpace()) @@ -1617,6 +1623,7 @@ CodeGenModule::MaybeEmitGlobalStdInitializerListInitializer(const VarDecl *D, D->getLocStart(), D->getLocation(), name, arrayType, sourceInfo, SC_Static); + backingArray->setTSCSpec(D->getTSCSpec()); // Now clone the InitListExpr to initialize the array instead. // Incredible hack: we want to use the existing InitListExpr here, so we need @@ -1707,6 +1714,39 @@ unsigned CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D, return AddrSpace; } +template<typename SomeDecl> +void CodeGenModule::MaybeHandleStaticInExternC(const SomeDecl *D, + llvm::GlobalValue *GV) { + if (!getLangOpts().CPlusPlus) + return; + + // Must have 'used' attribute, or else inline assembly can't rely on + // the name existing. + if (!D->template hasAttr<UsedAttr>()) + return; + + // Must have internal linkage and an ordinary name. + if (!D->getIdentifier() || D->getLinkage() != InternalLinkage) + return; + + // Must be in an extern "C" context. Entities declared directly within + // a record are not extern "C" even if the record is in such a context. + const SomeDecl *First = D->getFirstDeclaration(); + if (First->getDeclContext()->isRecord() || !First->isInExternCContext()) + return; + + // OK, this is an internal linkage entity inside an extern "C" linkage + // specification. Make a note of that so we can give it the "expected" + // mangled name if nothing else is using that name. + std::pair<StaticExternCMap::iterator, bool> R = + StaticExternCValues.insert(std::make_pair(D->getIdentifier(), GV)); + + // If we have multiple internal linkage entities with the same name + // in extern "C" regions, none of them gets that name. + if (!R.second) + R.first->second = 0; +} + void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { llvm::Constant *Init = 0; QualType ASTTy = D->getType(); @@ -1805,6 +1845,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { cast<llvm::GlobalValue>(Entry)->eraseFromParent(); } + MaybeHandleStaticInExternC(D, GV); + if (D->hasAttr<AnnotateAttr>()) AddGlobalAnnotations(D, GV); @@ -1870,11 +1912,17 @@ CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D, ((!CodeGenOpts.NoCommon && !D->getAttr<NoCommonAttr>()) || D->getAttr<CommonAttr>()) && !D->hasExternalStorage() && !D->getInit() && - !D->getAttr<SectionAttr>() && !D->isThreadSpecified() && + !D->getAttr<SectionAttr>() && !D->getTLSKind() && !D->getAttr<WeakImportAttr>()) { // Thread local vars aren't considered common linkage. return llvm::GlobalVariable::CommonLinkage; - } + } else if (D->getTLSKind() == VarDecl::TLS_Dynamic && + getTarget().getTriple().isMacOSX()) + // On Darwin, the backing variable for a C++11 thread_local variable always + // has internal linkage; all accesses should just be calls to the + // Itanium-specified entry point, which has the normal linkage of the + // variable. + return llvm::GlobalValue::InternalLinkage; return llvm::GlobalVariable::ExternalLinkage; } @@ -2083,6 +2131,8 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) { // FIXME: this is redundant with part of SetFunctionDefinitionAttributes setGlobalVisibility(Fn, D); + MaybeHandleStaticInExternC(D, Fn); + CodeGenFunction(*this).GenerateCode(D, Fn, FI); SetFunctionDefinitionAttributes(D, Fn); @@ -2231,7 +2281,8 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { llvm::Constant *Zero = llvm::Constant::getNullValue(Int32Ty); llvm::Constant *Zeros[] = { Zero, Zero }; - + llvm::Value *V; + // If we don't already have it, get __CFConstantStringClassReference. if (!CFConstantStringClassRef) { llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy); @@ -2239,9 +2290,11 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { llvm::Constant *GV = CreateRuntimeVariable(Ty, "__CFConstantStringClassReference"); // Decay array -> ptr - CFConstantStringClassRef = - llvm::ConstantExpr::getGetElementPtr(GV, Zeros); + V = llvm::ConstantExpr::getGetElementPtr(GV, Zeros); + CFConstantStringClassRef = V; } + else + V = CFConstantStringClassRef; QualType CFTy = getContext().getCFConstantStringType(); @@ -2251,7 +2304,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { llvm::Constant *Fields[4]; // Class pointer. - Fields[0] = CFConstantStringClassRef; + Fields[0] = cast<llvm::ConstantExpr>(V); // Flags. llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy); @@ -2286,6 +2339,8 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { new llvm::GlobalVariable(getModule(), C->getType(), /*isConstant=*/true, Linkage, C, ".str"); GV->setUnnamedAddr(true); + // Don't enforce the target's minimum global alignment, since the only use + // of the string is via this class initializer. if (isUTF16) { CharUnits Align = getContext().getTypeAlignInChars(getContext().ShortTy); GV->setAlignment(Align.getQuantity()); @@ -2310,7 +2365,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { GV = new llvm::GlobalVariable(getModule(), C->getType(), true, llvm::GlobalVariable::PrivateLinkage, C, "_unnamed_cfstring_"); - if (const char *Sect = getContext().getTargetInfo().getCFStringSection()) + if (const char *Sect = getTarget().getCFStringSection()) GV->setSection(Sect); Entry.setValue(GV); @@ -2338,7 +2393,7 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { llvm::Constant *Zero = llvm::Constant::getNullValue(Int32Ty); llvm::Constant *Zeros[] = { Zero, Zero }; - + llvm::Value *V; // If we don't already have it, get _NSConstantStringClassReference. if (!ConstantStringClassRef) { std::string StringClass(getLangOpts().ObjCConstantStringClass); @@ -2351,8 +2406,8 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { GV = getObjCRuntime().GetClassGlobal(str); // Make sure the result is of the correct type. llvm::Type *PTy = llvm::PointerType::getUnqual(Ty); - ConstantStringClassRef = - llvm::ConstantExpr::getBitCast(GV, PTy); + V = llvm::ConstantExpr::getBitCast(GV, PTy); + ConstantStringClassRef = V; } else { std::string str = StringClass.empty() ? "_NSConstantStringClassReference" @@ -2360,10 +2415,12 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { llvm::Type *PTy = llvm::ArrayType::get(Ty, 0); GV = CreateRuntimeVariable(PTy, str); // Decay array -> ptr - ConstantStringClassRef = - llvm::ConstantExpr::getGetElementPtr(GV, Zeros); + V = llvm::ConstantExpr::getGetElementPtr(GV, Zeros); + ConstantStringClassRef = V; } } + else + V = ConstantStringClassRef; if (!NSConstantStringType) { // Construct the type for a constant NSString. @@ -2402,7 +2459,7 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { llvm::Constant *Fields[3]; // Class pointer. - Fields[0] = ConstantStringClassRef; + Fields[0] = cast<llvm::ConstantExpr>(V); // String pointer. llvm::Constant *C = @@ -2417,6 +2474,8 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { new llvm::GlobalVariable(getModule(), C->getType(), isConstant, Linkage, C, ".str"); GV->setUnnamedAddr(true); + // Don't enforce the target's minimum global alignment, since the only use + // of the string is via this class initializer. CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy); GV->setAlignment(Align.getQuantity()); Fields[1] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros); @@ -2433,8 +2492,8 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { // FIXME. Fix section. if (const char *Sect = LangOpts.ObjCRuntime.isNonFragile() - ? getContext().getTargetInfo().getNSStringNonFragileABISection() - : getContext().getTargetInfo().getNSStringSection()) + ? getTarget().getNSStringNonFragileABISection() + : getTarget().getNSStringSection()) GV->setSection(Sect); Entry.setValue(GV); @@ -2521,7 +2580,7 @@ CodeGenModule::GetConstantArrayFromStringLiteral(const StringLiteral *E) { /// constant array for the given string literal. llvm::Constant * CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S) { - CharUnits Align = getContext().getTypeAlignInChars(S->getType()); + CharUnits Align = getContext().getAlignOfGlobalVarInChars(S->getType()); if (S->isAscii() || S->isUTF8()) { SmallString<64> Str(S->getString()); @@ -2590,6 +2649,10 @@ llvm::Constant *CodeGenModule::GetAddrOfConstantString(StringRef Str, if (!GlobalName) GlobalName = ".str"; + if (Alignment == 0) + Alignment = getContext().getAlignOfGlobalVarInChars(getContext().CharTy) + .getQuantity(); + // Don't share any string literals if strings aren't constant. if (LangOpts.WritableStrings) return GenerateStringLiteral(Str, false, *this, GlobalName, Alignment); @@ -2770,7 +2833,6 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { // No code generation needed. case Decl::UsingShadow: case Decl::Using: - case Decl::UsingDirective: case Decl::ClassTemplate: case Decl::FunctionTemplate: case Decl::TypeAliasTemplate: @@ -2778,6 +2840,10 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case Decl::Block: case Decl::Empty: break; + case Decl::UsingDirective: // using namespace X; [C++] + if (CGDebugInfo *DI = getModuleDebugInfo()) + DI->EmitUsingDirective(cast<UsingDirectiveDecl>(*D)); + return; case Decl::CXXConstructor: // Skip function templates if (cast<FunctionDecl>(D)->getDescribedFunctionTemplate() || @@ -2903,6 +2969,23 @@ static void EmitGlobalDeclMetadata(CodeGenModule &CGM, GlobalMetadata->addOperand(llvm::MDNode::get(CGM.getLLVMContext(), Ops)); } +/// For each function which is declared within an extern "C" region and marked +/// as 'used', but has internal linkage, create an alias from the unmangled +/// name to the mangled name if possible. People expect to be able to refer +/// to such functions with an unmangled name from inline assembly within the +/// same translation unit. +void CodeGenModule::EmitStaticExternCAliases() { + for (StaticExternCMap::iterator I = StaticExternCValues.begin(), + E = StaticExternCValues.end(); + I != E; ++I) { + IdentifierInfo *Name = I->first; + llvm::GlobalValue *Val = I->second; + if (Val && !getModule().getNamedValue(Name->getName())) + AddUsedGlobal(new llvm::GlobalAlias(Val->getType(), Val->getLinkage(), + Name->getName(), Val, &getModule())); + } +} + /// Emits metadata nodes associating all the global values in the /// current module with the Decls they came from. This is useful for /// projects using IR gen as a subroutine. diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 5b2153e..91138c6 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -67,7 +67,6 @@ namespace clang { class VarDecl; class LangOptions; class CodeGenOptions; - class TargetOptions; class DiagnosticsEngine; class AnnotateAttr; class CXXDestructorDecl; @@ -233,15 +232,22 @@ class CodeGenModule : public CodeGenTypeCache { ASTContext &Context; const LangOptions &LangOpts; const CodeGenOptions &CodeGenOpts; - const TargetOptions &TargetOpts; llvm::Module &TheModule; - const llvm::DataLayout &TheDataLayout; - mutable const TargetCodeGenInfo *TheTargetCodeGenInfo; DiagnosticsEngine &Diags; + const llvm::DataLayout &TheDataLayout; + const TargetInfo &Target; CGCXXABI &ABI; - CodeGenTypes Types; - CodeGenTBAA *TBAA; + llvm::LLVMContext &VMContext; + CodeGenTBAA *TBAA; + + mutable const TargetCodeGenInfo *TheTargetCodeGenInfo; + + // This should not be moved earlier, since its initialization depends on some + // of the previous reference members being already initialized and also checks + // if TheTargetCodeGenInfo is NULL + CodeGenTypes Types; + /// VTables - Holds information about C++ vtables. CodeGenVTables VTables; friend class CodeGenVTables; @@ -255,8 +261,8 @@ class CodeGenModule : public CodeGenTypeCache { RREntrypoints *RRData; // WeakRefReferences - A set of references that have only been seen via - // a weakref so far. This is used to remove the weak of the reference if we ever - // see a direct reference or a definition. + // a weakref so far. This is used to remove the weak of the reference if we + // ever see a direct reference or a definition. llvm::SmallPtrSet<llvm::GlobalValue*, 10> WeakRefReferences; /// DeferredDecls - This contains all the decls which have definitions but @@ -305,6 +311,20 @@ class CodeGenModule : public CodeGenTypeCache { llvm::DenseMap<QualType, llvm::Constant *> AtomicSetterHelperFnMap; llvm::DenseMap<QualType, llvm::Constant *> AtomicGetterHelperFnMap; + /// Map used to track internal linkage functions declared within + /// extern "C" regions. + typedef llvm::MapVector<IdentifierInfo *, + llvm::GlobalValue *> StaticExternCMap; + StaticExternCMap StaticExternCValues; + + /// \brief thread_local variables defined or used in this TU. + std::vector<std::pair<const VarDecl *, llvm::GlobalVariable *> > + CXXThreadLocals; + + /// \brief thread_local variables with initializers that need to run + /// before any thread_local variable in this TU is odr-used. + std::vector<llvm::Constant*> CXXThreadLocalInits; + /// CXXGlobalInits - Global variables with initializers that need to run /// before main. std::vector<llvm::Constant*> CXXGlobalInits; @@ -340,11 +360,11 @@ class CodeGenModule : public CodeGenTypeCache { /// CFConstantStringClassRef - Cached reference to the class for constant /// strings. This value has type int * but is actually an Obj-C class pointer. - llvm::Constant *CFConstantStringClassRef; + llvm::WeakVH CFConstantStringClassRef; /// ConstantStringClassRef - Cached reference to the class for constant /// strings. This value has type int * but is actually an Obj-C class pointer. - llvm::Constant *ConstantStringClassRef; + llvm::WeakVH ConstantStringClassRef; /// \brief The LLVM type corresponding to NSConstantString. llvm::StructType *NSConstantStringType; @@ -363,7 +383,6 @@ class CodeGenModule : public CodeGenTypeCache { bool isTriviallyRecursive(const FunctionDecl *F); bool shouldEmitFunction(const FunctionDecl *F); - llvm::LLVMContext &VMContext; /// @name Cache for Blocks Runtime Globals /// @{ @@ -396,8 +415,8 @@ class CodeGenModule : public CodeGenTypeCache { /// @} public: CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts, - const TargetOptions &TargetOpts, llvm::Module &M, - const llvm::DataLayout &TD, DiagnosticsEngine &Diags); + llvm::Module &M, const llvm::DataLayout &TD, + DiagnosticsEngine &Diags); ~CodeGenModule(); @@ -427,9 +446,6 @@ public: return *CUDARuntime; } - /// getCXXABI() - Return a reference to the configured C++ ABI. - CGCXXABI &getCXXABI() { return ABI; } - ARCEntrypoints &getARCEntrypoints() const { assert(getLangOpts().ObjCAutoRefCount && ARCData != 0); return *ARCData; @@ -483,21 +499,24 @@ public: } ASTContext &getContext() const { return Context; } - const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; } const LangOptions &getLangOpts() const { return LangOpts; } + const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; } llvm::Module &getModule() const { return TheModule; } - CodeGenTypes &getTypes() { return Types; } - CodeGenVTables &getVTables() { return VTables; } - VTableContext &getVTableContext() { return VTables.getVTableContext(); } DiagnosticsEngine &getDiags() const { return Diags; } const llvm::DataLayout &getDataLayout() const { return TheDataLayout; } - const TargetInfo &getTarget() const { return Context.getTargetInfo(); } + const TargetInfo &getTarget() const { return Target; } + CGCXXABI &getCXXABI() { return ABI; } llvm::LLVMContext &getLLVMContext() { return VMContext; } - const TargetCodeGenInfo &getTargetCodeGenInfo(); - bool isTargetDarwin() const; - + bool shouldUseTBAA() const { return TBAA != 0; } + const TargetCodeGenInfo &getTargetCodeGenInfo(); + + CodeGenTypes &getTypes() { return Types; } + + CodeGenVTables &getVTables() { return VTables; } + VTableContext &getVTableContext() { return VTables.getVTableContext(); } + llvm::MDNode *getTBAAInfo(QualType QTy); llvm::MDNode *getTBAAInfoForVTablePtr(); llvm::MDNode *getTBAAStructInfo(QualType QTy); @@ -512,8 +531,13 @@ public: bool isPaddedAtomicType(QualType type); bool isPaddedAtomicType(const AtomicType *type); - static void DecorateInstruction(llvm::Instruction *Inst, - llvm::MDNode *TBAAInfo); + /// Decorate the instruction with a TBAA tag. For scalar TBAA, the tag + /// is the same as the type. For struct-path aware TBAA, the tag + /// is different from the type: base type, access type and offset. + /// When ConvertTypeToTag is true, we create a tag based on the scalar type. + void DecorateInstruction(llvm::Instruction *Inst, + llvm::MDNode *TBAAInfo, + bool ConvertTypeToTag = true); /// getSize - Emit the given number of characters as a value of type size_t. llvm::ConstantInt *getSize(CharUnits numChars); @@ -563,8 +587,8 @@ public: return GetAddrOfGlobalVar(cast<VarDecl>(GD.getDecl())); } - /// CreateOrReplaceCXXRuntimeVariable - Will return a global variable of the given - /// type. If a variable with a different type already exists then a new + /// CreateOrReplaceCXXRuntimeVariable - Will return a global variable of the + /// given type. If a variable with a different type already exists then a new /// variable with the right type will be created and all uses of the old /// variable will be replaced with a bitcast to the new variable. llvm::GlobalVariable * @@ -689,7 +713,7 @@ public: /// (if one is created). llvm::Constant *GetAddrOfConstantString(StringRef Str, const char *GlobalName=0, - unsigned Alignment=1); + unsigned Alignment=0); /// GetAddrOfConstantCString - Returns a pointer to a character array /// containing the literal and a terminating '\0' character. The result has @@ -699,7 +723,7 @@ public: /// created). llvm::Constant *GetAddrOfConstantCString(const std::string &str, const char *GlobalName=0, - unsigned Alignment=1); + unsigned Alignment=0); /// GetAddrOfConstantCompoundLiteral - Returns a pointer to a constant global /// variable for the given file-scope compound literal expression. @@ -726,8 +750,7 @@ public: llvm::Value *getBuiltinLibFunction(const FunctionDecl *FD, unsigned BuiltinID); - llvm::Function *getIntrinsic(unsigned IID, ArrayRef<llvm::Type*> Tys = - ArrayRef<llvm::Type*>()); + llvm::Function *getIntrinsic(unsigned IID, ArrayRef<llvm::Type*> Tys = None); /// EmitTopLevelDecl - Emit code for a single top level declaration. void EmitTopLevelDecl(Decl *D); @@ -736,6 +759,12 @@ public: // variable has been instantiated. void HandleCXXStaticMemberVarInstantiation(VarDecl *VD); + /// \brief If the declaration has internal linkage but is inside an + /// extern "C" linkage specification, prepare to emit an alias for it + /// to the expected name. + template<typename SomeDecl> + void MaybeHandleStaticInExternC(const SomeDecl *D, llvm::GlobalValue *GV); + /// AddUsedGlobal - Add a global which should be forced to be /// present in the object file; these are emitted to the llvm.used /// metadata global. @@ -1004,6 +1033,9 @@ private: /// a C++ destructor Decl. void EmitCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type); + /// \brief Emit the function that initializes C++ thread_local variables. + void EmitCXXThreadLocalInitFunc(); + /// EmitCXXGlobalInitFunc - Emit the function that initializes C++ globals. void EmitCXXGlobalInitFunc(); @@ -1048,6 +1080,10 @@ private: /// \brief Emit the link options introduced by imported modules. void EmitModuleLinkOptions(); + /// \brief Emit aliases for internal-linkage declarations inside "C" language + /// linkage specifications, giving them the "expected" name where possible. + void EmitStaticExternCAliases(); + void EmitDeclMetadata(); /// EmitCoverageFile - Emit the llvm.gcov metadata used to tell LLVM where diff --git a/lib/CodeGen/CodeGenTBAA.cpp b/lib/CodeGen/CodeGenTBAA.cpp index 7e4d34a..5ff1560 100644 --- a/lib/CodeGen/CodeGenTBAA.cpp +++ b/lib/CodeGen/CodeGenTBAA.cpp @@ -50,13 +50,25 @@ llvm::MDNode *CodeGenTBAA::getRoot() { return Root; } +// For struct-path aware TBAA, the scalar type has the same format as +// the struct type: name, offset, pointer to another node in the type DAG. +// For scalar TBAA, the scalar type is the same as the scalar tag: +// name and a parent pointer. +llvm::MDNode *CodeGenTBAA::createTBAAScalarType(StringRef Name, + llvm::MDNode *Parent) { + if (CodeGenOpts.StructPathTBAA) + return MDHelper.createTBAAScalarTypeNode(Name, Parent); + else + return MDHelper.createTBAANode(Name, Parent); +} + llvm::MDNode *CodeGenTBAA::getChar() { // Define the root of the tree for user-accessible memory. C and C++ // give special powers to char and certain similar types. However, // these special powers only cover user-accessible memory, and doesn't // include things like vtables. if (!Char) - Char = MDHelper.createTBAANode("omnipotent char", getRoot()); + Char = createTBAAScalarType("omnipotent char", getRoot()); return Char; } @@ -124,7 +136,7 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { // "underlying types". default: return MetadataCache[Ty] = - MDHelper.createTBAANode(BTy->getName(Features), getChar()); + createTBAAScalarType(BTy->getName(Features), getChar()); } } @@ -132,8 +144,8 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { // TODO: Implement C++'s type "similarity" and consider dis-"similar" // pointers distinct. if (Ty->isPointerType()) - return MetadataCache[Ty] = MDHelper.createTBAANode("any pointer", - getChar()); + return MetadataCache[Ty] = createTBAAScalarType("any pointer", + getChar()); // Enum types are distinct types. In C++ they have "underlying types", // however they aren't related for TBAA. @@ -160,7 +172,7 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { llvm::raw_svector_ostream Out(OutName); MContext.mangleCXXRTTIName(QualType(ETy, 0), Out); Out.flush(); - return MetadataCache[Ty] = MDHelper.createTBAANode(OutName, getChar()); + return MetadataCache[Ty] = createTBAAScalarType(OutName, getChar()); } // For now, handle any other kind of type conservatively. @@ -168,7 +180,7 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { } llvm::MDNode *CodeGenTBAA::getTBAAInfoForVTablePtr() { - return MDHelper.createTBAANode("vtable pointer", getRoot()); + return createTBAAScalarType("vtable pointer", getRoot()); } bool @@ -192,8 +204,18 @@ CodeGenTBAA::CollectFields(uint64_t BaseOffset, const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); unsigned idx = 0; + const FieldDecl *LastFD = 0; + bool IsMsStruct = RD->isMsStruct(Context); for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i, ++idx) { + if (IsMsStruct) { + // Zero-length bitfields following non-bitfield members are ignored. + if (Context.ZeroBitfieldFollowsNonBitfield(*i, LastFD)) { + --idx; + continue; + } + LastFD = *i; + } uint64_t Offset = BaseOffset + Layout.getFieldOffset(idx) / Context.getCharWidth(); QualType FieldQTy = i->getType(); @@ -208,7 +230,9 @@ CodeGenTBAA::CollectFields(uint64_t BaseOffset, uint64_t Offset = BaseOffset; uint64_t Size = Context.getTypeSizeInChars(QTy).getQuantity(); llvm::MDNode *TBAAInfo = MayAlias ? getChar() : getTBAAInfo(QTy); - Fields.push_back(llvm::MDBuilder::TBAAStructField(Offset, Size, TBAAInfo)); + llvm::MDNode *TBAATag = CodeGenOpts.StructPathTBAA ? + getTBAAScalarTagInfo(TBAAInfo) : TBAAInfo; + Fields.push_back(llvm::MDBuilder::TBAAStructField(Offset, Size, TBAATag)); return true; } @@ -231,9 +255,11 @@ CodeGenTBAA::getTBAAStructInfo(QualType QTy) { static bool isTBAAPathStruct(QualType QTy) { if (const RecordType *TTy = QTy->getAs<RecordType>()) { const RecordDecl *RD = TTy->getDecl()->getDefinition(); + if (RD->hasFlexibleArrayMember()) + return false; // RD can be struct, union, class, interface or enum. - // For now, we only handle struct. - if (RD->isStruct() && !RD->hasFlexibleArrayMember()) + // For now, we only handle struct and class. + if (RD->isStruct() || RD->isClass()) return true; } return false; @@ -251,29 +277,31 @@ CodeGenTBAA::getTBAAStructTypeInfo(QualType QTy) { const RecordDecl *RD = TTy->getDecl()->getDefinition(); const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - SmallVector <std::pair<uint64_t, llvm::MDNode*>, 4> Fields; - // To reduce the size of MDNode for a given struct type, we only output - // once for all the fields with the same scalar types. - // Offsets for scalar fields in the type DAG are not used. - llvm::SmallSet <llvm::MDNode*, 4> ScalarFieldTypes; + SmallVector <std::pair<llvm::MDNode*, uint64_t>, 4> Fields; unsigned idx = 0; + const FieldDecl *LastFD = 0; + bool IsMsStruct = RD->isMsStruct(Context); for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i, ++idx) { + if (IsMsStruct) { + // Zero-length bitfields following non-bitfield members are ignored. + if (Context.ZeroBitfieldFollowsNonBitfield(*i, LastFD)) { + --idx; + continue; + } + LastFD = *i; + } + QualType FieldQTy = i->getType(); llvm::MDNode *FieldNode; if (isTBAAPathStruct(FieldQTy)) FieldNode = getTBAAStructTypeInfo(FieldQTy); - else { + else FieldNode = getTBAAInfo(FieldQTy); - // Ignore this field if the type already exists. - if (ScalarFieldTypes.count(FieldNode)) - continue; - ScalarFieldTypes.insert(FieldNode); - } if (!FieldNode) return StructTypeMetadataCache[Ty] = NULL; Fields.push_back(std::make_pair( - Layout.getFieldOffset(idx) / Context.getCharWidth(), FieldNode)); + FieldNode, Layout.getFieldOffset(idx) / Context.getCharWidth())); } // TODO: This is using the RTTI name. Is there a better way to get @@ -305,8 +333,18 @@ CodeGenTBAA::getTBAAStructTagInfo(QualType BaseQTy, llvm::MDNode *AccessNode, if (isTBAAPathStruct(BaseQTy)) BNode = getTBAAStructTypeInfo(BaseQTy); if (!BNode) - return StructTagMetadataCache[PathTag] = AccessNode; + return StructTagMetadataCache[PathTag] = + MDHelper.createTBAAStructTagNode(AccessNode, AccessNode, 0); return StructTagMetadataCache[PathTag] = MDHelper.createTBAAStructTagNode(BNode, AccessNode, Offset); } + +llvm::MDNode * +CodeGenTBAA::getTBAAScalarTagInfo(llvm::MDNode *AccessNode) { + if (llvm::MDNode *N = ScalarTagMetadataCache[AccessNode]) + return N; + + return ScalarTagMetadataCache[AccessNode] = + MDHelper.createTBAAStructTagNode(AccessNode, AccessNode, 0); +} diff --git a/lib/CodeGen/CodeGenTBAA.h b/lib/CodeGen/CodeGenTBAA.h index 9ddc3aa..f0c9e06 100644 --- a/lib/CodeGen/CodeGenTBAA.h +++ b/lib/CodeGen/CodeGenTBAA.h @@ -61,6 +61,8 @@ class CodeGenTBAA { llvm::DenseMap<const Type *, llvm::MDNode *> StructTypeMetadataCache; /// This maps TBAAPathTags to a tag node. llvm::DenseMap<TBAAPathTag, llvm::MDNode *> StructTagMetadataCache; + /// This maps a scalar type to a scalar tag node. + llvm::DenseMap<const llvm::MDNode *, llvm::MDNode *> ScalarTagMetadataCache; /// StructMetadataCache - This maps clang::Types to llvm::MDNodes describing /// them for struct assignments. @@ -84,6 +86,11 @@ class CodeGenTBAA { SmallVectorImpl<llvm::MDBuilder::TBAAStructField> &Fields, bool MayAlias); + /// A wrapper function to create a scalar type. For struct-path aware TBAA, + /// the scalar type has the same format as the struct type: name, offset, + /// pointer to another node in the type DAG. + llvm::MDNode *createTBAAScalarType(StringRef Name, llvm::MDNode *Parent); + public: CodeGenTBAA(ASTContext &Ctx, llvm::LLVMContext &VMContext, const CodeGenOptions &CGO, @@ -105,10 +112,13 @@ public: /// Get the MDNode in the type DAG for given struct type QType. llvm::MDNode *getTBAAStructTypeInfo(QualType QType); - /// Get the tag MDNode for a given base type, the actual sclar access MDNode + /// Get the tag MDNode for a given base type, the actual scalar access MDNode /// and offset into the base type. llvm::MDNode *getTBAAStructTagInfo(QualType BaseQType, llvm::MDNode *AccessNode, uint64_t Offset); + + /// Get the sclar tag MDNode for a given scalar type. + llvm::MDNode *getTBAAScalarTagInfo(llvm::MDNode *AccessNode); }; } // end namespace CodeGen diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index 8fc78e3..4240216 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -28,12 +28,12 @@ using namespace clang; using namespace CodeGen; -CodeGenTypes::CodeGenTypes(CodeGenModule &CGM) - : Context(CGM.getContext()), Target(Context.getTargetInfo()), - TheModule(CGM.getModule()), TheDataLayout(CGM.getDataLayout()), - TheABIInfo(CGM.getTargetCodeGenInfo().getABIInfo()), - TheCXXABI(CGM.getCXXABI()), - CodeGenOpts(CGM.getCodeGenOpts()), CGM(CGM) { +CodeGenTypes::CodeGenTypes(CodeGenModule &cgm) + : CGM(cgm), Context(cgm.getContext()), TheModule(cgm.getModule()), + TheDataLayout(cgm.getDataLayout()), + Target(cgm.getTarget()), TheCXXABI(cgm.getCXXABI()), + CodeGenOpts(cgm.getCodeGenOpts()), + TheABIInfo(cgm.getTargetCodeGenInfo().getABIInfo()) { SkippedLayout = false; } @@ -392,6 +392,8 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { } break; } + case Type::Auto: + llvm_unreachable("Unexpected undeduced auto type!"); case Type::Complex: { llvm::Type *EltTy = ConvertType(cast<ComplexType>(Ty)->getElementType()); ResultType = llvm::StructType::get(EltTy, EltTy, NULL); diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index 11fd76f..452375f 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -60,14 +60,17 @@ namespace CodeGen { class CodeGenTypes { public: // Some of this stuff should probably be left on the CGM. + CodeGenModule &CGM; ASTContext &Context; - const TargetInfo &Target; llvm::Module &TheModule; const llvm::DataLayout &TheDataLayout; - const ABIInfo &TheABIInfo; + const TargetInfo &Target; CGCXXABI &TheCXXABI; const CodeGenOptions &CodeGenOpts; - CodeGenModule &CGM; + + // This should not be moved earlier, since its initialization depends on some + // of the previous reference members being already initialized + const ABIInfo &TheABIInfo; private: /// The opaque type map for Objective-C interfaces. All direct @@ -107,14 +110,14 @@ private: llvm::DenseMap<const Type *, llvm::Type *> TypeCache; public: - CodeGenTypes(CodeGenModule &CGM); + CodeGenTypes(CodeGenModule &cgm); ~CodeGenTypes(); const llvm::DataLayout &getDataLayout() const { return TheDataLayout; } - const TargetInfo &getTarget() const { return Target; } ASTContext &getContext() const { return Context; } const ABIInfo &getABIInfo() const { return TheABIInfo; } const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; } + const TargetInfo &getTarget() const { return Target; } CGCXXABI &getCXXABI() const { return TheCXXABI; } llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); } diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index e25d422..e117e28 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -41,6 +41,20 @@ public: ItaniumCXXABI(CodeGen::CodeGenModule &CGM, bool IsARM = false) : CGCXXABI(CGM), IsARM(IsARM) { } + bool isReturnTypeIndirect(const CXXRecordDecl *RD) const { + // Structures with either a non-trivial destructor or a non-trivial + // copy constructor are always indirect. + return !RD->hasTrivialDestructor() || RD->hasNonTrivialCopyConstructor(); + } + + RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const { + // Structures with either a non-trivial destructor or a non-trivial + // copy constructor are always indirect. + if (!RD->hasTrivialDestructor() || RD->hasNonTrivialCopyConstructor()) + return RAA_Indirect; + return RAA_Default; + } + bool isZeroInitializable(const MemberPointerType *MPT); llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT); @@ -130,8 +144,16 @@ public: void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, llvm::GlobalVariable *DeclPtr, bool PerformInit); - void registerGlobalDtor(CodeGenFunction &CGF, llvm::Constant *dtor, - llvm::Constant *addr); + void registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D, + llvm::Constant *dtor, llvm::Constant *addr); + + llvm::Function *getOrCreateThreadLocalWrapper(const VarDecl *VD, + llvm::GlobalVariable *Var); + void EmitThreadLocalInitFuncs( + llvm::ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls, + llvm::Function *InitFunc); + LValue EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF, + const DeclRefExpr *DRE); }; class ARMCXXABI : public ItaniumCXXABI { @@ -177,7 +199,7 @@ public: } CodeGen::CGCXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) { - switch (CGM.getContext().getTargetInfo().getCXXABI().getKind()) { + switch (CGM.getTarget().getCXXABI().getKind()) { // For IR-generation purposes, there's no significant difference // between the ARM and iOS ABIs. case TargetCXXABI::GenericARM: @@ -1042,10 +1064,10 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, bool shouldPerformInit) { CGBuilderTy &Builder = CGF.Builder; - // We only need to use thread-safe statics for local variables; + // We only need to use thread-safe statics for local non-TLS variables; // global initialization is always single-threaded. - bool threadsafe = - (getContext().getLangOpts().ThreadsafeStatics && D.isLocalVarDecl()); + bool threadsafe = getContext().getLangOpts().ThreadsafeStatics && + D.isLocalVarDecl() && !D.getTLSKind(); // If we have a global variable with internal linkage and thread-safe statics // are disabled, we can just let the guard variable be of type i8. @@ -1080,6 +1102,8 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, llvm::ConstantInt::get(guardTy, 0), guardName.str()); guard->setVisibility(var->getVisibility()); + // If the variable is thread-local, so is its guard variable. + guard->setThreadLocalMode(var->getThreadLocalMode()); CGM.setStaticLocalDeclGuardAddress(&D, guard); } @@ -1180,7 +1204,14 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, /// Register a global destructor using __cxa_atexit. static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF, llvm::Constant *dtor, - llvm::Constant *addr) { + llvm::Constant *addr, + bool TLS) { + const char *Name = "__cxa_atexit"; + if (TLS) { + const llvm::Triple &T = CGF.getTarget().getTriple(); + Name = T.isMacOSX() ? "_tlv_atexit" : "__cxa_thread_atexit"; + } + // We're assuming that the destructor function is something we can // reasonably call with the default CC. Go ahead and cast it to the // right prototype. @@ -1193,8 +1224,7 @@ static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF, llvm::FunctionType::get(CGF.IntTy, paramTys, false); // Fetch the actual function. - llvm::Constant *atexit = - CGF.CGM.CreateRuntimeFunction(atexitTy, "__cxa_atexit"); + llvm::Constant *atexit = CGF.CGM.CreateRuntimeFunction(atexitTy, Name); if (llvm::Function *fn = dyn_cast<llvm::Function>(atexit)) fn->setDoesNotThrow(); @@ -1212,12 +1242,15 @@ static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF, /// Register a global destructor as best as we know how. void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF, + const VarDecl &D, llvm::Constant *dtor, llvm::Constant *addr) { // Use __cxa_atexit if available. - if (CGM.getCodeGenOpts().CXAAtExit) { - return emitGlobalDtorWithCXAAtExit(CGF, dtor, addr); - } + if (CGM.getCodeGenOpts().CXAAtExit) + return emitGlobalDtorWithCXAAtExit(CGF, dtor, addr, D.getTLSKind()); + + if (D.getTLSKind()) + CGM.ErrorUnsupported(&D, "non-trivial TLS destruction"); // In Apple kexts, we want to add a global destructor entry. // FIXME: shouldn't this be guarded by some variable? @@ -1228,3 +1261,138 @@ void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF, CGF.registerGlobalDtorWithAtExit(dtor, addr); } + +/// Get the appropriate linkage for the wrapper function. This is essentially +/// the weak form of the variable's linkage; every translation unit which wneeds +/// the wrapper emits a copy, and we want the linker to merge them. +static llvm::GlobalValue::LinkageTypes getThreadLocalWrapperLinkage( + llvm::GlobalValue::LinkageTypes VarLinkage) { + if (llvm::GlobalValue::isLinkerPrivateLinkage(VarLinkage)) + return llvm::GlobalValue::LinkerPrivateWeakLinkage; + // For internal linkage variables, we don't need an external or weak wrapper. + if (llvm::GlobalValue::isLocalLinkage(VarLinkage)) + return VarLinkage; + return llvm::GlobalValue::WeakODRLinkage; +} + +llvm::Function * +ItaniumCXXABI::getOrCreateThreadLocalWrapper(const VarDecl *VD, + llvm::GlobalVariable *Var) { + // Mangle the name for the thread_local wrapper function. + SmallString<256> WrapperName; + { + llvm::raw_svector_ostream Out(WrapperName); + getMangleContext().mangleItaniumThreadLocalWrapper(VD, Out); + Out.flush(); + } + + if (llvm::Value *V = Var->getParent()->getNamedValue(WrapperName)) + return cast<llvm::Function>(V); + + llvm::Type *RetTy = Var->getType(); + if (VD->getType()->isReferenceType()) + RetTy = RetTy->getPointerElementType(); + + llvm::FunctionType *FnTy = llvm::FunctionType::get(RetTy, false); + llvm::Function *Wrapper = llvm::Function::Create( + FnTy, getThreadLocalWrapperLinkage(Var->getLinkage()), WrapperName.str(), + &CGM.getModule()); + // Always resolve references to the wrapper at link time. + Wrapper->setVisibility(llvm::GlobalValue::HiddenVisibility); + return Wrapper; +} + +void ItaniumCXXABI::EmitThreadLocalInitFuncs( + llvm::ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls, + llvm::Function *InitFunc) { + for (unsigned I = 0, N = Decls.size(); I != N; ++I) { + const VarDecl *VD = Decls[I].first; + llvm::GlobalVariable *Var = Decls[I].second; + + // Mangle the name for the thread_local initialization function. + SmallString<256> InitFnName; + { + llvm::raw_svector_ostream Out(InitFnName); + getMangleContext().mangleItaniumThreadLocalInit(VD, Out); + Out.flush(); + } + + // If we have a definition for the variable, emit the initialization + // function as an alias to the global Init function (if any). Otherwise, + // produce a declaration of the initialization function. + llvm::GlobalValue *Init = 0; + bool InitIsInitFunc = false; + if (VD->hasDefinition()) { + InitIsInitFunc = true; + if (InitFunc) + Init = + new llvm::GlobalAlias(InitFunc->getType(), Var->getLinkage(), + InitFnName.str(), InitFunc, &CGM.getModule()); + } else { + // Emit a weak global function referring to the initialization function. + // This function will not exist if the TU defining the thread_local + // variable in question does not need any dynamic initialization for + // its thread_local variables. + llvm::FunctionType *FnTy = llvm::FunctionType::get(CGM.VoidTy, false); + Init = llvm::Function::Create( + FnTy, llvm::GlobalVariable::ExternalWeakLinkage, InitFnName.str(), + &CGM.getModule()); + } + + if (Init) + Init->setVisibility(Var->getVisibility()); + + llvm::Function *Wrapper = getOrCreateThreadLocalWrapper(VD, Var); + llvm::LLVMContext &Context = CGM.getModule().getContext(); + llvm::BasicBlock *Entry = llvm::BasicBlock::Create(Context, "", Wrapper); + CGBuilderTy Builder(Entry); + if (InitIsInitFunc) { + if (Init) + Builder.CreateCall(Init); + } else { + // Don't know whether we have an init function. Call it if it exists. + llvm::Value *Have = Builder.CreateIsNotNull(Init); + llvm::BasicBlock *InitBB = llvm::BasicBlock::Create(Context, "", Wrapper); + llvm::BasicBlock *ExitBB = llvm::BasicBlock::Create(Context, "", Wrapper); + Builder.CreateCondBr(Have, InitBB, ExitBB); + + Builder.SetInsertPoint(InitBB); + Builder.CreateCall(Init); + Builder.CreateBr(ExitBB); + + Builder.SetInsertPoint(ExitBB); + } + + // For a reference, the result of the wrapper function is a pointer to + // the referenced object. + llvm::Value *Val = Var; + if (VD->getType()->isReferenceType()) { + llvm::LoadInst *LI = Builder.CreateLoad(Val); + LI->setAlignment(CGM.getContext().getDeclAlign(VD).getQuantity()); + Val = LI; + } + + Builder.CreateRet(Val); + } +} + +LValue ItaniumCXXABI::EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF, + const DeclRefExpr *DRE) { + const VarDecl *VD = cast<VarDecl>(DRE->getDecl()); + QualType T = VD->getType(); + llvm::Type *Ty = CGF.getTypes().ConvertTypeForMem(T); + llvm::Value *Val = CGF.CGM.GetAddrOfGlobalVar(VD, Ty); + llvm::Function *Wrapper = + getOrCreateThreadLocalWrapper(VD, cast<llvm::GlobalVariable>(Val)); + + Val = CGF.Builder.CreateCall(Wrapper); + + LValue LV; + if (VD->getType()->isReferenceType()) + LV = CGF.MakeNaturalAlignAddrLValue(Val, T); + else + LV = CGF.MakeAddrLValue(Val, DRE->getType(), + CGF.getContext().getDeclAlign(VD)); + // FIXME: need setObjCGCLValueClass? + return LV; +} diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index 00b15c9..f5242ea 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -28,6 +28,17 @@ class MicrosoftCXXABI : public CGCXXABI { public: MicrosoftCXXABI(CodeGenModule &CGM) : CGCXXABI(CGM) {} + bool isReturnTypeIndirect(const CXXRecordDecl *RD) const { + // Structures that are not C++03 PODs are always indirect. + return !RD->isPOD(); + } + + RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const { + if (RD->hasNonTrivialCopyConstructor()) + return RAA_DirectInMemory; + return RAA_Default; + } + StringRef GetPureVirtualCallName() { return "_purecall"; } // No known support for deleted functions in MSVC yet, so this choice is // arbitrary. @@ -111,21 +122,46 @@ public: static bool needThisReturn(GlobalDecl GD); private: - llvm::Constant *getSimpleNullMemberPointer(const MemberPointerType *MPT); - - llvm::Constant *getZeroPtrDiff() { - return llvm::ConstantInt::get(CGM.PtrDiffTy, 0); + llvm::Constant *getZeroInt() { + return llvm::ConstantInt::get(CGM.IntTy, 0); } - llvm::Constant *getAllOnesPtrDiff() { - return llvm::Constant::getAllOnesValue(CGM.PtrDiffTy); + llvm::Constant *getAllOnesInt() { + return llvm::Constant::getAllOnesValue(CGM.IntTy); } + void + GetNullMemberPointerFields(const MemberPointerType *MPT, + llvm::SmallVectorImpl<llvm::Constant *> &fields); + + llvm::Value *AdjustVirtualBase(CodeGenFunction &CGF, const CXXRecordDecl *RD, + llvm::Value *Base, + llvm::Value *VirtualBaseAdjustmentOffset, + llvm::Value *VBPtrOffset /* optional */); + + /// \brief Emits a full member pointer with the fields common to data and + /// function member pointers. + llvm::Constant *EmitFullMemberPointer(llvm::Constant *FirstField, + bool IsMemberFunction, + const CXXRecordDecl *RD); + public: + virtual llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT); + + virtual bool isZeroInitializable(const MemberPointerType *MPT); + virtual llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT); virtual llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT, CharUnits offset); + virtual llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD); + virtual llvm::Constant *EmitMemberPointer(const APValue &MP, QualType MPT); + + virtual llvm::Value *EmitMemberPointerComparison(CodeGenFunction &CGF, + llvm::Value *L, + llvm::Value *R, + const MemberPointerType *MPT, + bool Inequality); virtual llvm::Value *EmitMemberPointerIsNotNull(CodeGenFunction &CGF, llvm::Value *MemPtr, @@ -136,6 +172,12 @@ public: llvm::Value *MemPtr, const MemberPointerType *MPT); + virtual llvm::Value * + EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, + llvm::Value *&This, + llvm::Value *MemPtr, + const MemberPointerType *MPT); + }; } @@ -375,49 +417,259 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, // Not sure whether we want thread-safe static local variables as VS // doesn't make them thread-safe. + if (D.getTLSKind()) + CGM.ErrorUnsupported(&D, "dynamic TLS initialization"); + // Emit the initializer and add a global destructor if appropriate. CGF.EmitCXXGlobalVarDeclInit(D, DeclPtr, PerformInit); } -// Returns true for member pointer types that we know how to represent with a -// simple ptrdiff_t. Currently we only know how to emit, test, and load member -// data pointers for complete single inheritance classes. -static bool isSimpleMemberPointer(const MemberPointerType *MPT) { +// Member pointer helpers. +static bool hasVBPtrOffsetField(MSInheritanceModel Inheritance) { + return Inheritance == MSIM_Unspecified; +} + +static bool hasOnlyOneField(MSInheritanceModel Inheritance) { + return Inheritance <= MSIM_SinglePolymorphic; +} + +// Only member pointers to functions need a this adjustment, since it can be +// combined with the field offset for data pointers. +static bool hasNonVirtualBaseAdjustmentField(bool IsMemberFunction, + MSInheritanceModel Inheritance) { + return (IsMemberFunction && Inheritance >= MSIM_Multiple); +} + +static bool hasVirtualBaseAdjustmentField(MSInheritanceModel Inheritance) { + return Inheritance >= MSIM_Virtual; +} + +// Use zero for the field offset of a null data member pointer if we can +// guarantee that zero is not a valid field offset, or if the member pointer has +// multiple fields. Polymorphic classes have a vfptr at offset zero, so we can +// use zero for null. If there are multiple fields, we can use zero even if it +// is a valid field offset because null-ness testing will check the other +// fields. +static bool nullFieldOffsetIsZero(MSInheritanceModel Inheritance) { + return Inheritance != MSIM_Multiple && Inheritance != MSIM_Single; +} + +bool MicrosoftCXXABI::isZeroInitializable(const MemberPointerType *MPT) { + // Null-ness for function memptrs only depends on the first field, which is + // the function pointer. The rest don't matter, so we can zero initialize. + if (MPT->isMemberFunctionPointer()) + return true; + + // The virtual base adjustment field is always -1 for null, so if we have one + // we can't zero initialize. The field offset is sometimes also -1 if 0 is a + // valid field offset. const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); - return (MPT->isMemberDataPointer() && - !MPT->getClass()->isIncompleteType() && - RD->getNumVBases() == 0); + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); + return (!hasVirtualBaseAdjustmentField(Inheritance) && + nullFieldOffsetIsZero(Inheritance)); } -llvm::Constant * -MicrosoftCXXABI::getSimpleNullMemberPointer(const MemberPointerType *MPT) { - if (isSimpleMemberPointer(MPT)) { - const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); - // A null member data pointer is represented as -1 if the class is not - // polymorphic, and 0 otherwise. - if (RD->isPolymorphic()) - return getZeroPtrDiff(); - return getAllOnesPtrDiff(); +llvm::Type * +MicrosoftCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) { + const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); + llvm::SmallVector<llvm::Type *, 4> fields; + if (MPT->isMemberFunctionPointer()) + fields.push_back(CGM.VoidPtrTy); // FunctionPointerOrVirtualThunk + else + fields.push_back(CGM.IntTy); // FieldOffset + + if (hasNonVirtualBaseAdjustmentField(MPT->isMemberFunctionPointer(), + Inheritance)) + fields.push_back(CGM.IntTy); + if (hasVBPtrOffsetField(Inheritance)) + fields.push_back(CGM.IntTy); + if (hasVirtualBaseAdjustmentField(Inheritance)) + fields.push_back(CGM.IntTy); // VirtualBaseAdjustmentOffset + + if (fields.size() == 1) + return fields[0]; + return llvm::StructType::get(CGM.getLLVMContext(), fields); +} + +void MicrosoftCXXABI:: +GetNullMemberPointerFields(const MemberPointerType *MPT, + llvm::SmallVectorImpl<llvm::Constant *> &fields) { + assert(fields.empty()); + const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); + if (MPT->isMemberFunctionPointer()) { + // FunctionPointerOrVirtualThunk + fields.push_back(llvm::Constant::getNullValue(CGM.VoidPtrTy)); + } else { + if (nullFieldOffsetIsZero(Inheritance)) + fields.push_back(getZeroInt()); // FieldOffset + else + fields.push_back(getAllOnesInt()); // FieldOffset } - return GetBogusMemberPointer(QualType(MPT, 0)); + + if (hasNonVirtualBaseAdjustmentField(MPT->isMemberFunctionPointer(), + Inheritance)) + fields.push_back(getZeroInt()); + if (hasVBPtrOffsetField(Inheritance)) + fields.push_back(getZeroInt()); + if (hasVirtualBaseAdjustmentField(Inheritance)) + fields.push_back(getAllOnesInt()); } llvm::Constant * MicrosoftCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) { - if (isSimpleMemberPointer(MPT)) - return getSimpleNullMemberPointer(MPT); - // FIXME: Implement function member pointers. - return GetBogusMemberPointer(QualType(MPT, 0)); + llvm::SmallVector<llvm::Constant *, 4> fields; + GetNullMemberPointerFields(MPT, fields); + if (fields.size() == 1) + return fields[0]; + llvm::Constant *Res = llvm::ConstantStruct::getAnon(fields); + assert(Res->getType() == ConvertMemberPointerType(MPT)); + return Res; +} + +llvm::Constant * +MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField, + bool IsMemberFunction, + const CXXRecordDecl *RD) +{ + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); + + // Single inheritance class member pointer are represented as scalars instead + // of aggregates. + if (hasOnlyOneField(Inheritance)) + return FirstField; + + llvm::SmallVector<llvm::Constant *, 4> fields; + fields.push_back(FirstField); + + if (hasNonVirtualBaseAdjustmentField(IsMemberFunction, Inheritance)) + fields.push_back(getZeroInt()); + + if (hasVBPtrOffsetField(Inheritance)) { + int64_t VBPtrOffset = + getContext().getASTRecordLayout(RD).getVBPtrOffset().getQuantity(); + if (VBPtrOffset == -1) + VBPtrOffset = 0; + fields.push_back(llvm::ConstantInt::get(CGM.IntTy, VBPtrOffset)); + } + + // The rest of the fields are adjusted by conversions to a more derived class. + if (hasVirtualBaseAdjustmentField(Inheritance)) + fields.push_back(getZeroInt()); + + return llvm::ConstantStruct::getAnon(fields); } llvm::Constant * MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT, CharUnits offset) { - // Member data pointers are plain offsets when no virtual bases are involved. - if (isSimpleMemberPointer(MPT)) - return llvm::ConstantInt::get(CGM.PtrDiffTy, offset.getQuantity()); - // FIXME: Implement member pointers other inheritance models. - return GetBogusMemberPointer(QualType(MPT, 0)); + const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + llvm::Constant *FirstField = + llvm::ConstantInt::get(CGM.IntTy, offset.getQuantity()); + return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/false, RD); +} + +llvm::Constant * +MicrosoftCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { + assert(MD->isInstance() && "Member function must not be static!"); + MD = MD->getCanonicalDecl(); + const CXXRecordDecl *RD = MD->getParent(); + CodeGenTypes &Types = CGM.getTypes(); + + llvm::Constant *FirstField; + if (MD->isVirtual()) { + // FIXME: We have to instantiate a thunk that loads the vftable and jumps to + // the right offset. + FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy); + } else { + const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>(); + llvm::Type *Ty; + // Check whether the function has a computable LLVM signature. + if (Types.isFuncTypeConvertible(FPT)) { + // The function has a computable LLVM signature; use the correct type. + Ty = Types.GetFunctionType(Types.arrangeCXXMethodDeclaration(MD)); + } else { + // Use an arbitrary non-function type to tell GetAddrOfFunction that the + // function type is incomplete. + Ty = CGM.PtrDiffTy; + } + FirstField = CGM.GetAddrOfFunction(MD, Ty); + FirstField = llvm::ConstantExpr::getBitCast(FirstField, CGM.VoidPtrTy); + } + + // The rest of the fields are common with data member pointers. + return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/true, RD); +} + +llvm::Constant * +MicrosoftCXXABI::EmitMemberPointer(const APValue &MP, QualType MPT) { + // FIXME PR15875: Implement member pointer conversions for Constants. + const CXXRecordDecl *RD = MPT->castAs<MemberPointerType>()->getClass()->getAsCXXRecordDecl(); + return EmitFullMemberPointer(llvm::Constant::getNullValue(CGM.VoidPtrTy), + /*IsMemberFunction=*/true, RD); +} + +/// Member pointers are the same if they're either bitwise identical *or* both +/// null. Null-ness for function members is determined by the first field, +/// while for data member pointers we must compare all fields. +llvm::Value * +MicrosoftCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF, + llvm::Value *L, + llvm::Value *R, + const MemberPointerType *MPT, + bool Inequality) { + CGBuilderTy &Builder = CGF.Builder; + + // Handle != comparisons by switching the sense of all boolean operations. + llvm::ICmpInst::Predicate Eq; + llvm::Instruction::BinaryOps And, Or; + if (Inequality) { + Eq = llvm::ICmpInst::ICMP_NE; + And = llvm::Instruction::Or; + Or = llvm::Instruction::And; + } else { + Eq = llvm::ICmpInst::ICMP_EQ; + And = llvm::Instruction::And; + Or = llvm::Instruction::Or; + } + + // If this is a single field member pointer (single inheritance), this is a + // single icmp. + const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); + if (hasOnlyOneField(Inheritance)) + return Builder.CreateICmp(Eq, L, R); + + // Compare the first field. + llvm::Value *L0 = Builder.CreateExtractValue(L, 0, "lhs.0"); + llvm::Value *R0 = Builder.CreateExtractValue(R, 0, "rhs.0"); + llvm::Value *Cmp0 = Builder.CreateICmp(Eq, L0, R0, "memptr.cmp.first"); + + // Compare everything other than the first field. + llvm::Value *Res = 0; + llvm::StructType *LType = cast<llvm::StructType>(L->getType()); + for (unsigned I = 1, E = LType->getNumElements(); I != E; ++I) { + llvm::Value *LF = Builder.CreateExtractValue(L, I); + llvm::Value *RF = Builder.CreateExtractValue(R, I); + llvm::Value *Cmp = Builder.CreateICmp(Eq, LF, RF, "memptr.cmp.rest"); + if (Res) + Res = Builder.CreateBinOp(And, Res, Cmp); + else + Res = Cmp; + } + + // Check if the first field is 0 if this is a function pointer. + if (MPT->isMemberFunctionPointer()) { + // (l1 == r1 && ...) || l0 == 0 + llvm::Value *Zero = llvm::Constant::getNullValue(L0->getType()); + llvm::Value *IsZero = Builder.CreateICmp(Eq, L0, Zero, "memptr.cmp.iszero"); + Res = Builder.CreateBinOp(Or, Res, IsZero); + } + + // Combine the comparison of the first field, which must always be true for + // this comparison to succeeed. + return Builder.CreateBinOp(And, Res, Cmp0, "memptr.cmp"); } llvm::Value * @@ -425,16 +677,90 @@ MicrosoftCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF, llvm::Value *MemPtr, const MemberPointerType *MPT) { CGBuilderTy &Builder = CGF.Builder; + llvm::SmallVector<llvm::Constant *, 4> fields; + // We only need one field for member functions. + if (MPT->isMemberFunctionPointer()) + fields.push_back(llvm::Constant::getNullValue(CGM.VoidPtrTy)); + else + GetNullMemberPointerFields(MPT, fields); + assert(!fields.empty()); + llvm::Value *FirstField = MemPtr; + if (MemPtr->getType()->isStructTy()) + FirstField = Builder.CreateExtractValue(MemPtr, 0); + llvm::Value *Res = Builder.CreateICmpNE(FirstField, fields[0], "memptr.cmp0"); + + // For function member pointers, we only need to test the function pointer + // field. The other fields if any can be garbage. + if (MPT->isMemberFunctionPointer()) + return Res; + + // Otherwise, emit a series of compares and combine the results. + for (int I = 1, E = fields.size(); I < E; ++I) { + llvm::Value *Field = Builder.CreateExtractValue(MemPtr, I); + llvm::Value *Next = Builder.CreateICmpNE(Field, fields[I], "memptr.cmp"); + Res = Builder.CreateAnd(Res, Next, "memptr.tobool"); + } + return Res; +} - // For member data pointers, this is just a check against -1 or 0. - if (isSimpleMemberPointer(MPT)) { - llvm::Constant *Val = getSimpleNullMemberPointer(MPT); - return Builder.CreateICmpNE(MemPtr, Val, "memptr.tobool"); +// Returns an adjusted base cast to i8*, since we do more address arithmetic on +// it. +llvm::Value * +MicrosoftCXXABI::AdjustVirtualBase(CodeGenFunction &CGF, + const CXXRecordDecl *RD, llvm::Value *Base, + llvm::Value *VirtualBaseAdjustmentOffset, + llvm::Value *VBPtrOffset) { + CGBuilderTy &Builder = CGF.Builder; + Base = Builder.CreateBitCast(Base, CGM.Int8PtrTy); + llvm::BasicBlock *OriginalBB = 0; + llvm::BasicBlock *SkipAdjustBB = 0; + llvm::BasicBlock *VBaseAdjustBB = 0; + + // In the unspecified inheritance model, there might not be a vbtable at all, + // in which case we need to skip the virtual base lookup. If there is a + // vbtable, the first entry is a no-op entry that gives back the original + // base, so look for a virtual base adjustment offset of zero. + if (VBPtrOffset) { + OriginalBB = Builder.GetInsertBlock(); + VBaseAdjustBB = CGF.createBasicBlock("memptr.vadjust"); + SkipAdjustBB = CGF.createBasicBlock("memptr.skip_vadjust"); + llvm::Value *IsVirtual = + Builder.CreateICmpNE(VirtualBaseAdjustmentOffset, getZeroInt(), + "memptr.is_vbase"); + Builder.CreateCondBr(IsVirtual, VBaseAdjustBB, SkipAdjustBB); + CGF.EmitBlock(VBaseAdjustBB); } - // FIXME: Implement member pointers other inheritance models. - ErrorUnsupportedABI(CGF, "function member pointer tests"); - return GetBogusMemberPointer(QualType(MPT, 0)); + // If we weren't given a dynamic vbptr offset, RD should be complete and we'll + // know the vbptr offset. + if (!VBPtrOffset) { + CharUnits offs = getContext().getASTRecordLayout(RD).getVBPtrOffset(); + VBPtrOffset = llvm::ConstantInt::get(CGM.IntTy, offs.getQuantity()); + } + // Load the vbtable pointer from the vbtable offset in the instance. + llvm::Value *VBPtr = + Builder.CreateInBoundsGEP(Base, VBPtrOffset, "memptr.vbptr"); + llvm::Value *VBTable = + Builder.CreateBitCast(VBPtr, CGM.Int8PtrTy->getPointerTo(0)); + VBTable = Builder.CreateLoad(VBTable, "memptr.vbtable"); + // Load an i32 offset from the vb-table. + llvm::Value *VBaseOffs = + Builder.CreateInBoundsGEP(VBTable, VirtualBaseAdjustmentOffset); + VBaseOffs = Builder.CreateBitCast(VBaseOffs, CGM.Int32Ty->getPointerTo(0)); + VBaseOffs = Builder.CreateLoad(VBaseOffs, "memptr.vbase_offs"); + // Add it to VBPtr. GEP will sign extend the i32 value for us. + llvm::Value *AdjustedBase = Builder.CreateInBoundsGEP(VBPtr, VBaseOffs); + + // Merge control flow with the case where we didn't have to adjust. + if (VBaseAdjustBB) { + Builder.CreateBr(SkipAdjustBB); + CGF.EmitBlock(SkipAdjustBB); + llvm::PHINode *Phi = Builder.CreatePHI(CGM.Int8PtrTy, 2, "memptr.base"); + Phi->addIncoming(Base, OriginalBB); + Phi->addIncoming(AdjustedBase, VBaseAdjustBB); + return Phi; + } + return AdjustedBase; } llvm::Value * @@ -442,32 +768,90 @@ MicrosoftCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF, llvm::Value *Base, llvm::Value *MemPtr, const MemberPointerType *MPT) { + assert(MPT->isMemberDataPointer()); unsigned AS = Base->getType()->getPointerAddressSpace(); llvm::Type *PType = CGF.ConvertTypeForMem(MPT->getPointeeType())->getPointerTo(AS); CGBuilderTy &Builder = CGF.Builder; - - if (MPT->isMemberFunctionPointer()) { - ErrorUnsupportedABI(CGF, "function member pointer address"); - return llvm::Constant::getNullValue(PType); + const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); + + // Extract the fields we need, regardless of model. We'll apply them if we + // have them. + llvm::Value *FieldOffset = MemPtr; + llvm::Value *VirtualBaseAdjustmentOffset = 0; + llvm::Value *VBPtrOffset = 0; + if (MemPtr->getType()->isStructTy()) { + // We need to extract values. + unsigned I = 0; + FieldOffset = Builder.CreateExtractValue(MemPtr, I++); + if (hasVBPtrOffsetField(Inheritance)) + VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++); + if (hasVirtualBaseAdjustmentField(Inheritance)) + VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, I++); } - llvm::Value *Addr; - if (isSimpleMemberPointer(MPT)) { - // Add the offset with GEP and i8*. - assert(MemPtr->getType() == CGM.PtrDiffTy); - Base = Builder.CreateBitCast(Base, Builder.getInt8Ty()->getPointerTo(AS)); - Addr = Builder.CreateInBoundsGEP(Base, MemPtr, "memptr.offset"); - } else { - ErrorUnsupportedABI(CGF, "non-scalar member pointers"); - return llvm::Constant::getNullValue(PType); + if (VirtualBaseAdjustmentOffset) { + Base = AdjustVirtualBase(CGF, RD, Base, VirtualBaseAdjustmentOffset, + VBPtrOffset); } + llvm::Value *Addr = + Builder.CreateInBoundsGEP(Base, FieldOffset, "memptr.offset"); // Cast the address to the appropriate pointer type, adopting the address // space of the base pointer. return Builder.CreateBitCast(Addr, PType); } +llvm::Value * +MicrosoftCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, + llvm::Value *&This, + llvm::Value *MemPtr, + const MemberPointerType *MPT) { + assert(MPT->isMemberFunctionPointer()); + const FunctionProtoType *FPT = + MPT->getPointeeType()->castAs<FunctionProtoType>(); + const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + llvm::FunctionType *FTy = + CGM.getTypes().GetFunctionType( + CGM.getTypes().arrangeCXXMethodType(RD, FPT)); + CGBuilderTy &Builder = CGF.Builder; + + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); + + // Extract the fields we need, regardless of model. We'll apply them if we + // have them. + llvm::Value *FunctionPointer = MemPtr; + llvm::Value *NonVirtualBaseAdjustment = NULL; + llvm::Value *VirtualBaseAdjustmentOffset = NULL; + llvm::Value *VBPtrOffset = NULL; + if (MemPtr->getType()->isStructTy()) { + // We need to extract values. + unsigned I = 0; + FunctionPointer = Builder.CreateExtractValue(MemPtr, I++); + if (hasNonVirtualBaseAdjustmentField(MPT, Inheritance)) + NonVirtualBaseAdjustment = Builder.CreateExtractValue(MemPtr, I++); + if (hasVBPtrOffsetField(Inheritance)) + VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++); + if (hasVirtualBaseAdjustmentField(Inheritance)) + VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, I++); + } + + if (VirtualBaseAdjustmentOffset) { + This = AdjustVirtualBase(CGF, RD, This, VirtualBaseAdjustmentOffset, + VBPtrOffset); + } + + if (NonVirtualBaseAdjustment) { + // Apply the adjustment and cast back to the original struct type. + llvm::Value *Ptr = Builder.CreateBitCast(This, Builder.getInt8PtrTy()); + Ptr = Builder.CreateInBoundsGEP(Ptr, NonVirtualBaseAdjustment); + This = Builder.CreateBitCast(Ptr, This->getType(), "this.adjusted"); + } + + return Builder.CreateBitCast(FunctionPointer, FTy->getPointerTo()); +} + CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) { return new MicrosoftCXXABI(CGM); } diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp index d6e5f06..69e5b32 100644 --- a/lib/CodeGen/ModuleBuilder.cpp +++ b/lib/CodeGen/ModuleBuilder.cpp @@ -31,15 +31,13 @@ namespace { OwningPtr<const llvm::DataLayout> TD; ASTContext *Ctx; const CodeGenOptions CodeGenOpts; // Intentionally copied in. - const TargetOptions TargetOpts; // Intentionally copied in. protected: OwningPtr<llvm::Module> M; OwningPtr<CodeGen::CodeGenModule> Builder; public: CodeGeneratorImpl(DiagnosticsEngine &diags, const std::string& ModuleName, - const CodeGenOptions &CGO, const TargetOptions &TO, - llvm::LLVMContext& C) - : Diags(diags), CodeGenOpts(CGO), TargetOpts(TO), + const CodeGenOptions &CGO, llvm::LLVMContext& C) + : Diags(diags), CodeGenOpts(CGO), M(new llvm::Module(ModuleName, C)) {} virtual ~CodeGeneratorImpl() {} @@ -58,8 +56,8 @@ namespace { M->setTargetTriple(Ctx->getTargetInfo().getTriple().getTriple()); M->setDataLayout(Ctx->getTargetInfo().getTargetDescription()); TD.reset(new llvm::DataLayout(Ctx->getTargetInfo().getTargetDescription())); - Builder.reset(new CodeGen::CodeGenModule(Context, CodeGenOpts, TargetOpts, - *M, *TD, Diags)); + Builder.reset(new CodeGen::CodeGenModule(Context, CodeGenOpts, *M, *TD, + Diags)); } virtual void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) { @@ -125,7 +123,7 @@ void CodeGenerator::anchor() { } CodeGenerator *clang::CreateLLVMCodeGen(DiagnosticsEngine &Diags, const std::string& ModuleName, const CodeGenOptions &CGO, - const TargetOptions &TO, + const TargetOptions &/*TO*/, llvm::LLVMContext& C) { - return new CodeGeneratorImpl(Diags, ModuleName, CGO, TO, C); + return new CodeGeneratorImpl(Diags, ModuleName, CGO, C); } diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 7cc63b7..32b27b3 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -14,6 +14,7 @@ #include "TargetInfo.h" #include "ABIInfo.h" +#include "CGCXXABI.h" #include "CodeGenFunction.h" #include "clang/AST/RecordLayout.h" #include "clang/Frontend/CodeGenOptions.h" @@ -43,6 +44,37 @@ static bool isAggregateTypeForABI(QualType T) { ABIInfo::~ABIInfo() {} +static bool isRecordReturnIndirect(const RecordType *RT, CodeGen::CodeGenTypes &CGT) { + const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); + if (!RD) + return false; + return CGT.CGM.getCXXABI().isReturnTypeIndirect(RD); +} + + +static bool isRecordReturnIndirect(QualType T, CodeGen::CodeGenTypes &CGT) { + const RecordType *RT = T->getAs<RecordType>(); + if (!RT) + return false; + return isRecordReturnIndirect(RT, CGT); +} + +static CGCXXABI::RecordArgABI getRecordArgABI(const RecordType *RT, + CodeGen::CodeGenTypes &CGT) { + const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); + if (!RD) + return CGCXXABI::RAA_Default; + return CGT.CGM.getCXXABI().getRecordArgABI(RD); +} + +static CGCXXABI::RecordArgABI getRecordArgABI(QualType T, + CodeGen::CodeGenTypes &CGT) { + const RecordType *RT = T->getAs<RecordType>(); + if (!RT) + return CGCXXABI::RAA_Default; + return getRecordArgABI(RT, CGT); +} + ASTContext &ABIInfo::getContext() const { return CGT.getContext(); } @@ -55,6 +87,9 @@ const llvm::DataLayout &ABIInfo::getDataLayout() const { return CGT.getDataLayout(); } +const TargetInfo &ABIInfo::getTarget() const { + return CGT.getTarget(); +} void ABIArgInfo::dump() const { raw_ostream &OS = llvm::errs(); @@ -167,27 +202,6 @@ static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays) { return true; } -/// hasNonTrivialDestructorOrCopyConstructor - Determine if a type has either -/// a non-trivial destructor or a non-trivial copy constructor. -static bool hasNonTrivialDestructorOrCopyConstructor(const RecordType *RT) { - const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); - if (!RD) - return false; - - return !RD->hasTrivialDestructor() || RD->hasNonTrivialCopyConstructor(); -} - -/// isRecordWithNonTrivialDestructorOrCopyConstructor - Determine if a type is -/// a record type with either a non-trivial destructor or a non-trivial copy -/// constructor. -static bool isRecordWithNonTrivialDestructorOrCopyConstructor(QualType T) { - const RecordType *RT = T->getAs<RecordType>(); - if (!RT) - return false; - - return hasNonTrivialDestructorOrCopyConstructor(RT); -} - /// isSingleElementStruct - Determine if a structure is a "single /// element struct", i.e. it has exactly one non-empty field or /// exactly one field which is itself a single element @@ -367,7 +381,7 @@ ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty) const { if (isAggregateTypeForABI(Ty)) { // Records with non trivial destructors/constructors should not be passed // by value. - if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) + if (isRecordReturnIndirect(Ty, CGT)) return ABIArgInfo::getIndirect(0, /*ByVal=*/false); return ABIArgInfo::getIndirect(0); @@ -398,6 +412,9 @@ ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const { //===----------------------------------------------------------------------===// // le32/PNaCl bitcode ABI Implementation +// +// This is a simplified version of the x86_32 ABI. Arguments and return values +// are always passed on the stack. //===----------------------------------------------------------------------===// class PNaClABIInfo : public ABIInfo { @@ -405,7 +422,7 @@ class PNaClABIInfo : public ABIInfo { PNaClABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {} ABIArgInfo classifyReturnType(QualType RetTy) const; - ABIArgInfo classifyArgumentType(QualType RetTy, unsigned &FreeRegs) const; + ABIArgInfo classifyArgumentType(QualType RetTy) const; virtual void computeInfo(CGFunctionInfo &FI) const; virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, @@ -421,13 +438,9 @@ class PNaClTargetCodeGenInfo : public TargetCodeGenInfo { void PNaClABIInfo::computeInfo(CGFunctionInfo &FI) const { FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); - // Obtain the initial number of registers available for passing integers - // from the function's regparm attribute. - unsigned FreeRegs = FI.getHasRegParm() ? FI.getRegParm() : 0; - for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) - it->info = classifyArgumentType(it->type, FreeRegs); + it->info = classifyArgumentType(it->type); } llvm::Value *PNaClABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, @@ -435,42 +448,22 @@ llvm::Value *PNaClABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, return 0; } -// \brief Classify argument of given type \p Ty. \p FreeRegs is the number of -// registers available for passing arguments - it can be updated by this -// method. -ABIArgInfo PNaClABIInfo::classifyArgumentType(QualType Ty, - unsigned &FreeRegs) const { +/// \brief Classify argument of given type \p Ty. +ABIArgInfo PNaClABIInfo::classifyArgumentType(QualType Ty) const { if (isAggregateTypeForABI(Ty)) { - // In the PNaCl ABI we always pass records/structures on the stack. The - // byval attribute can be used if the record doesn't have non-trivial - // constructors/destructors. - FreeRegs = 0; - if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) - return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT)) + return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory); return ABIArgInfo::getIndirect(0); - } - - // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs<EnumType>()) + } else if (const EnumType *EnumTy = Ty->getAs<EnumType>()) { + // Treat an enum type as its underlying type. Ty = EnumTy->getDecl()->getIntegerType(); + } else if (Ty->isFloatingType()) { + // Floating-point types don't go inreg. + return ABIArgInfo::getDirect(); + } - ABIArgInfo BaseInfo = (Ty->isPromotableIntegerType() ? + return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - - // Figure out how many of the free registers can be occupied by this type. - // regparm registers are 32-bit. - unsigned NumRegsRequired = (getContext().getTypeSize(Ty) + 31) / 32; - if (NumRegsRequired == 0) return BaseInfo; - if (NumRegsRequired > FreeRegs) { - // If this type needs more registers than we have available, no more - // passing in-registers can happen. - FreeRegs = 0; - return BaseInfo; - } - FreeRegs -= NumRegsRequired; - return BaseInfo.isDirect() ? - ABIArgInfo::getDirectInReg(BaseInfo.getCoerceToType()) : - ABIArgInfo::getExtendInReg(BaseInfo.getCoerceToType()); } ABIArgInfo PNaClABIInfo::classifyReturnType(QualType RetTy) const { @@ -520,7 +513,7 @@ class X86_32ABIInfo : public ABIInfo { bool IsDarwinVectorABI; bool IsSmallStructInRegABI; - bool IsWin32FloatStructABI; + bool IsWin32StructABI; unsigned DefaultNumRegisterParameters; static bool isRegisterSize(unsigned Size) { @@ -555,7 +548,7 @@ public: X86_32ABIInfo(CodeGen::CodeGenTypes &CGT, bool d, bool p, bool w, unsigned r) : ABIInfo(CGT), IsDarwinVectorABI(d), IsSmallStructInRegABI(p), - IsWin32FloatStructABI(w), DefaultNumRegisterParameters(r) {} + IsWin32StructABI(w), DefaultNumRegisterParameters(r) {} }; class X86_32TargetCodeGenInfo : public TargetCodeGenInfo { @@ -569,8 +562,7 @@ public: int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const { // Darwin uses different dwarf register numbers for EH. - if (CGM.isTargetDarwin()) return 5; - + if (CGM.getTarget().getTriple().isOSDarwin()) return 5; return 4; } @@ -682,9 +674,7 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, if (isAggregateTypeForABI(RetTy)) { if (const RecordType *RT = RetTy->getAs<RecordType>()) { - // Structures with either a non-trivial destructor or a non-trivial - // copy constructor are always indirect. - if (hasNonTrivialDestructorOrCopyConstructor(RT)) + if (isRecordReturnIndirect(RT, CGT)) return ABIArgInfo::getIndirect(0, /*ByVal=*/false); // Structures with flexible arrays are always indirect. @@ -708,7 +698,7 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, // We apply a similar transformation for pointer types to improve the // quality of the generated IR. if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext())) - if ((!IsWin32FloatStructABI && SeltTy->isRealFloatingType()) + if ((!IsWin32StructABI && SeltTy->isRealFloatingType()) || SeltTy->hasPointerRepresentation()) return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); @@ -865,13 +855,14 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, bool IsFastCall) const { // FIXME: Set alignment on indirect arguments. if (isAggregateTypeForABI(Ty)) { - // Structures with flexible arrays are always indirect. if (const RecordType *RT = Ty->getAs<RecordType>()) { - // Structures with either a non-trivial destructor or a non-trivial - // copy constructor are always indirect. - if (hasNonTrivialDestructorOrCopyConstructor(RT)) - return getIndirectResult(Ty, false, FreeRegs); + if (IsWin32StructABI) + return getIndirectResult(Ty, true, FreeRegs); + + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, CGT)) + return getIndirectResult(Ty, RAA == CGCXXABI::RAA_DirectInMemory, FreeRegs); + // Structures with flexible arrays are always indirect. if (RT->getDecl()->hasFlexibleArrayMember()) return getIndirectResult(Ty, true, FreeRegs); } @@ -1038,7 +1029,7 @@ bool X86_32TargetCodeGenInfo::initDwarfEHRegSizeTable( // 8 is %eip. AssignToArrayRange(Builder, Address, Four8, 0, 8); - if (CGF.CGM.isTargetDarwin()) { + if (CGF.CGM.getTarget().getTriple().isOSDarwin()) { // 12-16 are st(0..4). Not sure why we stop at 4. // These have size 16, which is sizeof(long double) on // platforms with 8-byte alignment for that type. @@ -1163,7 +1154,7 @@ class X86_64ABIInfo : public ABIInfo { /// required strict binary compatibility with older versions of GCC /// may need to exempt themselves. bool honorsRevision0_98() const { - return !getContext().getTargetInfo().getTriple().isOSDarwin(); + return !getTarget().getTriple().isOSDarwin(); } bool HasAVX; @@ -1198,7 +1189,7 @@ public: /// WinX86_64ABIInfo - The Windows X86_64 ABI information. class WinX86_64ABIInfo : public ABIInfo { - ABIArgInfo classify(QualType Ty) const; + ABIArgInfo classify(QualType Ty, bool IsReturnType) const; public: WinX86_64ABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {} @@ -1387,8 +1378,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Current = Integer; } else if ((k == BuiltinType::Float || k == BuiltinType::Double) || (k == BuiltinType::LongDouble && - getContext().getTargetInfo().getTriple().getOS() == - llvm::Triple::NaCl)) { + getTarget().getTriple().getOS() == llvm::Triple::NaCl)) { Current = SSE; } else if (k == BuiltinType::LongDouble) { Lo = X87; @@ -1476,8 +1466,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Current = SSE; else if (ET == getContext().DoubleTy || (ET == getContext().LongDoubleTy && - getContext().getTargetInfo().getTriple().getOS() == - llvm::Triple::NaCl)) + getTarget().getTriple().getOS() == llvm::Triple::NaCl)) Lo = Hi = SSE; else if (ET == getContext().LongDoubleTy) Current = ComplexX87; @@ -1546,7 +1535,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, // AMD64-ABI 3.2.3p2: Rule 2. If a C++ object has either a non-trivial // copy constructor or a non-trivial destructor, it is passed by invisible // reference. - if (hasNonTrivialDestructorOrCopyConstructor(RT)) + if (getRecordArgABI(RT, CGT)) return; const RecordDecl *RD = RT->getDecl(); @@ -1696,8 +1685,8 @@ ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty, ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } - if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) - return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT)) + return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory); // Compute the byval alignment. We specify the alignment of the byval in all // cases so that the mid-level optimizer knows the alignment of the byval. @@ -2185,7 +2174,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType( // COMPLEX_X87, it is passed in memory. case X87: case ComplexX87: - if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) + if (getRecordArgABI(Ty, CGT) == CGCXXABI::RAA_Indirect) ++neededInt; return getIndirectResult(Ty, freeIntRegs); @@ -2516,7 +2505,7 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, return ResAddr; } -ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty) const { +ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, bool IsReturnType) const { if (Ty->isVoidType()) return ABIArgInfo::getIgnore(); @@ -2527,14 +2516,19 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty) const { uint64_t Size = getContext().getTypeSize(Ty); if (const RecordType *RT = Ty->getAs<RecordType>()) { - if (hasNonTrivialDestructorOrCopyConstructor(RT) || - RT->getDecl()->hasFlexibleArrayMember()) + if (IsReturnType) { + if (isRecordReturnIndirect(RT, CGT)) + return ABIArgInfo::getIndirect(0, false); + } else { + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, CGT)) + return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory); + } + + if (RT->getDecl()->hasFlexibleArrayMember()) return ABIArgInfo::getIndirect(0, /*ByVal=*/false); // FIXME: mingw-w64-gcc emits 128-bit struct as i128 - if (Size == 128 && - getContext().getTargetInfo().getTriple().getOS() - == llvm::Triple::MinGW32) + if (Size == 128 && getTarget().getTriple().getOS() == llvm::Triple::MinGW32) return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size)); @@ -2557,11 +2551,11 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty) const { void WinX86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const { QualType RetTy = FI.getReturnType(); - FI.getReturnInfo() = classify(RetTy); + FI.getReturnInfo() = classify(RetTy, true); for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) - it->info = classify(it->type); + it->info = classify(it->type, false); } llvm::Value *WinX86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, @@ -2788,10 +2782,8 @@ PPC64_SVR4_ABIInfo::classifyArgumentType(QualType Ty) const { return ABIArgInfo::getDirect(); if (isAggregateTypeForABI(Ty)) { - // Records with non trivial destructors/constructors should not be passed - // by value. - if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) - return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT)) + return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory); return ABIArgInfo::getIndirect(0); } @@ -2964,8 +2956,7 @@ public: } bool isEABI() const { - StringRef Env = - getContext().getTargetInfo().getTriple().getEnvironmentName(); + StringRef Env = getTarget().getTriple().getEnvironmentName(); return (Env == "gnueabi" || Env == "eabi" || Env == "android" || Env == "androideabi"); } @@ -3064,7 +3055,7 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const { /// Return the default calling convention that LLVM will use. llvm::CallingConv::ID ARMABIInfo::getLLVMDefaultCC() const { // The default calling convention that LLVM will infer. - if (getContext().getTargetInfo().getTriple().getEnvironmentName()=="gnueabihf") + if (getTarget().getTriple().getEnvironmentName()=="gnueabihf") return llvm::CallingConv::ARM_AAPCS_VFP; else if (isEABI()) return llvm::CallingConv::ARM_AAPCS; @@ -3256,10 +3247,8 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, int *VFPRegs, if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); - // Structures with either a non-trivial destructor or a non-trivial - // copy constructor are always indirect. - if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) - return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT)) + return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory); if (getABIKind() == ARMABIInfo::AAPCS_VFP) { // Homogeneous Aggregates need to be expanded when we can fit the aggregate @@ -3422,7 +3411,7 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const { // Structures with either a non-trivial destructor or a non-trivial // copy constructor are always indirect. - if (isRecordWithNonTrivialDestructorOrCopyConstructor(RetTy)) + if (isRecordReturnIndirect(RetTy, CGT)) return ABIArgInfo::getIndirect(0, /*ByVal=*/false); // Are we following APCS? @@ -3746,12 +3735,10 @@ ABIArgInfo AArch64ABIInfo::classifyGenericType(QualType Ty, return tryUseRegs(Ty, FreeIntRegs, RegsNeeded, /*IsInt=*/ true); } - // Structures with either a non-trivial destructor or a non-trivial - // copy constructor are always indirect. - if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) { - if (FreeIntRegs > 0) + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT)) { + if (FreeIntRegs > 0 && RAA == CGCXXABI::RAA_Indirect) --FreeIntRegs; - return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory); } if (isEmptyRecord(getContext(), Ty, true)) { @@ -4130,6 +4117,293 @@ void NVPTXTargetCodeGenInfo::addKernelMetadata(llvm::Function *F) { } //===----------------------------------------------------------------------===// +// SystemZ ABI Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class SystemZABIInfo : public ABIInfo { +public: + SystemZABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {} + + bool isPromotableIntegerType(QualType Ty) const; + bool isCompoundType(QualType Ty) const; + bool isFPArgumentType(QualType Ty) const; + + ABIArgInfo classifyReturnType(QualType RetTy) const; + ABIArgInfo classifyArgumentType(QualType ArgTy) const; + + virtual void computeInfo(CGFunctionInfo &FI) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); + it != ie; ++it) + it->info = classifyArgumentType(it->type); + } + + virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const; +}; + +class SystemZTargetCodeGenInfo : public TargetCodeGenInfo { +public: + SystemZTargetCodeGenInfo(CodeGenTypes &CGT) + : TargetCodeGenInfo(new SystemZABIInfo(CGT)) {} +}; + +} + +bool SystemZABIInfo::isPromotableIntegerType(QualType Ty) const { + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = Ty->getAs<EnumType>()) + Ty = EnumTy->getDecl()->getIntegerType(); + + // Promotable integer types are required to be promoted by the ABI. + if (Ty->isPromotableIntegerType()) + return true; + + // 32-bit values must also be promoted. + if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) + switch (BT->getKind()) { + case BuiltinType::Int: + case BuiltinType::UInt: + return true; + default: + return false; + } + return false; +} + +bool SystemZABIInfo::isCompoundType(QualType Ty) const { + return Ty->isAnyComplexType() || isAggregateTypeForABI(Ty); +} + +bool SystemZABIInfo::isFPArgumentType(QualType Ty) const { + if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) + switch (BT->getKind()) { + case BuiltinType::Float: + case BuiltinType::Double: + return true; + default: + return false; + } + + if (const RecordType *RT = Ty->getAsStructureType()) { + const RecordDecl *RD = RT->getDecl(); + bool Found = false; + + // If this is a C++ record, check the bases first. + if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) + for (CXXRecordDecl::base_class_const_iterator I = CXXRD->bases_begin(), + E = CXXRD->bases_end(); I != E; ++I) { + QualType Base = I->getType(); + + // Empty bases don't affect things either way. + if (isEmptyRecord(getContext(), Base, true)) + continue; + + if (Found) + return false; + Found = isFPArgumentType(Base); + if (!Found) + return false; + } + + // Check the fields. + for (RecordDecl::field_iterator I = RD->field_begin(), + E = RD->field_end(); I != E; ++I) { + const FieldDecl *FD = *I; + + // Empty bitfields don't affect things either way. + // Unlike isSingleElementStruct(), empty structure and array fields + // do count. So do anonymous bitfields that aren't zero-sized. + if (FD->isBitField() && FD->getBitWidthValue(getContext()) == 0) + return true; + + // Unlike isSingleElementStruct(), arrays do not count. + // Nested isFPArgumentType structures still do though. + if (Found) + return false; + Found = isFPArgumentType(FD->getType()); + if (!Found) + return false; + } + + // Unlike isSingleElementStruct(), trailing padding is allowed. + // An 8-byte aligned struct s { float f; } is passed as a double. + return Found; + } + + return false; +} + +llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const { + // Assume that va_list type is correct; should be pointer to LLVM type: + // struct { + // i64 __gpr; + // i64 __fpr; + // i8 *__overflow_arg_area; + // i8 *__reg_save_area; + // }; + + // Every argument occupies 8 bytes and is passed by preference in either + // GPRs or FPRs. + Ty = CGF.getContext().getCanonicalType(Ty); + ABIArgInfo AI = classifyArgumentType(Ty); + bool InFPRs = isFPArgumentType(Ty); + + llvm::Type *APTy = llvm::PointerType::getUnqual(CGF.ConvertTypeForMem(Ty)); + bool IsIndirect = AI.isIndirect(); + unsigned UnpaddedBitSize; + if (IsIndirect) { + APTy = llvm::PointerType::getUnqual(APTy); + UnpaddedBitSize = 64; + } else + UnpaddedBitSize = getContext().getTypeSize(Ty); + unsigned PaddedBitSize = 64; + assert((UnpaddedBitSize <= PaddedBitSize) && "Invalid argument size."); + + unsigned PaddedSize = PaddedBitSize / 8; + unsigned Padding = (PaddedBitSize - UnpaddedBitSize) / 8; + + unsigned MaxRegs, RegCountField, RegSaveIndex, RegPadding; + if (InFPRs) { + MaxRegs = 4; // Maximum of 4 FPR arguments + RegCountField = 1; // __fpr + RegSaveIndex = 16; // save offset for f0 + RegPadding = 0; // floats are passed in the high bits of an FPR + } else { + MaxRegs = 5; // Maximum of 5 GPR arguments + RegCountField = 0; // __gpr + RegSaveIndex = 2; // save offset for r2 + RegPadding = Padding; // values are passed in the low bits of a GPR + } + + llvm::Value *RegCountPtr = + CGF.Builder.CreateStructGEP(VAListAddr, RegCountField, "reg_count_ptr"); + llvm::Value *RegCount = CGF.Builder.CreateLoad(RegCountPtr, "reg_count"); + llvm::Type *IndexTy = RegCount->getType(); + llvm::Value *MaxRegsV = llvm::ConstantInt::get(IndexTy, MaxRegs); + llvm::Value *InRegs = CGF.Builder.CreateICmpULT(RegCount, MaxRegsV, + "fits_in_regs"); + + llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg"); + llvm::BasicBlock *InMemBlock = CGF.createBasicBlock("vaarg.in_mem"); + llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end"); + CGF.Builder.CreateCondBr(InRegs, InRegBlock, InMemBlock); + + // Emit code to load the value if it was passed in registers. + CGF.EmitBlock(InRegBlock); + + // Work out the address of an argument register. + llvm::Value *PaddedSizeV = llvm::ConstantInt::get(IndexTy, PaddedSize); + llvm::Value *ScaledRegCount = + CGF.Builder.CreateMul(RegCount, PaddedSizeV, "scaled_reg_count"); + llvm::Value *RegBase = + llvm::ConstantInt::get(IndexTy, RegSaveIndex * PaddedSize + RegPadding); + llvm::Value *RegOffset = + CGF.Builder.CreateAdd(ScaledRegCount, RegBase, "reg_offset"); + llvm::Value *RegSaveAreaPtr = + CGF.Builder.CreateStructGEP(VAListAddr, 3, "reg_save_area_ptr"); + llvm::Value *RegSaveArea = + CGF.Builder.CreateLoad(RegSaveAreaPtr, "reg_save_area"); + llvm::Value *RawRegAddr = + CGF.Builder.CreateGEP(RegSaveArea, RegOffset, "raw_reg_addr"); + llvm::Value *RegAddr = + CGF.Builder.CreateBitCast(RawRegAddr, APTy, "reg_addr"); + + // Update the register count + llvm::Value *One = llvm::ConstantInt::get(IndexTy, 1); + llvm::Value *NewRegCount = + CGF.Builder.CreateAdd(RegCount, One, "reg_count"); + CGF.Builder.CreateStore(NewRegCount, RegCountPtr); + CGF.EmitBranch(ContBlock); + + // Emit code to load the value if it was passed in memory. + CGF.EmitBlock(InMemBlock); + + // Work out the address of a stack argument. + llvm::Value *OverflowArgAreaPtr = + CGF.Builder.CreateStructGEP(VAListAddr, 2, "overflow_arg_area_ptr"); + llvm::Value *OverflowArgArea = + CGF.Builder.CreateLoad(OverflowArgAreaPtr, "overflow_arg_area"); + llvm::Value *PaddingV = llvm::ConstantInt::get(IndexTy, Padding); + llvm::Value *RawMemAddr = + CGF.Builder.CreateGEP(OverflowArgArea, PaddingV, "raw_mem_addr"); + llvm::Value *MemAddr = + CGF.Builder.CreateBitCast(RawMemAddr, APTy, "mem_addr"); + + // Update overflow_arg_area_ptr pointer + llvm::Value *NewOverflowArgArea = + CGF.Builder.CreateGEP(OverflowArgArea, PaddedSizeV, "overflow_arg_area"); + CGF.Builder.CreateStore(NewOverflowArgArea, OverflowArgAreaPtr); + CGF.EmitBranch(ContBlock); + + // Return the appropriate result. + CGF.EmitBlock(ContBlock); + llvm::PHINode *ResAddr = CGF.Builder.CreatePHI(APTy, 2, "va_arg.addr"); + ResAddr->addIncoming(RegAddr, InRegBlock); + ResAddr->addIncoming(MemAddr, InMemBlock); + + if (IsIndirect) + return CGF.Builder.CreateLoad(ResAddr, "indirect_arg"); + + return ResAddr; +} + + +ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy) const { + if (RetTy->isVoidType()) + return ABIArgInfo::getIgnore(); + if (isCompoundType(RetTy) || getContext().getTypeSize(RetTy) > 64) + return ABIArgInfo::getIndirect(0); + return (isPromotableIntegerType(RetTy) ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); +} + +ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty) const { + // Handle the generic C++ ABI. + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT)) + return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory); + + // Integers and enums are extended to full register width. + if (isPromotableIntegerType(Ty)) + return ABIArgInfo::getExtend(); + + // Values that are not 1, 2, 4 or 8 bytes in size are passed indirectly. + uint64_t Size = getContext().getTypeSize(Ty); + if (Size != 8 && Size != 16 && Size != 32 && Size != 64) + return ABIArgInfo::getIndirect(0); + + // Handle small structures. + if (const RecordType *RT = Ty->getAs<RecordType>()) { + // Structures with flexible arrays have variable length, so really + // fail the size test above. + const RecordDecl *RD = RT->getDecl(); + if (RD->hasFlexibleArrayMember()) + return ABIArgInfo::getIndirect(0); + + // The structure is passed as an unextended integer, a float, or a double. + llvm::Type *PassTy; + if (isFPArgumentType(Ty)) { + assert(Size == 32 || Size == 64); + if (Size == 32) + PassTy = llvm::Type::getFloatTy(getVMContext()); + else + PassTy = llvm::Type::getDoubleTy(getVMContext()); + } else + PassTy = llvm::IntegerType::get(getVMContext(), Size); + return ABIArgInfo::getDirect(PassTy); + } + + // Non-structure compounds are passed indirectly. + if (isCompoundType(Ty)) + return ABIArgInfo::getIndirect(0); + + return ABIArgInfo::getDirect(0); +} + +//===----------------------------------------------------------------------===// // MBlaze ABI Implementation //===----------------------------------------------------------------------===// @@ -4436,11 +4710,9 @@ MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const { if (TySize == 0) return ABIArgInfo::getIgnore(); - // Records with non trivial destructors/constructors should not be passed - // by value. - if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) { + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT)) { Offset = OrigOffset + MinABIStackAlignInBytes; - return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory); } // If we have reached here, aggregates are passed directly by coercing to @@ -4510,6 +4782,9 @@ ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const { return ABIArgInfo::getIgnore(); if (isAggregateTypeForABI(RetTy) || RetTy->isVectorType()) { + if (isRecordReturnIndirect(RetTy, CGT)) + return ABIArgInfo::getIndirect(0); + if (Size <= 128) { if (RetTy->isAnyComplexType()) return ABIArgInfo::getDirect(); @@ -4518,7 +4793,7 @@ ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const { if (IsO32 && RetTy->isVectorType() && !RetTy->hasFloatingRepresentation()) return ABIArgInfo::getDirect(returnAggregateInRegs(RetTy, Size)); - if (!IsO32 && !isRecordWithNonTrivialDestructorOrCopyConstructor(RetTy)) + if (!IsO32) return ABIArgInfo::getDirect(returnAggregateInRegs(RetTy, Size)); } @@ -4556,7 +4831,7 @@ llvm::Value* MipsABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, int64_t TypeAlign = getContext().getTypeAlign(Ty) / 8; llvm::Type *PTy = llvm::PointerType::getUnqual(CGF.ConvertType(Ty)); llvm::Value *AddrTyped; - unsigned PtrWidth = getContext().getTargetInfo().getPointerWidth(0); + unsigned PtrWidth = getTarget().getPointerWidth(0); llvm::IntegerType *IntTy = (PtrWidth == 32) ? CGF.Int32Ty : CGF.Int64Ty; if (TypeAlign > MinABIStackAlignInBytes) { @@ -4728,10 +5003,8 @@ ABIArgInfo HexagonABIInfo::classifyArgumentType(QualType Ty) const { if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); - // Structures with either a non-trivial destructor or a non-trivial - // copy constructor are always indirect. - if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) - return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT)) + return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory); uint64_t Size = getContext().getTypeSize(Ty); if (Size > 64) @@ -4766,7 +5039,7 @@ ABIArgInfo HexagonABIInfo::classifyReturnType(QualType RetTy) const { // Structures with either a non-trivial destructor or a non-trivial // copy constructor are always indirect. - if (isRecordWithNonTrivialDestructorOrCopyConstructor(RetTy)) + if (isRecordReturnIndirect(RetTy, CGT)) return ABIArgInfo::getIndirect(0, /*ByVal=*/false); if (isEmptyRecord(getContext(), RetTy, true)) @@ -4817,7 +5090,7 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { if (TheTargetCodeGenInfo) return *TheTargetCodeGenInfo; - const llvm::Triple &Triple = getContext().getTargetInfo().getTriple(); + const llvm::Triple &Triple = getTarget().getTriple(); switch (Triple.getArch()) { default: return *(TheTargetCodeGenInfo = new DefaultTargetCodeGenInfo(Types)); @@ -4839,10 +5112,11 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { case llvm::Triple::thumb: { ARMABIInfo::ABIKind Kind = ARMABIInfo::AAPCS; - if (strcmp(getContext().getTargetInfo().getABI(), "apcs-gnu") == 0) + if (strcmp(getTarget().getABI(), "apcs-gnu") == 0) Kind = ARMABIInfo::APCS; else if (CodeGenOpts.FloatABI == "hard" || - (CodeGenOpts.FloatABI != "soft" && Triple.getEnvironment()==llvm::Triple::GNUEABIHF)) + (CodeGenOpts.FloatABI != "soft" && + Triple.getEnvironment() == llvm::Triple::GNUEABIHF)) Kind = ARMABIInfo::AAPCS_VFP; switch (Triple.getOS()) { @@ -4873,6 +5147,9 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { case llvm::Triple::msp430: return *(TheTargetCodeGenInfo = new MSP430TargetCodeGenInfo(Types)); + case llvm::Triple::systemz: + return *(TheTargetCodeGenInfo = new SystemZTargetCodeGenInfo(Types)); + case llvm::Triple::tce: return *(TheTargetCodeGenInfo = new TCETargetCodeGenInfo(Types)); @@ -4907,7 +5184,7 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { } case llvm::Triple::x86_64: { - bool HasAVX = strcmp(getContext().getTargetInfo().getABI(), "avx") == 0; + bool HasAVX = strcmp(getTarget().getABI(), "avx") == 0; switch (Triple.getOS()) { case llvm::Triple::Win32: @@ -4915,7 +5192,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { case llvm::Triple::Cygwin: return *(TheTargetCodeGenInfo = new WinX86_64TargetCodeGenInfo(Types)); case llvm::Triple::NaCl: - return *(TheTargetCodeGenInfo = new NaClX86_64TargetCodeGenInfo(Types, HasAVX)); + return *(TheTargetCodeGenInfo = new NaClX86_64TargetCodeGenInfo(Types, + HasAVX)); default: return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo(Types, HasAVX)); diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp index 6c57b62..4b8d151 100644 --- a/lib/Driver/ArgList.cpp +++ b/lib/Driver/ArgList.cpp @@ -206,6 +206,13 @@ bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier Neg, bool Default) const { return Default; } +bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier PosAlias, OptSpecifier Neg, + bool Default) const { + if (Arg *A = getLastArg(Pos, PosAlias, Neg)) + return A->getOption().matches(Pos) || A->getOption().matches(PosAlias); + return Default; +} + StringRef ArgList::getLastArgValue(OptSpecifier Id, StringRef Default) const { if (Arg *A = getLastArg(Id)) @@ -241,6 +248,14 @@ void ArgList::AddLastArg(ArgStringList &Output, OptSpecifier Id) const { } } +void ArgList::AddLastArg(ArgStringList &Output, OptSpecifier Id0, + OptSpecifier Id1) const { + if (Arg *A = getLastArg(Id0, Id1)) { + A->claim(); + A->render(*this, Output); + } +} + void ArgList::AddAllArgs(ArgStringList &Output, OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2) const { for (arg_iterator it = filtered_begin(Id0, Id1, Id2), diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index ad1921b..1dbbc9a 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -491,9 +491,8 @@ void Driver::generateCompilationDiagnostics(Compilation &C, << "\n\n********************"; } else { // Failure, remove preprocessed files. - if (!C.getArgs().hasArg(options::OPT_save_temps)) { + if (!C.getArgs().hasArg(options::OPT_save_temps)) C.CleanupFileList(C.getTempFiles(), true); - } Diag(clang::diag::note_drv_command_failed_diag_msg) << "Error generating preprocessed source(s)."; @@ -825,17 +824,6 @@ void Driver::BuildUniversalActions(const ToolChain &TC, if (!Archs.size()) Archs.push_back(Args.MakeArgString(TC.getDefaultUniversalArchName())); - // FIXME: We killed off some others but these aren't yet detected in a - // functional manner. If we added information to jobs about which "auxiliary" - // files they wrote then we could detect the conflict these cause downstream. - if (Archs.size() > 1) { - // No recovery needed, the point of this is just to prevent - // overwriting the same files. - if (const Arg *A = Args.getLastArg(options::OPT_save_temps)) - Diag(clang::diag::err_drv_invalid_opt_with_multiple_archs) - << A->getAsString(Args); - } - ActionList SingleActions; BuildActions(TC, Args, BAInputs, SingleActions); @@ -1221,6 +1209,17 @@ void Driver::BuildJobs(Compilation &C) const { } } + // Collect the list of architectures. + llvm::StringSet<> ArchNames; + if (C.getDefaultToolChain().getTriple().isOSDarwin()) { + for (ArgList::const_iterator it = C.getArgs().begin(), ie = C.getArgs().end(); + it != ie; ++it) { + Arg *A = *it; + if (A->getOption().matches(options::OPT_arch)) + ArchNames.insert(A->getValue()); + } + } + for (ActionList::const_iterator it = C.getActions().begin(), ie = C.getActions().end(); it != ie; ++it) { Action *A = *it; @@ -1243,6 +1242,7 @@ void Driver::BuildJobs(Compilation &C) const { BuildJobsForAction(C, A, &C.getDefaultToolChain(), /*BoundArch*/0, /*AtTopLevel*/ true, + /*MultipleArchs*/ ArchNames.size() > 1, /*LinkingOutput*/ LinkingOutput, II); } @@ -1337,6 +1337,7 @@ void Driver::BuildJobsForAction(Compilation &C, const ToolChain *TC, const char *BoundArch, bool AtTopLevel, + bool MultipleArchs, const char *LinkingOutput, InputInfo &Result) const { llvm::PrettyStackTraceString CrashInfo("Building compilation jobs"); @@ -1364,7 +1365,7 @@ void Driver::BuildJobsForAction(Compilation &C, TC = &C.getDefaultToolChain(); BuildJobsForAction(C, *BAA->begin(), TC, BAA->getArchName(), - AtTopLevel, LinkingOutput, Result); + AtTopLevel, MultipleArchs, LinkingOutput, Result); return; } @@ -1387,8 +1388,8 @@ void Driver::BuildJobsForAction(Compilation &C, SubJobAtTopLevel = true; InputInfo II; - BuildJobsForAction(C, *it, TC, BoundArch, - SubJobAtTopLevel, LinkingOutput, II); + BuildJobsForAction(C, *it, TC, BoundArch, SubJobAtTopLevel, MultipleArchs, + LinkingOutput, II); InputInfos.push_back(II); } @@ -1404,7 +1405,8 @@ void Driver::BuildJobsForAction(Compilation &C, if (JA->getType() == types::TY_Nothing) Result = InputInfo(A->getType(), BaseInput); else - Result = InputInfo(GetNamedOutputPath(C, *JA, BaseInput, AtTopLevel), + Result = InputInfo(GetNamedOutputPath(C, *JA, BaseInput, BoundArch, + AtTopLevel, MultipleArchs), A->getType(), BaseInput); if (CCCPrintBindings && !CCGenDiagnostics) { @@ -1425,7 +1427,9 @@ void Driver::BuildJobsForAction(Compilation &C, const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, const char *BaseInput, - bool AtTopLevel) const { + const char *BoundArch, + bool AtTopLevel, + bool MultipleArchs) const { llvm::PrettyStackTraceString CrashInfo("Computing output path"); // Output to a user requested destination? if (AtTopLevel && !isa<DsymutilJobAction>(JA) && @@ -1460,8 +1464,14 @@ const char *Driver::GetNamedOutputPath(Compilation &C, // Determine what the derived output name should be. const char *NamedOutput; - if (JA.getType() == types::TY_Image) { - NamedOutput = DefaultImageName.c_str(); + if (JA.getType() == types::TY_Image) { + if (MultipleArchs && BoundArch) { + SmallString<128> Output(DefaultImageName.c_str()); + Output += "-"; + Output.append(BoundArch); + NamedOutput = C.getArgs().MakeArgString(Output.c_str()); + } else + NamedOutput = DefaultImageName.c_str(); } else { const char *Suffix = types::getTypeTempSuffix(JA.getType()); assert(Suffix && "All types used for output should have a suffix."); @@ -1469,7 +1479,11 @@ const char *Driver::GetNamedOutputPath(Compilation &C, std::string::size_type End = std::string::npos; if (!types::appendSuffixForType(JA.getType())) End = BaseName.rfind('.'); - std::string Suffixed(BaseName.substr(0, End)); + SmallString<128> Suffixed(BaseName.substr(0, End)); + if (MultipleArchs && BoundArch) { + Suffixed += "-"; + Suffixed.append(BoundArch); + } Suffixed += '.'; Suffixed += Suffix; NamedOutput = C.getArgs().MakeArgString(Suffixed.c_str()); diff --git a/lib/Driver/SanitizerArgs.h b/lib/Driver/SanitizerArgs.h index e61f15a..326d80d 100644 --- a/lib/Driver/SanitizerArgs.h +++ b/lib/Driver/SanitizerArgs.h @@ -38,7 +38,8 @@ class SanitizerArgs { NeedsTsanRt = Thread, NeedsMsanRt = Memory, NeedsUbsanRt = Undefined | Integer, - NotAllowedWithTrap = Vptr + NotAllowedWithTrap = Vptr, + HasZeroBaseShadow = Thread | Memory }; unsigned Kind; std::string BlacklistFile; @@ -50,7 +51,7 @@ class SanitizerArgs { SanitizerArgs() : Kind(0), BlacklistFile(""), MsanTrackOrigins(false), AsanZeroBaseShadow(false), UbsanTrapOnError(false) {} /// Parses the sanitizer arguments from an argument list. - SanitizerArgs(const Driver &D, const ArgList &Args); + SanitizerArgs(const ToolChain &TC, const ArgList &Args); bool needsAsanRt() const { return Kind & NeedsAsanRt; } bool needsTsanRt() const { return Kind & NeedsTsanRt; } @@ -63,6 +64,9 @@ class SanitizerArgs { bool sanitizesVptr() const { return Kind & Vptr; } bool notAllowedWithTrap() const { return Kind & NotAllowedWithTrap; } + bool hasZeroBaseShadow() const { + return (Kind & HasZeroBaseShadow) || AsanZeroBaseShadow; + } void addArgs(const ArgList &Args, ArgStringList &CmdArgs) const { if (!Kind) diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index 19270b2..71f5393 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -19,6 +19,7 @@ #include "clang/Driver/Options.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" using namespace clang::driver; using namespace clang; @@ -333,6 +334,13 @@ ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{ CC1Args.push_back(DriverArgs.MakeArgString(Path)); } +void ToolChain::addExternCSystemIncludeIfExists(const ArgList &DriverArgs, + ArgStringList &CC1Args, + const Twine &Path) { + if (llvm::sys::fs::exists(Path)) + addExternCSystemInclude(DriverArgs, CC1Args, Path); +} + /// \brief Utility function to add a list of system include directories to CC1. /*static*/ void ToolChain::addSystemIncludes(const ArgList &DriverArgs, ArgStringList &CC1Args, diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index bcfe51e..fffba0e 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -294,7 +294,7 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, } } - SanitizerArgs Sanitize(getDriver(), Args); + SanitizerArgs Sanitize(*this, Args); // Add Ubsan runtime library, if required. if (Sanitize.needsUbsanRt()) { @@ -878,6 +878,10 @@ bool Darwin::isPICDefault() const { return true; } +bool Darwin::isPIEDefault() const { + return false; +} + bool Darwin::isPICDefaultForced() const { return getArch() == llvm::Triple::x86_64; } @@ -1082,6 +1086,7 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( }; static const char *const ARMHFTriples[] = { "arm-linux-gnueabihf", + "armv7hl-redhat-linux-gnueabi" }; static const char *const X86_64LibDirs[] = { "/lib64", "/lib" }; @@ -1116,7 +1121,8 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( static const char *const MIPSELLibDirs[] = { "/lib" }; static const char *const MIPSELTriples[] = { "mipsel-linux-gnu", - "mipsel-linux-android" + "mipsel-linux-android", + "mips-linux-gnu" }; static const char *const MIPS64LibDirs[] = { "/lib64", "/lib" }; @@ -1140,6 +1146,15 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( "ppc64-redhat-linux" }; + static const char *const SystemZLibDirs[] = { "/lib64", "/lib" }; + static const char *const SystemZTriples[] = { + "s390x-linux-gnu", + "s390x-unknown-linux-gnu", + "s390x-ibm-linux-gnu", + "s390x-suse-linux", + "s390x-redhat-linux" + }; + switch (TargetTriple.getArch()) { case llvm::Triple::aarch64: LibDirs.append(AArch64LibDirs, AArch64LibDirs @@ -1240,6 +1255,12 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( MultiarchTripleAliases.append( PPCTriples, PPCTriples + llvm::array_lengthof(PPCTriples)); break; + case llvm::Triple::systemz: + LibDirs.append( + SystemZLibDirs, SystemZLibDirs + llvm::array_lengthof(SystemZLibDirs)); + TripleAliases.append( + SystemZTriples, SystemZTriples + llvm::array_lengthof(SystemZTriples)); + break; default: // By default, just rely on the standard lib directories and the original @@ -1256,29 +1277,102 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( MultiarchTripleAliases.push_back(MultiarchTriple.str()); } +static bool isSoftFloatABI(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_msoft_float, + options::OPT_mhard_float, + options::OPT_mfloat_abi_EQ); + if (!A) return false; + + return A->getOption().matches(options::OPT_msoft_float) || + (A->getOption().matches(options::OPT_mfloat_abi_EQ) && + A->getValue() == StringRef("soft")); +} + +static bool isMipsArch(llvm::Triple::ArchType Arch) { + return Arch == llvm::Triple::mips || + Arch == llvm::Triple::mipsel || + Arch == llvm::Triple::mips64 || + Arch == llvm::Triple::mips64el; +} + +static bool isMips16(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_mips16, + options::OPT_mno_mips16); + return A && A->getOption().matches(options::OPT_mips16); +} + +static bool isMicroMips(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_mmicromips, + options::OPT_mno_micromips); + return A && A->getOption().matches(options::OPT_mmicromips); +} + // FIXME: There is the same routine in the Tools.cpp. static bool hasMipsN32ABIArg(const ArgList &Args) { Arg *A = Args.getLastArg(options::OPT_mabi_EQ); return A && (A->getValue() == StringRef("n32")); } -static StringRef getTargetMultiarchSuffix(llvm::Triple::ArchType TargetArch, - const ArgList &Args) { - if (TargetArch == llvm::Triple::x86_64 || - TargetArch == llvm::Triple::ppc64) - return "/64"; +static void appendMipsTargetSuffix(std::string &Path, + llvm::Triple::ArchType TargetArch, + const ArgList &Args) { + if (isMips16(Args)) + Path += "/mips16"; + else if (isMicroMips(Args)) + Path += "/micromips"; + + if (isSoftFloatABI(Args)) + Path += "/soft-float"; + if (TargetArch == llvm::Triple::mipsel || + TargetArch == llvm::Triple::mips64el) + Path += "/el"; +} + +static StringRef getMipsTargetABISuffix(llvm::Triple::ArchType TargetArch, + const ArgList &Args) { if (TargetArch == llvm::Triple::mips64 || - TargetArch == llvm::Triple::mips64el) { - if (hasMipsN32ABIArg(Args)) - return "/n32"; - else - return "/64"; - } + TargetArch == llvm::Triple::mips64el) + return hasMipsN32ABIArg(Args) ? "/n32" : "/64"; return "/32"; } +static bool findTargetMultiarchSuffix(std::string &Suffix, + StringRef Path, + llvm::Triple::ArchType TargetArch, + const ArgList &Args) { + if (isMipsArch(TargetArch)) { + StringRef ABISuffix = getMipsTargetABISuffix(TargetArch, Args); + + // First build and check a complex path to crtbegin.o + // depends on command line options (-mips16, -msoft-float, ...) + // like mips-linux-gnu/4.7/mips16/soft-float/el/crtbegin.o + appendMipsTargetSuffix(Suffix, TargetArch, Args); + + if (TargetArch == llvm::Triple::mips64 || + TargetArch == llvm::Triple::mips64el) + Suffix += ABISuffix; + + if (llvm::sys::fs::exists(Path + Suffix + "/crtbegin.o")) + return true; + + // Then fall back and probe a simple case like + // mips-linux-gnu/4.7/32/crtbegin.o + Suffix = ABISuffix; + return llvm::sys::fs::exists(Path + Suffix + "/crtbegin.o"); + } + + if (TargetArch == llvm::Triple::x86_64 || + TargetArch == llvm::Triple::ppc64 || + TargetArch == llvm::Triple::systemz) + Suffix = "/64"; + else + Suffix = "/32"; + + return llvm::sys::fs::exists(Path + Suffix + "/crtbegin.o"); +} + void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( llvm::Triple::ArchType TargetArch, const ArgList &Args, const std::string &LibDir, @@ -1328,9 +1422,11 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( // *if* there is a subdirectory of the right name with crtbegin.o in it, // we use that. If not, and if not a multiarch triple, we look for // crtbegin.o without the subdirectory. - StringRef MultiarchSuffix = getTargetMultiarchSuffix(TargetArch, Args); - if (llvm::sys::fs::exists(LI->path() + MultiarchSuffix + "/crtbegin.o")) { - GCCMultiarchSuffix = MultiarchSuffix.str(); + + std::string MultiarchSuffix; + if (findTargetMultiarchSuffix(MultiarchSuffix, + LI->path(), TargetArch, Args)) { + GCCMultiarchSuffix = MultiarchSuffix; } else { if (NeedsMultiarchSuffix || !llvm::sys::fs::exists(LI->path() + "/crtbegin.o")) @@ -1396,6 +1492,10 @@ bool Generic_GCC::isPICDefault() const { return false; } +bool Generic_GCC::isPIEDefault() const { + return false; +} + bool Generic_GCC::isPICDefaultForced() const { return false; } @@ -1630,6 +1730,10 @@ bool TCEToolChain::isPICDefault() const { return false; } +bool TCEToolChain::isPIEDefault() const { + return false; +} + bool TCEToolChain::isPICDefaultForced() const { return false; } @@ -1773,6 +1877,42 @@ Tool *NetBSD::buildLinker() const { return new tools::netbsd::Link(*this); } +ToolChain::CXXStdlibType +NetBSD::GetCXXStdlibType(const ArgList &Args) const { + if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { + StringRef Value = A->getValue(); + if (Value == "libstdc++") + return ToolChain::CST_Libstdcxx; + if (Value == "libc++") + return ToolChain::CST_Libcxx; + + getDriver().Diag(diag::err_drv_invalid_stdlib_name) + << A->getAsString(Args); + } + + return ToolChain::CST_Libstdcxx; +} + +void NetBSD::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libcxx: + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/include/c++/"); + break; + case ToolChain::CST_Libstdcxx: + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/include/g++"); + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/include/g++/backward"); + break; + } +} + /// Minix - Minix tool chain which can call as(1) and ld(1) directly. Minix::Minix(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) @@ -2036,13 +2176,6 @@ static void addPathIfExists(Twine Path, ToolChain::path_list &Paths) { if (llvm::sys::fs::exists(Path)) Paths.push_back(Path.str()); } -static bool isMipsArch(llvm::Triple::ArchType Arch) { - return Arch == llvm::Triple::mips || - Arch == llvm::Triple::mipsel || - Arch == llvm::Triple::mips64 || - Arch == llvm::Triple::mips64el; -} - static bool isMipsR2Arch(llvm::Triple::ArchType Arch, const ArgList &Args) { if (Arch != llvm::Triple::mips && @@ -2079,7 +2212,7 @@ static StringRef getMultilibDir(const llvm::Triple &Triple, Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { llvm::Triple::ArchType Arch = Triple.getArch(); - const std::string &SysRoot = getDriver().SysRoot; + std::string SysRoot = computeSysRoot(Args); // OpenSuse stores the linker with the compiler, add that to the search // path. @@ -2100,13 +2233,17 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) ExtraOpts.push_back("-X"); const bool IsAndroid = Triple.getEnvironment() == llvm::Triple::Android; + const bool IsMips = isMipsArch(Arch); + + if (IsMips && !SysRoot.empty()) + ExtraOpts.push_back("--sysroot=" + SysRoot); // Do not use 'gnu' hash style for Mips targets because .gnu.hash // and the MIPS ABI require .dynsym to be sorted in different ways. // .gnu.hash needs symbols to be grouped by hash code whereas the MIPS // ABI requires a mapping between the GOT and the symbol table. // Android loader does not support .gnu.hash. - if (!isMipsArch(Arch) && !IsAndroid) { + if (!IsMips && !IsAndroid) { if (IsRedhat(Distro) || IsOpenSuse(Distro) || (IsUbuntu(Distro) && Distro >= UbuntuMaverick)) ExtraOpts.push_back("--hash-style=gnu"); @@ -2171,6 +2308,15 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) if (IsAndroid) { addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib", Paths); } + // Sourcery CodeBench MIPS toolchain holds some libraries under + // the parent prefix of the GCC installation. + if (IsMips) { + std::string Suffix; + appendMipsTargetSuffix(Suffix, Arch, Args); + addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" + + Multilib + Suffix, + Paths); + } } addPathIfExists(SysRoot + "/lib/" + MultiarchTriple, Paths); addPathIfExists(SysRoot + "/lib/../" + Multilib, Paths); @@ -2197,6 +2343,8 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) } addPathIfExists(SysRoot + "/lib", Paths); addPathIfExists(SysRoot + "/usr/lib", Paths); + + IsPIEDefault = SanitizerArgs(*this, Args).hasZeroBaseShadow(); } bool Linux::HasNativeLLVMSupport() const { @@ -2224,15 +2372,31 @@ void Linux::addClangTargetOptions(const ArgList &DriverArgs, CC1Args.push_back("-fuse-init-array"); } +std::string Linux::computeSysRoot(const ArgList &Args) const { + if (!getDriver().SysRoot.empty()) + return getDriver().SysRoot; + + if (!GCCInstallation.isValid() || !isMipsArch(getTriple().getArch())) + return std::string(); + + std::string Path = + (GCCInstallation.getInstallPath() + + "/../../../../" + GCCInstallation.getTriple().str() + "/libc").str(); + appendMipsTargetSuffix(Path, getTriple().getArch(), Args); + + return llvm::sys::fs::exists(Path) ? Path : ""; +} + void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { const Driver &D = getDriver(); + std::string SysRoot = computeSysRoot(DriverArgs); if (DriverArgs.hasArg(options::OPT_nostdinc)) return; if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) - addSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/local/include"); + addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include"); if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { llvm::sys::Path P(D.ResourceDir); @@ -2250,7 +2414,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, CIncludeDirs.split(dirs, ":"); for (SmallVectorImpl<StringRef>::iterator I = dirs.begin(), E = dirs.end(); I != E; ++I) { - StringRef Prefix = llvm::sys::path::is_absolute(*I) ? D.SysRoot : ""; + StringRef Prefix = llvm::sys::path::is_absolute(*I) ? SysRoot : ""; addExternCSystemInclude(DriverArgs, CC1Args, Prefix + *I); } return; @@ -2259,6 +2423,20 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, // Lacking those, try to detect the correct set of system includes for the // target triple. + // Sourcery CodeBench and modern FSF Mips toolchains put extern C + // system includes under three additional directories. + if (GCCInstallation.isValid() && isMipsArch(getTriple().getArch())) { + addExternCSystemIncludeIfExists(DriverArgs, CC1Args, + GCCInstallation.getInstallPath() + + "/include"); + + addExternCSystemIncludeIfExists(DriverArgs, CC1Args, + GCCInstallation.getInstallPath() + + "/../../../../" + + GCCInstallation.getTriple().str() + + "/libc/usr/include"); + } + // Implement generic Debian multiarch support. const StringRef X86_64MultiarchIncludeDirs[] = { "/usr/include/x86_64-linux-gnu", @@ -2324,8 +2502,8 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, for (ArrayRef<StringRef>::iterator I = MultiarchIncludeDirs.begin(), E = MultiarchIncludeDirs.end(); I != E; ++I) { - if (llvm::sys::fs::exists(D.SysRoot + *I)) { - addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + *I); + if (llvm::sys::fs::exists(SysRoot + *I)) { + addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + *I); break; } } @@ -2336,9 +2514,9 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, // Add an include of '/include' directly. This isn't provided by default by // system GCCs, but is often used with cross-compiling GCCs, and harmless to // add even when Clang is acting as-if it were a system compiler. - addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/include"); + addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include"); - addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include"); + addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include"); } /// \brief Helper to add the three variant paths for a libstdc++ installation. @@ -2422,6 +2600,10 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, } } +bool Linux::isPIEDefault() const { + return IsPIEDefault; +} + /// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly. DragonFly::DragonFly(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) @@ -2434,7 +2616,10 @@ DragonFly::DragonFly(const Driver &D, const llvm::Triple& Triple, const ArgList getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); - getFilePaths().push_back("/usr/lib/gcc41"); + if (llvm::sys::fs::exists("/usr/lib/gcc47")) + getFilePaths().push_back("/usr/lib/gcc47"); + else + getFilePaths().push_back("/usr/lib/gcc44"); } Tool *DragonFly::buildAssembler() const { diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 3421c53..3afd8dd 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -123,6 +123,7 @@ public: virtual bool IsUnwindTablesDefault() const; virtual bool isPICDefault() const; + virtual bool isPIEDefault() const; virtual bool isPICDefaultForced() const; protected: @@ -332,6 +333,7 @@ public: return ToolChain::RLT_CompilerRT; } virtual bool isPICDefault() const; + virtual bool isPIEDefault() const; virtual bool isPICDefaultForced() const; virtual bool SupportsProfiling() const; @@ -472,6 +474,11 @@ public: virtual bool IsMathErrnoDefault() const { return false; } virtual bool IsObjCNonFragileABIDefault() const { return true; } + virtual CXXStdlibType GetCXXStdlibType(const ArgList &Args) const; + + virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const; + protected: virtual Tool *buildAssembler() const; virtual Tool *buildLinker() const; @@ -509,9 +516,11 @@ public: ArgStringList &CC1Args) const; virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const; + virtual bool isPIEDefault() const; std::string Linker; std::vector<std::string> ExtraOpts; + bool IsPIEDefault; protected: virtual Tool *buildAssembler() const; @@ -526,6 +535,8 @@ private: static bool addLibStdCXXIncludePaths(Twine Base, Twine TargetArchDir, const ArgList &DriverArgs, ArgStringList &CC1Args); + + std::string computeSysRoot(const ArgList &Args) const; }; class LLVM_LIBRARY_VISIBILITY Hexagon_TC : public Linux { @@ -562,6 +573,7 @@ public: bool IsMathErrnoDefault() const; bool isPICDefault() const; + bool isPIEDefault() const; bool isPICDefaultForced() const; }; @@ -572,6 +584,7 @@ public: virtual bool IsIntegratedAssemblerDefault() const; virtual bool IsUnwindTablesDefault() const; virtual bool isPICDefault() const; + virtual bool isPIEDefault() const; virtual bool isPICDefaultForced() const; virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs, diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 77a72ba..aba1fe4 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include <sys/stat.h> #include "Tools.h" #include "InputInfo.h" #include "SanitizerArgs.h" @@ -544,6 +545,9 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) { if (Triple.isOSDarwin()) return true; return false; + + case llvm::Triple::systemz: + return false; } } @@ -815,7 +819,9 @@ void Clang::AddARMTargetArgs(const ArgList &Args, CmdArgs.push_back("-mno-global-merge"); } - if (Args.hasArg(options::OPT_mno_implicit_float)) + if (!Args.hasFlag(options::OPT_mimplicit_float, + options::OPT_mno_implicit_float, + true)) CmdArgs.push_back("-no-implicit-float"); } @@ -851,8 +857,15 @@ static void getMipsCPUAndABI(const ArgList &Args, CPUName = A->getValue(); } - if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) + if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { ABIName = A->getValue(); + // Convert a GNU style Mips ABI name to the name + // accepted by LLVM Mips backend. + ABIName = llvm::StringSwitch<llvm::StringRef>(ABIName) + .Case("32", "o32") + .Case("64", "n64") + .Default(ABIName); + } // Setup default CPU and ABI names. if (CPUName.empty() && ABIName.empty()) { @@ -899,8 +912,6 @@ static StringRef getGnuCompatibleMipsABIName(StringRef ABI) { // Select the MIPS float ABI as determined by -msoft-float, -mhard-float, // and -mfloat-abi=. static StringRef getMipsFloatABI(const Driver &D, const ArgList &Args) { - // Select the float ABI as determined by -msoft-float, -mhard-float, - // and -mfloat-abi=. StringRef FloatABI; if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, @@ -911,7 +922,7 @@ static StringRef getMipsFloatABI(const Driver &D, const ArgList &Args) { FloatABI = "hard"; else { FloatABI = A->getValue(); - if (FloatABI != "soft" && FloatABI != "single" && FloatABI != "hard") { + if (FloatABI != "soft" && FloatABI != "hard") { D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); FloatABI = "hard"; } @@ -944,7 +955,7 @@ static void AddTargetFeature(const ArgList &Args, } void Clang::AddMIPSTargetArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { + ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getDriver(); StringRef CPUName; StringRef ABIName; @@ -977,12 +988,6 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, CmdArgs.push_back("-mips16-hard-float"); } } - else if (FloatABI == "single") { - // Restrict the use of hardware floating-point - // instructions to 32-bit operations. - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("+single-float"); - } else { // Floating point operations and argument passing are hard. assert(FloatABI == "hard" && "Invalid float abi!"); @@ -991,9 +996,15 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, } AddTargetFeature(Args, CmdArgs, + options::OPT_msingle_float, options::OPT_mdouble_float, + "single-float"); + AddTargetFeature(Args, CmdArgs, options::OPT_mips16, options::OPT_mno_mips16, "mips16"); AddTargetFeature(Args, CmdArgs, + options::OPT_mmicromips, options::OPT_mno_micromips, + "micromips"); + AddTargetFeature(Args, CmdArgs, options::OPT_mdsp, options::OPT_mno_dsp, "dsp"); AddTargetFeature(Args, CmdArgs, @@ -1127,11 +1138,11 @@ static std::string getR600TargetGPU(const ArgList &Args) { if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { std::string GPUName = A->getValue(); return llvm::StringSwitch<const char *>(GPUName) - .Cases("rv610", "rv620", "rv630", "r600") - .Cases("rv635", "rs780", "rs880", "r600") + .Cases("rv630", "rv635", "r600") + .Cases("rv610", "rv620", "rs780", "rs880") .Case("rv740", "rv770") .Case("palm", "cedar") - .Cases("sumo", "sumo2", "redwood") + .Cases("sumo", "sumo2", "sumo") .Case("hemlock", "cypress") .Case("aruba", "cayman") .Default(GPUName.c_str()); @@ -1255,6 +1266,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args, Args.hasArg(options::OPT_fapple_kext)); if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mno_soft_float, + options::OPT_mimplicit_float, options::OPT_mno_implicit_float)) { const Option &O = A->getOption(); NoImplicitFloat = (O.matches(options::OPT_mno_implicit_float) || @@ -1452,6 +1464,18 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType, CmdArgs.push_back("-fexceptions"); } +static bool ShouldDisableAutolink(const ArgList &Args, + const ToolChain &TC) { + bool Default = true; + if (TC.getTriple().isOSDarwin()) { + // The native darwin assembler doesn't support the linker_option directives, + // so we disable them if we think the .s file will be passed to it. + Default = TC.useIntegratedAs(); + } + return !Args.hasFlag(options::OPT_fautolink, options::OPT_fno_autolink, + Default); +} + static bool ShouldDisableCFI(const ArgList &Args, const ToolChain &TC) { bool Default = true; @@ -1508,11 +1532,12 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) { RelaxDefault); } -SanitizerArgs::SanitizerArgs(const Driver &D, const ArgList &Args) +SanitizerArgs::SanitizerArgs(const ToolChain &TC, const ArgList &Args) : Kind(0), BlacklistFile(""), MsanTrackOrigins(false), AsanZeroBaseShadow(false) { unsigned AllKinds = 0; // All kinds of sanitizers that were turned on // at least once (possibly, disabled further). + const Driver &D = TC.getDriver(); for (ArgList::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) { unsigned Add, Remove; if (!parse(D, Args, *I, Add, Remove, true)) @@ -1604,11 +1629,20 @@ SanitizerArgs::SanitizerArgs(const Driver &D, const ArgList &Args) /* Default */false); // Parse -f(no-)sanitize-address-zero-base-shadow options. - if (NeedsAsan) + if (NeedsAsan) { + bool IsAndroid = (TC.getTriple().getEnvironment() == llvm::Triple::Android); + bool ZeroBaseShadowDefault = IsAndroid; AsanZeroBaseShadow = - Args.hasFlag(options::OPT_fsanitize_address_zero_base_shadow, - options::OPT_fno_sanitize_address_zero_base_shadow, - /* Default */false); + Args.hasFlag(options::OPT_fsanitize_address_zero_base_shadow, + options::OPT_fno_sanitize_address_zero_base_shadow, + ZeroBaseShadowDefault); + // Zero-base shadow is a requirement on Android. + if (IsAndroid && !AsanZeroBaseShadow) { + D.Diag(diag::err_drv_argument_not_allowed_with) + << "-fno-sanitize-address-zero-base-shadow" + << lastArgumentForKind(D, Args, Address); + } + } } static void addSanitizerRTLinkFlagsLinux( @@ -1637,6 +1671,7 @@ static void addSanitizerRTLinkFlagsLinux( LibSanitizerArgs.begin(), LibSanitizerArgs.end()); CmdArgs.push_back("-lpthread"); + CmdArgs.push_back("-lrt"); CmdArgs.push_back("-ldl"); // If possible, use a dynamic symbols file to export the symbols from the @@ -1656,11 +1691,6 @@ static void addSanitizerRTLinkFlagsLinux( static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { if(TC.getTriple().getEnvironment() == llvm::Triple::Android) { - if (!Args.hasArg(options::OPT_shared)) { - if (!Args.hasArg(options::OPT_pie)) - TC.getDriver().Diag(diag::err_drv_asan_android_requires_pie); - } - SmallString<128> LibAsan(TC.getDriver().ResourceDir); llvm::sys::path::append(LibAsan, "lib", "linux", (Twine("libclang_rt.asan-") + @@ -1668,13 +1698,6 @@ static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args, CmdArgs.insert(CmdArgs.begin(), Args.MakeArgString(LibAsan)); } else { if (!Args.hasArg(options::OPT_shared)) { - bool ZeroBaseShadow = Args.hasFlag( - options::OPT_fsanitize_address_zero_base_shadow, - options::OPT_fno_sanitize_address_zero_base_shadow, false); - if (ZeroBaseShadow && !Args.hasArg(options::OPT_pie)) { - TC.getDriver().Diag(diag::err_drv_argument_only_allowed_with) << - "-fsanitize-address-zero-base-shadow" << "-pie"; - } addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "asan", true); } } @@ -1685,9 +1708,6 @@ static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args, static void addTsanRTLinux(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { if (!Args.hasArg(options::OPT_shared)) { - if (!Args.hasArg(options::OPT_pie)) - TC.getDriver().Diag(diag::err_drv_argument_only_allowed_with) << - "-fsanitize=thread" << "-pie"; addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "tsan", true); } } @@ -1697,9 +1717,6 @@ static void addTsanRTLinux(const ToolChain &TC, const ArgList &Args, static void addMsanRTLinux(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { if (!Args.hasArg(options::OPT_shared)) { - if (!Args.hasArg(options::OPT_pie)) - TC.getDriver().Diag(diag::err_drv_argument_only_allowed_with) << - "-fsanitize=memory" << "-pie"; addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "msan", true); } } @@ -1764,14 +1781,27 @@ static bool shouldUseLeafFramePointer(const ArgList &Args, /// If the PWD environment variable is set, add a CC1 option to specify the /// debug compilation directory. static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs) { - if (const char *pwd = ::getenv("PWD")) { - // GCC also verifies that stat(pwd) and stat(".") have the same inode - // number. Not doing those because stats are slow, but we could. - if (llvm::sys::path::is_absolute(pwd)) { - std::string CompDir = pwd; - CmdArgs.push_back("-fdebug-compilation-dir"); - CmdArgs.push_back(Args.MakeArgString(CompDir)); - } + struct stat StatPWDBuf, StatDotBuf; + + const char *pwd = ::getenv("PWD"); + if (!pwd) + return; + + if (llvm::sys::path::is_absolute(pwd) && + stat(pwd, &StatPWDBuf) == 0 && + stat(".", &StatDotBuf) == 0 && + StatPWDBuf.st_ino == StatDotBuf.st_ino && + StatPWDBuf.st_dev == StatDotBuf.st_dev) { + CmdArgs.push_back("-fdebug-compilation-dir"); + CmdArgs.push_back(Args.MakeArgString(pwd)); + return; + } + + // Fall back to using getcwd. + SmallString<128> cwd; + if (!llvm::sys::fs::current_path(cwd)) { + CmdArgs.push_back("-fdebug-compilation-dir"); + CmdArgs.push_back(Args.MakeArgString(cwd)); } } @@ -1817,6 +1847,13 @@ static void SplitDebugInfo(const ToolChain &TC, Compilation &C, C.addCommand(new Command(JA, T, Exec, StripArgs)); } +static bool isOptimizationLevelFast(const ArgList &Args) { + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) + if (A->getOption().matches(options::OPT_Ofast)) + return true; + return false; +} + void Clang::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -1969,6 +2006,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-analyzer-checker=deadcode"); + if (types::isCXX(Inputs[0].getType())) + CmdArgs.push_back("-analyzer-checker=cplusplus"); + // Enable the following experimental checkers for testing. CmdArgs.push_back("-analyzer-checker=security.insecureAPI.UncheckedReturn"); CmdArgs.push_back("-analyzer-checker=security.insecureAPI.getpw"); @@ -1997,37 +2037,38 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CheckCodeGenerationOptions(D, Args); - // For the PIC and PIE flag options, this logic is different from the legacy - // logic in very old versions of GCC, as that logic was just a bug no one had - // ever fixed. This logic is both more rational and consistent with GCC's new - // logic now that the bugs are fixed. The last argument relating to either - // PIC or PIE wins, and no other argument is used. If the last argument is - // any flavor of the '-fno-...' arguments, both PIC and PIE are disabled. Any - // PIE option implicitly enables PIC at the same level. - bool PIE = false; - bool PIC = getToolChain().isPICDefault(); + bool PIE = getToolChain().isPIEDefault(); + bool PIC = PIE || getToolChain().isPICDefault(); bool IsPICLevelTwo = PIC; - if (Arg *A = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, - options::OPT_fpic, options::OPT_fno_pic, - options::OPT_fPIE, options::OPT_fno_PIE, - options::OPT_fpie, options::OPT_fno_pie)) { - Option O = A->getOption(); - if (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) || - O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)) { - PIE = O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie); - PIC = PIE || O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic); - IsPICLevelTwo = O.matches(options::OPT_fPIE) || - O.matches(options::OPT_fPIC); - } else { - PIE = PIC = false; - } - } + + // For the PIC and PIE flag options, this logic is different from the + // legacy logic in very old versions of GCC, as that logic was just + // a bug no one had ever fixed. This logic is both more rational and + // consistent with GCC's new logic now that the bugs are fixed. The last + // argument relating to either PIC or PIE wins, and no other argument is + // used. If the last argument is any flavor of the '-fno-...' arguments, + // both PIC and PIE are disabled. Any PIE option implicitly enables PIC + // at the same level. + Arg *LastPICArg =Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, + options::OPT_fpic, options::OPT_fno_pic, + options::OPT_fPIE, options::OPT_fno_PIE, + options::OPT_fpie, options::OPT_fno_pie); // Check whether the tool chain trumps the PIC-ness decision. If the PIC-ness // is forced, then neither PIC nor PIE flags will have no effect. - if (getToolChain().isPICDefaultForced()) { - PIE = false; - PIC = getToolChain().isPICDefault(); - IsPICLevelTwo = PIC; + if (!getToolChain().isPICDefaultForced()) { + if (LastPICArg) { + Option O = LastPICArg->getOption(); + if (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) || + O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)) { + PIE = O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie); + PIC = PIE || O.matches(options::OPT_fPIC) || + O.matches(options::OPT_fpic); + IsPICLevelTwo = O.matches(options::OPT_fPIE) || + O.matches(options::OPT_fPIC); + } else { + PIE = PIC = false; + } + } } // Inroduce a Darwin-specific hack. If the default is PIC but the flags @@ -2101,7 +2142,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss, options::OPT_fno_zero_initialized_in_bss)) CmdArgs.push_back("-mno-zero-initialized-in-bss"); - if (!Args.hasFlag(options::OPT_fstrict_aliasing, + + bool OFastEnabled = isOptimizationLevelFast(Args); + // If -Ofast is the optimization level, then -fstrict-aliasing should be + // enabled. This alias option is being used to simplify the hasFlag logic. + OptSpecifier StrictAliasingAliasOption = OFastEnabled ? options::OPT_Ofast : + options::OPT_fstrict_aliasing; + if (!Args.hasFlag(options::OPT_fstrict_aliasing, StrictAliasingAliasOption, options::OPT_fno_strict_aliasing, getToolChain().IsStrictAliasingDefault())) CmdArgs.push_back("-relaxed-aliasing"); @@ -2117,13 +2164,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Handle segmented stacks. if (Args.hasArg(options::OPT_fsplit_stack)) CmdArgs.push_back("-split-stacks"); + + // If -Ofast is the optimization level, then -ffast-math should be enabled. + // This alias option is being used to simplify the getLastArg logic. + OptSpecifier FastMathAliasOption = OFastEnabled ? options::OPT_Ofast : + options::OPT_ffast_math; // Handle various floating point optimization flags, mapping them to the // appropriate LLVM code generation flags. The pattern for all of these is to // default off the codegen optimizations, and if any flag enables them and no // flag disables them after the flag enabling them, enable the codegen // optimization. This is complicated by several "umbrella" flags. - if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_ffinite_math_only, options::OPT_fno_finite_math_only, @@ -2133,7 +2185,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->getOption().getID() != options::OPT_fno_finite_math_only && A->getOption().getID() != options::OPT_fhonor_infinities) CmdArgs.push_back("-menable-no-infs"); - if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_ffinite_math_only, options::OPT_fno_finite_math_only, @@ -2146,7 +2198,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fmath-errno is the default on some platforms, e.g. BSD-derived OSes. bool MathErrno = getToolChain().IsMathErrnoDefault(); - if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_fmath_errno, options::OPT_fno_math_errno)) @@ -2159,7 +2211,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // entire set of LLVM optimizations, so collect them through all the flag // madness. bool AssociativeMath = false; - if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, options::OPT_fno_unsafe_math_optimizations, @@ -2170,7 +2222,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->getOption().getID() != options::OPT_fno_associative_math) AssociativeMath = true; bool ReciprocalMath = false; - if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, options::OPT_fno_unsafe_math_optimizations, @@ -2181,7 +2233,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->getOption().getID() != options::OPT_fno_reciprocal_math) ReciprocalMath = true; bool SignedZeros = true; - if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, options::OPT_fno_unsafe_math_optimizations, @@ -2192,7 +2244,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->getOption().getID() != options::OPT_fsigned_zeros) SignedZeros = false; bool TrappingMath = true; - if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, options::OPT_fno_unsafe_math_optimizations, @@ -2208,7 +2260,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Validate and pass through -fp-contract option. - if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, options::OPT_fno_fast_math, options::OPT_ffp_contract)) { if (A->getOption().getID() == options::OPT_ffp_contract) { @@ -2219,7 +2271,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Val; } - } else if (A->getOption().getID() == options::OPT_ffast_math) { + } else if (A->getOption().matches(options::OPT_ffast_math) || + (OFastEnabled && A->getOption().matches(options::OPT_Ofast))) { // If fast-math is set then set the fp-contract mode to fast. CmdArgs.push_back(Args.MakeArgString("-ffp-contract=fast")); } @@ -2230,9 +2283,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // preprocessor macros. This is distinct from enabling any optimizations as // these options induce language changes which must survive serialization // and deserialization, etc. - if (Arg *A = Args.getLastArg(options::OPT_ffast_math, options::OPT_fno_fast_math)) - if (A->getOption().matches(options::OPT_ffast_math)) - CmdArgs.push_back("-ffast-math"); + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, + options::OPT_fno_fast_math)) + if (!A->getOption().matches(options::OPT_fno_fast_math)) + CmdArgs.push_back("-ffast-math"); if (Arg *A = Args.getLastArg(options::OPT_ffinite_math_only, options::OPT_fno_fast_math)) if (A->getOption().matches(options::OPT_ffinite_math_only)) CmdArgs.push_back("-ffinite-math-only"); @@ -2597,6 +2651,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (ShouldDisableDwarfDirectory(Args, getToolChain())) CmdArgs.push_back("-fno-dwarf-directory-asm"); + if (ShouldDisableAutolink(Args, getToolChain())) + CmdArgs.push_back("-fno-autolink"); + // Add in -fdebug-compilation-dir if necessary. addDebugCompDirArg(Args, CmdArgs); @@ -2705,7 +2762,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree); Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type); - SanitizerArgs Sanitize(D, Args); + SanitizerArgs Sanitize(getToolChain(), Args); Sanitize.addArgs(Args, CmdArgs); if (!Args.hasFlag(options::OPT_fsanitize_recover, @@ -2892,16 +2949,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_interval); Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_after); - // -fmodules-autolink (on by default when modules is enabled) automatically - // links against libraries for imported modules. This requires the - // integrated assembler. - if (HaveModules && getToolChain().useIntegratedAs() && - Args.hasFlag(options::OPT_fmodules_autolink, - options::OPT_fno_modules_autolink, - true)) { - CmdArgs.push_back("-fmodules-autolink"); - } - // -faccess-control is default. if (Args.hasFlag(options::OPT_fno_access_control, options::OPT_faccess_control, @@ -3198,9 +3245,42 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Color diagnostics are the default, unless the terminal doesn't support // them. - if (Args.hasFlag(options::OPT_fcolor_diagnostics, - options::OPT_fno_color_diagnostics, - llvm::sys::Process::StandardErrHasColors())) + // Support both clang's -f[no-]color-diagnostics and gcc's + // -f[no-]diagnostics-colors[=never|always|auto]. + enum { Colors_On, Colors_Off, Colors_Auto } ShowColors = Colors_Auto; + for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); + it != ie; ++it) { + const Option &O = (*it)->getOption(); + if (!O.matches(options::OPT_fcolor_diagnostics) && + !O.matches(options::OPT_fdiagnostics_color) && + !O.matches(options::OPT_fno_color_diagnostics) && + !O.matches(options::OPT_fno_diagnostics_color) && + !O.matches(options::OPT_fdiagnostics_color_EQ)) + continue; + + (*it)->claim(); + if (O.matches(options::OPT_fcolor_diagnostics) || + O.matches(options::OPT_fdiagnostics_color)) { + ShowColors = Colors_On; + } else if (O.matches(options::OPT_fno_color_diagnostics) || + O.matches(options::OPT_fno_diagnostics_color)) { + ShowColors = Colors_Off; + } else { + assert(O.matches(options::OPT_fdiagnostics_color_EQ)); + StringRef value((*it)->getValue()); + if (value == "always") + ShowColors = Colors_On; + else if (value == "never") + ShowColors = Colors_Off; + else if (value == "auto") + ShowColors = Colors_Auto; + else + getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported) + << ("-fdiagnostics-color=" + value).str(); + } + } + if (ShowColors == Colors_On || + (ShowColors == Colors_Auto && llvm::sys::Process::StandardErrHasColors())) CmdArgs.push_back("-fcolor-diagnostics"); if (!Args.hasFlag(options::OPT_fshow_source_location, @@ -3222,8 +3302,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, false)) CmdArgs.push_back("-fasm-blocks"); + // If -Ofast is the optimization level, then -fvectorize should be enabled. + // This alias option is being used to simplify the hasFlag logic. + OptSpecifier VectorizeAliasOption = OFastEnabled ? options::OPT_Ofast : + options::OPT_fvectorize; + // -fvectorize is default. - if (Args.hasFlag(options::OPT_fvectorize, + if (Args.hasFlag(options::OPT_fvectorize, VectorizeAliasOption, options::OPT_fno_vectorize, true)) { CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-vectorize-loops"); @@ -3233,7 +3318,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasFlag(options::OPT_fslp_vectorize, options::OPT_fno_slp_vectorize, false)) { CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-vectorize"); + CmdArgs.push_back("-vectorize-slp"); + } + + // -fno-slp-vectorize-aggressive is default. + if (Args.hasFlag(options::OPT_fslp_vectorize_aggressive, + options::OPT_fno_slp_vectorize_aggressive, false)) { + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-vectorize-slp-aggressive"); } if (Arg *A = Args.getLastArg(options::OPT_fshow_overloads_EQ)) @@ -3298,6 +3390,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Forward -fcomment-block-commands to -cc1. Args.AddAllArgs(CmdArgs, options::OPT_fcomment_block_commands); + // Forward -fparse-all-comments to -cc1. + Args.AddAllArgs(CmdArgs, options::OPT_fparse_all_comments); // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option // parser. @@ -3673,6 +3767,14 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = getToolChain().getDriver().getClangProgramPath(); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); + + // Handle the debug info splitting at object creation time if we're + // creating an object. + // TODO: Currently only works on linux with newer objcopy. + if (Args.hasArg(options::OPT_gsplit_dwarf) && + (getToolChain().getTriple().getOS() == llvm::Triple::Linux)) + SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, + SplitDebugName(Args, Inputs)); } void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, @@ -3867,7 +3969,6 @@ void hexagon::Assemble::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back( Args.MakeArgString(std::string("-G") + SmallDataThreshold)); - Args.AddAllArgs(CmdArgs, options::OPT_g_Group); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); @@ -4579,7 +4680,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_L); - SanitizerArgs Sanitize(getToolChain().getDriver(), Args); + SanitizerArgs Sanitize(getToolChain(), Args); // If we're building a dynamic lib with -fsanitize=address, // unresolved symbols may appear. Mark all // of them as dynamic_lookup. Linking executables is handled in @@ -5706,6 +5807,12 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("-EL"); + Args.AddLastArg(CmdArgs, options::OPT_mips16, options::OPT_mno_mips16); + Args.AddLastArg(CmdArgs, options::OPT_mmicromips, + options::OPT_mno_micromips); + Args.AddLastArg(CmdArgs, options::OPT_mdsp, options::OPT_mno_dsp); + Args.AddLastArg(CmdArgs, options::OPT_mdspr2, options::OPT_mno_dspr2); + Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, options::OPT_fpic, options::OPT_fno_pic, options::OPT_fPIE, options::OPT_fno_PIE, @@ -5717,6 +5824,9 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, LastPICArg->getOption().matches(options::OPT_fpie))) { CmdArgs.push_back("-KPIC"); } + } else if (getToolChain().getArch() == llvm::Triple::systemz) { + // At the moment we always produce z10 code. + CmdArgs.push_back("-march=z10"); } Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, @@ -5784,6 +5894,10 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, const Driver &D = ToolChain.getDriver(); const bool isAndroid = ToolChain.getTriple().getEnvironment() == llvm::Triple::Android; + SanitizerArgs Sanitize(getToolChain(), Args); + const bool IsPIE = + !Args.hasArg(options::OPT_shared) && + (Args.hasArg(options::OPT_pie) || Sanitize.hasZeroBaseShadow()); ArgStringList CmdArgs; @@ -5798,7 +5912,7 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); - if (Args.hasArg(options::OPT_pie) && !Args.hasArg(options::OPT_shared)) + if (IsPIE) CmdArgs.push_back("-pie"); if (Args.hasArg(options::OPT_rdynamic)) @@ -5844,6 +5958,8 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, else CmdArgs.push_back("elf64ltsmip"); } + else if (ToolChain.getArch() == llvm::Triple::systemz) + CmdArgs.push_back("elf64_s390"); else CmdArgs.push_back("elf_x86_64"); @@ -5890,7 +6006,8 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, } else if (ToolChain.getArch() == llvm::Triple::ppc) CmdArgs.push_back("/lib/ld.so.1"); - else if (ToolChain.getArch() == llvm::Triple::ppc64) + else if (ToolChain.getArch() == llvm::Triple::ppc64 || + ToolChain.getArch() == llvm::Triple::systemz) CmdArgs.push_back("/lib64/ld64.so.1"); else CmdArgs.push_back("/lib64/ld-linux-x86-64.so.2"); @@ -5904,7 +6021,7 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!isAndroid) { const char *crt1 = NULL; if (!Args.hasArg(options::OPT_shared)){ - if (Args.hasArg(options::OPT_pie)) + if (IsPIE) crt1 = "Scrt1.o"; else crt1 = "crt1.o"; @@ -5920,7 +6037,7 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o"; else if (Args.hasArg(options::OPT_shared)) crtbegin = isAndroid ? "crtbegin_so.o" : "crtbeginS.o"; - else if (Args.hasArg(options::OPT_pie)) + else if (IsPIE) crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbeginS.o"; else crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbegin.o"; @@ -5971,8 +6088,6 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); - SanitizerArgs Sanitize(D, Args); - // Call these before we add the C++ ABI library. if (Sanitize.needsUbsanRt()) addUbsanRTLinux(getToolChain(), Args, CmdArgs, D.CCCIsCXX, @@ -6030,7 +6145,7 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, const char *crtend; if (Args.hasArg(options::OPT_shared)) crtend = isAndroid ? "crtend_so.o" : "crtendS.o"; - else if (Args.hasArg(options::OPT_pie)) + else if (IsPIE) crtend = isAndroid ? "crtend_android.o" : "crtendS.o"; else crtend = isAndroid ? "crtend_android.o" : "crtend.o"; @@ -6162,21 +6277,29 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + bool UseGCC47 = false; const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; + if (llvm::sys::fs::exists("/usr/lib/gcc47", UseGCC47)) + UseGCC47 = false; + if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + CmdArgs.push_back("--eh-frame-hdr"); if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); } else { + if (Args.hasArg(options::OPT_rdynamic)) + CmdArgs.push_back("-export-dynamic"); if (Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-Bshareable"); else { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/usr/libexec/ld-elf.so.2"); } + CmdArgs.push_back("--hash-style=both"); } // When building 32-bit code on DragonFly/pc64, we have to explicitly @@ -6196,18 +6319,26 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); - } else { - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o"))); + if (Args.hasArg(options::OPT_pg)) + CmdArgs.push_back(Args.MakeArgString( + getToolChain().GetFilePath("gcrt1.o"))); + else { + if (Args.hasArg(options::OPT_pie)) + CmdArgs.push_back(Args.MakeArgString( + getToolChain().GetFilePath("Scrt1.o"))); + else + CmdArgs.push_back(Args.MakeArgString( + getToolChain().GetFilePath("crt1.o"))); + } } + CmdArgs.push_back(Args.MakeArgString( + getToolChain().GetFilePath("crti.o"))); + if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) + CmdArgs.push_back(Args.MakeArgString( + getToolChain().GetFilePath("crtbeginS.o"))); + else + CmdArgs.push_back(Args.MakeArgString( + getToolChain().GetFilePath("crtbegin.o"))); } Args.AddAllArgs(CmdArgs, options::OPT_L); @@ -6220,20 +6351,19 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, !Args.hasArg(options::OPT_nodefaultlibs)) { // FIXME: GCC passes on -lgcc, -lgcc_pic and a whole lot of // rpaths - CmdArgs.push_back("-L/usr/lib/gcc41"); + if (UseGCC47) + CmdArgs.push_back("-L/usr/lib/gcc47"); + else + CmdArgs.push_back("-L/usr/lib/gcc44"); if (!Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("-rpath"); - CmdArgs.push_back("/usr/lib/gcc41"); - - CmdArgs.push_back("-rpath-link"); - CmdArgs.push_back("/usr/lib/gcc41"); - - CmdArgs.push_back("-rpath"); - CmdArgs.push_back("/usr/lib"); - - CmdArgs.push_back("-rpath-link"); - CmdArgs.push_back("/usr/lib"); + if (UseGCC47) { + CmdArgs.push_back("-rpath"); + CmdArgs.push_back("/usr/lib/gcc47"); + } else { + CmdArgs.push_back("-rpath"); + CmdArgs.push_back("/usr/lib/gcc44"); + } } if (D.CCCIsCXX) { @@ -6241,13 +6371,6 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lm"); } - if (Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back("-lgcc_pic"); - } else { - CmdArgs.push_back("-lgcc"); - } - - if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-lpthread"); @@ -6255,23 +6378,42 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lc"); } - if (Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back("-lgcc_pic"); + if (UseGCC47) { + if (Args.hasArg(options::OPT_static) || + Args.hasArg(options::OPT_static_libgcc)) { + CmdArgs.push_back("-lgcc"); + CmdArgs.push_back("-lgcc_eh"); + } else { + if (Args.hasArg(options::OPT_shared_libgcc)) { + CmdArgs.push_back("-lgcc_pic"); + if (!Args.hasArg(options::OPT_shared)) + CmdArgs.push_back("-lgcc"); + } else { + CmdArgs.push_back("-lgcc"); + CmdArgs.push_back("--as-needed"); + CmdArgs.push_back("-lgcc_pic"); + CmdArgs.push_back("--no-as-needed"); + } + } } else { - CmdArgs.push_back("-lgcc"); + if (Args.hasArg(options::OPT_shared)) { + CmdArgs.push_back("-lgcc_pic"); + } else { + CmdArgs.push_back("-lgcc"); + } } } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { - if (!Args.hasArg(options::OPT_shared)) + if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) CmdArgs.push_back(Args.MakeArgString( - getToolChain().GetFilePath("crtend.o"))); + getToolChain().GetFilePath("crtendS.o"))); else CmdArgs.push_back(Args.MakeArgString( - getToolChain().GetFilePath("crtendS.o"))); + getToolChain().GetFilePath("crtend.o"))); CmdArgs.push_back(Args.MakeArgString( - getToolChain().GetFilePath("crtn.o"))); + getToolChain().GetFilePath("crtn.o"))); } addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple()); diff --git a/lib/Driver/WindowsToolChain.cpp b/lib/Driver/WindowsToolChain.cpp index dac7e77..622c492 100644 --- a/lib/Driver/WindowsToolChain.cpp +++ b/lib/Driver/WindowsToolChain.cpp @@ -60,6 +60,10 @@ bool Windows::isPICDefault() const { return getArch() == llvm::Triple::x86_64; } +bool Windows::isPIEDefault() const { + return false; +} + bool Windows::isPICDefaultForced() const { return getArch() == llvm::Triple::x86_64; } diff --git a/lib/Edit/EditedSource.cpp b/lib/Edit/EditedSource.cpp index dd99ca9..34b5e62 100644 --- a/lib/Edit/EditedSource.cpp +++ b/lib/Edit/EditedSource.cpp @@ -188,6 +188,8 @@ void EditedSource::commitRemove(SourceLocation OrigLoc, unsigned diff = EndOffs.getOffset() - TopEnd.getOffset(); TopEnd = EndOffs; TopFA->RemoveLen += diff; + if (B == BeginOffs) + TopFA->Text = StringRef(); ++I; } diff --git a/lib/Format/BreakableToken.cpp b/lib/Format/BreakableToken.cpp new file mode 100644 index 0000000..3e2e0ce --- /dev/null +++ b/lib/Format/BreakableToken.cpp @@ -0,0 +1,179 @@ +//===--- BreakableToken.cpp - Format C++ code -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Contains implementation of BreakableToken class and classes derived +/// from it. +/// +//===----------------------------------------------------------------------===// + +#include "BreakableToken.h" +#include "llvm/ADT/STLExtras.h" +#include <algorithm> + +namespace clang { +namespace format { + +BreakableToken::Split BreakableComment::getSplit(unsigned LineIndex, + unsigned TailOffset, + unsigned ColumnLimit) const { + StringRef Text = getLine(LineIndex).substr(TailOffset); + unsigned ContentStartColumn = getContentStartColumn(LineIndex, TailOffset); + if (ColumnLimit <= ContentStartColumn + 1) + return Split(StringRef::npos, 0); + + unsigned MaxSplit = ColumnLimit - ContentStartColumn + 1; + StringRef::size_type SpaceOffset = Text.rfind(' ', MaxSplit); + if (SpaceOffset == StringRef::npos || + Text.find_last_not_of(' ', SpaceOffset) == StringRef::npos) { + SpaceOffset = Text.find(' ', MaxSplit); + } + if (SpaceOffset != StringRef::npos && SpaceOffset != 0) { + StringRef BeforeCut = Text.substr(0, SpaceOffset).rtrim(); + StringRef AfterCut = Text.substr(SpaceOffset).ltrim(); + return BreakableToken::Split(BeforeCut.size(), + AfterCut.begin() - BeforeCut.end()); + } + return BreakableToken::Split(StringRef::npos, 0); +} + +void BreakableComment::insertBreak(unsigned LineIndex, unsigned TailOffset, + Split Split, bool InPPDirective, + WhitespaceManager &Whitespaces) { + StringRef Text = getLine(LineIndex).substr(TailOffset); + StringRef AdditionalPrefix = Decoration; + if (Text.size() == Split.first + Split.second) { + // For all but the last line handle trailing space in trimLine. + if (LineIndex < Lines.size() - 1) + return; + // For the last line we need to break before "*/", but not to add "* ". + AdditionalPrefix = ""; + } + + unsigned WhitespaceStartColumn = + getContentStartColumn(LineIndex, TailOffset) + Split.first; + unsigned BreakOffset = Text.data() - TokenText.data() + Split.first; + unsigned CharsToRemove = Split.second; + Whitespaces.breakToken(Tok, BreakOffset, CharsToRemove, "", AdditionalPrefix, + InPPDirective, IndentAtLineBreak, + WhitespaceStartColumn); +} + +BreakableBlockComment::BreakableBlockComment(const SourceManager &SourceMgr, + const AnnotatedToken &Token, + unsigned StartColumn) + : BreakableComment(SourceMgr, Token.FormatTok, StartColumn + 2) { + assert(TokenText.startswith("/*") && TokenText.endswith("*/")); + + OriginalStartColumn = + SourceMgr.getSpellingColumnNumber(Tok.getStartOfNonWhitespace()) - 1; + + TokenText.substr(2, TokenText.size() - 4).split(Lines, "\n"); + + bool NeedsStar = true; + CommonPrefixLength = UINT_MAX; + if (Lines.size() == 1) { + if (Token.Parent == 0) { + // Standalone block comments will be aligned and prefixed with *s. + CommonPrefixLength = OriginalStartColumn + 1; + } else { + // Trailing comments can start on arbitrary column, and available + // horizontal space can be too small to align consecutive lines with + // the first one. We could, probably, align them to current + // indentation level, but now we just wrap them without indentation + // and stars. + CommonPrefixLength = 0; + NeedsStar = false; + } + } else { + for (size_t i = 1; i < Lines.size(); ++i) { + size_t FirstNonWhitespace = Lines[i].find_first_not_of(" "); + if (FirstNonWhitespace != StringRef::npos) { + NeedsStar = NeedsStar && (Lines[i][FirstNonWhitespace] == '*'); + CommonPrefixLength = + std::min<unsigned>(CommonPrefixLength, FirstNonWhitespace); + } + } + } + if (CommonPrefixLength == UINT_MAX) + CommonPrefixLength = 0; + + Decoration = NeedsStar ? "* " : ""; + + IndentAtLineBreak = + std::max<int>(StartColumn - OriginalStartColumn + CommonPrefixLength, 0); +} + +void BreakableBlockComment::alignLines(WhitespaceManager &Whitespaces) { + SourceLocation TokenLoc = Tok.getStartOfNonWhitespace(); + int IndentDelta = (StartColumn - 2) - OriginalStartColumn; + if (IndentDelta > 0) { + std::string WhiteSpace(IndentDelta, ' '); + for (size_t i = 1; i < Lines.size(); ++i) { + Whitespaces.addReplacement( + TokenLoc.getLocWithOffset(Lines[i].data() - TokenText.data()), 0, + WhiteSpace); + } + } else if (IndentDelta < 0) { + std::string WhiteSpace(-IndentDelta, ' '); + // Check that the line is indented enough. + for (size_t i = 1; i < Lines.size(); ++i) { + if (!Lines[i].startswith(WhiteSpace)) + return; + } + for (size_t i = 1; i < Lines.size(); ++i) { + Whitespaces.addReplacement( + TokenLoc.getLocWithOffset(Lines[i].data() - TokenText.data()), + -IndentDelta, ""); + } + } + + for (unsigned i = 1; i < Lines.size(); ++i) + Lines[i] = Lines[i].substr(CommonPrefixLength + Decoration.size()); +} + +void BreakableBlockComment::trimLine(unsigned LineIndex, unsigned TailOffset, + unsigned InPPDirective, + WhitespaceManager &Whitespaces) { + if (LineIndex == Lines.size() - 1) + return; + StringRef Text = Lines[LineIndex].substr(TailOffset); + if (!Text.endswith(" ") && !InPPDirective) + return; + + StringRef TrimmedLine = Text.rtrim(); + unsigned WhitespaceStartColumn = + getLineLengthAfterSplit(LineIndex, TailOffset); + unsigned BreakOffset = TrimmedLine.end() - TokenText.data(); + unsigned CharsToRemove = Text.size() - TrimmedLine.size() + 1; + Whitespaces.breakToken(Tok, BreakOffset, CharsToRemove, "", "", InPPDirective, + 0, WhitespaceStartColumn); +} + +BreakableLineComment::BreakableLineComment(const SourceManager &SourceMgr, + const AnnotatedToken &Token, + unsigned StartColumn) + : BreakableComment(SourceMgr, Token.FormatTok, StartColumn) { + assert(TokenText.startswith("//")); + Decoration = getLineCommentPrefix(TokenText); + Lines.push_back(TokenText.substr(Decoration.size())); + IndentAtLineBreak = StartColumn; + this->StartColumn += Decoration.size(); // Start column of the contents. +} + +StringRef BreakableLineComment::getLineCommentPrefix(StringRef Comment) { + const char *KnownPrefixes[] = { "/// ", "///", "// ", "//" }; + for (size_t i = 0; i < llvm::array_lengthof(KnownPrefixes); ++i) + if (Comment.startswith(KnownPrefixes[i])) + return KnownPrefixes[i]; + return ""; +} + +} // namespace format +} // namespace clang diff --git a/lib/Format/BreakableToken.h b/lib/Format/BreakableToken.h new file mode 100644 index 0000000..c130318 --- /dev/null +++ b/lib/Format/BreakableToken.h @@ -0,0 +1,240 @@ +//===--- BreakableToken.h - Format C++ code -------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Declares BreakableToken, BreakableStringLiteral, and +/// BreakableBlockComment classes, that contain token type-specific logic to +/// break long lines in tokens. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FORMAT_BREAKABLETOKEN_H +#define LLVM_CLANG_FORMAT_BREAKABLETOKEN_H + +#include "TokenAnnotator.h" +#include "WhitespaceManager.h" +#include <utility> + +namespace clang { +namespace format { + +class BreakableToken { +public: + BreakableToken(const SourceManager &SourceMgr, const FormatToken &Tok, + unsigned StartColumn) + : Tok(Tok), StartColumn(StartColumn), + TokenText(SourceMgr.getCharacterData(Tok.getStartOfNonWhitespace()), + Tok.TokenLength) {} + virtual ~BreakableToken() {} + virtual unsigned getLineCount() const = 0; + virtual unsigned getLineSize(unsigned Index) const = 0; + virtual unsigned getLineLengthAfterSplit(unsigned LineIndex, + unsigned TailOffset) const = 0; + + // Contains starting character index and length of split. + typedef std::pair<StringRef::size_type, unsigned> Split; + virtual Split getSplit(unsigned LineIndex, unsigned TailOffset, + unsigned ColumnLimit) const = 0; + virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split, + bool InPPDirective, + WhitespaceManager &Whitespaces) = 0; + virtual void trimLine(unsigned LineIndex, unsigned TailOffset, + unsigned InPPDirective, + WhitespaceManager &Whitespaces) {} +protected: + const FormatToken &Tok; + unsigned StartColumn; + StringRef TokenText; +}; + +class BreakableStringLiteral : public BreakableToken { +public: + BreakableStringLiteral(const SourceManager &SourceMgr, const FormatToken &Tok, + unsigned StartColumn) + : BreakableToken(SourceMgr, Tok, StartColumn) { + assert(TokenText.startswith("\"") && TokenText.endswith("\"")); + } + + virtual unsigned getLineCount() const { return 1; } + + virtual unsigned getLineSize(unsigned Index) const { + return Tok.TokenLength - 2; // Should be in sync with getLine + } + + virtual unsigned getLineLengthAfterSplit(unsigned LineIndex, + unsigned TailOffset) const { + return getDecorationLength() + getLine().size() - TailOffset; + } + + virtual Split getSplit(unsigned LineIndex, unsigned TailOffset, + unsigned ColumnLimit) const { + StringRef Text = getLine().substr(TailOffset); + if (ColumnLimit <= getDecorationLength()) + return Split(StringRef::npos, 0); + unsigned MaxSplit = ColumnLimit - getDecorationLength(); + assert(MaxSplit < Text.size()); + StringRef::size_type SpaceOffset = Text.rfind(' ', MaxSplit); + if (SpaceOffset != StringRef::npos && SpaceOffset != 0) + return Split(SpaceOffset + 1, 0); + StringRef::size_type SlashOffset = Text.rfind('/', MaxSplit); + if (SlashOffset != StringRef::npos && SlashOffset != 0) + return Split(SlashOffset + 1, 0); + StringRef::size_type SplitPoint = getStartOfCharacter(Text, MaxSplit); + if (SplitPoint != StringRef::npos && SplitPoint > 1) + // Do not split at 0. + return Split(SplitPoint, 0); + return Split(StringRef::npos, 0); + } + + virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split, + bool InPPDirective, WhitespaceManager &Whitespaces) { + unsigned WhitespaceStartColumn = StartColumn + Split.first + 2; + Whitespaces.breakToken(Tok, 1 + TailOffset + Split.first, Split.second, + "\"", "\"", InPPDirective, StartColumn, + WhitespaceStartColumn); + } + +private: + StringRef getLine() const { + // Get string without quotes. + // FIXME: Handle string prefixes. + return TokenText.substr(1, TokenText.size() - 2); + } + + unsigned getDecorationLength() const { return StartColumn + 2; } + + static StringRef::size_type getStartOfCharacter(StringRef Text, + StringRef::size_type Offset) { + StringRef::size_type NextEscape = Text.find('\\'); + while (NextEscape != StringRef::npos && NextEscape < Offset) { + StringRef::size_type SequenceLength = + getEscapeSequenceLength(Text.substr(NextEscape)); + if (Offset < NextEscape + SequenceLength) + return NextEscape; + NextEscape = Text.find('\\', NextEscape + SequenceLength); + } + return Offset; + } + + static unsigned getEscapeSequenceLength(StringRef Text) { + assert(Text[0] == '\\'); + if (Text.size() < 2) + return 1; + + switch (Text[1]) { + case 'u': + return 6; + case 'U': + return 10; + case 'x': + return getHexLength(Text); + default: + if (Text[1] >= '0' && Text[1] <= '7') + return getOctalLength(Text); + return 2; + } + } + + static unsigned getHexLength(StringRef Text) { + unsigned I = 2; // Point after '\x'. + while (I < Text.size() && ((Text[I] >= '0' && Text[I] <= '9') || + (Text[I] >= 'a' && Text[I] <= 'f') || + (Text[I] >= 'A' && Text[I] <= 'F'))) { + ++I; + } + return I; + } + + static unsigned getOctalLength(StringRef Text) { + unsigned I = 1; + while (I < Text.size() && I < 4 && (Text[I] >= '0' && Text[I] <= '7')) { + ++I; + } + return I; + } + +}; + +class BreakableComment : public BreakableToken { +public: + virtual unsigned getLineSize(unsigned Index) const { + return getLine(Index).size(); + } + + virtual unsigned getLineCount() const { return Lines.size(); } + + virtual unsigned getLineLengthAfterSplit(unsigned LineIndex, + unsigned TailOffset) const { + return getContentStartColumn(LineIndex, TailOffset) + + getLine(LineIndex).size() - TailOffset; + } + + virtual Split getSplit(unsigned LineIndex, unsigned TailOffset, + unsigned ColumnLimit) const; + virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split, + bool InPPDirective, WhitespaceManager &Whitespaces); + +protected: + BreakableComment(const SourceManager &SourceMgr, const FormatToken &Tok, + unsigned StartColumn) + : BreakableToken(SourceMgr, Tok, StartColumn) {} + + // Get comment lines without /* */, common prefix and trailing whitespace. + // Last line is not trimmed, as it is terminated by */, so its trailing + // whitespace is not really trailing. + StringRef getLine(unsigned Index) const { + return Index < Lines.size() - 1 ? Lines[Index].rtrim() : Lines[Index]; + } + + unsigned getContentStartColumn(unsigned LineIndex, + unsigned TailOffset) const { + return (TailOffset == 0 && LineIndex == 0) + ? StartColumn + : IndentAtLineBreak + Decoration.size(); + } + + unsigned IndentAtLineBreak; + StringRef Decoration; + SmallVector<StringRef, 16> Lines; +}; + +class BreakableBlockComment : public BreakableComment { +public: + BreakableBlockComment(const SourceManager &SourceMgr, + const AnnotatedToken &Token, unsigned StartColumn); + + void alignLines(WhitespaceManager &Whitespaces); + + virtual unsigned getLineLengthAfterSplit(unsigned LineIndex, + unsigned TailOffset) const { + return BreakableComment::getLineLengthAfterSplit(LineIndex, TailOffset) + + (LineIndex + 1 < Lines.size() ? 0 : 2); + } + + virtual void trimLine(unsigned LineIndex, unsigned TailOffset, + unsigned InPPDirective, WhitespaceManager &Whitespaces); + +private: + unsigned OriginalStartColumn; + unsigned CommonPrefixLength; +}; + +class BreakableLineComment : public BreakableComment { +public: + BreakableLineComment(const SourceManager &SourceMgr, + const AnnotatedToken &Token, unsigned StartColumn); + +private: + static StringRef getLineCommentPrefix(StringRef Comment); +}; + +} // namespace format +} // namespace clang + +#endif // LLVM_CLANG_FORMAT_BREAKABLETOKEN_H diff --git a/lib/Format/CMakeLists.txt b/lib/Format/CMakeLists.txt index d8630ee..560e38b 100644 --- a/lib/Format/CMakeLists.txt +++ b/lib/Format/CMakeLists.txt @@ -1,9 +1,11 @@ set(LLVM_LINK_COMPONENTS support) add_clang_library(clangFormat + BreakableToken.cpp + Format.cpp TokenAnnotator.cpp UnwrappedLineParser.cpp - Format.cpp + WhitespaceManager.cpp ) add_dependencies(clangFormat diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index 101b16f..a0557f7 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -15,8 +15,10 @@ #define DEBUG_TYPE "format-formatter" +#include "BreakableToken.h" #include "TokenAnnotator.h" #include "UnwrappedLineParser.h" +#include "WhitespaceManager.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/OperatorPrecedence.h" #include "clang/Basic/SourceManager.h" @@ -34,62 +36,66 @@ namespace format { FormatStyle getLLVMStyle() { FormatStyle LLVMStyle; - LLVMStyle.ColumnLimit = 80; - LLVMStyle.MaxEmptyLinesToKeep = 1; - LLVMStyle.PointerBindsToType = false; - LLVMStyle.DerivePointerBinding = false; LLVMStyle.AccessModifierOffset = -2; - LLVMStyle.Standard = FormatStyle::LS_Cpp03; - LLVMStyle.IndentCaseLabels = false; - LLVMStyle.SpacesBeforeTrailingComments = 1; - LLVMStyle.BinPackParameters = true; + LLVMStyle.AlignEscapedNewlinesLeft = false; LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true; - LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false; LLVMStyle.AllowShortIfStatementsOnASingleLine = false; + LLVMStyle.BinPackParameters = true; + LLVMStyle.ColumnLimit = 80; + LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false; + LLVMStyle.DerivePointerBinding = false; + LLVMStyle.IndentCaseLabels = false; + LLVMStyle.MaxEmptyLinesToKeep = 1; LLVMStyle.ObjCSpaceBeforeProtocolList = true; LLVMStyle.PenaltyExcessCharacter = 1000000; - LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 5; + LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 75; + LLVMStyle.PointerBindsToType = false; + LLVMStyle.SpacesBeforeTrailingComments = 1; + LLVMStyle.Standard = FormatStyle::LS_Cpp03; return LLVMStyle; } FormatStyle getGoogleStyle() { FormatStyle GoogleStyle; - GoogleStyle.ColumnLimit = 80; - GoogleStyle.MaxEmptyLinesToKeep = 1; - GoogleStyle.PointerBindsToType = true; - GoogleStyle.DerivePointerBinding = true; GoogleStyle.AccessModifierOffset = -1; - GoogleStyle.Standard = FormatStyle::LS_Auto; - GoogleStyle.IndentCaseLabels = true; - GoogleStyle.SpacesBeforeTrailingComments = 2; - GoogleStyle.BinPackParameters = true; + GoogleStyle.AlignEscapedNewlinesLeft = true; GoogleStyle.AllowAllParametersOfDeclarationOnNextLine = true; + GoogleStyle.AllowShortIfStatementsOnASingleLine = true; + GoogleStyle.BinPackParameters = true; + GoogleStyle.ColumnLimit = 80; GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true; - GoogleStyle.AllowShortIfStatementsOnASingleLine = false; + GoogleStyle.DerivePointerBinding = true; + GoogleStyle.IndentCaseLabels = true; + GoogleStyle.MaxEmptyLinesToKeep = 1; GoogleStyle.ObjCSpaceBeforeProtocolList = false; GoogleStyle.PenaltyExcessCharacter = 1000000; - GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 100; + GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 200; + GoogleStyle.PointerBindsToType = true; + GoogleStyle.SpacesBeforeTrailingComments = 2; + GoogleStyle.Standard = FormatStyle::LS_Auto; return GoogleStyle; } FormatStyle getChromiumStyle() { FormatStyle ChromiumStyle = getGoogleStyle(); ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false; + ChromiumStyle.AllowShortIfStatementsOnASingleLine = false; ChromiumStyle.BinPackParameters = false; ChromiumStyle.Standard = FormatStyle::LS_Cpp03; ChromiumStyle.DerivePointerBinding = false; return ChromiumStyle; } -static bool isTrailingComment(const AnnotatedToken &Tok) { - return Tok.is(tok::comment) && - (Tok.Children.empty() || Tok.Children[0].MustBreakBefore); -} - -static bool isComparison(const AnnotatedToken &Tok) { - prec::Level Precedence = getPrecedence(Tok); - return Tok.Type == TT_BinaryOperator && - (Precedence == prec::Equality || Precedence == prec::Relational); +FormatStyle getMozillaStyle() { + FormatStyle MozillaStyle = getLLVMStyle(); + MozillaStyle.AllowAllParametersOfDeclarationOnNextLine = false; + MozillaStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true; + MozillaStyle.DerivePointerBinding = true; + MozillaStyle.IndentCaseLabels = true; + MozillaStyle.ObjCSpaceBeforeProtocolList = false; + MozillaStyle.PenaltyReturnTypeOnItsOwnLine = 200; + MozillaStyle.PointerBindsToType = true; + return MozillaStyle; } // Returns the length of everything up to the first possible line break after @@ -104,373 +110,12 @@ static unsigned getLengthToMatchingParen(const AnnotatedToken &Tok) { return End->TotalLength - Tok.TotalLength + 1; } -static size_t -calculateColumnLimit(const FormatStyle &Style, bool InPPDirective) { - // In preprocessor directives reserve two chars for trailing " \" - return Style.ColumnLimit - (InPPDirective ? 2 : 0); -} - -/// \brief Manages the whitespaces around tokens and their replacements. -/// -/// This includes special handling for certain constructs, e.g. the alignment of -/// trailing line comments. -class WhitespaceManager { -public: - WhitespaceManager(SourceManager &SourceMgr, const FormatStyle &Style) - : SourceMgr(SourceMgr), Style(Style) {} - - /// \brief Replaces the whitespace in front of \p Tok. Only call once for - /// each \c AnnotatedToken. - void replaceWhitespace(const AnnotatedToken &Tok, unsigned NewLines, - unsigned Spaces, unsigned WhitespaceStartColumn) { - // 2+ newlines mean an empty line separating logic scopes. - if (NewLines >= 2) - alignComments(); - - SourceLocation TokenLoc = Tok.FormatTok.Tok.getLocation(); - bool LineExceedsColumnLimit = Spaces + WhitespaceStartColumn + - Tok.FormatTok.TokenLength > Style.ColumnLimit; - - // Align line comments if they are trailing or if they continue other - // trailing comments. - if (isTrailingComment(Tok)) { - // Remove the comment's trailing whitespace. - if (Tok.FormatTok.Tok.getLength() != Tok.FormatTok.TokenLength) - Replaces.insert(tooling::Replacement( - SourceMgr, TokenLoc.getLocWithOffset(Tok.FormatTok.TokenLength), - Tok.FormatTok.Tok.getLength() - Tok.FormatTok.TokenLength, "")); - - // Align comment with other comments. - if ((Tok.Parent != NULL || !Comments.empty()) && - !LineExceedsColumnLimit) { - StoredComment Comment; - Comment.Tok = Tok.FormatTok; - Comment.Spaces = Spaces; - Comment.NewLines = NewLines; - Comment.MinColumn = - NewLines > 0 ? Spaces : WhitespaceStartColumn + Spaces; - Comment.MaxColumn = Style.ColumnLimit - Tok.FormatTok.TokenLength; - Comment.Untouchable = false; - Comments.push_back(Comment); - return; - } - } - - // If this line does not have a trailing comment, align the stored comments. - if (Tok.Children.empty() && !isTrailingComment(Tok)) - alignComments(); - - if (Tok.Type == TT_BlockComment) { - indentBlockComment(Tok, Spaces, WhitespaceStartColumn, NewLines, false); - } else if (Tok.Type == TT_LineComment && LineExceedsColumnLimit) { - StringRef Line(SourceMgr.getCharacterData(TokenLoc), - Tok.FormatTok.TokenLength); - int StartColumn = Spaces + (NewLines == 0 ? WhitespaceStartColumn : 0); - StringRef Prefix = getLineCommentPrefix(Line); - std::string NewPrefix = std::string(StartColumn, ' ') + Prefix.str(); - splitLineInComment(Tok.FormatTok, Line.substr(Prefix.size()), - StartColumn + Prefix.size(), NewPrefix, - /*InPPDirective=*/ false, - /*CommentHasMoreLines=*/ false); - } - - storeReplacement(Tok.FormatTok, getNewLineText(NewLines, Spaces)); - } - - /// \brief Like \c replaceWhitespace, but additionally adds right-aligned - /// backslashes to escape newlines inside a preprocessor directive. - /// - /// This function and \c replaceWhitespace have the same behavior if - /// \c Newlines == 0. - void replacePPWhitespace(const AnnotatedToken &Tok, unsigned NewLines, - unsigned Spaces, unsigned WhitespaceStartColumn) { - if (Tok.Type == TT_BlockComment) - indentBlockComment(Tok, Spaces, WhitespaceStartColumn, NewLines, true); - - storeReplacement(Tok.FormatTok, - getNewLineText(NewLines, Spaces, WhitespaceStartColumn)); - } - - /// \brief Inserts a line break into the middle of a token. - /// - /// Will break at \p Offset inside \p Tok, putting \p Prefix before the line - /// break and \p Postfix before the rest of the token starts in the next line. - /// - /// \p InPPDirective, \p Spaces, \p WhitespaceStartColumn and \p Style are - /// used to generate the correct line break. - void breakToken(const FormatToken &Tok, unsigned Offset, - unsigned ReplaceChars, StringRef Prefix, StringRef Postfix, - bool InPPDirective, unsigned Spaces, - unsigned WhitespaceStartColumn) { - std::string NewLineText; - if (!InPPDirective) - NewLineText = getNewLineText(1, Spaces); - else - NewLineText = getNewLineText(1, Spaces, WhitespaceStartColumn); - std::string ReplacementText = (Prefix + NewLineText + Postfix).str(); - SourceLocation Location = Tok.Tok.getLocation().getLocWithOffset(Offset); - Replaces.insert(tooling::Replacement(SourceMgr, Location, ReplaceChars, - ReplacementText)); - } - - /// \brief Returns all the \c Replacements created during formatting. - const tooling::Replacements &generateReplacements() { - alignComments(); - return Replaces; - } - - void addUntouchableComment(unsigned Column) { - StoredComment Comment; - Comment.MinColumn = Column; - Comment.MaxColumn = Column; - Comment.Untouchable = true; - Comments.push_back(Comment); - } - -private: - static StringRef getLineCommentPrefix(StringRef Comment) { - const char *KnownPrefixes[] = { "/// ", "///", "// ", "//" }; - for (size_t i = 0; i < llvm::array_lengthof(KnownPrefixes); ++i) - if (Comment.startswith(KnownPrefixes[i])) - return KnownPrefixes[i]; - return ""; - } - - /// \brief Finds a common prefix of lines of a block comment to properly - /// indent (and possibly decorate with '*'s) added lines. - /// - /// The first line is ignored (it's special and starts with /*). The number of - /// lines should be more than one. - static StringRef findCommentLinesPrefix(ArrayRef<StringRef> Lines, - const char *PrefixChars = " *") { - assert(Lines.size() > 1); - StringRef Prefix(Lines[1].data(), Lines[1].find_first_not_of(PrefixChars)); - for (size_t i = 2; i < Lines.size(); ++i) { - for (size_t j = 0; j < Prefix.size() && j < Lines[i].size(); ++j) { - if (Prefix[j] != Lines[i][j]) { - Prefix = Prefix.substr(0, j); - break; - } - } - } - return Prefix; - } - - /// \brief Splits one line in a line or block comment, if it doesn't fit to - /// provided column limit. Removes trailing whitespace in each line. - /// - /// \param Line points to the line contents without leading // or /*. - /// - /// \param StartColumn is the column where the first character of Line will be - /// located after formatting. - /// - /// \param LinePrefix is inserted after each line break. - /// - /// When \param InPPDirective is true, each line break will be preceded by a - /// backslash in the last column to make line breaks inside the comment - /// visually consistent with line breaks outside the comment. This only makes - /// sense for block comments. - /// - /// When \param CommentHasMoreLines is false, no line breaks/trailing - /// backslashes will be inserted after it. - void splitLineInComment(const FormatToken &Tok, StringRef Line, - size_t StartColumn, StringRef LinePrefix, - bool InPPDirective, bool CommentHasMoreLines, - const char *WhiteSpaceChars = " ") { - size_t ColumnLimit = calculateColumnLimit(Style, InPPDirective); - const char *TokenStart = SourceMgr.getCharacterData(Tok.Tok.getLocation()); - - StringRef TrimmedLine = Line.rtrim(); - int TrailingSpaceLength = Line.size() - TrimmedLine.size(); - - // Don't touch leading whitespace. - Line = TrimmedLine.ltrim(); - StartColumn += TrimmedLine.size() - Line.size(); - - while (Line.size() + StartColumn > ColumnLimit) { - // Try to break at the last whitespace before the column limit. - size_t SpacePos = - Line.find_last_of(WhiteSpaceChars, ColumnLimit - StartColumn + 1); - if (SpacePos == StringRef::npos) { - // Try to find any whitespace in the line. - SpacePos = Line.find_first_of(WhiteSpaceChars); - if (SpacePos == StringRef::npos) // No whitespace found, give up. - break; - } - - StringRef NextCut = Line.substr(0, SpacePos).rtrim(); - StringRef RemainingLine = Line.substr(SpacePos).ltrim(); - if (RemainingLine.empty()) - break; - - if (RemainingLine == "*/" && LinePrefix.endswith("* ")) - LinePrefix = LinePrefix.substr(0, LinePrefix.size() - 2); - - Line = RemainingLine; - - size_t ReplaceChars = Line.begin() - NextCut.end(); - breakToken(Tok, NextCut.end() - TokenStart, ReplaceChars, "", LinePrefix, - InPPDirective, 0, NextCut.size() + StartColumn); - StartColumn = LinePrefix.size(); - } - - if (TrailingSpaceLength > 0 || (InPPDirective && CommentHasMoreLines)) { - // Remove trailing whitespace/insert backslash. + 1 is for \n - breakToken(Tok, Line.end() - TokenStart, TrailingSpaceLength + 1, "", "", - InPPDirective, 0, Line.size() + StartColumn); - } - } - - /// \brief Changes indentation of all lines in a block comment by Indent, - /// removes trailing whitespace from each line, splits lines that end up - /// exceeding the column limit. - void indentBlockComment(const AnnotatedToken &Tok, int Indent, - int WhitespaceStartColumn, int NewLines, - bool InPPDirective) { - assert(Tok.Type == TT_BlockComment); - int StartColumn = Indent + (NewLines == 0 ? WhitespaceStartColumn : 0); - const SourceLocation TokenLoc = Tok.FormatTok.Tok.getLocation(); - const int CurrentIndent = SourceMgr.getSpellingColumnNumber(TokenLoc) - 1; - const int IndentDelta = Indent - CurrentIndent; - const StringRef Text(SourceMgr.getCharacterData(TokenLoc), - Tok.FormatTok.TokenLength); - assert(Text.startswith("/*") && Text.endswith("*/")); - - SmallVector<StringRef, 16> Lines; - Text.split(Lines, "\n"); - - if (IndentDelta > 0) { - std::string WhiteSpace(IndentDelta, ' '); - for (size_t i = 1; i < Lines.size(); ++i) { - Replaces.insert(tooling::Replacement( - SourceMgr, TokenLoc.getLocWithOffset(Lines[i].data() - Text.data()), - 0, WhiteSpace)); - } - } else if (IndentDelta < 0) { - std::string WhiteSpace(-IndentDelta, ' '); - // Check that the line is indented enough. - for (size_t i = 1; i < Lines.size(); ++i) { - if (!Lines[i].startswith(WhiteSpace)) - return; - } - for (size_t i = 1; i < Lines.size(); ++i) { - Replaces.insert(tooling::Replacement( - SourceMgr, TokenLoc.getLocWithOffset(Lines[i].data() - Text.data()), - -IndentDelta, "")); - } - } - - // Split long lines in comments. - size_t OldPrefixSize = 0; - std::string NewPrefix; - if (Lines.size() > 1) { - StringRef CurrentPrefix = findCommentLinesPrefix(Lines); - OldPrefixSize = CurrentPrefix.size(); - NewPrefix = (IndentDelta < 0) - ? CurrentPrefix.substr(-IndentDelta).str() - : std::string(IndentDelta, ' ') + CurrentPrefix.str(); - if (CurrentPrefix.endswith("*")) { - NewPrefix += " "; - ++OldPrefixSize; - } - } else if (Tok.Parent == 0) { - NewPrefix = std::string(StartColumn, ' ') + " * "; - } - - StartColumn += 2; - for (size_t i = 0; i < Lines.size(); ++i) { - StringRef Line = Lines[i].substr(i == 0 ? 2 : OldPrefixSize); - splitLineInComment(Tok.FormatTok, Line, StartColumn, NewPrefix, - InPPDirective, i != Lines.size() - 1); - StartColumn = NewPrefix.size(); - } - } - - std::string getNewLineText(unsigned NewLines, unsigned Spaces) { - return std::string(NewLines, '\n') + std::string(Spaces, ' '); - } - - std::string getNewLineText(unsigned NewLines, unsigned Spaces, - unsigned WhitespaceStartColumn) { - std::string NewLineText; - if (NewLines > 0) { - unsigned Offset = - std::min<int>(Style.ColumnLimit - 1, WhitespaceStartColumn); - for (unsigned i = 0; i < NewLines; ++i) { - NewLineText += std::string(Style.ColumnLimit - Offset - 1, ' '); - NewLineText += "\\\n"; - Offset = 0; - } - } - return NewLineText + std::string(Spaces, ' '); - } - - /// \brief Structure to store a comment for later layout and alignment. - struct StoredComment { - FormatToken Tok; - unsigned MinColumn; - unsigned MaxColumn; - unsigned NewLines; - unsigned Spaces; - bool Untouchable; - }; - SmallVector<StoredComment, 16> Comments; - typedef SmallVector<StoredComment, 16>::iterator comment_iterator; - - /// \brief Try to align all stashed comments. - void alignComments() { - unsigned MinColumn = 0; - unsigned MaxColumn = UINT_MAX; - comment_iterator Start = Comments.begin(); - for (comment_iterator I = Start, E = Comments.end(); I != E; ++I) { - if (I->MinColumn > MaxColumn || I->MaxColumn < MinColumn) { - alignComments(Start, I, MinColumn); - MinColumn = I->MinColumn; - MaxColumn = I->MaxColumn; - Start = I; - } else { - MinColumn = std::max(MinColumn, I->MinColumn); - MaxColumn = std::min(MaxColumn, I->MaxColumn); - } - } - alignComments(Start, Comments.end(), MinColumn); - Comments.clear(); - } - - /// \brief Put all the comments between \p I and \p E into \p Column. - void alignComments(comment_iterator I, comment_iterator E, unsigned Column) { - while (I != E) { - if (!I->Untouchable) { - unsigned Spaces = I->Spaces + Column - I->MinColumn; - storeReplacement(I->Tok, getNewLineText(I->NewLines, Spaces)); - } - ++I; - } - } - - /// \brief Stores \p Text as the replacement for the whitespace in front of - /// \p Tok. - void storeReplacement(const FormatToken &Tok, const std::string Text) { - // Don't create a replacement, if it does not change anything. - if (StringRef(SourceMgr.getCharacterData(Tok.WhiteSpaceStart), - Tok.WhiteSpaceLength) == Text) - return; - - Replaces.insert(tooling::Replacement(SourceMgr, Tok.WhiteSpaceStart, - Tok.WhiteSpaceLength, Text)); - } - - SourceManager &SourceMgr; - tooling::Replacements Replaces; - const FormatStyle &Style; -}; - class UnwrappedLineFormatter { public: UnwrappedLineFormatter(const FormatStyle &Style, SourceManager &SourceMgr, const AnnotatedLine &Line, unsigned FirstIndent, const AnnotatedToken &RootToken, - WhitespaceManager &Whitespaces, bool StructuralError) + WhitespaceManager &Whitespaces) : Style(Style), SourceMgr(SourceMgr), Line(Line), FirstIndent(FirstIndent), RootToken(RootToken), Whitespaces(Whitespaces), Count(0) {} @@ -486,16 +131,12 @@ public: State.NextToken = &RootToken; State.Stack.push_back( ParenState(FirstIndent, FirstIndent, !Style.BinPackParameters, - /*HasMultiParameterLine=*/ false)); + /*NoLineBreak=*/ false)); State.LineContainsContinuedForLoopSection = false; State.ParenLevel = 0; State.StartOfStringLiteral = 0; State.StartOfLineLevel = State.ParenLevel; - DEBUG({ - DebugTokenState(*State.NextToken); - }); - // The first token has already been indented and thus consumed. moveStateToNextToken(State, /*DryRun=*/ false); @@ -530,13 +171,13 @@ private: struct ParenState { ParenState(unsigned Indent, unsigned LastSpace, bool AvoidBinPacking, - bool HasMultiParameterLine) + bool NoLineBreak) : Indent(Indent), LastSpace(LastSpace), FirstLessLess(0), BreakBeforeClosingBrace(false), QuestionColumn(0), AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false), - HasMultiParameterLine(HasMultiParameterLine), ColonPos(0), - StartOfFunctionCall(0), NestedNameSpecifierContinuation(0), - CallContinuation(0), VariablePos(0) {} + NoLineBreak(NoLineBreak), ColonPos(0), StartOfFunctionCall(0), + NestedNameSpecifierContinuation(0), CallContinuation(0), + VariablePos(0) {} /// \brief The position to which a specific parenthesis level needs to be /// indented. @@ -573,8 +214,8 @@ private: /// \c AvoidBinPacking is \c true). bool BreakBeforeParameter; - /// \brief This context already has a line with more than one parameter. - bool HasMultiParameterLine; + /// \brief Line breaking in this context would break a formatting rule. + bool NoLineBreak; /// \brief The position of the colon in an ObjC method declaration/call. unsigned ColonPos; @@ -610,14 +251,14 @@ private: return AvoidBinPacking; if (BreakBeforeParameter != Other.BreakBeforeParameter) return BreakBeforeParameter; - if (HasMultiParameterLine != Other.HasMultiParameterLine) - return HasMultiParameterLine; + if (NoLineBreak != Other.NoLineBreak) + return NoLineBreak; if (ColonPos != Other.ColonPos) return ColonPos < Other.ColonPos; if (StartOfFunctionCall != Other.StartOfFunctionCall) return StartOfFunctionCall < Other.StartOfFunctionCall; if (NestedNameSpecifierContinuation != - Other.NestedNameSpecifierContinuation) + Other.NestedNameSpecifierContinuation) return NestedNameSpecifierContinuation < Other.NestedNameSpecifierContinuation; if (CallContinuation != Other.CallContinuation) @@ -662,7 +303,7 @@ private: if (Column != Other.Column) return Column < Other.Column; if (LineContainsContinuedForLoopSection != - Other.LineContainsContinuedForLoopSection) + Other.LineContainsContinuedForLoopSection) return LineContainsContinuedForLoopSection; if (ParenLevel != Other.ParenLevel) return ParenLevel < Other.ParenLevel; @@ -730,7 +371,8 @@ private: State.Stack.back().VariablePos != 0) { State.Column = State.Stack.back().VariablePos; } else if (Previous.ClosesTemplateDeclaration || - (Current.Type == TT_StartOfName && State.ParenLevel == 0)) { + (Current.Type == TT_StartOfName && State.ParenLevel == 0 && + Line.StartsDefinition)) { State.Column = State.Stack.back().Indent; } else if (Current.Type == TT_ObjCSelectorName) { if (State.Stack.back().ColonPos > Current.FormatTok.TokenLength) { @@ -741,8 +383,7 @@ private: State.Stack.back().ColonPos = State.Column + Current.FormatTok.TokenLength; } - } else if (Current.Type == TT_StartOfName || Current.is(tok::question) || - Previous.is(tok::equal) || isComparison(Previous) || + } else if (Current.Type == TT_StartOfName || Previous.is(tok::equal) || Previous.Type == TT_ObjCMethodExpr) { State.Column = ContinuationIndent; } else { @@ -781,7 +422,9 @@ private: for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i) { State.Stack[i].BreakBeforeParameter = true; } - if (Current.isOneOf(tok::period, tok::arrow)) + const AnnotatedToken *TokenBefore = Current.getPreviousNoneComment(); + if (TokenBefore && !TokenBefore->isOneOf(tok::comma, tok::semi) && + !TokenBefore->opensScope()) State.Stack.back().BreakBeforeParameter = true; // If we break after {, we should also break before the corresponding }. @@ -822,7 +465,7 @@ private: if (Current.Type == TT_ObjCSelectorName && State.Stack.back().ColonPos == 0) { if (State.Stack.back().Indent + Current.LongestObjCSelectorName > - State.Column + Spaces + Current.FormatTok.TokenLength) + State.Column + Spaces + Current.FormatTok.TokenLength) State.Stack.back().ColonPos = State.Stack.back().Indent + Current.LongestObjCSelectorName; else @@ -830,12 +473,12 @@ private: State.Column + Spaces + Current.FormatTok.TokenLength; } - if (Current.Type != TT_LineComment && - (Previous.isOneOf(tok::l_paren, tok::l_brace) || - State.NextToken->Parent->Type == TT_TemplateOpener)) + if (Previous.opensScope() && Previous.Type != TT_ObjCMethodExpr && + Current.Type != TT_LineComment) State.Stack.back().Indent = State.Column + Spaces; - if (Previous.is(tok::comma) && !isTrailingComment(Current)) - State.Stack.back().HasMultiParameterLine = true; + if (Previous.is(tok::comma) && !Current.isTrailingComment() && + State.Stack.back().AvoidBinPacking) + State.Stack.back().NoLineBreak = true; State.Column += Spaces; if (Current.is(tok::l_paren) && Previous.isOneOf(tok::kw_if, tok::kw_for)) @@ -851,9 +494,7 @@ private: State.Stack.back().LastSpace = State.Column; else if (Previous.Type == TT_InheritanceColon) State.Stack.back().Indent = State.Column; - else if (Previous.ParameterCount > 1 && - (Previous.isOneOf(tok::l_paren, tok::l_square, tok::l_brace) || - Previous.Type == TT_TemplateOpener)) + else if (Previous.opensScope() && Previous.ParameterCount > 1) // If this function has multiple parameters, indent nested calls from // the start of the first parameter. State.Stack.back().LastSpace = State.Column; @@ -879,28 +520,55 @@ private: State.Stack.back().StartOfFunctionCall = Current.LastInChainOfCalls ? 0 : State.Column; if (Current.Type == TT_CtorInitializerColon) { + State.Stack.back().Indent = State.Column + 2; if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine) State.Stack.back().AvoidBinPacking = true; State.Stack.back().BreakBeforeParameter = false; } + // If return returns a binary expression, align after it. + if (Current.is(tok::kw_return) && !Current.FakeLParens.empty()) + State.Stack.back().LastSpace = State.Column + 7; + // In ObjC method declaration we align on the ":" of parameters, but we need // to ensure that we indent parameters on subsequent lines by at least 4. if (Current.Type == TT_ObjCMethodSpecifier) State.Stack.back().Indent += 4; // Insert scopes created by fake parenthesis. - for (unsigned i = 0, e = Current.FakeLParens; i != e; ++i) { + const AnnotatedToken *Previous = Current.getPreviousNoneComment(); + // Don't add extra indentation for the first fake parenthesis after + // 'return', assignements or opening <({[. The indentation for these cases + // is special cased. + bool SkipFirstExtraIndent = + Current.is(tok::kw_return) || + (Previous && (Previous->opensScope() || + getPrecedence(*Previous) == prec::Assignment)); + for (SmallVector<prec::Level, 4>::const_reverse_iterator + I = Current.FakeLParens.rbegin(), + E = Current.FakeLParens.rend(); + I != E; ++I) { ParenState NewParenState = State.Stack.back(); - NewParenState.Indent = std::max(State.Column, State.Stack.back().Indent); - NewParenState.BreakBeforeParameter = false; + NewParenState.Indent = + std::max(std::max(State.Column, NewParenState.Indent), + State.Stack.back().LastSpace); + + // Always indent conditional expressions. Never indent expression where + // the 'operator' is ',', ';' or an assignment (i.e. *I <= + // prec::Assignment) as those have different indentation rules. Indent + // other expression, unless the indentation needs to be skipped. + if (*I == prec::Conditional || + (!SkipFirstExtraIndent && *I > prec::Assignment)) + NewParenState.Indent += 4; + if (Previous && !Previous->opensScope()) + NewParenState.BreakBeforeParameter = false; State.Stack.push_back(NewParenState); + SkipFirstExtraIndent = false; } // If we encounter an opening (, [, { or <, we add a level to our stacks to // prepare for the following tokens. - if (Current.isOneOf(tok::l_paren, tok::l_square, tok::l_brace) || - State.NextToken->Type == TT_TemplateOpener) { + if (Current.opensScope()) { unsigned NewIndent; bool AvoidBinPacking; if (Current.is(tok::l_brace)) { @@ -909,12 +577,20 @@ private: } else { NewIndent = 4 + std::max(State.Stack.back().LastSpace, State.Stack.back().StartOfFunctionCall); - AvoidBinPacking = - !Style.BinPackParameters || State.Stack.back().AvoidBinPacking; + AvoidBinPacking = !Style.BinPackParameters; } State.Stack.push_back( ParenState(NewIndent, State.Stack.back().LastSpace, AvoidBinPacking, - State.Stack.back().HasMultiParameterLine)); + State.Stack.back().NoLineBreak)); + + if (Current.NoMoreTokensOnLevel && Current.FakeLParens.empty()) { + // This parenthesis was the last token possibly making use of Indent and + // LastSpace of the next higher ParenLevel. Thus, erase them to acieve + // better memoization results. + State.Stack[State.Stack.size() - 2].Indent = 0; + State.Stack[State.Stack.size() - 2].LastSpace = 0; + } + ++State.ParenLevel; } @@ -962,115 +638,74 @@ private: /// it if possible. unsigned breakProtrudingToken(const AnnotatedToken &Current, LineState &State, bool DryRun) { - if (Current.isNot(tok::string_literal)) - return 0; - // Only break up default narrow strings. - const char *LiteralData = Current.FormatTok.Tok.getLiteralData(); - if (!LiteralData || *LiteralData != '"') + llvm::OwningPtr<BreakableToken> Token; + unsigned StartColumn = State.Column - Current.FormatTok.TokenLength; + if (Current.is(tok::string_literal)) { + // Only break up default narrow strings. + const char *LiteralData = SourceMgr.getCharacterData( + Current.FormatTok.getStartOfNonWhitespace()); + if (!LiteralData || *LiteralData != '"') + return 0; + + Token.reset(new BreakableStringLiteral(SourceMgr, Current.FormatTok, + StartColumn)); + } else if (Current.Type == TT_BlockComment) { + BreakableBlockComment *BBC = + new BreakableBlockComment(SourceMgr, Current, StartColumn); + if (!DryRun) + BBC->alignLines(Whitespaces); + Token.reset(BBC); + } else if (Current.Type == TT_LineComment && + (Current.Parent == NULL || + Current.Parent->Type != TT_ImplicitStringLiteral)) { + Token.reset(new BreakableLineComment(SourceMgr, Current, StartColumn)); + } else { return 0; + } + bool BreakInserted = false; unsigned Penalty = 0; - unsigned TailOffset = 0; - unsigned TailLength = Current.FormatTok.TokenLength; - unsigned StartColumn = State.Column - Current.FormatTok.TokenLength; - unsigned OffsetFromStart = 0; - while (StartColumn + TailLength > getColumnLimit()) { - StringRef Text = StringRef(LiteralData + TailOffset, TailLength); - if (StartColumn + OffsetFromStart + 1 > getColumnLimit()) - break; - StringRef::size_type SplitPoint = getSplitPoint( - Text, getColumnLimit() - StartColumn - OffsetFromStart - 1); - if (SplitPoint == StringRef::npos) - break; - assert(SplitPoint != 0); - // +2, because 'Text' starts after the opening quotes, and does not - // include the closing quote we need to insert. - unsigned WhitespaceStartColumn = - StartColumn + OffsetFromStart + SplitPoint + 2; - State.Stack.back().LastSpace = StartColumn; + for (unsigned LineIndex = 0; LineIndex < Token->getLineCount(); + ++LineIndex) { + unsigned TailOffset = 0; + unsigned RemainingLength = + Token->getLineLengthAfterSplit(LineIndex, TailOffset); + while (RemainingLength > getColumnLimit()) { + BreakableToken::Split Split = + Token->getSplit(LineIndex, TailOffset, getColumnLimit()); + if (Split.first == StringRef::npos) + break; + assert(Split.first != 0); + unsigned NewRemainingLength = Token->getLineLengthAfterSplit( + LineIndex, TailOffset + Split.first + Split.second); + if (NewRemainingLength >= RemainingLength) + break; + if (!DryRun) { + Token->insertBreak(LineIndex, TailOffset, Split, Line.InPPDirective, + Whitespaces); + } + TailOffset += Split.first + Split.second; + RemainingLength = NewRemainingLength; + Penalty += Style.PenaltyExcessCharacter; + BreakInserted = true; + } + State.Column = RemainingLength; if (!DryRun) { - Whitespaces.breakToken(Current.FormatTok, TailOffset + SplitPoint + 1, - 0, "\"", "\"", Line.InPPDirective, StartColumn, - WhitespaceStartColumn); + Token->trimLine(LineIndex, TailOffset, Line.InPPDirective, Whitespaces); } - TailOffset += SplitPoint + 1; - TailLength -= SplitPoint + 1; - OffsetFromStart = 1; - Penalty += Style.PenaltyExcessCharacter; + } + + if (BreakInserted) { for (unsigned i = 0, e = State.Stack.size(); i != e; ++i) State.Stack[i].BreakBeforeParameter = true; + State.Stack.back().LastSpace = StartColumn; } - State.Column = StartColumn + TailLength; return Penalty; } - StringRef::size_type - getSplitPoint(StringRef Text, StringRef::size_type Offset) { - StringRef::size_type SpaceOffset = Text.rfind(' ', Offset); - if (SpaceOffset != StringRef::npos && SpaceOffset != 0) - return SpaceOffset; - StringRef::size_type SlashOffset = Text.rfind('/', Offset); - if (SlashOffset != StringRef::npos && SlashOffset != 0) - return SlashOffset; - StringRef::size_type Split = getStartOfCharacter(Text, Offset); - if (Split != StringRef::npos && Split > 1) - // Do not split at 0. - return Split - 1; - return StringRef::npos; - } - - StringRef::size_type - getStartOfCharacter(StringRef Text, StringRef::size_type Offset) { - StringRef::size_type NextEscape = Text.find('\\'); - while (NextEscape != StringRef::npos && NextEscape < Offset) { - StringRef::size_type SequenceLength = - getEscapeSequenceLength(Text.substr(NextEscape)); - if (Offset < NextEscape + SequenceLength) - return NextEscape; - NextEscape = Text.find('\\', NextEscape + SequenceLength); - } - return Offset; - } - - unsigned getEscapeSequenceLength(StringRef Text) { - assert(Text[0] == '\\'); - if (Text.size() < 2) - return 1; - - switch (Text[1]) { - case 'u': - return 6; - case 'U': - return 10; - case 'x': - return getHexLength(Text); - default: - if (Text[1] >= '0' && Text[1] <= '7') - return getOctalLength(Text); - return 2; - } - } - - unsigned getHexLength(StringRef Text) { - unsigned I = 2; // Point after '\x'. - while (I < Text.size() && ((Text[I] >= '0' && Text[I] <= '9') || - (Text[I] >= 'a' && Text[I] <= 'f') || - (Text[I] >= 'A' && Text[I] <= 'F'))) { - ++I; - } - return I; - } - - unsigned getOctalLength(StringRef Text) { - unsigned I = 1; - while (I < Text.size() && I < 4 && (Text[I] >= '0' && Text[I] <= '7')) { - ++I; - } - return I; - } - unsigned getColumnLimit() { - return calculateColumnLimit(Style, Line.InPPDirective); + // In preprocessor directives reserve two chars for trailing " \" + return Style.ColumnLimit - (Line.InPPDirective ? 2 : 0); } /// \brief An edge in the solution space from \c Previous->State to \c State, @@ -1194,12 +829,7 @@ private: !(State.NextToken->is(tok::r_brace) && State.Stack.back().BreakBeforeClosingBrace)) return false; - // Trying to insert a parameter on a new line if there are already more than - // one parameter on the current line is bin packing. - if (State.Stack.back().HasMultiParameterLine && - State.Stack.back().AvoidBinPacking) - return false; - return true; + return !State.Stack.back().NoLineBreak; } /// \brief Returns \c true, if a line break after \p State is mandatory. @@ -1216,7 +846,7 @@ private: State.NextToken->is(tok::question) || State.NextToken->Type == TT_ConditionalExpr) && State.Stack.back().BreakBeforeParameter && - !isTrailingComment(*State.NextToken) && + !State.NextToken->isTrailingComment() && State.NextToken->isNot(tok::r_paren) && State.NextToken->isNot(tok::r_brace)) return true; @@ -1310,6 +940,11 @@ public: // Now FormatTok is the next non-whitespace token. FormatTok.TokenLength = Text.size(); + if (FormatTok.Tok.is(tok::comment)) { + FormatTok.TrailingWhiteSpaceLength = Text.size() - Text.rtrim().size(); + FormatTok.TokenLength -= FormatTok.TrailingWhiteSpaceLength; + } + // In case the token starts with escaped newlines, we want to // take them into account as whitespace - this pattern is quite frequent // in macro definitions. @@ -1336,11 +971,6 @@ public: GreaterStashed = true; } - // If we reformat comments, we remove trailing whitespace. Update the length - // accordingly. - if (FormatTok.Tok.is(tok::comment)) - FormatTok.TokenLength = Text.rtrim().size(); - return FormatTok; } @@ -1373,7 +1003,7 @@ public: tooling::Replacements format() { LexerBasedFormatTokenSource Tokens(Lex, SourceMgr); UnwrappedLineParser Parser(Diag, Style, Tokens, *this); - StructuralError = Parser.parse(); + bool StructuralError = Parser.parse(); unsigned PreviousEndOfLineColumn = 0; TokenAnnotator Annotator(Style, SourceMgr, Lex, Tokens.getIdentTable().get("in")); @@ -1383,14 +1013,21 @@ public: deriveLocalStyle(); for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) { Annotator.calculateFormattingInformation(AnnotatedLines[i]); + } - // Adapt level to the next line if this is a comment. - // FIXME: Can/should this be done in the UnwrappedLineParser? - if (i + 1 != e && AnnotatedLines[i].First.is(tok::comment) && - AnnotatedLines[i].First.Children.empty() && - AnnotatedLines[i + 1].First.isNot(tok::r_brace)) - AnnotatedLines[i].Level = AnnotatedLines[i + 1].Level; + // Adapt level to the next line if this is a comment. + // FIXME: Can/should this be done in the UnwrappedLineParser? + const AnnotatedLine *NextNoneCommentLine = NULL; + for (unsigned i = AnnotatedLines.size() - 1; i > 0; --i) { + if (NextNoneCommentLine && AnnotatedLines[i].First.is(tok::comment) && + AnnotatedLines[i].First.Children.empty()) + AnnotatedLines[i].Level = NextNoneCommentLine->Level; + else + NextNoneCommentLine = + AnnotatedLines[i].First.isNot(tok::r_brace) ? &AnnotatedLines[i] + : NULL; } + std::vector<int> IndentForLevel; bool PreviousLineWasTouched = false; const AnnotatedToken *PreviousLineLastToken = 0; @@ -1416,17 +1053,19 @@ public: unsigned Indent = LevelIndent; if (static_cast<int>(Indent) + Offset >= 0) Indent += Offset; - if (!FirstTok.WhiteSpaceStart.isValid() || StructuralError) { - Indent = LevelIndent = - SourceMgr.getSpellingColumnNumber(FirstTok.Tok.getLocation()) - 1; - } else { + if (FirstTok.WhiteSpaceStart.isValid() && + // Insert a break even if there is a structural error in case where + // we break apart a line consisting of multiple unwrapped lines. + (FirstTok.NewlinesBefore == 0 || !StructuralError)) { formatFirstToken(TheLine.First, PreviousLineLastToken, Indent, TheLine.InPPDirective, PreviousEndOfLineColumn); + } else { + Indent = LevelIndent = + SourceMgr.getSpellingColumnNumber(FirstTok.Tok.getLocation()) - 1; } tryFitMultipleLinesInOne(Indent, I, E); UnwrappedLineFormatter Formatter(Style, SourceMgr, TheLine, Indent, - TheLine.First, Whitespaces, - StructuralError); + TheLine.First, Whitespaces); PreviousEndOfLineColumn = Formatter.format(I + 1 != E ? &*(I + 1) : NULL); IndentForLevel[TheLine.Level] = LevelIndent; @@ -1457,6 +1096,8 @@ public: if (TheLine.Last->is(tok::comment)) Whitespaces.addUntouchableComment(SourceMgr.getSpellingColumnNumber( TheLine.Last->FormatTok.Tok.getLocation()) - 1); + else + Whitespaces.alignComments(); } PreviousLineLastToken = I->Last; } @@ -1727,12 +1368,12 @@ private: WhitespaceManager Whitespaces; std::vector<CharSourceRange> Ranges; std::vector<AnnotatedLine> AnnotatedLines; - bool StructuralError; }; -tooling::Replacements -reformat(const FormatStyle &Style, Lexer &Lex, SourceManager &SourceMgr, - std::vector<CharSourceRange> Ranges, DiagnosticConsumer *DiagClient) { +tooling::Replacements reformat(const FormatStyle &Style, Lexer &Lex, + SourceManager &SourceMgr, + std::vector<CharSourceRange> Ranges, + DiagnosticConsumer *DiagClient) { IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); OwningPtr<DiagnosticConsumer> DiagPrinter; if (DiagClient == 0) { diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index 427157e..17abb01 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -16,12 +16,13 @@ #include "TokenAnnotator.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Lexer.h" +#include "llvm/Support/Debug.h" namespace clang { namespace format { -static bool isUnaryOperator(const AnnotatedToken &Tok) { - switch (Tok.FormatTok.Tok.getKind()) { +bool AnnotatedToken::isUnaryOperator() const { + switch (FormatTok.Tok.getKind()) { case tok::plus: case tok::plusplus: case tok::minus: @@ -36,49 +37,38 @@ static bool isUnaryOperator(const AnnotatedToken &Tok) { } } -static bool isBinaryOperator(const AnnotatedToken &Tok) { +bool AnnotatedToken::isBinaryOperator() const { // Comma is a binary operator, but does not behave as such wrt. formatting. - return getPrecedence(Tok) > prec::Comma; + return getPrecedence(*this) > prec::Comma; } -// Returns the previous token ignoring comments. -static AnnotatedToken *getPreviousToken(AnnotatedToken &Tok) { - AnnotatedToken *PrevToken = Tok.Parent; - while (PrevToken != NULL && PrevToken->is(tok::comment)) - PrevToken = PrevToken->Parent; - return PrevToken; -} -static const AnnotatedToken *getPreviousToken(const AnnotatedToken &Tok) { - return getPreviousToken(const_cast<AnnotatedToken &>(Tok)); +bool AnnotatedToken::isTrailingComment() const { + return is(tok::comment) && + (Children.empty() || Children[0].FormatTok.NewlinesBefore > 0); } -static bool isTrailingComment(AnnotatedToken *Tok) { - return Tok != NULL && Tok->is(tok::comment) && - (Tok->Children.empty() || - Tok->Children[0].FormatTok.NewlinesBefore > 0); +AnnotatedToken *AnnotatedToken::getPreviousNoneComment() const { + AnnotatedToken *Tok = Parent; + while (Tok != NULL && Tok->is(tok::comment)) + Tok = Tok->Parent; + return Tok; } -// Returns the next token ignoring comments. -static const AnnotatedToken *getNextToken(const AnnotatedToken &Tok) { - if (Tok.Children.empty()) - return NULL; - const AnnotatedToken *NextToken = &Tok.Children[0]; - while (NextToken->is(tok::comment)) { - if (NextToken->Children.empty()) - return NULL; - NextToken = &NextToken->Children[0]; - } - return NextToken; +const AnnotatedToken *AnnotatedToken::getNextNoneComment() const { + const AnnotatedToken *Tok = Children.empty() ? NULL : &Children[0]; + while (Tok != NULL && Tok->is(tok::comment)) + Tok = Tok->Children.empty() ? NULL : &Tok->Children[0]; + return Tok; } -static bool closesScope(const AnnotatedToken &Tok) { - return Tok.isOneOf(tok::r_paren, tok::r_brace, tok::r_square) || - Tok.Type == TT_TemplateCloser; +bool AnnotatedToken::closesScope() const { + return isOneOf(tok::r_paren, tok::r_brace, tok::r_square) || + Type == TT_TemplateCloser; } -static bool opensScope(const AnnotatedToken &Tok) { - return Tok.isOneOf(tok::l_paren, tok::l_brace, tok::l_square) || - Tok.Type == TT_TemplateOpener; +bool AnnotatedToken::opensScope() const { + return isOneOf(tok::l_paren, tok::l_brace, tok::l_square) || + Type == TT_TemplateOpener; } /// \brief A parser that gathers additional information about tokens. @@ -91,7 +81,7 @@ public: AnnotatingParser(SourceManager &SourceMgr, Lexer &Lex, AnnotatedLine &Line, IdentifierInfo &Ident_in) : SourceMgr(SourceMgr), Lex(Lex), Line(Line), CurrentToken(&Line.First), - KeywordVirtualFound(false), Ident_in(Ident_in) { + KeywordVirtualFound(false), NameFound(false), Ident_in(Ident_in) { Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/ false)); } @@ -165,6 +155,8 @@ private: } if (CurrentToken->is(tok::r_paren)) { + if (CurrentToken->Parent->closesScope()) + CurrentToken->Parent->MatchingParen->NoMoreTokensOnLevel = true; Left->MatchingParen = CurrentToken; CurrentToken->MatchingParen = Left; @@ -196,12 +188,12 @@ private: // ')' or ']'), it could be the start of an Objective-C method // expression, or it could the the start of an Objective-C array literal. AnnotatedToken *Left = CurrentToken->Parent; - AnnotatedToken *Parent = getPreviousToken(*Left); + AnnotatedToken *Parent = Left->getPreviousNoneComment(); bool StartsObjCMethodExpr = Contexts.back().CanBeExpression && (!Parent || Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren, tok::kw_return, tok::kw_throw) || - isUnaryOperator(*Parent) || Parent->Type == TT_ObjCForIn || + Parent->isUnaryOperator() || Parent->Type == TT_ObjCForIn || Parent->Type == TT_CastRParen || getBinOpPrecedence(Parent->FormatTok.Tok.getKind(), true, true) > prec::Unknown); @@ -253,24 +245,25 @@ private: } bool parseBrace() { - // Lines are fine to end with '{'. - if (CurrentToken == NULL) - return true; - ScopedContextCreator ContextCreator(*this, tok::l_brace, 1); - AnnotatedToken *Left = CurrentToken->Parent; - while (CurrentToken != NULL) { - if (CurrentToken->is(tok::r_brace)) { - Left->MatchingParen = CurrentToken; - CurrentToken->MatchingParen = Left; - next(); - return true; + if (CurrentToken != NULL) { + ScopedContextCreator ContextCreator(*this, tok::l_brace, 1); + AnnotatedToken *Left = CurrentToken->Parent; + while (CurrentToken != NULL) { + if (CurrentToken->is(tok::r_brace)) { + Left->MatchingParen = CurrentToken; + CurrentToken->MatchingParen = Left; + next(); + return true; + } + if (CurrentToken->isOneOf(tok::r_paren, tok::r_square)) + return false; + updateParameterCount(Left, CurrentToken); + if (!consumeToken()) + return false; } - if (CurrentToken->isOneOf(tok::r_paren, tok::r_square)) - return false; - updateParameterCount(Left, CurrentToken); - if (!consumeToken()) - return false; } + // No closing "}" found, this probably starts a definition. + Line.StartsDefinition = true; return true; } @@ -357,7 +350,7 @@ private: case tok::l_paren: if (!parseParens()) return false; - if (Line.MustBeDeclaration) + if (Line.MustBeDeclaration && NameFound && !Contexts.back().IsExpression) Line.MightBeFunctionDecl = true; break; case tok::l_square: @@ -467,6 +460,10 @@ private: case tok::pp_warning: parseWarningOrError(); break; + case tok::pp_if: + case tok::pp_elif: + parseLine(); + break; default: break; } @@ -573,7 +570,8 @@ private: }; void determineTokenType(AnnotatedToken &Current) { - if (getPrecedence(Current) == prec::Assignment) { + if (getPrecedence(Current) == prec::Assignment && + (!Current.Parent || Current.Parent->isNot(tok::kw_operator))) { Contexts.back().IsExpression = true; for (AnnotatedToken *Previous = Current.Parent; Previous && Previous->isNot(tok::comma); @@ -599,6 +597,9 @@ private: Contexts.back().IsExpression = true; } else if (Current.is(tok::kw_new)) { Contexts.back().CanBeExpression = false; + } else if (Current.is(tok::semi)) { + // This should be the condition or increment in a for-loop. + Contexts.back().IsExpression = true; } if (Current.Type == TT_Unknown) { @@ -611,6 +612,7 @@ private: Current.Parent->Type == TT_TemplateCloser)) { Contexts.back().FirstStartOfName = &Current; Current.Type = TT_StartOfName; + NameFound = true; } else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) { Current.Type = determineStarAmpUsage(Current, Contexts.back().IsExpression); @@ -620,7 +622,7 @@ private: Current.Type = determineIncrementUsage(Current); } else if (Current.is(tok::exclaim)) { Current.Type = TT_UnaryOperator; - } else if (isBinaryOperator(Current)) { + } else if (Current.isBinaryOperator()) { Current.Type = TT_BinaryOperator; } else if (Current.is(tok::comment)) { std::string Data(Lexer::getSpelling(Current.FormatTok.Tok, SourceMgr, @@ -664,11 +666,11 @@ private: /// \brief Return the type of the given token assuming it is * or &. TokenType determineStarAmpUsage(const AnnotatedToken &Tok, bool IsExpression) { - const AnnotatedToken *PrevToken = getPreviousToken(Tok); + const AnnotatedToken *PrevToken = Tok.getPreviousNoneComment(); if (PrevToken == NULL) return TT_UnaryOperator; - const AnnotatedToken *NextToken = getNextToken(Tok); + const AnnotatedToken *NextToken = Tok.getNextNoneComment(); if (NextToken == NULL) return TT_Unknown; @@ -687,7 +689,7 @@ private: if (PrevToken->FormatTok.Tok.isLiteral() || PrevToken->isOneOf(tok::r_paren, tok::r_square) || - NextToken->FormatTok.Tok.isLiteral() || isUnaryOperator(*NextToken)) + NextToken->FormatTok.Tok.isLiteral() || NextToken->isUnaryOperator()) return TT_BinaryOperator; // It is very unlikely that we are going to find a pointer or reference type @@ -699,7 +701,7 @@ private: } TokenType determinePlusMinusCaretUsage(const AnnotatedToken &Tok) { - const AnnotatedToken *PrevToken = getPreviousToken(Tok); + const AnnotatedToken *PrevToken = Tok.getPreviousNoneComment(); if (PrevToken == NULL) return TT_UnaryOperator; @@ -719,7 +721,7 @@ private: /// \brief Determine whether ++/-- are pre- or post-increments/-decrements. TokenType determineIncrementUsage(const AnnotatedToken &Tok) { - const AnnotatedToken *PrevToken = getPreviousToken(Tok); + const AnnotatedToken *PrevToken = Tok.getPreviousNoneComment(); if (PrevToken == NULL) return TT_UnaryOperator; if (PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::identifier)) @@ -768,6 +770,7 @@ private: AnnotatedLine &Line; AnnotatedToken *CurrentToken; bool KeywordVirtualFound; + bool NameFound; IdentifierInfo &Ident_in; }; @@ -782,12 +785,8 @@ public: if (Precedence > prec::PointerToMember || Current == NULL) return; - // Skip over "return" until we can properly parse it. - if (Current->is(tok::kw_return)) - next(); - // Eagerly consume trailing comments. - while (isTrailingComment(Current)) { + while (Current && Current->isTrailingComment()) { next(); } @@ -796,14 +795,13 @@ public: while (Current) { // Consume operators with higher precedence. - parse(prec::Level(Precedence + 1)); + parse(Precedence + 1); int CurrentPrecedence = 0; if (Current) { if (Current->Type == TT_ConditionalExpr) CurrentPrecedence = 1 + (int) prec::Conditional; - else if (Current->is(tok::semi) || Current->Type == TT_InlineASMColon || - Current->Type == TT_CtorInitializerColon) + else if (Current->is(tok::semi) || Current->Type == TT_InlineASMColon) CurrentPrecedence = 1; else if (Current->Type == TT_BinaryOperator || Current->is(tok::comma)) CurrentPrecedence = 1 + (int) getPrecedence(*Current); @@ -811,10 +809,10 @@ public: // At the end of the line or when an operator with higher precedence is // found, insert fake parenthesis and return. - if (Current == NULL || closesScope(*Current) || + if (Current == NULL || Current->closesScope() || (CurrentPrecedence != 0 && CurrentPrecedence < Precedence)) { if (OperatorFound) { - ++Start->FakeLParens; + Start->FakeLParens.push_back(prec::Level(Precedence - 1)); if (Current) ++Current->Parent->FakeRParens; } @@ -822,18 +820,11 @@ public: } // Consume scopes: (), [], <> and {} - if (opensScope(*Current)) { - AnnotatedToken *Left = Current; - while (Current && !closesScope(*Current)) { + if (Current->opensScope()) { + while (Current && !Current->closesScope()) { next(); parse(); } - // Remove fake parens that just duplicate the real parens. - if (Current && Left->Children[0].FakeLParens > 0 && - Current->Parent->FakeRParens > 0) { - --Left->Children[0].FakeLParens; - --Current->Parent->FakeRParens; - } next(); } else { // Operator found. @@ -892,7 +883,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { Current->MustBreakBefore = true; } else if (Current->Type == TT_LineComment) { Current->MustBreakBefore = Current->FormatTok.NewlinesBefore > 0; - } else if (isTrailingComment(Current->Parent) || + } else if (Current->Parent->isTrailingComment() || (Current->is(tok::string_literal) && Current->Parent->is(tok::string_literal))) { Current->MustBreakBefore = true; @@ -919,6 +910,10 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { Current = Current->Children.empty() ? NULL : &Current->Children[0]; } + + DEBUG({ + printDebugInfo(Line); + }); } unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, @@ -933,12 +928,14 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, // FIXME: Clean up hack of using BindingStrength to find top-level names. return Style.PenaltyReturnTypeOnItsOwnLine; else - return 100; + return 200; } if (Left.is(tok::equal) && Right.is(tok::l_brace)) return 150; if (Left.is(tok::coloncolon)) return 500; + if (Left.isOneOf(tok::kw_class, tok::kw_struct)) + return 5000; if (Left.Type == TT_RangeBasedForLoopColon || Left.Type == TT_InheritanceColon) @@ -969,7 +966,9 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr) return 20; - if (opensScope(Left)) + if (Left.is(tok::l_paren) && Line.MightBeFunctionDecl) + return 100; + if (Left.opensScope()) return Left.ParameterCount > 1 ? prec::Comma : 20; if (Right.is(tok::lessless)) { @@ -1050,13 +1049,15 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, return Line.Type == LT_ObjCDecl || Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch, tok::kw_return, tok::kw_catch, tok::kw_new, - tok::kw_delete); + tok::kw_delete, tok::semi); } if (Left.is(tok::at) && Right.FormatTok.Tok.getObjCKeywordID() != tok::objc_not_keyword) return false; if (Left.is(tok::l_brace) && Right.is(tok::r_brace)) return false; + if (Right.is(tok::ellipsis)) + return false; return true; } @@ -1088,7 +1089,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return false; if (Tok.is(tok::colon)) return !Line.First.isOneOf(tok::kw_case, tok::kw_default) && - !Tok.Children.empty() && Tok.Type != TT_ObjCMethodExpr; + Tok.getNextNoneComment() != NULL && Tok.Type != TT_ObjCMethodExpr; if (Tok.is(tok::l_paren) && !Tok.Children.empty() && Tok.Children[0].Type == TT_PointerOrReference && !Tok.Children[0].Children.empty() && @@ -1137,10 +1138,9 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, if (Right.Type == TT_ConditionalExpr || Right.is(tok::question)) return true; if (Right.Type == TT_RangeBasedForLoopColon || - Right.Type == TT_InheritanceColon) + Right.Type == TT_OverloadedOperatorLParen) return false; - if (Left.Type == TT_RangeBasedForLoopColon || - Left.Type == TT_InheritanceColon) + if (Left.Type == TT_RangeBasedForLoopColon) return true; if (Right.Type == TT_RangeBasedForLoopColon) return false; @@ -1174,8 +1174,9 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, return false; if (Left.is(tok::identifier) && Right.is(tok::string_literal)) return true; - return (isBinaryOperator(Left) && Left.isNot(tok::lessless)) || - Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace) || + return (Left.isBinaryOperator() && Left.isNot(tok::lessless)) || + Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace, + tok::kw_class, tok::kw_struct) || Right.isOneOf(tok::lessless, tok::arrow, tok::period, tok::colon) || (Left.is(tok::r_paren) && Left.Type != TT_CastRParen && Right.isOneOf(tok::identifier, tok::kw___attribute)) || @@ -1183,5 +1184,22 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, (Left.is(tok::l_square) && !Right.is(tok::r_square)); } +void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) { + llvm::errs() << "AnnotatedTokens:\n"; + const AnnotatedToken *Tok = &Line.First; + while (Tok) { + llvm::errs() << " M=" << Tok->MustBreakBefore + << " C=" << Tok->CanBreakBefore << " T=" << Tok->Type + << " S=" << Tok->SpacesRequiredBefore + << " P=" << Tok->SplitPenalty + << " Name=" << Tok->FormatTok.Tok.getName() << " FakeLParens="; + for (unsigned i = 0, e = Tok->FakeLParens.size(); i != e; ++i) + llvm::errs() << Tok->FakeLParens[i] << "/"; + llvm::errs() << " FakeRParens=" << Tok->FakeRParens << "\n"; + Tok = Tok->Children.empty() ? NULL : &Tok->Children[0]; + } + llvm::errs() << "----\n"; +} + } // namespace format } // namespace clang diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h index c41ee33..b364082 100644 --- a/lib/Format/TokenAnnotator.h +++ b/lib/Format/TokenAnnotator.h @@ -75,9 +75,9 @@ public: CanBreakBefore(false), MustBreakBefore(false), ClosesTemplateDeclaration(false), MatchingParen(NULL), ParameterCount(0), BindingStrength(0), SplitPenalty(0), - LongestObjCSelectorName(0), Parent(NULL), FakeLParens(0), + LongestObjCSelectorName(0), Parent(NULL), FakeRParens(0), LastInChainOfCalls(false), - PartOfMultiVariableDeclStmt(false) {} + PartOfMultiVariableDeclStmt(false), NoMoreTokensOnLevel(false) {} bool is(tok::TokenKind Kind) const { return FormatTok.Tok.is(Kind); } @@ -121,6 +121,15 @@ public: Children[0].isObjCAtKeyword(tok::objc_private)); } + /// \brief Returns whether \p Tok is ([{ or a template opening <. + bool opensScope() const; + /// \brief Returns whether \p Tok is )]} or a template opening >. + bool closesScope() const; + + bool isUnaryOperator() const; + bool isBinaryOperator() const; + bool isTrailingComment() const; + FormatToken FormatTok; TokenType Type; @@ -158,8 +167,12 @@ public: std::vector<AnnotatedToken> Children; AnnotatedToken *Parent; - /// \brief Insert this many fake ( before this token for correct indentation. - unsigned FakeLParens; + /// \brief Stores the number of required fake parentheses and the + /// corresponding operator precedence. + /// + /// If multiple fake parentheses start at a token, this vector stores them in + /// reverse order, i.e. inner fake parenthesis first. + SmallVector<prec::Level, 4> FakeLParens; /// \brief Insert this many fake ) after this token for correct indentation. unsigned FakeRParens; @@ -171,12 +184,24 @@ public: /// Only set if \c Type == \c TT_StartOfName. bool PartOfMultiVariableDeclStmt; - const AnnotatedToken *getPreviousNoneComment() const { - AnnotatedToken *Tok = Parent; - while (Tok != NULL && Tok->is(tok::comment)) - Tok = Tok->Parent; - return Tok; - } + /// \brief Set to \c true for "("-tokens if this is the last token other than + /// ")" in the next higher parenthesis level. + /// + /// If this is \c true, no more formatting decisions have to be made on the + /// next higher parenthesis level, enabling optimizations. + /// + /// Example: + /// \code + /// aaaaaa(aaaaaa()); + /// ^ // Set to true for this parenthesis. + /// \endcode + bool NoMoreTokensOnLevel; + + /// \brief Returns the previous token ignoring comments. + AnnotatedToken *getPreviousNoneComment() const; + + /// \brief Returns the next token ignoring comments. + const AnnotatedToken *getNextNoneComment() const; }; class AnnotatedLine { @@ -184,8 +209,8 @@ public: AnnotatedLine(const UnwrappedLine &Line) : First(Line.Tokens.front()), Level(Line.Level), InPPDirective(Line.InPPDirective), - MustBeDeclaration(Line.MustBeDeclaration), - MightBeFunctionDecl(false) { + MustBeDeclaration(Line.MustBeDeclaration), MightBeFunctionDecl(false), + StartsDefinition(false) { assert(!Line.Tokens.empty()); AnnotatedToken *Current = &First; for (std::list<FormatToken>::const_iterator I = ++Line.Tokens.begin(), @@ -201,7 +226,8 @@ public: : First(Other.First), Type(Other.Type), Level(Other.Level), InPPDirective(Other.InPPDirective), MustBeDeclaration(Other.MustBeDeclaration), - MightBeFunctionDecl(Other.MightBeFunctionDecl) { + MightBeFunctionDecl(Other.MightBeFunctionDecl), + StartsDefinition(Other.StartsDefinition) { Last = &First; while (!Last->Children.empty()) { Last->Children[0].Parent = Last; @@ -217,6 +243,7 @@ public: bool InPPDirective; bool MustBeDeclaration; bool MightBeFunctionDecl; + bool StartsDefinition; }; inline prec::Level getPrecedence(const AnnotatedToken &Tok) { @@ -248,6 +275,8 @@ private: bool canBreakBefore(const AnnotatedLine &Line, const AnnotatedToken &Right); + void printDebugInfo(const AnnotatedLine &Line); + const FormatStyle &Style; SourceManager &SourceMgr; Lexer &Lex; diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index 89a391b..722af5d 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -45,9 +45,11 @@ private: class ScopedMacroState : public FormatTokenSource { public: ScopedMacroState(UnwrappedLine &Line, FormatTokenSource *&TokenSource, - FormatToken &ResetToken) + FormatToken &ResetToken, bool &StructuralError) : Line(Line), TokenSource(TokenSource), ResetToken(ResetToken), - PreviousLineLevel(Line.Level), PreviousTokenSource(TokenSource) { + PreviousLineLevel(Line.Level), PreviousTokenSource(TokenSource), + StructuralError(StructuralError), + PreviousStructuralError(StructuralError) { TokenSource = this; Line.Level = 0; Line.InPPDirective = true; @@ -58,6 +60,7 @@ public: ResetToken = Token; Line.InPPDirective = false; Line.Level = PreviousLineLevel; + StructuralError = PreviousStructuralError; } virtual FormatToken getNextToken() { @@ -71,7 +74,7 @@ public: } private: - bool eof() { return Token.NewlinesBefore > 0 && Token.HasUnescapedNewline; } + bool eof() { return Token.HasUnescapedNewline; } FormatToken createEOF() { FormatToken FormatTok; @@ -85,6 +88,8 @@ private: FormatToken &ResetToken; unsigned PreviousLineLevel; FormatTokenSource *PreviousTokenSource; + bool &StructuralError; + bool PreviousStructuralError; FormatToken Token; }; @@ -124,13 +129,13 @@ UnwrappedLineParser::UnwrappedLineParser( clang::DiagnosticsEngine &Diag, const FormatStyle &Style, FormatTokenSource &Tokens, UnwrappedLineConsumer &Callback) : Line(new UnwrappedLine), MustBreakBeforeNextToken(false), - CurrentLines(&Lines), Diag(Diag), Style(Style), Tokens(&Tokens), - Callback(Callback) {} + CurrentLines(&Lines), StructuralError(false), Diag(Diag), Style(Style), + Tokens(&Tokens), Callback(Callback) {} bool UnwrappedLineParser::parse() { DEBUG(llvm::dbgs() << "----\n"); readToken(); - bool Error = parseFile(); + parseFile(); for (std::vector<UnwrappedLine>::iterator I = Lines.begin(), E = Lines.end(); I != E; ++I) { Callback.consumeUnwrappedLine(*I); @@ -139,23 +144,20 @@ bool UnwrappedLineParser::parse() { // Create line with eof token. pushToken(FormatTok); Callback.consumeUnwrappedLine(*Line); - - return Error; + return StructuralError; } -bool UnwrappedLineParser::parseFile() { +void UnwrappedLineParser::parseFile() { ScopedDeclarationState DeclarationState( *Line, DeclarationScopeStack, /*MustBeDeclaration=*/ !Line->InPPDirective); - bool Error = parseLevel(/*HasOpeningBrace=*/ false); + parseLevel(/*HasOpeningBrace=*/ false); // Make sure to format the remaining tokens. flushComments(true); addUnwrappedLine(); - return Error; } -bool UnwrappedLineParser::parseLevel(bool HasOpeningBrace) { - bool Error = false; +void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) { do { switch (FormatTok.Tok.getKind()) { case tok::comment: @@ -165,30 +167,27 @@ bool UnwrappedLineParser::parseLevel(bool HasOpeningBrace) { case tok::l_brace: // FIXME: Add parameter whether this can happen - if this happens, we must // be in a non-declaration context. - Error |= parseBlock(/*MustBeDeclaration=*/ false); + parseBlock(/*MustBeDeclaration=*/ false); addUnwrappedLine(); break; case tok::r_brace: - if (HasOpeningBrace) { - return false; - } else { - Diag.Report(FormatTok.Tok.getLocation(), - Diag.getCustomDiagID(clang::DiagnosticsEngine::Error, - "unexpected '}'")); - Error = true; - nextToken(); - addUnwrappedLine(); - } + if (HasOpeningBrace) + return; + Diag.Report(FormatTok.Tok.getLocation(), + Diag.getCustomDiagID(clang::DiagnosticsEngine::Error, + "unexpected '}'")); + StructuralError = true; + nextToken(); + addUnwrappedLine(); break; default: parseStructuralElement(); break; } } while (!eof()); - return Error; } -bool UnwrappedLineParser::parseBlock(bool MustBeDeclaration, +void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, unsigned AddLevels) { assert(FormatTok.Tok.is(tok::l_brace) && "'{' expected"); nextToken(); @@ -202,17 +201,17 @@ bool UnwrappedLineParser::parseBlock(bool MustBeDeclaration, if (!FormatTok.Tok.is(tok::r_brace)) { Line->Level -= AddLevels; - return true; + StructuralError = true; + return; } nextToken(); // Munch the closing brace. Line->Level -= AddLevels; - return false; } void UnwrappedLineParser::parsePPDirective() { assert(FormatTok.Tok.is(tok::hash) && "'#' expected"); - ScopedMacroState MacroState(*Line, Tokens, FormatTok); + ScopedMacroState MacroState(*Line, Tokens, FormatTok, StructuralError); nextToken(); if (FormatTok.Tok.getIdentifierInfo() == NULL) { @@ -260,9 +259,35 @@ void UnwrappedLineParser::parsePPUnknown() { addUnwrappedLine(); } +// Here we blacklist certain tokens that are not usually the first token in an +// unwrapped line. This is used in attempt to distinguish macro calls without +// trailing semicolons from other constructs split to several lines. +bool tokenCanStartNewLine(clang::Token Tok) { + // Semicolon can be a null-statement, l_square can be a start of a macro or + // a C++11 attribute, but this doesn't seem to be common. + return Tok.isNot(tok::semi) && Tok.isNot(tok::l_brace) && + Tok.isNot(tok::l_square) && + // Tokens that can only be used as binary operators and a part of + // overloaded operator names. + Tok.isNot(tok::period) && Tok.isNot(tok::periodstar) && + Tok.isNot(tok::arrow) && Tok.isNot(tok::arrowstar) && + Tok.isNot(tok::less) && Tok.isNot(tok::greater) && + Tok.isNot(tok::slash) && Tok.isNot(tok::percent) && + Tok.isNot(tok::lessless) && Tok.isNot(tok::greatergreater) && + Tok.isNot(tok::equal) && Tok.isNot(tok::plusequal) && + Tok.isNot(tok::minusequal) && Tok.isNot(tok::starequal) && + Tok.isNot(tok::slashequal) && Tok.isNot(tok::percentequal) && + Tok.isNot(tok::ampequal) && Tok.isNot(tok::pipeequal) && + Tok.isNot(tok::caretequal) && Tok.isNot(tok::greatergreaterequal) && + Tok.isNot(tok::lesslessequal) && + // Colon is used in labels, base class lists, initializer lists, + // range-based for loops, ternary operator, but should never be the + // first token in an unwrapped line. + Tok.isNot(tok::colon); +} + void UnwrappedLineParser::parseStructuralElement() { assert(!FormatTok.Tok.is(tok::l_brace)); - int TokenNumber = 0; switch (FormatTok.Tok.getKind()) { case tok::at: nextToken(); @@ -297,7 +322,6 @@ void UnwrappedLineParser::parseStructuralElement() { return; case tok::kw_inline: nextToken(); - TokenNumber++; if (FormatTok.Tok.is(tok::kw_namespace)) { parseNamespace(); return; @@ -347,7 +371,6 @@ void UnwrappedLineParser::parseStructuralElement() { break; } do { - ++TokenNumber; switch (FormatTok.Tok.getKind()) { case tok::at: nextToken(); @@ -384,9 +407,20 @@ void UnwrappedLineParser::parseStructuralElement() { return; case tok::identifier: nextToken(); - if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) { - parseLabel(); - return; + if (Line->Tokens.size() == 1) { + if (FormatTok.Tok.is(tok::colon)) { + parseLabel(); + return; + } + // Recognize function-like macro usages without trailing semicolon. + if (FormatTok.Tok.is(tok::l_paren)) { + parseParens(); + if (FormatTok.HasUnescapedNewline && + tokenCanStartNewLine(FormatTok.Tok)) { + addUnwrappedLine(); + return; + } + } } break; case tok::equal: @@ -405,16 +439,36 @@ void UnwrappedLineParser::parseStructuralElement() { void UnwrappedLineParser::parseBracedList() { nextToken(); + // FIXME: Once we have an expression parser in the UnwrappedLineParser, + // replace this by using parseAssigmentExpression() inside. + bool StartOfExpression = true; do { + // FIXME: When we start to support lambdas, we'll want to parse them away + // here, otherwise our bail-out scenarios below break. The better solution + // might be to just implement a more or less complete expression parser. switch (FormatTok.Tok.getKind()) { case tok::l_brace: + if (!StartOfExpression) { + // Probably a missing closing brace. Bail out. + addUnwrappedLine(); + return; + } parseBracedList(); + StartOfExpression = false; break; case tok::r_brace: nextToken(); return; + case tok::semi: + // Probably a missing closing brace. Bail out. + return; + case tok::comma: + nextToken(); + StartOfExpression = true; + break; default: nextToken(); + StartOfExpression = false; break; } } while (!eof()); @@ -427,6 +481,11 @@ void UnwrappedLineParser::parseReturn() { switch (FormatTok.Tok.getKind()) { case tok::l_brace: parseBracedList(); + if (FormatTok.Tok.isNot(tok::semi)) { + // Assume missing ';'. + addUnwrappedLine(); + return; + } break; case tok::l_paren: parseParens(); @@ -820,8 +879,7 @@ void UnwrappedLineParser::readToken() { do { FormatTok = Tokens->getNextToken(); while (!Line->InPPDirective && FormatTok.Tok.is(tok::hash) && - ((FormatTok.NewlinesBefore > 0 && FormatTok.HasUnescapedNewline) || - FormatTok.IsFirst)) { + (FormatTok.HasUnescapedNewline || FormatTok.IsFirst)) { // If there is an unfinished unwrapped line, we flush the preprocessor // directives only after that unwrapped line was finished later. bool SwitchToPreprocessorLines = diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h index f4fecc5..0c618e2 100644 --- a/lib/Format/UnwrappedLineParser.h +++ b/lib/Format/UnwrappedLineParser.h @@ -34,7 +34,7 @@ struct FormatToken { FormatToken() : NewlinesBefore(0), HasUnescapedNewline(false), WhiteSpaceLength(0), LastNewlineOffset(0), TokenLength(0), IsFirst(false), - MustBreakBefore(false) {} + MustBreakBefore(false), TrailingWhiteSpaceLength(0) {} /// \brief The \c Token. Token Tok; @@ -76,6 +76,18 @@ struct FormatToken { /// This happens for example when a preprocessor directive ended directly /// before the token. bool MustBreakBefore; + + /// \brief Number of characters of trailing whitespace. + unsigned TrailingWhiteSpaceLength; + + /// \brief Returns actual token start location without leading escaped + /// newlines and whitespace. + /// + /// This can be different to Tok.getLocation(), which includes leading escaped + /// newlines. + SourceLocation getStartOfNonWhitespace() const { + return WhiteSpaceStart.getLocWithOffset(WhiteSpaceLength); + } }; /// \brief An unwrapped line is a sequence of \c Token, that we would like to @@ -125,9 +137,9 @@ public: bool parse(); private: - bool parseFile(); - bool parseLevel(bool HasOpeningBrace); - bool parseBlock(bool MustBeDeclaration, unsigned AddLevels = 1); + void parseFile(); + void parseLevel(bool HasOpeningBrace); + void parseBlock(bool MustBeDeclaration, unsigned AddLevels = 1); void parsePPDirective(); void parsePPDefine(); void parsePPUnknown(); @@ -187,6 +199,10 @@ private: // whether we are in a compound statement or not. std::vector<bool> DeclarationScopeStack; + // Will be true if we encounter an error that leads to possibily incorrect + // indentation levels. + bool StructuralError; + clang::DiagnosticsEngine &Diag; const FormatStyle &Style; FormatTokenSource *Tokens; diff --git a/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp new file mode 100644 index 0000000..a75c592 --- /dev/null +++ b/lib/Format/WhitespaceManager.cpp @@ -0,0 +1,211 @@ +//===--- WhitespaceManager.cpp - Format C++ code --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements WhitespaceManager class. +/// +//===----------------------------------------------------------------------===// + +#include "WhitespaceManager.h" +#include "llvm/ADT/STLExtras.h" + +namespace clang { +namespace format { + +void WhitespaceManager::replaceWhitespace(const AnnotatedToken &Tok, + unsigned NewLines, unsigned Spaces, + unsigned WhitespaceStartColumn) { + if (NewLines > 0) + alignEscapedNewlines(); + + // 2+ newlines mean an empty line separating logic scopes. + if (NewLines >= 2) + alignComments(); + + // Align line comments if they are trailing or if they continue other + // trailing comments. + if (Tok.isTrailingComment()) { + SourceLocation TokenEndLoc = Tok.FormatTok.getStartOfNonWhitespace() + .getLocWithOffset(Tok.FormatTok.TokenLength); + // Remove the comment's trailing whitespace. + if (Tok.FormatTok.TrailingWhiteSpaceLength != 0) + Replaces.insert(tooling::Replacement( + SourceMgr, TokenEndLoc, Tok.FormatTok.TrailingWhiteSpaceLength, "")); + + bool LineExceedsColumnLimit = + Spaces + WhitespaceStartColumn + Tok.FormatTok.TokenLength > + Style.ColumnLimit; + // Align comment with other comments. + if ((Tok.Parent != NULL || !Comments.empty()) && + !LineExceedsColumnLimit) { + unsigned MinColumn = + NewLines > 0 ? Spaces : WhitespaceStartColumn + Spaces; + unsigned MaxColumn = Style.ColumnLimit - Tok.FormatTok.TokenLength; + Comments.push_back(StoredToken( + Tok.FormatTok.WhiteSpaceStart, Tok.FormatTok.WhiteSpaceLength, + MinColumn, MaxColumn, NewLines, Spaces)); + return; + } + } + + // If this line does not have a trailing comment, align the stored comments. + if (Tok.Children.empty() && !Tok.isTrailingComment()) + alignComments(); + + storeReplacement(Tok.FormatTok.WhiteSpaceStart, + Tok.FormatTok.WhiteSpaceLength, + getNewLineText(NewLines, Spaces)); +} + +void WhitespaceManager::replacePPWhitespace(const AnnotatedToken &Tok, + unsigned NewLines, unsigned Spaces, + unsigned WhitespaceStartColumn) { + if (NewLines == 0) { + replaceWhitespace(Tok, NewLines, Spaces, WhitespaceStartColumn); + } else { + // The earliest position for "\" is 2 after the last token. + unsigned MinColumn = WhitespaceStartColumn + 2; + unsigned MaxColumn = Style.ColumnLimit; + EscapedNewlines.push_back(StoredToken( + Tok.FormatTok.WhiteSpaceStart, Tok.FormatTok.WhiteSpaceLength, + MinColumn, MaxColumn, NewLines, Spaces)); + } +} + +void WhitespaceManager::breakToken(const FormatToken &Tok, unsigned Offset, + unsigned ReplaceChars, StringRef Prefix, + StringRef Postfix, bool InPPDirective, + unsigned Spaces, + unsigned WhitespaceStartColumn) { + SourceLocation Location = + Tok.getStartOfNonWhitespace().getLocWithOffset(Offset); + if (InPPDirective) { + // The earliest position for "\" is 2 after the last token. + unsigned MinColumn = WhitespaceStartColumn + 2; + unsigned MaxColumn = Style.ColumnLimit; + StoredToken StoredTok = StoredToken(Location, ReplaceChars, MinColumn, + MaxColumn, /*NewLines=*/ 1, Spaces); + StoredTok.Prefix = Prefix; + StoredTok.Postfix = Postfix; + EscapedNewlines.push_back(StoredTok); + } else { + std::string ReplacementText = + (Prefix + getNewLineText(1, Spaces) + Postfix).str(); + Replaces.insert(tooling::Replacement(SourceMgr, Location, ReplaceChars, + ReplacementText)); + } +} + +const tooling::Replacements &WhitespaceManager::generateReplacements() { + alignComments(); + alignEscapedNewlines(); + return Replaces; +} + +void WhitespaceManager::addReplacement(const SourceLocation &SourceLoc, + unsigned ReplaceChars, StringRef Text) { + Replaces.insert( + tooling::Replacement(SourceMgr, SourceLoc, ReplaceChars, Text)); +} + +void WhitespaceManager::addUntouchableComment(unsigned Column) { + StoredToken Tok = StoredToken(SourceLocation(), 0, Column, Column, 0, 0); + Tok.Untouchable = true; + Comments.push_back(Tok); +} + +std::string WhitespaceManager::getNewLineText(unsigned NewLines, + unsigned Spaces) { + return std::string(NewLines, '\n') + std::string(Spaces, ' '); +} + +std::string WhitespaceManager::getNewLineText(unsigned NewLines, + unsigned Spaces, + unsigned WhitespaceStartColumn, + unsigned EscapedNewlineColumn) { + std::string NewLineText; + if (NewLines > 0) { + unsigned Offset = + std::min<int>(EscapedNewlineColumn - 1, WhitespaceStartColumn); + for (unsigned i = 0; i < NewLines; ++i) { + NewLineText += std::string(EscapedNewlineColumn - Offset - 1, ' '); + NewLineText += "\\\n"; + Offset = 0; + } + } + return NewLineText + std::string(Spaces, ' '); +} + +void WhitespaceManager::alignComments() { + unsigned MinColumn = 0; + unsigned MaxColumn = UINT_MAX; + token_iterator Start = Comments.begin(); + for (token_iterator I = Start, E = Comments.end(); I != E; ++I) { + if (I->MinColumn > MaxColumn || I->MaxColumn < MinColumn) { + alignComments(Start, I, MinColumn); + MinColumn = I->MinColumn; + MaxColumn = I->MaxColumn; + Start = I; + } else { + MinColumn = std::max(MinColumn, I->MinColumn); + MaxColumn = std::min(MaxColumn, I->MaxColumn); + } + } + alignComments(Start, Comments.end(), MinColumn); + Comments.clear(); +} + +void WhitespaceManager::alignComments(token_iterator I, token_iterator E, + unsigned Column) { + while (I != E) { + if (!I->Untouchable) { + unsigned Spaces = I->Spaces + Column - I->MinColumn; + storeReplacement(I->ReplacementLoc, I->ReplacementLength, + getNewLineText(I->NewLines, Spaces)); + } + ++I; + } +} + +void WhitespaceManager::alignEscapedNewlines() { + unsigned MinColumn; + if (Style.AlignEscapedNewlinesLeft) { + MinColumn = 0; + for (token_iterator I = EscapedNewlines.begin(), E = EscapedNewlines.end(); + I != E; ++I) { + if (I->MinColumn > MinColumn) + MinColumn = I->MinColumn; + } + } else { + MinColumn = Style.ColumnLimit; + } + + for (token_iterator I = EscapedNewlines.begin(), E = EscapedNewlines.end(); + I != E; ++I) { + // I->MinColumn - 2 is the end of the previous token (i.e. the + // WhitespaceStartColumn). + storeReplacement( + I->ReplacementLoc, I->ReplacementLength, + I->Prefix + getNewLineText(I->NewLines, I->Spaces, I->MinColumn - 2, + MinColumn) + I->Postfix); + + } + EscapedNewlines.clear(); +} + +void WhitespaceManager::storeReplacement(SourceLocation Loc, unsigned Length, + const std::string Text) { + // Don't create a replacement, if it does not change anything. + if (StringRef(SourceMgr.getCharacterData(Loc), Length) == Text) + return; + Replaces.insert(tooling::Replacement(SourceMgr, Loc, Length, Text)); +} + +} // namespace format +} // namespace clang diff --git a/lib/Format/WhitespaceManager.h b/lib/Format/WhitespaceManager.h new file mode 100644 index 0000000..5f3dc55 --- /dev/null +++ b/lib/Format/WhitespaceManager.h @@ -0,0 +1,119 @@ +//===--- WhitespaceManager.h - Format C++ code ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief WhitespaceManager class manages whitespace around tokens and their +/// replacements. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FORMAT_WHITESPACEMANAGER_H +#define LLVM_CLANG_FORMAT_WHITESPACEMANAGER_H + +#include "TokenAnnotator.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Format/Format.h" +#include <string> + +namespace clang { +namespace format { + +/// \brief Manages the whitespaces around tokens and their replacements. +/// +/// This includes special handling for certain constructs, e.g. the alignment of +/// trailing line comments. +class WhitespaceManager { +public: + WhitespaceManager(SourceManager &SourceMgr, const FormatStyle &Style) + : SourceMgr(SourceMgr), Style(Style) {} + + /// \brief Replaces the whitespace in front of \p Tok. Only call once for + /// each \c AnnotatedToken. + void replaceWhitespace(const AnnotatedToken &Tok, unsigned NewLines, + unsigned Spaces, unsigned WhitespaceStartColumn); + + /// \brief Like \c replaceWhitespace, but additionally adds right-aligned + /// backslashes to escape newlines inside a preprocessor directive. + /// + /// This function and \c replaceWhitespace have the same behavior if + /// \c Newlines == 0. + void replacePPWhitespace(const AnnotatedToken &Tok, unsigned NewLines, + unsigned Spaces, unsigned WhitespaceStartColumn); + + /// \brief Inserts a line break into the middle of a token. + /// + /// Will break at \p Offset inside \p Tok, putting \p Prefix before the line + /// break and \p Postfix before the rest of the token starts in the next line. + /// + /// \p InPPDirective, \p Spaces, \p WhitespaceStartColumn and \p Style are + /// used to generate the correct line break. + void breakToken(const FormatToken &Tok, unsigned Offset, + unsigned ReplaceChars, StringRef Prefix, StringRef Postfix, + bool InPPDirective, unsigned Spaces, + unsigned WhitespaceStartColumn); + + /// \brief Returns all the \c Replacements created during formatting. + const tooling::Replacements &generateReplacements(); + + void addReplacement(const SourceLocation &SourceLoc, unsigned ReplaceChars, + StringRef Text); + + void addUntouchableComment(unsigned Column); + + /// \brief Try to align all stashed comments. + void alignComments(); + /// \brief Try to align all stashed escaped newlines. + void alignEscapedNewlines(); + +private: + std::string getNewLineText(unsigned NewLines, unsigned Spaces); + + std::string getNewLineText(unsigned NewLines, unsigned Spaces, + unsigned WhitespaceStartColumn, + unsigned EscapedNewlineColumn); + + /// \brief Structure to store tokens for later layout and alignment. + struct StoredToken { + StoredToken(SourceLocation ReplacementLoc, unsigned ReplacementLength, + unsigned MinColumn, unsigned MaxColumn, unsigned NewLines, + unsigned Spaces) + : ReplacementLoc(ReplacementLoc), ReplacementLength(ReplacementLength), + MinColumn(MinColumn), MaxColumn(MaxColumn), NewLines(NewLines), + Spaces(Spaces), Untouchable(false) {} + SourceLocation ReplacementLoc; + unsigned ReplacementLength; + unsigned MinColumn; + unsigned MaxColumn; + unsigned NewLines; + unsigned Spaces; + bool Untouchable; + std::string Prefix; + std::string Postfix; + }; + SmallVector<StoredToken, 16> Comments; + SmallVector<StoredToken, 16> EscapedNewlines; + typedef SmallVector<StoredToken, 16>::iterator token_iterator; + + /// \brief Put all the comments between \p I and \p E into \p Column. + void alignComments(token_iterator I, token_iterator E, unsigned Column); + + /// \brief Stores \p Text as the replacement for the whitespace in front of + /// \p Tok. + void storeReplacement(SourceLocation Loc, unsigned Length, + const std::string Text); + + SourceManager &SourceMgr; + tooling::Replacements Replaces; + const FormatStyle &Style; +}; + +} // namespace format +} // namespace clang + +#endif // LLVM_CLANG_FORMAT_WHITESPACEMANAGER_H diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp index bfb3083..b6c644e 100644 --- a/lib/Frontend/ASTMerge.cpp +++ b/lib/Frontend/ASTMerge.cpp @@ -34,7 +34,7 @@ bool ASTMergeAction::BeginSourceFileAction(CompilerInstance &CI, void ASTMergeAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); CI.getDiagnostics().getClient()->BeginSourceFile( - CI.getASTContext().getLangOpts()); + CI.getASTContext().getLangOpts()); CI.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument, &CI.getASTContext()); IntrusiveRefCntPtr<DiagnosticIDs> @@ -42,8 +42,9 @@ void ASTMergeAction::ExecuteAction() { for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) { IntrusiveRefCntPtr<DiagnosticsEngine> Diags(new DiagnosticsEngine(DiagIDs, &CI.getDiagnosticOpts(), - CI.getDiagnostics().getClient(), - /*ShouldOwnClient=*/false)); + new ForwardingDiagnosticConsumer( + *CI.getDiagnostics().getClient()), + /*ShouldOwnClient=*/true)); ASTUnit *Unit = ASTUnit::LoadFromASTFile(ASTFiles[I], Diags, CI.getFileSystemOpts(), false); if (!Unit) diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index c1115ae..8bd5172 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -236,6 +236,11 @@ ASTUnit::ASTUnit(bool _MainFileIsAST) } ASTUnit::~ASTUnit() { + // If we loaded from an AST file, balance out the BeginSourceFile call. + if (MainFileIsAST && getDiagnostics().getClient()) { + getDiagnostics().getClient()->EndSourceFile(); + } + clearFileLevelDecls(); // Clean up the temporary files and the preamble file. @@ -581,25 +586,24 @@ private: } }; + /// \brief Diagnostic consumer that saves each diagnostic it is given. class StoredDiagnosticConsumer : public DiagnosticConsumer { SmallVectorImpl<StoredDiagnostic> &StoredDiags; - + SourceManager *SourceMgr; + public: explicit StoredDiagnosticConsumer( SmallVectorImpl<StoredDiagnostic> &StoredDiags) - : StoredDiags(StoredDiags) { } - + : StoredDiags(StoredDiags), SourceMgr(0) { } + + virtual void BeginSourceFile(const LangOptions &LangOpts, + const Preprocessor *PP = 0) { + if (PP) + SourceMgr = &PP->getSourceManager(); + } + virtual void HandleDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info); - - DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { - // Just drop any diagnostics that come from cloned consumers; they'll - // have different source managers anyway. - // FIXME: We'd like to be able to capture these somehow, even if it's just - // file/line/column, because they could occur when parsing module maps or - // building modules on-demand. - return new IgnoringDiagConsumer(); - } }; /// \brief RAII object that optionally captures diagnostics, if @@ -635,7 +639,11 @@ void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level, // Default implementation (Warnings/errors count). DiagnosticConsumer::HandleDiagnostic(Level, Info); - StoredDiags.push_back(StoredDiagnostic(Level, Info)); + // Only record the diagnostic if it's part of the source manager we know + // about. This effectively drops diagnostics from modules we're building. + // FIXME: In the long run, ee don't want to drop source managers from modules. + if (!Info.hasSourceManager() || &Info.getSourceManager() == SourceMgr) + StoredDiags.push_back(StoredDiagnostic(Level, Info)); } ASTDeserializationListener *ASTUnit::getDeserializationListener() { @@ -662,8 +670,7 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> &Diags, Client = new StoredDiagnosticConsumer(AST.StoredDiagnostics); Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions(), Client, - /*ShouldOwnClient=*/true, - /*ShouldCloneClient=*/false); + /*ShouldOwnClient=*/true); } else if (CaptureDiagnostics) { Diags->setClient(new StoredDiagnosticConsumer(AST.StoredDiagnostics)); } @@ -835,6 +842,9 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, ReaderPtr->InitializeSema(*AST->TheSema); AST->Reader = ReaderPtr; + // Tell the diagnostic client that we have started a source file. + AST->getDiagnostics().getClient()->BeginSourceFile(Context.getLangOpts(),&PP); + return AST.take(); } @@ -1027,16 +1037,17 @@ public: } -static void checkAndRemoveNonDriverDiags(SmallVectorImpl<StoredDiagnostic> & - StoredDiagnostics) { +static bool isNonDriverDiag(const StoredDiagnostic &StoredDiag) { + return StoredDiag.getLocation().isValid(); +} + +static void +checkAndRemoveNonDriverDiags(SmallVectorImpl<StoredDiagnostic> &StoredDiags) { // Get rid of stored diagnostics except the ones from the driver which do not // have a source location. - for (unsigned I = 0; I < StoredDiagnostics.size(); ++I) { - if (StoredDiagnostics[I].getLocation().isValid()) { - StoredDiagnostics.erase(StoredDiagnostics.begin()+I); - --I; - } - } + StoredDiags.erase( + std::remove_if(StoredDiags.begin(), StoredDiags.end(), isNonDriverDiag), + StoredDiags.end()); } static void checkAndSanitizeDiags(SmallVectorImpl<StoredDiagnostic> & diff --git a/lib/Frontend/ChainedIncludesSource.cpp b/lib/Frontend/ChainedIncludesSource.cpp index a17def0..cde84ca 100644 --- a/lib/Frontend/ChainedIncludesSource.cpp +++ b/lib/Frontend/ChainedIncludesSource.cpp @@ -143,6 +143,7 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) { Clang->getASTConsumer().GetASTDeserializationListener())); if (!Reader) return 0; + Clang->setModuleManager(static_cast<ASTReader*>(Reader.get())); Clang->getASTContext().setExternalSource(Reader); } diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index df06a81..cf856fc 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -155,18 +155,15 @@ static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts, } void CompilerInstance::createDiagnostics(DiagnosticConsumer *Client, - bool ShouldOwnClient, - bool ShouldCloneClient) { + bool ShouldOwnClient) { Diagnostics = createDiagnostics(&getDiagnosticOpts(), Client, - ShouldOwnClient, ShouldCloneClient, - &getCodeGenOpts()); + ShouldOwnClient, &getCodeGenOpts()); } IntrusiveRefCntPtr<DiagnosticsEngine> CompilerInstance::createDiagnostics(DiagnosticOptions *Opts, DiagnosticConsumer *Client, bool ShouldOwnClient, - bool ShouldCloneClient, const CodeGenOptions *CodeGenOpts) { IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); IntrusiveRefCntPtr<DiagnosticsEngine> @@ -175,10 +172,7 @@ CompilerInstance::createDiagnostics(DiagnosticOptions *Opts, // Create the diagnostic client for reporting errors or for // implementing -verify. if (Client) { - if (ShouldCloneClient) - Diags->setClient(Client->clone(*Diags), ShouldOwnClient); - else - Diags->setClient(Client, ShouldOwnClient); + Diags->setClient(Client, ShouldOwnClient); } else Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts)); @@ -868,9 +862,10 @@ static void compileModule(CompilerInstance &ImportingInstance, // module. CompilerInstance Instance; Instance.setInvocation(&*Invocation); - Instance.createDiagnostics(&ImportingInstance.getDiagnosticClient(), - /*ShouldOwnClient=*/true, - /*ShouldCloneClient=*/true); + + Instance.createDiagnostics(new ForwardingDiagnosticConsumer( + ImportingInstance.getDiagnosticClient()), + /*ShouldOwnClient=*/true); // Note that this module is part of the module build stack, so that we // can detect cycles in the module graph. @@ -892,6 +887,7 @@ static void compileModule(CompilerInstance &ImportingInstance, llvm::CrashRecoveryContext CRC; CompileModuleMapData Data = { Instance, CreateModuleAction }; CRC.RunSafelyOnThread(&doCompileMapModule, &Data, ThreadStackSize); + // Delete the temporary module map file. // FIXME: Even though we're executing under crash protection, it would still diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 41f9417..42ea96f 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -29,6 +29,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Host.h" #include "llvm/Support/Path.h" +#include "llvm/Support/system_error.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -68,6 +69,9 @@ static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, if (A->getOption().matches(options::OPT_O0)) return 0; + if (A->getOption().matches(options::OPT_Ofast)) + return 3; + assert (A->getOption().matches(options::OPT_O)); StringRef S(A->getValue()); @@ -80,8 +84,7 @@ static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, return DefaultOpt; } -static unsigned getOptimizationLevelSize(ArgList &Args, InputKind IK, - DiagnosticsEngine &Diags) { +static unsigned getOptimizationLevelSize(ArgList &Args) { if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { if (A->getOption().matches(options::OPT_O)) { switch (A->getValue()[0]) { @@ -281,6 +284,7 @@ static bool ParseMigratorArgs(MigratorOptions &Opts, ArgList &Args) { static void ParseCommentArgs(CommentOptions &Opts, ArgList &Args) { Opts.BlockCommandNames = Args.getAllArgValues(OPT_fcomment_block_commands); + Opts.ParseAllComments = Args.hasArg(OPT_fparse_all_comments); } static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, @@ -317,7 +321,6 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info); Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file); - Opts.ModulesAutolink = Args.hasArg(OPT_fmodules_autolink); Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns); Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone); Opts.ForbidGuardVariables = Args.hasArg(OPT_fforbid_guard_variables); @@ -329,12 +332,13 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants); Opts.NoCommon = Args.hasArg(OPT_fno_common); Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float); - Opts.OptimizeSize = getOptimizationLevelSize(Args, IK, Diags); + Opts.OptimizeSize = getOptimizationLevelSize(Args); Opts.SimplifyLibCalls = !(Args.hasArg(OPT_fno_builtin) || Args.hasArg(OPT_ffreestanding)); Opts.UnrollLoops = Args.hasArg(OPT_funroll_loops) || (Opts.OptimizationLevel > 1 && !Opts.OptimizeSize); + Opts.Autolink = !Args.hasArg(OPT_fno_autolink); Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose); Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions); Opts.CUDAIsDevice = Args.hasArg(OPT_fcuda_is_device); @@ -564,7 +568,6 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Opts.VerifyDiagnostics = Args.hasArg(OPT_verify); Opts.ElideType = !Args.hasArg(OPT_fno_elide_type); Opts.ShowTemplateTree = Args.hasArg(OPT_fdiagnostics_show_template_tree); - Opts.WarnOnSpellCheck = Args.hasArg(OPT_fwarn_on_spellcheck); Opts.ErrorLimit = Args.getLastArgIntValue(OPT_ferror_limit, 0, Diags); Opts.MacroBacktraceLimit = Args.getLastArgIntValue(OPT_fmacro_backtrace_limit, @@ -1244,7 +1247,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.AccessControl = !Args.hasArg(OPT_fno_access_control); Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors); Opts.MathErrno = Args.hasArg(OPT_fmath_errno); - Opts.InstantiationDepth = Args.getLastArgIntValue(OPT_ftemplate_depth, 512, + Opts.InstantiationDepth = Args.getLastArgIntValue(OPT_ftemplate_depth, 256, Diags); Opts.ConstexprCallDepth = Args.getLastArgIntValue(OPT_fconstexpr_depth, 512, Diags); @@ -1292,7 +1295,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, // FIXME: Eliminate this dependency. unsigned Opt = getOptimizationLevel(Args, IK, Diags), - OptSize = getOptimizationLevelSize(Args, IK, Diags); + OptSize = getOptimizationLevelSize(Args); Opts.Optimize = Opt != 0; Opts.OptimizeSize = OptSize != 0; @@ -1684,5 +1687,21 @@ std::string CompilerInvocation::getModuleHash() const { hsOpts.UseStandardCXXIncludes, hsOpts.UseLibcxx); + // Darwin-specific hack: if we have a sysroot, use the contents of + // $sysroot/System/Library/CoreServices/SystemVersion.plist + // as part of the module hash. + if (!hsOpts.Sysroot.empty()) { + llvm::OwningPtr<llvm::MemoryBuffer> buffer; + SmallString<128> systemVersionFile; + systemVersionFile += hsOpts.Sysroot; + llvm::sys::path::append(systemVersionFile, "System"); + llvm::sys::path::append(systemVersionFile, "Library"); + llvm::sys::path::append(systemVersionFile, "CoreServices"); + llvm::sys::path::append(systemVersionFile, "SystemVersion.plist"); + if (!llvm::MemoryBuffer::getFile(systemVersionFile, buffer)) { + code = hash_combine(code, buffer.get()->getBuffer()); + } + } + return llvm::APInt(64, code).toString(36, /*Signed=*/false); } diff --git a/lib/Frontend/DiagnosticRenderer.cpp b/lib/Frontend/DiagnosticRenderer.cpp index 3b4f55c..4eee595 100644 --- a/lib/Frontend/DiagnosticRenderer.cpp +++ b/lib/Frontend/DiagnosticRenderer.cpp @@ -462,9 +462,8 @@ void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc, Message << "expanded from here"; else Message << "expanded from macro '" << MacroName << "'"; - emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note, - Message.str(), - SpellingRanges, ArrayRef<FixItHint>(), &SM); + emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note, Message.str(), + SpellingRanges, None, &SM); } DiagnosticNoteRenderer::~DiagnosticNoteRenderer() {} diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index 6031ad2..ece51a3 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -294,6 +294,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, source.reset(ChainedIncludesSource::create(CI)); if (!source) goto failure; + CI.setModuleManager(static_cast<ASTReader*>( + &static_cast<ChainedIncludesSource*>(source.get())->getFinalReader())); CI.getASTContext().setExternalSource(source); } else if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index 35eec56..f4ca4d49 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -24,6 +24,7 @@ #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" @@ -410,16 +411,16 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp #endif break; case llvm::Triple::DragonFly: - AddPath("/usr/include/c++/4.1", CXXSystem, false); + if (llvm::sys::fs::exists("/usr/lib/gcc47")) + AddPath("/usr/include/c++/4.7", CXXSystem, false); + else + AddPath("/usr/include/c++/4.4", CXXSystem, false); break; case llvm::Triple::FreeBSD: // FreeBSD 8.0 // FreeBSD 7.3 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2", "", "", "", triple); break; - case llvm::Triple::NetBSD: - AddGnuCPlusPlusIncludePaths("/usr/include/g++", "", "", "", triple); - break; case llvm::Triple::OpenBSD: { std::string t = triple.getTriple(); if (t.substr(0, 6) == "x86_64") diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 25cfac6..dc3ab53 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -302,12 +302,13 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, else if (!LangOpts.GNUMode && LangOpts.Digraphs) Builder.defineMacro("__STDC_VERSION__", "199409L"); } else { - // FIXME: LangOpts.CPlusPlus1y - + // FIXME: Use the right value for __cplusplus for C++1y once one is chosen. + if (LangOpts.CPlusPlus1y) + Builder.defineMacro("__cplusplus", "201305L"); // C++11 [cpp.predefined]p1: // The name __cplusplus is defined to the value 201103L when compiling a // C++ translation unit. - if (LangOpts.CPlusPlus11) + else if (LangOpts.CPlusPlus11) Builder.defineMacro("__cplusplus", "201103L"); // C++03 [cpp.predefined]p1: // The name __cplusplus is defined to the value 199711L when compiling a diff --git a/lib/Frontend/LogDiagnosticPrinter.cpp b/lib/Frontend/LogDiagnosticPrinter.cpp index 0a22481..2189b86 100644 --- a/lib/Frontend/LogDiagnosticPrinter.cpp +++ b/lib/Frontend/LogDiagnosticPrinter.cpp @@ -171,8 +171,3 @@ void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, Entries.push_back(DE); } -DiagnosticConsumer * -LogDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const { - return new LogDiagnosticPrinter(OS, &*DiagOpts, /*OwnsOutputStream=*/false); -} - diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index f70bd7c..9fd3649 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -127,10 +127,22 @@ public: virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, SrcMgr::CharacteristicKind FileType, FileID PrevFID); + virtual void InclusionDirective(SourceLocation HashLoc, + const Token &IncludeTok, + StringRef FileName, + bool IsAngled, + CharSourceRange FilenameRange, + const FileEntry *File, + StringRef SearchPath, + StringRef RelativePath, + const Module *Imported); virtual void Ident(SourceLocation Loc, const std::string &str); + virtual void PragmaCaptured(SourceLocation Loc, StringRef Str); virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, const std::string &Str); - virtual void PragmaMessage(SourceLocation Loc, StringRef Str); + virtual void PragmaMessage(SourceLocation Loc, StringRef Namespace, + PragmaMessageKind Kind, StringRef Str); + virtual void PragmaDebug(SourceLocation Loc, StringRef DebugType); virtual void PragmaDiagnosticPush(SourceLocation Loc, StringRef Namespace); virtual void PragmaDiagnosticPop(SourceLocation Loc, @@ -258,11 +270,12 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc, if (IncludeLoc.isValid()) MoveToLine(IncludeLoc); } else if (Reason == PPCallbacks::SystemHeaderPragma) { - MoveToLine(NewLine); - - // TODO GCC emits the # directive for this directive on the line AFTER the - // directive and emits a bunch of spaces that aren't needed. Emulate this - // strange behavior. + // GCC emits the # directive for this directive on the line AFTER the + // directive and emits a bunch of spaces that aren't needed. This is because + // otherwise we will emit a line marker for THIS line, which requires an + // extra blank line after the directive to avoid making all following lines + // off by one. We can do better by simply incrementing NewLine here. + NewLine += 1; } CurLine = NewLine; @@ -305,6 +318,27 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc, } } +void PrintPPOutputPPCallbacks::InclusionDirective(SourceLocation HashLoc, + const Token &IncludeTok, + StringRef FileName, + bool IsAngled, + CharSourceRange FilenameRange, + const FileEntry *File, + StringRef SearchPath, + StringRef RelativePath, + const Module *Imported) { + // When preprocessing, turn implicit imports into @imports. + // FIXME: This is a stop-gap until a more comprehensive "preprocessing with + // modules" solution is introduced. + if (Imported) { + startNewLineIfNeeded(); + MoveToLine(HashLoc); + OS << "@import " << Imported->getFullModuleName() << ";" + << " /* clang -E: implicit import for \"" << File->getName() << "\" */"; + EmittedTokensOnThisLine = true; + } +} + /// Ident - Handle #ident directives when read by the preprocessor. /// void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, const std::string &S) { @@ -315,6 +349,15 @@ void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, const std::string &S) { EmittedTokensOnThisLine = true; } +void PrintPPOutputPPCallbacks::PragmaCaptured(SourceLocation Loc, + StringRef Str) { + startNewLineIfNeeded(); + MoveToLine(Loc); + OS << "#pragma captured"; + + setEmittedDirectiveOnThisLine(); +} + /// MacroDefined - This hook is called whenever a macro definition is seen. void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok, const MacroDirective *MD) { @@ -367,12 +410,25 @@ void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc, } void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc, + StringRef Namespace, + PragmaMessageKind Kind, StringRef Str) { startNewLineIfNeeded(); MoveToLine(Loc); - OS << "#pragma message("; - - OS << '"'; + OS << "#pragma "; + if (!Namespace.empty()) + OS << Namespace << ' '; + switch (Kind) { + case PMK_Message: + OS << "message(\""; + break; + case PMK_Warning: + OS << "warning \""; + break; + case PMK_Error: + OS << "error \""; + break; + } for (unsigned i = 0, e = Str.size(); i != e; ++i) { unsigned char Char = Str[i]; @@ -385,8 +441,19 @@ void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc, << (char)('0'+ ((Char >> 0) & 7)); } OS << '"'; + if (Kind == PMK_Message) + OS << ')'; + setEmittedDirectiveOnThisLine(); +} + +void PrintPPOutputPPCallbacks::PragmaDebug(SourceLocation Loc, + StringRef DebugType) { + startNewLineIfNeeded(); + MoveToLine(Loc); + + OS << "#pragma clang __debug "; + OS << DebugType; - OS << ')'; setEmittedDirectiveOnThisLine(); } diff --git a/lib/Frontend/SerializedDiagnosticPrinter.cpp b/lib/Frontend/SerializedDiagnosticPrinter.cpp index 4bb662b..6514321 100644 --- a/lib/Frontend/SerializedDiagnosticPrinter.cpp +++ b/lib/Frontend/SerializedDiagnosticPrinter.cpp @@ -114,10 +114,6 @@ public: virtual void finish(); - DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { - return new SDiagsWriter(State); - } - private: /// \brief Emit the preamble for the serialized diagnostics. void EmitPreamble(); diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp index ca4ad60..1572d0f 100644 --- a/lib/Frontend/TextDiagnostic.cpp +++ b/lib/Frontend/TextDiagnostic.cpp @@ -1095,7 +1095,7 @@ void TextDiagnostic::emitSnippetAndCaret( unsigned ColNo = SM.getColumnNumber(FID, FileOffset); // Arbitrarily stop showing snippets when the line is too long. - static const ptrdiff_t MaxLineLengthToPrint = 4096; + static const size_t MaxLineLengthToPrint = 4096; if (ColNo > MaxLineLengthToPrint) return; @@ -1110,7 +1110,7 @@ void TextDiagnostic::emitSnippetAndCaret( ++LineEnd; // Arbitrarily stop showing snippets when the line is too long. - if (LineEnd - LineStart > MaxLineLengthToPrint) + if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint) return; // Copy the line of code into an std::string for ease of manipulation. diff --git a/lib/Frontend/TextDiagnosticBuffer.cpp b/lib/Frontend/TextDiagnosticBuffer.cpp index 039475a..5821436 100644 --- a/lib/Frontend/TextDiagnosticBuffer.cpp +++ b/lib/Frontend/TextDiagnosticBuffer.cpp @@ -75,6 +75,3 @@ void TextDiagnosticBuffer::FlushDiagnostics(DiagnosticsEngine &Diags) const { escapeDiag(it->second, Buf))); } -DiagnosticConsumer *TextDiagnosticBuffer::clone(DiagnosticsEngine &) const { - return new TextDiagnosticBuffer(); -} diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 010f649..c22798a 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -155,8 +155,3 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, OS.flush(); } - -DiagnosticConsumer * -TextDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const { - return new TextDiagnosticPrinter(OS, &*DiagOpts, /*OwnsOutputStream=*/false); -} diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp index 82f6e91..46745b6 100644 --- a/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -111,8 +111,13 @@ void VerifyDiagnosticConsumer::EndSourceFile() { void VerifyDiagnosticConsumer::HandleDiagnostic( DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) { - if (Info.hasSourceManager()) + if (Info.hasSourceManager()) { + // If this diagnostic is for a different source manager, ignore it. + if (SrcManager && &Info.getSourceManager() != SrcManager) + return; + setSourceManager(Info.getSourceManager()); + } #ifndef NDEBUG // Debug build tracks unparsed files for possible @@ -278,8 +283,10 @@ private: /// /// Returns true if any valid directives were found. static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, - SourceLocation Pos, DiagnosticsEngine &Diags, + Preprocessor *PP, SourceLocation Pos, VerifyDiagnosticConsumer::DirectiveStatus &Status) { + DiagnosticsEngine &Diags = PP ? PP->getDiagnostics() : SM.getDiagnostics(); + // A single comment may contain multiple directives. bool FoundDirective = false; for (ParseHelper PH(S); !PH.Done();) { @@ -353,10 +360,30 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, else ExpectedLine -= Line; ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), ExpectedLine, 1); } - } else { + } else if (PH.Next(Line)) { // Absolute line number. - if (PH.Next(Line) && Line > 0) + if (Line > 0) ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), Line, 1); + } else if (PP && PH.Search(":")) { + // Specific source file. + StringRef Filename(PH.C, PH.P-PH.C); + PH.Advance(); + + // Lookup file via Preprocessor, like a #include. + const DirectoryLookup *CurDir; + const FileEntry *FE = PP->LookupFile(Filename, false, NULL, CurDir, + NULL, NULL, 0); + if (!FE) { + Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin), + diag::err_verify_missing_file) << Filename << KindStr; + continue; + } + + if (SM.translateFile(FE).isInvalid()) + SM.createFileID(FE, Pos, SrcMgr::C_User); + + if (PH.Next(Line) && Line > 0) + ExpectedLoc = SM.translateFileLineCol(FE, Line, 1); } if (ExpectedLoc.isInvalid()) { @@ -454,6 +481,11 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP, SourceRange Comment) { SourceManager &SM = PP.getSourceManager(); + + // If this comment is for a different source manager, ignore it. + if (SrcManager && &SM != SrcManager) + return false; + SourceLocation CommentBegin = Comment.getBegin(); const char *CommentRaw = SM.getCharacterData(CommentBegin); @@ -465,7 +497,7 @@ bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP, // Fold any "\<EOL>" sequences size_t loc = C.find('\\'); if (loc == StringRef::npos) { - ParseDirective(C, &ED, SM, CommentBegin, PP.getDiagnostics(), Status); + ParseDirective(C, &ED, SM, &PP, CommentBegin, Status); return false; } @@ -495,7 +527,7 @@ bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP, } if (!C2.empty()) - ParseDirective(C2, &ED, SM, CommentBegin, PP.getDiagnostics(), Status); + ParseDirective(C2, &ED, SM, &PP, CommentBegin, Status); return false; } @@ -530,8 +562,7 @@ static bool findDirectives(SourceManager &SM, FileID FID, if (Comment.empty()) continue; // Find first directive. - if (ParseDirective(Comment, 0, SM, Tok.getLocation(), - SM.getDiagnostics(), Status)) + if (ParseDirective(Comment, 0, SM, 0, Tok.getLocation(), Status)) return true; } return false; @@ -551,8 +582,13 @@ static unsigned PrintUnexpected(DiagnosticsEngine &Diags, SourceManager *SourceM for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) { if (I->first.isInvalid() || !SourceMgr) OS << "\n (frontend)"; - else - OS << "\n Line " << SourceMgr->getPresumedLineNumber(I->first); + else { + OS << "\n "; + if (const FileEntry *File = SourceMgr->getFileEntryForID( + SourceMgr->getFileID(I->first))) + OS << " File " << File->getName(); + OS << " Line " << SourceMgr->getPresumedLineNumber(I->first); + } OS << ": " << I->second; } @@ -572,11 +608,12 @@ static unsigned PrintExpected(DiagnosticsEngine &Diags, SourceManager &SourceMgr llvm::raw_svector_ostream OS(Fmt); for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) { Directive &D = **I; - OS << "\n Line " << SourceMgr.getPresumedLineNumber(D.DiagnosticLoc); + OS << "\n File " << SourceMgr.getFilename(D.DiagnosticLoc) + << " Line " << SourceMgr.getPresumedLineNumber(D.DiagnosticLoc); if (D.DirectiveLoc != D.DiagnosticLoc) OS << " (directive at " - << SourceMgr.getFilename(D.DirectiveLoc) << ":" - << SourceMgr.getPresumedLineNumber(D.DirectiveLoc) << ")"; + << SourceMgr.getFilename(D.DirectiveLoc) << ':' + << SourceMgr.getPresumedLineNumber(D.DirectiveLoc) << ')'; OS << ": " << D.Text; } @@ -585,6 +622,22 @@ static unsigned PrintExpected(DiagnosticsEngine &Diags, SourceManager &SourceMgr return DL.size(); } +/// \brief Determine whether two source locations come from the same file. +static bool IsFromSameFile(SourceManager &SM, SourceLocation DirectiveLoc, + SourceLocation DiagnosticLoc) { + while (DiagnosticLoc.isMacroID()) + DiagnosticLoc = SM.getImmediateMacroCallerLoc(DiagnosticLoc); + + if (SM.isFromSameFile(DirectiveLoc, DiagnosticLoc)) + return true; + + const FileEntry *DiagFile = SM.getFileEntryForID(SM.getFileID(DiagnosticLoc)); + if (!DiagFile && SM.isFromMainFile(DirectiveLoc)) + return true; + + return (DiagFile == SM.getFileEntryForID(SM.getFileID(DirectiveLoc))); +} + /// CheckLists - Compare expected to seen diagnostic lists and return the /// the difference between them. /// @@ -607,6 +660,9 @@ static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr, if (LineNo1 != LineNo2) continue; + if (!IsFromSameFile(SourceMgr, D.DiagnosticLoc, II->first)) + continue; + const std::string &RightText = II->second; if (D.match(RightText)) break; @@ -764,14 +820,6 @@ void VerifyDiagnosticConsumer::CheckDiagnostics() { ED.Notes.clear(); } -DiagnosticConsumer * -VerifyDiagnosticConsumer::clone(DiagnosticsEngine &Diags) const { - if (!Diags.getClient()) - Diags.setClient(PrimaryClient->clone(Diags)); - - return new VerifyDiagnosticConsumer(Diags); -} - Directive *Directive::create(bool RegexKind, SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, StringRef Text, unsigned Min, unsigned Max) { diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp index b7547b9..767096a 100644 --- a/lib/Frontend/Warnings.cpp +++ b/lib/Frontend/Warnings.cpp @@ -56,7 +56,6 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags, Diags.setElideType(Opts.ElideType); Diags.setPrintTemplateTree(Opts.ShowTemplateTree); - Diags.setWarnOnSpellCheck(Opts.WarnOnSpellCheck); Diags.setShowColors(Opts.ShowColors); // Handle -ferror-limit diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt index 5e727a7..8be33b7 100644 --- a/lib/Headers/CMakeLists.txt +++ b/lib/Headers/CMakeLists.txt @@ -98,6 +98,7 @@ set_target_properties(clang-headers PROPERTIES FOLDER "Misc") if (other_output_dir) if(UNIX) add_custom_command(TARGET clang-headers POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory "${LLVM_BINARY_DIR}/lib/${CMAKE_CFG_INTDIR}" COMMAND ${CMAKE_COMMAND} -E create_symlink "${LLVM_BINARY_DIR}/bin/lib/clang" "${LLVM_BINARY_DIR}/lib/${CMAKE_CFG_INTDIR}/clang") endif() endif () diff --git a/lib/Headers/avxintrin.h b/lib/Headers/avxintrin.h index 412d284..0683a65 100644 --- a/lib/Headers/avxintrin.h +++ b/lib/Headers/avxintrin.h @@ -1078,78 +1078,78 @@ _mm256_setzero_si256(void) /* Cast between vector types */ static __inline __m256 __attribute__((__always_inline__, __nodebug__)) -_mm256_castpd_ps(__m256d __in) +_mm256_castpd_ps(__m256d __a) { - return (__m256)__in; + return (__m256)__a; } static __inline __m256i __attribute__((__always_inline__, __nodebug__)) -_mm256_castpd_si256(__m256d __in) +_mm256_castpd_si256(__m256d __a) { - return (__m256i)__in; + return (__m256i)__a; } static __inline __m256d __attribute__((__always_inline__, __nodebug__)) -_mm256_castps_pd(__m256 __in) +_mm256_castps_pd(__m256 __a) { - return (__m256d)__in; + return (__m256d)__a; } static __inline __m256i __attribute__((__always_inline__, __nodebug__)) -_mm256_castps_si256(__m256 __in) +_mm256_castps_si256(__m256 __a) { - return (__m256i)__in; + return (__m256i)__a; } static __inline __m256 __attribute__((__always_inline__, __nodebug__)) -_mm256_castsi256_ps(__m256i __in) +_mm256_castsi256_ps(__m256i __a) { - return (__m256)__in; + return (__m256)__a; } static __inline __m256d __attribute__((__always_inline__, __nodebug__)) -_mm256_castsi256_pd(__m256i __in) +_mm256_castsi256_pd(__m256i __a) { - return (__m256d)__in; + return (__m256d)__a; } static __inline __m128d __attribute__((__always_inline__, __nodebug__)) -_mm256_castpd256_pd128(__m256d __in) +_mm256_castpd256_pd128(__m256d __a) { - return __builtin_shufflevector(__in, __in, 0, 1); + return __builtin_shufflevector(__a, __a, 0, 1); } static __inline __m128 __attribute__((__always_inline__, __nodebug__)) -_mm256_castps256_ps128(__m256 __in) +_mm256_castps256_ps128(__m256 __a) { - return __builtin_shufflevector(__in, __in, 0, 1, 2, 3); + return __builtin_shufflevector(__a, __a, 0, 1, 2, 3); } static __inline __m128i __attribute__((__always_inline__, __nodebug__)) -_mm256_castsi256_si128(__m256i __in) +_mm256_castsi256_si128(__m256i __a) { - return __builtin_shufflevector(__in, __in, 0, 1); + return __builtin_shufflevector(__a, __a, 0, 1); } static __inline __m256d __attribute__((__always_inline__, __nodebug__)) -_mm256_castpd128_pd256(__m128d __in) +_mm256_castpd128_pd256(__m128d __a) { __m128d __zero = _mm_setzero_pd(); - return __builtin_shufflevector(__in, __zero, 0, 1, 2, 2); + return __builtin_shufflevector(__a, __zero, 0, 1, 2, 2); } static __inline __m256 __attribute__((__always_inline__, __nodebug__)) -_mm256_castps128_ps256(__m128 __in) +_mm256_castps128_ps256(__m128 __a) { __m128 __zero = _mm_setzero_ps(); - return __builtin_shufflevector(__in, __zero, 0, 1, 2, 3, 4, 4, 4, 4); + return __builtin_shufflevector(__a, __zero, 0, 1, 2, 3, 4, 4, 4, 4); } static __inline __m256i __attribute__((__always_inline__, __nodebug__)) -_mm256_castsi128_si256(__m128i __in) +_mm256_castsi128_si256(__m128i __a) { __m128i __zero = _mm_setzero_si128(); - return __builtin_shufflevector(__in, __zero, 0, 1, 2, 2); + return __builtin_shufflevector(__a, __zero, 0, 1, 2, 2); } /* SIMD load ops (unaligned) */ diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h index e18fae4..56c6c22 100644 --- a/lib/Headers/emmintrin.h +++ b/lib/Headers/emmintrin.h @@ -1379,39 +1379,39 @@ _mm_movemask_pd(__m128d __a) __builtin_shufflevector(__a, __b, (i) & 1, (((i) & 2) >> 1) + 2); }) static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) -_mm_castpd_ps(__m128d __in) +_mm_castpd_ps(__m128d __a) { - return (__m128)__in; + return (__m128)__a; } static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) -_mm_castpd_si128(__m128d __in) +_mm_castpd_si128(__m128d __a) { - return (__m128i)__in; + return (__m128i)__a; } static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) -_mm_castps_pd(__m128 __in) +_mm_castps_pd(__m128 __a) { - return (__m128d)__in; + return (__m128d)__a; } static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) -_mm_castps_si128(__m128 __in) +_mm_castps_si128(__m128 __a) { - return (__m128i)__in; + return (__m128i)__a; } static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) -_mm_castsi128_ps(__m128i __in) +_mm_castsi128_ps(__m128i __a) { - return (__m128)__in; + return (__m128)__a; } static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) -_mm_castsi128_pd(__m128i __in) +_mm_castsi128_pd(__m128i __a) { - return (__m128d)__in; + return (__m128d)__a; } static __inline__ void __attribute__((__always_inline__, __nodebug__)) diff --git a/lib/Headers/stddef.h b/lib/Headers/stddef.h index 5296224..6a64d6d 100644 --- a/lib/Headers/stddef.h +++ b/lib/Headers/stddef.h @@ -42,11 +42,25 @@ typedef __PTRDIFF_TYPE__ ptrdiff_t; typedef __SIZE_TYPE__ size_t; #endif +/* ISO9899:2011 7.20 (C11 Annex K): Define rsize_t if __STDC_WANT_LIB_EXT1__ is + * enabled. */ +#if (defined(__STDC_WANT_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__ >= 1 && \ + !defined(_RSIZE_T)) || __has_feature(modules) +/* Always define rsize_t when modules are available. */ +#if !__has_feature(modules) +#define _RSIZE_T +#endif +typedef __SIZE_TYPE__ rsize_t; +#endif + #ifndef __cplusplus /* Always define wchar_t when modules are available. */ #if !defined(_WCHAR_T) || __has_feature(modules) #if !__has_feature(modules) #define _WCHAR_T +#if defined(_MSC_EXTENSIONS) +#define _WCHAR_T_DEFINED +#endif #endif typedef __WCHAR_TYPE__ wchar_t; #endif diff --git a/lib/Headers/stdint.h b/lib/Headers/stdint.h index 6f1a876..11529c0 100644 --- a/lib/Headers/stdint.h +++ b/lib/Headers/stdint.h @@ -30,7 +30,48 @@ */ #if __STDC_HOSTED__ && \ defined(__has_include_next) && __has_include_next(<stdint.h>) + +// C99 7.18.3 Limits of other integer types +// +// Footnote 219, 220: C++ implementations should define these macros only when +// __STDC_LIMIT_MACROS is defined before <stdint.h> is included. +// +// Footnote 222: C++ implementations should define these macros only when +// __STDC_CONSTANT_MACROS is defined before <stdint.h> is included. +// +// C++11 [cstdint.syn]p2: +// +// The macros defined by <cstdint> are provided unconditionally. In particular, +// the symbols __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS (mentioned in +// footnotes 219, 220, and 222 in the C standard) play no role in C++. +// +// C11 removed the problematic footnotes. +// +// Work around this inconsistency by always defining those macros in C++ mode, +// so that a C library implementation which follows the C99 standard can be +// used in C++. +# ifdef __cplusplus +# if !defined(__STDC_LIMIT_MACROS) +# define __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS_DEFINED_BY_CLANG +# endif +# if !defined(__STDC_CONSTANT_MACROS) +# define __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS_DEFINED_BY_CLANG +# endif +# endif + # include_next <stdint.h> + +# ifdef __STDC_LIMIT_MACROS_DEFINED_BY_CLANG +# undef __STDC_LIMIT_MACROS +# undef __STDC_LIMIT_MACROS_DEFINED_BY_CLANG +# endif +# ifdef __STDC_CONSTANT_MACROS_DEFINED_BY_CLANG +# undef __STDC_CONSTANT_MACROS +# undef __STDC_CONSTANT_MACROS_DEFINED_BY_CLANG +# endif + #else /* C99 7.18.1.1 Exact-width integer types. @@ -626,6 +667,12 @@ typedef __UINTMAX_TYPE__ uintmax_t; #define PTRDIFF_MAX __INTN_MAX(__PTRDIFF_WIDTH__) #define SIZE_MAX __UINTN_MAX(__SIZE_WIDTH__) +/* ISO9899:2011 7.20 (C11 Annex K): Define RSIZE_MAX if __STDC_WANT_LIB_EXT1__ + * is enabled. */ +#if defined(__STDC_WANT_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__ >= 1 +#define RSIZE_MAX (SIZE_MAX >> 1) +#endif + /* C99 7.18.2.5 Limits of greatest-width integer types. */ #define INTMAX_MIN __INTN_MIN(__INTMAX_WIDTH__) #define INTMAX_MAX __INTN_MAX(__INTMAX_WIDTH__) diff --git a/lib/Headers/xopintrin.h b/lib/Headers/xopintrin.h index d107be4..9a5824c 100644 --- a/lib/Headers/xopintrin.h +++ b/lib/Headers/xopintrin.h @@ -1,4 +1,4 @@ -/*===---- xopintrin.h - FMA4 intrinsics ------------------------------------=== +/*===---- xopintrin.h - XOP intrinsics -------------------------------------=== * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,7 +22,7 @@ */ #ifndef __X86INTRIN_H -#error "Never use <fma4intrin.h> directly; include <x86intrin.h> instead." +#error "Never use <xopintrin.h> directly; include <x86intrin.h> instead." #endif #ifndef __XOPINTRIN_H diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index ed4666a..9958287 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -557,6 +557,7 @@ Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer, SourceLocation FileLoc = SourceLocation::getFromRawEncoding(StartOffset); Lexer TheLexer(FileLoc, LangOpts, Buffer->getBufferStart(), Buffer->getBufferStart(), Buffer->getBufferEnd()); + TheLexer.SetCommentRetentionState(true); // StartLoc will differ from FileLoc if there is a BOM that was skipped. SourceLocation StartLoc = TheLexer.getSourceLocation(); @@ -565,6 +566,7 @@ Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer, Token TheTok; Token IfStartTok; unsigned IfCount = 0; + SourceLocation ActiveCommentLoc; unsigned MaxLineOffset = 0; if (MaxLines) { @@ -612,13 +614,17 @@ Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer, } // Comments are okay; skip over them. - if (TheTok.getKind() == tok::comment) + if (TheTok.getKind() == tok::comment) { + if (ActiveCommentLoc.isInvalid()) + ActiveCommentLoc = TheTok.getLocation(); continue; + } if (TheTok.isAtStartOfLine() && TheTok.getKind() == tok::hash) { // This is the start of a preprocessor directive. Token HashTok = TheTok; InPreprocessorDirective = true; + ActiveCommentLoc = SourceLocation(); // Figure out which directive this is. Since we're lexing raw tokens, // we don't have an identifier table available. Instead, just look at @@ -689,7 +695,14 @@ Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer, break; } while (true); - SourceLocation End = IfCount? IfStartTok.getLocation() : TheTok.getLocation(); + SourceLocation End; + if (IfCount) + End = IfStartTok.getLocation(); + else if (ActiveCommentLoc.isValid()) + End = ActiveCommentLoc; // don't truncate a decl comment. + else + End = TheTok.getLocation(); + return std::make_pair(End.getRawEncoding() - StartLoc.getRawEncoding(), IfCount? IfStartTok.isAtStartOfLine() : TheTok.isAtStartOfLine()); diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp index 91da822..09f4a68 100644 --- a/lib/Lex/LiteralSupport.cpp +++ b/lib/Lex/LiteralSupport.cpp @@ -686,8 +686,13 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) { // Handle simple binary numbers 0b01010 if (*s == 'b' || *s == 'B') { - // 0b101010 is a GCC extension. - PP.Diag(TokLoc, diag::ext_binary_literal); + // 0b101010 is a C++1y / GCC extension. + PP.Diag(TokLoc, + PP.getLangOpts().CPlusPlus1y + ? diag::warn_cxx11_compat_binary_literal + : PP.getLangOpts().CPlusPlus + ? diag::ext_binary_literal_cxx1y + : diag::ext_binary_literal); ++s; radix = 2; DigitsBegin = s; diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp index f6e781a..d2dc04b 100644 --- a/lib/Lex/MacroArgs.cpp +++ b/lib/Lex/MacroArgs.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "MacroArgs.h" +#include "clang/Lex/MacroArgs.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" diff --git a/lib/Lex/MacroArgs.h b/lib/Lex/MacroArgs.h deleted file mode 100644 index 1fd295e..0000000 --- a/lib/Lex/MacroArgs.h +++ /dev/null @@ -1,125 +0,0 @@ -//===--- MacroArgs.h - Formal argument info for Macros ----------*- 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 MacroArgs interface. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_MACROARGS_H -#define LLVM_CLANG_MACROARGS_H - -#include "clang/Basic/LLVM.h" -#include "llvm/ADT/ArrayRef.h" -#include <vector> - -namespace clang { - class MacroInfo; - class Preprocessor; - class Token; - class SourceLocation; - -/// MacroArgs - An instance of this class captures information about -/// the formal arguments specified to a function-like macro invocation. -class MacroArgs { - /// NumUnexpArgTokens - The number of raw, unexpanded tokens for the - /// arguments. All of the actual argument tokens are allocated immediately - /// after the MacroArgs object in memory. This is all of the arguments - /// concatenated together, with 'EOF' markers at the end of each argument. - unsigned NumUnexpArgTokens; - - /// VarargsElided - True if this is a C99 style varargs macro invocation and - /// there was no argument specified for the "..." argument. If the argument - /// was specified (even empty) or this isn't a C99 style varargs function, or - /// if in strict mode and the C99 varargs macro had only a ... argument, this - /// is false. - bool VarargsElided; - - /// PreExpArgTokens - Pre-expanded tokens for arguments that need them. Empty - /// if not yet computed. This includes the EOF marker at the end of the - /// stream. - std::vector<std::vector<Token> > PreExpArgTokens; - - /// StringifiedArgs - This contains arguments in 'stringified' form. If the - /// stringified form of an argument has not yet been computed, this is empty. - std::vector<Token> StringifiedArgs; - - /// ArgCache - This is a linked list of MacroArgs objects that the - /// Preprocessor owns which we use to avoid thrashing malloc/free. - MacroArgs *ArgCache; - - MacroArgs(unsigned NumToks, bool varargsElided) - : NumUnexpArgTokens(NumToks), VarargsElided(varargsElided), ArgCache(0) {} - ~MacroArgs() {} -public: - /// MacroArgs ctor function - Create a new MacroArgs object with the specified - /// macro and argument info. - static MacroArgs *create(const MacroInfo *MI, - ArrayRef<Token> UnexpArgTokens, - bool VarargsElided, Preprocessor &PP); - - /// destroy - Destroy and deallocate the memory for this object. - /// - void destroy(Preprocessor &PP); - - /// ArgNeedsPreexpansion - If we can prove that the argument won't be affected - /// by pre-expansion, return false. Otherwise, conservatively return true. - bool ArgNeedsPreexpansion(const Token *ArgTok, Preprocessor &PP) const; - - /// getUnexpArgument - Return a pointer to the first token of the unexpanded - /// token list for the specified formal. - /// - const Token *getUnexpArgument(unsigned Arg) const; - - /// getArgLength - Given a pointer to an expanded or unexpanded argument, - /// return the number of tokens, not counting the EOF, that make up the - /// argument. - static unsigned getArgLength(const Token *ArgPtr); - - /// getPreExpArgument - Return the pre-expanded form of the specified - /// argument. - const std::vector<Token> & - getPreExpArgument(unsigned Arg, const MacroInfo *MI, Preprocessor &PP); - - /// getStringifiedArgument - Compute, cache, and return the specified argument - /// that has been 'stringified' as required by the # operator. - const Token &getStringifiedArgument(unsigned ArgNo, Preprocessor &PP, - SourceLocation ExpansionLocStart, - SourceLocation ExpansionLocEnd); - - /// getNumArguments - Return the number of arguments passed into this macro - /// invocation. - unsigned getNumArguments() const { return NumUnexpArgTokens; } - - - /// isVarargsElidedUse - Return true if this is a C99 style varargs macro - /// invocation and there was no argument specified for the "..." argument. If - /// the argument was specified (even empty) or this isn't a C99 style varargs - /// function, or if in strict mode and the C99 varargs macro had only a ... - /// argument, this returns false. - bool isVarargsElidedUse() const { return VarargsElided; } - - /// StringifyArgument - Implement C99 6.10.3.2p2, converting a sequence of - /// tokens into the literal string token that should be produced by the C # - /// preprocessor operator. If Charify is true, then it should be turned into - /// a character literal for the Microsoft charize (#@) extension. - /// - static Token StringifyArgument(const Token *ArgToks, - Preprocessor &PP, bool Charify, - SourceLocation ExpansionLocStart, - SourceLocation ExpansionLocEnd); - - - /// deallocate - This should only be called by the Preprocessor when managing - /// its freelist. - MacroArgs *deallocate(); -}; - -} // end namespace clang - -#endif diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp index 0c03201..3e7a44c 100644 --- a/lib/Lex/ModuleMap.cpp +++ b/lib/Lex/ModuleMap.cpp @@ -83,7 +83,7 @@ Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod, return Context; } -ModuleMap::ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC, +ModuleMap::ModuleMap(FileManager &FileMgr, DiagnosticConsumer &DC, const LangOptions &LangOpts, const TargetInfo *Target, HeaderSearch &HeaderInfo) : LangOpts(LangOpts), Target(Target), HeaderInfo(HeaderInfo), @@ -92,7 +92,8 @@ ModuleMap::ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC, IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs); Diags = IntrusiveRefCntPtr<DiagnosticsEngine>( new DiagnosticsEngine(DiagIDs, new DiagnosticOptions)); - Diags->setClient(DC.clone(*Diags), /*ShouldOwnClient=*/true); + Diags->setClient(new ForwardingDiagnosticConsumer(DC), + /*ShouldOwnClient=*/true); SourceMgr = new SourceManager(*Diags, FileMgr); } @@ -149,6 +150,24 @@ static StringRef sanitizeFilenameAsIdentifier(StringRef Name, return Name; } +/// \brief Determine whether the given file name is the name of a builtin +/// header, supplied by Clang to replace, override, or augment existing system +/// headers. +static bool isBuiltinHeader(StringRef FileName) { + return llvm::StringSwitch<bool>(FileName) + .Case("float.h", true) + .Case("iso646.h", true) + .Case("limits.h", true) + .Case("stdalign.h", true) + .Case("stdarg.h", true) + .Case("stdbool.h", true) + .Case("stddef.h", true) + .Case("stdint.h", true) + .Case("tgmath.h", true) + .Case("unwind.h", true) + .Default(false); +} + Module *ModuleMap::findModuleForHeader(const FileEntry *File) { HeadersMap::iterator Known = Headers.find(File); if (Known != Headers.end()) { @@ -158,6 +177,25 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) { return Known->second.getModule(); } + + // If we've found a builtin header within Clang's builtin include directory, + // load all of the module maps to see if it will get associated with a + // specific module (e.g., in /usr/include). + if (File->getDir() == BuiltinIncludeDir && + isBuiltinHeader(llvm::sys::path::filename(File->getName()))) { + SmallVector<Module *, 4> AllModules; + HeaderInfo.collectAllModules(AllModules); + + // Check again. + Known = Headers.find(File); + if (Known != Headers.end()) { + // If a header is not available, don't report that it maps to anything. + if (!Known->second.isAvailable()) + return 0; + + return Known->second.getModule(); + } + } const DirectoryEntry *Dir = File->getDir(); SmallVector<const DirectoryEntry *, 2> SkippedDirs; @@ -1266,24 +1304,6 @@ static void appendSubframeworkPaths(Module *Mod, } } -/// \brief Determine whether the given file name is the name of a builtin -/// header, supplied by Clang to replace, override, or augment existing system -/// headers. -static bool isBuiltinHeader(StringRef FileName) { - return llvm::StringSwitch<bool>(FileName) - .Case("float.h", true) - .Case("iso646.h", true) - .Case("limits.h", true) - .Case("stdalign.h", true) - .Case("stdarg.h", true) - .Case("stdbool.h", true) - .Case("stddef.h", true) - .Case("stdint.h", true) - .Case("tgmath.h", true) - .Case("unwind.h", true) - .Default(false); -} - /// \brief Parse a header declaration. /// /// header-declaration: diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 07c1867..50a0cb5 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -61,9 +61,12 @@ MacroInfo *Preprocessor::AllocateDeserializedMacroInfo(SourceLocation L, unsigned SubModuleID) { LLVM_STATIC_ASSERT(llvm::AlignOf<MacroInfo>::Alignment >= sizeof(SubModuleID), "alignment for MacroInfo is less than the ID"); - MacroInfo *MI = - (MacroInfo*)BP.Allocate(sizeof(MacroInfo) + sizeof(SubModuleID), - llvm::AlignOf<MacroInfo>::Alignment); + DeserializedMacroInfoChain *MIChain = + BP.Allocate<DeserializedMacroInfoChain>(); + MIChain->Next = DeserialMIChainHead; + DeserialMIChainHead = MIChain; + + MacroInfo *MI = &MIChain->MI; new (MI) MacroInfo(L); MI->FromASTFile = true; MI->setOwningModuleID(SubModuleID); @@ -793,7 +796,8 @@ void Preprocessor::HandleDirective(Token &Result) { /// GetLineValue - Convert a numeric token into an unsigned value, emitting /// Diagnostic DiagID if it is invalid, and returning the value in Val. static bool GetLineValue(Token &DigitTok, unsigned &Val, - unsigned DiagID, Preprocessor &PP) { + unsigned DiagID, Preprocessor &PP, + bool IsGNULineDirective=false) { if (DigitTok.isNot(tok::numeric_constant)) { PP.Diag(DigitTok, DiagID); @@ -817,7 +821,7 @@ static bool GetLineValue(Token &DigitTok, unsigned &Val, for (unsigned i = 0; i != ActualLength; ++i) { if (!isDigit(DigitTokBegin[i])) { PP.Diag(PP.AdvanceToTokenCharacter(DigitTok.getLocation(), i), - diag::err_pp_line_digit_sequence); + diag::err_pp_line_digit_sequence) << IsGNULineDirective; PP.DiscardUntilEndOfDirective(); return true; } @@ -832,7 +836,8 @@ static bool GetLineValue(Token &DigitTok, unsigned &Val, } if (DigitTokBegin[0] == '0' && Val) - PP.Diag(DigitTok.getLocation(), diag::warn_pp_line_decimal); + PP.Diag(DigitTok.getLocation(), diag::warn_pp_line_decimal) + << IsGNULineDirective; return false; } @@ -998,7 +1003,7 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) { // line # limit other than it fit in 32-bits. unsigned LineNo; if (GetLineValue(DigitTok, LineNo, diag::err_pp_linemarker_requires_integer, - *this)) + *this, true)) return; Token StrTok; diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 21451f5..24c6217 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/Preprocessor.h" -#include "MacroArgs.h" +#include "clang/Lex/MacroArgs.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -223,7 +223,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, // If this is a builtin macro, like __LINE__ or _Pragma, handle it specially. if (MI->isBuiltinMacro()) { if (Callbacks) Callbacks->MacroExpands(Identifier, MD, - Identifier.getLocation()); + Identifier.getLocation(),/*Args=*/0); ExpandBuiltinMacro(Identifier); return false; } @@ -277,11 +277,12 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, DelayedMacroExpandsCallbacks.push_back( MacroExpandsInfo(Identifier, MD, ExpansionRange)); } else { - Callbacks->MacroExpands(Identifier, MD, ExpansionRange); + Callbacks->MacroExpands(Identifier, MD, ExpansionRange, Args); if (!DelayedMacroExpandsCallbacks.empty()) { for (unsigned i=0, e = DelayedMacroExpandsCallbacks.size(); i!=e; ++i) { MacroExpandsInfo &Info = DelayedMacroExpandsCallbacks[i]; - Callbacks->MacroExpands(Info.Tok, Info.MD, Info.Range); + // FIXME: We lose macro args info with delayed callback. + Callbacks->MacroExpands(Info.Tok, Info.MD, Info.Range, /*Args=*/0); } DelayedMacroExpandsCallbacks.clear(); } @@ -751,6 +752,8 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("c_atomic", LangOpts.C11) .Case("c_generic_selections", LangOpts.C11) .Case("c_static_assert", LangOpts.C11) + .Case("c_thread_local", + LangOpts.C11 && PP.getTargetInfo().isTLSSupported()) // C++11 features .Case("cxx_access_control_sfinae", LangOpts.CPlusPlus11) .Case("cxx_alias_templates", LangOpts.CPlusPlus11) @@ -768,7 +771,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("cxx_explicit_conversions", LangOpts.CPlusPlus11) .Case("cxx_generalized_initializers", LangOpts.CPlusPlus11) .Case("cxx_implicit_moves", LangOpts.CPlusPlus11) - //.Case("cxx_inheriting_constructors", false) + .Case("cxx_inheriting_constructors", LangOpts.CPlusPlus11) .Case("cxx_inline_namespaces", LangOpts.CPlusPlus11) .Case("cxx_lambdas", LangOpts.CPlusPlus11) .Case("cxx_local_type_template_args", LangOpts.CPlusPlus11) @@ -782,11 +785,23 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("cxx_rvalue_references", LangOpts.CPlusPlus11) .Case("cxx_strong_enums", LangOpts.CPlusPlus11) .Case("cxx_static_assert", LangOpts.CPlusPlus11) + .Case("cxx_thread_local", + LangOpts.CPlusPlus11 && PP.getTargetInfo().isTLSSupported()) .Case("cxx_trailing_return", LangOpts.CPlusPlus11) .Case("cxx_unicode_literals", LangOpts.CPlusPlus11) .Case("cxx_unrestricted_unions", LangOpts.CPlusPlus11) .Case("cxx_user_literals", LangOpts.CPlusPlus11) .Case("cxx_variadic_templates", LangOpts.CPlusPlus11) + // C++1y features + .Case("cxx_binary_literals", LangOpts.CPlusPlus1y) + //.Case("cxx_contextual_conversions", LangOpts.CPlusPlus1y) + //.Case("cxx_generalized_capture", LangOpts.CPlusPlus1y) + //.Case("cxx_generic_lambda", LangOpts.CPlusPlus1y) + //.Case("cxx_relaxed_constexpr", LangOpts.CPlusPlus1y) + //.Case("cxx_return_type_deduction", LangOpts.CPlusPlus1y) + //.Case("cxx_runtime_array", LangOpts.CPlusPlus1y) + .Case("cxx_aggregate_nsdmi", LangOpts.CPlusPlus1y) + //.Case("cxx_variable_templates", LangOpts.CPlusPlus1y) // Type traits .Case("has_nothrow_assign", LangOpts.CPlusPlus) .Case("has_nothrow_copy", LangOpts.CPlusPlus) @@ -847,7 +862,7 @@ static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) { .Case("c_atomic", true) .Case("c_generic_selections", true) .Case("c_static_assert", true) - // C++0x features supported by other languages as extensions. + // C++11 features supported by other languages as extensions. .Case("cxx_atomic", LangOpts.CPlusPlus) .Case("cxx_deleted_functions", LangOpts.CPlusPlus) .Case("cxx_explicit_conversions", LangOpts.CPlusPlus) @@ -858,6 +873,8 @@ static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) { .Case("cxx_range_for", LangOpts.CPlusPlus) .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus) .Case("cxx_rvalue_references", LangOpts.CPlusPlus) + // C++1y features supported by other languages as extensions. + .Case("cxx_binary_literals", true) .Default(false); } diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp index 95e8a8c..b2ae4c9 100644 --- a/lib/Lex/Pragma.cpp +++ b/lib/Lex/Pragma.cpp @@ -254,14 +254,15 @@ void Preprocessor::Handle_Pragma(Token &Tok) { "Invalid string token!"); // Remove escaped quotes and escapes. - for (unsigned i = 1, e = StrVal.size(); i < e-2; ++i) { - if (StrVal[i] == '\\' && - (StrVal[i+1] == '\\' || StrVal[i+1] == '"')) { + unsigned ResultPos = 1; + for (unsigned i = 1, e = StrVal.size() - 2; i != e; ++i) { + if (StrVal[i] != '\\' || + (StrVal[i + 1] != '\\' && StrVal[i + 1] != '"')) { // \\ -> '\' and \" -> '"'. - StrVal.erase(StrVal.begin()+i); - --e; + StrVal[ResultPos++] = StrVal[i]; } } + StrVal.erase(StrVal.begin() + ResultPos, StrVal.end() - 2); } // Remove the front quote, replacing it with a space, so that the pragma @@ -434,8 +435,9 @@ void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) { // Emit a line marker. This will change any source locations from this point // forward to realize they are in a system header. // Create a line note with this information. - SourceMgr.AddLineNote(SysHeaderTok.getLocation(), PLoc.getLine(), FilenameID, - false, false, true, false); + SourceMgr.AddLineNote(SysHeaderTok.getLocation(), PLoc.getLine()+1, + FilenameID, /*IsEntry=*/false, /*IsExit=*/false, + /*IsSystem=*/true, /*IsExternC=*/false); } /// HandlePragmaDependency - Handle \#pragma GCC dependency "foo" blah. @@ -491,126 +493,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { } } -/// \brief Handle the microsoft \#pragma comment extension. -/// -/// The syntax is: -/// \code -/// #pragma comment(linker, "foo") -/// \endcode -/// 'linker' is one of five identifiers: compiler, exestr, lib, linker, user. -/// "foo" is a string, which is fully macro expanded, and permits string -/// concatenation, embedded escape characters etc. See MSDN for more details. -void Preprocessor::HandlePragmaComment(Token &Tok) { - SourceLocation CommentLoc = Tok.getLocation(); - Lex(Tok); - if (Tok.isNot(tok::l_paren)) { - Diag(CommentLoc, diag::err_pragma_comment_malformed); - return; - } - - // Read the identifier. - Lex(Tok); - if (Tok.isNot(tok::identifier)) { - Diag(CommentLoc, diag::err_pragma_comment_malformed); - return; - } - - // Verify that this is one of the 5 whitelisted options. - // FIXME: warn that 'exestr' is deprecated. - const IdentifierInfo *II = Tok.getIdentifierInfo(); - if (!II->isStr("compiler") && !II->isStr("exestr") && !II->isStr("lib") && - !II->isStr("linker") && !II->isStr("user")) { - Diag(Tok.getLocation(), diag::err_pragma_comment_unknown_kind); - return; - } - - // Read the optional string if present. - Lex(Tok); - std::string ArgumentString; - if (Tok.is(tok::comma) && !LexStringLiteral(Tok, ArgumentString, - "pragma comment", - /*MacroExpansion=*/true)) - return; - - // FIXME: If the kind is "compiler" warn if the string is present (it is - // ignored). - // FIXME: 'lib' requires a comment string. - // FIXME: 'linker' requires a comment string, and has a specific list of - // things that are allowable. - - if (Tok.isNot(tok::r_paren)) { - Diag(Tok.getLocation(), diag::err_pragma_comment_malformed); - return; - } - Lex(Tok); // eat the r_paren. - - if (Tok.isNot(tok::eod)) { - Diag(Tok.getLocation(), diag::err_pragma_comment_malformed); - return; - } - - // If the pragma is lexically sound, notify any interested PPCallbacks. - if (Callbacks) - Callbacks->PragmaComment(CommentLoc, II, ArgumentString); -} - -/// HandlePragmaMessage - Handle the microsoft and gcc \#pragma message -/// extension. The syntax is: -/// \code -/// #pragma message(string) -/// \endcode -/// OR, in GCC mode: -/// \code -/// #pragma message string -/// \endcode -/// string is a string, which is fully macro expanded, and permits string -/// concatenation, embedded escape characters, etc... See MSDN for more details. -void Preprocessor::HandlePragmaMessage(Token &Tok) { - SourceLocation MessageLoc = Tok.getLocation(); - Lex(Tok); - bool ExpectClosingParen = false; - switch (Tok.getKind()) { - case tok::l_paren: - // We have a MSVC style pragma message. - ExpectClosingParen = true; - // Read the string. - Lex(Tok); - break; - case tok::string_literal: - // We have a GCC style pragma message, and we just read the string. - break; - default: - Diag(MessageLoc, diag::err_pragma_message_malformed); - return; - } - - std::string MessageString; - if (!FinishLexStringLiteral(Tok, MessageString, "pragma message", - /*MacroExpansion=*/true)) - return; - - if (ExpectClosingParen) { - if (Tok.isNot(tok::r_paren)) { - Diag(Tok.getLocation(), diag::err_pragma_message_malformed); - return; - } - Lex(Tok); // eat the r_paren. - } - - if (Tok.isNot(tok::eod)) { - Diag(Tok.getLocation(), diag::err_pragma_message_malformed); - return; - } - - // Output the message. - Diag(MessageLoc, diag::warn_pragma_message) << MessageString; - - // If the pragma is lexically sound, notify any interested PPCallbacks. - if (Callbacks) - Callbacks->PragmaMessage(MessageLoc, MessageString); -} - -/// ParsePragmaPushOrPopMacro - Handle parsing of pragma push_macro/pop_macro. +/// ParsePragmaPushOrPopMacro - Handle parsing of pragma push_macro/pop_macro. /// Return the IdentifierInfo* associated with the macro to push or pop. IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) { // Remember the pragma token location. @@ -995,10 +878,40 @@ struct PragmaDebugHandler : public PragmaHandler { llvm::CrashRecoveryContext *CRC =llvm::CrashRecoveryContext::GetCurrent(); if (CRC) CRC->HandleCrash(); + } else if (II->isStr("captured")) { + HandleCaptured(PP); } else { PP.Diag(Tok, diag::warn_pragma_debug_unexpected_command) << II->getName(); } + + PPCallbacks *Callbacks = PP.getPPCallbacks(); + if (Callbacks) + Callbacks->PragmaDebug(Tok.getLocation(), II->getName()); + } + + void HandleCaptured(Preprocessor &PP) { + // Skip if emitting preprocessed output. + if (PP.isPreprocessedOutput()) + return; + + Token Tok; + PP.LexUnexpandedToken(Tok); + + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) + << "pragma clang __debug captured"; + return; + } + + SourceLocation NameLoc = Tok.getLocation(); + Token *Toks = PP.getPreprocessorAllocator().Allocate<Token>(1); + Toks->startToken(); + Toks->setKind(tok::annot_pragma_captured); + Toks->setLocation(NameLoc); + + PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, + /*OwnsTokens=*/false); } // Disable MSVC warning about runtime stack overflow. @@ -1086,15 +999,6 @@ public: } }; -/// PragmaCommentHandler - "\#pragma comment ...". -struct PragmaCommentHandler : public PragmaHandler { - PragmaCommentHandler() : PragmaHandler("comment") {} - virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, - Token &CommentTok) { - PP.HandlePragmaComment(CommentTok); - } -}; - /// PragmaIncludeAliasHandler - "\#pragma include_alias("...")". struct PragmaIncludeAliasHandler : public PragmaHandler { PragmaIncludeAliasHandler() : PragmaHandler("include_alias") {} @@ -1104,12 +1008,88 @@ struct PragmaIncludeAliasHandler : public PragmaHandler { } }; -/// PragmaMessageHandler - "\#pragma message("...")". +/// PragmaMessageHandler - Handle the microsoft and gcc \#pragma message +/// extension. The syntax is: +/// \code +/// #pragma message(string) +/// \endcode +/// OR, in GCC mode: +/// \code +/// #pragma message string +/// \endcode +/// string is a string, which is fully macro expanded, and permits string +/// concatenation, embedded escape characters, etc... See MSDN for more details. +/// Also handles \#pragma GCC warning and \#pragma GCC error which take the same +/// form as \#pragma message. struct PragmaMessageHandler : public PragmaHandler { - PragmaMessageHandler() : PragmaHandler("message") {} +private: + const PPCallbacks::PragmaMessageKind Kind; + const StringRef Namespace; + + static const char* PragmaKind(PPCallbacks::PragmaMessageKind Kind, + bool PragmaNameOnly = false) { + switch (Kind) { + case PPCallbacks::PMK_Message: + return PragmaNameOnly ? "message" : "pragma message"; + case PPCallbacks::PMK_Warning: + return PragmaNameOnly ? "warning" : "pragma warning"; + case PPCallbacks::PMK_Error: + return PragmaNameOnly ? "error" : "pragma error"; + } + llvm_unreachable("Unknown PragmaMessageKind!"); + } + +public: + PragmaMessageHandler(PPCallbacks::PragmaMessageKind Kind, + StringRef Namespace = StringRef()) + : PragmaHandler(PragmaKind(Kind, true)), Kind(Kind), Namespace(Namespace) {} + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, - Token &CommentTok) { - PP.HandlePragmaMessage(CommentTok); + Token &Tok) { + SourceLocation MessageLoc = Tok.getLocation(); + PP.Lex(Tok); + bool ExpectClosingParen = false; + switch (Tok.getKind()) { + case tok::l_paren: + // We have a MSVC style pragma message. + ExpectClosingParen = true; + // Read the string. + PP.Lex(Tok); + break; + case tok::string_literal: + // We have a GCC style pragma message, and we just read the string. + break; + default: + PP.Diag(MessageLoc, diag::err_pragma_message_malformed) << Kind; + return; + } + + std::string MessageString; + if (!PP.FinishLexStringLiteral(Tok, MessageString, PragmaKind(Kind), + /*MacroExpansion=*/true)) + return; + + if (ExpectClosingParen) { + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Tok.getLocation(), diag::err_pragma_message_malformed) << Kind; + return; + } + PP.Lex(Tok); // eat the r_paren. + } + + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok.getLocation(), diag::err_pragma_message_malformed) << Kind; + return; + } + + // Output the message. + PP.Diag(MessageLoc, (Kind == PPCallbacks::PMK_Error) + ? diag::err_pragma_message + : diag::warn_pragma_message) << MessageString; + + // If the pragma is lexically sound, notify any interested PPCallbacks. + if (PPCallbacks *Callbacks = PP.getPPCallbacks()) + Callbacks->PragmaMessage(MessageLoc, Namespace, Kind, MessageString); } }; @@ -1257,13 +1237,17 @@ void Preprocessor::RegisterBuiltinPragmas() { AddPragmaHandler(new PragmaMarkHandler()); AddPragmaHandler(new PragmaPushMacroHandler()); AddPragmaHandler(new PragmaPopMacroHandler()); - AddPragmaHandler(new PragmaMessageHandler()); + AddPragmaHandler(new PragmaMessageHandler(PPCallbacks::PMK_Message)); // #pragma GCC ... AddPragmaHandler("GCC", new PragmaPoisonHandler()); AddPragmaHandler("GCC", new PragmaSystemHeaderHandler()); AddPragmaHandler("GCC", new PragmaDependencyHandler()); AddPragmaHandler("GCC", new PragmaDiagnosticHandler("GCC")); + AddPragmaHandler("GCC", new PragmaMessageHandler(PPCallbacks::PMK_Warning, + "GCC")); + AddPragmaHandler("GCC", new PragmaMessageHandler(PPCallbacks::PMK_Error, + "GCC")); // #pragma clang ... AddPragmaHandler("clang", new PragmaPoisonHandler()); AddPragmaHandler("clang", new PragmaSystemHeaderHandler()); @@ -1278,7 +1262,6 @@ void Preprocessor::RegisterBuiltinPragmas() { // MS extensions. if (LangOpts.MicrosoftExt) { - AddPragmaHandler(new PragmaCommentHandler()); AddPragmaHandler(new PragmaIncludeAliasHandler()); AddPragmaHandler(new PragmaRegionHandler("region")); AddPragmaHandler(new PragmaRegionHandler("endregion")); diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp index b10e7f7..426b922 100644 --- a/lib/Lex/PreprocessingRecord.cpp +++ b/lib/Lex/PreprocessingRecord.cpp @@ -406,7 +406,8 @@ void PreprocessingRecord::Defined(const Token &MacroNameTok, } void PreprocessingRecord::MacroExpands(const Token &Id,const MacroDirective *MD, - SourceRange Range) { + SourceRange Range, + const MacroArgs *Args) { addMacroExpansion(Id, MD->getMacroInfo(), Range); } diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index 53c45dc..66f23f1 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -26,7 +26,7 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/Preprocessor.h" -#include "MacroArgs.h" +#include "clang/Lex/MacroArgs.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -67,7 +67,8 @@ Preprocessor::Preprocessor(IntrusiveRefCntPtr<PreprocessorOptions> PPOpts, CodeComplete(0), CodeCompletionFile(0), CodeCompletionOffset(0), CodeCompletionReached(0), SkipMainFilePreamble(0, true), CurPPLexer(0), CurDirLookup(0), CurLexerKind(CLK_Lexer), Callbacks(0), - MacroArgCache(0), Record(0), MIChainHead(0), MICache(0) { + MacroArgCache(0), Record(0), MIChainHead(0), MICache(0), + DeserialMIChainHead(0) { OwnsHeaderSearch = OwnsHeaders; ScratchBuf = new ScratchBuffer(SourceMgr); @@ -153,6 +154,9 @@ Preprocessor::~Preprocessor() { for (unsigned i = 0, e = NumCachedTokenLexers; i != e; ++i) delete TokenLexerCache[i]; + for (DeserializedMacroInfoChain *I = DeserialMIChainHead ; I ; I = I->Next) + I->MI.Destroy(); + // Free any cached MacroArgs. for (MacroArgs *ArgList = MacroArgCache; ArgList; ) ArgList = ArgList->deallocate(); diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp index 5b41fe9..07753c7 100644 --- a/lib/Lex/TokenLexer.cpp +++ b/lib/Lex/TokenLexer.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/TokenLexer.h" -#include "MacroArgs.h" +#include "clang/Lex/MacroArgs.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/MacroInfo.h" diff --git a/lib/Parse/CMakeLists.txt b/lib/Parse/CMakeLists.txt index 939998e..01c0694 100644 --- a/lib/Parse/CMakeLists.txt +++ b/lib/Parse/CMakeLists.txt @@ -17,6 +17,7 @@ add_clang_library(clangParse add_dependencies(clangParse ClangAttrClasses + ClangAttrExprArgs ClangAttrLateParsed ClangAttrList ClangAttrParsedAttrList diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index bc634b5..5fc4189 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -57,8 +57,7 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, if (FnD) { Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs, false, true); - bool TypeSpecContainsAuto - = D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; + bool TypeSpecContainsAuto = D.getDeclSpec().containsPlaceholderType(); if (Init.isUsable()) Actions.AddInitializerToDecl(FnD, Init.get(), false, TypeSpecContainsAuto); @@ -279,8 +278,11 @@ void Parser::LateParsedMemberInitializer::ParseLexedMemberInitializers() { void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); - if (HasTemplateScope) + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); + if (HasTemplateScope) { Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); + ++CurTemplateDepthTracker; + } // The current scope is still active if we're the top-level class. // Otherwise we'll need to push and enter a new scope. @@ -301,9 +303,11 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { // If this is a member template, introduce the template parameter scope. ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); - if (LM.TemplateScope) + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); + if (LM.TemplateScope) { Actions.ActOnReenterTemplateScope(getCurScope(), LM.Method); - + ++CurTemplateDepthTracker; + } // Start the delayed C++ method declaration Actions.ActOnStartDelayedCXXMethodDeclaration(getCurScope(), LM.Method); @@ -379,9 +383,11 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { void Parser::ParseLexedMethodDefs(ParsingClass &Class) { bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); - if (HasTemplateScope) + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); + if (HasTemplateScope) { Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); - + ++CurTemplateDepthTracker; + } bool HasClassScope = !Class.TopLevelClass; ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, HasClassScope); @@ -394,9 +400,11 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) { void Parser::ParseLexedMethodDef(LexedMethod &LM) { // If this is a member template, introduce the template parameter scope. ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); - if (LM.TemplateScope) + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); + if (LM.TemplateScope) { Actions.ActOnReenterTemplateScope(getCurScope(), LM.D); - + ++CurTemplateDepthTracker; + } // Save the current token position. SourceLocation origLoc = Tok.getLocation(); @@ -441,6 +449,13 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { } else Actions.ActOnDefaultCtorInitializers(LM.D); + assert((Actions.getDiagnostics().hasErrorOccurred() || + !isa<FunctionTemplateDecl>(LM.D) || + cast<FunctionTemplateDecl>(LM.D)->getTemplateParameters()->getDepth() + < TemplateParameterDepth) && + "TemplateParameterDepth should be greater than the depth of " + "current template being instantiated!"); + ParseFunctionStatementBody(LM.D, FnScope); // Clear the late-template-parsed bit if we set it before. @@ -466,9 +481,11 @@ void Parser::ParseLexedMemberInitializers(ParsingClass &Class) { bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); - if (HasTemplateScope) + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); + if (HasTemplateScope) { Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); - + ++CurTemplateDepthTracker; + } // Set or update the scope flags. bool AlreadyHasClassScope = Class.TopLevelClass; unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope; diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 990a909..6a87b78 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -178,6 +178,12 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, } } +/// \brief Determine whether the given attribute has all expression arguments. +static bool attributeHasExprArgs(const IdentifierInfo &II) { + return llvm::StringSwitch<bool>(II.getName()) +#include "clang/Parse/AttrExprArgs.inc" + .Default(false); +} /// Parse the arguments to a parameterized GNU attribute or /// a C++11 attribute in "gnu" namespace. @@ -247,6 +253,10 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, TypeParsed = true; break; } + // If the attribute has all expression arguments, and not a "parameter", + // break out to handle it below. + if (attributeHasExprArgs(*AttrName)) + break; ParmName = Tok.getIdentifierInfo(); ParmLoc = ConsumeToken(); break; @@ -364,6 +374,7 @@ bool Parser::IsSimpleMicrosoftDeclSpec(IdentifierInfo *Ident) { .Case("novtable", true) .Case("selectany", true) .Case("thread", true) + .Case("safebuffers", true ) .Default(false); } @@ -394,17 +405,119 @@ void Parser::ParseComplexMicrosoftDeclSpec(IdentifierInfo *Ident, // The property declspec is more complex in that it can take one or two // assignment expressions as a parameter, but the lhs of the assignment // must be named get or put. - // - // For right now, we will just skip to the closing right paren of the - // property expression. - // - // FIXME: we should deal with __declspec(property) at some point because it - // is used in the platform SDK headers for the Parallel Patterns Library - // and ATL. - BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.expectAndConsume(diag::err_expected_lparen_after, - Ident->getNameStart(), tok::r_paren)) + if (Tok.isNot(tok::l_paren)) { + Diag(Tok.getLocation(), diag::err_expected_lparen_after) + << Ident->getNameStart(); return; + } + BalancedDelimiterTracker T(*this, tok::l_paren); + T.expectAndConsume(diag::err_expected_lparen_after, + Ident->getNameStart(), tok::r_paren); + + enum AccessorKind { + AK_Invalid = -1, + AK_Put = 0, AK_Get = 1 // indices into AccessorNames + }; + IdentifierInfo *AccessorNames[] = { 0, 0 }; + bool HasInvalidAccessor = false; + + // Parse the accessor specifications. + while (true) { + // Stop if this doesn't look like an accessor spec. + if (!Tok.is(tok::identifier)) { + // If the user wrote a completely empty list, use a special diagnostic. + if (Tok.is(tok::r_paren) && !HasInvalidAccessor && + AccessorNames[AK_Put] == 0 && AccessorNames[AK_Get] == 0) { + Diag(Loc, diag::err_ms_property_no_getter_or_putter); + break; + } + + Diag(Tok.getLocation(), diag::err_ms_property_unknown_accessor); + break; + } + + AccessorKind Kind; + SourceLocation KindLoc = Tok.getLocation(); + StringRef KindStr = Tok.getIdentifierInfo()->getName(); + if (KindStr == "get") { + Kind = AK_Get; + } else if (KindStr == "put") { + Kind = AK_Put; + + // Recover from the common mistake of using 'set' instead of 'put'. + } else if (KindStr == "set") { + Diag(KindLoc, diag::err_ms_property_has_set_accessor) + << FixItHint::CreateReplacement(KindLoc, "put"); + Kind = AK_Put; + + // Handle the mistake of forgetting the accessor kind by skipping + // this accessor. + } else if (NextToken().is(tok::comma) || NextToken().is(tok::r_paren)) { + Diag(KindLoc, diag::err_ms_property_missing_accessor_kind); + ConsumeToken(); + HasInvalidAccessor = true; + goto next_property_accessor; + + // Otherwise, complain about the unknown accessor kind. + } else { + Diag(KindLoc, diag::err_ms_property_unknown_accessor); + HasInvalidAccessor = true; + Kind = AK_Invalid; + + // Try to keep parsing unless it doesn't look like an accessor spec. + if (!NextToken().is(tok::equal)) break; + } + + // Consume the identifier. + ConsumeToken(); + + // Consume the '='. + if (Tok.is(tok::equal)) { + ConsumeToken(); + } else { + Diag(Tok.getLocation(), diag::err_ms_property_expected_equal) + << KindStr; + break; + } + + // Expect the method name. + if (!Tok.is(tok::identifier)) { + Diag(Tok.getLocation(), diag::err_ms_property_expected_accessor_name); + break; + } + + if (Kind == AK_Invalid) { + // Just drop invalid accessors. + } else if (AccessorNames[Kind] != NULL) { + // Complain about the repeated accessor, ignore it, and keep parsing. + Diag(KindLoc, diag::err_ms_property_duplicate_accessor) << KindStr; + } else { + AccessorNames[Kind] = Tok.getIdentifierInfo(); + } + ConsumeToken(); + + next_property_accessor: + // Keep processing accessors until we run out. + if (Tok.is(tok::comma)) { + ConsumeAnyToken(); + continue; + + // If we run into the ')', stop without consuming it. + } else if (Tok.is(tok::r_paren)) { + break; + } else { + Diag(Tok.getLocation(), diag::err_ms_property_expected_comma_or_rparen); + break; + } + } + + // Only add the property attribute if it was well-formed. + if (!HasInvalidAccessor) { + Attrs.addNewPropertyAttr(Ident, Loc, 0, SourceLocation(), 0, + SourceLocation(), + AccessorNames[AK_Get], AccessorNames[AK_Put], + AttributeList::AS_Declspec); + } T.skipToEnd(); } else { // We don't recognize this as a valid declspec, but instead of creating the @@ -1489,35 +1602,42 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, MaybeParseGNUAttributes(D, &LateParsedAttrs); // Check to see if we have a function *definition* which must have a body. - if (AllowFunctionDefinitions && D.isFunctionDeclarator() && + if (D.isFunctionDeclarator() && // Look at the next token to make sure that this isn't a function // declaration. We have to check this because __attribute__ might be the // start of a function definition in GCC-extended K&R C. !isDeclarationAfterDeclarator()) { - if (isStartOfFunctionDefinition(D)) { - if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { - Diag(Tok, diag::err_function_declared_typedef); + if (AllowFunctionDefinitions) { + if (isStartOfFunctionDefinition(D)) { + if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { + Diag(Tok, diag::err_function_declared_typedef); - // Recover by treating the 'typedef' as spurious. - DS.ClearStorageClassSpecs(); - } + // Recover by treating the 'typedef' as spurious. + DS.ClearStorageClassSpecs(); + } - Decl *TheDecl = - ParseFunctionDefinition(D, ParsedTemplateInfo(), &LateParsedAttrs); - return Actions.ConvertDeclToDeclGroup(TheDecl); - } + Decl *TheDecl = + ParseFunctionDefinition(D, ParsedTemplateInfo(), &LateParsedAttrs); + return Actions.ConvertDeclToDeclGroup(TheDecl); + } - if (isDeclarationSpecifier()) { - // If there is an invalid declaration specifier right after the function - // prototype, then we must be in a missing semicolon case where this isn't - // actually a body. Just fall through into the code that handles it as a - // prototype, and let the top-level code handle the erroneous declspec - // where it would otherwise expect a comma or semicolon. + if (isDeclarationSpecifier()) { + // If there is an invalid declaration specifier right after the function + // prototype, then we must be in a missing semicolon case where this isn't + // actually a body. Just fall through into the code that handles it as a + // prototype, and let the top-level code handle the erroneous declspec + // where it would otherwise expect a comma or semicolon. + } else { + Diag(Tok, diag::err_expected_fn_body); + SkipUntil(tok::semi); + return DeclGroupPtrTy(); + } } else { - Diag(Tok, diag::err_expected_fn_body); - SkipUntil(tok::semi); - return DeclGroupPtrTy(); + if (Tok.is(tok::l_brace)) { + Diag(Tok, diag::err_function_definition_not_allowed); + SkipUntil(tok::r_brace, true, true); + } } } @@ -1527,14 +1647,23 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // C++0x [stmt.iter]p1: Check if we have a for-range-declarator. If so, we // must parse and analyze the for-range-initializer before the declaration is // analyzed. - if (FRI && Tok.is(tok::colon)) { - FRI->ColonLoc = ConsumeToken(); - if (Tok.is(tok::l_brace)) - FRI->RangeExpr = ParseBraceInitializer(); - else - FRI->RangeExpr = ParseExpression(); + // + // Handle the Objective-C for-in loop variable similarly, although we + // don't need to parse the container in advance. + if (FRI && (Tok.is(tok::colon) || isTokIdentifier_in())) { + bool IsForRangeLoop = false; + if (Tok.is(tok::colon)) { + IsForRangeLoop = true; + FRI->ColonLoc = ConsumeToken(); + if (Tok.is(tok::l_brace)) + FRI->RangeExpr = ParseBraceInitializer(); + else + FRI->RangeExpr = ParseExpression(); + } + Decl *ThisDecl = Actions.ActOnDeclarator(getCurScope(), D); - Actions.ActOnCXXForRangeDecl(ThisDecl); + if (IsForRangeLoop) + Actions.ActOnCXXForRangeDecl(ThisDecl); Actions.FinalizeDeclaration(ThisDecl); D.complete(ThisDecl); return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, &ThisDecl, 1); @@ -1691,8 +1820,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, } } - bool TypeContainsAuto = - D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; + bool TypeContainsAuto = D.getDeclSpec().containsPlaceholderType(); // Parse declarator '=' initializer. // If a '==' or '+=' is found, suggest a fixit to '='. @@ -1839,7 +1967,8 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS, if (DS.getStorageClassSpecLoc().isValid()) Diag(DS.getStorageClassSpecLoc(),diag::err_typename_invalid_storageclass); else - Diag(DS.getThreadSpecLoc(), diag::err_typename_invalid_storageclass); + Diag(DS.getThreadStorageClassSpecLoc(), + diag::err_typename_invalid_storageclass); DS.ClearStorageClassSpecs(); } @@ -1920,10 +2049,9 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, // error, do lookahead to try to do better recovery. This never applies // within a type specifier. Outside of C++, we allow this even if the // language doesn't "officially" support implicit int -- we support - // implicit int as an extension in C99 and C11. Allegedly, MS also - // supports implicit int in C++ mode. + // implicit int as an extension in C99 and C11. if (DSC != DSC_type_specifier && DSC != DSC_trailing && - (!getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt) && + !getLangOpts().CPlusPlus && isValidAfterIdentifierInDeclarator(NextToken())) { // If this token is valid for implicit int, e.g. "static x = 4", then // we just avoid eating the identifier, so it will be parsed as the @@ -2172,6 +2300,8 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, /// 'auto' /// 'register' /// [C++] 'mutable' +/// [C++11] 'thread_local' +/// [C11] '_Thread_local' /// [GNU] '__thread' /// function-specifier: [C99 6.7.4] /// [C99] 'inline' @@ -2608,7 +2738,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, PrevSpec, DiagID); break; case tok::kw_extern: - if (DS.isThreadSpecified()) + if (DS.getThreadStorageClassSpec() == DeclSpec::TSCS___thread) Diag(Tok, diag::ext_thread_before) << "extern"; isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_extern, Loc, PrevSpec, DiagID); @@ -2618,7 +2748,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, Loc, PrevSpec, DiagID); break; case tok::kw_static: - if (DS.isThreadSpecified()) + if (DS.getThreadStorageClassSpec() == DeclSpec::TSCS___thread) Diag(Tok, diag::ext_thread_before) << "static"; isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_static, Loc, PrevSpec, DiagID); @@ -2647,7 +2777,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, PrevSpec, DiagID); break; case tok::kw___thread: - isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec, DiagID); + isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS___thread, Loc, + PrevSpec, DiagID); + break; + case tok::kw_thread_local: + isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS_thread_local, Loc, + PrevSpec, DiagID); + break; + case tok::kw__Thread_local: + isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS__Thread_local, + Loc, PrevSpec, DiagID); break; // function-specifier @@ -3100,6 +3239,16 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, continue; } + if (Tok.is(tok::annot_pragma_pack)) { + HandlePragmaPack(); + continue; + } + + if (Tok.is(tok::annot_pragma_align)) { + HandlePragmaAlign(); + continue; + } + if (!Tok.is(tok::at)) { struct CFieldCallback : FieldCallback { Parser &P; @@ -3227,9 +3376,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, bool IsScopedUsingClassTag = false; // In C++11, recognize 'enum class' and 'enum struct'. - if (getLangOpts().CPlusPlus11 && - (Tok.is(tok::kw_class) || Tok.is(tok::kw_struct))) { - Diag(Tok, diag::warn_cxx98_compat_scoped_enum); + if (Tok.is(tok::kw_class) || Tok.is(tok::kw_struct)) { + Diag(Tok, getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_scoped_enum + : diag::ext_scoped_enum); IsScopedUsingClassTag = Tok.is(tok::kw_class); ScopedEnumKWLoc = ConsumeToken(); @@ -3614,8 +3763,8 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { MaybeParseGNUAttributes(attrs); Actions.ActOnEnumBody(StartLoc, T.getOpenLocation(), T.getCloseLocation(), - EnumDecl, EnumConstantDecls.data(), - EnumConstantDecls.size(), getCurScope(), + EnumDecl, EnumConstantDecls, + getCurScope(), attrs.getList()); EnumScope.Exit(); @@ -3894,6 +4043,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw_auto: case tok::kw_register: case tok::kw___thread: + case tok::kw_thread_local: + case tok::kw__Thread_local: // Modules case tok::kw___module_private__: @@ -4873,7 +5024,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D, Sema::CXXThisScopeRAII ThisScope(Actions, dyn_cast<CXXRecordDecl>(Actions.CurContext), DS.getTypeQualifiers() | - (D.getDeclSpec().isConstexprSpecified() + (D.getDeclSpec().isConstexprSpecified() && + !getLangOpts().CPlusPlus1y ? Qualifiers::Const : 0), IsCXX11MemberFunction); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index d7f8e98..f1fbbb1 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -674,15 +674,15 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ T.getCloseLocation()); } -/// ParseDecltypeSpecifier - Parse a C++0x decltype specifier. +/// ParseDecltypeSpecifier - Parse a C++11 decltype specifier. /// /// 'decltype' ( expression ) +/// 'decltype' ( 'auto' ) [C++1y] /// SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { assert((Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype)) && "Not a decltype specifier"); - ExprResult Result; SourceLocation StartLoc = Tok.getLocation(); SourceLocation EndLoc; @@ -709,29 +709,44 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { StartLoc : T.getOpenLocation(); } - // Parse the expression - - // C++0x [dcl.type.simple]p4: - // The operand of the decltype specifier is an unevaluated operand. - EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated, - 0, /*IsDecltype=*/true); - Result = ParseExpression(); - if (Result.isInvalid()) { - DS.SetTypeSpecError(); - if (SkipUntil(tok::r_paren, /*StopAtSemi=*/true, /*DontConsume=*/true)) { - EndLoc = ConsumeParen(); - } else { - if (PP.isBacktrackEnabled() && Tok.is(tok::semi)) { - // Backtrack to get the location of the last token before the semi. - PP.RevertCachedTokens(2); - ConsumeToken(); // the semi. - EndLoc = ConsumeAnyToken(); - assert(Tok.is(tok::semi)); + // Check for C++1y 'decltype(auto)'. + if (Tok.is(tok::kw_auto)) { + // No need to disambiguate here: an expression can't start with 'auto', + // because the typename-specifier in a function-style cast operation can't + // be 'auto'. + Diag(Tok.getLocation(), + getLangOpts().CPlusPlus1y + ? diag::warn_cxx11_compat_decltype_auto_type_specifier + : diag::ext_decltype_auto_type_specifier); + ConsumeToken(); + } else { + // Parse the expression + + // C++11 [dcl.type.simple]p4: + // The operand of the decltype specifier is an unevaluated operand. + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated, + 0, /*IsDecltype=*/true); + Result = ParseExpression(); + if (Result.isInvalid()) { + DS.SetTypeSpecError(); + if (SkipUntil(tok::r_paren, /*StopAtSemi=*/true, + /*DontConsume=*/true)) { + EndLoc = ConsumeParen(); } else { - EndLoc = Tok.getLocation(); + if (PP.isBacktrackEnabled() && Tok.is(tok::semi)) { + // Backtrack to get the location of the last token before the semi. + PP.RevertCachedTokens(2); + ConsumeToken(); // the semi. + EndLoc = ConsumeAnyToken(); + assert(Tok.is(tok::semi)); + } else { + EndLoc = Tok.getLocation(); + } } + return EndLoc; } - return EndLoc; + + Result = Actions.ActOnDecltypeExpression(Result.take()); } // Match the ')' @@ -743,7 +758,6 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { return T.getCloseLocation(); } - Result = Actions.ActOnDecltypeExpression(Result.take()); if (Result.isInvalid()) { DS.SetTypeSpecError(); return T.getCloseLocation(); @@ -751,12 +765,16 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { EndLoc = T.getCloseLocation(); } + assert(!Result.isInvalid()); const char *PrevSpec = 0; unsigned DiagID; // Check for duplicate type specifiers (e.g. "int decltype(a)"). - if (DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc, PrevSpec, - DiagID, Result.release())) { + if (Result.get() + ? DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc, PrevSpec, + DiagID, Result.release()) + : DS.SetTypeSpecType(DeclSpec::TST_decltype_auto, StartLoc, PrevSpec, + DiagID)) { Diag(StartLoc, DiagID) << PrevSpec; DS.SetTypeSpecError(); } @@ -773,8 +791,10 @@ void Parser::AnnotateExistingDecltypeSpecifier(const DeclSpec& DS, PP.EnterToken(Tok); Tok.setKind(tok::annot_decltype); - setExprAnnotation(Tok, DS.getTypeSpecType() == TST_decltype ? - DS.getRepAsExpr() : ExprResult()); + setExprAnnotation(Tok, + DS.getTypeSpecType() == TST_decltype ? DS.getRepAsExpr() : + DS.getTypeSpecType() == TST_decltype_auto ? ExprResult() : + ExprError()); Tok.setAnnotationEndLoc(EndLoc); Tok.setLocation(StartLoc); PP.AnnotateCachedTokens(Tok); @@ -2267,11 +2287,10 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SkipUntil(tok::comma, true, true); else if (ThisDecl) Actions.AddInitializerToDecl(ThisDecl, Init.get(), EqualLoc.isInvalid(), - DS.getTypeSpecType() == DeclSpec::TST_auto); + DS.containsPlaceholderType()); } else if (ThisDecl && DS.getStorageClassSpec() == DeclSpec::SCS_static) { // No initializer. - Actions.ActOnUninitializedDecl(ThisDecl, - DS.getTypeSpecType() == DeclSpec::TST_auto); + Actions.ActOnUninitializedDecl(ThisDecl, DS.containsPlaceholderType()); } if (ThisDecl) { diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 956ba36..9521ffb 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -691,8 +691,14 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, Res = getExprAnnotation(Tok); ConsumeToken(); break; - + case tok::kw_decltype: + // Annotate the token and tail recurse. + if (TryAnnotateTypeOrScopeToken()) + return ExprError(); + assert(Tok.isNot(tok::kw_decltype)); + return ParseCastExpression(isUnaryExpression, isAddressOfOperand); + case tok::identifier: { // primary-expression: identifier // unqualified-id: identifier // constant: enumeration-constant @@ -1408,8 +1414,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { CommaLocsTy CommaLocs; if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteCall(getCurScope(), LHS.get(), - ArrayRef<Expr *>()); + Actions.CodeCompleteCall(getCurScope(), LHS.get(), None); cutOffParsing(); return ExprError(); } diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 17c4adf..f259d5f 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -1455,7 +1455,9 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut, if (!InitExpr.isInvalid()) Actions.AddInitializerToDecl(DeclOut, InitExpr.take(), !CopyInitialization, - DS.getTypeSpecType() == DeclSpec::TST_auto); + DS.containsPlaceholderType()); + else + Actions.ActOnInitializerError(DeclOut); // FIXME: Build a reference to this declaration? Convert it to bool? // (This is currently handled by Sema). @@ -2033,7 +2035,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, // Parse the conversion-declarator, which is merely a sequence of // ptr-operators. - Declarator D(DS, Declarator::TypeNameContext); + Declarator D(DS, Declarator::ConversionIdContext); ParseDeclaratorInternal(D, /*DirectDeclParser=*/0); // Finish up the type. diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index 3b96717..8311aa2 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -412,7 +412,7 @@ ExprResult Parser::ParseBraceInitializer() { if (!getLangOpts().CPlusPlus) Diag(LBraceLoc, diag::ext_gnu_empty_initializer); // Match the '}'. - return Actions.ActOnInitList(LBraceLoc, MultiExprArg(), ConsumeBrace()); + return Actions.ActOnInitList(LBraceLoc, None, ConsumeBrace()); } bool InitExprsOk = true; diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index ad95dd5..4a572f1 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -1565,6 +1565,13 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { if (Tok.is(tok::l_brace)) // we have ivars ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc); + else if (Tok.is(tok::less)) { // we have illegal '<' try to recover + Diag(Tok, diag::err_unexpected_protocol_qualifier); + // try to recover. + AttributeFactory attr; + DeclSpec DS(attr); + (void)ParseObjCProtocolQualifiers(DS); + } } assert(ObjCImpDecl); @@ -1675,7 +1682,7 @@ Decl *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) { /// Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { assert(Tok.isObjCAtKeyword(tok::objc_synthesize) && - "ParseObjCPropertyDynamic(): Expected '@synthesize'"); + "ParseObjCPropertySynthesize(): Expected '@synthesize'"); ConsumeToken(); // consume synthesize while (true) { @@ -2501,7 +2508,14 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, return ExprError(); } - ExprResult Res(ParseAssignmentExpression()); + ExprResult Expr; + if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) { + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); + Expr = ParseBraceInitializer(); + } else + Expr = ParseAssignmentExpression(); + + ExprResult Res(Expr); if (Res.isInvalid()) { // We must manually skip to a ']', otherwise the expression skipper will // stop at the ']' when it skips to the ';'. We want it to skip beyond @@ -2747,7 +2761,9 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) { if (Tok.is(tok::colon)) { ConsumeToken(); } else { - return ExprError(Diag(Tok, diag::err_expected_colon)); + Diag(Tok, diag::err_expected_colon); + SkipUntil(tok::r_brace); + return ExprError(); } ExprResult ValueExpr(ParseAssignmentExpression()); diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp index dc6b3ed..3d1249a 100644 --- a/lib/Parse/ParsePragma.cpp +++ b/lib/Parse/ParsePragma.cpp @@ -15,6 +15,8 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" +#include "clang/Sema/Scope.h" +#include "llvm/ADT/StringSwitch.h" using namespace clang; /// \brief Handle the annotation token produced for #pragma unused(...) @@ -122,6 +124,33 @@ void Parser::HandlePragmaFPContract() { ConsumeToken(); // The annotation token. } +StmtResult Parser::HandlePragmaCaptured() +{ + assert(Tok.is(tok::annot_pragma_captured)); + ConsumeToken(); + + if (Tok.isNot(tok::l_brace)) { + PP.Diag(Tok, diag::err_expected_lbrace); + return StmtError(); + } + + SourceLocation Loc = Tok.getLocation(); + + ParseScope CapturedRegionScope(this, Scope::FnScope | Scope::DeclScope); + Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_Default, + /*NumParams=*/1); + + StmtResult R = ParseCompoundStatement(); + CapturedRegionScope.Exit(); + + if (R.isInvalid()) { + Actions.ActOnCapturedRegionError(); + return StmtError(); + } + + return Actions.ActOnCapturedRegionEnd(R.get()); +} + namespace { typedef llvm::PointerIntPair<IdentifierInfo *, 1, bool> OpenCLExtData; } @@ -151,6 +180,8 @@ void Parser::HandlePragmaOpenCLExtension() { } } + + // #pragma GCC visibility comes in two variants: // 'push' '(' [visibility] ')' // 'pop' @@ -762,3 +793,68 @@ PragmaOpenMPHandler::HandlePragma(Preprocessor &PP, PP.EnterTokenStream(Toks, Pragma.size(), /*DisableMacroExpansion=*/true, /*OwnsTokens=*/true); } + +/// \brief Handle the microsoft \#pragma comment extension. +/// +/// The syntax is: +/// \code +/// #pragma comment(linker, "foo") +/// \endcode +/// 'linker' is one of five identifiers: compiler, exestr, lib, linker, user. +/// "foo" is a string, which is fully macro expanded, and permits string +/// concatenation, embedded escape characters etc. See MSDN for more details. +void PragmaCommentHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &Tok) { + SourceLocation CommentLoc = Tok.getLocation(); + PP.Lex(Tok); + if (Tok.isNot(tok::l_paren)) { + PP.Diag(CommentLoc, diag::err_pragma_comment_malformed); + return; + } + + // Read the identifier. + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(CommentLoc, diag::err_pragma_comment_malformed); + return; + } + + // Verify that this is one of the 5 whitelisted options. + // FIXME: warn that 'exestr' is deprecated. + const IdentifierInfo *II = Tok.getIdentifierInfo(); + if (!II->isStr("compiler") && !II->isStr("exestr") && !II->isStr("lib") && + !II->isStr("linker") && !II->isStr("user")) { + PP.Diag(Tok.getLocation(), diag::err_pragma_comment_unknown_kind); + return; + } + + // Read the optional string if present. + PP.Lex(Tok); + std::string ArgumentString; + if (Tok.is(tok::comma) && !PP.LexStringLiteral(Tok, ArgumentString, + "pragma comment", + /*MacroExpansion=*/true)) + return; + + // FIXME: If the kind is "compiler" warn if the string is present (it is + // ignored). + // FIXME: 'lib' requires a comment string. + // FIXME: 'linker' requires a comment string, and has a specific list of + // things that are allowable. + + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Tok.getLocation(), diag::err_pragma_comment_malformed); + return; + } + PP.Lex(Tok); // eat the r_paren. + + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok.getLocation(), diag::err_pragma_comment_malformed); + return; + } + + // If the pragma is lexically sound, notify any interested PPCallbacks. + if (PP.getPPCallbacks()) + PP.getPPCallbacks()->PragmaComment(CommentLoc, II, ArgumentString); +} diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h index 841a60b..d9560f3 100644 --- a/lib/Parse/ParsePragma.h +++ b/lib/Parse/ParsePragma.h @@ -113,6 +113,14 @@ public: Token &FirstToken); }; +/// PragmaCommentHandler - "\#pragma comment ...". +class PragmaCommentHandler : public PragmaHandler { +public: + PragmaCommentHandler() : PragmaHandler("comment") {} + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); +}; + } // end namespace clang #endif diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 355f369..43b6965 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -14,13 +14,26 @@ #include "clang/Parse/Parser.h" #include "RAIIObjectsForParser.h" +#include "clang/AST/ASTContext.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Scope.h" #include "clang/Sema/TypoCorrection.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetAsmParser.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" #include "llvm/ADT/SmallString.h" using namespace clang; @@ -289,6 +302,9 @@ Retry: HandlePragmaOpenCLExtension(); return StmtEmpty(); + case tok::annot_pragma_captured: + return HandlePragmaCaptured(); + case tok::annot_pragma_openmp: SourceLocation DeclStart = Tok.getLocation(); DeclGroupPtrTy Res = ParseOpenMPDeclarativeDirective(); @@ -1660,6 +1676,281 @@ StmtResult Parser::ParseReturnStatement() { return Actions.ActOnReturnStmt(ReturnLoc, R.take()); } +namespace { + class ClangAsmParserCallback : public llvm::MCAsmParserSemaCallback { + Parser &TheParser; + SourceLocation AsmLoc; + StringRef AsmString; + + /// The tokens we streamed into AsmString and handed off to MC. + ArrayRef<Token> AsmToks; + + /// The offset of each token in AsmToks within AsmString. + ArrayRef<unsigned> AsmTokOffsets; + + public: + ClangAsmParserCallback(Parser &P, SourceLocation Loc, + StringRef AsmString, + ArrayRef<Token> Toks, + ArrayRef<unsigned> Offsets) + : TheParser(P), AsmLoc(Loc), AsmString(AsmString), + AsmToks(Toks), AsmTokOffsets(Offsets) { + assert(AsmToks.size() == AsmTokOffsets.size()); + } + + void *LookupInlineAsmIdentifier(StringRef &LineBuf, + InlineAsmIdentifierInfo &Info, + bool IsUnevaluatedContext) { + // Collect the desired tokens. + SmallVector<Token, 16> LineToks; + const Token *FirstOrigToken = 0; + findTokensForString(LineBuf, LineToks, FirstOrigToken); + + unsigned NumConsumedToks; + ExprResult Result = + TheParser.ParseMSAsmIdentifier(LineToks, NumConsumedToks, &Info, + IsUnevaluatedContext); + + // If we consumed the entire line, tell MC that. + // Also do this if we consumed nothing as a way of reporting failure. + if (NumConsumedToks == 0 || NumConsumedToks == LineToks.size()) { + // By not modifying LineBuf, we're implicitly consuming it all. + + // Otherwise, consume up to the original tokens. + } else { + assert(FirstOrigToken && "not using original tokens?"); + + // Since we're using original tokens, apply that offset. + assert(FirstOrigToken[NumConsumedToks].getLocation() + == LineToks[NumConsumedToks].getLocation()); + unsigned FirstIndex = FirstOrigToken - AsmToks.begin(); + unsigned LastIndex = FirstIndex + NumConsumedToks - 1; + + // The total length we've consumed is the relative offset + // of the last token we consumed plus its length. + unsigned TotalOffset = (AsmTokOffsets[LastIndex] + + AsmToks[LastIndex].getLength() + - AsmTokOffsets[FirstIndex]); + LineBuf = LineBuf.substr(0, TotalOffset); + } + + // Initialize the "decl" with the lookup result. + Info.OpDecl = static_cast<void*>(Result.take()); + return Info.OpDecl; + } + + bool LookupInlineAsmField(StringRef Base, StringRef Member, + unsigned &Offset) { + return TheParser.getActions().LookupInlineAsmField(Base, Member, + Offset, AsmLoc); + } + + static void DiagHandlerCallback(const llvm::SMDiagnostic &D, + void *Context) { + ((ClangAsmParserCallback*) Context)->handleDiagnostic(D); + } + + private: + /// Collect the appropriate tokens for the given string. + void findTokensForString(StringRef Str, SmallVectorImpl<Token> &TempToks, + const Token *&FirstOrigToken) const { + // For now, assert that the string we're working with is a substring + // of what we gave to MC. This lets us use the original tokens. + assert(!std::less<const char*>()(Str.begin(), AsmString.begin()) && + !std::less<const char*>()(AsmString.end(), Str.end())); + + // Try to find a token whose offset matches the first token. + unsigned FirstCharOffset = Str.begin() - AsmString.begin(); + const unsigned *FirstTokOffset + = std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), + FirstCharOffset); + + // For now, assert that the start of the string exactly + // corresponds to the start of a token. + assert(*FirstTokOffset == FirstCharOffset); + + // Use all the original tokens for this line. (We assume the + // end of the line corresponds cleanly to a token break.) + unsigned FirstTokIndex = FirstTokOffset - AsmTokOffsets.begin(); + FirstOrigToken = &AsmToks[FirstTokIndex]; + unsigned LastCharOffset = Str.end() - AsmString.begin(); + for (unsigned i = FirstTokIndex, e = AsmTokOffsets.size(); i != e; ++i) { + if (AsmTokOffsets[i] >= LastCharOffset) break; + TempToks.push_back(AsmToks[i]); + } + } + + void handleDiagnostic(const llvm::SMDiagnostic &D) { + // Compute an offset into the inline asm buffer. + // FIXME: This isn't right if .macro is involved (but hopefully, no + // real-world code does that). + const llvm::SourceMgr &LSM = *D.getSourceMgr(); + const llvm::MemoryBuffer *LBuf = + LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc())); + unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart(); + + // Figure out which token that offset points into. + const unsigned *TokOffsetPtr = + std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), Offset); + unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin(); + unsigned TokOffset = *TokOffsetPtr; + + // If we come up with an answer which seems sane, use it; otherwise, + // just point at the __asm keyword. + // FIXME: Assert the answer is sane once we handle .macro correctly. + SourceLocation Loc = AsmLoc; + if (TokIndex < AsmToks.size()) { + const Token &Tok = AsmToks[TokIndex]; + Loc = Tok.getLocation(); + Loc = Loc.getLocWithOffset(Offset - TokOffset); + } + TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing) + << D.getMessage(); + } + }; +} + +/// Parse an identifier in an MS-style inline assembly block. +/// +/// \param CastInfo - a void* so that we don't have to teach Parser.h +/// about the actual type. +ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks, + unsigned &NumLineToksConsumed, + void *CastInfo, + bool IsUnevaluatedContext) { + llvm::InlineAsmIdentifierInfo &Info = + *(llvm::InlineAsmIdentifierInfo *) CastInfo; + + // Push a fake token on the end so that we don't overrun the token + // stream. We use ';' because it expression-parsing should never + // overrun it. + const tok::TokenKind EndOfStream = tok::semi; + Token EndOfStreamTok; + EndOfStreamTok.startToken(); + EndOfStreamTok.setKind(EndOfStream); + LineToks.push_back(EndOfStreamTok); + + // Also copy the current token over. + LineToks.push_back(Tok); + + PP.EnterTokenStream(LineToks.begin(), + LineToks.size(), + /*disable macros*/ true, + /*owns tokens*/ false); + + // Clear the current token and advance to the first token in LineToks. + ConsumeAnyToken(); + + // Parse an optional scope-specifier if we're in C++. + CXXScopeSpec SS; + if (getLangOpts().CPlusPlus) { + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); + } + + // Require an identifier here. + SourceLocation TemplateKWLoc; + UnqualifiedId Id; + bool Invalid = ParseUnqualifiedId(SS, + /*EnteringContext=*/false, + /*AllowDestructorName=*/false, + /*AllowConstructorName=*/false, + /*ObjectType=*/ ParsedType(), + TemplateKWLoc, + Id); + + // If we've run into the poison token we inserted before, or there + // was a parsing error, then claim the entire line. + if (Invalid || Tok.is(EndOfStream)) { + NumLineToksConsumed = LineToks.size() - 2; + + // Otherwise, claim up to the start of the next token. + } else { + // Figure out how many tokens we are into LineToks. + unsigned LineIndex = 0; + while (LineToks[LineIndex].getLocation() != Tok.getLocation()) { + LineIndex++; + assert(LineIndex < LineToks.size() - 2); // we added two extra tokens + } + + NumLineToksConsumed = LineIndex; + } + + // Finally, restore the old parsing state by consuming all the + // tokens we staged before, implicitly killing off the + // token-lexer we pushed. + for (unsigned n = LineToks.size() - 2 - NumLineToksConsumed; n != 0; --n) { + ConsumeAnyToken(); + } + ConsumeToken(EndOfStream); + + // Leave LineToks in its original state. + LineToks.pop_back(); + LineToks.pop_back(); + + // Perform the lookup. + return Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, Info, + IsUnevaluatedContext); +} + +/// Turn a sequence of our tokens back into a string that we can hand +/// to the MC asm parser. +static bool buildMSAsmString(Preprocessor &PP, + SourceLocation AsmLoc, + ArrayRef<Token> AsmToks, + SmallVectorImpl<unsigned> &TokOffsets, + SmallString<512> &Asm) { + assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!"); + + // Is this the start of a new assembly statement? + bool isNewStatement = true; + + for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) { + const Token &Tok = AsmToks[i]; + + // Start each new statement with a newline and a tab. + if (!isNewStatement && + (Tok.is(tok::kw_asm) || Tok.isAtStartOfLine())) { + Asm += "\n\t"; + isNewStatement = true; + } + + // Preserve the existence of leading whitespace except at the + // start of a statement. + if (!isNewStatement && Tok.hasLeadingSpace()) + Asm += ' '; + + // Remember the offset of this token. + TokOffsets.push_back(Asm.size()); + + // Don't actually write '__asm' into the assembly stream. + if (Tok.is(tok::kw_asm)) { + // Complain about __asm at the end of the stream. + if (i + 1 == e) { + PP.Diag(AsmLoc, diag::err_asm_empty); + return true; + } + + continue; + } + + // Append the spelling of the token. + SmallString<32> SpellingBuffer; + bool SpellingInvalid = false; + Asm += PP.getSpelling(Tok, SpellingBuffer, &SpellingInvalid); + assert(!SpellingInvalid && "spelling was invalid after correct parse?"); + + // We are no longer at the start of a statement. + isNewStatement = false; + } + + // Ensure that the buffer is null-terminated. + Asm.push_back('\0'); + Asm.pop_back(); + + assert(TokOffsets.size() == AsmToks.size()); + return false; +} + /// ParseMicrosoftAsmStatement. When -fms-extensions/-fasm-blocks is enabled, /// this routine is called to collect the tokens for an MS asm statement. /// @@ -1768,9 +2059,114 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { return StmtError(); } + // Okay, prepare to use MC to parse the assembly. + SmallVector<StringRef, 4> ConstraintRefs; + SmallVector<Expr*, 4> Exprs; + SmallVector<StringRef, 4> ClobberRefs; + + // We need an actual supported target. + llvm::Triple TheTriple = Actions.Context.getTargetInfo().getTriple(); + llvm::Triple::ArchType ArchTy = TheTriple.getArch(); + bool UnsupportedArch = (ArchTy != llvm::Triple::x86 && + ArchTy != llvm::Triple::x86_64); + if (UnsupportedArch) + Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName(); + + // If we don't support assembly, or the assembly is empty, we don't + // need to instantiate the AsmParser, etc. + if (UnsupportedArch || AsmToks.empty()) { + return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, StringRef(), + /*NumOutputs*/ 0, /*NumInputs*/ 0, + ConstraintRefs, ClobberRefs, Exprs, EndLoc); + } + + // Expand the tokens into a string buffer. + SmallString<512> AsmString; + SmallVector<unsigned, 8> TokOffsets; + if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString)) + return StmtError(); + + // Find the target and create the target specific parser. + std::string Error; + const std::string &TT = TheTriple.getTriple(); + const llvm::Target *TheTarget = llvm::TargetRegistry::lookupTarget(TT, Error); + + OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TT)); + OwningPtr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT)); + OwningPtr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo()); + OwningPtr<llvm::MCSubtargetInfo> + STI(TheTarget->createMCSubtargetInfo(TT, "", "")); + + llvm::SourceMgr TempSrcMgr; + llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &TempSrcMgr); + llvm::MemoryBuffer *Buffer = + llvm::MemoryBuffer::getMemBuffer(AsmString, "<MS inline asm>"); + + // Tell SrcMgr about this buffer, which is what the parser will pick up. + TempSrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc()); + + OwningPtr<llvm::MCStreamer> Str(createNullStreamer(Ctx)); + OwningPtr<llvm::MCAsmParser> + Parser(createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI)); + OwningPtr<llvm::MCTargetAsmParser> + TargetParser(TheTarget->createMCAsmParser(*STI, *Parser)); + + // Get the instruction descriptor. + const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo(); + llvm::MCInstPrinter *IP = + TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI); + + // Change to the Intel dialect. + Parser->setAssemblerDialect(1); + Parser->setTargetParser(*TargetParser.get()); + Parser->setParsingInlineAsm(true); + TargetParser->setParsingInlineAsm(true); + + ClangAsmParserCallback Callback(*this, AsmLoc, AsmString, + AsmToks, TokOffsets); + TargetParser->setSemaCallback(&Callback); + TempSrcMgr.setDiagHandler(ClangAsmParserCallback::DiagHandlerCallback, + &Callback); + + unsigned NumOutputs; + unsigned NumInputs; + std::string AsmStringIR; + SmallVector<std::pair<void *, bool>, 4> OpExprs; + SmallVector<std::string, 4> Constraints; + SmallVector<std::string, 4> Clobbers; + if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR, + NumOutputs, NumInputs, OpExprs, Constraints, + Clobbers, MII, IP, Callback)) + return StmtError(); + + // Build the vector of clobber StringRefs. + unsigned NumClobbers = Clobbers.size(); + ClobberRefs.resize(NumClobbers); + for (unsigned i = 0; i != NumClobbers; ++i) + ClobberRefs[i] = StringRef(Clobbers[i]); + + // Recast the void pointers and build the vector of constraint StringRefs. + unsigned NumExprs = NumOutputs + NumInputs; + ConstraintRefs.resize(NumExprs); + Exprs.resize(NumExprs); + for (unsigned i = 0, e = NumExprs; i != e; ++i) { + Expr *OpExpr = static_cast<Expr *>(OpExprs[i].first); + if (!OpExpr) + return StmtError(); + + // Need address of variable. + if (OpExprs[i].second) + OpExpr = Actions.BuildUnaryOp(getCurScope(), AsmLoc, UO_AddrOf, OpExpr) + .take(); + + ConstraintRefs[i] = StringRef(Constraints[i]); + Exprs[i] = OpExpr; + } + // FIXME: We should be passing source locations for better diagnostics. - return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, - llvm::makeArrayRef(AsmToks), EndLoc); + return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, AsmStringIR, + NumOutputs, NumInputs, + ConstraintRefs, ClobberRefs, Exprs, EndLoc); } /// ParseAsmStatement - Parse a GNU extended asm statement. diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index f146669..84b7df7 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -39,28 +39,7 @@ Parser::ParseDeclarationStartingWithTemplate(unsigned Context, AccessAttrs); } -/// \brief RAII class that manages the template parameter depth. -namespace { - class TemplateParameterDepthCounter { - unsigned &Depth; - unsigned AddedLevels; - - public: - explicit TemplateParameterDepthCounter(unsigned &Depth) - : Depth(Depth), AddedLevels(0) { } - - ~TemplateParameterDepthCounter() { - Depth -= AddedLevels; - } - void operator++() { - ++Depth; - ++AddedLevels; - } - - operator unsigned() const { return Depth; } - }; -} /// \brief Parse a template declaration or an explicit specialization. /// @@ -117,7 +96,8 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, bool isSpecialization = true; bool LastParamListWasEmpty = false; TemplateParameterLists ParamLists; - TemplateParameterDepthCounter Depth(TemplateParameterDepth); + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); + do { // Consume the 'export', if any. SourceLocation ExportLoc; @@ -137,8 +117,8 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, // Parse the '<' template-parameter-list '>' SourceLocation LAngleLoc, RAngleLoc; SmallVector<Decl*, 4> TemplateParams; - if (ParseTemplateParameters(Depth, TemplateParams, LAngleLoc, - RAngleLoc)) { + if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(), + TemplateParams, LAngleLoc, RAngleLoc)) { // Skip until the semi-colon or a }. SkipUntil(tok::r_brace, true, true); if (Tok.is(tok::semi)) @@ -147,14 +127,15 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, } ParamLists.push_back( - Actions.ActOnTemplateParameterList(Depth, ExportLoc, + Actions.ActOnTemplateParameterList(CurTemplateDepthTracker.getDepth(), + ExportLoc, TemplateLoc, LAngleLoc, TemplateParams.data(), TemplateParams.size(), RAngleLoc)); if (!TemplateParams.empty()) { isSpecialization = false; - ++Depth; + ++CurTemplateDepthTracker; } else { LastParamListWasEmpty = true; } @@ -1168,6 +1149,9 @@ bool Parser::IsTemplateArgumentList(unsigned Skip) { /// template-argument-list ',' template-argument bool Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { + // Template argument lists are constant-evaluation contexts. + EnterExpressionEvaluationContext EvalContext(Actions,Sema::ConstantEvaluated); + while (true) { ParsedTemplateArgument Arg = ParseTemplateArgument(); if (Tok.is(tok::ellipsis)) { @@ -1249,53 +1233,56 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { return; // Get the FunctionDecl. - FunctionDecl *FD = 0; - if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(LMT.D)) - FD = FunTmpl->getTemplatedDecl(); - else - FD = cast<FunctionDecl>(LMT.D); + FunctionTemplateDecl *FunTmplD = dyn_cast<FunctionTemplateDecl>(LMT.D); + FunctionDecl *FunD = + FunTmplD ? FunTmplD->getTemplatedDecl() : cast<FunctionDecl>(LMT.D); + // Track template parameter depth. + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); // To restore the context after late parsing. Sema::ContextRAII GlobalSavedContext(Actions, Actions.CurContext); SmallVector<ParseScope*, 4> TemplateParamScopeStack; - DeclaratorDecl* Declarator = dyn_cast<DeclaratorDecl>(FD); - if (Declarator && Declarator->getNumTemplateParameterLists() != 0) { - TemplateParamScopeStack.push_back(new ParseScope(this, Scope::TemplateParamScope)); - Actions.ActOnReenterDeclaratorTemplateScope(getCurScope(), Declarator); - Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D); - } else { - // Get the list of DeclContext to reenter. - SmallVector<DeclContext*, 4> DeclContextToReenter; - DeclContext *DD = FD->getLexicalParent(); - while (DD && !DD->isTranslationUnit()) { - DeclContextToReenter.push_back(DD); - DD = DD->getLexicalParent(); - } - // Reenter template scopes from outmost to innermost. - SmallVector<DeclContext*, 4>::reverse_iterator II = - DeclContextToReenter.rbegin(); - for (; II != DeclContextToReenter.rend(); ++II) { - if (ClassTemplatePartialSpecializationDecl* MD = - dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(*II)) { - TemplateParamScopeStack.push_back(new ParseScope(this, - Scope::TemplateParamScope)); - Actions.ActOnReenterTemplateScope(getCurScope(), MD); - } else if (CXXRecordDecl* MD = dyn_cast_or_null<CXXRecordDecl>(*II)) { - TemplateParamScopeStack.push_back(new ParseScope(this, - Scope::TemplateParamScope, - MD->getDescribedClassTemplate() != 0 )); - Actions.ActOnReenterTemplateScope(getCurScope(), - MD->getDescribedClassTemplate()); - } - TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope)); - Actions.PushDeclContext(Actions.getCurScope(), *II); + // Get the list of DeclContexts to reenter. + SmallVector<DeclContext*, 4> DeclContextsToReenter; + DeclContext *DD = FunD->getLexicalParent(); + while (DD && !DD->isTranslationUnit()) { + DeclContextsToReenter.push_back(DD); + DD = DD->getLexicalParent(); + } + + // Reenter template scopes from outermost to innermost. + SmallVector<DeclContext*, 4>::reverse_iterator II = + DeclContextsToReenter.rbegin(); + for (; II != DeclContextsToReenter.rend(); ++II) { + if (ClassTemplatePartialSpecializationDecl *MD = + dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(*II)) { + TemplateParamScopeStack.push_back( + new ParseScope(this, Scope::TemplateParamScope)); + Actions.ActOnReenterTemplateScope(getCurScope(), MD); + ++CurTemplateDepthTracker; + } else if (CXXRecordDecl *MD = dyn_cast_or_null<CXXRecordDecl>(*II)) { + bool ManageScope = MD->getDescribedClassTemplate() != 0; + TemplateParamScopeStack.push_back( + new ParseScope(this, Scope::TemplateParamScope, ManageScope)); + Actions.ActOnReenterTemplateScope(getCurScope(), + MD->getDescribedClassTemplate()); + ++CurTemplateDepthTracker; } - TemplateParamScopeStack.push_back(new ParseScope(this, - Scope::TemplateParamScope)); - Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D); + TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope)); + Actions.PushDeclContext(Actions.getCurScope(), *II); } + TemplateParamScopeStack.push_back( + new ParseScope(this, Scope::TemplateParamScope)); + + DeclaratorDecl *Declarator = dyn_cast<DeclaratorDecl>(FunD); + if (Declarator && Declarator->getNumTemplateParameterLists() != 0) { + Actions.ActOnReenterDeclaratorTemplateScope(getCurScope(), Declarator); + ++CurTemplateDepthTracker; + } + Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D); + ++CurTemplateDepthTracker; assert(!LMT.Toks.empty() && "Empty body!"); @@ -1314,15 +1301,9 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope); // Recreate the containing function DeclContext. - Sema::ContextRAII FunctionSavedContext(Actions, Actions.getContainingDC(FD)); - - if (FunctionTemplateDecl *FunctionTemplate - = dyn_cast_or_null<FunctionTemplateDecl>(LMT.D)) - Actions.ActOnStartOfFunctionDef(getCurScope(), - FunctionTemplate->getTemplatedDecl()); - if (FunctionDecl *Function = dyn_cast_or_null<FunctionDecl>(LMT.D)) - Actions.ActOnStartOfFunctionDef(getCurScope(), Function); + Sema::ContextRAII FunctionSavedContext(Actions, Actions.getContainingDC(FunD)); + Actions.ActOnStartOfFunctionDef(getCurScope(), FunD); if (Tok.is(tok::kw_try)) { ParseFunctionTryBlock(LMT.D, FnScope); @@ -1333,8 +1314,12 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { Actions.ActOnDefaultCtorInitializers(LMT.D); if (Tok.is(tok::l_brace)) { + assert((!FunTmplD || FunTmplD->getTemplateParameters()->getDepth() < + TemplateParameterDepth) && + "TemplateParameterDepth should be greater than the depth of " + "current template being instantiated!"); ParseFunctionStatementBody(LMT.D, FnScope); - Actions.MarkAsLateParsedTemplate(FD, false); + Actions.MarkAsLateParsedTemplate(FunD, false); } else Actions.ActOnFinishFunctionBody(LMT.D, 0); } diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 5e0ef2b..dff3b64 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -837,11 +837,12 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw_char16_t: case tok::kw_char32_t: case tok::kw___underlying_type: - case tok::kw_thread_local: case tok::kw__Decimal32: case tok::kw__Decimal64: case tok::kw__Decimal128: case tok::kw___thread: + case tok::kw_thread_local: + case tok::kw__Thread_local: case tok::kw_typeof: case tok::kw___cdecl: case tok::kw___stdcall: @@ -893,7 +894,7 @@ bool Parser::isTentativelyDeclared(IdentifierInfo *II) { /// function-specifier /// 'friend' /// 'typedef' -/// [C++0x] 'constexpr' +/// [C++11] 'constexpr' /// [GNU] attributes declaration-specifiers[opt] /// /// storage-class-specifier: @@ -903,6 +904,8 @@ bool Parser::isTentativelyDeclared(IdentifierInfo *II) { /// 'mutable' /// 'auto' /// [GNU] '__thread' +/// [C++11] 'thread_local' +/// [C11] '_Thread_local' /// /// function-specifier: /// 'inline' @@ -937,8 +940,9 @@ bool Parser::isTentativelyDeclared(IdentifierInfo *II) { /// 'void' /// [GNU] typeof-specifier /// [GNU] '_Complex' -/// [C++0x] 'auto' [TODO] -/// [C++0x] 'decltype' ( expression ) +/// [C++11] 'auto' +/// [C++11] 'decltype' ( expression ) +/// [C++1y] 'decltype' ( 'auto' ) /// /// type-name: /// class-name @@ -1073,6 +1077,8 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case tok::kw_mutable: case tok::kw_auto: case tok::kw___thread: + case tok::kw_thread_local: + case tok::kw__Thread_local: // function-specifier case tok::kw_inline: case tok::kw_virtual: diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 1ebba3e..455139b 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -102,6 +102,11 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies) OpenMPHandler.reset(new PragmaNoOpenMPHandler()); PP.AddPragmaHandler(OpenMPHandler.get()); + if (getLangOpts().MicrosoftExt) { + MSCommentHandler.reset(new PragmaCommentHandler()); + PP.AddPragmaHandler(MSCommentHandler.get()); + } + CommentSemaHandler.reset(new ActionCommentHandler(actions)); PP.addCommentHandler(CommentSemaHandler.get()); @@ -436,6 +441,11 @@ Parser::~Parser() { PP.RemovePragmaHandler(OpenMPHandler.get()); OpenMPHandler.reset(); + if (getLangOpts().MicrosoftExt) { + PP.RemovePragmaHandler(MSCommentHandler.get()); + MSCommentHandler.reset(); + } + PP.RemovePragmaHandler("STDC", FPContractHandler.get()); FPContractHandler.reset(); @@ -1141,8 +1151,8 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { diag::err_invalid_storage_class_in_func_decl); DS.ClearStorageClassSpecs(); } - if (DS.isThreadSpecified()) { - Diag(DS.getThreadSpecLoc(), + if (DS.getThreadStorageClassSpec() != DeclSpec::TSCS_unspecified) { + Diag(DS.getThreadStorageClassSpecLoc(), diag::err_invalid_storage_class_in_func_decl); DS.ClearStorageClassSpecs(); } diff --git a/lib/Rewrite/Frontend/FixItRewriter.cpp b/lib/Rewrite/Frontend/FixItRewriter.cpp index a3bbdcf..166c607 100644 --- a/lib/Rewrite/Frontend/FixItRewriter.cpp +++ b/lib/Rewrite/Frontend/FixItRewriter.cpp @@ -197,9 +197,4 @@ void FixItRewriter::Diag(SourceLocation Loc, unsigned DiagID) { Diags.setClient(this); } -DiagnosticConsumer *FixItRewriter::clone(DiagnosticsEngine &Diags) const { - return new FixItRewriter(Diags, Diags.getSourceManager(), - Rewrite.getLangOpts(), FixItOpts); -} - FixItOptions::~FixItOptions() {} diff --git a/lib/Rewrite/Frontend/InclusionRewriter.cpp b/lib/Rewrite/Frontend/InclusionRewriter.cpp index d95fb07..878be84 100644 --- a/lib/Rewrite/Frontend/InclusionRewriter.cpp +++ b/lib/Rewrite/Frontend/InclusionRewriter.cpp @@ -15,7 +15,9 @@ #include "clang/Rewrite/Frontend/Rewriters.h" #include "clang/Basic/SourceManager.h" #include "clang/Frontend/PreprocessorOutputOptions.h" +#include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -27,10 +29,11 @@ class InclusionRewriter : public PPCallbacks { /// Information about which #includes were actually performed, /// created by preprocessor callbacks. struct FileChange { + const Module *Mod; SourceLocation From; FileID Id; SrcMgr::CharacteristicKind FileType; - FileChange(SourceLocation From) : From(From) { + FileChange(SourceLocation From, const Module *Mod) : Mod(Mod), From(From) { } }; Preprocessor &PP; ///< Used to find inclusion directives. @@ -65,6 +68,7 @@ private: void WriteLineInfo(const char *Filename, int Line, SrcMgr::CharacteristicKind FileType, StringRef EOL, StringRef Extra = StringRef()); + void WriteImplicitModuleImport(const Module *Mod, StringRef EOL); void OutputContentUpTo(const MemoryBuffer &FromFile, unsigned &WriteFrom, unsigned WriteTo, StringRef EOL, int &lines, @@ -72,6 +76,9 @@ private: void CommentOutDirective(Lexer &DirectivesLex, const Token &StartToken, const MemoryBuffer &FromFile, StringRef EOL, unsigned &NextToWrite, int &Lines); + bool HandleHasInclude(FileID FileId, Lexer &RawLex, + const DirectoryLookup *Lookup, Token &Tok, + bool &FileExists); const FileChange *FindFileChangeLocation(SourceLocation Loc) const; StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken); }; @@ -117,6 +124,12 @@ void InclusionRewriter::WriteLineInfo(const char *Filename, int Line, OS << EOL; } +void InclusionRewriter::WriteImplicitModuleImport(const Module *Mod, + StringRef EOL) { + OS << "@import " << Mod->getFullModuleName() << ";" + << " /* clang -frewrite-includes: implicit import */" << EOL; +} + /// FileChanged - Whenever the preprocessor enters or exits a #include file /// it invokes this handler. void InclusionRewriter::FileChanged(SourceLocation Loc, @@ -157,13 +170,14 @@ void InclusionRewriter::InclusionDirective(SourceLocation HashLoc, const FileEntry * /*File*/, StringRef /*SearchPath*/, StringRef /*RelativePath*/, - const Module * /*Imported*/) { + const Module *Imported) { assert(LastInsertedFileChange == FileChanges.end() && "Another inclusion " "directive was found before the previous one was processed"); std::pair<FileChangeMap::iterator, bool> p = FileChanges.insert( - std::make_pair(HashLoc.getRawEncoding(), FileChange(HashLoc))); + std::make_pair(HashLoc.getRawEncoding(), FileChange(HashLoc, Imported))); assert(p.second && "Unexpected revisitation of the same include directive"); - LastInsertedFileChange = p.first; + if (!Imported) + LastInsertedFileChange = p.first; } /// Simple lookup for a SourceLocation (specifically one denoting the hash in @@ -245,6 +259,75 @@ StringRef InclusionRewriter::NextIdentifierName(Lexer &RawLex, return StringRef(); } +// Expand __has_include and __has_include_next if possible. If there's no +// definitive answer return false. +bool InclusionRewriter::HandleHasInclude( + FileID FileId, Lexer &RawLex, const DirectoryLookup *Lookup, Token &Tok, + bool &FileExists) { + // Lex the opening paren. + RawLex.LexFromRawLexer(Tok); + if (Tok.isNot(tok::l_paren)) + return false; + + RawLex.LexFromRawLexer(Tok); + + SmallString<128> FilenameBuffer; + StringRef Filename; + // Since the raw lexer doesn't give us angle_literals we have to parse them + // ourselves. + // FIXME: What to do if the file name is a macro? + if (Tok.is(tok::less)) { + RawLex.LexFromRawLexer(Tok); + + FilenameBuffer += '<'; + do { + if (Tok.is(tok::eod)) // Sanity check. + return false; + + if (Tok.is(tok::raw_identifier)) + PP.LookUpIdentifierInfo(Tok); + + // Get the string piece. + SmallVector<char, 128> TmpBuffer; + bool Invalid = false; + StringRef TmpName = PP.getSpelling(Tok, TmpBuffer, &Invalid); + if (Invalid) + return false; + + FilenameBuffer += TmpName; + + RawLex.LexFromRawLexer(Tok); + } while (Tok.isNot(tok::greater)); + + FilenameBuffer += '>'; + Filename = FilenameBuffer; + } else { + if (Tok.isNot(tok::string_literal)) + return false; + + bool Invalid = false; + Filename = PP.getSpelling(Tok, FilenameBuffer, &Invalid); + if (Invalid) + return false; + } + + // Lex the closing paren. + RawLex.LexFromRawLexer(Tok); + if (Tok.isNot(tok::r_paren)) + return false; + + // Now ask HeaderInfo if it knows about the header. + // FIXME: Subframeworks aren't handled here. Do we care? + bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename); + const DirectoryLookup *CurDir; + const FileEntry *File = PP.getHeaderSearchInfo().LookupFile( + Filename, isAngled, 0, CurDir, + PP.getSourceManager().getFileEntryForID(FileId), 0, 0, 0, false); + + FileExists = File != 0; + return true; +} + /// Use a raw lexer to analyze \p FileId, inccrementally copying parts of it /// and including content of included files recursively. bool InclusionRewriter::Process(FileID FileId, @@ -253,7 +336,7 @@ bool InclusionRewriter::Process(FileID FileId, bool Invalid; const MemoryBuffer &FromFile = *SM.getBuffer(FileId, &Invalid); if (Invalid) // invalid inclusion - return true; + return false; const char *FileName = FromFile.getBufferIdentifier(); Lexer RawLex(FileId, &FromFile, PP.getSourceManager(), PP.getLangOpts()); RawLex.SetCommentRetentionState(false); @@ -264,7 +347,7 @@ bool InclusionRewriter::Process(FileID FileId, WriteLineInfo(FileName, 1, FileType, EOL, " 1"); if (SM.getFileIDSize(FileId) == 0) - return true; + return false; // The next byte to be copied from the source file unsigned NextToWrite = 0; @@ -282,26 +365,31 @@ bool InclusionRewriter::Process(FileID FileId, RawLex.LexFromRawLexer(RawToken); if (RawToken.is(tok::raw_identifier)) PP.LookUpIdentifierInfo(RawToken); - if (RawToken.is(tok::identifier)) { + if (RawToken.is(tok::identifier) || RawToken.is(tok::kw_if)) { switch (RawToken.getIdentifierInfo()->getPPKeywordID()) { case tok::pp_include: case tok::pp_include_next: case tok::pp_import: { CommentOutDirective(RawLex, HashToken, FromFile, EOL, NextToWrite, Line); + StringRef LineInfoExtra; if (const FileChange *Change = FindFileChangeLocation( HashToken.getLocation())) { - // now include and recursively process the file - if (Process(Change->Id, Change->FileType)) + if (Change->Mod) { + WriteImplicitModuleImport(Change->Mod, EOL); + + // else now include and recursively process the file + } else if (Process(Change->Id, Change->FileType)) { // and set lineinfo back to this file, if the nested one was // actually included // `2' indicates returning to a file (after having included // another file. - WriteLineInfo(FileName, Line, FileType, EOL, " 2"); - } else - // fix up lineinfo (since commented out directive changed line - // numbers) for inclusions that were skipped due to header guards - WriteLineInfo(FileName, Line, FileType, EOL); + LineInfoExtra = " 2"; + } + } + // fix up lineinfo (since commented out directive changed line + // numbers) for inclusions that were skipped due to header guards + WriteLineInfo(FileName, Line, FileType, EOL, LineInfoExtra); break; } case tok::pp_pragma: { @@ -323,6 +411,50 @@ bool InclusionRewriter::Process(FileID FileId, } break; } + case tok::pp_if: + case tok::pp_elif: + // Rewrite special builtin macros to avoid pulling in host details. + do { + // Walk over the directive. + RawLex.LexFromRawLexer(RawToken); + if (RawToken.is(tok::raw_identifier)) + PP.LookUpIdentifierInfo(RawToken); + + if (RawToken.is(tok::identifier)) { + bool HasFile; + SourceLocation Loc = RawToken.getLocation(); + + // Rewrite __has_include(x) + if (RawToken.getIdentifierInfo()->isStr("__has_include")) { + if (!HandleHasInclude(FileId, RawLex, 0, RawToken, HasFile)) + continue; + // Rewrite __has_include_next(x) + } else if (RawToken.getIdentifierInfo()->isStr( + "__has_include_next")) { + const DirectoryLookup *Lookup = PP.GetCurDirLookup(); + if (Lookup) + ++Lookup; + + if (!HandleHasInclude(FileId, RawLex, Lookup, RawToken, + HasFile)) + continue; + } else { + continue; + } + // Replace the macro with (0) or (1), followed by the commented + // out macro for reference. + OutputContentUpTo(FromFile, NextToWrite, SM.getFileOffset(Loc), + EOL, Line); + OS << '(' << (int) HasFile << ")/*"; + OutputContentUpTo(FromFile, NextToWrite, + SM.getFileOffset(RawToken.getLocation()) + + RawToken.getLength(), + EOL, Line); + OS << "*/"; + } + } while (RawToken.isNot(tok::eod)); + + break; default: break; } diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index 00d3c47..1295339 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -1333,8 +1333,12 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler { LocEndOfScope = FunEndLocation; PartialDiagnosticAt Warning(LocEndOfScope, S.PDiag(DiagID) << LockName); - PartialDiagnosticAt Note(LocLocked, S.PDiag(diag::note_locked_here)); - Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note))); + if (LocLocked.isValid()) { + PartialDiagnosticAt Note(LocLocked, S.PDiag(diag::note_locked_here)); + Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note))); + return; + } + Warnings.push_back(DelayedDiag(Warning, OptionalNotes())); } diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp index e227d4e..9ac4c63 100644 --- a/lib/Sema/AttributeList.cpp +++ b/lib/Sema/AttributeList.cpp @@ -23,6 +23,8 @@ size_t AttributeList::allocated_size() const { if (IsAvailability) return AttributeFactory::AvailabilityAllocSize; else if (IsTypeTagForDatatype) return AttributeFactory::TypeTagForDatatypeAllocSize; + else if (IsProperty) + return AttributeFactory::PropertyAllocSize; return (sizeof(AttributeList) + NumArgs * sizeof(Expr*)); } diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index e1d55db..3b3ab2c 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -24,6 +24,7 @@ #include "clang/Sema/Sema.h" #include "clang/Sema/SemaDiagnostic.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" #include "llvm/Support/ErrorHandling.h" #include <cstring> using namespace clang; @@ -293,6 +294,11 @@ bool Declarator::isDeclarationOfFunction() const { case TST_event_t: return false; + case TST_decltype_auto: + // This must have an initializer, so can't be a function declaration, + // even if the initializer has function type. + return false; + case TST_decltype: case TST_typeofExpr: if (Expr *E = DS.getRepAsExpr()) @@ -325,7 +331,7 @@ bool Declarator::isDeclarationOfFunction() const { unsigned DeclSpec::getParsedSpecifiers() const { unsigned Res = 0; if (StorageClassSpec != SCS_unspecified || - SCS_thread_specified) + ThreadStorageClassSpec != TSCS_unspecified) Res |= PQ_StorageClassSpecifier; if (TypeQualifiers != TQ_unspecified) @@ -367,6 +373,16 @@ const char *DeclSpec::getSpecifierName(DeclSpec::SCS S) { llvm_unreachable("Unknown typespec!"); } +const char *DeclSpec::getSpecifierName(DeclSpec::TSCS S) { + switch (S) { + case DeclSpec::TSCS_unspecified: return "unspecified"; + case DeclSpec::TSCS___thread: return "__thread"; + case DeclSpec::TSCS_thread_local: return "thread_local"; + case DeclSpec::TSCS__Thread_local: return "_Thread_local"; + } + llvm_unreachable("Unknown typespec!"); +} + const char *DeclSpec::getSpecifierName(TSW W) { switch (W) { case TSW_unspecified: return "unspecified"; @@ -423,6 +439,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { case DeclSpec::TST_typeofExpr: return "typeof"; case DeclSpec::TST_auto: return "auto"; case DeclSpec::TST_decltype: return "(decltype)"; + case DeclSpec::TST_decltype_auto: return "decltype(auto)"; case DeclSpec::TST_underlyingType: return "__underlying_type"; case DeclSpec::TST_unknown_anytype: return "__unknown_anytype"; case DeclSpec::TST_atomic: return "_Atomic"; @@ -483,7 +500,7 @@ bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc, } if (StorageClassSpec != SCS_unspecified) { - // Maybe this is an attempt to use C++0x 'auto' outside of C++0x mode. + // Maybe this is an attempt to use C++11 'auto' outside of C++11 mode. bool isInvalid = true; if (TypeSpecType == TST_unspecified && S.getLangOpts().CPlusPlus) { if (SC == SCS_auto) @@ -510,16 +527,14 @@ bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc, return false; } -bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc, +bool DeclSpec::SetStorageClassSpecThread(TSCS TSC, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { - if (SCS_thread_specified) { - PrevSpec = "__thread"; - DiagID = diag::ext_duplicate_declspec; - return true; - } - SCS_thread_specified = true; - SCS_threadLoc = Loc; + if (ThreadStorageClassSpec != TSCS_unspecified) + return BadSpecifier(TSC, (TSCS)ThreadStorageClassSpec, PrevSpec, DiagID); + + ThreadStorageClassSpec = TSC; + ThreadStorageClassSpecLoc = Loc; return false; } @@ -825,6 +840,39 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) { // Check the type specifier components first. + // If decltype(auto) is used, no other type specifiers are permitted. + if (TypeSpecType == TST_decltype_auto && + (TypeSpecWidth != TSW_unspecified || + TypeSpecComplex != TSC_unspecified || + TypeSpecSign != TSS_unspecified || + TypeAltiVecVector || TypeAltiVecPixel || TypeAltiVecBool || + TypeQualifiers)) { + const unsigned NumLocs = 8; + SourceLocation ExtraLocs[NumLocs] = { + TSWLoc, TSCLoc, TSSLoc, AltiVecLoc, + TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc + }; + FixItHint Hints[NumLocs]; + SourceLocation FirstLoc; + for (unsigned I = 0; I != NumLocs; ++I) { + if (!ExtraLocs[I].isInvalid()) { + if (FirstLoc.isInvalid() || + PP.getSourceManager().isBeforeInTranslationUnit(ExtraLocs[I], + FirstLoc)) + FirstLoc = ExtraLocs[I]; + Hints[I] = FixItHint::CreateRemoval(ExtraLocs[I]); + } + } + TypeSpecWidth = TSW_unspecified; + TypeSpecComplex = TSC_unspecified; + TypeSpecSign = TSS_unspecified; + TypeAltiVecVector = TypeAltiVecPixel = TypeAltiVecBool = false; + TypeQualifiers = 0; + Diag(D, TSTLoc, diag::err_decltype_auto_cannot_be_combined) + << Hints[0] << Hints[1] << Hints[2] << Hints[3] + << Hints[4] << Hints[5] << Hints[6] << Hints[7]; + } + // Validate and finalize AltiVec vector declspec. if (TypeAltiVecVector) { if (TypeAltiVecBool) { @@ -923,12 +971,39 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) { } } + // C11 6.7.1/3, C++11 [dcl.stc]p1, GNU TLS: __thread, thread_local and + // _Thread_local can only appear with the 'static' and 'extern' storage class + // specifiers. We also allow __private_extern__ as an extension. + if (ThreadStorageClassSpec != TSCS_unspecified) { + switch (StorageClassSpec) { + case SCS_unspecified: + case SCS_extern: + case SCS_private_extern: + case SCS_static: + break; + default: + if (PP.getSourceManager().isBeforeInTranslationUnit( + getThreadStorageClassSpecLoc(), getStorageClassSpecLoc())) + Diag(D, getStorageClassSpecLoc(), + diag::err_invalid_decl_spec_combination) + << DeclSpec::getSpecifierName(getThreadStorageClassSpec()) + << SourceRange(getThreadStorageClassSpecLoc()); + else + Diag(D, getThreadStorageClassSpecLoc(), + diag::err_invalid_decl_spec_combination) + << DeclSpec::getSpecifierName(getStorageClassSpec()) + << SourceRange(getStorageClassSpecLoc()); + // Discard the thread storage class specifier to recover. + ThreadStorageClassSpec = TSCS_unspecified; + ThreadStorageClassSpecLoc = SourceLocation(); + } + } + // If no type specifier was provided and we're parsing a language where // the type specifier is not optional, but we got 'auto' as a storage // class specifier, then assume this is an attempt to use C++0x's 'auto' // type specifier. - // FIXME: Does Microsoft really support implicit int in C++? - if (PP.getLangOpts().CPlusPlus && !PP.getLangOpts().MicrosoftExt && + if (PP.getLangOpts().CPlusPlus && TypeSpecType == TST_unspecified && StorageClassSpec == SCS_auto) { TypeSpecType = TST_auto; StorageClassSpec = SCS_unspecified; @@ -936,7 +1011,7 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) { StorageClassSpecLoc = SourceLocation(); } // Diagnose if we've recovered from an ill-formed 'auto' storage class - // specifier in a pre-C++0x dialect of C++. + // specifier in a pre-C++11 dialect of C++. if (!PP.getLangOpts().CPlusPlus11 && TypeSpecType == TST_auto) Diag(D, TSTLoc, diag::ext_auto_type_specifier); if (PP.getLangOpts().CPlusPlus && !PP.getLangOpts().CPlusPlus11 && @@ -952,16 +1027,27 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) { // C++ [class.friend]p6: // No storage-class-specifier shall appear in the decl-specifier-seq // of a friend declaration. - if (isFriendSpecified() && getStorageClassSpec()) { - DeclSpec::SCS SC = getStorageClassSpec(); - const char *SpecName = getSpecifierName(SC); + if (isFriendSpecified() && + (getStorageClassSpec() || getThreadStorageClassSpec())) { + SmallString<32> SpecName; + SourceLocation SCLoc; + FixItHint StorageHint, ThreadHint; + + if (DeclSpec::SCS SC = getStorageClassSpec()) { + SpecName = getSpecifierName(SC); + SCLoc = getStorageClassSpecLoc(); + StorageHint = FixItHint::CreateRemoval(SCLoc); + } - SourceLocation SCLoc = getStorageClassSpecLoc(); - SourceLocation SCEndLoc = SCLoc.getLocWithOffset(strlen(SpecName)); + if (DeclSpec::TSCS TSC = getThreadStorageClassSpec()) { + if (!SpecName.empty()) SpecName += " "; + SpecName += getSpecifierName(TSC); + SCLoc = getThreadStorageClassSpecLoc(); + ThreadHint = FixItHint::CreateRemoval(SCLoc); + } Diag(D, SCLoc, diag::err_friend_storage_spec) - << SpecName - << FixItHint::CreateRemoval(SourceRange(SCLoc, SCEndLoc)); + << SpecName << StorageHint << ThreadHint; ClearStorageClassSpecs(); } diff --git a/lib/Sema/ScopeInfo.cpp b/lib/Sema/ScopeInfo.cpp index 4d29a34..2f48bec 100644 --- a/lib/Sema/ScopeInfo.cpp +++ b/lib/Sema/ScopeInfo.cpp @@ -187,3 +187,4 @@ void FunctionScopeInfo::markSafeWeakUse(const Expr *E) { FunctionScopeInfo::~FunctionScopeInfo() { } BlockScopeInfo::~BlockScopeInfo() { } LambdaScopeInfo::~LambdaScopeInfo() { } +CapturedRegionScopeInfo::~CapturedRegionScopeInfo() { } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 6bab9e8..e718be2 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -90,7 +90,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1), CurrentInstantiationScope(0), TyposCorrected(0), - AnalysisWarnings(*this), Ident_super(0) + AnalysisWarnings(*this), CurScope(0), Ident_super(0) { TUScope = 0; @@ -590,12 +590,11 @@ void Sema::ActOnEndOfTranslationUnit() { } // Remove file scoped decls that turned out to be used. - UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(0, - true), - UnusedFileScopedDecls.end(), - std::bind1st(std::ptr_fun(ShouldRemoveFromUnused), - this)), - UnusedFileScopedDecls.end()); + UnusedFileScopedDecls.erase( + std::remove_if(UnusedFileScopedDecls.begin(0, true), + UnusedFileScopedDecls.end(), + std::bind1st(std::ptr_fun(ShouldRemoveFromUnused), this)), + UnusedFileScopedDecls.end()); if (TUKind == TU_Prefix) { // Translation unit prefixes don't need any of the checking below. @@ -751,9 +750,13 @@ void Sema::ActOnEndOfTranslationUnit() { if (DiagD->isReferenced()) { Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl) << /*variable*/1 << DiagD->getDeclName(); - } else { + } else if (getSourceManager().isFromMainFile(DiagD->getLocation())) { + // If the declaration is in a header which is included into multiple + // TUs, it will declare one variable per TU, and one of the other + // variables may be used. So, only warn if the declaration is in the + // main file. Diag(DiagD->getLocation(), diag::warn_unused_variable) - << DiagD->getDeclName(); + << DiagD->getDeclName(); } } } @@ -798,7 +801,7 @@ DeclContext *Sema::getFunctionLevelDeclContext() { DeclContext *DC = CurContext; while (true) { - if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC)) { + if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC) || isa<CapturedDecl>(DC)) { DC = DC->getParent(); } else if (isa<CXXMethodDecl>(DC) && cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call && @@ -1073,7 +1076,8 @@ void Sema::ActOnComment(SourceRange Comment) { if (!LangOpts.RetainCommentsFromSystemHeaders && SourceMgr.isInSystemHeader(Comment.getBegin())) return; - RawComment RC(SourceMgr, Comment); + RawComment RC(SourceMgr, Comment, false, + LangOpts.CommentOpts.ParseAllComments); if (RC.isAlmostTrailingComment()) { SourceRange MagicMarkerRange(Comment.getBegin(), Comment.getBegin().getLocWithOffset(3)); @@ -1292,7 +1296,7 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, // FIXME: Try this before emitting the fixit, and suppress diagnostics // while doing so. E = ActOnCallExpr(0, E.take(), ParenInsertionLoc, - MultiExprArg(), ParenInsertionLoc.getLocWithOffset(1)); + None, ParenInsertionLoc.getLocWithOffset(1)); return true; } @@ -1309,3 +1313,18 @@ IdentifierInfo *Sema::getSuperIdentifier() const { Ident_super = &Context.Idents.get("super"); return Ident_super; } + +void Sema::PushCapturedRegionScope(Scope *S, CapturedDecl *CD, RecordDecl *RD, + CapturedRegionKind K) { + CapturingScopeInfo *CSI = new CapturedRegionScopeInfo(getDiagnostics(), S, CD, RD, + CD->getContextParam(), K); + CSI->ReturnType = Context.VoidTy; + FunctionScopes.push_back(CSI); +} + +CapturedRegionScopeInfo *Sema::getCurCapturedRegion() { + if (FunctionScopes.empty()) + return 0; + + return dyn_cast<CapturedRegionScopeInfo>(FunctionScopes.back()); +} diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index 79a9d3c..3ef1fde 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -84,10 +84,10 @@ struct EffectiveContext { : Inner(DC), Dependent(DC->isDependentContext()) { - // C++ [class.access.nest]p1: + // C++11 [class.access.nest]p1: // A nested class is a member and as such has the same access // rights as any other member. - // C++ [class.access]p2: + // C++11 [class.access]p2: // A member of a class can also access all the names to which // the class has access. A local class of a member function // may access the same names that the member function itself @@ -1476,18 +1476,18 @@ static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, llvm_unreachable("falling off end"); } -void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *decl) { +void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *D) { // Access control for names used in the declarations of functions // and function templates should normally be evaluated in the context // of the declaration, just in case it's a friend of something. // However, this does not apply to local extern declarations. - DeclContext *DC = decl->getDeclContext(); - if (FunctionDecl *fn = dyn_cast<FunctionDecl>(decl)) { - if (!DC->isFunctionOrMethod()) DC = fn; - } else if (FunctionTemplateDecl *fnt = dyn_cast<FunctionTemplateDecl>(decl)) { - // Never a local declaration. - DC = fnt->getTemplatedDecl(); + DeclContext *DC = D->getDeclContext(); + if (FunctionDecl *FN = dyn_cast<FunctionDecl>(D)) { + if (!DC->isFunctionOrMethod()) + DC = FN; + } else if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) { + DC = cast<DeclContext>(TD->getTemplatedDecl()); } EffectiveContext EC(DC); diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index e2a4084..eb11a57 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -333,7 +333,7 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT, : (CT == CT_Functional)? InitializationKind::CreateFunctionalCast(range, listInitialization) : InitializationKind::CreateCast(/*type range?*/ range); - InitializationSequence sequence(S, entity, initKind, &src, 1); + InitializationSequence sequence(S, entity, initKind, src); assert(sequence.Failed() && "initialization succeeded on second try?"); switch (sequence.getFailureKind()) { @@ -1418,7 +1418,7 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, ? InitializationKind::CreateFunctionalCast(OpRange, ListInitialization) : InitializationKind::CreateCast(OpRange); Expr *SrcExprRaw = SrcExpr.get(); - InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExprRaw, 1); + InitializationSequence InitSeq(Self, Entity, InitKind, SrcExprRaw); // At this point of CheckStaticCast, if the destination is a reference, // or the expression is an overload expression this has to work. @@ -1452,7 +1452,7 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, DestType = Self.Context.getCanonicalType(DestType); QualType SrcType = SrcExpr->getType(); if (const ReferenceType *DestTypeTmp =DestType->getAs<ReferenceType>()) { - if (DestTypeTmp->isLValueReferenceType() && !SrcExpr->isLValue()) { + if (isa<LValueReferenceType>(DestTypeTmp) && !SrcExpr->isLValue()) { // Cannot const_cast non-lvalue to lvalue reference type. But if this // is C-style, static_cast might find a way, so we simply suggest a // message and tell the parent to keep searching. @@ -1460,6 +1460,16 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, return TC_NotApplicable; } + // It's not completely clear under the standard whether we can + // const_cast bit-field gl-values. Doing so would not be + // intrinsically complicated, but for now, we say no for + // consistency with other compilers and await the word of the + // committee. + if (SrcExpr->refersToBitField()) { + msg = diag::err_bad_cxx_cast_bitfield; + return TC_NotApplicable; + } + // C++ 5.2.11p4: An lvalue of type T1 can be [cast] to an lvalue of type T2 // [...] if a pointer to T1 can be [cast] to the type pointer to T2. DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType()); diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 4e11b3a..a0998a4 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -586,12 +586,11 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, } bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac, - Expr **Args, unsigned NumArgs) { + ArrayRef<const Expr *> Args) { VariadicCallType CallType = Method->isVariadic() ? VariadicMethod : VariadicDoesNotApply; - checkCall(Method, llvm::makeArrayRef<const Expr *>(Args, NumArgs), - Method->param_size(), + checkCall(Method, Args, Method->param_size(), /*IsMemberFunction=*/false, lbrac, Method->getSourceRange(), CallType); @@ -2009,7 +2008,7 @@ public: PartialDiagnostic PDiag, SourceLocation StringLoc, bool IsStringLocation, Range StringRange, - ArrayRef<FixItHint> Fixit = ArrayRef<FixItHint>()); + ArrayRef<FixItHint> Fixit = None); protected: bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc, @@ -2036,7 +2035,7 @@ protected: template <typename Range> void EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation StringLoc, bool IsStringLocation, Range StringRange, - ArrayRef<FixItHint> Fixit = ArrayRef<FixItHint>()); + ArrayRef<FixItHint> Fixit = None); void CheckPositionalAndNonpositionalArgs( const analyze_format_string::FormatSpecifier *FS); @@ -2744,6 +2743,10 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, return true; QualType ExprTy = E->getType(); + while (const TypeOfExprType *TET = dyn_cast<TypeOfExprType>(ExprTy)) { + ExprTy = TET->getUnderlyingExpr()->getType(); + } + if (AT.matchesType(S.Context, ExprTy)) return true; @@ -4308,7 +4311,7 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { IntRange::forValueOfType(C, E->getType()); } - if (FieldDecl *BitField = E->getBitField()) + if (FieldDecl *BitField = E->getSourceBitField()) return IntRange(BitField->getBitWidthValue(C), BitField->getType()->isUnsignedIntegerOrEnumerationType()); @@ -4685,7 +4688,7 @@ static void AnalyzeAssignment(Sema &S, BinaryOperator *E) { // We want to recurse on the RHS as normal unless we're assigning to // a bitfield. - if (FieldDecl *Bitfield = E->getLHS()->getBitField()) { + if (FieldDecl *Bitfield = E->getLHS()->getSourceBitField()) { if (AnalyzeBitFieldAssignment(S, Bitfield, E->getRHS(), E->getOperatorLoc())) { // Recurse, ignoring any implicit conversions on the RHS. @@ -5699,12 +5702,14 @@ bool Sema::CheckParmsForFunctionDef(ParmVarDecl **P, ParmVarDecl **PEnd, // notation in their sequences of declarator specifiers to specify // variable length array types. QualType PType = Param->getOriginalType(); - if (const ArrayType *AT = Context.getAsArrayType(PType)) { + while (const ArrayType *AT = Context.getAsArrayType(PType)) { if (AT->getSizeModifier() == ArrayType::Star) { // FIXME: This diagnostic should point the '[*]' if source-location // information is added for it. Diag(Param->getLocation(), diag::err_array_star_in_function_definition); + break; } + PType= AT->getElementType(); } } diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 2db1e2a..fd2ce17 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -3348,13 +3348,12 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, // be a receiver of a class message, this may be a class message send with // the initial opening bracket '[' missing. Add appropriate completions. if (AllowNonIdentifiers && !AllowNestedNameSpecifiers && + DS.getParsedSpecifiers() == DeclSpec::PQ_TypeSpecifier && DS.getTypeSpecType() == DeclSpec::TST_typename && - DS.getStorageClassSpec() == DeclSpec::SCS_unspecified && - !DS.isThreadSpecified() && !DS.isExternInLinkageSpec() && DS.getTypeSpecComplex() == DeclSpec::TSC_unspecified && DS.getTypeSpecSign() == DeclSpec::TSS_unspecified && - DS.getTypeQualifiers() == 0 && - S && + !DS.isTypeAltiVecVector() && + S && (S->getFlags() & Scope::DeclScope) != 0 && (S->getFlags() & (Scope::ClassScope | Scope::TemplateParamScope | Scope::FunctionPrototypeScope | @@ -5472,7 +5471,7 @@ static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, M != MEnd; ++M) { for (ObjCMethodList *MethList = &M->second.second; MethList && MethList->Method; - MethList = MethList->Next) { + MethList = MethList->getNext()) { if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, NumSelIdents)) continue; @@ -5645,7 +5644,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, M != MEnd; ++M) { for (ObjCMethodList *MethList = &M->second.first; MethList && MethList->Method; - MethList = MethList->Next) { + MethList = MethList->getNext()) { if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, NumSelIdents)) continue; @@ -7086,7 +7085,7 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S, for (ObjCMethodList *MethList = IsInstanceMethod ? &M->second.first : &M->second.second; MethList && MethList->Method; - MethList = MethList->Next) { + MethList = MethList->getNext()) { if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, NumSelIdents)) continue; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index adf3505..e0e8bd6 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -129,7 +129,7 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const { /// /// If name lookup results in an ambiguity, this routine will complain /// and then return NULL. -ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, +ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec *SS, bool isClassName, bool HasTrailingDot, ParsedType ObjectTypePtr, @@ -1219,7 +1219,10 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { return false; } else { // 'static inline' functions are used in headers; don't warn. - if (FD->getStorageClass() == SC_Static && + // Make sure we get the storage class from the canonical declaration, + // since otherwise we will get spurious warnings on specialized + // static template functions. + if (FD->getCanonicalDecl()->getStorageClass() == SC_Static && FD->isInlineSpecified()) return false; } @@ -1613,20 +1616,7 @@ static void filterNonConflictingPreviousDecls(ASTContext &context, if (!old->isHidden()) continue; - // If either has no-external linkage, ignore the old declaration. - // If this declaration would have external linkage if it were the first - // declaration of this name, then it may in fact be a redeclaration of - // some hidden declaration, so include those too. We don't need to worry - // about some previous visible declaration giving this declaration external - // linkage, because in that case, we'll mark this declaration as a redecl - // of the visible decl, and that decl will already be a redecl of the - // hidden declaration if that's appropriate. - // - // Don't cache this linkage computation, because it's not yet correct: we - // may later give this declaration a previous declaration which changes - // its linkage. - if (old->getLinkage() != ExternalLinkage || - !decl->hasExternalLinkageUncached()) + if (old->getLinkage() != ExternalLinkage) filter.erase(); } @@ -2256,11 +2246,9 @@ static bool haveIncompatibleLanguageLinkages(const T *Old, const T *New) { return false; LanguageLinkage OldLinkage = Old->getLanguageLinkage(); - if (OldLinkage == CXXLanguageLinkage && - New->getDeclContext()->isExternCContext()) + if (OldLinkage == CXXLanguageLinkage && New->isInExternCContext()) return true; - if (OldLinkage == CLanguageLinkage && - New->getDeclContext()->isExternCXXContext()) + if (OldLinkage == CLanguageLinkage && New->isInExternCXXContext()) return true; return false; } @@ -2451,12 +2439,22 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) { // Certain function declarations cannot be overloaded: // -- Function declarations that differ only in the return type // cannot be overloaded. - QualType OldReturnType = OldType->getResultType(); - QualType NewReturnType = cast<FunctionType>(NewQType)->getResultType(); + + // Go back to the type source info to compare the declared return types, + // per C++1y [dcl.type.auto]p??: + // Redeclarations or specializations of a function or function template + // with a declared return type that uses a placeholder type shall also + // use that placeholder, not a deduced type. + QualType OldDeclaredReturnType = (Old->getTypeSourceInfo() + ? Old->getTypeSourceInfo()->getType()->castAs<FunctionType>() + : OldType)->getResultType(); + QualType NewDeclaredReturnType = (New->getTypeSourceInfo() + ? New->getTypeSourceInfo()->getType()->castAs<FunctionType>() + : NewType)->getResultType(); QualType ResQT; - if (OldReturnType != NewReturnType) { - if (NewReturnType->isObjCObjectPointerType() - && OldReturnType->isObjCObjectPointerType()) + if (!Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType)) { + if (NewDeclaredReturnType->isObjCObjectPointerType() && + OldDeclaredReturnType->isObjCObjectPointerType()) ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType); if (ResQT.isNull()) { if (New->isCXXClassMember() && New->isOutOfLine()) @@ -2471,8 +2469,21 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) { NewQType = ResQT; } - const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old); - CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New); + QualType OldReturnType = OldType->getResultType(); + QualType NewReturnType = cast<FunctionType>(NewQType)->getResultType(); + if (OldReturnType != NewReturnType) { + // If this function has a deduced return type and has already been + // defined, copy the deduced value from the old declaration. + AutoType *OldAT = Old->getResultType()->getContainedAutoType(); + if (OldAT && OldAT->isDeduced()) { + New->setType(SubstAutoType(New->getType(), OldAT->getDeducedType())); + NewQType = Context.getCanonicalType( + SubstAutoType(NewQType, OldAT->getDeducedType())); + } + } + + const CXXMethodDecl *OldMethod = dyn_cast<CXXMethodDecl>(Old); + CXXMethodDecl *NewMethod = dyn_cast<CXXMethodDecl>(New); if (OldMethod && NewMethod) { // Preserve triviality. NewMethod->setTrivial(OldMethod->isTrivial()); @@ -2697,21 +2708,31 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) { // Fall through to diagnose conflicting types. } - // A function that has already been declared has been redeclared or defined - // with a different type- show appropriate diagnostic - if (unsigned BuiltinID = Old->getBuiltinID()) { - // The user has declared a builtin function with an incompatible - // signature. + // A function that has already been declared has been redeclared or + // defined with a different type; show an appropriate diagnostic. + + // If the previous declaration was an implicitly-generated builtin + // declaration, then at the very least we should use a specialized note. + unsigned BuiltinID; + if (Old->isImplicit() && (BuiltinID = Old->getBuiltinID())) { + // If it's actually a library-defined builtin function like 'malloc' + // or 'printf', just warn about the incompatible redeclaration. if (Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) { - // The function the user is redeclaring is a library-defined - // function like 'malloc' or 'printf'. Warn about the - // redeclaration, then pretend that we don't know about this - // library built-in. Diag(New->getLocation(), diag::warn_redecl_library_builtin) << New; Diag(Old->getLocation(), diag::note_previous_builtin_declaration) << Old << Old->getType(); - New->getIdentifier()->setBuiltinID(Builtin::NotBuiltin); - Old->setInvalidDecl(); + + // If this is a global redeclaration, just forget hereafter + // about the "builtin-ness" of the function. + // + // Doing this for local extern declarations is problematic. If + // the builtin declaration remains visible, a second invalid + // local declaration will produce a hard error; if it doesn't + // remain visible, a single bogus local redeclaration (which is + // actually only a warning) could break all the downstream code. + if (!New->getDeclContext()->isFunctionOrMethod()) + New->getIdentifier()->setBuiltinID(Builtin::NotBuiltin); + return false; } @@ -2769,7 +2790,10 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod, ObjCMethodDecl *oldMethod) { // Merge the attributes, including deprecated/unavailable - mergeDeclAttributes(newMethod, oldMethod, AMK_Override); + AvailabilityMergeKind MergeKind = + isa<ObjCImplDecl>(newMethod->getDeclContext()) ? AMK_Redeclaration + : AMK_Override; + mergeDeclAttributes(newMethod, oldMethod, MergeKind); // Merge attributes from the parameters. ObjCMethodDecl::param_const_iterator oi = oldMethod->param_begin(), @@ -2795,8 +2819,7 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool OldWasHidden) { QualType MergedT; if (getLangOpts().CPlusPlus) { - AutoType *AT = New->getType()->getContainedAutoType(); - if (AT && !AT->isDeduced()) { + if (New->getType()->isUndeducedType()) { // We don't know what the new type is until the initializer is attached. return; } else if (Context.hasSameType(New->getType(), Old->getType())) { @@ -2868,6 +2891,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous, return New->setInvalidDecl(); } + if (!shouldLinkPossiblyHiddenDecl(Old, New)) + return; + // C++ [class.mem]p1: // A member shall not be declared twice in the member-specification [...] // @@ -2950,12 +2976,22 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous, return New->setInvalidDecl(); } - if (New->isThreadSpecified() && !Old->isThreadSpecified()) { - Diag(New->getLocation(), diag::err_thread_non_thread) << New->getDeclName(); - Diag(Old->getLocation(), diag::note_previous_definition); - } else if (!New->isThreadSpecified() && Old->isThreadSpecified()) { - Diag(New->getLocation(), diag::err_non_thread_thread) << New->getDeclName(); - Diag(Old->getLocation(), diag::note_previous_definition); + if (New->getTLSKind() != Old->getTLSKind()) { + if (!Old->getTLSKind()) { + Diag(New->getLocation(), diag::err_thread_non_thread) << New->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_declaration); + } else if (!New->getTLSKind()) { + Diag(New->getLocation(), diag::err_non_thread_thread) << New->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_declaration); + } else { + // Do not allow redeclaration to change the variable between requiring + // static and dynamic initialization. + // FIXME: GCC allows this, but uses the TLS keyword on the first + // declaration to determine the kind. Do we need to be compatible here? + Diag(New->getLocation(), diag::err_thread_thread_different_kind) + << New->getDeclName() << (New->getTLSKind() == VarDecl::TLS_Dynamic); + Diag(Old->getLocation(), diag::note_previous_declaration); + } } // C++ doesn't have tentative definitions, so go right ahead and check here. @@ -3179,8 +3215,9 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, Diag(DS.getStorageClassSpecLoc(), DiagID) << DeclSpec::getSpecifierName(SCS); - if (DS.isThreadSpecified()) - Diag(DS.getThreadSpecLoc(), DiagID) << "__thread"; + if (DeclSpec::TSCS TSCS = DS.getThreadStorageClassSpec()) + Diag(DS.getThreadStorageClassSpecLoc(), DiagID) + << DeclSpec::getSpecifierName(TSCS); if (DS.getTypeQualifiers()) { if (DS.getTypeQualifiers() & DeclSpec::TQ_const) Diag(DS.getConstSpecLoc(), DiagID) << "const"; @@ -3333,10 +3370,16 @@ static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, /// a VarDecl::StorageClass. Any error reporting is up to the caller: /// illegal input values are mapped to SC_None. static StorageClass -StorageClassSpecToVarDeclStorageClass(DeclSpec::SCS StorageClassSpec) { +StorageClassSpecToVarDeclStorageClass(const DeclSpec &DS) { + DeclSpec::SCS StorageClassSpec = DS.getStorageClassSpec(); + assert(StorageClassSpec != DeclSpec::SCS_typedef && + "Parser allowed 'typedef' as storage class VarDecl."); switch (StorageClassSpec) { case DeclSpec::SCS_unspecified: return SC_None; - case DeclSpec::SCS_extern: return SC_Extern; + case DeclSpec::SCS_extern: + if (DS.isExternInLinkageSpec()) + return SC_None; + return SC_Extern; case DeclSpec::SCS_static: return SC_Static; case DeclSpec::SCS_auto: return SC_Auto; case DeclSpec::SCS_register: return SC_Register; @@ -3534,9 +3577,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, FieldCollector->Add(cast<FieldDecl>(Anon)); } else { DeclSpec::SCS SCSpec = DS.getStorageClassSpec(); - assert(SCSpec != DeclSpec::SCS_typedef && - "Parser allowed 'typedef' as storage class VarDecl."); - VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec); + VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(DS); if (SCSpec == DeclSpec::SCS_mutable) { // mutable can only appear on non-static class members, so it's always // an error here @@ -4324,34 +4365,6 @@ Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, "Decl is not a locally-scoped decl!"); // Note that we have a locally-scoped external with this name. LocallyScopedExternCDecls[ND->getDeclName()] = ND; - - if (!Previous.isSingleResult()) - return; - - NamedDecl *PrevDecl = Previous.getFoundDecl(); - - // If there was a previous declaration of this entity, it may be in - // our identifier chain. Update the identifier chain with the new - // declaration. - if (S && IdResolver.ReplaceDecl(PrevDecl, ND)) { - // The previous declaration was found on the identifer resolver - // chain, so remove it from its scope. - - if (S->isDeclScope(PrevDecl)) { - // Special case for redeclarations in the SAME scope. - // Because this declaration is going to be added to the identifier chain - // later, we should temporarily take it OFF the chain. - IdResolver.RemoveDecl(ND); - - } else { - // Find the scope for the original declaration. - while (S && !S->isDeclScope(PrevDecl)) - S = S->getParent(); - } - - if (S) - S->RemoveDecl(PrevDecl); - } } llvm::DenseMap<DeclarationName, NamedDecl *>::iterator @@ -4408,8 +4421,6 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, DiagnoseFunctionSpecifiers(D.getDeclSpec()); - if (D.getDeclSpec().isThreadSpecified()) - Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); if (D.getDeclSpec().isConstexprSpecified()) Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) << 1; @@ -4603,7 +4614,7 @@ bool Sema::inferObjCARCLifetime(ValueDecl *decl) { if (VarDecl *var = dyn_cast<VarDecl>(decl)) { // Thread-local variables cannot have lifetime. if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone && - var->isThreadSpecified()) { + var->getTLSKind()) { Diag(var->getLocation(), diag::err_arc_thread_ownership) << var->getType(); return true; @@ -4689,12 +4700,10 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, DeclarationName Name = GetNameForDeclarator(D).getName(); DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec(); - assert(SCSpec != DeclSpec::SCS_typedef && - "Parser allowed 'typedef' as storage class VarDecl."); - VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec); + VarDecl::StorageClass SC = + StorageClassSpecToVarDeclStorageClass(D.getDeclSpec()); - if (getLangOpts().OpenCL && !getOpenCLOptions().cl_khr_fp16) - { + if (getLangOpts().OpenCL && !getOpenCLOptions().cl_khr_fp16) { // OpenCL v1.2 s6.1.1.1: reject declaring variables of the half and // half array type (unless the cl_khr_fp16 extension is enabled). if (Context.getBaseElementType(R)->isHalfType()) { @@ -4711,6 +4720,16 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, SC = SC_None; } + // C++11 [dcl.stc]p4: + // When thread_local is applied to a variable of block scope the + // storage-class-specifier static is implied if it does not appear + // explicitly. + // Core issue: 'static' is not implied if the variable is declared 'extern'. + if (SCSpec == DeclSpec::SCS_unspecified && + D.getDeclSpec().getThreadStorageClassSpec() == + DeclSpec::TSCS_thread_local && DC->isFunctionOrMethod()) + SC = SC_Static; + IdentifierInfo *II = Name.getAsIdentifierInfo(); if (!II) { Diag(D.getIdentifierLoc(), diag::err_bad_variable_name) @@ -4845,8 +4864,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, // If this decl has an auto type in need of deduction, make a note of the // Decl so we can diagnose uses of it in its own initializer. - if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto && - R->getContainedAutoType()) + if (D.getDeclSpec().containsPlaceholderType() && R->getContainedAutoType()) ParsingInitForAutoVars.insert(NewVD); if (D.isInvalidType() || Invalid) @@ -4868,13 +4886,16 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, // lexical context will be different from the semantic context. NewVD->setLexicalDeclContext(CurContext); - if (D.getDeclSpec().isThreadSpecified()) { + if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) { if (NewVD->hasLocalStorage()) - Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_non_global); + Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), + diag::err_thread_non_global) + << DeclSpec::getSpecifierName(TSCS); else if (!Context.getTargetInfo().isTLSSupported()) - Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_unsupported); + Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), + diag::err_thread_unsupported); else - NewVD->setThreadSpecified(true); + NewVD->setTSCSpec(TSCS); } // C99 6.7.4p3 @@ -5130,7 +5151,7 @@ static bool mayConflictWithNonVisibleExternC(const T *ND) { // This code runs before the init of foo is set, and therefore before // the type of foo is known. Not knowing the type we cannot know its linkage // unless it is in an extern C block. - if (!DC->isExternCContext()) { + if (!ND->isInExternCContext()) { const ASTContext &Context = ND->getASTContext(); if (Context.getLangOpts().CPlusPlus) return false; @@ -5139,27 +5160,18 @@ static bool mayConflictWithNonVisibleExternC(const T *ND) { return ND->isExternC(); } -/// \brief Perform semantic checking on a newly-created variable -/// declaration. -/// -/// This routine performs all of the type-checking required for a -/// variable declaration once it has been built. It is used both to -/// check variables after they have been parsed and their declarators -/// have been translated into a declaration, and to check variables -/// that have been instantiated from a template. -/// -/// Sets NewVD->isInvalidDecl() if an error was encountered. -/// -/// Returns true if the variable declaration is a redeclaration. -bool Sema::CheckVariableDeclaration(VarDecl *NewVD, - LookupResult &Previous) { +void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { // If the decl is already known invalid, don't check it. if (NewVD->isInvalidDecl()) - return false; + return; TypeSourceInfo *TInfo = NewVD->getTypeSourceInfo(); QualType T = TInfo->getType(); + // Defer checking an 'auto' type until its initializer is attached. + if (T->isUndeducedType()) + return; + if (T->isObjCObjectType()) { Diag(NewVD->getLocation(), diag::err_statically_allocated_object) << FixItHint::CreateInsertion(NewVD->getLocation(), "*"); @@ -5174,16 +5186,26 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, if (NewVD->hasLocalStorage() && T.getAddressSpace() != 0) { Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl); NewVD->setInvalidDecl(); - return false; + return; } + // OpenCL v1.2 s6.5 - All program scope variables must be declared in the + // __constant address space. + if (getLangOpts().OpenCL && NewVD->isFileVarDecl() + && T.getAddressSpace() != LangAS::opencl_constant + && !T->isSamplerT()){ + Diag(NewVD->getLocation(), diag::err_opencl_global_invalid_addr_space); + NewVD->setInvalidDecl(); + return; + } + // OpenCL v1.2 s6.8 -- The static qualifier is valid only in program // scope. if ((getLangOpts().OpenCLVersion >= 120) && NewVD->isStaticLocal()) { Diag(NewVD->getLocation(), diag::err_static_function_scope); NewVD->setInvalidDecl(); - return false; + return; } if (NewVD->hasLocalStorage() && T.isObjCGCWeak() @@ -5224,7 +5246,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, Diag(NewVD->getLocation(), diag::err_vla_decl_has_extern_linkage) << SizeRange; NewVD->setInvalidDecl(); - return false; + return; } if (FixedTInfo == 0) { @@ -5233,7 +5255,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, else Diag(NewVD->getLocation(), diag::err_vm_decl_has_extern_linkage); NewVD->setInvalidDecl(); - return false; + return; } Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size); @@ -5241,6 +5263,54 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, NewVD->setTypeSourceInfo(FixedTInfo); } + if (T->isVoidType() && NewVD->isThisDeclarationADefinition()) { + Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type) + << T; + NewVD->setInvalidDecl(); + return; + } + + if (!NewVD->hasLocalStorage() && NewVD->hasAttr<BlocksAttr>()) { + Diag(NewVD->getLocation(), diag::err_block_on_nonlocal); + NewVD->setInvalidDecl(); + return; + } + + if (isVM && NewVD->hasAttr<BlocksAttr>()) { + Diag(NewVD->getLocation(), diag::err_block_on_vm); + NewVD->setInvalidDecl(); + return; + } + + if (NewVD->isConstexpr() && !T->isDependentType() && + RequireLiteralType(NewVD->getLocation(), T, + diag::err_constexpr_var_non_literal)) { + // Can't perform this check until the type is deduced. + NewVD->setInvalidDecl(); + return; + } +} + +/// \brief Perform semantic checking on a newly-created variable +/// declaration. +/// +/// This routine performs all of the type-checking required for a +/// variable declaration once it has been built. It is used both to +/// check variables after they have been parsed and their declarators +/// have been translated into a declaration, and to check variables +/// that have been instantiated from a template. +/// +/// Sets NewVD->isInvalidDecl() if an error was encountered. +/// +/// Returns true if the variable declaration is a redeclaration. +bool Sema::CheckVariableDeclaration(VarDecl *NewVD, + LookupResult &Previous) { + CheckVariableDeclarationType(NewVD); + + // If the decl is already known invalid, don't check it. + if (NewVD->isInvalidDecl()) + return false; + // If we did not find anything by this name, look for a non-visible // extern "C" declaration with the same name. // @@ -5279,32 +5349,6 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, // Filter out any non-conflicting previous declarations. filterNonConflictingPreviousDecls(Context, NewVD, Previous); - if (T->isVoidType() && !NewVD->hasExternalStorage()) { - Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type) - << T; - NewVD->setInvalidDecl(); - return false; - } - - if (!NewVD->hasLocalStorage() && NewVD->hasAttr<BlocksAttr>()) { - Diag(NewVD->getLocation(), diag::err_block_on_nonlocal); - NewVD->setInvalidDecl(); - return false; - } - - if (isVM && NewVD->hasAttr<BlocksAttr>()) { - Diag(NewVD->getLocation(), diag::err_block_on_vm); - NewVD->setInvalidDecl(); - return false; - } - - if (NewVD->isConstexpr() && !T->isDependentType() && - RequireLiteralType(NewVD->getLocation(), T, - diag::err_constexpr_var_non_literal)) { - NewVD->setInvalidDecl(); - return false; - } - if (!Previous.empty()) { MergeVarDecl(NewVD, Previous, PreviousWasHidden); return true; @@ -5631,7 +5675,10 @@ static FunctionDecl::StorageClass getFunctionStorageClass(Sema &SemaRef, D.setInvalidType(); break; case DeclSpec::SCS_unspecified: break; - case DeclSpec::SCS_extern: return SC_Extern; + case DeclSpec::SCS_extern: + if (D.getDeclSpec().isExternInLinkageSpec()) + return SC_None; + return SC_Extern; case DeclSpec::SCS_static: { if (SemaRef.CurContext->getRedeclContext()->isFunctionOrMethod()) { // C99 6.7.1p5: @@ -5823,8 +5870,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, DeclarationName Name = NameInfo.getName(); FunctionDecl::StorageClass SC = getFunctionStorageClass(*this, D); - if (D.getDeclSpec().isThreadSpecified()) - Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) + Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), + diag::err_invalid_thread) + << DeclSpec::getSpecifierName(TSCS); // Do not allow returning a objc interface by-value. if (R->getAs<FunctionType>()->getResultType()->isObjCObjectType()) { @@ -6017,6 +6066,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Okay: Add virtual to the method. NewFD->setVirtualAsWritten(true); } + + if (getLangOpts().CPlusPlus1y && + NewFD->getResultType()->isUndeducedType()) + Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_auto_fn_virtual); } // C++ [dcl.fct.spec]p3: @@ -6521,9 +6574,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, EPI.Variadic = true; EPI.ExtInfo = FT->getExtInfo(); - QualType R = Context.getFunctionType(FT->getResultType(), - ArrayRef<QualType>(), - EPI); + QualType R = Context.getFunctionType(FT->getResultType(), None, EPI); NewFD->setType(R); } @@ -6667,8 +6718,11 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // there's no more work to do here; we'll just add the new // function to the scope. if (!AllowOverloadingOfFunction(Previous, Context)) { - Redeclaration = true; - OldDecl = Previous.getFoundDecl(); + NamedDecl *Candidate = Previous.getFoundDecl(); + if (shouldLinkPossiblyHiddenDecl(Candidate, NewFD)) { + Redeclaration = true; + OldDecl = Candidate; + } } else { switch (CheckOverload(S, NewFD, Previous, OldDecl, /*NewIsUsingDecl*/ false)) { @@ -6710,9 +6764,12 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // // This needs to be delayed until we know whether this is an out-of-line // definition of a static member function. + // + // This rule is not present in C++1y, so we produce a backwards + // compatibility warning whenever it happens in C++11. CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD); - if (MD && MD->isConstexpr() && !MD->isStatic() && - !isa<CXXConstructorDecl>(MD) && + if (!getLangOpts().CPlusPlus1y && MD && MD->isConstexpr() && + !MD->isStatic() && !isa<CXXConstructorDecl>(MD) && (MD->getTypeQualifiers() & Qualifiers::Const) == 0) { CXXMethodDecl *OldMD = dyn_cast_or_null<CXXMethodDecl>(OldDecl); if (FunctionTemplateDecl *OldTD = @@ -6727,6 +6784,18 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, ArrayRef<QualType>(FPT->arg_type_begin(), FPT->getNumArgs()), EPI)); + + // Warn that we did this, if we're not performing template instantiation. + // In that case, we'll have warned already when the template was defined. + if (ActiveTemplateInstantiations.empty()) { + SourceLocation AddConstLoc; + if (FunctionTypeLoc FTL = MD->getTypeSourceInfo()->getTypeLoc() + .IgnoreParens().getAs<FunctionTypeLoc>()) + AddConstLoc = PP.getLocForEndOfToken(FTL.getRParenLoc()); + + Diag(MD->getLocation(), diag::warn_cxx1y_compat_constexpr_not_const) + << FixItHint::CreateInsertion(AddConstLoc, " const"); + } } } @@ -7164,7 +7233,7 @@ namespace { return; } Inherited::VisitUnaryOperator(E); - } + } void VisitObjCMessageExpr(ObjCMessageExpr *E) { return; } @@ -7248,10 +7317,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init); // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. - AutoType *Auto = 0; - if (TypeMayContainAuto && - (Auto = VDecl->getType()->getContainedAutoType()) && - !Auto->isDeduced()) { + if (TypeMayContainAuto && VDecl->getType()->isUndeducedType()) { Expr *DeduceInit = Init; // Initializer could be a C++ direct-initializer. Deduction only works if it // contains exactly one expression. @@ -7289,17 +7355,16 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, Init = Result.take(); DefaultedToAuto = true; } - - TypeSourceInfo *DeducedType = 0; + + QualType DeducedType; if (DeduceAutoType(VDecl->getTypeSourceInfo(), DeduceInit, DeducedType) == DAR_Failed) DiagnoseAutoDeductionFailure(VDecl, DeduceInit); - if (!DeducedType) { + if (DeducedType.isNull()) { RealDecl->setInvalidDecl(); return; } - VDecl->setTypeSourceInfo(DeducedType); - VDecl->setType(DeducedType->getType()); + VDecl->setType(DeducedType); assert(VDecl->isLinkageValid()); // In ARC, infer lifetime. @@ -7311,8 +7376,9 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // We only want to warn outside of template instantiations, though: // inside a template, the 'id' could have come from a parameter. if (ActiveTemplateInstantiations.empty() && !DefaultedToAuto && - DeducedType->getType()->isObjCIdType()) { - SourceLocation Loc = DeducedType->getTypeLoc().getBeginLoc(); + DeducedType->isObjCIdType()) { + SourceLocation Loc = + VDecl->getTypeSourceInfo()->getTypeLoc().getBeginLoc(); Diag(Loc, diag::warn_auto_var_is_id) << VDecl->getDeclName() << DeduceInit->getSourceRange(); } @@ -7321,6 +7387,11 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // the previously declared type. if (VarDecl *Old = VDecl->getPreviousDecl()) MergeVarDeclTypes(VDecl, Old, /*OldWasHidden*/ false); + + // Check the deduced type is valid for a variable declaration. + CheckVariableDeclarationType(VDecl); + if (VDecl->isInvalidDecl()) + return; } if (VDecl->isLocalVarDecl() && VDecl->hasExternalStorage()) { @@ -7426,15 +7497,13 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, : InitializationKind::CreateCopy(VDecl->getLocation(), Init->getLocStart()); - Expr **Args = &Init; - unsigned NumArgs = 1; - if (CXXDirectInit) { - Args = CXXDirectInit->getExprs(); - NumArgs = CXXDirectInit->getNumExprs(); - } - InitializationSequence InitSeq(*this, Entity, Kind, Args, NumArgs); - ExprResult Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(Args, NumArgs), &DclT); + MultiExprArg Args = Init; + if (CXXDirectInit) + Args = MultiExprArg(CXXDirectInit->getExprs(), + CXXDirectInit->getNumExprs()); + + InitializationSequence InitSeq(*this, Entity, Kind, Args); + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT); if (Result.isInvalid()) { VDecl->setInvalidDecl(); return; @@ -7595,7 +7664,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, } // Suggest adding 'constexpr' in C++11 for literal types. - } else if (getLangOpts().CPlusPlus11 && DclT->isLiteralType()) { + } else if (getLangOpts().CPlusPlus11 && DclT->isLiteralType(Context)) { Diag(VDecl->getLocation(), diag::err_in_class_initializer_literal_type) << DclT << Init->getSourceRange() << FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr "); @@ -7616,6 +7685,19 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // C99 6.7.8p4. All file scoped initializers need to be constant. if (!getLangOpts().CPlusPlus && !VDecl->isInvalidDecl()) CheckForConstantInitializer(Init, DclT); + else if (VDecl->getTLSKind() == VarDecl::TLS_Static && + !VDecl->isInvalidDecl() && !DclT->isDependentType() && + !Init->isValueDependent() && !VDecl->isConstexpr() && + !Init->isConstantInitializer( + Context, VDecl->getType()->isReferenceType())) { + // GNU C++98 edits for __thread, [basic.start.init]p4: + // An object of thread storage duration shall not require dynamic + // initialization. + // FIXME: Need strict checking here. + Diag(VDecl->getLocation(), diag::err_thread_dynamic_init); + if (getLangOpts().CPlusPlus11) + Diag(VDecl->getLocation(), diag::note_use_thread_local); + } } // We will represent direct-initialization similarly to copy-initialization: @@ -7870,9 +7952,9 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, InitializedEntity Entity = InitializedEntity::InitializeVariable(Var); InitializationKind Kind = InitializationKind::CreateDefault(Var->getLocation()); - - InitializationSequence InitSeq(*this, Entity, Kind, 0, 0); - ExprResult Init = InitSeq.Perform(*this, Entity, Kind, MultiExprArg()); + + InitializationSequence InitSeq(*this, Entity, Kind, None); + ExprResult Init = InitSeq.Perform(*this, Entity, Kind, None); if (Init.isInvalid()) Var->setInvalidDecl(); else if (Init.get()) { @@ -7961,6 +8043,16 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { Diag(var->getLocation(), diag::warn_missing_variable_declarations) << var; } + if (var->getTLSKind() == VarDecl::TLS_Static && + var->getType().isDestructedType()) { + // GNU C++98 edits for __thread, [basic.start.term]p3: + // The type of an object with thread storage duration shall not + // have a non-trivial destructor. + Diag(var->getLocation(), diag::err_thread_nontrivial_dtor); + if (getLangOpts().CPlusPlus11) + Diag(var->getLocation(), diag::note_use_thread_local); + } + // All the following checks are C++ only. if (!getLangOpts().CPlusPlus) return; @@ -8106,7 +8198,7 @@ Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, getASTContext().addUnnamedTag(Tag); return BuildDeclaratorGroup(Decls.data(), Decls.size(), - DS.getTypeSpecType() == DeclSpec::TST_auto); + DS.containsPlaceholderType()); } /// BuildDeclaratorGroup - convert a list of declarations into a declaration @@ -8131,8 +8223,8 @@ Sema::BuildDeclaratorGroup(Decl **Group, unsigned NumDecls, // Don't reissue diagnostics when instantiating a template. if (AT && D->isInvalidDecl()) break; - if (AT && AT->isDeduced()) { - QualType U = AT->getDeducedType(); + QualType U = AT ? AT->getDeducedType() : QualType(); + if (!U.isNull()) { CanQualType UCanon = Context.getCanonicalType(U); if (Deduced.isNull()) { Deduced = U; @@ -8141,6 +8233,7 @@ Sema::BuildDeclaratorGroup(Decl **Group, unsigned NumDecls, } else if (DeducedCanon != UCanon) { Diag(D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), diag::err_auto_different_deductions) + << (AT->isDecltypeAuto() ? 1 : 0) << Deduced << DeducedDecl->getDeclName() << U << D->getDeclName() << DeducedDecl->getInit()->getSourceRange() @@ -8222,13 +8315,14 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { D.getMutableDeclSpec().ClearStorageClassSpecs(); } - if (D.getDeclSpec().isThreadSpecified()) - Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); - if (D.getDeclSpec().isConstexprSpecified()) - Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) + if (DeclSpec::TSCS TSCS = DS.getThreadStorageClassSpec()) + Diag(DS.getThreadStorageClassSpecLoc(), diag::err_invalid_thread) + << DeclSpec::getSpecifierName(TSCS); + if (DS.isConstexprSpecified()) + Diag(DS.getConstexprSpecLoc(), diag::err_invalid_constexpr) << 0; - DiagnoseFunctionSpecifiers(D.getDeclSpec()); + DiagnoseFunctionSpecifiers(DS); TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType parmDeclType = TInfo->getType(); @@ -8787,6 +8881,21 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (FD) { FD->setBody(Body); + if (getLangOpts().CPlusPlus1y && !FD->isInvalidDecl() && + !FD->isDependentContext()) { + if (FD->getResultType()->isUndeducedType()) { + // If the function has a deduced result type but contains no 'return' + // statements, the result type as written must be exactly 'auto', and + // the deduced result type is 'void'. + if (!FD->getResultType()->getAs<AutoType>()) { + Diag(dcl->getLocation(), diag::err_auto_fn_no_return_but_not_auto) + << FD->getResultType(); + FD->setInvalidDecl(); + } + Context.adjustDeducedFunctionResultType(FD, Context.VoidTy); + } + } + // The only way to be included in UndefinedButUsed is if there is an // ODR use before the definition. Avoid the expensive map lookup if this // is the first declaration. @@ -10348,8 +10457,10 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, DiagnoseFunctionSpecifiers(D.getDeclSpec()); - if (D.getDeclSpec().isThreadSpecified()) - Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) + Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), + diag::err_invalid_thread) + << DeclSpec::getSpecifierName(TSCS); // Check to see if this name was declared as a member previously NamedDecl *PrevDecl = 0; @@ -10557,8 +10668,8 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, // FIXME: We need to pass in the attributes given an AST // representation, not a parser representation. if (D) { - // FIXME: What to pass instead of TUScope? - ProcessDeclAttributes(TUScope, NewFD, *D); + // FIXME: The current scope is almost... but not entirely... correct here. + ProcessDeclAttributes(getCurScope(), NewFD, *D); if (NewFD->hasAttrs()) CheckAlignasUnderalignment(NewFD); @@ -11497,8 +11608,8 @@ struct DenseMapInfoDupKey { // Emits a warning when an element is implicitly set a value that // a previous element has already been set to. -static void CheckForDuplicateEnumValues(Sema &S, Decl **Elements, - unsigned NumElements, EnumDecl *Enum, +static void CheckForDuplicateEnumValues(Sema &S, ArrayRef<Decl *> Elements, + EnumDecl *Enum, QualType EnumType) { if (S.Diags.getDiagnosticLevel(diag::warn_duplicate_enum_values, Enum->getLocation()) == @@ -11524,8 +11635,8 @@ static void CheckForDuplicateEnumValues(Sema &S, Decl **Elements, // Populate the EnumMap with all values represented by enum constants without // an initialier. - for (unsigned i = 0; i < NumElements; ++i) { - EnumConstantDecl *ECD = cast<EnumConstantDecl>(Elements[i]); + for (unsigned i = 0, e = Elements.size(); i != e; ++i) { + EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elements[i]); // Null EnumConstantDecl means a previous diagnostic has been emitted for // this constant. Skip this enum since it may be ill-formed. @@ -11545,7 +11656,7 @@ static void CheckForDuplicateEnumValues(Sema &S, Decl **Elements, } // Create vectors for any values that has duplicates. - for (unsigned i = 0; i < NumElements; ++i) { + for (unsigned i = 0, e = Elements.size(); i != e; ++i) { EnumConstantDecl *ECD = cast<EnumConstantDecl>(Elements[i]); if (!ValidDuplicateEnum(ECD, Enum)) continue; @@ -11609,7 +11720,7 @@ static void CheckForDuplicateEnumValues(Sema &S, Decl **Elements, void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, SourceLocation RBraceLoc, Decl *EnumDeclX, - Decl **Elements, unsigned NumElements, + ArrayRef<Decl *> Elements, Scope *S, AttributeList *Attr) { EnumDecl *Enum = cast<EnumDecl>(EnumDeclX); QualType EnumType = Context.getTypeDeclType(Enum); @@ -11618,7 +11729,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, ProcessDeclAttributeList(S, Enum, Attr); if (Enum->isDependentType()) { - for (unsigned i = 0; i != NumElements; ++i) { + for (unsigned i = 0, e = Elements.size(); i != e; ++i) { EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elements[i]); if (!ECD) continue; @@ -11645,7 +11756,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, // Keep track of whether all elements have type int. bool AllElementsInt = true; - for (unsigned i = 0; i != NumElements; ++i) { + for (unsigned i = 0, e = Elements.size(); i != e; ++i) { EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elements[i]); if (!ECD) continue; // Already issued a diagnostic. @@ -11762,7 +11873,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, // Loop over all of the enumerator constants, changing their types to match // the type of the enum if needed. - for (unsigned i = 0; i != NumElements; ++i) { + for (unsigned i = 0, e = Elements.size(); i != e; ++i) { EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elements[i]); if (!ECD) continue; // Already issued a diagnostic. @@ -11830,7 +11941,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, if (InFunctionDeclarator) DeclsInPrototypeScope.push_back(Enum); - CheckForDuplicateEnumValues(*this, Elements, NumElements, Enum, EnumType); + CheckForDuplicateEnumValues(*this, Elements, Enum, EnumType); // Now that the enum type is defined, ensure it's not been underaligned. if (Enum->hasAttrs()) diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 982e7a5..7b3345a 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -284,7 +284,7 @@ static bool mayBeSharedVariable(const Decl *D) { if (isa<FieldDecl>(D)) return true; if (const VarDecl *vd = dyn_cast<VarDecl>(D)) - return (vd->hasGlobalStorage() && !(vd->isThreadSpecified())); + return vd->hasGlobalStorage() && !vd->getTLSKind(); return false; } @@ -709,7 +709,7 @@ static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D, // Check that all arguments are lockable objects. checkAttrArgsAreLockableObjs(S, D, Attr, Args); - if (Args.size() == 0) + if (Args.empty()) return false; return true; @@ -858,7 +858,7 @@ static bool checkLocksRequiredCommon(Sema &S, Decl *D, // check that all arguments are lockable objects checkAttrArgsAreLockableObjs(S, D, Attr, Args); - if (Args.size() == 0) + if (Args.empty()) return false; return true; @@ -1656,7 +1656,7 @@ static void handleTLSModelAttr(Sema &S, Decl *D, return; } - if (!isa<VarDecl>(D) || !cast<VarDecl>(D)->isThreadSpecified()) { + if (!isa<VarDecl>(D) || !cast<VarDecl>(D)->getTLSKind()) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) << Attr.getName() << ExpectedTLSVar; return; @@ -2246,8 +2246,11 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, MergedObsoleted == Obsoleted) return NULL; + // Only create a new attribute if !Override, but we want to do + // the checking. if (!checkAvailabilityAttr(*this, Range, Platform, MergedIntroduced, - MergedDeprecated, MergedObsoleted)) { + MergedDeprecated, MergedObsoleted) && + !Override) { return ::new (Context) AvailabilityAttr(Range, Context, Platform, Introduced, Deprecated, Obsoleted, IsUnavailable, Message, @@ -4886,6 +4889,7 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, break; // Microsoft attributes: + case AttributeList::AT_MsProperty: break; case AttributeList::AT_MsStruct: handleMsStructAttr(S, D, Attr); break; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 35890e6..e6a131a 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -65,6 +65,7 @@ namespace { bool VisitDeclRefExpr(DeclRefExpr *DRE); bool VisitCXXThisExpr(CXXThisExpr *ThisE); bool VisitLambdaExpr(LambdaExpr *Lambda); + bool VisitPseudoObjectExpr(PseudoObjectExpr *POE); }; /// VisitExpr - Visit all of the children of this expression. @@ -115,6 +116,23 @@ namespace { << ThisE->getSourceRange(); } + bool CheckDefaultArgumentVisitor::VisitPseudoObjectExpr(PseudoObjectExpr *POE) { + bool Invalid = false; + for (PseudoObjectExpr::semantics_iterator + i = POE->semantics_begin(), e = POE->semantics_end(); i != e; ++i) { + Expr *E = *i; + + // Look through bindings. + if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) { + E = OVE->getSourceExpr(); + assert(E && "pseudo-object binding without source expression?"); + } + + Invalid |= Visit(E); + } + return Invalid; + } + bool CheckDefaultArgumentVisitor::VisitLambdaExpr(LambdaExpr *Lambda) { // C++11 [expr.lambda.prim]p13: // A lambda-expression appearing in a default argument shall not @@ -127,8 +145,9 @@ namespace { } } -void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc, - CXXMethodDecl *Method) { +void +Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc, + const CXXMethodDecl *Method) { // If we have an MSAny spec already, don't bother. if (!Method || ComputedEST == EST_MSAny) return; @@ -246,7 +265,7 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg, Param); InitializationKind Kind = InitializationKind::CreateCopy(Param->getLocation(), EqualLoc); - InitializationSequence InitSeq(*this, Entity, Kind, &Arg, 1); + InitializationSequence InitSeq(*this, Entity, Kind, Arg); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Arg); if (Result.isInvalid()) return true; @@ -614,25 +633,11 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { unsigned NumParams = FD->getNumParams(); unsigned p; - bool IsLambda = FD->getOverloadedOperator() == OO_Call && - isa<CXXMethodDecl>(FD) && - cast<CXXMethodDecl>(FD)->getParent()->isLambda(); - // Find first parameter with a default argument for (p = 0; p < NumParams; ++p) { ParmVarDecl *Param = FD->getParamDecl(p); - if (Param->hasDefaultArg()) { - // C++11 [expr.prim.lambda]p5: - // [...] Default arguments (8.3.6) shall not be specified in the - // parameter-declaration-clause of a lambda-declarator. - // - // FIXME: Core issue 974 strikes this sentence, we only provide an - // extension warning. - if (IsLambda) - Diag(Param->getLocation(), diag::ext_lambda_default_arguments) - << Param->getDefaultArgRange(); + if (Param->hasDefaultArg()) break; - } } // C++ [dcl.fct.default]p4: @@ -770,12 +775,13 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) { } /// Check the given declaration statement is legal within a constexpr function -/// body. C++0x [dcl.constexpr]p3,p4. +/// body. C++11 [dcl.constexpr]p3,p4, and C++1y [dcl.constexpr]p3. /// -/// \return true if the body is OK, false if we have diagnosed a problem. +/// \return true if the body is OK (maybe only as an extension), false if we +/// have diagnosed a problem. static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, - DeclStmt *DS) { - // C++0x [dcl.constexpr]p3 and p4: + DeclStmt *DS, SourceLocation &Cxx1yLoc) { + // C++11 [dcl.constexpr]p3 and p4: // The definition of a constexpr function(p3) or constructor(p4) [...] shall // contain only for (DeclStmt::decl_iterator DclIt = DS->decl_begin(), @@ -786,6 +792,7 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, case Decl::UsingShadow: case Decl::UsingDirective: case Decl::UnresolvedUsingTypename: + case Decl::UnresolvedUsingValue: // - static_assert-declarations // - using-declarations, // - using-directives, @@ -809,20 +816,63 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, case Decl::Enum: case Decl::CXXRecord: - // As an extension, we allow the declaration (but not the definition) of - // classes and enumerations in all declarations, not just in typedef and - // alias declarations. - if (cast<TagDecl>(*DclIt)->isThisDeclarationADefinition()) { - SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_type_definition) + // C++1y allows types to be defined, not just declared. + if (cast<TagDecl>(*DclIt)->isThisDeclarationADefinition()) + SemaRef.Diag(DS->getLocStart(), + SemaRef.getLangOpts().CPlusPlus1y + ? diag::warn_cxx11_compat_constexpr_type_definition + : diag::ext_constexpr_type_definition) << isa<CXXConstructorDecl>(Dcl); - return false; - } continue; - case Decl::Var: - SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_var_declaration) + case Decl::EnumConstant: + case Decl::IndirectField: + case Decl::ParmVar: + // These can only appear with other declarations which are banned in + // C++11 and permitted in C++1y, so ignore them. + continue; + + case Decl::Var: { + // C++1y [dcl.constexpr]p3 allows anything except: + // a definition of a variable of non-literal type or of static or + // thread storage duration or for which no initialization is performed. + VarDecl *VD = cast<VarDecl>(*DclIt); + if (VD->isThisDeclarationADefinition()) { + if (VD->isStaticLocal()) { + SemaRef.Diag(VD->getLocation(), + diag::err_constexpr_local_var_static) + << isa<CXXConstructorDecl>(Dcl) + << (VD->getTLSKind() == VarDecl::TLS_Dynamic); + return false; + } + if (!VD->getType()->isDependentType() && + SemaRef.RequireLiteralType( + VD->getLocation(), VD->getType(), + diag::err_constexpr_local_var_non_literal_type, + isa<CXXConstructorDecl>(Dcl))) + return false; + if (!VD->hasInit()) { + SemaRef.Diag(VD->getLocation(), + diag::err_constexpr_local_var_no_init) + << isa<CXXConstructorDecl>(Dcl); + return false; + } + } + SemaRef.Diag(VD->getLocation(), + SemaRef.getLangOpts().CPlusPlus1y + ? diag::warn_cxx11_compat_constexpr_local_var + : diag::ext_constexpr_local_var) << isa<CXXConstructorDecl>(Dcl); - return false; + continue; + } + + case Decl::NamespaceAlias: + case Decl::Function: + // These are disallowed in C++11 and permitted in C++1y. Allow them + // everywhere as an extension. + if (!Cxx1yLoc.isValid()) + Cxx1yLoc = DS->getLocStart(); + continue; default: SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_body_invalid_stmt) @@ -871,6 +921,124 @@ static void CheckConstexprCtorInitializer(Sema &SemaRef, } } +/// Check the provided statement is allowed in a constexpr function +/// definition. +static bool +CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, + llvm::SmallVectorImpl<SourceLocation> &ReturnStmts, + SourceLocation &Cxx1yLoc) { + // - its function-body shall be [...] a compound-statement that contains only + switch (S->getStmtClass()) { + case Stmt::NullStmtClass: + // - null statements, + return true; + + case Stmt::DeclStmtClass: + // - static_assert-declarations + // - using-declarations, + // - using-directives, + // - typedef declarations and alias-declarations that do not define + // classes or enumerations, + if (!CheckConstexprDeclStmt(SemaRef, Dcl, cast<DeclStmt>(S), Cxx1yLoc)) + return false; + return true; + + case Stmt::ReturnStmtClass: + // - and exactly one return statement; + if (isa<CXXConstructorDecl>(Dcl)) { + // C++1y allows return statements in constexpr constructors. + if (!Cxx1yLoc.isValid()) + Cxx1yLoc = S->getLocStart(); + return true; + } + + ReturnStmts.push_back(S->getLocStart()); + return true; + + case Stmt::CompoundStmtClass: { + // C++1y allows compound-statements. + if (!Cxx1yLoc.isValid()) + Cxx1yLoc = S->getLocStart(); + + CompoundStmt *CompStmt = cast<CompoundStmt>(S); + for (CompoundStmt::body_iterator BodyIt = CompStmt->body_begin(), + BodyEnd = CompStmt->body_end(); BodyIt != BodyEnd; ++BodyIt) { + if (!CheckConstexprFunctionStmt(SemaRef, Dcl, *BodyIt, ReturnStmts, + Cxx1yLoc)) + return false; + } + return true; + } + + case Stmt::AttributedStmtClass: + if (!Cxx1yLoc.isValid()) + Cxx1yLoc = S->getLocStart(); + return true; + + case Stmt::IfStmtClass: { + // C++1y allows if-statements. + if (!Cxx1yLoc.isValid()) + Cxx1yLoc = S->getLocStart(); + + IfStmt *If = cast<IfStmt>(S); + if (!CheckConstexprFunctionStmt(SemaRef, Dcl, If->getThen(), ReturnStmts, + Cxx1yLoc)) + return false; + if (If->getElse() && + !CheckConstexprFunctionStmt(SemaRef, Dcl, If->getElse(), ReturnStmts, + Cxx1yLoc)) + return false; + return true; + } + + case Stmt::WhileStmtClass: + case Stmt::DoStmtClass: + case Stmt::ForStmtClass: + case Stmt::CXXForRangeStmtClass: + case Stmt::ContinueStmtClass: + // C++1y allows all of these. We don't allow them as extensions in C++11, + // because they don't make sense without variable mutation. + if (!SemaRef.getLangOpts().CPlusPlus1y) + break; + if (!Cxx1yLoc.isValid()) + Cxx1yLoc = S->getLocStart(); + for (Stmt::child_range Children = S->children(); Children; ++Children) + if (*Children && + !CheckConstexprFunctionStmt(SemaRef, Dcl, *Children, ReturnStmts, + Cxx1yLoc)) + return false; + return true; + + case Stmt::SwitchStmtClass: + case Stmt::CaseStmtClass: + case Stmt::DefaultStmtClass: + case Stmt::BreakStmtClass: + // C++1y allows switch-statements, and since they don't need variable + // mutation, we can reasonably allow them in C++11 as an extension. + if (!Cxx1yLoc.isValid()) + Cxx1yLoc = S->getLocStart(); + for (Stmt::child_range Children = S->children(); Children; ++Children) + if (*Children && + !CheckConstexprFunctionStmt(SemaRef, Dcl, *Children, ReturnStmts, + Cxx1yLoc)) + return false; + return true; + + default: + if (!isa<Expr>(S)) + break; + + // C++1y allows expression-statements. + if (!Cxx1yLoc.isValid()) + Cxx1yLoc = S->getLocStart(); + return true; + } + + SemaRef.Diag(S->getLocStart(), diag::err_constexpr_body_invalid_stmt) + << isa<CXXConstructorDecl>(Dcl); + return false; +} + /// Check the body for the given constexpr function declaration only contains /// the permitted types of statement. C++11 [dcl.constexpr]p3,p4. /// @@ -891,43 +1059,24 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { return false; } + SmallVector<SourceLocation, 4> ReturnStmts; + // - its function-body shall be [...] a compound-statement that contains only + // [... list of cases ...] CompoundStmt *CompBody = cast<CompoundStmt>(Body); - - SmallVector<SourceLocation, 4> ReturnStmts; + SourceLocation Cxx1yLoc; for (CompoundStmt::body_iterator BodyIt = CompBody->body_begin(), BodyEnd = CompBody->body_end(); BodyIt != BodyEnd; ++BodyIt) { - switch ((*BodyIt)->getStmtClass()) { - case Stmt::NullStmtClass: - // - null statements, - continue; - - case Stmt::DeclStmtClass: - // - static_assert-declarations - // - using-declarations, - // - using-directives, - // - typedef declarations and alias-declarations that do not define - // classes or enumerations, - if (!CheckConstexprDeclStmt(*this, Dcl, cast<DeclStmt>(*BodyIt))) - return false; - continue; - - case Stmt::ReturnStmtClass: - // - and exactly one return statement; - if (isa<CXXConstructorDecl>(Dcl)) - break; - - ReturnStmts.push_back((*BodyIt)->getLocStart()); - continue; - - default: - break; - } + if (!CheckConstexprFunctionStmt(*this, Dcl, *BodyIt, ReturnStmts, Cxx1yLoc)) + return false; + } - Diag((*BodyIt)->getLocStart(), diag::err_constexpr_body_invalid_stmt) + if (Cxx1yLoc.isValid()) + Diag(Cxx1yLoc, + getLangOpts().CPlusPlus1y + ? diag::warn_cxx11_compat_constexpr_body_invalid_stmt + : diag::ext_constexpr_body_invalid_stmt) << isa<CXXConstructorDecl>(Dcl); - return false; - } if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Dcl)) { @@ -983,14 +1132,23 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { } } else { if (ReturnStmts.empty()) { - Diag(Dcl->getLocation(), diag::err_constexpr_body_no_return); - return false; + // C++1y doesn't require constexpr functions to contain a 'return' + // statement. We still do, unless the return type is void, because + // otherwise if there's no return statement, the function cannot + // be used in a core constant expression. + bool OK = getLangOpts().CPlusPlus1y && Dcl->getResultType()->isVoidType(); + Diag(Dcl->getLocation(), + OK ? diag::warn_cxx11_compat_constexpr_body_no_return + : diag::err_constexpr_body_no_return); + return OK; } if (ReturnStmts.size() > 1) { - Diag(ReturnStmts.back(), diag::err_constexpr_body_multiple_return); + Diag(ReturnStmts.back(), + getLangOpts().CPlusPlus1y + ? diag::warn_cxx11_compat_constexpr_body_multiple_return + : diag::ext_constexpr_body_multiple_return); for (unsigned I = 0; I < ReturnStmts.size() - 1; ++I) Diag(ReturnStmts[I], diag::note_constexpr_body_previous_return); - return false; } } @@ -1584,6 +1742,13 @@ static bool InitializationHasSideEffects(const FieldDecl &FD) { return false; } +static AttributeList *getMSPropertyAttr(AttributeList *list) { + for (AttributeList* it = list; it != 0; it = it->getNext()) + if (it->isDeclspecPropertyAttribute()) + return it; + return 0; +} + /// ActOnCXXMemberDeclarator - This is invoked when a C++ class member /// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the /// bitfield width if there is one, 'InitExpr' specifies the initializer if @@ -1660,30 +1825,24 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, // data members and cannot be applied to names declared const or static, // and cannot be applied to reference members. switch (DS.getStorageClassSpec()) { - case DeclSpec::SCS_unspecified: - case DeclSpec::SCS_typedef: - case DeclSpec::SCS_static: - // FALL THROUGH. - break; - case DeclSpec::SCS_mutable: - if (isFunc) { - if (DS.getStorageClassSpecLoc().isValid()) - Diag(DS.getStorageClassSpecLoc(), diag::err_mutable_function); - else - Diag(DS.getThreadSpecLoc(), diag::err_mutable_function); + case DeclSpec::SCS_unspecified: + case DeclSpec::SCS_typedef: + case DeclSpec::SCS_static: + break; + case DeclSpec::SCS_mutable: + if (isFunc) { + Diag(DS.getStorageClassSpecLoc(), diag::err_mutable_function); - // FIXME: It would be nicer if the keyword was ignored only for this - // declarator. Otherwise we could get follow-up errors. - D.getMutableDeclSpec().ClearStorageClassSpecs(); - } - break; - default: - if (DS.getStorageClassSpecLoc().isValid()) - Diag(DS.getStorageClassSpecLoc(), - diag::err_storageclass_invalid_for_member); - else - Diag(DS.getThreadSpecLoc(), diag::err_storageclass_invalid_for_member); + // FIXME: It would be nicer if the keyword was ignored only for this + // declarator. Otherwise we could get follow-up errors. D.getMutableDeclSpec().ClearStorageClassSpecs(); + } + break; + default: + Diag(DS.getStorageClassSpecLoc(), + diag::err_storageclass_invalid_for_member); + D.getMutableDeclSpec().ClearStorageClassSpecs(); + break; } bool isInstField = ((DS.getStorageClassSpec() == DeclSpec::SCS_unspecified || @@ -1769,8 +1928,16 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, SS.clear(); } - Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth, - InitStyle, AS); + AttributeList *MSPropertyAttr = + getMSPropertyAttr(D.getDeclSpec().getAttributes().getList()); + if (MSPropertyAttr) { + Member = HandleMSProperty(S, cast<CXXRecordDecl>(CurContext), Loc, D, + BitWidth, InitStyle, AS, MSPropertyAttr); + isInstField = false; + } else { + Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, + BitWidth, InitStyle, AS); + } assert(Member && "HandleField never returns null"); } else { assert(InitStyle == ICIS_NoInit || D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static); @@ -1990,14 +2157,12 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation InitLoc, Diag(FD->getLocation(), diag::warn_dangling_std_initializer_list) << /*at end of ctor*/1 << InitExpr->getSourceRange(); } - Expr **Inits = &InitExpr; - unsigned NumInits = 1; InitializedEntity Entity = InitializedEntity::InitializeMember(FD); InitializationKind Kind = FD->getInClassInitStyle() == ICIS_ListInit ? InitializationKind::CreateDirectList(InitExpr->getLocStart()) : InitializationKind::CreateCopy(InitExpr->getLocStart(), InitLoc); - InitializationSequence Seq(*this, Entity, Kind, Inits, NumInits); - Init = Seq.Perform(*this, Entity, Kind, MultiExprArg(Inits, NumInits)); + InitializationSequence Seq(*this, Entity, Kind, InitExpr); + Init = Seq.Perform(*this, Entity, Kind, InitExpr); if (Init.isInvalid()) { FD->setInvalidDecl(); return; @@ -2360,23 +2525,19 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init, // foo(foo) // where foo is not also a parameter to the constructor. // TODO: implement -Wuninitialized and fold this into that framework. - Expr **Args; - unsigned NumArgs; + MultiExprArg Args; if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) { - Args = ParenList->getExprs(); - NumArgs = ParenList->getNumExprs(); + Args = MultiExprArg(ParenList->getExprs(), ParenList->getNumExprs()); } else if (InitListExpr *InitList = dyn_cast<InitListExpr>(Init)) { - Args = InitList->getInits(); - NumArgs = InitList->getNumInits(); + Args = MultiExprArg(InitList->getInits(), InitList->getNumInits()); } else { // Template instantiation doesn't reconstruct ParenListExprs for us. - Args = &Init; - NumArgs = 1; + Args = Init; } if (getDiagnostics().getDiagnosticLevel(diag::warn_field_is_uninit, IdLoc) != DiagnosticsEngine::Ignored) - for (unsigned i = 0; i < NumArgs; ++i) + for (unsigned i = 0, e = Args.size(); i != e; ++i) // FIXME: Warn about the case when other fields are used before being // initialized. For example, let this field be the i'th field. When // initializing the i'th field, throw a warning if any of the >= i'th @@ -2397,8 +2558,7 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init, bool InitList = false; if (isa<InitListExpr>(Init)) { InitList = true; - Args = &Init; - NumArgs = 1; + Args = Init; if (isStdInitializerList(Member->getType(), 0)) { Diag(IdLoc, diag::warn_dangling_std_initializer_list) @@ -2415,10 +2575,8 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init, : InitializationKind::CreateDirect(IdLoc, InitRange.getBegin(), InitRange.getEnd()); - InitializationSequence InitSeq(*this, MemberEntity, Kind, Args, NumArgs); - ExprResult MemberInit = InitSeq.Perform(*this, MemberEntity, Kind, - MultiExprArg(Args, NumArgs), - 0); + InitializationSequence InitSeq(*this, MemberEntity, Kind, Args); + ExprResult MemberInit = InitSeq.Perform(*this, MemberEntity, Kind, Args, 0); if (MemberInit.isInvalid()) return true; @@ -2454,12 +2612,10 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init, Diag(NameLoc, diag::warn_cxx98_compat_delegating_ctor); bool InitList = true; - Expr **Args = &Init; - unsigned NumArgs = 1; + MultiExprArg Args = Init; if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) { InitList = false; - Args = ParenList->getExprs(); - NumArgs = ParenList->getNumExprs(); + Args = MultiExprArg(ParenList->getExprs(), ParenList->getNumExprs()); } SourceRange InitRange = Init->getSourceRange(); @@ -2470,10 +2626,9 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init, InitList ? InitializationKind::CreateDirectList(NameLoc) : InitializationKind::CreateDirect(NameLoc, InitRange.getBegin(), InitRange.getEnd()); - InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args, NumArgs); + InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args); ExprResult DelegationInit = InitSeq.Perform(*this, DelegationEntity, Kind, - MultiExprArg(Args, NumArgs), - 0); + Args, 0); if (DelegationInit.isInvalid()) return true; @@ -2593,12 +2748,10 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // Initialize the base. bool InitList = true; - Expr **Args = &Init; - unsigned NumArgs = 1; + MultiExprArg Args = Init; if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) { InitList = false; - Args = ParenList->getExprs(); - NumArgs = ParenList->getNumExprs(); + Args = MultiExprArg(ParenList->getExprs(), ParenList->getNumExprs()); } InitializedEntity BaseEntity = @@ -2607,9 +2760,8 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, InitList ? InitializationKind::CreateDirectList(BaseLoc) : InitializationKind::CreateDirect(BaseLoc, InitRange.getBegin(), InitRange.getEnd()); - InitializationSequence InitSeq(*this, BaseEntity, Kind, Args, NumArgs); - ExprResult BaseInit = InitSeq.Perform(*this, BaseEntity, Kind, - MultiExprArg(Args, NumArgs), 0); + InitializationSequence InitSeq(*this, BaseEntity, Kind, Args); + ExprResult BaseInit = InitSeq.Perform(*this, BaseEntity, Kind, Args, 0); if (BaseInit.isInvalid()) return true; @@ -2695,8 +2847,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, InitializationKind InitKind = InitializationKind::CreateDirect( Constructor->getLocation(), SourceLocation(), SourceLocation()); - InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, - Args.data(), Args.size()); + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, Args); BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, Args); break; } @@ -2705,8 +2856,8 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, case IIK_Default: { InitializationKind InitKind = InitializationKind::CreateDefault(Constructor->getLocation()); - InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0); - BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, MultiExprArg()); + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, None); + BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, None); break; } @@ -2743,10 +2894,8 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, InitializationKind InitKind = InitializationKind::CreateDirect(Constructor->getLocation(), SourceLocation(), SourceLocation()); - InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, - &CopyCtorArg, 1); - BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, - MultiExprArg(&CopyCtorArg, 1)); + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, CopyCtorArg); + BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, CopyCtorArg); break; } } @@ -2897,8 +3046,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, InitializationKind::CreateDirect(Loc, SourceLocation(), SourceLocation()); Expr *CtorArgE = CtorArg.takeAs<Expr>(); - InitializationSequence InitSeq(SemaRef, Entities.back(), InitKind, - &CtorArgE, 1); + InitializationSequence InitSeq(SemaRef, Entities.back(), InitKind, CtorArgE); ExprResult MemberInit = InitSeq.Perform(SemaRef, Entities.back(), InitKind, @@ -2936,10 +3084,10 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, : InitializedEntity::InitializeMember(Field); InitializationKind InitKind = InitializationKind::CreateDefault(Loc); - - InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0); - ExprResult MemberInit = - InitSeq.Perform(SemaRef, InitEntity, InitKind, MultiExprArg()); + + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, None); + ExprResult MemberInit = + InitSeq.Perform(SemaRef, InitEntity, InitKind, None); MemberInit = SemaRef.MaybeCreateExprWithCleanups(MemberInit); if (MemberInit.isInvalid()) @@ -3040,7 +3188,7 @@ struct BaseAndFieldInfo { AllToInit.push_back(Init); // Check whether this initializer makes the field "used". - if (Init->getInit() && Init->getInit()->HasSideEffects(S.Context)) + if (Init->getInit()->HasSideEffects(S.Context)) S.UnusedPrivateFields.remove(Init->getAnyMember()); return false; @@ -3089,16 +3237,18 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info, // has a brace-or-equal-initializer, the entity is initialized as specified // in [dcl.init]. if (Field->hasInClassInitializer() && !Info.isImplicitCopyOrMove()) { + Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context, + Info.Ctor->getLocation(), Field); CXXCtorInitializer *Init; if (Indirect) Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Indirect, SourceLocation(), - SourceLocation(), 0, + SourceLocation(), DIE, SourceLocation()); else Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field, SourceLocation(), - SourceLocation(), 0, + SourceLocation(), DIE, SourceLocation()); return Info.addFieldInitializer(Init); } @@ -4226,9 +4376,8 @@ updateExceptionSpec(Sema &S, FunctionDecl *FD, const FunctionProtoType *FPT, const Sema::ImplicitExceptionSpecification &ExceptSpec) { FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); ExceptSpec.getEPI(EPI); - const FunctionProtoType *NewFPT = cast<FunctionProtoType>( - S.Context.getFunctionType(FPT->getResultType(), FPT->getArgTypes(), EPI)); - FD->setType(QualType(NewFPT, 0)); + FD->setType(S.Context.getFunctionType(FPT->getResultType(), + FPT->getArgTypes(), EPI)); } void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) { @@ -4427,7 +4576,7 @@ void Sema::CheckExplicitlyDefaultedMemberExceptionSpec( FunctionProtoType::ExtProtoInfo EPI; computeImplicitExceptionSpec(*this, MD->getLocation(), MD).getEPI(EPI); const FunctionProtoType *ImplicitType = cast<FunctionProtoType>( - Context.getFunctionType(Context.VoidTy, ArrayRef<QualType>(), EPI)); + Context.getFunctionType(Context.VoidTy, None, EPI)); // Ensure that it matches. CheckEquivalentExceptionSpec( @@ -5409,8 +5558,10 @@ void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { for (unsigned i = 0, e = Data.OverloadedMethods.size(); i != e; ++i) { CXXMethodDecl *overloadedMD = Data.OverloadedMethods[i]; - Diag(overloadedMD->getLocation(), + PartialDiagnostic PD = PDiag( diag::note_hidden_overloaded_virtual_declared_here) << overloadedMD; + HandleFunctionTypeMismatch(PD, MD->getType(), overloadedMD->getType()); + Diag(overloadedMD->getLocation(), PD); } } } @@ -5860,7 +6011,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, EPI.Variadic = false; EPI.TypeQuals = 0; EPI.RefQualifier = RQ_None; - return Context.getFunctionType(Context.VoidTy, ArrayRef<QualType>(), EPI); + return Context.getFunctionType(Context.VoidTy, None, EPI); } /// CheckConversionDeclarator - Called by ActOnDeclarator to check the @@ -5941,8 +6092,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, // of the errors above fired) and with the conversion type as the // return type. if (D.isInvalidType()) - R = Context.getFunctionType(ConvType, ArrayRef<QualType>(), - Proto->getExtProtoInfo()); + R = Context.getFunctionType(ConvType, None, Proto->getExtProtoInfo()); // C++0x explicit conversion operators. if (D.getDeclSpec().isExplicitSpecified()) @@ -7503,9 +7653,73 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc, } Sema::ImplicitExceptionSpecification -Sema::ComputeInheritingCtorExceptionSpec(CXXMethodDecl *MD) { +Sema::ComputeInheritingCtorExceptionSpec(CXXConstructorDecl *CD) { + CXXRecordDecl *ClassDecl = CD->getParent(); + + // C++ [except.spec]p14: + // An inheriting constructor [...] shall have an exception-specification. [...] ImplicitExceptionSpecification ExceptSpec(*this); - // FIXME: Compute the exception spec. + if (ClassDecl->isInvalidDecl()) + return ExceptSpec; + + // Inherited constructor. + const CXXConstructorDecl *InheritedCD = CD->getInheritedConstructor(); + const CXXRecordDecl *InheritedDecl = InheritedCD->getParent(); + // FIXME: Copying or moving the parameters could add extra exceptions to the + // set, as could the default arguments for the inherited constructor. This + // will be addressed when we implement the resolution of core issue 1351. + ExceptSpec.CalledDecl(CD->getLocStart(), InheritedCD); + + // Direct base-class constructors. + for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(), + BEnd = ClassDecl->bases_end(); + B != BEnd; ++B) { + if (B->isVirtual()) // Handled below. + continue; + + if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) { + CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); + if (BaseClassDecl == InheritedDecl) + continue; + CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl); + if (Constructor) + ExceptSpec.CalledDecl(B->getLocStart(), Constructor); + } + } + + // Virtual base-class constructors. + for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(), + BEnd = ClassDecl->vbases_end(); + B != BEnd; ++B) { + if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) { + CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); + if (BaseClassDecl == InheritedDecl) + continue; + CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl); + if (Constructor) + ExceptSpec.CalledDecl(B->getLocStart(), Constructor); + } + } + + // Field constructors. + for (RecordDecl::field_iterator F = ClassDecl->field_begin(), + FEnd = ClassDecl->field_end(); + F != FEnd; ++F) { + if (F->hasInClassInitializer()) { + if (Expr *E = F->getInClassInitializer()) + ExceptSpec.CalledExpr(E); + else if (!F->isInvalidDecl()) + Diag(CD->getLocation(), + diag::err_in_class_initializer_references_def_ctor) << CD; + } else if (const RecordType *RecordTy + = Context.getBaseElementType(F->getType())->getAs<RecordType>()) { + CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); + CXXConstructorDecl *Constructor = LookupDefaultConstructor(FieldRecDecl); + if (Constructor) + ExceptSpec.CalledDecl(F->getLocation(), Constructor); + } + } + return ExceptSpec; } @@ -7577,9 +7791,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( FunctionProtoType::ExtProtoInfo EPI; EPI.ExceptionSpecType = EST_Unevaluated; EPI.ExceptionSpecDecl = DefaultCon; - DefaultCon->setType(Context.getFunctionType(Context.VoidTy, - ArrayRef<QualType>(), - EPI)); + DefaultCon->setType(Context.getFunctionType(Context.VoidTy, None, EPI)); // We don't need to use SpecialMemberIsTrivial here; triviality for default // constructors is easy to compute. @@ -7635,208 +7847,308 @@ void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) { CheckDelayedExplicitlyDefaultedMemberExceptionSpecs(); } -void Sema::DeclareInheritingConstructors(CXXRecordDecl *ClassDecl) { - // We start with an initial pass over the base classes to collect those that - // inherit constructors from. If there are none, we can forgo all further - // processing. - typedef SmallVector<const RecordType *, 4> BasesVector; - BasesVector BasesToInheritFrom; - for (CXXRecordDecl::base_class_iterator BaseIt = ClassDecl->bases_begin(), - BaseE = ClassDecl->bases_end(); - BaseIt != BaseE; ++BaseIt) { - if (BaseIt->getInheritConstructors()) { - QualType Base = BaseIt->getType(); - if (Base->isDependentType()) { - // If we inherit constructors from anything that is dependent, just - // abort processing altogether. We'll get another chance for the - // instantiations. - // FIXME: We need to ensure that any call to a constructor of this class - // is considered instantiation-dependent in this case. - return; +namespace { +/// Information on inheriting constructors to declare. +class InheritingConstructorInfo { +public: + InheritingConstructorInfo(Sema &SemaRef, CXXRecordDecl *Derived) + : SemaRef(SemaRef), Derived(Derived) { + // Mark the constructors that we already have in the derived class. + // + // C++11 [class.inhctor]p3: [...] a constructor is implicitly declared [...] + // unless there is a user-declared constructor with the same signature in + // the class where the using-declaration appears. + visitAll(Derived, &InheritingConstructorInfo::noteDeclaredInDerived); + } + + void inheritAll(CXXRecordDecl *RD) { + visitAll(RD, &InheritingConstructorInfo::inherit); + } + +private: + /// Information about an inheriting constructor. + struct InheritingConstructor { + InheritingConstructor() + : DeclaredInDerived(false), BaseCtor(0), DerivedCtor(0) {} + + /// If \c true, a constructor with this signature is already declared + /// in the derived class. + bool DeclaredInDerived; + + /// The constructor which is inherited. + const CXXConstructorDecl *BaseCtor; + + /// The derived constructor we declared. + CXXConstructorDecl *DerivedCtor; + }; + + /// Inheriting constructors with a given canonical type. There can be at + /// most one such non-template constructor, and any number of templated + /// constructors. + struct InheritingConstructorsForType { + InheritingConstructor NonTemplate; + llvm::SmallVector< + std::pair<TemplateParameterList*, InheritingConstructor>, 4> Templates; + + InheritingConstructor &getEntry(Sema &S, const CXXConstructorDecl *Ctor) { + if (FunctionTemplateDecl *FTD = Ctor->getDescribedFunctionTemplate()) { + TemplateParameterList *ParamList = FTD->getTemplateParameters(); + for (unsigned I = 0, N = Templates.size(); I != N; ++I) + if (S.TemplateParameterListsAreEqual(ParamList, Templates[I].first, + false, S.TPL_TemplateMatch)) + return Templates[I].second; + Templates.push_back(std::make_pair(ParamList, InheritingConstructor())); + return Templates.back().second; } - BasesToInheritFrom.push_back(Base->castAs<RecordType>()); + + return NonTemplate; } + }; + + /// Get or create the inheriting constructor record for a constructor. + InheritingConstructor &getEntry(const CXXConstructorDecl *Ctor, + QualType CtorType) { + return Map[CtorType.getCanonicalType()->castAs<FunctionProtoType>()] + .getEntry(SemaRef, Ctor); } - if (BasesToInheritFrom.empty()) - return; - // FIXME: Constructor templates. - - // Now collect the constructors that we already have in the current class. - // Those take precedence over inherited constructors. - // C++11 [class.inhctor]p3: [...] a constructor is implicitly declared [...] - // unless there is a user-declared constructor with the same signature in - // the class where the using-declaration appears. - llvm::SmallSet<const Type *, 8> ExistingConstructors; - for (CXXRecordDecl::ctor_iterator CtorIt = ClassDecl->ctor_begin(), - CtorE = ClassDecl->ctor_end(); - CtorIt != CtorE; ++CtorIt) - ExistingConstructors.insert( - Context.getCanonicalType(CtorIt->getType()).getTypePtr()); - - DeclarationName CreatedCtorName = - Context.DeclarationNames.getCXXConstructorName( - ClassDecl->getTypeForDecl()->getCanonicalTypeUnqualified()); - - // Now comes the true work. - // First, we keep a map from constructor types to the base that introduced - // them. Needed for finding conflicting constructors. We also keep the - // actually inserted declarations in there, for pretty diagnostics. - typedef std::pair<CanQualType, CXXConstructorDecl *> ConstructorInfo; - typedef llvm::DenseMap<const Type *, ConstructorInfo> ConstructorToSourceMap; - ConstructorToSourceMap InheritedConstructors; - for (BasesVector::iterator BaseIt = BasesToInheritFrom.begin(), - BaseE = BasesToInheritFrom.end(); - BaseIt != BaseE; ++BaseIt) { - const RecordType *Base = *BaseIt; - CanQualType CanonicalBase = Base->getCanonicalTypeUnqualified(); - CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(Base->getDecl()); - for (CXXRecordDecl::ctor_iterator CtorIt = BaseDecl->ctor_begin(), - CtorE = BaseDecl->ctor_end(); - CtorIt != CtorE; ++CtorIt) { - // Find the using declaration for inheriting this base's constructors. - // FIXME: Don't perform name lookup just to obtain a source location! - DeclarationName Name = - Context.DeclarationNames.getCXXConstructorName(CanonicalBase); - LookupResult Result(*this, Name, SourceLocation(), LookupUsingDeclName); - LookupQualifiedName(Result, CurContext); - UsingDecl *UD = Result.getAsSingle<UsingDecl>(); - SourceLocation UsingLoc = UD ? UD->getLocation() : - ClassDecl->getLocation(); - - // C++11 [class.inhctor]p1: - // The candidate set of inherited constructors from the class X named in - // the using-declaration consists of actual constructors and notional - // constructors that result from the transformation of defaulted - // parameters as follows: - // - all non-template constructors of X, and - // - for each non-template constructor of X that has at least one - // parameter with a default argument, the set of constructors that - // results from omitting any ellipsis parameter specification and - // successively omitting parameters with a default argument from the - // end of the parameter-type-list, and - // FIXME: ...also constructor templates. - CXXConstructorDecl *BaseCtor = *CtorIt; - bool CanBeCopyOrMove = BaseCtor->isCopyOrMoveConstructor(); - const FunctionProtoType *BaseCtorType = - BaseCtor->getType()->getAs<FunctionProtoType>(); - - // Determine whether this would be a copy or move constructor for the - // derived class. - if (BaseCtorType->getNumArgs() >= 1 && - BaseCtorType->getArgType(0)->isReferenceType() && - Context.hasSameUnqualifiedType( - BaseCtorType->getArgType(0)->getPointeeType(), - Context.getTagDeclType(ClassDecl))) - CanBeCopyOrMove = true; - - ArrayRef<QualType> ArgTypes(BaseCtorType->getArgTypes()); - FunctionProtoType::ExtProtoInfo EPI = BaseCtorType->getExtProtoInfo(); - // Core issue (no number yet): the ellipsis is always discarded. - if (EPI.Variadic) { - Diag(UsingLoc, diag::warn_using_decl_constructor_ellipsis); - Diag(BaseCtor->getLocation(), - diag::note_using_decl_constructor_ellipsis); - EPI.Variadic = false; - } + typedef void (InheritingConstructorInfo::*VisitFn)(const CXXConstructorDecl*); - for (unsigned Params = BaseCtor->getMinRequiredArguments(), - MaxParams = BaseCtor->getNumParams(); - Params <= MaxParams; ++Params) { - // Skip default constructors. They're never inherited. - if (Params == 0) - continue; + /// Process all constructors for a class. + void visitAll(const CXXRecordDecl *RD, VisitFn Callback) { + for (CXXRecordDecl::ctor_iterator CtorIt = RD->ctor_begin(), + CtorE = RD->ctor_end(); + CtorIt != CtorE; ++CtorIt) + (this->*Callback)(*CtorIt); + for (CXXRecordDecl::specific_decl_iterator<FunctionTemplateDecl> + I(RD->decls_begin()), E(RD->decls_end()); + I != E; ++I) { + const FunctionDecl *FD = (*I)->getTemplatedDecl(); + if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) + (this->*Callback)(CD); + } + } - // Skip copy and move constructors for both base and derived class - // for the same reason. - if (CanBeCopyOrMove && Params == 1) - continue; + /// Note that a constructor (or constructor template) was declared in Derived. + void noteDeclaredInDerived(const CXXConstructorDecl *Ctor) { + getEntry(Ctor, Ctor->getType()).DeclaredInDerived = true; + } - // Build up a function type for this particular constructor. - QualType NewCtorType = - Context.getFunctionType(Context.VoidTy, ArgTypes.slice(0, Params), - EPI); - const Type *CanonicalNewCtorType = - Context.getCanonicalType(NewCtorType).getTypePtr(); - - // C++11 [class.inhctor]p3: - // ... a constructor is implicitly declared with the same constructor - // characteristics unless there is a user-declared constructor with - // the same signature in the class where the using-declaration appears - if (ExistingConstructors.count(CanonicalNewCtorType)) - continue; + /// Inherit a single constructor. + void inherit(const CXXConstructorDecl *Ctor) { + const FunctionProtoType *CtorType = + Ctor->getType()->castAs<FunctionProtoType>(); + ArrayRef<QualType> ArgTypes(CtorType->getArgTypes()); + FunctionProtoType::ExtProtoInfo EPI = CtorType->getExtProtoInfo(); - // C++11 [class.inhctor]p7: - // If two using-declarations declare inheriting constructors with the - // same signature, the program is ill-formed - std::pair<ConstructorToSourceMap::iterator, bool> result = - InheritedConstructors.insert(std::make_pair( - CanonicalNewCtorType, - std::make_pair(CanonicalBase, (CXXConstructorDecl*)0))); - if (!result.second) { - // Already in the map. If it came from a different class, that's an - // error. Not if it's from the same. - CanQualType PreviousBase = result.first->second.first; - if (CanonicalBase != PreviousBase) { - const CXXConstructorDecl *PrevCtor = result.first->second.second; - const CXXConstructorDecl *PrevBaseCtor = - PrevCtor->getInheritedConstructor(); - assert(PrevBaseCtor && "Conflicting constructor was not inherited"); - - Diag(UsingLoc, diag::err_using_decl_constructor_conflict); - Diag(BaseCtor->getLocation(), - diag::note_using_decl_constructor_conflict_current_ctor); - Diag(PrevBaseCtor->getLocation(), - diag::note_using_decl_constructor_conflict_previous_ctor); - Diag(PrevCtor->getLocation(), - diag::note_using_decl_constructor_conflict_previous_using); - } else { - // Core issue (no number): if the same inheriting constructor is - // produced by multiple base class constructors from the same base - // class, the inheriting constructor is defined as deleted. - SetDeclDeleted(result.first->second.second, UsingLoc); - } - continue; - } + SourceLocation UsingLoc = getUsingLoc(Ctor->getParent()); - // OK, we're there, now add the constructor. - DeclarationNameInfo DNI(CreatedCtorName, UsingLoc); - CXXConstructorDecl *NewCtor = CXXConstructorDecl::Create( - Context, ClassDecl, UsingLoc, DNI, NewCtorType, - /*TInfo=*/0, BaseCtor->isExplicit(), /*Inline=*/true, - /*ImplicitlyDeclared=*/true, /*Constexpr=*/BaseCtor->isConstexpr()); - NewCtor->setAccess(BaseCtor->getAccess()); - - // Build an unevaluated exception specification for this constructor. - EPI.ExceptionSpecType = EST_Unevaluated; - EPI.ExceptionSpecDecl = NewCtor; - NewCtor->setType(Context.getFunctionType(Context.VoidTy, - ArgTypes.slice(0, Params), - EPI)); - - // Build up the parameter decls and add them. - SmallVector<ParmVarDecl *, 16> ParamDecls; - for (unsigned i = 0; i < Params; ++i) { - ParmVarDecl *PD = ParmVarDecl::Create(Context, NewCtor, - UsingLoc, UsingLoc, - /*IdentifierInfo=*/0, - BaseCtorType->getArgType(i), - /*TInfo=*/0, SC_None, - /*DefaultArg=*/0); - PD->setScopeInfo(0, i); - PD->setImplicit(); - ParamDecls.push_back(PD); - } - NewCtor->setParams(ParamDecls); - NewCtor->setInheritedConstructor(BaseCtor); - if (BaseCtor->isDeleted()) - SetDeclDeleted(NewCtor, UsingLoc); + // Core issue (no number yet): the ellipsis is always discarded. + if (EPI.Variadic) { + SemaRef.Diag(UsingLoc, diag::warn_using_decl_constructor_ellipsis); + SemaRef.Diag(Ctor->getLocation(), + diag::note_using_decl_constructor_ellipsis); + EPI.Variadic = false; + } - ClassDecl->addDecl(NewCtor); - result.first->second.second = NewCtor; + // Declare a constructor for each number of parameters. + // + // C++11 [class.inhctor]p1: + // The candidate set of inherited constructors from the class X named in + // the using-declaration consists of [... modulo defects ...] for each + // constructor or constructor template of X, the set of constructors or + // constructor templates that results from omitting any ellipsis parameter + // specification and successively omitting parameters with a default + // argument from the end of the parameter-type-list + unsigned MinParams = minParamsToInherit(Ctor); + unsigned Params = Ctor->getNumParams(); + if (Params >= MinParams) { + do + declareCtor(UsingLoc, Ctor, + SemaRef.Context.getFunctionType( + Ctor->getResultType(), ArgTypes.slice(0, Params), EPI)); + while (Params > MinParams && + Ctor->getParamDecl(--Params)->hasDefaultArg()); + } + } + + /// Find the using-declaration which specified that we should inherit the + /// constructors of \p Base. + SourceLocation getUsingLoc(const CXXRecordDecl *Base) { + // No fancy lookup required; just look for the base constructor name + // directly within the derived class. + ASTContext &Context = SemaRef.Context; + DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(Context.getRecordType(Base))); + DeclContext::lookup_const_result Decls = Derived->lookup(Name); + return Decls.empty() ? Derived->getLocation() : Decls[0]->getLocation(); + } + + unsigned minParamsToInherit(const CXXConstructorDecl *Ctor) { + // C++11 [class.inhctor]p3: + // [F]or each constructor template in the candidate set of inherited + // constructors, a constructor template is implicitly declared + if (Ctor->getDescribedFunctionTemplate()) + return 0; + + // For each non-template constructor in the candidate set of inherited + // constructors other than a constructor having no parameters or a + // copy/move constructor having a single parameter, a constructor is + // implicitly declared [...] + if (Ctor->getNumParams() == 0) + return 1; + if (Ctor->isCopyOrMoveConstructor()) + return 2; + + // Per discussion on core reflector, never inherit a constructor which + // would become a default, copy, or move constructor of Derived either. + const ParmVarDecl *PD = Ctor->getParamDecl(0); + const ReferenceType *RT = PD->getType()->getAs<ReferenceType>(); + return (RT && RT->getPointeeCXXRecordDecl() == Derived) ? 2 : 1; + } + + /// Declare a single inheriting constructor, inheriting the specified + /// constructor, with the given type. + void declareCtor(SourceLocation UsingLoc, const CXXConstructorDecl *BaseCtor, + QualType DerivedType) { + InheritingConstructor &Entry = getEntry(BaseCtor, DerivedType); + + // C++11 [class.inhctor]p3: + // ... a constructor is implicitly declared with the same constructor + // characteristics unless there is a user-declared constructor with + // the same signature in the class where the using-declaration appears + if (Entry.DeclaredInDerived) + return; + + // C++11 [class.inhctor]p7: + // If two using-declarations declare inheriting constructors with the + // same signature, the program is ill-formed + if (Entry.DerivedCtor) { + if (BaseCtor->getParent() != Entry.BaseCtor->getParent()) { + // Only diagnose this once per constructor. + if (Entry.DerivedCtor->isInvalidDecl()) + return; + Entry.DerivedCtor->setInvalidDecl(); + + SemaRef.Diag(UsingLoc, diag::err_using_decl_constructor_conflict); + SemaRef.Diag(BaseCtor->getLocation(), + diag::note_using_decl_constructor_conflict_current_ctor); + SemaRef.Diag(Entry.BaseCtor->getLocation(), + diag::note_using_decl_constructor_conflict_previous_ctor); + SemaRef.Diag(Entry.DerivedCtor->getLocation(), + diag::note_using_decl_constructor_conflict_previous_using); + } else { + // Core issue (no number): if the same inheriting constructor is + // produced by multiple base class constructors from the same base + // class, the inheriting constructor is defined as deleted. + SemaRef.SetDeclDeleted(Entry.DerivedCtor, UsingLoc); } + + return; } + + ASTContext &Context = SemaRef.Context; + DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(Context.getRecordType(Derived))); + DeclarationNameInfo NameInfo(Name, UsingLoc); + + TemplateParameterList *TemplateParams = 0; + if (const FunctionTemplateDecl *FTD = + BaseCtor->getDescribedFunctionTemplate()) { + TemplateParams = FTD->getTemplateParameters(); + // We're reusing template parameters from a different DeclContext. This + // is questionable at best, but works out because the template depth in + // both places is guaranteed to be 0. + // FIXME: Rebuild the template parameters in the new context, and + // transform the function type to refer to them. + } + + // Build type source info pointing at the using-declaration. This is + // required by template instantiation. + TypeSourceInfo *TInfo = + Context.getTrivialTypeSourceInfo(DerivedType, UsingLoc); + FunctionProtoTypeLoc ProtoLoc = + TInfo->getTypeLoc().IgnoreParens().castAs<FunctionProtoTypeLoc>(); + + CXXConstructorDecl *DerivedCtor = CXXConstructorDecl::Create( + Context, Derived, UsingLoc, NameInfo, DerivedType, + TInfo, BaseCtor->isExplicit(), /*Inline=*/true, + /*ImplicitlyDeclared=*/true, /*Constexpr=*/BaseCtor->isConstexpr()); + + // Build an unevaluated exception specification for this constructor. + const FunctionProtoType *FPT = DerivedType->castAs<FunctionProtoType>(); + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.ExceptionSpecType = EST_Unevaluated; + EPI.ExceptionSpecDecl = DerivedCtor; + DerivedCtor->setType(Context.getFunctionType(FPT->getResultType(), + FPT->getArgTypes(), EPI)); + + // Build the parameter declarations. + SmallVector<ParmVarDecl *, 16> ParamDecls; + for (unsigned I = 0, N = FPT->getNumArgs(); I != N; ++I) { + TypeSourceInfo *TInfo = + Context.getTrivialTypeSourceInfo(FPT->getArgType(I), UsingLoc); + ParmVarDecl *PD = ParmVarDecl::Create( + Context, DerivedCtor, UsingLoc, UsingLoc, /*IdentifierInfo=*/0, + FPT->getArgType(I), TInfo, SC_None, /*DefaultArg=*/0); + PD->setScopeInfo(0, I); + PD->setImplicit(); + ParamDecls.push_back(PD); + ProtoLoc.setArg(I, PD); + } + + // Set up the new constructor. + DerivedCtor->setAccess(BaseCtor->getAccess()); + DerivedCtor->setParams(ParamDecls); + DerivedCtor->setInheritedConstructor(BaseCtor); + if (BaseCtor->isDeleted()) + SemaRef.SetDeclDeleted(DerivedCtor, UsingLoc); + + // If this is a constructor template, build the template declaration. + if (TemplateParams) { + FunctionTemplateDecl *DerivedTemplate = + FunctionTemplateDecl::Create(SemaRef.Context, Derived, UsingLoc, Name, + TemplateParams, DerivedCtor); + DerivedTemplate->setAccess(BaseCtor->getAccess()); + DerivedCtor->setDescribedFunctionTemplate(DerivedTemplate); + Derived->addDecl(DerivedTemplate); + } else { + Derived->addDecl(DerivedCtor); + } + + Entry.BaseCtor = BaseCtor; + Entry.DerivedCtor = DerivedCtor; } + + Sema &SemaRef; + CXXRecordDecl *Derived; + typedef llvm::DenseMap<const Type *, InheritingConstructorsForType> MapType; + MapType Map; +}; +} + +void Sema::DeclareInheritingConstructors(CXXRecordDecl *ClassDecl) { + // Defer declaring the inheriting constructors until the class is + // instantiated. + if (ClassDecl->isDependentContext()) + return; + + // Find base classes from which we might inherit constructors. + SmallVector<CXXRecordDecl*, 4> InheritedBases; + for (CXXRecordDecl::base_class_iterator BaseIt = ClassDecl->bases_begin(), + BaseE = ClassDecl->bases_end(); + BaseIt != BaseE; ++BaseIt) + if (BaseIt->getInheritConstructors()) + InheritedBases.push_back(BaseIt->getType()->getAsCXXRecordDecl()); + + // Go no further if we're not inheriting any constructors. + if (InheritedBases.empty()) + return; + + // Declare the inherited constructors. + InheritingConstructorInfo ICI(*this, ClassDecl); + for (unsigned I = 0, N = InheritedBases.size(); I != N; ++I) + ICI.inheritAll(InheritedBases[I]); } void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation, @@ -7943,9 +8255,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { FunctionProtoType::ExtProtoInfo EPI; EPI.ExceptionSpecType = EST_Unevaluated; EPI.ExceptionSpecDecl = Destructor; - Destructor->setType(Context.getFunctionType(Context.VoidTy, - ArrayRef<QualType>(), - EPI)); + Destructor->setType(Context.getFunctionType(Context.VoidTy, None, EPI)); AddOverriddenMethods(ClassDecl, Destructor); @@ -8049,9 +8359,7 @@ void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl, FunctionProtoType::ExtProtoInfo EPI = DtorType->getExtProtoInfo(); EPI.ExceptionSpecType = EST_Unevaluated; EPI.ExceptionSpecDecl = Destructor; - Destructor->setType(Context.getFunctionType(Context.VoidTy, - ArrayRef<QualType>(), - EPI)); + Destructor->setType(Context.getFunctionType(Context.VoidTy, None, EPI)); // FIXME: If the destructor has a body that could throw, and the newly created // spec doesn't allow exceptions, we should emit a warning, because this @@ -10174,7 +10482,8 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, // FIXME: Add all the various semantics of linkage specifications LinkageSpecDecl *D = LinkageSpecDecl::Create(Context, CurContext, - ExternLoc, LangLoc, Language); + ExternLoc, LangLoc, Language, + LBraceLoc.isValid()); CurContext->addDecl(D); PushDeclContext(S, D); return D; @@ -10307,9 +10616,8 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, Expr *opaqueValue = new (Context) OpaqueValueExpr(Loc, initType, VK_LValue, OK_Ordinary); - InitializationSequence sequence(*this, entity, initKind, &opaqueValue, 1); - ExprResult result = sequence.Perform(*this, entity, initKind, - MultiExprArg(&opaqueValue, 1)); + InitializationSequence sequence(*this, entity, initKind, opaqueValue); + ExprResult result = sequence.Perform(*this, entity, initKind, opaqueValue); if (result.isInvalid()) Invalid = true; else { @@ -10798,29 +11106,39 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, // Find the appropriate context according to the above. DC = CurContext; + + // Skip class contexts. If someone can cite chapter and verse + // for this behavior, that would be nice --- it's what GCC and + // EDG do, and it seems like a reasonable intent, but the spec + // really only says that checks for unqualified existing + // declarations should stop at the nearest enclosing namespace, + // not that they should only consider the nearest enclosing + // namespace. + while (DC->isRecord()) + DC = DC->getParent(); + + DeclContext *LookupDC = DC; + while (LookupDC->isTransparentContext()) + LookupDC = LookupDC->getParent(); + while (true) { - // Skip class contexts. If someone can cite chapter and verse - // for this behavior, that would be nice --- it's what GCC and - // EDG do, and it seems like a reasonable intent, but the spec - // really only says that checks for unqualified existing - // declarations should stop at the nearest enclosing namespace, - // not that they should only consider the nearest enclosing - // namespace. - while (DC->isRecord() || DC->isTransparentContext()) - DC = DC->getParent(); - - LookupQualifiedName(Previous, DC); + LookupQualifiedName(Previous, LookupDC); // TODO: decide what we think about using declarations. - if (isLocal || !Previous.empty()) + if (isLocal) + break; + + if (!Previous.empty()) { + DC = LookupDC; break; + } if (isTemplateId) { - if (isa<TranslationUnitDecl>(DC)) break; + if (isa<TranslationUnitDecl>(LookupDC)) break; } else { - if (DC->isFileContext()) break; + if (LookupDC->isFileContext()) break; } - DC = DC->getParent(); + LookupDC = LookupDC->getParent(); } DCScope = getScopeForDeclContext(S, DC); @@ -11373,8 +11691,7 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, // Ignore any vtable uses in unevaluated operands or for classes that do // not have a vtable. if (!Class->isDynamicClass() || Class->isDependentContext() || - CurContext->isDependentContext() || - ExprEvalContexts.back().Context == Unevaluated) + CurContext->isDependentContext() || isUnevaluatedContext()) return; // Try to insert this class into the map. @@ -11562,10 +11879,10 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field); InitializationKind InitKind = InitializationKind::CreateDefault(ObjCImplementation->getLocation()); - - InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); - ExprResult MemberInit = - InitSeq.Perform(*this, InitEntity, InitKind, MultiExprArg()); + + InitializationSequence InitSeq(*this, InitEntity, InitKind, None); + ExprResult MemberInit = + InitSeq.Perform(*this, InitEntity, InitKind, None); MemberInit = MaybeCreateExprWithCleanups(MemberInit); // Note, MemberInit could actually come back empty if no initialization // is required (e.g., because it would call a trivial default constructor) @@ -11921,3 +12238,94 @@ bool Sema::CheckCUDATarget(CUDAFunctionTarget CallerTarget, return false; } + +/// HandleMSProperty - Analyze a __delcspec(property) field of a C++ class. +/// +MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record, + SourceLocation DeclStart, + Declarator &D, Expr *BitWidth, + InClassInitStyle InitStyle, + AccessSpecifier AS, + AttributeList *MSPropertyAttr) { + IdentifierInfo *II = D.getIdentifier(); + if (!II) { + Diag(DeclStart, diag::err_anonymous_property); + return NULL; + } + SourceLocation Loc = D.getIdentifierLoc(); + + TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); + QualType T = TInfo->getType(); + if (getLangOpts().CPlusPlus) { + CheckExtraCXXDefaultArguments(D); + + if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, + UPPC_DataMemberType)) { + D.setInvalidType(); + T = Context.IntTy; + TInfo = Context.getTrivialTypeSourceInfo(T, Loc); + } + } + + DiagnoseFunctionSpecifiers(D.getDeclSpec()); + + if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) + Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), + diag::err_invalid_thread) + << DeclSpec::getSpecifierName(TSCS); + + // Check to see if this name was declared as a member previously + NamedDecl *PrevDecl = 0; + LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration); + LookupName(Previous, S); + switch (Previous.getResultKind()) { + case LookupResult::Found: + case LookupResult::FoundUnresolvedValue: + PrevDecl = Previous.getAsSingle<NamedDecl>(); + break; + + case LookupResult::FoundOverloaded: + PrevDecl = Previous.getRepresentativeDecl(); + break; + + case LookupResult::NotFound: + case LookupResult::NotFoundInCurrentInstantiation: + case LookupResult::Ambiguous: + break; + } + + if (PrevDecl && PrevDecl->isTemplateParameter()) { + // Maybe we will complain about the shadowed template parameter. + DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); + // Just pretend that we didn't see the previous declaration. + PrevDecl = 0; + } + + if (PrevDecl && !isDeclInScope(PrevDecl, Record, S)) + PrevDecl = 0; + + SourceLocation TSSL = D.getLocStart(); + MSPropertyDecl *NewPD; + const AttributeList::PropertyData &Data = MSPropertyAttr->getPropertyData(); + NewPD = new (Context) MSPropertyDecl(Record, Loc, + II, T, TInfo, TSSL, + Data.GetterId, Data.SetterId); + ProcessDeclAttributes(TUScope, NewPD, D); + NewPD->setAccess(AS); + + if (NewPD->isInvalidDecl()) + Record->setInvalidDecl(); + + if (D.getDeclSpec().isModulePrivateSpecified()) + NewPD->setModulePrivate(); + + if (NewPD->isInvalidDecl() && PrevDecl) { + // Don't introduce NewFD into scope; there's already something + // with the same name in the same scope. + } else if (II) { + PushOnScopeChains(NewPD, S); + } else + Record->addDecl(NewPD); + + return NewPD; +} diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 5c26d7f..f33e7bc 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -745,7 +745,10 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, << ProtocolId[i].first; continue; } - + // If this is a forward protocol declaration, get its definition. + if (!PDecl->isThisDeclarationADefinition() && PDecl->getDefinition()) + PDecl = PDecl->getDefinition(); + (void)DiagnoseUseOfDecl(PDecl, ProtocolId[i].second); // If this is a forward declaration and we are supposed to warn in this @@ -1042,7 +1045,7 @@ Decl *Sema::ActOnStartClassImplementation( ObjCImplementationDecl* IMPDecl = ObjCImplementationDecl::Create(Context, CurContext, IDecl, SDecl, - ClassLoc, AtClassImplLoc); + ClassLoc, AtClassImplLoc, SuperClassLoc); if (CheckObjCDeclScope(IMPDecl)) return ActOnObjCContainerStartDefinition(IMPDecl); @@ -1833,7 +1836,7 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, if (!(LangOpts.ObjCDefaultSynthProperties && LangOpts.ObjCRuntime.isNonFragile()) || IDecl->isObjCRequiresPropertyDefs()) - DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap); + DiagnoseUnimplementedProperties(S, IMPDecl, CDecl); SelectorSet ClsMap; for (ObjCImplementationDecl::classmeth_iterator @@ -1880,17 +1883,7 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, E = C->protocol_end(); PI != E; ++PI) CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, InsMap, ClsMap, CDecl); - // Report unimplemented properties in the category as well. - // When reporting on missing setter/getters, do not report when - // setter/getter is implemented in category's primary class - // implementation. - if (ObjCInterfaceDecl *ID = C->getClassInterface()) - if (ObjCImplDecl *IMP = ID->getImplementation()) { - for (ObjCImplementationDecl::instmeth_iterator - I = IMP->instmeth_begin(), E = IMP->instmeth_end(); I!=E; ++I) - InsMap.insert((*I)->getSelector()); - } - DiagnoseUnimplementedProperties(S, IMPDecl, CDecl, InsMap); + DiagnoseUnimplementedProperties(S, IMPDecl, CDecl); } } else llvm_unreachable("invalid ObjCContainerDecl type."); @@ -2082,17 +2075,24 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left, } void Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method) { + // Record at the head of the list whether there were 0, 1, or >= 2 methods + // inside categories. + if (ObjCCategoryDecl * + CD = dyn_cast<ObjCCategoryDecl>(Method->getDeclContext())) + if (!CD->IsClassExtension() && List->getBits() < 2) + List->setBits(List->getBits()+1); + // If the list is empty, make it a singleton list. if (List->Method == 0) { List->Method = Method; - List->Next = 0; + List->setNext(0); return; } // We've seen a method with this name, see if we have already seen this type // signature. ObjCMethodList *Previous = List; - for (; List; Previous = List, List = List->Next) { + for (; List; Previous = List, List = List->getNext()) { if (!MatchTwoMethodDeclarations(Method, List->Method)) continue; @@ -2121,7 +2121,7 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method) { // We have a new signature for an existing method - add it. // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". ObjCMethodList *Mem = BumpAlloc.Allocate<ObjCMethodList>(); - Previous->Next = new (Mem) ObjCMethodList(Method, 0); + Previous->setNext(new (Mem) ObjCMethodList(Method, 0)); } /// \brief Read the contents of the method pool for a given selector from @@ -2183,7 +2183,7 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, // Gather the non-hidden methods. ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second; llvm::SmallVector<ObjCMethodDecl *, 4> Methods; - for (ObjCMethodList *M = &MethList; M; M = M->Next) { + for (ObjCMethodList *M = &MethList; M; M = M->getNext()) { if (M->Method && !M->Method->isHidden()) { // If we're not supposed to warn about mismatches, we're done. if (!warn) @@ -2800,10 +2800,47 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod, i = overrides.begin(), e = overrides.end(); i != e; ++i) { ObjCMethodDecl *overridden = *i; - if (isa<ObjCProtocolDecl>(overridden->getDeclContext()) || - CurrentClass != overridden->getClassInterface() || - overridden->isOverriding()) - hasOverriddenMethodsInBaseOrProtocol = true; + if (!hasOverriddenMethodsInBaseOrProtocol) { + if (isa<ObjCProtocolDecl>(overridden->getDeclContext()) || + CurrentClass != overridden->getClassInterface() || + overridden->isOverriding()) { + hasOverriddenMethodsInBaseOrProtocol = true; + + } else if (isa<ObjCImplDecl>(ObjCMethod->getDeclContext())) { + // OverrideSearch will return as "overridden" the same method in the + // interface. For hasOverriddenMethodsInBaseOrProtocol, we need to + // check whether a category of a base class introduced a method with the + // same selector, after the interface method declaration. + // To avoid unnecessary lookups in the majority of cases, we use the + // extra info bits in GlobalMethodPool to check whether there were any + // category methods with this selector. + GlobalMethodPool::iterator It = + MethodPool.find(ObjCMethod->getSelector()); + if (It != MethodPool.end()) { + ObjCMethodList &List = + ObjCMethod->isInstanceMethod()? It->second.first: It->second.second; + unsigned CategCount = List.getBits(); + if (CategCount > 0) { + // If the method is in a category we'll do lookup if there were at + // least 2 category methods recorded, otherwise only one will do. + if (CategCount > 1 || + !isa<ObjCCategoryImplDecl>(overridden->getDeclContext())) { + OverrideSearch overrides(*this, overridden); + for (OverrideSearch::iterator + OI= overrides.begin(), OE= overrides.end(); OI!=OE; ++OI) { + ObjCMethodDecl *SuperOverridden = *OI; + if (isa<ObjCProtocolDecl>(SuperOverridden->getDeclContext()) || + CurrentClass != SuperOverridden->getClassInterface()) { + hasOverriddenMethodsInBaseOrProtocol = true; + overridden->setOverriding(true); + break; + } + } + } + } + } + } + } // Propagate down the 'related result type' bit from overridden methods. if (RTC != Sema::RTC_Incompatible && overridden->hasRelatedResultType()) @@ -3187,12 +3224,14 @@ Decl *Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) { if (DS.getStorageClassSpec() == DeclSpec::SCS_register) { Diag(DS.getStorageClassSpecLoc(), diag::warn_register_objc_catch_parm) << FixItHint::CreateRemoval(SourceRange(DS.getStorageClassSpecLoc())); - } else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) { + } else if (DeclSpec::SCS SCS = DS.getStorageClassSpec()) { Diag(DS.getStorageClassSpecLoc(), diag::err_storage_spec_on_catch_parm) - << DS.getStorageClassSpec(); - } - if (D.getDeclSpec().isThreadSpecified()) - Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + << DeclSpec::getSpecifierName(SCS); + } + if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) + Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), + diag::err_invalid_thread) + << DeclSpec::getSpecifierName(TSCS); D.getMutableDeclSpec().ClearStorageClassSpecs(); DiagnoseFunctionSpecifiers(D.getDeclSpec()); diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 26c3d35..1a5f482 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -1011,7 +1011,6 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::ConditionalOperatorClass: case Expr::CompoundLiteralExprClass: case Expr::CXXConstCastExprClass: - case Expr::CXXDefaultArgExprClass: case Expr::CXXReinterpretCastExprClass: case Expr::DesignatedInitExprClass: case Expr::ExprWithCleanupsClass: @@ -1044,6 +1043,12 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::StmtExprClass: return CT_Can; + case Expr::CXXDefaultArgExprClass: + return canThrow(cast<CXXDefaultArgExpr>(E)->getExpr()); + + case Expr::CXXDefaultInitExprClass: + return canThrow(cast<CXXDefaultInitExpr>(E)->getExpr()); + case Expr::ChooseExprClass: if (E->isTypeDependent() || E->isValueDependent()) return CT_Dependent; @@ -1111,6 +1116,9 @@ CanThrowResult Sema::canThrow(const Expr *E) { // These expressions can never throw. return CT_Cannot; + case Expr::MSPropertyRefExprClass: + llvm_unreachable("Invalid class for expression"); + #define STMT(CLASS, PARENT) case Expr::CLASS##Class: #define STMT_RANGE(Base, First, Last) #define LAST_STMT_RANGE(BASE, FIRST, LAST) diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 76330f5..dd05b82 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -55,6 +55,12 @@ bool Sema::CanUseDecl(NamedDecl *D) { if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { if (FD->isDeleted()) return false; + + // If the function has a deduced return type, and we can't deduce it, + // then we can't use it either. + if (getLangOpts().CPlusPlus1y && FD->getResultType()->isUndeducedType() && + DeduceReturnType(FD, SourceLocation(), /*Diagnose*/false)) + return false; } // See if this function is unavailable. @@ -278,6 +284,12 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, NoteDeletedFunction(FD); return true; } + + // If the function has a deduced return type, and we can't deduce it, + // then we can't use it either. + if (getLangOpts().CPlusPlus1y && FD->getResultType()->isUndeducedType() && + DeduceReturnType(FD, Loc)) + return true; } DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass); @@ -806,7 +818,7 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, return ExprError(); ExprResult Call = ActOnCallExpr(TUScope, TrapFn.get(), - E->getLocStart(), MultiExprArg(), + E->getLocStart(), None, E->getLocEnd()); if (Call.isInvalid()) return ExprError(); @@ -1916,15 +1928,17 @@ ExprResult Sema::ActOnIdExpression(Scope *S, // If this name wasn't predeclared and if this is not a function // call, diagnose the problem. if (R.empty()) { - // In Microsoft mode, if we are inside a template class member function - // and we can't resolve an identifier then assume the identifier is type - // dependent. The goal is to postpone name lookup to instantiation time - // to be able to search into type dependent base classes. - if (getLangOpts().MicrosoftMode && CurContext->isDependentContext() && - isa<CXXMethodDecl>(CurContext)) - return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo, - IsAddressOfOperand, TemplateArgs); + // whose parent class has dependent base classes, and we can't resolve + // an identifier, then assume the identifier is type dependent. The + // goal is to postpone name lookup to instantiation time to be able to + // search into the type dependent base classes. + if (getLangOpts().MicrosoftMode) { + CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext); + if (MD && MD->getParent()->hasAnyDependentBases()) + return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo, + IsAddressOfOperand, TemplateArgs); + } CorrectionCandidateCallback DefaultValidator; if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator)) @@ -2636,6 +2650,10 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, break; } + case Decl::MSProperty: + valueKind = VK_LValue; + break; + case Decl::CXXMethod: // If we're referring to a method with an __unknown_anytype // result type, make the entire expression __unknown_anytype. @@ -2760,8 +2778,7 @@ ExprResult Sema::ActOnCharacterConstant(const Token &Tok, Scope *UDLScope) { // C++11 [lex.ext]p6: The literal L is treated as a call of the form // operator "" X (ch) return BuildCookedLiteralOperatorCall(*this, UDLScope, UDSuffix, UDSuffixLoc, - llvm::makeArrayRef(&Lit, 1), - Tok.getLocation()); + Lit, Tok.getLocation()); } ExprResult Sema::ActOnIntegerConstant(SourceLocation Loc, uint64_t Val) { @@ -2858,7 +2875,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { // Perform literal operator lookup to determine if we're building a raw // literal or a cooked one. LookupResult R(*this, OpName, UDSuffixLoc, LookupOrdinaryName); - switch (LookupLiteralOperator(UDLScope, R, llvm::makeArrayRef(&CookedTy, 1), + switch (LookupLiteralOperator(UDLScope, R, CookedTy, /*AllowRawAndTemplate*/true)) { case LOLR_Error: return ExprError(); @@ -2874,8 +2891,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { Lit = IntegerLiteral::Create(Context, ResultVal, CookedTy, Tok.getLocation()); } - return BuildLiteralOperatorCall(R, OpNameInfo, - llvm::makeArrayRef(&Lit, 1), + return BuildLiteralOperatorCall(R, OpNameInfo, Lit, Tok.getLocation()); } @@ -2891,8 +2907,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { Expr *Lit = StringLiteral::Create( Context, StringRef(TokSpelling.data(), Length), StringLiteral::Ascii, /*Pascal*/false, StrTy, &TokLoc, 1); - return BuildLiteralOperatorCall(R, OpNameInfo, - llvm::makeArrayRef(&Lit, 1), TokLoc); + return BuildLiteralOperatorCall(R, OpNameInfo, Lit, TokLoc); } case LOLR_Template: @@ -2910,8 +2925,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { TemplateArgumentLocInfo ArgInfo; ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo)); } - return BuildLiteralOperatorCall(R, OpNameInfo, ArrayRef<Expr*>(), - Tok.getLocation(), &ExplicitArgs); + return BuildLiteralOperatorCall(R, OpNameInfo, None, Tok.getLocation(), + &ExplicitArgs); } llvm_unreachable("unexpected literal operator lookup result"); @@ -3150,13 +3165,7 @@ static void warnOnSizeofOnArrayDecay(Sema &S, SourceLocation Loc, QualType T, bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, UnaryExprOrTypeTrait ExprKind) { QualType ExprTy = E->getType(); - - // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, - // the result is the size of the referenced type." - // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the - // result shall be the alignment of the referenced type." - if (const ReferenceType *Ref = ExprTy->getAs<ReferenceType>()) - ExprTy = Ref->getPointeeType(); + assert(!ExprTy->isReferenceType()); if (ExprKind == UETT_VecStep) return CheckVecStepTraitOperandType(*this, ExprTy, E->getExprLoc(), @@ -3172,10 +3181,9 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, ExprKind, E->getSourceRange())) return true; - // Completeing the expression's type may have changed it. + // Completing the expression's type may have changed it. ExprTy = E->getType(); - if (const ReferenceType *Ref = ExprTy->getAs<ReferenceType>()) - ExprTy = Ref->getPointeeType(); + assert(!ExprTy->isReferenceType()); if (CheckObjCTraitOperandConstraints(*this, ExprTy, E->getExprLoc(), E->getSourceRange(), ExprKind)) @@ -3260,25 +3268,67 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType, static bool CheckAlignOfExpr(Sema &S, Expr *E) { E = E->IgnoreParens(); - // alignof decl is always ok. - if (isa<DeclRefExpr>(E)) - return false; - // Cannot know anything else if the expression is dependent. if (E->isTypeDependent()) return false; - if (E->getBitField()) { + if (E->getObjectKind() == OK_BitField) { S.Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield) << 1 << E->getSourceRange(); return true; } - // Alignment of a field access is always okay, so long as it isn't a - // bit-field. - if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) - if (isa<FieldDecl>(ME->getMemberDecl())) + ValueDecl *D = 0; + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { + D = DRE->getDecl(); + } else if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) { + D = ME->getMemberDecl(); + } + + // If it's a field, require the containing struct to have a + // complete definition so that we can compute the layout. + // + // This requires a very particular set of circumstances. For a + // field to be contained within an incomplete type, we must in the + // process of parsing that type. To have an expression refer to a + // field, it must be an id-expression or a member-expression, but + // the latter are always ill-formed when the base type is + // incomplete, including only being partially complete. An + // id-expression can never refer to a field in C because fields + // are not in the ordinary namespace. In C++, an id-expression + // can implicitly be a member access, but only if there's an + // implicit 'this' value, and all such contexts are subject to + // delayed parsing --- except for trailing return types in C++11. + // And if an id-expression referring to a field occurs in a + // context that lacks a 'this' value, it's ill-formed --- except, + // agian, in C++11, where such references are allowed in an + // unevaluated context. So C++11 introduces some new complexity. + // + // For the record, since __alignof__ on expressions is a GCC + // extension, GCC seems to permit this but always gives the + // nonsensical answer 0. + // + // We don't really need the layout here --- we could instead just + // directly check for all the appropriate alignment-lowing + // attributes --- but that would require duplicating a lot of + // logic that just isn't worth duplicating for such a marginal + // use-case. + if (FieldDecl *FD = dyn_cast_or_null<FieldDecl>(D)) { + // Fast path this check, since we at least know the record has a + // definition if we can find a member of it. + if (!FD->getParent()->isCompleteDefinition()) { + S.Diag(E->getExprLoc(), diag::err_alignof_member_of_incomplete_type) + << E->getSourceRange(); + return true; + } + + // Otherwise, if it's a field, and the field doesn't have + // reference type, then it must have a complete type (or be a + // flexible array member, which we explicitly want to + // white-list anyway), which makes the following checks trivial. + if (!FD->getType()->isReferenceType()) return false; + } return S.CheckUnaryExprOrTypeTraitOperand(E, UETT_AlignOf); } @@ -3333,7 +3383,7 @@ Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, isInvalid = CheckAlignOfExpr(*this, E); } else if (ExprKind == UETT_VecStep) { isInvalid = CheckVecStepExpr(E); - } else if (E->getBitField()) { // C99 6.5.3.4p1. + } else if (E->refersToBitField()) { // C99 6.5.3.4p1. Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield) << 0; isInvalid = true; } else { @@ -3665,14 +3715,11 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, Param); // Instantiate the expression. - MultiLevelTemplateArgumentList ArgList + MultiLevelTemplateArgumentList MutiLevelArgList = getTemplateInstantiationArgs(FD, 0, /*RelativeToPrimary=*/true); - std::pair<const TemplateArgument *, unsigned> Innermost - = ArgList.getInnermost(); InstantiatingTemplate Inst(*this, CallLoc, Param, - ArrayRef<TemplateArgument>(Innermost.first, - Innermost.second)); + MutiLevelArgList.getInnermost()); if (Inst) return ExprError(); @@ -3684,7 +3731,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, // default argument expression appears. ContextRAII SavedContext(*this, FD); LocalInstantiationScope Local(*this); - Result = SubstExpr(UninstExpr, ArgList); + Result = SubstExpr(UninstExpr, MutiLevelArgList); } if (Result.isInvalid()) return ExprError(); @@ -3697,7 +3744,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, /*FIXME:EqualLoc*/UninstExpr->getLocStart()); Expr *ResultE = Result.takeAs<Expr>(); - InitializationSequence InitSeq(*this, Entity, Kind, &ResultE, 1); + InitializationSequence InitSeq(*this, Entity, Kind, ResultE); Result = InitSeq.Perform(*this, Entity, Kind, ResultE); if (Result.isInvalid()) return ExprError(); @@ -4023,6 +4070,63 @@ Sema::CheckStaticArrayArgument(SourceLocation CallLoc, /// to have a function type. static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *fn); +/// Is the given type a placeholder that we need to lower out +/// immediately during argument processing? +static bool isPlaceholderToRemoveAsArg(QualType type) { + // Placeholders are never sugared. + const BuiltinType *placeholder = dyn_cast<BuiltinType>(type); + if (!placeholder) return false; + + switch (placeholder->getKind()) { + // Ignore all the non-placeholder types. +#define PLACEHOLDER_TYPE(ID, SINGLETON_ID) +#define BUILTIN_TYPE(ID, SINGLETON_ID) case BuiltinType::ID: +#include "clang/AST/BuiltinTypes.def" + return false; + + // We cannot lower out overload sets; they might validly be resolved + // by the call machinery. + case BuiltinType::Overload: + return false; + + // Unbridged casts in ARC can be handled in some call positions and + // should be left in place. + case BuiltinType::ARCUnbridgedCast: + return false; + + // Pseudo-objects should be converted as soon as possible. + case BuiltinType::PseudoObject: + return true; + + // The debugger mode could theoretically but currently does not try + // to resolve unknown-typed arguments based on known parameter types. + case BuiltinType::UnknownAny: + return true; + + // These are always invalid as call arguments and should be reported. + case BuiltinType::BoundMember: + case BuiltinType::BuiltinFn: + return true; + } + llvm_unreachable("bad builtin type kind"); +} + +/// Check an argument list for placeholders that we won't try to +/// handle later. +static bool checkArgsForPlaceholders(Sema &S, MultiExprArg args) { + // Apply this processing to all the arguments at once instead of + // dying at the first failure. + bool hasInvalid = false; + for (size_t i = 0, e = args.size(); i != e; i++) { + if (isPlaceholderToRemoveAsArg(args[i]->getType())) { + ExprResult result = S.CheckPlaceholderExpr(args[i]); + if (result.isInvalid()) hasInvalid = true; + else args[i] = result.take(); + } + } + return hasInvalid; +} + /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma /// locations. @@ -4035,6 +4139,9 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, if (Result.isInvalid()) return ExprError(); Fn = Result.take(); + if (checkArgsForPlaceholders(*this, ArgExprs)) + return ExprError(); + if (getLangOpts().CPlusPlus) { // If this is a pseudo-destructor expression, build the call immediately. if (isa<CXXPseudoDestructorExpr>(Fn)) { @@ -4046,10 +4153,15 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, ArgExprs.back()->getLocEnd())); } - return Owned(new (Context) CallExpr(Context, Fn, MultiExprArg(), + return Owned(new (Context) CallExpr(Context, Fn, None, Context.VoidTy, VK_RValue, RParenLoc)); } + if (Fn->getType() == Context.PseudoObjectTy) { + ExprResult result = CheckPlaceholderExpr(Fn); + if (result.isInvalid()) return ExprError(); + Fn = result.take(); + } // Determine whether this is a dependent call inside a C++ template, // in which case we won't do any semantic analysis now. @@ -4397,12 +4509,12 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, return ExprError(); InitializedEntity Entity - = InitializedEntity::InitializeTemporary(literalType); + = InitializedEntity::InitializeCompoundLiteralInit(TInfo); InitializationKind Kind = InitializationKind::CreateCStyleCast(LParenLoc, SourceRange(LParenLoc, RParenLoc), /*InitList=*/true); - InitializationSequence InitSeq(*this, Entity, Kind, &LiteralExpr, 1); + InitializationSequence InitSeq(*this, Entity, Kind, LiteralExpr); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, LiteralExpr, &literalType); if (Result.isInvalid()) @@ -6823,18 +6935,6 @@ QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS, bool IsCompAssign) { checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false); - // C99 6.5.7p2: Each of the operands shall have integer type. - if (!LHS.get()->getType()->hasIntegerRepresentation() || - !RHS.get()->getType()->hasIntegerRepresentation()) - return InvalidOperands(Loc, LHS, RHS); - - // C++0x: Don't allow scoped enums. FIXME: Use something better than - // hasIntegerRepresentation() above instead of this. - if (isScopedEnumerationType(LHS.get()->getType()) || - isScopedEnumerationType(RHS.get()->getType())) { - return InvalidOperands(Loc, LHS, RHS); - } - // Vector shifts promote their scalar inputs to vector type. if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) @@ -6856,7 +6956,19 @@ QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS, RHS = UsualUnaryConversions(RHS.take()); if (RHS.isInvalid()) return QualType(); + QualType RHSType = RHS.get()->getType(); + + // C99 6.5.7p2: Each of the operands shall have integer type. + if (!LHSType->hasIntegerRepresentation() || + !RHSType->hasIntegerRepresentation()) + return InvalidOperands(Loc, LHS, RHS); + // C++0x: Don't allow scoped enums. FIXME: Use something better than + // hasIntegerRepresentation() above instead of this. + if (isScopedEnumerationType(LHSType) || + isScopedEnumerationType(RHSType)) { + return InvalidOperands(Loc, LHS, RHS); + } // Sanity-check shift operands DiagnoseBadShiftValues(*this, LHS, RHS, Loc, Opc, LHSType); @@ -7213,17 +7325,6 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, } if (literalString) { - std::string resultComparison; - switch (Opc) { - case BO_LT: resultComparison = ") < 0"; break; - case BO_GT: resultComparison = ") > 0"; break; - case BO_LE: resultComparison = ") <= 0"; break; - case BO_GE: resultComparison = ") >= 0"; break; - case BO_EQ: resultComparison = ") == 0"; break; - case BO_NE: resultComparison = ") != 0"; break; - default: llvm_unreachable("Invalid comparison operator"); - } - DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_stringcompare) << isa<ObjCEncodeExpr>(literalStringStripped) @@ -8246,6 +8347,9 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp, << op->getType() << op->getSourceRange(); if (sfinae) return QualType(); + // Materialize the temporary as an lvalue so that we can take its address. + OrigOp = op = new (S.Context) + MaterializeTemporaryExpr(op->getType(), OrigOp.take(), true); } else if (isa<ObjCSelectorExpr>(op)) { return S.Context.getPointerType(op->getType()); } else if (lval == Expr::LV_MemberFunction) { @@ -8501,6 +8605,36 @@ static void DiagnoseSelfAssignment(Sema &S, Expr *LHSExpr, Expr *RHSExpr, << LHSExpr->getSourceRange() << RHSExpr->getSourceRange(); } +/// Check if a bitwise-& is performed on an Objective-C pointer. This +/// is usually indicative of introspection within the Objective-C pointer. +static void checkObjCPointerIntrospection(Sema &S, ExprResult &L, ExprResult &R, + SourceLocation OpLoc) { + if (!S.getLangOpts().ObjC1) + return; + + const Expr *ObjCPointerExpr = 0, *OtherExpr = 0; + const Expr *LHS = L.get(); + const Expr *RHS = R.get(); + + if (LHS->IgnoreParenCasts()->getType()->isObjCObjectPointerType()) { + ObjCPointerExpr = LHS; + OtherExpr = RHS; + } + else if (RHS->IgnoreParenCasts()->getType()->isObjCObjectPointerType()) { + ObjCPointerExpr = RHS; + OtherExpr = LHS; + } + + // This warning is deliberately made very specific to reduce false + // positives with logic that uses '&' for hashing. This logic mainly + // looks for code trying to introspect into tagged pointers, which + // code should generally never do. + if (ObjCPointerExpr && isa<IntegerLiteral>(OtherExpr->IgnoreParenCasts())) { + S.Diag(OpLoc, diag::warn_objc_pointer_masking) + << ObjCPointerExpr->getSourceRange(); + } +} + /// CreateBuiltinBinOp - Creates a new built-in binary operation with /// operator @p Opc at location @c TokLoc. This routine only supports /// built-in operations; ActOnBinOp handles overloaded operators. @@ -8518,7 +8652,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, InitializationKind::CreateDirectList(RHSExpr->getLocStart()); InitializedEntity Entity = InitializedEntity::InitializeTemporary(LHSExpr->getType()); - InitializationSequence InitSeq(*this, Entity, Kind, &RHSExpr, 1); + InitializationSequence InitSeq(*this, Entity, Kind, RHSExpr); ExprResult Init = InitSeq.Perform(*this, Entity, Kind, RHSExpr); if (Init.isInvalid()) return Init; @@ -8578,6 +8712,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, false); break; case BO_And: + checkObjCPointerIntrospection(*this, LHS, RHS, OpLoc); case BO_Xor: case BO_Or: ResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc); @@ -8819,6 +8954,33 @@ static void DiagnoseAdditionInShift(Sema &S, SourceLocation OpLoc, } } +static void DiagnoseShiftCompare(Sema &S, SourceLocation OpLoc, + Expr *LHSExpr, Expr *RHSExpr) { + CXXOperatorCallExpr *OCE = dyn_cast<CXXOperatorCallExpr>(LHSExpr); + if (!OCE) + return; + + FunctionDecl *FD = OCE->getDirectCallee(); + if (!FD || !FD->isOverloadedOperator()) + return; + + OverloadedOperatorKind Kind = FD->getOverloadedOperator(); + if (Kind != OO_LessLess && Kind != OO_GreaterGreater) + return; + + S.Diag(OpLoc, diag::warn_overloaded_shift_in_comparison) + << LHSExpr->getSourceRange() << RHSExpr->getSourceRange() + << (Kind == OO_LessLess); + SuggestParentheses(S, OCE->getOperatorLoc(), + S.PDiag(diag::note_precedence_silence) + << (Kind == OO_LessLess ? "<<" : ">>"), + OCE->getSourceRange()); + SuggestParentheses(S, OpLoc, + S.PDiag(diag::note_evaluate_comparison_first), + SourceRange(OCE->getArg(1)->getLocStart(), + RHSExpr->getLocEnd())); +} + /// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky /// precedence. static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc, @@ -8847,6 +9009,11 @@ static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc, DiagnoseAdditionInShift(Self, OpLoc, LHSExpr, Shift); DiagnoseAdditionInShift(Self, OpLoc, RHSExpr, Shift); } + + // Warn on overloaded shift operators and comparisons, such as: + // cout << 5 == 4; + if (BinaryOperator::isComparisonOp(Opc)) + DiagnoseShiftCompare(Self, OpLoc, LHSExpr, RHSExpr); } // Binary Operators. 'Tok' is the token for the operator. @@ -9611,7 +9778,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, FunctionProtoType::ExtProtoInfo EPI; EPI.HasTrailingReturn = false; EPI.TypeQuals |= DeclSpec::TQ_const; - T = Context.getFunctionType(Context.DependentTy, ArrayRef<QualType>(), EPI); + T = Context.getFunctionType(Context.DependentTy, None, EPI); Sig = Context.getTrivialTypeSourceInfo(T); } @@ -9790,7 +9957,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, if (isa<FunctionNoProtoType>(FTy)) { FunctionProtoType::ExtProtoInfo EPI; EPI.ExtInfo = Ext; - BlockTy = Context.getFunctionType(RetTy, ArrayRef<QualType>(), EPI); + BlockTy = Context.getFunctionType(RetTy, None, EPI); // Otherwise, if we don't need to change anything about the function type, // preserve its sugar structure. @@ -9815,7 +9982,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, } else { FunctionProtoType::ExtProtoInfo EPI; EPI.ExtInfo = FunctionType::ExtInfo().withNoReturn(NoReturn); - BlockTy = Context.getFunctionType(RetTy, ArrayRef<QualType>(), EPI); + BlockTy = Context.getFunctionType(RetTy, None, EPI); } DiagnoseUnusedParameters(BSI->TheDecl->param_begin(), @@ -10047,6 +10214,10 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, if (Hint.isNull() && !CheckInferredResultType) { ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); } + else if (CheckInferredResultType) { + SrcType = SrcType.getUnqualifiedType(); + DstType = DstType.getUnqualifiedType(); + } MayHaveConvFixit = true; break; case IncompatiblePointerSign: @@ -10446,11 +10617,11 @@ namespace { } ExprResult Sema::TransformToPotentiallyEvaluated(Expr *E) { - assert(ExprEvalContexts.back().Context == Unevaluated && + assert(isUnevaluatedContext() && "Should only transform unevaluated expressions"); ExprEvalContexts.back().Context = ExprEvalContexts[ExprEvalContexts.size()-2].Context; - if (ExprEvalContexts.back().Context == Unevaluated) + if (isUnevaluatedContext()) return E; return TransformToPE(*this).TransformExpr(E); } @@ -10482,7 +10653,7 @@ void Sema::PopExpressionEvaluationContext() { ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back(); if (!Rec.Lambdas.empty()) { - if (Rec.Context == Unevaluated) { + if (Rec.isUnevaluated()) { // C++11 [expr.prim.lambda]p2: // A lambda-expression shall not appear in an unevaluated operand // (Clause 5). @@ -10508,7 +10679,7 @@ void Sema::PopExpressionEvaluationContext() { // 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 || Rec.Context == ConstantEvaluated) { + if (Rec.isUnevaluated() || Rec.Context == ConstantEvaluated) { ExprCleanupObjects.erase(ExprCleanupObjects.begin() + Rec.NumCleanupObjects, ExprCleanupObjects.end()); ExprNeedsCleanups = Rec.ParentNeedsCleanups; @@ -10547,6 +10718,7 @@ static bool IsPotentiallyEvaluatedContext(Sema &SemaRef) { switch (SemaRef.ExprEvalContexts.back().Context) { case Sema::Unevaluated: + case Sema::UnevaluatedAbstract: // We are in an expression that is not potentially evaluated; do nothing. // (Depending on how you read the standard, we actually do need to do // something here for null pointer constants, but the standard's @@ -10793,6 +10965,34 @@ diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, // capture. } +/// \brief Capture the given variable in the captured region. +static ExprResult captureInCapturedRegion(Sema &S, CapturedRegionScopeInfo *RSI, + VarDecl *Var, QualType FieldType, + QualType DeclRefType, + SourceLocation Loc, + bool RefersToEnclosingLocal) { + // The current implemention assumes that all variables are captured + // by references. Since there is no capture by copy, no expression evaluation + // will be needed. + // + RecordDecl *RD = RSI->TheRecordDecl; + + FieldDecl *Field + = FieldDecl::Create(S.Context, RD, Loc, Loc, 0, FieldType, + S.Context.getTrivialTypeSourceInfo(FieldType, Loc), + 0, false, ICIS_NoInit); + Field->setImplicit(true); + Field->setAccess(AS_private); + RD->addDecl(Field); + + Expr *Ref = new (S.Context) DeclRefExpr(Var, RefersToEnclosingLocal, + DeclRefType, VK_LValue, Loc); + Var->setReferenced(true); + Var->setUsed(true); + + return Ref; +} + /// \brief Capture the given variable in the given lambda expression. static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI, VarDecl *Var, QualType FieldType, @@ -10894,9 +11094,9 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI, InitializationKind InitKind = InitializationKind::CreateDirect(Loc, Loc, Loc); - InitializationSequence Init(S, Entities.back(), InitKind, &Ref, 1); + InitializationSequence Init(S, Entities.back(), InitKind, Ref); ExprResult Result(true); - if (!Init.Diagnose(S, Entities.back(), InitKind, &Ref, 1)) + if (!Init.Diagnose(S, Entities.back(), InitKind, Ref)) Result = Init.Perform(S, Entities.back(), InitKind, Ref); // If this initialization requires any cleanups (e.g., due to a @@ -10933,10 +11133,10 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc, bool Explicit = (Kind != TryCapture_Implicit); unsigned FunctionScopesIndex = FunctionScopes.size() - 1; do { - // Only block literals and lambda expressions can capture; other - // scopes don't work. + // Only block literals, captured statements, and lambda expressions can + // capture; other scopes don't work. DeclContext *ParentDC; - if (isa<BlockDecl>(DC)) + if (isa<BlockDecl>(DC) || isa<CapturedDecl>(DC)) ParentDC = DC->getParent(); else if (isa<CXXMethodDecl>(DC) && cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call && @@ -10970,7 +11170,7 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc, } bool IsBlock = isa<BlockScopeInfo>(CSI); - bool IsLambda = !IsBlock; + bool IsLambda = isa<LambdaScopeInfo>(CSI); // Lambdas are not allowed to capture unnamed variables // (e.g. anonymous unions). @@ -11130,8 +11330,31 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc, SourceLocation(), CaptureType, CopyExpr); Nested = true; continue; - } - + } + + if (CapturedRegionScopeInfo *RSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) { + // By default, capture variables by reference. + bool ByRef = true; + // Using an LValue reference type is consistent with Lambdas (see below). + CaptureType = Context.getLValueReferenceType(DeclRefType); + + Expr *CopyExpr = 0; + if (BuildAndDiagnose) { + ExprResult Result = captureInCapturedRegion(*this, RSI, Var, + CaptureType, DeclRefType, + Loc, Nested); + if (!Result.isInvalid()) + CopyExpr = Result.take(); + } + + // Actually capture the variable. + if (BuildAndDiagnose) + CSI->addCapture(Var, /*isBlock*/false, ByRef, Nested, Loc, + SourceLocation(), CaptureType, CopyExpr); + Nested = true; + continue; + } + LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI); // Determine whether we are capturing by reference or by value. @@ -11580,6 +11803,7 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, const PartialDiagnostic &PD) { switch (ExprEvalContexts.back().Context) { case Unevaluated: + case UnevaluatedAbstract: // The argument will never be evaluated, so don't complain. break; diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 3f2cb02..27032a9 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -684,7 +684,8 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, MarkFunctionReferenced(E->getExprLoc(), Destructor); CheckDestructorAccess(E->getExprLoc(), Destructor, PDiag(diag::err_access_dtor_exception) << Ty); - DiagnoseUseOfDecl(Destructor, E->getExprLoc()); + if (DiagnoseUseOfDecl(Destructor, E->getExprLoc())) + return ExprError(); return Owned(E); } @@ -728,9 +729,21 @@ Sema::CXXThisScopeRAII::~CXXThisScopeRAII() { } } +static Expr *captureThis(ASTContext &Context, RecordDecl *RD, + QualType ThisTy, SourceLocation Loc) { + FieldDecl *Field + = FieldDecl::Create(Context, RD, Loc, Loc, 0, ThisTy, + Context.getTrivialTypeSourceInfo(ThisTy, Loc), + 0, false, ICIS_NoInit); + Field->setImplicit(true); + Field->setAccess(AS_private); + RD->addDecl(Field); + return new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit*/true); +} + void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) { // We don't need to capture this in an unevaluated context. - if (ExprEvalContexts.back().Context == Unevaluated && !Explicit) + if (isUnevaluatedContext() && !Explicit) return; // Otherwise, check that we can capture 'this'. @@ -746,6 +759,7 @@ void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) { if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref || CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval || CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_Block || + CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_CapturedRegion || Explicit) { // This closure can capture 'this'; continue looking upwards. NumClosures++; @@ -767,18 +781,13 @@ void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) { CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[idx]); Expr *ThisExpr = 0; QualType ThisTy = getCurrentThisType(); - if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI)) { + if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI)) // For lambda expressions, build a field and an initializing expression. - CXXRecordDecl *Lambda = LSI->Lambda; - FieldDecl *Field - = FieldDecl::Create(Context, Lambda, Loc, Loc, 0, ThisTy, - Context.getTrivialTypeSourceInfo(ThisTy, Loc), - 0, false, ICIS_NoInit); - Field->setImplicit(true); - Field->setAccess(AS_private); - Lambda->addDecl(Field); - ThisExpr = new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/true); - } + ThisExpr = captureThis(Context, LSI->Lambda, ThisTy, Loc); + else if (CapturedRegionScopeInfo *RSI + = dyn_cast<CapturedRegionScopeInfo>(FunctionScopes[idx])) + ThisExpr = captureThis(Context, RSI->TheRecordDecl, ThisTy, Loc); + bool isNested = NumClosures > 1; CSI->addThisCapture(isNested, Loc, ThisTy, ThisExpr); } @@ -831,23 +840,20 @@ Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep, ExprResult Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, SourceLocation LParenLoc, - MultiExprArg exprs, + MultiExprArg Exprs, SourceLocation RParenLoc) { QualType Ty = TInfo->getType(); SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc(); - if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(exprs)) { + if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs)) { return Owned(CXXUnresolvedConstructExpr::Create(Context, TInfo, LParenLoc, - exprs, + Exprs, RParenLoc)); } - unsigned NumExprs = exprs.size(); - Expr **Exprs = exprs.data(); - bool ListInitialization = LParenLoc.isInvalid(); - assert((!ListInitialization || (NumExprs == 1 && isa<InitListExpr>(Exprs[0]))) + assert((!ListInitialization || (Exprs.size() == 1 && isa<InitListExpr>(Exprs[0]))) && "List initialization must have initializer list as expression."); SourceRange FullRange = SourceRange(TyBeginLoc, ListInitialization ? Exprs[0]->getSourceRange().getEnd() : RParenLoc); @@ -856,7 +862,7 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, // If the expression list is a single expression, the type conversion // expression is equivalent (in definedness, and if defined in meaning) to the // corresponding cast expression. - if (NumExprs == 1 && !ListInitialization) { + if (Exprs.size() == 1 && !ListInitialization) { Expr *Arg = Exprs[0]; return BuildCXXFunctionalCastExpr(TInfo, LParenLoc, Arg, RParenLoc); } @@ -879,15 +885,13 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, return ExprError(); InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo); - InitializationKind Kind - = NumExprs ? ListInitialization - ? InitializationKind::CreateDirectList(TyBeginLoc) - : InitializationKind::CreateDirect(TyBeginLoc, - LParenLoc, RParenLoc) - : InitializationKind::CreateValue(TyBeginLoc, - LParenLoc, RParenLoc); - InitializationSequence InitSeq(*this, Entity, Kind, Exprs, NumExprs); - ExprResult Result = InitSeq.Perform(*this, Entity, Kind, exprs); + InitializationKind Kind = + Exprs.size() ? ListInitialization + ? InitializationKind::CreateDirectList(TyBeginLoc) + : InitializationKind::CreateDirect(TyBeginLoc, LParenLoc, RParenLoc) + : InitializationKind::CreateValue(TyBeginLoc, LParenLoc, RParenLoc); + InitializationSequence InitSeq(*this, Entity, Kind, Exprs); + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Exprs); if (!Result.isInvalid() && ListInitialization && isa<InitListExpr>(Result.get())) { @@ -983,7 +987,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, Declarator &D, Expr *Initializer) { - bool TypeContainsAuto = D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; + bool TypeContainsAuto = D.getDeclSpec().containsPlaceholderType(); Expr *ArraySize = 0; // If the specified type is an array, unwrap it and save the expression. @@ -1110,9 +1114,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, HaveCompleteInit = true; // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. - AutoType *AT = 0; - if (TypeMayContainAuto && - (AT = AllocType->getContainedAutoType()) && !AT->isDeduced()) { + if (TypeMayContainAuto && AllocType->isUndeducedType()) { if (initStyle == CXXNewExpr::NoInit || NumInits == 0) return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg) << AllocType << TypeRange); @@ -1127,16 +1129,14 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, << AllocType << TypeRange); } Expr *Deduce = Inits[0]; - TypeSourceInfo *DeducedType = 0; + QualType DeducedType; if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed) return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure) << AllocType << Deduce->getType() << TypeRange << Deduce->getSourceRange()); - if (!DeducedType) + if (DeducedType.isNull()) return ExprError(); - - AllocTypeInfo = DeducedType; - AllocType = AllocTypeInfo->getType(); + AllocType = DeducedType; } // Per C++0x [expr.new]p5, the type being constructed may be a @@ -1170,6 +1170,11 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, QualType ResultType = Context.getPointerType(AllocType); + if (ArraySize && ArraySize->getType()->isNonOverloadPlaceholderType()) { + ExprResult result = CheckPlaceholderExpr(ArraySize); + if (result.isInvalid()) return ExprError(); + ArraySize = result.take(); + } // C++98 5.3.4p6: "The expression in a direct-new-declarator shall have // integral or enumeration type with a non-negative value." // C++11 [expr.new]p6: The expression [...] shall be of integral or unscoped @@ -1405,7 +1410,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, InitializedEntity Entity = InitializedEntity::InitializeNew(StartLoc, InitType); - InitializationSequence InitSeq(*this, Entity, Kind, Inits, NumInits); + InitializationSequence InitSeq(*this, Entity, Kind, MultiExprArg(Inits, NumInits)); ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind, MultiExprArg(Inits, NumInits)); if (FullInit.isInvalid()) @@ -1422,11 +1427,13 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // Mark the new and delete operators as referenced. if (OperatorNew) { - DiagnoseUseOfDecl(OperatorNew, StartLoc); + if (DiagnoseUseOfDecl(OperatorNew, StartLoc)) + return ExprError(); MarkFunctionReferenced(StartLoc, OperatorNew); } if (OperatorDelete) { - DiagnoseUseOfDecl(OperatorDelete, StartLoc); + if (DiagnoseUseOfDecl(OperatorDelete, StartLoc)) + return ExprError(); MarkFunctionReferenced(StartLoc, OperatorDelete); } @@ -1442,7 +1449,8 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, CheckDestructorAccess(StartLoc, dtor, PDiag(diag::err_access_dtor) << BaseAllocType); - DiagnoseUseOfDecl(dtor, StartLoc); + if (DiagnoseUseOfDecl(dtor, StartLoc)) + return ExprError(); } } } @@ -2200,7 +2208,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) { MarkFunctionReferenced(StartLoc, const_cast<CXXDestructorDecl*>(Dtor)); - DiagnoseUseOfDecl(Dtor, StartLoc); + if (DiagnoseUseOfDecl(Dtor, StartLoc)) + return ExprError(); } // C++ [expr.delete]p3: @@ -2266,6 +2275,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar, SourceLocation StmtLoc, bool ConvertToBoolean) { + if (ConditionVar->isInvalidDecl()) + return ExprError(); + QualType T = ConditionVar->getType(); // C++ [stmt.select]p2: @@ -3119,7 +3131,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, case UTT_IsPOD: return T.isPODType(Self.Context); case UTT_IsLiteral: - return T->isLiteralType(); + return T->isLiteralType(Self.Context); case UTT_IsEmpty: if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return !RD->isUnion() && RD->isEmpty(); @@ -3486,8 +3498,7 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, InitializedEntity To(InitializedEntity::InitializeTemporary(Args[0])); InitializationKind InitKind(InitializationKind::CreateDirect(KWLoc, KWLoc, RParenLoc)); - InitializationSequence Init(S, To, InitKind, - ArgExprs.begin(), ArgExprs.size()); + InitializationSequence Init(S, To, InitKind, ArgExprs); if (Init.Failed()) return false; @@ -3645,7 +3656,7 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT, EnterExpressionEvaluationContext Unevaluated(Self, Sema::Unevaluated); Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); - InitializationSequence Init(Self, To, Kind, &FromPtr, 1); + InitializationSequence Init(Self, To, Kind, FromPtr); if (Init.Failed()) return false; @@ -4045,7 +4056,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, QualType T = Self.Context.getLValueReferenceType(ToType); InitializedEntity Entity = InitializedEntity::InitializeTemporary(T); - InitializationSequence InitSeq(Self, Entity, Kind, &From, 1); + InitializationSequence InitSeq(Self, Entity, Kind, From); if (InitSeq.isDirectReferenceBinding()) { ToType = T; HaveConversion = true; @@ -4053,7 +4064,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, } if (InitSeq.isAmbiguous()) - return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); + return InitSeq.Diagnose(Self, Entity, Kind, From); } // -- If E2 is an rvalue, or if the conversion above cannot be done: @@ -4073,14 +4084,14 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, if (FRec == TRec || FDerivedFromT) { if (TTy.isAtLeastAsQualifiedAs(FTy)) { InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); - InitializationSequence InitSeq(Self, Entity, Kind, &From, 1); + InitializationSequence InitSeq(Self, Entity, Kind, From); if (InitSeq) { HaveConversion = true; return false; } if (InitSeq.isAmbiguous()) - return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); + return InitSeq.Diagnose(Self, Entity, Kind, From); } } @@ -4098,11 +4109,11 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, TTy = TTy.getUnqualifiedType(); InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); - InitializationSequence InitSeq(Self, Entity, Kind, &From, 1); + InitializationSequence InitSeq(Self, Entity, Kind, From); HaveConversion = !InitSeq.Failed(); ToType = TTy; if (InitSeq.isAmbiguous()) - return InitSeq.Diagnose(Self, Entity, Kind, &From, 1); + return InitSeq.Diagnose(Self, Entity, Kind, From); return false; } @@ -4116,7 +4127,7 @@ static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS SourceLocation QuestionLoc) { Expr *Args[2] = { LHS.get(), RHS.get() }; OverloadCandidateSet CandidateSet(QuestionLoc); - Self.AddBuiltinOperatorCandidates(OO_Conditional, QuestionLoc, Args, 2, + Self.AddBuiltinOperatorCandidates(OO_Conditional, QuestionLoc, Args, CandidateSet); OverloadCandidateSet::iterator Best; @@ -4175,7 +4186,7 @@ static bool ConvertForConditional(Sema &Self, ExprResult &E, QualType T) { InitializationKind Kind = InitializationKind::CreateCopy(E.get()->getLocStart(), SourceLocation()); Expr *Arg = E.take(); - InitializationSequence InitSeq(Self, Entity, Kind, &Arg, 1); + InitializationSequence InitSeq(Self, Entity, Kind, Arg); ExprResult Result = InitSeq.Perform(Self, Entity, Kind, Arg); if (Result.isInvalid()) return true; @@ -4624,8 +4635,8 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, = InitializedEntity::InitializeTemporary(Composite1); InitializationKind Kind = InitializationKind::CreateCopy(Loc, SourceLocation()); - InitializationSequence E1ToC1(*this, Entity1, Kind, &E1, 1); - InitializationSequence E2ToC1(*this, Entity1, Kind, &E2, 1); + InitializationSequence E1ToC1(*this, Entity1, Kind, E1); + InitializationSequence E2ToC1(*this, Entity1, Kind, E2); if (E1ToC1 && E2ToC1) { // Conversion to Composite1 is viable. @@ -4634,8 +4645,8 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // Composite2 is also viable. InitializedEntity Entity2 = InitializedEntity::InitializeTemporary(Composite2); - InitializationSequence E1ToC2(*this, Entity2, Kind, &E1, 1); - InitializationSequence E2ToC2(*this, Entity2, Kind, &E2, 1); + InitializationSequence E1ToC2(*this, Entity2, Kind, E1); + InitializationSequence E2ToC2(*this, Entity2, Kind, E2); if (E1ToC2 && E2ToC2) { // Both Composite1 and Composite2 are viable and are different; // this is an ambiguity. @@ -4663,8 +4674,8 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // Check whether Composite2 is viable. InitializedEntity Entity2 = InitializedEntity::InitializeTemporary(Composite2); - InitializationSequence E1ToC2(*this, Entity2, Kind, &E1, 1); - InitializationSequence E2ToC2(*this, Entity2, Kind, &E2, 1); + InitializationSequence E1ToC2(*this, Entity2, Kind, E1); + InitializationSequence E2ToC2(*this, Entity2, Kind, E2); if (!E1ToC2 || !E2ToC2) return QualType(); @@ -4813,7 +4824,8 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { CheckDestructorAccess(E->getExprLoc(), Destructor, PDiag(diag::err_access_dtor_temp) << E->getType()); - DiagnoseUseOfDecl(Destructor, E->getExprLoc()); + if (DiagnoseUseOfDecl(Destructor, E->getExprLoc())) + return ExprError(); // If destructor is trivial, we can avoid the extra copy. if (Destructor->isTrivial()) @@ -4968,7 +4980,8 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) { CheckDestructorAccess(Bind->getExprLoc(), Destructor, PDiag(diag::err_access_dtor_temp) << Bind->getType()); - DiagnoseUseOfDecl(Destructor, Bind->getExprLoc()); + if (DiagnoseUseOfDecl(Destructor, Bind->getExprLoc())) + return ExprError(); // We need a cleanup, but we don't need to remember the temporary. ExprNeedsCleanups = true; @@ -5086,7 +5099,7 @@ ExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc, return ActOnCallExpr(/*Scope*/ 0, MemExpr, /*LPLoc*/ ExpectedLParenLoc, - MultiExprArg(), + None, /*RPLoc*/ ExpectedLParenLoc); } @@ -5434,7 +5447,7 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, ResultType = ResultType.getNonLValueExprType(Context); CXXMemberCallExpr *CE = - new (Context) CXXMemberCallExpr(Context, ME, MultiExprArg(), ResultType, VK, + new (Context) CXXMemberCallExpr(Context, ME, None, ResultType, VK, Exp.get()->getLocEnd()); return CE; } diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index 847db24..545ac27 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -60,6 +60,9 @@ enum IMAKind { /// The reference may be to an unresolved using declaration. IMA_Unresolved, + /// The reference is a contextually-permitted abstract member reference. + IMA_Abstract, + /// The reference may be to an unresolved using declaration and the /// context is not an instance method. IMA_Unresolved_StaticContext, @@ -105,7 +108,8 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, NamedDecl *D = *I; if (D->isCXXInstanceMember()) { - if (dyn_cast<FieldDecl>(D) || dyn_cast<IndirectFieldDecl>(D)) + if (dyn_cast<FieldDecl>(D) || dyn_cast<MSPropertyDecl>(D) + || dyn_cast<IndirectFieldDecl>(D)) isField = true; CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext()); @@ -119,19 +123,32 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, // member reference. if (Classes.empty()) return IMA_Static; - - bool IsCXX11UnevaluatedField = false; - if (SemaRef.getLangOpts().CPlusPlus11 && isField) { - // C++11 [expr.prim.general]p12: - // An id-expression that denotes a non-static data member or non-static - // member function of a class can only be used: - // (...) - // - if that id-expression denotes a non-static data member and it - // appears in an unevaluated operand. - const Sema::ExpressionEvaluationContextRecord& record - = SemaRef.ExprEvalContexts.back(); - if (record.Context == Sema::Unevaluated) - IsCXX11UnevaluatedField = true; + + // C++11 [expr.prim.general]p12: + // An id-expression that denotes a non-static data member or non-static + // member function of a class can only be used: + // (...) + // - if that id-expression denotes a non-static data member and it + // appears in an unevaluated operand. + // + // This rule is specific to C++11. However, we also permit this form + // in unevaluated inline assembly operands, like the operand to a SIZE. + IMAKind AbstractInstanceResult = IMA_Static; // happens to be 'false' + assert(!AbstractInstanceResult); + switch (SemaRef.ExprEvalContexts.back().Context) { + case Sema::Unevaluated: + if (isField && SemaRef.getLangOpts().CPlusPlus11) + AbstractInstanceResult = IMA_Field_Uneval_Context; + break; + + case Sema::UnevaluatedAbstract: + AbstractInstanceResult = IMA_Abstract; + break; + + case Sema::ConstantEvaluated: + case Sema::PotentiallyEvaluated: + case Sema::PotentiallyEvaluatedIfUsed: + break; } // If the current context is not an instance method, it can't be @@ -140,8 +157,8 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, if (hasNonInstance) return IMA_Mixed_StaticContext; - return IsCXX11UnevaluatedField ? IMA_Field_Uneval_Context - : IMA_Error_StaticContext; + return AbstractInstanceResult ? AbstractInstanceResult + : IMA_Error_StaticContext; } CXXRecordDecl *contextClass; @@ -171,8 +188,8 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, // which case it's an error if any of those members are selected). if (isProvablyNotDerivedFrom(SemaRef, contextClass, Classes)) return hasNonInstance ? IMA_Mixed_Unrelated : - IsCXX11UnevaluatedField ? IMA_Field_Uneval_Context : - IMA_Error_Unrelated; + AbstractInstanceResult ? AbstractInstanceResult : + IMA_Error_Unrelated; return (hasNonInstance ? IMA_Mixed : IMA_Instance); } @@ -232,6 +249,7 @@ Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, << R.getLookupNameInfo().getName(); // Fall through. case IMA_Static: + case IMA_Abstract: case IMA_Mixed_StaticContext: case IMA_Unresolved_StaticContext: if (TemplateArgs || TemplateKWLoc.isValid()) @@ -778,6 +796,19 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, return Owned(result); } +static ExprResult +BuildMSPropertyRefExpr(Sema &S, Expr *BaseExpr, bool IsArrow, + const CXXScopeSpec &SS, + MSPropertyDecl *PD, + const DeclarationNameInfo &NameInfo) { + // Property names are always simple identifiers and therefore never + // require any interesting additional storage. + return new (S.Context) MSPropertyRefExpr(BaseExpr, PD, IsArrow, + S.Context.PseudoObjectTy, VK_LValue, + SS.getWithLocInContext(S.Context), + NameInfo.getLoc()); +} + /// \brief Build a MemberExpr AST node. static MemberExpr *BuildMemberExpr(Sema &SemaRef, ASTContext &C, Expr *Base, bool isArrow, @@ -935,6 +966,10 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow, SS, FD, FoundDecl, MemberNameInfo); + if (MSPropertyDecl *PD = dyn_cast<MSPropertyDecl>(MemberDecl)) + return BuildMSPropertyRefExpr(*this, BaseExpr, IsArrow, SS, PD, + MemberNameInfo); + if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl)) // We may have found a field within an anonymous union or struct // (C++ [class.union]). diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index e7b5ec9..cf77896 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -239,7 +239,7 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc, &CX.Idents.get("value"), NumberType, /*TInfo=*/0, SC_None, 0); - Method->setMethodParams(S.Context, value, ArrayRef<SourceLocation>()); + Method->setMethodParams(S.Context, value, None); } if (!validateBoxingMethod(S, Loc, S.NSNumberDecl, Sel, Method)) @@ -343,7 +343,7 @@ static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element, InitializationKind Kind = InitializationKind::CreateCopy(Element->getLocStart(), SourceLocation()); - InitializationSequence Seq(S, Entity, Kind, &Element, 1); + InitializationSequence Seq(S, Entity, Kind, Element); if (!Seq.Failed()) return Seq.Perform(S, Entity, Kind, Element); } @@ -490,7 +490,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { Context.getPointerType(ConstCharType), /*TInfo=*/0, SC_None, 0); - M->setMethodParams(Context, value, ArrayRef<SourceLocation>()); + M->setMethodParams(Context, value, None); BoxingMethod = M; } @@ -665,7 +665,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) { Context.UnsignedLongTy, /*TInfo=*/0, SC_None, 0); Params.push_back(cnt); - Method->setMethodParams(Context, Params, ArrayRef<SourceLocation>()); + Method->setMethodParams(Context, Params, None); } if (!validateBoxingMethod(*this, SR.getBegin(), NSArrayDecl, Sel, Method)) @@ -788,7 +788,7 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, Context.UnsignedLongTy, /*TInfo=*/0, SC_None, 0); Params.push_back(cnt); - Method->setMethodParams(Context, Params, ArrayRef<SourceLocation>()); + Method->setMethodParams(Context, Params, None); } if (!validateBoxingMethod(*this, SR.getBegin(), NSDictionaryDecl, Sel, @@ -1191,6 +1191,12 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, bool isClassMessage, bool isSuperMessage, SourceLocation lbrac, SourceLocation rbrac, QualType &ReturnType, ExprValueKind &VK) { + SourceLocation SelLoc; + if (!SelectorLocs.empty() && SelectorLocs.front().isValid()) + SelLoc = SelectorLocs.front(); + else + SelLoc = lbrac; + if (!Method) { // Apply default argument promotion as for (C99 6.5.2.2p6). for (unsigned i = 0; i != NumArgs; i++) { @@ -1200,7 +1206,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, ExprResult result; if (getLangOpts().DebuggerSupport) { QualType paramTy; // ignored - result = checkUnknownAnyArg(lbrac, Args[i], paramTy); + result = checkUnknownAnyArg(SelLoc, Args[i], paramTy); } else { result = DefaultArgumentPromotion(Args[i]); } @@ -1216,7 +1222,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, DiagID = isClassMessage ? diag::warn_class_method_not_found : diag::warn_inst_method_not_found; if (!getLangOpts().DebuggerSupport) - Diag(lbrac, DiagID) + Diag(SelLoc, DiagID) << Sel << isClassMessage << SourceRange(SelectorLocs.front(), SelectorLocs.back()); @@ -1242,7 +1248,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, NumNamedArgs = Method->param_size(); // FIXME. This need be cleaned up. if (NumArgs < NumNamedArgs) { - Diag(lbrac, diag::err_typecheck_call_too_few_args) + Diag(SelLoc, diag::err_typecheck_call_too_few_args) << 2 << NumNamedArgs << NumArgs; return false; } @@ -1268,7 +1274,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, // from the argument. if (param->getType() == Context.UnknownAnyTy) { QualType paramType; - ExprResult argE = checkUnknownAnyArg(lbrac, argExpr, paramType); + ExprResult argE = checkUnknownAnyArg(SelLoc, argExpr, paramType); if (argE.isInvalid()) { IsError = true; } else { @@ -1287,7 +1293,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, param); - ExprResult ArgE = PerformCopyInitialization(Entity, lbrac, Owned(argExpr)); + ExprResult ArgE = PerformCopyInitialization(Entity, SelLoc, Owned(argExpr)); if (ArgE.isInvalid()) IsError = true; else @@ -1317,10 +1323,11 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, } } - DiagnoseSentinelCalls(Method, lbrac, Args, NumArgs); + DiagnoseSentinelCalls(Method, SelLoc, Args, NumArgs); // Do additional checkings on method. - IsError |= CheckObjCMethodCall(Method, lbrac, Args, NumArgs); + IsError |= CheckObjCMethodCall(Method, SelLoc, + llvm::makeArrayRef<const Expr *>(Args, NumArgs)); return IsError; } @@ -1328,7 +1335,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, bool Sema::isSelfExpr(Expr *receiver) { // 'self' is objc 'self' in an objc method only. ObjCMethodDecl *method = - dyn_cast<ObjCMethodDecl>(CurContext->getNonClosureAncestor()); + dyn_cast_or_null<ObjCMethodDecl>(CurContext->getNonClosureAncestor()); if (!method) return false; receiver = receiver->IgnoreParenLValueCasts(); @@ -1993,7 +2000,12 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, << FixItHint::CreateInsertion(Loc, "["); LBracLoc = Loc; } - + SourceLocation SelLoc; + if (!SelectorLocs.empty() && SelectorLocs.front().isValid()) + SelLoc = SelectorLocs.front(); + else + SelLoc = Loc; + if (ReceiverType->isDependentType()) { // If the receiver type is dependent, we can't type-check anything // at this point. Build a dependent expression. @@ -2018,7 +2030,7 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, assert(Class && "We don't know which class we're messaging?"); // objc++ diagnoses during typename annotation. if (!getLangOpts().CPlusPlus) - (void)DiagnoseUseOfDecl(Class, Loc); + (void)DiagnoseUseOfDecl(Class, SelLoc); // Find the method we are messaging. if (!Method) { SourceRange TypeRange @@ -2043,7 +2055,7 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, if (!Method) Method = Class->lookupPrivateClassMethod(Sel); - if (Method && DiagnoseUseOfDecl(Method, Loc)) + if (Method && DiagnoseUseOfDecl(Method, SelLoc)) return ExprError(); } @@ -2159,7 +2171,14 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, bool isImplicit) { // The location of the receiver. SourceLocation Loc = SuperLoc.isValid()? SuperLoc : Receiver->getLocStart(); - + SourceRange RecRange = + SuperLoc.isValid()? SuperLoc : Receiver->getSourceRange(); + SourceLocation SelLoc; + if (!SelectorLocs.empty() && SelectorLocs.front().isValid()) + SelLoc = SelectorLocs.front(); + else + SelLoc = Loc; + if (LBracLoc.isInvalid()) { Diag(Loc, diag::err_missing_open_square_message_send) << FixItHint::CreateInsertion(Loc, "["); @@ -2264,7 +2283,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, Method = LookupMethodInQualifiedType(Sel, QClassTy, true); // warn if instance method found for a Class message. if (Method) { - Diag(Loc, diag::warn_instance_method_on_class_found) + Diag(SelLoc, diag::warn_instance_method_on_class_found) << Method->getSelector() << Sel; Diag(Method->getLocation(), diag::note_method_declared_at) << Method->getDeclName(); @@ -2279,7 +2298,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (!Method) Method = ClassDecl->lookupPrivateClassMethod(Sel); } - if (Method && DiagnoseUseOfDecl(Method, Loc)) + if (Method && DiagnoseUseOfDecl(Method, SelLoc)) return ExprError(); } if (!Method) { @@ -2298,7 +2317,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) { if (ID->getSuperClass()) - Diag(Loc, diag::warn_root_inst_method_not_found) + Diag(SelLoc, diag::warn_root_inst_method_not_found) << Sel << SourceRange(LBracLoc, RBracLoc); } } @@ -2317,7 +2336,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, Method = LookupMethodInQualifiedType(Sel, QIdTy, true); if (!Method) Method = LookupMethodInQualifiedType(Sel, QIdTy, false); - if (Method && DiagnoseUseOfDecl(Method, Loc)) + if (Method && DiagnoseUseOfDecl(Method, SelLoc)) return ExprError(); } else if (const ObjCObjectPointerType *OCIType = ReceiverType->getAsObjCInterfacePointerType()) { @@ -2353,8 +2372,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, Method = ClassDecl->lookupPrivateMethod(Sel); if (!Method && getLangOpts().ObjCAutoRefCount) { - Diag(Loc, diag::err_arc_may_not_respond) - << OCIType->getPointeeType() << Sel + Diag(SelLoc, diag::err_arc_may_not_respond) + << OCIType->getPointeeType() << Sel << RecRange << SourceRange(SelectorLocs.front(), SelectorLocs.back()); return ExprError(); } @@ -2367,12 +2386,13 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, Method = LookupInstanceMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc)); if (Method && !forwardClass) - Diag(Loc, diag::warn_maynot_respond) - << OCIType->getInterfaceDecl()->getIdentifier() << Sel; + Diag(SelLoc, diag::warn_maynot_respond) + << OCIType->getInterfaceDecl()->getIdentifier() + << Sel << RecRange; } } } - if (Method && DiagnoseUseOfDecl(Method, Loc, forwardClass)) + if (Method && DiagnoseUseOfDecl(Method, SelLoc, forwardClass)) return ExprError(); } else { // Reject other random receiver types (e.g. structs). @@ -2401,8 +2421,6 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, diag::err_illegal_message_expr_incomplete_type)) return ExprError(); - SourceLocation SelLoc = SelectorLocs.front(); - // In ARC, forbid the user from sending messages to // retain/release/autorelease/dealloc/retainCount explicitly. if (getLangOpts().ObjCAutoRefCount) { @@ -2427,8 +2445,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, case OMF_release: case OMF_autorelease: case OMF_retainCount: - Diag(Loc, diag::err_arc_illegal_explicit_message) - << Sel << SelLoc; + Diag(SelLoc, diag::err_arc_illegal_explicit_message) + << Sel << RecRange; break; case OMF_performSelector: diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 63309e3..9e8936e 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -82,6 +82,24 @@ static Expr *IsStringInit(Expr *init, QualType declType, ASTContext &Context) { return IsStringInit(init, arrayType, Context); } +/// Update the type of a string literal, including any surrounding parentheses, +/// to match the type of the object which it is initializing. +static void updateStringLiteralType(Expr *E, QualType Ty) { + while (true) { + E->setType(Ty); + if (isa<StringLiteral>(E) || isa<ObjCEncodeExpr>(E)) + break; + else if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) + E = PE->getSubExpr(); + else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) + E = UO->getSubExpr(); + else if (GenericSelectionExpr *GSE = dyn_cast<GenericSelectionExpr>(E)) + E = GSE->getResultExpr(); + else + llvm_unreachable("unexpected expr in string literal init"); + } +} + static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT, Sema &S) { // Get the length of the string as parsed. @@ -97,6 +115,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT, DeclT = S.Context.getConstantArrayType(IAT->getElementType(), ConstVal, ArrayType::Normal, 0); + updateStringLiteralType(Str, DeclT); return; } @@ -106,7 +125,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT, // the size may be smaller or larger than the string we are initializing. // FIXME: Avoid truncation for 64-bit length strings. if (S.getLangOpts().CPlusPlus) { - if (StringLiteral *SL = dyn_cast<StringLiteral>(Str)) { + if (StringLiteral *SL = dyn_cast<StringLiteral>(Str->IgnoreParens())) { // For Pascal strings it's OK to strip off the terminating null character, // so the example below is valid: // @@ -132,7 +151,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT, // something like: // char x[1] = "foo"; // then this will set the string literal's type to char[1]. - Str->setType(DeclT); + updateStringLiteralType(Str, DeclT); } //===----------------------------------------------------------------------===// @@ -279,7 +298,7 @@ void InitListChecker::CheckValueInitializable(const InitializedEntity &Entity) { SourceLocation Loc; InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc, true); - InitializationSequence InitSeq(SemaRef, Entity, Kind, 0, 0); + InitializationSequence InitSeq(SemaRef, Entity, Kind, None); if (InitSeq.Failed()) hadError = true; } @@ -293,6 +312,21 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, InitializedEntity MemberEntity = InitializedEntity::InitializeMember(Field, &ParentEntity); if (Init >= NumInits || !ILE->getInit(Init)) { + // If there's no explicit initializer but we have a default initializer, use + // that. This only happens in C++1y, since classes with default + // initializers are not aggregates in C++11. + if (Field->hasInClassInitializer()) { + Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context, + ILE->getRBraceLoc(), Field); + if (Init < NumInits) + ILE->setInit(Init, DIE); + else { + ILE->updateInit(SemaRef.Context, Init, DIE); + RequiresSecondPass = true; + } + return; + } + // FIXME: We probably don't need to handle references // specially here, since value-initialization of references is // handled in InitializationSequence. @@ -312,15 +346,15 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc, true); - InitializationSequence InitSeq(SemaRef, MemberEntity, Kind, 0, 0); + InitializationSequence InitSeq(SemaRef, MemberEntity, Kind, None); if (!InitSeq) { - InitSeq.Diagnose(SemaRef, MemberEntity, Kind, 0, 0); + InitSeq.Diagnose(SemaRef, MemberEntity, Kind, None); hadError = true; return; } ExprResult MemberInit - = InitSeq.Perform(SemaRef, MemberEntity, Kind, MultiExprArg()); + = InitSeq.Perform(SemaRef, MemberEntity, Kind, None); if (MemberInit.isInvalid()) { hadError = true; return; @@ -358,15 +392,24 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, Loc = ILE->getSyntacticForm()->getLocStart(); if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) { - if (RType->getDecl()->isUnion() && - ILE->getInitializedFieldInUnion()) + const RecordDecl *RDecl = RType->getDecl(); + if (RDecl->isUnion() && ILE->getInitializedFieldInUnion()) FillInValueInitForField(0, ILE->getInitializedFieldInUnion(), Entity, ILE, RequiresSecondPass); - else { + else if (RDecl->isUnion() && isa<CXXRecordDecl>(RDecl) && + cast<CXXRecordDecl>(RDecl)->hasInClassInitializer()) { + for (RecordDecl::field_iterator Field = RDecl->field_begin(), + FieldEnd = RDecl->field_end(); + Field != FieldEnd; ++Field) { + if (Field->hasInClassInitializer()) { + FillInValueInitForField(0, *Field, Entity, ILE, RequiresSecondPass); + break; + } + } + } else { unsigned Init = 0; - for (RecordDecl::field_iterator - Field = RType->getDecl()->field_begin(), - FieldEnd = RType->getDecl()->field_end(); + for (RecordDecl::field_iterator Field = RDecl->field_begin(), + FieldEnd = RDecl->field_end(); Field != FieldEnd; ++Field) { if (Field->isUnnamedBitfield()) continue; @@ -381,7 +424,7 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, ++Init; // Only look at the first initialization of a union. - if (RType->getDecl()->isUnion()) + if (RDecl->isUnion()) break; } } @@ -421,15 +464,15 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, if (!InitExpr && !ILE->hasArrayFiller()) { InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc, true); - InitializationSequence InitSeq(SemaRef, ElementEntity, Kind, 0, 0); + InitializationSequence InitSeq(SemaRef, ElementEntity, Kind, None); if (!InitSeq) { - InitSeq.Diagnose(SemaRef, ElementEntity, Kind, 0, 0); + InitSeq.Diagnose(SemaRef, ElementEntity, Kind, None); hadError = true; return; } ExprResult ElementInit - = InitSeq.Perform(SemaRef, ElementEntity, Kind, MultiExprArg()); + = InitSeq.Perform(SemaRef, ElementEntity, Kind, None); if (ElementInit.isInvalid()) { hadError = true; return; @@ -784,12 +827,12 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // FIXME: Better EqualLoc? InitializationKind Kind = InitializationKind::CreateCopy(expr->getLocStart(), SourceLocation()); - InitializationSequence Seq(SemaRef, Entity, Kind, &expr, 1); + InitializationSequence Seq(SemaRef, Entity, Kind, expr); if (Seq) { if (!VerifyOnly) { ExprResult Result = - Seq.Perform(SemaRef, Entity, Kind, MultiExprArg(&expr, 1)); + Seq.Perform(SemaRef, Entity, Kind, expr); if (Result.isInvalid()) hadError = true; @@ -819,8 +862,8 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, hadError = true; else { ExprRes = SemaRef.DefaultFunctionArrayLvalueConversion(ExprRes.take()); - if (ExprRes.isInvalid()) - hadError = true; + if (ExprRes.isInvalid()) + hadError = true; } UpdateStructuredListElement(StructuredList, StructuredIndex, ExprRes.takeAs<Expr>()); @@ -1323,8 +1366,23 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, } if (DeclType->isUnionType() && IList->getNumInits() == 0) { - // Value-initialize the first named member of the union. RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl(); + + // If there's a default initializer, use it. + if (isa<CXXRecordDecl>(RD) && cast<CXXRecordDecl>(RD)->hasInClassInitializer()) { + if (VerifyOnly) + return; + for (RecordDecl::field_iterator FieldEnd = RD->field_end(); + Field != FieldEnd; ++Field) { + if (Field->hasInClassInitializer()) { + StructuredList->setInitializedFieldInUnion(*Field); + // FIXME: Actually build a CXXDefaultInitExpr? + return; + } + } + } + + // Value-initialize the first named member of the union. for (RecordDecl::field_iterator FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) { if (Field->getDeclName()) { @@ -1428,7 +1486,7 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, // 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()) { + if (!it->isUnnamedBitfield() && !it->hasInClassInitializer()) { SemaRef.Diag(IList->getSourceRange().getEnd(), diag::warn_missing_field_initializers) << it->getName(); break; @@ -1441,7 +1499,7 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, !Field->getType()->isIncompleteArrayType()) { // FIXME: Should check for holes left by designated initializers too. for (; Field != FieldEnd && !hadError; ++Field) { - if (!Field->isUnnamedBitfield()) + if (!Field->isUnnamedBitfield() && !Field->hasInClassInitializer()) CheckValueInitializable( InitializedEntity::InitializeMember(*Field, &Entity)); } @@ -2073,7 +2131,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, InitListExpr *Result = new (SemaRef.Context) InitListExpr(SemaRef.Context, - InitRange.getBegin(), MultiExprArg(), + InitRange.getBegin(), None, InitRange.getEnd()); QualType ResultType = CurrentObjectType; @@ -2336,6 +2394,7 @@ DeclarationName InitializedEntity::getName() const { case EK_VectorElement: case EK_ComplexElement: case EK_BlockElement: + case EK_CompoundLiteralInit: return DeclarationName(); } @@ -2362,6 +2421,7 @@ DeclaratorDecl *InitializedEntity::getDecl() const { case EK_ComplexElement: case EK_BlockElement: case EK_LambdaCapture: + case EK_CompoundLiteralInit: return 0; } @@ -2379,6 +2439,7 @@ bool InitializedEntity::allowsNRVO() const { case EK_Member: case EK_New: case EK_Temporary: + case EK_CompoundLiteralInit: case EK_Base: case EK_Delegating: case EK_ArrayElement: @@ -2409,6 +2470,7 @@ void InitializationSequence::Step::Destroy() { case SK_QualificationConversionRValue: case SK_QualificationConversionXValue: case SK_QualificationConversionLValue: + case SK_LValueToRValue: case SK_ListInitialization: case SK_ListConstructorCall: case SK_UnwrapInitList: @@ -2555,6 +2617,15 @@ void InitializationSequence::AddQualificationConversionStep(QualType Ty, Steps.push_back(S); } +void InitializationSequence::AddLValueToRValueStep(QualType Ty) { + assert(!Ty.hasQualifiers() && "rvalues may not have qualifiers"); + + Step S; + S.Kind = SK_LValueToRValue; + S.Type = Ty; + Steps.push_back(S); +} + void InitializationSequence::AddConversionSequenceStep( const ImplicitConversionSequence &ICS, QualType T) { @@ -2758,7 +2829,7 @@ static bool TryInitializerListConstruction(Sema &S, static OverloadingResult ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, - Expr **Args, unsigned NumArgs, + MultiExprArg Args, OverloadCandidateSet &CandidateSet, ArrayRef<NamedDecl *> Ctors, OverloadCandidateSet::iterator &Best, @@ -2784,7 +2855,7 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, // If we're performing copy initialization using a copy constructor, we // suppress user-defined conversions on the arguments. We do the same for // move constructors. - if ((CopyInitializing || (InitListSyntax && NumArgs == 1)) && + if ((CopyInitializing || (InitListSyntax && Args.size() == 1)) && Constructor->isCopyOrMoveConstructor()) SuppressUserConversions = true; } @@ -2794,8 +2865,7 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, (!OnlyListConstructors || S.isInitListConstructor(Constructor))) { if (ConstructorTmpl) S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, - /*ExplicitArgs*/ 0, - llvm::makeArrayRef(Args, NumArgs), + /*ExplicitArgs*/ 0, Args, CandidateSet, SuppressUserConversions); else { // C++ [over.match.copy]p1: @@ -2805,10 +2875,9 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, // context of direct-initialization, explicit conversion functions // are also considered. bool AllowExplicitConv = AllowExplicit && !CopyInitializing && - NumArgs == 1 && + Args.size() == 1 && Constructor->isCopyOrMoveConstructor(); - S.AddOverloadCandidate(Constructor, FoundDecl, - llvm::makeArrayRef(Args, NumArgs), CandidateSet, + S.AddOverloadCandidate(Constructor, FoundDecl, Args, CandidateSet, SuppressUserConversions, /*PartialOverloading=*/false, /*AllowExplicit=*/AllowExplicitConv); @@ -2828,11 +2897,10 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, static void TryConstructorInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, - Expr **Args, unsigned NumArgs, - QualType DestType, + MultiExprArg Args, QualType DestType, InitializationSequence &Sequence, bool InitListSyntax = false) { - assert((!InitListSyntax || (NumArgs == 1 && isa<InitListExpr>(Args[0]))) && + assert((!InitListSyntax || (Args.size() == 1 && isa<InitListExpr>(Args[0]))) && "InitListSyntax must come with a single initializer list argument."); // The type we're constructing needs to be complete. @@ -2881,15 +2949,14 @@ static void TryConstructorInitialization(Sema &S, // If the initializer list has no elements and T has a default constructor, // the first phase is omitted. if (ILE->getNumInits() != 0 || !DestRecordDecl->hasDefaultConstructor()) - Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, NumArgs, + Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, CandidateSet, Ctors, Best, CopyInitialization, AllowExplicit, /*OnlyListConstructor=*/true, InitListSyntax); // Time to unwrap the init list. - Args = ILE->getInits(); - NumArgs = ILE->getNumInits(); + Args = MultiExprArg(ILE->getInits(), ILE->getNumInits()); } // C++11 [over.match.list]p1: @@ -2899,7 +2966,7 @@ static void TryConstructorInitialization(Sema &S, // elements of the initializer list. if (Result == OR_No_Viable_Function) { AsInitializerList = false; - Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, NumArgs, + Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, CandidateSet, Ctors, Best, CopyInitialization, AllowExplicit, /*OnlyListConstructors=*/false, @@ -3106,8 +3173,8 @@ static void TryListInitialization(Sema &S, return; // - Otherwise, if T is a class type, constructors are considered. - Expr *Arg = InitList; - TryConstructorInitialization(S, Entity, Kind, &Arg, 1, DestType, + Expr *InitListAsExpr = InitList; + TryConstructorInitialization(S, Entity, Kind, InitListAsExpr, DestType, Sequence, /*InitListSyntax*/true); } else Sequence.SetFailed( @@ -3351,6 +3418,57 @@ static void TryReferenceInitialization(Sema &S, T1Quals, cv2T2, T2, T2Quals, Sequence); } +/// Converts the target of reference initialization so that it has the +/// appropriate qualifiers and value kind. +/// +/// In this case, 'x' is an 'int' lvalue, but it needs to be 'const int'. +/// \code +/// int x; +/// const int &r = x; +/// \endcode +/// +/// In this case the reference is binding to a bitfield lvalue, which isn't +/// valid. Perform a load to create a lifetime-extended temporary instead. +/// \code +/// const int &r = someStruct.bitfield; +/// \endcode +static ExprValueKind +convertQualifiersAndValueKindIfNecessary(Sema &S, + InitializationSequence &Sequence, + Expr *Initializer, + QualType cv1T1, + Qualifiers T1Quals, + Qualifiers T2Quals, + bool IsLValueRef) { + bool IsNonAddressableType = Initializer->refersToBitField() || + Initializer->refersToVectorElement(); + + if (IsNonAddressableType) { + // C++11 [dcl.init.ref]p5: [...] Otherwise, the reference shall be an + // lvalue reference to a non-volatile const type, or the reference shall be + // an rvalue reference. + // + // If not, we can't make a temporary and bind to that. Give up and allow the + // error to be diagnosed later. + if (IsLValueRef && (!T1Quals.hasConst() || T1Quals.hasVolatile())) { + assert(Initializer->isGLValue()); + return Initializer->getValueKind(); + } + + // Force a load so we can materialize a temporary. + Sequence.AddLValueToRValueStep(cv1T1.getUnqualifiedType()); + return VK_RValue; + } + + if (T1Quals != T2Quals) { + Sequence.AddQualificationConversionStep(cv1T1, + Initializer->getValueKind()); + } + + return Initializer->getValueKind(); +} + + /// \brief Reference initialization without resolving overloaded functions. static void TryReferenceInitializationCore(Sema &S, const InitializedEntity &Entity, @@ -3406,11 +3524,11 @@ static void TryReferenceInitializationCore(Sema &S, Sequence.AddObjCObjectConversionStep( S.Context.getQualifiedType(T1, T2Quals)); - if (T1Quals != T2Quals) - Sequence.AddQualificationConversionStep(cv1T1, VK_LValue); - bool BindingTemporary = T1Quals.hasConst() && !T1Quals.hasVolatile() && - (Initializer->getBitField() || Initializer->refersToVectorElement()); - Sequence.AddReferenceBindingStep(cv1T1, BindingTemporary); + ExprValueKind ValueKind = + convertQualifiersAndValueKindIfNecessary(S, Sequence, Initializer, + cv1T1, T1Quals, T2Quals, + isLValueRef); + Sequence.AddReferenceBindingStep(cv1T1, ValueKind == VK_RValue); return; } @@ -3493,10 +3611,12 @@ static void TryReferenceInitializationCore(Sema &S, Sequence.AddObjCObjectConversionStep( S.Context.getQualifiedType(T1, T2Quals)); - if (T1Quals != T2Quals) - Sequence.AddQualificationConversionStep(cv1T1, ValueKind); - Sequence.AddReferenceBindingStep(cv1T1, - /*bindingTemporary=*/InitCategory.isPRValue()); + ValueKind = convertQualifiersAndValueKindIfNecessary(S, Sequence, + Initializer, cv1T1, + T1Quals, T2Quals, + isLValueRef); + + Sequence.AddReferenceBindingStep(cv1T1, ValueKind == VK_RValue); return; } @@ -3668,12 +3788,11 @@ static void TryValueInitialization(Sema &S, // building the constructor call. This affects the semantics of a few // things (such as whether an explicit default constructor can be called). Expr *InitListAsExpr = InitList; - Expr **Args = InitList ? &InitListAsExpr : 0; - unsigned NumArgs = InitList ? 1 : 0; + MultiExprArg Args(&InitListAsExpr, InitList ? 1 : 0); bool InitListSyntax = InitList; - return TryConstructorInitialization(S, Entity, Kind, Args, NumArgs, T, - Sequence, InitListSyntax); + return TryConstructorInitialization(S, Entity, Kind, Args, T, Sequence, + InitListSyntax); } } @@ -3696,7 +3815,7 @@ static void TryDefaultInitialization(Sema &S, // constructor for T is called (and the initialization is ill-formed if // T has no accessible default constructor); if (DestType->isRecordType() && S.getLangOpts().CPlusPlus) { - TryConstructorInitialization(S, Entity, Kind, 0, 0, DestType, Sequence); + TryConstructorInitialization(S, Entity, Kind, None, DestType, Sequence); return; } @@ -4068,11 +4187,25 @@ static bool TryOCLZeroEventInitialization(Sema &S, InitializationSequence::InitializationSequence(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, - Expr **Args, - unsigned NumArgs) + MultiExprArg Args) : FailedCandidateSet(Kind.getLocation()) { ASTContext &Context = S.Context; + // Eliminate non-overload placeholder types in the arguments. We + // need to do this before checking whether types are dependent + // because lowering a pseudo-object expression might well give us + // something of dependent type. + for (unsigned I = 0, E = Args.size(); I != E; ++I) + if (Args[I]->getType()->isNonOverloadPlaceholderType()) { + // FIXME: should we be doing this here? + ExprResult result = S.CheckPlaceholderExpr(Args[I]); + if (result.isInvalid()) { + SetFailed(FK_PlaceholderType); + return; + } + Args[I] = result.take(); + } + // C++0x [dcl.init]p16: // The semantics of initializers are as follows. The destination type is // the type of the object or reference being initialized and the source @@ -4082,7 +4215,7 @@ InitializationSequence::InitializationSequence(Sema &S, QualType DestType = Entity.getType(); if (DestType->isDependentType() || - Expr::hasAnyTypeDependentArguments(llvm::makeArrayRef(Args, NumArgs))) { + Expr::hasAnyTypeDependentArguments(Args)) { SequenceKind = DependentSequence; return; } @@ -4090,21 +4223,9 @@ InitializationSequence::InitializationSequence(Sema &S, // Almost everything is a normal sequence. setSequenceKind(NormalSequence); - for (unsigned I = 0; I != NumArgs; ++I) - if (Args[I]->getType()->isNonOverloadPlaceholderType()) { - // FIXME: should we be doing this here? - ExprResult result = S.CheckPlaceholderExpr(Args[I]); - if (result.isInvalid()) { - SetFailed(FK_PlaceholderType); - return; - } - Args[I] = result.take(); - } - - QualType SourceType; Expr *Initializer = 0; - if (NumArgs == 1) { + if (Args.size() == 1) { Initializer = Args[0]; if (!isa<InitListExpr>(Initializer)) SourceType = Initializer->getType(); @@ -4126,7 +4247,7 @@ InitializationSequence::InitializationSequence(Sema &S, // (8.3.2), shall be initialized by an object, or function, of type T or // by an object that can be converted into a T. // (Therefore, multiple arguments are not permitted.) - if (NumArgs != 1) + if (Args.size() != 1) SetFailed(FK_TooManyInitsForReference); else TryReferenceInitialization(S, Entity, Kind, Args[0], *this); @@ -4135,7 +4256,7 @@ InitializationSequence::InitializationSequence(Sema &S, // - If the initializer is (), the object is value-initialized. if (Kind.getKind() == InitializationKind::IK_Value || - (Kind.getKind() == InitializationKind::IK_Direct && NumArgs == 0)) { + (Kind.getKind() == InitializationKind::IK_Direct && Args.empty())) { TryValueInitialization(S, Entity, Kind, *this); return; } @@ -4232,7 +4353,7 @@ InitializationSequence::InitializationSequence(Sema &S, (Kind.getKind() == InitializationKind::IK_Copy && (Context.hasSameUnqualifiedType(SourceType, DestType) || S.IsDerivedFrom(SourceType, DestType)))) - TryConstructorInitialization(S, Entity, Kind, Args, NumArgs, + TryConstructorInitialization(S, Entity, Kind, Args, Entity.getType(), *this); // - Otherwise (i.e., for the remaining copy-initialization cases), // user-defined conversion sequences that can convert from the source @@ -4245,11 +4366,11 @@ InitializationSequence::InitializationSequence(Sema &S, return; } - if (NumArgs > 1) { + if (Args.size() > 1) { SetFailed(FK_TooManyInitsForScalar); return; } - assert(NumArgs == 1 && "Zero-argument case handled above"); + assert(Args.size() == 1 && "Zero-argument case handled above"); // - Otherwise, if the source type is a (possibly cv-qualified) class // type, conversion functions are considered. @@ -4350,6 +4471,7 @@ getAssignmentAction(const InitializedEntity &Entity) { case InitializedEntity::EK_ComplexElement: case InitializedEntity::EK_BlockElement: case InitializedEntity::EK_LambdaCapture: + case InitializedEntity::EK_CompoundLiteralInit: return Sema::AA_Initializing; } @@ -4372,6 +4494,7 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) { case InitializedEntity::EK_Exception: case InitializedEntity::EK_BlockElement: case InitializedEntity::EK_LambdaCapture: + case InitializedEntity::EK_CompoundLiteralInit: return false; case InitializedEntity::EK_Parameter: @@ -4402,6 +4525,7 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) { case InitializedEntity::EK_Temporary: case InitializedEntity::EK_ArrayElement: case InitializedEntity::EK_Exception: + case InitializedEntity::EK_CompoundLiteralInit: return true; } @@ -4483,6 +4607,7 @@ static SourceLocation getInitializationLoc(const InitializedEntity &Entity, case InitializedEntity::EK_VectorElement: case InitializedEntity::EK_ComplexElement: case InitializedEntity::EK_BlockElement: + case InitializedEntity::EK_CompoundLiteralInit: return Initializer->getLocStart(); } llvm_unreachable("missed an InitializedEntity kind?"); @@ -4619,8 +4744,7 @@ static ExprResult CopyObject(Sema &S, // Determine the arguments required to actually perform the // constructor call (we might have derived-to-base conversions, or // the copy constructor may have default arguments). - if (S.CompleteConstructorCall(Constructor, MultiExprArg(&CurInitExpr, 1), - Loc, ConstructorArgs)) + if (S.CompleteConstructorCall(Constructor, CurInitExpr, Loc, ConstructorArgs)) return ExprError(); // Actually perform the constructor call. @@ -4711,6 +4835,31 @@ static bool isReferenceBinding(const InitializationSequence::Step &s) { s.Kind == InitializationSequence::SK_BindReferenceToTemporary; } +/// Returns true if the parameters describe a constructor initialization of +/// an explicit temporary object, e.g. "Point(x, y)". +static bool isExplicitTemporary(const InitializedEntity &Entity, + const InitializationKind &Kind, + unsigned NumArgs) { + switch (Entity.getKind()) { + case InitializedEntity::EK_Temporary: + case InitializedEntity::EK_CompoundLiteralInit: + break; + default: + return false; + } + + switch (Kind.getKind()) { + case InitializationKind::IK_DirectList: + return true; + // FIXME: Hack to work around cast weirdness. + case InitializationKind::IK_Direct: + case InitializationKind::IK_Value: + return NumArgs != 1; + default: + return false; + } +} + static ExprResult PerformConstructorInitialization(Sema &S, const InitializedEntity &Entity, @@ -4761,14 +4910,11 @@ PerformConstructorInitialization(Sema &S, return ExprError(); - if (Entity.getKind() == InitializedEntity::EK_Temporary && - (Kind.getKind() == InitializationKind::IK_DirectList || - (NumArgs != 1 && // FIXME: Hack to work around cast weirdness - (Kind.getKind() == InitializationKind::IK_Direct || - Kind.getKind() == InitializationKind::IK_Value)))) { + if (isExplicitTemporary(Entity, Kind, NumArgs)) { // An explicitly-constructed temporary, e.g., X(1, 2). S.MarkFunctionReferenced(Loc, Constructor); - S.DiagnoseUseOfDecl(Constructor, Loc); + if (S.DiagnoseUseOfDecl(Constructor, Loc)) + return ExprError(); TypeSourceInfo *TSInfo = Entity.getTypeSourceInfo(); if (!TSInfo) @@ -4827,7 +4973,8 @@ PerformConstructorInitialization(Sema &S, // Only check access if all of that succeeded. S.CheckConstructorAccess(Loc, Constructor, Entity, Step.Function.FoundDecl.getAccess()); - S.DiagnoseUseOfDecl(Step.Function.FoundDecl, Loc); + if (S.DiagnoseUseOfDecl(Step.Function.FoundDecl, Loc)) + return ExprError(); if (shouldBindAsTemporary(Entity)) CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); @@ -4865,6 +5012,7 @@ InitializedEntityOutlivesFullExpression(const InitializedEntity &Entity) { case InitializedEntity::EK_Parameter: case InitializedEntity::EK_Temporary: case InitializedEntity::EK_LambdaCapture: + case InitializedEntity::EK_CompoundLiteralInit: // The entity being initialized might not outlive the full-expression. return false; } @@ -4879,8 +5027,7 @@ InitializationSequence::Perform(Sema &S, MultiExprArg Args, QualType *ResultType) { if (Failed()) { - unsigned NumArgs = Args.size(); - Diagnose(S, Entity, Kind, Args.data(), NumArgs); + Diagnose(S, Entity, Kind, Args); return ExprError(); } @@ -4988,6 +5135,7 @@ InitializationSequence::Perform(Sema &S, case SK_QualificationConversionLValue: case SK_QualificationConversionXValue: case SK_QualificationConversionRValue: + case SK_LValueToRValue: case SK_ConversionSequence: case SK_ListInitialization: case SK_UnwrapInitList: @@ -5030,7 +5178,8 @@ InitializationSequence::Perform(Sema &S, // Overload resolution determined which function invoke; update the // initializer to reflect that choice. S.CheckAddressOfMemberAccess(CurInit.get(), Step->Function.FoundDecl); - S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Kind.getLocation()); + if (S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Kind.getLocation())) + return ExprError(); CurInit = S.FixOverloadedFunctionReference(CurInit, Step->Function.FoundDecl, Step->Function.Function); @@ -5076,13 +5225,18 @@ InitializationSequence::Perform(Sema &S, } case SK_BindReference: - if (FieldDecl *BitField = CurInit.get()->getBitField()) { - // References cannot bind to bit fields (C++ [dcl.init.ref]p5). + // References cannot bind to bit-fields (C++ [dcl.init.ref]p5). + if (CurInit.get()->refersToBitField()) { + // We don't necessarily have an unambiguous source bit-field. + FieldDecl *BitField = CurInit.get()->getSourceBitField(); S.Diag(Kind.getLocation(), diag::err_reference_bind_to_bitfield) << Entity.getType().isVolatileQualified() - << BitField->getDeclName() + << (BitField ? BitField->getDeclName() : DeclarationName()) + << (BitField != NULL) << CurInit.get()->getSourceRange(); - S.Diag(BitField->getLocation(), diag::note_bitfield_decl); + if (BitField) + S.Diag(BitField->getLocation(), diag::note_bitfield_decl); + return ExprError(); } @@ -5104,6 +5258,9 @@ InitializationSequence::Perform(Sema &S, break; case SK_BindReferenceToTemporary: + // Make sure the "temporary" is actually an rvalue. + assert(CurInit.get()->isRValue() && "not a temporary"); + // Check exception specifications if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType)) return ExprError(); @@ -5163,7 +5320,8 @@ InitializationSequence::Perform(Sema &S, S.CheckConstructorAccess(Kind.getLocation(), Constructor, Entity, FoundFn.getAccess()); - S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation()); + if (S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation())) + return ExprError(); CastKind = CK_ConstructorConversion; QualType Class = S.Context.getTypeDeclType(Constructor->getParent()); @@ -5177,7 +5335,8 @@ InitializationSequence::Perform(Sema &S, CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn); S.CheckMemberOperatorAccess(Kind.getLocation(), CurInit.get(), 0, FoundFn); - S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation()); + if (S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation())) + return ExprError(); // FIXME: Should we move this initialization into a separate // derived-to-base conversion? I believe the answer is "no", because @@ -5211,7 +5370,8 @@ InitializationSequence::Perform(Sema &S, S.CheckDestructorAccess(CurInit.get()->getLocStart(), Destructor, S.PDiag(diag::err_access_dtor_temp) << T); S.MarkFunctionReferenced(CurInit.get()->getLocStart(), Destructor); - S.DiagnoseUseOfDecl(Destructor, CurInit.get()->getLocStart()); + if (S.DiagnoseUseOfDecl(Destructor, CurInit.get()->getLocStart())) + return ExprError(); } } @@ -5241,6 +5401,16 @@ InitializationSequence::Perform(Sema &S, break; } + case SK_LValueToRValue: { + assert(CurInit.get()->isGLValue() && "cannot load from a prvalue"); + CurInit = S.Owned(ImplicitCastExpr::Create(S.Context, Step->Type, + CK_LValueToRValue, + CurInit.take(), + /*BasePath=*/0, + VK_RValue)); + break; + } + case SK_ConversionSequence: { Sema::CheckedConversionKind CCK = Kind.isCStyleCast()? Sema::CCK_CStyleCast @@ -5483,7 +5653,8 @@ InitializationSequence::Perform(Sema &S, S.MarkFunctionReferenced(Kind.getLocation(), Destructor); S.CheckDestructorAccess(Kind.getLocation(), Destructor, S.PDiag(diag::err_access_dtor_temp) << E); - S.DiagnoseUseOfDecl(Destructor, Kind.getLocation()); + if (S.DiagnoseUseOfDecl(Destructor, Kind.getLocation())) + return ExprError(); } } } @@ -5621,7 +5792,7 @@ static void emitBadConversionNotes(Sema &S, const InitializedEntity &entity, bool InitializationSequence::Diagnose(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, - Expr **Args, unsigned NumArgs) { + ArrayRef<Expr *> Args) { if (!Failed()) return false; @@ -5629,7 +5800,7 @@ bool InitializationSequence::Diagnose(Sema &S, switch (Failure) { case FK_TooManyInitsForReference: // FIXME: Customize for the initialized entity? - if (NumArgs == 0) { + if (Args.empty()) { // Dig out the reference subobject which is uninitialized and diagnose it. // If this is value-initialization, this could be nested some way within // the target type. @@ -5641,7 +5812,7 @@ bool InitializationSequence::Diagnose(Sema &S, (void)Diagnosed; } else // FIXME: diagnostic below could be better! S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits) - << SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd()); + << SourceRange(Args.front()->getLocStart(), Args.back()->getLocEnd()); break; case FK_ArrayNeedsInitList: @@ -5688,16 +5859,14 @@ bool InitializationSequence::Diagnose(Sema &S, << DestType << Args[0]->getType() << Args[0]->getSourceRange(); - FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, - llvm::makeArrayRef(Args, NumArgs)); + FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, Args); break; case OR_No_Viable_Function: S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition) << Args[0]->getType() << DestType.getNonReferenceType() << Args[0]->getSourceRange(); - FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, - llvm::makeArrayRef(Args, NumArgs)); + FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, Args); break; case OR_Deleted: { @@ -5790,7 +5959,7 @@ bool InitializationSequence::Diagnose(Sema &S, R = SourceRange(InitList->getInit(0)->getLocEnd(), InitList->getLocEnd()); else - R = SourceRange(Args[0]->getLocEnd(), Args[NumArgs - 1]->getLocEnd()); + R = SourceRange(Args.front()->getLocEnd(), Args.back()->getLocEnd()); R.setBegin(S.PP.getLocForEndOfToken(R.getBegin())); if (Kind.isCStyleOrFunctionalCast()) @@ -5815,15 +5984,14 @@ bool InitializationSequence::Diagnose(Sema &S, case FK_ListConstructorOverloadFailed: case FK_ConstructorOverloadFailed: { SourceRange ArgsRange; - if (NumArgs) - ArgsRange = SourceRange(Args[0]->getLocStart(), - Args[NumArgs - 1]->getLocEnd()); + if (Args.size()) + ArgsRange = SourceRange(Args.front()->getLocStart(), + Args.back()->getLocEnd()); if (Failure == FK_ListConstructorOverloadFailed) { - assert(NumArgs == 1 && "List construction from other than 1 argument."); + assert(Args.size() == 1 && "List construction from other than 1 argument."); InitListExpr *InitList = cast<InitListExpr>(Args[0]); - Args = InitList->getInits(); - NumArgs = InitList->getNumInits(); + Args = MultiExprArg(InitList->getInits(), InitList->getNumInits()); } // FIXME: Using "DestType" for the entity we're printing is probably @@ -5832,8 +6000,7 @@ bool InitializationSequence::Diagnose(Sema &S, case OR_Ambiguous: S.Diag(Kind.getLocation(), diag::err_ovl_ambiguous_init) << DestType << ArgsRange; - FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, - llvm::makeArrayRef(Args, NumArgs)); + FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, Args); break; case OR_No_Viable_Function: @@ -5880,8 +6047,7 @@ bool InitializationSequence::Diagnose(Sema &S, S.Diag(Kind.getLocation(), diag::err_ovl_no_viable_function_in_init) << DestType << ArgsRange; - FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, - llvm::makeArrayRef(Args, NumArgs)); + FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, Args); break; case OR_Deleted: { @@ -6185,6 +6351,10 @@ void InitializationSequence::dump(raw_ostream &OS) const { OS << "qualification conversion (lvalue)"; break; + case SK_LValueToRValue: + OS << "load (lvalue to rvalue)"; + break; + case SK_ConversionSequence: OS << "implicit conversion sequence ("; S->ICS->DebugPrint(); // FIXME: use OS @@ -6395,7 +6565,7 @@ Sema::CanPerformCopyInitialization(const InitializedEntity &Entity, InitializationKind Kind = InitializationKind::CreateCopy(InitE->getLocStart(), SourceLocation()); - InitializationSequence Seq(*this, Entity, Kind, &InitE, 1); + InitializationSequence Seq(*this, Entity, Kind, InitE); return !Seq.Failed(); } @@ -6417,10 +6587,10 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity, InitializationKind Kind = InitializationKind::CreateCopy(InitE->getLocStart(), EqualLoc, AllowExplicit); - InitializationSequence Seq(*this, Entity, Kind, &InitE, 1); + InitializationSequence Seq(*this, Entity, Kind, InitE); Init.release(); - ExprResult Result = Seq.Perform(*this, Entity, Kind, MultiExprArg(&InitE, 1)); + ExprResult Result = Seq.Perform(*this, Entity, Kind, InitE); if (!Result.isInvalid() && TopLevelOfInitList) DiagnoseNarrowingInInitList(*this, Seq, Entity.getType(), diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 53fa6da..c7ba3cc 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -452,8 +452,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, FunctionProtoType::ExtProtoInfo EPI; EPI.HasTrailingReturn = true; EPI.TypeQuals |= DeclSpec::TQ_const; - QualType MethodTy = Context.getFunctionType(Context.DependentTy, - ArrayRef<QualType>(), + QualType MethodTy = Context.getFunctionType(Context.DependentTy, None, EPI); MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy); ExplicitParams = false; @@ -708,7 +707,7 @@ static void addFunctionPointerConversion(Sema &S, FunctionProtoType::ExtProtoInfo ExtInfo; ExtInfo.TypeQuals = Qualifiers::Const; QualType ConvTy = - S.Context.getFunctionType(FunctionPtrTy, ArrayRef<QualType>(), ExtInfo); + S.Context.getFunctionType(FunctionPtrTy, None, ExtInfo); SourceLocation Loc = IntroducerRange.getBegin(); DeclarationName Name @@ -779,8 +778,7 @@ static void addBlockPointerConversion(Sema &S, FunctionProtoType::ExtProtoInfo ExtInfo; ExtInfo.TypeQuals = Qualifiers::Const; - QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, ArrayRef<QualType>(), - ExtInfo); + QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, None, ExtInfo); SourceLocation Loc = IntroducerRange.getBegin(); DeclarationName Name @@ -862,6 +860,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, CaptureDefault = LCD_ByCopy; break; + case CapturingScopeInfo::ImpCap_CapturedRegion: case CapturingScopeInfo::ImpCap_LambdaByref: CaptureDefault = LCD_ByRef; break; @@ -949,6 +948,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, if (!CurContext->isDependentContext()) { switch (ExprEvalContexts.back().Context) { case Unevaluated: + case UnevaluatedAbstract: // We don't actually diagnose this case immediately, because we // could be within a context where we might find out later that // the expression is potentially evaluated (e.g., for typeid). diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index f26b8ed..9ab3b2d 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -731,7 +731,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { EPI.NumExceptions = 0; QualType ExpectedType = R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(), - ArrayRef<QualType>(), EPI); + None, EPI); // Perform template argument deduction against the type that we would // expect the function to have. @@ -884,6 +884,8 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // } // } // + UnqualUsingDirectiveSet UDirs; + bool VisitedUsingDirectives = false; DeclContext *OutsideOfTemplateParamDC = 0; for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) { DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity()); @@ -957,9 +959,28 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // If this is a file context, we need to perform unqualified name // lookup considering using directives. if (Ctx->isFileContext()) { - UnqualUsingDirectiveSet UDirs; - UDirs.visit(Ctx, Ctx); - UDirs.done(); + // If we haven't handled using directives yet, do so now. + if (!VisitedUsingDirectives) { + // Add using directives from this context up to the top level. + for (DeclContext *UCtx = Ctx; UCtx; UCtx = UCtx->getParent()) { + if (UCtx->isTransparentContext()) + continue; + + UDirs.visit(UCtx, UCtx); + } + + // Find the innermost file scope, so we can add using directives + // from local scopes. + Scope *InnermostFileScope = S; + while (InnermostFileScope && + !isNamespaceOrTranslationUnitScope(InnermostFileScope)) + InnermostFileScope = InnermostFileScope->getParent(); + UDirs.visitScopeChain(Initial, InnermostFileScope); + + UDirs.done(); + + VisitedUsingDirectives = true; + } if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs)) { R.resolveKind(); @@ -994,11 +1015,11 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // // FIXME: Cache this sorted list in Scope structure, and DeclContext, so we // don't build it for each lookup! - - UnqualUsingDirectiveSet UDirs; - UDirs.visitScopeChain(Initial, S); - UDirs.done(); - + if (!VisitedUsingDirectives) { + UDirs.visitScopeChain(Initial, S); + UDirs.done(); + } + // Lookup namespace scope, and global scope. // Unqualified name lookup in C++ requires looking into scopes // that aren't strictly lexical, and therefore we walk through the @@ -2066,6 +2087,10 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { case Type::Complex: break; + // Non-deduced auto types only get here for error cases. + case Type::Auto: + break; + // If T is an Objective-C object or interface type, or a pointer to an // object or interface type, the associated namespace is the global // namespace. @@ -2561,6 +2586,12 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R, bool IsRaw = false; bool IsExactMatch = false; + // If the declaration we found is invalid, skip it. + if (D->isInvalidDecl()) { + F.erase(); + continue; + } + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { if (FD->getNumParams() == 1 && FD->getParamDecl(0)->getType()->getAs<PointerType>()) @@ -3405,7 +3436,7 @@ class NamespaceSpecifierSet { } DeclContextList NamespaceSpecifierSet::BuildContextChain(DeclContext *Start) { - assert(Start && "Bulding a context chain from a null context"); + assert(Start && "Building a context chain from a null context"); DeclContextList Chain; for (DeclContext *DC = Start->getPrimaryContext(); DC != NULL; DC = DC->getLookupParent()) { @@ -3761,13 +3792,6 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, if (S && S->isInObjcMethodScope() && Typo == getSuperIdentifier()) return TypoCorrection(); - // This is for testing. - if (Diags.getWarnOnSpellCheck()) { - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Warning, - "spell-checking initiated for %0"); - Diag(TypoName.getLoc(), DiagID) << TypoName.getName(); - } - NamespaceSpecifierSet Namespaces(Context, CurContext, SS); TypoCorrectionConsumer Consumer(*this, Typo); diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index c348a9c..91f0881 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -996,8 +996,10 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, PropertyIvarType->getAs<ObjCObjectPointerType>()) { const ObjCInterfaceDecl *ObjI = ObjT->getInterfaceDecl(); if (ObjI && ObjI->isArcWeakrefUnavailable()) { - Diag(PropertyDiagLoc, diag::err_arc_weak_unavailable_property); - Diag(property->getLocation(), diag::note_property_declare); + Diag(property->getLocation(), + diag::err_arc_weak_unavailable_property) << PropertyIvarType; + Diag(ClassImpDecl->getLocation(), diag::note_implemented_by_class) + << ClassImpDecl->getName(); err = true; } } @@ -1660,8 +1662,7 @@ void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) { } void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, - ObjCContainerDecl *CDecl, - const SelectorSet &InsMap) { + ObjCContainerDecl *CDecl) { ObjCContainerDecl::PropertyMap NoNeedToImplPropMap; ObjCInterfaceDecl *IDecl; // Gather properties which need not be implemented in this class @@ -1690,6 +1691,26 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, EI = IMPDecl->propimpl_end(); I != EI; ++I) PropImplMap.insert(I->getPropertyDecl()); + SelectorSet InsMap; + // Collect property accessors implemented in current implementation. + for (ObjCImplementationDecl::instmeth_iterator + I = IMPDecl->instmeth_begin(), E = IMPDecl->instmeth_end(); I!=E; ++I) + InsMap.insert((*I)->getSelector()); + + ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl); + ObjCInterfaceDecl *PrimaryClass = 0; + if (C && !C->IsClassExtension()) + if ((PrimaryClass = C->getClassInterface())) + // Report unimplemented properties in the category as well. + if (ObjCImplDecl *IMP = PrimaryClass->getImplementation()) { + // When reporting on missing setter/getters, do not report when + // setter/getter is implemented in category's primary class + // implementation. + for (ObjCImplementationDecl::instmeth_iterator + I = IMP->instmeth_begin(), E = IMP->instmeth_end(); I!=E; ++I) + InsMap.insert((*I)->getSelector()); + } + for (ObjCContainerDecl::PropertyMap::iterator P = PropMap.begin(), E = PropMap.end(); P != E; ++P) { ObjCPropertyDecl *Prop = P->second; @@ -1699,7 +1720,13 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, PropImplMap.count(Prop) || Prop->getAvailability() == AR_Unavailable) continue; - if (!InsMap.count(Prop->getGetterName())) { + // When reporting on missing property getter implementation in + // categories, do not report when they are declared in primary class, + // class's protocol, or one of it super classes. This is because, + // the class is going to implement them. + if (!InsMap.count(Prop->getGetterName()) && + (PrimaryClass == 0 || + !PrimaryClass->lookupPropertyAccessor(Prop->getGetterName(), C))) { Diag(IMPDecl->getLocation(), isa<ObjCCategoryDecl>(CDecl) ? diag::warn_setter_getter_impl_required_in_category : @@ -1713,8 +1740,13 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, Diag(RID->getLocation(), diag::note_suppressed_class_declare); } - - if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) { + // When reporting on missing property setter implementation in + // categories, do not report when they are declared in primary class, + // class's protocol, or one of it super classes. This is because, + // the class is going to implement them. + if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName()) && + (PrimaryClass == 0 || + !PrimaryClass->lookupPropertyAccessor(Prop->getSetterName(), C))) { Diag(IMPDecl->getLocation(), isa<ObjCCategoryDecl>(CDecl) ? diag::warn_setter_getter_impl_required_in_category : @@ -1975,8 +2007,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, /*TInfo=*/0, SC_None, 0); - SetterMethod->setMethodParams(Context, Argument, - ArrayRef<SourceLocation>()); + SetterMethod->setMethodParams(Context, Argument, None); AddPropertyAttrs(*this, SetterMethod, property); diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index b8acb2d..c815d4f 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -165,8 +165,8 @@ OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl( continue; } - // Check if threadspecified is set. - if (VD->isThreadSpecified()) { + // Check if this is a TLS variable. + if (VD->getTLSKind()) { Diag(ILoc, diag::err_omp_var_thread_local) << VD; Diag(VD->getLocation(), diag::note_forward_declaration) << VD; continue; diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 89d495d..529ba12 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -42,13 +42,15 @@ CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl, bool HadMultipleCandidates, SourceLocation Loc = SourceLocation(), const DeclarationNameLoc &LocInfo = DeclarationNameLoc()){ + if (S.DiagnoseUseOfDecl(FoundDecl, Loc)) + return ExprError(); + DeclRefExpr *DRE = new (S.Context) DeclRefExpr(Fn, false, Fn->getType(), VK_LValue, Loc, LocInfo); if (HadMultipleCandidates) DRE->setHadMultipleCandidates(true); S.MarkDeclRefReferenced(DRE); - S.DiagnoseUseOfDecl(FoundDecl, Loc); ExprResult E = S.Owned(DRE); E = S.DefaultFunctionArrayConversion(E.take()); @@ -940,6 +942,9 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old, continue; } + if (!shouldLinkPossiblyHiddenDecl(*I, New)) + continue; + Match = *I; return Ovl_Match; } @@ -1832,7 +1837,7 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { // conversion. using llvm::APSInt; if (From) - if (FieldDecl *MemberDecl = From->getBitField()) { + if (FieldDecl *MemberDecl = From->getSourceBitField()) { APSInt BitWidth; if (FromType->isIntegralType(Context) && MemberDecl->getBitWidth()->isIntegerConstantExpr(BitWidth, Context)) { @@ -5024,7 +5029,7 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T, Expr::EvalResult Eval; Eval.Diag = &Notes; - if (!Result.get()->EvaluateAsRValue(Eval, Context)) { + if (!Result.get()->EvaluateAsRValue(Eval, Context) || !Eval.Val.isInt()) { // The expression can't be folded, so we can't keep it at this position in // the AST. Result = ExprError(); @@ -5473,7 +5478,7 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, Expr::Classification ObjectClassification, - Expr **Args, unsigned NumArgs, + ArrayRef<Expr *> Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions) { NamedDecl *Decl = FoundDecl.getDecl(); @@ -5488,12 +5493,12 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, AddMethodTemplateCandidate(TD, FoundDecl, ActingContext, /*ExplicitArgs*/ 0, ObjectType, ObjectClassification, - llvm::makeArrayRef(Args, NumArgs), CandidateSet, + Args, CandidateSet, SuppressUserConversions); } else { AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext, ObjectType, ObjectClassification, - llvm::makeArrayRef(Args, NumArgs), + Args, CandidateSet, SuppressUserConversions); } } @@ -5721,6 +5726,14 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, if (!CandidateSet.isNewCandidate(Conversion)) return; + // If the conversion function has an undeduced return type, trigger its + // deduction now. + if (getLangOpts().CPlusPlus1y && ConvType->isUndeducedType()) { + if (DeduceReturnType(Conversion, From->getExprLoc())) + return; + ConvType = Conversion->getConversionType().getNonReferenceType(); + } + // Overload resolution is always an unevaluated context. EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated); @@ -5800,7 +5813,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, // there are 0 arguments (i.e., nothing is allocated using ASTContext's // allocator). QualType CallResultType = ConversionType.getNonLValueExprType(Context); - CallExpr Call(Context, &ConversionFn, MultiExprArg(), CallResultType, VK, + CallExpr Call(Context, &ConversionFn, None, CallResultType, VK, From->getLocStart()); ImplicitConversionSequence ICS = TryCopyInitialization(*this, &Call, ToType, @@ -5963,7 +5976,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, // Determine the implicit conversion sequences for each of the // arguments. - for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) { + for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) { if (ArgIdx < NumArgsInProto) { // (C++ 13.3.2p3): for F to be a viable function, there shall // exist for each argument an implicit conversion sequence @@ -6000,7 +6013,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, /// [over.match.oper]). void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, SourceLocation OpLoc, - Expr **Args, unsigned NumArgs, + ArrayRef<Expr *> Args, OverloadCandidateSet& CandidateSet, SourceRange OpRange) { DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); @@ -6015,13 +6028,15 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, // constructed as follows: QualType T1 = Args[0]->getType(); - // -- If T1 is a class type, the set of member candidates is the - // result of the qualified lookup of T1::operator@ - // (13.3.1.1.1); otherwise, the set of member candidates is - // empty. + // -- If T1 is a complete class type or a class currently being + // defined, the set of member candidates is the result of the + // qualified lookup of T1::operator@ (13.3.1.1.1); otherwise, + // the set of member candidates is empty. if (const RecordType *T1Rec = T1->getAs<RecordType>()) { - // Complete the type if it can be completed. Otherwise, we're done. - if (RequireCompleteType(OpLoc, T1, 0)) + // Complete the type if it can be completed. + RequireCompleteType(OpLoc, T1, 0); + // If the type is neither complete nor being defined, bail out now. + if (!T1Rec->getDecl()->getDefinition()) return; LookupResult Operators(*this, OpName, OpLoc, LookupOrdinaryName); @@ -6033,7 +6048,8 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, Oper != OperEnd; ++Oper) AddMethodCandidate(Oper.getPair(), Args[0]->getType(), - Args[0]->Classify(Context), Args + 1, NumArgs - 1, + Args[0]->Classify(Context), + Args.slice(1), CandidateSet, /* SuppressUserConversions = */ false); } @@ -6048,7 +6064,7 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, /// (at the beginning of the argument list) that will be contextually /// converted to bool. void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, - Expr **Args, unsigned NumArgs, + ArrayRef<Expr *> Args, OverloadCandidateSet& CandidateSet, bool IsAssignmentOperator, unsigned NumContextualBoolArguments) { @@ -6056,20 +6072,20 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated); // Add this candidate - OverloadCandidate &Candidate = CandidateSet.addCandidate(NumArgs); + OverloadCandidate &Candidate = CandidateSet.addCandidate(Args.size()); Candidate.FoundDecl = DeclAccessPair::make(0, AS_none); Candidate.Function = 0; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; Candidate.BuiltinTypes.ResultTy = ResultTy; - for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) + for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) Candidate.BuiltinTypes.ParamTypes[ArgIdx] = ParamTys[ArgIdx]; // Determine the implicit conversion sequences for each of the // arguments. Candidate.Viable = true; - Candidate.ExplicitCallArguments = NumArgs; - for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + Candidate.ExplicitCallArguments = Args.size(); + for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) { // C++ [over.match.oper]p4: // For the built-in assignment operators, conversions of the // left operand are restricted as follows: @@ -6395,15 +6411,14 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, /// given type to the candidate set. static void AddBuiltinAssignmentOperatorCandidates(Sema &S, QualType T, - Expr **Args, - unsigned NumArgs, + ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet) { QualType ParamTypes[2]; // T& operator=(T&, T) ParamTypes[0] = S.Context.getLValueReferenceType(T); ParamTypes[1] = T; - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, /*IsAssignmentOperator=*/true); if (!S.Context.getCanonicalType(T).isVolatileQualified()) { @@ -6411,7 +6426,7 @@ static void AddBuiltinAssignmentOperatorCandidates(Sema &S, ParamTypes[0] = S.Context.getLValueReferenceType(S.Context.getVolatileType(T)); ParamTypes[1] = T; - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, /*IsAssignmentOperator=*/true); } } @@ -6482,8 +6497,7 @@ namespace { class BuiltinOperatorOverloadBuilder { // Common instance state available to all overload candidate addition methods. Sema &S; - Expr **Args; - unsigned NumArgs; + ArrayRef<Expr *> Args; Qualifiers VisibleTypeConversionsQuals; bool HasArithmeticOrEnumeralCandidateType; SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes; @@ -6606,10 +6620,10 @@ class BuiltinOperatorOverloadBuilder { }; // Non-volatile version. - if (NumArgs == 1) - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); + if (Args.size() == 1) + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet); else - S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, CandidateSet); // Use a heuristic to reduce number of builtin candidates in the set: // add volatile version only if there are conversions to a volatile type. @@ -6617,10 +6631,10 @@ class BuiltinOperatorOverloadBuilder { ParamTypes[0] = S.Context.getLValueReferenceType( S.Context.getVolatileType(CandidateTy)); - if (NumArgs == 1) - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); + if (Args.size() == 1) + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet); else - S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, CandidateSet); } // Add restrict version only if there are conversions to a restrict type @@ -6630,10 +6644,10 @@ class BuiltinOperatorOverloadBuilder { ParamTypes[0] = S.Context.getLValueReferenceType( S.Context.getCVRQualifiedType(CandidateTy, Qualifiers::Restrict)); - if (NumArgs == 1) - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, CandidateSet); + if (Args.size() == 1) + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet); else - S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, CandidateSet); if (HasVolatile) { ParamTypes[0] @@ -6641,11 +6655,10 @@ class BuiltinOperatorOverloadBuilder { S.Context.getCVRQualifiedType(CandidateTy, (Qualifiers::Volatile | Qualifiers::Restrict))); - if (NumArgs == 1) - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 1, - CandidateSet); + if (Args.size() == 1) + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet); else - S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(CandidateTy, ParamTypes, Args, CandidateSet); } } @@ -6653,12 +6666,12 @@ class BuiltinOperatorOverloadBuilder { public: BuiltinOperatorOverloadBuilder( - Sema &S, Expr **Args, unsigned NumArgs, + Sema &S, ArrayRef<Expr *> Args, Qualifiers VisibleTypeConversionsQuals, bool HasArithmeticOrEnumeralCandidateType, SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes, OverloadCandidateSet &CandidateSet) - : S(S), Args(Args), NumArgs(NumArgs), + : S(S), Args(Args), VisibleTypeConversionsQuals(VisibleTypeConversionsQuals), HasArithmeticOrEnumeralCandidateType( HasArithmeticOrEnumeralCandidateType), @@ -6760,7 +6773,7 @@ public: continue; S.AddBuiltinCandidate(S.Context.getLValueReferenceType(PointeeTy), - &ParamTy, Args, 1, CandidateSet); + &ParamTy, Args, CandidateSet); } } @@ -6777,7 +6790,7 @@ public: for (unsigned Arith = FirstPromotedArithmeticType; Arith < LastPromotedArithmeticType; ++Arith) { QualType ArithTy = getArithmeticType(Arith); - S.AddBuiltinCandidate(ArithTy, &ArithTy, Args, 1, CandidateSet); + S.AddBuiltinCandidate(ArithTy, &ArithTy, Args, CandidateSet); } // Extension: We also add these operators for vector types. @@ -6786,7 +6799,7 @@ public: VecEnd = CandidateTypes[0].vector_end(); Vec != VecEnd; ++Vec) { QualType VecTy = *Vec; - S.AddBuiltinCandidate(VecTy, &VecTy, Args, 1, CandidateSet); + S.AddBuiltinCandidate(VecTy, &VecTy, Args, CandidateSet); } } @@ -6801,7 +6814,7 @@ public: PtrEnd = CandidateTypes[0].pointer_end(); Ptr != PtrEnd; ++Ptr) { QualType ParamTy = *Ptr; - S.AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet); + S.AddBuiltinCandidate(ParamTy, &ParamTy, Args, CandidateSet); } } @@ -6817,7 +6830,7 @@ public: for (unsigned Int = FirstPromotedIntegralType; Int < LastPromotedIntegralType; ++Int) { QualType IntTy = getArithmeticType(Int); - S.AddBuiltinCandidate(IntTy, &IntTy, Args, 1, CandidateSet); + S.AddBuiltinCandidate(IntTy, &IntTy, Args, CandidateSet); } // Extension: We also add this operator for vector types. @@ -6826,7 +6839,7 @@ public: VecEnd = CandidateTypes[0].vector_end(); Vec != VecEnd; ++Vec) { QualType VecTy = *Vec; - S.AddBuiltinCandidate(VecTy, &VecTy, Args, 1, CandidateSet); + S.AddBuiltinCandidate(VecTy, &VecTy, Args, CandidateSet); } } @@ -6840,7 +6853,7 @@ public: /// Set of (canonical) types that we've already handled. llvm::SmallPtrSet<QualType, 8> AddedTypes; - for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) { for (BuiltinCandidateTypeSet::iterator MemPtr = CandidateTypes[ArgIdx].member_pointer_begin(), MemPtrEnd = CandidateTypes[ArgIdx].member_pointer_end(); @@ -6851,8 +6864,7 @@ public: continue; QualType ParamTypes[2] = { *MemPtr, *MemPtr }; - S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, - CandidateSet); + S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, CandidateSet); } } } @@ -6884,7 +6896,7 @@ public: llvm::DenseSet<std::pair<CanQualType, CanQualType> > UserDefinedBinaryOperators; - for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) { if (CandidateTypes[ArgIdx].enumeration_begin() != CandidateTypes[ArgIdx].enumeration_end()) { for (OverloadCandidateSet::iterator C = CandidateSet.begin(), @@ -6917,7 +6929,7 @@ public: /// Set of (canonical) types that we've already handled. llvm::SmallPtrSet<QualType, 8> AddedTypes; - for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) { for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes[ArgIdx].pointer_begin(), PtrEnd = CandidateTypes[ArgIdx].pointer_end(); @@ -6927,8 +6939,7 @@ public: continue; QualType ParamTypes[2] = { *Ptr, *Ptr }; - S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, - CandidateSet); + S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, CandidateSet); } for (BuiltinCandidateTypeSet::iterator Enum = CandidateTypes[ArgIdx].enumeration_begin(), @@ -6944,17 +6955,16 @@ public: continue; QualType ParamTypes[2] = { *Enum, *Enum }; - S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, - CandidateSet); + S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, CandidateSet); } if (CandidateTypes[ArgIdx].hasNullPtrType()) { CanQualType NullPtrTy = S.Context.getCanonicalType(S.Context.NullPtrTy); if (AddedTypes.insert(NullPtrTy) && - !UserDefinedBinaryOperators.count(std::make_pair(NullPtrTy, + !UserDefinedBinaryOperators.count(std::make_pair(NullPtrTy, NullPtrTy))) { QualType ParamTypes[2] = { NullPtrTy, NullPtrTy }; - S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, + S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, CandidateSet); } } @@ -6999,8 +7009,7 @@ public: if (Arg == 0 || Op == OO_Plus) { // operator+(T*, ptrdiff_t) or operator-(T*, ptrdiff_t) // T* operator+(ptrdiff_t, T*); - S.AddBuiltinCandidate(*Ptr, AsymetricParamTypes, Args, 2, - CandidateSet); + S.AddBuiltinCandidate(*Ptr, AsymetricParamTypes, Args, CandidateSet); } if (Op == OO_Minus) { // ptrdiff_t operator-(T, T); @@ -7009,7 +7018,7 @@ public: QualType ParamTypes[2] = { *Ptr, *Ptr }; S.AddBuiltinCandidate(S.Context.getPointerDiffType(), ParamTypes, - Args, 2, CandidateSet); + Args, CandidateSet); } } } @@ -7057,7 +7066,7 @@ public: QualType Result = isComparison ? S.Context.BoolTy : getUsualArithmeticConversions(Left, Right); - S.AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet); + S.AddBuiltinCandidate(Result, LandR, Args, CandidateSet); } } @@ -7080,7 +7089,7 @@ public: Result = *Vec2; } - S.AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet); + S.AddBuiltinCandidate(Result, LandR, Args, CandidateSet); } } } @@ -7112,7 +7121,7 @@ public: QualType Result = (Op == OO_LessLess || Op == OO_GreaterGreater) ? LandR[0] : getUsualArithmeticConversions(Left, Right); - S.AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet); + S.AddBuiltinCandidate(Result, LandR, Args, CandidateSet); } } } @@ -7136,8 +7145,7 @@ public: if (!AddedTypes.insert(S.Context.getCanonicalType(*Enum))) continue; - AddBuiltinAssignmentOperatorCandidates(S, *Enum, Args, 2, - CandidateSet); + AddBuiltinAssignmentOperatorCandidates(S, *Enum, Args, CandidateSet); } for (BuiltinCandidateTypeSet::iterator @@ -7147,8 +7155,7 @@ public: if (!AddedTypes.insert(S.Context.getCanonicalType(*MemPtr))) continue; - AddBuiltinAssignmentOperatorCandidates(S, *MemPtr, Args, 2, - CandidateSet); + AddBuiltinAssignmentOperatorCandidates(S, *MemPtr, Args, CandidateSet); } } } @@ -7188,7 +7195,7 @@ public: S.Context.getLValueReferenceType(*Ptr), isEqualOp ? *Ptr : S.Context.getPointerDiffType(), }; - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/ isEqualOp); bool NeedVolatile = !(*Ptr).isVolatileQualified() && @@ -7197,7 +7204,7 @@ public: // volatile version ParamTypes[0] = S.Context.getLValueReferenceType(S.Context.getVolatileType(*Ptr)); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/isEqualOp); } @@ -7206,7 +7213,7 @@ public: // restrict version ParamTypes[0] = S.Context.getLValueReferenceType(S.Context.getRestrictType(*Ptr)); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/isEqualOp); if (NeedVolatile) { @@ -7216,8 +7223,7 @@ public: S.Context.getCVRQualifiedType(*Ptr, (Qualifiers::Volatile | Qualifiers::Restrict))); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, - CandidateSet, + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/isEqualOp); } } @@ -7238,7 +7244,7 @@ public: }; // non-volatile version - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/true); bool NeedVolatile = !(*Ptr).isVolatileQualified() && @@ -7247,8 +7253,8 @@ public: // volatile version ParamTypes[0] = S.Context.getLValueReferenceType(S.Context.getVolatileType(*Ptr)); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, - CandidateSet, /*IsAssigmentOperator=*/true); + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, + /*IsAssigmentOperator=*/true); } if (!(*Ptr).isRestrictQualified() && @@ -7256,8 +7262,8 @@ public: // restrict version ParamTypes[0] = S.Context.getLValueReferenceType(S.Context.getRestrictType(*Ptr)); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, - CandidateSet, /*IsAssigmentOperator=*/true); + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, + /*IsAssigmentOperator=*/true); if (NeedVolatile) { // volatile restrict version @@ -7266,9 +7272,8 @@ public: S.Context.getCVRQualifiedType(*Ptr, (Qualifiers::Volatile | Qualifiers::Restrict))); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, - CandidateSet, /*IsAssigmentOperator=*/true); - + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, + /*IsAssigmentOperator=*/true); } } } @@ -7300,7 +7305,7 @@ public: // Add this built-in operator as a candidate (VQ is empty). ParamTypes[0] = S.Context.getLValueReferenceType(getArithmeticType(Left)); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/isEqualOp); // Add this built-in operator as a candidate (VQ is 'volatile'). @@ -7308,8 +7313,7 @@ public: ParamTypes[0] = S.Context.getVolatileType(getArithmeticType(Left)); ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, - CandidateSet, + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/isEqualOp); } } @@ -7328,15 +7332,14 @@ public: ParamTypes[1] = *Vec2; // Add this built-in operator as a candidate (VQ is empty). ParamTypes[0] = S.Context.getLValueReferenceType(*Vec1); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet, + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/isEqualOp); // Add this built-in operator as a candidate (VQ is 'volatile'). if (VisibleTypeConversionsQuals.hasVolatile()) { ParamTypes[0] = S.Context.getVolatileType(*Vec1); ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, - CandidateSet, + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/isEqualOp); } } @@ -7368,14 +7371,13 @@ public: // Add this built-in operator as a candidate (VQ is empty). ParamTypes[0] = S.Context.getLValueReferenceType(getArithmeticType(Left)); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet); if (VisibleTypeConversionsQuals.hasVolatile()) { // Add this built-in operator as a candidate (VQ is 'volatile'). ParamTypes[0] = getArithmeticType(Left); ParamTypes[0] = S.Context.getVolatileType(ParamTypes[0]); ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]); - S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, - CandidateSet); + S.AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, CandidateSet); } } } @@ -7390,13 +7392,13 @@ public: // bool operator||(bool, bool); void addExclaimOverload() { QualType ParamTy = S.Context.BoolTy; - S.AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet, + S.AddBuiltinCandidate(ParamTy, &ParamTy, Args, CandidateSet, /*IsAssignmentOperator=*/false, /*NumContextualBoolArguments=*/1); } void addAmpAmpOrPipePipeOverload() { QualType ParamTypes[2] = { S.Context.BoolTy, S.Context.BoolTy }; - S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2, CandidateSet, + S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, CandidateSet, /*IsAssignmentOperator=*/false, /*NumContextualBoolArguments=*/2); } @@ -7424,7 +7426,7 @@ public: QualType ResultTy = S.Context.getLValueReferenceType(PointeeType); // T& operator[](T*, ptrdiff_t) - S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, CandidateSet); } for (BuiltinCandidateTypeSet::iterator @@ -7439,7 +7441,7 @@ public: QualType ResultTy = S.Context.getLValueReferenceType(PointeeType); // T& operator[](ptrdiff_t, T*) - S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, CandidateSet); } } @@ -7490,7 +7492,7 @@ public: continue; T = Q1.apply(S.Context, T); QualType ResultTy = S.Context.getLValueReferenceType(T); - S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(ResultTy, ParamTypes, Args, CandidateSet); } } } @@ -7518,7 +7520,7 @@ public: continue; QualType ParamTypes[2] = { *Ptr, *Ptr }; - S.AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(*Ptr, ParamTypes, Args, CandidateSet); } for (BuiltinCandidateTypeSet::iterator @@ -7529,7 +7531,7 @@ public: continue; QualType ParamTypes[2] = { *MemPtr, *MemPtr }; - S.AddBuiltinCandidate(*MemPtr, ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(*MemPtr, ParamTypes, Args, CandidateSet); } if (S.getLangOpts().CPlusPlus11) { @@ -7544,7 +7546,7 @@ public: continue; QualType ParamTypes[2] = { *Enum, *Enum }; - S.AddBuiltinCandidate(*Enum, ParamTypes, Args, 2, CandidateSet); + S.AddBuiltinCandidate(*Enum, ParamTypes, Args, CandidateSet); } } } @@ -7561,7 +7563,7 @@ public: void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, SourceLocation OpLoc, - Expr **Args, unsigned NumArgs, + llvm::ArrayRef<Expr *> Args, OverloadCandidateSet& CandidateSet) { // Find all of the types that the arguments can convert to, but only // if the operator we're looking at has built-in operator candidates @@ -7569,13 +7571,13 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // candidate types or either arithmetic or enumeral candidate types. Qualifiers VisibleTypeConversionsQuals; VisibleTypeConversionsQuals.addConst(); - for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) + for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) VisibleTypeConversionsQuals += CollectVRQualifiers(Context, Args[ArgIdx]); bool HasNonRecordCandidateType = false; bool HasArithmeticOrEnumeralCandidateType = false; SmallVector<BuiltinCandidateTypeSet, 2> CandidateTypes; - for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) { + for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) { CandidateTypes.push_back(BuiltinCandidateTypeSet(*this)); CandidateTypes[ArgIdx].AddTypesConvertedFrom(Args[ArgIdx]->getType(), OpLoc, @@ -7596,12 +7598,12 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // // We can't exit early for !, ||, or &&, since there we have always have // 'bool' overloads. - if (!HasNonRecordCandidateType && + if (!HasNonRecordCandidateType && !(Op == OO_Exclaim || Op == OO_AmpAmp || Op == OO_PipePipe)) return; // Setup an object to manage the common state for building overloads. - BuiltinOperatorOverloadBuilder OpBuilder(*this, Args, NumArgs, + BuiltinOperatorOverloadBuilder OpBuilder(*this, Args, VisibleTypeConversionsQuals, HasArithmeticOrEnumeralCandidateType, CandidateTypes, CandidateSet); @@ -7628,12 +7630,12 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, break; case OO_Plus: // '+' is either unary or binary - if (NumArgs == 1) + if (Args.size() == 1) OpBuilder.addUnaryPlusPointerOverloads(); // Fall through. case OO_Minus: // '-' is either unary or binary - if (NumArgs == 1) { + if (Args.size() == 1) { OpBuilder.addUnaryPlusOrMinusArithmeticOverloads(); } else { OpBuilder.addBinaryPlusOrMinusPointerOverloads(Op); @@ -7642,7 +7644,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, break; case OO_Star: // '*' is either unary or binary - if (NumArgs == 1) + if (Args.size() == 1) OpBuilder.addUnaryStarPointerOverloads(); else OpBuilder.addGenericBinaryArithmeticOverloads(/*isComparison=*/false); @@ -7680,7 +7682,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, break; case OO_Amp: // '&' is either unary or binary - if (NumArgs == 1) + if (Args.size() == 1) // C++ [over.match.oper]p3: // -- For the operator ',', the unary operator '&', or the // operator '->', the built-in candidates set is empty. @@ -8508,13 +8510,35 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, return; } - case Sema::TDK_NonDeducedMismatch: + case Sema::TDK_NonDeducedMismatch: { // FIXME: Provide a source location to indicate what we couldn't match. + TemplateArgument FirstTA = *Cand->DeductionFailure.getFirstArg(); + TemplateArgument SecondTA = *Cand->DeductionFailure.getSecondArg(); + if (FirstTA.getKind() == TemplateArgument::Template && + SecondTA.getKind() == TemplateArgument::Template) { + TemplateName FirstTN = FirstTA.getAsTemplate(); + TemplateName SecondTN = SecondTA.getAsTemplate(); + if (FirstTN.getKind() == TemplateName::Template && + SecondTN.getKind() == TemplateName::Template) { + if (FirstTN.getAsTemplateDecl()->getName() == + SecondTN.getAsTemplateDecl()->getName()) { + // FIXME: This fixes a bad diagnostic where both templates are named + // the same. This particular case is a bit difficult since: + // 1) It is passed as a string to the diagnostic printer. + // 2) The diagnostic printer only attempts to find a better + // name for types, not decls. + // Ideally, this should folded into the diagnostic printer. + S.Diag(Fn->getLocation(), + diag::note_ovl_candidate_non_deduced_mismatch_qualified) + << FirstTN.getAsTemplateDecl() << SecondTN.getAsTemplateDecl(); + return; + } + } + } S.Diag(Fn->getLocation(), diag::note_ovl_candidate_non_deduced_mismatch) - << *Cand->DeductionFailure.getFirstArg() - << *Cand->DeductionFailure.getSecondArg(); + << FirstTA << SecondTA; return; - + } // TODO: diagnose these individually, then kill off // note_ovl_candidate_bad_deduction, which is uselessly vague. case Sema::TDK_MiscellaneousDeductionFailure: @@ -9109,17 +9133,19 @@ private: = S.DeduceTemplateArguments(FunctionTemplate, &OvlExplicitTemplateArgs, TargetFunctionType, Specialization, - Info)) { + Info, /*InOverloadResolution=*/true)) { // FIXME: make a note of the failed deduction for diagnostics. (void)Result; return false; } - // Template argument deduction ensures that we have an exact match. + // Template argument deduction ensures that we have an exact match or + // compatible pointer-to-function arguments that would be adjusted by ICS. // This function template specicalization works. Specialization = cast<FunctionDecl>(Specialization->getCanonicalDecl()); - assert(TargetFunctionType - == Context.getCanonicalType(Specialization->getType())); + assert(S.isSameOrCompatibleFunctionType( + Context.getCanonicalType(Specialization->getType()), + Context.getCanonicalType(TargetFunctionType))); Matches.push_back(std::make_pair(CurAccessFunPair, Specialization)); return true; } @@ -9141,6 +9167,13 @@ private: if (S.CheckCUDATarget(Caller, FunDecl)) return false; + // If any candidate has a placeholder return type, trigger its deduction + // now. + if (S.getLangOpts().CPlusPlus1y && + FunDecl->getResultType()->isUndeducedType() && + S.DeduceReturnType(FunDecl, SourceExpr->getLocStart(), Complain)) + return false; + QualType ResultTy; if (Context.hasSameUnqualifiedType(TargetFunctionType, FunDecl->getType()) || @@ -9384,7 +9417,8 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, TemplateDeductionInfo Info(ovl->getNameLoc()); if (TemplateDeductionResult Result = DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs, - Specialization, Info)) { + Specialization, Info, + /*InOverloadResolution=*/true)) { // FIXME: make a note of the failed deduction for diagnostics. (void)Result; continue; @@ -9406,6 +9440,11 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, if (FoundResult) *FoundResult = I.getPair(); } + if (Matched && getLangOpts().CPlusPlus1y && + Matched->getResultType()->isUndeducedType() && + DeduceReturnType(Matched, ovl->getExprLoc(), Complain)) + return 0; + return Matched; } @@ -9932,7 +9971,8 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, case OR_Success: { FunctionDecl *FDecl = (*Best)->Function; SemaRef.CheckUnresolvedLookupAccess(ULE, (*Best)->FoundDecl); - SemaRef.DiagnoseUseOfDecl(FDecl, ULE->getNameLoc()); + if (SemaRef.DiagnoseUseOfDecl(FDecl, ULE->getNameLoc())) + return ExprError(); Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl); return SemaRef.BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc, ExecConfig); @@ -10065,6 +10105,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, NumArgs = 2; } + ArrayRef<Expr *> ArgsArray(Args, NumArgs); + if (Input->isTypeDependent()) { if (Fns.empty()) return Owned(new (Context) UnaryOperator(Input, @@ -10079,8 +10121,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, NestedNameSpecifierLoc(), OpNameInfo, /*ADL*/ true, IsOverloaded(Fns), Fns.begin(), Fns.end()); - return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, - llvm::makeArrayRef(Args, NumArgs), + return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, ArgsArray, Context.DependentTy, VK_RValue, OpLoc, false)); @@ -10090,20 +10131,18 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, OverloadCandidateSet CandidateSet(OpLoc); // Add the candidates from the given function set. - AddFunctionCandidates(Fns, llvm::makeArrayRef(Args, NumArgs), CandidateSet, - false); + AddFunctionCandidates(Fns, ArgsArray, CandidateSet, false); // Add operator candidates that are member functions. - AddMemberOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet); + AddMemberOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet); // Add candidates from ADL. - AddArgumentDependentLookupCandidates(OpName, /*Operator*/ true, - OpLoc, llvm::makeArrayRef(Args, NumArgs), - /*ExplicitTemplateArgs*/ 0, + AddArgumentDependentLookupCandidates(OpName, /*Operator*/ true, OpLoc, + ArgsArray, /*ExplicitTemplateArgs*/ 0, CandidateSet); // Add builtin operator candidates. - AddBuiltinOperatorCandidates(Op, OpLoc, &Args[0], NumArgs, CandidateSet); + AddBuiltinOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet); bool HadMultipleCandidates = (CandidateSet.size() > 1); @@ -10154,8 +10193,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, Args[0] = Input; CallExpr *TheCall = - new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.take(), - llvm::makeArrayRef(Args, NumArgs), + new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.take(), ArgsArray, ResultTy, VK, OpLoc, false); if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall, @@ -10181,8 +10219,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, // This is an erroneous use of an operator which can be overloaded by // a non-member function. Check for non-member operators which were // defined too late to be candidates. - if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, - llvm::makeArrayRef(Args, NumArgs))) + if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, ArgsArray)) // FIXME: Recover by calling the found function. return ExprError(); @@ -10195,8 +10232,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, << UnaryOperator::getOpcodeStr(Opc) << Input->getType() << Input->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, - llvm::makeArrayRef(Args, NumArgs), + CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, ArgsArray, UnaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); @@ -10206,8 +10242,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, << UnaryOperator::getOpcodeStr(Opc) << getDeletedOrUnavailableSuffix(Best->Function) << Input->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, - llvm::makeArrayRef(Args, NumArgs), + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, ArgsArray, UnaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); } @@ -10315,7 +10350,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, AddFunctionCandidates(Fns, Args, CandidateSet, false); // Add operator candidates that are member functions. - AddMemberOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet); + AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet); // Add candidates from ADL. AddArgumentDependentLookupCandidates(OpName, /*Operator*/ true, @@ -10324,7 +10359,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, CandidateSet); // Add builtin operator candidates. - AddBuiltinOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet); + AddBuiltinOperatorCandidates(Op, OpLoc, Args, CandidateSet); bool HadMultipleCandidates = (CandidateSet.size() > 1); @@ -10545,10 +10580,10 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // Subscript can only be overloaded as a member function. // Add operator candidates that are member functions. - AddMemberOperatorCandidates(OO_Subscript, LLoc, Args, 2, CandidateSet); + AddMemberOperatorCandidates(OO_Subscript, LLoc, Args, CandidateSet); // Add builtin operator candidates. - AddBuiltinOperatorCandidates(OO_Subscript, LLoc, Args, 2, CandidateSet); + AddBuiltinOperatorCandidates(OO_Subscript, LLoc, Args, CandidateSet); bool HadMultipleCandidates = (CandidateSet.size() > 1); @@ -10815,7 +10850,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, Method = cast<CXXMethodDecl>(Best->Function); FoundDecl = Best->FoundDecl; CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl); - DiagnoseUseOfDecl(Best->FoundDecl, UnresExpr->getNameLoc()); + if (DiagnoseUseOfDecl(Best->FoundDecl, UnresExpr->getNameLoc())) + return ExprError(); break; case OR_No_Viable_Function: @@ -10956,7 +10992,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) { AddMethodCandidate(Oper.getPair(), Object.get()->getType(), - Object.get()->Classify(Context), Args, NumArgs, CandidateSet, + Object.get()->Classify(Context), + llvm::makeArrayRef(Args, NumArgs), CandidateSet, /*SuppressUserConversions=*/ false); } @@ -11066,7 +11103,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, Best->Conversions[0].UserDefined.ConversionFunction); CheckMemberOperatorAccess(LParenLoc, Object.get(), 0, Best->FoundDecl); - DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc); + if (DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc)) + return ExprError(); // We selected one of the surrogate functions that converts the // object parameter to a function pointer. Perform the conversion @@ -11248,7 +11286,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) { for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) { AddMethodCandidate(Oper.getPair(), Base->getType(), Base->Classify(Context), - 0, 0, CandidateSet, /*SuppressUserConversions=*/false); + None, CandidateSet, /*SuppressUserConversions=*/false); } bool HadMultipleCandidates = (CandidateSet.size() > 1); @@ -11363,7 +11401,7 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R, // Check the argument types. This should almost always be a no-op, except // that array-to-pointer decay is applied to string literals. Expr *ConvArgs[2]; - for (unsigned ArgIdx = 0; ArgIdx != Args.size(); ++ArgIdx) { + for (unsigned ArgIdx = 0, N = Args.size(); ArgIdx != N; ++ArgIdx) { ExprResult InputInit = PerformCopyInitialization( InitializedEntity::InitializeParameter(Context, FD->getParamDecl(ArgIdx)), SourceLocation(), Args[ArgIdx]); @@ -11420,7 +11458,7 @@ Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc, << RangeLoc << BEF << Range->getType(); return FRS_DiagnosticIssued; } - *CallExpr = ActOnCallExpr(S, MemberRef.get(), Loc, MultiExprArg(), Loc, 0); + *CallExpr = ActOnCallExpr(S, MemberRef.get(), Loc, None, Loc, 0); if (CallExpr->isInvalid()) { *CallExpr = ExprError(); Diag(Range->getLocStart(), diag::note_in_for_range) diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp index b135507..054d557 100644 --- a/lib/Sema/SemaPseudoObject.cpp +++ b/lib/Sema/SemaPseudoObject.cpp @@ -153,6 +153,23 @@ namespace { refExpr->getRBracket()); } }; + + struct MSPropertyRefRebuilder : Rebuilder<MSPropertyRefRebuilder> { + Expr *NewBase; + MSPropertyRefRebuilder(Sema &S, Expr *newBase) + : Rebuilder<MSPropertyRefRebuilder>(S), NewBase(newBase) {} + + typedef MSPropertyRefExpr specific_type; + Expr *rebuildSpecific(MSPropertyRefExpr *refExpr) { + assert(refExpr->getBaseExpr()); + + return new (S.Context) + MSPropertyRefExpr(NewBase, refExpr->getPropertyDecl(), + refExpr->isArrow(), refExpr->getType(), + refExpr->getValueKind(), refExpr->getQualifierLoc(), + refExpr->getMemberLoc()); + } + }; class PseudoOpBuilder { public: @@ -284,6 +301,18 @@ namespace { ExprResult buildSet(Expr *op, SourceLocation, bool); }; + class MSPropertyOpBuilder : public PseudoOpBuilder { + MSPropertyRefExpr *RefExpr; + + public: + MSPropertyOpBuilder(Sema &S, MSPropertyRefExpr *refExpr) : + PseudoOpBuilder(S, refExpr->getSourceRange().getBegin()), + RefExpr(refExpr) {} + + Expr *rebuildAndCaptureObject(Expr *); + ExprResult buildGet(); + ExprResult buildSet(Expr *op, SourceLocation, bool); + }; } /// Capture the given expression in an OpaqueValueExpr. @@ -412,7 +441,8 @@ PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc, QualType resultType = result.get()->getType(); // That's the postfix result. - if (UnaryOperator::isPostfix(opcode) && CanCaptureValueOfType(resultType)) { + if (UnaryOperator::isPostfix(opcode) && + (result.get()->isTypeDependent() || CanCaptureValueOfType(resultType))) { result = capture(result.take()); setResultToLastSemantic(); } @@ -633,12 +663,11 @@ ExprResult ObjCPropertyOpBuilder::buildGet() { assert(InstanceReceiver || RefExpr->isSuperReceiver()); msg = S.BuildInstanceMessageImplicit(InstanceReceiver, receiverType, GenericLoc, Getter->getSelector(), - Getter, MultiExprArg()); + Getter, None); } else { msg = S.BuildClassMessageImplicit(receiverType, RefExpr->isSuperReceiver(), - GenericLoc, - Getter->getSelector(), Getter, - MultiExprArg()); + GenericLoc, Getter->getSelector(), + Getter, None); } return msg; } @@ -1088,8 +1117,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() { /*TInfo=*/0, SC_None, 0); - AtIndexGetter->setMethodParams(S.Context, Argument, - ArrayRef<SourceLocation>()); + AtIndexGetter->setMethodParams(S.Context, Argument, None); } if (!AtIndexGetter) { @@ -1213,7 +1241,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() { SC_None, 0); Params.push_back(key); - AtIndexSetter->setMethodParams(S.Context, Params, ArrayRef<SourceLocation>()); + AtIndexSetter->setMethodParams(S.Context, Params, None); } if (!AtIndexSetter) { @@ -1324,6 +1352,77 @@ ExprResult ObjCSubscriptOpBuilder::buildSet(Expr *op, SourceLocation opcLoc, } //===----------------------------------------------------------------------===// +// MSVC __declspec(property) references +//===----------------------------------------------------------------------===// + +Expr *MSPropertyOpBuilder::rebuildAndCaptureObject(Expr *syntacticBase) { + Expr *NewBase = capture(RefExpr->getBaseExpr()); + + syntacticBase = + MSPropertyRefRebuilder(S, NewBase).rebuild(syntacticBase); + + return syntacticBase; +} + +ExprResult MSPropertyOpBuilder::buildGet() { + if (!RefExpr->getPropertyDecl()->hasGetter()) { + S.Diag(RefExpr->getMemberLoc(), diag::err_no_getter_for_property) + << RefExpr->getPropertyDecl()->getName(); + return ExprError(); + } + + UnqualifiedId GetterName; + IdentifierInfo *II = RefExpr->getPropertyDecl()->getGetterId(); + GetterName.setIdentifier(II, RefExpr->getMemberLoc()); + CXXScopeSpec SS; + SS.Adopt(RefExpr->getQualifierLoc()); + ExprResult GetterExpr = S.ActOnMemberAccessExpr( + S.getCurScope(), RefExpr->getBaseExpr(), SourceLocation(), + RefExpr->isArrow() ? tok::arrow : tok::period, SS, SourceLocation(), + GetterName, 0, true); + if (GetterExpr.isInvalid()) { + S.Diag(RefExpr->getMemberLoc(), diag::error_cannot_find_suitable_getter) + << RefExpr->getPropertyDecl()->getName(); + return ExprError(); + } + + MultiExprArg ArgExprs; + return S.ActOnCallExpr(S.getCurScope(), GetterExpr.take(), + RefExpr->getSourceRange().getBegin(), ArgExprs, + RefExpr->getSourceRange().getEnd()); +} + +ExprResult MSPropertyOpBuilder::buildSet(Expr *op, SourceLocation sl, + bool captureSetValueAsResult) { + if (!RefExpr->getPropertyDecl()->hasSetter()) { + S.Diag(RefExpr->getMemberLoc(), diag::err_no_setter_for_property) + << RefExpr->getPropertyDecl()->getName(); + return ExprError(); + } + + UnqualifiedId SetterName; + IdentifierInfo *II = RefExpr->getPropertyDecl()->getSetterId(); + SetterName.setIdentifier(II, RefExpr->getMemberLoc()); + CXXScopeSpec SS; + SS.Adopt(RefExpr->getQualifierLoc()); + ExprResult SetterExpr = S.ActOnMemberAccessExpr( + S.getCurScope(), RefExpr->getBaseExpr(), SourceLocation(), + RefExpr->isArrow() ? tok::arrow : tok::period, SS, SourceLocation(), + SetterName, 0, true); + if (SetterExpr.isInvalid()) { + S.Diag(RefExpr->getMemberLoc(), diag::error_cannot_find_suitable_setter) + << RefExpr->getPropertyDecl()->getName(); + return ExprError(); + } + + SmallVector<Expr*, 1> ArgExprs; + ArgExprs.push_back(op); + return S.ActOnCallExpr(S.getCurScope(), SetterExpr.take(), + RefExpr->getSourceRange().getBegin(), ArgExprs, + op->getSourceRange().getEnd()); +} + +//===----------------------------------------------------------------------===// // General Sema routines. //===----------------------------------------------------------------------===// @@ -1338,6 +1437,10 @@ ExprResult Sema::checkPseudoObjectRValue(Expr *E) { = dyn_cast<ObjCSubscriptRefExpr>(opaqueRef)) { ObjCSubscriptOpBuilder builder(*this, refExpr); return builder.buildRValueOperation(E); + } else if (MSPropertyRefExpr *refExpr + = dyn_cast<MSPropertyRefExpr>(opaqueRef)) { + MSPropertyOpBuilder builder(*this, refExpr); + return builder.buildRValueOperation(E); } else { llvm_unreachable("unknown pseudo-object kind!"); } @@ -1360,6 +1463,10 @@ ExprResult Sema::checkPseudoObjectIncDec(Scope *Sc, SourceLocation opcLoc, } else if (isa<ObjCSubscriptRefExpr>(opaqueRef)) { Diag(opcLoc, diag::err_illegal_container_subscripting_op); return ExprError(); + } else if (MSPropertyRefExpr *refExpr + = dyn_cast<MSPropertyRefExpr>(opaqueRef)) { + MSPropertyOpBuilder builder(*this, refExpr); + return builder.buildIncDecOperation(Sc, opcLoc, opcode, op); } else { llvm_unreachable("unknown pseudo-object kind!"); } @@ -1389,6 +1496,10 @@ ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc, = dyn_cast<ObjCSubscriptRefExpr>(opaqueRef)) { ObjCSubscriptOpBuilder builder(*this, refExpr); return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS); + } else if (MSPropertyRefExpr *refExpr + = dyn_cast<MSPropertyRefExpr>(opaqueRef)) { + MSPropertyOpBuilder builder(*this, refExpr); + return builder.buildAssignmentOperation(S, opcLoc, opcode, LHS, RHS); } else { llvm_unreachable("unknown pseudo-object kind!"); } @@ -1414,6 +1525,10 @@ static Expr *stripOpaqueValuesFromPseudoObjectRef(Sema &S, Expr *E) { OpaqueValueExpr *keyOVE = cast<OpaqueValueExpr>(refExpr->getKeyExpr()); return ObjCSubscriptRefRebuilder(S, baseOVE->getSourceExpr(), keyOVE->getSourceExpr()).rebuild(E); + } else if (MSPropertyRefExpr *refExpr + = dyn_cast<MSPropertyRefExpr>(opaqueRef)) { + OpaqueValueExpr *baseOVE = cast<OpaqueValueExpr>(refExpr->getBaseExpr()); + return MSPropertyRefRebuilder(S, baseOVE->getSourceExpr()).rebuild(E); } else { llvm_unreachable("unknown pseudo-object kind!"); } diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index ff1db82..248665a 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -22,7 +22,6 @@ #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/TypeLoc.h" -#include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" @@ -77,9 +76,22 @@ StmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, SourceLocation StartLoc, void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) { DeclGroupRef DG = dg.getAsVal<DeclGroupRef>(); - // If we have an invalid decl, just return. - if (DG.isNull() || !DG.isSingleDecl()) return; - VarDecl *var = cast<VarDecl>(DG.getSingleDecl()); + // If we don't have a declaration, or we have an invalid declaration, + // just return. + if (DG.isNull() || !DG.isSingleDecl()) + return; + + Decl *decl = DG.getSingleDecl(); + if (!decl || decl->isInvalidDecl()) + return; + + // Only variable declarations are permitted. + VarDecl *var = dyn_cast<VarDecl>(decl); + if (!var) { + Diag(decl->getLocation(), diag::err_non_variable_decl_in_for); + decl->setInvalidDecl(); + return; + } // suppress any potential 'unused variable' warning. var->setUsed(); @@ -355,7 +367,7 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal, // Recover from an error by just forgetting about it. } } - + LHSVal = ActOnFinishFullExpr(LHSVal, LHSVal->getExprLoc(), false, getLangOpts().CPlusPlus11).take(); if (RHSVal) @@ -1426,9 +1438,10 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, VarDecl *VD = dyn_cast<VarDecl>(*DI); if (VD && VD->isLocalVarDecl() && !VD->hasLocalStorage()) VD = 0; - if (VD == 0) - Diag((*DI)->getLocation(), diag::err_non_variable_decl_in_for); - // FIXME: mark decl erroneous! + if (VD == 0) { + Diag((*DI)->getLocation(), diag::err_non_local_variable_decl_in_for); + (*DI)->setInvalidDecl(); + } } } } @@ -1562,14 +1575,41 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, return StmtError(Diag((*DS->decl_begin())->getLocation(), diag::err_toomany_element_decls)); - VarDecl *D = cast<VarDecl>(DS->getSingleDecl()); + VarDecl *D = dyn_cast<VarDecl>(DS->getSingleDecl()); + if (!D || D->isInvalidDecl()) + return StmtError(); + FirstType = D->getType(); // C99 6.8.5p3: The declaration part of a 'for' statement shall only // declare identifiers for objects having storage class 'auto' or // 'register'. if (!D->hasLocalStorage()) return StmtError(Diag(D->getLocation(), - diag::err_non_variable_decl_in_for)); + diag::err_non_local_variable_decl_in_for)); + + // If the type contained 'auto', deduce the 'auto' to 'id'. + if (FirstType->getContainedAutoType()) { + OpaqueValueExpr OpaqueId(D->getLocation(), Context.getObjCIdType(), + VK_RValue); + Expr *DeducedInit = &OpaqueId; + if (DeduceAutoType(D->getTypeSourceInfo(), DeducedInit, FirstType) == + DAR_Failed) + DiagnoseAutoDeductionFailure(D, DeducedInit); + if (FirstType.isNull()) { + D->setInvalidDecl(); + return StmtError(); + } + + D->setType(FirstType); + + if (ActiveTemplateInstantiations.empty()) { + SourceLocation Loc = + D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(); + Diag(Loc, diag::warn_auto_var_is_id) + << D->getDeclName(); + } + } + } else { Expr *FirstE = cast<Expr>(First); if (!FirstE->isTypeDependent() && !FirstE->isLValue()) @@ -1601,20 +1641,19 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, /// Finish building a variable declaration for a for-range statement. /// \return true if an error occurs. static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init, - SourceLocation Loc, int diag) { + SourceLocation Loc, int DiagID) { // Deduce the type for the iterator variable now rather than leaving it to // AddInitializerToDecl, so we can produce a more suitable diagnostic. - TypeSourceInfo *InitTSI = 0; + QualType InitType; if ((!isa<InitListExpr>(Init) && Init->getType()->isVoidType()) || - SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitTSI) == + SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitType) == Sema::DAR_Failed) - SemaRef.Diag(Loc, diag) << Init->getType(); - if (!InitTSI) { + SemaRef.Diag(Loc, DiagID) << Init->getType(); + if (InitType.isNull()) { Decl->setInvalidDecl(); return true; } - Decl->setTypeSourceInfo(InitTSI); - Decl->setType(InitTSI->getType()); + Decl->setType(InitType); // In ARC, infer lifetime. // FIXME: ARC may want to turn this into 'const __unsafe_unretained' if @@ -1879,7 +1918,15 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, StmtResult BeginEndDecl = BeginEnd; ExprResult NotEqExpr = Cond, IncrExpr = Inc; - if (!BeginEndDecl.get() && !RangeVarType->isDependentType()) { + if (RangeVarType->isDependentType()) { + // The range is implicitly used as a placeholder when it is dependent. + RangeVar->setUsed(); + + // Deduce any 'auto's in the loop variable as 'DependentTy'. We'll fill + // them in properly when we instantiate the loop. + if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) + LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy)); + } else if (!BeginEndDecl.get()) { SourceLocation RangeLoc = RangeVar->getLocation(); const QualType RangeVarNonRefType = RangeVarType.getNonReferenceType(); @@ -1934,6 +1981,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, RangeLoc)); else if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(UnqAT)) + // FIXME: Need to build an OpaqueValueExpr for this rather than + // recomputing it! BoundExpr = VAT->getSizeExpr(); else { // Can't be a DependentSizedArrayType or an IncompleteArrayType since @@ -2064,9 +2113,6 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, if (LoopVar->isInvalidDecl()) NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin); } - } else { - // The range is implicitly used as a placeholder when it is dependent. - RangeVar->setUsed(); } // Don't bother to actually allocate the result if we're just trying to @@ -2263,7 +2309,7 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity, InitializationKind Kind = InitializationKind::CreateCopy(Value->getLocStart(), Value->getLocStart()); - InitializationSequence Seq(*this, Entity, Kind, &InitExpr, 1); + InitializationSequence Seq(*this, Entity, Kind, InitExpr); // [...] If overload resolution fails, or if the type of the first // parameter of the selected constructor is not an rvalue reference @@ -2296,7 +2342,7 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity, // Complete type-checking the initialization of the return type // using the constructor we found. - Res = Seq.Perform(*this, Entity, Kind, MultiExprArg(&Value, 1)); + Res = Seq.Perform(*this, Entity, Kind, Value); } } } @@ -2359,6 +2405,10 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr); return StmtError(); } + } else if (CapturedRegionScopeInfo *CurRegion = + dyn_cast<CapturedRegionScopeInfo>(CurCap)) { + Diag(ReturnLoc, diag::err_return_in_captured_stmt) << CurRegion->getRegionName(); + return StmtError(); } else { LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CurCap); if (LSI->CallOperator->getType()->getAs<FunctionType>()->getNoReturnAttr()){ @@ -2432,12 +2482,80 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { return Owned(Result); } +/// Deduce the return type for a function from a returned expression, per +/// C++1y [dcl.spec.auto]p6. +bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, + SourceLocation ReturnLoc, + Expr *&RetExpr, + AutoType *AT) { + TypeLoc OrigResultType = FD->getTypeSourceInfo()->getTypeLoc(). + IgnoreParens().castAs<FunctionProtoTypeLoc>().getResultLoc(); + QualType Deduced; + + if (RetExpr) { + // If the deduction is for a return statement and the initializer is + // a braced-init-list, the program is ill-formed. + if (isa<InitListExpr>(RetExpr)) { + Diag(RetExpr->getExprLoc(), diag::err_auto_fn_return_init_list); + return true; + } + + // Otherwise, [...] deduce a value for U using the rules of template + // argument deduction. + DeduceAutoResult DAR = DeduceAutoType(OrigResultType, RetExpr, Deduced); + + if (DAR == DAR_Failed && !FD->isInvalidDecl()) + Diag(RetExpr->getExprLoc(), diag::err_auto_fn_deduction_failure) + << OrigResultType.getType() << RetExpr->getType(); + + if (DAR != DAR_Succeeded) + return true; + } else { + // In the case of a return with no operand, the initializer is considered + // to be void(). + // + // Deduction here can only succeed if the return type is exactly 'cv auto' + // or 'decltype(auto)', so just check for that case directly. + if (!OrigResultType.getType()->getAs<AutoType>()) { + Diag(ReturnLoc, diag::err_auto_fn_return_void_but_not_auto) + << OrigResultType.getType(); + return true; + } + // We always deduce U = void in this case. + Deduced = SubstAutoType(OrigResultType.getType(), Context.VoidTy); + if (Deduced.isNull()) + return true; + } + + // If a function with a declared return type that contains a placeholder type + // has multiple return statements, the return type is deduced for each return + // statement. [...] if the type deduced is not the same in each deduction, + // the program is ill-formed. + if (AT->isDeduced() && !FD->isInvalidDecl()) { + AutoType *NewAT = Deduced->getContainedAutoType(); + if (!Context.hasSameType(AT->getDeducedType(), NewAT->getDeducedType())) { + Diag(ReturnLoc, diag::err_auto_fn_different_deductions) + << (AT->isDecltypeAuto() ? 1 : 0) + << NewAT->getDeducedType() << AT->getDeducedType(); + return true; + } + } else if (!FD->isInvalidDecl()) { + // Update all declarations of the function to have the deduced return type. + Context.adjustDeducedFunctionResultType(FD, Deduced); + } + + return false; +} + StmtResult Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // Check for unexpanded parameter packs. if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp)) return StmtError(); + // FIXME: Unify this and C++1y auto function handling. In particular, we + // should allow 'return { 1, 2, 3 };' in a lambda to deduce + // 'std::initializer_list<int>'. if (isa<CapturingScopeInfo>(getCurFunction())) return ActOnCapScopeReturnStmt(ReturnLoc, RetValExp); @@ -2460,6 +2578,23 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { } else // If we don't have a function/method context, bail. return StmtError(); + // FIXME: Add a flag to the ScopeInfo to indicate whether we're performing + // deduction. + bool HasDependentReturnType = FnRetType->isDependentType(); + if (getLangOpts().CPlusPlus1y) { + if (AutoType *AT = FnRetType->getContainedAutoType()) { + FunctionDecl *FD = cast<FunctionDecl>(CurContext); + if (CurContext->isDependentContext()) + HasDependentReturnType = true; + else if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) { + FD->setInvalidDecl(); + return StmtError(); + } else { + FnRetType = FD->getResultType(); + } + } + } + ReturnStmt *Result = 0; if (FnRetType->isVoidType()) { if (RetValExp) { @@ -2525,7 +2660,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { } Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0); - } else if (!RetValExp && !FnRetType->isDependentType()) { + } else if (!RetValExp && !HasDependentReturnType) { unsigned DiagID = diag::warn_return_missing_expr; // C90 6.6.6.4p4 // C99 6.8.6.4p1 (ext_ since GCC warns) if (getLangOpts().C99) DiagID = diag::ext_return_missing_expr; @@ -2536,9 +2671,9 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/; Result = new (Context) ReturnStmt(ReturnLoc); } else { - assert(RetValExp || FnRetType->isDependentType()); + assert(RetValExp || HasDependentReturnType); const VarDecl *NRVOCandidate = 0; - if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) { + if (!HasDependentReturnType && !RetValExp->isTypeDependent()) { // we have a non-void function with an expression, continue checking QualType RetType = (RelatedRetType.isNull() ? FnRetType : RelatedRetType); @@ -2870,3 +3005,124 @@ StmtResult Sema::ActOnMSDependentExistsStmt(SourceLocation KeywordLoc, GetNameFromUnqualifiedId(Name), Nested); } + +RecordDecl* +Sema::CreateCapturedStmtRecordDecl(CapturedDecl *&CD, SourceLocation Loc, + unsigned NumParams) { + DeclContext *DC = CurContext; + while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext())) + DC = DC->getParent(); + + RecordDecl *RD = 0; + if (getLangOpts().CPlusPlus) + RD = CXXRecordDecl::Create(Context, TTK_Struct, DC, Loc, Loc, /*Id=*/0); + else + RD = RecordDecl::Create(Context, TTK_Struct, DC, Loc, Loc, /*Id=*/0); + + DC->addDecl(RD); + RD->setImplicit(); + RD->startDefinition(); + + CD = CapturedDecl::Create(Context, CurContext, NumParams); + DC->addDecl(CD); + + // Build the context parameter + assert(NumParams > 0 && "CapturedStmt requires context parameter"); + DC = CapturedDecl::castToDeclContext(CD); + IdentifierInfo *VarName = &Context.Idents.get("__context"); + QualType ParamType = Context.getPointerType(Context.getTagDeclType(RD)); + ImplicitParamDecl *Param + = ImplicitParamDecl::Create(Context, DC, Loc, VarName, ParamType); + DC->addDecl(Param); + + CD->setContextParam(Param); + + return RD; +} + +static void buildCapturedStmtCaptureList( + SmallVectorImpl<CapturedStmt::Capture> &Captures, + SmallVectorImpl<Expr *> &CaptureInits, + ArrayRef<CapturingScopeInfo::Capture> Candidates) { + + typedef ArrayRef<CapturingScopeInfo::Capture>::const_iterator CaptureIter; + for (CaptureIter Cap = Candidates.begin(); Cap != Candidates.end(); ++Cap) { + + if (Cap->isThisCapture()) { + Captures.push_back(CapturedStmt::Capture(Cap->getLocation(), + CapturedStmt::VCK_This)); + CaptureInits.push_back(Cap->getCopyExpr()); + continue; + } + + assert(Cap->isReferenceCapture() && + "non-reference capture not yet implemented"); + + Captures.push_back(CapturedStmt::Capture(Cap->getLocation(), + CapturedStmt::VCK_ByRef, + Cap->getVariable())); + CaptureInits.push_back(Cap->getCopyExpr()); + } +} + +void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, + CapturedRegionKind Kind, + unsigned NumParams) { + CapturedDecl *CD = 0; + RecordDecl *RD = CreateCapturedStmtRecordDecl(CD, Loc, NumParams); + + // Enter the capturing scope for this captured region. + PushCapturedRegionScope(CurScope, CD, RD, Kind); + + if (CurScope) + PushDeclContext(CurScope, CD); + else + CurContext = CD; + + PushExpressionEvaluationContext(PotentiallyEvaluated); +} + +void Sema::ActOnCapturedRegionError() { + DiscardCleanupsInEvaluationContext(); + PopExpressionEvaluationContext(); + + CapturedRegionScopeInfo *RSI = getCurCapturedRegion(); + RecordDecl *Record = RSI->TheRecordDecl; + Record->setInvalidDecl(); + + SmallVector<Decl*, 4> Fields; + for (RecordDecl::field_iterator I = Record->field_begin(), + E = Record->field_end(); I != E; ++I) + Fields.push_back(*I); + ActOnFields(/*Scope=*/0, Record->getLocation(), Record, Fields, + SourceLocation(), SourceLocation(), /*AttributeList=*/0); + + PopDeclContext(); + PopFunctionScopeInfo(); +} + +StmtResult Sema::ActOnCapturedRegionEnd(Stmt *S) { + CapturedRegionScopeInfo *RSI = getCurCapturedRegion(); + + SmallVector<CapturedStmt::Capture, 4> Captures; + SmallVector<Expr *, 4> CaptureInits; + buildCapturedStmtCaptureList(Captures, CaptureInits, RSI->Captures); + + CapturedDecl *CD = RSI->TheCapturedDecl; + RecordDecl *RD = RSI->TheRecordDecl; + + CapturedStmt *Res = CapturedStmt::Create(getASTContext(), S, + RSI->CapRegionKind, Captures, + CaptureInits, CD, RD); + + CD->setBody(Res->getCapturedStmt()); + RD->completeDefinition(); + + DiscardCleanupsInEvaluationContext(); + PopExpressionEvaluationContext(); + + PopDeclContext(); + PopFunctionScopeInfo(); + + return Owned(Res); +} diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp index da33bdf..fce95be 100644 --- a/lib/Sema/SemaStmtAsm.cpp +++ b/lib/Sema/SemaStmtAsm.cpp @@ -22,18 +22,6 @@ #include "clang/Sema/ScopeInfo.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCObjectFileInfo.h" -#include "llvm/MC/MCParser/MCAsmParser.h" -#include "llvm/MC/MCRegisterInfo.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCSubtargetInfo.h" -#include "llvm/MC/MCTargetAsmParser.h" -#include "llvm/Support/SourceMgr.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/TargetSelect.h" using namespace clang; using namespace sema; @@ -381,158 +369,60 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, return Owned(NS); } -// getSpelling - Get the spelling of the AsmTok token. -static StringRef getSpelling(Sema &SemaRef, Token AsmTok) { - StringRef Asm; - SmallString<512> TokenBuf; - TokenBuf.resize(512); - bool StringInvalid = false; - Asm = SemaRef.PP.getSpelling(AsmTok, TokenBuf, &StringInvalid); - assert (!StringInvalid && "Expected valid string!"); - return Asm; -} +ExprResult Sema::LookupInlineAsmIdentifier(CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + UnqualifiedId &Id, + InlineAsmIdentifierInfo &Info, + bool IsUnevaluatedContext) { + Info.clear(); -// Build the inline assembly string. Returns true on error. -static bool buildMSAsmString(Sema &SemaRef, - SourceLocation AsmLoc, - ArrayRef<Token> AsmToks, - SmallVectorImpl<unsigned> &TokOffsets, - std::string &AsmString) { - assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!"); - - SmallString<512> Asm; - for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) { - bool isNewAsm = ((i == 0) || - AsmToks[i].isAtStartOfLine() || - AsmToks[i].is(tok::kw_asm)); - if (isNewAsm) { - if (i != 0) - Asm += "\n\t"; - - if (AsmToks[i].is(tok::kw_asm)) { - i++; // Skip __asm - if (i == e) { - SemaRef.Diag(AsmLoc, diag::err_asm_empty); - return true; - } + if (IsUnevaluatedContext) + PushExpressionEvaluationContext(UnevaluatedAbstract, + ReuseLambdaContextDecl); - } - } + ExprResult Result = ActOnIdExpression(getCurScope(), SS, TemplateKWLoc, Id, + /*trailing lparen*/ false, + /*is & operand*/ false); - if (i && AsmToks[i].hasLeadingSpace() && !isNewAsm) - Asm += ' '; + if (IsUnevaluatedContext) + PopExpressionEvaluationContext(); - StringRef Spelling = getSpelling(SemaRef, AsmToks[i]); - Asm += Spelling; - TokOffsets.push_back(Asm.size()); - } - AsmString = Asm.str(); - return false; -} + if (!Result.isUsable()) return Result; -namespace { - -class MCAsmParserSemaCallbackImpl : public llvm::MCAsmParserSemaCallback { - Sema &SemaRef; - SourceLocation AsmLoc; - ArrayRef<Token> AsmToks; - ArrayRef<unsigned> TokOffsets; - -public: - MCAsmParserSemaCallbackImpl(Sema &Ref, SourceLocation Loc, - ArrayRef<Token> Toks, - ArrayRef<unsigned> Offsets) - : SemaRef(Ref), AsmLoc(Loc), AsmToks(Toks), TokOffsets(Offsets) { } - ~MCAsmParserSemaCallbackImpl() {} - - void *LookupInlineAsmIdentifier(StringRef Name, void *SrcLoc, - unsigned &Length, unsigned &Size, - unsigned &Type, bool &IsVarDecl){ - SourceLocation Loc = SourceLocation::getFromPtrEncoding(SrcLoc); - - NamedDecl *OpDecl = SemaRef.LookupInlineAsmIdentifier(Name, Loc, Length, - Size, Type, - IsVarDecl); - return static_cast<void *>(OpDecl); - } + Result = CheckPlaceholderExpr(Result.take()); + if (!Result.isUsable()) return Result; - bool LookupInlineAsmField(StringRef Base, StringRef Member, - unsigned &Offset) { - return SemaRef.LookupInlineAsmField(Base, Member, Offset, AsmLoc); - } + QualType T = Result.get()->getType(); - static void MSAsmDiagHandlerCallback(const llvm::SMDiagnostic &D, - void *Context) { - ((MCAsmParserSemaCallbackImpl*)Context)->MSAsmDiagHandler(D); - } - void MSAsmDiagHandler(const llvm::SMDiagnostic &D) { - // Compute an offset into the inline asm buffer. - // FIXME: This isn't right if .macro is involved (but hopefully, no - // real-world code does that). - const llvm::SourceMgr &LSM = *D.getSourceMgr(); - const llvm::MemoryBuffer *LBuf = - LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc())); - unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart(); - - // Figure out which token that offset points into. - const unsigned *OffsetPtr = - std::lower_bound(TokOffsets.begin(), TokOffsets.end(), Offset); - unsigned TokIndex = OffsetPtr - TokOffsets.begin(); - - // If we come up with an answer which seems sane, use it; otherwise, - // just point at the __asm keyword. - // FIXME: Assert the answer is sane once we handle .macro correctly. - SourceLocation Loc = AsmLoc; - if (TokIndex < AsmToks.size()) { - const Token *Tok = &AsmToks[TokIndex]; - Loc = Tok->getLocation(); - Loc = Loc.getLocWithOffset(Offset - (*OffsetPtr - Tok->getLength())); - } - SemaRef.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage(); + // For now, reject dependent types. + if (T->isDependentType()) { + Diag(Id.getLocStart(), diag::err_asm_incomplete_type) << T; + return ExprError(); } -}; -} - -NamedDecl *Sema::LookupInlineAsmIdentifier(StringRef Name, SourceLocation Loc, - unsigned &Length, unsigned &Size, - unsigned &Type, bool &IsVarDecl) { - Length = 1; - Size = 0; - Type = 0; - IsVarDecl = false; - LookupResult Result(*this, &Context.Idents.get(Name), Loc, - Sema::LookupOrdinaryName); - - if (!LookupName(Result, getCurScope())) { - // If we don't find anything, return null; the AsmParser will assume - // it is a label of some sort. - return 0; + // Any sort of function type is fine. + if (T->isFunctionType()) { + return Result; } - if (!Result.isSingleResult()) { - // FIXME: Diagnose result. - return 0; + // Otherwise, it needs to be a complete type. + if (RequireCompleteExprType(Result.get(), diag::err_asm_incomplete_type)) { + return ExprError(); } - NamedDecl *FoundDecl = Result.getFoundDecl(); - if (isa<FunctionDecl>(FoundDecl)) - return FoundDecl; - if (VarDecl *Var = dyn_cast<VarDecl>(FoundDecl)) { - QualType Ty = Var->getType(); - Type = Size = Context.getTypeSizeInChars(Ty).getQuantity(); - if (Ty->isArrayType()) { - const ArrayType *ATy = Context.getAsArrayType(Ty); - Type = Context.getTypeSizeInChars(ATy->getElementType()).getQuantity(); - Length = Size / Type; - } - IsVarDecl = true; - return FoundDecl; + // Compute the type size (and array length if applicable?). + Info.Type = Info.Size = Context.getTypeSizeInChars(T).getQuantity(); + if (T->isArrayType()) { + const ArrayType *ATy = Context.getAsArrayType(T); + Info.Type = Context.getTypeSizeInChars(ATy->getElementType()).getQuantity(); + Info.Length = Info.Size / Info.Type; } - // FIXME: Handle other kinds of results? (FieldDecl, etc.) - // FIXME: Diagnose if we find something we can't handle, like a typedef. - return 0; + // We can work with the expression as long as it's not an r-value. + if (!Result.get()->isRValue()) + Info.IsVarDecl = true; + + return Result; } bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member, @@ -579,124 +469,18 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member, } StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, - ArrayRef<Token> AsmToks,SourceLocation EndLoc) { - SmallVector<IdentifierInfo*, 4> Names; - SmallVector<StringRef, 4> ConstraintRefs; - SmallVector<Expr*, 4> Exprs; - SmallVector<StringRef, 4> ClobberRefs; - - llvm::Triple TheTriple = Context.getTargetInfo().getTriple(); - llvm::Triple::ArchType ArchTy = TheTriple.getArch(); - bool UnsupportedArch = ArchTy != llvm::Triple::x86 && - ArchTy != llvm::Triple::x86_64; - if (UnsupportedArch) - Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName(); - - // Empty asm statements don't need to instantiate the AsmParser, etc. - if (UnsupportedArch || AsmToks.empty()) { - StringRef EmptyAsmStr; - MSAsmStmt *NS = - new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true, - /*IsVolatile*/ true, AsmToks, /*NumOutputs*/ 0, - /*NumInputs*/ 0, Names, ConstraintRefs, Exprs, - EmptyAsmStr, ClobberRefs, EndLoc); - return Owned(NS); - } - - std::string AsmString; - SmallVector<unsigned, 8> TokOffsets; - if (buildMSAsmString(*this, AsmLoc, AsmToks, TokOffsets, AsmString)) - return StmtError(); - - // Get the target specific parser. - std::string Error; - const std::string &TT = TheTriple.getTriple(); - const llvm::Target *TheTarget(llvm::TargetRegistry::lookupTarget(TT, Error)); - - OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TT)); - OwningPtr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT)); - OwningPtr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo()); - OwningPtr<llvm::MCSubtargetInfo> - STI(TheTarget->createMCSubtargetInfo(TT, "", "")); - - llvm::SourceMgr SrcMgr; - llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr); - llvm::MemoryBuffer *Buffer = - llvm::MemoryBuffer::getMemBuffer(AsmString, "<inline asm>"); - - // Tell SrcMgr about this buffer, which is what the parser will pick up. - SrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc()); - - OwningPtr<llvm::MCStreamer> Str(createNullStreamer(Ctx)); - OwningPtr<llvm::MCAsmParser> - Parser(createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI)); - OwningPtr<llvm::MCTargetAsmParser> - TargetParser(TheTarget->createMCAsmParser(*STI, *Parser)); - - // Get the instruction descriptor. - const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo(); - llvm::MCInstPrinter *IP = - TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI); - - // Change to the Intel dialect. - Parser->setAssemblerDialect(1); - Parser->setTargetParser(*TargetParser.get()); - Parser->setParsingInlineAsm(true); - TargetParser->setParsingInlineAsm(true); - - MCAsmParserSemaCallbackImpl MCAPSI(*this, AsmLoc, AsmToks, TokOffsets); - TargetParser->setSemaCallback(&MCAPSI); - SrcMgr.setDiagHandler(MCAsmParserSemaCallbackImpl::MSAsmDiagHandlerCallback, - &MCAPSI); - - unsigned NumOutputs; - unsigned NumInputs; - std::string AsmStringIR; - SmallVector<std::pair<void *, bool>, 4> OpDecls; - SmallVector<std::string, 4> Constraints; - SmallVector<std::string, 4> Clobbers; - if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR, - NumOutputs, NumInputs, OpDecls, Constraints, - Clobbers, MII, IP, MCAPSI)) - return StmtError(); - - // Build the vector of clobber StringRefs. - unsigned NumClobbers = Clobbers.size(); - ClobberRefs.resize(NumClobbers); - for (unsigned i = 0; i != NumClobbers; ++i) - ClobberRefs[i] = StringRef(Clobbers[i]); - - // Recast the void pointers and build the vector of constraint StringRefs. - unsigned NumExprs = NumOutputs + NumInputs; - Names.resize(NumExprs); - ConstraintRefs.resize(NumExprs); - Exprs.resize(NumExprs); - for (unsigned i = 0, e = NumExprs; i != e; ++i) { - NamedDecl *OpDecl = static_cast<NamedDecl *>(OpDecls[i].first); - if (!OpDecl) - return StmtError(); - - DeclarationNameInfo NameInfo(OpDecl->getDeclName(), AsmLoc); - ExprResult OpExpr = BuildDeclarationNameExpr(CXXScopeSpec(), NameInfo, - OpDecl); - if (OpExpr.isInvalid()) - return StmtError(); - - // Need address of variable. - if (OpDecls[i].second) - OpExpr = BuildUnaryOp(getCurScope(), AsmLoc, clang::UO_AddrOf, - OpExpr.take()); - - Names[i] = OpDecl->getIdentifier(); - ConstraintRefs[i] = StringRef(Constraints[i]); - Exprs[i] = OpExpr.take(); - } - - bool IsSimple = NumExprs > 0; + ArrayRef<Token> AsmToks, + StringRef AsmString, + unsigned NumOutputs, unsigned NumInputs, + ArrayRef<StringRef> Constraints, + ArrayRef<StringRef> Clobbers, + ArrayRef<Expr*> Exprs, + SourceLocation EndLoc) { + bool IsSimple = (NumOutputs != 0 || NumInputs != 0); MSAsmStmt *NS = new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple, /*IsVolatile*/ true, AsmToks, NumOutputs, NumInputs, - Names, ConstraintRefs, Exprs, AsmStringIR, - ClobberRefs, EndLoc); + Constraints, Exprs, AsmString, + Clobbers, EndLoc); return Owned(NS); } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 9906261..b9695cc 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3842,8 +3842,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, } // A template argument must have static storage duration. - // FIXME: Ensure this works for thread_local as well as __thread. - if (Var->isThreadSpecified()) { + if (Var->getTLSKind()) { S.Diag(Arg->getLocStart(), diag::err_template_arg_thread_local) << Arg->getSourceRange(); S.Diag(Var->getLocation(), diag::note_template_arg_refers_here); @@ -6461,6 +6460,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, // Set source locations for keywords. Specialization->setExternLoc(ExternLoc); Specialization->setTemplateKeywordLoc(TemplateLoc); + Specialization->setRBraceLoc(SourceLocation()); if (Attr) ProcessDeclAttributeList(S, Specialization, Attr); diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index f3bbe8a..8efc7a0 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -52,7 +52,11 @@ namespace clang { TDF_SkipNonDependent = 0x08, /// \brief Whether we are performing template argument deduction for /// parameters and arguments in a top-level template argument - TDF_TopLevelParameterTypeList = 0x10 + TDF_TopLevelParameterTypeList = 0x10, + /// \brief Within template argument deduction from overload resolution per + /// C++ [over.over] allow matching function types that are compatible in + /// terms of noreturn and default calling convention adjustments. + TDF_InOverloadResolution = 0x20 }; } @@ -867,6 +871,32 @@ static bool hasInconsistentOrSupersetQualifiersOf(QualType ParamType, == ParamQs.getCVRQualifiers()); } +/// \brief Compare types for equality with respect to possibly compatible +/// function types (noreturn adjustment, implicit calling conventions). If any +/// of parameter and argument is not a function, just perform type comparison. +/// +/// \param Param the template parameter type. +/// +/// \param Arg the argument type. +bool Sema::isSameOrCompatibleFunctionType(CanQualType Param, + CanQualType Arg) { + const FunctionType *ParamFunction = Param->getAs<FunctionType>(), + *ArgFunction = Arg->getAs<FunctionType>(); + + // Just compare if not functions. + if (!ParamFunction || !ArgFunction) + return Param == Arg; + + // Noreturn adjustment. + QualType AdjustedParam; + if (IsNoReturnConversion(Param, Arg, AdjustedParam)) + return Arg == Context.getCanonicalType(AdjustedParam); + + // FIXME: Compatible calling conventions. + + return Param == Arg; +} + /// \brief Deduce the template arguments by comparing the parameter type and /// the argument type (C++ [temp.deduct.type]). /// @@ -1103,6 +1133,8 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, return Sema::TDK_Success; // Check the cv-qualifiers on the parameter and argument types. + CanQualType CanParam = S.Context.getCanonicalType(Param); + CanQualType CanArg = S.Context.getCanonicalType(Arg); if (!(TDF & TDF_IgnoreQualifiers)) { if (TDF & TDF_ParamWithReferenceType) { if (hasInconsistentOrSupersetQualifiersOf(Param, Arg)) @@ -1114,14 +1146,25 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // If the parameter type is not dependent, there is nothing to deduce. if (!Param->isDependentType()) { - if (!(TDF & TDF_SkipNonDependent) && Param != Arg) - return Sema::TDK_NonDeducedMismatch; - + if (!(TDF & TDF_SkipNonDependent)) { + bool NonDeduced = (TDF & TDF_InOverloadResolution)? + !S.isSameOrCompatibleFunctionType(CanParam, CanArg) : + Param != Arg; + if (NonDeduced) { + return Sema::TDK_NonDeducedMismatch; + } + } return Sema::TDK_Success; } - } else if (!Param->isDependentType() && - Param.getUnqualifiedType() == Arg.getUnqualifiedType()) { - return Sema::TDK_Success; + } else if (!Param->isDependentType()) { + CanQualType ParamUnqualType = CanParam.getUnqualifiedType(), + ArgUnqualType = CanArg.getUnqualifiedType(); + bool Success = (TDF & TDF_InOverloadResolution)? + S.isSameOrCompatibleFunctionType(ParamUnqualType, + ArgUnqualType) : + ParamUnqualType == ArgUnqualType; + if (Success) + return Sema::TDK_Success; } switch (Param->getTypeClass()) { @@ -2761,21 +2804,25 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, /// Gets the type of a function for template-argument-deducton /// purposes when it's considered as part of an overload set. -static QualType GetTypeOfFunction(ASTContext &Context, - const OverloadExpr::FindResult &R, +static QualType GetTypeOfFunction(Sema &S, const OverloadExpr::FindResult &R, FunctionDecl *Fn) { + // We may need to deduce the return type of the function now. + if (S.getLangOpts().CPlusPlus1y && Fn->getResultType()->isUndeducedType() && + S.DeduceReturnType(Fn, R.Expression->getExprLoc(), /*Diagnose*/false)) + return QualType(); + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) if (Method->isInstance()) { // An instance method that's referenced in a form that doesn't // look like a member pointer is just invalid. if (!R.HasFormOfMemberPointer) return QualType(); - return Context.getMemberPointerType(Fn->getType(), - Context.getTypeDeclType(Method->getParent()).getTypePtr()); + return S.Context.getMemberPointerType(Fn->getType(), + S.Context.getTypeDeclType(Method->getParent()).getTypePtr()); } if (!R.IsAddressOfOperand) return Fn->getType(); - return Context.getPointerType(Fn->getType()); + return S.Context.getPointerType(Fn->getType()); } /// Apply the deduction rules for overload sets. @@ -2809,7 +2856,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, // But we can still look for an explicit specialization. if (FunctionDecl *ExplicitSpec = S.ResolveSingleFunctionTemplateSpecialization(Ovl)) - return GetTypeOfFunction(S.Context, R, ExplicitSpec); + return GetTypeOfFunction(S, R, ExplicitSpec); } return QualType(); @@ -2842,7 +2889,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, } FunctionDecl *Fn = cast<FunctionDecl>(D); - QualType ArgType = GetTypeOfFunction(S.Context, R, Fn); + QualType ArgType = GetTypeOfFunction(S, R, Fn); if (ArgType.isNull()) continue; // Function-to-pointer conversion. @@ -3316,7 +3363,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ArgFunctionType, FunctionDecl *&Specialization, - TemplateDeductionInfo &Info) { + TemplateDeductionInfo &Info, + bool InOverloadResolution) { if (FunctionTemplate->isInvalidDecl()) return TDK_Invalid; @@ -3347,12 +3395,23 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, Deduced.resize(TemplateParams->size()); + // If the function has a deduced return type, substitute it for a dependent + // type so that we treat it as a non-deduced context in what follows. + bool HasUndeducedReturnType = false; + if (getLangOpts().CPlusPlus1y && InOverloadResolution && + Function->getResultType()->isUndeducedType()) { + FunctionType = SubstAutoType(FunctionType, Context.DependentTy); + HasUndeducedReturnType = true; + } + if (!ArgFunctionType.isNull()) { + unsigned TDF = TDF_TopLevelParameterTypeList; + if (InOverloadResolution) TDF |= TDF_InOverloadResolution; // Deduce template arguments from the function type. if (TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams, - FunctionType, ArgFunctionType, Info, - Deduced, TDF_TopLevelParameterTypeList)) + FunctionType, ArgFunctionType, + Info, Deduced, TDF)) return Result; } @@ -3362,12 +3421,26 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, Specialization, Info)) return Result; - // If the requested function type does not match the actual type of the - // specialization, template argument deduction fails. - if (!ArgFunctionType.isNull() && - !Context.hasSameType(ArgFunctionType, Specialization->getType())) + // If the function has a deduced return type, deduce it now, so we can check + // that the deduced function type matches the requested type. + if (HasUndeducedReturnType && + Specialization->getResultType()->isUndeducedType() && + DeduceReturnType(Specialization, Info.getLocation(), false)) return TDK_MiscellaneousDeductionFailure; + // If the requested function type does not match the actual type of the + // specialization with respect to arguments of compatible pointer to function + // types, template argument deduction fails. + if (!ArgFunctionType.isNull()) { + if (InOverloadResolution && !isSameOrCompatibleFunctionType( + Context.getCanonicalType(Specialization->getType()), + Context.getCanonicalType(ArgFunctionType))) + return TDK_MiscellaneousDeductionFailure; + else if(!InOverloadResolution && + !Context.hasSameType(Specialization->getType(), ArgFunctionType)) + return TDK_MiscellaneousDeductionFailure; + } + return TDK_Success; } @@ -3499,9 +3572,11 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo *ExplicitTemplateArgs, FunctionDecl *&Specialization, - TemplateDeductionInfo &Info) { + TemplateDeductionInfo &Info, + bool InOverloadResolution) { return DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs, - QualType(), Specialization, Info); + QualType(), Specialization, Info, + InOverloadResolution); } namespace { @@ -3522,13 +3597,19 @@ namespace { // auto &&lref = lvalue; // must transform into "rvalue reference to T" not "rvalue reference to // auto type deduced as T" in order for [temp.deduct.call]p3 to apply. - if (isa<TemplateTypeParmType>(Replacement)) { + if (!Replacement.isNull() && isa<TemplateTypeParmType>(Replacement)) { QualType Result = Replacement; - TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result); + TemplateTypeParmTypeLoc NewTL = + TLB.push<TemplateTypeParmTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; } else { - QualType Result = RebuildAutoType(Replacement); + bool Dependent = + !Replacement.isNull() && Replacement->isDependentType(); + QualType Result = + SemaRef.Context.getAutoType(Dependent ? QualType() : Replacement, + TL.getTypePtr()->isDecltypeAuto(), + Dependent); AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; @@ -3539,69 +3620,63 @@ namespace { // Lambdas never need to be transformed. return E; } - }; - /// Determine whether the specified type (which contains an 'auto' type - /// specifier) is dependent. This is not trivial, because the 'auto' specifier - /// itself claims to be type-dependent. - bool isDependentAutoType(QualType Ty) { - while (1) { - QualType Pointee = Ty->getPointeeType(); - if (!Pointee.isNull()) { - Ty = Pointee; - } else if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>()){ - if (MPT->getClass()->isDependentType()) - return true; - Ty = MPT->getPointeeType(); - } else if (const FunctionProtoType *FPT = Ty->getAs<FunctionProtoType>()){ - for (FunctionProtoType::arg_type_iterator I = FPT->arg_type_begin(), - E = FPT->arg_type_end(); - I != E; ++I) - if ((*I)->isDependentType()) - return true; - Ty = FPT->getResultType(); - } else if (Ty->isDependentSizedArrayType()) { - return true; - } else if (const ArrayType *AT = Ty->getAsArrayTypeUnsafe()) { - Ty = AT->getElementType(); - } else if (Ty->getAs<DependentSizedExtVectorType>()) { - return true; - } else if (const VectorType *VT = Ty->getAs<VectorType>()) { - Ty = VT->getElementType(); - } else { - break; - } + QualType Apply(TypeLoc TL) { + // Create some scratch storage for the transformed type locations. + // FIXME: We're just going to throw this information away. Don't build it. + TypeLocBuilder TLB; + TLB.reserve(TL.getFullDataSize()); + return TransformType(TLB, TL); } - assert(Ty->getAs<AutoType>() && "didn't find 'auto' in auto type"); - return false; - } + }; +} + +Sema::DeduceAutoResult +Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result) { + return DeduceAutoType(Type->getTypeLoc(), Init, Result); } -/// \brief Deduce the type for an auto type-specifier (C++0x [dcl.spec.auto]p6) +/// \brief Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6) /// /// \param Type the type pattern using the auto type-specifier. -/// /// \param Init the initializer for the variable whose type is to be deduced. -/// /// \param Result if type deduction was successful, this will be set to the -/// deduced type. This may still contain undeduced autos if the type is -/// dependent. This will be set to null if deduction succeeded, but auto -/// substitution failed; the appropriate diagnostic will already have been -/// produced in that case. +/// deduced type. Sema::DeduceAutoResult -Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, - TypeSourceInfo *&Result) { +Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) { if (Init->getType()->isNonOverloadPlaceholderType()) { - ExprResult result = CheckPlaceholderExpr(Init); - if (result.isInvalid()) return DAR_FailedAlreadyDiagnosed; - Init = result.take(); + ExprResult NonPlaceholder = CheckPlaceholderExpr(Init); + if (NonPlaceholder.isInvalid()) + return DAR_FailedAlreadyDiagnosed; + Init = NonPlaceholder.take(); } - if (Init->isTypeDependent() || isDependentAutoType(Type->getType())) { - Result = Type; + if (Init->isTypeDependent() || Type.getType()->isDependentType()) { + Result = SubstituteAutoTransform(*this, Context.DependentTy).Apply(Type); + assert(!Result.isNull() && "substituting DependentTy can't fail"); return DAR_Succeeded; } + // If this is a 'decltype(auto)' specifier, do the decltype dance. + // Since 'decltype(auto)' can only occur at the top of the type, we + // don't need to go digging for it. + if (const AutoType *AT = Type.getType()->getAs<AutoType>()) { + if (AT->isDecltypeAuto()) { + if (isa<InitListExpr>(Init)) { + Diag(Init->getLocStart(), diag::err_decltype_auto_initializer_list); + return DAR_FailedAlreadyDiagnosed; + } + + QualType Deduced = BuildDecltypeType(Init, Init->getLocStart()); + // FIXME: Support a non-canonical deduced type for 'auto'. + Deduced = Context.getCanonicalType(Deduced); + Result = SubstituteAutoTransform(*this, Deduced).Apply(Type); + if (Result.isNull()) + return DAR_FailedAlreadyDiagnosed; + return DAR_Succeeded; + } + } + SourceLocation Loc = Init->getExprLoc(); LocalInstantiationScope InstScope(*this); @@ -3615,10 +3690,9 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, FixedSizeTemplateParameterList<1> TemplateParams(Loc, Loc, &TemplParamPtr, Loc); - TypeSourceInfo *FuncParamInfo = - SubstituteAutoTransform(*this, TemplArg).TransformType(Type); - assert(FuncParamInfo && "substituting template parameter for 'auto' failed"); - QualType FuncParam = FuncParamInfo->getType(); + QualType FuncParam = SubstituteAutoTransform(*this, TemplArg).Apply(Type); + assert(!FuncParam.isNull() && + "substituting template parameter for 'auto' failed"); // Deduce type of TemplParam in Func(Init) SmallVector<DeducedTemplateArgument, 1> Deduced; @@ -3659,21 +3733,27 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, return DAR_FailedAlreadyDiagnosed; } - Result = SubstituteAutoTransform(*this, DeducedType).TransformType(Type); + Result = SubstituteAutoTransform(*this, DeducedType).Apply(Type); + if (Result.isNull()) + return DAR_FailedAlreadyDiagnosed; // Check that the deduced argument type is compatible with the original // argument type per C++ [temp.deduct.call]p4. - if (!InitList && Result && - CheckOriginalCallArgDeduction(*this, + if (!InitList && !Result.isNull() && + CheckOriginalCallArgDeduction(*this, Sema::OriginalCallArg(FuncParam,0,InitType), - Result->getType())) { - Result = 0; + Result)) { + Result = QualType(); return DAR_Failed; } return DAR_Succeeded; } +QualType Sema::SubstAutoType(QualType Type, QualType Deduced) { + return SubstituteAutoTransform(*this, Deduced).TransformType(Type); +} + void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) { if (isa<InitListExpr>(Init)) Diag(VDecl->getLocation(), @@ -3685,6 +3765,22 @@ void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) { << Init->getSourceRange(); } +bool Sema::DeduceReturnType(FunctionDecl *FD, SourceLocation Loc, + bool Diagnose) { + assert(FD->getResultType()->isUndeducedType()); + + if (FD->getTemplateInstantiationPattern()) + InstantiateFunctionDefinition(Loc, FD); + + bool StillUndeduced = FD->getResultType()->isUndeducedType(); + if (StillUndeduced && Diagnose && !FD->isInvalidDecl()) { + Diag(Loc, diag::err_auto_fn_used_before_defined) << FD; + Diag(FD->getLocation(), diag::note_callee_decl) << FD; + } + + return StillUndeduced; +} + static void MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, bool OnlyDeduced, @@ -4053,7 +4149,7 @@ static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) { /// template argument deduction. UnresolvedSetIterator Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin, - UnresolvedSetIterator SpecEnd, + UnresolvedSetIterator SpecEnd, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments, SourceLocation Loc, @@ -4110,11 +4206,10 @@ Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin, } // Diagnose the ambiguity. - if (Complain) + if (Complain) { Diag(Loc, AmbigDiag); - if (Complain) - // FIXME: Can we order the candidates in some sane way? + // FIXME: Can we order the candidates in some sane way? for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I) { PartialDiagnostic PD = CandidateDiag; PD << getTemplateArgumentBindingsText( @@ -4125,6 +4220,7 @@ Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin, TargetType); Diag((*I)->getLocation(), PD); } + } return SpecEnd; } diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index f755b8c..7ef04e9 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -2701,11 +2701,10 @@ void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) { llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D]; if (Stored.isNull()) Stored = Inst; - else if (Stored.is<Decl *>()) { + else if (DeclArgumentPack *Pack = Stored.dyn_cast<DeclArgumentPack *>()) + Pack->push_back(Inst); + else assert(Stored.get<Decl *>() == Inst && "Already instantiated this local"); - Stored = Inst; - } else - LocalDecls[D].get<DeclArgumentPack *>()->push_back(Inst); } void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D, diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 33e83d0..d1428c5 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -339,7 +339,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { D->getLocation(), D->getIdentifier(), DI->getType(), DI, D->getStorageClass()); - Var->setThreadSpecified(D->isThreadSpecified()); + Var->setTSCSpec(D->getTSCSpec()); Var->setInitStyle(D->getInitStyle()); Var->setCXXForRangeDecl(D->isCXXForRangeDecl()); Var->setConstexpr(D->isConstexpr()); @@ -525,6 +525,53 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { return Field; } +Decl *TemplateDeclInstantiator::VisitMSPropertyDecl(MSPropertyDecl *D) { + bool Invalid = false; + TypeSourceInfo *DI = D->getTypeSourceInfo(); + + if (DI->getType()->isVariablyModifiedType()) { + SemaRef.Diag(D->getLocation(), diag::err_property_is_variably_modified) + << D->getName(); + Invalid = true; + } else if (DI->getType()->isInstantiationDependentType()) { + DI = SemaRef.SubstType(DI, TemplateArgs, + D->getLocation(), D->getDeclName()); + if (!DI) { + DI = D->getTypeSourceInfo(); + Invalid = true; + } else if (DI->getType()->isFunctionType()) { + // C++ [temp.arg.type]p3: + // If a declaration acquires a function type through a type + // dependent on a template-parameter and this causes a + // declaration that does not use the syntactic form of a + // function declarator to have function type, the program is + // ill-formed. + SemaRef.Diag(D->getLocation(), diag::err_field_instantiates_to_function) + << DI->getType(); + Invalid = true; + } + } else { + SemaRef.MarkDeclarationsReferencedInType(D->getLocation(), DI->getType()); + } + + MSPropertyDecl *Property = new (SemaRef.Context) + MSPropertyDecl(Owner, D->getLocation(), + D->getDeclName(), DI->getType(), DI, + D->getLocStart(), + D->getGetterId(), D->getSetterId()); + + SemaRef.InstantiateAttrs(TemplateArgs, D, Property, LateAttrs, + StartingScope); + + if (Invalid) + Property->setInvalidDecl(); + + Property->setAccess(D->getAccess()); + Owner->addDecl(Property); + + return Property; +} + Decl *TemplateDeclInstantiator::VisitIndirectFieldDecl(IndirectFieldDecl *D) { NamedDecl **NamedChain = new (SemaRef.Context)NamedDecl*[D->getChainingSize()]; @@ -754,7 +801,7 @@ void TemplateDeclInstantiator::InstantiateEnumDefinition( // FIXME: Fixup LBraceLoc SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(), Enum->getRBraceLoc(), Enum, - Enumerators.data(), Enumerators.size(), + Enumerators, 0, 0); } @@ -1105,12 +1152,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, // this declaration. FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); if (FunctionTemplate && !TemplateParams) { - std::pair<const TemplateArgument *, unsigned> Innermost - = TemplateArgs.getInnermost(); + ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost(); void *InsertPos = 0; FunctionDecl *SpecFunc - = FunctionTemplate->findSpecialization(Innermost.first, Innermost.second, + = FunctionTemplate->findSpecialization(Innermost.begin(), Innermost.size(), InsertPos); // If we already have a function template specialization, return it. @@ -1162,7 +1208,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, FunctionDecl *Function = FunctionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(), D->getNameInfo(), T, TInfo, - D->getStorageClass(), + D->getCanonicalDecl()->getStorageClass(), D->isInlineSpecified(), D->hasWrittenPrototype(), D->isConstexpr()); @@ -1235,12 +1281,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, } } else if (FunctionTemplate) { // Record this function template specialization. - std::pair<const TemplateArgument *, unsigned> Innermost - = TemplateArgs.getInnermost(); + ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost(); Function->setFunctionTemplateSpecialization(FunctionTemplate, TemplateArgumentList::CreateCopy(SemaRef.Context, - Innermost.first, - Innermost.second), + Innermost.begin(), + Innermost.size()), /*InsertPos=*/0); } else if (isFriend) { // Note, we need this connection even if the friend doesn't have a body. @@ -1413,12 +1458,12 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, // We are creating a function template specialization from a function // template. Check whether there is already a function template // specialization for this particular set of template arguments. - std::pair<const TemplateArgument *, unsigned> Innermost - = TemplateArgs.getInnermost(); + ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost(); void *InsertPos = 0; FunctionDecl *SpecFunc - = FunctionTemplate->findSpecialization(Innermost.first, Innermost.second, + = FunctionTemplate->findSpecialization(Innermost.begin(), + Innermost.size(), InsertPos); // If we already have a function template specialization, return it. @@ -1513,6 +1558,36 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Constructor->isExplicit(), Constructor->isInlineSpecified(), false, Constructor->isConstexpr()); + + // Claim that the instantiation of a constructor or constructor template + // inherits the same constructor that the template does. + if (CXXConstructorDecl *Inh = const_cast<CXXConstructorDecl *>( + Constructor->getInheritedConstructor())) { + // If we're instantiating a specialization of a function template, our + // "inherited constructor" will actually itself be a function template. + // Instantiate a declaration of it, too. + if (FunctionTemplate) { + assert(!TemplateParams && Inh->getDescribedFunctionTemplate() && + !Inh->getParent()->isDependentContext() && + "inheriting constructor template in dependent context?"); + Sema::InstantiatingTemplate Inst(SemaRef, Constructor->getLocation(), + Inh); + if (Inst) + return 0; + Sema::ContextRAII SavedContext(SemaRef, Inh->getDeclContext()); + LocalInstantiationScope LocalScope(SemaRef); + + // Use the same template arguments that we deduced for the inheriting + // constructor. There's no way they could be deduced differently. + MultiLevelTemplateArgumentList InheritedArgs; + InheritedArgs.addOuterTemplateArguments(TemplateArgs.getInnermost()); + Inh = cast_or_null<CXXConstructorDecl>( + SemaRef.SubstDecl(Inh, Inh->getDeclContext(), InheritedArgs)); + if (!Inh) + return 0; + } + cast<CXXConstructorDecl>(Method)->setInheritedConstructor(Inh); + } } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { Method = CXXDestructorDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, @@ -1526,10 +1601,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Conversion->isConstexpr(), Conversion->getLocEnd()); } else { + StorageClass SC = D->isStatic() ? SC_Static : SC_None; Method = CXXMethodDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, - D->getStorageClass(), - D->isInlineSpecified(), + SC, D->isInlineSpecified(), D->isConstexpr(), D->getLocEnd()); } @@ -1565,12 +1640,11 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method->setDescribedFunctionTemplate(FunctionTemplate); } else if (FunctionTemplate) { // Record this function template specialization. - std::pair<const TemplateArgument *, unsigned> Innermost - = TemplateArgs.getInnermost(); + ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost(); Method->setFunctionTemplateSpecialization(FunctionTemplate, TemplateArgumentList::CreateCopy(SemaRef.Context, - Innermost.first, - Innermost.second), + Innermost.begin(), + Innermost.size()), /*InsertPos=*/0); } else if (!isFriend) { // Record that this is an instantiation of a member function. @@ -2688,15 +2762,16 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *ExceptionSpecTemplate = Tmpl; if (EPI.ExceptionSpecType == EST_Uninstantiated) ExceptionSpecTemplate = EPI.ExceptionSpecTemplate; - assert(EPI.ExceptionSpecType != EST_Unevaluated && - "instantiating implicitly-declared special member"); + ExceptionSpecificationType NewEST = EST_Uninstantiated; + if (EPI.ExceptionSpecType == EST_Unevaluated) + NewEST = EST_Unevaluated; // Mark the function has having an uninstantiated exception specification. const FunctionProtoType *NewProto = New->getType()->getAs<FunctionProtoType>(); assert(NewProto && "Template instantiation without function prototype?"); EPI = NewProto->getExtProtoInfo(); - EPI.ExceptionSpecType = EST_Uninstantiated; + EPI.ExceptionSpecType = NewEST; EPI.ExceptionSpecDecl = New; EPI.ExceptionSpecTemplate = ExceptionSpecTemplate; New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(), @@ -2733,7 +2808,6 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, if (Tmpl->isVirtualAsWritten()) New->setVirtualAsWritten(true); - // FIXME: attributes // FIXME: New needs a pointer to Tmpl return false; } @@ -2820,13 +2894,15 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, return; } - // C++0x [temp.explicit]p9: - // Except for inline functions, other explicit instantiation declarations - // have the effect of suppressing the implicit instantiation of the entity - // to which they refer. + // C++1y [temp.explicit]p10: + // Except for inline functions, declarations with types deduced from their + // initializer or return value, and class template specializations, other + // explicit instantiation declarations have the effect of suppressing the + // implicit instantiation of the entity to which they refer. if (Function->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDeclaration && - !PatternDecl->isInlined()) + !PatternDecl->isInlined() && + !PatternDecl->getResultType()->isUndeducedType()) return; if (PatternDecl->isInlined()) diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index c0ad2be..db885ae 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -727,6 +727,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case TST_interface: case TST_class: case TST_auto: + case TST_decltype_auto: case TST_unknown_anytype: case TST_image1d_t: case TST_image1d_array_t: diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 7169eea..0959f7d 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -793,9 +793,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // "At least one type specifier shall be given in the declaration // specifiers in each declaration, and in the specifier-qualifier list in // each struct declaration and type name." - // FIXME: Does Microsoft really have the implicit int extension in C++? - if (S.getLangOpts().CPlusPlus && - !S.getLangOpts().MicrosoftExt) { + if (S.getLangOpts().CPlusPlus) { S.Diag(DeclLoc, diag::err_missing_type_specifier) << DS.getSourceRange(); @@ -994,11 +992,14 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { } break; - case DeclSpec::TST_auto: { + case DeclSpec::TST_auto: // TypeQuals handled by caller. - Result = Context.getAutoType(QualType()); + Result = Context.getAutoType(QualType(), /*decltype(auto)*/false); + break; + + case DeclSpec::TST_decltype_auto: + Result = Context.getAutoType(QualType(), /*decltype(auto)*/true); break; - } case DeclSpec::TST_unknown_anytype: Result = Context.UnknownAnyTy; @@ -1457,12 +1458,6 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, return QualType(); } - if (T->getContainedAutoType()) { - Diag(Loc, diag::err_illegal_decl_array_of_auto) - << getPrintableNameForEntity(Entity) << T; - return QualType(); - } - if (const RecordType *EltTy = T->getAs<RecordType>()) { // If the element type is a struct or union that contains a variadic // array, accept it as a GNU extension: C99 6.7.2.1p2. @@ -1572,6 +1567,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, if (!getLangOpts().C99) { if (T->isVariableArrayType()) { // Prohibit the use of non-POD types in VLAs. + // FIXME: C++1y allows this. QualType BaseT = Context.getBaseElementType(T); if (!T->isDependentType() && !BaseT.isPODType(Context) && @@ -1587,7 +1583,9 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, } // Just extwarn about VLAs. else - Diag(Loc, diag::ext_vla); + Diag(Loc, getLangOpts().CPlusPlus1y + ? diag::warn_cxx11_compat_array_of_runtime_bound + : diag::ext_vla); } else if (ASM != ArrayType::Normal || Quals != 0) Diag(Loc, getLangOpts().CPlusPlus? diag::err_c99_array_usage_cxx @@ -2020,6 +2018,8 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, // The TagDecl owned by the DeclSpec. TagDecl *OwnedTagDecl = 0; + bool ContainsPlaceholderType = false; + switch (D.getName().getKind()) { case UnqualifiedId::IK_ImplicitSelfParam: case UnqualifiedId::IK_OperatorFunctionId: @@ -2027,6 +2027,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, case UnqualifiedId::IK_LiteralOperatorId: case UnqualifiedId::IK_TemplateId: T = ConvertDeclSpecToType(state); + ContainsPlaceholderType = D.getDeclSpec().containsPlaceholderType(); if (!D.isInvalidType() && D.getDeclSpec().isTypeSpecOwned()) { OwnedTagDecl = cast<TagDecl>(D.getDeclSpec().getRepAsDecl()); @@ -2050,6 +2051,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, // converts to. T = SemaRef.GetTypeFromParser(D.getName().ConversionFunctionId, &ReturnTypeInfo); + ContainsPlaceholderType = T->getContainedAutoType(); break; } @@ -2060,7 +2062,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, // In C++11, a function declarator using 'auto' must have a trailing return // type (this is checked later) and we can skip this. In other languages // using auto, we need to check regardless. - if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto && + if (ContainsPlaceholderType && (!SemaRef.getLangOpts().CPlusPlus11 || !D.isFunctionDeclarator())) { int Error = -1; @@ -2103,10 +2105,15 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, Error = 10; // Type alias break; case Declarator::TrailingReturnContext: - Error = 11; // Function return type + if (!SemaRef.getLangOpts().CPlusPlus1y) + Error = 11; // Function return type + break; + case Declarator::ConversionIdContext: + if (!SemaRef.getLangOpts().CPlusPlus1y) + Error = 12; // conversion-type-id break; case Declarator::TypeNameContext: - Error = 12; // Generic + Error = 13; // Generic break; case Declarator::FileContext: case Declarator::BlockContext: @@ -2142,15 +2149,19 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, } } + SourceRange AutoRange = D.getDeclSpec().getTypeSpecTypeLoc(); + if (D.getName().getKind() == UnqualifiedId::IK_ConversionFunctionId) + AutoRange = D.getName().getSourceRange(); + if (Error != -1) { - SemaRef.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), - diag::err_auto_not_allowed) - << Error; + SemaRef.Diag(AutoRange.getBegin(), diag::err_auto_not_allowed) + << Error << AutoRange; T = SemaRef.Context.IntTy; D.setInvalidType(true); } else - SemaRef.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), - diag::warn_cxx98_compat_auto_type_specifier); + SemaRef.Diag(AutoRange.getBegin(), + diag::warn_cxx98_compat_auto_type_specifier) + << AutoRange; } if (SemaRef.getLangOpts().CPlusPlus && @@ -2182,6 +2193,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, D.setInvalidType(true); break; case Declarator::TypeNameContext: + case Declarator::ConversionIdContext: case Declarator::TemplateParamContext: case Declarator::CXXNewContext: case Declarator::CXXCatchContext: @@ -2399,6 +2411,46 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, (T->castAs<FunctionProtoType>()->getTypeQuals() != 0 || T->castAs<FunctionProtoType>()->getRefQualifier() != RQ_None); + // If T is 'decltype(auto)', the only declarators we can have are parens + // and at most one function declarator if this is a function declaration. + if (const AutoType *AT = T->getAs<AutoType>()) { + if (AT->isDecltypeAuto()) { + for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) { + unsigned Index = E - I - 1; + DeclaratorChunk &DeclChunk = D.getTypeObject(Index); + unsigned DiagId = diag::err_decltype_auto_compound_type; + unsigned DiagKind = 0; + switch (DeclChunk.Kind) { + case DeclaratorChunk::Paren: + continue; + case DeclaratorChunk::Function: { + unsigned FnIndex; + if (D.isFunctionDeclarationContext() && + D.isFunctionDeclarator(FnIndex) && FnIndex == Index) + continue; + DiagId = diag::err_decltype_auto_function_declarator_not_declaration; + break; + } + case DeclaratorChunk::Pointer: + case DeclaratorChunk::BlockPointer: + case DeclaratorChunk::MemberPointer: + DiagKind = 0; + break; + case DeclaratorChunk::Reference: + DiagKind = 1; + break; + case DeclaratorChunk::Array: + DiagKind = 2; + break; + } + + S.Diag(DeclChunk.Loc, DiagId) << DiagKind; + D.setInvalidType(true); + break; + } + } + } + // Walk the DeclTypeInfo, building the recursive type as we go. // DeclTypeInfos are ordered from the identifier out, which is // opposite of what we want :). @@ -2527,6 +2579,15 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } } + if (const AutoType *AT = T->getContainedAutoType()) { + // We've already diagnosed this for decltype(auto). + if (!AT->isDecltypeAuto()) + S.Diag(DeclType.Loc, diag::err_illegal_decl_array_of_auto) + << getPrintableNameForEntity(Name) << T; + T = QualType(); + break; + } + T = S.BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals, SourceRange(DeclType.Loc, DeclType.EndLoc), Name); break; @@ -2544,7 +2605,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // trailing-return-type is only required if we're declaring a function, // and not, for instance, a pointer to a function. if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto && - !FTI.hasTrailingReturnType() && chunkIndex == 0) { + !FTI.hasTrailingReturnType() && chunkIndex == 0 && + !S.getLangOpts().CPlusPlus1y) { S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_auto_missing_trailing_return); T = Context.IntTy; @@ -2557,7 +2619,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, << T << D.getDeclSpec().getSourceRange(); D.setInvalidType(true); } else if (D.getContext() != Declarator::LambdaExprContext && - (T.hasQualifiers() || !isa<AutoType>(T))) { + (T.hasQualifiers() || !isa<AutoType>(T) || + cast<AutoType>(T)->isDecltypeAuto())) { S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_trailing_return_without_auto) << T << D.getDeclSpec().getSourceRange(); @@ -3044,6 +3107,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case Declarator::ObjCCatchContext: case Declarator::BlockLiteralContext: case Declarator::LambdaExprContext: + case Declarator::ConversionIdContext: case Declarator::TrailingReturnContext: case Declarator::TemplateTypeArgContext: // FIXME: We may want to allow parameter packs in block-literal contexts @@ -3781,7 +3845,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, QualType &type) { bool NonObjCPointer = false; - if (!type->isDependentType()) { + if (!type->isDependentType() && !type->isUndeducedType()) { if (const PointerType *ptr = type->getAs<PointerType>()) { QualType pointee = ptr->getPointeeType(); if (pointee->isObjCRetainableType() || pointee->isPointerType()) @@ -4806,7 +4870,7 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, QualType ElemType = Context.getBaseElementType(T); RequireCompleteType(Loc, ElemType, 0); - if (T->isLiteralType()) + if (T->isLiteralType(Context)) return false; if (Diagnoser.Suppressed) @@ -4848,7 +4912,7 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, } else if (RD->hasNonLiteralTypeFieldsOrBases()) { for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { - if (!I->getType()->isLiteralType()) { + if (!I->getType()->isLiteralType(Context)) { Diag(I->getLocStart(), diag::note_non_literal_base_class) << RD << I->getType() << I->getSourceRange(); @@ -4857,7 +4921,7 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, } for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I) { - if (!I->getType()->isLiteralType() || + if (!I->getType()->isLiteralType(Context) || I->getType().isVolatileQualified()) { Diag(I->getLocation(), diag::note_non_literal_field) << RD << *I << I->getType() diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index bdd68a7..89e23ef 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -754,17 +754,20 @@ public: UnaryTransformType::UTTKind UKind, SourceLocation Loc); - /// \brief Build a new C++0x decltype type. + /// \brief Build a new C++11 decltype type. /// /// By default, performs semantic analysis when building the decltype type. /// Subclasses may override this routine to provide different behavior. QualType RebuildDecltypeType(Expr *Underlying, SourceLocation Loc); - /// \brief Build a new C++0x auto type. + /// \brief Build a new C++11 auto type. /// /// By default, builds a new AutoType with the given deduced type. - QualType RebuildAutoType(QualType Deduced) { - return SemaRef.Context.getAutoType(Deduced); + QualType RebuildAutoType(QualType Deduced, bool IsDecltypeAuto) { + // Note, IsDependent is always false here: we implicitly convert an 'auto' + // which has been deduced to a dependent type into an undeduced 'auto', so + // that we'll retry deduction after the transformation. + return SemaRef.Context.getAutoType(Deduced, IsDecltypeAuto); } /// \brief Build a new template specialization type. @@ -1187,8 +1190,16 @@ public: /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, - ArrayRef<Token> AsmToks, SourceLocation EndLoc) { - return getSema().ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, EndLoc); + ArrayRef<Token> AsmToks, + StringRef AsmString, + unsigned NumOutputs, unsigned NumInputs, + ArrayRef<StringRef> Constraints, + ArrayRef<StringRef> Clobbers, + ArrayRef<Expr*> Exprs, + SourceLocation EndLoc) { + return getSema().ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, AsmString, + NumOutputs, NumInputs, + Constraints, Clobbers, Exprs, EndLoc); } /// \brief Build a new Objective-C \@try statement. @@ -1338,6 +1349,23 @@ public: Expr *Cond, Expr *Inc, Stmt *LoopVar, SourceLocation RParenLoc) { + // If we've just learned that the range is actually an Objective-C + // collection, treat this as an Objective-C fast enumeration loop. + if (DeclStmt *RangeStmt = dyn_cast<DeclStmt>(Range)) { + if (RangeStmt->isSingleDecl()) { + if (VarDecl *RangeVar = dyn_cast<VarDecl>(RangeStmt->getSingleDecl())) { + if (RangeVar->isInvalidDecl()) + return StmtError(); + + Expr *RangeExpr = RangeVar->getInit(); + if (!RangeExpr->isTypeDependent() && + RangeExpr->getType()->isObjCObjectPointerType()) + return getSema().ActOnObjCForCollectionStmt(ForLoc, LoopVar, RangeExpr, + RParenLoc); + } + } + } + return getSema().BuildCXXForRangeStmt(ForLoc, ColonLoc, Range, BeginEnd, Cond, Inc, LoopVar, RParenLoc, Sema::BFRK_Rebuild); @@ -1966,6 +1994,17 @@ public: Param)); } + /// \brief Build a new C++11 default-initialization expression. + /// + /// By default, builds a new default field initialization expression, which + /// does not require any semantic analysis. Subclasses may override this + /// routine to provide different behavior. + ExprResult RebuildCXXDefaultInitExpr(SourceLocation Loc, + FieldDecl *Field) { + return getSema().Owned(CXXDefaultInitExpr::Create(getSema().Context, Loc, + Field)); + } + /// \brief Build a new C++ zero-initialization expression. /// /// By default, performs semantic analysis to build the new expression. @@ -1974,7 +2013,7 @@ public: SourceLocation LParenLoc, SourceLocation RParenLoc) { return getSema().BuildCXXTypeConstructExpr(TSInfo, LParenLoc, - MultiExprArg(), RParenLoc); + None, RParenLoc); } /// \brief Build a new C++ "new" expression. @@ -2609,13 +2648,13 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init, // Revert value-initialization back to empty parens. if (CXXScalarValueInitExpr *VIE = dyn_cast<CXXScalarValueInitExpr>(Init)) { SourceRange Parens = VIE->getSourceRange(); - return getDerived().RebuildParenListExpr(Parens.getBegin(), MultiExprArg(), + return getDerived().RebuildParenListExpr(Parens.getBegin(), None, Parens.getEnd()); } // FIXME: We shouldn't build ImplicitValueInitExprs for direct-initialization. if (isa<ImplicitValueInitExpr>(Init)) - return getDerived().RebuildParenListExpr(SourceLocation(), MultiExprArg(), + return getDerived().RebuildParenListExpr(SourceLocation(), None, SourceLocation()); // Revert initialization by constructor back to a parenthesized or braced list @@ -3382,7 +3421,7 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB, Qs.removeObjCLifetime(); Deduced = SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(), Qs); - Result = SemaRef.Context.getAutoType(Deduced); + Result = SemaRef.Context.getAutoType(Deduced, AutoTy->isDecltypeAuto()); TLB.TypeWasModifiedSafely(Result); } else { // Otherwise, complain about the addition of a qualifier to an @@ -4475,8 +4514,9 @@ QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB, } QualType Result = TL.getType(); - if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced) { - Result = getDerived().RebuildAutoType(NewDeduced); + if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced || + T->isDependentType()) { + Result = getDerived().RebuildAutoType(NewDeduced, T->isDecltypeAuto()); if (Result.isNull()) return QualType(); } @@ -5617,8 +5657,30 @@ TreeTransform<Derived>::TransformMSAsmStmt(MSAsmStmt *S) { ArrayRef<Token> AsmToks = llvm::makeArrayRef(S->getAsmToks(), S->getNumAsmToks()); + bool HadError = false, HadChange = false; + + ArrayRef<Expr*> SrcExprs = S->getAllExprs(); + SmallVector<Expr*, 8> TransformedExprs; + TransformedExprs.reserve(SrcExprs.size()); + for (unsigned i = 0, e = SrcExprs.size(); i != e; ++i) { + ExprResult Result = getDerived().TransformExpr(SrcExprs[i]); + if (!Result.isUsable()) { + HadError = true; + } else { + HadChange |= (Result.get() != SrcExprs[i]); + TransformedExprs.push_back(Result.take()); + } + } + + if (HadError) return StmtError(); + if (!HadChange && !getDerived().AlwaysRebuild()) + return Owned(S); + return getDerived().RebuildMSAsmStmt(S->getAsmLoc(), S->getLBraceLoc(), - AsmToks, S->getEndLoc()); + AsmToks, S->getAsmString(), + S->getNumOutputs(), S->getNumInputs(), + S->getAllConstraints(), S->getClobbers(), + TransformedExprs, S->getEndLoc()); } template<typename Derived> @@ -5919,12 +5981,15 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) { BeginEnd.get() != S->getBeginEndStmt() || Cond.get() != S->getCond() || Inc.get() != S->getInc() || - LoopVar.get() != S->getLoopVarStmt()) + LoopVar.get() != S->getLoopVarStmt()) { NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(), S->getColonLoc(), Range.get(), BeginEnd.get(), Cond.get(), Inc.get(), LoopVar.get(), S->getRParenLoc()); + if (NewStmt.isInvalid()) + return StmtError(); + } StmtResult Body = getDerived().TransformStmt(S->getBody()); if (Body.isInvalid()) @@ -5932,12 +5997,15 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) { // Body has changed but we didn't rebuild the for-range statement. Rebuild // it now so we have a new statement to attach the body to. - if (Body.get() != S->getBody() && NewStmt.get() == S) + if (Body.get() != S->getBody() && NewStmt.get() == S) { NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(), S->getColonLoc(), Range.get(), BeginEnd.get(), Cond.get(), Inc.get(), LoopVar.get(), S->getRParenLoc()); + if (NewStmt.isInvalid()) + return StmtError(); + } if (NewStmt.get() == S) return SemaRef.Owned(S); @@ -6015,6 +6083,32 @@ TreeTransform<Derived>::TransformMSDependentExistsStmt( } template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformMSPropertyRefExpr(MSPropertyRefExpr *E) { + NestedNameSpecifierLoc QualifierLoc; + if (E->getQualifierLoc()) { + QualifierLoc + = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc()); + if (!QualifierLoc) + return ExprError(); + } + + MSPropertyDecl *PD = cast_or_null<MSPropertyDecl>( + getDerived().TransformDecl(E->getMemberLoc(), E->getPropertyDecl())); + if (!PD) + return ExprError(); + + ExprResult Base = getDerived().TransformExpr(E->getBaseExpr()); + if (Base.isInvalid()) + return ExprError(); + + return new (SemaRef.getASTContext()) + MSPropertyRefExpr(Base.get(), PD, E->isArrow(), + SemaRef.getASTContext().PseudoObjectTy, VK_LValue, + QualifierLoc, E->getMemberLoc()); +} + +template<typename Derived> StmtResult TreeTransform<Derived>::TransformSEHTryStmt(SEHTryStmt *S) { StmtResult TryBlock; // = getDerived().TransformCompoundStmt(S->getTryBlock()); @@ -6159,6 +6253,8 @@ TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E) { template<typename Derived> ExprResult TreeTransform<Derived>::TransformUserDefinedLiteral(UserDefinedLiteral *E) { + if (FunctionDecl *FD = E->getDirectCallee()) + SemaRef.MarkFunctionReferenced(E->getLocStart(), FD); return SemaRef.MaybeBindToTemporary(E); } @@ -7220,6 +7316,21 @@ TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) { template<typename Derived> ExprResult +TreeTransform<Derived>::TransformCXXDefaultInitExpr(CXXDefaultInitExpr *E) { + FieldDecl *Field + = cast_or_null<FieldDecl>(getDerived().TransformDecl(E->getLocStart(), + E->getField())); + if (!Field) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && Field == E->getField()) + return SemaRef.Owned(E); + + return getDerived().RebuildCXXDefaultInitExpr(E->getExprLoc(), Field); +} + +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformCXXScalarValueInitExpr( CXXScalarValueInitExpr *E) { TypeSourceInfo *T = getDerived().TransformType(E->getTypeSourceInfo()); @@ -8592,16 +8703,11 @@ TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E) { template<typename Derived> ExprResult TreeTransform<Derived>:: TransformObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) { - ExprResult result = getDerived().TransformExpr(E->getSubExpr()); - if (result.isInvalid()) return ExprError(); - Expr *subExpr = result.take(); - - if (!getDerived().AlwaysRebuild() && - subExpr == E->getSubExpr()) - return SemaRef.Owned(E); - - return SemaRef.Owned(new(SemaRef.Context) - ObjCIndirectCopyRestoreExpr(subExpr, E->getType(), E->shouldCopy())); + // This is a kind of implicit conversion, and it needs to get dropped + // and recomputed for the same general reasons that ImplicitCastExprs + // do, as well a more specific one: this expression is only valid when + // it appears *immediately* as an argument expression. + return getDerived().TransformExpr(E->getSubExpr()); } template<typename Derived> @@ -9340,6 +9446,23 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base, /*TemplateArgs*/ 0); } +template<typename Derived> +StmtResult +TreeTransform<Derived>::TransformCapturedStmt(CapturedStmt *S) { + SourceLocation Loc = S->getLocStart(); + unsigned NumParams = S->getCapturedDecl()->getNumParams(); + getSema().ActOnCapturedRegionStart(Loc, /*CurScope*/0, + S->getCapturedRegionKind(), NumParams); + StmtResult Body = getDerived().TransformStmt(S->getCapturedStmt()); + + if (Body.isInvalid()) { + getSema().ActOnCapturedRegionError(); + return StmtError(); + } + + return getSema().ActOnCapturedRegionEnd(Body.take()); +} + } // end namespace clang #endif // LLVM_CLANG_SEMA_TREETRANSFORM_H diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp index 7bbe6b1..24b268f 100644 --- a/lib/Serialization/ASTCommon.cpp +++ b/lib/Serialization/ASTCommon.cpp @@ -119,6 +119,7 @@ serialization::getDefinitiveDeclContext(const DeclContext *DC) { case Decl::CXXConversion: case Decl::ObjCMethod: case Decl::Block: + case Decl::Captured: // Objective C categories, category implementations, and class // implementations can only be defined in one place. case Decl::ObjCCategory: @@ -180,6 +181,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::UnresolvedUsingValue: case Decl::IndirectField: case Decl::Field: + case Decl::MSProperty: case Decl::ObjCIvar: case Decl::ObjCAtDefsField: case Decl::ImplicitParam: @@ -202,6 +204,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::FriendTemplate: case Decl::StaticAssert: case Decl::Block: + case Decl::Captured: case Decl::ClassScopeFunctionSpecialization: case Decl::Import: case Decl::OMPThreadPrivate: diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index d984415..22caeb8 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -257,7 +257,8 @@ static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts, const PreprocessorOptions &ExistingPPOpts, DiagnosticsEngine *Diags, FileManager &FileMgr, - std::string &SuggestedPredefines) { + std::string &SuggestedPredefines, + const LangOptions &LangOpts) { // Check macro definitions. MacroDefinitionsMap ASTFileMacros; collectMacroDefinitions(PPOpts, ASTFileMacros); @@ -323,6 +324,15 @@ static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts, return true; } + // Detailed record is important since it is used for the module cache hash. + if (LangOpts.Modules && + PPOpts.DetailedRecord != ExistingPPOpts.DetailedRecord) { + if (Diags) { + Diags->Report(diag::err_pch_pp_detailed_record) << PPOpts.DetailedRecord; + } + return true; + } + // Compute the #include and #include_macros lines we need. for (unsigned I = 0, N = ExistingPPOpts.Includes.size(); I != N; ++I) { StringRef File = ExistingPPOpts.Includes[I]; @@ -363,7 +373,8 @@ bool PCHValidator::ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, return checkPreprocessorOptions(PPOpts, ExistingPPOpts, Complain? &Reader.Diags : 0, PP.getFileManager(), - SuggestedPredefines); + SuggestedPredefines, + PP.getLangOpts()); } void PCHValidator::ReadHeaderFileInfo(const HeaderFileInfo &HFI, @@ -428,8 +439,12 @@ ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d, data_type Result; Result.ID = Reader.getGlobalSelectorID(F, ReadUnalignedLE32(d)); - unsigned NumInstanceMethods = ReadUnalignedLE16(d); - unsigned NumFactoryMethods = ReadUnalignedLE16(d); + unsigned NumInstanceMethodsAndBits = ReadUnalignedLE16(d); + unsigned NumFactoryMethodsAndBits = ReadUnalignedLE16(d); + Result.InstanceBits = NumInstanceMethodsAndBits & 0x3; + Result.FactoryBits = NumFactoryMethodsAndBits & 0x3; + unsigned NumInstanceMethods = NumInstanceMethodsAndBits >> 2; + unsigned NumFactoryMethods = NumFactoryMethodsAndBits >> 2; // Load instance methods for (unsigned I = 0; I != NumInstanceMethods; ++I) { @@ -1088,6 +1103,19 @@ bool ASTReader::ReadBlockAbbrevs(BitstreamCursor &Cursor, unsigned BlockID) { } } +Token ASTReader::ReadToken(ModuleFile &F, const RecordData &Record, + unsigned &Idx) { + Token Tok; + Tok.startToken(); + Tok.setLocation(ReadSourceLocation(F, Record, Idx)); + Tok.setLength(Record[Idx++]); + if (IdentifierInfo *II = getLocalIdentifier(F, Record[Idx++])) + Tok.setIdentifierInfo(II); + Tok.setKind((tok::TokenKind)Record[Idx++]); + Tok.setFlag((Token::TokenFlags)Record[Idx++]); + return Tok; +} + MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) { BitstreamCursor &Stream = F.MacroCursor; @@ -1188,14 +1216,8 @@ MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) { // erroneous, just pretend we didn't see this. if (Macro == 0) break; - Token Tok; - Tok.startToken(); - Tok.setLocation(ReadSourceLocation(F, Record[0])); - Tok.setLength(Record[1]); - if (IdentifierInfo *II = getLocalIdentifier(F, Record[2])) - Tok.setIdentifierInfo(II); - Tok.setKind((tok::TokenKind)Record[3]); - Tok.setFlag((Token::TokenFlags)Record[4]); + unsigned Idx = 0; + Token Tok = ReadToken(F, Record, Idx); Macro->AddTokenToBody(Tok); break; } @@ -1563,9 +1585,9 @@ void ASTReader::installPCHMacroDirectives(IdentifierInfo *II, } /// \brief For the given macro definitions, check if they are both in system -/// modules and if one of the two is in the clang builtin headers. -static bool isSystemAndClangMacro(MacroInfo *PrevMI, MacroInfo *NewMI, - Module *NewOwner, ASTReader &Reader) { +/// modules. +static bool areDefinedInSystemModules(MacroInfo *PrevMI, MacroInfo *NewMI, + Module *NewOwner, ASTReader &Reader) { assert(PrevMI && NewMI); if (!NewOwner) return false; @@ -1576,22 +1598,7 @@ static bool isSystemAndClangMacro(MacroInfo *PrevMI, MacroInfo *NewMI, return false; if (PrevOwner == NewOwner) return false; - if (!PrevOwner->IsSystem || !NewOwner->IsSystem) - return false; - - SourceManager &SM = Reader.getSourceManager(); - FileID PrevFID = SM.getFileID(PrevMI->getDefinitionLoc()); - FileID NewFID = SM.getFileID(NewMI->getDefinitionLoc()); - const FileEntry *PrevFE = SM.getFileEntryForID(PrevFID); - const FileEntry *NewFE = SM.getFileEntryForID(NewFID); - if (PrevFE == 0 || NewFE == 0) - return false; - - Preprocessor &PP = Reader.getPreprocessor(); - ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap(); - const DirectoryEntry *BuiltinDir = ModMap.getBuiltinIncludeDir(); - - return (PrevFE->getDir() == BuiltinDir) != (NewFE->getDir() == BuiltinDir); + return PrevOwner->IsSystem && NewOwner->IsSystem; } void ASTReader::installImportedMacro(IdentifierInfo *II, MacroDirective *MD, @@ -1607,15 +1614,12 @@ void ASTReader::installImportedMacro(IdentifierInfo *II, MacroDirective *MD, if (NewMI != PrevMI && !PrevMI->isIdenticalTo(*NewMI, PP, /*Syntactically=*/true)) { // Before marking the macros as ambiguous, check if this is a case where - // the system macro uses a not identical definition compared to a macro - // from the clang headers. For example: + // both macros are in system headers. If so, we trust that the system + // did not get it wrong. This also handles cases where Clang's own + // headers have a different spelling of certain system macros: // #define LONG_MAX __LONG_MAX__ (clang's limits.h) // #define LONG_MAX 0x7fffffffffffffffL (system's limits.h) - // in which case don't mark them to avoid the "ambiguous macro expansion" - // warning. - // FIXME: This should go away if the system headers get "fixed" to use - // identical definitions. - if (!isSystemAndClangMacro(PrevMI, NewMI, Owner, *this)) { + if (!areDefinedInSystemModules(PrevMI, NewMI, Owner, *this)) { PrevDef.getDirective()->setAmbiguous(true); DefMD->setAmbiguous(true); } @@ -2754,7 +2758,7 @@ static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) { ObjCMethodList &Start = Method->isInstanceMethod()? Known->second.first : Known->second.second; bool Found = false; - for (ObjCMethodList *List = &Start; List; List = List->Next) { + for (ObjCMethodList *List = &Start; List; List = List->getNext()) { if (!Found) { if (List->Method == Method) { Found = true; @@ -2764,8 +2768,8 @@ static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) { } } - if (List->Next) - List->Method = List->Next->Method; + if (List->getNext()) + List->Method = List->getNext()->Method; else List->Method = Method; } @@ -3324,10 +3328,10 @@ void ASTReader::finalizeForWriting() { HiddenNamesMap.clear(); } -/// SkipCursorToControlBlock - Given a cursor at the start of an AST file, scan -/// ahead and drop the cursor into the start of the CONTROL_BLOCK, returning -/// false on success and true on failure. -static bool SkipCursorToControlBlock(BitstreamCursor &Cursor) { +/// \brief Given a cursor at the start of an AST file, scan ahead and drop the +/// cursor into the start of the given block ID, returning false on success and +/// true on failure. +static bool SkipCursorToBlock(BitstreamCursor &Cursor, unsigned BlockID) { while (1) { llvm::BitstreamEntry Entry = Cursor.advance(); switch (Entry.Kind) { @@ -3341,8 +3345,8 @@ static bool SkipCursorToControlBlock(BitstreamCursor &Cursor) { break; case llvm::BitstreamEntry::SubBlock: - if (Entry.ID == CONTROL_BLOCK_ID) { - if (Cursor.EnterSubBlock(CONTROL_BLOCK_ID)) + if (Entry.ID == BlockID) { + if (Cursor.EnterSubBlock(BlockID)) return true; // Found it! return false; @@ -3386,7 +3390,7 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName, } // Scan for the CONTROL_BLOCK_ID block. - if (SkipCursorToControlBlock(Stream)) { + if (SkipCursorToBlock(Stream, CONTROL_BLOCK_ID)) { Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName; return std::string(); } @@ -3441,7 +3445,7 @@ namespace { bool Complain, std::string &SuggestedPredefines) { return checkPreprocessorOptions(ExistingPPOpts, PPOpts, 0, FileMgr, - SuggestedPredefines); + SuggestedPredefines, ExistingLangOpts); } }; } @@ -3473,8 +3477,29 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename, } // Scan for the CONTROL_BLOCK_ID block. - if (SkipCursorToControlBlock(Stream)) + if (SkipCursorToBlock(Stream, CONTROL_BLOCK_ID)) return true; + + bool NeedsInputFiles = Listener.needsInputFileVisitation(); + BitstreamCursor InputFilesCursor; + if (NeedsInputFiles) { + InputFilesCursor = Stream; + if (SkipCursorToBlock(InputFilesCursor, INPUT_FILES_BLOCK_ID)) + return true; + + // Read the abbreviations + while (true) { + uint64_t Offset = InputFilesCursor.GetCurrentBitNo(); + unsigned Code = InputFilesCursor.ReadCode(); + + // We expect all abbrevs to be at the start of the block. + if (Code != llvm::bitc::DEFINE_ABBREV) { + InputFilesCursor.JumpToBit(Offset); + break; + } + InputFilesCursor.ReadAbbrevRecord(); + } + } // Scan for ORIGINAL_FILE inside the control block. RecordData Record; @@ -3532,6 +3557,35 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename, break; } + case INPUT_FILE_OFFSETS: { + if (!NeedsInputFiles) + break; + + unsigned NumInputFiles = Record[0]; + unsigned NumUserFiles = Record[1]; + const uint32_t *InputFileOffs = (const uint32_t *)Blob.data(); + for (unsigned I = 0; I != NumInputFiles; ++I) { + // Go find this input file. + bool isSystemFile = I >= NumUserFiles; + BitstreamCursor &Cursor = InputFilesCursor; + SavedStreamPosition SavedPosition(Cursor); + Cursor.JumpToBit(InputFileOffs[I]); + + unsigned Code = Cursor.ReadCode(); + RecordData Record; + StringRef Blob; + bool shouldContinue = false; + switch ((InputFileRecordTypes)Cursor.readRecord(Code, Record, &Blob)) { + case INPUT_FILE: + shouldContinue = Listener.visitInputFile(Blob, isSystemFile); + break; + } + if (!shouldContinue) + break; + } + break; + } + default: // No other validation to perform. break; @@ -3907,6 +3961,7 @@ bool ASTReader::ParseLanguageOptions(const RecordData &Record, LangOpts.CommentOpts.BlockCommandNames.push_back( ReadString(Record, Idx)); } + LangOpts.CommentOpts.ParseAllComments = Record[Idx++]; return Listener.ReadLanguageOptions(LangOpts, Complain); } @@ -4017,6 +4072,7 @@ bool ASTReader::ParsePreprocessorOptions(const RecordData &Record, } PPOpts.UsePredefines = Record[Idx++]; + PPOpts.DetailedRecord = Record[Idx++]; PPOpts.ImplicitPCHInclude = ReadString(Record, Idx); PPOpts.ImplicitPTHInclude = ReadString(Record, Idx); PPOpts.ObjCXXARCStandardLibrary = @@ -4639,8 +4695,12 @@ QualType ASTReader::readTypeRecord(unsigned Index) { return Context.getUnaryTransformType(BaseType, UnderlyingType, UKind); } - case TYPE_AUTO: - return Context.getAutoType(readType(*Loc.F, Record, Idx)); + case TYPE_AUTO: { + QualType Deduced = readType(*Loc.F, Record, Idx); + bool IsDecltypeAuto = Record[Idx++]; + bool IsDependent = Deduced.isNull() ? Record[Idx++] : false; + return Context.getAutoType(Deduced, IsDecltypeAuto, IsDependent); + } case TYPE_RECORD: { if (Record.size() != 2) { @@ -6015,8 +6075,8 @@ void ASTReader::InitializeSema(Sema &S) { // Makes sure any declarations that were deserialized "too early" // still get added to the identifier's declaration chains. for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) { - NamedDecl *ND = cast<NamedDecl>(PreloadedDecls[I]->getMostRecentDecl()); - SemaObj->pushExternalDeclIntoScope(ND, PreloadedDecls[I]->getDeclName()); + pushExternalDeclIntoScope(PreloadedDecls[I], + PreloadedDecls[I]->getDeclName()); } PreloadedDecls.clear(); @@ -6122,7 +6182,10 @@ StringRef ASTIdentifierIterator::Next() { return Result; } -IdentifierIterator *ASTReader::getIdentifiers() const { +IdentifierIterator *ASTReader::getIdentifiers() { + if (!loadGlobalIndex()) + return GlobalIndex->createIdentifierIterator(); + return new ASTIdentifierIterator(*this); } @@ -6131,13 +6194,16 @@ namespace clang { namespace serialization { ASTReader &Reader; Selector Sel; unsigned PriorGeneration; + unsigned InstanceBits; + unsigned FactoryBits; SmallVector<ObjCMethodDecl *, 4> InstanceMethods; SmallVector<ObjCMethodDecl *, 4> FactoryMethods; public: ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel, unsigned PriorGeneration) - : Reader(Reader), Sel(Sel), PriorGeneration(PriorGeneration) { } + : Reader(Reader), Sel(Sel), PriorGeneration(PriorGeneration), + InstanceBits(0), FactoryBits(0) { } static bool visit(ModuleFile &M, void *UserData) { ReadMethodPoolVisitor *This @@ -6170,6 +6236,8 @@ namespace clang { namespace serialization { This->InstanceMethods.append(Data.Instance.begin(), Data.Instance.end()); This->FactoryMethods.append(Data.Factory.begin(), Data.Factory.end()); + This->InstanceBits = Data.InstanceBits; + This->FactoryBits = Data.FactoryBits; return true; } @@ -6182,6 +6250,9 @@ namespace clang { namespace serialization { ArrayRef<ObjCMethodDecl *> getFactoryMethods() const { return FactoryMethods; } + + unsigned getInstanceBits() const { return InstanceBits; } + unsigned getFactoryBits() const { return FactoryBits; } }; } } // end namespace clang::serialization @@ -6219,6 +6290,8 @@ void ASTReader::ReadMethodPool(Selector Sel) { addMethodsToPool(S, Visitor.getInstanceMethods(), Pos->second.first); addMethodsToPool(S, Visitor.getFactoryMethods(), Pos->second.second); + Pos->second.first.setBits(Visitor.getInstanceBits()); + Pos->second.second.setBits(Visitor.getFactoryBits()); } void ASTReader::ReadKnownNamespaces( @@ -6417,8 +6490,7 @@ ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II, // Introduce this declaration into the translation-unit scope // and add it to the declaration chain for this identifier, so // that (unqualified) name lookup will find it. - NamedDecl *ND = cast<NamedDecl>(D->getMostRecentDecl()); - SemaObj->pushExternalDeclIntoScope(ND, II); + pushExternalDeclIntoScope(D, II); } else { // Queue this declaration so that it will be added to the // translation unit scope and identifier's declaration chain @@ -7165,9 +7237,9 @@ void ASTReader::ReadComments() { (RawComment::CommentKind) Record[Idx++]; bool IsTrailingComment = Record[Idx++]; bool IsAlmostTrailingComment = Record[Idx++]; - Comments.push_back(new (Context) RawComment(SR, Kind, - IsTrailingComment, - IsAlmostTrailingComment)); + Comments.push_back(new (Context) RawComment( + SR, Kind, IsTrailingComment, IsAlmostTrailingComment, + Context.getLangOpts().CommentOpts.ParseAllComments)); break; } } @@ -7205,8 +7277,7 @@ void ASTReader::finishPendingActions() { TLD != TLDEnd; ++TLD) { IdentifierInfo *II = TLD->first; for (unsigned I = 0, N = TLD->second.size(); I != N; ++I) { - NamedDecl *ND = cast<NamedDecl>(TLD->second[I]->getMostRecentDecl()); - SemaObj->pushExternalDeclIntoScope(ND, II); + pushExternalDeclIntoScope(cast<NamedDecl>(TLD->second[I]), II); } } @@ -7346,6 +7417,21 @@ void ASTReader::FinishedDeserializing() { } } +void ASTReader::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) { + D = cast<NamedDecl>(D->getMostRecentDecl()); + + if (SemaObj->IdResolver.tryAddTopLevelDecl(D, Name) && SemaObj->TUScope) { + SemaObj->TUScope->AddDecl(D); + } else if (SemaObj->TUScope) { + // Adding the decl to IdResolver may have failed because it was already in + // (even though it was not added in scope). If it is already in, make sure + // it gets in the scope as well. + if (std::find(SemaObj->IdResolver.begin(Name), + SemaObj->IdResolver.end(), D) != SemaObj->IdResolver.end()) + SemaObj->TUScope->AddDecl(D); + } +} + ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, StringRef isysroot, bool DisableValidation, bool AllowASTWithCompilerErrors, bool UseGlobalIndex) diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 0fbdd7e..f7fa818 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -244,6 +244,7 @@ namespace clang { void VisitCXXDestructorDecl(CXXDestructorDecl *D); void VisitCXXConversionDecl(CXXConversionDecl *D); void VisitFieldDecl(FieldDecl *FD); + void VisitMSPropertyDecl(MSPropertyDecl *FD); void VisitIndirectFieldDecl(IndirectFieldDecl *FD); void VisitVarDecl(VarDecl *VD); void VisitImplicitParamDecl(ImplicitParamDecl *PD); @@ -265,6 +266,7 @@ namespace clang { void VisitFriendTemplateDecl(FriendTemplateDecl *D); void VisitStaticAssertDecl(StaticAssertDecl *D); void VisitBlockDecl(BlockDecl *BD); + void VisitCapturedDecl(CapturedDecl *CD); void VisitEmptyDecl(EmptyDecl *D); std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC); @@ -847,6 +849,7 @@ void ASTDeclReader::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { VisitObjCImplDecl(D); D->setSuperClass(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx)); + D->SuperLoc = ReadSourceLocation(Record, Idx); D->setIvarLBraceLoc(ReadSourceLocation(Record, Idx)); D->setIvarRBraceLoc(ReadSourceLocation(Record, Idx)); D->setHasNonZeroConstructors(Record[Idx++]); @@ -879,6 +882,12 @@ void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) { } } +void ASTDeclReader::VisitMSPropertyDecl(MSPropertyDecl *PD) { + VisitDeclaratorDecl(PD); + PD->GetterId = Reader.GetIdentifierInfo(F, Record, Idx); + PD->SetterId = Reader.GetIdentifierInfo(F, Record, Idx); +} + void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) { VisitValueDecl(FD); @@ -895,7 +904,7 @@ void ASTDeclReader::VisitVarDecl(VarDecl *VD) { VisitDeclaratorDecl(VD); VD->VarDeclBits.SClass = (StorageClass)Record[Idx++]; - VD->VarDeclBits.ThreadSpecified = Record[Idx++]; + VD->VarDeclBits.TSCSpec = Record[Idx++]; VD->VarDeclBits.InitStyle = Record[Idx++]; VD->VarDeclBits.ExceptionVar = Record[Idx++]; VD->VarDeclBits.NRVOVariable = Record[Idx++]; @@ -987,6 +996,13 @@ void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) { captures.end(), capturesCXXThis); } +void ASTDeclReader::VisitCapturedDecl(CapturedDecl *CD) { + VisitDecl(CD); + // Body is set by VisitCapturedStmt. + for (unsigned i = 0; i < CD->NumParams; ++i) + CD->setParam(i, ReadDeclAs<ImplicitParamDecl>(Record, Idx)); +} + void ASTDeclReader::VisitLinkageSpecDecl(LinkageSpecDecl *D) { VisitDecl(D); D->setLanguage((LinkageSpecDecl::LanguageIDs)Record[Idx++]); @@ -2136,6 +2152,12 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { case DECL_BLOCK: D = BlockDecl::CreateDeserialized(Context, ID); break; + case DECL_MS_PROPERTY: + D = MSPropertyDecl::CreateDeserialized(Context, ID); + break; + case DECL_CAPTURED: + D = CapturedDecl::CreateDeserialized(Context, ID, Record[Idx++]); + break; case DECL_CXX_BASE_SPECIFIERS: Error("attempt to read a C++ base-specifier record as a declaration"); return 0; diff --git a/lib/Serialization/ASTReaderInternals.h b/lib/Serialization/ASTReaderInternals.h index 327da44..9149b18 100644 --- a/lib/Serialization/ASTReaderInternals.h +++ b/lib/Serialization/ASTReaderInternals.h @@ -152,6 +152,8 @@ class ASTSelectorLookupTrait { public: struct data_type { SelectorID ID; + unsigned InstanceBits; + unsigned FactoryBits; SmallVector<ObjCMethodDecl *, 2> Instance; SmallVector<ObjCMethodDecl *, 2> Factory; }; diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 078ecb7..e1357ba 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Lex/Token.h" #include "llvm/ADT/SmallString.h" using namespace clang; using namespace clang::serialization; @@ -32,14 +33,22 @@ namespace clang { const ASTReader::RecordData &Record; unsigned &Idx; + Token ReadToken(const RecordData &R, unsigned &I) { + return Reader.ReadToken(F, R, I); + } + SourceLocation ReadSourceLocation(const RecordData &R, unsigned &I) { return Reader.ReadSourceLocation(F, R, I); } - + SourceRange ReadSourceRange(const RecordData &R, unsigned &I) { return Reader.ReadSourceRange(F, R, I); } - + + std::string ReadString(const RecordData &R, unsigned &I) { + return Reader.ReadString(R, I); + } + TypeSourceInfo *GetTypeSourceInfo(const RecordData &R, unsigned &I) { return Reader.GetTypeSourceInfo(F, R, I); } @@ -286,18 +295,25 @@ void ASTStmtReader::VisitDeclStmt(DeclStmt *S) { } } -void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) { +void ASTStmtReader::VisitAsmStmt(AsmStmt *S) { VisitStmt(S); - unsigned NumOutputs = Record[Idx++]; - unsigned NumInputs = Record[Idx++]; - unsigned NumClobbers = Record[Idx++]; + S->NumOutputs = Record[Idx++]; + S->NumInputs = Record[Idx++]; + S->NumClobbers = Record[Idx++]; S->setAsmLoc(ReadSourceLocation(Record, Idx)); - S->setRParenLoc(ReadSourceLocation(Record, Idx)); S->setVolatile(Record[Idx++]); S->setSimple(Record[Idx++]); +} +void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) { + VisitAsmStmt(S); + S->setRParenLoc(ReadSourceLocation(Record, Idx)); S->setAsmString(cast_or_null<StringLiteral>(Reader.ReadSubStmt())); + unsigned NumOutputs = S->getNumOutputs(); + unsigned NumInputs = S->getNumInputs(); + unsigned NumClobbers = S->getNumClobbers(); + // Outputs and inputs SmallVector<IdentifierInfo *, 16> Names; SmallVector<StringLiteral*, 16> Constraints; @@ -320,8 +336,75 @@ void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) { } void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) { - // FIXME: Statement reader not yet implemented for MS style inline asm. + VisitAsmStmt(S); + S->LBraceLoc = ReadSourceLocation(Record, Idx); + S->EndLoc = ReadSourceLocation(Record, Idx); + S->NumAsmToks = Record[Idx++]; + std::string AsmStr = ReadString(Record, Idx); + + // Read the tokens. + SmallVector<Token, 16> AsmToks; + AsmToks.reserve(S->NumAsmToks); + for (unsigned i = 0, e = S->NumAsmToks; i != e; ++i) { + AsmToks.push_back(ReadToken(Record, Idx)); + } + + // The calls to reserve() for the FooData vectors are mandatory to + // prevent dead StringRefs in the Foo vectors. + + // Read the clobbers. + SmallVector<std::string, 16> ClobbersData; + SmallVector<StringRef, 16> Clobbers; + ClobbersData.reserve(S->NumClobbers); + Clobbers.reserve(S->NumClobbers); + for (unsigned i = 0, e = S->NumClobbers; i != e; ++i) { + ClobbersData.push_back(ReadString(Record, Idx)); + Clobbers.push_back(ClobbersData.back()); + } + + // Read the operands. + unsigned NumOperands = S->NumOutputs + S->NumInputs; + SmallVector<Expr*, 16> Exprs; + SmallVector<std::string, 16> ConstraintsData; + SmallVector<StringRef, 16> Constraints; + Exprs.reserve(NumOperands); + ConstraintsData.reserve(NumOperands); + Constraints.reserve(NumOperands); + for (unsigned i = 0; i != NumOperands; ++i) { + Exprs.push_back(cast<Expr>(Reader.ReadSubStmt())); + ConstraintsData.push_back(ReadString(Record, Idx)); + Constraints.push_back(ConstraintsData.back()); + } + + S->initialize(Reader.getContext(), AsmStr, AsmToks, + Constraints, Exprs, Clobbers); +} + +void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) { VisitStmt(S); + S->setCapturedDecl(ReadDeclAs<CapturedDecl>(Record, Idx)); + S->setCapturedRegionKind(static_cast<CapturedRegionKind>(Record[Idx++])); + S->setCapturedRecordDecl(ReadDeclAs<RecordDecl>(Record, Idx)); + + // Capture inits + for (CapturedStmt::capture_init_iterator I = S->capture_init_begin(), + E = S->capture_init_end(); + I != E; ++I) + *I = Reader.ReadSubExpr(); + + // Body + S->setCapturedStmt(Reader.ReadSubStmt()); + S->getCapturedDecl()->setBody(S->getCapturedStmt()); + + // Captures + for (CapturedStmt::capture_iterator I = S->capture_begin(), + E = S->capture_end(); + I != E; ++I) { + I->VarAndKind.setPointer(ReadDeclAs<VarDecl>(Record, Idx)); + I->VarAndKind + .setInt(static_cast<CapturedStmt::VariableCaptureKind>(Record[Idx++])); + I->Loc = ReadSourceLocation(Record, Idx); + } } void ASTStmtReader::VisitExpr(Expr *E) { @@ -1226,6 +1309,12 @@ void ASTStmtReader::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { E->Loc = ReadSourceLocation(Record, Idx); } +void ASTStmtReader::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) { + VisitExpr(E); + E->Field = ReadDeclAs<FieldDecl>(Record, Idx); + E->Loc = ReadSourceLocation(Record, Idx); +} + void ASTStmtReader::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { VisitExpr(E); E->setTemporary(Reader.ReadCXXTemporary(F, Record, Idx)); @@ -1498,6 +1587,15 @@ void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) { //===----------------------------------------------------------------------===// // Microsoft Expressions and Statements //===----------------------------------------------------------------------===// +void ASTStmtReader::VisitMSPropertyRefExpr(MSPropertyRefExpr *E) { + VisitExpr(E); + E->IsArrow = (Record[Idx++] != 0); + E->BaseExpr = Reader.ReadSubExpr(); + E->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx); + E->MemberLoc = ReadSourceLocation(Record, Idx); + E->TheDecl = ReadDeclAs<MSPropertyDecl>(Record, Idx); +} + void ASTStmtReader::VisitCXXUuidofExpr(CXXUuidofExpr *E) { VisitExpr(E); E->setSourceRange(ReadSourceRange(Record, Idx)); @@ -1715,6 +1813,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { S = new (Context) MSAsmStmt(Empty); break; + case STMT_CAPTURED: + S = CapturedStmt::CreateDeserialized(Context, + Record[ASTStmtReader::NumExprFields]); + break; + case EXPR_PREDEFINED: S = new (Context) PredefinedExpr(Empty); break; @@ -2073,6 +2176,9 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { case EXPR_CXX_UUIDOF_EXPR: S = new (Context) CXXUuidofExpr(Empty, true); break; + case EXPR_CXX_PROPERTY_REF_EXPR: + S = new (Context) MSPropertyRefExpr(Empty); + break; case EXPR_CXX_UUIDOF_TYPE: S = new (Context) CXXUuidofExpr(Empty, false); break; @@ -2091,6 +2197,9 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { S = new (Context) CXXDefaultArgExpr(Empty); break; } + case EXPR_CXX_DEFAULT_INIT: + S = new (Context) CXXDefaultInitExpr(Empty); + break; case EXPR_CXX_BIND_TEMPORARY: S = new (Context) CXXBindTemporaryExpr(Empty); break; diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index cf93d1c..b8ada04 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -245,6 +245,9 @@ void ASTTypeWriter::VisitUnaryTransformType(const UnaryTransformType *T) { void ASTTypeWriter::VisitAutoType(const AutoType *T) { Writer.AddTypeRef(T->getDeducedType(), Record); + Record.push_back(T->isDecltypeAuto()); + if (T->getDeducedType().isNull()) + Record.push_back(T->isDependentType()); Code = TYPE_AUTO; } @@ -907,6 +910,7 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(DECL_OBJC_PROPERTY); RECORD(DECL_OBJC_PROPERTY_IMPL); RECORD(DECL_FIELD); + RECORD(DECL_MS_PROPERTY); RECORD(DECL_VAR); RECORD(DECL_IMPLICIT_PARAM); RECORD(DECL_PARM_VAR); @@ -1069,6 +1073,7 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, I != IEnd; ++I) { AddString(*I, Record); } + Record.push_back(LangOpts.CommentOpts.ParseAllComments); Stream.EmitRecord(LANGUAGE_OPTIONS, Record); @@ -1167,6 +1172,8 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, AddString(PPOpts.MacroIncludes[I], Record); Record.push_back(PPOpts.UsePredefines); + // Detailed record is important since it is used for the module cache hash. + Record.push_back(PPOpts.DetailedRecord); AddString(PPOpts.ImplicitPCHInclude, Record); AddString(PPOpts.ImplicitPTHInclude, Record); Record.push_back(static_cast<unsigned>(PPOpts.ObjCXXARCStandardLibrary)); @@ -2005,18 +2012,7 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) { // tokens in it because they are created by the parser, and thus can't // be in a macro definition. const Token &Tok = MI->getReplacementToken(TokNo); - - Record.push_back(Tok.getLocation().getRawEncoding()); - Record.push_back(Tok.getLength()); - - // FIXME: When reading literal tokens, reconstruct the literal pointer - // if it is needed. - AddIdentifierRef(Tok.getIdentifierInfo(), Record); - // FIXME: Should translate token kind to a stable encoding. - Record.push_back(Tok.getKind()); - // FIXME: Should translate token flags to a stable encoding. - Record.push_back(Tok.getFlags()); - + AddToken(Tok, Record); Stream.EmitRecord(PP_TOKEN, Record); Record.clear(); } @@ -2690,11 +2686,11 @@ public: clang::io::Emit16(Out, KeyLen); unsigned DataLen = 4 + 2 + 2; // 2 bytes for each of the method counts for (const ObjCMethodList *Method = &Methods.Instance; Method; - Method = Method->Next) + Method = Method->getNext()) if (Method->Method) DataLen += 4; for (const ObjCMethodList *Method = &Methods.Factory; Method; - Method = Method->Next) + Method = Method->getNext()) if (Method->Method) DataLen += 4; clang::io::Emit16(Out, DataLen); @@ -2720,24 +2716,31 @@ public: clang::io::Emit32(Out, Methods.ID); unsigned NumInstanceMethods = 0; for (const ObjCMethodList *Method = &Methods.Instance; Method; - Method = Method->Next) + Method = Method->getNext()) if (Method->Method) ++NumInstanceMethods; unsigned NumFactoryMethods = 0; for (const ObjCMethodList *Method = &Methods.Factory; Method; - Method = Method->Next) + Method = Method->getNext()) if (Method->Method) ++NumFactoryMethods; - clang::io::Emit16(Out, NumInstanceMethods); - clang::io::Emit16(Out, NumFactoryMethods); + unsigned InstanceBits = Methods.Instance.getBits(); + assert(InstanceBits < 4); + unsigned NumInstanceMethodsAndBits = + (NumInstanceMethods << 2) | InstanceBits; + unsigned FactoryBits = Methods.Factory.getBits(); + assert(FactoryBits < 4); + unsigned NumFactoryMethodsAndBits = (NumFactoryMethods << 2) | FactoryBits; + clang::io::Emit16(Out, NumInstanceMethodsAndBits); + clang::io::Emit16(Out, NumFactoryMethodsAndBits); for (const ObjCMethodList *Method = &Methods.Instance; Method; - Method = Method->Next) + Method = Method->getNext()) if (Method->Method) clang::io::Emit32(Out, Writer.getDeclID(Method->Method)); for (const ObjCMethodList *Method = &Methods.Factory; Method; - Method = Method->Next) + Method = Method->getNext()) if (Method->Method) clang::io::Emit32(Out, Writer.getDeclID(Method->Method)); @@ -2786,12 +2789,12 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) { // Selector already exists. Did it change? bool changed = false; for (ObjCMethodList *M = &Data.Instance; !changed && M && M->Method; - M = M->Next) { + M = M->getNext()) { if (!M->Method->isFromASTFile()) changed = true; } for (ObjCMethodList *M = &Data.Factory; !changed && M && M->Method; - M = M->Next) { + M = M->getNext()) { if (!M->Method->isFromASTFile()) changed = true; } @@ -3096,7 +3099,28 @@ public: for (SmallVector<Decl *, 16>::reverse_iterator D = Decls.rbegin(), DEnd = Decls.rend(); D != DEnd; ++D) - clang::io::Emit32(Out, Writer.getDeclID(*D)); + clang::io::Emit32(Out, Writer.getDeclID(getMostRecentLocalDecl(*D))); + } + + /// \brief Returns the most recent local decl or the given decl if there are + /// no local ones. The given decl is assumed to be the most recent one. + Decl *getMostRecentLocalDecl(Decl *Orig) { + // The only way a "from AST file" decl would be more recent from a local one + // is if it came from a module. + if (!PP.getLangOpts().Modules) + return Orig; + + // Look for a local in the decl chain. + for (Decl *D = Orig; D; D = D->getPreviousDecl()) { + if (!D->isFromASTFile()) + return D; + // If we come up a decl from a (chained-)PCH stop since we won't find a + // local one. + if (D->getOwningModuleID() == 0) + break; + } + + return Orig; } }; } // end anonymous namespace @@ -3626,6 +3650,19 @@ void ASTWriter::WriteAttributes(ArrayRef<const Attr*> Attrs, } } +void ASTWriter::AddToken(const Token &Tok, RecordDataImpl &Record) { + AddSourceLocation(Tok.getLocation(), Record); + Record.push_back(Tok.getLength()); + + // FIXME: When reading literal tokens, reconstruct the literal pointer + // if it is needed. + AddIdentifierRef(Tok.getIdentifierInfo(), Record); + // FIXME: Should translate token kind to a stable encoding. + Record.push_back(Tok.getKind()); + // FIXME: Should translate token flags to a stable encoding. + Record.push_back(Tok.getFlags()); +} + void ASTWriter::AddString(StringRef Str, RecordDataImpl &Record) { Record.push_back(Str.size()); Record.insert(Record.end(), Str.begin(), Str.end()); diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 023599d..67349db 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -81,6 +81,7 @@ namespace clang { void VisitCXXDestructorDecl(CXXDestructorDecl *D); void VisitCXXConversionDecl(CXXConversionDecl *D); void VisitFieldDecl(FieldDecl *D); + void VisitMSPropertyDecl(MSPropertyDecl *D); void VisitIndirectFieldDecl(IndirectFieldDecl *D); void VisitVarDecl(VarDecl *D); void VisitImplicitParamDecl(ImplicitParamDecl *D); @@ -102,6 +103,7 @@ namespace clang { void VisitFriendTemplateDecl(FriendTemplateDecl *D); void VisitStaticAssertDecl(StaticAssertDecl *D); void VisitBlockDecl(BlockDecl *D); + void VisitCapturedDecl(CapturedDecl *D); void VisitEmptyDecl(EmptyDecl *D); void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, @@ -611,6 +613,7 @@ void ASTDeclWriter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { void ASTDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { VisitObjCImplDecl(D); Writer.AddDeclRef(D->getSuperClass(), Record); + Writer.AddSourceLocation(D->getSuperClassLoc(), Record); Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record); Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record); Record.push_back(D->hasNonZeroConstructors()); @@ -662,6 +665,13 @@ void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) { Code = serialization::DECL_FIELD; } +void ASTDeclWriter::VisitMSPropertyDecl(MSPropertyDecl *D) { + VisitDeclaratorDecl(D); + Writer.AddIdentifierRef(D->getGetterId(), Record); + Writer.AddIdentifierRef(D->getSetterId(), Record); + Code = serialization::DECL_MS_PROPERTY; +} + void ASTDeclWriter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { VisitValueDecl(D); Record.push_back(D->getChainingSize()); @@ -677,7 +687,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { VisitRedeclarable(D); VisitDeclaratorDecl(D); Record.push_back(D->getStorageClass()); - Record.push_back(D->isThreadSpecified()); + Record.push_back(D->getTSCSpec()); Record.push_back(D->getInitStyle()); Record.push_back(D->isExceptionVariable()); Record.push_back(D->isNRVOVariable()); @@ -766,7 +776,7 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { // Check things we know are true of *every* PARM_VAR_DECL, which is more than // just us assuming it. - assert(!D->isThreadSpecified() && "PARM_VAR_DECL can't be __thread"); + assert(!D->getTSCSpec() && "PARM_VAR_DECL can't use TLS"); assert(D->getAccess() == AS_none && "PARM_VAR_DECL can't be public/private"); assert(!D->isExceptionVariable() && "PARM_VAR_DECL can't be exception var"); assert(D->getPreviousDecl() == 0 && "PARM_VAR_DECL can't be redecl"); @@ -816,6 +826,15 @@ void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) { Code = serialization::DECL_BLOCK; } +void ASTDeclWriter::VisitCapturedDecl(CapturedDecl *CD) { + Record.push_back(CD->getNumParams()); + VisitDecl(CD); + // Body is stored by VisitCapturedStmt. + for (unsigned i = 0; i < CD->getNumParams(); ++i) + Writer.AddDeclRef(CD->getParam(i), Record); + Code = serialization::DECL_CAPTURED; +} + void ASTDeclWriter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { VisitDecl(D); Record.push_back(D->getLanguage()); @@ -1515,7 +1534,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo // VarDecl Abv->Add(BitCodeAbbrevOp(0)); // StorageClass - Abv->Add(BitCodeAbbrevOp(0)); // isThreadSpecified + Abv->Add(BitCodeAbbrevOp(0)); // getTSCSpec Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable Abv->Add(BitCodeAbbrevOp(0)); // isNRVOVariable @@ -1594,7 +1613,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo // VarDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClass - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isThreadSpecified + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // getTSCSpec Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // CXXDirectInitializer Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isExceptionVariable Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isNRVOVariable diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index b6f1d54..5f7ac01 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Lex/Token.h" #include "llvm/Bitcode/BitstreamWriter.h" using namespace clang; @@ -216,15 +217,19 @@ void ASTStmtWriter::VisitDeclStmt(DeclStmt *S) { Code = serialization::STMT_DECL; } -void ASTStmtWriter::VisitGCCAsmStmt(GCCAsmStmt *S) { +void ASTStmtWriter::VisitAsmStmt(AsmStmt *S) { VisitStmt(S); Record.push_back(S->getNumOutputs()); Record.push_back(S->getNumInputs()); Record.push_back(S->getNumClobbers()); Writer.AddSourceLocation(S->getAsmLoc(), Record); - Writer.AddSourceLocation(S->getRParenLoc(), Record); Record.push_back(S->isVolatile()); Record.push_back(S->isSimple()); +} + +void ASTStmtWriter::VisitGCCAsmStmt(GCCAsmStmt *S) { + VisitAsmStmt(S); + Writer.AddSourceLocation(S->getRParenLoc(), Record); Writer.AddStmt(S->getAsmString()); // Outputs @@ -249,12 +254,72 @@ void ASTStmtWriter::VisitGCCAsmStmt(GCCAsmStmt *S) { } void ASTStmtWriter::VisitMSAsmStmt(MSAsmStmt *S) { - // FIXME: Statement writer not yet implemented for MS style inline asm. - VisitStmt(S); + VisitAsmStmt(S); + Writer.AddSourceLocation(S->getLBraceLoc(), Record); + Writer.AddSourceLocation(S->getEndLoc(), Record); + Record.push_back(S->getNumAsmToks()); + Writer.AddString(S->getAsmString(), Record); + + // Tokens + for (unsigned I = 0, N = S->getNumAsmToks(); I != N; ++I) { + Writer.AddToken(S->getAsmToks()[I], Record); + } + + // Clobbers + for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I) { + Writer.AddString(S->getClobber(I), Record); + } + + // Outputs + for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) { + Writer.AddStmt(S->getOutputExpr(I)); + Writer.AddString(S->getOutputConstraint(I), Record); + } + + // Inputs + for (unsigned I = 0, N = S->getNumInputs(); I != N; ++I) { + Writer.AddStmt(S->getInputExpr(I)); + Writer.AddString(S->getInputConstraint(I), Record); + } Code = serialization::STMT_MSASM; } +void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) { + VisitStmt(S); + // NumCaptures + Record.push_back(std::distance(S->capture_begin(), S->capture_end())); + + // CapturedDecl and captured region kind + Writer.AddDeclRef(S->getCapturedDecl(), Record); + Record.push_back(S->getCapturedRegionKind()); + + Writer.AddDeclRef(S->getCapturedRecordDecl(), Record); + + // Capture inits + for (CapturedStmt::capture_init_iterator I = S->capture_init_begin(), + E = S->capture_init_end(); + I != E; ++I) + Writer.AddStmt(*I); + + // Body + Writer.AddStmt(S->getCapturedStmt()); + + // Captures + for (CapturedStmt::capture_iterator I = S->capture_begin(), + E = S->capture_end(); + I != E; ++I) { + if (I->capturesThis()) + Writer.AddDeclRef(0, Record); + else + Writer.AddDeclRef(I->getCapturedVar(), Record); + Record.push_back(I->getCaptureKind()); + Writer.AddSourceLocation(I->getLocation(), Record); + } + + Code = serialization::STMT_CAPTURED; +} + void ASTStmtWriter::VisitExpr(Expr *E) { VisitStmt(E); Writer.AddTypeRef(E->getType(), Record); @@ -1216,6 +1281,13 @@ void ASTStmtWriter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { Code = serialization::EXPR_CXX_DEFAULT_ARG; } +void ASTStmtWriter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) { + VisitExpr(E); + Writer.AddDeclRef(E->getField(), Record); + Writer.AddSourceLocation(E->getExprLoc(), Record); + Code = serialization::EXPR_CXX_DEFAULT_INIT; +} + void ASTStmtWriter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { VisitExpr(E); Writer.AddCXXTemporary(E->getTemporary(), Record); @@ -1534,6 +1606,16 @@ void ASTStmtWriter::VisitAsTypeExpr(AsTypeExpr *E) { //===----------------------------------------------------------------------===// // Microsoft Expressions and Statements. //===----------------------------------------------------------------------===// +void ASTStmtWriter::VisitMSPropertyRefExpr(MSPropertyRefExpr *E) { + VisitExpr(E); + Record.push_back(E->isArrow()); + Writer.AddStmt(E->getBaseExpr()); + Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record); + Writer.AddSourceLocation(E->getMemberLoc(), Record); + Writer.AddDeclRef(E->getPropertyDecl(), Record); + Code = serialization::EXPR_CXX_PROPERTY_REF_EXPR; +} + void ASTStmtWriter::VisitCXXUuidofExpr(CXXUuidofExpr *E) { VisitExpr(E); Writer.AddSourceRange(E->getSourceRange(), Record); diff --git a/lib/Serialization/GlobalModuleIndex.cpp b/lib/Serialization/GlobalModuleIndex.cpp index f9acb84..b6693e4 100644 --- a/lib/Serialization/GlobalModuleIndex.cpp +++ b/lib/Serialization/GlobalModuleIndex.cpp @@ -818,3 +818,34 @@ GlobalModuleIndex::writeIndex(FileManager &FileMgr, StringRef Path) { // We're done. return EC_None; } + +namespace { + class GlobalIndexIdentifierIterator : public IdentifierIterator { + /// \brief The current position within the identifier lookup table. + IdentifierIndexTable::key_iterator Current; + + /// \brief The end position within the identifier lookup table. + IdentifierIndexTable::key_iterator End; + + public: + explicit GlobalIndexIdentifierIterator(IdentifierIndexTable &Idx) { + Current = Idx.key_begin(); + End = Idx.key_end(); + } + + virtual StringRef Next() { + if (Current == End) + return StringRef(); + + StringRef Result = *Current; + ++Current; + return Result; + } + }; +} + +IdentifierIterator *GlobalModuleIndex::createIdentifierIterator() const { + IdentifierIndexTable &Table = + *static_cast<IdentifierIndexTable *>(IdentifierIndex); + return new GlobalIndexIdentifierIterator(Table); +} diff --git a/lib/StaticAnalyzer/Checkers/AllocationDiagnostics.cpp b/lib/StaticAnalyzer/Checkers/AllocationDiagnostics.cpp new file mode 100644 index 0000000..3dec8a5 --- /dev/null +++ b/lib/StaticAnalyzer/Checkers/AllocationDiagnostics.cpp @@ -0,0 +1,24 @@ +//=- AllocationDiagnostics.cpp - Config options for allocation diags *- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Declares the configuration functions for leaks/allocation diagnostics. +// +//===-------------------------- + +#include "AllocationDiagnostics.h" + +namespace clang { +namespace ento { + +bool shouldIncludeAllocationSiteInLeakDiagnostics(AnalyzerOptions &AOpts) { + return AOpts.getBooleanOption("leak-diagnostics-reference-allocation", + false); +} + +}} diff --git a/lib/StaticAnalyzer/Checkers/AllocationDiagnostics.h b/lib/StaticAnalyzer/Checkers/AllocationDiagnostics.h new file mode 100644 index 0000000..2b314a3 --- /dev/null +++ b/lib/StaticAnalyzer/Checkers/AllocationDiagnostics.h @@ -0,0 +1,31 @@ +//=--- AllocationDiagnostics.h - Config options for allocation diags *- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Declares the configuration functions for leaks/allocation diagnostics. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SA_LIB_CHECKERS_ALLOC_DIAGS_H +#define LLVM_CLANG_SA_LIB_CHECKERS_ALLOC_DIAGS_H + +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" + +namespace clang { namespace ento { + +/// \brief Returns true if leak diagnostics should directly reference +/// the allocatin site (where possible). +/// +/// The default is false. +/// +bool shouldIncludeAllocationSiteInLeakDiagnostics(AnalyzerOptions &AOpts); + +}} + +#endif + diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index 533a324..fba14a0 100644 --- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp @@ -123,18 +123,29 @@ void NilArgChecker::WarnIfNilArg(CheckerContext &C, if (Class == FC_NSArray) { os << "Array element cannot be nil"; } else if (Class == FC_NSDictionary) { - if (Arg == 0) - os << "Dictionary object cannot be nil"; - else { + if (Arg == 0) { + os << "Value stored into '"; + os << GetReceiverInterfaceName(msg) << "' cannot be nil"; + } else { assert(Arg == 1); - os << "Dictionary key cannot be nil"; + os << "'"<< GetReceiverInterfaceName(msg) << "' key cannot be nil"; } } else llvm_unreachable("Missing foundation class for the subscript expr"); } else { - os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '" - << msg.getSelector().getAsString() << "' cannot be nil"; + if (Class == FC_NSDictionary) { + if (Arg == 0) + os << "Value argument "; + else { + assert(Arg == 1); + os << "Key argument "; + } + os << "to '" << msg.getSelector().getAsString() << "' cannot be nil"; + } else { + os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '" + << msg.getSelector().getAsString() << "' cannot be nil"; + } } BugReport *R = new BugReport(*BT, os.str(), N); @@ -377,7 +388,7 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE, // FIXME: If the pointee isn't an integer type, should we flag a warning? // People can do weird stuff with pointers. - if (!T->isIntegerType()) + if (!T->isIntegralOrEnumerationType()) return; uint64_t SourceSize = Ctx.getTypeSize(T); @@ -748,38 +759,81 @@ static bool isKnownNonNilCollectionType(QualType T) { } } -void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS, - CheckerContext &C) const { - ProgramStateRef State = C.getState(); - - // Check if this is the branch for the end of the loop. - SVal CollectionSentinel = State->getSVal(FCS, C.getLocationContext()); - if (CollectionSentinel.isZeroConstant()) - return; - +/// Assumes that the collection is non-nil. +/// +/// If the collection is known to be nil, returns NULL to indicate an infeasible +/// path. +static ProgramStateRef checkCollectionNonNil(CheckerContext &C, + ProgramStateRef State, + const ObjCForCollectionStmt *FCS) { + if (!State) + return NULL; + + SVal CollectionVal = C.getSVal(FCS->getCollection()); + Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>(); + if (!KnownCollection) + return State; + + ProgramStateRef StNonNil, StNil; + llvm::tie(StNonNil, StNil) = State->assume(*KnownCollection); + if (StNil && !StNonNil) { + // The collection is nil. This path is infeasible. + return NULL; + } + + return StNonNil; +} + +/// Assumes that the collection elements are non-nil. +/// +/// This only applies if the collection is one of those known not to contain +/// nil values. +static ProgramStateRef checkElementNonNil(CheckerContext &C, + ProgramStateRef State, + const ObjCForCollectionStmt *FCS) { + if (!State) + return NULL; + // See if the collection is one where we /know/ the elements are non-nil. - const Expr *Collection = FCS->getCollection(); - if (!isKnownNonNilCollectionType(Collection->getType())) - return; - - // FIXME: Copied from ExprEngineObjC. + if (!isKnownNonNilCollectionType(FCS->getCollection()->getType())) + return State; + + const LocationContext *LCtx = C.getLocationContext(); const Stmt *Element = FCS->getElement(); - SVal ElementVar; + + // FIXME: Copied from ExprEngineObjC. + Optional<Loc> ElementLoc; if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) { const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl()); assert(ElemDecl->getInit() == 0); - ElementVar = State->getLValue(ElemDecl, C.getLocationContext()); + ElementLoc = State->getLValue(ElemDecl, LCtx); } else { - ElementVar = State->getSVal(Element, C.getLocationContext()); + ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>(); } - if (!ElementVar.getAs<Loc>()) - return; + if (!ElementLoc) + return State; // Go ahead and assume the value is non-nil. - SVal Val = State->getSVal(ElementVar.castAs<Loc>()); - State = State->assume(Val.castAs<DefinedOrUnknownSVal>(), true); - C.addTransition(State); + SVal Val = State->getSVal(*ElementLoc); + return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true); +} + +void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS, + CheckerContext &C) const { + // Check if this is the branch for the end of the loop. + SVal CollectionSentinel = C.getSVal(FCS); + if (CollectionSentinel.isZeroConstant()) + return; + + ProgramStateRef State = C.getState(); + State = checkCollectionNonNil(C, State, FCS); + State = checkElementNonNil(C, State, FCS); + + if (!State) + C.generateSink(); + else if (State != C.getState()) + C.addTransition(State); } namespace { diff --git a/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt index b7df10e..7da6825 100644 --- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt +++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt @@ -4,6 +4,7 @@ clang_tablegen(Checkers.inc -gen-clang-sa-checkers TARGET ClangSACheckers) add_clang_library(clangStaticAnalyzerCheckers + AllocationDiagnostics.cpp AnalyzerStatsChecker.cpp ArrayBoundChecker.cpp ArrayBoundCheckerV2.cpp @@ -42,8 +43,8 @@ add_clang_library(clangStaticAnalyzerCheckers MallocSizeofChecker.cpp NSAutoreleasePoolChecker.cpp NSErrorChecker.cpp - NonNullParamChecker.cpp NoReturnFunctionChecker.cpp + NonNullParamChecker.cpp ObjCAtSyncChecker.cpp ObjCContainersASTChecker.cpp ObjCContainersChecker.cpp diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index cc55e9f..aa1ca6f 100644 --- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -114,6 +114,8 @@ public: bool isBounded = false, bool ignoreCase = false) const; + void evalStrsep(CheckerContext &C, const CallExpr *CE) const; + // Utility methods std::pair<ProgramStateRef , ProgramStateRef > static assumeZero(CheckerContext &C, @@ -1752,6 +1754,63 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, C.addTransition(state); } +void CStringChecker::evalStrsep(CheckerContext &C, const CallExpr *CE) const { + //char *strsep(char **stringp, const char *delim); + if (CE->getNumArgs() < 2) + return; + + // Sanity: does the search string parameter match the return type? + const Expr *SearchStrPtr = CE->getArg(0); + QualType CharPtrTy = SearchStrPtr->getType()->getPointeeType(); + if (CharPtrTy.isNull() || + CE->getType().getUnqualifiedType() != CharPtrTy.getUnqualifiedType()) + return; + + CurrentFunctionDescription = "strsep()"; + ProgramStateRef State = C.getState(); + const LocationContext *LCtx = C.getLocationContext(); + + // Check that the search string pointer is non-null (though it may point to + // a null string). + SVal SearchStrVal = State->getSVal(SearchStrPtr, LCtx); + State = checkNonNull(C, State, SearchStrPtr, SearchStrVal); + if (!State) + return; + + // Check that the delimiter string is non-null. + const Expr *DelimStr = CE->getArg(1); + SVal DelimStrVal = State->getSVal(DelimStr, LCtx); + State = checkNonNull(C, State, DelimStr, DelimStrVal); + if (!State) + return; + + SValBuilder &SVB = C.getSValBuilder(); + SVal Result; + if (Optional<Loc> SearchStrLoc = SearchStrVal.getAs<Loc>()) { + // Get the current value of the search string pointer, as a char*. + Result = State->getSVal(*SearchStrLoc, CharPtrTy); + + // Invalidate the search string, representing the change of one delimiter + // character to NUL. + State = InvalidateBuffer(C, State, SearchStrPtr, Result); + + // Overwrite the search string pointer. The new value is either an address + // further along in the same string, or NULL if there are no more tokens. + State = State->bindLoc(*SearchStrLoc, + SVB.conjureSymbolVal(getTag(), CE, LCtx, CharPtrTy, + C.blockCount())); + } else { + assert(SearchStrVal.isUnknown()); + // Conjure a symbolic value. It's the best we can do. + Result = SVB.conjureSymbolVal(0, CE, LCtx, C.blockCount()); + } + + // Set the return value, and finish. + State = State->BindExpr(CE, LCtx, Result); + C.addTransition(State); +} + + //===----------------------------------------------------------------------===// // The driver method, and other Checker callbacks. //===----------------------------------------------------------------------===// @@ -1762,6 +1821,7 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { if (!FDecl) return false; + // FIXME: Poorly-factored string switches are slow. FnCheck evalFunction = 0; if (C.isCLibraryFunction(FDecl, "memcpy")) evalFunction = &CStringChecker::evalMemcpy; @@ -1793,6 +1853,8 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { evalFunction = &CStringChecker::evalStrcasecmp; else if (C.isCLibraryFunction(FDecl, "strncasecmp")) evalFunction = &CStringChecker::evalStrncasecmp; + else if (C.isCLibraryFunction(FDecl, "strsep")) + evalFunction = &CStringChecker::evalStrsep; else if (C.isCLibraryFunction(FDecl, "bcopy")) evalFunction = &CStringChecker::evalBcopy; else if (C.isCLibraryFunction(FDecl, "bcmp")) diff --git a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp index 3a57a56..92c0eef 100644 --- a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp @@ -101,6 +101,8 @@ public: // - strncat(dst, src, sizeof(dst) - 1); // - strncat(dst, src, sizeof(dst)); bool WalkAST::containsBadStrncatPattern(const CallExpr *CE) { + if (CE->getNumArgs() != 3) + return false; const Expr *DstArg = CE->getArg(0); const Expr *SrcArg = CE->getArg(1); const Expr *LenArg = CE->getArg(2); diff --git a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp index 7ef13ab..63080ea 100644 --- a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp +++ b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp @@ -345,7 +345,7 @@ void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) { return; // Verify the first argument type is integer. - if (!FPT->getArgType(0)->isIntegerType()) + if (!FPT->getArgType(0)->isIntegralOrUnscopedEnumerationType()) return; // Verify the second argument type is char*. @@ -602,7 +602,7 @@ void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) { if (!PT) return; - if (! PT->getPointeeType()->isIntegerType()) + if (! PT->getPointeeType()->isIntegralOrUnscopedEnumerationType()) return; } else if (FTP->getNumArgs() != 0) @@ -725,7 +725,7 @@ void WalkAST::checkUncheckedReturnValue(CallExpr *CE) { // The arguments must be integers. for (unsigned i = 0; i < FTP->getNumArgs(); i++) - if (! FTP->getArgType(i)->isIntegerType()) + if (! FTP->getArgType(i)->isIntegralOrUnscopedEnumerationType()) return; // Issue a warning. diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td index 3db3fb9..fc35b22 100644 --- a/lib/StaticAnalyzer/Checkers/Checkers.td +++ b/lib/StaticAnalyzer/Checkers/Checkers.td @@ -167,6 +167,11 @@ def ReturnUndefChecker : Checker<"UndefReturn">, //===----------------------------------------------------------------------===// let ParentPackage = Cplusplus in { + +def NewDeleteChecker : Checker<"NewDelete">, + HelpText<"Check for double-free and use-after-free problems. Traces memory managed by new/delete.">, + DescFile<"MallocChecker.cpp">; + } // end: "cplusplus" let ParentPackage = CplusplusAlpha in { @@ -175,8 +180,8 @@ def VirtualCallChecker : Checker<"VirtualCall">, HelpText<"Check virtual function calls during construction or destruction">, DescFile<"VirtualCallChecker.cpp">; -def NewDeleteChecker : Checker<"NewDelete">, - HelpText<"Check for memory leaks, double free, and use-after-free problems. Traces memory managed by new/delete.">, +def NewDeleteLeaksChecker : Checker<"NewDeleteLeaks">, + HelpText<"Check for memory leaks. Traces memory managed by new/delete.">, DescFile<"MallocChecker.cpp">; } // end: "alpha.cplusplus" diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp index f2e3e6d..f336a6e 100644 --- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp @@ -101,7 +101,8 @@ void ReachableCode::computeReachableBlocks() { } } -static const Expr *LookThroughTransitiveAssignments(const Expr *Ex) { +static const Expr * +LookThroughTransitiveAssignmentsAndCommaOperators(const Expr *Ex) { while (Ex) { const BinaryOperator *BO = dyn_cast<BinaryOperator>(Ex->IgnoreParenCasts()); @@ -111,6 +112,10 @@ static const Expr *LookThroughTransitiveAssignments(const Expr *Ex) { Ex = BO->getRHS(); continue; } + if (BO->getOpcode() == BO_Comma) { + Ex = BO->getRHS(); + continue; + } break; } return Ex; @@ -266,7 +271,9 @@ public: if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { // Special case: check for assigning null to a pointer. // This is a common form of defensive programming. - const Expr *RHS = LookThroughTransitiveAssignments(B->getRHS()); + const Expr *RHS = + LookThroughTransitiveAssignmentsAndCommaOperators(B->getRHS()); + RHS = RHS->IgnoreParenCasts(); QualType T = VD->getType(); if (T->isPointerType() || T->isObjCObjectPointerType()) { @@ -274,7 +281,6 @@ public: return; } - RHS = RHS->IgnoreParenCasts(); // Special case: self-assignments. These are often used to shut up // "unused variable" compiler warnings. if (const DeclRefExpr *RhsDR = dyn_cast<DeclRefExpr>(RHS)) @@ -326,7 +332,7 @@ public: // Look through transitive assignments, e.g.: // int x = y = 0; - E = LookThroughTransitiveAssignments(E); + E = LookThroughTransitiveAssignmentsAndCommaOperators(E); // Don't warn on C++ objects (yet) until we can show that their // constructors/destructors don't have side effects. diff --git a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp index 29b4a63..fe12866 100644 --- a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp +++ b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file defines a checkers that display debugging information. +// This file defines checkers that display debugging information. // //===----------------------------------------------------------------------===// diff --git a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index 9f176a4..759aa66 100644 --- a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -27,7 +27,8 @@ namespace { class DynamicTypePropagation: public Checker< check::PreCall, check::PostCall, - check::PostStmt<ImplicitCastExpr> > { + check::PostStmt<ImplicitCastExpr>, + check::PostStmt<CXXNewExpr> > { const ObjCObjectType *getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, CheckerContext &C) const; @@ -38,6 +39,7 @@ public: void checkPreCall(const CallEvent &Call, CheckerContext &C) const; void checkPostCall(const CallEvent &Call, CheckerContext &C) const; void checkPostStmt(const ImplicitCastExpr *CastE, CheckerContext &C) const; + void checkPostStmt(const CXXNewExpr *NewE, CheckerContext &C) const; }; } @@ -190,6 +192,20 @@ void DynamicTypePropagation::checkPostStmt(const ImplicitCastExpr *CastE, return; } +void DynamicTypePropagation::checkPostStmt(const CXXNewExpr *NewE, + CheckerContext &C) const { + if (NewE->isArray()) + return; + + // We only track dynamic type info for regions. + const MemRegion *MR = C.getSVal(NewE).getAsRegion(); + if (!MR) + return; + + C.addTransition(C.getState()->setDynamicTypeInfo(MR, NewE->getType(), + /*CanBeSubclass=*/false)); +} + const ObjCObjectType * DynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, CheckerContext &C) const { diff --git a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp index 5ed28e9..cc940be 100644 --- a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp @@ -437,6 +437,7 @@ visit(const ObjCImplementationDecl *ImplD) const { // Remove ivars invalidated by the partial invalidation methods. They do not // need to be invalidated in the regular invalidation methods. + bool AtImplementationContainsAtLeastOnePartialInvalidationMethod = false; for (MethodSet::iterator I = PartialInfo.InvalidationMethods.begin(), E = PartialInfo.InvalidationMethods.end(); I != E; ++I) { @@ -446,6 +447,8 @@ visit(const ObjCImplementationDecl *ImplD) const { const ObjCMethodDecl *D = ImplD->getMethod(InterfD->getSelector(), InterfD->isInstanceMethod()); if (D && D->hasBody()) { + AtImplementationContainsAtLeastOnePartialInvalidationMethod = true; + bool CalledAnotherInvalidationMethod = false; // The MethodCrowler is going to remove the invalidated ivars. MethodCrawler(Ivars, @@ -471,7 +474,7 @@ visit(const ObjCImplementationDecl *ImplD) const { containsInvalidationMethod(InterfaceD, Info, /*LookForPartial*/ false); // Report an error in case none of the invalidation methods are declared. - if (!Info.needsInvalidation()) { + if (!Info.needsInvalidation() && !PartialInfo.needsInvalidation()) { if (Filter.check_MissingInvalidationMethod) reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD, /*MissingDeclaration*/ true); @@ -520,9 +523,19 @@ visit(const ObjCImplementationDecl *ImplD) const { } // Report an error in case none of the invalidation methods are implemented. - if (!AtImplementationContainsAtLeastOneInvalidationMethod) - reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD, - /*MissingDeclaration*/ false); + if (!AtImplementationContainsAtLeastOneInvalidationMethod) { + if (AtImplementationContainsAtLeastOnePartialInvalidationMethod) { + // Warn on the ivars that were not invalidated by the prrtial + // invalidation methods. + for (IvarSet::const_iterator + I = Ivars.begin(), E = Ivars.end(); I != E; ++I) + reportIvarNeedsInvalidation(I->first, IvarToPopertyMap, 0); + } else { + // Otherwise, no invalidation methods were implemented. + reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD, + /*MissingDeclaration*/ false); + } + } } void IvarInvalidationCheckerImpl:: @@ -551,19 +564,27 @@ reportNoInvalidationMethod(const ObjCIvarDecl *FirstIvarDecl, void IvarInvalidationCheckerImpl:: reportIvarNeedsInvalidation(const ObjCIvarDecl *IvarD, - const IvarToPropMapTy &IvarToPopertyMap, - const ObjCMethodDecl *MethodD) const { + const IvarToPropMapTy &IvarToPopertyMap, + const ObjCMethodDecl *MethodD) const { SmallString<128> sbuf; llvm::raw_svector_ostream os(sbuf); printIvar(os, IvarD, IvarToPopertyMap); os << "needs to be invalidated or set to nil"; - PathDiagnosticLocation MethodDecLocation = - PathDiagnosticLocation::createEnd(MethodD->getBody(), - BR.getSourceManager(), - Mgr.getAnalysisDeclContext(MethodD)); - BR.EmitBasicReport(MethodD, "Incomplete invalidation", - categories::CoreFoundationObjectiveC, os.str(), - MethodDecLocation); + if (MethodD) { + PathDiagnosticLocation MethodDecLocation = + PathDiagnosticLocation::createEnd(MethodD->getBody(), + BR.getSourceManager(), + Mgr.getAnalysisDeclContext(MethodD)); + BR.EmitBasicReport(MethodD, "Incomplete invalidation", + categories::CoreFoundationObjectiveC, os.str(), + MethodDecLocation); + } else { + BR.EmitBasicReport(IvarD, "Incomplete invalidation", + categories::CoreFoundationObjectiveC, os.str(), + PathDiagnosticLocation::createBegin(IvarD, + BR.getSourceManager())); + + } } void IvarInvalidationCheckerImpl::MethodCrawler::markInvalidated( diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 4b0e766..5d3eb65 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -50,7 +50,12 @@ class RefState { Released, // The responsibility for freeing resources has transfered from // this reference. A relinquished symbol should not be freed. - Relinquished }; + Relinquished, + // We are no longer guaranteed to have observed all manipulations + // of this pointer/memory. For example, it could have been + // passed as a parameter to an opaque function. + Escaped + }; const Stmt *S; unsigned K : 2; // Kind enum, but stored as a bitfield. @@ -58,12 +63,15 @@ class RefState { // family. RefState(Kind k, const Stmt *s, unsigned family) - : S(s), K(k), Family(family) {} + : S(s), K(k), Family(family) { + assert(family != AF_None); + } public: bool isAllocated() const { return K == Allocated; } bool isReleased() const { return K == Released; } bool isRelinquished() const { return K == Relinquished; } - AllocationFamily getAllocationFamily() const { + bool isEscaped() const { return K == Escaped; } + AllocationFamily getAllocationFamily() const { return (AllocationFamily)Family; } const Stmt *getStmt() const { return S; } @@ -81,6 +89,9 @@ public: static RefState getRelinquished(unsigned family, const Stmt *s) { return RefState(Relinquished, s, family); } + static RefState getEscaped(const RefState *RS) { + return RefState(Escaped, RS->getStmt(), RS->getAllocationFamily()); + } void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(K); @@ -136,7 +147,7 @@ class MallocChecker : public Checker<check::DeadSymbols, check::PointerEscape, check::ConstPointerEscape, check::PreStmt<ReturnStmt>, - check::PreStmt<CallExpr>, + check::PreCall, check::PostStmt<CallExpr>, check::PostStmt<CXXNewExpr>, check::PreStmt<CXXDeleteExpr>, @@ -164,12 +175,13 @@ public: DefaultBool CMallocPessimistic; DefaultBool CMallocOptimistic; DefaultBool CNewDeleteChecker; + DefaultBool CNewDeleteLeaksChecker; DefaultBool CMismatchedDeallocatorChecker; }; ChecksFilter Filter; - void checkPreStmt(const CallExpr *S, CheckerContext &C) const; + void checkPreCall(const CallEvent &Call, CheckerContext &C) const; void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const; void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const; @@ -282,19 +294,20 @@ private: PointerEscapeKind Kind, bool(*CheckRefState)(const RefState*)) const; - // Used to suppress warnings if they are not related to the tracked family - // (derived from AllocDeallocStmt). - bool isTrackedFamily(AllocationFamily Family) const; - bool isTrackedFamily(CheckerContext &C, const Stmt *AllocDeallocStmt) const; - bool isTrackedFamily(CheckerContext &C, SymbolRef Sym) const; - + ///@{ + /// Tells if a given family/call/symbol is tracked by the current checker. + bool isTrackedByCurrentChecker(AllocationFamily Family) const; + bool isTrackedByCurrentChecker(CheckerContext &C, + const Stmt *AllocDeallocStmt) const; + bool isTrackedByCurrentChecker(CheckerContext &C, SymbolRef Sym) const; + ///@} static bool SummarizeValue(raw_ostream &os, SVal V); static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR); void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange Range, const Expr *DeallocExpr) const; void ReportMismatchedDealloc(CheckerContext &C, SourceRange Range, - const Expr *DeallocExpr, - const RefState *RS) const; + const Expr *DeallocExpr, const RefState *RS, + SymbolRef Sym) const; void ReportOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range, const Expr *DeallocExpr, const Expr *AllocExpr = 0) const; @@ -1007,36 +1020,37 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, if (RsBase) { - bool DeallocMatchesAlloc = - RsBase->getAllocationFamily() == AF_None || - RsBase->getAllocationFamily() == getAllocationFamily(C, ParentExpr); - - // Check if an expected deallocation function matches the real one. - if (!DeallocMatchesAlloc && RsBase->isAllocated()) { - ReportMismatchedDealloc(C, ArgExpr->getSourceRange(), ParentExpr, RsBase); - return 0; - } - - // Check double free. - if (DeallocMatchesAlloc && - (RsBase->isReleased() || RsBase->isRelinquished()) && + // Check for double free first. + if ((RsBase->isReleased() || RsBase->isRelinquished()) && !didPreviousFreeFail(State, SymBase, PreviousRetStatusSymbol)) { ReportDoubleFree(C, ParentExpr->getSourceRange(), RsBase->isReleased(), SymBase, PreviousRetStatusSymbol); return 0; - } - // Check if the memory location being freed is the actual location - // allocated, or an offset. - RegionOffset Offset = R->getAsOffset(); - if (RsBase->isAllocated() && - Offset.isValid() && - !Offset.hasSymbolicOffset() && - Offset.getOffset() != 0) { - const Expr *AllocExpr = cast<Expr>(RsBase->getStmt()); - ReportOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, - AllocExpr); - return 0; + // If the pointer is allocated or escaped, but we are now trying to free it, + // check that the call to free is proper. + } else if (RsBase->isAllocated() || RsBase->isEscaped()) { + + // Check if an expected deallocation function matches the real one. + bool DeallocMatchesAlloc = + RsBase->getAllocationFamily() == getAllocationFamily(C, ParentExpr); + if (!DeallocMatchesAlloc) { + ReportMismatchedDealloc(C, ArgExpr->getSourceRange(), + ParentExpr, RsBase, SymBase); + return 0; + } + + // Check if the memory location being freed is the actual location + // allocated, or an offset. + RegionOffset Offset = R->getAsOffset(); + if (Offset.isValid() && + !Offset.hasSymbolicOffset() && + Offset.getOffset() != 0) { + const Expr *AllocExpr = cast<Expr>(RsBase->getStmt()); + ReportOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, + AllocExpr); + return 0; + } } } @@ -1056,7 +1070,8 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, } } - AllocationFamily Family = RsBase ? RsBase->getAllocationFamily() : AF_None; + AllocationFamily Family = RsBase ? RsBase->getAllocationFamily() + : getAllocationFamily(C, ParentExpr); // Normal free. if (Hold) return State->set<RegionState>(SymBase, @@ -1067,7 +1082,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, RefState::getReleased(Family, ParentExpr)); } -bool MallocChecker::isTrackedFamily(AllocationFamily Family) const { +bool MallocChecker::isTrackedByCurrentChecker(AllocationFamily Family) const { switch (Family) { case AF_Malloc: { if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic) @@ -1081,22 +1096,24 @@ bool MallocChecker::isTrackedFamily(AllocationFamily Family) const { return true; } case AF_None: { - return true; + llvm_unreachable("no family"); } } llvm_unreachable("unhandled family"); } -bool MallocChecker::isTrackedFamily(CheckerContext &C, - const Stmt *AllocDeallocStmt) const { - return isTrackedFamily(getAllocationFamily(C, AllocDeallocStmt)); +bool +MallocChecker::isTrackedByCurrentChecker(CheckerContext &C, + const Stmt *AllocDeallocStmt) const { + return isTrackedByCurrentChecker(getAllocationFamily(C, AllocDeallocStmt)); } -bool MallocChecker::isTrackedFamily(CheckerContext &C, SymbolRef Sym) const { - const RefState *RS = C.getState()->get<RegionState>(Sym); +bool MallocChecker::isTrackedByCurrentChecker(CheckerContext &C, + SymbolRef Sym) const { - return RS ? isTrackedFamily(RS->getAllocationFamily()) - : isTrackedFamily(AF_None); + const RefState *RS = C.getState()->get<RegionState>(Sym); + assert(RS); + return isTrackedByCurrentChecker(RS->getAllocationFamily()); } bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) { @@ -1194,7 +1211,7 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal, !Filter.CNewDeleteChecker) return; - if (!isTrackedFamily(C, DeallocExpr)) + if (!isTrackedByCurrentChecker(C, DeallocExpr)) return; if (ExplodedNode *N = C.generateSink()) { @@ -1236,7 +1253,8 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal, void MallocChecker::ReportMismatchedDealloc(CheckerContext &C, SourceRange Range, const Expr *DeallocExpr, - const RefState *RS) const { + const RefState *RS, + SymbolRef Sym) const { if (!Filter.CMismatchedDeallocatorChecker) return; @@ -1266,7 +1284,9 @@ void MallocChecker::ReportMismatchedDealloc(CheckerContext &C, os << ", not " << DeallocOs.str(); BugReport *R = new BugReport(*BT_MismatchedDealloc, os.str(), N); + R->markInteresting(Sym); R->addRange(Range); + R->addVisitor(new MallocBugVisitor(Sym)); C.emitReport(R); } } @@ -1279,7 +1299,7 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal, !Filter.CNewDeleteChecker) return; - if (!isTrackedFamily(C, AllocExpr)) + if (!isTrackedByCurrentChecker(C, AllocExpr)) return; ExplodedNode *N = C.generateSink(); @@ -1331,7 +1351,7 @@ void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range, !Filter.CNewDeleteChecker) return; - if (!isTrackedFamily(C, Sym)) + if (!isTrackedByCurrentChecker(C, Sym)) return; if (ExplodedNode *N = C.generateSink()) { @@ -1356,7 +1376,7 @@ void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range, !Filter.CNewDeleteChecker) return; - if (!isTrackedFamily(C, Sym)) + if (!isTrackedByCurrentChecker(C, Sym)) return; if (ExplodedNode *N = C.generateSink()) { @@ -1510,13 +1530,19 @@ MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym, // Find the most recent expression bound to the symbol in the current // context. - if (!ReferenceRegion) { - if (const MemRegion *MR = C.getLocationRegionIfPostStore(N)) { - SVal Val = State->getSVal(MR); - if (Val.getAsLocSymbol() == Sym) - ReferenceRegion = MR; + if (!ReferenceRegion) { + if (const MemRegion *MR = C.getLocationRegionIfPostStore(N)) { + SVal Val = State->getSVal(MR); + if (Val.getAsLocSymbol() == Sym) { + const VarRegion* VR = MR->getBaseRegion()->getAs<VarRegion>(); + // Do not show local variables belonging to a function other than + // where the error is reported. + if (!VR || + (VR->getStackFrame() == LeakContext->getCurrentStackFrame())) + ReferenceRegion = MR; + } + } } - } // Allocation node, is the last node in the current context in which the // symbol was tracked. @@ -1532,12 +1558,21 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const { if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic && - !Filter.CNewDeleteChecker) + !Filter.CNewDeleteLeaksChecker) return; - if (!isTrackedFamily(C, Sym)) + const RefState *RS = C.getState()->get<RegionState>(Sym); + assert(RS && "cannot leak an untracked symbol"); + AllocationFamily Family = RS->getAllocationFamily(); + if (!isTrackedByCurrentChecker(Family)) return; + // Special case for new and new[]; these are controlled by a separate checker + // flag so that they can be selectively disabled. + if (Family == AF_CXXNew || Family == AF_CXXNewArray) + if (!Filter.CNewDeleteLeaksChecker) + return; + assert(N); if (!BT_Leak) { BT_Leak.reset(new BugType("Memory leak", "Memory Error")); @@ -1570,11 +1605,11 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N, SmallString<200> buf; llvm::raw_svector_ostream os(buf); - os << "Memory is never released; potential leak"; if (Region && Region->canPrintPretty()) { - os << " of memory pointed to by '"; + os << "Potential leak of memory pointed to by "; Region->printPretty(os); - os << '\''; + } else { + os << "Potential memory leak"; } BugReport *R = new BugReport(*BT_Leak, os.str(), N, @@ -1638,26 +1673,39 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper, C.addTransition(state->set<RegionState>(RS), N); } -void MallocChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const { +void MallocChecker::checkPreCall(const CallEvent &Call, + CheckerContext &C) const { + // We will check for double free in the post visit. - if ((Filter.CMallocOptimistic || Filter.CMallocPessimistic) && - isFreeFunction(C.getCalleeDecl(CE), C.getASTContext())) - return; + if (const AnyFunctionCall *FC = dyn_cast<AnyFunctionCall>(&Call)) { + const FunctionDecl *FD = FC->getDecl(); + if (!FD) + return; - if (Filter.CNewDeleteChecker && - isStandardNewDelete(C.getCalleeDecl(CE), C.getASTContext())) - return; + if ((Filter.CMallocOptimistic || Filter.CMallocPessimistic) && + isFreeFunction(FD, C.getASTContext())) + return; - // Check use after free, when a freed pointer is passed to a call. - ProgramStateRef State = C.getState(); - for (CallExpr::const_arg_iterator I = CE->arg_begin(), - E = CE->arg_end(); I != E; ++I) { - const Expr *A = *I; - if (A->getType().getTypePtr()->isAnyPointerType()) { - SymbolRef Sym = C.getSVal(A).getAsSymbol(); + if (Filter.CNewDeleteChecker && + isStandardNewDelete(FD, C.getASTContext())) + return; + } + + // Check if the callee of a method is deleted. + if (const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&Call)) { + SymbolRef Sym = CC->getCXXThisVal().getAsSymbol(); + if (!Sym || checkUseAfterFree(Sym, C, CC->getCXXThisExpr())) + return; + } + + // Check arguments for being used after free. + for (unsigned I = 0, E = Call.getNumArgs(); I != E; ++I) { + SVal ArgSVal = Call.getArgSVal(I); + if (ArgSVal.getAs<Loc>()) { + SymbolRef Sym = ArgSVal.getAsSymbol(); if (!Sym) continue; - if (checkUseAfterFree(Sym, C, A)) + if (checkUseAfterFree(Sym, C, Call.getArgExpr(I))) return; } } @@ -1976,8 +2024,10 @@ ProgramStateRef MallocChecker::checkPointerEscapeAux(ProgramStateRef State, SymbolRef sym = *I; if (const RefState *RS = State->get<RegionState>(sym)) { - if (RS->isAllocated() && CheckRefState(RS)) + if (RS->isAllocated() && CheckRefState(RS)) { State = State->remove<RegionState>(sym); + State = State->set<RegionState>(sym, RefState::getEscaped(RS)); + } } } return State; @@ -2042,7 +2092,7 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N, } else if (isReleased(RS, RSPrev, S)) { Msg = "Memory is released"; StackHint = new StackHintGeneratorForSymbol(Sym, - "Returned released memory"); + "Returning; memory was released"); } else if (isRelinquished(RS, RSPrev, S)) { Msg = "Memory ownership is transfered"; StackHint = new StackHintGeneratorForSymbol(Sym, ""); @@ -2102,6 +2152,14 @@ void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State, } } +void ento::registerNewDeleteLeaksChecker(CheckerManager &mgr) { + registerCStringCheckerBasic(mgr); + mgr.registerChecker<MallocChecker>()->Filter.CNewDeleteLeaksChecker = true; + // We currently treat NewDeleteLeaks checker as a subchecker of NewDelete + // checker. + mgr.registerChecker<MallocChecker>()->Filter.CNewDeleteChecker = true; +} + #define REGISTER_CHECKER(name) \ void ento::register##name(CheckerManager &mgr) {\ registerCStringCheckerBasic(mgr); \ diff --git a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp index ce7d4cc..d29f34f 100644 --- a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp @@ -188,7 +188,7 @@ public: for (CallExpr::const_arg_iterator ai = i->AllocCall->arg_begin(), ae = i->AllocCall->arg_end(); ai != ae; ++ai) { - if (!(*ai)->getType()->isIntegerType()) + if (!(*ai)->getType()->isIntegralOrUnscopedEnumerationType()) continue; SizeofFinder SFinder; diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index 79409e8..0f456ea 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -37,6 +37,8 @@ #include "llvm/ADT/StringExtras.h" #include <cstdarg> +#include "AllocationDiagnostics.h" + using namespace clang; using namespace ento; using llvm::StrInStrNoCase; @@ -324,7 +326,7 @@ void RefVal::print(raw_ostream &Out) const { break; case RefVal::ErrorOverAutorelease: - Out << "Over autoreleased"; + Out << "Over-autoreleased"; break; case RefVal::ErrorReturnedNotOwned: @@ -1114,12 +1116,14 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) { // correctly. ScratchArgs = AF.add(ScratchArgs, 12, StopTracking); S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); - } else if (FName == "dispatch_set_context") { + } else if (FName == "dispatch_set_context" || + FName == "xpc_connection_set_context") { // <rdar://problem/11059275> - The analyzer currently doesn't have // a good way to reason about the finalizer function for libdispatch. // If we pass a context object that is memory managed, stop tracking it. + // <rdar://problem/13783514> - Same problem, but for XPC. // FIXME: this hack should possibly go away once we can handle - // libdispatch finalizers. + // libdispatch and XPC finalizers. ScratchArgs = AF.add(ScratchArgs, 1, StopTracking); S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); } else if (FName.startswith("NSLog")) { @@ -1660,10 +1664,10 @@ namespace { class OverAutorelease : public CFRefBug { public: OverAutorelease() - : CFRefBug("Object sent -autorelease too many times") {} + : CFRefBug("Object autoreleased too many times") {} const char *getDescription() const { - return "Object sent -autorelease too many times"; + return "Object autoreleased too many times"; } }; @@ -1773,11 +1777,11 @@ namespace { class CFRefLeakReport : public CFRefReport { const MemRegion* AllocBinding; - public: CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, bool GCEnabled, const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym, - CheckerContext &Ctx); + CheckerContext &Ctx, + bool IncludeAllocationLine); PathDiagnosticLocation getLocation(const SourceManager &SM) const { assert(Location.isValid()); @@ -2048,7 +2052,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N, return 0; assert(PrevV.getAutoreleaseCount() < CurrV.getAutoreleaseCount()); - os << "Object sent -autorelease message"; + os << "Object autoreleased"; break; } @@ -2134,32 +2138,86 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N, // Find the first node in the current function context that referred to the // tracked symbol and the memory location that value was stored to. Note, the // value is only reported if the allocation occurred in the same function as -// the leak. -static std::pair<const ExplodedNode*,const MemRegion*> +// the leak. The function can also return a location context, which should be +// treated as interesting. +struct AllocationInfo { + const ExplodedNode* N; + const MemRegion *R; + const LocationContext *InterestingMethodContext; + AllocationInfo(const ExplodedNode *InN, + const MemRegion *InR, + const LocationContext *InInterestingMethodContext) : + N(InN), R(InR), InterestingMethodContext(InInterestingMethodContext) {} +}; + +static AllocationInfo GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N, SymbolRef Sym) { - const ExplodedNode *Last = N; + const ExplodedNode *AllocationNode = N; + const ExplodedNode *AllocationNodeInCurrentContext = N; const MemRegion* FirstBinding = 0; const LocationContext *LeakContext = N->getLocationContext(); + // The location context of the init method called on the leaked object, if + // available. + const LocationContext *InitMethodContext = 0; + while (N) { ProgramStateRef St = N->getState(); + const LocationContext *NContext = N->getLocationContext(); if (!getRefBinding(St, Sym)) break; StoreManager::FindUniqueBinding FB(Sym); StateMgr.iterBindings(St, FB); - if (FB) FirstBinding = FB.getRegion(); + + if (FB) { + const MemRegion *R = FB.getRegion(); + const VarRegion *VR = R->getBaseRegion()->getAs<VarRegion>(); + // Do not show local variables belonging to a function other than + // where the error is reported. + if (!VR || VR->getStackFrame() == LeakContext->getCurrentStackFrame()) + FirstBinding = R; + } - // Allocation node, is the last node in the current context in which the - // symbol was tracked. - if (N->getLocationContext() == LeakContext) - Last = N; + // AllocationNode is the last node in which the symbol was tracked. + AllocationNode = N; + + // AllocationNodeInCurrentContext, is the last node in the current context + // in which the symbol was tracked. + if (NContext == LeakContext) + AllocationNodeInCurrentContext = N; + + // Find the last init that was called on the given symbol and store the + // init method's location context. + if (!InitMethodContext) + if (Optional<CallEnter> CEP = N->getLocation().getAs<CallEnter>()) { + const Stmt *CE = CEP->getCallExpr(); + if (const ObjCMessageExpr *ME = dyn_cast_or_null<ObjCMessageExpr>(CE)) { + const Stmt *RecExpr = ME->getInstanceReceiver(); + if (RecExpr) { + SVal RecV = St->getSVal(RecExpr, NContext); + if (ME->getMethodFamily() == OMF_init && RecV.getAsSymbol() == Sym) + InitMethodContext = CEP->getCalleeContext(); + } + } + } N = N->pred_empty() ? NULL : *(N->pred_begin()); } + // If we are reporting a leak of the object that was allocated with alloc, + // mark its init method as interesting. + const LocationContext *InterestingMethodContext = 0; + if (InitMethodContext) { + const ProgramPoint AllocPP = AllocationNode->getLocation(); + if (Optional<StmtPoint> SP = AllocPP.getAs<StmtPoint>()) + if (const ObjCMessageExpr *ME = SP->getStmtAs<ObjCMessageExpr>()) + if (ME->getMethodFamily() == OMF_alloc) + InterestingMethodContext = InitMethodContext; + } + // If allocation happened in a function different from the leak node context, // do not report the binding. assert(N && "Could not find allocation node"); @@ -2167,7 +2225,9 @@ GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N, FirstBinding = 0; } - return std::make_pair(Last, FirstBinding); + return AllocationInfo(AllocationNodeInCurrentContext, + FirstBinding, + InterestingMethodContext); } PathDiagnosticPiece* @@ -2190,12 +2250,12 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC, // We are reporting a leak. Walk up the graph to get to the first node where // the symbol appeared, and also get the first VarDecl that tracked object // is stored to. - const ExplodedNode *AllocNode = 0; - const MemRegion* FirstBinding = 0; - - llvm::tie(AllocNode, FirstBinding) = + AllocationInfo AllocI = GetAllocationSite(BRC.getStateManager(), EndN, Sym); + const MemRegion* FirstBinding = AllocI.R; + BR.markInteresting(AllocI.InterestingMethodContext); + SourceManager& SM = BRC.getSourceManager(); // Compute an actual location for the leak. Sometimes a leak doesn't @@ -2267,8 +2327,9 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC, CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, bool GCEnabled, const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym, - CheckerContext &Ctx) -: CFRefReport(D, LOpts, GCEnabled, Log, n, sym, false) { + CheckerContext &Ctx, + bool IncludeAllocationLine) + : CFRefReport(D, LOpts, GCEnabled, Log, n, sym, false) { // Most bug reports are cached at the location where they occurred. // With leaks, we want to unique them by the location where they were @@ -2282,9 +2343,13 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, const SourceManager& SMgr = Ctx.getSourceManager(); - llvm::tie(AllocNode, AllocBinding) = // Set AllocBinding. + AllocationInfo AllocI = GetAllocationSite(Ctx.getStateManager(), getErrorNode(), sym); + AllocNode = AllocI.N; + AllocBinding = AllocI.R; + markInteresting(AllocI.InterestingMethodContext); + // Get the SourceLocation for the allocation site. // FIXME: This will crash the analyzer if an allocation comes from an // implicit call. (Currently there are no such allocations in Cocoa, though.) @@ -2295,8 +2360,17 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, else AllocStmt = P.castAs<PostStmt>().getStmt(); assert(AllocStmt && "All allocations must come from explicit calls"); - Location = PathDiagnosticLocation::createBegin(AllocStmt, SMgr, - n->getLocationContext()); + + PathDiagnosticLocation AllocLocation = + PathDiagnosticLocation::createBegin(AllocStmt, SMgr, + AllocNode->getLocationContext()); + Location = AllocLocation; + + // Set uniqieing info, which will be used for unique the bug reports. The + // leaks should be uniqued on the allocation site. + UniqueingLocation = AllocLocation; + UniqueingDecl = AllocNode->getLocationContext()->getDecl(); + // Fill in the description of the bug. Description.clear(); llvm::raw_string_ostream os(Description); @@ -2305,9 +2379,13 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, os << "(when using garbage collection) "; os << "of an object"; - // FIXME: AllocBinding doesn't get populated for RegionStore yet. - if (AllocBinding) + if (AllocBinding) { os << " stored into '" << AllocBinding->getString() << '\''; + if (IncludeAllocationLine) { + FullSourceLoc SL(AllocStmt->getLocStart(), Ctx.getSourceManager()); + os << " (allocated on line " << SL.getSpellingLineNumber() << ")"; + } + } addVisitor(new CFRefLeakReportVisitor(sym, GCEnabled, Log)); } @@ -2348,8 +2426,14 @@ class RetainCountChecker mutable SummaryLogTy SummaryLog; mutable bool ShouldResetSummaryLog; + /// Optional setting to indicate if leak reports should include + /// the allocation line. + mutable bool IncludeAllocationLine; + public: - RetainCountChecker() : ShouldResetSummaryLog(false) {} + RetainCountChecker(AnalyzerOptions &AO) + : ShouldResetSummaryLog(false), + IncludeAllocationLine(shouldIncludeAllocationSiteInLeakDiagnostics(AO)) {} virtual ~RetainCountChecker() { DeleteContainerSeconds(DeadSymbolTags); @@ -3294,7 +3378,8 @@ void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S, CFRefReport *report = new CFRefLeakReport(*getLeakAtReturnBug(LOpts, GCEnabled), LOpts, GCEnabled, SummaryLog, - N, Sym, C); + N, Sym, C, IncludeAllocationLine); + C.emitReport(report); } } @@ -3480,10 +3565,12 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state, if (N) { SmallString<128> sbuf; llvm::raw_svector_ostream os(sbuf); - os << "Object over-autoreleased: object was sent -autorelease "; + os << "Object was autoreleased "; if (V.getAutoreleaseCount() > 1) - os << V.getAutoreleaseCount() << " times "; - os << "but the object has a +" << V.getCount() << " retain count"; + os << V.getAutoreleaseCount() << " times but the object "; + else + os << "but "; + os << "has a +" << V.getCount() << " retain count"; if (!overAutorelease) overAutorelease.reset(new OverAutorelease()); @@ -3534,7 +3621,8 @@ RetainCountChecker::processLeaks(ProgramStateRef state, assert(BT && "BugType not initialized."); CFRefLeakReport *report = new CFRefLeakReport(*BT, LOpts, GCEnabled, - SummaryLog, N, *I, Ctx); + SummaryLog, N, *I, Ctx, + IncludeAllocationLine); Ctx.emitReport(report); } } @@ -3656,6 +3744,6 @@ void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State, //===----------------------------------------------------------------------===// void ento::registerRetainCountChecker(CheckerManager &Mgr) { - Mgr.registerChecker<RetainCountChecker>(); + Mgr.registerChecker<RetainCountChecker>(Mgr.getAnalyzerOptions()); } diff --git a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp index 7a5d993..ed96c40 100644 --- a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp @@ -55,8 +55,17 @@ void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS, // void test() { // return foo(); // } - if (RT.isNull() || !RT->isVoidType()) - emitUndef(C, RetE); + if (!RT.isNull() && RT->isVoidType()) + return; + + // Not all blocks have explicitly-specified return types; if the return type + // is not available, but the return value expression has 'void' type, assume + // Sema already checked it. + if (RT.isNull() && isa<BlockDecl>(SFC->getDecl()) && + RetE->getType()->isVoidType()) + return; + + emitUndef(C, RetE); return; } diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp index 8f8eb3b..a85235c 100644 --- a/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -52,77 +52,22 @@ void BugReporterContext::anchor() {} // Helper routines for walking the ExplodedGraph and fetching statements. //===----------------------------------------------------------------------===// -static inline const Stmt *GetStmt(const ProgramPoint &P) { - if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) - return SP->getStmt(); - if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) - return BE->getSrc()->getTerminator(); - if (Optional<CallEnter> CE = P.getAs<CallEnter>()) - return CE->getCallExpr(); - if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) - return CEE->getCalleeContext()->getCallSite(); - - return 0; -} - -static inline const ExplodedNode* -GetPredecessorNode(const ExplodedNode *N) { - return N->pred_empty() ? NULL : *(N->pred_begin()); -} - -static inline const ExplodedNode* -GetSuccessorNode(const ExplodedNode *N) { - return N->succ_empty() ? NULL : *(N->succ_begin()); -} - static const Stmt *GetPreviousStmt(const ExplodedNode *N) { - for (N = GetPredecessorNode(N); N; N = GetPredecessorNode(N)) - if (const Stmt *S = GetStmt(N->getLocation())) + for (N = N->getFirstPred(); N; N = N->getFirstPred()) + if (const Stmt *S = PathDiagnosticLocation::getStmt(N)) return S; return 0; } -static const Stmt *GetNextStmt(const ExplodedNode *N) { - for (N = GetSuccessorNode(N); N; N = GetSuccessorNode(N)) - if (const Stmt *S = GetStmt(N->getLocation())) { - // Check if the statement is '?' or '&&'/'||'. These are "merges", - // not actual statement points. - switch (S->getStmtClass()) { - case Stmt::ChooseExprClass: - case Stmt::BinaryConditionalOperatorClass: continue; - case Stmt::ConditionalOperatorClass: continue; - case Stmt::BinaryOperatorClass: { - BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode(); - if (Op == BO_LAnd || Op == BO_LOr) - continue; - break; - } - default: - break; - } - return S; - } - - return 0; -} - static inline const Stmt* GetCurrentOrPreviousStmt(const ExplodedNode *N) { - if (const Stmt *S = GetStmt(N->getLocation())) + if (const Stmt *S = PathDiagnosticLocation::getStmt(N)) return S; return GetPreviousStmt(N); } -static inline const Stmt* -GetCurrentOrNextStmt(const ExplodedNode *N) { - if (const Stmt *S = GetStmt(N->getLocation())) - return S; - - return GetNextStmt(N); -} - //===----------------------------------------------------------------------===// // Diagnostic cleanup. //===----------------------------------------------------------------------===// @@ -198,10 +143,16 @@ static void removeRedundantMsgs(PathPieces &path) { } } +/// A map from PathDiagnosticPiece to the LocationContext of the inlined +/// function call it represents. +typedef llvm::DenseMap<const PathPieces *, const LocationContext *> + LocationContextMap; + /// Recursively scan through a path and prune out calls and macros pieces /// that aren't needed. Return true if afterwards the path contains /// "interesting stuff" which means it shouldn't be pruned from the parent path. -bool BugReporter::RemoveUnneededCalls(PathPieces &pieces, BugReport *R) { +static bool removeUnneededCalls(PathPieces &pieces, BugReport *R, + LocationContextMap &LCM) { bool containsSomethingInteresting = false; const unsigned N = pieces.size(); @@ -222,13 +173,13 @@ bool BugReporter::RemoveUnneededCalls(PathPieces &pieces, BugReport *R) { case PathDiagnosticPiece::Call: { PathDiagnosticCallPiece *call = cast<PathDiagnosticCallPiece>(piece); // Check if the location context is interesting. - assert(LocationContextMap.count(call)); - if (R->isInteresting(LocationContextMap[call])) { + assert(LCM.count(&call->path)); + if (R->isInteresting(LCM[&call->path])) { containsSomethingInteresting = true; break; } - if (!RemoveUnneededCalls(call->path, R)) + if (!removeUnneededCalls(call->path, R, LCM)) continue; containsSomethingInteresting = true; @@ -236,7 +187,7 @@ bool BugReporter::RemoveUnneededCalls(PathPieces &pieces, BugReport *R) { } case PathDiagnosticPiece::Macro: { PathDiagnosticMacroPiece *macro = cast<PathDiagnosticMacroPiece>(piece); - if (!RemoveUnneededCalls(macro->subPieces, R)) + if (!removeUnneededCalls(macro->subPieces, R, LCM)) continue; containsSomethingInteresting = true; break; @@ -355,7 +306,7 @@ public: PathDiagnosticLocation PathDiagnosticBuilder::ExecutionContinues(const ExplodedNode *N) { - if (const Stmt *S = GetNextStmt(N)) + if (const Stmt *S = PathDiagnosticLocation::getNextStmt(N)) return PathDiagnosticLocation(S, getSourceManager(), LC); return PathDiagnosticLocation::createDeclEnd(N->getLocationContext(), @@ -566,6 +517,7 @@ static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM); static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N, + LocationContextMap &LCM, ArrayRef<BugReporterVisitor *> visitors) { SourceManager& SMgr = PDB.getSourceManager(); @@ -578,7 +530,7 @@ static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD, while (NextNode) { N = NextNode; PDB.LC = N->getLocationContext(); - NextNode = GetPredecessorNode(N); + NextNode = N->getFirstPred(); ProgramPoint P = N->getLocation(); @@ -586,8 +538,8 @@ static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD, if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) { PathDiagnosticCallPiece *C = PathDiagnosticCallPiece::construct(N, *CE, SMgr); - GRBugReporter& BR = PDB.getBugReporter(); - BR.addCallPieceLocationContextPair(C, CE->getCalleeContext()); + // Record the mapping from call piece to LocationContext. + LCM[&C->path] = CE->getCalleeContext(); PD.getActivePath().push_front(C); PD.pushActivePath(&C->path); CallStack.push_back(StackDiagPair(C, N)); @@ -610,8 +562,8 @@ static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD, } else { const Decl *Caller = CE->getLocationContext()->getDecl(); C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller); - GRBugReporter& BR = PDB.getBugReporter(); - BR.addCallPieceLocationContextPair(C, CE->getCalleeContext()); + // Record the mapping from call piece to LocationContext. + LCM[&C->path] = CE->getCalleeContext(); } C->setCallee(*CE, SMgr); @@ -640,7 +592,7 @@ static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD, case Stmt::GotoStmtClass: case Stmt::IndirectGotoStmtClass: { - const Stmt *S = GetNextStmt(N); + const Stmt *S = PathDiagnosticLocation::getNextStmt(N); if (!S) break; @@ -929,6 +881,50 @@ public: bool isDead() const { return IsDead; } }; +static PathDiagnosticLocation cleanUpLocation(PathDiagnosticLocation L, + const LocationContext *LC, + bool firstCharOnly = false) { + if (const Stmt *S = L.asStmt()) { + const Stmt *Original = S; + while (1) { + // Adjust the location for some expressions that are best referenced + // by one of their subexpressions. + switch (S->getStmtClass()) { + default: + break; + case Stmt::ParenExprClass: + case Stmt::GenericSelectionExprClass: + S = cast<Expr>(S)->IgnoreParens(); + firstCharOnly = true; + continue; + case Stmt::BinaryConditionalOperatorClass: + case Stmt::ConditionalOperatorClass: + S = cast<AbstractConditionalOperator>(S)->getCond(); + firstCharOnly = true; + continue; + case Stmt::ChooseExprClass: + S = cast<ChooseExpr>(S)->getCond(); + firstCharOnly = true; + continue; + case Stmt::BinaryOperatorClass: + S = cast<BinaryOperator>(S)->getLHS(); + firstCharOnly = true; + continue; + } + + break; + } + + if (S != Original) + L = PathDiagnosticLocation(S, L.getManager(), LC); + } + + if (firstCharOnly) + L = PathDiagnosticLocation::createSingleLocation(L); + + return L; +} + class EdgeBuilder { std::vector<ContextLocation> CLocs; typedef std::vector<ContextLocation>::iterator iterator; @@ -943,53 +939,12 @@ class EdgeBuilder { PathDiagnosticLocation getContextLocation(const PathDiagnosticLocation &L); - PathDiagnosticLocation cleanUpLocation(PathDiagnosticLocation L, - bool firstCharOnly = false) { - if (const Stmt *S = L.asStmt()) { - const Stmt *Original = S; - while (1) { - // Adjust the location for some expressions that are best referenced - // by one of their subexpressions. - switch (S->getStmtClass()) { - default: - break; - case Stmt::ParenExprClass: - case Stmt::GenericSelectionExprClass: - S = cast<Expr>(S)->IgnoreParens(); - firstCharOnly = true; - continue; - case Stmt::BinaryConditionalOperatorClass: - case Stmt::ConditionalOperatorClass: - S = cast<AbstractConditionalOperator>(S)->getCond(); - firstCharOnly = true; - continue; - case Stmt::ChooseExprClass: - S = cast<ChooseExpr>(S)->getCond(); - firstCharOnly = true; - continue; - case Stmt::BinaryOperatorClass: - S = cast<BinaryOperator>(S)->getLHS(); - firstCharOnly = true; - continue; - } - - break; - } - if (S != Original) - L = PathDiagnosticLocation(S, L.getManager(), PDB.LC); - } - - if (firstCharOnly) - L = PathDiagnosticLocation::createSingleLocation(L); - - return L; - } void popLocation() { if (!CLocs.back().isDead() && CLocs.back().asLocation().isFileID()) { // For contexts, we only one the first character as the range. - rawAddEdge(cleanUpLocation(CLocs.back(), true)); + rawAddEdge(cleanUpLocation(CLocs.back(), PDB.LC, true)); } CLocs.pop_back(); } @@ -1026,7 +981,8 @@ public: PrevLoc = PathDiagnosticLocation(); } - void addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd = false); + void addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd = false, + bool IsPostJump = false); void rawAddEdge(PathDiagnosticLocation NewLoc); @@ -1102,8 +1058,8 @@ void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) { return; } - const PathDiagnosticLocation &NewLocClean = cleanUpLocation(NewLoc); - const PathDiagnosticLocation &PrevLocClean = cleanUpLocation(PrevLoc); + const PathDiagnosticLocation &NewLocClean = cleanUpLocation(NewLoc, PDB.LC); + const PathDiagnosticLocation &PrevLocClean = cleanUpLocation(PrevLoc, PDB.LC); if (PrevLocClean.asLocation().isInvalid()) { PrevLoc = NewLoc; @@ -1122,7 +1078,8 @@ void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) { PrevLoc = NewLoc; } -void EdgeBuilder::addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd) { +void EdgeBuilder::addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd, + bool IsPostJump) { if (!alwaysAdd && NewLoc.asLocation().isMacroID()) return; @@ -1135,13 +1092,14 @@ void EdgeBuilder::addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd) { // Is the top location context the same as the one for the new location? if (TopContextLoc == CLoc) { if (alwaysAdd) { - if (IsConsumedExpr(TopContextLoc) && - !IsControlFlowExpr(TopContextLoc.asStmt())) - TopContextLoc.markDead(); + if (IsConsumedExpr(TopContextLoc)) + TopContextLoc.markDead(); rawAddEdge(NewLoc); } + if (IsPostJump) + TopContextLoc.markDead(); return; } @@ -1149,13 +1107,13 @@ void EdgeBuilder::addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd) { if (alwaysAdd) { rawAddEdge(NewLoc); - if (IsConsumedExpr(CLoc) && !IsControlFlowExpr(CLoc.asStmt())) { - CLocs.push_back(ContextLocation(CLoc, true)); + if (IsConsumedExpr(CLoc)) { + CLocs.push_back(ContextLocation(CLoc, /*IsDead=*/true)); return; } } - CLocs.push_back(CLoc); + CLocs.push_back(ContextLocation(CLoc, /*IsDead=*/IsPostJump)); return; } @@ -1340,7 +1298,7 @@ static const Stmt *getStmtBeforeCond(ParentMap &PM, const Stmt *Term, if (!isContainedByStmt(PM, Term, S)) return S; } - N = GetPredecessorNode(N); + N = N->getFirstPred(); } return 0; } @@ -1376,6 +1334,7 @@ static bool isInLoopBody(ParentMap &PM, const Stmt *S, const Stmt *Term) { static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N, + LocationContextMap &LCM, ArrayRef<BugReporterVisitor *> visitors) { EdgeBuilder EB(PD, PDB); const SourceManager& SM = PDB.getSourceManager(); @@ -1385,7 +1344,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD, const ExplodedNode *NextNode = N->pred_empty() ? NULL : *(N->pred_begin()); while (NextNode) { N = NextNode; - NextNode = GetPredecessorNode(N); + NextNode = N->getFirstPred(); ProgramPoint P = N->getLocation(); do { @@ -1406,10 +1365,9 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD, PathDiagnosticCallPiece *C = PathDiagnosticCallPiece::construct(N, *CE, SM); - GRBugReporter& BR = PDB.getBugReporter(); - BR.addCallPieceLocationContextPair(C, CE->getCalleeContext()); + LCM[&C->path] = CE->getCalleeContext(); - EB.addEdge(C->callReturn, true); + EB.addEdge(C->callReturn, /*AlwaysAdd=*/true, /*IsPostJump=*/true); EB.flushLocations(); PD.getActivePath().push_front(C); @@ -1444,8 +1402,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD, } else { const Decl *Caller = CE->getLocationContext()->getDecl(); C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller); - GRBugReporter& BR = PDB.getBugReporter(); - BR.addCallPieceLocationContextPair(C, CE->getCalleeContext()); + LCM[&C->path] = CE->getCalleeContext(); } C->setCallee(*CE, SM); @@ -1573,6 +1530,458 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD, return PDB.getBugReport()->isValid(); } +/// \brief Adds a sanitized control-flow diagnostic edge to a path. +static void addEdgeToPath(PathPieces &path, + PathDiagnosticLocation &PrevLoc, + PathDiagnosticLocation NewLoc, + const LocationContext *LC) { + if (!NewLoc.isValid()) + return; + + SourceLocation NewLocL = NewLoc.asLocation(); + if (NewLocL.isInvalid() || NewLocL.isMacroID()) + return; + + if (!PrevLoc.isValid()) { + PrevLoc = NewLoc; + return; + } + + // FIXME: ignore intra-macro edges for now. + if (NewLoc.asLocation().getExpansionLoc() == + PrevLoc.asLocation().getExpansionLoc()) + return; + + path.push_front(new PathDiagnosticControlFlowPiece(NewLoc, + PrevLoc)); + PrevLoc = NewLoc; +} + +static bool +GenerateAlternateExtensivePathDiagnostic(PathDiagnostic& PD, + PathDiagnosticBuilder &PDB, + const ExplodedNode *N, + LocationContextMap &LCM, + ArrayRef<BugReporterVisitor *> visitors) { + + BugReport *report = PDB.getBugReport(); + const SourceManager& SM = PDB.getSourceManager(); + StackDiagVector CallStack; + InterestingExprs IE; + + // Record the last location for a given visited stack frame. + llvm::DenseMap<const StackFrameContext *, PathDiagnosticLocation> + PrevLocMap; + + const ExplodedNode *NextNode = N->getFirstPred(); + while (NextNode) { + N = NextNode; + NextNode = N->getFirstPred(); + ProgramPoint P = N->getLocation(); + const LocationContext *LC = N->getLocationContext(); + assert(!LCM[&PD.getActivePath()] || LCM[&PD.getActivePath()] == LC); + LCM[&PD.getActivePath()] = LC; + PathDiagnosticLocation &PrevLoc = PrevLocMap[LC->getCurrentStackFrame()]; + + do { + if (Optional<PostStmt> PS = P.getAs<PostStmt>()) { + // For expressions, make sure we propagate the + // interesting symbols correctly. + if (const Expr *Ex = PS->getStmtAs<Expr>()) + reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE, + N->getState().getPtr(), Ex, + N->getLocationContext()); + + PathDiagnosticLocation L = + PathDiagnosticLocation(PS->getStmt(), SM, LC); + addEdgeToPath(PD.getActivePath(), PrevLoc, L, LC); + break; + } + + // Have we encountered an exit from a function call? + if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) { + const Stmt *S = CE->getCalleeContext()->getCallSite(); + // Propagate the interesting symbols accordingly. + if (const Expr *Ex = dyn_cast_or_null<Expr>(S)) { + reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE, + N->getState().getPtr(), Ex, + N->getLocationContext()); + } + + // We are descending into a call (backwards). Construct + // a new call piece to contain the path pieces for that call. + PathDiagnosticCallPiece *C = + PathDiagnosticCallPiece::construct(N, *CE, SM); + + // Record the location context for this call piece. + LCM[&C->path] = CE->getCalleeContext(); + + // Add the edge to the return site. + addEdgeToPath(PD.getActivePath(), PrevLoc, C->callReturn, LC); + + // Make the contents of the call the active path for now. + PD.pushActivePath(&C->path); + CallStack.push_back(StackDiagPair(C, N)); + break; + } + + // Have we encountered an entrance to a call? It may be + // the case that we have not encountered a matching + // call exit before this point. This means that the path + // terminated within the call itself. + if (Optional<CallEnter> CE = P.getAs<CallEnter>()) { + // Add an edge to the start of the function. + const Decl *D = CE->getCalleeContext()->getDecl(); + addEdgeToPath(PD.getActivePath(), PrevLoc, + PathDiagnosticLocation::createBegin(D, SM), LC); + + // Did we visit an entire call? + bool VisitedEntireCall = PD.isWithinCall(); + PD.popActivePath(); + + PathDiagnosticCallPiece *C; + if (VisitedEntireCall) { + C = cast<PathDiagnosticCallPiece>(PD.getActivePath().front()); + } else { + const Decl *Caller = CE->getLocationContext()->getDecl(); + C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller); + LCM[&C->path] = CE->getCalleeContext(); + } + C->setCallee(*CE, SM); + + if (!CallStack.empty()) { + assert(CallStack.back().first == C); + CallStack.pop_back(); + } + break; + } + + // Block edges. + if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { + // Does this represent entering a call? If so, look at propagating + // interesting symbols across call boundaries. + if (NextNode) { + const LocationContext *CallerCtx = NextNode->getLocationContext(); + const LocationContext *CalleeCtx = PDB.LC; + if (CallerCtx != CalleeCtx) { + reversePropagateInterestingSymbols(*PDB.getBugReport(), IE, + N->getState().getPtr(), + CalleeCtx, CallerCtx); + } + } + + // Are we jumping to the head of a loop? Add a special diagnostic. + if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) { + PathDiagnosticLocation L(Loop, SM, PDB.LC); + const CompoundStmt *CS = NULL; + + if (const ForStmt *FS = dyn_cast<ForStmt>(Loop)) + CS = dyn_cast<CompoundStmt>(FS->getBody()); + else if (const WhileStmt *WS = dyn_cast<WhileStmt>(Loop)) + CS = dyn_cast<CompoundStmt>(WS->getBody()); + + PathDiagnosticEventPiece *p = + new PathDiagnosticEventPiece(L, "Looping back to the head " + "of the loop"); + p->setPrunable(true); + + addEdgeToPath(PD.getActivePath(), PrevLoc, p->getLocation(), LC); + PD.getActivePath().push_front(p); + + if (CS) { + addEdgeToPath(PD.getActivePath(), PrevLoc, + PathDiagnosticLocation::createEndBrace(CS, SM), LC); + } + } + + const CFGBlock *BSrc = BE->getSrc(); + ParentMap &PM = PDB.getParentMap(); + + if (const Stmt *Term = BSrc->getTerminator()) { + // Are we jumping past the loop body without ever executing the + // loop (because the condition was false)? + if (isLoopJumpPastBody(Term, &*BE) && + !isInLoopBody(PM, + getStmtBeforeCond(PM, + BSrc->getTerminatorCondition(), + N), + Term)) + { + PathDiagnosticLocation L(Term, SM, PDB.LC); + PathDiagnosticEventPiece *PE = + new PathDiagnosticEventPiece(L, "Loop body executed 0 times"); + PE->setPrunable(true); + addEdgeToPath(PD.getActivePath(), PrevLoc, + PE->getLocation(), LC); + PD.getActivePath().push_front(PE); + } + } + break; + } + } while (0); + + if (!NextNode) + continue; + + // Add pieces from custom visitors. + for (ArrayRef<BugReporterVisitor *>::iterator I = visitors.begin(), + E = visitors.end(); + I != E; ++I) { + if (PathDiagnosticPiece *p = (*I)->VisitNode(N, NextNode, PDB, *report)) { + addEdgeToPath(PD.getActivePath(), PrevLoc, p->getLocation(), LC); + PD.getActivePath().push_front(p); + updateStackPiecesWithMessage(p, CallStack); + } + } + } + + return report->isValid(); +} + +const Stmt *getLocStmt(PathDiagnosticLocation L) { + if (!L.isValid()) + return 0; + return L.asStmt(); +} + +const Stmt *getStmtParent(const Stmt *S, ParentMap &PM) { + if (!S) + return 0; + return PM.getParentIgnoreParens(S); +} + +#if 0 +static bool isConditionForTerminator(const Stmt *S, const Stmt *Cond) { + // Note that we intentionally to do not handle || and && here. + switch (S->getStmtClass()) { + case Stmt::ForStmtClass: + return cast<ForStmt>(S)->getCond() == Cond; + case Stmt::WhileStmtClass: + return cast<WhileStmt>(S)->getCond() == Cond; + case Stmt::DoStmtClass: + return cast<DoStmt>(S)->getCond() == Cond; + case Stmt::ChooseExprClass: + return cast<ChooseExpr>(S)->getCond() == Cond; + case Stmt::IndirectGotoStmtClass: + return cast<IndirectGotoStmt>(S)->getTarget() == Cond; + case Stmt::SwitchStmtClass: + return cast<SwitchStmt>(S)->getCond() == Cond; + case Stmt::BinaryConditionalOperatorClass: + return cast<BinaryConditionalOperator>(S)->getCond() == Cond; + case Stmt::ConditionalOperatorClass: + return cast<ConditionalOperator>(S)->getCond() == Cond; + case Stmt::ObjCForCollectionStmtClass: + return cast<ObjCForCollectionStmt>(S)->getElement() == Cond; + default: + return false; + } +} +#endif + +typedef llvm::DenseSet<const PathDiagnosticControlFlowPiece *> + ControlFlowBarrierSet; + +typedef llvm::DenseSet<const PathDiagnosticCallPiece *> + OptimizedCallsSet; + +static bool isBarrier(ControlFlowBarrierSet &CFBS, + const PathDiagnosticControlFlowPiece *P) { + return CFBS.count(P); +} + +static bool optimizeEdges(PathPieces &path, SourceManager &SM, + ControlFlowBarrierSet &CFBS, + OptimizedCallsSet &OCS, + LocationContextMap &LCM) { + bool hasChanges = false; + const LocationContext *LC = LCM[&path]; + assert(LC); + bool isFirst = true; + + for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ) { + bool wasFirst = isFirst; + isFirst = false; + + // Optimize subpaths. + if (PathDiagnosticCallPiece *CallI = dyn_cast<PathDiagnosticCallPiece>(*I)){ + // Record the fact that a call has been optimized so we only do the + // effort once. + if (!OCS.count(CallI)) { + while (optimizeEdges(CallI->path, SM, CFBS, OCS, LCM)) {} + OCS.insert(CallI); + } + ++I; + continue; + } + + // Pattern match the current piece and its successor. + PathDiagnosticControlFlowPiece *PieceI = + dyn_cast<PathDiagnosticControlFlowPiece>(*I); + + if (!PieceI) { + ++I; + continue; + } + + ParentMap &PM = LC->getParentMap(); + const Stmt *s1Start = getLocStmt(PieceI->getStartLocation()); + const Stmt *s1End = getLocStmt(PieceI->getEndLocation()); + const Stmt *level1 = getStmtParent(s1Start, PM); + const Stmt *level2 = getStmtParent(s1End, PM); + + if (wasFirst) { +#if 0 + // Apply the "first edge" case for Rule V. here. + if (s1Start && level1 && isConditionForTerminator(level1, s1Start)) { + PathDiagnosticLocation NewLoc(level2, SM, LC); + PieceI->setStartLocation(NewLoc); + CFBS.insert(PieceI); + return true; + } +#endif + // Apply the "first edge" case for Rule III. here. + if (!isBarrier(CFBS, PieceI) && + level1 && level2 && level2 == PM.getParent(level1)) { + path.erase(I); + // Since we are erasing the current edge at the start of the + // path, just return now so we start analyzing the start of the path + // again. + return true; + } + } + + PathPieces::iterator NextI = I; ++NextI; + if (NextI == E) + break; + + PathDiagnosticControlFlowPiece *PieceNextI = + dyn_cast<PathDiagnosticControlFlowPiece>(*NextI); + + if (!PieceNextI) { + ++I; + continue; + } + + const Stmt *s2Start = getLocStmt(PieceNextI->getStartLocation()); + const Stmt *s2End = getLocStmt(PieceNextI->getEndLocation()); + const Stmt *level3 = getStmtParent(s2Start, PM); + const Stmt *level4 = getStmtParent(s2End, PM); + + // Rule I. + // + // If we have two consecutive control edges whose end/begin locations + // are at the same level (e.g. statements or top-level expressions within + // a compound statement, or siblings share a single ancestor expression), + // then merge them if they have no interesting intermediate event. + // + // For example: + // + // (1.1 -> 1.2) -> (1.2 -> 1.3) becomes (1.1 -> 1.3) because the common + // parent is '1'. Here 'x.y.z' represents the hierarchy of statements. + // + // NOTE: this will be limited later in cases where we add barriers + // to prevent this optimization. + // + if (level1 && level1 == level2 && level1 == level3 && level1 == level4) { + PieceI->setEndLocation(PieceNextI->getEndLocation()); + path.erase(NextI); + hasChanges = true; + continue; + } + + // Rule II. + // + // If we have two consecutive control edges where we decend to a + // subexpression and then pop out merge them. + // + // NOTE: this will be limited later in cases where we add barriers + // to prevent this optimization. + // + // For example: + // + // (1.1 -> 1.1.1) -> (1.1.1 -> 1.2) becomes (1.1 -> 1.2). + if (level1 && level2 && + level1 == level4 && + level2 == level3 && PM.getParentIgnoreParens(level2) == level1) { + PieceI->setEndLocation(PieceNextI->getEndLocation()); + path.erase(NextI); + hasChanges = true; + continue; + } + + // Rule III. + // + // Eliminate unnecessary edges where we descend to a subexpression from + // a statement at the same level as our parent. + // + // NOTE: this will be limited later in cases where we add barriers + // to prevent this optimization. + // + // For example: + // + // (1.1 -> 1.1.1) -> (1.1.1 -> X) becomes (1.1 -> X). + // + if (level1 && level2 && level1 == PM.getParentIgnoreParens(level2)) { + PieceI->setEndLocation(PieceNextI->getEndLocation()); + path.erase(NextI); + hasChanges = true; + continue; + } + + // Rule IV. + // + // Eliminate unnecessary edges where we ascend from a subexpression to + // a statement at the same level as our parent. + // + // NOTE: this will be limited later in cases where we add barriers + // to prevent this optimization. + // + // For example: + // + // (X -> 1.1.1) -> (1.1.1 -> 1.1) becomes (X -> 1.1). + // [first edge] (1.1.1 -> 1.1) -> eliminate + // + if (level2 && level4 && level2 == level3 && level4 == PM.getParent(level2)){ + PieceI->setEndLocation(PieceNextI->getEndLocation()); + path.erase(NextI); + hasChanges = true; + continue; + } +#if 0 + // Rule V. + // + // Replace terminator conditions with terminators when the condition + // itself has no control-flow. + // + // For example: + // + // (X -> condition) -> (condition -> Y) becomes (X -> term) -> (term -> Y) + // [first edge] (condition -> Y) becomes (term -> Y) + // + // This applies to 'if', 'for', 'while', 'do .. while', 'switch'... + // + if (!isBarrier(CFBS, PieceNextI) && + s1End && s1End == s2Start && level2) { + if (isConditionForTerminator(level2, s1End)) { + PathDiagnosticLocation NewLoc(level2, SM, LC); + PieceI->setEndLocation(NewLoc); + PieceNextI->setStartLocation(NewLoc); + CFBS.insert(PieceI); + hasChanges = true; + continue; + } + + } +#endif + + // No changes at this index? Move to the next one. + ++I; + } + + // No changes. + return hasChanges; +} + //===----------------------------------------------------------------------===// // Methods for BugType and subclasses. //===----------------------------------------------------------------------===// @@ -1758,7 +2167,7 @@ const Stmt *BugReport::getStmt() const { S = GetPreviousStmt(ErrorNode); } if (!S) - S = GetStmt(ProgP); + S = PathDiagnosticLocation::getStmt(ErrorNode); return S; } @@ -1785,22 +2194,7 @@ PathDiagnosticLocation BugReport::getLocation(const SourceManager &SM) const { if (ErrorNode) { assert(!Location.isValid() && "Either Location or ErrorNode should be specified but not both."); - - if (const Stmt *S = GetCurrentOrPreviousStmt(ErrorNode)) { - const LocationContext *LC = ErrorNode->getLocationContext(); - - // For member expressions, return the location of the '.' or '->'. - if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) - return PathDiagnosticLocation::createMemberLoc(ME, SM); - // For binary operators, return the location of the operator. - if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) - return PathDiagnosticLocation::createOperatorLoc(B, SM); - - if (ErrorNode->getLocation().getAs<PostStmtPurgeDeadSymbols>()) - return PathDiagnosticLocation::createEnd(S, SM, LC); - - return PathDiagnosticLocation::createBegin(S, SM, LC); - } + return PathDiagnosticLocation::createEndOfPath(ErrorNode, SM); } else { assert(Location.isValid()); return Location; @@ -2010,7 +2404,8 @@ bool TrimmedGraph::popNextReportGraph(ReportGraph &GraphWrapper) { while (true) { // Create the equivalent node in the new graph with the same state // and location. - ExplodedNode *NewN = GNew->getNode(OrigN->getLocation(), OrigN->getState()); + ExplodedNode *NewN = GNew->getNode(OrigN->getLocation(), OrigN->getState(), + OrigN->isSink()); // Store the mapping to the original node. InterExplodedGraphMap::const_iterator IMitr = InverseMap.find(OrigN); @@ -2165,6 +2560,13 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD, typedef PathDiagnosticConsumer::PathGenerationScheme PathGenerationScheme; PathGenerationScheme ActiveScheme = PC.getGenerationScheme(); + if (ActiveScheme == PathDiagnosticConsumer::Extensive) { + AnalyzerOptions &options = getEngine().getAnalysisManager().options; + if (options.getBooleanOption("path-diagnostics-alternate", false)) { + ActiveScheme = PathDiagnosticConsumer::AlternateExtensive; + } + } + TrimmedGraph TrimG(&getGraph(), errorNodes); ReportGraph ErrorGraph; @@ -2186,6 +2588,7 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD, BugReport::VisitorList visitors; unsigned origReportConfigToken, finalReportConfigToken; + LocationContextMap LCM; // While generating diagnostics, it's possible the visitors will decide // new symbols and regions are interesting, or add other visitors based on @@ -2220,12 +2623,19 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD, PD.setEndOfPath(LastPiece); } + // Make sure we get a clean location context map so we don't + // hold onto old mappings. + LCM.clear(); + switch (ActiveScheme) { + case PathDiagnosticConsumer::AlternateExtensive: + GenerateAlternateExtensivePathDiagnostic(PD, PDB, N, LCM, visitors); + break; case PathDiagnosticConsumer::Extensive: - GenerateExtensivePathDiagnostic(PD, PDB, N, visitors); + GenerateExtensivePathDiagnostic(PD, PDB, N, LCM, visitors); break; case PathDiagnosticConsumer::Minimal: - GenerateMinimalPathDiagnostic(PD, PDB, N, visitors); + GenerateMinimalPathDiagnostic(PD, PDB, N, LCM, visitors); break; case PathDiagnosticConsumer::None: GenerateVisitorsOnlyPathDiagnostic(PD, PDB, N, visitors); @@ -2249,12 +2659,19 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD, if (R->shouldPrunePath() && getEngine().getAnalysisManager().options.shouldPrunePaths()) { - bool stillHasNotes = RemoveUnneededCalls(PD.getMutablePieces(), R); + bool stillHasNotes = removeUnneededCalls(PD.getMutablePieces(), R, LCM); assert(stillHasNotes); (void)stillHasNotes; } adjustCallLocations(PD.getMutablePieces()); + + if (ActiveScheme == PathDiagnosticConsumer::AlternateExtensive) { + ControlFlowBarrierSet CFBS; + OptimizedCallsSet OCS; + while (optimizeEdges(PD.getMutablePieces(), getSourceManager(), CFBS, + OCS, LCM)) {} + } } // We found a report and didn't suppress it. diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index f600362..e078745 100644 --- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -41,7 +41,7 @@ bool bugreporter::isDeclRefExprToReference(const Expr *E) { } const Expr *bugreporter::getDerefExpr(const Stmt *S) { - // Pattern match for a few useful cases (do something smarter later): + // Pattern match for a few useful cases: // a[0], p->f, *p const Expr *E = dyn_cast<Expr>(S); if (!E) @@ -61,6 +61,10 @@ const Expr *bugreporter::getDerefExpr(const Stmt *S) { else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { if (ME->isArrow() || isDeclRefExprToReference(ME->getBase())) { return ME->getBase()->IgnoreParenCasts(); + } else { + // If we have a member expr with a dot, the base must have been + // dereferenced. + return getDerefExpr(ME->getBase()); } } else if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) { @@ -69,6 +73,9 @@ const Expr *bugreporter::getDerefExpr(const Stmt *S) { else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(E)) { return AE->getBase(); } + else if (isDeclRefExprToReference(E)) { + return E; + } break; } @@ -307,9 +314,9 @@ public: if (LValue) { if (const MemRegion *MR = LValue->getAsRegion()) { if (MR->canPrintPretty()) { - Out << " (reference to '"; + Out << " (reference to "; MR->printPretty(Out); - Out << "')"; + Out << ")"; } } } else { @@ -411,6 +418,35 @@ void FindLastStoreBRVisitor ::Profile(llvm::FoldingSetNodeID &ID) const { ID.AddBoolean(EnableNullFPSuppression); } +/// Returns true if \p N represents the DeclStmt declaring and initializing +/// \p VR. +static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) { + Optional<PostStmt> P = N->getLocationAs<PostStmt>(); + if (!P) + return false; + + const DeclStmt *DS = P->getStmtAs<DeclStmt>(); + if (!DS) + return false; + + if (DS->getSingleDecl() != VR->getDecl()) + return false; + + const MemSpaceRegion *VarSpace = VR->getMemorySpace(); + const StackSpaceRegion *FrameSpace = dyn_cast<StackSpaceRegion>(VarSpace); + if (!FrameSpace) { + // If we ever directly evaluate global DeclStmts, this assertion will be + // invalid, but this still seems preferable to silently accepting an + // initialization that may be for a path-sensitive variable. + assert(VR->getDecl()->isStaticLocal() && "non-static stackless VarRegion"); + return true; + } + + assert(VR->getDecl()->hasLocalStorage()); + const LocationContext *LCtx = N->getLocationContext(); + return FrameSpace->getStackFrame() == LCtx->getCurrentStackFrame(); +} + PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, const ExplodedNode *Pred, BugReporterContext &BRC, @@ -425,13 +461,9 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, // First see if we reached the declaration of the region. if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { - if (Optional<PostStmt> P = Pred->getLocationAs<PostStmt>()) { - if (const DeclStmt *DS = P->getStmtAs<DeclStmt>()) { - if (DS->getSingleDecl() == VR->getDecl()) { - StoreSite = Pred; - InitE = VR->getDecl()->getInit(); - } - } + if (isInitializationOfVar(Pred, VR)) { + StoreSite = Pred; + InitE = VR->getDecl()->getInit(); } } @@ -511,9 +543,6 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, } } - if (!R->canPrintPretty()) - return 0; - // Okay, we've found the binding. Emit an appropriate message. SmallString<256> sbuf; llvm::raw_svector_ostream os(sbuf); @@ -525,9 +554,11 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, const VarRegion *VR = dyn_cast<VarRegion>(R); if (DS) { - action = "initialized to "; + action = R->canPrintPretty() ? "initialized to " : + "Initializing to "; } else if (isa<BlockExpr>(S)) { - action = "captured by block as "; + action = R->canPrintPretty() ? "captured by block as " : + "Captured by block as "; if (VR) { // See if we can get the BlockVarRegion. ProgramStateRef State = StoreSite->getState(); @@ -545,12 +576,10 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, } if (action) { - if (!R) - return 0; - - os << '\''; - R->printPretty(os); - os << "' "; + if (R->canPrintPretty()) { + R->printPretty(os); + os << " "; + } if (V.getAs<loc::ConcreteInt>()) { bool b = false; @@ -573,14 +602,18 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, if (V.isUndef()) { if (isa<VarRegion>(R)) { const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl()); - if (VD->getInit()) - os << "initialized to a garbage value"; - else - os << "declared without an initial value"; + if (VD->getInit()) { + os << (R->canPrintPretty() ? "initialized" : "Initializing") + << " to a garbage value"; + } else { + os << (R->canPrintPretty() ? "declared" : "Declaring") + << " without an initial value"; + } } } else { - os << "initialized here"; + os << (R->canPrintPretty() ? "initialized" : "Initialized") + << " here"; } } } @@ -606,10 +639,11 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, // Printed parameter indexes are 1-based, not 0-based. unsigned Idx = Param->getFunctionScopeIndex() + 1; - os << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter '"; - - R->printPretty(os); - os << '\''; + os << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter"; + if (R->canPrintPretty()) { + os << " "; + R->printPretty(os); + } } } @@ -619,27 +653,42 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, if (R->isBoundable()) { if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) { if (TR->getValueType()->isObjCObjectPointerType()) { - os << "nil object reference stored to "; + os << "nil object reference stored"; b = true; } } } + if (!b) { + if (R->canPrintPretty()) + os << "Null pointer value stored"; + else + os << "Storing null pointer value"; + } + + } else if (V.isUndef()) { + if (R->canPrintPretty()) + os << "Uninitialized value stored"; + else + os << "Storing uninitialized value"; - if (!b) - os << "Null pointer value stored to "; - } - else if (V.isUndef()) { - os << "Uninitialized value stored to "; } else if (Optional<nonloc::ConcreteInt> CV = V.getAs<nonloc::ConcreteInt>()) { - os << "The value " << CV->getValue() << " is assigned to "; - } - else - os << "Value assigned to "; + if (R->canPrintPretty()) + os << "The value " << CV->getValue() << " is assigned"; + else + os << "Assigning " << CV->getValue(); - os << '\''; - R->printPretty(os); - os << '\''; + } else { + if (R->canPrintPretty()) + os << "Value assigned"; + else + os << "Assigning value"; + } + + if (R->canPrintPretty()) { + os << " to "; + R->printPretty(os); + } } // Construct a new PathDiagnosticPiece. @@ -682,6 +731,14 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, if (IsSatisfied) return NULL; + // Start tracking after we see the first state in which the value is + // constrained. + if (!IsTrackingTurnedOn) + if (!isUnderconstrained(N)) + IsTrackingTurnedOn = true; + if (!IsTrackingTurnedOn) + return 0; + // Check if in the previous state it was feasible for this constraint // to *not* be true. if (isUnderconstrained(PrevN)) { @@ -691,8 +748,7 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, // As a sanity check, make sure that the negation of the constraint // was infeasible in the current state. If it is feasible, we somehow // missed the transition point. - if (isUnderconstrained(N)) - return NULL; + assert(!isUnderconstrained(N)); // We found the transition point for the constraint. We now need to // pretty-print the constraint. (work-in-progress) @@ -853,7 +909,7 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, Inner = Ex; } - if (IsArg) { + if (IsArg && !Inner) { assert(N->getLocation().getAs<CallEnter>() && "Tracking arg but not at call"); } else { // Walk through nodes until we get one that matches the statement exactly. @@ -882,7 +938,7 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, // At this point in the path, the receiver should be live since we are at the // message send expr. If it is nil, start tracking it. if (const Expr *Receiver = NilReceiverBRVisitor::getNilReceiver(S, N)) - trackNullOrUndefValue(N, Receiver, report, IsArg, EnableNullFPSuppression); + trackNullOrUndefValue(N, Receiver, report, false, EnableNullFPSuppression); // See if the expression we're interested refers to a variable. @@ -926,45 +982,24 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, if (R) { // Mark both the variable region and its contents as interesting. - SVal V = state->getRawSVal(loc::MemRegionVal(R)); - - // If the value matches the default for the variable region, that - // might mean that it's been cleared out of the state. Fall back to - // the full argument expression (with casts and such intact). - if (IsArg) { - bool UseArgValue = V.isUnknownOrUndef() || V.isZeroConstant(); - if (!UseArgValue) { - const SymbolRegionValue *SRV = - dyn_cast_or_null<SymbolRegionValue>(V.getAsLocSymbol()); - if (SRV) - UseArgValue = (SRV->getRegion() == R); - } - if (UseArgValue) - V = state->getSValAsScalarOrLoc(S, N->getLocationContext()); - } + SVal V = LVState->getRawSVal(loc::MemRegionVal(R)); report.markInteresting(R); report.markInteresting(V); report.addVisitor(new UndefOrNullArgVisitor(R)); - if (isa<SymbolicRegion>(R)) { - TrackConstraintBRVisitor *VI = - new TrackConstraintBRVisitor(loc::MemRegionVal(R), false); - report.addVisitor(VI); - } - // If the contents are symbolic, find out when they became null. - if (V.getAsLocSymbol()) { + if (V.getAsLocSymbol(/*IncludeBaseRegions*/ true)) { BugReporterVisitor *ConstraintTracker = new TrackConstraintBRVisitor(V.castAs<DefinedSVal>(), false); report.addVisitor(ConstraintTracker); // Add visitor, which will suppress inline defensive checks. - if (N->getState()->isNull(V).isConstrainedTrue() && + if (LVState->isNull(V).isConstrainedTrue() && EnableNullFPSuppression) { BugReporterVisitor *IDCSuppressor = new SuppressInlineDefensiveChecksVisitor(V.castAs<DefinedSVal>(), - N); + LVNode); report.addVisitor(IDCSuppressor); } } @@ -994,7 +1029,13 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, if (Optional<loc::MemRegionVal> L = V.getAs<loc::MemRegionVal>()) { // At this point we are dealing with the region's LValue. // However, if the rvalue is a symbolic region, we should track it as well. - SVal RVal = state->getSVal(L->getRegion()); + // Try to use the correct type when looking up the value. + SVal RVal; + if (const Expr *E = dyn_cast<Expr>(S)) + RVal = state->getRawSVal(L.getValue(), E->getType()); + else + RVal = state->getSVal(L->getRegion()); + const MemRegion *RegionRVal = RVal.getAsRegion(); report.addVisitor(new UndefOrNullArgVisitor(L->getRegion())); @@ -1030,10 +1071,22 @@ PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, if (!P) return 0; - const Expr *Receiver = getNilReceiver(P->getStmt(), N); + const Stmt *S = P->getStmt(); + const Expr *Receiver = getNilReceiver(S, N); if (!Receiver) return 0; + llvm::SmallString<256> Buf; + llvm::raw_svector_ostream OS(Buf); + + if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) { + OS << "'" << ME->getSelector().getAsString() << "' not called"; + } + else { + OS << "No method is called"; + } + OS << " because the receiver is nil"; + // The receiver was nil, and hence the method was skipped. // Register a BugReporterVisitor to issue a message telling us how // the receiver was null. @@ -1042,8 +1095,7 @@ PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, // Issue a message saying that the method was skipped. PathDiagnosticLocation L(Receiver, BRC.getSourceManager(), N->getLocationContext()); - return new PathDiagnosticEventPiece(L, "No method is called " - "because the receiver is nil"); + return new PathDiagnosticEventPiece(L, OS.str()); } // Registers every VarDecl inside a Stmt with a last store visitor. @@ -1372,7 +1424,7 @@ ConditionBRVisitor::VisitConditionVariable(StringRef LhsString, Out << (tookTrue ? "not nil" : "nil"); else if (Ty->isBooleanType()) Out << (tookTrue ? "true" : "false"); - else if (Ty->isIntegerType()) + else if (Ty->isIntegralOrEnumerationType()) Out << (tookTrue ? "non-zero" : "zero"); else return 0; diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp index 45b2e21..dfd20b8 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -239,8 +239,20 @@ QualType CallEvent::getDeclaredResultType(const Decl *D) { assert(D); if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D)) return FD->getResultType(); - else if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(D)) + if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(D)) return MD->getResultType(); + if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) { + // Blocks are difficult because the return type may not be stored in the + // BlockDecl itself. The AST should probably be enhanced, but for now we + // just do what we can. + QualType Ty = BD->getSignatureAsWritten()->getType(); + if (const FunctionType *FT = Ty->getAs<FunctionType>()) + if (!FT->getResultType()->isDependentType()) + return FT->getResultType(); + + return QualType(); + } + return QualType(); } diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp index fe352aa..7b133f6 100644 --- a/lib/StaticAnalyzer/Core/Environment.cpp +++ b/lib/StaticAnalyzer/Core/Environment.cpp @@ -80,43 +80,17 @@ SVal Environment::getSVal(const EnvironmentEntry &Entry, llvm_unreachable("Should have been handled by ignoreTransparentExprs"); case Stmt::AddrLabelExprClass: - return svalBuilder.makeLoc(cast<AddrLabelExpr>(S)); - - case Stmt::CharacterLiteralClass: { - const CharacterLiteral *C = cast<CharacterLiteral>(S); - return svalBuilder.makeIntVal(C->getValue(), C->getType()); - } - + case Stmt::CharacterLiteralClass: case Stmt::CXXBoolLiteralExprClass: - return svalBuilder.makeBoolVal(cast<CXXBoolLiteralExpr>(S)); - case Stmt::CXXScalarValueInitExprClass: - case Stmt::ImplicitValueInitExprClass: { - QualType Ty = cast<Expr>(S)->getType(); - return svalBuilder.makeZeroVal(Ty); - } - + case Stmt::ImplicitValueInitExprClass: case Stmt::IntegerLiteralClass: - return svalBuilder.makeIntVal(cast<IntegerLiteral>(S)); - case Stmt::ObjCBoolLiteralExprClass: - return svalBuilder.makeBoolVal(cast<ObjCBoolLiteralExpr>(S)); - - // For special C0xx nullptr case, make a null pointer SVal. case Stmt::CXXNullPtrLiteralExprClass: - return svalBuilder.makeNull(); - - case Stmt::ObjCStringLiteralClass: { - MemRegionManager &MRMgr = svalBuilder.getRegionManager(); - const ObjCStringLiteral *SL = cast<ObjCStringLiteral>(S); - return svalBuilder.makeLoc(MRMgr.getObjCStringRegion(SL)); - } - - case Stmt::StringLiteralClass: { - MemRegionManager &MRMgr = svalBuilder.getRegionManager(); - const StringLiteral *SL = cast<StringLiteral>(S); - return svalBuilder.makeLoc(MRMgr.getStringRegion(SL)); - } + case Stmt::ObjCStringLiteralClass: + case Stmt::StringLiteralClass: + // Known constants; defer to SValBuilder. + return svalBuilder.getConstantVal(cast<Expr>(S)).getValue(); case Stmt::ReturnStmtClass: { const ReturnStmt *RS = cast<ReturnStmt>(S); @@ -127,10 +101,8 @@ SVal Environment::getSVal(const EnvironmentEntry &Entry, // Handle all other Stmt* using a lookup. default: - break; + return lookupExpr(EnvironmentEntry(S, LCtx)); } - - return lookupExpr(EnvironmentEntry(S, LCtx)); } Environment EnvironmentManager::bindExpr(Environment Env, diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index ab4dbd7..bfe4e15 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -106,7 +106,8 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) { const ParmVarDecl *PD = FD->getParamDecl(0); QualType T = PD->getType(); - if (!T->isIntegerType()) + const BuiltinType *BT = dyn_cast<BuiltinType>(T); + if (!BT || !BT->isInteger()) break; const MemRegion *R = state->getRegion(PD, InitLoc); @@ -180,7 +181,8 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State, } else { // We need to create a region no matter what. For sanity, make sure we don't // try to stuff a Loc into a non-pointer temporary region. - assert(!V.getAs<Loc>() || Loc::isLocType(Result->getType())); + assert(!V.getAs<Loc>() || Loc::isLocType(Result->getType()) || + Result->getType()->isMemberPointerType()); } ProgramStateManager &StateMgr = State->getStateManager(); @@ -602,11 +604,13 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, switch (S->getStmtClass()) { // C++ and ARC stuff we don't support yet. case Expr::ObjCIndirectCopyRestoreExprClass: + case Stmt::CXXDefaultInitExprClass: case Stmt::CXXDependentScopeMemberExprClass: case Stmt::CXXPseudoDestructorExprClass: case Stmt::CXXTryStmtClass: case Stmt::CXXTypeidExprClass: case Stmt::CXXUuidofExprClass: + case Stmt::MSPropertyRefExprClass: case Stmt::CXXUnresolvedConstructExprClass: case Stmt::DependentScopeDeclRefExprClass: case Stmt::UnaryTypeTraitExprClass: @@ -653,6 +657,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::SwitchStmtClass: case Stmt::WhileStmtClass: case Expr::MSDependentExistsStmtClass: + case Stmt::CapturedStmtClass: llvm_unreachable("Stmt should not be in analyzer evaluation loop"); case Stmt::ObjCSubscriptRefExprClass: @@ -736,21 +741,22 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, const CXXDefaultArgExpr *DefaultE = cast<CXXDefaultArgExpr>(S); const Expr *ArgE = DefaultE->getExpr(); - // Avoid creating and destroying a lot of APSInts. - SVal V; - llvm::APSInt Result; + bool IsTemporary = false; + if (const MaterializeTemporaryExpr *MTE = + dyn_cast<MaterializeTemporaryExpr>(ArgE)) { + ArgE = MTE->GetTemporaryExpr(); + IsTemporary = true; + } + + Optional<SVal> ConstantVal = svalBuilder.getConstantVal(ArgE); + if (!ConstantVal) + ConstantVal = UnknownVal(); for (ExplodedNodeSet::iterator I = PreVisit.begin(), E = PreVisit.end(); I != E; ++I) { ProgramStateRef State = (*I)->getState(); - - if (ArgE->EvaluateAsInt(Result, getContext())) - V = svalBuilder.makeIntVal(Result); - else - V = State->getSVal(ArgE, LCtx); - - State = State->BindExpr(DefaultE, LCtx, V); - if (DefaultE->isGLValue()) + State = State->BindExpr(DefaultE, LCtx, *ConstantVal); + if (IsTemporary) State = createTemporaryRegionIfNeeded(State, LCtx, DefaultE, DefaultE); Bldr2.generateNode(S, *I, State); @@ -860,9 +866,13 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, const LocationContext *LCtx = Pred->getLocationContext(); ProgramStateRef NewState = createTemporaryRegionIfNeeded(State, LCtx, OCE->getArg(0)); - if (NewState != State) + if (NewState != State) { Pred = Bldr.generateNode(OCE, Pred, NewState, /*Tag=*/0, ProgramPoint::PreStmtKind); + // Did we cache out? + if (!Pred) + break; + } } } // FALLTHROUGH @@ -1235,7 +1245,7 @@ static SVal RecoverCastedSymbol(ProgramStateManager& StateMgr, while (const CastExpr *CE = dyn_cast<CastExpr>(Ex)) { QualType T = CE->getType(); - if (!T->isIntegerType()) + if (!T->isIntegralOrEnumerationType()) return UnknownVal(); uint64_t newBits = Ctx.getTypeSize(T); @@ -1250,7 +1260,8 @@ static SVal RecoverCastedSymbol(ProgramStateManager& StateMgr, // We reached a non-cast. Is it a symbolic value? QualType T = Ex->getType(); - if (!bitsInit || !T->isIntegerType() || Ctx.getTypeSize(T) > bits) + if (!bitsInit || !T->isIntegralOrEnumerationType() || + Ctx.getTypeSize(T) > bits) return UnknownVal(); return state->getSVal(Ex, LCtx); @@ -1342,7 +1353,7 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term, if (X.isUnknownOrUndef()) { // Give it a chance to recover from unknown. if (const Expr *Ex = dyn_cast<Expr>(Condition)) { - if (Ex->getType()->isIntegerType()) { + if (Ex->getType()->isIntegralOrEnumerationType()) { // Try to recover some path-sensitivity. Right now casts of symbolic // integers that promote their values are currently not tracked well. // If 'Condition' is such an expression, try and recover the @@ -1802,7 +1813,8 @@ ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State, return getCheckerManager().runCheckersForPointerEscape(State, *Invalidated, 0, - PSK_EscapeOther); + PSK_EscapeOther, + IsConst); // Note: Due to current limitations of RegionStore, we only process the top // level const pointers correctly. The lower level const pointers are diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 3a3c971..67aeab6 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -68,12 +68,14 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, // SymSymExpr. unsigned Count = currBldrCtx->blockCount(); if (LeftV.getAs<Loc>() && - RHS->getType()->isIntegerType() && RightV.isUnknown()) { + RHS->getType()->isIntegralOrEnumerationType() && + RightV.isUnknown()) { RightV = svalBuilder.conjureSymbolVal(RHS, LCtx, RHS->getType(), Count); } if (RightV.getAs<Loc>() && - LHS->getType()->isIntegerType() && LeftV.isUnknown()) { + LHS->getType()->isIntegralOrEnumerationType() && + LeftV.isUnknown()) { LeftV = svalBuilder.conjureSymbolVal(LHS, LCtx, LHS->getType(), Count); } @@ -401,26 +403,32 @@ void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL, ExplodedNodeSet &Dst) { StmtNodeBuilder B(Pred, Dst, *currBldrCtx); - const InitListExpr *ILE - = cast<InitListExpr>(CL->getInitializer()->IgnoreParens()); + ProgramStateRef State = Pred->getState(); + const LocationContext *LCtx = Pred->getLocationContext(); + + const Expr *Init = CL->getInitializer(); + SVal V = State->getSVal(CL->getInitializer(), LCtx); - ProgramStateRef state = Pred->getState(); - SVal ILV = state->getSVal(ILE, Pred->getLocationContext()); - const LocationContext *LC = Pred->getLocationContext(); - state = state->bindCompoundLiteral(CL, LC, ILV); - - // Compound literal expressions are a GNU extension in C++. - // Unlike in C, where CLs are lvalues, in C++ CLs are prvalues, - // and like temporary objects created by the functional notation T() - // CLs are destroyed at the end of the containing full-expression. - // HOWEVER, an rvalue of array type is not something the analyzer can - // reason about, since we expect all regions to be wrapped in Locs. - // So we treat array CLs as lvalues as well, knowing that they will decay - // to pointers as soon as they are used. - if (CL->isGLValue() || CL->getType()->isArrayType()) - B.generateNode(CL, Pred, state->BindExpr(CL, LC, state->getLValue(CL, LC))); - else - B.generateNode(CL, Pred, state->BindExpr(CL, LC, ILV)); + if (isa<CXXConstructExpr>(Init)) { + // No work needed. Just pass the value up to this expression. + } else { + assert(isa<InitListExpr>(Init)); + Loc CLLoc = State->getLValue(CL, LCtx); + State = State->bindLoc(CLLoc, V); + + // Compound literal expressions are a GNU extension in C++. + // Unlike in C, where CLs are lvalues, in C++ CLs are prvalues, + // and like temporary objects created by the functional notation T() + // CLs are destroyed at the end of the containing full-expression. + // HOWEVER, an rvalue of array type is not something the analyzer can + // reason about, since we expect all regions to be wrapped in Locs. + // So we treat array CLs as lvalues as well, knowing that they will decay + // to pointers as soon as they are used. + if (CL->isGLValue() || CL->getType()->isArrayType()) + V = CLLoc; + } + + B.generateNode(CL, Pred, State->BindExpr(CL, LCtx, V)); } void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, @@ -615,11 +623,15 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, const Expr *R, ExplodedNode *Pred, ExplodedNodeSet &Dst) { + assert(L && R); + StmtNodeBuilder B(Pred, Dst, *currBldrCtx); ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); const CFGBlock *SrcBlock = 0; + // Find the predecessor block. + ProgramStateRef SrcState = state; for (const ExplodedNode *N = Pred ; N ; N = *N->pred_begin()) { ProgramPoint PP = N->getLocation(); if (PP.getAs<PreStmtPurgeDeadSymbols>() || PP.getAs<BlockEntrance>()) { @@ -627,6 +639,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, continue; } SrcBlock = PP.castAs<BlockEdge>().getSrc(); + SrcState = N->getState(); break; } @@ -642,14 +655,25 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, CFGElement CE = *I; if (Optional<CFGStmt> CS = CE.getAs<CFGStmt>()) { const Expr *ValEx = cast<Expr>(CS->getStmt()); - hasValue = true; - V = state->getSVal(ValEx, LCtx); + ValEx = ValEx->IgnoreParens(); + + // For GNU extension '?:' operator, the left hand side will be an + // OpaqueValueExpr, so get the underlying expression. + if (const OpaqueValueExpr *OpaqueEx = dyn_cast<OpaqueValueExpr>(L)) + L = OpaqueEx->getSourceExpr(); + + // If the last expression in the predecessor block matches true or false + // subexpression, get its the value. + if (ValEx == L->IgnoreParens() || ValEx == R->IgnoreParens()) { + hasValue = true; + V = SrcState->getSVal(ValEx, LCtx); + } break; } } - assert(hasValue); - (void) hasValue; + if (!hasValue) + V = svalBuilder.conjureSymbolVal(0, Ex, LCtx, currBldrCtx->blockCount()); // Generate a new node with the binding from the appropriate path. B.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V, true)); @@ -662,8 +686,9 @@ VisitOffsetOfExpr(const OffsetOfExpr *OOE, APSInt IV; if (OOE->EvaluateAsInt(IV, getContext())) { assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType())); - assert(OOE->getType()->isIntegerType()); - assert(IV.isSigned() == OOE->getType()->isSignedIntegerOrEnumerationType()); + assert(OOE->getType()->isBuiltinType()); + assert(OOE->getType()->getAs<BuiltinType>()->isInteger()); + assert(IV.isSigned() == OOE->getType()->isSignedIntegerType()); SVal X = svalBuilder.makeIntVal(IV); B.generateNode(OOE, Pred, Pred->getState()->BindExpr(OOE, Pred->getLocationContext(), diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index f01e4e7..06570a4 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -676,46 +676,40 @@ static CallInlinePolicy mayInlineCallKind(const CallEvent &Call, return CIP_Allowed; } -/// Returns true if the given C++ class is a container. -/// -/// Our heuristic for this is whether it contains a method named 'begin()' or a -/// nested type named 'iterator'. -static bool isContainerClass(const ASTContext &Ctx, const CXXRecordDecl *RD) { - // Don't record any path information. - CXXBasePaths Paths(false, false, false); - - const IdentifierInfo &BeginII = Ctx.Idents.get("begin"); - DeclarationName BeginName = Ctx.DeclarationNames.getIdentifier(&BeginII); - DeclContext::lookup_const_result BeginDecls = RD->lookup(BeginName); - if (!BeginDecls.empty()) - return true; - if (RD->lookupInBases(&CXXRecordDecl::FindOrdinaryMember, - BeginName.getAsOpaquePtr(), - Paths)) - return true; - - const IdentifierInfo &IterII = Ctx.Idents.get("iterator"); - DeclarationName IteratorName = Ctx.DeclarationNames.getIdentifier(&IterII); - DeclContext::lookup_const_result IterDecls = RD->lookup(IteratorName); - if (!IterDecls.empty()) +/// Returns true if the given C++ class contains a member with the given name. +static bool hasMember(const ASTContext &Ctx, const CXXRecordDecl *RD, + StringRef Name) { + const IdentifierInfo &II = Ctx.Idents.get(Name); + DeclarationName DeclName = Ctx.DeclarationNames.getIdentifier(&II); + if (!RD->lookup(DeclName).empty()) return true; + + CXXBasePaths Paths(false, false, false); if (RD->lookupInBases(&CXXRecordDecl::FindOrdinaryMember, - IteratorName.getAsOpaquePtr(), + DeclName.getAsOpaquePtr(), Paths)) return true; return false; } +/// Returns true if the given C++ class is a container or iterator. +/// +/// Our heuristic for this is whether it contains a method named 'begin()' or a +/// nested type named 'iterator' or 'iterator_category'. +static bool isContainerClass(const ASTContext &Ctx, const CXXRecordDecl *RD) { + return hasMember(Ctx, RD, "begin") || + hasMember(Ctx, RD, "iterator") || + hasMember(Ctx, RD, "iterator_category"); +} + /// Returns true if the given function refers to a constructor or destructor of -/// a C++ container. +/// a C++ container or iterator. /// /// We generally do a poor job modeling most containers right now, and would -/// prefer not to inline their methods. +/// prefer not to inline their setup and teardown. static bool isContainerCtorOrDtor(const ASTContext &Ctx, const FunctionDecl *FD) { - // Heuristic: a type is a container if it contains a "begin()" method - // or a type named "iterator". if (!(isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD))) return false; diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp index b3a1e65..42073d4 100644 --- a/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -555,38 +555,75 @@ void StackLocalsSpaceRegion::dumpToStream(raw_ostream &os) const { } bool MemRegion::canPrintPretty() const { + return canPrintPrettyAsExpr(); +} + +bool MemRegion::canPrintPrettyAsExpr() const { return false; } void MemRegion::printPretty(raw_ostream &os) const { + assert(canPrintPretty() && "This region cannot be printed pretty."); + os << "'"; + printPrettyAsExpr(os); + os << "'"; + return; +} + +void MemRegion::printPrettyAsExpr(raw_ostream &os) const { + llvm_unreachable("This region cannot be printed pretty."); return; } -bool VarRegion::canPrintPretty() const { +bool VarRegion::canPrintPrettyAsExpr() const { return true; } -void VarRegion::printPretty(raw_ostream &os) const { +void VarRegion::printPrettyAsExpr(raw_ostream &os) const { os << getDecl()->getName(); } -bool ObjCIvarRegion::canPrintPretty() const { +bool ObjCIvarRegion::canPrintPrettyAsExpr() const { return true; } -void ObjCIvarRegion::printPretty(raw_ostream &os) const { +void ObjCIvarRegion::printPrettyAsExpr(raw_ostream &os) const { os << getDecl()->getName(); } bool FieldRegion::canPrintPretty() const { - return superRegion->canPrintPretty(); + return true; } -void FieldRegion::printPretty(raw_ostream &os) const { - superRegion->printPretty(os); +bool FieldRegion::canPrintPrettyAsExpr() const { + return superRegion->canPrintPrettyAsExpr(); +} + +void FieldRegion::printPrettyAsExpr(raw_ostream &os) const { + assert(canPrintPrettyAsExpr()); + superRegion->printPrettyAsExpr(os); os << "." << getDecl()->getName(); } +void FieldRegion::printPretty(raw_ostream &os) const { + if (canPrintPrettyAsExpr()) { + os << "\'"; + printPrettyAsExpr(os); + os << "'"; + } else { + os << "field " << "\'" << getDecl()->getName() << "'"; + } + return; +} + +bool CXXBaseObjectRegion::canPrintPrettyAsExpr() const { + return superRegion->canPrintPrettyAsExpr(); +} + +void CXXBaseObjectRegion::printPrettyAsExpr(raw_ostream &os) const { + superRegion->printPrettyAsExpr(os); +} + //===----------------------------------------------------------------------===// // MemRegionManager methods. //===----------------------------------------------------------------------===// @@ -1043,6 +1080,17 @@ const MemRegion *MemRegion::StripCasts(bool StripBaseCasts) const { } } +const SymbolicRegion *MemRegion::getSymbolicBase() const { + const SubRegion *SubR = dyn_cast<SubRegion>(this); + + while (SubR) { + if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(SubR)) + return SymR; + SubR = dyn_cast<SubRegion>(SubR->getSuperRegion()); + } + return 0; +} + // FIXME: Merge with the implementation of the same method in Store.cpp static bool IsCompleteType(ASTContext &Ctx, QualType Ty) { if (const RecordType *RT = Ty->getAs<RecordType>()) { diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index 7c0fb14..0351310 100644 --- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -297,11 +297,16 @@ static Optional<bool> comparePiece(const PathDiagnosticPiece &X, static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) { if (X.size() != Y.size()) return X.size() < Y.size(); - for (unsigned i = 0, n = X.size(); i != n; ++i) { - Optional<bool> b = comparePiece(*X[i], *Y[i]); + + PathPieces::const_iterator X_I = X.begin(), X_end = X.end(); + PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end(); + + for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) { + Optional<bool> b = comparePiece(**X_I, **Y_I); if (b.hasValue()) return b.getValue(); } + return None; } @@ -608,31 +613,73 @@ PathDiagnosticLocation return PathDiagnosticLocation(S, SMng, P.getLocationContext()); } +const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) { + ProgramPoint P = N->getLocation(); + if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) + return SP->getStmt(); + if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) + return BE->getSrc()->getTerminator(); + if (Optional<CallEnter> CE = P.getAs<CallEnter>()) + return CE->getCallExpr(); + if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) + return CEE->getCalleeContext()->getCallSite(); + if (Optional<PostInitializer> PIPP = P.getAs<PostInitializer>()) + return PIPP->getInitializer()->getInit(); + + return 0; +} + +const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) { + for (N = N->getFirstSucc(); N; N = N->getFirstSucc()) { + if (const Stmt *S = getStmt(N)) { + // Check if the statement is '?' or '&&'/'||'. These are "merges", + // not actual statement points. + switch (S->getStmtClass()) { + case Stmt::ChooseExprClass: + case Stmt::BinaryConditionalOperatorClass: + case Stmt::ConditionalOperatorClass: + continue; + case Stmt::BinaryOperatorClass: { + BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode(); + if (Op == BO_LAnd || Op == BO_LOr) + continue; + break; + } + default: + break; + } + // We found the statement, so return it. + return S; + } + } + + return 0; +} + PathDiagnosticLocation - PathDiagnosticLocation::createEndOfPath(const ExplodedNode* N, + PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N, const SourceManager &SM) { assert(N && "Cannot create a location with a null node."); + const Stmt *S = getStmt(N); - const ExplodedNode *NI = N; - const Stmt *S = 0; - - while (NI) { - ProgramPoint P = NI->getLocation(); - if (Optional<StmtPoint> PS = P.getAs<StmtPoint>()) { - S = PS->getStmt(); - if (P.getAs<PostStmtPurgeDeadSymbols>()) - return PathDiagnosticLocation::createEnd(S, SM, - NI->getLocationContext()); - break; - } else if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { - S = BE->getSrc()->getTerminator(); - break; - } - NI = NI->succ_empty() ? 0 : *(NI->succ_begin()); - } + if (!S) + S = getNextStmt(N); if (S) { - const LocationContext *LC = NI->getLocationContext(); + ProgramPoint P = N->getLocation(); + const LocationContext *LC = N->getLocationContext(); + + // For member expressions, return the location of the '.' or '->'. + if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) + return PathDiagnosticLocation::createMemberLoc(ME, SM); + + // For binary operators, return the location of the operator. + if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) + return PathDiagnosticLocation::createOperatorLoc(B, SM); + + if (P.getAs<PostStmtPurgeDeadSymbols>()) + return PathDiagnosticLocation::createEnd(S, SM, LC); + if (S->getLocStart().isValid()) return PathDiagnosticLocation(S, SM, LC); return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM); diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp index 7dcc088..8509555 100644 --- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -296,6 +296,8 @@ static void ReportCall(raw_ostream &o, for (PathPieces::const_iterator I = P.path.begin(), E = P.path.end();I!=E;++I) ReportPiece(o, **I, FM, SM, LangOpts, indent, depth, true); + + --depth; IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit = P.getCallExitEvent(); diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp index bff2242..653b69b 100644 --- a/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -111,14 +111,6 @@ ProgramStateManager::removeDeadBindings(ProgramStateRef state, return ConstraintMgr->removeDeadBindings(Result, SymReaper); } -ProgramStateRef ProgramState::bindCompoundLiteral(const CompoundLiteralExpr *CL, - const LocationContext *LC, - SVal V) const { - const StoreRef &newStore = - getStateManager().StoreMgr->bindCompoundLiteral(getStore(), CL, LC, V); - return makeWithStore(newStore); -} - ProgramStateRef ProgramState::bindLoc(Loc LV, SVal V, bool notifyChanges) const { ProgramStateManager &Mgr = getStateManager(); ProgramStateRef newState = makeWithStore(Mgr.StoreMgr->Bind(getStore(), @@ -270,7 +262,7 @@ SVal ProgramState::getSValAsScalarOrLoc(const MemRegion *R) const { if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) { QualType T = TR->getValueType(); - if (Loc::isLocType(T) || T->isIntegerType()) + if (Loc::isLocType(T) || T->isIntegralOrEnumerationType()) return getSVal(R); } @@ -383,7 +375,7 @@ ConditionTruthVal ProgramState::isNull(SVal V) const { if (V.isConstant()) return false; - SymbolRef Sym = V.getAsSymbol(); + SymbolRef Sym = V.getAsSymbol(/* IncludeBaseRegion */ true); if (!Sym) return ConditionTruthVal(); diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp index 0f4a682..88c4eee 100644 --- a/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -19,10 +19,12 @@ #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/AnalysisContext.h" #include "clang/Basic/TargetInfo.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h" #include "llvm/ADT/ImmutableList.h" #include "llvm/ADT/ImmutableMap.h" #include "llvm/ADT/Optional.h" @@ -323,6 +325,7 @@ class invalidateRegionsWorker; class RegionStoreManager : public StoreManager { public: const RegionStoreFeatures Features; + RegionBindings::Factory RBFactory; mutable ClusterBindings::Factory CBFactory; @@ -332,6 +335,16 @@ private: SValListTy> LazyBindingsMapTy; LazyBindingsMapTy LazyBindingsMap; + /// The largest number of fields a struct can have and still be + /// considered "small". + /// + /// This is currently used to decide whether or not it is worth "forcing" a + /// LazyCompoundVal on bind. + /// + /// This is controlled by 'region-store-small-struct-limit' option. + /// To disable all small-struct-dependent behavior, set the option to "0". + unsigned SmallStructLimit; + /// \brief A helper used to populate the work list with the given set of /// regions. void populateWorkList(invalidateRegionsWorker &W, @@ -342,7 +355,14 @@ private: public: RegionStoreManager(ProgramStateManager& mgr, const RegionStoreFeatures &f) : StoreManager(mgr), Features(f), - RBFactory(mgr.getAllocator()), CBFactory(mgr.getAllocator()) {} + RBFactory(mgr.getAllocator()), CBFactory(mgr.getAllocator()), + SmallStructLimit(0) { + if (SubEngine *Eng = StateMgr.getOwningEngine()) { + AnalyzerOptions &Options = Eng->getAnalysisManager().options; + SmallStructLimit = + Options.getOptionAsInteger("region-store-small-struct-limit", 2); + } + } /// setImplicitDefaultValue - Set the default binding for the provided @@ -409,19 +429,20 @@ public: // Part of public interface to class. .getRootWithoutRetain(), *this); } - /// \brief Create a new store that binds a value to a compound literal. + /// Attempt to extract the fields of \p LCV and bind them to the struct region + /// \p R. /// - /// \param ST The original store whose bindings are the basis for the new - /// store. + /// This path is used when it seems advantageous to "force" loading the values + /// within a LazyCompoundVal to bind memberwise to the struct region, rather + /// than using a Default binding at the base of the entire region. This is a + /// heuristic attempting to avoid building long chains of LazyCompoundVals. /// - /// \param CL The compound literal to bind (the binding key). - /// - /// \param LC The LocationContext for the binding. - /// - /// \param V The value to bind to the compound literal. - StoreRef bindCompoundLiteral(Store ST, - const CompoundLiteralExpr *CL, - const LocationContext *LC, SVal V); + /// \returns The updated store bindings, or \c None if binding non-lazily + /// would be too expensive. + Optional<RegionBindingsRef> tryBindSmallStruct(RegionBindingsConstRef B, + const TypedValueRegion *R, + const RecordDecl *RD, + nonloc::LazyCompoundVal LCV); /// BindStruct - Bind a compound value to a structure. RegionBindingsRef bindStruct(RegionBindingsConstRef B, @@ -490,8 +511,7 @@ public: // Part of public interface to class. SVal getBindingForFieldOrElementCommon(RegionBindingsConstRef B, const TypedValueRegion *R, - QualType Ty, - const MemRegion *superR); + QualType Ty); SVal getLazyBinding(const SubRegion *LazyBindingRegion, RegionBindingsRef LazyBinding); @@ -604,6 +624,17 @@ ento::CreateFieldsOnlyRegionStoreManager(ProgramStateManager &StMgr) { //===----------------------------------------------------------------------===// namespace { +/// Used to determine which global regions are automatically included in the +/// initial worklist of a ClusterAnalysis. +enum GlobalsFilterKind { + /// Don't include any global regions. + GFK_None, + /// Only include system globals. + GFK_SystemOnly, + /// Include all global regions. + GFK_All +}; + template <typename DERIVED> class ClusterAnalysis { protected: @@ -620,19 +651,36 @@ protected: SValBuilder &svalBuilder; RegionBindingsRef B; - - const bool includeGlobals; +private: + GlobalsFilterKind GlobalsFilter; + +protected: const ClusterBindings *getCluster(const MemRegion *R) { return B.lookup(R); } + /// Returns true if the memory space of the given region is one of the global + /// regions specially included at the start of analysis. + bool isInitiallyIncludedGlobalRegion(const MemRegion *R) { + switch (GlobalsFilter) { + case GFK_None: + return false; + case GFK_SystemOnly: + return isa<GlobalSystemSpaceRegion>(R->getMemorySpace()); + case GFK_All: + return isa<NonStaticGlobalSpaceRegion>(R->getMemorySpace()); + } + + llvm_unreachable("unknown globals filter"); + } + public: ClusterAnalysis(RegionStoreManager &rm, ProgramStateManager &StateMgr, - RegionBindingsRef b, const bool includeGlobals) + RegionBindingsRef b, GlobalsFilterKind GFK) : RM(rm), Ctx(StateMgr.getContext()), svalBuilder(StateMgr.getSValBuilder()), - B(b), includeGlobals(includeGlobals) {} + B(b), GlobalsFilter(GFK) {} RegionBindingsRef getRegionBindings() const { return B; } @@ -650,9 +698,9 @@ public: assert(!Cluster.isEmpty() && "Empty clusters should be removed"); static_cast<DERIVED*>(this)->VisitAddedToCluster(Base, Cluster); - if (includeGlobals) - if (isa<NonStaticGlobalSpaceRegion>(Base->getMemorySpace())) - AddToWorkList(Base, &Cluster); + // If this is an interesting global region, add it the work list up front. + if (isInitiallyIncludedGlobalRegion(Base)) + AddToWorkList(WorkListElement(Base), &Cluster); } } @@ -905,8 +953,8 @@ public: InvalidatedSymbols &is, InvalidatedSymbols &inConstIS, StoreManager::InvalidatedRegions *r, - bool includeGlobals) - : ClusterAnalysis<invalidateRegionsWorker>(rm, stateMgr, b, includeGlobals), + GlobalsFilterKind GFK) + : ClusterAnalysis<invalidateRegionsWorker>(rm, stateMgr, b, GFK), Ex(ex), Count(count), LCtx(lctx), IS(is), ConstIS(inConstIS), Regions(r){} /// \param IsConst Specifies if the region we are invalidating is constant. @@ -949,6 +997,7 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR, for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E; ++I) VisitBinding(I.getData()); + // Invalidate the contents of a non-const base region. if (!IsConst) B = B.remove(baseR); } @@ -981,18 +1030,19 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR, } // Symbolic region? - SymbolRef RegionSym = 0; - if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR)) - RegionSym = SR->getSymbol(); + if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR)) { + SymbolRef RegionSym = SR->getSymbol(); - if (IsConst) { // Mark that symbol touched by the invalidation. - ConstIS.insert(RegionSym); - return; + if (IsConst) + ConstIS.insert(RegionSym); + else + IS.insert(RegionSym); } - - // Mark that symbol touched by the invalidation. - IS.insert(RegionSym); + + // Nothing else should be done for a const region. + if (IsConst) + return; // Otherwise, we have a normal data region. Record that we touched the region. if (Regions) @@ -1013,7 +1063,13 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR, const TypedValueRegion *TR = cast<TypedValueRegion>(baseR); QualType T = TR->getValueType(); - // Invalidate the binding. + if (isInitiallyIncludedGlobalRegion(baseR)) { + // If the region is a global and we are invalidating all globals, + // erasing the entry is good enough. This causes all globals to be lazily + // symbolicated from the same base symbol. + return; + } + if (T->isStructureOrClassType()) { // Invalidate the region by setting its default value to // conjured symbol. The type of the symbol is irrelavant. @@ -1031,16 +1087,6 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR, B = B.addBinding(baseR, BindingKey::Default, V); return; } - - if (includeGlobals && - isa<NonStaticGlobalSpaceRegion>(baseR->getMemorySpace())) { - // If the region is a global and we are invalidating all globals, - // just erase the entry. This causes all globals to be lazily - // symbolicated from the same base symbol. - B = B.removeBinding(baseR); - return; - } - DefinedOrUnknownSVal V = svalBuilder.conjureSymbolVal(baseR, Ex, LCtx, T,Count); @@ -1116,9 +1162,19 @@ RegionStoreManager::invalidateRegions(Store store, InvalidatedRegions *TopLevelRegions, InvalidatedRegions *TopLevelConstRegions, InvalidatedRegions *Invalidated) { - RegionBindingsRef B = RegionStoreManager::getRegionBindings(store); + GlobalsFilterKind GlobalsFilter; + if (Call) { + if (Call->isInSystemHeader()) + GlobalsFilter = GFK_SystemOnly; + else + GlobalsFilter = GFK_All; + } else { + GlobalsFilter = GFK_None; + } + + RegionBindingsRef B = getRegionBindings(store); invalidateRegionsWorker W(*this, StateMgr, B, Ex, Count, LCtx, IS, ConstIS, - Invalidated, false); + Invalidated, GlobalsFilter); // Scan the bindings and generate the clusters. W.GenerateClusters(); @@ -1138,14 +1194,17 @@ RegionStoreManager::invalidateRegions(Store store, // invalidate them. (Note that function-static and immutable globals are never // invalidated by this.) // TODO: This could possibly be more precise with modules. - if (Call) { + switch (GlobalsFilter) { + case GFK_All: + B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind, + Ex, Count, LCtx, B, Invalidated); + // FALLTHROUGH + case GFK_SystemOnly: B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind, Ex, Count, LCtx, B, Invalidated); - - if (!Call->isInSystemHeader()) { - B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind, - Ex, Count, LCtx, B, Invalidated); - } + // FALLTHROUGH + case GFK_None: + break; } return StoreRef(B.asStore(), *this); @@ -1506,7 +1565,7 @@ SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B, } } } - return getBindingForFieldOrElementCommon(B, R, R->getElementType(),superR); + return getBindingForFieldOrElementCommon(B, R, R->getElementType()); } SVal RegionStoreManager::getBindingForField(RegionBindingsConstRef B, @@ -1517,7 +1576,7 @@ SVal RegionStoreManager::getBindingForField(RegionBindingsConstRef B, return *V; QualType Ty = R->getValueType(); - return getBindingForFieldOrElementCommon(B, R, Ty, R->getSuperRegion()); + return getBindingForFieldOrElementCommon(B, R, Ty); } Optional<SVal> @@ -1580,8 +1639,7 @@ SVal RegionStoreManager::getLazyBinding(const SubRegion *LazyBindingRegion, SVal RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B, const TypedValueRegion *R, - QualType Ty, - const MemRegion *superR) { + QualType Ty) { // At this point we have already checked in either getBindingForElement or // getBindingForField if 'R' has a direct binding. @@ -1614,8 +1672,9 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B, // quickly result in a warning. bool hasPartialLazyBinding = false; - const SubRegion *Base = dyn_cast<SubRegion>(superR); - while (Base) { + const SubRegion *SR = dyn_cast<SubRegion>(R); + while (SR) { + const MemRegion *Base = SR->getSuperRegion(); if (Optional<SVal> D = getBindingForDerivedDefaultValue(B, Base, R, Ty)) { if (D->getAs<nonloc::LazyCompoundVal>()) { hasPartialLazyBinding = true; @@ -1633,7 +1692,7 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B, // If our super region is a field or element itself, walk up the region // hierarchy to see if there is a default value installed in an ancestor. - Base = dyn_cast<SubRegion>(Base->getSuperRegion()); + SR = dyn_cast<SubRegion>(Base); } if (R->hasStackNonParametersStorage()) { @@ -1641,7 +1700,7 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B, // Currently we don't reason specially about Clang-style vectors. Check // if superR is a vector and if so return Unknown. if (const TypedValueRegion *typedSuperR = - dyn_cast<TypedValueRegion>(superR)) { + dyn_cast<TypedValueRegion>(R->getSuperRegion())) { if (typedSuperR->getValueType()->isVectorType()) return UnknownVal(); } @@ -1682,26 +1741,6 @@ SVal RegionStoreManager::getBindingForObjCIvar(RegionBindingsConstRef B, return getBindingForLazySymbol(R); } -static Optional<SVal> getConstValue(SValBuilder &SVB, const VarDecl *VD) { - ASTContext &Ctx = SVB.getContext(); - if (!VD->getType().isConstQualified()) - return None; - - const Expr *Init = VD->getInit(); - if (!Init) - return None; - - llvm::APSInt Result; - if (!Init->isGLValue() && Init->EvaluateAsInt(Result, Ctx)) - return SVB.makeIntVal(Result); - - if (Init->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull)) - return SVB.makeNull(); - - // FIXME: Handle other possible constant expressions. - return None; -} - SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B, const VarRegion *R) { @@ -1718,8 +1757,10 @@ SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B, return svalBuilder.getRegionValueSymbolVal(R); // Is 'VD' declared constant? If so, retrieve the constant value. - if (Optional<SVal> V = getConstValue(svalBuilder, VD)) - return *V; + if (VD->getType().isConstQualified()) + if (const Expr *Init = VD->getInit()) + if (Optional<SVal> V = svalBuilder.getConstantVal(Init)) + return *V; // This must come after the check for constants because closure-captured // constant variables may appear in UnknownSpaceRegion. @@ -1891,14 +1932,6 @@ RegionStoreManager::bind(RegionBindingsConstRef B, Loc L, SVal V) { return NewB.addBinding(BindingKey::Make(R, BindingKey::Direct), V); } -// FIXME: this method should be merged into Bind(). -StoreRef RegionStoreManager::bindCompoundLiteral(Store ST, - const CompoundLiteralExpr *CL, - const LocationContext *LC, - SVal V) { - return Bind(ST, loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)), V); -} - RegionBindingsRef RegionStoreManager::setImplicitDefaultValue(RegionBindingsConstRef B, const MemRegion *R, @@ -1907,7 +1940,7 @@ RegionStoreManager::setImplicitDefaultValue(RegionBindingsConstRef B, if (Loc::isLocType(T)) V = svalBuilder.makeNull(); - else if (T->isIntegerType()) + else if (T->isIntegralOrEnumerationType()) V = svalBuilder.makeZeroVal(T); else if (T->isStructureOrClassType() || T->isArrayType()) { // Set the default value to a zero constant when it is a structure @@ -1977,7 +2010,7 @@ RegionStoreManager::bindArray(RegionBindingsConstRef B, else if (ElementTy->isArrayType()) NewB = bindArray(NewB, ER, *VI); else - NewB = bind(NewB, svalBuilder.makeLoc(ER), *VI); + NewB = bind(NewB, loc::MemRegionVal(ER), *VI); } // If the init list is shorter than the array length, set the @@ -2018,17 +2051,59 @@ RegionBindingsRef RegionStoreManager::bindVector(RegionBindingsConstRef B, NonLoc Idx = svalBuilder.makeArrayIndex(index); const ElementRegion *ER = MRMgr.getElementRegion(ElemType, Idx, R, Ctx); - + if (ElemType->isArrayType()) NewB = bindArray(NewB, ER, *VI); else if (ElemType->isStructureOrClassType()) NewB = bindStruct(NewB, ER, *VI); else - NewB = bind(NewB, svalBuilder.makeLoc(ER), *VI); + NewB = bind(NewB, loc::MemRegionVal(ER), *VI); } return NewB; } +Optional<RegionBindingsRef> +RegionStoreManager::tryBindSmallStruct(RegionBindingsConstRef B, + const TypedValueRegion *R, + const RecordDecl *RD, + nonloc::LazyCompoundVal LCV) { + FieldVector Fields; + + if (const CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(RD)) + if (Class->getNumBases() != 0 || Class->getNumVBases() != 0) + return None; + + for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); + I != E; ++I) { + const FieldDecl *FD = *I; + if (FD->isUnnamedBitfield()) + continue; + + // If there are too many fields, or if any of the fields are aggregates, + // just use the LCV as a default binding. + if (Fields.size() == SmallStructLimit) + return None; + + QualType Ty = FD->getType(); + if (!(Ty->isScalarType() || Ty->isReferenceType())) + return None; + + Fields.push_back(*I); + } + + RegionBindingsRef NewB = B; + + for (FieldVector::iterator I = Fields.begin(), E = Fields.end(); I != E; ++I){ + const FieldRegion *SourceFR = MRMgr.getFieldRegion(*I, LCV.getRegion()); + SVal V = getBindingForField(getRegionBindings(LCV.getStore()), SourceFR); + + const FieldRegion *DestFR = MRMgr.getFieldRegion(*I, R); + NewB = bind(NewB, loc::MemRegionVal(DestFR), V); + } + + return NewB; +} + RegionBindingsRef RegionStoreManager::bindStruct(RegionBindingsConstRef B, const TypedValueRegion* R, SVal V) { @@ -2039,13 +2114,19 @@ RegionBindingsRef RegionStoreManager::bindStruct(RegionBindingsConstRef B, assert(T->isStructureOrClassType()); const RecordType* RT = T->getAs<RecordType>(); - RecordDecl *RD = RT->getDecl(); + const RecordDecl *RD = RT->getDecl(); if (!RD->isCompleteDefinition()) return B; // Handle lazy compound values and symbolic values. - if (V.getAs<nonloc::LazyCompoundVal>() || V.getAs<nonloc::SymbolVal>()) + if (Optional<nonloc::LazyCompoundVal> LCV = + V.getAs<nonloc::LazyCompoundVal>()) { + if (Optional<RegionBindingsRef> NewB = tryBindSmallStruct(B, R, RD, *LCV)) + return *NewB; + return bindAggregate(B, R, V); + } + if (V.getAs<nonloc::SymbolVal>()) return bindAggregate(B, R, V); // We may get non-CompoundVal accidentally due to imprecise cast logic or @@ -2077,7 +2158,7 @@ RegionBindingsRef RegionStoreManager::bindStruct(RegionBindingsConstRef B, else if (FTy->isStructureOrClassType()) NewB = bindStruct(NewB, FR, *VI); else - NewB = bind(NewB, svalBuilder.makeLoc(FR), *VI); + NewB = bind(NewB, loc::MemRegionVal(FR), *VI); ++VI; } @@ -2115,8 +2196,7 @@ public: ProgramStateManager &stateMgr, RegionBindingsRef b, SymbolReaper &symReaper, const StackFrameContext *LCtx) - : ClusterAnalysis<removeDeadBindingsWorker>(rm, stateMgr, b, - /* includeGlobals = */ false), + : ClusterAnalysis<removeDeadBindingsWorker>(rm, stateMgr, b, GFK_None), SymReaper(symReaper), CurrentLCtx(LCtx) {} // Called by ClusterAnalysis. diff --git a/lib/StaticAnalyzer/Core/SValBuilder.cpp b/lib/StaticAnalyzer/Core/SValBuilder.cpp index c72e780..9d77a3e 100644 --- a/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -33,7 +33,7 @@ DefinedOrUnknownSVal SValBuilder::makeZeroVal(QualType type) { if (Loc::isLocType(type)) return makeNull(); - if (type->isIntegerType()) + if (type->isIntegralOrEnumerationType()) return makeIntVal(0, type); // FIXME: Handle floats. @@ -106,12 +106,19 @@ SValBuilder::getRegionValueSymbolVal(const TypedValueRegion* region) { return nonloc::SymbolVal(sym); } -DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag, - const Expr *expr, +DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *SymbolTag, + const Expr *Ex, const LocationContext *LCtx, - unsigned count) { - QualType T = expr->getType(); - return conjureSymbolVal(symbolTag, expr, LCtx, T, count); + unsigned Count) { + QualType T = Ex->getType(); + + // Compute the type of the result. If the expression is not an R-value, the + // result should be a location. + QualType ExType = Ex->getType(); + if (Ex->isGLValue()) + T = LCtx->getAnalysisDeclContext()->getASTContext().getPointerType(ExType); + + return conjureSymbolVal(SymbolTag, Ex, LCtx, T, Count); } DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag, @@ -217,6 +224,68 @@ loc::MemRegionVal SValBuilder::getCXXThis(const CXXRecordDecl *D, return loc::MemRegionVal(getRegionManager().getCXXThisRegion(PT, SFC)); } +Optional<SVal> SValBuilder::getConstantVal(const Expr *E) { + E = E->IgnoreParens(); + + switch (E->getStmtClass()) { + // Handle expressions that we treat differently from the AST's constant + // evaluator. + case Stmt::AddrLabelExprClass: + return makeLoc(cast<AddrLabelExpr>(E)); + + case Stmt::CXXScalarValueInitExprClass: + case Stmt::ImplicitValueInitExprClass: + return makeZeroVal(E->getType()); + + case Stmt::ObjCStringLiteralClass: { + const ObjCStringLiteral *SL = cast<ObjCStringLiteral>(E); + return makeLoc(getRegionManager().getObjCStringRegion(SL)); + } + + case Stmt::StringLiteralClass: { + const StringLiteral *SL = cast<StringLiteral>(E); + return makeLoc(getRegionManager().getStringRegion(SL)); + } + + // Fast-path some expressions to avoid the overhead of going through the AST's + // constant evaluator + case Stmt::CharacterLiteralClass: { + const CharacterLiteral *C = cast<CharacterLiteral>(E); + return makeIntVal(C->getValue(), C->getType()); + } + + case Stmt::CXXBoolLiteralExprClass: + return makeBoolVal(cast<CXXBoolLiteralExpr>(E)); + + case Stmt::IntegerLiteralClass: + return makeIntVal(cast<IntegerLiteral>(E)); + + case Stmt::ObjCBoolLiteralExprClass: + return makeBoolVal(cast<ObjCBoolLiteralExpr>(E)); + + case Stmt::CXXNullPtrLiteralExprClass: + return makeNull(); + + // If we don't have a special case, fall back to the AST's constant evaluator. + default: { + // Don't try to come up with a value for materialized temporaries. + if (E->isGLValue()) + return None; + + ASTContext &Ctx = getContext(); + llvm::APSInt Result; + if (E->EvaluateAsInt(Result, Ctx)) + return makeIntVal(Result); + + if (Loc::isLocType(E->getType())) + if (E->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull)) + return makeNull(); + + return None; + } + } +} + //===----------------------------------------------------------------------===// SVal SValBuilder::makeSymExprValNN(ProgramStateRef State, @@ -320,6 +389,22 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) { if (val.isUnknownOrUndef() || castTy == originalTy) return val; + if (castTy->isBooleanType()) { + if (val.isUnknownOrUndef()) + return val; + if (val.isConstant()) + return makeTruthVal(!val.isZeroConstant(), castTy); + if (SymbolRef Sym = val.getAsSymbol()) { + BasicValueFactory &BVF = getBasicValueFactory(); + // FIXME: If we had a state here, we could see if the symbol is known to + // be zero, but we don't. + return makeNonLoc(Sym, BO_NE, BVF.getValue(0, Sym->getType()), castTy); + } + + assert(val.getAs<Loc>()); + return makeTruthVal(true, castTy); + } + // For const casts, casts to void, just propagate the value. if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType()) if (shouldBeModeledWithNoOp(Context, Context.getPointerType(castTy), @@ -327,11 +412,11 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) { return val; // Check for casts from pointers to integers. - if (castTy->isIntegerType() && Loc::isLocType(originalTy)) + if (castTy->isIntegralOrEnumerationType() && Loc::isLocType(originalTy)) return evalCastFromLoc(val.castAs<Loc>(), castTy); // Check for casts from integers to pointers. - if (Loc::isLocType(castTy) && originalTy->isIntegerType()) { + if (Loc::isLocType(castTy) && originalTy->isIntegralOrEnumerationType()) { if (Optional<nonloc::LocAsInteger> LV = val.getAs<nonloc::LocAsInteger>()) { if (const MemRegion *R = LV->getLoc().getAsRegion()) { StoreManager &storeMgr = StateMgr.getStoreManager(); @@ -361,7 +446,7 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) { // Are we casting from an array to an integer? If so, cast the decayed // pointer value to an integer. - assert(castTy->isIntegerType()); + assert(castTy->isIntegralOrEnumerationType()); // FIXME: Keep these here for now in case we decide soon that we // need the original decayed type. @@ -373,7 +458,7 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) { // Check for casts from a region to a specific type. if (const MemRegion *R = val.getAsRegion()) { // Handle other casts of locations to integers. - if (castTy->isIntegerType()) + if (castTy->isIntegralOrEnumerationType()) return evalCastFromLoc(loc::MemRegionVal(R), castTy); // FIXME: We should handle the case where we strip off view layers to get diff --git a/lib/StaticAnalyzer/Core/SVals.cpp b/lib/StaticAnalyzer/Core/SVals.cpp index 38e216f..6506915 100644 --- a/lib/StaticAnalyzer/Core/SVals.cpp +++ b/lib/StaticAnalyzer/Core/SVals.cpp @@ -64,14 +64,18 @@ const FunctionDecl *SVal::getAsFunctionDecl() const { /// /// Implicit casts (ex: void* -> char*) can turn Symbolic region into Element /// region. If that is the case, gets the underlining region. -SymbolRef SVal::getAsLocSymbol() const { +/// When IncludeBaseRegions is set to true and the SubRegion is non-symbolic, +/// the first symbolic parent region is returned. +SymbolRef SVal::getAsLocSymbol(bool IncludeBaseRegions) const { // FIXME: should we consider SymbolRef wrapped in CodeTextRegion? if (Optional<nonloc::LocAsInteger> X = getAs<nonloc::LocAsInteger>()) return X->getLoc().getAsLocSymbol(); if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) { - const MemRegion *R = X->stripCasts(); - if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R)) + const MemRegion *R = X->getRegion(); + if (const SymbolicRegion *SymR = IncludeBaseRegions ? + R->getSymbolicBase() : + dyn_cast<SymbolicRegion>(R->StripCasts())) return SymR->getSymbol(); } return 0; @@ -99,13 +103,17 @@ SymbolRef SVal::getLocSymbolInBase() const { // TODO: The next 3 functions have to be simplified. /// \brief If this SVal wraps a symbol return that SymbolRef. -/// Otherwise return 0. -SymbolRef SVal::getAsSymbol() const { +/// Otherwise, return 0. +/// +/// Casts are ignored during lookup. +/// \param IncludeBaseRegions The boolean that controls whether the search +/// should continue to the base regions if the region is not symbolic. +SymbolRef SVal::getAsSymbol(bool IncludeBaseRegion) const { // FIXME: should we consider SymbolRef wrapped in CodeTextRegion? if (Optional<nonloc::SymbolVal> X = getAs<nonloc::SymbolVal>()) return X->getSymbol(); - return getAsLocSymbol(); + return getAsLocSymbol(IncludeBaseRegion); } /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp index 9b759df..a06268d 100644 --- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp +++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp @@ -90,20 +90,15 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state, case loc::MemRegionKind: { // FIXME: Should this go into the storemanager? - const MemRegion *R = Cond.castAs<loc::MemRegionVal>().getRegion(); - const SubRegion *SubR = dyn_cast<SubRegion>(R); - - while (SubR) { - // FIXME: now we only find the first symbolic region. - if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(SubR)) { - const llvm::APSInt &zero = getBasicVals().getZeroWithPtrWidth(); - if (Assumption) - return assumeSymNE(state, SymR->getSymbol(), zero, zero); - else - return assumeSymEQ(state, SymR->getSymbol(), zero, zero); - } - SubR = dyn_cast<SubRegion>(SubR->getSuperRegion()); + + // FIXME: now we only find the first symbolic region. + if (const SymbolicRegion *SymR = R->getSymbolicBase()) { + const llvm::APSInt &zero = getBasicVals().getZeroWithPtrWidth(); + if (Assumption) + return assumeSymNE(state, SymR->getSymbol(), zero, zero); + else + return assumeSymEQ(state, SymR->getSymbol(), zero, zero); } // FALL-THROUGH. @@ -137,7 +132,7 @@ SimpleConstraintManager::assumeAuxForSymbol(ProgramStateRef State, QualType T = Sym->getType(); // None of the constraint solvers currently support non-integer types. - if (!T->isIntegerType()) + if (!T->isIntegralOrEnumerationType()) return State; const llvm::APSInt &zero = BVF.getValue(0, T); diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp index 5cc8926..ee627f2 100644 --- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -109,7 +109,7 @@ SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) { // Only handle casts from integers to integers - if val is an integer constant // being cast to a non integer type, produce unknown. - if (!isLocType && !castTy->isIntegerType()) + if (!isLocType && !castTy->isIntegralOrEnumerationType()) return UnknownVal(); llvm::APSInt i = val.castAs<nonloc::ConcreteInt>().getValue(); @@ -137,7 +137,7 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) { if (castTy->isUnionType()) return UnknownVal(); - if (castTy->isIntegerType()) { + if (castTy->isIntegralOrEnumerationType()) { unsigned BitWidth = Context.getTypeSize(castTy); if (!val.getAs<loc::ConcreteInt>()) @@ -438,9 +438,13 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state, case BO_GE: case BO_EQ: case BO_NE: + assert(resultTy->isBooleanType() || + resultTy == getConditionType()); + assert(symIntExpr->getType()->isBooleanType() || + getContext().hasSameUnqualifiedType(symIntExpr->getType(), + getConditionType())); // Negate the comparison and make a value. opc = BinaryOperator::negateComparisonOp(opc); - assert(symIntExpr->getType() == resultTy); return makeNonLoc(symIntExpr->getLHS(), opc, symIntExpr->getRHS(), resultTy); } diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp index a0c24fe..690ed08 100644 --- a/lib/StaticAnalyzer/Core/Store.cpp +++ b/lib/StaticAnalyzer/Core/Store.cpp @@ -289,62 +289,82 @@ SVal StoreManager::evalDerivedToBase(SVal Derived, QualType BaseType, return loc::MemRegionVal(BaseReg); } -SVal StoreManager::evalDynamicCast(SVal Base, QualType DerivedType, +/// Returns the static type of the given region, if it represents a C++ class +/// object. +/// +/// This handles both fully-typed regions, where the dynamic type is known, and +/// symbolic regions, where the dynamic type is merely bounded (and even then, +/// only ostensibly!), but does not take advantage of any dynamic type info. +static const CXXRecordDecl *getCXXRecordType(const MemRegion *MR) { + if (const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(MR)) + return TVR->getValueType()->getAsCXXRecordDecl(); + if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR)) + return SR->getSymbol()->getType()->getPointeeCXXRecordDecl(); + return 0; +} + +SVal StoreManager::evalDynamicCast(SVal Base, QualType TargetType, bool &Failed) { Failed = false; - Optional<loc::MemRegionVal> BaseRegVal = Base.getAs<loc::MemRegionVal>(); - if (!BaseRegVal) + const MemRegion *MR = Base.getAsRegion(); + if (!MR) return UnknownVal(); - const MemRegion *BaseRegion = BaseRegVal->stripCasts(/*StripBases=*/false); // Assume the derived class is a pointer or a reference to a CXX record. - DerivedType = DerivedType->getPointeeType(); - assert(!DerivedType.isNull()); - const CXXRecordDecl *DerivedDecl = DerivedType->getAsCXXRecordDecl(); - if (!DerivedDecl && !DerivedType->isVoidType()) + TargetType = TargetType->getPointeeType(); + assert(!TargetType.isNull()); + const CXXRecordDecl *TargetClass = TargetType->getAsCXXRecordDecl(); + if (!TargetClass && !TargetType->isVoidType()) return UnknownVal(); // Drill down the CXXBaseObject chains, which represent upcasts (casts from // derived to base). - const MemRegion *SR = BaseRegion; - while (const TypedRegion *TSR = dyn_cast_or_null<TypedRegion>(SR)) { - QualType BaseType = TSR->getLocationType()->getPointeeType(); - assert(!BaseType.isNull()); - const CXXRecordDecl *SRDecl = BaseType->getAsCXXRecordDecl(); - if (!SRDecl) - return UnknownVal(); - + while (const CXXRecordDecl *MRClass = getCXXRecordType(MR)) { // If found the derived class, the cast succeeds. - if (SRDecl == DerivedDecl) - return loc::MemRegionVal(TSR); + if (MRClass == TargetClass) + return loc::MemRegionVal(MR); - if (!DerivedType->isVoidType()) { + if (!TargetType->isVoidType()) { // Static upcasts are marked as DerivedToBase casts by Sema, so this will // only happen when multiple or virtual inheritance is involved. CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true, /*DetectVirtual=*/false); - if (SRDecl->isDerivedFrom(DerivedDecl, Paths)) - return evalDerivedToBase(loc::MemRegionVal(TSR), Paths.front()); + if (MRClass->isDerivedFrom(TargetClass, Paths)) + return evalDerivedToBase(loc::MemRegionVal(MR), Paths.front()); } - if (const CXXBaseObjectRegion *R = dyn_cast<CXXBaseObjectRegion>(TSR)) + if (const CXXBaseObjectRegion *BaseR = dyn_cast<CXXBaseObjectRegion>(MR)) { // Drill down the chain to get the derived classes. - SR = R->getSuperRegion(); - else { - // We reached the bottom of the hierarchy. - - // If this is a cast to void*, return the region. - if (DerivedType->isVoidType()) - return loc::MemRegionVal(TSR); + MR = BaseR->getSuperRegion(); + continue; + } - // We did not find the derived class. We we must be casting the base to - // derived, so the cast should fail. - Failed = true; - return UnknownVal(); + // If this is a cast to void*, return the region. + if (TargetType->isVoidType()) + return loc::MemRegionVal(MR); + + // Strange use of reinterpret_cast can give us paths we don't reason + // about well, by putting in ElementRegions where we'd expect + // CXXBaseObjectRegions. If it's a valid reinterpret_cast (i.e. if the + // derived class has a zero offset from the base class), then it's safe + // to strip the cast; if it's invalid, -Wreinterpret-base-class should + // catch it. In the interest of performance, the analyzer will silently + // do the wrong thing in the invalid case (because offsets for subregions + // will be wrong). + const MemRegion *Uncasted = MR->StripCasts(/*IncludeBaseCasts=*/false); + if (Uncasted == MR) { + // We reached the bottom of the hierarchy and did not find the derived + // class. We we must be casting the base to derived, so the cast should + // fail. + break; } + + MR = Uncasted; } - + + // We failed if the region we ended up with has perfect type info. + Failed = isa<TypedValueRegion>(MR); return UnknownVal(); } diff --git a/lib/StaticAnalyzer/Core/SymbolManager.cpp b/lib/StaticAnalyzer/Core/SymbolManager.cpp index de2f5bc..7c75b6c 100644 --- a/lib/StaticAnalyzer/Core/SymbolManager.cpp +++ b/lib/StaticAnalyzer/Core/SymbolManager.cpp @@ -340,8 +340,8 @@ bool SymbolManager::canSymbolicate(QualType T) { if (Loc::isLocType(T)) return true; - if (T->isIntegerType()) - return T->isScalarType(); + if (T->isIntegralOrEnumerationType()) + return true; if (T->isRecordType() && !T->isUnionType()) return true; diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp index 4fad5a8..e7def08 100644 --- a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp +++ b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp @@ -100,11 +100,12 @@ void ClangCheckerRegistry::warnIncompatible(DiagnosticsEngine *diags, } -CheckerManager *ento::createCheckerManager(const AnalyzerOptions &opts, +CheckerManager *ento::createCheckerManager(AnalyzerOptions &opts, const LangOptions &langOpts, ArrayRef<std::string> plugins, DiagnosticsEngine &diags) { - OwningPtr<CheckerManager> checkerMgr(new CheckerManager(langOpts)); + OwningPtr<CheckerManager> checkerMgr(new CheckerManager(langOpts, + &opts)); SmallVector<CheckerOptInfo, 8> checkerOpts; for (unsigned i = 0, e = opts.CheckersControlList.size(); i != e; ++i) { |