Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ TBA
* Fixed a whitespace/newline false positive for control conditions containing lambdas. (#410)
* We now error on relative include paths (``./``, ``../``). (#432)
* This makes ``#include "./foo.h"`` produce two separate errors: that foo.cpp should include foo.h and that relative paths are not allowed.
* Deleted single-argument constructors no longer trigger ``runtime/explicit``. (#386)

2.0.2 (2025-04-08)
===========
Expand Down
48 changes: 48 additions & 0 deletions cpplint.py
Original file line number Diff line number Diff line change
Expand Up @@ -3786,6 +3786,43 @@ def InnermostClass(self):
return None


def _GetConstructorSuffix(clean_lines, linenum, match_end):
"""Returns the constructor declaration suffix up to its top-level terminator."""
constructor_suffix = []
paren_depth = 0
bracket_depth = 0
brace_depth = 0
suffix_line = clean_lines.elided[linenum][match_end:]
next_line = linenum + 1

while True:
for char in suffix_line:
if char == ";" and not paren_depth and not bracket_depth and not brace_depth:
constructor_suffix.append(char)
return "".join(constructor_suffix)
if char == "{" and not paren_depth and not bracket_depth and not brace_depth:
return "".join(constructor_suffix)

constructor_suffix.append(char)
if char == "(":
paren_depth += 1
elif char == ")":
paren_depth -= 1
elif char == "[":
bracket_depth += 1
elif char == "]":
bracket_depth -= 1
elif char == "{":
brace_depth += 1
elif char == "}":
brace_depth -= 1

if next_line >= clean_lines.NumLines():
return "".join(constructor_suffix)
suffix_line = "\n" + clean_lines.elided[next_line]
next_line += 1


def CheckForNonStandardConstructs(filename, clean_lines, linenum, nesting_state, error):
r"""Logs an error if we see certain non-ANSI constructs ignored by gcc-2.

Expand Down Expand Up @@ -3932,6 +3969,16 @@ def CheckForNonStandardConstructs(filename, clean_lines, linenum, nesting_state,

if explicit_constructor_match:
is_marked_explicit = explicit_constructor_match.group(1)
constructor_suffix = _GetConstructorSuffix(
clean_lines, linenum, explicit_constructor_match.end()
)
is_deleted = bool(
re.search(
r"=\s*delete\s*(?:\(.*\))?\s*;\s*$",
constructor_suffix,
re.DOTALL,
)
)

if not explicit_constructor_match.group(2):
constructor_args = []
Expand Down Expand Up @@ -3990,6 +4037,7 @@ def CheckForNonStandardConstructs(filename, clean_lines, linenum, nesting_state,

if (
not is_marked_explicit
and not is_deleted
and onearg_constructor
and not initializer_list_constructor
and not copy_constructor
Expand Down
62 changes: 62 additions & 0 deletions cpplint_unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1639,6 +1639,68 @@ class Foo {
};""",
"Single-parameter constructors should be marked explicit. [runtime/explicit] [4]",
)
# Deleted constructors cannot be called implicitly.
self.TestMultiLineLint(
"""
class Foo {
Foo(int f) = delete;
};""",
"",
)
# Deleted constructors may include a noexcept suffix or split the
# deleted marker across lines.
self.TestMultiLineLint(
"""
class Foo {
Foo(int f) noexcept = delete;
};""",
"",
)
self.TestMultiLineLint(
"""
class Foo {
Foo(int f) noexcept(noexcept(T{})) = delete;
};""",
"",
)
self.TestMultiLineLint(
"""
class Foo {
template <class T>
Foo(T value) requires Integral<T> = delete;
};""",
"",
)
self.TestMultiLineLint(
"""
class Foo {
template <class T>
Foo(T value) requires Integral<T>;
};""",
"Single-parameter constructors should be marked explicit. [runtime/explicit] [4]",
)
self.TestMultiLineLint(
"""
class Foo {
Foo(int f) throw() = delete;
};""",
"",
)
self.TestMultiLineLint(
"""
class Foo {
Foo(int f) = delete("use Bar instead");
};""",
"",
)
self.TestMultiLineLint(
"""
class Foo {
Foo(int f)
= delete;
};""",
"",
)
# missing explicit is bad, even with whitespace
self.TestMultiLineLint(
"""
Expand Down