Skip to content

Commit

Permalink
CMake: detect and refuse broken std::regex
Browse files Browse the repository at this point in the history
Swift SVN r32256
  • Loading branch information
gribozavr committed Sep 26, 2015
1 parent 82fd400 commit 0b4a54f
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 22 deletions.
29 changes: 29 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ endif()
# Include CMake modules
#

include(CheckCXXSourceRuns)
include(CMakeParseArguments)
include(SwiftTranslateFlag)
include(SwiftHandleGybSources)
Expand Down Expand Up @@ -305,6 +306,34 @@ if(XCODE)
swift_common_xcode_cxx_config()
endif()

function(check_working_std_regex result_var_name)
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
# Apple operating systems use libc++, which has a working std::regex.
set("${result_var_name}" TRUE PARENT_SCOPE)
else()
# libstdc++ 4.8 has an incomplete std::regex implementation, and crashes
# on many regexes.
# libstdc++ 4.9 works.
set(std_regex_test_source
"
#include <regex>
const std::regex broken_regex{
\"([a]+)\",
std::regex::ECMAScript | std::regex::nosubs};
int main() {}
")

check_cxx_source_runs("${std_regex_test_source}" result)
if (result)
set("${result_var_name}" TRUE PARENT_SCOPE)
else()
set("${result_var_name}" FALSE PARENT_SCOPE)
endif()
endif()
endfunction()
check_working_std_regex(SWIFT_HAVE_WORKING_STD_REGEX)

#
# Enable additional warnings.
#
Expand Down
1 change: 1 addition & 0 deletions include/swift/Config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@

#cmakedefine SWIFT_ENABLE_OBJECT_LITERALS 1
#cmakedefine SWIFT_ENABLE_TARGET_TVOS 1
#cmakedefine SWIFT_HAVE_WORKING_STD_REGEX 1

#endif // SWIFT_CONFIG_H
60 changes: 38 additions & 22 deletions lib/IDE/SyntaxModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "swift/Basic/SourceManager.h"
#include "swift/Parse/Lexer.h"
#include "swift/Parse/Token.h"
#include "swift/Config.h"
#include "swift/Subsystems.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/MemoryBuffer.h"
Expand Down Expand Up @@ -238,8 +239,8 @@ class ModelASTWalker : public ASTWalker {
unsigned BufferID;
std::vector<StructureElement> SubStructureStack;
SourceLoc LastLoc;
static const std::regex URLRxs[3];
static const std::regex DocCommentRxs[3];
static const std::regex &getURLRegex(unsigned Index);
static const std::regex &getDocCommentRegex(unsigned Index);

Optional<SyntaxNode> parseFieldNode(StringRef Text, StringRef OrigText,
SourceLoc OrigLoc);
Expand Down Expand Up @@ -307,26 +308,32 @@ class ModelASTWalker : public ASTWalker {
}
};

const std::regex ModelASTWalker::URLRxs[3] = {
const std::regex &ModelASTWalker::getURLRegex(unsigned Index) {
static const std::regex Regexes[3] = {
std::regex{ RegexStrURL, std::regex::ECMAScript | std::regex::nosubs },
std::regex{ RegexStrMailURL, std::regex::ECMAScript | std::regex::nosubs },
std::regex{ RegexStrRadarURL, std::regex::ECMAScript | std::regex::nosubs }
};
};
return Regexes[Index];
}

const std::regex ModelASTWalker::DocCommentRxs[3] = {
std::regex {
RegexStrParameter,
std::regex::egrep | std::regex::icase | std::regex::optimize
},
std::regex {
RegexStrDocCommentParametersHeading,
std::regex::egrep | std::regex::icase | std::regex::optimize
},
std::regex {
RegexStrDocCommentField,
std::regex::egrep | std::regex::icase | std::regex::optimize
}
};
const std::regex &ModelASTWalker::getDocCommentRegex(unsigned Index) {
static const std::regex Regexes[3] = {
std::regex {
RegexStrParameter,
std::regex::egrep | std::regex::icase | std::regex::optimize
},
std::regex {
RegexStrDocCommentParametersHeading,
std::regex::egrep | std::regex::icase | std::regex::optimize
},
std::regex {
RegexStrDocCommentField,
std::regex::egrep | std::regex::icase | std::regex::optimize
}
};
return Regexes[Index];
}

SyntaxStructureKind syntaxStructureKindFromNominalTypeDecl(NominalTypeDecl *N) {
if (isa<ClassDecl>(N))
Expand Down Expand Up @@ -1291,6 +1298,10 @@ bool ModelASTWalker::processComment(CharSourceRange Range) {
bool ModelASTWalker::findUrlStartingLoc(StringRef Text,
unsigned &Start,
std::regex &Regex) {
#ifndef SWIFT_HAVE_WORKING_STD_REGEX
return false;
#endif

static const auto MailToPosition = std::find(URLProtocols.begin(),
URLProtocols.end(),
"mailto");
Expand All @@ -1306,11 +1317,11 @@ bool ModelASTWalker::findUrlStartingLoc(StringRef Text,
Text.substr(Index - It->size(), It->size()) == *It) {
Start = Index - It->size();
if (It < MailToPosition)
Regex = URLRxs[0];
Regex = getURLRegex(0);
else if (It < RadarPosition)
Regex = URLRxs[1];
Regex = getURLRegex(1);
else
Regex = URLRxs[2];
Regex = getURLRegex(2);
return true;
}
}
Expand Down Expand Up @@ -1350,8 +1361,13 @@ bool ModelASTWalker::searchForURL(CharSourceRange Range) {
Optional<SyntaxNode> ModelASTWalker::parseFieldNode(StringRef Text,
StringRef OrigText,
SourceLoc OrigLoc) {
#ifndef SWIFT_HAVE_WORKING_STD_REGEX
return None;
#endif

std::match_results<StringRef::iterator> Matches;
for (auto &Rx : DocCommentRxs) {
for (unsigned i = 0; i != 3; ++i) {
auto &Rx = getDocCommentRegex(i);
bool HadMatch = std::regex_search(Text.begin(), Text.end(), Matches, Rx);
if (HadMatch)
break;
Expand Down
1 change: 1 addition & 0 deletions test/IDE/coloring.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// RUN: %target-swift-ide-test -syntax-coloring -source-filename %s | FileCheck %s
// RUN: %target-swift-ide-test -syntax-coloring -typecheck -source-filename %s | FileCheck %s
// XFAIL: broken_std_regex

#line 17 "abc.swift"
// CHECK: <#kw>#line</#kw> <int>17</int> <str>"abc.swift"</str>
Expand Down
3 changes: 3 additions & 0 deletions test/lit.site.cfg.in
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ if "@SWIFT_ENABLE_OBJECT_LITERALS@" == "TRUE":
if "@SWIFT_OPTIMIZED@" == "TRUE":
config.available_features.add("optimized_stdlib")

if "@SWIFT_HAVE_WORKING_STD_REGEX@" == "FALSE":
config.available_features.add('broken_std_regex')

# Let the main config do the real work.
if config.test_exec_root is None:
config.test_exec_root = os.path.dirname(os.path.realpath(__file__))
Expand Down

0 comments on commit 0b4a54f

Please sign in to comment.