diff options
-rw-r--r-- | include/clang/AST/ASTDiagnostic.h | 2 | ||||
-rw-r--r-- | include/clang/Analysis/AnalysisDiagnostic.h | 2 | ||||
-rw-r--r-- | include/clang/Basic/Diagnostic.h | 55 | ||||
-rw-r--r-- | include/clang/Basic/Diagnostic.td | 3 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 13 | ||||
-rw-r--r-- | include/clang/Driver/DriverDiagnostic.h | 2 | ||||
-rw-r--r-- | include/clang/Frontend/FrontendDiagnostic.h | 2 | ||||
-rw-r--r-- | include/clang/Lex/LexDiagnostic.h | 2 | ||||
-rw-r--r-- | include/clang/Parse/ParseDiagnostic.h | 2 | ||||
-rw-r--r-- | include/clang/Sema/SemaDiagnostic.h | 2 | ||||
-rw-r--r-- | lib/Basic/Diagnostic.cpp | 25 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 18 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 28 | ||||
-rw-r--r-- | test/SemaTemplate/temp_class_spec.cpp | 5 | ||||
-rw-r--r-- | www/cxx_status.html | 8 |
16 files changed, 133 insertions, 39 deletions
diff --git a/include/clang/AST/ASTDiagnostic.h b/include/clang/AST/ASTDiagnostic.h index 244ca9e10f..e9f150574b 100644 --- a/include/clang/AST/ASTDiagnostic.h +++ b/include/clang/AST/ASTDiagnostic.h @@ -15,7 +15,7 @@ namespace clang { namespace diag { enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM, #define ASTSTART #include "clang/Basic/DiagnosticASTKinds.inc" #undef DIAG diff --git a/include/clang/Analysis/AnalysisDiagnostic.h b/include/clang/Analysis/AnalysisDiagnostic.h index e82dc9ed9f..3ee7335185 100644 --- a/include/clang/Analysis/AnalysisDiagnostic.h +++ b/include/clang/Analysis/AnalysisDiagnostic.h @@ -15,7 +15,7 @@ namespace clang { namespace diag { enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM, #define ANALYSISSTART #include "clang/Basic/DiagnosticAnalysisKinds.inc" #undef DIAG diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index 22e7fb3f85..207710bdff 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -50,7 +50,7 @@ namespace clang { // Get typedefs for common diagnostics. enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM, #include "clang/Basic/DiagnosticCommonKinds.inc" NUM_BUILTIN_COMMON_DIAGNOSTICS #undef DIAG @@ -313,6 +313,16 @@ public: /// the diagnostic, this returns null. static const char *getWarningOptionForDiag(unsigned DiagID); + /// \brief Determines whether the given built-in diagnostic ID is + /// for an error that is suppressed if it occurs during C++ template + /// argument deduction. + /// + /// When an error is suppressed due to SFINAE, the template argument + /// deduction fails but no diagnostic is emitted. Certain classes of + /// errors, such as those errors that involve C++ access control, + /// are not SFINAE errors. + static bool isBuiltinSFINAEDiag(unsigned DiagID); + /// getDiagnosticLevel - Based on the way the client configured the Diagnostic /// object, classify the specified diagnostic ID into a Level, consumable by /// the DiagnosticClient. @@ -409,7 +419,10 @@ private: /// ProcessDiag - This is the method used to report a diagnostic that is /// finally fully formed. - void ProcessDiag(); + /// + /// \returns true if the diagnostic was emitted, false if it was + /// suppressed. + bool ProcessDiag(); }; //===----------------------------------------------------------------------===// @@ -448,14 +461,26 @@ public: NumCodeModificationHints = D.NumCodeModificationHints; } + /// \brief Simple enumeration value used to give a name to the + /// suppress-diagnostic constructor. + enum SuppressKind { Suppress }; + + /// \brief Create an empty DiagnosticBuilder object that represents + /// no actual diagnostic. + explicit DiagnosticBuilder(SuppressKind) + : DiagObj(0), NumArgs(0), NumRanges(0), NumCodeModificationHints(0) { } + /// \brief Force the diagnostic builder to emit the diagnostic now. /// /// Once this function has been called, the DiagnosticBuilder object /// should not be used again before it is destroyed. - void Emit() { + /// + /// \returns true if a diagnostic was emitted, false if the + /// diagnostic was suppressed. + bool Emit() { // If DiagObj is null, then its soul was stolen by the copy ctor // or the user called Emit(). - if (DiagObj == 0) return; + if (DiagObj == 0) return false; // When emitting diagnostics, we set the final argument count into // the Diagnostic object. @@ -465,13 +490,15 @@ public: // Process the diagnostic, sending the accumulated information to the // DiagnosticClient. - DiagObj->ProcessDiag(); + bool Emitted = DiagObj->ProcessDiag(); // Clear out the current diagnostic object. DiagObj->Clear(); // This diagnostic is dead. DiagObj = 0; + + return Emitted; } /// Destructor - The dtor emits the diagnostic if it hasn't already @@ -486,28 +513,34 @@ public: void AddString(const std::string &S) const { assert(NumArgs < Diagnostic::MaxArguments && "Too many arguments to diagnostic!"); - DiagObj->DiagArgumentsKind[NumArgs] = Diagnostic::ak_std_string; - DiagObj->DiagArgumentsStr[NumArgs++] = S; + if (DiagObj) { + DiagObj->DiagArgumentsKind[NumArgs] = Diagnostic::ak_std_string; + DiagObj->DiagArgumentsStr[NumArgs++] = S; + } } void AddTaggedVal(intptr_t V, Diagnostic::ArgumentKind Kind) const { assert(NumArgs < Diagnostic::MaxArguments && "Too many arguments to diagnostic!"); - DiagObj->DiagArgumentsKind[NumArgs] = Kind; - DiagObj->DiagArgumentsVal[NumArgs++] = V; + if (DiagObj) { + DiagObj->DiagArgumentsKind[NumArgs] = Kind; + DiagObj->DiagArgumentsVal[NumArgs++] = V; + } } void AddSourceRange(const SourceRange &R) const { assert(NumRanges < sizeof(DiagObj->DiagRanges)/sizeof(DiagObj->DiagRanges[0]) && "Too many arguments to diagnostic!"); - DiagObj->DiagRanges[NumRanges++] = &R; + if (DiagObj) + DiagObj->DiagRanges[NumRanges++] = &R; } void AddCodeModificationHint(const CodeModificationHint &Hint) const { assert(NumCodeModificationHints < Diagnostic::MaxCodeModificationHints && "Too many code modification hints!"); - DiagObj->CodeModificationHints[NumCodeModificationHints++] = Hint; + if (DiagObj) + DiagObj->CodeModificationHints[NumCodeModificationHints++] = Hint; } }; diff --git a/include/clang/Basic/Diagnostic.td b/include/clang/Basic/Diagnostic.td index 67d8eaafc9..6aa3b438ab 100644 --- a/include/clang/Basic/Diagnostic.td +++ b/include/clang/Basic/Diagnostic.td @@ -45,6 +45,7 @@ class Diagnostic<string text, DiagClass DC, DiagMapping defaultmapping> { string Component = ?; string Text = text; DiagClass Class = DC; + bit SFINAE = 1; DiagMapping DefaultMapping = defaultmapping; DiagGroup Group; } @@ -61,6 +62,8 @@ class DefaultWarn { DiagMapping DefaultMapping = MAP_WARNING; } class DefaultError { DiagMapping DefaultMapping = MAP_ERROR; } class DefaultFatal { DiagMapping DefaultMapping = MAP_FATAL; } +class NoSFINAE { bit SFINAE = 0; } + // Definitions for Diagnostics. include "DiagnosticASTKinds.td" include "DiagnosticAnalysisKinds.td" diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 26c5fc80b8..fa4f430591 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -331,7 +331,7 @@ def note_overridden_virtual_function : Note< def err_covariant_return_inaccessible_base : Error< "return type of virtual function %2 is not covariant with the return type " "of the function it overrides " - "(conversion from %0 to inaccessible base class %1)">; + "(conversion from %0 to inaccessible base class %1)">, NoSFINAE; def err_covariant_return_ambiguous_derived_to_base_conv : Error< "return type of virtual function %3 is not covariant with the return type of " "the function it overrides (ambiguous conversion from derived class " @@ -782,7 +782,8 @@ def unsup_template_partial_spec_ordering : Error< // C++ Template Instantiation def err_template_recursion_depth_exceeded : Error< - "recursive template instantiation exceeded maximum depth of %0">,DefaultFatal; + "recursive template instantiation exceeded maximum depth of %0">, + DefaultFatal, NoSFINAE; def note_template_recursion_depth : Note< "use -ftemplate-depth-N to increase recursive template instantiation depth">; @@ -1604,7 +1605,7 @@ def err_memptr_conv_via_virtual : Error< // C++ access control def err_conv_to_inaccessible_base : Error< - "conversion from %0 to inaccessible base class %1">; + "conversion from %0 to inaccessible base class %1">, NoSFINAE; def note_inheritance_specifier_here : Note< "'%0' inheritance specifier here">; def note_inheritance_implicitly_private_here : Note< @@ -1851,8 +1852,10 @@ def warn_ivar_use_hidden : Warning< "local declaration of %0 hides instance variable">; def error_ivar_use_in_class_method : Error< "instance variable %0 accessed in class method">; -def error_private_ivar_access : Error<"instance variable %0 is private">; -def error_protected_ivar_access : Error<"instance variable %0 is protected">; +def error_private_ivar_access : Error<"instance variable %0 is private">, + NoSFINAE; +def error_protected_ivar_access : Error<"instance variable %0 is protected">, + NoSFINAE; def warn_maynot_respond : Warning<"%0 may not respond to %1">; def warn_attribute_method_def : Warning< "method attribute can only be specified on method declarations">; diff --git a/include/clang/Driver/DriverDiagnostic.h b/include/clang/Driver/DriverDiagnostic.h index 2a4413c24e..705c3422cd 100644 --- a/include/clang/Driver/DriverDiagnostic.h +++ b/include/clang/Driver/DriverDiagnostic.h @@ -15,7 +15,7 @@ namespace clang { namespace diag { enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM, #define DRIVERSTART #include "clang/Basic/DiagnosticDriverKinds.inc" #undef DIAG diff --git a/include/clang/Frontend/FrontendDiagnostic.h b/include/clang/Frontend/FrontendDiagnostic.h index 02432ca3a5..079abae3ee 100644 --- a/include/clang/Frontend/FrontendDiagnostic.h +++ b/include/clang/Frontend/FrontendDiagnostic.h @@ -15,7 +15,7 @@ namespace clang { namespace diag { enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM, #define FRONTENDSTART #include "clang/Basic/DiagnosticFrontendKinds.inc" #undef DIAG diff --git a/include/clang/Lex/LexDiagnostic.h b/include/clang/Lex/LexDiagnostic.h index 1502efb55e..03d9b7b3bb 100644 --- a/include/clang/Lex/LexDiagnostic.h +++ b/include/clang/Lex/LexDiagnostic.h @@ -15,7 +15,7 @@ namespace clang { namespace diag { enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM, #define LEXSTART #include "clang/Basic/DiagnosticLexKinds.inc" #undef DIAG diff --git a/include/clang/Parse/ParseDiagnostic.h b/include/clang/Parse/ParseDiagnostic.h index a85c6ad6ca..fa600ddadf 100644 --- a/include/clang/Parse/ParseDiagnostic.h +++ b/include/clang/Parse/ParseDiagnostic.h @@ -15,7 +15,7 @@ namespace clang { namespace diag { enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM, #define PARSESTART #include "clang/Basic/DiagnosticParseKinds.inc" #undef DIAG diff --git a/include/clang/Sema/SemaDiagnostic.h b/include/clang/Sema/SemaDiagnostic.h index e215ed48fb..de92844f4d 100644 --- a/include/clang/Sema/SemaDiagnostic.h +++ b/include/clang/Sema/SemaDiagnostic.h @@ -15,7 +15,7 @@ namespace clang { namespace diag { enum { -#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP) ENUM, +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) ENUM, #define SEMASTART #include "clang/Basic/DiagnosticSemaKinds.inc" #undef DIAG diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 3b3d61b08d..323f7a7d4a 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -46,6 +46,7 @@ struct StaticDiagInfoRec { unsigned short DiagID; unsigned Mapping : 3; unsigned Class : 3; + bool SFINAE : 1; const char *Description; const char *OptionGroup; @@ -58,8 +59,8 @@ struct StaticDiagInfoRec { }; static const StaticDiagInfoRec StaticDiagInfo[] = { -#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP) \ - { diag::ENUM, DEFAULT_MAPPING, CLASS, DESC, GROUP }, +#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP,SFINAE) \ + { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, DESC, GROUP }, #include "clang/Basic/DiagnosticCommonKinds.inc" #include "clang/Basic/DiagnosticDriverKinds.inc" #include "clang/Basic/DiagnosticFrontendKinds.inc" @@ -68,7 +69,7 @@ static const StaticDiagInfoRec StaticDiagInfo[] = { #include "clang/Basic/DiagnosticASTKinds.inc" #include "clang/Basic/DiagnosticSemaKinds.inc" #include "clang/Basic/DiagnosticAnalysisKinds.inc" -{ 0, 0, 0, 0, 0 } + { 0, 0, 0, 0, 0, 0} }; #undef DIAG @@ -89,7 +90,7 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) { #endif // Search the diagnostic table with a binary search. - StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0 }; + StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0 }; const StaticDiagInfoRec *Found = std::lower_bound(StaticDiagInfo, StaticDiagInfo + NumDiagEntries, Find); @@ -115,6 +116,12 @@ const char *Diagnostic::getWarningOptionForDiag(unsigned DiagID) { return 0; } +bool Diagnostic::isBuiltinSFINAEDiag(unsigned DiagID) { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return Info->SFINAE && Info->Class != CLASS_NOTE; + return false; +} + /// getDiagClass - Return the class field of the diagnostic. /// static unsigned getBuiltinDiagClass(unsigned DiagID) { @@ -399,7 +406,7 @@ bool Diagnostic::setDiagnosticGroupMapping(const char *Group, /// ProcessDiag - This is the method used to report a diagnostic that is /// finally fully formed. -void Diagnostic::ProcessDiag() { +bool Diagnostic::ProcessDiag() { DiagnosticInfo Info(this); // Figure out the diagnostic level of this message. @@ -449,13 +456,13 @@ void Diagnostic::ProcessDiag() { // If a fatal error has already been emitted, silence all subsequent // diagnostics. if (FatalErrorOccurred) - return; + return false; // If the client doesn't care about this message, don't issue it. If this is // a note and the last real diagnostic was ignored, ignore it too. if (DiagLevel == Diagnostic::Ignored || (DiagLevel == Diagnostic::Note && LastDiagLevel == Diagnostic::Ignored)) - return; + return false; // If this diagnostic is in a system header and is not a clang error, suppress // it. @@ -464,7 +471,7 @@ void Diagnostic::ProcessDiag() { Info.getLocation().getSpellingLoc().isInSystemHeader() && (DiagLevel != Diagnostic::Note || LastDiagLevel == Diagnostic::Ignored)) { LastDiagLevel = Diagnostic::Ignored; - return; + return false; } if (DiagLevel >= Diagnostic::Error) { @@ -477,6 +484,8 @@ void Diagnostic::ProcessDiag() { if (Client->IncludeInDiagnosticCounts()) ++NumDiagnostics; CurDiagID = ~0U; + + return true; } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index e3cea5be42..4dc5222072 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -316,7 +316,8 @@ NamedDecl *Sema::getCurFunctionOrMethodDecl() { } Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { - this->Emit(); + if (!this->Emit()) + return; // If this is not a note, and we're in a template instantiation // that is different from the last template instantiation where diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 169ce8216c..b310568740 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -297,11 +297,21 @@ public: SemaDiagnosticBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID) : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) { } + explicit SemaDiagnosticBuilder(Sema &SemaRef) + : DiagnosticBuilder(DiagnosticBuilder::Suppress), SemaRef(SemaRef) { } + ~SemaDiagnosticBuilder(); }; /// \brief Emit a diagnostic. SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { + if (isSFINAEContext() && Diagnostic::isBuiltinSFINAEDiag(DiagID)) { + // If we encountered an error during template argument + // deduction, and that error is one of the SFINAE errors, + // supress the diagnostic. + return SemaDiagnosticBuilder(*this); + } + DiagnosticBuilder DB = Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID); return SemaDiagnosticBuilder(DB, *this, DiagID); } @@ -2322,6 +2332,14 @@ public: void PrintInstantiationStack(); + /// \brief Determines whether we are currently in a context where + /// template argument substitution failures are not considered + /// errors. + /// + /// When this routine returns true, the emission of most diagnostics + /// will be suppressed and there will be no local error recovery. + bool isSFINAEContext() const; + /// \brief A stack-allocated class that identifies which local /// variable declaration instantiations are present in this scope. /// diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 4d03e79c65..18b2d75acc 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -199,6 +199,34 @@ void Sema::PrintInstantiationStack() { } } +bool Sema::isSFINAEContext() const { + using llvm::SmallVector; + for (SmallVector<ActiveTemplateInstantiation, 16>::const_reverse_iterator + Active = ActiveTemplateInstantiations.rbegin(), + ActiveEnd = ActiveTemplateInstantiations.rend(); + Active != ActiveEnd; + ++Active) { + + switch(Active->Kind) { + case ActiveTemplateInstantiation::PartialSpecDeductionInstantiation: + // We're in a template argument deduction context, so SFINAE + // applies. + return true; + + case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation: + // A default template argument instantiation may or may not be a + // SFINAE context; look further up the stack. + break; + + case ActiveTemplateInstantiation::TemplateInstantiation: + // This is a template instantiation, so there is no SFINAE. + return false; + } + } + + return false; +} + //===----------------------------------------------------------------------===/ // Template Instantiation for Types //===----------------------------------------------------------------------===/ diff --git a/test/SemaTemplate/temp_class_spec.cpp b/test/SemaTemplate/temp_class_spec.cpp index 6fedce76ae..1a534236c8 100644 --- a/test/SemaTemplate/temp_class_spec.cpp +++ b/test/SemaTemplate/temp_class_spec.cpp @@ -251,9 +251,8 @@ int is_nested_value_type_identity0[ is_nested_value_type_identity<HasValueType<int> >::value? -1 : 1]; int is_nested_value_type_identity1[ is_nested_value_type_identity<HasIdentityValueType>::value? 1 : -1]; -// FIXME: Enable when we have SFINAE support -//int is_nested_value_type_identity2[ -// is_nested_value_type_identity<NoValueType>::value? -1 : 1]; +int is_nested_value_type_identity2[ + is_nested_value_type_identity<NoValueType>::value? -1 : 1]; // C++ [temp.class.spec]p4: diff --git a/www/cxx_status.html b/www/cxx_status.html index f1c3fb952d..d5ff8ac057 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -2085,10 +2085,10 @@ welcome!</p> </tr> <tr> <td> 14.8.2 [temp.deduct]</td> - <td class="broken" align="center"></td> - <td class="broken" align="center"></td> - <td class="broken" align="center"></td> - <td class="broken" align="center"></td> + <td class="na" align="center">N/A</td> + <td class="na" align="center">N/A</td> + <td class="medium" align="center"></td> + <td class="na" align="center">N/A</td> <td></td> </tr> <tr> |