Merge "Add initial header checker." am: 322a84666f
am: c5a3275da8
Change-Id: Ibbc78888f013013da507b342afc4de903fbd2d06
This commit is contained in:
@@ -16,4 +16,5 @@
|
||||
|
||||
subdirs = [
|
||||
"abides",
|
||||
"header-checker",
|
||||
]
|
||||
|
||||
120
vndk/tools/header-checker/Android.bp
Normal file
120
vndk/tools/header-checker/Android.bp
Normal file
@@ -0,0 +1,120 @@
|
||||
//
|
||||
// Copyright (C) 2016 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
cc_defaults {
|
||||
name: "header-checker-defaults",
|
||||
|
||||
defaults: [
|
||||
"clang-defaults",
|
||||
],
|
||||
|
||||
cflags: [
|
||||
"-Wall",
|
||||
"-Werror",
|
||||
"-std=c++11",
|
||||
],
|
||||
}
|
||||
|
||||
cc_defaults {
|
||||
name: "header-checker-lib-defaults",
|
||||
|
||||
shared_libs: [
|
||||
"libclang",
|
||||
"libLLVM",
|
||||
],
|
||||
}
|
||||
|
||||
cc_defaults {
|
||||
name: "header-checker-lib-debug-defaults",
|
||||
|
||||
static_libs: [
|
||||
"libclangTooling",
|
||||
"libclangFrontendTool",
|
||||
"libclangFrontend",
|
||||
"libclangDriver",
|
||||
"libclangSerialization",
|
||||
"libclangCodeGen",
|
||||
"libclangRewriteFrontend",
|
||||
"libclangRewrite",
|
||||
"libclangParse",
|
||||
"libclangSema",
|
||||
"libclangStaticAnalyzerFrontend",
|
||||
"libclangStaticAnalyzerCheckers",
|
||||
"libclangStaticAnalyzerMPIChecker",
|
||||
"libclangStaticAnalyzerCore",
|
||||
"libclangAnalysis",
|
||||
"libclangEdit",
|
||||
"libclangAST",
|
||||
"libclangLex",
|
||||
"libclangBasic",
|
||||
"libLLVMIRReader",
|
||||
"libLLVMAsmParser",
|
||||
"libLLVMAsmPrinter",
|
||||
"libLLVMBitReader",
|
||||
"libLLVMBitWriter",
|
||||
"libLLVMMC",
|
||||
"libLLVMMCParser",
|
||||
"libLLVMCore",
|
||||
"libLLVMOption",
|
||||
"libLLVMProfileData",
|
||||
"libLLVMObject",
|
||||
"libLLVMMCDisassembler",
|
||||
"libLLVMSupport",
|
||||
],
|
||||
}
|
||||
|
||||
cc_binary_host {
|
||||
name: "header-checker",
|
||||
|
||||
defaults: [
|
||||
"header-checker-defaults",
|
||||
"header-checker-lib-debug-defaults",
|
||||
],
|
||||
|
||||
srcs: ["src/*.cpp"],
|
||||
|
||||
target: {
|
||||
windows: {
|
||||
host_ldlibs: [
|
||||
"-limagehlp",
|
||||
"-lole32",
|
||||
"-lversion",
|
||||
],
|
||||
cflags: [
|
||||
// Skip missing-field-initializer warnings for mingw.
|
||||
"-Wno-error=missing-field-initializers",
|
||||
],
|
||||
},
|
||||
linux: {
|
||||
host_ldlibs: [
|
||||
"-ldl",
|
||||
"-lpthread",
|
||||
],
|
||||
},
|
||||
darwin: {
|
||||
host_ldlibs: [
|
||||
"-ldl",
|
||||
"-lpthread",
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
product_variables: {
|
||||
unbundled_build: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
0
vndk/tools/header-checker/MODULE_LICENSE_APACHE2
Normal file
0
vndk/tools/header-checker/MODULE_LICENSE_APACHE2
Normal file
12
vndk/tools/header-checker/README.md
Normal file
12
vndk/tools/header-checker/README.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# VNDK Header Checker
|
||||
|
||||
`header-checker` is a tool to check for ABI compliance. First, we can create a
|
||||
reference dump for each header file when we are preparing a formal release.
|
||||
After the release, we can check the ABI compliance by comparing the information
|
||||
in the reference dump and the latest header.
|
||||
|
||||
## Usage
|
||||
|
||||
Example 1:
|
||||
|
||||
$ header-checker -g -r example1.ast tests/example1.h -- clang -x c++
|
||||
160
vndk/tools/header-checker/src/frontend_action.cpp
Normal file
160
vndk/tools/header-checker/src/frontend_action.cpp
Normal file
@@ -0,0 +1,160 @@
|
||||
// Copyright (C) 2016 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "frontend_action.h"
|
||||
|
||||
#include <clang/AST/AST.h>
|
||||
#include <clang/AST/ASTConsumer.h>
|
||||
#include <clang/AST/RecursiveASTVisitor.h>
|
||||
#include <clang/Frontend/CompilerInstance.h>
|
||||
#include <clang/Frontend/MultiplexConsumer.h>
|
||||
#include <clang/Lex/PPCallbacks.h>
|
||||
#include <clang/Lex/Preprocessor.h>
|
||||
#include <clang/Lex/Token.h>
|
||||
#include <clang/Serialization/ASTWriter.h>
|
||||
#include <llvm/ADT/STLExtras.h>
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
static constexpr bool kLoadRefAsImplicitPCH = false;
|
||||
|
||||
class HeaderCheckVisitor
|
||||
: public clang::RecursiveASTVisitor<HeaderCheckVisitor> {
|
||||
public:
|
||||
bool VisitRecordDecl(const clang::RecordDecl *decl) {
|
||||
llvm::errs() << "struct: " << decl->getName() << "\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitCXXRecordDecl(const clang::CXXRecordDecl *decl) {
|
||||
llvm::errs() << "class: " << decl->getName() << "\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitFunctionDecl(const clang::FunctionDecl *decl) {
|
||||
llvm::errs() << "func: " << decl->getName() << "\n";
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class HeaderCheckerConsumer : public clang::ASTConsumer {
|
||||
public:
|
||||
void HandleTranslationUnit(clang::ASTContext &ctx) override {
|
||||
llvm::errs() << "HandleTranslationUnit ------------------------------\n";
|
||||
clang::TranslationUnitDecl* translation_unit = ctx.getTranslationUnitDecl();
|
||||
HeaderCheckVisitor v;
|
||||
v.TraverseDecl(translation_unit);
|
||||
}
|
||||
|
||||
void HandleVTable(clang::CXXRecordDecl *crd) override {
|
||||
llvm::errs() << "HandleVTable: " << crd->getName() << "\n";
|
||||
}
|
||||
};
|
||||
|
||||
class HeaderCheckerPPCallbacks : public clang::PPCallbacks {
|
||||
private:
|
||||
llvm::StringRef ToString(const clang::Token &tok) {
|
||||
return tok.getIdentifierInfo()->getName();
|
||||
}
|
||||
|
||||
public:
|
||||
void MacroDefined(const clang::Token ¯o_name_tok,
|
||||
const clang::MacroDirective *) override {
|
||||
assert(macro_name_tok.isAnyIdentifier());
|
||||
llvm::errs() << "defines: " << ToString(macro_name_tok) << "\n";
|
||||
}
|
||||
};
|
||||
|
||||
HeaderCheckerFrontendAction::HeaderCheckerFrontendAction(
|
||||
const std::string &ref_dump_name, bool should_generate_ref_dump)
|
||||
: ref_dump_name_(ref_dump_name),
|
||||
should_generate_ref_dump_(should_generate_ref_dump) { }
|
||||
|
||||
static bool VisitRefDumpDecls(void *ctx, const clang::Decl *decl) {
|
||||
HeaderCheckVisitor v;
|
||||
v.TraverseDecl(const_cast<clang::Decl *>(decl));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HeaderCheckerFrontendAction::BeginSourceFileAction(
|
||||
clang::CompilerInstance &ci, llvm::StringRef header_file) {
|
||||
|
||||
// Load reference dump file.
|
||||
if (llvm::sys::fs::exists(ref_dump_name_)) {
|
||||
if (kLoadRefAsImplicitPCH) {
|
||||
ci.getPreprocessorOpts().ImplicitPCHInclude = ref_dump_name_;
|
||||
} else {
|
||||
clang::DiagnosticsEngine &diag = ci.getDiagnostics();
|
||||
|
||||
diag.getClient()->BeginSourceFile(ci.getLangOpts(),
|
||||
&ci.getPreprocessor());
|
||||
|
||||
// FIXME: Must replace getPCHContainerReader() with other ASTReader.
|
||||
ref_dump_ = clang::ASTUnit::LoadFromASTFile(
|
||||
ref_dump_name_, ci.getPCHContainerReader(), &diag,
|
||||
ci.getFileSystemOpts(), ci.getCodeGenOpts().DebugTypeExtRefs);
|
||||
|
||||
diag.getClient()->EndSourceFile();
|
||||
|
||||
if (ref_dump_) {
|
||||
llvm::errs() << "Loaded: " << ref_dump_name_ << " : "
|
||||
<< ref_dump_->top_level_size() << "\n";
|
||||
|
||||
ref_dump_->visitLocalTopLevelDecls(nullptr, VisitRefDumpDecls);
|
||||
llvm::errs() << "----------------------------------------\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void HeaderCheckerFrontendAction::EndSourceFileAction() {
|
||||
ref_dump_.reset();
|
||||
}
|
||||
|
||||
std::unique_ptr<clang::ASTConsumer>
|
||||
HeaderCheckerFrontendAction::CreateASTConsumer(clang::CompilerInstance &ci,
|
||||
llvm::StringRef header_file) {
|
||||
// Add preprocessor callbacks.
|
||||
clang::Preprocessor &pp = ci.getPreprocessor();
|
||||
pp.addPPCallbacks(llvm::make_unique<HeaderCheckerPPCallbacks>());
|
||||
|
||||
// Create AST consumers.
|
||||
std::vector<std::unique_ptr<clang::ASTConsumer>> consumers;
|
||||
consumers.push_back(llvm::make_unique<HeaderCheckerConsumer>());
|
||||
|
||||
if (should_generate_ref_dump_) {
|
||||
std::string sysroot;
|
||||
llvm::raw_pwrite_stream *ref_dump_os = ci.createOutputFile(
|
||||
ref_dump_name_, true, false, header_file, "", true);
|
||||
if (!ref_dump_os) {
|
||||
llvm::errs() << "ERROR: Failed to create reference dump file: "
|
||||
<< ref_dump_name_ << "\n";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto buffer = std::make_shared<clang::PCHBuffer>();
|
||||
consumers.push_back(
|
||||
llvm::make_unique<clang::PCHGenerator>(
|
||||
ci.getPreprocessor(), ref_dump_name_, nullptr, "", buffer,
|
||||
ci.getFrontendOpts().ModuleFileExtensions, false, false));
|
||||
consumers.push_back(
|
||||
ci.getPCHContainerWriter().CreatePCHContainerGenerator(
|
||||
ci, header_file, ref_dump_name_, ref_dump_os, buffer));
|
||||
}
|
||||
|
||||
return llvm::make_unique<clang::MultiplexConsumer>(std::move(consumers));
|
||||
}
|
||||
49
vndk/tools/header-checker/src/frontend_action.h
Normal file
49
vndk/tools/header-checker/src/frontend_action.h
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright (C) 2016 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef FRONTEND_ACTION_H_
|
||||
#define FRONTEND_ACTION_H_
|
||||
|
||||
#include <clang/Frontend/FrontendAction.h>
|
||||
#include <llvm/ADT/StringRef.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace clang {
|
||||
class ASTConsumer;
|
||||
class CompilerInstance;
|
||||
} // namespace clang
|
||||
|
||||
class HeaderCheckerFrontendAction : public clang::ASTFrontendAction {
|
||||
private:
|
||||
std::string ref_dump_name_;
|
||||
std::unique_ptr<clang::ASTUnit> ref_dump_;
|
||||
bool should_generate_ref_dump_;
|
||||
|
||||
public:
|
||||
HeaderCheckerFrontendAction(const std::string &ref_dump_name,
|
||||
bool should_generate_ref_dump);
|
||||
|
||||
protected:
|
||||
bool BeginSourceFileAction(clang::CompilerInstance &ci,
|
||||
llvm::StringRef header_file) override;
|
||||
|
||||
void EndSourceFileAction() override;
|
||||
|
||||
std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
|
||||
clang::CompilerInstance &ci, llvm::StringRef header_file) override;
|
||||
};
|
||||
|
||||
#endif // FRONTEND_ACTION_H_
|
||||
29
vndk/tools/header-checker/src/frontend_action_factory.cpp
Normal file
29
vndk/tools/header-checker/src/frontend_action_factory.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright (C) 2016 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "frontend_action_factory.h"
|
||||
|
||||
#include "frontend_action.h"
|
||||
|
||||
#include <clang/Frontend/FrontendActions.h>
|
||||
|
||||
HeaderCheckerFrontendActionFactory::HeaderCheckerFrontendActionFactory(
|
||||
const std::string &ref_dump_name, bool should_generate_ref_dump)
|
||||
: ref_dump_name_(ref_dump_name),
|
||||
should_generate_ref_dump_(should_generate_ref_dump) { }
|
||||
|
||||
clang::FrontendAction *HeaderCheckerFrontendActionFactory::create() {
|
||||
return new HeaderCheckerFrontendAction(ref_dump_name_,
|
||||
should_generate_ref_dump_);
|
||||
}
|
||||
33
vndk/tools/header-checker/src/frontend_action_factory.h
Normal file
33
vndk/tools/header-checker/src/frontend_action_factory.h
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright (C) 2016 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef FRONTEND_ACTION_FACTORY_H_
|
||||
#define FRONTEND_ACTION_FACTORY_H_
|
||||
|
||||
#include <clang/Tooling/Tooling.h>
|
||||
|
||||
class HeaderCheckerFrontendActionFactory
|
||||
: public clang::tooling::FrontendActionFactory {
|
||||
private:
|
||||
std::string ref_dump_name_;
|
||||
bool should_generate_ref_dump_;
|
||||
|
||||
public:
|
||||
HeaderCheckerFrontendActionFactory(const std::string &ref_dump_name,
|
||||
bool should_generate_ref_dump);
|
||||
|
||||
clang::FrontendAction *create() override;
|
||||
};
|
||||
|
||||
#endif // FRONTEND_ACTION_FACTORY_H_
|
||||
98
vndk/tools/header-checker/src/header_checker.cpp
Normal file
98
vndk/tools/header-checker/src/header_checker.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright (C) 2016 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "frontend_action_factory.h"
|
||||
|
||||
#include <clang/Frontend/FrontendActions.h>
|
||||
#include <clang/Tooling/CommonOptionsParser.h>
|
||||
#include <clang/Tooling/CompilationDatabase.h>
|
||||
#include <clang/Tooling/Tooling.h>
|
||||
#include <llvm/Support/CommandLine.h>
|
||||
#include <llvm/Support/FileSystem.h>
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static llvm::cl::OptionCategory header_checker_category(
|
||||
"header-checker options");
|
||||
|
||||
static llvm::cl::opt<std::string> header_file(
|
||||
llvm::cl::Positional, llvm::cl::desc("<header>"), llvm::cl::Required,
|
||||
llvm::cl::cat(header_checker_category));
|
||||
|
||||
static llvm::cl::opt<std::string> ref_dump(
|
||||
"r", llvm::cl::value_desc("refdump"), llvm::cl::Required,
|
||||
llvm::cl::desc("Specify the reference dump file name"),
|
||||
llvm::cl::cat(header_checker_category));
|
||||
|
||||
static llvm::cl::opt<bool> gen_ref_dump(
|
||||
"g", llvm::cl::init(false),
|
||||
llvm::cl::desc("Generate reference dump for header file"),
|
||||
llvm::cl::cat(header_checker_category));
|
||||
|
||||
// Hide irrelevant command line options defined in LLVM libraries.
|
||||
static void HideIrrelevantCommandLineOptions() {
|
||||
llvm::StringMap<llvm::cl::Option *> &map = llvm::cl::getRegisteredOptions();
|
||||
for (llvm::StringMapEntry<llvm::cl::Option *> &p : map) {
|
||||
if (p.second->Category == &header_checker_category) {
|
||||
continue;
|
||||
}
|
||||
if (p.first().startswith("help")) {
|
||||
continue;
|
||||
}
|
||||
p.second->setHiddenFlag(llvm::cl::Hidden);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
HideIrrelevantCommandLineOptions();
|
||||
|
||||
// Create compilation database from command line arguments after "--".
|
||||
std::unique_ptr<clang::tooling::CompilationDatabase> compilations(
|
||||
clang::tooling::FixedCompilationDatabase::loadFromCommandLine(
|
||||
argc, argv));
|
||||
|
||||
// Parse the command line options.
|
||||
llvm::cl::ParseCommandLineOptions(argc, argv, "header-checker");
|
||||
|
||||
// Check the availability of input header file and reference dump file.
|
||||
if (!llvm::sys::fs::exists(header_file)) {
|
||||
llvm::errs() << "ERROR: Header file \"" << header_file << "\" not found\n";
|
||||
::exit(1);
|
||||
}
|
||||
|
||||
if (!gen_ref_dump && !llvm::sys::fs::exists(ref_dump)) {
|
||||
llvm::errs() << "ERROR: Reference file \"" << ref_dump << "\" not found\n";
|
||||
::exit(1);
|
||||
}
|
||||
|
||||
// Check the availability of clang compilation options.
|
||||
if (!compilations) {
|
||||
llvm::errs() << "ERROR: Clang compilation options not specified.\n";
|
||||
::exit(1);
|
||||
}
|
||||
|
||||
// Initialize clang tools and run front-end action.
|
||||
std::vector<std::string> header_files{ header_file };
|
||||
|
||||
clang::tooling::ClangTool tool(*compilations, header_files);
|
||||
|
||||
std::unique_ptr<clang::tooling::FrontendActionFactory> factory(
|
||||
new HeaderCheckerFrontendActionFactory(ref_dump, gen_ref_dump));
|
||||
|
||||
return tool.run(factory.get());
|
||||
}
|
||||
50
vndk/tools/header-checker/tests/example1.h
Normal file
50
vndk/tools/header-checker/tests/example1.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef EXAMPLE1_H_
|
||||
#define EXAMPLE1_H_
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Hello {
|
||||
int foo;
|
||||
int bar;
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
struct StackNode {
|
||||
public:
|
||||
T value_;
|
||||
StackNode<T>* next_;
|
||||
|
||||
public:
|
||||
StackNode(T t, StackNode* next = nullptr)
|
||||
: value_(static_cast<T&&>(t)),
|
||||
next_(next) { }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class Stack {
|
||||
private:
|
||||
StackNode<T>* head_;
|
||||
|
||||
public:
|
||||
Stack() : head_(nullptr) { }
|
||||
|
||||
void push(T t) {
|
||||
head_ = new StackNode<T>(static_cast<T&&>(t), head_);
|
||||
}
|
||||
|
||||
T pop() {
|
||||
StackNode<T>* cur = head_;
|
||||
head_ = cur->next_;
|
||||
T res = static_cast<T&&>(cur->value_);
|
||||
delete cur;
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // EXAMPLE1_H_
|
||||
Reference in New Issue
Block a user