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
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
// 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
/// 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.
/// 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();
};
//===----------------------------------------------------------------------===//
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.
// 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
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;
}
};
string Component = ?;
string Text = text;
DiagClass Class = DC;
+ bit SFINAE = 1;
DiagMapping DefaultMapping = defaultmapping;
DiagGroup Group;
}
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"
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 "
// 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">;
// 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<
"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">;
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
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
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
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
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
unsigned short DiagID;
unsigned Mapping : 3;
unsigned Class : 3;
+ bool SFINAE : 1;
const char *Description;
const char *OptionGroup;
};
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"
#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
#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);
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) {
/// 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.
// 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.
Info.getLocation().getSpellingLoc().isInSystemHeader() &&
(DiagLevel != Diagnostic::Note || LastDiagLevel == Diagnostic::Ignored)) {
LastDiagLevel = Diagnostic::Ignored;
- return;
+ return false;
}
if (DiagLevel >= Diagnostic::Error) {
if (Client->IncludeInDiagnosticCounts()) ++NumDiagnostics;
CurDiagID = ~0U;
+
+ return true;
}
}
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
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);
}
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.
///
}
}
+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
//===----------------------------------------------------------------------===/
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:
</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>