forked from OSchip/llvm-project
Allow CorrectTypo to replace CXXScopeSpecifiers that refer to classes.
Now that CorrectTypo knows how to correctly search classes for typo correction candidates, there is no good reason to only replace an existing CXXScopeSpecifier if it refers to a namespace. While the actual enablement was a matter of changing a single comparison, the fallout from enabling the functionality required a lot more code changes (including my two previous commits). llvm-svn: 193020
This commit is contained in:
parent
f7b63e3e18
commit
8aa8da85ca
|
@ -7301,9 +7301,10 @@ void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) {
|
||||||
namespace {
|
namespace {
|
||||||
class UsingValidatorCCC : public CorrectionCandidateCallback {
|
class UsingValidatorCCC : public CorrectionCandidateCallback {
|
||||||
public:
|
public:
|
||||||
UsingValidatorCCC(bool HasTypenameKeyword, bool IsInstantiation)
|
UsingValidatorCCC(bool HasTypenameKeyword, bool IsInstantiation,
|
||||||
|
bool RequireMember)
|
||||||
: HasTypenameKeyword(HasTypenameKeyword),
|
: HasTypenameKeyword(HasTypenameKeyword),
|
||||||
IsInstantiation(IsInstantiation) {}
|
IsInstantiation(IsInstantiation), RequireMember(RequireMember) {}
|
||||||
|
|
||||||
bool ValidateCandidate(const TypoCorrection &Candidate) LLVM_OVERRIDE {
|
bool ValidateCandidate(const TypoCorrection &Candidate) LLVM_OVERRIDE {
|
||||||
NamedDecl *ND = Candidate.getCorrectionDecl();
|
NamedDecl *ND = Candidate.getCorrectionDecl();
|
||||||
|
@ -7312,6 +7313,10 @@ public:
|
||||||
if (!ND || isa<NamespaceDecl>(ND))
|
if (!ND || isa<NamespaceDecl>(ND))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (RequireMember && !isa<FieldDecl>(ND) && !isa<CXXMethodDecl>(ND) &&
|
||||||
|
!isa<TypeDecl>(ND))
|
||||||
|
return false;
|
||||||
|
|
||||||
// Completely unqualified names are invalid for a 'using' declaration.
|
// Completely unqualified names are invalid for a 'using' declaration.
|
||||||
if (Candidate.WillReplaceSpecifier() && !Candidate.getCorrectionSpecifier())
|
if (Candidate.WillReplaceSpecifier() && !Candidate.getCorrectionSpecifier())
|
||||||
return false;
|
return false;
|
||||||
|
@ -7325,6 +7330,7 @@ public:
|
||||||
private:
|
private:
|
||||||
bool HasTypenameKeyword;
|
bool HasTypenameKeyword;
|
||||||
bool IsInstantiation;
|
bool IsInstantiation;
|
||||||
|
bool RequireMember;
|
||||||
};
|
};
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
|
||||||
|
@ -7440,7 +7446,8 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
|
||||||
|
|
||||||
// Try to correct typos if possible.
|
// Try to correct typos if possible.
|
||||||
if (R.empty()) {
|
if (R.empty()) {
|
||||||
UsingValidatorCCC CCC(HasTypenameKeyword, IsInstantiation);
|
UsingValidatorCCC CCC(HasTypenameKeyword, IsInstantiation,
|
||||||
|
CurContext->isRecord());
|
||||||
if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
|
if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
|
||||||
R.getLookupKind(), S, &SS, CCC)){
|
R.getLookupKind(), S, &SS, CCC)){
|
||||||
// We reject any correction for which ND would be NULL.
|
// We reject any correction for which ND would be NULL.
|
||||||
|
|
|
@ -538,13 +538,42 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Callback to only accept typo corrections that are either a ValueDecl or a
|
// Callback to only accept typo corrections that are either a ValueDecl or a
|
||||||
// FunctionTemplateDecl.
|
// FunctionTemplateDecl and are declared in the current record or, for a C++
|
||||||
|
// classes, one of its base classes.
|
||||||
class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback {
|
class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback {
|
||||||
public:
|
public:
|
||||||
|
explicit RecordMemberExprValidatorCCC(const RecordType *RTy)
|
||||||
|
: Record(RTy->getDecl()) {}
|
||||||
|
|
||||||
virtual bool ValidateCandidate(const TypoCorrection &candidate) {
|
virtual bool ValidateCandidate(const TypoCorrection &candidate) {
|
||||||
NamedDecl *ND = candidate.getCorrectionDecl();
|
NamedDecl *ND = candidate.getCorrectionDecl();
|
||||||
return ND && (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND));
|
// Don't accept candidates that cannot be member functions, constants,
|
||||||
|
// variables, or templates.
|
||||||
|
if (!ND || !(isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Accept candidates that occur in the current record.
|
||||||
|
if (Record->containsDecl(ND))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Record)) {
|
||||||
|
// Accept candidates that occur in any of the current class' base classes.
|
||||||
|
for (CXXRecordDecl::base_class_const_iterator BS = RD->bases_begin(),
|
||||||
|
BSEnd = RD->bases_end();
|
||||||
|
BS != BSEnd; ++BS) {
|
||||||
|
if (const RecordType *BSTy = dyn_cast_or_null<RecordType>(
|
||||||
|
BS->getType().getTypePtrOrNull())) {
|
||||||
|
if (BSTy->getDecl()->containsDecl(ND))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const RecordDecl *const Record;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -600,7 +629,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
|
||||||
// We didn't find anything with the given name, so try to correct
|
// We didn't find anything with the given name, so try to correct
|
||||||
// for typos.
|
// for typos.
|
||||||
DeclarationName Name = R.getLookupName();
|
DeclarationName Name = R.getLookupName();
|
||||||
RecordMemberExprValidatorCCC Validator;
|
RecordMemberExprValidatorCCC Validator(RTy);
|
||||||
TypoCorrection Corrected = SemaRef.CorrectTypo(R.getLookupNameInfo(),
|
TypoCorrection Corrected = SemaRef.CorrectTypo(R.getLookupNameInfo(),
|
||||||
R.getLookupKind(), NULL,
|
R.getLookupKind(), NULL,
|
||||||
&SS, Validator, DC);
|
&SS, Validator, DC);
|
||||||
|
|
|
@ -4157,7 +4157,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
|
||||||
// corrections.
|
// corrections.
|
||||||
bool SearchNamespaces
|
bool SearchNamespaces
|
||||||
= getLangOpts().CPlusPlus &&
|
= getLangOpts().CPlusPlus &&
|
||||||
(IsUnqualifiedLookup || (QualifiedDC && QualifiedDC->isNamespace()));
|
(IsUnqualifiedLookup || (SS && SS->isSet()));
|
||||||
// In a few cases we *only* want to search for corrections based on just
|
// In a few cases we *only* want to search for corrections based on just
|
||||||
// adding or changing the nested name specifier.
|
// adding or changing the nested name specifier.
|
||||||
unsigned TypoLen = Typo->getName().size();
|
unsigned TypoLen = Typo->getName().size();
|
||||||
|
@ -4400,6 +4400,18 @@ retry_lookup:
|
||||||
switch (TmpRes.getResultKind()) {
|
switch (TmpRes.getResultKind()) {
|
||||||
case LookupResult::Found:
|
case LookupResult::Found:
|
||||||
case LookupResult::FoundOverloaded: {
|
case LookupResult::FoundOverloaded: {
|
||||||
|
if (SS && SS->isValid()) {
|
||||||
|
std::string NewQualified = TC.getAsString(getLangOpts());
|
||||||
|
std::string OldQualified;
|
||||||
|
llvm::raw_string_ostream OldOStream(OldQualified);
|
||||||
|
SS->getScopeRep()->print(OldOStream, getPrintingPolicy());
|
||||||
|
OldOStream << TypoName;
|
||||||
|
// If correction candidate would be an identical written qualified
|
||||||
|
// identifer, then the existing CXXScopeSpec probably included a
|
||||||
|
// typedef that didn't get accounted for properly.
|
||||||
|
if (OldOStream.str() == NewQualified)
|
||||||
|
break;
|
||||||
|
}
|
||||||
for (LookupResult::iterator TRD = TmpRes.begin(),
|
for (LookupResult::iterator TRD = TmpRes.begin(),
|
||||||
TRDEnd = TmpRes.end();
|
TRDEnd = TmpRes.end();
|
||||||
TRD != TRDEnd; ++TRD) {
|
TRD != TRDEnd; ++TRD) {
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
// special access rights to the friends, but they do not make the nominated
|
// special access rights to the friends, but they do not make the nominated
|
||||||
// friends members of the befriending class.
|
// friends members of the befriending class.
|
||||||
|
|
||||||
struct S { static void f(); };
|
struct S { static void f(); }; // expected-note 2 {{'S' declared here}}
|
||||||
S* g() { return 0; }
|
S* g() { return 0; } // expected-note 2 {{'g' declared here}}
|
||||||
|
|
||||||
struct X {
|
struct X {
|
||||||
friend struct S;
|
friend struct S;
|
||||||
|
@ -19,8 +19,8 @@ void test1() {
|
||||||
S s;
|
S s;
|
||||||
g()->f();
|
g()->f();
|
||||||
S::f();
|
S::f();
|
||||||
X::g(); // expected-error{{no member named 'g' in 'X'}}
|
X::g(); // expected-error{{no member named 'g' in 'X'; did you mean simply 'g'?}}
|
||||||
X::S x_s; // expected-error{{no type named 'S' in 'X'}}
|
X::S x_s; // expected-error{{no type named 'S' in 'X'; did you mean simply 'S'?}}
|
||||||
X x;
|
X x;
|
||||||
x.g(); // expected-error{{no member named 'g' in 'X'}}
|
x.g(); // expected-error{{no member named 'g' in 'X'}}
|
||||||
}
|
}
|
||||||
|
@ -36,24 +36,24 @@ namespace N {
|
||||||
friend struct S2* g2();
|
friend struct S2* g2();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct S2 { static void f2(); };
|
struct S2 { static void f2(); }; // expected-note 2 {{'S2' declared here}}
|
||||||
S2* g2() { return 0; }
|
S2* g2() { return 0; } // expected-note 2 {{'g2' declared here}}
|
||||||
|
|
||||||
void test() {
|
void test() {
|
||||||
g()->f();
|
g()->f();
|
||||||
S s;
|
S s;
|
||||||
S::f();
|
S::f();
|
||||||
X::g(); // expected-error{{no member named 'g' in 'N::X'}}
|
X::g(); // expected-error{{no member named 'g' in 'N::X'; did you mean simply 'g'?}}
|
||||||
X::S x_s; // expected-error{{no type named 'S' in 'N::X'}}
|
X::S x_s; // expected-error{{no type named 'S' in 'N::X'; did you mean simply 'S'?}}
|
||||||
X x;
|
X x;
|
||||||
x.g(); // expected-error{{no member named 'g' in 'N::X'}}
|
x.g(); // expected-error{{no member named 'g' in 'N::X'}}
|
||||||
|
|
||||||
g2();
|
g2();
|
||||||
S2 s2;
|
S2 s2;
|
||||||
::g2(); // expected-error{{no member named 'g2' in the global namespace}}
|
::g2(); // expected-error{{no member named 'g2' in the global namespace; did you mean simply 'g2'?}}
|
||||||
::S2 g_s2; // expected-error{{no type named 'S2' in the global namespace}}
|
::S2 g_s2; // expected-error{{no type named 'S2' in the global namespace; did you mean simply 'S2'?}}
|
||||||
X::g2(); // expected-error{{no member named 'g2' in 'N::X'}}
|
X::g2(); // expected-error{{no member named 'g2' in 'N::X'; did you mean simply 'g2'?}}
|
||||||
X::S2 x_s2; // expected-error{{no type named 'S2' in 'N::X'}}
|
X::S2 x_s2; // expected-error{{no type named 'S2' in 'N::X'; did you mean simply 'S2'?}}
|
||||||
x.g2(); // expected-error{{no member named 'g2' in 'N::X'}}
|
x.g2(); // expected-error{{no member named 'g2' in 'N::X'}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@ namespace test3 {
|
||||||
|
|
||||||
template <class T> class Outer::A<T, typename T::nature> {
|
template <class T> class Outer::A<T, typename T::nature> {
|
||||||
public:
|
public:
|
||||||
static void foo();
|
static void foo(); // expected-note {{'Outer::A<B, Green>::foo' declared here}}
|
||||||
};
|
};
|
||||||
|
|
||||||
class B {
|
class B {
|
||||||
|
@ -102,7 +102,7 @@ namespace test3 {
|
||||||
|
|
||||||
void test() {
|
void test() {
|
||||||
Outer::A<B, Green>::foo();
|
Outer::A<B, Green>::foo();
|
||||||
Outer::A<B, Blue>::foo(); // expected-error {{no member named 'foo'}}
|
Outer::A<B, Blue>::foo(); // expected-error {{no member named 'foo' in 'test3::Outer::A<test3::B, test3::Blue>'; did you mean 'Outer::A<B, Green>::foo'?}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ A<int> a;
|
||||||
A<int>::E a0 = A<int>().v;
|
A<int>::E a0 = A<int>().v;
|
||||||
int n = A<int>::E::e1; // expected-error {{implicit instantiation of undefined member}}
|
int n = A<int>::E::e1; // expected-error {{implicit instantiation of undefined member}}
|
||||||
|
|
||||||
template<typename T> enum A<T>::E : T { e1, e2 };
|
template<typename T> enum A<T>::E : T { e1, e2 }; // expected-note 2 {{declared here}}
|
||||||
|
|
||||||
// FIXME: Now that A<T>::E is defined, we are supposed to inject its enumerators
|
// FIXME: Now that A<T>::E is defined, we are supposed to inject its enumerators
|
||||||
// into the already-instantiated class A<T>. This seems like a really bad idea,
|
// into the already-instantiated class A<T>. This seems like a really bad idea,
|
||||||
|
@ -20,7 +20,7 @@ template<typename T> enum A<T>::E : T { e1, e2 };
|
||||||
//
|
//
|
||||||
// Either do as the standard says, or only include enumerators lexically defined
|
// Either do as the standard says, or only include enumerators lexically defined
|
||||||
// within the class in its scope.
|
// within the class in its scope.
|
||||||
A<int>::E a1 = A<int>::e1; // expected-error {{no member named 'e1' in 'A<int>'}}
|
A<int>::E a1 = A<int>::e1; // expected-error {{no member named 'e1' in 'A<int>'; did you mean simply 'e1'?}}
|
||||||
|
|
||||||
A<char>::E a2 = A<char>::e2;
|
A<char>::E a2 = A<char>::e2;
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ D<int>::E d1 = D<int>::E::e1; // expected-error {{incomplete type 'D<int>::E'}}
|
||||||
template<> enum class D<int>::E { e2 };
|
template<> enum class D<int>::E { e2 };
|
||||||
D<int>::E d2 = D<int>::E::e2;
|
D<int>::E d2 = D<int>::E::e2;
|
||||||
D<char>::E d3 = D<char>::E::e1; // expected-note {{first required here}}
|
D<char>::E d3 = D<char>::E::e1; // expected-note {{first required here}}
|
||||||
D<char>::E d4 = D<char>::E::e2; // expected-error {{no member named 'e2'}}
|
D<char>::E d4 = D<char>::E::e2; // expected-error {{no member named 'e2' in 'D<char>::E'; did you mean simply 'e2'?}}
|
||||||
template<> enum class D<char>::E { e3 }; // expected-error {{explicit specialization of 'E' after instantiation}}
|
template<> enum class D<char>::E { e3 }; // expected-error {{explicit specialization of 'E' after instantiation}}
|
||||||
|
|
||||||
template<> enum class D<short>::E;
|
template<> enum class D<short>::E;
|
||||||
|
|
|
@ -4,7 +4,7 @@ class A {};
|
||||||
|
|
||||||
namespace B {
|
namespace B {
|
||||||
namespace A {} // expected-note{{namespace '::B::A' defined here}} \
|
namespace A {} // expected-note{{namespace '::B::A' defined here}} \
|
||||||
// expected-note{{namespace 'B::A' defined here}}
|
// expected-note 2{{namespace 'B::A' defined here}}
|
||||||
using namespace A ;
|
using namespace A ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ namespace D {
|
||||||
|
|
||||||
using namespace ! ; // expected-error{{expected namespace name}}
|
using namespace ! ; // expected-error{{expected namespace name}}
|
||||||
using namespace A ; // expected-error{{no namespace named 'A'; did you mean 'B::A'?}}
|
using namespace A ; // expected-error{{no namespace named 'A'; did you mean 'B::A'?}}
|
||||||
using namespace ::A // expected-error{{expected namespace name}} \
|
using namespace ::A // expected-error{{no namespace named 'A' in the global namespace; did you mean 'B::A'?}} \
|
||||||
// expected-error{{expected ';' after namespace name}}
|
// expected-error{{expected ';' after namespace name}}
|
||||||
B ;
|
B ;
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ int test8( foo x ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stress test to make sure Clang doesn't crash.
|
// Stress test to make sure Clang doesn't crash.
|
||||||
void test9(int x) {
|
void test9(int x) { // expected-note {{'x' declared here}}
|
||||||
switch(x) {
|
switch(x) {
|
||||||
case 1: return;
|
case 1: return;
|
||||||
2: case; // expected-error {{expected 'case' keyword before expression}} \
|
2: case; // expected-error {{expected 'case' keyword before expression}} \
|
||||||
|
@ -104,8 +104,8 @@ void test9(int x) {
|
||||||
7: :x; // expected-error {{expected 'case' keyword before expression}} \
|
7: :x; // expected-error {{expected 'case' keyword before expression}} \
|
||||||
expected-error {{expected expression}}
|
expected-error {{expected expression}}
|
||||||
8:: x; // expected-error {{expected ';' after expression}} \
|
8:: x; // expected-error {{expected ';' after expression}} \
|
||||||
expected-error {{no member named 'x' in the global namespace}} \
|
expected-error {{no member named 'x' in the global namespace; did you mean simply 'x'?}} \
|
||||||
expected-warning {{expression result unused}}
|
expected-warning 2 {{expression result unused}}
|
||||||
9:: :y; // expected-error {{expected ';' after expression}} \
|
9:: :y; // expected-error {{expected ';' after expression}} \
|
||||||
expected-error {{expected unqualified-id}} \
|
expected-error {{expected unqualified-id}} \
|
||||||
expected-warning {{expression result unused}}
|
expected-warning {{expression result unused}}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||||
namespace A {
|
namespace A {
|
||||||
namespace B {
|
namespace B {
|
||||||
class C { };
|
class C { }; // expected-note 2 {{'A::B::C' declared here}}
|
||||||
struct S { };
|
struct S { };
|
||||||
union U { };
|
union U { };
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,12 @@ namespace B {
|
||||||
|
|
||||||
void g() {
|
void g() {
|
||||||
A::B::D::E; // expected-error {{no member named 'D' in namespace 'A::B'}}
|
A::B::D::E; // expected-error {{no member named 'D' in namespace 'A::B'}}
|
||||||
B::B::C::D; // expected-error {{no member named 'C' in 'B::B'}}
|
// FIXME: The typo corrections below should be suppressed since A::B::C
|
||||||
::C::D; // expected-error {{no member named 'C' in the global namespace}}
|
// doesn't have a member named D.
|
||||||
|
B::B::C::D; // expected-error {{no member named 'C' in 'B::B'; did you mean 'A::B::C'?}} \
|
||||||
|
// expected-error {{no member named 'D' in 'A::B::C'}}
|
||||||
|
::C::D; // expected-error {{no member named 'C' in the global namespace; did you mean 'A::B::C'?}}\
|
||||||
|
// expected-error {{no member named 'D' in 'A::B::C'}}
|
||||||
}
|
}
|
||||||
|
|
||||||
int A::B::i = 10; // expected-error {{no member named 'i' in namespace 'A::B'}}
|
int A::B::i = 10; // expected-error {{no member named 'i' in namespace 'A::B'}}
|
||||||
|
|
|
@ -168,3 +168,16 @@ namespace PR17019 {
|
||||||
evil<int> Q(0); // expected-note {{in instantiation of member function}}
|
evil<int> Q(0); // expected-note {{in instantiation of member function}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace fix_class_name_qualifier {
|
||||||
|
class MessageHeaders {};
|
||||||
|
class MessageUtils {
|
||||||
|
public:
|
||||||
|
static void ParseMessageHeaders(int, int); // expected-note {{'MessageUtils::ParseMessageHeaders' declared here}}
|
||||||
|
};
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
// No, we didn't mean to call MessageHeaders::MessageHeaders.
|
||||||
|
MessageHeaders::ParseMessageHeaders(5, 4); // expected-error {{no member named 'ParseMessageHeaders' in 'fix_class_name_qualifier::MessageHeaders'; did you mean 'MessageUtils::ParseMessageHeaders'?}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -217,10 +217,14 @@ namespace PR13051 {
|
||||||
operator bool() const;
|
operator bool() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
void f() {
|
void foo(); // expected-note{{'foo' declared here}}
|
||||||
f(&S<int>::tempalte f<int>); // expected-error{{did you mean 'template'?}}
|
void g(void(*)());
|
||||||
f(&S<int>::opeartor bool); // expected-error{{did you mean 'operator'?}}
|
void g(bool(S<int>::*)() const);
|
||||||
f(&S<int>::foo); // expected-error-re{{no member named 'foo' in 'PR13051::S<int>'$}}
|
|
||||||
|
void test() {
|
||||||
|
g(&S<int>::tempalte f<int>); // expected-error{{did you mean 'template'?}}
|
||||||
|
g(&S<int>::opeartor bool); // expected-error{{did you mean 'operator'?}}
|
||||||
|
g(&S<int>::foo); // expected-error{{no member named 'foo' in 'PR13051::S<int>'; did you mean simply 'foo'?}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -252,16 +252,16 @@ namespace PR8372 {
|
||||||
|
|
||||||
namespace PR9227 {
|
namespace PR9227 {
|
||||||
template <bool B> struct enable_if_bool { };
|
template <bool B> struct enable_if_bool { };
|
||||||
template <> struct enable_if_bool<true> { typedef int type; };
|
template <> struct enable_if_bool<true> { typedef int type; }; // expected-note{{'enable_if_bool<true>::type' declared here}}
|
||||||
void test_bool() { enable_if_bool<false>::type i; } // expected-error{{enable_if_bool<false>}}
|
void test_bool() { enable_if_bool<false>::type i; } // expected-error{{enable_if_bool<false>'; did you mean 'enable_if_bool<true>::type'?}}
|
||||||
|
|
||||||
template <char C> struct enable_if_char { };
|
template <char C> struct enable_if_char { };
|
||||||
template <> struct enable_if_char<'a'> { typedef int type; };
|
template <> struct enable_if_char<'a'> { typedef int type; }; // expected-note 5{{'enable_if_char<'a'>::type' declared here}}
|
||||||
void test_char_0() { enable_if_char<0>::type i; } // expected-error{{enable_if_char<'\x00'>}}
|
void test_char_0() { enable_if_char<0>::type i; } // expected-error{{enable_if_char<'\x00'>'; did you mean 'enable_if_char<'a'>::type'?}}
|
||||||
void test_char_b() { enable_if_char<'b'>::type i; } // expected-error{{enable_if_char<'b'>}}
|
void test_char_b() { enable_if_char<'b'>::type i; } // expected-error{{enable_if_char<'b'>'; did you mean 'enable_if_char<'a'>::type'?}}
|
||||||
void test_char_possibly_negative() { enable_if_char<'\x02'>::type i; } // expected-error{{enable_if_char<'\x02'>}}
|
void test_char_possibly_negative() { enable_if_char<'\x02'>::type i; } // expected-error{{enable_if_char<'\x02'>'; did you mean 'enable_if_char<'a'>::type'?}}
|
||||||
void test_char_single_quote() { enable_if_char<'\''>::type i; } // expected-error{{enable_if_char<'\''>}}
|
void test_char_single_quote() { enable_if_char<'\''>::type i; } // expected-error{{enable_if_char<'\''>'; did you mean 'enable_if_char<'a'>::type'?}}
|
||||||
void test_char_backslash() { enable_if_char<'\\'>::type i; } // expected-error{{enable_if_char<'\\'>}}
|
void test_char_backslash() { enable_if_char<'\\'>::type i; } // expected-error{{enable_if_char<'\\'>'; did you mean 'enable_if_char<'a'>::type'?}}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace PR10579 {
|
namespace PR10579 {
|
||||||
|
|
Loading…
Reference in New Issue