diff options
Diffstat (limited to 'lib')
69 files changed, 2014 insertions, 569 deletions
diff --git a/lib/ARCMigrate/TransUnbridgedCasts.cpp b/lib/ARCMigrate/TransUnbridgedCasts.cpp index fc4a75fdb8..a5752f8157 100644 --- a/lib/ARCMigrate/TransUnbridgedCasts.cpp +++ b/lib/ARCMigrate/TransUnbridgedCasts.cpp @@ -148,7 +148,7 @@ private: if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 && FD->getParent()->isTranslationUnit() && - FD->hasExternalLinkage()) { + FD->isExternallyVisible()) { Expr *Arg = callE->getArg(0); if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { const Expr *sub = ICE->getSubExpr(); @@ -413,7 +413,7 @@ private: FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 && FD->getParent()->isTranslationUnit() && - FD->hasExternalLinkage()) + FD->isExternallyVisible()) return true; return false; diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp index 087219535a..6c724af53a 100644 --- a/lib/ARCMigrate/Transforms.cpp +++ b/lib/ARCMigrate/Transforms.cpp @@ -94,7 +94,7 @@ bool trans::isPlusOne(const Expr *E) { if (FD->isGlobal() && FD->getIdentifier() && FD->getParent()->isTranslationUnit() && - FD->hasExternalLinkage() && + FD->isExternallyVisible() && ento::cocoa::isRefType(callE->getType(), "CF", FD->getIdentifier()->getName())) { StringRef fname = FD->getIdentifier()->getName(); @@ -198,7 +198,7 @@ bool trans::isGlobalVar(Expr *E) { E = E->IgnoreParenCasts(); if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) return DRE->getDecl()->getDeclContext()->isFileContext() && - DRE->getDecl()->hasExternalLinkage(); + DRE->getDecl()->isExternallyVisible(); if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E)) return isGlobalVar(condOp->getTrueExpr()) && isGlobalVar(condOp->getFalseExpr()); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 986bb8c3d2..b19150f048 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -409,6 +409,8 @@ comments::FullComment *ASTContext::cloneFullComment(comments::FullComment *FC, comments::FullComment *ASTContext::getCommentForDecl( const Decl *D, const Preprocessor *PP) const { + if (D->isInvalidDecl()) + return NULL; D = adjustDeclToTemplate(D); const Decl *Canonical = D->getCanonicalDecl(); @@ -1343,8 +1345,28 @@ ASTContext::getTypeInfoDataSizeInChars(QualType T) const { return sizeAndAlign; } +/// getConstantArrayInfoInChars - Performing the computation in CharUnits +/// instead of in bits prevents overflowing the uint64_t for some large arrays. +std::pair<CharUnits, CharUnits> +static getConstantArrayInfoInChars(const ASTContext &Context, + const ConstantArrayType *CAT) { + std::pair<CharUnits, CharUnits> EltInfo = + Context.getTypeInfoInChars(CAT->getElementType()); + uint64_t Size = CAT->getSize().getZExtValue(); + assert((Size == 0 || static_cast<uint64_t>(EltInfo.first.getQuantity()) <= + (uint64_t)(-1)/Size) && + "Overflow in array type char size evaluation"); + uint64_t Width = EltInfo.first.getQuantity() * Size; + unsigned Align = EltInfo.second.getQuantity(); + Width = llvm::RoundUpToAlignment(Width, Align); + return std::make_pair(CharUnits::fromQuantity(Width), + CharUnits::fromQuantity(Align)); +} + std::pair<CharUnits, CharUnits> ASTContext::getTypeInfoInChars(const Type *T) const { + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T)) + return getConstantArrayInfoInChars(*this, CAT); std::pair<uint64_t, unsigned> Info = getTypeInfo(T); return std::make_pair(toCharUnitsFromBits(Info.first), toCharUnitsFromBits(Info.second)); @@ -1700,10 +1722,10 @@ int64_t ASTContext::toBits(CharUnits CharSize) const { /// getTypeSizeInChars - Return the size of the specified type, in characters. /// This method does not work on incomplete types. CharUnits ASTContext::getTypeSizeInChars(QualType T) const { - return toCharUnitsFromBits(getTypeSize(T)); + return getTypeInfoInChars(T).first; } CharUnits ASTContext::getTypeSizeInChars(const Type *T) const { - return toCharUnitsFromBits(getTypeSize(T)); + return getTypeInfoInChars(T).first; } /// getTypeAlignInChars - Return the ABI-specified alignment of a type, in @@ -7767,30 +7789,23 @@ QualType ASTContext::GetBuiltinType(unsigned Id, } GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) { - GVALinkage External = GVA_StrongExternal; - - Linkage L = FD->getLinkage(); - switch (L) { - case NoLinkage: - case InternalLinkage: - case UniqueExternalLinkage: + if (!FD->isExternallyVisible()) return GVA_Internal; - - case ExternalLinkage: - switch (FD->getTemplateSpecializationKind()) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - External = GVA_StrongExternal; - break; - case TSK_ExplicitInstantiationDefinition: - return GVA_ExplicitTemplateInstantiation; + GVALinkage External = GVA_StrongExternal; + switch (FD->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + External = GVA_StrongExternal; + break; + + case TSK_ExplicitInstantiationDefinition: + return GVA_ExplicitTemplateInstantiation; - case TSK_ExplicitInstantiationDeclaration: - case TSK_ImplicitInstantiation: - External = GVA_TemplateInstantiation; - break; - } + case TSK_ExplicitInstantiationDeclaration: + case TSK_ImplicitInstantiation: + External = GVA_TemplateInstantiation; + break; } if (!FD->isInlined()) @@ -7820,6 +7835,9 @@ GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) { } GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) { + if (!VD->isExternallyVisible()) + return GVA_Internal; + // If this is a static data member, compute the kind of template // specialization. Otherwise, this variable is not part of a // template. @@ -7827,30 +7845,20 @@ GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) { if (VD->isStaticDataMember()) TSK = VD->getTemplateSpecializationKind(); - Linkage L = VD->getLinkage(); + switch (TSK) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + return GVA_StrongExternal; - switch (L) { - case NoLinkage: - case InternalLinkage: - case UniqueExternalLinkage: - return GVA_Internal; + case TSK_ExplicitInstantiationDeclaration: + llvm_unreachable("Variable should not be instantiated"); + // Fall through to treat this like any other instantiation. - case ExternalLinkage: - switch (TSK) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - return GVA_StrongExternal; + case TSK_ExplicitInstantiationDefinition: + return GVA_ExplicitTemplateInstantiation; - case TSK_ExplicitInstantiationDeclaration: - llvm_unreachable("Variable should not be instantiated"); - // Fall through to treat this like any other instantiation. - - case TSK_ExplicitInstantiationDefinition: - return GVA_ExplicitTemplateInstantiation; - - case TSK_ImplicitInstantiation: - return GVA_TemplateInstantiation; - } + case TSK_ImplicitInstantiation: + return GVA_TemplateInstantiation; } llvm_unreachable("Invalid Linkage!"); @@ -7986,7 +7994,8 @@ size_t ASTContext::getSideTableAllocatedMemory() const { void ASTContext::addUnnamedTag(const TagDecl *Tag) { // FIXME: This mangling should be applied to function local classes too if (!Tag->getName().empty() || Tag->getTypedefNameForAnonDecl() || - !isa<CXXRecordDecl>(Tag->getParent()) || Tag->getLinkage() != ExternalLinkage) + !isa<CXXRecordDecl>(Tag->getParent()) || + !Tag->isExternallyVisible()) return; std::pair<llvm::DenseMap<const DeclContext *, unsigned>::iterator, bool> P = diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index 766a7a995b..e0f552ba67 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -300,8 +300,7 @@ void clang::FormatASTNodeDiagnosticArgument( assert(ModLen == 0 && ArgLen == 0 && "Invalid modifier for DeclarationName argument"); - DeclarationName N = DeclarationName::getFromOpaqueInteger(Val); - N.printName(OS); + OS << DeclarationName::getFromOpaqueInteger(Val); break; } case DiagnosticsEngine::ak_nameddecl: { diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 340cc41f7e..cd974f0d02 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -449,9 +449,7 @@ void ASTDumper::dumpBareDeclRef(const Decl *D) { if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) { ColorScope Color(*this, DeclNameColor); - OS << " '"; - ND->getDeclName().printName(OS); - OS << "'"; + OS << " '" << ND->getDeclName() << '\''; } if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) @@ -1331,7 +1329,7 @@ void ASTDumper::dumpStmt(const Stmt *S) { return; } - setMoreChildren(S->children()); + setMoreChildren(!S->children().empty()); ConstStmtVisitor<ASTDumper>::Visit(S); setMoreChildren(false); for (Stmt::const_child_range CI = S->children(); CI; ++CI) { diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 915eb6feb8..204b9d001c 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -2610,8 +2610,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { continue; if (FunctionDecl *FoundFunction = dyn_cast<FunctionDecl>(FoundDecls[I])) { - if (isExternalLinkage(FoundFunction->getLinkage()) && - isExternalLinkage(D->getLinkage())) { + if (FoundFunction->hasExternalFormalLinkage() && + D->hasExternalFormalLinkage()) { if (Importer.IsStructurallyEquivalent(D->getType(), FoundFunction->getType())) { // FIXME: Actually try to merge the body and other attributes. @@ -2878,7 +2878,7 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { if (Importer.IsStructurallyEquivalent(D->getType(), FoundField->getType(), - Name)) { + !Name.isEmpty())) { Importer.Imported(D, FoundField); return FoundField; } @@ -2995,8 +2995,8 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { if (VarDecl *FoundVar = dyn_cast<VarDecl>(FoundDecls[I])) { // We have found a variable that we may need to merge with. Check it. - if (isExternalLinkage(FoundVar->getLinkage()) && - isExternalLinkage(D->getLinkage())) { + if (FoundVar->hasExternalFormalLinkage() && + D->hasExternalFormalLinkage()) { if (Importer.IsStructurallyEquivalent(D->getType(), FoundVar->getType())) { MergeWithVar = FoundVar; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index ab9d73b917..b8f478728f 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -483,6 +483,10 @@ static bool isSingleLineExternC(const Decl &D) { return false; } +static bool isExternalLinkage(Linkage L) { + return L == UniqueExternalLinkage || L == ExternalLinkage; +} + static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVComputationKind computation) { assert(D->getDeclContext()->getRedeclContext()->isFileContext() && @@ -660,9 +664,20 @@ 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->isInExternCContext() && - Function->getType()->getLinkage() == UniqueExternalLinkage) - return LinkageInfo::uniqueExternal(); + !Function->isInExternCContext()) { + // Only look at the type-as-written. If this function has an auto-deduced + // return type, we can't compute the linkage of that type because it could + // require looking at the linkage of this function, and we don't need this + // for correctness because the type is not part of the function's + // signature. + // FIXME: This is a hack. We should be able to solve this circularity some + // other way. + QualType TypeAsWritten = Function->getType(); + if (TypeSourceInfo *TSI = Function->getTypeSourceInfo()) + TypeAsWritten = TSI->getType(); + if (TypeAsWritten->getLinkage() == UniqueExternalLinkage) + return LinkageInfo::uniqueExternal(); + } // Consider LV from the template and the template arguments. // We're at file scope, so we do not need to worry about nested @@ -874,7 +889,7 @@ bool NamedDecl::isLinkageValid() const { Linkage(CachedLinkage); } -Linkage NamedDecl::getLinkage() const { +Linkage NamedDecl::getLinkageInternal() const { if (HasCachedLinkage) return Linkage(CachedLinkage); @@ -1278,7 +1293,7 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { } bool NamedDecl::hasLinkage() const { - return getLinkage() != NoLinkage; + return getLinkageInternal() != NoLinkage; } NamedDecl *NamedDecl::getUnderlyingDeclImpl() { @@ -1502,7 +1517,7 @@ template<typename T> static LanguageLinkage getLanguageLinkageTemplate(const T &D) { // C++ [dcl.link]p1: All function types, function names with external linkage, // and variable names with external linkage have a language linkage. - if (!isExternalLinkage(D.getLinkage())) + if (!D.hasExternalFormalLinkage()) return NoLanguageLinkage; // Language linkage is a C++ concept, but saying that everything else in C has @@ -2304,7 +2319,7 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const { const FunctionDecl *Prev = this; bool FoundBody = false; while ((Prev = Prev->getPreviousDecl())) { - FoundBody |= Prev->Body; + FoundBody |= Prev->Body.isValid(); if (Prev->Body) { // If it's not the case that both 'inline' and 'extern' are @@ -2332,7 +2347,7 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const { const FunctionDecl *Prev = this; bool FoundBody = false; while ((Prev = Prev->getPreviousDecl())) { - FoundBody |= Prev->Body; + FoundBody |= Prev->Body.isValid(); if (RedeclForcesDefC99(Prev)) return false; } diff --git a/lib/AST/DeclOpenMP.cpp b/lib/AST/DeclOpenMP.cpp index c0d10a0f41..522caefe3b 100644 --- a/lib/AST/DeclOpenMP.cpp +++ b/lib/AST/DeclOpenMP.cpp @@ -28,9 +28,9 @@ void OMPThreadPrivateDecl::anchor() { } OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - ArrayRef<DeclRefExpr *> VL) { + ArrayRef<Expr *> VL) { unsigned Size = sizeof(OMPThreadPrivateDecl) + - (VL.size() * sizeof(DeclRefExpr *)); + (VL.size() * sizeof(Expr *)); void *Mem = C.Allocate(Size, llvm::alignOf<OMPThreadPrivateDecl>()); OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate, @@ -43,7 +43,7 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C, OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C, unsigned ID, unsigned N) { - unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(DeclRefExpr *)); + unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(Expr *)); void *Mem = AllocateDeserializedDecl(C, ID, Size); OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate, @@ -52,9 +52,9 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C, return D; } -void OMPThreadPrivateDecl::setVars(ArrayRef<DeclRefExpr *> VL) { +void OMPThreadPrivateDecl::setVars(ArrayRef<Expr *> VL) { assert(VL.size() == NumVars && "Number of variables is not the same as the preallocated buffer"); - DeclRefExpr **Vars = reinterpret_cast<DeclRefExpr **>(this + 1); + Expr **Vars = reinterpret_cast<Expr **>(this + 1); std::copy(VL.begin(), VL.end(), Vars); } diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index d47972bc61..1c9fd2d5f6 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -1180,9 +1180,9 @@ void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { if (!D->varlist_empty()) { for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(), E = D->varlist_end(); - I != E; ++I) { + I != E; ++I) { Out << (I == D->varlist_begin() ? '(' : ',') - << *cast<NamedDecl>((*I)->getDecl()); + << *cast<NamedDecl>(cast<DeclRefExpr>(*I)->getDecl()); } Out << ")"; } diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index e4a41b6ffb..e064e23a0a 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -133,6 +133,66 @@ int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) { llvm_unreachable("Invalid DeclarationName Kind!"); } +raw_ostream &operator<<(raw_ostream &OS, DeclarationName N) { + switch (N.getNameKind()) { + case DeclarationName::Identifier: + if (const IdentifierInfo *II = N.getAsIdentifierInfo()) + OS << II->getName(); + return OS; + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + return OS << N.getObjCSelector().getAsString(); + + case DeclarationName::CXXConstructorName: { + QualType ClassType = N.getCXXNameType(); + if (const RecordType *ClassRec = ClassType->getAs<RecordType>()) + return OS << *ClassRec->getDecl(); + return OS << ClassType.getAsString(); + } + + case DeclarationName::CXXDestructorName: { + OS << '~'; + QualType Type = N.getCXXNameType(); + if (const RecordType *Rec = Type->getAs<RecordType>()) + return OS << *Rec->getDecl(); + return OS << Type.getAsString(); + } + + case DeclarationName::CXXOperatorName: { + static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = { + 0, +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + Spelling, +#include "clang/Basic/OperatorKinds.def" + }; + const char *OpName = OperatorNames[N.getCXXOverloadedOperator()]; + assert(OpName && "not an overloaded operator"); + + OS << "operator"; + if (OpName[0] >= 'a' && OpName[0] <= 'z') + OS << ' '; + return OS << OpName; + } + + case DeclarationName::CXXLiteralOperatorName: + return OS << "operator \"\" " << N.getCXXLiteralIdentifier()->getName(); + + case DeclarationName::CXXConversionFunctionName: { + OS << "operator "; + QualType Type = N.getCXXNameType(); + if (const RecordType *Rec = Type->getAs<RecordType>()) + return OS << *Rec->getDecl(); + return OS << Type.getAsString(); + } + case DeclarationName::CXXUsingDirective: + return OS << "<using-directive>"; + } + + llvm_unreachable("Unexpected declaration name kind"); +} + } // end namespace clang DeclarationName::NameKind DeclarationName::getNameKind() const { @@ -180,80 +240,10 @@ bool DeclarationName::isDependentName() const { std::string DeclarationName::getAsString() const { std::string Result; llvm::raw_string_ostream OS(Result); - printName(OS); + OS << *this; return OS.str(); } -void DeclarationName::printName(raw_ostream &OS) const { - switch (getNameKind()) { - case Identifier: - if (const IdentifierInfo *II = getAsIdentifierInfo()) - OS << II->getName(); - return; - - case ObjCZeroArgSelector: - case ObjCOneArgSelector: - case ObjCMultiArgSelector: - OS << getObjCSelector().getAsString(); - return; - - case CXXConstructorName: { - QualType ClassType = getCXXNameType(); - if (const RecordType *ClassRec = ClassType->getAs<RecordType>()) - OS << *ClassRec->getDecl(); - else - OS << ClassType.getAsString(); - return; - } - - case CXXDestructorName: { - OS << '~'; - QualType Type = getCXXNameType(); - if (const RecordType *Rec = Type->getAs<RecordType>()) - OS << *Rec->getDecl(); - else - OS << Type.getAsString(); - return; - } - - case CXXOperatorName: { - static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = { - 0, -#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ - Spelling, -#include "clang/Basic/OperatorKinds.def" - }; - const char *OpName = OperatorNames[getCXXOverloadedOperator()]; - assert(OpName && "not an overloaded operator"); - - OS << "operator"; - if (OpName[0] >= 'a' && OpName[0] <= 'z') - OS << ' '; - OS << OpName; - return; - } - - case CXXLiteralOperatorName: - OS << "operator \"\" " << getCXXLiteralIdentifier()->getName(); - return; - - case CXXConversionFunctionName: { - OS << "operator "; - QualType Type = getCXXNameType(); - if (const RecordType *Rec = Type->getAs<RecordType>()) - OS << *Rec->getDecl(); - else - OS << Type.getAsString(); - return; - } - case CXXUsingDirective: - OS << "<using-directive>"; - return; - } - - llvm_unreachable("Unexpected declaration name kind"); -} - QualType DeclarationName::getCXXNameType() const { if (CXXSpecialName *CXXName = getAsCXXSpecialName()) return CXXName->Type; @@ -336,8 +326,7 @@ DeclarationName DeclarationName::getUsingDirectiveName() { } void DeclarationName::dump() const { - printName(llvm::errs()); - llvm::errs() << '\n'; + llvm::errs() << *this << '\n'; } DeclarationNameTable::DeclarationNameTable(const ASTContext &C) : Ctx(C) { @@ -537,7 +526,7 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const { case DeclarationName::CXXOperatorName: case DeclarationName::CXXLiteralOperatorName: case DeclarationName::CXXUsingDirective: - Name.printName(OS); + OS << Name; return; case DeclarationName::CXXConstructorName: @@ -549,9 +538,8 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const { else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) OS << "operator "; OS << TInfo->getType().getAsString(); - } - else - Name.printName(OS); + } else + OS << Name; return; } llvm_unreachable("Unexpected declaration name kind"); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 15cf5ac4ab..f587dfa93e 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -423,7 +423,7 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, FoundD = 0; std::size_t Size = sizeof(DeclRefExpr); - if (QualifierLoc != 0) + if (QualifierLoc) Size += sizeof(NestedNameSpecifierLoc); if (FoundD) Size += sizeof(NamedDecl *); diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index bf967961aa..3741bf12d5 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -1809,7 +1809,7 @@ struct CompleteObject { assert(Value && "missing value for complete object"); } - operator bool() const { return Value; } + LLVM_EXPLICIT operator bool() const { return Value; } }; /// Find the designated sub-object of an rvalue. @@ -2769,7 +2769,9 @@ enum EvalStmtResult { /// Hit a 'continue' statement. ESR_Continue, /// Hit a 'break' statement. - ESR_Break + ESR_Break, + /// Still scanning for 'case' or 'default' statement. + ESR_CaseNotFound }; } @@ -2803,12 +2805,13 @@ static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl, } static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, - const Stmt *S); + const Stmt *S, const SwitchCase *SC = 0); /// 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)) { + const Stmt *Body, + const SwitchCase *Case = 0) { + switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body, Case)) { case ESR_Break: return ESR_Succeeded; case ESR_Succeeded: @@ -2816,17 +2819,127 @@ static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info, return ESR_Continue; case ESR_Failed: case ESR_Returned: + case ESR_CaseNotFound: return ESR; } llvm_unreachable("Invalid EvalStmtResult!"); } +/// Evaluate a switch statement. +static EvalStmtResult EvaluateSwitch(APValue &Result, EvalInfo &Info, + const SwitchStmt *SS) { + // Evaluate the switch condition. + if (SS->getConditionVariable() && + !EvaluateDecl(Info, SS->getConditionVariable())) + return ESR_Failed; + APSInt Value; + if (!EvaluateInteger(SS->getCond(), Value, Info)) + return ESR_Failed; + + // Find the switch case corresponding to the value of the condition. + // FIXME: Cache this lookup. + const SwitchCase *Found = 0; + for (const SwitchCase *SC = SS->getSwitchCaseList(); SC; + SC = SC->getNextSwitchCase()) { + if (isa<DefaultStmt>(SC)) { + Found = SC; + continue; + } + + const CaseStmt *CS = cast<CaseStmt>(SC); + APSInt LHS = CS->getLHS()->EvaluateKnownConstInt(Info.Ctx); + APSInt RHS = CS->getRHS() ? CS->getRHS()->EvaluateKnownConstInt(Info.Ctx) + : LHS; + if (LHS <= Value && Value <= RHS) { + Found = SC; + break; + } + } + + if (!Found) + return ESR_Succeeded; + + // Search the switch body for the switch case and evaluate it from there. + switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, SS->getBody(), Found)) { + case ESR_Break: + return ESR_Succeeded; + case ESR_Succeeded: + case ESR_Continue: + case ESR_Failed: + case ESR_Returned: + return ESR; + case ESR_CaseNotFound: + llvm_unreachable("couldn't find switch case"); + } + llvm_unreachable("Invalid EvalStmtResult!"); +} + // Evaluate a statement. static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, - const Stmt *S) { + const Stmt *S, const SwitchCase *Case) { if (!Info.nextStep(S)) return ESR_Failed; + // If we're hunting down a 'case' or 'default' label, recurse through + // substatements until we hit the label. + if (Case) { + // FIXME: We don't start the lifetime of objects whose initialization we + // jump over. However, such objects must be of class type with a trivial + // default constructor that initialize all subobjects, so must be empty, + // so this almost never matters. + switch (S->getStmtClass()) { + case Stmt::CompoundStmtClass: + // FIXME: Precompute which substatement of a compound statement we + // would jump to, and go straight there rather than performing a + // linear scan each time. + case Stmt::LabelStmtClass: + case Stmt::AttributedStmtClass: + case Stmt::DoStmtClass: + break; + + case Stmt::CaseStmtClass: + case Stmt::DefaultStmtClass: + if (Case == S) + Case = 0; + break; + + case Stmt::IfStmtClass: { + // FIXME: Precompute which side of an 'if' we would jump to, and go + // straight there rather than scanning both sides. + const IfStmt *IS = cast<IfStmt>(S); + EvalStmtResult ESR = EvaluateStmt(Result, Info, IS->getThen(), Case); + if (ESR != ESR_CaseNotFound || !IS->getElse()) + return ESR; + return EvaluateStmt(Result, Info, IS->getElse(), Case); + } + + case Stmt::WhileStmtClass: { + EvalStmtResult ESR = + EvaluateLoopBody(Result, Info, cast<WhileStmt>(S)->getBody(), Case); + if (ESR != ESR_Continue) + return ESR; + break; + } + + case Stmt::ForStmtClass: { + const ForStmt *FS = cast<ForStmt>(S); + EvalStmtResult ESR = + EvaluateLoopBody(Result, Info, FS->getBody(), Case); + if (ESR != ESR_Continue) + return ESR; + if (FS->getInc() && !EvaluateIgnoredValue(Info, FS->getInc())) + return ESR_Failed; + break; + } + + case Stmt::DeclStmtClass: + // FIXME: If the variable has initialization that can't be jumped over, + // bail out of any immediately-surrounding compound-statement too. + default: + return ESR_CaseNotFound; + } + } + // FIXME: Mark all temporaries in the current frame as destroyed at // the end of each full-expression. switch (S->getStmtClass()) { @@ -2865,11 +2978,13 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, const CompoundStmt *CS = cast<CompoundStmt>(S); for (CompoundStmt::const_body_iterator BI = CS->body_begin(), BE = CS->body_end(); BI != BE; ++BI) { - EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI); - if (ESR != ESR_Succeeded) + EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI, Case); + if (ESR == ESR_Succeeded) + Case = 0; + else if (ESR != ESR_CaseNotFound) return ESR; } - return ESR_Succeeded; + return Case ? ESR_CaseNotFound : ESR_Succeeded; } case Stmt::IfStmtClass: { @@ -2909,9 +3024,10 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, const DoStmt *DS = cast<DoStmt>(S); bool Continue; do { - EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody()); + EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody(), Case); if (ESR != ESR_Continue) return ESR; + Case = 0; if (!EvaluateAsBooleanCondition(DS->getCond(), Continue, Info)) return ESR_Failed; @@ -2983,11 +3099,27 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info, return ESR_Succeeded; } + case Stmt::SwitchStmtClass: + return EvaluateSwitch(Result, Info, cast<SwitchStmt>(S)); + case Stmt::ContinueStmtClass: return ESR_Continue; case Stmt::BreakStmtClass: return ESR_Break; + + case Stmt::LabelStmtClass: + return EvaluateStmt(Result, Info, cast<LabelStmt>(S)->getSubStmt(), Case); + + case Stmt::AttributedStmtClass: + // As a general principle, C++11 attributes can be ignored without + // any semantic impact. + return EvaluateStmt(Result, Info, cast<AttributedStmt>(S)->getSubStmt(), + Case); + + case Stmt::CaseStmtClass: + case Stmt::DefaultStmtClass: + return EvaluateStmt(Result, Info, cast<SwitchCase>(S)->getSubStmt(), Case); } } @@ -3029,6 +3161,11 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, Declaration->isConstexpr()) return false; + // Bail out with no diagnostic if the function declaration itself is invalid. + // We will have produced a relevant diagnostic while parsing it. + if (Declaration->isInvalidDecl()) + return false; + // Can we evaluate this function call? if (Definition && Definition->isConstexpr() && !Definition->isInvalidDecl()) return true; diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index d28aced172..3137f3c8fd 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -405,7 +405,7 @@ bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) { if (DC->isFunctionOrMethod() && D->hasLinkage()) while (!DC->isNamespace() && !DC->isTranslationUnit()) DC = getEffectiveParentContext(DC); - if (DC->isTranslationUnit() && D->getLinkage() != InternalLinkage) + if (DC->isTranslationUnit() && D->getFormalLinkage() != InternalLinkage) return false; } @@ -1053,7 +1053,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, // static void foo(); // This naming convention is the same as that followed by GCC, // though it shouldn't actually matter. - if (ND && ND->getLinkage() == InternalLinkage && + if (ND && ND->getFormalLinkage() == InternalLinkage && getEffectiveDeclContext(ND)->isFileContext()) Out << 'L'; diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index 7c797eef4d..d03060b391 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -22,6 +22,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/Basic/ABI.h" #include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/TargetInfo.h" #include <map> using namespace clang; @@ -58,19 +59,27 @@ class MicrosoftCXXNameMangler { ASTContext &getASTContext() const { return Context.getASTContext(); } + // FIXME: If we add support for __ptr32/64 qualifiers, then we should push + // this check into mangleQualifiers(). + const bool PointersAre64Bit; + 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), - UseNameBackReferences(true) { } + UseNameBackReferences(true), + PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) == + 64) { } MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_, const CXXDestructorDecl *D, CXXDtorType Type) : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), - UseNameBackReferences(true) { } + UseNameBackReferences(true), + PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) == + 64) { } raw_ostream &getStream() const { return Out; } @@ -199,7 +208,7 @@ bool MicrosoftMangleContext::shouldMangleDeclName(const NamedDecl *D) { // Variables at global scope with internal linkage are not mangled. if (!FD) { const DeclContext *DC = D->getDeclContext(); - if (DC->isTranslationUnit() && D->getLinkage() == InternalLinkage) + if (DC->isTranslationUnit() && D->getFormalLinkage() == InternalLinkage) return false; } @@ -1228,32 +1237,36 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, } void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) { - // <function-class> ::= A # private: near - // ::= B # private: far - // ::= C # private: static near - // ::= D # private: static far - // ::= E # private: virtual near - // ::= F # private: virtual far - // ::= G # private: thunk near - // ::= H # private: thunk far - // ::= I # protected: near - // ::= J # protected: far - // ::= K # protected: static near - // ::= L # protected: static far - // ::= M # protected: virtual near - // ::= N # protected: virtual far - // ::= O # protected: thunk near - // ::= P # protected: thunk far - // ::= Q # public: near - // ::= R # public: far - // ::= S # public: static near - // ::= T # public: static far - // ::= U # public: virtual near - // ::= V # public: virtual far - // ::= W # public: thunk near - // ::= X # public: thunk far - // ::= Y # global near - // ::= Z # global far + // <function-class> ::= <member-function> E? # E designates a 64-bit 'this' + // # pointer. in 64-bit mode *all* + // # 'this' pointers are 64-bit. + // ::= <global-function> + // <member-function> ::= A # private: near + // ::= B # private: far + // ::= C # private: static near + // ::= D # private: static far + // ::= E # private: virtual near + // ::= F # private: virtual far + // ::= G # private: thunk near + // ::= H # private: thunk far + // ::= I # protected: near + // ::= J # protected: far + // ::= K # protected: static near + // ::= L # protected: static far + // ::= M # protected: virtual near + // ::= N # protected: virtual far + // ::= O # protected: thunk near + // ::= P # protected: thunk far + // ::= Q # public: near + // ::= R # public: far + // ::= S # public: static near + // ::= T # public: static far + // ::= U # public: virtual near + // ::= V # public: virtual far + // ::= W # public: thunk near + // ::= X # public: thunk far + // <global-function> ::= Y # global near + // ::= Z # global far if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { switch (MD->getAccess()) { default: @@ -1281,6 +1294,8 @@ void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) { else Out << 'Q'; } + if (PointersAre64Bit && !MD->isStatic()) + Out << 'E'; } else Out << 'Y'; } @@ -1380,9 +1395,9 @@ void MicrosoftCXXNameMangler::mangleType(const TagType *T) { // <type> ::= <array-type> // <array-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> // [Y <dimension-count> <dimension>+] -// <element-type> # as global -// ::= Q <cvr-qualifiers> [Y <dimension-count> <dimension>+] -// <element-type> # as param +// <element-type> # as global, E is never required +// ::= Q E? <cvr-qualifiers> [Y <dimension-count> <dimension>+] +// <element-type> # as param, E is required for 64-bit // 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. @@ -1394,6 +1409,8 @@ void MicrosoftCXXNameMangler::mangleDecayedArrayType(const ArrayType *T, manglePointerQualifiers(T->getElementType().getQualifiers()); } else { Out << 'Q'; + if (PointersAre64Bit) + Out << 'E'; } mangleType(T->getElementType(), SourceRange()); } @@ -1494,10 +1511,13 @@ void MicrosoftCXXNameMangler::mangleType( } // <type> ::= <pointer-type> -// <pointer-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> <type> +// <pointer-type> ::= E? <pointer-cvr-qualifiers> <cvr-qualifiers> <type> +// # the E is required for 64-bit non static pointers void MicrosoftCXXNameMangler::mangleType(const PointerType *T, SourceRange Range) { QualType PointeeTy = T->getPointeeType(); + if (PointersAre64Bit && !T->getPointeeType()->isFunctionType()) + Out << 'E'; mangleType(PointeeTy, Range); } void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T, @@ -1508,18 +1528,24 @@ void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T, } // <type> ::= <reference-type> -// <reference-type> ::= A <cvr-qualifiers> <type> +// <reference-type> ::= A E? <cvr-qualifiers> <type> +// # the E is required for 64-bit non static lvalue references void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T, SourceRange Range) { Out << 'A'; + if (PointersAre64Bit && !T->getPointeeType()->isFunctionType()) + Out << 'E'; mangleType(T->getPointeeType(), Range); } // <type> ::= <r-value-reference-type> -// <r-value-reference-type> ::= $$Q <cvr-qualifiers> <type> +// <r-value-reference-type> ::= $$Q E? <cvr-qualifiers> <type> +// # the E is required for 64-bit non static rvalue references void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T, SourceRange Range) { Out << "$$Q"; + if (PointersAre64Bit && !T->getPointeeType()->isFunctionType()) + Out << 'E'; mangleType(T->getPointeeType(), Range); } diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 42c3ba31bc..eb39d08424 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -211,7 +211,7 @@ void EmptySubobjectMap::AddSubobjectAtOffset(const CXXRecordDecl *RD, if (!RD->isEmpty()) return; - // If we have empty structures inside an union, we can assign both + // If we have empty structures inside a union, we can assign both // the same offset. Just avoid pushing them twice in the list. ClassVectorTy& Classes = EmptyClassOffsets[Offset]; if (std::find(Classes.begin(), Classes.end(), RD) != Classes.end()) @@ -2354,7 +2354,7 @@ static const CXXMethodDecl *computeKeyFunction(ASTContext &Context, // A class that is not externally visible doesn't have a key function. (Or // at least, there's no point to assigning a key function to such a class; // this doesn't affect the ABI.) - if (RD->getLinkage() != ExternalLinkage) + if (!RD->isExternallyVisible()) return 0; // Template instantiations don't have key functions,see Itanium C++ ABI 5.2.6. diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index a1f0b08494..eacf367818 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -2124,7 +2124,7 @@ static CachedProperties computeCachedProperties(const Type *T) { // - it is a class or enumeration type that is named (or has a name // for linkage purposes (7.1.3)) and the name has linkage; or // - it is a specialization of a class template (14); or - Linkage L = Tag->getLinkage(); + Linkage L = Tag->getLinkageInternal(); bool IsLocalOrUnnamed = Tag->getDeclContext()->isFunctionOrMethod() || !Tag->hasNameForLinkage(); @@ -2166,7 +2166,7 @@ static CachedProperties computeCachedProperties(const Type *T) { return result; } case Type::ObjCInterface: { - Linkage L = cast<ObjCInterfaceType>(T)->getDecl()->getLinkage(); + Linkage L = cast<ObjCInterfaceType>(T)->getDecl()->getLinkageInternal(); return CachedProperties(L, false); } case Type::ObjCObject: diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp index 6ebd736e3c..eccc9cd4d3 100644 --- a/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/lib/ASTMatchers/ASTMatchFinder.cpp @@ -744,6 +744,14 @@ void MatchFinder::addMatcher(const TypeLocMatcher &NodeMatch, new TypeLocMatcher(NodeMatch), Action)); } +bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, + MatchCallback *Action) { + MatcherCallbackPairs.push_back(std::make_pair(NodeMatch.clone(), Action)); + // TODO: Do runtime type checking to make sure the matcher is one of the valid + // top-level matchers. + return true; +} + ASTConsumer *MatchFinder::newASTConsumer() { return new internal::MatchASTConsumer(&MatcherCallbackPairs, ParsingDone); } diff --git a/lib/ASTMatchers/CMakeLists.txt b/lib/ASTMatchers/CMakeLists.txt index 86560d61c9..4a390a8fc3 100644 --- a/lib/ASTMatchers/CMakeLists.txt +++ b/lib/ASTMatchers/CMakeLists.txt @@ -1,3 +1,5 @@ +add_subdirectory(Dynamic) + set(LLVM_LINK_COMPONENTS support) add_clang_library(clangASTMatchers diff --git a/lib/ASTMatchers/Dynamic/CMakeLists.txt b/lib/ASTMatchers/Dynamic/CMakeLists.txt new file mode 100644 index 0000000000..843341b297 --- /dev/null +++ b/lib/ASTMatchers/Dynamic/CMakeLists.txt @@ -0,0 +1,16 @@ +set(LLVM_LINK_COMPONENTS support) + +add_clang_library(clangDynamicASTMatchers + Diagnostics.cpp + VariantValue.cpp + Parser.cpp + Registry.cpp + ) + +add_dependencies(clangDynamicASTMatchers + clangASTMatchers + ) + +target_link_libraries(clangDynamicASTMatchers + clangASTMatchers + ) diff --git a/lib/ASTMatchers/Dynamic/Diagnostics.cpp b/lib/ASTMatchers/Dynamic/Diagnostics.cpp new file mode 100644 index 0000000000..fb3cac370f --- /dev/null +++ b/lib/ASTMatchers/Dynamic/Diagnostics.cpp @@ -0,0 +1,113 @@ +//===--- Diagnostics.cpp - Helper class for error diagnostics -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/ASTMatchers/Dynamic/Diagnostics.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +Diagnostics::ArgStream & +Diagnostics::ArgStream::operator<<(const Twine &Arg) { + Out->push_back(Arg.str()); + return *this; +} + +Diagnostics::ArgStream Diagnostics::pushErrorFrame(const SourceRange &Range, + ErrorType Error) { + Frames.insert(Frames.begin(), ErrorFrame()); + ErrorFrame &Last = Frames.front(); + Last.Range = Range; + Last.Type = Error; + ArgStream Out = { &Last.Args }; + return Out; +} + +StringRef ErrorTypeToString(Diagnostics::ErrorType Type) { + switch (Type) { + case Diagnostics::ET_RegistryNotFound: + return "Matcher not found: $0"; + case Diagnostics::ET_RegistryWrongArgCount: + return "Incorrect argument count. (Expected = $0) != (Actual = $1)"; + case Diagnostics::ET_RegistryWrongArgType: + return "Incorrect type on function $0 for arg $1."; + + case Diagnostics::ET_ParserStringError: + return "Error parsing string token: <$0>"; + case Diagnostics::ET_ParserMatcherArgFailure: + return "Error parsing argument $0 for matcher $1."; + case Diagnostics::ET_ParserMatcherFailure: + return "Error building matcher $0."; + case Diagnostics::ET_ParserNoOpenParen: + return "Error parsing matcher. Found token <$0> while looking for '('."; + case Diagnostics::ET_ParserNoCloseParen: + return "Error parsing matcher. Found end-of-code while looking for ')'."; + case Diagnostics::ET_ParserNoComma: + return "Error parsing matcher. Found token <$0> while looking for ','."; + case Diagnostics::ET_ParserNoCode: + return "End of code found while looking for token."; + case Diagnostics::ET_ParserNotAMatcher: + return "Input value is not a matcher expression."; + case Diagnostics::ET_ParserInvalidToken: + return "Invalid token <$0> found when looking for a value."; + + case Diagnostics::ET_None: + return "<N/A>"; + } + llvm_unreachable("Unknown ErrorType value."); +} + +std::string FormatErrorString(StringRef FormatString, + ArrayRef<std::string> Args) { + std::string Out; + while (!FormatString.empty()) { + std::pair<StringRef, StringRef> Pieces = FormatString.split("$"); + Out += Pieces.first.str(); + if (Pieces.second.empty()) break; + + const char Next = Pieces.second.front(); + FormatString = Pieces.second.drop_front(); + if (Next >= '0' && Next <= '9') { + const unsigned Index = Next - '0'; + if (Index < Args.size()) { + Out += Args[Index]; + } else { + Out += "<Argument_Not_Provided>"; + } + } + } + return Out; +} + +std::string Diagnostics::ErrorFrame::ToString() const { + StringRef FormatString = ErrorTypeToString(Type); + std::string ErrorOut = FormatErrorString(FormatString, Args); + if (Range.Start.Line > 0 && Range.Start.Column > 0) + return (Twine(Range.Start.Line) + ":" + Twine(Range.Start.Column) + ": " + + ErrorOut).str(); + return ErrorOut; +} + +std::string Diagnostics::ToString() const { + if (Frames.empty()) return ""; + return Frames[Frames.size() - 1].ToString(); +} + +std::string Diagnostics::ToStringFull() const { + std::string Result; + for (size_t i = 0, end = Frames.size(); i != end; ++i) { + if (i > 0) Result += "\n"; + Result += Frames[i].ToString(); + } + return Result; +} + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang diff --git a/lib/ASTMatchers/Dynamic/Makefile b/lib/ASTMatchers/Dynamic/Makefile new file mode 100644 index 0000000000..a57d752229 --- /dev/null +++ b/lib/ASTMatchers/Dynamic/Makefile @@ -0,0 +1,13 @@ +##===- clang/lib/ASTMatchers/Dynamic/Makefile --------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +CLANG_LEVEL := ../../.. +LIBRARYNAME := clangDynamicASTMatchers + +include $(CLANG_LEVEL)/Makefile diff --git a/lib/ASTMatchers/Dynamic/Marshallers.h b/lib/ASTMatchers/Dynamic/Marshallers.h new file mode 100644 index 0000000000..e75a175738 --- /dev/null +++ b/lib/ASTMatchers/Dynamic/Marshallers.h @@ -0,0 +1,223 @@ +//===--- Marshallers.h - Generic matcher function marshallers -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Functions templates and classes to wrap matcher construct functions. +/// +/// A collection of template function and classes that provide a generic +/// marshalling layer on top of matcher construct functions. +/// These are used by the registry to export all marshaller constructors with +/// the same generic interface. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H +#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H + +#include <list> +#include <string> +#include <vector> + +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/ASTMatchers/Dynamic/Diagnostics.h" +#include "clang/ASTMatchers/Dynamic/VariantValue.h" +#include "clang/Basic/LLVM.h" +#include "llvm/Support/type_traits.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +namespace internal { + +/// \brief Helper template class to just from argument type to the right is/get +/// functions in VariantValue. +/// Used to verify and extract the matcher arguments below. +template <class T> struct ArgTypeTraits; +template <class T> struct ArgTypeTraits<const T &> : public ArgTypeTraits<T> { +}; + +template <> struct ArgTypeTraits<std::string> { + static bool is(const VariantValue &Value) { return Value.isString(); } + static const std::string &get(const VariantValue &Value) { + return Value.getString(); + } +}; + +template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T> > { + static bool is(const VariantValue &Value) { return Value.isMatcher(); } + static ast_matchers::internal::Matcher<T> get(const VariantValue &Value) { + return Value.getTypedMatcher<T>(); + } + +}; + +/// \brief Generic MatcherCreate interface. +/// +/// Provides a \c run() method that constructs the matcher from the provided +/// arguments. +class MatcherCreateCallback { +public: + virtual ~MatcherCreateCallback() {} + virtual DynTypedMatcher *run(const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) const = 0; +}; + +/// \brief Simple callback implementation. Marshaller and function are provided. +/// +/// \param Marshaller Function to unpack the arguments and call \c Func +/// \param Func Matcher construct function. This is the function that +/// compile-time matcher expressions would use to create the matcher. +template <typename MarshallerType, typename FuncType> +class FixedArgCountMatcherCreateCallback : public MatcherCreateCallback { +public: + FixedArgCountMatcherCreateCallback(MarshallerType Marshaller, FuncType Func, + StringRef MatcherName) + : Marshaller(Marshaller), Func(Func), MatcherName(MatcherName.str()) {} + + DynTypedMatcher *run(const SourceRange &NameRange, + ArrayRef<ParserValue> Args, Diagnostics *Error) const { + return Marshaller(Func, MatcherName, NameRange, Args, Error); + } + +private: + const MarshallerType Marshaller; + const FuncType Func; + const std::string MatcherName; +}; + +/// \brief Helper function to do template argument deduction. +template <typename MarshallerType, typename FuncType> +MatcherCreateCallback * +createMarshallerCallback(MarshallerType Marshaller, FuncType Func, + StringRef MatcherName) { + return new FixedArgCountMatcherCreateCallback<MarshallerType, FuncType>( + Marshaller, Func, MatcherName); +} + +/// \brief Helper macros to check the arguments on all marshaller functions. +#define CHECK_ARG_COUNT(count) \ + if (Args.size() != count) { \ + Error->pushErrorFrame(NameRange, Error->ET_RegistryWrongArgCount) \ + << count << Args.size(); \ + return NULL; \ + } + +#define CHECK_ARG_TYPE(index, type) \ + if (!ArgTypeTraits<type>::is(Args[index].Value)) { \ + Error->pushErrorFrame(Args[index].Range, Error->ET_RegistryWrongArgType) \ + << MatcherName << (index + 1); \ + return NULL; \ + } + +/// \brief Metafunction to normalize argument types. +/// +/// We need to remove the const& out of the function parameters to be able to +/// find values on VariantValue. +template <typename T> +struct remove_const_ref : + public llvm::remove_const<typename llvm::remove_reference<T>::type> { +}; + +/// \brief 0-arg marshaller function. +template <typename ReturnType> +DynTypedMatcher *matcherMarshall0(ReturnType (*Func)(), StringRef MatcherName, + const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) { + CHECK_ARG_COUNT(0); + return Func().clone(); +} + +/// \brief 1-arg marshaller function. +template <typename ReturnType, typename InArgType1> +DynTypedMatcher *matcherMarshall1(ReturnType (*Func)(InArgType1), + StringRef MatcherName, + const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) { + typedef typename remove_const_ref<InArgType1>::type ArgType1; + CHECK_ARG_COUNT(1); + CHECK_ARG_TYPE(0, ArgType1); + return Func(ArgTypeTraits<ArgType1>::get(Args[0].Value)).clone(); +} + +/// \brief Variadic marshaller function. +template <typename BaseType, typename DerivedType> +class VariadicMatcherCreateCallback : public MatcherCreateCallback { +public: + explicit VariadicMatcherCreateCallback(StringRef MatcherName) + : MatcherName(MatcherName.str()) {} + + typedef ast_matchers::internal::Matcher<DerivedType> DerivedMatcherType; + + DynTypedMatcher *run(const SourceRange &NameRange, ArrayRef<ParserValue> Args, + Diagnostics *Error) const { + std::list<DerivedMatcherType> References; + std::vector<const DerivedMatcherType *> InnerArgs(Args.size()); + for (size_t i = 0, e = Args.size(); i != e; ++i) { + CHECK_ARG_TYPE(i, DerivedMatcherType); + References.push_back( + ArgTypeTraits<DerivedMatcherType>::get(Args[i].Value)); + InnerArgs[i] = &References.back(); + } + return ast_matchers::internal::makeDynCastAllOfComposite<BaseType>( + ArrayRef<const DerivedMatcherType *>(InnerArgs)).clone(); + } + +private: + const std::string MatcherName; +}; + +#undef CHECK_ARG_COUNT +#undef CHECK_ARG_TYPE + +/// Helper functions to select the appropriate marshaller functions. +/// They detects the number of arguments, arguments types and return type. + +/// \brief 0-arg overload +template <typename ReturnType> +MatcherCreateCallback *makeMatcherAutoMarshall(ReturnType (*Func)(), + StringRef MatcherName) { + return createMarshallerCallback(matcherMarshall0<ReturnType>, Func, + MatcherName); +} + +/// \brief 1-arg overload +template <typename ReturnType, typename ArgType1> +MatcherCreateCallback *makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1), + StringRef MatcherName) { + return createMarshallerCallback(matcherMarshall1<ReturnType, ArgType1>, Func, + MatcherName); +} + +/// \brief Variadic overload. +template <typename MatcherType> +MatcherCreateCallback *makeMatcherAutoMarshall( + ast_matchers::internal::VariadicAllOfMatcher<MatcherType> Func, + StringRef MatcherName) { + return new VariadicMatcherCreateCallback<MatcherType, MatcherType>( + MatcherName); +} + +template <typename BaseType, typename MatcherType> +MatcherCreateCallback * +makeMatcherAutoMarshall(ast_matchers::internal::VariadicDynCastAllOfMatcher< + BaseType, MatcherType> Func, + StringRef MatcherName) { + return new VariadicMatcherCreateCallback<BaseType, MatcherType>(MatcherName); +} + +} // namespace internal +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang + +#endif // LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H diff --git a/lib/ASTMatchers/Dynamic/Parser.cpp b/lib/ASTMatchers/Dynamic/Parser.cpp new file mode 100644 index 0000000000..1678820da0 --- /dev/null +++ b/lib/ASTMatchers/Dynamic/Parser.cpp @@ -0,0 +1,332 @@ +//===--- Parser.cpp - Matcher expression parser -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Recursive parser implementation for the matcher expression grammar. +/// +//===----------------------------------------------------------------------===// + +#include <string> +#include <vector> + +#include "clang/ASTMatchers/Dynamic/Parser.h" +#include "clang/ASTMatchers/Dynamic/Registry.h" +#include "clang/Basic/CharInfo.h" +#include "llvm/ADT/Twine.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +/// \brief Simple structure to hold information for one token from the parser. +struct Parser::TokenInfo { + /// \brief Different possible tokens. + enum TokenKind { + TK_Eof = 0, + TK_OpenParen = 1, + TK_CloseParen = 2, + TK_Comma = 3, + TK_Literal = 4, + TK_Ident = 5, + TK_InvalidChar = 6, + TK_Error = 7 + }; + + TokenInfo() : Text(), Kind(TK_Eof), Range(), Value() {} + + StringRef Text; + TokenKind Kind; + SourceRange Range; + VariantValue Value; +}; + +/// \brief Simple tokenizer for the parser. +class Parser::CodeTokenizer { +public: + explicit CodeTokenizer(StringRef MatcherCode, Diagnostics *Error) + : Code(MatcherCode), StartOfLine(MatcherCode), Line(1), Error(Error) { + NextToken = getNextToken(); + } + + /// \brief Returns but doesn't consume the next token. + const TokenInfo &peekNextToken() const { return NextToken; } + + /// \brief Consumes and returns the next token. + TokenInfo consumeNextToken() { + TokenInfo ThisToken = NextToken; + NextToken = getNextToken(); + return ThisToken; + } + + TokenInfo::TokenKind nextTokenKind() const { return NextToken.Kind; } + +private: + TokenInfo getNextToken() { + consumeWhitespace(); + TokenInfo Result; + Result.Range.Start = currentLocation(); + + if (Code.empty()) { + Result.Kind = TokenInfo::TK_Eof; + Result.Text = ""; + return Result; + } + + switch (Code[0]) { + case ',': + Result.Kind = TokenInfo::TK_Comma; + Result.Text = Code.substr(0, 1); + Code = Code.drop_front(); + break; + case '(': + Result.Kind = TokenInfo::TK_OpenParen; + Result.Text = Code.substr(0, 1); + Code = Code.drop_front(); + break; + case ')': + Result.Kind = TokenInfo::TK_CloseParen; + Result.Text = Code.substr(0, 1); + Code = Code.drop_front(); + break; + + case '"': + case '\'': + // Parse a string literal. + consumeStringLiteral(&Result); + break; + + default: + if (isAlphanumeric(Code[0])) { + // Parse an identifier + size_t TokenLength = 1; + while (TokenLength < Code.size() && isAlphanumeric(Code[TokenLength])) + ++TokenLength; + Result.Kind = TokenInfo::TK_Ident; + Result.Text = Code.substr(0, TokenLength); + Code = Code.drop_front(TokenLength); + } else { + Result.Kind = TokenInfo::TK_InvalidChar; + Result.Text = Code.substr(0, 1); + Code = Code.drop_front(1); + } + break; + } + + Result.Range.End = currentLocation(); + return Result; + } + + /// \brief Consume a string literal. + /// + /// \c Code must be positioned at the start of the literal (the opening + /// quote). Consumed until it finds the same closing quote character. + void consumeStringLiteral(TokenInfo *Result) { + bool InEscape = false; + const char Marker = Code[0]; + for (size_t Length = 1, Size = Code.size(); Length != Size; ++Length) { + if (InEscape) { + InEscape = false; + continue; + } + if (Code[Length] == '\\') { + InEscape = true; + continue; + } + if (Code[Length] == Marker) { + Result->Kind = TokenInfo::TK_Literal; + Result->Text = Code.substr(0, Length + 1); + Result->Value = Code.substr(1, Length - 1).str(); + Code = Code.drop_front(Length + 1); + return; + } + } + + StringRef ErrorText = Code; + Code = Code.drop_front(Code.size()); + SourceRange Range; + Range.Start = Result->Range.Start; + Range.End = currentLocation(); + Error->pushErrorFrame(Range, Error->ET_ParserStringError) + << ErrorText; + Result->Kind = TokenInfo::TK_Error; + } + + /// \brief Consume all leading whitespace from \c Code. + void consumeWhitespace() { + while (!Code.empty() && isWhitespace(Code[0])) { + if (Code[0] == '\n') { + ++Line; + StartOfLine = Code.drop_front(); + } + Code = Code.drop_front(); + } + } + + SourceLocation currentLocation() { + SourceLocation Location; + Location.Line = Line; + Location.Column = Code.data() - StartOfLine.data() + 1; + return Location; + } + + StringRef Code; + StringRef StartOfLine; + unsigned Line; + Diagnostics *Error; + TokenInfo NextToken; +}; + +Parser::Sema::~Sema() {} + +/// \brief Parse and validate a matcher expression. +/// \return \c true on success, in which case \c Value has the matcher parsed. +/// If the input is malformed, or some argument has an error, it +/// returns \c false. +bool Parser::parseMatcherExpressionImpl(VariantValue *Value) { + const TokenInfo NameToken = Tokenizer->consumeNextToken(); + assert(NameToken.Kind == TokenInfo::TK_Ident); + const TokenInfo OpenToken = Tokenizer->consumeNextToken(); + if (OpenToken.Kind != TokenInfo::TK_OpenParen) { + Error->pushErrorFrame(OpenToken.Range, Error->ET_ParserNoOpenParen) + << OpenToken.Text; + return false; + } + + std::vector<ParserValue> Args; + TokenInfo EndToken; + while (Tokenizer->nextTokenKind() != TokenInfo::TK_Eof) { + if (Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen) { + // End of args. + EndToken = Tokenizer->consumeNextToken(); + break; + } + if (Args.size() > 0) { + // We must find a , token to continue. + const TokenInfo CommaToken = Tokenizer->consumeNextToken(); + if (CommaToken.Kind != TokenInfo::TK_Comma) { + Error->pushErrorFrame(CommaToken.Range, Error->ET_ParserNoComma) + << CommaToken.Text; + return false; + } + } + + ParserValue ArgValue; + ArgValue.Text = Tokenizer->peekNextToken().Text; + ArgValue.Range = Tokenizer->peekNextToken().Range; + if (!parseExpressionImpl(&ArgValue.Value)) { + Error->pushErrorFrame(NameToken.Range, + Error->ET_ParserMatcherArgFailure) + << (Args.size() + 1) << NameToken.Text; + return false; + } + + Args.push_back(ArgValue); + } + + if (EndToken.Kind == TokenInfo::TK_Eof) { + Error->pushErrorFrame(OpenToken.Range, Error->ET_ParserNoCloseParen); + return false; + } + + // Merge the start and end infos. + SourceRange MatcherRange = NameToken.Range; + MatcherRange.End = EndToken.Range.End; + DynTypedMatcher *Result = + S->actOnMatcherExpression(NameToken.Text, MatcherRange, Args, Error); + if (Result == NULL) { + Error->pushErrorFrame(NameToken.Range, Error->ET_ParserMatcherFailure) + << NameToken.Text; + return false; + } + + Value->takeMatcher(Result); + return true; +} + +/// \brief Parse an <Expresssion> +bool Parser::parseExpressionImpl(VariantValue *Value) { + switch (Tokenizer->nextTokenKind()) { + case TokenInfo::TK_Literal: + *Value = Tokenizer->consumeNextToken().Value; + return true; + + case TokenInfo::TK_Ident: + return parseMatcherExpressionImpl(Value); + + case TokenInfo::TK_Eof: + Error->pushErrorFrame(Tokenizer->consumeNextToken().Range, + Error->ET_ParserNoCode); + return false; + + case TokenInfo::TK_Error: + // This error was already reported by the tokenizer. + return false; + + case TokenInfo::TK_OpenParen: + case TokenInfo::TK_CloseParen: + case TokenInfo::TK_Comma: + case TokenInfo::TK_InvalidChar: + const TokenInfo Token = Tokenizer->consumeNextToken(); + Error->pushErrorFrame(Token.Range, Error->ET_ParserInvalidToken) + << Token.Text; + return false; + } + + llvm_unreachable("Unknown token kind."); +} + +Parser::Parser(CodeTokenizer *Tokenizer, Sema *S, + Diagnostics *Error) + : Tokenizer(Tokenizer), S(S), Error(Error) {} + +class RegistrySema : public Parser::Sema { +public: + virtual ~RegistrySema() {} + DynTypedMatcher *actOnMatcherExpression(StringRef MatcherName, + const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) { + return Registry::constructMatcher(MatcherName, NameRange, Args, Error); + } +}; + +bool Parser::parseExpression(StringRef Code, VariantValue *Value, + Diagnostics *Error) { + RegistrySema S; + return parseExpression(Code, &S, Value, Error); +} + +bool Parser::parseExpression(StringRef Code, Sema *S, + VariantValue *Value, Diagnostics *Error) { + CodeTokenizer Tokenizer(Code, Error); + return Parser(&Tokenizer, S, Error).parseExpressionImpl(Value); +} + +DynTypedMatcher *Parser::parseMatcherExpression(StringRef Code, + Diagnostics *Error) { + RegistrySema S; + return parseMatcherExpression(Code, &S, Error); +} + +DynTypedMatcher *Parser::parseMatcherExpression(StringRef Code, + Parser::Sema *S, + Diagnostics *Error) { + VariantValue Value; + if (!parseExpression(Code, S, &Value, Error)) + return NULL; + if (!Value.isMatcher()) { + Error->pushErrorFrame(SourceRange(), Error->ET_ParserNotAMatcher); + return NULL; + } + return Value.getMatcher().clone(); +} + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp new file mode 100644 index 0000000000..53e90f1c77 --- /dev/null +++ b/lib/ASTMatchers/Dynamic/Registry.cpp @@ -0,0 +1,153 @@ +//===--- Registry.cpp - Matcher registry ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Registry map populated at static initialization time. +/// +//===----------------------------------------------------------------------===// + +#include "clang/ASTMatchers/Dynamic/Registry.h" + +#include <utility> + +#include "Marshallers.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/ManagedStatic.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { +namespace { + +using internal::MatcherCreateCallback; + +typedef llvm::StringMap<const MatcherCreateCallback *> ConstructorMap; +class RegistryMaps { +public: + RegistryMaps(); + ~RegistryMaps(); + + const ConstructorMap &constructors() const { return Constructors; } + +private: + void registerMatcher(StringRef MatcherName, MatcherCreateCallback *Callback); + ConstructorMap Constructors; +}; + +void RegistryMaps::registerMatcher(StringRef MatcherName, + MatcherCreateCallback *Callback) { + Constructors[MatcherName] = Callback; +} + +#define REGISTER_MATCHER(name) \ + registerMatcher(#name, internal::makeMatcherAutoMarshall( \ + ::clang::ast_matchers::name, #name)); + +/// \brief Generate a registry map with all the known matchers. +RegistryMaps::RegistryMaps() { + // TODO: This list is not complete. It only has non-overloaded matchers, + // which are the simplest to add to the system. Overloaded matchers require + // more supporting code that was omitted from the first revision for + // simplicitly of code review. + + REGISTER_MATCHER(binaryOperator); + REGISTER_MATCHER(bindTemporaryExpr); + REGISTER_MATCHER(boolLiteral); + REGISTER_MATCHER(callExpr); + REGISTER_MATCHER(characterLiteral); + REGISTER_MATCHER(compoundStmt); + REGISTER_MATCHER(conditionalOperator); + REGISTER_MATCHER(constCastExpr); + REGISTER_MATCHER(constructExpr); + REGISTER_MATCHER(constructorDecl); + REGISTER_MATCHER(declRefExpr); + REGISTER_MATCHER(declStmt); + REGISTER_MATCHER(defaultArgExpr); + REGISTER_MATCHER(doStmt); + REGISTER_MATCHER(dynamicCastExpr); + REGISTER_MATCHER(explicitCastExpr); + REGISTER_MATCHER(expr); + REGISTER_MATCHER(fieldDecl); + REGISTER_MATCHER(forStmt); + REGISTER_MATCHER(functionDecl); + REGISTER_MATCHER(hasAnyParameter); + REGISTER_MATCHER(hasAnySubstatement); + REGISTER_MATCHER(hasConditionVariableStatement); + REGISTER_MATCHER(hasDestinationType); + REGISTER_MATCHER(hasEitherOperand); + REGISTER_MATCHER(hasFalseExpression); + REGISTER_MATCHER(hasImplicitDestinationType); + REGISTER_MATCHER(hasInitializer); + REGISTER_MATCHER(hasLHS); + REGISTER_MATCHER(hasName); + REGISTER_MATCHER(hasObjectExpression); + REGISTER_MATCHER(hasRHS); + REGISTER_MATCHER(hasSourceExpression); + REGISTER_MATCHER(hasTrueExpression); + REGISTER_MATCHER(hasUnaryOperand); + REGISTER_MATCHER(ifStmt); + REGISTER_MATCHER(implicitCastExpr); + REGISTER_MATCHER(integerLiteral); + REGISTER_MATCHER(isArrow); + REGISTER_MATCHER(isConstQualified); + REGISTER_MATCHER(isImplicit); + REGISTER_MATCHER(member); + REGISTER_MATCHER(memberExpr); + REGISTER_MATCHER(methodDecl); + REGISTER_MATCHER(namedDecl); + REGISTER_MATCHER(newExpr); + REGISTER_MATCHER(ofClass); + REGISTER_MATCHER(on); + REGISTER_MATCHER(onImplicitObjectArgument); + REGISTER_MATCHER(operatorCallExpr); + REGISTER_MATCHER(recordDecl); + REGISTER_MATCHER(reinterpretCastExpr); + REGISTER_MATCHER(staticCastExpr); + REGISTER_MATCHER(stmt); + REGISTER_MATCHER(stringLiteral); + REGISTER_MATCHER(switchCase); + REGISTER_MATCHER(to); + REGISTER_MATCHER(unaryOperator); + REGISTER_MATCHER(varDecl); + REGISTER_MATCHER(whileStmt); +} + +RegistryMaps::~RegistryMaps() { + for (ConstructorMap::iterator it = Constructors.begin(), + end = Constructors.end(); + it != end; ++it) { + delete it->second; + } +} + +static llvm::ManagedStatic<RegistryMaps> RegistryData; + +} // anonymous namespace + +// static +DynTypedMatcher *Registry::constructMatcher(StringRef MatcherName, + const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) { + ConstructorMap::const_iterator it = + RegistryData->constructors().find(MatcherName); + if (it == RegistryData->constructors().end()) { + Error->pushErrorFrame(NameRange, Error->ET_RegistryNotFound) + << MatcherName; + return NULL; + } + + return it->second->run(NameRange, Args, Error); +} + +} // namespace dynamic +} // namespace ast_matchers +} // namespace clang diff --git a/lib/ASTMatchers/Dynamic/VariantValue.cpp b/lib/ASTMatchers/Dynamic/VariantValue.cpp new file mode 100644 index 0000000000..e310fbfc58 --- /dev/null +++ b/lib/ASTMatchers/Dynamic/VariantValue.cpp @@ -0,0 +1,105 @@ +//===--- VariantValue.cpp - Polymorphic value type -*- C++ -*-===/ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Polymorphic value type. +/// +//===----------------------------------------------------------------------===// + +#include "clang/ASTMatchers/Dynamic/VariantValue.h" + +namespace clang { +namespace ast_matchers { +namespace dynamic { + +VariantValue::VariantValue(const VariantValue &Other) : Type(VT_Nothing) { + *this = Other; +} + +VariantValue::VariantValue(const DynTypedMatcher &Matcher) : Type(VT_Nothing) { + setMatcher(Matcher); +} + +VariantValue::VariantValue(const std::string &String) : Type(VT_Nothing) { + setString(String); +} + +VariantValue::~VariantValue() { reset(); } + +VariantValue &VariantValue::operator=(const VariantValue &Other) { + if (this == &Other) return *this; + reset(); + switch (Other.Type) { + case VT_String: + setString(Other.getString()); + break; + case VT_Matcher: + setMatcher(Other.getMatcher()); + break; + case VT_Nothing: + Type = VT_Nothing; + break; + } + return *this; +} + +void VariantValue::reset() { + switch (Type) { + case VT_String: + delete Value.String; + break; + case VT_Matcher: + delete Value.Matcher; + break; + // Cases that do nothing. + case VT_Nothing: + break; + } + Type = VT_Nothing; +} + +bool VariantValue::isString() const { + return Type == VT_String; +} + +const std::string &VariantValue::getString() const { + assert(isString()); + return *Value.String; +} + +void VariantValue::setString(const std::string &NewValue) { + reset(); + Type = VT_String; + Value.String = new std::string(NewValue); +} + +bool VariantValue::isMatcher() const { + return Type == VT_Matcher; +} + +const DynTypedMatcher &VariantValue::getMatcher() const { + assert(isMatcher()); + return *Value.Matcher; +} + +void VariantValue::setMatcher(const DynTypedMatcher &NewValue) { + reset(); + Type = VT_Matcher; + Value.Matcher = NewValue.clone(); +} + +void VariantValue::takeMatcher(DynTypedMatcher *NewValue) { + reset(); + Type = VT_Matcher; + Value.Matcher = NewValue; +} + +} // end namespace dynamic +} // end namespace ast_matchers +} // end namespace clang diff --git a/lib/ASTMatchers/Makefile b/lib/ASTMatchers/Makefile index 76d82719a1..3ee9ccb580 100644 --- a/lib/ASTMatchers/Makefile +++ b/lib/ASTMatchers/Makefile @@ -10,4 +10,6 @@ CLANG_LEVEL := ../.. LIBRARYNAME := clangASTMatchers +PARALLEL_DIRS = Dynamic + include $(CLANG_LEVEL)/Makefile diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 096c7a080b..6eb84ce92c 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -155,7 +155,7 @@ public: return !(*this == rhs); } - operator bool() const { + LLVM_EXPLICIT operator bool() const { return *this != const_iterator(); } diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp index 835908d2a1..b90fbc7a7c 100644 --- a/lib/Basic/OpenMPKinds.cpp +++ b/lib/Basic/OpenMPKinds.cpp @@ -32,7 +32,7 @@ const char *clang::getOpenMPDirectiveName(OpenMPDirectiveKind Kind) { assert(Kind < NUM_OPENMP_DIRECTIVES); switch (Kind) { case OMPD_unknown: - return ("unknown"); + return "unknown"; #define OPENMP_DIRECTIVE(Name) \ case OMPD_##Name : return #Name; #include "clang/Basic/OpenMPKinds.def" @@ -41,3 +41,4 @@ const char *clang::getOpenMPDirectiveName(OpenMPDirectiveKind Kind) { } llvm_unreachable("Invalid OpenMP directive kind"); } + diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 638d6a028c..6b376b30ad 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -3527,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) @@ -3559,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 = MaxAtomicInlineWidth = 64; + 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 @@ -4275,6 +4304,11 @@ public: // 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"; + // This is an LP64 platform. + LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + IntMaxType = SignedLong; + UIntMaxType = UnsignedLong; + Int64Type = SignedLong; } virtual void getTargetDefines(const LangOptions &Opts, diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index d18767897f..bd5afb6d17 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -1645,11 +1645,10 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { if (BuiltinID == ARM::BI__clear_cache) { + assert(E->getNumArgs() == 2 && "__clear_cache takes 2 arguments"); const FunctionDecl *FD = E->getDirectCallee(); - // Oddly people write this call without args on occasion and gcc accepts - // it - it's also marked as varargs in the description file. SmallVector<Value*, 2> Ops; - for (unsigned i = 0; i < E->getNumArgs(); i++) + for (unsigned i = 0; i < 2; i++) Ops.push_back(EmitScalarExpr(E->getArg(i))); llvm::Type *Ty = CGM.getTypes().ConvertType(FD->getType()); llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty); diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 7d5d260304..f6ad8f2cc5 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -1220,9 +1220,11 @@ CollectTemplateParams(const TemplateParameterList *TPList, V = CGM.GetAddrOfGlobalVar(VD); // Member function pointers have special support for building them, though // this is currently unsupported in LLVM CodeGen. - if (InstanceMember) + if (InstanceMember) { if (const CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(D)) V = CGM.getCXXABI().EmitMemberPointer(method); + } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + V = CGM.GetAddrOfFunction(FD); // Member data pointers have special handling too to compute the fixed // offset within the object. if (isa<FieldDecl>(D)) { @@ -2172,8 +2174,21 @@ llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType, } llvm::DIDescriptor CGDebugInfo::getDeclarationOrDefinition(const Decl *D) { - if (const TypeDecl *RD = dyn_cast<TypeDecl>(D)) - return CreatePointeeType(QualType(RD->getTypeForDecl(), 0), llvm::DIFile()); + // We only need a declaration (not a definition) of the type - so use whatever + // we would otherwise do to get a type for a pointee. (forward declarations in + // limited debug info, full definitions (if the type definition is available) + // in unlimited debug info) + if (const TypeDecl *TD = dyn_cast<TypeDecl>(D)) { + llvm::DIFile DefUnit = getOrCreateFile(TD->getLocation()); + return CreatePointeeType(CGM.getContext().getTypeDeclType(TD), DefUnit); + } + // Otherwise fall back to a fairly rudimentary cache of existing declarations. + // This doesn't handle providing declarations (for functions or variables) for + // entities without definitions in this TU, nor when the definition proceeds + // the call to this function. + // FIXME: This should be split out into more specific maps with support for + // emitting forward declarations and merging definitions with declarations, + // the same way as we do for types. llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator I = DeclCache.find(D->getCanonicalDecl()); if (I == DeclCache.end()) diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index e61a50eeb4..f221a0cd3e 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -95,6 +95,8 @@ class CGDebugInfo { llvm::DenseMap<const char *, llvm::WeakVH> DIFileCache; llvm::DenseMap<const FunctionDecl *, llvm::WeakVH> SPCache; + /// \brief Cache declarations relevant to DW_TAG_imported_declarations (C++ + /// using declarations) that aren't covered by other more specific caches. llvm::DenseMap<const Decl *, llvm::WeakVH> DeclCache; llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH> NameSpaceCache; llvm::DenseMap<const Decl *, llvm::WeakVH> StaticDataMemberCache; diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp index 069cd5f9e7..9a345cf472 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -719,7 +719,7 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, /// Note that we only call this at the end of the translation unit. llvm::GlobalVariable::LinkageTypes CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) { - if (RD->getLinkage() != ExternalLinkage) + if (!RD->isExternallyVisible()) return llvm::GlobalVariable::InternalLinkage; // We're at the end of the translation unit, so the current key diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 6caf1689a9..5a7c305c64 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -2422,7 +2422,7 @@ public: return ConstantEmission(C, false); } - operator bool() const { return ValueAndIsReference.getOpaqueValue() != 0; } + LLVM_EXPLICIT operator bool() const { return ValueAndIsReference.getOpaqueValue() != 0; } bool isReference() const { return ValueAndIsReference.getInt(); } LValue getReferenceLValue(CodeGenFunction &CGF, Expr *refExpr) const { diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 695048e5b3..0736879037 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -1763,7 +1763,7 @@ void CodeGenModule::MaybeHandleStaticInExternC(const SomeDecl *D, return; // Must have internal linkage and an ordinary name. - if (!D->getIdentifier() || D->getLinkage() != InternalLinkage) + if (!D->getIdentifier() || D->getFormalLinkage() != InternalLinkage) return; // Must be in an extern "C" context. Entities declared directly within diff --git a/lib/CodeGen/CodeGenTBAA.cpp b/lib/CodeGen/CodeGenTBAA.cpp index 5ff1560a48..3f0eaee536 100644 --- a/lib/CodeGen/CodeGenTBAA.cpp +++ b/lib/CodeGen/CodeGenTBAA.cpp @@ -162,8 +162,7 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { // on their mangled names, if they're external. // TODO: Is there a way to get a program-wide unique name for a // decl with local linkage or no linkage? - if (Features.CPlusPlus && - ETy->getDecl()->getLinkage() != ExternalLinkage) + if (Features.CPlusPlus && !ETy->getDecl()->isExternallyVisible()) return MetadataCache[Ty] = getChar(); // TODO: This is using the RTTI name. Is there a better way to get diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index 9a320f94bd..9fd8ac6916 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -19,11 +19,9 @@ #include "TokenAnnotator.h" #include "UnwrappedLineParser.h" #include "WhitespaceManager.h" -#include "clang/Basic/Diagnostic.h" #include "clang/Basic/OperatorPrecedence.h" #include "clang/Basic/SourceManager.h" #include "clang/Format/Format.h" -#include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Lex/Lexer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Allocator.h" @@ -36,11 +34,21 @@ namespace llvm { namespace yaml { template <> struct ScalarEnumerationTraits<clang::format::FormatStyle::LanguageStandard> { - static void enumeration(IO &io, - clang::format::FormatStyle::LanguageStandard &value) { - io.enumCase(value, "C++03", clang::format::FormatStyle::LS_Cpp03); - io.enumCase(value, "C++11", clang::format::FormatStyle::LS_Cpp11); - io.enumCase(value, "Auto", clang::format::FormatStyle::LS_Auto); + static void enumeration(IO &IO, + clang::format::FormatStyle::LanguageStandard &Value) { + IO.enumCase(Value, "C++03", clang::format::FormatStyle::LS_Cpp03); + IO.enumCase(Value, "C++11", clang::format::FormatStyle::LS_Cpp11); + IO.enumCase(Value, "Auto", clang::format::FormatStyle::LS_Auto); + } +}; + +template <> +struct ScalarEnumerationTraits<clang::format::FormatStyle::BraceBreakingStyle> { + static void + enumeration(IO &IO, clang::format::FormatStyle::BraceBreakingStyle &Value) { + IO.enumCase(Value, "Attach", clang::format::FormatStyle::BS_Attach); + IO.enumCase(Value, "Linux", clang::format::FormatStyle::BS_Linux); + IO.enumCase(Value, "Stroustrup", clang::format::FormatStyle::BS_Stroustrup); } }; @@ -85,6 +93,9 @@ template <> struct MappingTraits<clang::format::FormatStyle> { IO.mapOptional("SpacesBeforeTrailingComments", Style.SpacesBeforeTrailingComments); IO.mapOptional("Standard", Style.Standard); + IO.mapOptional("IndentWidth", Style.IndentWidth); + IO.mapOptional("UseTab", Style.UseTab); + IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces); } }; } @@ -111,6 +122,9 @@ FormatStyle getLLVMStyle() { LLVMStyle.PointerBindsToType = false; LLVMStyle.SpacesBeforeTrailingComments = 1; LLVMStyle.Standard = FormatStyle::LS_Cpp03; + LLVMStyle.IndentWidth = 2; + LLVMStyle.UseTab = false; + LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach; return LLVMStyle; } @@ -132,6 +146,9 @@ FormatStyle getGoogleStyle() { GoogleStyle.PointerBindsToType = true; GoogleStyle.SpacesBeforeTrailingComments = 2; GoogleStyle.Standard = FormatStyle::LS_Auto; + GoogleStyle.IndentWidth = 2; + GoogleStyle.UseTab = false; + GoogleStyle.BreakBeforeBraces = FormatStyle::BS_Attach; return GoogleStyle; } @@ -185,7 +202,7 @@ std::string configurationAsText(const FormatStyle &Style) { // reference here. FormatStyle NonConstStyle = Style; Output << NonConstStyle; - return Text; + return Stream.str(); } // Returns the length of everything up to the first possible line break after @@ -267,7 +284,7 @@ private: AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false), NoLineBreak(NoLineBreak), ColonPos(0), StartOfFunctionCall(0), NestedNameSpecifierContinuation(0), CallContinuation(0), - VariablePos(0) {} + VariablePos(0), ForFakeParenthesis(false) {} /// \brief The position to which a specific parenthesis level needs to be /// indented. @@ -326,6 +343,13 @@ private: /// Used to align further variables if necessary. unsigned VariablePos; + /// \brief \c true if this \c ParenState was created for a fake parenthesis. + /// + /// Does not need to be considered for memoization / the comparison function + /// as otherwise identical states will have the same fake/non-fake + /// \c ParenStates. + bool ForFakeParenthesis; + bool operator<(const ParenState &Other) const { if (Indent != Other.Indent) return Indent < Other.Indent; @@ -429,7 +453,7 @@ private: if (Newline) { unsigned WhitespaceStartColumn = State.Column; if (Current.is(tok::r_brace)) { - State.Column = Line.Level * 2; + State.Column = Line.Level * Style.IndentWidth; } else if (Current.is(tok::string_literal) && State.StartOfStringLiteral != 0) { State.Column = State.StartOfStringLiteral; @@ -480,6 +504,8 @@ private: !State.Stack.back().AvoidBinPacking) || Previous.Type == TT_BinaryOperator) State.Stack.back().BreakBeforeParameter = false; + if (Previous.Type == TT_TemplateCloser && State.ParenLevel == 0) + State.Stack.back().BreakBeforeParameter = false; if (!DryRun) { unsigned NewLines = 1; @@ -507,6 +533,7 @@ private: } const AnnotatedToken *TokenBefore = Current.getPreviousNoneComment(); if (TokenBefore && !TokenBefore->isOneOf(tok::comma, tok::semi) && + TokenBefore->Type != TT_TemplateCloser && TokenBefore->Type != TT_BinaryOperator && !TokenBefore->opensScope()) State.Stack.back().BreakBeforeParameter = true; @@ -517,7 +544,8 @@ private: if (State.Stack.back().AvoidBinPacking) { // If we are breaking after '(', '{', '<', this is not bin packing // unless AllowAllParametersOfDeclarationOnNextLine is false. - if ((Previous.isNot(tok::l_paren) && Previous.isNot(tok::l_brace)) || + if (!(Previous.isOneOf(tok::l_paren, tok::l_brace) || + Previous.Type == TT_BinaryOperator) || (!Style.AllowAllParametersOfDeclarationOnNextLine && Line.MustBeDeclaration)) State.Stack.back().BreakBeforeParameter = true; @@ -604,6 +632,11 @@ private: Current.LastInChainOfCalls ? 0 : State.Column + Current.FormatTok.TokenLength; if (Current.Type == TT_CtorInitializerColon) { + // Indent 2 from the column, so: + // SomeClass::SomeClass() + // : First(...), ... + // Next(...) + // ^ line up here. State.Stack.back().Indent = State.Column + 2; if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine) State.Stack.back().AvoidBinPacking = true; @@ -633,6 +666,7 @@ private: E = Current.FakeLParens.rend(); I != E; ++I) { ParenState NewParenState = State.Stack.back(); + NewParenState.ForFakeParenthesis = true; NewParenState.Indent = std::max(std::max(State.Column, NewParenState.Indent), State.Stack.back().LastSpace); @@ -654,27 +688,31 @@ private: // prepare for the following tokens. if (Current.opensScope()) { unsigned NewIndent; + unsigned LastSpace = State.Stack.back().LastSpace; bool AvoidBinPacking; if (Current.is(tok::l_brace)) { - NewIndent = 2 + State.Stack.back().LastSpace; + NewIndent = Style.IndentWidth + LastSpace; AvoidBinPacking = false; } else { - NewIndent = 4 + std::max(State.Stack.back().LastSpace, - State.Stack.back().StartOfFunctionCall); + NewIndent = + 4 + std::max(LastSpace, State.Stack.back().StartOfFunctionCall); AvoidBinPacking = !Style.BinPackParameters; } - State.Stack.push_back( - ParenState(NewIndent, State.Stack.back().LastSpace, AvoidBinPacking, - 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 + // LastSpace of the next higher ParenLevel. Thus, erase them to achieve // better memoization results. - State.Stack[State.Stack.size() - 2].Indent = 0; - State.Stack[State.Stack.size() - 2].LastSpace = 0; + for (unsigned i = State.Stack.size() - 1; i > 0; --i) { + State.Stack[i].Indent = 0; + State.Stack[i].LastSpace = 0; + if (!State.Stack[i].ForFakeParenthesis) + break; + } } + State.Stack.push_back(ParenState(NewIndent, LastSpace, AvoidBinPacking, + State.Stack.back().NoLineBreak)); ++State.ParenLevel; } @@ -702,10 +740,10 @@ private: State.Stack.back().VariablePos = VariablePos; } - if (Current.is(tok::string_literal)) { + if (Current.is(tok::string_literal) && State.StartOfStringLiteral == 0) { State.StartOfStringLiteral = State.Column; - } else if (Current.isNot(tok::comment)) { - State.StartOfStringLiteral = 0; + } else if (!Current.isOneOf(tok::comment, tok::identifier, tok::hash, + tok::string_literal)) { } State.Column += Current.FormatTok.TokenLength; @@ -720,10 +758,18 @@ private: /// \brief If the current token sticks out over the end of the line, break /// it if possible. + /// + /// \returns An extra penalty if a token was broken, otherwise 0. + /// + /// Note that the penalty of the token protruding the allowed line length is + /// already handled in \c addNextStateToQueue; the returned penalty will only + /// cover the cost of the additional line breaks. unsigned breakProtrudingToken(const AnnotatedToken &Current, LineState &State, - bool DryRun) { + bool DryRun, + unsigned UnbreakableTailLength = 0) { llvm::OwningPtr<BreakableToken> Token; - unsigned StartColumn = State.Column - Current.FormatTok.TokenLength; + unsigned StartColumn = State.Column - Current.FormatTok.TokenLength - + UnbreakableTailLength; if (Current.is(tok::string_literal)) { // Only break up default narrow strings. const char *LiteralData = SourceMgr.getCharacterData( @@ -744,42 +790,55 @@ private: Current.Parent->Type != TT_ImplicitStringLiteral)) { Token.reset(new BreakableLineComment(SourceMgr, Current, StartColumn)); } else { - return 0; + // If a token that we cannot breaks protrudes, it means we were unable to + // break a sequence of tokens due to disallowed breaks between the tokens. + // Thus, we recursively search backwards to try to find a breakable token. + if (State.Column <= getColumnLimit() || + Current.CanBreakBefore || !Current.Parent) + return 0; + return breakProtrudingToken( + *Current.Parent, State, DryRun, + UnbreakableTailLength + Current.FormatTok.TokenLength); } + if (UnbreakableTailLength >= getColumnLimit()) + return 0; + unsigned RemainingSpace = getColumnLimit() - UnbreakableTailLength; bool BreakInserted = false; unsigned Penalty = 0; + unsigned PositionAfterLastLineInToken = 0; for (unsigned LineIndex = 0; LineIndex < Token->getLineCount(); ++LineIndex) { unsigned TailOffset = 0; - unsigned RemainingLength = + unsigned RemainingTokenLength = Token->getLineLengthAfterSplit(LineIndex, TailOffset); - while (RemainingLength > getColumnLimit()) { + while (RemainingTokenLength > RemainingSpace) { BreakableToken::Split Split = - Token->getSplit(LineIndex, TailOffset, getColumnLimit()); + Token->getSplit(LineIndex, TailOffset, RemainingSpace); if (Split.first == StringRef::npos) break; assert(Split.first != 0); - unsigned NewRemainingLength = Token->getLineLengthAfterSplit( + unsigned NewRemainingTokenLength = Token->getLineLengthAfterSplit( LineIndex, TailOffset + Split.first + Split.second); - if (NewRemainingLength >= RemainingLength) + if (NewRemainingTokenLength >= RemainingTokenLength) break; if (!DryRun) { Token->insertBreak(LineIndex, TailOffset, Split, Line.InPPDirective, Whitespaces); } TailOffset += Split.first + Split.second; - RemainingLength = NewRemainingLength; + RemainingTokenLength = NewRemainingTokenLength; Penalty += Style.PenaltyExcessCharacter; BreakInserted = true; } - State.Column = RemainingLength; + PositionAfterLastLineInToken = RemainingTokenLength; if (!DryRun) { Token->trimLine(LineIndex, TailOffset, Line.InPPDirective, Whitespaces); } } if (BreakInserted) { + State.Column = PositionAfterLastLineInToken + UnbreakableTailLength; for (unsigned i = 0, e = State.Stack.size(); i != e; ++i) State.Stack[i].BreakBeforeParameter = true; State.Stack.back().LastSpace = StartColumn; @@ -961,6 +1020,10 @@ private: getRemainingLength(State) + State.Column > getColumnLimit() && State.ParenLevel < State.StartOfLineLevel) return true; + + if (Current.Type == TT_StartOfName && Line.MightBeFunctionDecl && + State.Stack.back().BreakBeforeParameter && State.ParenLevel == 0) + return true; return false; } @@ -1082,17 +1145,16 @@ private: class Formatter : public UnwrappedLineConsumer { public: - Formatter(DiagnosticsEngine &Diag, const FormatStyle &Style, Lexer &Lex, - SourceManager &SourceMgr, + Formatter(const FormatStyle &Style, Lexer &Lex, SourceManager &SourceMgr, const std::vector<CharSourceRange> &Ranges) - : Diag(Diag), Style(Style), Lex(Lex), SourceMgr(SourceMgr), + : Style(Style), Lex(Lex), SourceMgr(SourceMgr), Whitespaces(SourceMgr, Style), Ranges(Ranges) {} virtual ~Formatter() {} tooling::Replacements format() { LexerBasedFormatTokenSource Tokens(Lex, SourceMgr); - UnwrappedLineParser Parser(Diag, Style, Tokens, *this); + UnwrappedLineParser Parser(Style, Tokens, *this); bool StructuralError = Parser.parse(); unsigned PreviousEndOfLineColumn = 0; TokenAnnotator Annotator(Style, SourceMgr, Lex, @@ -1136,9 +1198,15 @@ public: (touchesLine(TheLine) || touchesPPDirective(I + 1, E))) FormatPPDirective = true; + // Determine indent and try to merge multiple unwrapped lines. while (IndentForLevel.size() <= TheLine.Level) IndentForLevel.push_back(-1); IndentForLevel.resize(TheLine.Level + 1); + unsigned Indent = getIndent(IndentForLevel, TheLine.Level); + if (static_cast<int>(Indent) + Offset >= 0) + Indent += Offset; + tryFitMultipleLinesInOne(Indent, I, E); + bool WasMoved = PreviousLineWasTouched && FirstTok.NewlinesBefore == 0; if (TheLine.First.is(tok::eof)) { if (PreviousLineWasTouched) { @@ -1149,9 +1217,6 @@ public: } else if (TheLine.Type != LT_Invalid && (WasMoved || FormatPPDirective || touchesLine(TheLine))) { unsigned LevelIndent = getIndent(IndentForLevel, TheLine.Level); - unsigned Indent = LevelIndent; - if (static_cast<int>(Indent) + Offset >= 0) - Indent += Offset; 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. @@ -1162,7 +1227,6 @@ public: Indent = LevelIndent = SourceMgr.getSpellingColumnNumber(FirstTok.Tok.getLocation()) - 1; } - tryFitMultipleLinesInOne(Indent, I, E); UnwrappedLineFormatter Formatter(Style, SourceMgr, TheLine, Indent, TheLine.First, Whitespaces); PreviousEndOfLineColumn = @@ -1171,18 +1235,17 @@ public: PreviousLineWasTouched = true; } else { if (FirstTok.NewlinesBefore > 0 || FirstTok.IsFirst) { - unsigned Indent = + unsigned LevelIndent = SourceMgr.getSpellingColumnNumber(FirstTok.Tok.getLocation()) - 1; - unsigned LevelIndent = Indent; + // Remove trailing whitespace of the previous line if it was touched. + if (PreviousLineWasTouched || touchesEmptyLineBefore(TheLine)) + formatFirstToken(TheLine.First, PreviousLineLastToken, LevelIndent, + TheLine.InPPDirective, PreviousEndOfLineColumn); + if (static_cast<int>(LevelIndent) - Offset >= 0) LevelIndent -= Offset; if (TheLine.First.isNot(tok::comment)) IndentForLevel[TheLine.Level] = LevelIndent; - - // Remove trailing whitespace of the previous line if it was touched. - if (PreviousLineWasTouched || touchesEmptyLineBefore(TheLine)) - formatFirstToken(TheLine.First, PreviousLineLastToken, Indent, - TheLine.InPPDirective, PreviousEndOfLineColumn); } // If we did not reformat this unwrapped line, the column at the end of // the last token is unchanged - thus, we can calculate the end of the @@ -1253,7 +1316,7 @@ private: return IndentForLevel[Level]; if (Level == 0) return 0; - return getIndent(IndentForLevel, Level - 1) + 2; + return getIndent(IndentForLevel, Level - 1) + Style.IndentWidth; } /// \brief Get the offset of the line relatively to the level. @@ -1270,8 +1333,6 @@ private: /// /// This will change \c Line and \c AnnotatedLine to contain the merged line, /// if possible; note that \c I will be incremented when lines are merged. - /// - /// Returns whether the resulting \c Line can fit in a single line. void tryFitMultipleLinesInOne(unsigned Indent, std::vector<AnnotatedLine>::iterator &I, std::vector<AnnotatedLine>::iterator E) { @@ -1295,7 +1356,6 @@ private: I->First.FormatTok.IsFirst)) { tryMergeSimplePPDirective(I, E, Limit); } - return; } void tryMergeSimplePPDirective(std::vector<AnnotatedLine>::iterator &I, @@ -1341,13 +1401,17 @@ private: void tryMergeSimpleBlock(std::vector<AnnotatedLine>::iterator &I, std::vector<AnnotatedLine>::iterator E, unsigned Limit) { + // No merging if the brace already is on the next line. + if (Style.BreakBeforeBraces != FormatStyle::BS_Attach) + return; + // First, check that the current line allows merging. This is the case if // we're not in a control flow statement and the last token is an opening // brace. AnnotatedLine &Line = *I; if (Line.First.isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::r_brace, tok::kw_else, tok::kw_try, tok::kw_catch, - tok::kw_for, + tok::kw_for, tok::kw_namespace, // This gets rid of all ObjC @ keywords and methods. tok::at, tok::minus, tok::plus)) return; @@ -1418,9 +1482,9 @@ private: bool touchesLine(const AnnotatedLine &TheLine) { const FormatToken *First = &TheLine.First.FormatTok; const FormatToken *Last = &TheLine.Last->FormatTok; - CharSourceRange LineRange = CharSourceRange::getTokenRange( + CharSourceRange LineRange = CharSourceRange::getCharRange( First->WhiteSpaceStart.getLocWithOffset(First->LastNewlineOffset), - Last->Tok.getLocation()); + Last->Tok.getLocation().getLocWithOffset(Last->TokenLength - 1)); return touchesRanges(LineRange); } @@ -1473,7 +1537,6 @@ private: } } - DiagnosticsEngine &Diag; FormatStyle Style; Lexer &Lex; SourceManager &SourceMgr; @@ -1484,20 +1547,8 @@ private: 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) { - DiagPrinter.reset(new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts)); - DiagPrinter->BeginSourceFile(Lex.getLangOpts(), Lex.getPP()); - DiagClient = DiagPrinter.get(); - } - DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts, - DiagClient, false); - Diagnostics.setSourceManager(&SourceMgr); - Formatter formatter(Diagnostics, Style, Lex, SourceMgr, Ranges); + std::vector<CharSourceRange> Ranges) { + Formatter formatter(Style, Lex, SourceMgr, Ranges); return formatter.format(); } diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index 12031166e2..21518c6824 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -101,8 +101,10 @@ private: return true; } if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace, - tok::pipepipe, tok::ampamp, tok::question, - tok::colon)) + tok::question, tok::colon)) + return false; + if (CurrentToken->isOneOf(tok::pipepipe, tok::ampamp) && + Line.First.isNot(tok::kw_template)) return false; updateParameterCount(Left, CurrentToken); if (!consumeToken()) @@ -155,6 +157,9 @@ private: } if (CurrentToken->is(tok::r_paren)) { + if (CurrentToken->Children.empty() || + !CurrentToken->Children[0].isOneOf(tok::l_paren, tok::l_square)) + Left->DefinesFunctionType = false; if (CurrentToken->Parent->closesScope()) CurrentToken->Parent->MatchingParen->NoMoreTokensOnLevel = true; Left->MatchingParen = CurrentToken; @@ -591,6 +596,7 @@ private: } } else if (Current.isOneOf(tok::kw_return, tok::kw_throw) || (Current.is(tok::l_paren) && !Line.MustBeDeclaration && + !Line.InPPDirective && (!Current.Parent || Current.Parent->isNot(tok::kw_for)))) { Contexts.back().IsExpression = true; } else if (Current.isOneOf(tok::r_paren, tok::greater, tok::comma)) { @@ -871,8 +877,6 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) { Line.First.SpacesRequiredBefore = 1; Line.First.MustBreakBefore = Line.First.FormatTok.MustBreakBefore; Line.First.CanBreakBefore = Line.First.MustBreakBefore; - - Line.First.TotalLength = Line.First.FormatTok.TokenLength; } void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h index 5ea30159a2..227dd52396 100644 --- a/lib/Format/TokenAnnotator.h +++ b/lib/Format/TokenAnnotator.h @@ -75,10 +75,11 @@ public: : FormatTok(FormatTok), Type(TT_Unknown), SpacesRequiredBefore(0), CanBreakBefore(false), MustBreakBefore(false), ClosesTemplateDeclaration(false), MatchingParen(NULL), - ParameterCount(0), BindingStrength(0), SplitPenalty(0), - LongestObjCSelectorName(0), DefinesFunctionType(false), Parent(NULL), - FakeRParens(0), LastInChainOfCalls(false), - PartOfMultiVariableDeclStmt(false), NoMoreTokensOnLevel(false) {} + ParameterCount(0), TotalLength(FormatTok.TokenLength), + BindingStrength(0), SplitPenalty(0), LongestObjCSelectorName(0), + DefinesFunctionType(false), Parent(NULL), FakeRParens(0), + LastInChainOfCalls(false), PartOfMultiVariableDeclStmt(false), + NoMoreTokensOnLevel(false) {} bool is(tok::TokenKind Kind) const { return FormatTok.Tok.is(Kind); } diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index 722af5d2b7..4138bb98ae 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -16,7 +16,6 @@ #define DEBUG_TYPE "format-parser" #include "UnwrappedLineParser.h" -#include "clang/Basic/Diagnostic.h" #include "llvm/Support/Debug.h" namespace clang { @@ -125,11 +124,11 @@ private: UnwrappedLine *PreBlockLine; }; -UnwrappedLineParser::UnwrappedLineParser( - clang::DiagnosticsEngine &Diag, const FormatStyle &Style, - FormatTokenSource &Tokens, UnwrappedLineConsumer &Callback) +UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style, + FormatTokenSource &Tokens, + UnwrappedLineConsumer &Callback) : Line(new UnwrappedLine), MustBreakBeforeNextToken(false), - CurrentLines(&Lines), StructuralError(false), Diag(Diag), Style(Style), + CurrentLines(&Lines), StructuralError(false), Style(Style), Tokens(&Tokens), Callback(Callback) {} bool UnwrappedLineParser::parse() { @@ -173,9 +172,6 @@ void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) { case tok::r_brace: if (HasOpeningBrace) return; - Diag.Report(FormatTok.Tok.getLocation(), - Diag.getCustomDiagID(clang::DiagnosticsEngine::Error, - "unexpected '}'")); StructuralError = true; nextToken(); addUnwrappedLine(); @@ -402,6 +398,10 @@ void UnwrappedLineParser::parseStructuralElement() { // structural element. // FIXME: Figure out cases where this is not true, and add projections for // them (the one we know is missing are lambdas). + if (Style.BreakBeforeBraces == FormatStyle::BS_Linux || + Style.BreakBeforeBraces == FormatStyle::BS_Stroustrup) + addUnwrappedLine(); + parseBlock(/*MustBeDeclaration=*/ false); addUnwrappedLine(); return; @@ -577,6 +577,9 @@ void UnwrappedLineParser::parseNamespace() { if (FormatTok.Tok.is(tok::identifier)) nextToken(); if (FormatTok.Tok.is(tok::l_brace)) { + if (Style.BreakBeforeBraces == FormatStyle::BS_Linux) + addUnwrappedLine(); + parseBlock(/*MustBeDeclaration=*/ true, 0); // Munch the semicolon after a namespace. This is more common than one would // think. Puttin the semicolon into its own line is very ugly. @@ -751,8 +754,12 @@ void UnwrappedLineParser::parseRecord() { } } } - if (FormatTok.Tok.is(tok::l_brace)) + if (FormatTok.Tok.is(tok::l_brace)) { + if (Style.BreakBeforeBraces == FormatStyle::BS_Linux) + addUnwrappedLine(); + parseBlock(/*MustBeDeclaration=*/ true); + } // We fall through to parsing a structural element afterwards, so // class A {} n, m; // will end up in one unwrapped line. diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h index 0c618e24d4..82e93bef48 100644 --- a/lib/Format/UnwrappedLineParser.h +++ b/lib/Format/UnwrappedLineParser.h @@ -23,9 +23,6 @@ #include <list> namespace clang { - -class DiagnosticsEngine; - namespace format { /// \brief A wrapper around a \c Token storing information about the @@ -129,8 +126,7 @@ public: class UnwrappedLineParser { public: - UnwrappedLineParser(clang::DiagnosticsEngine &Diag, const FormatStyle &Style, - FormatTokenSource &Tokens, + UnwrappedLineParser(const FormatStyle &Style, FormatTokenSource &Tokens, UnwrappedLineConsumer &Callback); /// Returns true in case of a structural error. @@ -203,7 +199,6 @@ private: // indentation levels. bool StructuralError; - clang::DiagnosticsEngine &Diag; const FormatStyle &Style; FormatTokenSource *Tokens; UnwrappedLineConsumer &Callback; diff --git a/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp index a75c592bfe..7ffebacba5 100644 --- a/lib/Format/WhitespaceManager.cpp +++ b/lib/Format/WhitespaceManager.cpp @@ -122,7 +122,7 @@ void WhitespaceManager::addUntouchableComment(unsigned Column) { std::string WhitespaceManager::getNewLineText(unsigned NewLines, unsigned Spaces) { - return std::string(NewLines, '\n') + std::string(Spaces, ' '); + return std::string(NewLines, '\n') + getIndentText(Spaces); } std::string WhitespaceManager::getNewLineText(unsigned NewLines, @@ -139,7 +139,15 @@ std::string WhitespaceManager::getNewLineText(unsigned NewLines, Offset = 0; } } - return NewLineText + std::string(Spaces, ' '); + return NewLineText + getIndentText(Spaces); +} + +std::string WhitespaceManager::getIndentText(unsigned Spaces) { + if (!Style.UseTab) + return std::string(Spaces, ' '); + + return std::string(Spaces / Style.IndentWidth, '\t') + + std::string(Spaces % Style.IndentWidth, ' '); } void WhitespaceManager::alignComments() { diff --git a/lib/Format/WhitespaceManager.h b/lib/Format/WhitespaceManager.h index 5f3dc55eda..1b24b3f6d7 100644 --- a/lib/Format/WhitespaceManager.h +++ b/lib/Format/WhitespaceManager.h @@ -78,6 +78,8 @@ private: unsigned WhitespaceStartColumn, unsigned EscapedNewlineColumn); + std::string getIndentText(unsigned Spaces); + /// \brief Structure to store tokens for later layout and alignment. struct StoredToken { StoredToken(SourceLocation ReplacementLoc, unsigned ReplacementLength, diff --git a/lib/Lex/HeaderMap.cpp b/lib/Lex/HeaderMap.cpp index dcf1f0c70c..478462c3c2 100644 --- a/lib/Lex/HeaderMap.cpp +++ b/lib/Lex/HeaderMap.cpp @@ -82,7 +82,7 @@ const HeaderMap *HeaderMap::Create(const FileEntry *FE, FileManager &FM) { if (FileSize <= sizeof(HMapHeader)) return 0; OwningPtr<const llvm::MemoryBuffer> FileBuffer(FM.getBufferForFile(FE)); - if (FileBuffer == 0) return 0; // Unreadable file? + if (!FileBuffer) return 0; // Unreadable file? const char *FileStart = FileBuffer->getBufferStart(); // We know the file is at least as big as the header, check it now. diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 50a0cb55f7..ba3291aa39 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -241,7 +241,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, bool FoundElse, SourceLocation ElseLoc) { ++NumSkipped; - assert(CurTokenLexer == 0 && CurPPLexer && "Lexing a macro, not a file?"); + assert(!CurTokenLexer && CurPPLexer && "Lexing a macro, not a file?"); CurPPLexer->pushConditionalLevel(IfTokenLoc, /*isSkipping*/false, FoundNonSkipPortion, FoundElse); diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp index be4defe786..a22d67a6ed 100644 --- a/lib/Lex/PPLexerChange.cpp +++ b/lib/Lex/PPLexerChange.cpp @@ -70,7 +70,7 @@ PreprocessorLexer *Preprocessor::getCurrentFileLexer() const { /// start lexing tokens from it instead of the current buffer. void Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir, SourceLocation Loc) { - assert(CurTokenLexer == 0 && "Cannot #include a file inside a macro!"); + assert(!CurTokenLexer && "Cannot #include a file inside a macro!"); ++NumEnteredSourceFiles; if (MaxIncludeStackDepth < IncludeMacroStack.size()) diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 6a87b78879..8ad028155a 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2524,7 +2524,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // erroneous: We already checked about that it has no type specifier, and // C++ doesn't have implicit int. Diagnose it as a typo w.r.t. to the // typename. - if (TypeRep == 0) { + if (!TypeRep) { ConsumeToken(); // Eat the scope spec so the identifier is current. ParsedAttributesWithRange Attrs(AttrFactory); if (ParseImplicitInt(DS, &SS, TemplateInfo, AS, DSContext, Attrs)) { diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp index 507a6b1bcd..e192ae2e23 100644 --- a/lib/Parse/ParseOpenMP.cpp +++ b/lib/Parse/ParseOpenMP.cpp @@ -12,8 +12,10 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTConsumer.h" -#include "clang/Parse/Parser.h" #include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Parser.h" +#include "clang/Sema/Scope.h" +#include "llvm/ADT/PointerIntPair.h" #include "RAIIObjectsForParser.h" using namespace clang; @@ -21,22 +23,24 @@ using namespace clang; // OpenMP declarative directives. //===----------------------------------------------------------------------===// -/// \brief Parses OpenMP declarative directive -/// threadprivate-directive -/// annot_pragma_openmp threadprivate simple-variable-list +/// \brief Parsing of declarative OpenMP directives. +/// +/// threadprivate-directive: +/// annot_pragma_openmp 'threadprivate' simple-variable-list /// Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); SourceLocation Loc = ConsumeToken(); - SmallVector<DeclarationNameInfo, 5> Identifiers; - OpenMPDirectiveKind Kind = Tok.isAnnotation() ? - OMPD_unknown : - getOpenMPDirectiveKind(PP.getSpelling(Tok)); - switch(Kind) { + SmallVector<Expr *, 5> Identifiers; + OpenMPDirectiveKind DKind = Tok.isAnnotation() ? + OMPD_unknown : + getOpenMPDirectiveKind(PP.getSpelling(Tok)); + + switch (DKind) { case OMPD_threadprivate: ConsumeToken(); - if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers)) { + if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, true)) { // The last seen token is annot_pragma_openmp_end - need to check for // extra tokens. if (Tok.isNot(tok::annot_pragma_openmp_end)) { @@ -44,9 +48,9 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { << getOpenMPDirectiveName(OMPD_threadprivate); SkipUntil(tok::annot_pragma_openmp_end, false, true); } + // Skip the last annot_pragma_openmp_end. ConsumeToken(); return Actions.ActOnOpenMPThreadprivateDirective(Loc, - getCurScope(), Identifiers); } break; @@ -55,7 +59,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { break; default: Diag(Tok, diag::err_omp_unexpected_directive) - << getOpenMPDirectiveName(Kind); + << getOpenMPDirectiveName(DKind); break; } SkipUntil(tok::annot_pragma_openmp_end, false); @@ -63,56 +67,69 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { } /// \brief Parses list of simple variables for '#pragma omp threadprivate' -/// directive -/// simple-variable-list: -/// ( unqualified-id {, unqualified-id} ) annot_pragma_openmp_end +/// directive. +/// +/// simple-variable-list: +/// '(' id-expression {, id-expression} ')' /// -bool Parser::ParseOpenMPSimpleVarList( - OpenMPDirectiveKind Kind, - SmallVectorImpl<DeclarationNameInfo> &IdList) { +bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, + SmallVectorImpl<Expr *> &VarList, + bool AllowScopeSpecifier) { + VarList.clear(); // Parse '('. - bool IsCorrect = true; - BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.expectAndConsume(diag::err_expected_lparen_after, - getOpenMPDirectiveName(Kind))) { - SkipUntil(tok::annot_pragma_openmp_end, false, true); - return false; - } + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + bool LParen = !T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPDirectiveName(Kind)); + bool IsCorrect = LParen; + bool NoIdentIsFound = true; // Read tokens while ')' or annot_pragma_openmp_end is not found. - do { + while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) { CXXScopeSpec SS; SourceLocation TemplateKWLoc; UnqualifiedId Name; // Read var name. Token PrevTok = Tok; + NoIdentIsFound = false; - if (ParseUnqualifiedId(SS, false, false, false, ParsedType(), - TemplateKWLoc, Name)) { + if (AllowScopeSpecifier && getLangOpts().CPlusPlus && + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false)) { IsCorrect = false; SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, false, true); - } - else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) && - Tok.isNot(tok::annot_pragma_openmp_end)) { + } else if (ParseUnqualifiedId(SS, false, false, false, ParsedType(), + TemplateKWLoc, Name)) { + IsCorrect = false; + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + false, true); + } else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) && + Tok.isNot(tok::annot_pragma_openmp_end)) { IsCorrect = false; SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, false, true); - Diag(PrevTok.getLocation(), diag::err_expected_unqualified_id) - << getLangOpts().CPlusPlus + Diag(PrevTok.getLocation(), diag::err_expected_ident) << SourceRange(PrevTok.getLocation(), PrevTokLocation); } else { - IdList.push_back(Actions.GetNameFromUnqualifiedId(Name)); + DeclarationNameInfo NameInfo = Actions.GetNameFromUnqualifiedId(Name); + ExprResult Res = Actions.ActOnOpenMPIdExpression(getCurScope(), SS, + NameInfo); + if (Res.isUsable()) + VarList.push_back(Res.take()); } // Consume ','. if (Tok.is(tok::comma)) { ConsumeToken(); } - } while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)); + } - if (IsCorrect || Tok.is(tok::r_paren)) { - IsCorrect = !T.consumeClose() && IsCorrect; + if (NoIdentIsFound) { + Diag(Tok, diag::err_expected_ident); + IsCorrect = false; } - return !IsCorrect && IdList.empty(); + // Parse ')'. + IsCorrect = ((LParen || Tok.is(tok::r_paren)) && !T.consumeClose()) + && IsCorrect; + + return !IsCorrect && VarList.empty(); } diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 43b6965d31..f47b0e5435 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -2091,8 +2091,8 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { 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::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT)); OwningPtr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo()); OwningPtr<llvm::MCSubtargetInfo> STI(TheTarget->createMCSubtargetInfo(TT, "", "")); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 2117df45f3..a5371f9e61 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -1897,7 +1897,7 @@ bool BalancedDelimiterTracker::diagnoseOverflow() { P.Diag(P.Tok, diag::err_bracket_depth_exceeded) << P.getLangOpts().BracketDepth; P.Diag(P.Tok, diag::note_bracket_depth); - P.SkipUntil(tok::eof); + P.SkipUntil(tok::eof, FinalToken); return true; } @@ -1927,7 +1927,8 @@ bool BalancedDelimiterTracker::diagnoseMissingClose() { } P.Diag(P.Tok, DID); P.Diag(LOpen, diag::note_matching) << LHSName; - if (P.SkipUntil(Close, /*StopAtSemi*/ true, /*DontConsume*/ true)) + if (P.SkipUntil(Close, FinalToken, /*StopAtSemi*/ true, /*DontConsume*/ true) + && P.Tok.is(Close)) LClose = P.ConsumeAnyToken(); return true; } diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h index 213950a6db..f68a2e09fe 100644 --- a/lib/Parse/RAIIObjectsForParser.h +++ b/lib/Parse/RAIIObjectsForParser.h @@ -358,7 +358,7 @@ namespace clang { /// pair, such as braces { ... } or parentheses ( ... ). class BalancedDelimiterTracker : public GreaterThanIsOperatorScope { Parser& P; - tok::TokenKind Kind, Close; + tok::TokenKind Kind, Close, FinalToken; SourceLocation (Parser::*Consumer)(); SourceLocation LOpen, LClose; @@ -377,9 +377,10 @@ namespace clang { bool diagnoseMissingClose(); public: - BalancedDelimiterTracker(Parser& p, tok::TokenKind k) + BalancedDelimiterTracker(Parser& p, tok::TokenKind k, + tok::TokenKind FinalToken = tok::semi) : GreaterThanIsOperatorScope(p.GreaterThanIsOperator, true), - P(p), Kind(k) + P(p), Kind(k), FinalToken(FinalToken) { switch (Kind) { default: llvm_unreachable("Unexpected balanced token"); diff --git a/lib/Rewrite/Core/Rewriter.cpp b/lib/Rewrite/Core/Rewriter.cpp index c1c6595d16..540e8b27fd 100644 --- a/lib/Rewrite/Core/Rewriter.cpp +++ b/lib/Rewrite/Core/Rewriter.cpp @@ -463,7 +463,7 @@ public: } } - bool ok() { return FileStream; } + bool ok() { return FileStream.isValid(); } raw_ostream &getStream() { return *FileStream; } private: diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index 3b3ab2c27b..dfce324b70 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -651,7 +651,7 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc, DeclRep = Rep; TSTLoc = TagKwLoc; TSTNameLoc = TagNameLoc; - TypeSpecOwned = Owned; + TypeSpecOwned = Owned && Rep != 0; return false; } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index e718be2f8b..b7810da98e 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -332,7 +332,7 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) { if (D->getMostRecentDecl()->isUsed()) return true; - if (D->hasExternalLinkage()) + if (D->isExternallyVisible()) return true; if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { @@ -402,13 +402,13 @@ void Sema::getUndefinedButUsed( if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { if (FD->isDefined()) continue; - if (FD->hasExternalLinkage() && + if (FD->isExternallyVisible() && !FD->getMostRecentDecl()->isInlined()) continue; } else { if (cast<VarDecl>(ND)->hasDefinition() != VarDecl::DeclarationOnly) continue; - if (ND->hasExternalLinkage()) + if (ND->isExternallyVisible()) continue; } @@ -435,7 +435,7 @@ static void checkUndefinedButUsed(Sema &S) { I = Undefined.begin(), E = Undefined.end(); I != E; ++I) { NamedDecl *ND = I->first; - if (ND->getLinkage() != ExternalLinkage) { + if (!ND->isExternallyVisible()) { S.Diag(ND->getLocation(), diag::warn_undefined_internal) << isa<VarDecl>(ND) << ND; } else { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 5d8839a65b..49be515f0b 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1194,7 +1194,7 @@ bool Sema::mightHaveNonExternalLinkage(const DeclaratorDecl *D) { DC = DC->getParent(); } - return !D->hasExternalLinkage(); + return !D->isExternallyVisible(); } bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { @@ -1614,7 +1614,7 @@ static void filterNonConflictingPreviousDecls(ASTContext &context, if (!old->isHidden()) continue; - if (old->getLinkage() != ExternalLinkage) + if (!old->isExternallyVisible()) filter.erase(); } @@ -2314,7 +2314,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) { // storage classes. if (!isa<CXXMethodDecl>(New) && !isa<CXXMethodDecl>(Old) && New->getStorageClass() == SC_Static && - isExternalLinkage(Old->getLinkage()) && + Old->hasExternalFormalLinkage() && !New->getTemplateSpecializationInfo() && !canRedefineFunction(Old, getLangOpts())) { if (getLangOpts().MicrosoftExt) { @@ -2923,7 +2923,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous, // [dcl.stc]p8: Check if we have a non-static decl followed by a static. if (New->getStorageClass() == SC_Static && !New->isStaticDataMember() && - isExternalLinkage(Old->getLinkage())) { + Old->hasExternalFormalLinkage()) { Diag(New->getLocation(), diag::err_static_non_static) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); @@ -4625,13 +4625,13 @@ bool Sema::inferObjCARCLifetime(ValueDecl *decl) { static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) { // 'weak' only applies to declarations with external linkage. if (WeakAttr *Attr = ND.getAttr<WeakAttr>()) { - if (ND.getLinkage() != ExternalLinkage) { + if (!ND.isExternallyVisible()) { S.Diag(Attr->getLocation(), diag::err_attribute_weak_static); ND.dropAttr<WeakAttr>(); } } if (WeakRefAttr *Attr = ND.getAttr<WeakRefAttr>()) { - if (ND.hasExternalLinkage()) { + if (ND.isExternallyVisible()) { S.Diag(Attr->getLocation(), diag::err_attribute_weakref_not_static); ND.dropAttr<WeakRefAttr>(); } @@ -6579,7 +6579,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // If there's a #pragma GCC visibility in scope, and this isn't a class // member, set the visibility of this function. - if (!DC->isRecord() && NewFD->hasExternalLinkage()) + if (!DC->isRecord() && NewFD->isExternallyVisible()) AddPushedVisibilityAttribute(NewFD); // If there's a #pragma clang arc_cf_code_audited in scope, consider @@ -7816,7 +7816,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, // declared with no linkage (C99 6.2.2p6), the type for the // object shall be complete. if (!Type->isDependentType() && Var->isLocalVarDecl() && - !Var->getLinkage() && !Var->isInvalidDecl() && + !Var->hasLinkage() && !Var->isInvalidDecl() && RequireCompleteType(Var->getLocation(), Type, diag::err_typecheck_decl_incomplete_type)) Var->setInvalidDecl(); @@ -8029,7 +8029,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { } if (var->isThisDeclarationADefinition() && - var->hasExternalLinkage() && + var->isExternallyVisible() && getDiagnostics().getDiagnosticLevel( diag::warn_missing_variable_declarations, var->getLocation())) { @@ -8138,7 +8138,7 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) { const DeclContext *DC = VD->getDeclContext(); // If there's a #pragma GCC visibility in scope, and this isn't a class // member, set the visibility of this variable. - if (!DC->isRecord() && VD->hasExternalLinkage()) + if (!DC->isRecord() && VD->isExternallyVisible()) AddPushedVisibilityAttribute(VD); if (VD->isFileVarDecl()) @@ -8904,7 +8904,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, // ODR use before the definition. Avoid the expensive map lookup if this // is the first declaration. if (FD->getPreviousDecl() != 0 && FD->getPreviousDecl()->isUsed()) { - if (FD->getLinkage() != ExternalLinkage) + if (!FD->isExternallyVisible()) UndefinedButUsed.erase(FD); else if (FD->isInlined() && (LangOpts.CPlusPlus || !LangOpts.GNUInline) && diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index e5d0316f73..437a9da422 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -9307,7 +9307,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, ParmVarDecl *Other = MoveAssignOperator->getParamDecl(0); QualType OtherRefType = Other->getType()-> getAs<RValueReferenceType>()->getPointeeType(); - assert(OtherRefType.getQualifiers() == 0 && + assert(!OtherRefType.getQualifiers() && "Bad argument type of defaulted move assignment"); // Our location for everything implicitly-generated. @@ -11824,7 +11824,7 @@ bool Sema::DefineUsedVTables() { Consumer.HandleVTable(Class, VTablesUsed[Canonical]); // Optionally warn if we're emitting a weak vtable. - if (Class->hasExternalLinkage() && + if (Class->isExternallyVisible() && Class->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) { const FunctionDecl *KeyFunctionDef = 0; if (!KeyFunction || diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index f33e7bcb16..3265ab02dc 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -2945,7 +2945,7 @@ Decl *Sema::ActOnMethodDeclaration( QualType ArgType; TypeSourceInfo *DI; - if (ArgInfo[i].Type == 0) { + if (!ArgInfo[i].Type) { ArgType = Context.getObjCIdType(); DI = 0; } else { @@ -3052,6 +3052,8 @@ Decl *Sema::ActOnMethodDeclaration( Diag(ObjCMethod->getLocation(), diag::err_duplicate_method_decl) << ObjCMethod->getDeclName(); Diag(PrevMethod->getLocation(), diag::note_previous_declaration); + ObjCMethod->setInvalidDecl(); + return ObjCMethod; } // If this Objective-C method does not have a related result type, but we diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index b6b6444738..fa2bfd260b 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -197,11 +197,11 @@ static void diagnoseUseOfInternalDeclInInlineFunction(Sema &S, return; if (!Current->isInlined()) return; - if (Current->getLinkage() != ExternalLinkage) + if (!Current->isExternallyVisible()) return; - + // Check if the decl has internal linkage. - if (D->getLinkage() != InternalLinkage) + if (D->getFormalLinkage() != InternalLinkage) return; // Downgrade from ExtWarn to Extension if @@ -4468,7 +4468,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, ExprResult Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, ParsedType Ty, SourceLocation RParenLoc, Expr *InitExpr) { - assert((Ty != 0) && "ActOnCompoundLiteral(): missing type"); + assert(Ty && "ActOnCompoundLiteral(): missing type"); // FIXME: put back this assert when initializers are worked out. //assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression"); @@ -11459,7 +11459,7 @@ static void MarkVarDeclODRUsed(Sema &SemaRef, VarDecl *Var, // Keep track of used but undefined variables. // FIXME: We shouldn't suppress this warning for static data members. if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly && - Var->getLinkage() != ExternalLinkage && + !Var->isExternallyVisible() && !(Var->isStaticDataMember() && Var->hasInit())) { SourceLocation &old = SemaRef.UndefinedButUsed[Var->getCanonicalDecl()]; if (old.isInvalid()) old = Loc; diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index d37f61ab8a..23116d84ad 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -1221,10 +1221,17 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, else DiagID = isClassMessage ? diag::warn_class_method_not_found : diag::warn_inst_method_not_found; - if (!getLangOpts().DebuggerSupport) + if (!getLangOpts().DebuggerSupport) { Diag(SelLoc, DiagID) << Sel << isClassMessage << SourceRange(SelectorLocs.front(), SelectorLocs.back()); + // Find the class to which we are sending this message. + if (ReceiverType->isObjCObjectPointerType()) { + if (ObjCInterfaceDecl *Class = + ReceiverType->getAs<ObjCObjectPointerType>()->getInterfaceDecl()) + Diag(Class->getLocation(), diag::note_receiver_class_declared); + } + } // In debuggers, we want to use __unknown_anytype for these // results so that clients can cast them. diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 7016e565da..a3b78787e4 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -32,54 +32,99 @@ using namespace clang; // Sema Initialization Checking //===----------------------------------------------------------------------===// -static Expr *IsStringInit(Expr *Init, const ArrayType *AT, - ASTContext &Context) { +/// \brief Check whether T is compatible with a wide character type (wchar_t, +/// char16_t or char32_t). +static bool IsWideCharCompatible(QualType T, ASTContext &Context) { + if (Context.typesAreCompatible(Context.getWideCharType(), T)) + return true; + if (Context.getLangOpts().CPlusPlus || Context.getLangOpts().C11) { + return Context.typesAreCompatible(Context.Char16Ty, T) || + Context.typesAreCompatible(Context.Char32Ty, T); + } + return false; +} + +enum StringInitFailureKind { + SIF_None, + SIF_NarrowStringIntoWideChar, + SIF_WideStringIntoChar, + SIF_IncompatWideStringIntoWideChar, + SIF_Other +}; + +/// \brief Check whether the array of type AT can be initialized by the Init +/// expression by means of string initialization. Returns SIF_None if so, +/// otherwise returns a StringInitFailureKind that describes why the +/// initialization would not work. +static StringInitFailureKind IsStringInit(Expr *Init, const ArrayType *AT, + ASTContext &Context) { if (!isa<ConstantArrayType>(AT) && !isa<IncompleteArrayType>(AT)) - return 0; + return SIF_Other; // See if this is a string literal or @encode. Init = Init->IgnoreParens(); // Handle @encode, which is a narrow string. if (isa<ObjCEncodeExpr>(Init) && AT->getElementType()->isCharType()) - return Init; + return SIF_None; // Otherwise we can only handle string literals. StringLiteral *SL = dyn_cast<StringLiteral>(Init); - if (SL == 0) return 0; + if (SL == 0) + return SIF_Other; - QualType ElemTy = Context.getCanonicalType(AT->getElementType()); + const QualType ElemTy = + Context.getCanonicalType(AT->getElementType()).getUnqualifiedType(); switch (SL->getKind()) { case StringLiteral::Ascii: case StringLiteral::UTF8: // char array can be initialized with a narrow string. // Only allow char x[] = "foo"; not char x[] = L"foo"; - return ElemTy->isCharType() ? Init : 0; + if (ElemTy->isCharType()) + return SIF_None; + if (IsWideCharCompatible(ElemTy, Context)) + return SIF_NarrowStringIntoWideChar; + return SIF_Other; + // C99 6.7.8p15 (with correction from DR343), or C11 6.7.9p15: + // "An array with element type compatible with a qualified or unqualified + // version of wchar_t, char16_t, or char32_t may be initialized by a wide + // string literal with the corresponding encoding prefix (L, u, or U, + // respectively), optionally enclosed in braces. case StringLiteral::UTF16: - return ElemTy->isChar16Type() ? Init : 0; + if (Context.typesAreCompatible(Context.Char16Ty, ElemTy)) + return SIF_None; + if (ElemTy->isCharType()) + return SIF_WideStringIntoChar; + if (IsWideCharCompatible(ElemTy, Context)) + return SIF_IncompatWideStringIntoWideChar; + return SIF_Other; case StringLiteral::UTF32: - return ElemTy->isChar32Type() ? Init : 0; + if (Context.typesAreCompatible(Context.Char32Ty, ElemTy)) + return SIF_None; + if (ElemTy->isCharType()) + return SIF_WideStringIntoChar; + if (IsWideCharCompatible(ElemTy, Context)) + return SIF_IncompatWideStringIntoWideChar; + return SIF_Other; case StringLiteral::Wide: - // wchar_t array can be initialized with a wide string: C99 6.7.8p15 (with - // correction from DR343): "An array with element type compatible with a - // qualified or unqualified version of wchar_t may be initialized by a wide - // string literal, optionally enclosed in braces." - if (Context.typesAreCompatible(Context.getWideCharType(), - ElemTy.getUnqualifiedType())) - return Init; - - return 0; + if (Context.typesAreCompatible(Context.getWideCharType(), ElemTy)) + return SIF_None; + if (ElemTy->isCharType()) + return SIF_WideStringIntoChar; + if (IsWideCharCompatible(ElemTy, Context)) + return SIF_IncompatWideStringIntoWideChar; + return SIF_Other; } llvm_unreachable("missed a StringLiteral kind?"); } -static Expr *IsStringInit(Expr *init, QualType declType, ASTContext &Context) { +static bool IsStringInit(Expr* init, QualType declType, ASTContext& Context) { const ArrayType *arrayType = Context.getAsArrayType(declType); - if (!arrayType) return 0; - - return IsStringInit(init, arrayType, Context); + if (!arrayType) + return false; + return IsStringInit(init, arrayType, Context) == SIF_None; } /// Update the type of a string literal, including any surrounding parentheses, @@ -806,10 +851,10 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // array member. There's nothing we can do with the completed // type here, though. - if (Expr *Str = IsStringInit(expr, arrayType, SemaRef.Context)) { + if (IsStringInit(expr, arrayType, SemaRef.Context) == SIF_None) { if (!VerifyOnly) { - CheckStringInit(Str, ElemType, arrayType, SemaRef); - UpdateStructuredListElement(StructuredList, StructuredIndex, Str); + CheckStringInit(expr, ElemType, arrayType, SemaRef); + UpdateStructuredListElement(StructuredList, StructuredIndex, expr); } ++Index; return; @@ -1189,16 +1234,17 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, // Check for the special-case of initializing an array with a string. if (Index < IList->getNumInits()) { - if (Expr *Str = IsStringInit(IList->getInit(Index), arrayType, - SemaRef.Context)) { + if (IsStringInit(IList->getInit(Index), arrayType, SemaRef.Context) == + SIF_None) { // We place the string literal directly into the resulting // initializer list. This is the only place where the structure // of the structured initializer list doesn't match exactly, // because doing so would involve allocating one character // constant for each string. if (!VerifyOnly) { - CheckStringInit(Str, DeclType, arrayType, SemaRef); - UpdateStructuredListElement(StructuredList, StructuredIndex, Str); + CheckStringInit(IList->getInit(Index), DeclType, arrayType, SemaRef); + UpdateStructuredListElement(StructuredList, StructuredIndex, + IList->getInit(Index)); StructuredList->resizeInits(SemaRef.Context, StructuredIndex); } ++Index; @@ -2507,6 +2553,10 @@ bool InitializationSequence::isAmbiguous() const { case FK_TooManyInitsForReference: case FK_ArrayNeedsInitList: case FK_ArrayNeedsInitListOrStringLiteral: + case FK_ArrayNeedsInitListOrWideStringLiteral: + case FK_NarrowStringIntoWideCharArray: + case FK_WideStringIntoCharArray: + case FK_IncompatWideStringIntoWideChar: case FK_AddressOfOverloadFailed: // FIXME: Could do better case FK_NonConstLValueReferenceBindingToTemporary: case FK_NonConstLValueReferenceBindingToUnrelated: @@ -4278,9 +4328,23 @@ InitializationSequence::InitializationSequence(Sema &S, return; } - if (Initializer && IsStringInit(Initializer, DestAT, Context)) { - TryStringLiteralInitialization(S, Entity, Kind, Initializer, *this); - return; + if (Initializer) { + switch (IsStringInit(Initializer, DestAT, Context)) { + case SIF_None: + TryStringLiteralInitialization(S, Entity, Kind, Initializer, *this); + return; + case SIF_NarrowStringIntoWideChar: + SetFailed(FK_NarrowStringIntoWideCharArray); + return; + case SIF_WideStringIntoChar: + SetFailed(FK_WideStringIntoCharArray); + return; + case SIF_IncompatWideStringIntoWideChar: + SetFailed(FK_IncompatWideStringIntoWideChar); + return; + case SIF_Other: + break; + } } // Note: as an GNU C extension, we allow initialization of an @@ -4307,8 +4371,10 @@ InitializationSequence::InitializationSequence(Sema &S, TryListInitialization(S, Entity, Kind, cast<InitListExpr>(Initializer), *this); AddParenthesizedArrayInitStep(DestType); - } else if (DestAT->getElementType()->isAnyCharacterType()) + } else if (DestAT->getElementType()->isCharType()) SetFailed(FK_ArrayNeedsInitListOrStringLiteral); + else if (IsWideCharCompatible(DestAT->getElementType(), Context)) + SetFailed(FK_ArrayNeedsInitListOrWideStringLiteral); else SetFailed(FK_ArrayNeedsInitList); @@ -5816,11 +5882,24 @@ bool InitializationSequence::Diagnose(Sema &S, break; case FK_ArrayNeedsInitList: + S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) << 0; + break; case FK_ArrayNeedsInitListOrStringLiteral: - S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) - << (Failure == FK_ArrayNeedsInitListOrStringLiteral); + S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) << 1; + break; + case FK_ArrayNeedsInitListOrWideStringLiteral: + S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) << 2; + break; + case FK_NarrowStringIntoWideCharArray: + S.Diag(Kind.getLocation(), diag::err_array_init_narrow_string_into_wchar); + break; + case FK_WideStringIntoCharArray: + S.Diag(Kind.getLocation(), diag::err_array_init_wide_string_into_char); + break; + case FK_IncompatWideStringIntoWideChar: + S.Diag(Kind.getLocation(), + diag::err_array_init_incompat_wide_string_into_wchar); break; - case FK_ArrayTypeMismatch: case FK_NonConstantArrayInit: S.Diag(Kind.getLocation(), @@ -6192,6 +6271,22 @@ void InitializationSequence::dump(raw_ostream &OS) const { OS << "array requires initializer list or string literal"; break; + case FK_ArrayNeedsInitListOrWideStringLiteral: + OS << "array requires initializer list or wide string literal"; + break; + + case FK_NarrowStringIntoWideCharArray: + OS << "narrow string into wide char array"; + break; + + case FK_WideStringIntoCharArray: + OS << "wide string into char array"; + break; + + case FK_IncompatWideStringIntoWideChar: + OS << "incompatible wide string into wide char array"; + break; + case FK_ArrayTypeMismatch: OS << "array type mismatch"; break; diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 9ab3b2d08e..c70367691f 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -4166,7 +4166,7 @@ std::string TypoCorrection::getAsString(const LangOptions &LO) const { std::string tmpBuffer; llvm::raw_string_ostream PrefixOStream(tmpBuffer); CorrectionNameSpec->print(PrefixOStream, PrintingPolicy(LO)); - CorrectionName.printName(PrefixOStream); + PrefixOStream << CorrectionName; return PrefixOStream.str(); } diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index c815d4f9ab..4953d2d14e 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// /// \file /// \brief This file implements semantic analysis for OpenMP directives and -/// clauses +/// clauses. /// //===----------------------------------------------------------------------===// @@ -22,117 +22,121 @@ using namespace clang; namespace { - class VarDeclFilterCCC : public CorrectionCandidateCallback { - private: - Sema &Actions; - public: - VarDeclFilterCCC(Sema &S) : Actions(S) { } - virtual bool ValidateCandidate(const TypoCorrection &Candidate) { - NamedDecl *ND = Candidate.getCorrectionDecl(); - if (VarDecl *VD = dyn_cast_or_null<VarDecl>(ND)) { - return VD->hasGlobalStorage() && - Actions.isDeclInScope(ND, Actions.getCurLexicalContext(), - Actions.getCurScope()); - } - return false; - } - }; +class VarDeclFilterCCC : public CorrectionCandidateCallback { +private: + Sema &Actions; +public: + VarDeclFilterCCC(Sema &S) : Actions(S) { } + virtual bool ValidateCandidate(const TypoCorrection &Candidate) { + NamedDecl *ND = Candidate.getCorrectionDecl(); + if (VarDecl *VD = dyn_cast_or_null<VarDecl>(ND)) { + return VD->hasGlobalStorage() && + Actions.isDeclInScope(ND, Actions.getCurLexicalContext(), + Actions.getCurScope()); + } + return false; + } +}; } -Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective( - SourceLocation Loc, - Scope *CurScope, - ArrayRef<DeclarationNameInfo> IdList) { - SmallVector<DeclRefExpr *, 5> Vars; - for (ArrayRef<DeclarationNameInfo>::iterator I = IdList.begin(), - E = IdList.end(); - I != E; ++I) { - LookupResult Lookup(*this, *I, LookupOrdinaryName); - LookupParsedName(Lookup, CurScope, NULL, true); - if (Lookup.isAmbiguous()) - continue; +ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, + CXXScopeSpec &ScopeSpec, + const DeclarationNameInfo &Id) { + LookupResult Lookup(*this, Id, LookupOrdinaryName); + LookupParsedName(Lookup, CurScope, &ScopeSpec, true); - VarDecl *VD; - if (!Lookup.isSingleResult()) { - VarDeclFilterCCC Validator(*this); - TypoCorrection Corrected = CorrectTypo(*I, LookupOrdinaryName, CurScope, - 0, Validator); - std::string CorrectedStr = Corrected.getAsString(getLangOpts()); - std::string CorrectedQuotedStr = Corrected.getQuoted(getLangOpts()); - if (Lookup.empty()) { - if (Corrected.isResolved()) { - Diag(I->getLoc(), diag::err_undeclared_var_use_suggest) - << I->getName() << CorrectedQuotedStr - << FixItHint::CreateReplacement(I->getLoc(), CorrectedStr); - } else { - Diag(I->getLoc(), diag::err_undeclared_var_use) - << I->getName(); - } + if (Lookup.isAmbiguous()) + return ExprError(); + + VarDecl *VD; + if (!Lookup.isSingleResult()) { + VarDeclFilterCCC Validator(*this); + TypoCorrection Corrected = CorrectTypo(Id, LookupOrdinaryName, CurScope, + 0, Validator); + std::string CorrectedStr = Corrected.getAsString(getLangOpts()); + std::string CorrectedQuotedStr = Corrected.getQuoted(getLangOpts()); + if (Lookup.empty()) { + if (Corrected.isResolved()) { + Diag(Id.getLoc(), diag::err_undeclared_var_use_suggest) + << Id.getName() << CorrectedQuotedStr + << FixItHint::CreateReplacement(Id.getLoc(), CorrectedStr); } else { - Diag(I->getLoc(), diag::err_omp_expected_var_arg_suggest) - << I->getName() << Corrected.isResolved() << CorrectedQuotedStr - << FixItHint::CreateReplacement(I->getLoc(), CorrectedStr); + Diag(Id.getLoc(), diag::err_undeclared_var_use) + << Id.getName(); } - if (!Corrected.isResolved()) continue; - VD = Corrected.getCorrectionDeclAs<VarDecl>(); } else { - if (!(VD = Lookup.getAsSingle<VarDecl>())) { - Diag(I->getLoc(), diag::err_omp_expected_var_arg_suggest) - << I->getName() << 0; - Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at); - continue; - } + Diag(Id.getLoc(), diag::err_omp_expected_var_arg_suggest) + << Id.getName() << Corrected.isResolved() << CorrectedQuotedStr + << FixItHint::CreateReplacement(Id.getLoc(), CorrectedStr); } - - // OpenMP [2.9.2, Syntax, C/C++] - // Variables must be file-scope, namespace-scope, or static block-scope. - if (!VD->hasGlobalStorage()) { - Diag(I->getLoc(), diag::err_omp_global_var_arg) - << getOpenMPDirectiveName(OMPD_threadprivate) - << !VD->isStaticLocal(); - Diag(VD->getLocation(), diag::note_forward_declaration) << VD; - continue; + if (!Corrected.isResolved()) return ExprError(); + VD = Corrected.getCorrectionDeclAs<VarDecl>(); + } else { + if (!(VD = Lookup.getAsSingle<VarDecl>())) { + Diag(Id.getLoc(), diag::err_omp_expected_var_arg_suggest) + << Id.getName() << 0; + Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at); + return ExprError(); } + } + Lookup.suppressDiagnostics(); - // OpenMP [2.9.2, Restrictions, C/C++, p.2] - // A threadprivate directive for file-scope variables must appear outside - // any definition or declaration. - // OpenMP [2.9.2, Restrictions, C/C++, p.3] - // A threadprivate directive for static class member variables must appear - // in the class definition, in the same scope in which the member - // variables are declared. - // OpenMP [2.9.2, Restrictions, C/C++, p.4] - // A threadprivate directive for namespace-scope variables must appear - // outside any definition or declaration other than the namespace - // definition itself. - // OpenMP [2.9.2, Restrictions, C/C++, p.6] - // A threadprivate directive for static block-scope variables must appear - // in the scope of the variable and not in a nested scope. - NamedDecl *ND = cast<NamedDecl>(VD); - if (!isDeclInScope(ND, getCurLexicalContext(), CurScope)) { - Diag(I->getLoc(), diag::err_omp_var_scope) - << getOpenMPDirectiveName(OMPD_threadprivate) << VD; - Diag(VD->getLocation(), diag::note_forward_declaration) << VD; - continue; - } + // OpenMP [2.9.2, Syntax, C/C++] + // Variables must be file-scope, namespace-scope, or static block-scope. + if (!VD->hasGlobalStorage()) { + Diag(Id.getLoc(), diag::err_omp_global_var_arg) + << getOpenMPDirectiveName(OMPD_threadprivate) + << !VD->isStaticLocal(); + bool IsDecl = VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; + return ExprError(); + } - // OpenMP [2.9.2, Restrictions, C/C++, p.2-6] - // A threadprivate directive must lexically precede all references to any - // of the variables in its list. - if (VD->isUsed()) { - Diag(I->getLoc(), diag::err_omp_var_used) - << getOpenMPDirectiveName(OMPD_threadprivate) << VD; - continue; - } + // OpenMP [2.9.2, Restrictions, C/C++, p.2] + // A threadprivate directive for file-scope variables must appear outside + // any definition or declaration. + // OpenMP [2.9.2, Restrictions, C/C++, p.3] + // A threadprivate directive for static class member variables must appear + // in the class definition, in the same scope in which the member + // variables are declared. + // OpenMP [2.9.2, Restrictions, C/C++, p.4] + // A threadprivate directive for namespace-scope variables must appear + // outside any definition or declaration other than the namespace + // definition itself. + // OpenMP [2.9.2, Restrictions, C/C++, p.6] + // A threadprivate directive for static block-scope variables must appear + // in the scope of the variable and not in a nested scope. + NamedDecl *ND = cast<NamedDecl>(VD); + if (!isDeclInScope(ND, getCurLexicalContext(), CurScope)) { + Diag(Id.getLoc(), diag::err_omp_var_scope) + << getOpenMPDirectiveName(OMPD_threadprivate) << VD; + bool IsDecl = VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : + diag::note_defined_here) << VD; + return ExprError(); + } - QualType ExprType = VD->getType().getNonReferenceType(); - DeclRefExpr *Var = cast<DeclRefExpr>(BuildDeclRefExpr(VD, - ExprType, - VK_RValue, - I->getLoc()).take()); - Vars.push_back(Var); + // OpenMP [2.9.2, Restrictions, C/C++, p.2-6] + // A threadprivate directive must lexically precede all references to any + // of the variables in its list. + if (VD->isUsed()) { + Diag(Id.getLoc(), diag::err_omp_var_used) + << getOpenMPDirectiveName(OMPD_threadprivate) << VD; + return ExprError(); } - if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, Vars)) { + + QualType ExprType = VD->getType().getNonReferenceType(); + ExprResult DE = BuildDeclRefExpr(VD, ExprType, VK_RValue, Id.getLoc()); + return DE; +} + +Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective( + SourceLocation Loc, + ArrayRef<Expr *> VarList) { + if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, VarList)) { CurContext->addDecl(D); return DeclGroupPtrTy::make(DeclGroupRef(D)); } @@ -141,18 +145,19 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective( OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl( SourceLocation Loc, - ArrayRef<DeclRefExpr *> VarList) { - SmallVector<DeclRefExpr *, 5> Vars; - for (ArrayRef<DeclRefExpr *>::iterator I = VarList.begin(), + ArrayRef<Expr *> VarList) { + SmallVector<Expr *, 8> Vars; + for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end(); I != E; ++I) { - VarDecl *VD = cast<VarDecl>((*I)->getDecl()); - SourceLocation ILoc = (*I)->getLocation(); + DeclRefExpr *DE = cast<DeclRefExpr>(*I); + VarDecl *VD = cast<VarDecl>(DE->getDecl()); + SourceLocation ILoc = DE->getExprLoc(); // OpenMP [2.9.2, Restrictions, C/C++, p.10] // A threadprivate variable must not have an incomplete type. if (RequireCompleteType(ILoc, VD->getType(), - diag::err_omp_incomplete_type)) { + diag::err_omp_threadprivate_incomplete_type)) { continue; } @@ -160,15 +165,21 @@ OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl( // A threadprivate variable must not have a reference type. if (VD->getType()->isReferenceType()) { Diag(ILoc, diag::err_omp_ref_type_arg) - << getOpenMPDirectiveName(OMPD_threadprivate) << VD->getType(); - Diag(VD->getLocation(), diag::note_forward_declaration) << VD; + << getOpenMPDirectiveName(OMPD_threadprivate); + bool IsDecl = VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : + diag::note_defined_here) << VD; continue; } // 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; + bool IsDecl = VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : + diag::note_defined_here) << VD; continue; } @@ -179,3 +190,4 @@ OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl( getCurLexicalContext(), Loc, Vars); } + diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index b9695cc1e1..7f1def7daf 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3793,14 +3793,14 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, } // Address / reference template args must have external linkage in C++98. - if (Entity->getLinkage() == InternalLinkage) { + if (Entity->getFormalLinkage() == InternalLinkage) { S.Diag(Arg->getLocStart(), S.getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_template_arg_object_internal : diag::ext_template_arg_object_internal) << !Func << Entity << Arg->getSourceRange(); S.Diag(Entity->getLocation(), diag::note_template_arg_internal_object) << !Func; - } else if (Entity->getLinkage() == NoLinkage) { + } else if (!Entity->hasLinkage()) { S.Diag(Arg->getLocStart(), diag::err_template_arg_object_no_linkage) << !Func << Entity << Arg->getSourceRange(); S.Diag(Entity->getLocation(), diag::note_template_arg_internal_object) diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 42e1757bcb..ff59cdcbc4 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2231,13 +2231,13 @@ Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl( Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl( OMPThreadPrivateDecl *D) { - SmallVector<DeclRefExpr *, 5> Vars; - for (ArrayRef<DeclRefExpr *>::iterator I = D->varlist_begin(), - E = D->varlist_end(); + SmallVector<Expr *, 5> Vars; + for (ArrayRef<Expr *>::iterator I = D->varlist_begin(), + E = D->varlist_end(); I != E; ++I) { Expr *Var = SemaRef.SubstExpr(*I, TemplateArgs).take(); assert(isa<DeclRefExpr>(Var) && "threadprivate arg is not a DeclRefExpr"); - Vars.push_back(cast<DeclRefExpr>(Var)); + Vars.push_back(Var); } OMPThreadPrivateDecl *TD = diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 086acd261d..b117b733a4 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -1644,10 +1644,10 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D, void ASTDeclReader::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { VisitDecl(D); unsigned NumVars = D->varlist_size(); - SmallVector<DeclRefExpr *, 16> Vars; + SmallVector<Expr *, 16> Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) { - Vars.push_back(cast<DeclRefExpr>(Reader.ReadExpr(F))); + Vars.push_back(Reader.ReadExpr(F)); } D->setVars(Vars); } @@ -1783,14 +1783,14 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { //prototyped/non-prototyped functions, etc. if (FunctionDecl *FuncX = dyn_cast<FunctionDecl>(X)) { FunctionDecl *FuncY = cast<FunctionDecl>(Y); - return (FuncX->getLinkage() == FuncY->getLinkage()) && + return (FuncX->getLinkageInternal() == FuncY->getLinkageInternal()) && FuncX->getASTContext().hasSameType(FuncX->getType(), FuncY->getType()); } // Variables with the same type and linkage match. if (VarDecl *VarX = dyn_cast<VarDecl>(X)) { VarDecl *VarY = cast<VarDecl>(Y); - return (VarX->getLinkage() == VarY->getLinkage()) && + return (VarX->getLinkageInternal() == VarY->getLinkageInternal()) && VarX->getASTContext().hasSameType(VarX->getType(), VarY->getType()); } diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 67349db687..7a22afaba7 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -334,7 +334,7 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { Record.push_back(D->hasImplicitReturnZero()); Record.push_back(D->isConstexpr()); Record.push_back(D->HasSkippedBody); - Record.push_back(D->getLinkage()); + Record.push_back(D->getLinkageInternal()); Writer.AddSourceLocation(D->getLocEnd(), Record); Record.push_back(D->getTemplatedKind()); @@ -694,7 +694,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { Record.push_back(D->isCXXForRangeDecl()); Record.push_back(D->isARCPseudoStrong()); Record.push_back(D->isConstexpr()); - Record.push_back(D->getLinkage()); + Record.push_back(D->getLinkageInternal()); if (D->getInit()) { Record.push_back(!D->isInitKnownICE() ? 1 : (D->isInitICE() ? 3 : 2)); diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index 6388a8df64..ba779ff191 100644 --- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp @@ -90,20 +90,49 @@ static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID) { //===----------------------------------------------------------------------===// namespace { - class NilArgChecker : public Checker<check::PreObjCMessage> { + class NilArgChecker : public Checker<check::PreObjCMessage, + check::PostStmt<ObjCDictionaryLiteral>, + check::PostStmt<ObjCArrayLiteral> > { mutable OwningPtr<APIMisuse> BT; - void WarnIfNilArg(CheckerContext &C, - const ObjCMethodCall &msg, unsigned Arg, - FoundationClass Class, - bool CanBeSubscript = false) const; + void warnIfNilExpr(const Expr *E, + const char *Msg, + CheckerContext &C) const; + + void warnIfNilArg(CheckerContext &C, + const ObjCMethodCall &msg, unsigned Arg, + FoundationClass Class, + bool CanBeSubscript = false) const; + + void generateBugReport(ExplodedNode *N, + StringRef Msg, + SourceRange Range, + const Expr *Expr, + CheckerContext &C) const; public: void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; + void checkPostStmt(const ObjCDictionaryLiteral *DL, + CheckerContext &C) const; + void checkPostStmt(const ObjCArrayLiteral *AL, + CheckerContext &C) const; }; } -void NilArgChecker::WarnIfNilArg(CheckerContext &C, +void NilArgChecker::warnIfNilExpr(const Expr *E, + const char *Msg, + CheckerContext &C) const { + ProgramStateRef State = C.getState(); + if (State->isNull(C.getSVal(E)).isConstrainedTrue()) { + + if (ExplodedNode *N = C.generateSink()) { + generateBugReport(N, Msg, E->getSourceRange(), E, C); + } + + } +} + +void NilArgChecker::warnIfNilArg(CheckerContext &C, const ObjCMethodCall &msg, unsigned int Arg, FoundationClass Class, @@ -113,9 +142,6 @@ void NilArgChecker::WarnIfNilArg(CheckerContext &C, if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue()) return; - if (!BT) - BT.reset(new APIMisuse("nil argument")); - if (ExplodedNode *N = C.generateSink()) { SmallString<128> sbuf; llvm::raw_svector_ostream os(sbuf); @@ -149,14 +175,26 @@ void NilArgChecker::WarnIfNilArg(CheckerContext &C, << msg.getSelector().getAsString() << "' cannot be nil"; } } - - BugReport *R = new BugReport(*BT, os.str(), N); - R->addRange(msg.getArgSourceRange(Arg)); - bugreporter::trackNullOrUndefValue(N, msg.getArgExpr(Arg), *R); - C.emitReport(R); + + generateBugReport(N, os.str(), msg.getArgSourceRange(Arg), + msg.getArgExpr(Arg), C); } } +void NilArgChecker::generateBugReport(ExplodedNode *N, + StringRef Msg, + SourceRange Range, + const Expr *E, + CheckerContext &C) const { + if (!BT) + BT.reset(new APIMisuse("nil argument")); + + BugReport *R = new BugReport(*BT, Msg, N); + R->addRange(Range); + bugreporter::trackNullOrUndefValue(N, E, *R); + C.emitReport(R); +} + void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const { const ObjCInterfaceDecl *ID = msg.getReceiverInterface(); @@ -225,28 +263,45 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg, if (S.getNameForSlot(0).equals("dictionaryWithObject") && S.getNameForSlot(1).equals("forKey")) { Arg = 0; - WarnIfNilArg(C, msg, /* Arg */1, Class); + warnIfNilArg(C, msg, /* Arg */1, Class); } else if (S.getNameForSlot(0).equals("setObject") && S.getNameForSlot(1).equals("forKey")) { Arg = 0; - WarnIfNilArg(C, msg, /* Arg */1, Class); + warnIfNilArg(C, msg, /* Arg */1, Class); } else if (S.getNameForSlot(0).equals("setObject") && S.getNameForSlot(1).equals("forKeyedSubscript")) { CanBeSubscript = true; Arg = 0; - WarnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript); + warnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript); } else if (S.getNameForSlot(0).equals("removeObjectForKey")) { Arg = 0; } } - // If argument is '0', report a warning. if ((Arg != InvalidArgIndex)) - WarnIfNilArg(C, msg, Arg, Class, CanBeSubscript); + warnIfNilArg(C, msg, Arg, Class, CanBeSubscript); } +void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL, + CheckerContext &C) const { + unsigned NumOfElements = AL->getNumElements(); + for (unsigned i = 0; i < NumOfElements; ++i) { + warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C); + } +} + +void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL, + CheckerContext &C) const { + unsigned NumOfElements = DL->getNumElements(); + for (unsigned i = 0; i < NumOfElements; ++i) { + ObjCDictionaryElement Element = DL->getKeyValueElement(i); + warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C); + warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C); + } +} + //===----------------------------------------------------------------------===// // Error reporting. //===----------------------------------------------------------------------===// diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 00c92d8153..fe579a3fbf 100644 --- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -1465,9 +1465,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, SmallString<256> Buf; llvm::raw_svector_ostream Out(Buf); - Out << "Assuming '"; - VD->getDeclName().printName(Out); - Out << "' is "; + Out << "Assuming '" << VD->getDeclName() << "' is "; QualType VDTy = VD->getType(); diff --git a/lib/StaticAnalyzer/Core/CheckerContext.cpp b/lib/StaticAnalyzer/Core/CheckerContext.cpp index 74eeef1c67..6b22bf411c 100644 --- a/lib/StaticAnalyzer/Core/CheckerContext.cpp +++ b/lib/StaticAnalyzer/Core/CheckerContext.cpp @@ -68,7 +68,7 @@ bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD, // If this function is not externally visible, it is not a C library function. // Note that we make an exception for inline functions, which may be // declared in header files without external linkage. - if (!FD->isInlined() && FD->getLinkage() != ExternalLinkage) + if (!FD->isInlined() && !FD->isExternallyVisible()) return false; if (Name.empty()) |