Reject template-ids containing literal-operator-ids that have a dependent

nested-name-specifier, rather than crashing. (In fact, reject all
literal-operator-ids that have a non-namespace nested-name-specifier). The
grammar doesn't allow these in some cases, and in other cases does allow them
but instantiation will always fail.

llvm-svn: 196443
This commit is contained in:
Richard Smith 2013-12-05 00:58:33 +00:00
parent b9a69f6129
commit d091dc179d
6 changed files with 66 additions and 7 deletions

View File

@ -6009,6 +6009,8 @@ def err_operator_delete_param_type : Error<
// C++ literal operators
def err_literal_operator_outside_namespace : Error<
"literal operator %0 must be in a namespace or global scope">;
def err_literal_operator_id_outside_namespace : Error<
"non-namespace scope '%0' cannot have a literal operator member">;
def err_literal_operator_default_argument : Error<
"literal operator cannot have a default argument">;
// FIXME: This diagnostic sucks

View File

@ -2478,6 +2478,7 @@ public:
bool RValueThis, unsigned ThisQuals);
CXXDestructorDecl *LookupDestructor(CXXRecordDecl *Class);
bool checkLiteralOperatorId(const CXXScopeSpec &SS, const UnqualifiedId &Id);
LiteralOperatorLookupResult LookupLiteralOperator(Scope *S, LookupResult &R,
ArrayRef<QualType> ArgTys,
bool AllowRaw,

View File

@ -287,19 +287,23 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
TentativeParsingAction TPA(*this);
SourceLocation TemplateKWLoc = ConsumeToken();
UnqualifiedId TemplateName;
if (Tok.is(tok::identifier)) {
// Consume the identifier.
TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
ConsumeToken();
} else if (Tok.is(tok::kw_operator)) {
if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType,
// We don't need to actually parse the unqualified-id in this case,
// because a simple-template-id cannot start with 'operator', but
// go ahead and parse it anyway for consistency with the case where
// we already annotated the template-id.
if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType,
TemplateName)) {
TPA.Commit();
break;
}
if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId &&
TemplateName.getKind() != UnqualifiedId::IK_LiteralOperatorId) {
Diag(TemplateName.getSourceRange().getBegin(),
@ -2131,9 +2135,10 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
}
Result.setLiteralOperatorId(II, KeywordLoc, SuffixLoc);
return false;
return Actions.checkLiteralOperatorId(SS, Result);
}
// Parse a conversion-function-id.
//
// conversion-function-id: [C++ 12.3.2]

View File

@ -333,6 +333,34 @@ ParsedType Sema::getDestructorType(const DeclSpec& DS, ParsedType ObjectType) {
return ParsedType();
}
bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS,
const UnqualifiedId &Name) {
assert(Name.getKind() == UnqualifiedId::IK_LiteralOperatorId);
if (!SS.isValid())
return false;
switch (SS.getScopeRep()->getKind()) {
case NestedNameSpecifier::Identifier:
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
// Per C++11 [over.literal]p2, literal operators can only be declared at
// namespace scope. Therefore, this unqualified-id cannot name anything.
// Reject it early, because we have no AST representation for this in the
// case where the scope is dependent.
Diag(Name.getLocStart(), diag::err_literal_operator_id_outside_namespace)
<< SS.getScopeRep();
return true;
case NestedNameSpecifier::Global:
case NestedNameSpecifier::Namespace:
case NestedNameSpecifier::NamespaceAlias:
return false;
}
llvm_unreachable("unknown nested name specifier kind");
}
/// \brief Build a C++ typeid expression with a type operand.
ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
SourceLocation TypeidLoc,

View File

@ -2914,8 +2914,7 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
return TNK_Function_template;
case UnqualifiedId::IK_LiteralOperatorId:
llvm_unreachable(
"We don't support these; Parse shouldn't have allowed propagation");
llvm_unreachable("literal operator id cannot have a dependent scope");
default:
break;

View File

@ -141,3 +141,27 @@ namespace PR14950 {
int operator"" _b(); // expected-error {{no function template matches function template specialization}}
int main() { return 0_b; } // expected-error {{no matching literal operator for call to 'operator "" _b'}}
}
namespace bad_names {
template<char...> int operator""_x();
template<typename T> void f() {
class T:: // expected-error {{anonymous class}} expected-warning {{does not declare anything}}
operator // expected-error {{expected identifier}}
""_q<'a'>;
T::template operator""_q<'a'>(); // expected-error {{non-namespace scope 'T::' cannot have a literal operator member}} expected-error +{{}}
T::template operator""_q<'a'>::X; // expected-error {{non-namespace scope 'T::' cannot have a literal operator member}} expected-error +{{}}
T::operator""_q<'a'>(); // expected-error {{non-namespace scope 'T::' cannot have a literal operator member}} expected-error +{{}}
typename T::template operator""_q<'a'> a; // expected-error {{non-namespace scope 'T::' cannot have a literal operator member}} expected-error +{{}}
typename T::operator""_q(""); // expected-error +{{}} expected-note {{to match}}
T::operator""_q(""); // expected-error {{non-namespace scope 'T::' cannot have a literal operator member}}
bad_names::operator""_x<'a', 'b', 'c'>();
};
struct S {};
void g() {
S::operator""_q(); // expected-error {{non-namespace scope 'S::' cannot have a literal operator member}}
}
}