diff options
-rw-r--r-- | include/clang/AST/APValue.h | 16 | ||||
-rw-r--r-- | include/clang/Basic/Diagnostic.h | 20 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticASTKinds.td | 4 | ||||
-rw-r--r-- | include/clang/Driver/CC1Options.td | 2 | ||||
-rw-r--r-- | include/clang/Driver/Options.td | 4 | ||||
-rw-r--r-- | include/clang/Frontend/DiagnosticOptions.h | 5 | ||||
-rw-r--r-- | lib/AST/APValue.cpp | 249 | ||||
-rw-r--r-- | lib/AST/ExprConstant.cpp | 124 | ||||
-rw-r--r-- | lib/Basic/Diagnostic.cpp | 1 | ||||
-rw-r--r-- | lib/Driver/Tools.cpp | 5 | ||||
-rw-r--r-- | lib/Frontend/CompilerInvocation.cpp | 9 | ||||
-rw-r--r-- | lib/Frontend/Warnings.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 2 | ||||
-rw-r--r-- | test/CXX/expr/expr.const/p2-0x.cpp | 18 | ||||
-rw-r--r-- | test/SemaCXX/constant-expression-cxx11.cpp | 17 | ||||
-rw-r--r-- | test/SemaCXX/constexpr-backtrace-limit.cpp | 34 | ||||
-rw-r--r-- | test/SemaCXX/constexpr-printing.cpp | 73 | ||||
-rw-r--r-- | unittests/AST/APValueTest.cpp | 83 | ||||
-rw-r--r-- | unittests/AST/Makefile | 15 | ||||
-rw-r--r-- | unittests/CMakeLists.txt | 5 | ||||
-rw-r--r-- | unittests/Makefile | 2 |
21 files changed, 483 insertions, 207 deletions
diff --git a/include/clang/AST/APValue.h b/include/clang/AST/APValue.h index cca00371c2..151956903c 100644 --- a/include/clang/AST/APValue.h +++ b/include/clang/AST/APValue.h @@ -21,6 +21,7 @@ #include "llvm/ADT/PointerUnion.h" namespace clang { + class ASTContext; class CharUnits; class DiagnosticBuilder; class Expr; @@ -28,6 +29,7 @@ namespace clang { class Decl; class ValueDecl; class CXXRecordDecl; + class QualType; /// APValue - This class implements a discriminated union of [uninitialized] /// [APSInt] [APFloat], [Complex APSInt] [Complex APFloat], [Expr + Offset], @@ -171,8 +173,11 @@ public: bool isUnion() const { return Kind == Union; } bool isMemberPointer() const { return Kind == MemberPointer; } - void print(raw_ostream &OS) const; void dump() const; + void dump(raw_ostream &OS) const; + + void printPretty(raw_ostream &OS, ASTContext &Ctx, QualType Ty) const; + std::string getAsString(ASTContext &Ctx, QualType Ty) const; APSInt &getInt() { assert(isInt() && "Invalid accessor"); @@ -394,15 +399,6 @@ private: ArrayRef<const CXXRecordDecl*> Path); }; -inline raw_ostream &operator<<(raw_ostream &OS, const APValue &V) { - V.print(OS); - return OS; -} - -// Writes a concise representation of V to DB, in a single << operation. -const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - const APValue &V); - } // end namespace clang. #endif diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index 6fd81b05ba..e6f30b17dc 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -158,6 +158,8 @@ private: unsigned ErrorLimit; // Cap of # errors emitted, 0 -> no limit. unsigned TemplateBacktraceLimit; // Cap on depth of template backtrace stack, // 0 -> no limit. + unsigned ConstexprBacktraceLimit; // Cap on depth of constexpr evaluation + // backtrace stack, 0 -> no limit. ExtensionHandling ExtBehavior; // Map extensions onto warnings or errors? llvm::IntrusiveRefCntPtr<DiagnosticIDs> Diags; DiagnosticConsumer *Client; @@ -363,13 +365,25 @@ public: void setTemplateBacktraceLimit(unsigned Limit) { TemplateBacktraceLimit = Limit; } - + /// \brief Retrieve the maximum number of template instantiation - /// nodes to emit along with a given diagnostic. + /// notes to emit along with a given diagnostic. unsigned getTemplateBacktraceLimit() const { return TemplateBacktraceLimit; } - + + /// \brief Specify the maximum number of constexpr evaluation + /// notes to emit along with a given diagnostic. + void setConstexprBacktraceLimit(unsigned Limit) { + ConstexprBacktraceLimit = Limit; + } + + /// \brief Retrieve the maximum number of constexpr evaluation + /// notes to emit along with a given diagnostic. + unsigned getConstexprBacktraceLimit() const { + return ConstexprBacktraceLimit; + } + /// setIgnoreAllWarnings - When set to true, any unmapped warnings are /// ignored. If this and WarningsAsErrors are both set, then this one wins. void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; } diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td index e9b3147521..ae6b59ca9d 100644 --- a/include/clang/Basic/DiagnosticASTKinds.td +++ b/include/clang/Basic/DiagnosticASTKinds.td @@ -33,6 +33,10 @@ def note_constexpr_past_end : Note< def note_constexpr_temporary_here : Note<"temporary created here">; def note_constexpr_depth_limit_exceeded : Note< "constexpr evaluation exceeded maximum depth of %0 calls">; +def note_constexpr_calls_suppressed : Note< + "(skipping %0 call%s0 in backtrace; use -fconstexpr-backtrace-limit=0 to " + "see all)">; +def note_constexpr_call_here : Note<"in call to '%0'">; // inline asm related. let CategoryName = "Inline Assembly Issue" in { diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index e8c5398dec..d275af24f2 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -291,6 +291,8 @@ def fmacro_backtrace_limit : Separate<"-fmacro-backtrace-limit">, MetaVarName<"< HelpText<"Set the maximum number of entries to print in a macro expansion backtrace (0 = no limit).">; def ftemplate_backtrace_limit : Separate<"-ftemplate-backtrace-limit">, MetaVarName<"<N>">, HelpText<"Set the maximum number of entries to print in a template instantiation backtrace (0 = no limit).">; +def fconstexpr_backtrace_limit : Separate<"-fconstexpr-backtrace-limit">, MetaVarName<"<N>">, + HelpText<"Set the maximum number of entries to print in a constexpr evaluation backtrace (0 = no limit).">; def fmessage_length : Separate<"-fmessage-length">, MetaVarName<"<N>">, HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">; def fcolor_diagnostics : Flag<"-fcolor-diagnostics">, diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 730a08d3d8..745ee193cd 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -290,6 +290,9 @@ def fcommon : Flag<"-fcommon">, Group<f_Group>; def fcompile_resource_EQ : Joined<"-fcompile-resource=">, Group<f_Group>; def fconstant_cfstrings : Flag<"-fconstant-cfstrings">, Group<f_Group>; def fconstant_string_class_EQ : Joined<"-fconstant-string-class=">, Group<f_Group>; +def fconstexpr_depth_EQ : Joined<"-fconstexpr-depth=">, Group<f_Group>; +def fconstexpr_backtrace_limit_EQ : Joined<"-fconstexpr-backtrace-limit=">, + Group<f_Group>; def fcreate_profile : Flag<"-fcreate-profile">, Group<f_Group>; def fcxx_exceptions: Flag<"-fcxx-exceptions">, Group<f_Group>; def fdebug_pass_arguments : Flag<"-fdebug-pass-arguments">, Group<f_Group>; @@ -490,7 +493,6 @@ def fsyntax_only : Flag<"-fsyntax-only">, Flags<[DriverOption]>; def ftabstop_EQ : Joined<"-ftabstop=">, Group<f_Group>; def ftemplate_depth_EQ : Joined<"-ftemplate-depth=">, Group<f_Group>; def ftemplate_depth_ : Joined<"-ftemplate-depth-">, Group<f_Group>; -def fconstexpr_depth_EQ : Joined<"-fconstexpr-depth=">, Group<f_Group>; def ftemplate_backtrace_limit_EQ : Joined<"-ftemplate-backtrace-limit=">, Group<f_Group>; def ftest_coverage : Flag<"-ftest-coverage">, Group<f_Group>; diff --git a/include/clang/Frontend/DiagnosticOptions.h b/include/clang/Frontend/DiagnosticOptions.h index 8433da4fa4..282ca5d366 100644 --- a/include/clang/Frontend/DiagnosticOptions.h +++ b/include/clang/Frontend/DiagnosticOptions.h @@ -51,12 +51,14 @@ public: unsigned ErrorLimit; /// Limit # errors emitted. unsigned MacroBacktraceLimit; /// Limit depth of macro expansion backtrace. unsigned TemplateBacktraceLimit; /// Limit depth of instantiation backtrace. + unsigned ConstexprBacktraceLimit; /// Limit depth of constexpr backtrace. /// The distance between tab stops. unsigned TabStop; enum { DefaultTabStop = 8, MaxTabStop = 100, DefaultMacroBacktraceLimit = 6, - DefaultTemplateBacktraceLimit = 10 }; + DefaultTemplateBacktraceLimit = 10, + DefaultConstexprBacktraceLimit = 10 }; /// Column limit for formatting message diagnostics, or 0 if unused. unsigned MessageLength; @@ -99,6 +101,7 @@ public: ErrorLimit = 0; TemplateBacktraceLimit = DefaultTemplateBacktraceLimit; MacroBacktraceLimit = DefaultMacroBacktraceLimit; + ConstexprBacktraceLimit = DefaultConstexprBacktraceLimit; } }; diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index b99a66267c..0d4dea82cc 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -12,7 +12,11 @@ //===----------------------------------------------------------------------===// #include "clang/AST/APValue.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" #include "clang/Basic/Diagnostic.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" @@ -203,7 +207,7 @@ void APValue::MakeUninit() { } void APValue::dump() const { - print(llvm::errs()); + dump(llvm::errs()); llvm::errs() << '\n'; } @@ -215,7 +219,7 @@ static double GetApproxValue(const llvm::APFloat &F) { return V.convertToDouble(); } -void APValue::print(raw_ostream &OS) const { +void APValue::dump(raw_ostream &OS) const { switch (getKind()) { case Uninitialized: OS << "Uninitialized"; @@ -227,9 +231,12 @@ void APValue::print(raw_ostream &OS) const { OS << "Float: " << GetApproxValue(getFloat()); return; case Vector: - OS << "Vector: " << getVectorElt(0); - for (unsigned i = 1; i != getVectorLength(); ++i) - OS << ", " << getVectorElt(i); + OS << "Vector: "; + getVectorElt(0).dump(OS); + for (unsigned i = 1; i != getVectorLength(); ++i) { + OS << ", "; + getVectorElt(i).dump(OS); + } return; case ComplexInt: OS << "ComplexInt: " << getComplexIntReal() << ", " << getComplexIntImag(); @@ -244,28 +251,36 @@ void APValue::print(raw_ostream &OS) const { case Array: OS << "Array: "; for (unsigned I = 0, N = getArrayInitializedElts(); I != N; ++I) { - OS << getArrayInitializedElt(I); + getArrayInitializedElt(I).dump(OS); if (I != getArraySize() - 1) OS << ", "; } - if (hasArrayFiller()) - OS << getArraySize() - getArrayInitializedElts() << " x " - << getArrayFiller(); + if (hasArrayFiller()) { + OS << getArraySize() - getArrayInitializedElts() << " x "; + getArrayFiller().dump(OS); + } return; case Struct: OS << "Struct "; if (unsigned N = getStructNumBases()) { - OS << " bases: " << getStructBase(0); - for (unsigned I = 1; I != N; ++I) - OS << ", " << getStructBase(I); + OS << " bases: "; + getStructBase(0).dump(OS); + for (unsigned I = 1; I != N; ++I) { + OS << ", "; + getStructBase(I).dump(OS); + } } if (unsigned N = getStructNumFields()) { - OS << " fields: " << getStructField(0); - for (unsigned I = 1; I != N; ++I) - OS << ", " << getStructField(I); + OS << " fields: "; + getStructField(0).dump(OS); + for (unsigned I = 1; I != N; ++I) { + OS << ", "; + getStructField(I).dump(OS); + } } return; case Union: - OS << "Union: " << getUnionValue(); + OS << "Union: "; + getUnionValue().dump(OS); return; case MemberPointer: OS << "MemberPointer: <todo>"; @@ -274,78 +289,198 @@ void APValue::print(raw_ostream &OS) const { llvm_unreachable("Unknown APValue kind!"); } -static void WriteShortAPValueToStream(raw_ostream& Out, - const APValue& V) { - switch (V.getKind()) { +void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ + switch (getKind()) { case APValue::Uninitialized: - Out << "Uninitialized"; + Out << "<uninitialized>"; return; case APValue::Int: - Out << V.getInt(); + Out << getInt(); return; case APValue::Float: - Out << GetApproxValue(V.getFloat()); + Out << GetApproxValue(getFloat()); return; - case APValue::Vector: - Out << '['; - WriteShortAPValueToStream(Out, V.getVectorElt(0)); - for (unsigned i = 1; i != V.getVectorLength(); ++i) { + case APValue::Vector: { + Out << '{'; + QualType ElemTy = Ty->getAs<VectorType>()->getElementType(); + getVectorElt(0).printPretty(Out, Ctx, ElemTy); + for (unsigned i = 1; i != getVectorLength(); ++i) { Out << ", "; - WriteShortAPValueToStream(Out, V.getVectorElt(i)); + getVectorElt(i).printPretty(Out, Ctx, ElemTy); } - Out << ']'; + Out << '}'; return; + } case APValue::ComplexInt: - Out << V.getComplexIntReal() << "+" << V.getComplexIntImag() << "i"; + Out << getComplexIntReal() << "+" << getComplexIntImag() << "i"; return; case APValue::ComplexFloat: - Out << GetApproxValue(V.getComplexFloatReal()) << "+" - << GetApproxValue(V.getComplexFloatImag()) << "i"; + Out << GetApproxValue(getComplexFloatReal()) << "+" + << GetApproxValue(getComplexFloatImag()) << "i"; return; - case APValue::LValue: - Out << "LValue: <todo>"; + case APValue::LValue: { + LValueBase Base = getLValueBase(); + if (!Base) { + Out << "0"; + return; + } + + bool IsReference = Ty->isReferenceType(); + QualType InnerTy + = IsReference ? Ty.getNonReferenceType() : Ty->getPointeeType(); + + if (!hasLValuePath()) { + // No lvalue path: just print the offset. + CharUnits O = getLValueOffset(); + CharUnits S = Ctx.getTypeSizeInChars(InnerTy); + if (!O.isZero()) { + if (IsReference) + Out << "*("; + if (O % S) { + Out << "(char*)"; + S = CharUnits::One(); + } + Out << '&'; + } else if (!IsReference) + Out << '&'; + + if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) + Out << *VD; + else + Base.get<const Expr*>()->printPretty(Out, Ctx, 0, + Ctx.getPrintingPolicy()); + if (!O.isZero()) { + Out << " + " << (O / S); + if (IsReference) + Out << ')'; + } + return; + } + + // We have an lvalue path. Print it out nicely. + if (!IsReference) + Out << '&'; + else if (isLValueOnePastTheEnd()) + Out << "*(&"; + + QualType ElemTy; + if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) { + Out << *VD; + ElemTy = VD->getType(); + } else { + const Expr *E = Base.get<const Expr*>(); + E->printPretty(Out, Ctx, 0,Ctx.getPrintingPolicy()); + ElemTy = E->getType(); + } + + ArrayRef<LValuePathEntry> Path = getLValuePath(); + const CXXRecordDecl *CastToBase = 0; + for (unsigned I = 0, N = Path.size(); I != N; ++I) { + if (ElemTy->getAs<RecordType>()) { + // The lvalue refers to a class type, so the next path entry is a base + // or member. + const Decl *BaseOrMember = + BaseOrMemberType::getFromOpaqueValue(Path[I].BaseOrMember).getPointer(); + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) { + CastToBase = RD; + ElemTy = Ctx.getRecordType(RD); + } else { + const ValueDecl *VD = cast<ValueDecl>(BaseOrMember); + Out << "."; + if (CastToBase) + Out << *CastToBase << "::"; + Out << *VD; + ElemTy = VD->getType(); + } + } else { + // The lvalue must refer to an array. + Out << '[' << Path[I].ArrayIndex << ']'; + ElemTy = Ctx.getAsArrayType(ElemTy)->getElementType(); + } + } + + // Handle formatting of one-past-the-end lvalues. + if (isLValueOnePastTheEnd()) { + // FIXME: If CastToBase is non-0, we should prefix the output with + // "(CastToBase*)". + Out << " + 1"; + if (IsReference) + Out << ')'; + } return; - case APValue::Array: + } + case APValue::Array: { + const ArrayType *AT = Ctx.getAsArrayType(Ty); + QualType ElemTy = AT->getElementType(); Out << '{'; - if (unsigned N = V.getArrayInitializedElts()) { - Out << V.getArrayInitializedElt(0); - for (unsigned I = 1; I != N; ++I) - Out << ", " << V.getArrayInitializedElt(I); + if (unsigned N = getArrayInitializedElts()) { + getArrayInitializedElt(0).printPretty(Out, Ctx, ElemTy); + for (unsigned I = 1; I != N; ++I) { + Out << ", "; + if (I == 10) { + // Avoid printing out the entire contents of large arrays. + Out << "..."; + break; + } + getArrayInitializedElt(I).printPretty(Out, Ctx, ElemTy); + } } Out << '}'; return; - case APValue::Struct: + } + case APValue::Struct: { Out << '{'; - if (unsigned N = V.getStructNumBases()) { - Out << V.getStructBase(0); - for (unsigned I = 1; I != N; ++I) - Out << ", " << V.getStructBase(I); - if (V.getStructNumFields()) - Out << ", "; + const RecordDecl *RD = Ty->getAs<RecordType>()->getDecl(); + bool First = true; + if (unsigned N = getStructNumBases()) { + const CXXRecordDecl *CD = cast<CXXRecordDecl>(RD); + CXXRecordDecl::base_class_const_iterator BI = CD->bases_begin(); + for (unsigned I = 0; I != N; ++I, ++BI) { + assert(BI != CD->bases_end()); + if (!First) + Out << ", "; + getStructBase(I).printPretty(Out, Ctx, BI->getType()); + First = false; + } } - if (unsigned N = V.getStructNumFields()) { - Out << V.getStructField(0); - for (unsigned I = 1; I != N; ++I) - Out << ", " << V.getStructField(I); + for (RecordDecl::field_iterator FI = RD->field_begin(); + FI != RD->field_end(); ++FI) { + if (!First) + Out << ", "; + if ((*FI)->isUnnamedBitfield()) continue; + getStructField((*FI)->getFieldIndex()). + printPretty(Out, Ctx, (*FI)->getType()); + First = false; } Out << '}'; return; + } case APValue::Union: - Out << '{' << V.getUnionValue() << '}'; + Out << '{'; + if (const FieldDecl *FD = getUnionField()) { + Out << "." << *FD << " = "; + getUnionValue().printPretty(Out, Ctx, FD->getType()); + } + Out << '}'; return; case APValue::MemberPointer: - Out << "MemberPointer: <todo>"; + // FIXME: This is not enough to unambiguously identify the member in a + // multiple-inheritance scenario. + if (const ValueDecl *VD = getMemberPointerDecl()) { + Out << '&' << *cast<CXXRecordDecl>(VD->getDeclContext()) << "::" << *VD; + return; + } + Out << "0"; return; } llvm_unreachable("Unknown APValue kind!"); } -const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, - const APValue &V) { - llvm::SmallString<64> Buffer; - llvm::raw_svector_ostream Out(Buffer); - WriteShortAPValueToStream(Out, V); - return DB << Out.str(); +std::string APValue::getAsString(ASTContext &Ctx, QualType Ty) const { + std::string Result; + llvm::raw_string_ostream Out(Result); + printPretty(Out, Ctx, Ty); + return Result; } const APValue::LValueBase APValue::getLValueBase() const { diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index dd1110ab11..31b211eff6 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -231,6 +231,12 @@ namespace { /// Parent - The caller of this stack frame. CallStackFrame *Caller; + /// CallLoc - The location of the call expression for this call. + SourceLocation CallLoc; + + /// Callee - The function which was called. + const FunctionDecl *Callee; + /// This - The binding for the this pointer in this call, if any. const LValue *This; @@ -243,7 +249,8 @@ namespace { /// Temporaries - Temporary lvalues materialized within this stack frame. MapTy Temporaries; - CallStackFrame(EvalInfo &Info, const LValue *This, + CallStackFrame(EvalInfo &Info, SourceLocation CallLoc, + const FunctionDecl *Callee, const LValue *This, const CCValue *Arguments); ~CallStackFrame(); }; @@ -300,8 +307,8 @@ namespace { EvalInfo(const ASTContext &C, Expr::EvalStatus &S) : Ctx(const_cast<ASTContext&>(C)), EvalStatus(S), CurrentCall(0), - CallStackDepth(0), BottomFrame(*this, 0, 0), EvaluatingDecl(0), - EvaluatingDeclValue(0), HasActiveDiagnostic(false) {} + CallStackDepth(0), BottomFrame(*this, SourceLocation(), 0, 0, 0), + EvaluatingDecl(0), EvaluatingDeclValue(0), HasActiveDiagnostic(false) {} const CCValue *getOpaqueValue(const OpaqueValueExpr *e) const { MapTy::const_iterator i = OpaqueValues.find(e); @@ -332,6 +339,9 @@ namespace { return EvalStatus.Diag->back().second; } + /// Add notes containing a call stack to the current point of evaluation. + void addCallStack(unsigned Limit); + public: /// Diagnose that the evaluation cannot be folded. OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId, @@ -340,11 +350,17 @@ namespace { // isn't a constant expression. This diagnostic is more important. // FIXME: We might want to show both diagnostics to the user. if (EvalStatus.Diag) { + unsigned CallStackNotes = CallStackDepth - 1; + unsigned Limit = Ctx.getDiagnostics().getConstexprBacktraceLimit(); + if (Limit) + CallStackNotes = std::min(CallStackNotes, Limit + 1); + HasActiveDiagnostic = true; EvalStatus.Diag->clear(); - EvalStatus.Diag->reserve(1 + ExtraNotes); - // FIXME: Add a call stack for constexpr evaluation. - return OptionalDiagnostic(&addDiag(Loc, DiagId)); + EvalStatus.Diag->reserve(1 + ExtraNotes + CallStackNotes); + addDiag(Loc, DiagId); + addCallStack(Limit); + return OptionalDiagnostic(&(*EvalStatus.Diag)[0].second); } HasActiveDiagnostic = false; return OptionalDiagnostic(); @@ -367,20 +383,87 @@ namespace { return OptionalDiagnostic(&addDiag(Loc, DiagId)); } }; +} + +CallStackFrame::CallStackFrame(EvalInfo &Info, SourceLocation CallLoc, + const FunctionDecl *Callee, const LValue *This, + const CCValue *Arguments) + : Info(Info), Caller(Info.CurrentCall), CallLoc(CallLoc), Callee(Callee), + This(This), Arguments(Arguments) { + Info.CurrentCall = this; + ++Info.CallStackDepth; +} + +CallStackFrame::~CallStackFrame() { + assert(Info.CurrentCall == this && "calls retired out of order"); + --Info.CallStackDepth; + Info.CurrentCall = Caller; +} + +/// Produce a string describing the given constexpr call. +static void describeCall(CallStackFrame *Frame, llvm::raw_ostream &Out) { + unsigned ArgIndex = 0; + bool IsMemberCall = isa<CXXMethodDecl>(Frame->Callee) && + !isa<CXXConstructorDecl>(Frame->Callee); + + if (!IsMemberCall) + Out << *Frame->Callee << '('; + + for (FunctionDecl::param_const_iterator I = Frame->Callee->param_begin(), + E = Frame->Callee->param_end(); I != E; ++I, ++ArgIndex) { + if (ArgIndex > IsMemberCall) + Out << ", "; - CallStackFrame::CallStackFrame(EvalInfo &Info, const LValue *This, - const CCValue *Arguments) - : Info(Info), Caller(Info.CurrentCall), This(This), Arguments(Arguments) { - Info.CurrentCall = this; - ++Info.CallStackDepth; + const ParmVarDecl *Param = *I; + const CCValue &Arg = Frame->Arguments[ArgIndex]; + if (!Arg.isLValue() || Arg.getLValueDesignator().Invalid) + Arg.printPretty(Out, Frame->Info.Ctx, Param->getType()); + else { + // Deliberately slice off the frame to form an APValue we can print. + APValue Value(Arg.getLValueBase(), Arg.getLValueOffset(), + Arg.getLValueDesignator().Entries, + Arg.getLValueDesignator().OnePastTheEnd); + Value.printPretty(Out, Frame->Info.Ctx, Param->getType()); + } + + if (ArgIndex == 0 && IsMemberCall) + Out << "->" << *Frame->Callee << '('; } - CallStackFrame::~CallStackFrame() { - assert(Info.CurrentCall == this && "calls retired out of order"); - --Info.CallStackDepth; - Info.CurrentCall = Caller; + Out << ')'; +} + +void EvalInfo::addCallStack(unsigned Limit) { + // Determine which calls to skip, if any. + unsigned ActiveCalls = CallStackDepth - 1; + unsigned SkipStart = ActiveCalls, SkipEnd = SkipStart; + if (Limit && Limit < ActiveCalls) { + SkipStart = Limit / 2 + Limit % 2; + SkipEnd = ActiveCalls - Limit / 2; + } + + // Walk the call stack and add the diagnostics. + unsigned CallIdx = 0; + for (CallStackFrame *Frame = CurrentCall; Frame != &BottomFrame; + Frame = Frame->Caller, ++CallIdx) { + // Skip this call? + if (CallIdx >= SkipStart && CallIdx < SkipEnd) { + if (CallIdx == SkipStart) { + // Note that we're skipping calls. + addDiag(Frame->CallLoc, diag::note_constexpr_calls_suppressed) + << unsigned(ActiveCalls - Limit); + } + continue; + } + + llvm::SmallVector<char, 128> Buffer; + llvm::raw_svector_ostream Out(Buffer); + describeCall(Frame, Out); + addDiag(Frame->CallLoc, diag::note_constexpr_call_here) << Out.str(); } +} +namespace { struct ComplexValue { private: bool IsInt; @@ -1465,7 +1548,8 @@ static bool EvaluateArgs(ArrayRef<const Expr*> Args, ArgVector &ArgValues, } /// Evaluate a function call. -static bool HandleFunctionCall(const Expr *CallExpr, const LValue *This, +static bool HandleFunctionCall(const Expr *CallExpr, const FunctionDecl *Callee, + const LValue *This, ArrayRef<const Expr*> Args, const Stmt *Body, EvalInfo &Info, APValue &Result) { if (!Info.CheckCallLimit(CallExpr->getExprLoc())) @@ -1475,7 +1559,8 @@ static bool HandleFunctionCall(const Expr *CallExpr, const LValue *This, if (!EvaluateArgs(Args, ArgValues, Info)) return false; - CallStackFrame Frame(Info, This, ArgValues.data()); + CallStackFrame Frame(Info, CallExpr->getExprLoc(), Callee, This, + ArgValues.data()); return EvaluateStmt(Result, Info, Body) == ESR_Returned; } @@ -1492,7 +1577,8 @@ static bool HandleConstructorCall(const Expr *CallExpr, const LValue &This, if (!EvaluateArgs(Args, ArgValues, Info)) return false; - CallStackFrame Frame(Info, &This, ArgValues.data()); + CallStackFrame Frame(Info, CallExpr->getExprLoc(), Definition, + &This, ArgValues.data()); // If it's a delegating constructor, just delegate. if (Definition->isDelegatingConstructor()) { @@ -1855,7 +1941,7 @@ public: APValue Result; if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition) || - !HandleFunctionCall(E, This, Args, Body, Info, Result)) + !HandleFunctionCall(E, Definition, This, Args, Body, Info, Result)) return false; return DerivedSuccess(CCValue(Result, CCValue::GlobalValue()), E); diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 7ea296233a..1643572159 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -53,6 +53,7 @@ DiagnosticsEngine::DiagnosticsEngine( ErrorLimit = 0; TemplateBacktraceLimit = 0; + ConstexprBacktraceLimit = 0; Reset(); } diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 60e6d3dd32..798d787c65 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -1808,6 +1808,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue(Args)); } + if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_backtrace_limit_EQ)) { + CmdArgs.push_back("-fconstexpr-backtrace-limit"); + CmdArgs.push_back(A->getValue(Args)); + } + // Pass -fmessage-length=. CmdArgs.push_back("-fmessage-length"); if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) { diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 797147e5af..3ad555bfe8 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -354,6 +354,11 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts, Res.push_back("-ftemplate-backtrace-limit"); Res.push_back(llvm::utostr(Opts.TemplateBacktraceLimit)); } + if (Opts.ConstexprBacktraceLimit + != DiagnosticOptions::DefaultConstexprBacktraceLimit) { + Res.push_back("-fconstexpr-backtrace-limit"); + Res.push_back(llvm::utostr(Opts.ConstexprBacktraceLimit)); + } if (Opts.TabStop != DiagnosticOptions::DefaultTabStop) { Res.push_back("-ftabstop"); @@ -1229,6 +1234,10 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, = Args.getLastArgIntValue(OPT_ftemplate_backtrace_limit, DiagnosticOptions::DefaultTemplateBacktraceLimit, Diags); + Opts.ConstexprBacktraceLimit + = Args.getLastArgIntValue(OPT_fconstexpr_backtrace_limit, + DiagnosticOptions::DefaultConstexprBacktraceLimit, + Diags); Opts.TabStop = Args.getLastArgIntValue(OPT_ftabstop, DiagnosticOptions::DefaultTabStop, Diags); if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) { diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp index e63bc21cb4..6f441112f3 100644 --- a/lib/Frontend/Warnings.cpp +++ b/lib/Frontend/Warnings.cpp @@ -58,6 +58,8 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags, Diags.setErrorLimit(Opts.ErrorLimit); if (Opts.TemplateBacktraceLimit) Diags.setTemplateBacktraceLimit(Opts.TemplateBacktraceLimit); + if (Opts.ConstexprBacktraceLimit) + Diags.setConstexprBacktraceLimit(Opts.ConstexprBacktraceLimit); // If -pedantic or -pedantic-errors was specified, then we want to map all // extension diagnostics onto WARNING or ERROR unless the user has futz'd diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index a95a257131..7dbf830431 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -5707,7 +5707,7 @@ static void DiagnoseNarrowingInInitList( ? diag::err_init_list_constant_narrowing : diag::warn_init_list_constant_narrowing) << InitE->getSourceRange() - << ConstantValue + << ConstantValue.getAsString(S.getASTContext(), EntityType) << EntityType.getLocalUnqualifiedType(); } else S.Diag(InitE->getLocStart(), diff --git a/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp index 2e5e7f2ca4..0e6d69dd12 100644 --- a/test/CXX/expr/expr.const/p2-0x.cpp +++ b/test/CXX/expr/expr.const/p2-0x.cpp @@ -56,7 +56,7 @@ namespace NonConstExprReturn { return n; // expected-note {{reference to temporary cannot be returned from a constexpr function}} } struct NonConstExprFunction { - int n : id_ref( // expected-error {{constant expression}} + int n : id_ref( // expected-error {{constant expression}} expected-note {{in call to 'id_ref(16)'}} 16 // expected-note {{temporary created here}} ); }; @@ -64,10 +64,10 @@ namespace NonConstExprReturn { return &a; // expected-note {{pointer to 'n' cannot be returned from a constexpr function}} } constexpr const int *return_param(int n) { // expected-note {{declared here}} - return address_of(n); + return address_of(n); // expected-note {{in call to 'address_of(n)'}} } struct S { - int n : *return_param(0); // expected-error {{constant expression}} + int n : *return_param(0); // expected-error {{constant expression}} expected-note {{in call to 'return_param(0)'}} }; } @@ -87,7 +87,7 @@ namespace NonConstExprCtor { constexpr T t2(0); // expected-error {{must be initialized by a constant expression}} struct S { - int n : T(4).r; // expected-error {{constant expression}} expected-note {{temporary created here}} + int n : T(4).r; // expected-error {{constant expression}} expected-note {{temporary created here}} expected-note {{in call to 'T(4)'}} }; } @@ -95,17 +95,17 @@ namespace NonConstExprCtor { // exceed the implementation-defined recursion limits (see Annex B); namespace RecursionLimits { constexpr int RecurseForever(int n) { - return n + RecurseForever(n+1); // expected-note {{constexpr evaluation exceeded maximum depth of 256 calls}} + return n + RecurseForever(n+1); // expected-note {{constexpr evaluation exceeded maximum depth of 256 calls}} expected-note 9{{in call to 'RecurseForever(}} expected-note {{skipping 246 calls}} } struct AlsoRecurseForever { constexpr AlsoRecurseForever(int n) : - n(AlsoRecurseForever(n+1).n) // expected-note {{constexpr evaluation exceeded maximum depth of 256 calls}} + n(AlsoRecurseForever(n+1).n) // expected-note {{constexpr evaluation exceeded maximum depth of 256 calls}} expected-note 9{{in call to 'AlsoRecurseForever(}} expected-note {{skipping 246 calls}} {} int n; }; struct S { - int k : RecurseForever(0); // expected-error {{constant expression}} - int l : AlsoRecurseForever(0).n; // expected-error {{constant expression}} + int k : RecurseForever(0); // expected-error {{constant expression}} expected-note {{in call to}} + int l : AlsoRecurseForever(0).n; // expected-error {{constant expression}} expected-note {{in call to}} }; } @@ -135,7 +135,7 @@ namespace UndefinedBehavior { return q[0]; // expected-note {{dereferenced pointer past the end of subobject of 's' is not a constant expression}} } struct T { - int n : f(p); // expected-error {{not an integer constant expression}} + int n : f(p); // expected-error {{not an integer constant expression}} expected-note {{in call to 'f(&s.m + 1)'}} }; } diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index 4b59157ea6..5105418af1 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -416,7 +416,11 @@ constexpr int ZipFoldR(int (*F)(int x, int y, int c), int n, const int *xs, const int *ys, int c) { return n ? F( *xs, // expected-note {{subexpression not valid}} - *ys, ZipFoldR(F, n-1, xs+1, ys+1, c)) : c; + *ys, + ZipFoldR(F, n-1, xs+1, ys+1, c)) // \ + expected-note {{in call to 'ZipFoldR(&SubMul, 2, &xs[4], &ys[4], 1)'}} \ + expected-note {{in call to 'ZipFoldR(&SubMul, 1, &xs[5], &ys[5], 1)'}} + : c; } constexpr int MulAdd(int x, int y, int c) { return x * y + c; } constexpr int InnerProduct = ZipFoldR(MulAdd, 5, xs, ys, 0); @@ -425,7 +429,9 @@ static_assert(InnerProduct == 35, ""); constexpr int SubMul(int x, int y, int c) { return (x - y) * c; } constexpr int DiffProd = ZipFoldR(SubMul, 2, xs+3, ys+3, 1); static_assert(DiffProd == 8, ""); -static_assert(ZipFoldR(SubMul, 3, xs+3, ys+3, 1), ""); // expected-error {{constant expression}} +static_assert(ZipFoldR(SubMul, 3, xs+3, ys+3, 1), ""); // \ + expected-error {{constant expression}} \ + expected-note {{in call to 'ZipFoldR(&SubMul, 3, &xs[3], &ys[3], 1)'}} constexpr const int *p = xs + 3; constexpr int xs4 = p[1]; // ok @@ -441,6 +447,13 @@ static_assert((&zs[0][0][0][2])[-1] == 2, ""); static_assert(**(**(zs + 1) + 1) == 11, ""); static_assert(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][-1] + 1) == 11, ""); +constexpr int fail(const int &p) { + return (&p)[64]; // expected-note {{subexpression}} +} +static_assert(fail(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][-1] + 1)) == 11, ""); // \ +expected-error {{static_assert expression is not an integral constant expression}} \ +expected-note {{in call to 'fail(zs[1][0][1][0])'}} + constexpr int arr[40] = { 1, 2, 3, [8] = 4 }; // expected-warning {{extension}} constexpr int SumNonzero(const int *p) { return *p + (*p ? SumNonzero(p+1) : 0); diff --git a/test/SemaCXX/constexpr-backtrace-limit.cpp b/test/SemaCXX/constexpr-backtrace-limit.cpp new file mode 100644 index 0000000000..d2923abf20 --- /dev/null +++ b/test/SemaCXX/constexpr-backtrace-limit.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit 0 -fconstexpr-depth 4 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST1 +// TEST1: constant expression +// TEST1-NEXT: exceeded maximum depth of 4 +// TEST1-NEXT: in call to 'recurse(2)' +// TEST1-NEXT: in call to 'recurse(3)' +// TEST1-NEXT: in call to 'recurse(4)' +// TEST1-NEXT: in call to 'recurse(5)' + +// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit 2 -fconstexpr-depth 4 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST2 +// TEST2: constant expression +// TEST2-NEXT: exceeded maximum depth of 4 +// TEST2-NEXT: in call to 'recurse(2)' +// TEST2-NEXT: skipping 2 calls +// TEST2-NEXT: in call to 'recurse(5)' + +// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit 2 -fconstexpr-depth 8 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST3 +// TEST3: constant expression +// TEST3-NEXT: subexpression +// TEST3-NEXT: in call to 'recurse(0)' +// TEST3-NEXT: skipping 4 calls +// TEST3-NEXT: in call to 'recurse(5)' + +// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit 8 -fconstexpr-depth 8 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST4 +// TEST4: constant expression +// TEST4-NEXT: subexpression +// TEST4-NEXT: in call to 'recurse(0)' +// TEST4-NEXT: in call to 'recurse(1)' +// TEST4-NEXT: in call to 'recurse(2)' +// TEST4-NEXT: in call to 'recurse(3)' +// TEST4-NEXT: in call to 'recurse(4)' +// TEST4-NEXT: in call to 'recurse(5)' + +constexpr int recurse(int n) { return n ? recurse(n-1) : *(int*)n; } +static_assert(recurse(5), ""); diff --git a/test/SemaCXX/constexpr-printing.cpp b/test/SemaCXX/constexpr-printing.cpp new file mode 100644 index 0000000000..341495ccec --- /dev/null +++ b/test/SemaCXX/constexpr-printing.cpp @@ -0,0 +1,73 @@ +// RUN: %clang_cc1 %s -std=c++11 -fsyntax-only -verify + +constexpr int extract(struct S &s); + +struct S { + constexpr S() : n(extract(*this)), m(0) {} + constexpr S(int k) : n(k), m(extract(*this)) {} + int n, m; +}; + +constexpr int extract(S &s) { return s.n; } + +// FIXME: once we produce notes for constexpr variable declarations, this should +// produce a note indicating that S.n is used uninitialized. +constexpr S s1; // expected-error {{constant expression}} +constexpr S s2(10); + +typedef __attribute__((vector_size(16))) int vector_int; + +struct T { + constexpr T() : arr() {} + int arr[4]; +}; +struct U : T { + constexpr U(const int *p) : T(), another(), p(p) {} + constexpr U(const U &u) : T(), another(), p(u.p) {} + T another; + const int *p; +}; +constexpr U u1(&u1.arr[2]); + +constexpr int test_printing(int a, float b, _Complex int c, _Complex float d, + int *e, int &f, vector_int g, U h) { + return *e; // expected-note {{subexpression}} +} +U u2(0); +static_assert(test_printing(12, 39.762, 3 + 4i, 12.9 + 3.6i, &u2.arr[4], u2.another.arr[2], (vector_int){5, 1, 2, 3}, u1) == 0, ""); // \ +expected-error {{constant expression}} \ +expected-note {{in call to 'test_printing(12, 3.976200e+01, 3+4i, 1.290000e+01+3.600000e+00i, &u2.T::arr[4], u2.another.arr[2], {5, 1, 2, 3}, {{{}}, {{}}, &u1.T::arr[2]})'}} + +struct V { + // FIXME: when we can generate these as constexpr constructors, remove the + // explicit definitions. + constexpr V() : arr{[255] = 42} {} + constexpr V(const V &v) : arr{[255] = 42} {} + int arr[256]; +}; +constexpr V v; +constexpr int get(const int *p) { return *p; } // expected-note {{subexpression}} +constexpr int passLargeArray(V v) { return get(v.arr+256); } // expected-note {{in call to 'get(&v.arr[256])'}} +static_assert(passLargeArray(v) == 0, ""); // expected-error {{constant expression}} expected-note {{in call to 'passLargeArray({{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...}})'}} + +union Union { + constexpr Union(int n) : b(n) {} + constexpr Union(const Union &u) : b(u.b) {} + int a, b; +}; +constexpr Union myUnion = 76; + +constexpr int badness(Union u) { return u.a + u.b; } // expected-note {{subexpression}} +static_assert(badness(myUnion), ""); // expected-error {{constant expression}} \ + expected-note {{in call to 'badness({.b = 76})'}} + +struct MemPtrTest { + int n; + void f(); +}; +MemPtrTest mpt; +constexpr int MemPtr(int (MemPtrTest::*a), void (MemPtrTest::*b)(), int &c) { + return c; // expected-note {{subexpression}} +} +static_assert(MemPtr(&MemPtrTest::n, &MemPtrTest::f, mpt.*&MemPtrTest::n), ""); // expected-error {{constant expression}} \ +expected-note {{in call to 'MemPtr(&MemPtrTest::n, &MemPtrTest::f, mpt.n)'}} diff --git a/unittests/AST/APValueTest.cpp b/unittests/AST/APValueTest.cpp deleted file mode 100644 index 5ac454de5f..0000000000 --- a/unittests/AST/APValueTest.cpp +++ /dev/null @@ -1,83 +0,0 @@ -//===- unittests/AST/APValueTest.cpp - APValue tests ---===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/APValue.h" - -#include "clang/Basic/Diagnostic.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallString.h" - -#include "gtest/gtest.h" - -using namespace llvm; -using namespace clang; - -namespace { - -class DiagnosticOutputGetter { - class LastDiagnosticString : public DiagnosticConsumer { - SmallString<64> LastDiagnostic; - public: - virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, - const Diagnostic &Info) { - LastDiagnostic.clear(); - Info.FormatDiagnostic(LastDiagnostic); - } - - StringRef get() const { return LastDiagnostic; } - - virtual DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { - return new LastDiagnosticString(); - } - }; - - const IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs; - const unsigned diag_just_format; - LastDiagnosticString LastDiagnostic; - DiagnosticsEngine Diag; - -public: - DiagnosticOutputGetter() - : DiagIDs(new DiagnosticIDs), - diag_just_format(DiagIDs->getCustomDiagID(DiagnosticIDs::Error, "%0")), - Diag(DiagIDs, &LastDiagnostic, false) { - } - - template<typename T> - std::string operator()(const T& value) { - Diag.Report(diag_just_format) << value; - return LastDiagnostic.get().str(); - } -}; - -TEST(APValue, Diagnostics) { - DiagnosticOutputGetter GetDiagnosticOutput; - - EXPECT_EQ("Uninitialized", GetDiagnosticOutput(APValue())); - EXPECT_EQ("5", GetDiagnosticOutput(APValue(APSInt(APInt(16, 5))))); - EXPECT_EQ("3.141590e+00", - GetDiagnosticOutput(APValue(APFloat(APFloat::IEEEdouble, - "3.14159")))); - EXPECT_EQ("3+4i", - GetDiagnosticOutput(APValue(APSInt(APInt(16, 3)), - APSInt(APInt(16, 4))))); - EXPECT_EQ("3.200000e+00+5.700000e+00i", - GetDiagnosticOutput(APValue( - APFloat(APFloat::IEEEdouble, "3.2"), - APFloat(APFloat::IEEEdouble, "5.7")))); - APValue V[] = { - APValue(APSInt(APInt(16, 3))), - APValue(APSInt(APInt(16, 4))), - APValue(APSInt(APInt(16, 5))) - }; - EXPECT_EQ("[3, 4, 5]", - GetDiagnosticOutput(APValue(V, array_lengthof(V)))); -} - -} // anonymous namespace diff --git a/unittests/AST/Makefile b/unittests/AST/Makefile deleted file mode 100644 index 74191d037f..0000000000 --- a/unittests/AST/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -##===- unittests/Frontend/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 = ../.. -TESTNAME = AST -LINK_COMPONENTS := support mc -USEDLIBS = clangAST.a clangBasic.a - -include $(CLANG_LEVEL)/unittests/Makefile diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index 901f167f35..cb44dc59dc 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -50,11 +50,6 @@ if(SUPPORTS_NO_VARIADIC_MACROS_FLAG) add_definitions("-Wno-variadic-macros") endif() -add_clang_unittest(AST - AST/APValueTest.cpp - USED_LIBS gtest gtest_main clangAST - ) - add_clang_unittest(Basic Basic/FileManagerTest.cpp USED_LIBS gtest gtest_main clangBasic diff --git a/unittests/Makefile b/unittests/Makefile index f4ce6adaa7..951e17e217 100644 --- a/unittests/Makefile +++ b/unittests/Makefile @@ -14,7 +14,7 @@ ifndef CLANG_LEVEL IS_UNITTEST_LEVEL := 1 CLANG_LEVEL := .. -PARALLEL_DIRS = AST Basic Frontend +PARALLEL_DIRS = Basic Frontend endif # CLANG_LEVEL |