[cfe-commits] r156963 - in /cfe/trunk: include/clang/Parse/Parser.h lib/Parse/ParseTentative.cpp test/CXX/except/except.spec/p5-pointers.cpp test/SemaCXX/unknown-type-name.cpp
Richard Smith
richard-llvm at metafoo.co.uk
Wed May 16 16:40:18 PDT 2012
Author: rsmith
Date: Wed May 16 18:40:17 2012
New Revision: 156963
URL: http://llvm.org/viewvc/llvm-project?rev=156963&view=rev
Log:
Recover better from a missing 'typename' in a function template definition.
Disambiguate past such a potential problem, and use the absence of 'typename'
to break ties in favor of a parenthesized thingy being an initializer, if
nothing else in the declaration disambiguates it as declaring a function.
Modified:
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/lib/Parse/ParseTentative.cpp
cfe/trunk/test/CXX/except/except.spec/p5-pointers.cpp
cfe/trunk/test/SemaCXX/unknown-type-name.cpp
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=156963&r1=156962&r2=156963&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Wed May 16 18:40:17 2012
@@ -1753,7 +1753,8 @@
/// BracedCastResult.
/// Doesn't consume tokens.
TPResult
- isCXXDeclarationSpecifier(TPResult BracedCastResult = TPResult::False());
+ isCXXDeclarationSpecifier(TPResult BracedCastResult = TPResult::False(),
+ bool *HasMissingTypename = 0);
// "Tentative parsing" functions, used for disambiguation. If a parsing error
// is encountered they will return TPResult::Error().
@@ -1762,13 +1763,13 @@
// that more tentative parsing is necessary for disambiguation.
// They all consume tokens, so backtracking should be used after calling them.
- TPResult TryParseDeclarationSpecifier();
+ TPResult TryParseDeclarationSpecifier(bool *HasMissingTypename = 0);
TPResult TryParseSimpleDeclaration(bool AllowForRangeDecl);
TPResult TryParseTypeofSpecifier();
TPResult TryParseProtocolQualifiers();
TPResult TryParseInitDeclaratorList();
TPResult TryParseDeclarator(bool mayBeAbstract, bool mayHaveIdentifier=true);
- TPResult TryParseParameterDeclarationClause();
+ TPResult TryParseParameterDeclarationClause(bool *InvalidAsDeclaration = 0);
TPResult TryParseFunctionDeclarator();
TPResult TryParseBracketDeclarator();
Modified: cfe/trunk/lib/Parse/ParseTentative.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=156963&r1=156962&r2=156963&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTentative.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTentative.cpp Wed May 16 18:40:17 2012
@@ -827,6 +827,10 @@
/// be either a decl-specifier or a function-style cast, and TPResult::Error()
/// if a parsing error was found and reported.
///
+/// If HasMissingTypename is provided, a name with a dependent scope specifier
+/// will be treated as ambiguous if the 'typename' keyword is missing. If this
+/// happens, *HasMissingTypename will be set to 'true'.
+///
/// decl-specifier:
/// storage-class-specifier
/// type-specifier
@@ -918,7 +922,8 @@
/// [GNU] restrict
///
Parser::TPResult
-Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult) {
+Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
+ bool *HasMissingTypename) {
switch (Tok.getKind()) {
case tok::identifier: // foo::bar
// Check for need to substitute AltiVec __vector keyword
@@ -936,7 +941,7 @@
return (!getLangOpts().ObjC1 && Next.is(tok::identifier)) ?
TPResult::True() : TPResult::False();
}
- return isCXXDeclarationSpecifier(BracedCastResult);
+ return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename);
case tok::coloncolon: { // ::foo::bar
const Token &Next = NextToken();
@@ -950,7 +955,7 @@
// recurse to handle whatever we get.
if (TryAnnotateTypeOrScopeToken())
return TPResult::Error();
- return isCXXDeclarationSpecifier(BracedCastResult);
+ return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename);
// decl-specifier:
// storage-class-specifier
@@ -1052,12 +1057,20 @@
bool isIdentifier = Tok.is(tok::identifier);
TPResult TPR = TPResult::False();
if (!isIdentifier)
- TPR = isCXXDeclarationSpecifier(BracedCastResult);
+ TPR = isCXXDeclarationSpecifier(BracedCastResult,
+ HasMissingTypename);
PA.Revert();
if (isIdentifier ||
TPR == TPResult::True() || TPR == TPResult::Error())
return TPResult::Error();
+
+ if (HasMissingTypename) {
+ // We can't tell whether this is a missing 'typename' or a valid
+ // expression.
+ *HasMissingTypename = true;
+ return TPResult::Ambiguous();
+ }
}
}
return TPResult::False();
@@ -1221,21 +1234,24 @@
return TPResult::Error();
}
-Parser::TPResult Parser::TryParseDeclarationSpecifier() {
- TPResult TPR = isCXXDeclarationSpecifier();
+Parser::TPResult
+Parser::TryParseDeclarationSpecifier(bool *HasMissingTypename) {
+ TPResult TPR = isCXXDeclarationSpecifier(TPResult::False(),
+ HasMissingTypename);
if (TPR != TPResult::Ambiguous())
return TPR;
if (Tok.is(tok::kw_typeof))
TryParseTypeofSpecifier();
else {
+ if (Tok.is(tok::annot_cxxscope))
+ ConsumeToken();
ConsumeToken();
if (getLangOpts().ObjC1 && Tok.is(tok::less))
TryParseProtocolQualifiers();
}
- assert(Tok.is(tok::l_paren) && "Expected '('!");
return TPResult::Ambiguous();
}
@@ -1263,9 +1279,28 @@
TentativeParsingAction PA(*this);
ConsumeParen();
- TPResult TPR = TryParseParameterDeclarationClause();
- if (TPR == TPResult::Ambiguous() && Tok.isNot(tok::r_paren))
- TPR = TPResult::False();
+ bool InvalidAsDeclaration = false;
+ TPResult TPR = TryParseParameterDeclarationClause(&InvalidAsDeclaration);
+ if (TPR == TPResult::Ambiguous()) {
+ if (Tok.isNot(tok::r_paren))
+ TPR = TPResult::False();
+ else {
+ const Token &Next = NextToken();
+ if (Next.is(tok::amp) || Next.is(tok::ampamp) ||
+ Next.is(tok::kw_const) || Next.is(tok::kw_volatile) ||
+ Next.is(tok::kw_throw) || Next.is(tok::kw_noexcept) ||
+ Next.is(tok::l_square) || isCXX0XVirtSpecifier(Next) ||
+ Next.is(tok::l_brace) || Next.is(tok::kw_try) ||
+ Next.is(tok::equal))
+ // The next token cannot appear after a constructor-style initializer,
+ // and can appear next in a function definition. This must be a function
+ // declarator.
+ TPR = TPResult::True();
+ else if (InvalidAsDeclaration)
+ // Use the absence of 'typename' as a tie-breaker.
+ TPR = TPResult::False();
+ }
+ }
SourceLocation TPLoc = Tok.getLocation();
PA.Revert();
@@ -1303,7 +1338,8 @@
/// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt]
/// attributes[opt] '=' assignment-expression
///
-Parser::TPResult Parser::TryParseParameterDeclarationClause() {
+Parser::TPResult
+Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration) {
if (Tok.is(tok::r_paren))
return TPResult::True();
@@ -1336,7 +1372,7 @@
// decl-specifier-seq
// A parameter-declaration's initializer must be preceded by an '=', so
// decl-specifier-seq '{' is not a parameter in C++11.
- TPResult TPR = TryParseDeclarationSpecifier();
+ TPResult TPR = TryParseDeclarationSpecifier(InvalidAsDeclaration);
if (TPR != TPResult::Ambiguous())
return TPR;
Modified: cfe/trunk/test/CXX/except/except.spec/p5-pointers.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/except/except.spec/p5-pointers.cpp?rev=156963&r1=156962&r2=156963&view=diff
==============================================================================
--- cfe/trunk/test/CXX/except/except.spec/p5-pointers.cpp (original)
+++ cfe/trunk/test/CXX/except/except.spec/p5-pointers.cpp Wed May 16 18:40:17 2012
@@ -65,9 +65,9 @@
void (*(*t7)())() throw(B1) = &s8; // valid
void (*(*t8)())() throw(A) = &s8; // expected-error {{return types differ}}
void (*(*t9)())() throw(D) = &s8; // expected-error {{return types differ}}
- void (*t10)(void (*)() throw(B1)) = &s9; // valid expected-warning{{disambiguated}}
- void (*t11)(void (*)() throw(A)) = &s9; // expected-error {{argument types differ}} expected-warning{{disambiguated}}
- void (*t12)(void (*)() throw(D)) = &s9; // expected-error {{argument types differ}} expected-warning{{disambiguated}}
+ void (*t10)(void (*)() throw(B1)) = &s9; // valid
+ void (*t11)(void (*)() throw(A)) = &s9; // expected-error {{argument types differ}}
+ void (*t12)(void (*)() throw(D)) = &s9; // expected-error {{argument types differ}}
}
// Member function stuff
Modified: cfe/trunk/test/SemaCXX/unknown-type-name.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/unknown-type-name.cpp?rev=156963&r1=156962&r2=156963&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/unknown-type-name.cpp (original)
+++ cfe/trunk/test/SemaCXX/unknown-type-name.cpp Wed May 16 18:40:17 2012
@@ -22,6 +22,11 @@
type f();
type g();
+
+ static int n;
+ static type m;
+ static int h(T::type, int); // expected-error{{missing 'typename'}}
+ static int h(T::type x, char); // expected-error{{missing 'typename'}}
};
template<typename T>
@@ -31,11 +36,49 @@
A<T>::type A<T>::f() { return type(); } // expected-error{{missing 'typename'}}
template<typename T>
+void f(T::type) { } // expected-error{{missing 'typename'}}
+
+template<typename T>
+void g(T::type x) { } // expected-error{{missing 'typename'}}
+
+template<typename T>
+void f(T::type, int) { } // expected-error{{missing 'typename'}}
+
+template<typename T>
+void f(T::type x, char) { } // expected-error{{missing 'typename'}}
+
+template<typename T>
void f(int, T::type) { } // expected-error{{missing 'typename'}}
template<typename T>
+void f(char, T::type x) { } // expected-error{{missing 'typename'}}
+
+template<typename T>
void f(int, T::type, int) { } // expected-error{{missing 'typename'}}
+template<typename T>
+void f(int, T::type x, char) { } // expected-error{{missing 'typename'}}
+
+template<typename T> int A<T>::n(T::value); // ok
+template<typename T>
+A<T>::type // expected-error{{missing 'typename'}}
+A<T>::m(T::value, 0); // ok
+
+template<typename T> int A<T>::h(T::type, int) {} // expected-error{{missing 'typename'}}
+template<typename T> int A<T>::h(T::type x, char) {} // expected-error{{missing 'typename'}}
+
+template<typename T> int h(T::type, int); // expected-error{{missing 'typename'}}
+template<typename T> int h(T::type x, char); // expected-error{{missing 'typename'}}
+
+template<typename T> int junk1(T::junk); // expected-error{{declared as a template}}
+template<typename T> int junk2(T::junk) throw(); // expected-error{{missing 'typename'}}
+template<typename T> int junk3(T::junk) = delete; // expected-error{{missing 'typename'}} expected-warning{{C++11}}
+template<typename T> int junk4(T::junk j); // expected-error{{missing 'typename'}}
+
+// FIXME: We can tell this was intended to be a function because it does not
+// have a dependent nested name specifier.
+template<typename T> int i(T::type, int()); // expected-error{{variable 'i' declared as a template}}
+
// FIXME: We know which type specifier should have been specified here. Provide
// a fix-it to add 'typename A<T>::type'
template<typename T>
More information about the cfe-commits
mailing list